mirror of
https://github.com/VueTorrent/VueTorrent.git
synced 2025-05-02 13:31:45 +03:00
0.4.7 (#80)
This commit is contained in:
parent
f895738e70
commit
39e5549b80
81 changed files with 4718 additions and 4235 deletions
src/components/Modals
AddModal.vueChangeLocationModal.vueConfirmDeleteModal.vueRenameModal.vue
SearchModal
SettingsModal
SortModal.vueTagsAndCategories
TorrentDetailModal
|
@ -1,129 +1,132 @@
|
|||
<template>
|
||||
<v-dialog max-width="500px" v-model="dialog">
|
||||
<v-card>
|
||||
<v-container :class="`pa-0 project done`">
|
||||
<v-card-title class="justify-center">
|
||||
<h2>Add a new Torrent</h2>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-form v-model="valid" ref="form">
|
||||
<v-container>
|
||||
<v-row no-gutters>
|
||||
<v-col ref="fileZone">
|
||||
<div
|
||||
@drop.prevent="addDropFile"
|
||||
@dragover.prevent
|
||||
>
|
||||
<v-file-input
|
||||
v-if="!urls"
|
||||
v-model="files"
|
||||
color="deep-purple accent-4"
|
||||
counter
|
||||
label="File input"
|
||||
multiple
|
||||
placeholder="Select your files"
|
||||
prepend-icon="mdi-paperclip"
|
||||
:rules="fileInputRules"
|
||||
outlined
|
||||
:show-size="1000"
|
||||
>
|
||||
<template
|
||||
v-slot:selection="{ index, text }"
|
||||
>
|
||||
<v-chip
|
||||
v-if="index < 2"
|
||||
color="deep-purple accent-4"
|
||||
dark
|
||||
label
|
||||
small
|
||||
>{{ text }}</v-chip
|
||||
>
|
||||
<span
|
||||
v-else-if="index === 2"
|
||||
class="overline grey--text text--darken-3 mx-2"
|
||||
>+{{
|
||||
files.length - 2
|
||||
}}
|
||||
File(s)</span
|
||||
>
|
||||
</template>
|
||||
</v-file-input>
|
||||
</div>
|
||||
<v-textarea
|
||||
v-if="files.length == 0"
|
||||
label="URL"
|
||||
prepend-icon="mdi-link"
|
||||
rows="1"
|
||||
required
|
||||
:autofocus="!phoneLayout"
|
||||
v-model="urls"
|
||||
auto-grow
|
||||
clearable
|
||||
hint="One link per line"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-combobox
|
||||
v-model="category"
|
||||
:items="availableCategories"
|
||||
clearable
|
||||
label="Category"
|
||||
prepend-icon="tag"
|
||||
@input="categoryChanged"
|
||||
></v-combobox>
|
||||
|
||||
<v-text-field
|
||||
:disabled="autoTMM"
|
||||
v-model="directory"
|
||||
label="Download Directory"
|
||||
prepend-icon="folder"
|
||||
></v-text-field>
|
||||
<v-row no-gutters>
|
||||
<v-flex xs12 sm6>
|
||||
<v-checkbox
|
||||
v-model="start"
|
||||
label="Start torrent"
|
||||
></v-checkbox>
|
||||
</v-flex>
|
||||
<v-flex xs12 sm6>
|
||||
<v-checkbox
|
||||
v-model="skip_checking"
|
||||
label="Skip hash check"
|
||||
></v-checkbox>
|
||||
</v-flex>
|
||||
<v-flex xs12 sm6>
|
||||
<v-checkbox
|
||||
v-model="root_folder"
|
||||
label="Create subfolder"
|
||||
></v-checkbox>
|
||||
</v-flex>
|
||||
<v-flex xs12 sm6>
|
||||
<v-checkbox
|
||||
v-model="autoTMM"
|
||||
label="Automatic Torrent Management"
|
||||
></v-checkbox>
|
||||
</v-flex>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-form>
|
||||
</v-card-text>
|
||||
|
||||
<v-spacer></v-spacer>
|
||||
<v-form>
|
||||
<v-card-actions class="justify-center">
|
||||
<v-btn
|
||||
text
|
||||
@click="submit"
|
||||
:disabled="!valid"
|
||||
class="blue_accent white--text mx-0 mt-3"
|
||||
>Add Torrent</v-btn
|
||||
<v-dialog v-model="dialog" max-width="500px">
|
||||
<v-card>
|
||||
<v-container :class="`pa-0 project done`">
|
||||
<v-card-title class="justify-center">
|
||||
<h2>Add a new Torrent</h2>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-form ref="form" v-model="valid">
|
||||
<v-container>
|
||||
<v-row no-gutters>
|
||||
<v-col ref="fileZone">
|
||||
<div
|
||||
@drop.prevent="addDropFile"
|
||||
@dragover.prevent
|
||||
>
|
||||
<v-file-input
|
||||
v-if="!urls"
|
||||
v-model="files"
|
||||
color="deep-purple accent-4"
|
||||
counter
|
||||
label="File input"
|
||||
multiple
|
||||
placeholder="Select your files"
|
||||
prepend-icon="mdi-paperclip"
|
||||
:rules="fileInputRules"
|
||||
outlined
|
||||
:show-size="1000"
|
||||
>
|
||||
<template
|
||||
#selection="{ index, text }"
|
||||
>
|
||||
<v-chip
|
||||
v-if="index < 2"
|
||||
color="deep-purple accent-4"
|
||||
dark
|
||||
label
|
||||
small
|
||||
>
|
||||
</v-card-actions>
|
||||
</v-form>
|
||||
{{ text }}
|
||||
</v-chip>
|
||||
<span
|
||||
v-else-if="index === 2"
|
||||
class="overline grey--text text--darken-3 mx-2"
|
||||
>
|
||||
+{{
|
||||
files.length - 2
|
||||
}}
|
||||
File(s)
|
||||
</span>
|
||||
</template>
|
||||
</v-file-input>
|
||||
</div>
|
||||
<v-textarea
|
||||
v-if="files.length == 0"
|
||||
v-model="urls"
|
||||
label="URL"
|
||||
prepend-icon="mdi-link"
|
||||
rows="1"
|
||||
required
|
||||
:autofocus="!phoneLayout"
|
||||
auto-grow
|
||||
clearable
|
||||
hint="One link per line"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-combobox
|
||||
v-model="category"
|
||||
:items="availableCategories"
|
||||
clearable
|
||||
label="Category"
|
||||
prepend-icon="tag"
|
||||
@input="categoryChanged"
|
||||
/>
|
||||
|
||||
<v-text-field
|
||||
v-model="directory"
|
||||
:disabled="autoTMM"
|
||||
label="Download Directory"
|
||||
prepend-icon="folder"
|
||||
/>
|
||||
<v-row no-gutters>
|
||||
<v-flex xs12 sm6>
|
||||
<v-checkbox
|
||||
v-model="start"
|
||||
label="Start torrent"
|
||||
/>
|
||||
</v-flex>
|
||||
<v-flex xs12 sm6>
|
||||
<v-checkbox
|
||||
v-model="skip_checking"
|
||||
label="Skip hash check"
|
||||
/>
|
||||
</v-flex>
|
||||
<v-flex xs12 sm6>
|
||||
<v-checkbox
|
||||
v-model="root_folder"
|
||||
label="Create subfolder"
|
||||
/>
|
||||
</v-flex>
|
||||
<v-flex xs12 sm6>
|
||||
<v-checkbox
|
||||
v-model="autoTMM"
|
||||
label="Automatic Torrent Management"
|
||||
/>
|
||||
</v-flex>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</v-form>
|
||||
</v-card-text>
|
||||
|
||||
<v-spacer />
|
||||
<v-form>
|
||||
<v-card-actions class="justify-center">
|
||||
<v-btn
|
||||
text
|
||||
:disabled="!valid"
|
||||
class="blue_accent white--text mx-0 mt-3"
|
||||
@click="submit"
|
||||
>
|
||||
Add Torrent
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-form>
|
||||
</v-container>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -131,102 +134,104 @@ import { mapGetters } from 'vuex'
|
|||
import Modal from '@/mixins/Modal'
|
||||
import qbit from '@/services/qbit'
|
||||
export default {
|
||||
name: 'AddModal',
|
||||
props: ['initialMagnet'],
|
||||
mixins: [Modal],
|
||||
data() {
|
||||
return {
|
||||
files: [],
|
||||
category: null,
|
||||
directory: '',
|
||||
start: true,
|
||||
skip_checking: false,
|
||||
root_folder: true,
|
||||
autoTMM: true,
|
||||
fileInputRules: [
|
||||
v => {
|
||||
const result = v.every(f => {
|
||||
if (f.type) return f.type === 'application/x-bittorrent'
|
||||
else return /^.*\.torrent$/.test(f.name)
|
||||
})
|
||||
return result ? result : 'One or more files is not a valid torrent'
|
||||
}
|
||||
],
|
||||
loading: false,
|
||||
urls: null,
|
||||
valid: false
|
||||
name: 'AddModal',
|
||||
mixins: [Modal],
|
||||
props: ['initialMagnet'],
|
||||
data() {
|
||||
return {
|
||||
files: [],
|
||||
category: null,
|
||||
directory: '',
|
||||
start: true,
|
||||
skip_checking: false,
|
||||
root_folder: true,
|
||||
autoTMM: true,
|
||||
fileInputRules: [
|
||||
v => {
|
||||
const result = v.every(f => {
|
||||
if (f.type) return f.type === 'application/x-bittorrent'
|
||||
else return /^.*\.torrent$/.test(f.name)
|
||||
})
|
||||
|
||||
return result ? result : 'One or more files is not a valid torrent'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addDropFile(e) {
|
||||
this.files.push(...Array.from(e.dataTransfer.files))
|
||||
},
|
||||
submit() {
|
||||
if (this.files.length || this.urls) {
|
||||
const torrents = []
|
||||
const params = {
|
||||
urls: null,
|
||||
paused: !this.start,
|
||||
skip_checking: this.skip_checking,
|
||||
root_folder: this.root_folder,
|
||||
autoTMM: this.autoTMM
|
||||
}
|
||||
if (this.files.length) torrents.push(...this.files)
|
||||
if (this.urls) params.urls = this.urls
|
||||
if (this.category) params.category = this.category
|
||||
if (!this.autoTMM) params.savepath = this.directory
|
||||
|
||||
qbit.addTorrents(params, torrents)
|
||||
|
||||
this.resetForm()
|
||||
|
||||
this.$store.commit('DELETE_MODAL', this.guid)
|
||||
}
|
||||
},
|
||||
categoryChanged() {
|
||||
if (this.autoTMM) this.directory = this.savepath
|
||||
},
|
||||
resetForm() {
|
||||
this.url = null
|
||||
this.files = []
|
||||
this.category = null
|
||||
this.directory = this.savepath
|
||||
this.skip_checking = null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['getSettings', 'getCategories']),
|
||||
settings() {
|
||||
return this.getSettings()
|
||||
},
|
||||
validFile() {
|
||||
return this.Files.length > 0
|
||||
},
|
||||
phoneLayout() {
|
||||
return this.$vuetify.breakpoint.xsOnly
|
||||
},
|
||||
savepath() {
|
||||
let savePath = this.getSettings().save_path
|
||||
if (this.category) {
|
||||
savePath += this.category
|
||||
const category = this.getCategories()[this.category]
|
||||
if (category && category.savePath) savePath = category.savePath
|
||||
}
|
||||
return savePath
|
||||
},
|
||||
availableCategories() {
|
||||
return Object.keys(this.getCategories())
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
settings(newvalue) {
|
||||
this.directory = newvalue.save_path
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$store.commit('FETCH_SETTINGS')
|
||||
this.$store.commit('FETCH_CATEGORIES')
|
||||
this.urls = this.initialMagnet
|
||||
],
|
||||
loading: false,
|
||||
urls: null,
|
||||
valid: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['getSettings', 'getCategories']),
|
||||
settings() {
|
||||
return this.getSettings()
|
||||
},
|
||||
validFile() {
|
||||
return this.Files.length > 0
|
||||
},
|
||||
phoneLayout() {
|
||||
return this.$vuetify.breakpoint.xsOnly
|
||||
},
|
||||
savepath() {
|
||||
let savePath = this.getSettings().save_path
|
||||
if (this.category) {
|
||||
savePath += this.category
|
||||
const category = this.getCategories()[this.category]
|
||||
if (category && category.savePath) savePath = category.savePath
|
||||
}
|
||||
|
||||
return savePath
|
||||
},
|
||||
availableCategories() {
|
||||
return Object.keys(this.getCategories())
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
settings(newvalue) {
|
||||
this.directory = newvalue.save_path
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$store.commit('FETCH_SETTINGS')
|
||||
this.$store.commit('FETCH_CATEGORIES')
|
||||
this.urls = this.initialMagnet
|
||||
},
|
||||
methods: {
|
||||
addDropFile(e) {
|
||||
this.files.push(...Array.from(e.dataTransfer.files))
|
||||
},
|
||||
submit() {
|
||||
if (this.files.length || this.urls) {
|
||||
const torrents = []
|
||||
const params = {
|
||||
urls: null,
|
||||
paused: !this.start,
|
||||
skip_checking: this.skip_checking,
|
||||
root_folder: this.root_folder,
|
||||
autoTMM: this.autoTMM
|
||||
}
|
||||
if (this.files.length) torrents.push(...this.files)
|
||||
if (this.urls) params.urls = this.urls
|
||||
if (this.category) params.category = this.category
|
||||
if (!this.autoTMM) params.savepath = this.directory
|
||||
|
||||
qbit.addTorrents(params, torrents)
|
||||
|
||||
this.resetForm()
|
||||
|
||||
this.$store.commit('DELETE_MODAL', this.guid)
|
||||
}
|
||||
},
|
||||
categoryChanged() {
|
||||
if (this.autoTMM) this.directory = this.savepath
|
||||
},
|
||||
resetForm() {
|
||||
this.url = null
|
||||
this.files = []
|
||||
this.category = null
|
||||
this.directory = this.savepath
|
||||
this.skip_checking = null
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,50 +1,59 @@
|
|||
<template>
|
||||
<v-dialog
|
||||
v-model="dialog"
|
||||
scrollable
|
||||
:width="dialogWidth"
|
||||
:fullscreen="phoneLayout"
|
||||
>
|
||||
<v-card style="overflow: hidden !important">
|
||||
<v-container :style="{ height: phoneLayout ? '100vh' : '' }">
|
||||
<v-card-title class="pb-0 justify-center">
|
||||
<h2>Change Torrent Location</h2>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<div>
|
||||
<v-container>
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
label="Torrent Name"
|
||||
prepend-icon="insert_drive_file"
|
||||
readonly
|
||||
v-model="torrent.name"
|
||||
/>
|
||||
<v-text-field
|
||||
label="Directory"
|
||||
prepend-icon="folder"
|
||||
v-model="newPath"
|
||||
v-on:keydown.enter="setLocation"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</div>
|
||||
</v-card-text>
|
||||
<div>
|
||||
<v-card-actions class="justify-center">
|
||||
<v-btn color="success" @click="setLocation">Save</v-btn>
|
||||
</v-card-actions>
|
||||
</div>
|
||||
<v-dialog
|
||||
v-model="dialog"
|
||||
scrollable
|
||||
:width="dialogWidth"
|
||||
:fullscreen="phoneLayout"
|
||||
>
|
||||
<v-card style="overflow: hidden !important">
|
||||
<v-container :style="{ height: phoneLayout ? '100vh' : '' }">
|
||||
<v-card-title class="pb-0 justify-center">
|
||||
<h2>Change Torrent Location</h2>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<div>
|
||||
<v-container>
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
v-model="torrent.name"
|
||||
label="Torrent Name"
|
||||
prepend-icon="insert_drive_file"
|
||||
readonly
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="newPath"
|
||||
label="Directory"
|
||||
prepend-icon="folder"
|
||||
@keydown.enter="setLocation"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
<v-fab-transition v-if="phoneLayout">
|
||||
<v-btn @click="close" color="red" dark absolute bottom right>
|
||||
<v-icon>close</v-icon>
|
||||
</v-btn>
|
||||
</v-fab-transition>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</div>
|
||||
</v-card-text>
|
||||
<div>
|
||||
<v-card-actions class="justify-center">
|
||||
<v-btn color="success" @click="setLocation">
|
||||
Save
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</div>
|
||||
</v-container>
|
||||
<v-fab-transition v-if="phoneLayout">
|
||||
<v-btn
|
||||
color="red"
|
||||
dark
|
||||
absolute
|
||||
bottom
|
||||
right
|
||||
@click="close"
|
||||
>
|
||||
<v-icon>close</v-icon>
|
||||
</v-btn>
|
||||
</v-fab-transition>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -53,36 +62,36 @@ import { mapGetters } from 'vuex'
|
|||
import { Modal, FullScreenModal } from '@/mixins'
|
||||
import qbit from '@/services/qbit'
|
||||
export default {
|
||||
name: 'ChangeLocationModal',
|
||||
mixins: [Modal, FullScreenModal],
|
||||
props: {
|
||||
hash: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
newPath: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['getTorrent']),
|
||||
dialogWidth() {
|
||||
return this.phoneLayout ? '100%' : '750px'
|
||||
},
|
||||
torrent() {
|
||||
return this.getTorrent(this.hash)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setLocation() {
|
||||
qbit.setTorrentLocation([this.hash], this.newPath)
|
||||
this.close()
|
||||
},
|
||||
close() {
|
||||
this.$store.commit('DELETE_MODAL', this.guid)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.newPath = this.torrent.savePath
|
||||
name: 'ChangeLocationModal',
|
||||
mixins: [Modal, FullScreenModal],
|
||||
props: {
|
||||
hash: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
newPath: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['getTorrent']),
|
||||
dialogWidth() {
|
||||
return this.phoneLayout ? '100%' : '750px'
|
||||
},
|
||||
torrent() {
|
||||
return this.getTorrent(this.hash)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.newPath = this.torrent.savePath
|
||||
},
|
||||
methods: {
|
||||
setLocation() {
|
||||
qbit.setTorrentLocation([this.hash], this.newPath)
|
||||
this.close()
|
||||
},
|
||||
close() {
|
||||
this.$store.commit('DELETE_MODAL', this.guid)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,43 +1,48 @@
|
|||
<template>
|
||||
<v-dialog v-model="dialog" scrollable max-width="500px">
|
||||
<v-card>
|
||||
<v-container :class="`pa-0 project done`">
|
||||
<v-card-title class="justify-center">
|
||||
<h2>Confirm Removal</h2>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-list flat>
|
||||
<v-list-item
|
||||
v-for="t in torrents"
|
||||
:key="t.hash"
|
||||
>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title class="truncate" v-text="t.name"></v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-card-text>
|
||||
<v-card-actions class="justify-center pb-5">
|
||||
<v-btn text class="error white--text mt-3"
|
||||
@click="close()"
|
||||
>Cancel</v-btn
|
||||
>
|
||||
<v-btn
|
||||
text
|
||||
class="green_accent white--text mt-3"
|
||||
@click="deleteWithoutFiles()"
|
||||
>Delete</v-btn
|
||||
>
|
||||
<v-btn
|
||||
text
|
||||
class="green_accent white--text mt-3"
|
||||
@click="deleteWithFiles()"
|
||||
>Delete with files</v-btn
|
||||
>
|
||||
</v-card-actions>
|
||||
</v-container>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
<v-dialog v-model="dialog" scrollable max-width="500px">
|
||||
<v-card>
|
||||
<v-container :class="`pa-0 project done`">
|
||||
<v-card-title class="justify-center">
|
||||
<h2>Confirm Removal</h2>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-list flat>
|
||||
<v-list-item
|
||||
v-for="t in torrents"
|
||||
:key="t.hash"
|
||||
>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title class="truncate" v-text="t.name" />
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-card-text>
|
||||
<v-card-actions class="justify-center pb-5">
|
||||
<v-btn
|
||||
text
|
||||
class="error white--text mt-3"
|
||||
@click="close()"
|
||||
>
|
||||
Cancel
|
||||
</v-btn>
|
||||
<v-btn
|
||||
text
|
||||
class="green_accent white--text mt-3"
|
||||
@click="deleteWithoutFiles()"
|
||||
>
|
||||
Delete
|
||||
</v-btn>
|
||||
<v-btn
|
||||
text
|
||||
class="green_accent white--text mt-3"
|
||||
@click="deleteWithFiles()"
|
||||
>
|
||||
Delete with files
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-container>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -45,27 +50,27 @@ import { mapState, mapGetters } from 'vuex'
|
|||
import { Modal } from '@/mixins'
|
||||
import qbit from '@/services/qbit'
|
||||
export default {
|
||||
name: 'ConfirmDeleteModal',
|
||||
mixins: [Modal],
|
||||
methods: {
|
||||
close() {
|
||||
this.$store.commit('DELETE_MODAL', this.guid)
|
||||
},
|
||||
deleteWithoutFiles() {
|
||||
qbit.deleteTorrents(this.selected_torrents, false)
|
||||
this.close()
|
||||
},
|
||||
deleteWithFiles() {
|
||||
qbit.deleteTorrents(this.selected_torrents, true)
|
||||
this.close()
|
||||
}
|
||||
name: 'ConfirmDeleteModal',
|
||||
mixins: [Modal],
|
||||
methods: {
|
||||
close() {
|
||||
this.$store.commit('DELETE_MODAL', this.guid)
|
||||
},
|
||||
computed: {
|
||||
...mapState(['selected_torrents']),
|
||||
...mapGetters(['getTorrents']),
|
||||
torrents() {
|
||||
return this.getTorrents().filter(t => this.selected_torrents.includes(t.hash))
|
||||
}
|
||||
...mapState(['selected_torrents']),
|
||||
...mapGetters(['getTorrents']),
|
||||
torrents() {
|
||||
return this.getTorrents().filter(t => this.selected_torrents.includes(t.hash))
|
||||
}
|
||||
},
|
||||
deleteWithoutFiles() {
|
||||
qbit.deleteTorrents(this.selected_torrents, false)
|
||||
this.close()
|
||||
},
|
||||
deleteWithFiles() {
|
||||
qbit.deleteTorrents(this.selected_torrents, true)
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<template>
|
||||
<v-dialog
|
||||
v-model="dialog"
|
||||
scrollable
|
||||
:width="dialogWidth"
|
||||
:fullscreen="phoneLayout"
|
||||
v-model="dialog"
|
||||
scrollable
|
||||
:width="dialogWidth"
|
||||
:fullscreen="phoneLayout"
|
||||
>
|
||||
<v-card style="overflow: hidden !important">
|
||||
<v-container :style="{ height: phoneLayout ? '100vh' : '' }">
|
||||
|
@ -16,9 +16,9 @@
|
|||
<v-row>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
label="Torrent Name"
|
||||
prepend-icon="insert_drive_file"
|
||||
v-model="name"
|
||||
v-model="name"
|
||||
label="Torrent Name"
|
||||
prepend-icon="insert_drive_file"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
@ -27,12 +27,21 @@
|
|||
</v-card-text>
|
||||
<div>
|
||||
<v-card-actions class="justify-center">
|
||||
<v-btn color="success" @click="rename">Save</v-btn>
|
||||
<v-btn color="success" @click="rename">
|
||||
Save
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</div>
|
||||
</v-container>
|
||||
<v-fab-transition v-if="phoneLayout">
|
||||
<v-btn @click="close" color="red" dark absolute bottom right>
|
||||
<v-btn
|
||||
color="red"
|
||||
dark
|
||||
absolute
|
||||
bottom
|
||||
right
|
||||
@click="close"
|
||||
>
|
||||
<v-icon>close</v-icon>
|
||||
</v-btn>
|
||||
</v-fab-transition>
|
||||
|
@ -45,36 +54,36 @@ import { mapGetters } from 'vuex'
|
|||
import { Modal, FullScreenModal } from '@/mixins'
|
||||
import qbit from '@/services/qbit'
|
||||
export default {
|
||||
name: 'RenameModal',
|
||||
mixins: [Modal, FullScreenModal],
|
||||
props: {
|
||||
hash: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['getTorrent']),
|
||||
dialogWidth() {
|
||||
return this.phoneLayout ? '100%' : '750px'
|
||||
},
|
||||
torrent() {
|
||||
return this.getTorrent(this.hash)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
rename() {
|
||||
qbit.setTorrentName(this.hash, this.name)
|
||||
this.close()
|
||||
},
|
||||
close() {
|
||||
this.$store.commit('DELETE_MODAL', this.guid)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.name = this.torrent.name
|
||||
name: 'RenameModal',
|
||||
mixins: [Modal, FullScreenModal],
|
||||
props: {
|
||||
hash: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['getTorrent']),
|
||||
dialogWidth() {
|
||||
return this.phoneLayout ? '100%' : '750px'
|
||||
},
|
||||
torrent() {
|
||||
return this.getTorrent(this.hash)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.name = this.torrent.name
|
||||
},
|
||||
methods: {
|
||||
rename() {
|
||||
qbit.setTorrentName(this.hash, this.name)
|
||||
this.close()
|
||||
},
|
||||
close() {
|
||||
this.$store.commit('DELETE_MODAL', this.guid)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -5,36 +5,36 @@
|
|||
</v-btn>
|
||||
|
||||
<v-bottom-sheet
|
||||
scrollable
|
||||
inset
|
||||
v-model="opened"
|
||||
v-if="this.$vuetify.breakpoint.smAndDown"
|
||||
v-if="this.$vuetify.breakpoint.smAndDown"
|
||||
v-model="opened"
|
||||
scrollable
|
||||
inset
|
||||
>
|
||||
<v-sheet>
|
||||
<v-card>
|
||||
<v-card-title> <v-icon>mdi-toy-brick</v-icon> Plugin manager </v-card-title>
|
||||
<v-card-text>
|
||||
<v-switch
|
||||
v-for="(plugin, key) in searchPlugins"
|
||||
:key="key"
|
||||
:input-value="plugin.enabled"
|
||||
:label="plugin.fullName"
|
||||
@change="togglePlugin(plugin)"
|
||||
v-for="(plugin, key) in searchPlugins"
|
||||
:key="key"
|
||||
:input-value="plugin.enabled"
|
||||
:label="plugin.fullName"
|
||||
@change="togglePlugin(plugin)"
|
||||
/>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-sheet>
|
||||
</v-bottom-sheet>
|
||||
<v-dialog v-model="opened" width="50%" v-else>
|
||||
<v-dialog v-else v-model="opened" width="50%">
|
||||
<v-card>
|
||||
<v-card-title> <v-icon>mdi-toy-brick</v-icon> Plugin manager </v-card-title>
|
||||
<v-card-text>
|
||||
<v-switch
|
||||
v-for="(plugin, key) in searchPlugins"
|
||||
:key="key"
|
||||
v-model="plugin.enabled"
|
||||
:label="plugin.fullName"
|
||||
@change="togglePlugin(plugin)"
|
||||
v-for="(plugin, key) in searchPlugins"
|
||||
:key="key"
|
||||
v-model="plugin.enabled"
|
||||
:label="plugin.fullName"
|
||||
@change="togglePlugin(plugin)"
|
||||
/>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
@ -46,22 +46,22 @@
|
|||
import { mapState } from 'vuex'
|
||||
import qbit from '@/services/qbit'
|
||||
export default {
|
||||
name: 'PluginsManager',
|
||||
data: () =>({
|
||||
opened: false
|
||||
}),
|
||||
computed: {
|
||||
...mapState(['searchPlugins'])
|
||||
},
|
||||
methods: {
|
||||
togglePlugin(plugin) {
|
||||
qbit.enableSearchPlugin([plugin.name], plugin.enabled)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
opened() {
|
||||
this.$store.commit('FETCH_SEARCH_PLUGINS')
|
||||
}
|
||||
name: 'PluginsManager',
|
||||
data: () => ({
|
||||
opened: false
|
||||
}),
|
||||
computed: {
|
||||
...mapState(['searchPlugins'])
|
||||
},
|
||||
watch: {
|
||||
opened() {
|
||||
this.$store.commit('FETCH_SEARCH_PLUGINS')
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
togglePlugin(plugin) {
|
||||
qbit.enableSearchPlugin([plugin.name], plugin.enabled)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,78 +1,86 @@
|
|||
<template>
|
||||
<v-dialog
|
||||
v-model="dialog"
|
||||
scrollable
|
||||
:width="dialogWidth"
|
||||
:fullscreen="phoneLayout"
|
||||
:style="{ height: phoneLayout ? '100vh' : '' }"
|
||||
>
|
||||
<v-card :style="{ height: phoneLayout ? '100vh' : '' }">
|
||||
<v-card-title class="justify-center">
|
||||
<h2>Search</h2>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-form
|
||||
ref="form"
|
||||
v-model="searchForm.valid"
|
||||
>
|
||||
<v-container fluid>
|
||||
<v-flex row class="col-12 col-sm-6 col-md-8 mx-auto">
|
||||
<v-text-field
|
||||
v-model="searchForm.pattern"
|
||||
prepend-inner-icon="mdi-magnify"
|
||||
@keypress.enter="$refs.searchButton.click"
|
||||
label="Search"
|
||||
:rules="[v => !!v || 'Searchterm is required']"
|
||||
clearable
|
||||
style="width: 70%"
|
||||
/>
|
||||
<v-spacer/>
|
||||
<v-btn
|
||||
ref="searchButton"
|
||||
:disabled="!searchForm.valid"
|
||||
:color="loading ? 'warning' : 'primary'"
|
||||
@click="loading ? stopSearch() : startSearch()"
|
||||
>
|
||||
{{ loading ? "Stop" : "Search"}}
|
||||
</v-btn>
|
||||
</v-flex>
|
||||
</v-container>
|
||||
</v-form>
|
||||
<perfect-scrollbar>
|
||||
<v-data-table
|
||||
:headers="grid.headers"
|
||||
:items="search.results"
|
||||
:items-per-page="10"
|
||||
:loading="loading"
|
||||
:style="{ maxHeight: '60vh'}"
|
||||
>
|
||||
<template #[`item.fileName`]="{ item }">
|
||||
<a
|
||||
:href="item.descrLink"
|
||||
target="_blank"
|
||||
v-text="item.fileName"
|
||||
/>
|
||||
</template>
|
||||
<template v-slot:[`item.fileSize`]="{ item }">
|
||||
{{ item.fileSize | formatSize }}
|
||||
</template>
|
||||
<template v-slot:[`item.actions`]="{ item }">
|
||||
<v-icon @click="downloadTorrent(item)">mdi-download</v-icon>
|
||||
</template>
|
||||
</v-data-table>
|
||||
</perfect-scrollbar>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<PluginManager/>
|
||||
</v-card-actions>
|
||||
<v-fab-transition v-if="phoneLayout">
|
||||
<v-btn @click="close" color="red" dark absolute bottom right>
|
||||
<v-icon>close</v-icon>
|
||||
</v-btn>
|
||||
</v-fab-transition>
|
||||
</v-card>
|
||||
|
||||
</v-dialog>
|
||||
<v-dialog
|
||||
v-model="dialog"
|
||||
scrollable
|
||||
:width="dialogWidth"
|
||||
:fullscreen="phoneLayout"
|
||||
:style="{ height: phoneLayout ? '100vh' : '' }"
|
||||
>
|
||||
<v-card :style="{ height: phoneLayout ? '100vh' : '' }">
|
||||
<v-card-title class="justify-center">
|
||||
<h2>Search</h2>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-form
|
||||
ref="form"
|
||||
v-model="searchForm.valid"
|
||||
>
|
||||
<v-container fluid>
|
||||
<v-flex row class="col-12 col-sm-6 col-md-8 mx-auto">
|
||||
<v-text-field
|
||||
v-model="searchForm.pattern"
|
||||
prepend-inner-icon="mdi-magnify"
|
||||
label="Search"
|
||||
:rules="[v => !!v || 'Searchterm is required']"
|
||||
clearable
|
||||
style="width: 70%"
|
||||
@keypress.enter="$refs.searchButton.click"
|
||||
/>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
ref="searchButton"
|
||||
:disabled="!searchForm.valid"
|
||||
:color="loading ? 'warning' : 'primary'"
|
||||
@click="loading ? stopSearch() : startSearch()"
|
||||
>
|
||||
{{ loading ? "Stop" : "Search" }}
|
||||
</v-btn>
|
||||
</v-flex>
|
||||
</v-container>
|
||||
</v-form>
|
||||
<perfect-scrollbar>
|
||||
<v-data-table
|
||||
:headers="grid.headers"
|
||||
:items="search.results"
|
||||
:items-per-page="10"
|
||||
:loading="loading"
|
||||
:style="{ maxHeight: '60vh'}"
|
||||
>
|
||||
<template #[`item.fileName`]="{ item }">
|
||||
<a
|
||||
:href="item.descrLink"
|
||||
target="_blank"
|
||||
v-text="item.fileName"
|
||||
/>
|
||||
</template>
|
||||
<template #[`item.fileSize`]="{ item }">
|
||||
{{ item.fileSize | formatSize }}
|
||||
</template>
|
||||
<template #[`item.actions`]="{ item }">
|
||||
<v-icon @click="downloadTorrent(item)">
|
||||
mdi-download
|
||||
</v-icon>
|
||||
</template>
|
||||
</v-data-table>
|
||||
</perfect-scrollbar>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<PluginManager />
|
||||
</v-card-actions>
|
||||
<v-fab-transition v-if="phoneLayout">
|
||||
<v-btn
|
||||
color="red"
|
||||
dark
|
||||
absolute
|
||||
bottom
|
||||
right
|
||||
@click="close"
|
||||
>
|
||||
<v-icon>close</v-icon>
|
||||
</v-btn>
|
||||
</v-fab-transition>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -82,85 +90,86 @@ import { Modal, FullScreenModal, General } from '@/mixins'
|
|||
import PluginManager from './PluginManager'
|
||||
|
||||
export default {
|
||||
name: 'SearchModal',
|
||||
components: { PluginManager },
|
||||
mixins: [Modal, FullScreenModal, General],
|
||||
data() {
|
||||
return {
|
||||
search: {
|
||||
id: null,
|
||||
status: null,
|
||||
interval: null,
|
||||
results: []
|
||||
},
|
||||
loading: false,
|
||||
grid: {
|
||||
headers: [
|
||||
{ text: 'Name', value: 'fileName' },
|
||||
{ text: 'Size', value: 'fileSize' },
|
||||
{ text: 'Seeds', value: 'nbSeeders' },
|
||||
{ text: 'Peers', value: 'nbLeechers' },
|
||||
{ text: 'Search_engine', value: 'siteUrl' },
|
||||
{ text: 'Action', value: 'actions', sortable: false }
|
||||
]
|
||||
},
|
||||
searchForm: {
|
||||
valid: false,
|
||||
pattern: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['getSearchPlugins']),
|
||||
dialogWidth() {
|
||||
return this.phoneLayout ? '100%' : '60%'
|
||||
},
|
||||
enabledSearchPlugins() {
|
||||
return this.getSearchPlugins().filter(p => p.enabled)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async startSearch() {
|
||||
if (this.searchForm.pattern.length && !this.search.interval) {
|
||||
this.loading = true
|
||||
this.search.status = 'Running'
|
||||
this.search.results = []
|
||||
const data = await qbit.startSearch(
|
||||
this.searchForm.pattern,
|
||||
this.enabledSearchPlugins.map(p => p.name)
|
||||
)
|
||||
this.search.id = data.id
|
||||
await this.getStatus()
|
||||
this.search.interval = setInterval(async () => {
|
||||
const status = await this.getStatus()
|
||||
if (status === 'Stopped') {
|
||||
clearInterval(this.search.interval)
|
||||
this.search.interval = null
|
||||
await this.getResults()
|
||||
}
|
||||
}, 500)
|
||||
}
|
||||
},
|
||||
async getStatus() {
|
||||
if (this.search.id) {
|
||||
const data = await qbit.getSearchStatus(this.search.id)
|
||||
return (this.search.status = data[0].status)
|
||||
}
|
||||
},
|
||||
async getResults() {
|
||||
const data = await qbit.getSearchResults(this.search.id)
|
||||
this.search.results = data.results
|
||||
this.loading = false
|
||||
},
|
||||
downloadTorrent(item) {
|
||||
this.createModal('addModal', { initialMagnet: item.fileUrl })
|
||||
},
|
||||
stopSearch() {
|
||||
qbit.stopSearch(this.search.id)
|
||||
},
|
||||
close() {
|
||||
this.$store.commit('DELETE_MODAL', this.guid)
|
||||
}
|
||||
name: 'SearchModal',
|
||||
components: { PluginManager },
|
||||
mixins: [Modal, FullScreenModal, General],
|
||||
data() {
|
||||
return {
|
||||
search: {
|
||||
id: null,
|
||||
status: null,
|
||||
interval: null,
|
||||
results: []
|
||||
},
|
||||
loading: false,
|
||||
grid: {
|
||||
headers: [
|
||||
{ text: 'Name', value: 'fileName' },
|
||||
{ text: 'Size', value: 'fileSize' },
|
||||
{ text: 'Seeds', value: 'nbSeeders' },
|
||||
{ text: 'Peers', value: 'nbLeechers' },
|
||||
{ text: 'Search_engine', value: 'siteUrl' },
|
||||
{ text: 'Action', value: 'actions', sortable: false }
|
||||
]
|
||||
},
|
||||
searchForm: {
|
||||
valid: false,
|
||||
pattern: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['getSearchPlugins']),
|
||||
dialogWidth() {
|
||||
return this.phoneLayout ? '100%' : '60%'
|
||||
},
|
||||
enabledSearchPlugins() {
|
||||
return this.getSearchPlugins().filter(p => p.enabled)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async startSearch() {
|
||||
if (this.searchForm.pattern.length && !this.search.interval) {
|
||||
this.loading = true
|
||||
this.search.status = 'Running'
|
||||
this.search.results = []
|
||||
const data = await qbit.startSearch(
|
||||
this.searchForm.pattern,
|
||||
this.enabledSearchPlugins.map(p => p.name)
|
||||
)
|
||||
this.search.id = data.id
|
||||
await this.getStatus()
|
||||
this.search.interval = setInterval(async () => {
|
||||
const status = await this.getStatus()
|
||||
if (status === 'Stopped') {
|
||||
clearInterval(this.search.interval)
|
||||
this.search.interval = null
|
||||
await this.getResults()
|
||||
}
|
||||
}, 500)
|
||||
}
|
||||
},
|
||||
async getStatus() {
|
||||
if (this.search.id) {
|
||||
const data = await qbit.getSearchStatus(this.search.id)
|
||||
|
||||
return (this.search.status = data[0].status)
|
||||
}
|
||||
},
|
||||
async getResults() {
|
||||
const data = await qbit.getSearchResults(this.search.id)
|
||||
this.search.results = data.results
|
||||
this.loading = false
|
||||
},
|
||||
downloadTorrent(item) {
|
||||
this.createModal('addModal', { initialMagnet: item.fileUrl })
|
||||
},
|
||||
stopSearch() {
|
||||
qbit.stopSearch(this.search.id)
|
||||
},
|
||||
close() {
|
||||
this.$store.commit('DELETE_MODAL', this.guid)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,90 +1,109 @@
|
|||
<template>
|
||||
<v-dialog
|
||||
v-model="dialog"
|
||||
scrollable
|
||||
:width="dialogWidth"
|
||||
:fullscreen="phoneLayout"
|
||||
>
|
||||
<v-card style="min-height: 400px; overflow: hidden !important">
|
||||
<div :style="{ height: phoneLayout ? '100vh' : '' }">
|
||||
<v-card-title class="pb-0 justify-center primary">
|
||||
<h2 class="white--text">Settings</h2>
|
||||
</v-card-title>
|
||||
<v-tabs v-model="tab" background-color="primary" dark fixed-tabs>
|
||||
<v-tab href="#downloads">Downloads</v-tab>
|
||||
<v-tab href="#bittorrent">BitTorrent</v-tab>
|
||||
<v-tab href="#webui">WebUI</v-tab>
|
||||
<v-tab href="#vuetorrent">VueTorrent</v-tab>
|
||||
<v-tab href="#tagsAndCategories">Tags & Categories</v-tab>
|
||||
</v-tabs>
|
||||
<v-tabs-items v-model="tab" :touch="updateTab(tab)">
|
||||
<v-tab-item value="downloads">
|
||||
<Downloads :is-active="tab === 'downloads'" />
|
||||
</v-tab-item>
|
||||
<v-tab-item value="bittorrent">
|
||||
<BitTorrent :is-active="tab === 'bittorrent'" />
|
||||
</v-tab-item>
|
||||
<v-tab-item value="webui">
|
||||
<WebUI :is-active="tab === 'webui'" />
|
||||
</v-tab-item>
|
||||
<v-dialog
|
||||
v-model="dialog"
|
||||
scrollable
|
||||
:width="dialogWidth"
|
||||
:fullscreen="phoneLayout"
|
||||
>
|
||||
<v-card style="min-height: 400px; overflow: hidden !important">
|
||||
<div :style="{ height: phoneLayout ? '100vh' : '' }">
|
||||
<v-card-title class="pb-0 justify-center primary">
|
||||
<h2 class="white--text">
|
||||
Settings
|
||||
</h2>
|
||||
</v-card-title>
|
||||
<v-tabs
|
||||
v-model="tab"
|
||||
background-color="primary"
|
||||
dark
|
||||
fixed-tabs
|
||||
>
|
||||
<v-tab href="#downloads">
|
||||
Downloads
|
||||
</v-tab>
|
||||
<v-tab href="#bittorrent">
|
||||
BitTorrent
|
||||
</v-tab>
|
||||
<v-tab href="#webui">
|
||||
WebUI
|
||||
</v-tab>
|
||||
<v-tab href="#vuetorrent">
|
||||
VueTorrent
|
||||
</v-tab>
|
||||
<v-tab href="#tagsAndCategories">
|
||||
Tags & Categories
|
||||
</v-tab>
|
||||
</v-tabs>
|
||||
<v-tabs-items v-model="tab" :touch="updateTab(tab)">
|
||||
<v-tab-item value="downloads">
|
||||
<Downloads :is-active="tab === 'downloads'" />
|
||||
</v-tab-item>
|
||||
<v-tab-item value="bittorrent">
|
||||
<BitTorrent :is-active="tab === 'bittorrent'" />
|
||||
</v-tab-item>
|
||||
<v-tab-item value="webui">
|
||||
<WebUI :is-active="tab === 'webui'" />
|
||||
</v-tab-item>
|
||||
|
||||
<v-tab-item value="vuetorrent">
|
||||
<VueTorrent :is-active="tab === 'vuetorrent'" />
|
||||
</v-tab-item>
|
||||
<v-tab-item value="tagsAndCategories">
|
||||
<TagsAndCategories
|
||||
:is-active="tab === 'tagsAndCategories'"
|
||||
/>
|
||||
</v-tab-item>
|
||||
</v-tabs-items>
|
||||
</div>
|
||||
<v-card-actions class="d-flex justify-center">
|
||||
<v-btn color="success" @click="saveSettings">Save</v-btn>
|
||||
<v-fab-transition v-if="phoneLayout">
|
||||
<v-btn
|
||||
@click="close"
|
||||
color="red"
|
||||
dark
|
||||
absolute
|
||||
bottom
|
||||
right
|
||||
>
|
||||
<v-icon>close</v-icon>
|
||||
</v-btn>
|
||||
</v-fab-transition>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
<v-tab-item value="vuetorrent">
|
||||
<VueTorrent :is-active="tab === 'vuetorrent'" />
|
||||
</v-tab-item>
|
||||
<v-tab-item value="tagsAndCategories">
|
||||
<TagsAndCategories
|
||||
:is-active="tab === 'tagsAndCategories'"
|
||||
/>
|
||||
</v-tab-item>
|
||||
</v-tabs-items>
|
||||
</div>
|
||||
<v-card-actions class="d-flex justify-center">
|
||||
<v-btn color="success" @click="saveSettings">
|
||||
Save
|
||||
</v-btn>
|
||||
<v-fab-transition v-if="phoneLayout">
|
||||
<v-btn
|
||||
color="red"
|
||||
dark
|
||||
absolute
|
||||
bottom
|
||||
right
|
||||
@click="close"
|
||||
>
|
||||
<v-icon>close</v-icon>
|
||||
</v-btn>
|
||||
</v-fab-transition>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Modal, FullScreenModal, SettingsTab } from '@/mixins'
|
||||
import {
|
||||
WebUI,
|
||||
BitTorrent,
|
||||
Downloads,
|
||||
VueTorrent,
|
||||
TagsAndCategories
|
||||
WebUI,
|
||||
BitTorrent,
|
||||
Downloads,
|
||||
VueTorrent,
|
||||
TagsAndCategories
|
||||
} from './Tabs'
|
||||
|
||||
export default {
|
||||
name: 'SettingsModal',
|
||||
mixins: [Modal, FullScreenModal, SettingsTab],
|
||||
components: { WebUI, BitTorrent, Downloads, VueTorrent, TagsAndCategories },
|
||||
data() {
|
||||
return {
|
||||
tab: null,
|
||||
items: [],
|
||||
peers: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.deleteModal()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$store.commit('FETCH_SETTINGS')
|
||||
name: 'SettingsModal',
|
||||
components: { WebUI, BitTorrent, Downloads, VueTorrent, TagsAndCategories },
|
||||
mixins: [Modal, FullScreenModal, SettingsTab],
|
||||
data() {
|
||||
return {
|
||||
tab: null,
|
||||
items: [],
|
||||
peers: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$store.commit('FETCH_SETTINGS')
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.deleteModal()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,156 +1,156 @@
|
|||
<template>
|
||||
<v-container>
|
||||
<v-card flat>
|
||||
<perfect-scrollbar>
|
||||
<v-card-text :style="{ minHeight: phoneLayout ? '' : '70vh', maxHeight: '70vh'}">
|
||||
<h3>Privacy</h3>
|
||||
<div class="settings_content ml-5 mr-5">
|
||||
<v-checkbox
|
||||
dense
|
||||
:label="`Enable DHT (decentralized network) to find more peers`"
|
||||
v-model="settings.dht"
|
||||
/>
|
||||
<v-checkbox
|
||||
dense
|
||||
:label="`Enable Peer Exchange (PeX) to find more peers`"
|
||||
v-model="settings.pex"
|
||||
/>
|
||||
<v-checkbox
|
||||
dense
|
||||
:label="`Enable Local Peer Discovery to find more peers`"
|
||||
v-model="settings.lsd"
|
||||
/>
|
||||
<v-checkbox
|
||||
dense
|
||||
:label="`Enable anonymous mode`"
|
||||
v-model="settings.anonymous_mode"
|
||||
/>
|
||||
</div>
|
||||
<v-card flat>
|
||||
<perfect-scrollbar>
|
||||
<v-card-text :style="{ minHeight: phoneLayout ? '' : '70vh', maxHeight: '70vh'}">
|
||||
<h3>Privacy</h3>
|
||||
<div class="settings_content ml-5 mr-5">
|
||||
<v-checkbox
|
||||
v-model="settings.dht"
|
||||
dense
|
||||
:label="`Enable DHT (decentralized network) to find more peers`"
|
||||
/>
|
||||
<v-checkbox
|
||||
v-model="settings.pex"
|
||||
dense
|
||||
:label="`Enable Peer Exchange (PeX) to find more peers`"
|
||||
/>
|
||||
<v-checkbox
|
||||
v-model="settings.lsd"
|
||||
dense
|
||||
:label="`Enable Local Peer Discovery to find more peers`"
|
||||
/>
|
||||
<v-checkbox
|
||||
v-model="settings.anonymous_mode"
|
||||
dense
|
||||
:label="`Enable anonymous mode`"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<v-checkbox
|
||||
v-model="settings.queueing_enabled"
|
||||
dense
|
||||
:label="`Torrent Queueing`"
|
||||
/>
|
||||
<div class="settings_content ml-5 mr-5">
|
||||
<v-text-field
|
||||
v-model="settings.max_active_downloads"
|
||||
class="mb-2"
|
||||
outlined
|
||||
dense
|
||||
hide-details
|
||||
:label="`Maximum active downloads`"
|
||||
:disabled="!settings.queueing_enabled"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="settings.max_active_uploads"
|
||||
class="mb-2"
|
||||
outlined
|
||||
dense
|
||||
hide-details
|
||||
:label="`Maximum active uploads`"
|
||||
:disabled="!settings.queueing_enabled"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="settings.max_active_torrents"
|
||||
class="mb-2"
|
||||
outlined
|
||||
dense
|
||||
hide-details
|
||||
:label="`Maximum active torrents`"
|
||||
:disabled="!settings.queueing_enabled"
|
||||
/>
|
||||
|
||||
<v-checkbox
|
||||
v-model="settings.dont_count_slow_torrents"
|
||||
dense
|
||||
:label="`Do not count slow torrents in these limits`"
|
||||
/>
|
||||
|
||||
<div class="settings_content">
|
||||
<v-text-field
|
||||
v-model="settings.slow_torrent_dl_rate_threshold"
|
||||
class="mb-2"
|
||||
outlined
|
||||
dense
|
||||
hide-details
|
||||
:label="`Download rate threshold KiB/s`"
|
||||
:disabled="!settings.dont_count_slow_torrents"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="settings.slow_torrent_ul_rate_threshold"
|
||||
class="mb-2"
|
||||
outlined
|
||||
dense
|
||||
hide-details
|
||||
:label="`Upload rate threshold KiB/s`"
|
||||
:disabled="!settings.dont_count_slow_torrents"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="settings.slow_torrent_inactive_timer"
|
||||
class="mb-2"
|
||||
outlined
|
||||
dense
|
||||
hide-details
|
||||
:label="`Torrent inactivity timer`"
|
||||
:disabled="!settings.dont_count_slow_torrents"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>Seeding Limits</h3>
|
||||
<div class="settings_content ml-5 mr-5">
|
||||
<v-row dense>
|
||||
<v-col cols="10">
|
||||
<v-checkbox
|
||||
dense
|
||||
:label="`Torrent Queueing`"
|
||||
v-model="settings.queueing_enabled"
|
||||
v-model="settings.max_ratio_enabled"
|
||||
dense
|
||||
:label="`When ratio reaches`"
|
||||
/>
|
||||
<div class="settings_content ml-5 mr-5">
|
||||
<v-text-field
|
||||
class="mb-2"
|
||||
outlined
|
||||
dense
|
||||
hide-details
|
||||
:label="`Maximum active downloads`"
|
||||
:disabled="!settings.queueing_enabled"
|
||||
v-model="settings.max_active_downloads"
|
||||
/>
|
||||
<v-text-field
|
||||
class="mb-2"
|
||||
outlined
|
||||
dense
|
||||
hide-details
|
||||
:label="`Maximum active uploads`"
|
||||
:disabled="!settings.queueing_enabled"
|
||||
v-model="settings.max_active_uploads"
|
||||
/>
|
||||
<v-text-field
|
||||
class="mb-2"
|
||||
outlined
|
||||
dense
|
||||
hide-details
|
||||
:label="`Maximum active torrents`"
|
||||
:disabled="!settings.queueing_enabled"
|
||||
v-model="settings.max_active_torrents"
|
||||
/>
|
||||
|
||||
<v-checkbox
|
||||
dense
|
||||
:label="`Do not count slow torrents in these limits`"
|
||||
v-model="settings.dont_count_slow_torrents"
|
||||
/>
|
||||
|
||||
<div class="settings_content">
|
||||
<v-text-field
|
||||
class="mb-2"
|
||||
outlined
|
||||
dense
|
||||
hide-details
|
||||
:label="`Download rate threshold KiB/s`"
|
||||
:disabled="!settings.dont_count_slow_torrents"
|
||||
v-model="settings.slow_torrent_dl_rate_threshold"
|
||||
/>
|
||||
<v-text-field
|
||||
class="mb-2"
|
||||
outlined
|
||||
dense
|
||||
hide-details
|
||||
:label="`Upload rate threshold KiB/s`"
|
||||
:disabled="!settings.dont_count_slow_torrents"
|
||||
v-model="settings.slow_torrent_ul_rate_threshold"
|
||||
/>
|
||||
<v-text-field
|
||||
class="mb-2"
|
||||
outlined
|
||||
dense
|
||||
hide-details
|
||||
:label="`Torrent inactivity timer`"
|
||||
:disabled="!settings.dont_count_slow_torrents"
|
||||
v-model="settings.slow_torrent_inactive_timer"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>Seeding Limits</h3>
|
||||
<div class="settings_content ml-5 mr-5">
|
||||
<v-row dense>
|
||||
<v-col cols="10">
|
||||
<v-checkbox
|
||||
dense
|
||||
:label="`When ratio reaches`"
|
||||
v-model="settings.max_ratio_enabled"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
class="mb-2"
|
||||
outlined
|
||||
dense
|
||||
hide-details
|
||||
:disabled="!settings.max_ratio_enabled"
|
||||
v-model="settings.max_ratio"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row dense>
|
||||
<v-col cols="10">
|
||||
<v-checkbox
|
||||
dense
|
||||
label="When seeding time reaches"
|
||||
v-model="settings.max_seeding_time_enabled"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
class="mb-2"
|
||||
outlined
|
||||
dense
|
||||
hide-details
|
||||
:disabled="!settings.max_seeding_time_enabled"
|
||||
v-model="settings.max_seeding_time"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</perfect-scrollbar>
|
||||
</v-card>
|
||||
</v-container>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
v-model="settings.max_ratio"
|
||||
class="mb-2"
|
||||
outlined
|
||||
dense
|
||||
hide-details
|
||||
:disabled="!settings.max_ratio_enabled"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row dense>
|
||||
<v-col cols="10">
|
||||
<v-checkbox
|
||||
v-model="settings.max_seeding_time_enabled"
|
||||
dense
|
||||
label="When seeding time reaches"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
v-model="settings.max_seeding_time"
|
||||
class="mb-2"
|
||||
outlined
|
||||
dense
|
||||
hide-details
|
||||
:disabled="!settings.max_seeding_time_enabled"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</perfect-scrollbar>
|
||||
</v-card>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { SettingsTab, FullScreenModal } from '@/mixins'
|
||||
|
||||
export default {
|
||||
name: 'BitTorrent',
|
||||
mixins: [SettingsTab, FullScreenModal]
|
||||
name: 'BitTorrent',
|
||||
mixins: [SettingsTab, FullScreenModal]
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,79 +1,79 @@
|
|||
<template>
|
||||
<v-container>
|
||||
<v-card flat>
|
||||
<v-card-text :style="{ minHeight: phoneLayout ? '' : '70vh'}">
|
||||
<h3>When adding a torrent</h3>
|
||||
<div class="settings_content ml-5 mr-5">
|
||||
<v-checkbox
|
||||
dense
|
||||
:label="`Create subfolder for torrents with multiple files`"
|
||||
v-model="settings.create_subfolder_enabled"
|
||||
/>
|
||||
<v-checkbox
|
||||
dense
|
||||
:label="`Do not start the download automatically`"
|
||||
v-model="settings.start_paused_enabled"
|
||||
/>
|
||||
</div>
|
||||
<v-card flat>
|
||||
<v-card-text :style="{ minHeight: phoneLayout ? '' : '70vh'}">
|
||||
<h3>When adding a torrent</h3>
|
||||
<div class="settings_content ml-5 mr-5">
|
||||
<v-checkbox
|
||||
v-model="settings.create_subfolder_enabled"
|
||||
dense
|
||||
:label="`Create subfolder for torrents with multiple files`"
|
||||
/>
|
||||
<v-checkbox
|
||||
v-model="settings.start_paused_enabled"
|
||||
dense
|
||||
:label="`Do not start the download automatically`"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<v-checkbox
|
||||
dense
|
||||
:label="`Pre-allocate disk space for all files`"
|
||||
v-model="settings.preallocate_all"
|
||||
/>
|
||||
<v-checkbox
|
||||
dense
|
||||
:label="` Append .!qB extension to incomplete files`"
|
||||
v-model="settings.incomplete_files_ext"
|
||||
/>
|
||||
<v-checkbox
|
||||
v-model="settings.preallocate_all"
|
||||
dense
|
||||
:label="`Pre-allocate disk space for all files`"
|
||||
/>
|
||||
<v-checkbox
|
||||
v-model="settings.incomplete_files_ext"
|
||||
dense
|
||||
:label="` Append .!qB extension to incomplete files`"
|
||||
/>
|
||||
|
||||
<h3>Saving Management</h3>
|
||||
<div class="settings_content ml-5 mr-5">
|
||||
<v-row dense>
|
||||
<v-col cols="5" class="d-flex align-center">
|
||||
<h4>Default Save Path</h4>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
class="mb-2"
|
||||
outlined
|
||||
dense
|
||||
hide-details
|
||||
v-model="settings.save_path"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row dense>
|
||||
<v-col cols="5">
|
||||
<v-checkbox
|
||||
dense
|
||||
:label="`Keep incomplete torrents in:`"
|
||||
v-model="settings.temp_path_enabled"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
class="mb-2"
|
||||
outlined
|
||||
dense
|
||||
hide-details
|
||||
:disabled="!settings.temp_path_enabled"
|
||||
v-model="settings.temp_path"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-container>
|
||||
<h3>Saving Management</h3>
|
||||
<div class="settings_content ml-5 mr-5">
|
||||
<v-row dense>
|
||||
<v-col cols="5" class="d-flex align-center">
|
||||
<h4>Default Save Path</h4>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
v-model="settings.save_path"
|
||||
class="mb-2"
|
||||
outlined
|
||||
dense
|
||||
hide-details
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row dense>
|
||||
<v-col cols="5">
|
||||
<v-checkbox
|
||||
v-model="settings.temp_path_enabled"
|
||||
dense
|
||||
:label="`Keep incomplete torrents in:`"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
v-model="settings.temp_path"
|
||||
class="mb-2"
|
||||
outlined
|
||||
dense
|
||||
hide-details
|
||||
:disabled="!settings.temp_path_enabled"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { FullScreenModal, SettingsTab } from '@/mixins'
|
||||
|
||||
export default {
|
||||
name: 'Downloads',
|
||||
mixins: [SettingsTab, FullScreenModal]
|
||||
name: 'Downloads',
|
||||
mixins: [SettingsTab, FullScreenModal]
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,73 +1,80 @@
|
|||
<template>
|
||||
<v-container>
|
||||
<v-card flat>
|
||||
<v-card-text
|
||||
class="mx-auto mt-5"
|
||||
style="font-size: 1.1em;"
|
||||
:style="{ minHeight: phoneLayout ? '' : '64vh'}"
|
||||
>
|
||||
<v-layout row wrap>
|
||||
<v-flex class="mx-auto text-center" xs12 md6>
|
||||
<div>
|
||||
<h3>Available Tags:</h3>
|
||||
</div>
|
||||
<div class="mt-3 d-flex flex-wrap justify-center">
|
||||
<v-chip
|
||||
v-for="tag in availableTags"
|
||||
:key="tag"
|
||||
small
|
||||
class="download white--text caption mx-2 my-1"
|
||||
style="font-size: 0.95em !important"
|
||||
>
|
||||
{{ tag }}
|
||||
</v-chip>
|
||||
</div>
|
||||
<v-card-actions class="justify-center pb-5">
|
||||
<v-btn text class="error white--text mt-3" @click="deleteTag"
|
||||
>Delete</v-btn
|
||||
>
|
||||
<v-btn
|
||||
text
|
||||
class="green_accent white--text mt-3"
|
||||
@click="createTag"
|
||||
>Create new</v-btn
|
||||
>
|
||||
</v-card-actions>
|
||||
</v-flex>
|
||||
<v-flex class="mx-auto text-center" xs12 md6>
|
||||
<div>
|
||||
<h3>Available Categories:</h3>
|
||||
</div>
|
||||
<div class="d-flex flex-wrap mt-3 justify-center" xs12 sm12>
|
||||
<v-chip
|
||||
v-for="cat in availableCategories"
|
||||
:key="cat.name"
|
||||
small
|
||||
class="upload white--text caption mx-2 my-1"
|
||||
style="font-size: 0.95em !important"
|
||||
@click="editCategory(cat)"
|
||||
@click:close="editCategory(cat)"
|
||||
>
|
||||
{{ cat.name }}
|
||||
</v-chip>
|
||||
</div>
|
||||
<v-card-actions class="justify-center pb-5">
|
||||
<v-btn
|
||||
text
|
||||
class="error white--text mt-3"
|
||||
@click="deleteCategory"
|
||||
>Delete</v-btn
|
||||
>
|
||||
<v-btn
|
||||
text
|
||||
class="green_accent white--text mt-3"
|
||||
@click="createCategory"
|
||||
>Create new</v-btn
|
||||
>
|
||||
</v-card-actions>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-card-text>
|
||||
<v-card-text
|
||||
class="mx-auto mt-5"
|
||||
style="font-size: 1.1em;"
|
||||
:style="{ minHeight: phoneLayout ? '' : '64vh'}"
|
||||
>
|
||||
<v-layout row wrap>
|
||||
<v-flex class="mx-auto text-center" xs12 md6>
|
||||
<div>
|
||||
<h3>Available Tags:</h3>
|
||||
</div>
|
||||
<div class="mt-3 d-flex flex-wrap justify-center">
|
||||
<v-chip
|
||||
v-for="tag in availableTags"
|
||||
:key="tag"
|
||||
small
|
||||
class="download white--text caption mx-2 my-1"
|
||||
style="font-size: 0.95em !important"
|
||||
>
|
||||
{{ tag }}
|
||||
</v-chip>
|
||||
</div>
|
||||
<v-card-actions class="justify-center pb-5">
|
||||
<v-btn
|
||||
text
|
||||
class="error white--text mt-3"
|
||||
@click="deleteTag"
|
||||
>
|
||||
Delete
|
||||
</v-btn>
|
||||
<v-btn
|
||||
text
|
||||
class="green_accent white--text mt-3"
|
||||
@click="createTag"
|
||||
>
|
||||
Create new
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-flex>
|
||||
<v-flex class="mx-auto text-center" xs12 md6>
|
||||
<div>
|
||||
<h3>Available Categories:</h3>
|
||||
</div>
|
||||
<div class="d-flex flex-wrap mt-3 justify-center" xs12 sm12>
|
||||
<v-chip
|
||||
v-for="cat in availableCategories"
|
||||
:key="cat.name"
|
||||
small
|
||||
class="upload white--text caption mx-2 my-1"
|
||||
style="font-size: 0.95em !important"
|
||||
@click="editCategory(cat)"
|
||||
@click:close="editCategory(cat)"
|
||||
>
|
||||
{{ cat.name }}
|
||||
</v-chip>
|
||||
</div>
|
||||
<v-card-actions class="justify-center pb-5">
|
||||
<v-btn
|
||||
text
|
||||
class="error white--text mt-3"
|
||||
@click="deleteCategory"
|
||||
>
|
||||
Delete
|
||||
</v-btn>
|
||||
<v-btn
|
||||
text
|
||||
class="green_accent white--text mt-3"
|
||||
@click="createCategory"
|
||||
>
|
||||
Create new
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-container>
|
||||
</template>
|
||||
|
@ -80,51 +87,51 @@ import qbit from '@/services/qbit'
|
|||
import { Tab, General, FullScreenModal } from '@/mixins'
|
||||
|
||||
export default {
|
||||
name: 'TagsAndCategories',
|
||||
mixins: [Tab, General, FullScreenModal],
|
||||
props: {
|
||||
hash: String
|
||||
},
|
||||
data: () => ({
|
||||
selectedCategory: null
|
||||
}),
|
||||
computed: {
|
||||
...mapGetters(['getTorrent', 'getAvailableTags', 'getCategories']),
|
||||
name: 'TagsAndCategories',
|
||||
mixins: [Tab, General, FullScreenModal],
|
||||
props: {
|
||||
hash: String
|
||||
},
|
||||
data: () => ({
|
||||
selectedCategory: null
|
||||
}),
|
||||
computed: {
|
||||
...mapGetters(['getTorrent', 'getAvailableTags', 'getCategories']),
|
||||
|
||||
availableTags() {
|
||||
return this.getAvailableTags()
|
||||
},
|
||||
availableCategories() {
|
||||
return this.getCategories()
|
||||
}
|
||||
availableTags() {
|
||||
return this.getAvailableTags()
|
||||
},
|
||||
methods: {
|
||||
activeMethod() {
|
||||
this.fetchCategories()
|
||||
},
|
||||
async fetchCategories() {
|
||||
const { data } = await qbit.getCategories()
|
||||
this.categories = data
|
||||
},
|
||||
deleteTag() {
|
||||
this.createModal('DeleteTagDialog')
|
||||
},
|
||||
createTag() {
|
||||
this.createModal('CreateTagDialog')
|
||||
},
|
||||
createCategory() {
|
||||
this.createModal('CreateCategoryDialog')
|
||||
},
|
||||
deleteCategory() {
|
||||
this.createModal('DeleteCategoryDialog')
|
||||
},
|
||||
editCategory(cat) {
|
||||
this.createModal('CreateCategoryDialog', { initialCategory: cat })
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$store.commit('FETCH_CATEGORIES')
|
||||
availableCategories() {
|
||||
return this.getCategories()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$store.commit('FETCH_CATEGORIES')
|
||||
},
|
||||
methods: {
|
||||
activeMethod() {
|
||||
this.fetchCategories()
|
||||
},
|
||||
async fetchCategories() {
|
||||
const { data } = await qbit.getCategories()
|
||||
this.categories = data
|
||||
},
|
||||
deleteTag() {
|
||||
this.createModal('DeleteTagDialog')
|
||||
},
|
||||
createTag() {
|
||||
this.createModal('CreateTagDialog')
|
||||
},
|
||||
createCategory() {
|
||||
this.createModal('CreateCategoryDialog')
|
||||
},
|
||||
deleteCategory() {
|
||||
this.createModal('DeleteCategoryDialog')
|
||||
},
|
||||
editCategory(cat) {
|
||||
this.createModal('CreateCategoryDialog', { initialCategory: cat })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,25 +1,29 @@
|
|||
<template>
|
||||
<v-card flat>
|
||||
<perfect-scrollbar>
|
||||
<v-card-text :style="{ minHeight: phoneLayout ? '' : '70vh', maxHeight: '70vh'}">
|
||||
<v-tabs v-model="tab">
|
||||
<v-tab href="#general">General</v-tab>
|
||||
<v-tab href="#dashboard">Dashboard</v-tab>
|
||||
</v-tabs>
|
||||
<v-tabs-items
|
||||
v-model="tab"
|
||||
:touch="updateTab(tab)"
|
||||
>
|
||||
<v-tab-item value="general">
|
||||
<General :is-active="tab === 'downloads'" />
|
||||
</v-tab-item>
|
||||
<v-tab-item value="dashboard">
|
||||
<Dashboard :is-active="tab === 'bittorrent'" />
|
||||
</v-tab-item>
|
||||
</v-tabs-items>
|
||||
</v-card-text>
|
||||
</perfect-scrollbar>
|
||||
</v-card>
|
||||
<v-card flat>
|
||||
<perfect-scrollbar>
|
||||
<v-card-text :style="{ minHeight: phoneLayout ? '' : '70vh', maxHeight: '70vh'}">
|
||||
<v-tabs v-model="tab">
|
||||
<v-tab href="#general">
|
||||
General
|
||||
</v-tab>
|
||||
<v-tab href="#dashboard">
|
||||
Dashboard
|
||||
</v-tab>
|
||||
</v-tabs>
|
||||
<v-tabs-items
|
||||
v-model="tab"
|
||||
:touch="updateTab(tab)"
|
||||
>
|
||||
<v-tab-item value="general">
|
||||
<General :is-active="tab === 'downloads'" />
|
||||
</v-tab-item>
|
||||
<v-tab-item value="dashboard">
|
||||
<Dashboard :is-active="tab === 'bittorrent'" />
|
||||
</v-tab-item>
|
||||
</v-tabs-items>
|
||||
</v-card-text>
|
||||
</perfect-scrollbar>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -28,18 +32,18 @@ import Dashboard from './Vuetorrent/Dashboard'
|
|||
import { FullScreenModal } from '@/mixins'
|
||||
|
||||
export default {
|
||||
name: 'VueTorrent',
|
||||
components: {
|
||||
General, Dashboard
|
||||
},
|
||||
mixins: [FullScreenModal],
|
||||
data: () => ({
|
||||
tab: null
|
||||
}),
|
||||
methods: {
|
||||
updateTab(tab) {
|
||||
this.tab = tab
|
||||
}
|
||||
name: 'VueTorrent',
|
||||
components: {
|
||||
General, Dashboard
|
||||
},
|
||||
mixins: [FullScreenModal],
|
||||
data: () => ({
|
||||
tab: null
|
||||
}),
|
||||
methods: {
|
||||
updateTab(tab) {
|
||||
this.tab = tab
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -2,55 +2,65 @@
|
|||
<div class="ma-3 pa-2">
|
||||
<v-card flat>
|
||||
<v-card-text class="pa-0">
|
||||
<v-layout row wrap align-center justify-center>
|
||||
<v-flex class="box ma-1" style="width:50px !important;" xs12 md5>
|
||||
<v-subheader>
|
||||
Properties to display for busy torrents
|
||||
</v-subheader>
|
||||
<v-row dense >
|
||||
<v-list flat class="ma-0 pa-0">
|
||||
<draggable
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
align-center
|
||||
justify-center
|
||||
>
|
||||
<v-flex
|
||||
class="box ma-1"
|
||||
style="width:50px !important;"
|
||||
xs12
|
||||
md5
|
||||
>
|
||||
<v-subheader>
|
||||
Properties to display for busy torrents
|
||||
</v-subheader>
|
||||
<v-row dense>
|
||||
<v-list flat class="ma-0 pa-0">
|
||||
<draggable
|
||||
:list="busyTorrentProperties"
|
||||
tag="tbody"
|
||||
>
|
||||
<v-list-item
|
||||
>
|
||||
<v-list-item
|
||||
v-for="(item, index) in busyTorrentProperties"
|
||||
:key="index"
|
||||
style="width: 30vh"
|
||||
>
|
||||
<v-checkbox v-model="item.active" dense class="pa-0 ma-0 mt-3"/>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title class="truncate" v-text="item.name"/>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</draggable>
|
||||
</v-list>
|
||||
</v-row>
|
||||
</v-flex>
|
||||
>
|
||||
<v-checkbox v-model="item.active" dense class="pa-0 ma-0 mt-3" />
|
||||
<v-list-item-content>
|
||||
<v-list-item-title class="truncate" v-text="item.name" />
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</draggable>
|
||||
</v-list>
|
||||
</v-row>
|
||||
</v-flex>
|
||||
<v-flex class="box ma-1" xs12 md5>
|
||||
<v-subheader>
|
||||
Properties to display for completed torrents
|
||||
</v-subheader>
|
||||
<v-subheader>
|
||||
Properties to display for completed torrents
|
||||
</v-subheader>
|
||||
<v-row dense>
|
||||
<v-list flat class="ma-0 pa-0">
|
||||
<draggable
|
||||
<v-list flat class="ma-0 pa-0">
|
||||
<draggable
|
||||
:list="doneTorrentProperties"
|
||||
tag="tbody"
|
||||
>
|
||||
<v-list-item
|
||||
>
|
||||
<v-list-item
|
||||
v-for="(item, index) in doneTorrentProperties"
|
||||
:key="index"
|
||||
style="width: 30vh"
|
||||
>
|
||||
<v-checkbox v-model="item.active" dense class="pa-0 ma-0 mt-3"/>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title class="truncate" v-text="item.name"/>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</draggable>
|
||||
</v-list>
|
||||
</v-row>
|
||||
</v-flex>
|
||||
>
|
||||
<v-checkbox v-model="item.active" dense class="pa-0 ma-0 mt-3" />
|
||||
<v-list-item-content>
|
||||
<v-list-item-title class="truncate" v-text="item.name" />
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</draggable>
|
||||
</v-list>
|
||||
</v-row>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
@ -60,18 +70,18 @@
|
|||
<script>
|
||||
import draggable from 'vuedraggable'
|
||||
export default {
|
||||
name: 'Dashboard',
|
||||
components: {
|
||||
draggable
|
||||
name: 'Dashboard',
|
||||
components: {
|
||||
draggable
|
||||
},
|
||||
computed: {
|
||||
busyTorrentProperties() {
|
||||
return this.$store.state.webuiSettings.busyTorrentProperties
|
||||
},
|
||||
computed: {
|
||||
busyTorrentProperties() {
|
||||
return this.$store.state.webuiSettings.busyTorrentProperties
|
||||
},
|
||||
doneTorrentProperties() {
|
||||
return this.$store.state.webuiSettings.doneTorrentProperties
|
||||
}
|
||||
doneTorrentProperties() {
|
||||
return this.$store.state.webuiSettings.doneTorrentProperties
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -3,101 +3,129 @@
|
|||
<v-card flat>
|
||||
<v-card-text class="pa-0" style="font-size: 1.1em">
|
||||
<div class="box">
|
||||
<v-subheader
|
||||
>These settings are for the custom WebUI
|
||||
itself</v-subheader
|
||||
>
|
||||
<v-subheader>
|
||||
These settings are for the custom WebUI
|
||||
itself
|
||||
</v-subheader>
|
||||
<v-form class="px-6 mt-3">
|
||||
<v-container>
|
||||
<v-switch
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
v-model="showCurrentSpeed"
|
||||
color="green_accent"
|
||||
>
|
||||
<template #label> Show Current Speed </template>
|
||||
</v-switch>
|
||||
<v-switch
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
v-model="showSpeedGraph"
|
||||
color="green_accent"
|
||||
>
|
||||
<template #label> Show Speed Graph</template>
|
||||
</v-switch>
|
||||
<v-switch
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
v-model="showSessionStat"
|
||||
color="green_accent"
|
||||
>
|
||||
<template #label> Show Session Stats </template>
|
||||
</v-switch>
|
||||
<v-switch
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
v-model="freeSpace"
|
||||
color="green_accent"
|
||||
>
|
||||
<template #label> Show Free Space </template>
|
||||
</v-switch>
|
||||
<v-switch
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
v-model="showGlobalRemoveResumePause"
|
||||
color="green_accent"
|
||||
v-model="showCurrentSpeed"
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
color="green_accent"
|
||||
>
|
||||
<template #label>
|
||||
Global Remove/Resume/Pause Buttons</template
|
||||
>
|
||||
Show Current Speed
|
||||
</template>
|
||||
</v-switch>
|
||||
<v-switch
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
v-model="denseDashboard"
|
||||
color="green_accent"
|
||||
v-model="showSpeedGraph"
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
color="green_accent"
|
||||
>
|
||||
<template #label>
|
||||
Dense version of the dasbhoard</template
|
||||
>
|
||||
Show Speed Graph
|
||||
</template>
|
||||
</v-switch>
|
||||
<v-switch
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
v-model="showTrackerFilter"
|
||||
color="green_accent"
|
||||
v-model="showSessionStat"
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
color="green_accent"
|
||||
>
|
||||
<template #label>
|
||||
Show Tracker Filter</template
|
||||
>
|
||||
Show Session Stats
|
||||
</template>
|
||||
</v-switch>
|
||||
<v-switch
|
||||
v-model="freeSpace"
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
color="green_accent"
|
||||
>
|
||||
<template #label>
|
||||
Show Free Space
|
||||
</template>
|
||||
</v-switch>
|
||||
<v-switch
|
||||
v-model="showGlobalRemoveResumePause"
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
color="green_accent"
|
||||
>
|
||||
<template #label>
|
||||
Global Remove/Resume/Pause Buttons
|
||||
</template>
|
||||
</v-switch>
|
||||
<v-switch
|
||||
v-model="denseDashboard"
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
color="green_accent"
|
||||
>
|
||||
<template #label>
|
||||
Dense version of the dasbhoard
|
||||
</template>
|
||||
</v-switch>
|
||||
<v-switch
|
||||
v-model="showTrackerFilter"
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
color="green_accent"
|
||||
>
|
||||
<template #label>
|
||||
Show Tracker Filter
|
||||
</template>
|
||||
</v-switch>
|
||||
<v-switch
|
||||
v-model="showSpeedInTitle"
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
color="green_accent"
|
||||
>
|
||||
<template #label>
|
||||
Show Speed in Title
|
||||
</template>
|
||||
</v-switch>
|
||||
<v-row dense>
|
||||
<v-col cols="8" sm="8" md="10">
|
||||
<p class="subtitle-1">Pagination size:</p>
|
||||
<p class="subtitle-1">
|
||||
Pagination size:
|
||||
</p>
|
||||
</v-col>
|
||||
<v-col cols="4" sm="4" md="2">
|
||||
<v-select
|
||||
class="pa-0 ma-0"
|
||||
color="green_accent"
|
||||
:items="paginationSizes"
|
||||
v-model="paginationSize"
|
||||
></v-select>
|
||||
v-model="paginationSize"
|
||||
class="pa-0 ma-0"
|
||||
color="green_accent"
|
||||
:items="paginationSizes"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row dense>
|
||||
<v-col cols="10" sm="10" md="11">
|
||||
<p class="subtitle-1">Current Version:</p>
|
||||
<p class="subtitle-1">
|
||||
Current Version:
|
||||
</p>
|
||||
</v-col>
|
||||
<v-col cols="2" sm="2" md="1">
|
||||
<p class="mb-2">{{ version }}</p>
|
||||
<p class="mb-2">
|
||||
{{ version }}
|
||||
</p>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row dense>
|
||||
<v-col cols="10" sm="10" md="11">
|
||||
<p class="subtitle-1">QBittorrent Version:</p>
|
||||
<p class="subtitle-1">
|
||||
QBittorrent Version:
|
||||
</p>
|
||||
</v-col>
|
||||
<v-col cols="2" sm="2" md="1">
|
||||
<p class="mb-2">{{ Qbitversion }}</p>
|
||||
<p class="mb-2">
|
||||
{{ Qbitversion }}
|
||||
</p>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
|
@ -112,92 +140,101 @@
|
|||
import { mapState, mapGetters } from 'vuex'
|
||||
import qbit from '@/services/qbit'
|
||||
export default {
|
||||
name: 'General',
|
||||
data() {
|
||||
return {
|
||||
paginationSizes: [5, 15, 30, 50],
|
||||
Qbitversion: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['webuiSettings']),
|
||||
...mapGetters(['getAppVersion']),
|
||||
freeSpace: {
|
||||
get() {
|
||||
return this.webuiSettings.showFreeSpace
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.showFreeSpace = val
|
||||
}
|
||||
},
|
||||
showCurrentSpeed: {
|
||||
get() {
|
||||
return this.webuiSettings.showCurrentSpeed
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.showCurrentSpeed = val
|
||||
}
|
||||
},
|
||||
showSpeedGraph: {
|
||||
get() {
|
||||
return this.webuiSettings.showSpeedGraph
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.showSpeedGraph = val
|
||||
}
|
||||
},
|
||||
showSessionStat: {
|
||||
get() {
|
||||
return this.webuiSettings.showSessionStat
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.showSessionStat = val
|
||||
}
|
||||
},
|
||||
showGlobalRemoveResumePause: {
|
||||
get() {
|
||||
return this.webuiSettings.showGlobalRemoveResumePause
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.showGlobalRemoveResumePause = val
|
||||
}
|
||||
},
|
||||
denseDashboard: {
|
||||
get() {
|
||||
return this.webuiSettings.denseDashboard
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.denseDashboard = val
|
||||
}
|
||||
},
|
||||
showTrackerFilter: {
|
||||
get() {
|
||||
return this.webuiSettings.showTrackerFilter
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.showTrackerFilter = val
|
||||
}
|
||||
},
|
||||
paginationSize: {
|
||||
get() {
|
||||
return this.webuiSettings.paginationSize
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.paginationSize = val
|
||||
}
|
||||
},
|
||||
version() {
|
||||
return this.getAppVersion()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async fetchQbitVersion() {
|
||||
this.Qbitversion = await qbit.getAppVersion()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.fetchQbitVersion()
|
||||
name: 'General',
|
||||
data() {
|
||||
return {
|
||||
paginationSizes: [5, 15, 30, 50],
|
||||
Qbitversion: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['webuiSettings']),
|
||||
...mapGetters(['getAppVersion']),
|
||||
freeSpace: {
|
||||
get() {
|
||||
return this.webuiSettings.showFreeSpace
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.showFreeSpace = val
|
||||
}
|
||||
},
|
||||
showCurrentSpeed: {
|
||||
get() {
|
||||
return this.webuiSettings.showCurrentSpeed
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.showCurrentSpeed = val
|
||||
}
|
||||
},
|
||||
showSpeedGraph: {
|
||||
get() {
|
||||
return this.webuiSettings.showSpeedGraph
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.showSpeedGraph = val
|
||||
}
|
||||
},
|
||||
showSessionStat: {
|
||||
get() {
|
||||
return this.webuiSettings.showSessionStat
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.showSessionStat = val
|
||||
}
|
||||
},
|
||||
showGlobalRemoveResumePause: {
|
||||
get() {
|
||||
return this.webuiSettings.showGlobalRemoveResumePause
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.showGlobalRemoveResumePause = val
|
||||
}
|
||||
},
|
||||
denseDashboard: {
|
||||
get() {
|
||||
return this.webuiSettings.denseDashboard
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.denseDashboard = val
|
||||
}
|
||||
},
|
||||
showTrackerFilter: {
|
||||
get() {
|
||||
return this.webuiSettings.showTrackerFilter
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.showTrackerFilter = val
|
||||
}
|
||||
},
|
||||
showSpeedInTitle: {
|
||||
get() {
|
||||
return this.webuiSettings.showSpeedInTitle
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.showSpeedInTitle = val
|
||||
document.title = 'VueTorrent'
|
||||
}
|
||||
},
|
||||
paginationSize: {
|
||||
get() {
|
||||
return this.webuiSettings.paginationSize
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.paginationSize = val
|
||||
}
|
||||
},
|
||||
version() {
|
||||
return this.getAppVersion()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.fetchQbitVersion()
|
||||
},
|
||||
methods: {
|
||||
async fetchQbitVersion() {
|
||||
this.Qbitversion = await qbit.getAppVersion()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,65 +1,67 @@
|
|||
<template>
|
||||
<v-container>
|
||||
<v-card flat>
|
||||
<v-card-text class="pa-0" style="font-size: 1.1em"
|
||||
:style="{ minHeight: phoneLayout ? '' : '70vh'}"
|
||||
>
|
||||
<div class="box">
|
||||
<v-subheader>Use Alternative WebUI</v-subheader>
|
||||
<div class="ml-5 mr-5">
|
||||
<v-checkbox
|
||||
dense
|
||||
:label="`Use Alternative WebUI`"
|
||||
v-model="settings.alternative_webui_enabled"
|
||||
/>
|
||||
<v-text-field
|
||||
outlined
|
||||
dense
|
||||
hide-details="true"
|
||||
:label="`Files location`"
|
||||
:disabled="!settings.alternative_webui_enabled"
|
||||
v-model="settings.alternative_webui_path"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box">
|
||||
<v-subheader
|
||||
>Web User Interface (Remote Control)</v-subheader
|
||||
>
|
||||
<v-row class="ml-5 mr-5">
|
||||
<v-col cols="10">
|
||||
<v-text-field
|
||||
class="mr-1"
|
||||
outlined
|
||||
dense
|
||||
hide-details="true"
|
||||
:label="`IP Address:`"
|
||||
v-model="settings.web_ui_address"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
class="ml-1"
|
||||
outlined
|
||||
dense
|
||||
hide-details="true"
|
||||
:label="`Port`"
|
||||
v-model="settings.web_ui_port"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-container>
|
||||
<v-card flat>
|
||||
<v-card-text
|
||||
class="pa-0"
|
||||
style="font-size: 1.1em"
|
||||
:style="{ minHeight: phoneLayout ? '' : '70vh'}"
|
||||
>
|
||||
<div class="box">
|
||||
<v-subheader>Use Alternative WebUI</v-subheader>
|
||||
<div class="ml-5 mr-5">
|
||||
<v-checkbox
|
||||
v-model="settings.alternative_webui_enabled"
|
||||
dense
|
||||
:label="`Use Alternative WebUI`"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="settings.alternative_webui_path"
|
||||
outlined
|
||||
dense
|
||||
hide-details="true"
|
||||
:label="`Files location`"
|
||||
:disabled="!settings.alternative_webui_enabled"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box">
|
||||
<v-subheader>
|
||||
Web User Interface (Remote Control)
|
||||
</v-subheader>
|
||||
<v-row class="ml-5 mr-5">
|
||||
<v-col cols="10">
|
||||
<v-text-field
|
||||
v-model="settings.web_ui_address"
|
||||
class="mr-1"
|
||||
outlined
|
||||
dense
|
||||
hide-details="true"
|
||||
:label="`IP Address:`"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
v-model="settings.web_ui_port"
|
||||
class="ml-1"
|
||||
outlined
|
||||
dense
|
||||
hide-details="true"
|
||||
:label="`Port`"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { FullScreenModal, SettingsTab } from '@/mixins'
|
||||
|
||||
export default {
|
||||
name: 'WebUI',
|
||||
mixins: [SettingsTab, FullScreenModal]
|
||||
name: 'WebUI',
|
||||
mixins: [SettingsTab, FullScreenModal]
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,82 +1,84 @@
|
|||
<template>
|
||||
<v-dialog v-model="dialog" scrollable max-width="500px">
|
||||
<v-card>
|
||||
<v-container :class="`pa-0 project done`">
|
||||
<v-card-title class="justify-center">
|
||||
<h2>Sort Torrents</h2>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-form class="px-6 mt-3 justify-center mx-auto">
|
||||
<v-container class="sortmodal">
|
||||
<v-select
|
||||
:value="sortProperty"
|
||||
v-model="sort_options.sort"
|
||||
flat
|
||||
class="ml-2 mr-2"
|
||||
:items="options"
|
||||
item-text="name"
|
||||
item-value="value"
|
||||
dense
|
||||
solo
|
||||
background-color="select"
|
||||
height="55"
|
||||
></v-select>
|
||||
<v-switch
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
v-model="sort_options.reverse"
|
||||
color="green_accent"
|
||||
style="padding-left: 10px !important"
|
||||
>
|
||||
<template #label> Reverse </template>
|
||||
</v-switch>
|
||||
</v-container>
|
||||
</v-form>
|
||||
</v-card-text>
|
||||
<v-dialog v-model="dialog" scrollable max-width="500px">
|
||||
<v-card>
|
||||
<v-container :class="`pa-0 project done`">
|
||||
<v-card-title class="justify-center">
|
||||
<h2>Sort Torrents</h2>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-form class="px-6 mt-3 justify-center mx-auto">
|
||||
<v-container class="sortmodal">
|
||||
<v-select
|
||||
v-model="sort_options.sort"
|
||||
:value="sortProperty"
|
||||
flat
|
||||
class="ml-2 mr-2"
|
||||
:items="options"
|
||||
item-text="name"
|
||||
item-value="value"
|
||||
dense
|
||||
solo
|
||||
background-color="select"
|
||||
height="55"
|
||||
/>
|
||||
<v-switch
|
||||
v-model="sort_options.reverse"
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
color="green_accent"
|
||||
style="padding-left: 10px !important"
|
||||
>
|
||||
<template #label>
|
||||
Reverse
|
||||
</template>
|
||||
</v-switch>
|
||||
</v-container>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</v-form>
|
||||
</v-card-text>
|
||||
</v-container>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import { Modal } from '@/mixins'
|
||||
export default {
|
||||
name: 'Sort',
|
||||
mixins: [Modal],
|
||||
data() {
|
||||
return {
|
||||
sortProperty: { value: 'added_on', name: 'Added On' },
|
||||
reverse: true,
|
||||
options: [
|
||||
{ value: 'added_on', name: 'Added On' },
|
||||
{ value: 'availability', name: 'Availability' },
|
||||
{ value: 'category', name: 'Category' },
|
||||
{ value: 'completed', name: 'Completed' },
|
||||
{ value: 'dlspeed', name: 'Download Speed' },
|
||||
{ value: 'downloaded', name: 'Downloaded' },
|
||||
{ value: 'eta', name: 'ETA' },
|
||||
{ value: 'name', name: 'Name' },
|
||||
{ value: 'num_leechs', name: 'Peers' },
|
||||
{ value: 'priority', name: 'Priority' },
|
||||
{ value: 'progress', name: 'Progress' },
|
||||
{ value: 'ratio', name: 'Ratio' },
|
||||
{ value: 'size', name: 'Size' },
|
||||
{ value: 'state', name: 'State' },
|
||||
{ value: 'time_active', name: 'Time Active' },
|
||||
{ value: 'uploaded', name: 'Uploaded' },
|
||||
{ value: 'upspeed', name: 'Upload Speed' }
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.$store.commit('DELETE_MODAL', this.guid)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['sort_options'])
|
||||
name: 'Sort',
|
||||
mixins: [Modal],
|
||||
data() {
|
||||
return {
|
||||
sortProperty: { value: 'added_on', name: 'Added On' },
|
||||
reverse: true,
|
||||
options: [
|
||||
{ value: 'added_on', name: 'Added On' },
|
||||
{ value: 'availability', name: 'Availability' },
|
||||
{ value: 'category', name: 'Category' },
|
||||
{ value: 'completed', name: 'Completed' },
|
||||
{ value: 'dlspeed', name: 'Download Speed' },
|
||||
{ value: 'downloaded', name: 'Downloaded' },
|
||||
{ value: 'eta', name: 'ETA' },
|
||||
{ value: 'name', name: 'Name' },
|
||||
{ value: 'num_leechs', name: 'Peers' },
|
||||
{ value: 'priority', name: 'Priority' },
|
||||
{ value: 'progress', name: 'Progress' },
|
||||
{ value: 'ratio', name: 'Ratio' },
|
||||
{ value: 'size', name: 'Size' },
|
||||
{ value: 'state', name: 'State' },
|
||||
{ value: 'time_active', name: 'Time Active' },
|
||||
{ value: 'uploaded', name: 'Uploaded' },
|
||||
{ value: 'upspeed', name: 'Upload Speed' }
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['sort_options'])
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.$store.commit('DELETE_MODAL', this.guid)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,55 +1,61 @@
|
|||
<template>
|
||||
<v-dialog v-model="dialog" max-width="600px">
|
||||
<v-card>
|
||||
<v-container style="min-height: 200px" :class="`pa-0 project done`">
|
||||
<v-card-title class="justify-center">
|
||||
<h2>{{ hasInitialCategory ? 'Edit' : 'Create New' }} Category</h2>
|
||||
</v-card-title>
|
||||
<v-dialog v-model="dialog" max-width="600px">
|
||||
<v-card>
|
||||
<v-container style="min-height: 200px" :class="`pa-0 project done`">
|
||||
<v-card-title class="justify-center">
|
||||
<h2>{{ hasInitialCategory ? 'Edit' : 'Create New' }} Category</h2>
|
||||
</v-card-title>
|
||||
|
||||
<v-form ref="categoryForm" class="px-6 mt-3">
|
||||
<v-container>
|
||||
<v-text-field
|
||||
class="mx-auto"
|
||||
style="max-width: 200px"
|
||||
v-model="category.name"
|
||||
:rules="nameRules"
|
||||
:counter="15"
|
||||
label="Category name"
|
||||
required
|
||||
></v-text-field>
|
||||
<v-text-field
|
||||
class="mx-auto"
|
||||
style="max-width: 200px"
|
||||
v-model="category.savePath"
|
||||
:rules="PathRules"
|
||||
:counter="40"
|
||||
label="Path"
|
||||
required
|
||||
></v-text-field>
|
||||
</v-container>
|
||||
</v-form>
|
||||
</v-container>
|
||||
<v-card-actions class="justify-center pb-5 project done">
|
||||
<v-btn text @click="cancel" class="error white--text mt-3"
|
||||
>Cancel</v-btn
|
||||
>
|
||||
<v-btn
|
||||
v-if="!hasInitialCategory"
|
||||
text
|
||||
@click="create"
|
||||
class="green_accent white--text mt-3"
|
||||
>Save</v-btn
|
||||
>
|
||||
<v-btn
|
||||
v-else
|
||||
text
|
||||
@click="edit"
|
||||
class="green_accent white--text mt-3"
|
||||
>Edit</v-btn
|
||||
>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
<v-form ref="categoryForm" class="px-6 mt-3">
|
||||
<v-container>
|
||||
<v-text-field
|
||||
v-model="category.name"
|
||||
class="mx-auto"
|
||||
style="max-width: 200px"
|
||||
:rules="nameRules"
|
||||
:counter="15"
|
||||
label="Category name"
|
||||
required
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="category.savePath"
|
||||
class="mx-auto"
|
||||
style="max-width: 200px"
|
||||
:rules="PathRules"
|
||||
:counter="40"
|
||||
label="Path"
|
||||
required
|
||||
/>
|
||||
</v-container>
|
||||
</v-form>
|
||||
</v-container>
|
||||
<v-card-actions class="justify-center pb-5 project done">
|
||||
<v-btn
|
||||
text
|
||||
class="error white--text mt-3"
|
||||
@click="cancel"
|
||||
>
|
||||
Cancel
|
||||
</v-btn>
|
||||
<v-btn
|
||||
v-if="!hasInitialCategory"
|
||||
text
|
||||
class="green_accent white--text mt-3"
|
||||
@click="create"
|
||||
>
|
||||
Save
|
||||
</v-btn>
|
||||
<v-btn
|
||||
v-else
|
||||
text
|
||||
class="green_accent white--text mt-3"
|
||||
@click="edit"
|
||||
>
|
||||
Edit
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -59,57 +65,57 @@ import { Modal } from '@/mixins'
|
|||
import Vue from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'createNewCategoryDialog',
|
||||
props: {
|
||||
initialCategory: Object
|
||||
},
|
||||
mixins: [Modal],
|
||||
computed: {
|
||||
...mapGetters(['getSelectedCategory']),
|
||||
hasInitialCategory() {
|
||||
return (
|
||||
this.initialCategory &&
|
||||
name: 'CreateNewCategoryDialog',
|
||||
mixins: [Modal],
|
||||
props: {
|
||||
initialCategory: Object
|
||||
},
|
||||
data: () => ({
|
||||
nameRules: [
|
||||
v => !!v || 'Category name is required',
|
||||
v =>
|
||||
(v && v.length <= 15) ||
|
||||
'Category name must be less than 15 characters'
|
||||
],
|
||||
PathRules: [
|
||||
v => !!v || 'Path is required',
|
||||
v => (v && v.length <= 40) || 'Path must be less than 40 characters'
|
||||
],
|
||||
category: { name: '', savePath: '' }
|
||||
}),
|
||||
computed: {
|
||||
...mapGetters(['getSelectedCategory']),
|
||||
hasInitialCategory() {
|
||||
return (
|
||||
this.initialCategory &&
|
||||
this.initialCategory.name
|
||||
)
|
||||
}
|
||||
},
|
||||
data: () => ({
|
||||
nameRules: [
|
||||
v => !!v || 'Category name is required',
|
||||
v =>
|
||||
(v && v.length <= 15) ||
|
||||
'Category name must be less than 15 characters'
|
||||
],
|
||||
PathRules: [
|
||||
v => !!v || 'Path is required',
|
||||
v => (v && v.length <= 40) || 'Path must be less than 40 characters'
|
||||
],
|
||||
category: { name: '', savePath: '' }
|
||||
}),
|
||||
methods: {
|
||||
create() {
|
||||
qbit.createCategory(this.category)
|
||||
this.cancel()
|
||||
},
|
||||
cancel() {
|
||||
this.category.name = ''
|
||||
this.category.savePath = ''
|
||||
this.$refs.categoryForm.reset()
|
||||
this.$store.commit('FETCH_CATEGORIES')
|
||||
this.deleteModal()
|
||||
},
|
||||
edit() {
|
||||
qbit.editCategory(this.category)
|
||||
Vue.$toast.success('Category edited successfully!')
|
||||
this.cancel()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$store.commit('FETCH_CATEGORIES')
|
||||
if (this.hasInitialCategory) {
|
||||
this.category = this.initialCategory
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$store.commit('FETCH_CATEGORIES')
|
||||
if (this.hasInitialCategory) {
|
||||
this.category = this.initialCategory
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
create() {
|
||||
qbit.createCategory(this.category)
|
||||
this.cancel()
|
||||
},
|
||||
cancel() {
|
||||
this.category.name = ''
|
||||
this.category.savePath = ''
|
||||
this.$refs.categoryForm.reset()
|
||||
this.$store.commit('FETCH_CATEGORIES')
|
||||
this.deleteModal()
|
||||
},
|
||||
edit() {
|
||||
qbit.editCategory(this.category)
|
||||
Vue.$toast.success('Category edited successfully!')
|
||||
this.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,63 +1,68 @@
|
|||
<template>
|
||||
<v-dialog v-model="dialog" max-width="600px">
|
||||
<v-card>
|
||||
<v-container style="min-height: 200px" :class="`pa-0 project done`">
|
||||
<v-card-title class="justify-center">
|
||||
<h2>Create New Tag</h2>
|
||||
</v-card-title>
|
||||
<v-dialog v-model="dialog" max-width="600px">
|
||||
<v-card>
|
||||
<v-container style="min-height: 200px" :class="`pa-0 project done`">
|
||||
<v-card-title class="justify-center">
|
||||
<h2>Create New Tag</h2>
|
||||
</v-card-title>
|
||||
|
||||
<v-form class="px-6 mt-3">
|
||||
<v-container>
|
||||
<v-text-field
|
||||
class="mx-auto"
|
||||
style="max-width: 200px"
|
||||
v-model="tagname"
|
||||
:rules="rules"
|
||||
:counter="10"
|
||||
label="Tag name"
|
||||
required
|
||||
></v-text-field>
|
||||
</v-container>
|
||||
</v-form>
|
||||
</v-container>
|
||||
<v-card-actions class="justify-center pb-5 project done">
|
||||
<v-btn text @click="cancel" class="error white--text mt-3"
|
||||
>Cancel</v-btn
|
||||
>
|
||||
<v-btn
|
||||
text
|
||||
@click="create"
|
||||
class="green_accent white--text mt-3"
|
||||
>Save</v-btn
|
||||
>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
<v-form class="px-6 mt-3">
|
||||
<v-container>
|
||||
<v-text-field
|
||||
v-model="tagname"
|
||||
class="mx-auto"
|
||||
style="max-width: 200px"
|
||||
:rules="rules"
|
||||
:counter="10"
|
||||
label="Tag name"
|
||||
required
|
||||
/>
|
||||
</v-container>
|
||||
</v-form>
|
||||
</v-container>
|
||||
<v-card-actions class="justify-center pb-5 project done">
|
||||
<v-btn
|
||||
text
|
||||
class="error white--text mt-3"
|
||||
@click="cancel"
|
||||
>
|
||||
Cancel
|
||||
</v-btn>
|
||||
<v-btn
|
||||
text
|
||||
class="green_accent white--text mt-3"
|
||||
@click="create"
|
||||
>
|
||||
Save
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import qbit from '@/services/qbit'
|
||||
import { Modal } from '@/mixins'
|
||||
export default {
|
||||
name: 'createTagDialog',
|
||||
mixins: [Modal],
|
||||
data: () => ({
|
||||
tagname: '',
|
||||
rules: [
|
||||
v => !!v || 'Tag is required',
|
||||
v => v.length <= 10 || 'Tag must be less than 10 characters'
|
||||
]
|
||||
}),
|
||||
methods: {
|
||||
create() {
|
||||
qbit.createTag(this.tagname)
|
||||
this.cancel()
|
||||
},
|
||||
cancel() {
|
||||
this.tagname = ''
|
||||
this.deleteModal()
|
||||
}
|
||||
name: 'CreateTagDialog',
|
||||
mixins: [Modal],
|
||||
data: () => ({
|
||||
tagname: '',
|
||||
rules: [
|
||||
v => !!v || 'Tag is required',
|
||||
v => v.length <= 10 || 'Tag must be less than 10 characters'
|
||||
]
|
||||
}),
|
||||
methods: {
|
||||
create() {
|
||||
qbit.createTag(this.tagname)
|
||||
this.cancel()
|
||||
},
|
||||
cancel() {
|
||||
this.tagname = ''
|
||||
this.deleteModal()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,44 +1,48 @@
|
|||
<template>
|
||||
<v-dialog :value="dialog" max-width="600px">
|
||||
<v-card>
|
||||
<v-container style="min-height: 200px" :class="`pa-0 project done`">
|
||||
<v-card-title class="justify-center">
|
||||
<h2>Delete Category</h2>
|
||||
</v-card-title>
|
||||
<v-dialog :value="dialog" max-width="600px">
|
||||
<v-card>
|
||||
<v-container style="min-height: 200px" :class="`pa-0 project done`">
|
||||
<v-card-title class="justify-center">
|
||||
<h2>Delete Category</h2>
|
||||
</v-card-title>
|
||||
|
||||
<v-list
|
||||
rounded
|
||||
v-if="categories"
|
||||
class="text-center mx-auto"
|
||||
style="max-width: 200px"
|
||||
>
|
||||
<v-list-item
|
||||
@click="deleteCategory(t)"
|
||||
v-for="(t, i) in categories"
|
||||
:key="i"
|
||||
>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title
|
||||
v-text="t.name"
|
||||
></v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
<v-card-subtitle
|
||||
class="text-center mx-auto"
|
||||
style="font-size: 1.5em; margin-top: 20px"
|
||||
v-else
|
||||
>
|
||||
No categories found
|
||||
</v-card-subtitle>
|
||||
</v-container>
|
||||
<v-card-actions class="justify-center pb-5 project done">
|
||||
<v-btn text @click="cancel" class="error white--text mt-3"
|
||||
>Close</v-btn
|
||||
>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
<v-list
|
||||
v-if="categories"
|
||||
rounded
|
||||
class="text-center mx-auto"
|
||||
style="max-width: 200px"
|
||||
>
|
||||
<v-list-item
|
||||
v-for="(t, i) in categories"
|
||||
:key="i"
|
||||
@click="deleteCategory(t)"
|
||||
>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title
|
||||
v-text="t.name"
|
||||
/>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
<v-card-subtitle
|
||||
v-else
|
||||
class="text-center mx-auto"
|
||||
style="font-size: 1.5em; margin-top: 20px"
|
||||
>
|
||||
No categories found
|
||||
</v-card-subtitle>
|
||||
</v-container>
|
||||
<v-card-actions class="justify-center pb-5 project done">
|
||||
<v-btn
|
||||
text
|
||||
class="error white--text mt-3"
|
||||
@click="cancel"
|
||||
>
|
||||
Close
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -46,24 +50,24 @@ import qbit from '@/services/qbit'
|
|||
import { Modal } from '@/mixins'
|
||||
import { mapGetters } from 'vuex'
|
||||
export default {
|
||||
name: 'DeleteCategoryDialog',
|
||||
mixins: [Modal],
|
||||
computed: {
|
||||
...mapGetters(['getCategories']),
|
||||
categories() {
|
||||
return this.getCategories()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
deleteCategory(cat) {
|
||||
qbit.deleteCategory(cat.name)
|
||||
this.cancel()
|
||||
},
|
||||
cancel() {
|
||||
this.$store.commit('FETCH_CATEGORIES')
|
||||
this.deleteModal()
|
||||
}
|
||||
name: 'DeleteCategoryDialog',
|
||||
mixins: [Modal],
|
||||
computed: {
|
||||
...mapGetters(['getCategories']),
|
||||
categories() {
|
||||
return this.getCategories()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
deleteCategory(cat) {
|
||||
qbit.deleteCategory(cat.name)
|
||||
this.cancel()
|
||||
},
|
||||
cancel() {
|
||||
this.$store.commit('FETCH_CATEGORIES')
|
||||
this.deleteModal()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,42 +1,46 @@
|
|||
<template>
|
||||
<v-dialog v-model="dialog" max-width="600px">
|
||||
<v-card>
|
||||
<v-container style="min-height: 200px" :class="`pa-0 project done`">
|
||||
<v-card-title class="justify-center">
|
||||
<h2>Delete Tag</h2>
|
||||
</v-card-title>
|
||||
<v-dialog v-model="dialog" max-width="600px">
|
||||
<v-card>
|
||||
<v-container style="min-height: 200px" :class="`pa-0 project done`">
|
||||
<v-card-title class="justify-center">
|
||||
<h2>Delete Tag</h2>
|
||||
</v-card-title>
|
||||
|
||||
<v-list
|
||||
rounded
|
||||
v-if="availableTags && availableTags.length"
|
||||
class="text-center mx-auto"
|
||||
style="max-width: 200px"
|
||||
>
|
||||
<v-list-item
|
||||
@click="deleteTag(t)"
|
||||
v-for="(t, i) in availableTags"
|
||||
:key="i"
|
||||
>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-text="t"></v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
<v-card-subtitle
|
||||
class="text-center mx-auto"
|
||||
style="font-size: 1.5em; margin-top: 20px"
|
||||
v-else
|
||||
>
|
||||
No tags found
|
||||
</v-card-subtitle>
|
||||
</v-container>
|
||||
<v-card-actions class="justify-center pb-5 project done">
|
||||
<v-btn text @click="cancel" class="error white--text mt-3"
|
||||
>Close</v-btn
|
||||
>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
<v-list
|
||||
v-if="availableTags && availableTags.length"
|
||||
rounded
|
||||
class="text-center mx-auto"
|
||||
style="max-width: 200px"
|
||||
>
|
||||
<v-list-item
|
||||
v-for="(t, i) in availableTags"
|
||||
:key="i"
|
||||
@click="deleteTag(t)"
|
||||
>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-text="t" />
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
<v-card-subtitle
|
||||
v-else
|
||||
class="text-center mx-auto"
|
||||
style="font-size: 1.5em; margin-top: 20px"
|
||||
>
|
||||
No tags found
|
||||
</v-card-subtitle>
|
||||
</v-container>
|
||||
<v-card-actions class="justify-center pb-5 project done">
|
||||
<v-btn
|
||||
text
|
||||
class="error white--text mt-3"
|
||||
@click="cancel"
|
||||
>
|
||||
Close
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -44,23 +48,23 @@ import qbit from '@/services/qbit'
|
|||
import { Modal } from '@/mixins'
|
||||
import { mapGetters } from 'vuex'
|
||||
export default {
|
||||
name: 'DeleteTagDialog',
|
||||
mixins: [Modal],
|
||||
computed: {
|
||||
...mapGetters(['getTorrent', 'getAvailableTags']),
|
||||
availableTags() {
|
||||
return this.getAvailableTags()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
deleteTag(tag) {
|
||||
qbit.deleteTag(tag)
|
||||
this.cancel()
|
||||
},
|
||||
cancel() {
|
||||
this.deleteModal()
|
||||
}
|
||||
name: 'DeleteTagDialog',
|
||||
mixins: [Modal],
|
||||
computed: {
|
||||
...mapGetters(['getTorrent', 'getAvailableTags']),
|
||||
availableTags() {
|
||||
return this.getAvailableTags()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
deleteTag(tag) {
|
||||
qbit.deleteTag(tag)
|
||||
this.cancel()
|
||||
},
|
||||
cancel() {
|
||||
this.deleteModal()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@ import CreateNewCategoryDialog from './CreateCategoryDialog.vue'
|
|||
import DeleteCategoryDialog from './DeleteCategoryDialog'
|
||||
|
||||
export {
|
||||
CreateNewTagDialog,
|
||||
DeleteTagDialog,
|
||||
CreateNewCategoryDialog,
|
||||
DeleteCategoryDialog
|
||||
CreateNewTagDialog,
|
||||
DeleteTagDialog,
|
||||
CreateNewCategoryDialog,
|
||||
DeleteCategoryDialog
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<v-card flat>
|
||||
<perfect-scrollbar>
|
||||
<v-card-text :style="{ minHeight: phoneLayout ? '' : '75vh', maxHeight: '75vh'}">
|
||||
<v-card-text :style="{ minHeight: phoneLayout ? '' : '75vh', maxHeight: '75vh'}">
|
||||
<v-treeview
|
||||
v-model="selected"
|
||||
:items="fileTree"
|
||||
|
@ -11,21 +11,23 @@
|
|||
item-key="fullName"
|
||||
open-all
|
||||
>
|
||||
<template v-slot:prepend="{ item, open }">
|
||||
<template #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>
|
||||
<v-icon v-else>
|
||||
{{ item.icon }}
|
||||
</v-icon>
|
||||
</template>
|
||||
<template v-slot:label="{ item }">
|
||||
<template #label="{ item }">
|
||||
<span v-if="!item.editing">{{ item.name }}</span>
|
||||
<v-text-field
|
||||
autofocus
|
||||
v-if="item.editing"
|
||||
v-model="item.newName"
|
||||
autofocus
|
||||
/>
|
||||
</template>
|
||||
<template v-slot:append="{ item }">
|
||||
<template #append="{ item }">
|
||||
<span v-if="!item.icon">{{ item.children.length }} Files</span>
|
||||
<div v-else>
|
||||
<span>[{{ item.size }}]</span>
|
||||
|
@ -70,96 +72,97 @@ import qbit from '@/services/qbit'
|
|||
import { treeify } from '@/helpers'
|
||||
import { FullScreenModal } from '@/mixins'
|
||||
export default {
|
||||
name: 'Content',
|
||||
mixins: [FullScreenModal],
|
||||
props: {
|
||||
hash: String,
|
||||
isActive: Boolean
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
opened: null,
|
||||
selected: [],
|
||||
treeData: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
fileTree() {
|
||||
if (this.treeData) {
|
||||
return treeify(this.treeData)
|
||||
}
|
||||
return []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async getTorrentFiles() {
|
||||
const { data } = await qbit.getTorrentFiles(this.hash)
|
||||
data.forEach((d, i) => {
|
||||
d.id = i
|
||||
d.name = d.name.replace('.unwanted/', '')
|
||||
})
|
||||
this.treeData = data
|
||||
},
|
||||
async changeFilePriorities(newValue, oldValue) {
|
||||
if (newValue.length == oldValue.length) return
|
||||
|
||||
const filesToExclude = oldValue
|
||||
.filter(f => !newValue.includes(f))
|
||||
.map(name => this.treeData.find(f => f.name === name))
|
||||
.filter(f => f.priority !== 0)
|
||||
.map(f => f.id)
|
||||
const filesToInclude = newValue
|
||||
.filter(f => !oldValue.includes(f))
|
||||
.map(name => this.treeData.find(f => f.name === name))
|
||||
.filter(f => f.priority === 0)
|
||||
.map(f => f.id)
|
||||
|
||||
if (filesToExclude.length) {
|
||||
await qbit.setTorrentFilePriority(this.hash, filesToExclude, 0)
|
||||
}
|
||||
if (filesToInclude.length) {
|
||||
await qbit.setTorrentFilePriority(this.hash, filesToInclude, 1)
|
||||
}
|
||||
if (filesToExclude.length || filesToInclude.length) {
|
||||
await this.getTorrentFiles()
|
||||
}
|
||||
},
|
||||
togleEditing(item) {
|
||||
item.editing = !item.editing
|
||||
},
|
||||
edit(item) {
|
||||
item.newName = item.name
|
||||
this.togleEditing(item)
|
||||
},
|
||||
renameFile(item) {
|
||||
qbit.renameFile(this.hash, item.id, item.newName)
|
||||
item.name = item.newName
|
||||
this.togleEditing(item)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
isActive(active) {
|
||||
if (active) {
|
||||
this.getTorrentFiles()
|
||||
}
|
||||
},
|
||||
selected(newValue, oldValue) {
|
||||
this.changeFilePriorities(newValue, oldValue)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getTorrentFiles().then(() => {
|
||||
this.opened = []
|
||||
.concat(
|
||||
...this.treeData
|
||||
.map(file => file.name.split('/'))
|
||||
.filter(f => f.splice(-1, 1))
|
||||
)
|
||||
.filter((f, index, self) => index === self.indexOf(f))
|
||||
this.selected = this.treeData
|
||||
.filter(file => file.priority !== 0)
|
||||
.map(file => file.name)
|
||||
})
|
||||
name: 'Content',
|
||||
mixins: [FullScreenModal],
|
||||
props: {
|
||||
hash: String,
|
||||
isActive: Boolean
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
opened: null,
|
||||
selected: [],
|
||||
treeData: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
fileTree() {
|
||||
if (this.treeData) {
|
||||
return treeify(this.treeData)
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
isActive(active) {
|
||||
if (active) {
|
||||
this.getTorrentFiles()
|
||||
}
|
||||
},
|
||||
selected(newValue, oldValue) {
|
||||
this.changeFilePriorities(newValue, oldValue)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getTorrentFiles().then(() => {
|
||||
this.opened = []
|
||||
.concat(
|
||||
...this.treeData
|
||||
.map(file => file.name.split('/'))
|
||||
.filter(f => f.splice(-1, 1))
|
||||
)
|
||||
.filter((f, index, self) => index === self.indexOf(f))
|
||||
this.selected = this.treeData
|
||||
.filter(file => file.priority !== 0)
|
||||
.map(file => file.name)
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
async getTorrentFiles() {
|
||||
const { data } = await qbit.getTorrentFiles(this.hash)
|
||||
data.forEach((d, i) => {
|
||||
d.id = i
|
||||
d.name = d.name.replace('.unwanted/', '')
|
||||
})
|
||||
this.treeData = data
|
||||
},
|
||||
async changeFilePriorities(newValue, oldValue) {
|
||||
if (newValue.length == oldValue.length) return
|
||||
|
||||
const filesToExclude = oldValue
|
||||
.filter(f => !newValue.includes(f))
|
||||
.map(name => this.treeData.find(f => f.name === name))
|
||||
.filter(f => f.priority !== 0)
|
||||
.map(f => f.id)
|
||||
const filesToInclude = newValue
|
||||
.filter(f => !oldValue.includes(f))
|
||||
.map(name => this.treeData.find(f => f.name === name))
|
||||
.filter(f => f.priority === 0)
|
||||
.map(f => f.id)
|
||||
|
||||
if (filesToExclude.length) {
|
||||
await qbit.setTorrentFilePriority(this.hash, filesToExclude, 0)
|
||||
}
|
||||
if (filesToInclude.length) {
|
||||
await qbit.setTorrentFilePriority(this.hash, filesToInclude, 1)
|
||||
}
|
||||
if (filesToExclude.length || filesToInclude.length) {
|
||||
await this.getTorrentFiles()
|
||||
}
|
||||
},
|
||||
togleEditing(item) {
|
||||
item.editing = !item.editing
|
||||
},
|
||||
edit(item) {
|
||||
item.newName = item.name
|
||||
this.togleEditing(item)
|
||||
},
|
||||
renameFile(item) {
|
||||
qbit.renameFile(this.hash, item.id, item.newName)
|
||||
item.name = item.newName
|
||||
this.togleEditing(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -8,104 +8,137 @@
|
|||
<v-simple-table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="grey--text">Torrent title</td>
|
||||
<td class="grey--text">
|
||||
Torrent title
|
||||
</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.name }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Directory</td>
|
||||
<td class="grey--text">
|
||||
Directory
|
||||
</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.savePath }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="margin-top: 10px !important">
|
||||
<td class="grey--text">hash</td>
|
||||
<td class="grey--text">
|
||||
hash
|
||||
</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.hash }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Size</td>
|
||||
<td class="grey--text">
|
||||
Size
|
||||
</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.size }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Done:</td>
|
||||
<td class="grey--text">
|
||||
Done:
|
||||
</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.dloaded }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Uploaded:</td>
|
||||
<td class="grey--text">
|
||||
Uploaded:
|
||||
</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.uploaded }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Ratio</td>
|
||||
<td class="grey--text">
|
||||
Ratio
|
||||
</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.ratio }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Download Speed</td>
|
||||
<td class="grey--text">
|
||||
Download Speed
|
||||
</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.dlspeed }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Upload Speed</td>
|
||||
<td class="grey--text">
|
||||
Upload Speed
|
||||
</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.upspeed }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">ETA</td>
|
||||
<td class="grey--text">
|
||||
ETA
|
||||
</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.eta }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Peers</td>
|
||||
<td class="grey--text">
|
||||
Peers
|
||||
</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.num_leechs
|
||||
}}<span class="grey--text">/{{ torrent.available_peers }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Seeds</td>
|
||||
<td class="grey--text">
|
||||
Seeds
|
||||
</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.num_seeds
|
||||
}}<span class="grey--text">/{{ torrent.available_seeds }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Added on</td>
|
||||
<td class="grey--text">
|
||||
Added on
|
||||
</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.added_on }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="torrent.tracker">
|
||||
<td class="grey--text">Tracker</td>
|
||||
<td class="grey--text">
|
||||
Tracker
|
||||
</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.tracker }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="torrent.comment">
|
||||
<td class="grey--text">Comment</td>
|
||||
<td class="grey--text">
|
||||
Comment
|
||||
</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.comment }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Status</td>
|
||||
<td class="grey--text">
|
||||
Status
|
||||
</td>
|
||||
<v-chip
|
||||
small
|
||||
:class="`${torrent.state.toLowerCase()} white--text my-2 caption`"
|
||||
>{{ torrent.state }}</v-chip
|
||||
>
|
||||
{{ torrent.state }}
|
||||
</v-chip>
|
||||
</tr>
|
||||
</tbody>
|
||||
</v-simple-table>
|
||||
|
@ -118,17 +151,17 @@
|
|||
import { mapGetters } from 'vuex'
|
||||
import { FullScreenModal } from '@/mixins'
|
||||
export default {
|
||||
name: 'Info',
|
||||
mixins: [FullScreenModal],
|
||||
props: {
|
||||
hash: String
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['getTorrent']),
|
||||
torrent() {
|
||||
return this.getTorrent(this.hash)
|
||||
}
|
||||
name: 'Info',
|
||||
mixins: [FullScreenModal],
|
||||
props: {
|
||||
hash: String
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['getTorrent']),
|
||||
torrent() {
|
||||
return this.getTorrent(this.hash)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
:hide-default-footer="true"
|
||||
:style="{ minHeight: phoneLayout ? '' : '75vh', maxHeight: '75vh'}"
|
||||
>
|
||||
<template v-slot:item="row">
|
||||
<template #item="row">
|
||||
<tr>
|
||||
<td class="ip">
|
||||
<template v-if="row.item.country_code">
|
||||
|
@ -18,16 +18,20 @@
|
|||
:title="row.item.country"
|
||||
:alt="codeToFlag(row.item.country_code).char"
|
||||
:src="codeToFlag(row.item.country_code).url"
|
||||
/>
|
||||
<template v-else>{{
|
||||
codeToFlag(row.item.country_code).char
|
||||
}}</template>
|
||||
>
|
||||
<template v-else>
|
||||
{{
|
||||
codeToFlag(row.item.country_code).char
|
||||
}}
|
||||
</template>
|
||||
</template>
|
||||
{{ row.item.ip }}
|
||||
<span class="grey--text">:{{ row.item.port }}</span>
|
||||
</td>
|
||||
<td>{{ row.item.connection }}</td>
|
||||
<td :title="row.item.flags_desc">{{ row.item.flags }}</td>
|
||||
<td :title="row.item.flags_desc">
|
||||
{{ row.item.flags }}
|
||||
</td>
|
||||
<td>{{ row.item.client }}</td>
|
||||
<td>{{ row.item.progress | progress }}</td>
|
||||
<td>{{ row.item.dl_speed | networkSpeed }}</td>
|
||||
|
@ -48,66 +52,66 @@ import qbit from '@/services/qbit'
|
|||
import { codeToFlag, isWindows } from '@/helpers'
|
||||
import { FullScreenModal } from '@/mixins'
|
||||
export default {
|
||||
name: 'Peers',
|
||||
mixins: [FullScreenModal],
|
||||
props: { hash: String, isActive: Boolean },
|
||||
data: () => ({
|
||||
headers: [
|
||||
{ text: 'IP', value: 'ip' },
|
||||
{ text: 'Connection', value: 'connection' },
|
||||
{ text: 'Flags', value: 'flags' },
|
||||
{ text: 'Client', value: 'client' },
|
||||
{ text: 'Progress', value: 'progress' },
|
||||
{ text: 'DL Speed', value: 'dl_speed' },
|
||||
{ text: 'Downloaded', value: 'downloaded' },
|
||||
{ text: 'UP Speed', value: 'up_speed' },
|
||||
{ text: 'Uploaded', value: 'uploaded' },
|
||||
{ text: 'Relevance', value: 'relevance' },
|
||||
{ text: 'Files', value: 'files' }
|
||||
],
|
||||
peersObj: null
|
||||
}),
|
||||
methods: {
|
||||
codeToFlag(val) {
|
||||
return codeToFlag(val)
|
||||
},
|
||||
isWindows() {
|
||||
return isWindows()
|
||||
},
|
||||
async getTorrentPeers() {
|
||||
const { data } = await qbit.getTorrentPeers(
|
||||
this.hash,
|
||||
this.rid + 1 || undefined
|
||||
)
|
||||
|
||||
this.rid = data.rid
|
||||
|
||||
this.peersObj = data.peers
|
||||
}
|
||||
name: 'Peers',
|
||||
mixins: [FullScreenModal],
|
||||
props: { hash: String, isActive: Boolean },
|
||||
data: () => ({
|
||||
headers: [
|
||||
{ text: 'IP', value: 'ip' },
|
||||
{ text: 'Connection', value: 'connection' },
|
||||
{ text: 'Flags', value: 'flags' },
|
||||
{ text: 'Client', value: 'client' },
|
||||
{ text: 'Progress', value: 'progress' },
|
||||
{ text: 'DL Speed', value: 'dl_speed' },
|
||||
{ text: 'Downloaded', value: 'downloaded' },
|
||||
{ text: 'UP Speed', value: 'up_speed' },
|
||||
{ text: 'Uploaded', value: 'uploaded' },
|
||||
{ text: 'Relevance', value: 'relevance' },
|
||||
{ text: 'Files', value: 'files' }
|
||||
],
|
||||
peersObj: null
|
||||
}),
|
||||
computed: {
|
||||
rid: {
|
||||
get() {
|
||||
return this.$store.state.rid
|
||||
},
|
||||
set(val) {
|
||||
this.$store.state.rid = val
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
isActive(active) {
|
||||
if (active) {
|
||||
this.getTorrentPeers()
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
rid: {
|
||||
get() {
|
||||
return this.$store.state.rid
|
||||
},
|
||||
set(val) {
|
||||
this.$store.state.rid = val
|
||||
}
|
||||
},
|
||||
peers() {
|
||||
return map(this.peersObj, (value, key) => merge({}, value, { key }))
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getTorrentPeers()
|
||||
peers() {
|
||||
return map(this.peersObj, (value, key) => merge({}, value, { key }))
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
isActive(active) {
|
||||
if (active) {
|
||||
this.getTorrentPeers()
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getTorrentPeers()
|
||||
},
|
||||
methods: {
|
||||
codeToFlag(val) {
|
||||
return codeToFlag(val)
|
||||
},
|
||||
isWindows() {
|
||||
return isWindows()
|
||||
},
|
||||
async getTorrentPeers() {
|
||||
const { data } = await qbit.getTorrentPeers(
|
||||
this.hash,
|
||||
this.rid + 1 || undefined
|
||||
)
|
||||
|
||||
this.rid = data.rid
|
||||
|
||||
this.peersObj = data.peers
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -6,7 +6,12 @@
|
|||
:style="{ minHeight: phoneLayout ? '' : '75vh'}"
|
||||
>
|
||||
<v-row>
|
||||
<v-col :cols="12" :lg="6" :md="6" :sm="12">
|
||||
<v-col
|
||||
:cols="12"
|
||||
:lg="6"
|
||||
:md="6"
|
||||
:sm="12"
|
||||
>
|
||||
<v-layout class="mx-auto" row wrap>
|
||||
<v-flex xs12 sm12>
|
||||
<h3>Available Tags:</h3>
|
||||
|
@ -39,14 +44,22 @@
|
|||
style="font-size: 0.95em !important"
|
||||
@click="deleteTag(tag)"
|
||||
@click:close="deleteTag(tag)"
|
||||
>{{ tag }}</v-chip
|
||||
>
|
||||
{{ tag }}
|
||||
</v-chip>
|
||||
</div>
|
||||
<div v-else>
|
||||
None
|
||||
</div>
|
||||
<div v-else>None</div>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-col>
|
||||
<v-col :cols="12" :lg="6" :md="6" :sm="12">
|
||||
<v-col
|
||||
:cols="12"
|
||||
:lg="6"
|
||||
:md="6"
|
||||
:sm="12"
|
||||
>
|
||||
<v-layout
|
||||
class="mx-auto"
|
||||
:class="this.$vuetify.breakpoint.smAndDown ? 'mt-12' : ''"
|
||||
|
@ -82,9 +95,12 @@
|
|||
style="font-size: 0.95em !important"
|
||||
@click="deleteCategory"
|
||||
@click:close="deleteCategory"
|
||||
>{{ torrent.category }}</v-chip
|
||||
>
|
||||
<div v-else>None</div>
|
||||
{{ torrent.category }}
|
||||
</v-chip>
|
||||
<div v-else>
|
||||
None
|
||||
</div>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-col>
|
||||
|
@ -100,45 +116,46 @@ import qbit from '@/services/qbit'
|
|||
import { FullScreenModal } from '@/mixins'
|
||||
|
||||
export default {
|
||||
name: 'TorrentTagsAndCategories',
|
||||
props: {
|
||||
hash: String
|
||||
name: 'TorrentTagsAndCategories',
|
||||
mixins: [FullScreenModal],
|
||||
props: {
|
||||
hash: String
|
||||
},
|
||||
data: () => ({
|
||||
categories: []
|
||||
}),
|
||||
computed: {
|
||||
...mapGetters(['getTorrent', 'getAvailableTags', 'getCategories']),
|
||||
torrent() {
|
||||
return this.getTorrent(this.hash)
|
||||
},
|
||||
mixins: [FullScreenModal],
|
||||
data: () => ({
|
||||
categories: []
|
||||
}),
|
||||
computed: {
|
||||
...mapGetters(['getTorrent', 'getAvailableTags', 'getCategories']),
|
||||
torrent() {
|
||||
return this.getTorrent(this.hash)
|
||||
},
|
||||
availableTags() {
|
||||
const availableTags = this.getAvailableTags()
|
||||
const currentTags = this.getTorrent(this.hash).tags
|
||||
return difference(availableTags, currentTags)
|
||||
},
|
||||
availableCategories() {
|
||||
return this.getCategories()
|
||||
}
|
||||
availableTags() {
|
||||
const availableTags = this.getAvailableTags()
|
||||
const currentTags = this.getTorrent(this.hash).tags
|
||||
|
||||
return difference(availableTags, currentTags)
|
||||
},
|
||||
methods: {
|
||||
addTag(tag) {
|
||||
qbit.addTorrentTag(this.hash, tag)
|
||||
},
|
||||
deleteTag(tag) {
|
||||
qbit.removeTorrentTag(this.hash, tag)
|
||||
},
|
||||
setCategory(cat) {
|
||||
qbit.setCategory(this.hash, cat)
|
||||
},
|
||||
deleteCategory() {
|
||||
qbit.setCategory(this.hash, '')
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$store.commit('FETCH_CATEGORIES')
|
||||
availableCategories() {
|
||||
return this.getCategories()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$store.commit('FETCH_CATEGORIES')
|
||||
},
|
||||
methods: {
|
||||
addTag(tag) {
|
||||
qbit.addTorrentTag(this.hash, tag)
|
||||
},
|
||||
deleteTag(tag) {
|
||||
qbit.removeTorrentTag(this.hash, tag)
|
||||
},
|
||||
setCategory(cat) {
|
||||
qbit.setCategory(this.hash, cat)
|
||||
},
|
||||
deleteCategory() {
|
||||
qbit.setCategory(this.hash, '')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
:hide-default-footer="true"
|
||||
:style="{ minHeight: phoneLayout ? '' : '75vh', maxHeight: '75vh'}"
|
||||
>
|
||||
<template v-slot:item="row">
|
||||
<template #item="row">
|
||||
<tr>
|
||||
<td>{{ row.item.tier }}</td>
|
||||
<td>{{ row.item.url }}</td>
|
||||
|
@ -27,63 +27,63 @@
|
|||
import qbit from '@/services/qbit'
|
||||
import { FullScreenModal } from '@/mixins'
|
||||
export default {
|
||||
name: 'Trackers',
|
||||
mixins: [FullScreenModal],
|
||||
props: { hash: String, isActive: Boolean },
|
||||
data: () => ({
|
||||
headers: [
|
||||
{ text: '#', value: 'tier' },
|
||||
{ text: 'URL', value: 'url' },
|
||||
{ text: 'Status', value: 'status' },
|
||||
{ text: 'Peers', value: 'num_peers' },
|
||||
{ text: 'Seeds', value: 'num_seeds' },
|
||||
{ text: 'Leeches', value: 'num_leeches' },
|
||||
{ text: 'Downloaded', value: 'num_downloaded' },
|
||||
{ text: 'Message', value: 'msg' }
|
||||
],
|
||||
tempTrackers: []
|
||||
}),
|
||||
methods: {
|
||||
async getTorrentTrackers() {
|
||||
const { data } = await qbit.getTorrentTrackers(this.hash)
|
||||
this.tempTrackers = data
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
isActive(active) {
|
||||
if (active) {
|
||||
this.getTorrentTrackers()
|
||||
}
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
formatTrackerStatus(status) {
|
||||
const map = [
|
||||
'Disabled',
|
||||
'Not contacted',
|
||||
'Working',
|
||||
'Updating',
|
||||
'Not working'
|
||||
]
|
||||
name: 'Trackers',
|
||||
filters: {
|
||||
formatTrackerStatus(status) {
|
||||
const map = [
|
||||
'Disabled',
|
||||
'Not contacted',
|
||||
'Working',
|
||||
'Updating',
|
||||
'Not working'
|
||||
]
|
||||
|
||||
return map[status]
|
||||
},
|
||||
formatTrackerNum(num) {
|
||||
if (num === -1) {
|
||||
return 'N/A'
|
||||
}
|
||||
return map[status]
|
||||
},
|
||||
formatTrackerNum(num) {
|
||||
if (num === -1) {
|
||||
return 'N/A'
|
||||
}
|
||||
|
||||
return num.toString()
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
trackers() {
|
||||
return this.tempTrackers
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getTorrentTrackers()
|
||||
return num.toString()
|
||||
}
|
||||
},
|
||||
mixins: [FullScreenModal],
|
||||
props: { hash: String, isActive: Boolean },
|
||||
data: () => ({
|
||||
headers: [
|
||||
{ text: '#', value: 'tier' },
|
||||
{ text: 'URL', value: 'url' },
|
||||
{ text: 'Status', value: 'status' },
|
||||
{ text: 'Peers', value: 'num_peers' },
|
||||
{ text: 'Seeds', value: 'num_seeds' },
|
||||
{ text: 'Leeches', value: 'num_leeches' },
|
||||
{ text: 'Downloaded', value: 'num_downloaded' },
|
||||
{ text: 'Message', value: 'msg' }
|
||||
],
|
||||
tempTrackers: []
|
||||
}),
|
||||
computed: {
|
||||
trackers() {
|
||||
return this.tempTrackers
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
isActive(active) {
|
||||
if (active) {
|
||||
this.getTorrentTrackers()
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getTorrentTrackers()
|
||||
},
|
||||
methods: {
|
||||
async getTorrentTrackers() {
|
||||
const { data } = await qbit.getTorrentTrackers(this.hash)
|
||||
this.tempTrackers = data
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,59 +1,83 @@
|
|||
<template>
|
||||
<v-dialog
|
||||
v-model="dialog"
|
||||
scrollable
|
||||
:width="dialogWidth"
|
||||
:fullscreen="phoneLayout"
|
||||
<v-dialog
|
||||
v-model="dialog"
|
||||
scrollable
|
||||
:width="dialogWidth"
|
||||
:fullscreen="phoneLayout"
|
||||
>
|
||||
<v-card
|
||||
v-if="torrent"
|
||||
style="min-height: 400px; overflow: hidden !important"
|
||||
>
|
||||
<v-card
|
||||
v-if="torrent"
|
||||
style="min-height: 400px; overflow: hidden !important"
|
||||
<div
|
||||
:class="`pa-0 project ${torrent.state}`"
|
||||
:style="{ height: phoneLayout ? '100vh' : '' }"
|
||||
>
|
||||
<v-card-title class="pb-0 justify-center primary">
|
||||
<h2 class="white--text">
|
||||
Torrent Detail
|
||||
</h2>
|
||||
</v-card-title>
|
||||
<v-tabs
|
||||
v-model="tab"
|
||||
background-color="primary"
|
||||
dark
|
||||
fixed-tabs
|
||||
>
|
||||
<div
|
||||
:class="`pa-0 project ${torrent.state}`"
|
||||
:style="{ height: phoneLayout ? '100vh' : '' }"
|
||||
>
|
||||
<v-card-title class="pb-0 justify-center primary">
|
||||
<h2 class="white--text">Torrent Detail</h2>
|
||||
</v-card-title>
|
||||
<v-tabs v-model="tab" background-color="primary" dark fixed-tabs>
|
||||
<v-tab href="#info">Info</v-tab>
|
||||
<v-tab href="#trackers">Trackers</v-tab>
|
||||
<v-tab href="#peers">Peers</v-tab>
|
||||
<v-tab href="#content">Content</v-tab>
|
||||
<v-tab href="#tagsAndCategories">Tags & Categories</v-tab>
|
||||
</v-tabs>
|
||||
<v-tabs-items v-model="tab" :touch="updateTab(tab)">
|
||||
<v-tab-item value="info">
|
||||
<info :is-active="tab === 'info'" :hash="hash" />
|
||||
</v-tab-item>
|
||||
<v-tab-item value="trackers">
|
||||
<Trackers
|
||||
:is-active="tab === 'trackers'"
|
||||
:hash="hash"
|
||||
/>
|
||||
</v-tab-item>
|
||||
<v-tab-item value="peers">
|
||||
<Peers :is-active="tab === 'peers'" :hash="hash" />
|
||||
</v-tab-item>
|
||||
<v-tab-item value="content">
|
||||
<Content :is-active="tab === 'content'" :hash="hash" />
|
||||
</v-tab-item>
|
||||
<v-tab-item value="tagsAndCategories">
|
||||
<TagsAndCategories
|
||||
:is-active="tab === 'tagsAndCategories'"
|
||||
:hash="hash"
|
||||
/>
|
||||
</v-tab-item>
|
||||
</v-tabs-items>
|
||||
</div>
|
||||
<v-fab-transition v-if="phoneLayout">
|
||||
<v-btn @click="close" color="red" dark absolute bottom right>
|
||||
<v-icon>close</v-icon>
|
||||
</v-btn>
|
||||
</v-fab-transition>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
<v-tab href="#info">
|
||||
Info
|
||||
</v-tab>
|
||||
<v-tab href="#trackers">
|
||||
Trackers
|
||||
</v-tab>
|
||||
<v-tab href="#peers">
|
||||
Peers
|
||||
</v-tab>
|
||||
<v-tab href="#content">
|
||||
Content
|
||||
</v-tab>
|
||||
<v-tab href="#tagsAndCategories">
|
||||
Tags & Categories
|
||||
</v-tab>
|
||||
</v-tabs>
|
||||
<v-tabs-items v-model="tab" :touch="updateTab(tab)">
|
||||
<v-tab-item value="info">
|
||||
<info :is-active="tab === 'info'" :hash="hash" />
|
||||
</v-tab-item>
|
||||
<v-tab-item value="trackers">
|
||||
<Trackers
|
||||
:is-active="tab === 'trackers'"
|
||||
:hash="hash"
|
||||
/>
|
||||
</v-tab-item>
|
||||
<v-tab-item value="peers">
|
||||
<Peers :is-active="tab === 'peers'" :hash="hash" />
|
||||
</v-tab-item>
|
||||
<v-tab-item value="content">
|
||||
<Content :is-active="tab === 'content'" :hash="hash" />
|
||||
</v-tab-item>
|
||||
<v-tab-item value="tagsAndCategories">
|
||||
<TagsAndCategories
|
||||
:is-active="tab === 'tagsAndCategories'"
|
||||
:hash="hash"
|
||||
/>
|
||||
</v-tab-item>
|
||||
</v-tabs-items>
|
||||
</div>
|
||||
<v-fab-transition v-if="phoneLayout">
|
||||
<v-btn
|
||||
color="red"
|
||||
dark
|
||||
absolute
|
||||
bottom
|
||||
right
|
||||
@click="close"
|
||||
>
|
||||
<v-icon>close</v-icon>
|
||||
</v-btn>
|
||||
</v-fab-transition>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -63,29 +87,29 @@ import { Modal, FullScreenModal } from '@/mixins'
|
|||
import { Content, Info, Peers, Trackers, TagsAndCategories } from './Tabs'
|
||||
|
||||
export default {
|
||||
name: 'TorrentDetailModal',
|
||||
mixins: [Modal, FullScreenModal],
|
||||
components: { Content, Info, Peers, Trackers, TagsAndCategories },
|
||||
props: {
|
||||
hash: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tab: null,
|
||||
items: [{ tab: 'Info' }, { tab: 'Content' }],
|
||||
peers: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.deleteModal()
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['getTorrent']),
|
||||
torrent() {
|
||||
return this.getTorrent(this.hash)
|
||||
}
|
||||
name: 'TorrentDetailModal',
|
||||
components: { Content, Info, Peers, Trackers, TagsAndCategories },
|
||||
mixins: [Modal, FullScreenModal],
|
||||
props: {
|
||||
hash: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tab: null,
|
||||
items: [{ tab: 'Info' }, { tab: 'Content' }],
|
||||
peers: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['getTorrent']),
|
||||
torrent() {
|
||||
return this.getTorrent(this.hash)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.deleteModal()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue