diff options
Diffstat (limited to 'src/components')
-rw-r--r-- | src/components/services/Rtorrent.vue | 115 | ||||
-rw-r--r-- | src/components/services/qBittorrent.vue | 242 |
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> |
27 | import Generic from './Generic.vue'; | 26 | import Generic from "./Generic.vue"; |
28 | 27 | ||
29 | // Units to add to download and upload rates. | 28 | // Units to add to download and upload rates. |
30 | const units = ['B', 'kiB', 'MiB', 'GiB']; | 29 | const 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. |
35 | const displayRate = (rate) => { | 34 | const 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 | ||
47 | export default { | 49 | export 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> |
27 | import service from "@/mixins/service.js"; | 27 | </template> |
28 | import Generic from "./Generic.vue"; | 28 | |
29 | const units = ["B", "KB", "MB", "GB"]; | 29 | <script> |
30 | 30 | import service from "@/mixins/service.js"; | |
31 | // Take the rate in bytes and keep dividing it by 1k until the lowest | 31 | import Generic from "./Generic.vue"; |
32 | // value for which we have a unit is determined. Return the value with | 32 | const units = ["B", "KB", "MB", "GB"]; |
33 | // up to two decimals as a string and unit/s appended. | 33 | |
34 | const 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) { | 37 | const 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` | |
48 | export default { | 48 | ); |
49 | name: "qBittorrent", | 49 | }; |
50 | mixins: [service], | 50 | |
51 | props: { item: Object }, | 51 | export 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> | ||