mirror of
https://github.com/VueTorrent/VueTorrent.git
synced 2024-11-28 13:08:53 +03:00
torrent detail page + file list
This commit is contained in:
parent
7819abb1e7
commit
09832e6f1a
15 changed files with 554 additions and 323 deletions
81
README.md
81
README.md
|
@ -1,71 +1,130 @@
|
|||
|
||||
# VueTorrent
|
||||
|
||||
|
||||
|
||||
The sleekest looking WEBUI for qBittorrent made with Vuejs!
|
||||
|
||||
|
||||
|
||||
> Vue, qBitorrent, Vuetify
|
||||
|
||||
|
||||
|
||||
## Screenshots
|
||||
|
||||
|
||||
|
||||
<p align="center">
|
||||
|
||||
<a href="https://i.imgur.com/vPBcrK4.png"><img src="https://i.imgur.com/vPBcrK4.png" title="Desktop" alt="Desktop Screenshot" ></a>
|
||||
|
||||
<a href="https://imgur.com/xgwECT2.png"><img src="https://imgur.com/xgwECT2.png" title="Desktop" alt="Desktop Screenshot" ></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
|
||||
|
||||
<p align="center">
|
||||
<a href="https://i.imgur.com/SUOEyy9.png"><img src="https://i.imgur.com/SUOEyy9.png" title="Mobile" alt="Mobile Screenshot" width="320" height="540"></a>
|
||||
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
|
||||
- Download & Unzip the latest release
|
||||
|
||||
|
||||
|
||||
- Point your Alternate WEBUI location to it
|
||||
|
||||
|
||||
|
||||
## Development
|
||||
|
||||
|
||||
|
||||
- clone the repo
|
||||
|
||||
|
||||
|
||||
- npm install
|
||||
|
||||
|
||||
|
||||
- npm run serve
|
||||
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
|
||||
|
||||
- viewing sessions status ( down / upload speed, session uploaded / downloaded )
|
||||
|
||||
- adding / removing / pausing / resuming torrents
|
||||
|
||||
|
||||
|
||||
- sorting by every property shown!
|
||||
|
||||
|
||||
|
||||
* mobile friendly! (maybe not for thousands of torrents...)
|
||||
|
||||
|
||||
|
||||
- works on QBittorrent V4.2 and later
|
||||
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
|
||||
I'll gladly accept help/pull requests & advice! (this is my first project of this nature, pls be kind 😛 ).
|
||||
|
||||
|
||||
|
||||
## FAQ
|
||||
|
||||
- **Why build this??**
|
||||
|
||||
|
||||
- **Why build this??**
|
||||
|
||||
|
||||
|
||||
* Why not? Most WebUI's look very dated and now it's no longer necessary to search for a remote control app!
|
||||
|
||||
|
||||
|
||||
## Support
|
||||
|
||||
|
||||
|
||||
Reach out to me at one of the following places!
|
||||
|
||||
- <a href="https://m.me/WijnsDaan" target="_blank">`Facebook Messenger`</a>
|
||||
|
||||
|
||||
- <a href="https://m.me/WijnsDaan" target="_blank">`Facebook Messenger`</a>
|
||||
|
||||
|
||||
|
||||
* Open up an issue 😛
|
||||
|
||||
[<img src="https://cdn.buymeacoffee.com/buttons/lato-blue.png" alt="drawing" width="180"/>](https://www.buymeacoffee.com/wdaan "Buy me a coffee")
|
||||
|
||||
|
||||
[<img src="https://cdn.buymeacoffee.com/buttons/lato-blue.png" alt="drawing" width="180"/>](https://www.buymeacoffee.com/wdaan "Buy me a coffee")
|
||||
|
||||
|
||||
|
||||
## Credits
|
||||
|
||||
- Dashboard design heavily inspired by: '[Net Ninja - Vuetify](https://github.com/iamshaunjp/vuetify-playlist)'.
|
||||
Also check out The Net Ninja's Youtube Channel.
|
||||
|
||||
|
||||
* This repo '[CzBiX qb-web ](https://github.com/CzBiX/qb-web)'
|
||||
- Dashboard design heavily inspired by: '[Net Ninja - Vuetify](https://github.com/iamshaunjp/vuetify-playlist)'.
|
||||
|
||||
Also check out The Net Ninja's Youtube Channel.
|
||||
|
||||
|
||||
|
||||
* This repo '[CzBiX qb-web ](https://github.com/CzBiX/qb-web)'3.0)
|
379
package-lock.json
generated
379
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -19,6 +19,7 @@
|
|||
"vue-observe-visibility": "^0.4.6",
|
||||
"vue-router": "^3.2.0",
|
||||
"vue-toastification": "^1.7.1",
|
||||
"vue2-perfect-scrollbar": "^1.5.0",
|
||||
"vuetify": "^2.2.11",
|
||||
"vuex": "^3.4.0",
|
||||
"vuex-persist": "^2.2.0"
|
||||
|
|
18
src/App.vue
18
src/App.vue
|
@ -1,9 +1,10 @@
|
|||
<template>
|
||||
<v-app :style="{ backgroundColor : background }" >
|
||||
<AddModal />
|
||||
<Navbar v-if="authenticated" />
|
||||
<v-container fill-height fill-width>
|
||||
<v-content>
|
||||
<TorrentDetailModal/>
|
||||
<Navbar v-if="isAuthenticated" />
|
||||
<v-container class="pa-4">
|
||||
<v-content fill-height fill-width>
|
||||
<router-view></router-view>
|
||||
</v-content>
|
||||
</v-container>
|
||||
|
@ -13,6 +14,7 @@
|
|||
<script>
|
||||
import { mapState, mapGetters } from 'vuex'
|
||||
import Navbar from '@/components/Navbar.vue'
|
||||
import {isAuthenticated} from '@/services/auth.js'
|
||||
|
||||
export default {
|
||||
components: { Navbar },
|
||||
|
@ -20,14 +22,22 @@ export default {
|
|||
data() {
|
||||
return {}
|
||||
},
|
||||
methods: {
|
||||
async getAuth(){
|
||||
return await isAuthenticated()
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['authenticated', 'rid', 'mainData', 'preferences']),
|
||||
...mapState(['rid', 'mainData', 'preferences']),
|
||||
...mapGetters(['getTheme']),
|
||||
theme() {
|
||||
return this.getTheme() ? 'dark' : 'light'
|
||||
},
|
||||
background(){
|
||||
return this.$vuetify.theme.themes[this.theme].background
|
||||
},
|
||||
isAuthenticated(){
|
||||
return this.getAuth()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
203
src/components/Modals/TorrentDetailModal.vue
Normal file
203
src/components/Modals/TorrentDetailModal.vue
Normal file
|
@ -0,0 +1,203 @@
|
|||
<template>
|
||||
<v-dialog max-width="800px" v-model="dialog" scrollable>
|
||||
<v-card
|
||||
v-if="torrent"
|
||||
style="min-height: 400px; overflow:hidden !important"
|
||||
>
|
||||
<v-container :class="`pa-0 project ${torrent.state}`">
|
||||
<v-card-title class="justify-center primary">
|
||||
<h2 class="white--text">Torrent Detail</h2>
|
||||
</v-card-title>
|
||||
<v-tabs v-model="tab" background-color="primary" fixed-tabs>
|
||||
<v-tab v-for="item in items" :key="item.tab">
|
||||
{{ item.tab }}
|
||||
</v-tab>
|
||||
</v-tabs>
|
||||
|
||||
<v-tabs-items v-model="tab">
|
||||
<v-tab-item>
|
||||
<v-card flat>
|
||||
<v-card-text style="font-size: 1.2em">
|
||||
<v-flex>
|
||||
<span class="grey--text">Torrent title </span>
|
||||
<span class="torrentmodaltext--text ">{{
|
||||
torrent.name
|
||||
}}</span>
|
||||
</v-flex>
|
||||
<v-flex class="mt-2">
|
||||
<span class="grey--text">hash </span>
|
||||
<span class="torrentmodaltext--text ">{{
|
||||
torrent.hash
|
||||
}}</span>
|
||||
</v-flex>
|
||||
<v-flex class="mt-2">
|
||||
<span class="grey--text">Size </span>
|
||||
<span class="torrentmodaltext--text ">
|
||||
{{ torrent.size }}
|
||||
</span>
|
||||
</v-flex>
|
||||
<v-flex class="mt-2">
|
||||
<span class="grey--text">Done: </span>
|
||||
<span class="torrentmodaltext--text ">
|
||||
{{ torrent.dloaded }}
|
||||
</span>
|
||||
</v-flex>
|
||||
<v-flex class="mt-2">
|
||||
<span class="grey--text">Download </span>
|
||||
<span class="torrentmodaltext--text ">{{
|
||||
torrent.dlspeed
|
||||
}}</span>
|
||||
</v-flex>
|
||||
<v-flex class="mt-2">
|
||||
<span class="grey--text">Upload </span>
|
||||
<span class="torrentmodaltext--text ">{{
|
||||
torrent.upspeed
|
||||
}}</span>
|
||||
</v-flex>
|
||||
<v-flex class="mt-2">
|
||||
<span class="grey--text">ETA </span>
|
||||
<span class="torrentmodaltext--text ">{{
|
||||
torrent.eta
|
||||
}}</span>
|
||||
</v-flex>
|
||||
<v-flex class="mt-2">
|
||||
<span class="grey--text">Peers </span>
|
||||
<span class="torrentmodaltext--text ">
|
||||
{{ torrent.num_leechs
|
||||
}}<span class="grey--text"
|
||||
>/{{ torrent.available_peers }}</span
|
||||
>
|
||||
</span>
|
||||
</v-flex>
|
||||
<v-flex class="mt-2">
|
||||
<span class=" grey--text">Seeds </span>
|
||||
<span class="torrentmodaltext--text ">
|
||||
{{ torrent.num_seeds
|
||||
}}<span class="grey--text"
|
||||
>/{{ torrent.available_seeds }}</span
|
||||
>
|
||||
</span>
|
||||
</v-flex>
|
||||
<v-flex class="mt-2">
|
||||
<span class=" grey--text">Ratio </span>
|
||||
<span class="torrentmodaltext--text ">
|
||||
{{ torrent.ratio }}%
|
||||
</span>
|
||||
</v-flex>
|
||||
<v-flex>
|
||||
<span class="grey--text">Status </span>
|
||||
<v-chip
|
||||
small
|
||||
:class="`${torrent.state} white--text my-2 caption`"
|
||||
>{{ torrent.state }}</v-chip
|
||||
>
|
||||
</v-flex>
|
||||
<v-flex>
|
||||
<v-progress-linear
|
||||
height="5"
|
||||
stream
|
||||
rounded
|
||||
color="cyan darken-1"
|
||||
background-color="cyan lighten-3"
|
||||
:buffer-value="torrent.progress"
|
||||
></v-progress-linear>
|
||||
</v-flex>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-tab-item>
|
||||
<v-tab-item>
|
||||
|
||||
<v-card flat class="scrollbar" style="overflow-y: auto !important;">
|
||||
<perfect-scrollbar>
|
||||
<v-card-text style="max-height: 500px; min-height: 400px;">
|
||||
<v-treeview
|
||||
v-model="tree"
|
||||
:items="fileTree"
|
||||
activatable
|
||||
item-key="name"
|
||||
open-on-click
|
||||
>
|
||||
<template v-slot:prepend="{ item, open }">
|
||||
<v-icon v-if="!item.icon">
|
||||
{{ open ? "mdi-folder-open" : "mdi-folder" }}
|
||||
</v-icon>
|
||||
<v-icon v-else>
|
||||
{{ item.icon }}
|
||||
</v-icon>
|
||||
</template>
|
||||
<template v-slot:append="{ item }">
|
||||
<span v-if="!item.icon">
|
||||
{{ item.children.length }} Files
|
||||
</span>
|
||||
<div v-else>
|
||||
<span>[{{ item.size }}]</span>
|
||||
<span class="ml-4">{{ item.progress }}%</span>
|
||||
</div>
|
||||
</template>
|
||||
</v-treeview>
|
||||
</v-card-text>
|
||||
</perfect-scrollbar>
|
||||
</v-card>
|
||||
|
||||
</v-tab-item>
|
||||
</v-tabs-items>
|
||||
</v-container>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Modal from "@/mixins/Modal";
|
||||
import { mapGetters } from "vuex";
|
||||
import qbit from "@/services/qbit";
|
||||
import { treeify } from "@/helpers";
|
||||
|
||||
export default {
|
||||
name: "TorrentDetailModal",
|
||||
mixins: [Modal],
|
||||
data() {
|
||||
return {
|
||||
tab: null,
|
||||
items: [{ tab: "Info" }, { tab: "Content" }],
|
||||
tempFileTree: [],
|
||||
fileTree: [],
|
||||
tree: [],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async getTorrentProperties() {
|
||||
const { data } = await qbit.getTorrentFiles(this.hash);
|
||||
// console.log(data)
|
||||
return data;
|
||||
},
|
||||
async getTorrentFiles() {
|
||||
const { data } = await qbit.getTorrentFiles(this.hash);
|
||||
this.fileTree = treeify(data);
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(["getTorrent"]),
|
||||
hash() {
|
||||
return this.$store.state.selectedDetailTorrent;
|
||||
},
|
||||
torrent() {
|
||||
return this.getTorrent(this.hash);
|
||||
},
|
||||
torrentFiles() {
|
||||
let arr = this.getTorrentFiles();
|
||||
console.log(arr);
|
||||
return arr.map(this.addnode);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
dialog(visible) {
|
||||
if (visible) {
|
||||
this.getTorrentProperties();
|
||||
this.getTorrentFiles();
|
||||
} else {
|
||||
this.fileTree = [];
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -226,7 +226,7 @@ export default {
|
|||
animations: {
|
||||
enabled: false,
|
||||
dynamicAnimation: {
|
||||
speed: 2000
|
||||
speed: 1000
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -249,18 +249,6 @@ export default {
|
|||
}
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: 'upload',
|
||||
type: 'area',
|
||||
data: this.$store.state.upload_data
|
||||
},
|
||||
{
|
||||
name: 'download',
|
||||
type: 'area',
|
||||
data: this.$store.state.download_data
|
||||
}
|
||||
],
|
||||
chartInterval: null
|
||||
}
|
||||
},
|
||||
|
@ -301,16 +289,24 @@ export default {
|
|||
},
|
||||
altSpeed(){
|
||||
return this.getStatus().altSpeed
|
||||
},
|
||||
series(){
|
||||
return [
|
||||
{
|
||||
name: 'upload',
|
||||
type: 'area',
|
||||
data: this.$store.state.upload_data
|
||||
},
|
||||
{
|
||||
name: 'download',
|
||||
type: 'area',
|
||||
data: this.$store.state.download_data
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.chartInterval = setInterval(async () => {
|
||||
this.updateChart()
|
||||
}, 2000)
|
||||
this.$vuetify.theme.dark = this.getTheme()
|
||||
},
|
||||
beforeDestroy() {
|
||||
clearInterval(this.chartInterval)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -89,9 +89,10 @@
|
|||
<v-flex xs12 sm12 md12>
|
||||
<v-progress-linear
|
||||
height="3"
|
||||
rounded
|
||||
color="cyan darken-1"
|
||||
background-color="cyan lighten-3"
|
||||
:value="(torrent.dloaded / torrent.size) * 100"
|
||||
:value="torrent.progress"
|
||||
></v-progress-linear>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
|
@ -99,7 +100,6 @@
|
|||
<span>{{ torrent.name }}</span>
|
||||
</v-tooltip>
|
||||
<v-divider></v-divider>
|
||||
|
||||
<vue-context ref="menu">
|
||||
<torrentRightClickMenu :hash="torrent.hash" />
|
||||
</vue-context>
|
||||
|
|
|
@ -6,6 +6,11 @@
|
|||
:dark="dark"
|
||||
>
|
||||
<v-list dense rounded>
|
||||
<v-list-item @click="showInfo" link>
|
||||
<v-icon>info</v-icon>
|
||||
<v-list-item-title class="ml-2" style="font-size:15px;">Show Info</v-list-item-title>
|
||||
</v-list-item>
|
||||
<v-divider/>
|
||||
<v-list-item @click="resume" link>
|
||||
<v-icon>play_arrow</v-icon>
|
||||
<v-list-item-title class="ml-2" style="font-size:15px;">Resume</v-list-item-title>
|
||||
|
@ -54,6 +59,10 @@ export default {
|
|||
},
|
||||
deleteWithFiles(){
|
||||
qbit.deleteTorrents([this.hash], true)
|
||||
},
|
||||
showInfo(){
|
||||
this.$store.commit('TOGGLE_MODAL', 'TorrentDetailModal')
|
||||
this.$store.commit('SET_SELECTED_TORRENT_DETAIL', this.hash)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
|
79
src/helpers.js
Normal file
79
src/helpers.js
Normal file
|
@ -0,0 +1,79 @@
|
|||
/* eslint-disable no-unused-vars */
|
||||
export function formatBytes(a, b) {
|
||||
if (a == 0) return "0 Bytes";
|
||||
const c = 1024;
|
||||
const d = b || 2;
|
||||
const e = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
||||
const f = Math.floor(Math.log(a) / Math.log(c));
|
||||
return `${parseFloat((a / Math.pow(c, f)).toFixed(d))} ${e[f]}`;
|
||||
}
|
||||
|
||||
export function getIconForFileType(type) {
|
||||
let types = {
|
||||
html: "mdi-language-html5",
|
||||
js: "mdi-nodejs",
|
||||
json: "mdi-json",
|
||||
md: "mdi-markdown",
|
||||
pdf: "mdi-file-pdf",
|
||||
png: "mdi-file-image",
|
||||
txt: "mdi-file-document-outline",
|
||||
sub: "mdi-file-document-outline",
|
||||
idx: "mdi-file-document-outline",
|
||||
xls: "mdi-file-excel",
|
||||
avi: "movie",
|
||||
mp4: "movie",
|
||||
mkv: "movie",
|
||||
};
|
||||
|
||||
if (!types[type]) return "insert_drive_file";
|
||||
|
||||
return types[type];
|
||||
}
|
||||
|
||||
export function treeify(paths) {
|
||||
let result = [];
|
||||
let level = { result };
|
||||
|
||||
paths.forEach((path) => {
|
||||
path.name.split("/").reduce((r, name, i, a) => {
|
||||
if (!r[name]) {
|
||||
r[name] = { result: [] };
|
||||
r.result.push(createFile(path, name, r[name].result));
|
||||
}
|
||||
|
||||
return r[name];
|
||||
}, level);
|
||||
});
|
||||
|
||||
//parse folders
|
||||
result = result.map((el) => parseFolder(el));
|
||||
|
||||
function parseFolder(el) {
|
||||
if (el.children.length !== 0) {
|
||||
let folder = createFolder(el.name, el.children);
|
||||
folder.children = folder.children.map((el) => parseFolder(el));
|
||||
return folder;
|
||||
}
|
||||
return el;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function createFile(data, name, children) {
|
||||
return {
|
||||
name: name,
|
||||
progress: Math.round(data.progress * 100),
|
||||
size: formatBytes(data.size),
|
||||
icon: getIconForFileType(name.split(".").pop()),
|
||||
children: children,
|
||||
};
|
||||
}
|
||||
|
||||
function createFolder(name, children) {
|
||||
return {
|
||||
name: name,
|
||||
type: "directory",
|
||||
children: children,
|
||||
};
|
||||
}
|
11
src/main.js
11
src/main.js
|
@ -11,7 +11,16 @@ Vue.use(VueObserveVisibility)
|
|||
import Toast from 'vue-toastification'
|
||||
import 'vue-toastification/dist/index.css'
|
||||
import vuetify from './plugins/vuetify'
|
||||
Vue.use(Toast)
|
||||
Vue.use(Toast, {
|
||||
maxToasts: 5,
|
||||
timeout: 2000
|
||||
})
|
||||
|
||||
import PerfectScrollbar from 'vue2-perfect-scrollbar'
|
||||
import 'vue2-perfect-scrollbar/dist/vue2-perfect-scrollbar.css'
|
||||
|
||||
Vue.use(PerfectScrollbar)
|
||||
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ export default class Status {
|
|||
this.upspeed = this.formatBytes(data.up_info_speed, 1)
|
||||
this.freeDiskSpace = this.formatBytes(data.free_space_on_disk)
|
||||
this.altSpeed = data.use_alt_speed_limits
|
||||
this.dlspeedRaw = Math.round(data.dl_info_speed / 1000)
|
||||
this.upspeedRaw = Math.round(data.up_info_speed / 1000)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
export default class Torrent {
|
||||
constructor(data) {
|
||||
this.id = data.id
|
||||
this.name = data.name
|
||||
this.size = this.formatBytes(data.size)
|
||||
this.birth = new Date(data.added_on * 1000).toLocaleString()
|
||||
|
@ -20,6 +19,9 @@ export default class Torrent {
|
|||
// available seeds
|
||||
this.available_seeds = data.num_complete
|
||||
this.available_peers = data.num_incomplete
|
||||
this.savePath = data.save_path
|
||||
this.progress = Math.round(data.downloaded / data.size * 100)
|
||||
this.ratio = Math.round(data.ratio * 100)
|
||||
}
|
||||
|
||||
formatState(state) {
|
||||
|
|
|
@ -29,7 +29,8 @@ export default new Vuetify({
|
|||
torrent: '#fff',
|
||||
torrent_selected: colors.grey.lighten2,
|
||||
background: colors.grey.lighten4,
|
||||
search: colors.grey.darken1
|
||||
search: colors.grey.darken1,
|
||||
torrentmodaltext: colors.grey.darken4
|
||||
},
|
||||
dark: {
|
||||
primary: "#35495e",
|
||||
|
@ -44,7 +45,8 @@ export default new Vuetify({
|
|||
torrent: colors.grey.darken3,
|
||||
torrent_selected: colors.grey,
|
||||
background: colors.grey.darken4,
|
||||
search: colors.grey.darken3
|
||||
search: colors.grey.darken3,
|
||||
torrentmodaltext: colors.grey.lighten4
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -33,9 +33,11 @@ export default new Vuex.Store({
|
|||
modals: {
|
||||
addmodal: false,
|
||||
deletemodal: false,
|
||||
settingsmodal: false
|
||||
settingsmodal: false,
|
||||
torrentdetailmodal: false
|
||||
},
|
||||
settings : {}
|
||||
settings : {},
|
||||
selectedDetailTorrent: null
|
||||
},
|
||||
getters: {
|
||||
containsTorrent: state => hash =>
|
||||
|
@ -43,7 +45,8 @@ export default new Vuex.Store({
|
|||
getTheme: state => () => state.darkTheme,
|
||||
getModalState: state => name => state.modals[name.toLowerCase()],
|
||||
getSettings: state => () => state.settings,
|
||||
getStatus: state => () => state.status
|
||||
getStatus: state => () => state.status,
|
||||
getTorrent: state => hash => state.torrents.filter(el => el.hash === hash)[0]
|
||||
},
|
||||
|
||||
mutations: {
|
||||
|
@ -92,40 +95,17 @@ export default new Vuex.Store({
|
|||
state.status = new Status(data.server_state)
|
||||
|
||||
// graph
|
||||
|
||||
state.download_data.splice(0, 1)
|
||||
if (state.status.dlspeed.indexOf('KB' > -1)) {
|
||||
state.download_data.push(
|
||||
state.status.dlspeed.substring(
|
||||
0,
|
||||
state.status.dlspeed.indexOf(' ')
|
||||
) / 1000
|
||||
)
|
||||
} else {
|
||||
state.download_data.push(
|
||||
state.status.dlspeed(0, state.status.dlspeed.indexOf(' '))
|
||||
)
|
||||
}
|
||||
state.download_data.push(state.status.dlspeedRaw)
|
||||
state.upload_data.splice(0, 1)
|
||||
if (state.status.upspeed.indexOf('KB' > -1)) {
|
||||
state.upload_data.push(
|
||||
state.status.upspeed.substring(
|
||||
0,
|
||||
state.status.upspeed.indexOf(' ')
|
||||
) / 1000
|
||||
)
|
||||
} else {
|
||||
state.upload_data.push(
|
||||
state.status.upspeed.substring(
|
||||
0,
|
||||
state.status.upspeed.indexOf(' ')
|
||||
)
|
||||
)
|
||||
}
|
||||
state.upload_data.push(state.status.upspeedRaw)
|
||||
},
|
||||
SET_SETTINGS: async state => {
|
||||
const {data} = await qbit.getAppPreferences()
|
||||
state.settings.savePath = data.save_path;
|
||||
},
|
||||
SET_SELECTED_TORRENT_DETAIL: (state, hash) => {
|
||||
state.selectedDetailTorrent = hash
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div style="height: 89vh" color="background" @click.self="resetSelected">
|
||||
<div color="background" @click.self="resetSelected">
|
||||
<h1 style="font-size: 1.1em !important" class="subtitle-1 grey--text">Dashboard</h1>
|
||||
<v-container color="background" class="my-4" @click.self="resetSelected">
|
||||
<v-container color="background" class="my-4 pa-0" @click.self="resetSelected">
|
||||
<!-- justify-center here in layout to center!! -->
|
||||
<v-flex xs12 sm6 md3 @click.self="resetSelected">
|
||||
<v-text-field
|
||||
|
|
Loading…
Reference in a new issue