aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/components/services/Rtorrent.vue115
-rw-r--r--src/components/services/qBittorrent.vue242
2 files changed, 185 insertions, 172 deletions
diff --git a/src/components/services/Rtorrent.vue b/src/components/services/Rtorrent.vue
index 75efb7b..ed8e7a6 100644
--- a/src/components/services/Rtorrent.vue
+++ b/src/components/services/Rtorrent.vue
@@ -8,14 +8,13 @@
8 <span class="down"> 8 <span class="down">
9 <i class="fas fa-download"></i> {{ downRate }} 9 <i class="fas fa-download"></i> {{ downRate }}
10 </span> 10 </span>
11 <span class="up"> 11 <span class="up"> <i class="fas fa-upload"></i> {{ upRate }} </span>
12 <i class="fas fa-upload"></i> {{ upRate }}
13 </span>
14 </template> 12 </template>
15 </p> 13 </p>
16 </template> 14 </template>
17 <template #indicator> 15 <template #indicator>
18 <span v-if="!error" class="count">{{ count }} 16 <span v-if="!error" class="count"
17 >{{ count }}
19 <template v-if="count === 1">torrent</template> 18 <template v-if="count === 1">torrent</template>
20 <template v-else>torrents</template> 19 <template v-else>torrents</template>
21 </span> 20 </span>
@@ -24,38 +23,41 @@
24</template> 23</template>
25 24
26<script> 25<script>
27import Generic from './Generic.vue'; 26import Generic from "./Generic.vue";
28 27
29// Units to add to download and upload rates. 28// Units to add to download and upload rates.
30const units = ['B', 'kiB', 'MiB', 'GiB']; 29const units = ["B", "kiB", "MiB", "GiB"];
31 30
32// Take the rate in bytes and keep dividing it by 1k until the lowest 31// Take the rate in bytes and keep dividing it by 1k until the lowest
33// value for which we have a unit is determined. Return the value with 32// value for which we have a unit is determined. Return the value with
34// up to two decimals as a string and unit/s appended. 33// up to two decimals as a string and unit/s appended.
35const displayRate = (rate) => { 34const displayRate = (rate) => {
36 let i = 0; 35 let i = 0;
37 36
38 while (rate > 1000 && i < units.length) { 37 while (rate > 1000 && i < units.length) {
39 rate /= 1000; 38 rate /= 1000;
40 i++; 39 i++;
41 } 40 }
42 41
43 return Intl.NumberFormat(undefined, {maximumFractionDigits: 2}) 42 return (
44 .format(rate || 0) + ` ${units[i]}/s`; 43 Intl.NumberFormat(undefined, { maximumFractionDigits: 2 }).format(
45} 44 rate || 0
45 ) + ` ${units[i]}/s`
46 );
47};
46 48
47export default { 49export default {
48 name: 'rTorrent', 50 name: "rTorrent",
49 props: {item: Object}, 51 props: { item: Object },
50 components: {Generic}, 52 components: { Generic },
51 // Properties for download, upload, torrent count and errors. 53 // Properties for download, upload, torrent count and errors.
52 data: () => ({dl: null, ul: null, count: null, error: null}), 54 data: () => ({ dl: null, ul: null, count: null, error: null }),
53 // Computed properties for the rate labels. 55 // Computed properties for the rate labels.
54 computed: { 56 computed: {
55 downRate: function() { 57 downRate: function () {
56 return displayRate(this.dl); 58 return displayRate(this.dl);
57 }, 59 },
58 upRate: function() { 60 upRate: function () {
59 return displayRate(this.ul); 61 return displayRate(this.ul);
60 }, 62 },
61 }, 63 },
@@ -72,7 +74,7 @@ export default {
72 if (torrentInterval > 0) { 74 if (torrentInterval > 0) {
73 setInterval(() => this.fetchCount(), torrentInterval); 75 setInterval(() => this.fetchCount(), torrentInterval);
74 } 76 }
75 77
76 // Fetch the initial values. 78 // Fetch the initial values.
77 this.fetchRates(); 79 this.fetchRates();
78 this.fetchCount(); 80 this.fetchCount();
@@ -81,62 +83,71 @@ export default {
81 // Perform two calls to the XML-RPC service and fetch download 83 // Perform two calls to the XML-RPC service and fetch download
82 // and upload rates. Values are saved to the `ul` and `dl` 84 // and upload rates. Values are saved to the `ul` and `dl`
83 // properties. 85 // properties.
84 fetchRates: async function() { 86 fetchRates: async function () {
85 this.getRate('throttle.global_up.rate') 87 this.getRate("throttle.global_up.rate")
86 .then((ul) => this.ul = ul) 88 .then((ul) => (this.ul = ul))
87 .catch(() => this.error = true); 89 .catch(() => (this.error = true));
88 90
89 this.getRate('throttle.global_down.rate') 91 this.getRate("throttle.global_down.rate")
90 .then((dl) => this.dl = dl) 92 .then((dl) => (this.dl = dl))
91 .catch(() => this.error = true); 93 .catch(() => (this.error = true));
92 }, 94 },
93 // Perform a call to the XML-RPC service to fetch the number of 95 // Perform a call to the XML-RPC service to fetch the number of
94 // torrents. 96 // torrents.
95 fetchCount: async function() { 97 fetchCount: async function () {
96 this.getCount().catch(() => this.error = true); 98 this.getCount().catch(() => (this.error = true));
97 }, 99 },
98 // Fetch a numeric value from the XML-RPC service by requesting 100 // Fetch a numeric value from the XML-RPC service by requesting
99 // the specified method name and parsing the XML. The response 101 // the specified method name and parsing the XML. The response
100 // is expected to adhere to the structure of a single numeric 102 // is expected to adhere to the structure of a single numeric
101 // value. 103 // value.
102 getRate: async function(methodName) { 104 getRate: async function (methodName) {
103 return this.getXml(methodName) 105 return this.getXml(methodName).then((xml) =>
104 .then((xml) => parseInt(xml.getElementsByTagName('value')[0].firstChild.textContent, 10)); 106 parseInt(
107 xml.getElementsByTagName("value")[0].firstChild.textContent,
108 10
109 )
110 );
105 }, 111 },
106 // Fetch the numer of torrents by requesting the download list 112 // Fetch the numer of torrents by requesting the download list
107 // and counting the number of entries therein. 113 // and counting the number of entries therein.
108 getCount: async function() { 114 getCount: async function () {
109 return this.getXml('download_list') 115 return this.getXml("download_list").then((xml) => {
110 .then((xml) => { 116 const arrayEl = xml.getElementsByTagName("array");
111 const arrayEl = xml.getElementsByTagName('array'); 117 this.count = arrayEl
112 this.count = arrayEl ? arrayEl[0].getElementsByTagName('value').length : 0; 118 ? arrayEl[0].getElementsByTagName("value").length
113 }); 119 : 0;
120 });
114 }, 121 },
115 // Perform a call to the XML-RPC service and parse the response 122 // Perform a call to the XML-RPC service and parse the response
116 // as XML, which is then returned. 123 // as XML, which is then returned.
117 getXml: async function(methodName) { 124 getXml: async function (methodName) {
118 const headers = {'Content-Type': 'text/xml'}; 125 const headers = { "Content-Type": "text/xml" };
119 126
120 if (this.item.username && this.item.password) { 127 if (this.item.username && this.item.password) {
121 headers['Authorization'] = `${this.item.username}:${this.item.password}`; 128 headers[
129 "Authorization"
130 ] = `${this.item.username}:${this.item.password}`;
122 } 131 }
123 132
124 return fetch(`${this.item.xmlrpc.replace(/\/$/, '')}/RPC2`, { 133 return fetch(`${this.item.xmlrpc.replace(/\/$/, "")}/RPC2`, {
125 method: 'POST', 134 method: "POST",
126 headers, 135 headers,
127 body: `<methodCall><methodName>${methodName}</methodName></methodCall>` 136 body: `<methodCall><methodName>${methodName}</methodName></methodCall>`,
128 }) 137 })
129 .then((response) => { 138 .then((response) => {
130 if (!response.ok) { 139 if (!response.ok) {
131 throw Error(response.statusText); 140 throw Error(response.statusText);
132 } 141 }
133 142
134 return response.text(); 143 return response.text();
135 }) 144 })
136 .then((text) => Promise.resolve(new DOMParser().parseFromString(text, 'text/xml'))); 145 .then((text) =>
137 } 146 Promise.resolve(new DOMParser().parseFromString(text, "text/xml"))
138 } 147 );
139} 148 },
149 },
150};
140</script> 151</script>
141 152
142<style scoped lang="scss"> 153<style scoped lang="scss">
@@ -150,4 +161,4 @@ export default {
150 color: var(--text); 161 color: var(--text);
151 font-size: 0.8em; 162 font-size: 0.8em;
152} 163}
153</style> \ No newline at end of file 164</style>
diff --git a/src/components/services/qBittorrent.vue b/src/components/services/qBittorrent.vue
index 1f1ef49..06dd47c 100644
--- a/src/components/services/qBittorrent.vue
+++ b/src/components/services/qBittorrent.vue
@@ -1,120 +1,122 @@
1<template> 1<template>
2 <Generic :item="item"> 2 <Generic :item="item">
3 <template #content> 3 <template #content>
4 <p class="title is-4">{{ item.name }}</p> 4 <p class="title is-4">{{ item.name }}</p>
5 <p class="subtitle is-6"> 5 <p class="subtitle is-6">
6 <span v-if="error" class="error">An error has occurred.</span> 6 <span v-if="error" class="error">An error has occurred.</span>
7 <template v-else> 7 <template v-else>
8 <span class="down monospace"> 8 <span class="down monospace">
9 <p class="fas fa-download "></p> {{ downRate }} 9 <p class="fas fa-download"></p>
10 </span> 10 {{ downRate }}
11 <span class="up monospace"> 11 </span>
12 <p class="fas fa-upload"></p> {{ upRate }} 12 <span class="up monospace">
13 </span> 13 <p class="fas fa-upload"></p>
14 </template> 14 {{ upRate }}
15 </p> 15 </span>
16 </template> 16 </template>
17 <template #indicator> 17 </p>
18 <span v-if="!error" class="count">{{ count }} 18 </template>
19 <template v-if="count === 1">torrent</template> 19 <template #indicator>
20 <template v-else>torrents</template> 20 <span v-if="!error" class="count"
21 </span> 21 >{{ count }}
22 </template> 22 <template v-if="count === 1">torrent</template>
23 </Generic> 23 <template v-else>torrents</template>
24</template> 24 </span>
25 25 </template>
26<script> 26 </Generic>
27import service from "@/mixins/service.js"; 27</template>
28import Generic from "./Generic.vue"; 28
29const units = ["B", "KB", "MB", "GB"]; 29<script>
30 30import service from "@/mixins/service.js";
31// Take the rate in bytes and keep dividing it by 1k until the lowest 31import Generic from "./Generic.vue";
32// value for which we have a unit is determined. Return the value with 32const units = ["B", "KB", "MB", "GB"];
33// up to two decimals as a string and unit/s appended. 33
34const displayRate = (rate) => { 34// Take the rate in bytes and keep dividing it by 1k until the lowest
35 let i = 0; 35// value for which we have a unit is determined. Return the value with
36 36// up to two decimals as a string and unit/s appended.
37 while (rate > 1000 && i < units.length) { 37const displayRate = (rate) => {
38 rate /= 1000; 38 let i = 0;
39 i++; 39
40 } 40 while (rate > 1000 && i < units.length) {
41 return ( 41 rate /= 1000;
42 Intl.NumberFormat(undefined, { maximumFractionDigits: 2 }).format( 42 i++;
43 rate || 0 43 }
44 ) + ` ${units[i]}/s` 44 return (
45 ); 45 Intl.NumberFormat(undefined, { maximumFractionDigits: 2 }).format(
46}; 46 rate || 0
47 47 ) + ` ${units[i]}/s`
48export default { 48 );
49 name: "qBittorrent", 49};
50 mixins: [service], 50
51 props: { item: Object }, 51export default {
52 components: { Generic }, 52 name: "qBittorrent",
53 data: () => ({ dl: null, ul: null, count: null, error: null }), 53 mixins: [service],
54 computed: { 54 props: { item: Object },
55 downRate: function () { 55 components: { Generic },
56 return displayRate(this.dl); 56 data: () => ({ dl: null, ul: null, count: null, error: null }),
57 }, 57 computed: {
58 upRate: function () { 58 downRate: function () {
59 return displayRate(this.ul); 59 return displayRate(this.dl);
60 }, 60 },
61 }, 61 upRate: function () {
62 created() { 62 return displayRate(this.ul);
63 const rateInterval = parseInt(this.item.rateInterval, 10) || 0; 63 },
64 const torrentInterval = parseInt(this.item.torrentInterval, 10) || 0; 64 },
65 if (rateInterval > 0) { 65 created() {
66 setInterval(() => this.getRate(), rateInterval); 66 const rateInterval = parseInt(this.item.rateInterval, 10) || 0;
67 } 67 const torrentInterval = parseInt(this.item.torrentInterval, 10) || 0;
68 if (torrentInterval > 0) { 68 if (rateInterval > 0) {
69 setInterval(() => this.fetchCount(), torrentInterval); 69 setInterval(() => this.getRate(), rateInterval);
70 } 70 }
71 71 if (torrentInterval > 0) {
72 this.getRate(); 72 setInterval(() => this.fetchCount(), torrentInterval);
73 this.fetchCount(); 73 }
74 }, 74
75 methods: { 75 this.getRate();
76 fetchCount: async function () { 76 this.fetchCount();
77 try { 77 },
78 const body = await this.fetch('/api/v2/torrents/info'); 78 methods: {
79 this.error = false; 79 fetchCount: async function () {
80 this.count = body.length; 80 try {
81 } catch (e) { 81 const body = await this.fetch("/api/v2/torrents/info");
82 this.error = true; 82 this.error = false;
83 console.error(e); 83 this.count = body.length;
84 } 84 } catch (e) {
85 }, 85 this.error = true;
86 getRate: async function () { 86 console.error(e);
87 try { 87 }
88 const body = await this.fetch('/api/v2/transfer/info'); 88 },
89 this.error = false; 89 getRate: async function () {
90 this.dl = body.dl_info_speed; 90 try {
91 this.ul = body.up_info_speed; 91 const body = await this.fetch("/api/v2/transfer/info");
92 } catch (e) { 92 this.error = false;
93 this.error = true; 93 this.dl = body.dl_info_speed;
94 console.error(e); 94 this.ul = body.up_info_speed;
95 } 95 } catch (e) {
96 }, 96 this.error = true;
97 }, 97 console.error(e);
98}; 98 }
99 99 },
100</script> 100 },
101 101};
102<style scoped lang="scss"> 102</script>
103.error { 103
104 color: #e51111 !important; 104<style scoped lang="scss">
105} 105.error {
106 106 color: #e51111 !important;
107.down { 107}
108 margin-right: 1em; 108
109} 109.down {
110 110 margin-right: 1em;
111.count { 111}
112 color: var(--text); 112
113 font-size: 0.8em; 113.count {
114} 114 color: var(--text);
115 115 font-size: 0.8em;
116.monospace { 116}
117 font-weight: 300; 117
118 font-family: monospace; 118.monospace {
119} 119 font-weight: 300;
120</style> \ No newline at end of file 120 font-family: monospace;
121}
122</style>