Moved eslint to lint

This commit is contained in:
Kylart 2018-07-20 20:11:46 +02:00
parent fadb588e62
commit b04a502471
28 changed files with 1943 additions and 1933 deletions

9
.eslintrc.js Normal file
View File

@ -0,0 +1,9 @@
module.exports = {
extends: [
'standard',
'plugin:vue/essential'
],
parserOptions: {
ecmaVersion: 2017
}
};

View File

@ -80,127 +80,127 @@
</template>
<script>
import Meta from 'mixins/global/meta'
import ReadMagnet from 'mixins/global/readMagnet'
import DragDrop from 'mixins/global/dragDrop'
import Meta from 'mixins/global/meta'
import ReadMagnet from 'mixins/global/readMagnet'
import DragDrop from 'mixins/global/dragDrop'
export default {
mixins: [Meta, ReadMagnet, DragDrop],
mounted () {
this.isBrowser = !window.navigator.appVersion.includes('Electron')
export default {
mixins: [Meta, ReadMagnet, DragDrop],
mounted () {
this.isBrowser = !window.navigator.appVersion.includes('Electron')
this.$nextTick(() => {
if (process.env.NODE_ENV === 'development') {
const devtools = document.createElement('script')
devtools.src = 'http://localhost:8098'
this.$nextTick(() => {
if (process.env.NODE_ENV === 'development') {
const devtools = document.createElement('script')
devtools.src = 'http://localhost:8098'
document.body.appendChild(devtools)
document.body.appendChild(devtools)
}
})
},
data () {
return {
searchModal: false,
drawer: false,
isBrowser: false,
itemGroup: [
{divider: true},
{header: 'Core'},
{
title: 'Downloading',
action: 'file_download',
group: 'core',
items: [
{
title: 'Downloader',
action: 'file_download',
href: '/downloader'
}, {
title: 'Latest releases',
action: 'access_time',
href: '/'
}
]
}, {
title: 'Torrent',
action: 'folder_open',
group: 'torrent',
items: [
// {
// title: 'Torrenting',
// action: 'file_upload',
// href: '/torrenting'
// },
{
title: 'Streaming',
action: 'tv',
href: '/streaming'
}
]
},
{divider: true},
{header: 'Anime world'},
{
title: 'News',
action: 'info_outline',
group: 'news',
items: [
{
title: 'Seasons',
action: 'hourglass_empty',
href: '/seasons'
},
{
title: 'News',
action: 'more',
href: '/news'
}
]
},
{divider: true},
{header: 'Local'},
{
title: 'Anime related',
action: 'folder_open',
group: 'local',
items: [
{
title: 'Animes',
action: 'tv',
href: '/localPage'
}, {
title: 'Watch list',
action: 'sort_by_alpha',
href: '/watchList'
}, {
title: 'MyAnimeList',
action: 'web',
href: '/malPage'
}
]
}
]
}
},
methods: {
toggleDrawer () {
this.$store.commit('toggleDrawer')
},
actOnWindow (action) {
this.$axios.get('/_win', {
params: {
action
}
})
},
data () {
return {
searchModal: false,
drawer: false,
isBrowser: false,
itemGroup: [
{divider: true},
{header: 'Core'},
{
title: 'Downloading',
action: 'file_download',
group: 'core',
items: [
{
title: 'Downloader',
action: 'file_download',
href: '/downloader'
}, {
title: 'Latest releases',
action: 'access_time',
href: '/'
}
]
}, {
title: 'Torrent',
action: 'folder_open',
group: 'torrent',
items: [
// {
// title: 'Torrenting',
// action: 'file_upload',
// href: '/torrenting'
// },
{
title: 'Streaming',
action: 'tv',
href: '/streaming'
}
]
},
{divider: true},
{header: 'Anime world'},
{
title: 'News',
action: 'info_outline',
group: 'news',
items: [
{
title: 'Seasons',
action: 'hourglass_empty',
href: '/seasons'
},
{
title: 'News',
action: 'more',
href: '/news'
}
]
},
{divider: true},
{header: 'Local'},
{
title: 'Anime related',
action: 'folder_open',
group: 'local',
items: [
{
title: 'Animes',
action: 'tv',
href: '/localPage'
}, {
title: 'Watch list',
action: 'sort_by_alpha',
href: '/watchList'
}, {
title: 'MyAnimeList',
action: 'web',
href: '/malPage'
}
]
}
]
}
openInBrowser () {
this.$store.dispatch('openInBrowser')
},
methods: {
toggleDrawer () {
this.$store.commit('toggleDrawer')
},
actOnWindow (action) {
this.$axios.get('/_win', {
params: {
action
}
})
},
openInBrowser () {
this.$store.dispatch('openInBrowser')
},
restartAndUpdate () {
this.$store.dispatch('update/updateApp')
}
restartAndUpdate () {
this.$store.dispatch('update/updateApp')
}
}
}
</script>
<style lang="stylus" scoped>

14
assets/improvements.todo Normal file
View File

@ -0,0 +1,14 @@
✔ Finish info modal design @done (8/16/2017, 6:48:22 PM)
✔ Implement auto-update on start and every hour @done (9/3/2017, 4:02:49 PM)
✔ Separate Store modules @done (2017-9-20 11:20:12)
✔ Use Pug for all templates @done (8/14/2017, 6:58:43 PM)
✔ Implement sound on notification @done (8/14/2017, 10:28:04 PM)
✔ Open in browser not working on Linux and Windows @done (9/4/2017, 11:37:15 PM)
✔ Responsive (large screen) season page @done (9/4/2017, 11:43:47 PM)
✔ Message on empty history @done (9/4/2017, 11:49:25 PM)
✔ Can't minimize when maximized on windows and Linux @done (9/4/2017, 11:53:52 PM)
✔ Inside news open several times @done (9/6/2017, 10:30:00 PM)
✘ Fallback folder if default local folder was deleted @cancelled (2018-5-20 19:35:38)
✔ Downloader broken with Erai-raws. Some improvements are needed with this sub @done (2018-5-20 19:35:19)
✔ Don't show the downloader modal if there is no magnet to show @done (2017-9-25 10:53:14)
✔ Save the release entries to put it back if an error occurs on refresh (#27) @done (2018-5-20 19:35:16)

View File

@ -14,3 +14,4 @@ export { default as VideoModal } from './videoModal.vue'
export { default as VideoPlayer } from './videoPlayer.vue'
export { default as PlayerSlider } from './playerSlider.vue'
export { default as Overlay } from './overlay.vue'
export { default as ListEntry } from './listEntry.vue'

View File

@ -26,57 +26,57 @@
</template>
<script>
export default {
data () {
return {
selected: [],
options: [{
label: 'Watch list',
value: 'watchList'
}, {
label: 'Watching',
value: 'watching'
}, {
label: 'Seen',
value: 'seen'
}, {
label: 'On Hold',
value: 'onHold'
}, {
label: 'Dropped',
value: 'dropped'
}]
}
export default {
data () {
return {
selected: [],
options: [{
label: 'Watch list',
value: 'watchList'
}, {
label: 'Watching',
value: 'watching'
}, {
label: 'Seen',
value: 'seen'
}, {
label: 'On Hold',
value: 'onHold'
}, {
label: 'Dropped',
value: 'dropped'
}]
}
},
methods: {
hide () {
this.$store.commit('setAddToChoice', false)
},
methods: {
hide () {
this.$store.commit('setAddToChoice', false)
},
add () {
this.selected.forEach((listName) => {
this.$store.dispatch('watchLists/updateList', {
listName,
entry: this.title
})
add () {
this.selected.forEach((listName) => {
this.$store.dispatch('watchLists/updateList', {
listName,
entry: this.title
})
})
this.hide()
this.hide()
}
},
computed: {
show: {
get () {
return this.$store.state.addToChoice.show
},
set (bool) {
this.$store.commit('setAddToChoice', bool)
}
},
computed: {
show: {
get () {
return this.$store.state.addToChoice.show
},
set (bool) {
this.$store.commit('setAddToChoice', bool)
}
},
title () {
return this.$store.state.addToChoice.title
}
title () {
return this.$store.state.addToChoice.title
}
}
}
</script>
<style lang="stylus" scoped>

View File

@ -43,88 +43,88 @@
</template>
<script>
export default {
mounted () {
export default {
mounted () {
this.generateHistory()
},
data () {
return {
nbElems: 30,
elems: {}
}
},
computed: {
history () {
return this.$store.state.history.entries
},
modal: {
get () {
return this.$store.state.history.modal
},
set (bool) {
this.$store.commit('history/setModal', bool)
}
}
},
methods: {
handleScroll () {
const elem = document.getElementsByClassName('dialog--active')[0]
const modalHeight = elem.clientHeight
const cardHeight = document.querySelector('.dialog--active .card').clientHeight
const scroll = elem.scrollTop
const maxScroll = cardHeight - modalHeight
const scrollPercent = scroll / maxScroll
if (scrollPercent > 0.65) {
this.nbElems += 5
this.generateHistory()
}
},
isDelete (type) {
return type === 'Delete'
? 'delete'
: 'not-delete'
},
clearEntry (info, item) {
this.$store.dispatch('history/remove', {
date: item,
info
})
},
async refresh () {
await this.$store.dispatch('history/get')
this.generateHistory()
},
data () {
return {
nbElems: 30,
elems: {}
}
close () {
this.$store.commit('history/setModal', false)
},
computed: {
history () {
return this.$store.state.history.entries
},
modal: {
get () {
return this.$store.state.history.modal
},
set (bool) {
this.$store.commit('history/setModal', bool)
}
generateHistory () {
// This is still improvable
const keys = this.$_.keys(this.history).reverse()
this.elems = {}
for (let i = 0, l = this.nbElems; i < l; ++i) {
this.elems[keys[i]] = this.history[keys[i]]
}
},
methods: {
handleScroll () {
const elem = document.getElementsByClassName('dialog--active')[0]
const modalHeight = elem.clientHeight
const cardHeight = document.querySelector('.dialog--active .card').clientHeight
const scroll = elem.scrollTop
const maxScroll = cardHeight - modalHeight
const scrollPercent = scroll / maxScroll
if (scrollPercent > 0.65) {
this.nbElems += 5
this.generateHistory()
}
},
isDelete (type) {
return type === 'Delete'
? 'delete'
: 'not-delete'
},
clearEntry (info, item) {
this.$store.dispatch('history/remove', {
date: item,
info
})
},
async refresh () {
await this.$store.dispatch('history/get')
this.generateHistory()
},
close () {
this.$store.commit('history/setModal', false)
},
generateHistory () {
// This is still improvable
const keys = this.$_.keys(this.history).reverse()
this.elems = {}
for (let i = 0, l = this.nbElems; i < l; ++i) {
this.elems[keys[i]] = this.history[keys[i]]
}
}
},
watch: {
modal (bool) {
if (bool) {
this.$nextTick(() => {
this.elem = document.getElementsByClassName('dialog--active')[0]
this.elem.addEventListener('scroll', this.handleScroll)
})
} else {
}
},
watch: {
modal (bool) {
if (bool) {
this.$nextTick(() => {
this.elem = document.getElementsByClassName('dialog--active')[0]
this.elem.removeEventListener('scroll', this.handleScroll)
}
this.elem.addEventListener('scroll', this.handleScroll)
})
} else {
this.elem = document.getElementsByClassName('dialog--active')[0]
this.elem.removeEventListener('scroll', this.handleScroll)
}
}
}
}
</script>
<style lang="stylus" scoped>

View File

@ -33,99 +33,99 @@
</template>
<script>
import _ from 'lodash'
import _ from 'lodash'
export default {
data () {
return {
searchTerm: '',
results: []
export default {
data () {
return {
searchTerm: '',
results: []
}
},
computed: {
show: {
get () {
return this.$store.state.search.search
},
set (bool) {
this.$store.commit('search/show', bool)
if (!bool) this.$store.commit('mal/isAdding', bool)
}
},
computed: {
show: {
get () {
return this.$store.state.search.search
},
set (bool) {
this.$store.commit('search/show', bool)
if (!bool) this.$store.commit('mal/isAdding', bool)
}
},
isSearch () {
return !this.$store.state.mal.isAdding
isSearch () {
return !this.$store.state.mal.isAdding
}
},
methods: {
close () {
this.$store.commit('search/show', false)
this.$store.commit('mal/isAdding', false)
},
clear () {
this.searchTerm = ''
this.$refs.input.focus()
},
actOnThis (item) {
if (this.isSearch) {
this.search(item)
} else {
this.close()
// This might change when I'll work with Kitsu etc...
// MAL specific
this.$store.commit('mal/setEntry', item)
this.$store.commit('mal/showForm', true)
}
},
methods: {
close () {
this.$store.commit('search/show', false)
this.$store.commit('mal/isAdding', false)
},
clear () {
this.searchTerm = ''
this.$refs.input.focus()
},
actOnThis (item) {
if (this.isSearch) {
this.search(item)
} else {
this.close()
// This might change when I'll work with Kitsu etc...
// MAL specific
this.$store.commit('mal/setEntry', item)
this.$store.commit('mal/showForm', true)
}
},
async search (item) {
this.searchTerm = item.name
async search (item) {
this.searchTerm = item.name
if (this.$store.state.search.info.info.title === item.name) {
this.$store.commit('search/showInfo', true)
this.close()
} else {
this.close()
if (this.$store.state.search.info.info.title === item.name) {
this.$store.commit('search/showInfo', true)
this.close()
} else {
this.close()
this.$store.dispatch('search/fromUrl', item)
}
},
quickSearch: _.debounce(
async function () {
const term = this.searchTerm
this.$store.dispatch('search/fromUrl', item)
}
},
quickSearch: _.debounce(
async function () {
const term = this.searchTerm
if (term && term.length > 2) {
try {
const {data, status} = await this.$axios.get(`searchTermOnMal`, {
params: {term}
})
if (term && term.length > 2) {
try {
const {data, status} = await this.$axios.get(`searchTermOnMal`, {
params: {term}
})
if (status === 200) {
this.results = data
} else {
throw new Error('Error while searching.')
}
} catch (e) {
console.log((new Date()).toLocaleTimeString(), e.message)
this.$store.commit('setInfoSnackbar', e.message)
if (status === 200) {
this.results = data
} else {
throw new Error('Error while searching.')
}
} else {
this.results = []
} catch (e) {
console.log((new Date()).toLocaleTimeString(), e.message)
this.$store.commit('setInfoSnackbar', e.message)
}
},
300)
},
watch: {
async searchTerm () {
this.quickSearch()
},
show (bool) {
if (bool) {
this.$nextTick(() => {
this.$refs.input.focus()
})
} else {
this.results = []
}
},
300)
},
watch: {
async searchTerm () {
this.quickSearch()
},
show (bool) {
if (bool) {
this.$nextTick(() => {
this.$refs.input.focus()
})
}
}
}
}
</script>
<style lang="stylus" scoped>

View File

@ -71,74 +71,74 @@
</template>
<script>
export default {
data () {
return {
fab: false,
lists: [
{text: 'Watch List', listName: 'watchList', action: 'watch_later'},
{text: 'Watching', listName: 'watching', action: 'tv'},
{text: 'Seen', listName: 'seen', action: 'done_all'},
{text: 'On Hold', listName: 'onHold', action: 'av_timer'},
{text: 'Dropped', listName: 'dropped', action: 'visibility_off'}
]
}
export default {
data () {
return {
fab: false,
lists: [
{text: 'Watch List', listName: 'watchList', action: 'watch_later'},
{text: 'Watching', listName: 'watching', action: 'tv'},
{text: 'Seen', listName: 'seen', action: 'done_all'},
{text: 'On Hold', listName: 'onHold', action: 'av_timer'},
{text: 'Dropped', listName: 'dropped', action: 'visibility_off'}
]
}
},
methods: {
addTo (listName) {
this.$store.dispatch('watchLists/updateList', {
listName,
entry: this.info.title
})
},
methods: {
addTo (listName) {
this.$store.dispatch('watchLists/updateList', {
listName,
entry: this.info.title
})
},
close () {
this.$store.commit('search/showInfo', false)
},
showMal () {
this.$store.commit('mal/setEntry', this.info)
this.close()
this.$store.commit('mal/showForm', true)
},
showChoices () {
this.close()
this.$store.commit('setAddToChoiceTitle', this.info.title)
this.$store.commit('setAddToChoice', true)
},
open () {
this.$axios.get('openThis', {
params: {
type: 'link',
link: this.url
}
})
},
log () {
this.$store.commit('setInfoSnackbar', `Link copied!`)
}
close () {
this.$store.commit('search/showInfo', false)
},
computed: {
info () {
return this.$store.state.search.info.info
},
error () {
return this.$store.state.search.info.error
},
loading () {
return this.$store.state.search.info.loading
},
searchTerm () {
return this.$store.state.search.info.term
},
episodeLabel () {
return this.info.episodes !== 1
? 'episodes'
: 'episode'
},
url () {
return `https://myanimelist.net/anime/${this.info.id}/${encodeURI(this.info.title)}`
}
showMal () {
this.$store.commit('mal/setEntry', this.info)
this.close()
this.$store.commit('mal/showForm', true)
},
showChoices () {
this.close()
this.$store.commit('setAddToChoiceTitle', this.info.title)
this.$store.commit('setAddToChoice', true)
},
open () {
this.$axios.get('openThis', {
params: {
type: 'link',
link: this.url
}
})
},
log () {
this.$store.commit('setInfoSnackbar', `Link copied!`)
}
},
computed: {
info () {
return this.$store.state.search.info.info
},
error () {
return this.$store.state.search.info.error
},
loading () {
return this.$store.state.search.info.loading
},
searchTerm () {
return this.$store.state.search.info.term
},
episodeLabel () {
return this.info.episodes !== 1
? 'episodes'
: 'episode'
},
url () {
return `https://myanimelist.net/anime/${this.info.id}/${encodeURI(this.info.title)}`
}
}
}
</script>
<style lang="stylus" scoped>

View File

@ -5,10 +5,9 @@
</template>
<script>
export default {
data: () => ({
lastYear: (new Date()).getFullYear()
})
}
export default {
data: () => ({
lastYear: (new Date()).getFullYear()
})
}
</script>

View File

@ -31,50 +31,50 @@
</template>
<script>
export default{
props: {
item: String,
deleteEntry: Function,
select: Function,
selected: Object,
index: Number
export default{
props: {
item: String,
deleteEntry: Function,
select: Function,
selected: Object,
index: Number
},
data () {
const vm = this
return {
buttons: [
{
action: 'file_download',
text: 'Download',
method: (item) => vm.download(item)
}, {
action: 'tv',
text: 'Watch',
method: (item) => vm.watch(item)
}, {
action: 'info_outline',
text: 'Information',
method: (item) => vm.$store.dispatch('search/fromName', item)
}, {
action: 'delete_sweep',
text: 'Delete this entry',
method: (item) => vm.deleteEntry(item, vm.index)
}
]
}
},
methods: {
download (name) {
this.$store.dispatch('downloader/download', {
name,
isDownloader: false
})
},
data () {
const vm = this
return {
buttons: [
{
action: 'file_download',
text: 'Download',
method: (item) => vm.download(item)
}, {
action: 'tv',
text: 'Watch',
method: (item) => vm.watch(item)
}, {
action: 'info_outline',
text: 'Information',
method: (item) => vm.$store.dispatch('search/fromName', item)
}, {
action: 'delete_sweep',
text: 'Delete this entry',
method: (item) => vm.deleteEntry(item, vm.index)
}
]
}
},
methods: {
download (name) {
this.$store.dispatch('downloader/download', {
name,
isDownloader: false
})
},
watch (name) {
this.$router.push({path: '/streaming', query: {name}})
}
watch (name) {
this.$router.push({path: '/streaming', query: {name}})
}
}
}
</script>
<style lang="stylus" scoped>
@ -106,4 +106,8 @@
.selected
background-color #2E7D32
.v-input
padding 0
margin 0
</style>

View File

@ -23,19 +23,19 @@
</style>
<script>
export default {
data () {
return {
number: this.ran()
}
},
methods: {
ran () {
return parseInt(Math.random() * 2 + 1)
}
},
beforeMount () {
this.number = this.ran()
export default {
data () {
return {
number: this.ran()
}
},
methods: {
ran () {
return parseInt(Math.random() * 2 + 1)
}
},
beforeMount () {
this.number = this.ran()
}
}
</script>

View File

@ -62,88 +62,88 @@
</template>
<script>
export default {
data () {
return {
snack: false,
selected: []
export default {
data () {
return {
snack: false,
selected: []
}
},
computed: {
values () {
return this.$store.state.downloader.modal
},
show () {
return this.values.show
},
eol () {
if (this.$store.state.platform === 'win32') {
return '\r\n'
} else {
return '\n'
}
},
computed: {
values () {
return this.$store.state.downloader.modal
},
show () {
return this.values.show
},
eol () {
if (this.$store.state.platform === 'win32') {
return '\r\n'
} else {
return '\n'
}
},
magnets () {
return this.values.magnets.map((magnet) => {
return magnet.link
})
},
filteredNames () {
return this.$_.uniq(this.values.magnets.map((magnet) => {
return magnet.name.split(' ').slice(1, -3).join(' ')
}))
}
magnets () {
return this.values.magnets.map((magnet) => {
return magnet.link
})
},
watch: {
show () {
this.show && this.$store.dispatch('player/play')
this.selected = this.magnets
}
filteredNames () {
return this.$_.uniq(this.values.magnets.map((magnet) => {
return magnet.name.split(' ').slice(1, -3).join(' ')
}))
}
},
watch: {
show () {
this.show && this.$store.dispatch('player/play')
this.selected = this.magnets
}
},
methods: {
close () {
this.$store.commit('downloader/closeModal')
},
methods: {
close () {
this.$store.commit('downloader/closeModal')
},
getLinks (name) {
return this.values.magnets.map((magnet) => {
if (magnet.name.includes(name)) return magnet
}).filter((e) => typeof e !== 'undefined' && e)
},
selectAll (name) {
// Find all magnets with that name
const magnets = this.$_.map(this.values.magnets, (e) => {
if (e.name.includes(name)) return e.link
}).filter((e) => typeof e !== 'undefined' && e)
getLinks (name) {
return this.values.magnets.map((magnet) => {
if (magnet.name.includes(name)) return magnet
}).filter((e) => typeof e !== 'undefined' && e)
},
selectAll (name) {
// Find all magnets with that name
const magnets = this.$_.map(this.values.magnets, (e) => {
if (e.name.includes(name)) return e.link
}).filter((e) => typeof e !== 'undefined' && e)
// Checking if some of them are present in current selected array
let allSelected = false
let counter = 0
this.$_.each(magnets, (magnet) => {
if (this.$_.find(this.selected, (o) => o === magnet)) {
++counter
if (counter === magnets.length) allSelected = true
// Checking if some of them are present in current selected array
let allSelected = false
let counter = 0
this.$_.each(magnets, (magnet) => {
if (this.$_.find(this.selected, (o) => o === magnet)) {
++counter
if (counter === magnets.length) allSelected = true
}
})
// Selecting or unselecting accordingly
this.$_.each(magnets, (magnet) => {
allSelected
? this.selected = this.selected.filter((link) => link !== magnet)
: !this.selected.includes(magnet) && this.selected.push(magnet)
})
},
openSelected () {
this.$_.each(this.selected, (l) => {
this.$axios.get('openThis', {
params: {
type: 'link',
link: l
}
})
// Selecting or unselecting accordingly
this.$_.each(magnets, (magnet) => {
allSelected
? this.selected = this.selected.filter((link) => link !== magnet)
: !this.selected.includes(magnet) && this.selected.push(magnet)
})
},
openSelected () {
this.$_.each(this.selected, (l) => {
this.$axios.get('openThis', {
params: {
type: 'link',
link: l
}
})
})
}
})
}
}
}
</script>
<style lang="stylus" scoped>
@ -179,4 +179,3 @@
text-align right
width 100%
</style>

View File

@ -127,186 +127,186 @@
</template>
<script>
export default {
data () {
return {
datePickers: [false, false],
status: [
{text: 'Watching', value: 1},
{text: 'Completed', value: 2},
{text: 'On Hold', value: 3},
{text: 'Dropped', value: 4},
{text: 'Plan to watch', value: 6}
],
score: [
{text: 'None', value: null},
{text: '1 - Appalling', value: 1},
{text: '2 - Horrible', value: 2},
{text: '3 - Very bad', value: 3},
{text: '4 - Bad', value: 4},
{text: '5 - Average', value: 5},
{text: '6 - Fine', value: 6},
{text: '7 - Good', value: 7},
{text: '8 - Very good', value: 8},
{text: '9 - Great', value: 9},
{text: '10 - Masterpiece', value: 10}
].reverse(),
storage: [
{text: 'Hard Drive', value: 1},
{text: 'DVD / CD', value: 2},
{text: 'Retail DVD', value: 4},
{text: 'VHS', value: 5},
{text: 'External HD', value: 6},
{text: 'NAS', value: 7},
{text: 'Blu-ray', value: 8},
{text: 'None', value: 3}
],
priority: [
{text: 'Low', value: 0},
{text: 'Medium', value: 1},
{text: 'High', value: 2}
],
rewatch: [
{text: 'Very low', value: 1},
{text: 'Low', value: 2},
{text: 'Medium', value: 3},
{text: 'High', value: 4},
{text: 'Very high', value: 5}
],
initForm: {
status: 1,
episode: '',
score: '',
date_start: null,
date_finish: null,
tags: [],
priority: 0,
times_rewatched: 0,
rewatch_value: null,
storage_type: null,
comments: ''
export default {
data () {
return {
datePickers: [false, false],
status: [
{text: 'Watching', value: 1},
{text: 'Completed', value: 2},
{text: 'On Hold', value: 3},
{text: 'Dropped', value: 4},
{text: 'Plan to watch', value: 6}
],
score: [
{text: 'None', value: null},
{text: '1 - Appalling', value: 1},
{text: '2 - Horrible', value: 2},
{text: '3 - Very bad', value: 3},
{text: '4 - Bad', value: 4},
{text: '5 - Average', value: 5},
{text: '6 - Fine', value: 6},
{text: '7 - Good', value: 7},
{text: '8 - Very good', value: 8},
{text: '9 - Great', value: 9},
{text: '10 - Masterpiece', value: 10}
].reverse(),
storage: [
{text: 'Hard Drive', value: 1},
{text: 'DVD / CD', value: 2},
{text: 'Retail DVD', value: 4},
{text: 'VHS', value: 5},
{text: 'External HD', value: 6},
{text: 'NAS', value: 7},
{text: 'Blu-ray', value: 8},
{text: 'None', value: 3}
],
priority: [
{text: 'Low', value: 0},
{text: 'Medium', value: 1},
{text: 'High', value: 2}
],
rewatch: [
{text: 'Very low', value: 1},
{text: 'Low', value: 2},
{text: 'Medium', value: 3},
{text: 'High', value: 4},
{text: 'Very high', value: 5}
],
initForm: {
status: 1,
episode: '',
score: '',
date_start: null,
date_finish: null,
tags: [],
priority: 0,
times_rewatched: 0,
rewatch_value: null,
storage_type: null,
comments: ''
},
form: {
status: 1,
episode: '',
score: '',
date_start: null,
date_finish: null,
tags: [],
priority: 0,
times_rewatched: 0,
rewatch_value: null,
storage_type: null,
comments: ''
}
}
},
computed: {
show: {
get () {
return this.$store.state.mal.form
},
set (bool) {
this.$store.commit('mal/showForm', bool)
}
},
entry () {
return this.$store.state.mal.entry
},
entryTitle () {
return ': ' + (this.entry.title || this.entry.name)
},
nbEpisodes () {
return this.entry.nbEpisodes || this.entry.episodes
},
isEdit () {
return this.entry.lastUpdate
},
addOrEdit () {
return this.isEdit ? 'Edit' : 'Add'
}
},
methods: {
close () {
this.$store.commit('mal/showForm', false)
this.form = this.initForm
},
submit () {
const id = this.entry.id
const opts = this.$_.clone(this.form)
opts.tags = opts.tags.join(', ')
const formatDate = (date) => {
if (date) {
date = date.split('-')
const d = date[2]
const m = date[1]
const y = date[0]
return m + d + y
} else {
return null
}
}
opts.date_start = formatDate(opts.date_start)
opts.date_finish = formatDate(opts.date_finish)
this.$store.dispatch('mal/actOnList', {
type: {
support: 'anime',
action: this.isEdit ? 'update' : 'add'
},
form: {
status: 1,
episode: '',
score: '',
date_start: null,
date_finish: null,
tags: [],
priority: 0,
times_rewatched: 0,
rewatch_value: null,
storage_type: null,
comments: ''
}
}
id,
opts
})
this.close()
},
computed: {
show: {
get () {
return this.$store.state.mal.form
deleteEntry () {
const id = this.entry.id
this.$store.dispatch('mal/actOnList', {
type: {
support: 'anime',
action: 'delete'
},
set (bool) {
this.$store.commit('mal/showForm', bool)
}
},
entry () {
return this.$store.state.mal.entry
},
entryTitle () {
return ': ' + (this.entry.title || this.entry.name)
},
nbEpisodes () {
return this.entry.nbEpisodes || this.entry.episodes
},
isEdit () {
return this.entry.lastUpdate
},
addOrEdit () {
return this.isEdit ? 'Edit' : 'Add'
id
})
this.$store.commit('mal/removeFromLists', id)
this.close()
}
},
watch: {
async entry (obj) {
if (this.isEdit) {
this.form.status = obj.status
this.form.score = obj.score || null
this.form.episode = obj.nbWatchedEpisode || null
this.form.date_start = obj.startDate || null
this.form.date_finish = obj.endDate || null
this.form.tags = obj.tags.length ? obj.tags.split(', ') : []
this.form.date_start = obj.myStartDate === '0000-00-00' ? null : obj.myStartDate
this.form.date_finish = obj.myEndDate === '0000-00-00' ? null : obj.myEndDate
}
},
methods: {
close () {
this.$store.commit('mal/showForm', false)
this.form = this.initForm
},
submit () {
const id = this.entry.id
const opts = this.$_.clone(this.form)
opts.tags = opts.tags.join(', ')
const {id} = obj
if (obj.name) {
try {
const {data} = await this.$axios.get(`getInfoFromMal`, {
params: {url: obj.url}
})
const formatDate = (date) => {
if (date) {
date = date.split('-')
const d = date[2]
const m = date[1]
const y = date[0]
return m + d + y
} else {
return null
}
}
opts.date_start = formatDate(opts.date_start)
opts.date_finish = formatDate(opts.date_finish)
this.$store.dispatch('mal/actOnList', {
type: {
support: 'anime',
action: this.isEdit ? 'update' : 'add'
},
id,
opts
})
this.close()
},
deleteEntry () {
const id = this.entry.id
this.$store.dispatch('mal/actOnList', {
type: {
support: 'anime',
action: 'delete'
},
id
})
this.$store.commit('mal/removeFromLists', id)
this.close()
}
},
watch: {
async entry (obj) {
if (this.isEdit) {
this.form.status = obj.status
this.form.score = obj.score || null
this.form.episode = obj.nbWatchedEpisode || null
this.form.date_start = obj.startDate || null
this.form.date_finish = obj.endDate || null
this.form.tags = obj.tags.length ? obj.tags.split(', ') : []
this.form.date_start = obj.myStartDate === '0000-00-00' ? null : obj.myStartDate
this.form.date_finish = obj.myEndDate === '0000-00-00' ? null : obj.myEndDate
}
const {id} = obj
if (obj.name) {
try {
const {data} = await this.$axios.get(`getInfoFromMal`, {
params: {url: obj.url}
})
this.$store.commit('mal/setEntry', {id, ...data})
} catch (e) {
console.error((new Date()).toLocaleTimeString(), e)
}
this.$store.commit('mal/setEntry', {id, ...data})
} catch (e) {
console.error((new Date()).toLocaleTimeString(), e)
}
}
}
}
}
</script>
<style lang="stylus" scoped>

View File

@ -16,16 +16,16 @@
</template>
<script>
export default {
props: {
item: Object
},
methods: {
open (link) {
this.$store.dispatch('news/openLink', link)
}
export default {
props: {
item: Object
},
methods: {
open (link) {
this.$store.dispatch('news/openLink', link)
}
}
}
</script>
<style lang="stylus" scoped>

View File

@ -6,16 +6,15 @@
</template>
<script>
export default {
computed: {
isVisible () {
return this.$store.state.overlay.show
}
export default {
computed: {
isVisible () {
return this.$store.state.overlay.show
}
}
}
</script>
<style lang="stylus" scoped>
#overlay
position absolute
@ -50,4 +49,3 @@
padding 10px
border-radius 3px
</style>

View File

@ -56,7 +56,6 @@ export default {
}
</script>
<style lang="stylus">
.slider__buffer-container
@ -74,4 +73,4 @@ export default {
background-color #0D47A1
height 2px
position absolute
</style>
</style>

View File

@ -176,59 +176,59 @@
</template>
<script>
export default {
data () {
return {
configModal: false,
radios: ['480p', '720p', '1080p'],
mal: {
password: '',
isVisible: false
}
export default {
data () {
return {
configModal: false,
radios: ['480p', '720p', '1080p'],
mal: {
password: '',
isVisible: false
}
}
},
computed: {
config: {
get () {
return this.$store.state.config.config
},
set (val) {
this.$store.commit('config/set', val)
}
},
computed: {
config: {
get () {
return this.$store.state.config.config
},
set (val) {
this.$store.commit('config/set', val)
}
},
fansubChoices () {
return this.$store.state.config.fansubs
},
soundChoices () {
return this.$store.state.config.sounds
},
subtitlesLanguages () {
return this.$store.state.config.subtitlesLanguages
}
fansubChoices () {
return this.$store.state.config.fansubs
},
methods: {
changePath () {
this.$store.dispatch('config/changeDir')
},
save () {
this.$store.commit('config/set', this.config)
this.$store.dispatch('config/save')
this.$store.dispatch('player/setUp')
this.configModal = false
},
play () {
this.$store.dispatch('player/testSound')
},
async malRegister () {
if (this.mal.password && this.config.malUsername) {
await this.$store.dispatch('mal/setupAccount', {
username: this.config.malUsername,
password: this.mal.password
})
}
soundChoices () {
return this.$store.state.config.sounds
},
subtitlesLanguages () {
return this.$store.state.config.subtitlesLanguages
}
},
methods: {
changePath () {
this.$store.dispatch('config/changeDir')
},
save () {
this.$store.commit('config/set', this.config)
this.$store.dispatch('config/save')
this.$store.dispatch('player/setUp')
this.configModal = false
},
play () {
this.$store.dispatch('player/testSound')
},
async malRegister () {
if (this.mal.password && this.config.malUsername) {
await this.$store.dispatch('mal/setupAccount', {
username: this.config.malUsername,
password: this.mal.password
})
}
}
}
}
</script>
<style lang="stylus" scoped>

View File

@ -10,135 +10,135 @@
</template>
<script>
export default {
name: 'Video-Container',
export default {
name: 'Video-Container',
data () {
data () {
return {
fullscreen: false,
height: 85,
width: 85,
bottom: 0,
right: 0,
z: 2,
isMinimized: false
}
},
computed: {
values () {
return this.$store.state.streaming.player
},
show () {
return this.values.show
},
style () {
return {
fullscreen: false,
height: 85,
width: 85,
bottom: 0,
right: 0,
z: 2,
isMinimized: false
width: this.width + '%',
height: this.height + '%',
bottom: this.bottom + '%',
right: this.right + '%',
'z-index': this.z
}
},
computed: {
values () {
return this.$store.state.streaming.player
},
show () {
return this.values.show
},
style () {
return {
width: this.width + '%',
height: this.height + '%',
bottom: this.bottom + '%',
right: this.right + '%',
'z-index': this.z
}
},
listeners () {
return {
32: () => this.togglePlay(),
27: () => this.close(),
37: () => this.forward(-5),
39: () => this.forward(5),
38: () => this.increaseVolume(5),
40: () => this.increaseVolume(-5)
}
listeners () {
return {
32: () => this.togglePlay(),
27: () => this.close(),
37: () => this.forward(-5),
39: () => this.forward(5),
38: () => this.increaseVolume(5),
40: () => this.increaseVolume(-5)
}
}
},
methods: {
center () {
this.$nextTick(() => {
const el = document.getElementsByTagName('video')[0]
if (el) {
const { clientHeight: videoHeight, clientWidth: videoWidth } = el
const { innerHeight: winHeight, innerWidth: winWidth } = window
this.bottom = (((winHeight - videoHeight) / winHeight) * 100) / 2
this.right = (((winWidth - videoWidth) / winWidth) * 100) / 2
}
})
},
close () {
this.$store.commit('streaming/close')
},
minimize () {
if (this.isMinimized) {
this.width = 85
this.height = 85
methods: {
center () {
this.$nextTick(() => {
const el = document.getElementsByTagName('video')[0]
this.center()
} else {
this.width = 40
this.height = 40
if (el) {
const { clientHeight: videoHeight, clientWidth: videoWidth } = el
const { innerHeight: winHeight, innerWidth: winWidth } = window
this.bottom = 0
this.right = 0
}
this.$nextTick(() => this.$refs.player.setHeight())
this.isMinimized = !this.isMinimized
},
async toggleFullScreen () {
this.fullscreen = !this.fullscreen
await this.$axios.get('/_fullScreen', { params: { bool: this.fullscreen } })
this.isMinimized = false
if (this.fullscreen) {
this.z = 3
this.width = 100
this.height = 100
this.bottom = 0
this.right = 0
} else {
this.width = 85
this.height = 85
this.z = 2
this.center()
}
this.$nextTick(() => this.$refs.player.setHeight())
},
forward (value) {
this.$refs.player.timeForward(value)
},
increaseVolume (value) {
this.$refs.player.increaseVolume(value)
},
togglePlay () {
this.$refs.player.togglePlay()
},
addListeners (e) {
if (this.listeners.hasOwnProperty(e.keyCode)) this.listeners[e.keyCode]()
}
},
watch: {
show (val) {
if (val) {
this.center()
this.bottom = (((winHeight - videoHeight) / winHeight) * 100) / 2
this.right = (((winWidth - videoWidth) / winWidth) * 100) / 2
}
})
},
close () {
this.$store.commit('streaming/close')
},
minimize () {
if (this.isMinimized) {
this.width = 85
this.height = 85
this.center()
} else {
this.width = 40
this.height = 40
this.bottom = 0
this.right = 0
this.minimize()
}
this.$nextTick(() => this.$refs.player.setHeight())
this.isMinimized = !this.isMinimized
},
async toggleFullScreen () {
this.fullscreen = !this.fullscreen
await this.$axios.get('/_fullScreen', { params: { bool: this.fullscreen } })
this.isMinimized = false
if (this.fullscreen) {
this.z = 3
this.width = 100
this.height = 100
this.bottom = 0
this.right = 0
} else {
this.width = 85
this.height = 85
this.z = 2
this.center()
}
this.$nextTick(() => this.$refs.player.setHeight())
},
forward (value) {
this.$refs.player.timeForward(value)
},
increaseVolume (value) {
this.$refs.player.increaseVolume(value)
},
togglePlay () {
this.$refs.player.togglePlay()
},
addListeners (e) {
if (this.listeners.hasOwnProperty(e.keyCode)) this.listeners[e.keyCode]()
}
},
watch: {
show (val) {
if (val) {
this.center()
if (this.isMinimized) {
this.minimize()
}
window.addEventListener('keydown', this.addListeners)
} else {
window.removeEventListener('keydown', this.addListeners)
}
window.addEventListener('keydown', this.addListeners)
} else {
window.removeEventListener('keydown', this.addListeners)
}
}
}
}
</script>
<style lang="stylus" scoped>

View File

@ -85,255 +85,255 @@
</template>
<script>
import { fromAss } from 'assets/subtitle-parser'
import Subtitle from 'mixins/subtitles'
import { fromAss } from 'assets/subtitle-parser'
import Subtitle from 'mixins/subtitles'
export default {
name: 'video-player',
mixins: [Subtitle],
props: ['value', 'title'],
data () {
return {
waiting: false,
paused: true,
muted: false,
fullscreen: false,
buffered: [],
timeline: 0,
volume: 100,
currentTime: 0,
duration: 0,
controlsHidden: true,
autoplay: true,
isAss: false,
styles: null,
info: null,
isMagnetRe: /^magnet:\?/,
name: '',
isPrefLanguageSet: false,
hasAppendedToHistory: false
}
},
computed: {
config: {
get () {
return this.$store.state.config.config.video
},
set () {}
export default {
name: 'video-player',
mixins: [Subtitle],
props: ['value', 'title'],
data () {
return {
waiting: false,
paused: true,
muted: false,
fullscreen: false,
buffered: [],
timeline: 0,
volume: 100,
currentTime: 0,
duration: 0,
controlsHidden: true,
autoplay: true,
isAss: false,
styles: null,
info: null,
isMagnetRe: /^magnet:\?/,
name: '',
isPrefLanguageSet: false,
hasAppendedToHistory: false
}
},
computed: {
config: {
get () {
return this.$store.state.config.config.video
},
isMagnet () {
return this.isMagnetRe.test(this.value) || this.value.slice(-8) === '.torrent'
},
videoTitle () {
return this.title || this.name
}
set () {}
},
async created () {
if (this.isMagnet) await this.$axios.get('torrent/init')
isMagnet () {
return this.isMagnetRe.test(this.value) || this.value.slice(-8) === '.torrent'
},
mounted () {
const { video } = this.$refs
const textTracks = {}
videoTitle () {
return this.title || this.name
}
},
async created () {
if (this.isMagnet) await this.$axios.get('torrent/init')
},
mounted () {
const { video } = this.$refs
const textTracks = {}
video.addEventListener('loadedmetadata', () => {
// We need to get the subtitles only when the torrent is ready to be read.
// Otherwise, there is no file to get the subtitles from.
this.eventSource = new window.EventSource(`/tracks/${this.value}`)
this.setHeight()
video.addEventListener('loadedmetadata', () => {
// We need to get the subtitles only when the torrent is ready to be read.
// Otherwise, there is no file to get the subtitles from.
this.eventSource = new window.EventSource(`/tracks/${this.value}`)
this.setHeight()
this.eventSource.addEventListener('tracks', ({ data }) => {
const tracks = JSON.parse(data)
let isStyleSet = false
this.eventSource.addEventListener('tracks', ({ data }) => {
const tracks = JSON.parse(data)
let isStyleSet = false
tracks.forEach(track => {
const language = (track.language || 'eng').slice(0, 2)
const trackNumber = +track.number
this.allCues[trackNumber] = []
tracks.forEach(track => {
const language = (track.language || 'eng').slice(0, 2)
const trackNumber = +track.number
this.allCues[trackNumber] = []
this.numToLang[trackNumber] = language
this.numToLang[trackNumber] = language
if (track.type === 'ass') {
this.isAss = true
const parsedTracks = fromAss.tracks(tracks)
this.styles = parsedTracks.styles
this.info = parsedTracks.info
if (track.type === 'ass') {
this.isAss = true
const parsedTracks = fromAss.tracks(tracks)
this.styles = parsedTracks.styles
this.info = parsedTracks.info
// Let's suppose each track have the same style and that only the language of each changes.
if (!isStyleSet) {
fromAss.setStyles(this.styles, this.value, this.info)
isStyleSet = true
}
// Let's suppose each track have the same style and that only the language of each changes.
if (!isStyleSet) {
fromAss.setStyles(this.styles, this.value, this.info)
isStyleSet = true
}
}
if (language === this.config.preferredLanguage) {
this.isPrefLanguageSet = true
this.trackNum = trackNumber
}
})
if (tracks.length === 1 && !this.isPrefLanguageSet) {
this.trackNum = +Object.keys(this.numToLang)[0]
if (language === this.config.preferredLanguage) {
this.isPrefLanguageSet = true
this.trackNum = trackNumber
}
})
this.eventSource.addEventListener('subtitle', ({ data }) => {
const { trackNumber, subtitle } = JSON.parse(data)
if (trackNumber in this.allCues) {
if (this.isAss) {
const cue = fromAss.subtitles(subtitle, this.styles, this.info)
this.allCues[trackNumber].push(cue)
} else {
const cue = new window.VTTCue(subtitle.time / 1000, (subtitle.time + subtitle.duration) / 1000, subtitle.text)
textTracks[trackNumber].addCue(cue)
}
}
})
if (this.title) {
this.addToHistory()
if (tracks.length === 1 && !this.isPrefLanguageSet) {
this.trackNum = +Object.keys(this.numToLang)[0]
}
this.eventSource.addEventListener('name', ({ data }) => {
const { name } = JSON.parse(data)
this.name = name
this.addToHistory()
})
})
video && !this.fullscreen && this.config.fullscreen && this.toggleFullScreen()
},
beforeDestroy () {
this.eventSource && this.eventSource.close()
this.fullscreen && this.toggleFullScreen()
this.eventSource.addEventListener('subtitle', ({ data }) => {
const { trackNumber, subtitle } = JSON.parse(data)
if (trackNumber in this.allCues) {
if (this.isAss) {
const cue = fromAss.subtitles(subtitle, this.styles, this.info)
// Removing cue styling from head
const { head } = document
head.removeChild(head.children[head.childElementCount - 1])
if (this.isMagnet) {
this.$axios.delete('torrent/remove', {
params: {
magnet: this.value
this.allCues[trackNumber].push(cue)
} else {
const cue = new window.VTTCue(subtitle.time / 1000, (subtitle.time + subtitle.duration) / 1000, subtitle.text)
textTracks[trackNumber].addCue(cue)
}
})
}
})
if (this.title) {
this.addToHistory()
}
this.eventSource.addEventListener('name', ({ data }) => {
const { name } = JSON.parse(data)
this.name = name
this.addToHistory()
})
})
video && !this.fullscreen && this.config.fullscreen && this.toggleFullScreen()
},
beforeDestroy () {
this.eventSource && this.eventSource.close()
this.fullscreen && this.toggleFullScreen()
// Removing cue styling from head
const { head } = document
head.removeChild(head.children[head.childElementCount - 1])
if (this.isMagnet) {
this.$axios.delete('torrent/remove', {
params: {
magnet: this.value
}
})
}
},
methods: {
formatTime (time = 0) {
const minutes = ('0' + Math.floor(time / 60)).slice(-2)
const seconds = ('0' + Math.floor(time % 60)).slice(-2)
return `${minutes}:${seconds}`
},
togglePlay () {
const { video } = this.$refs
this.showControls()
this.paused ? video.play() : video.pause()
},
toggleMute () {
this.muted = this.$refs.video.muted = !this.muted
},
toggleFullScreen () {
this.$parent.toggleFullScreen()
this.fullscreen = !this.fullscreen
},
onTimelineChangeEvent () {
const { video } = this.$refs
if (video) {
this.timeline = 100 / video.duration * video.currentTime
this.currentTime = this.formatTime(video.currentTime)
this.duration = this.formatTime(video.duration)
this.rawTime = video.currentTime
if (this.isAss) this.updateActiveCues()
}
},
methods: {
formatTime (time = 0) {
const minutes = ('0' + Math.floor(time / 60)).slice(-2)
const seconds = ('0' + Math.floor(time % 60)).slice(-2)
return `${minutes}:${seconds}`
},
togglePlay () {
const { video } = this.$refs
this.showControls()
this.paused ? video.play() : video.pause()
},
toggleMute () {
this.muted = this.$refs.video.muted = !this.muted
},
toggleFullScreen () {
this.$parent.toggleFullScreen()
this.fullscreen = !this.fullscreen
},
onTimelineChangeEvent () {
const { video } = this.$refs
if (video) {
this.timeline = 100 / video.duration * video.currentTime
this.currentTime = this.formatTime(video.currentTime)
this.duration = this.formatTime(video.duration)
this.rawTime = video.currentTime
if (this.isAss) this.updateActiveCues()
onProgress () {
const { video } = this.$refs
if (video) {
const buffered = []
for (let i = 0, l = video.buffered.length; i < l; ++i) {
buffered.push([
video.buffered.start(i) / video.duration * 100,
video.buffered.end(i) / video.duration * 100
])
}
},
onProgress () {
const { video } = this.$refs
if (video) {
const buffered = []
for (let i = 0, l = video.buffered.length; i < l; ++i) {
buffered.push([
video.buffered.start(i) / video.duration * 100,
video.buffered.end(i) / video.duration * 100
])
}
this.buffered = buffered
}
},
onCanPlay () {
this.waiting = false
},
onSeeked () {
this.index = 0
},
changeTimeline (value) {
const { video } = this.$refs
if (video) { video.currentTime = video.duration * ((this.timeline = value) / 100) }
},
timeForward (value) {
const { video } = this.$refs
this.buffered = buffered
}
},
onCanPlay () {
this.waiting = false
},
onSeeked () {
this.index = 0
},
changeTimeline (value) {
const { video } = this.$refs
if (video) { video.currentTime = video.duration * ((this.timeline = value) / 100) }
},
timeForward (value) {
const { video } = this.$refs
if (video) {
video.currentTime += value
}
},
changeVolume (value) {
if (this.$refs.video) this.$refs.video.volume = (this.volume = value) / 100
},
increaseVolume (value) {
const { video } = this.$refs
if (video) {
video.currentTime += value
}
},
changeVolume (value) {
if (this.$refs.video) this.$refs.video.volume = (this.volume = value) / 100
},
increaseVolume (value) {
const { video } = this.$refs
if (video) {
const currentVolume = video.volume * 100
let newVolume = currentVolume + value
if (video) {
const currentVolume = video.volume * 100
let newVolume = currentVolume + value
newVolume = newVolume >= 0 && newVolume <= 100
? newVolume
: currentVolume
newVolume = newVolume >= 0 && newVolume <= 100
? newVolume
: currentVolume
this.volume = newVolume
this.$refs.video.volume = newVolume / 100
}
},
onMouseMove (e) {
if (Math.abs(e.movementX) > 1 || Math.abs(e.movementY) > 1) { this.showControls() }
},
showControls () {
this.controlsHidden = false
if (this.timeoutID) clearTimeout(this.timeoutID)
this.timeoutID = setTimeout(() => (this.controlsHidden = true), 3000)
},
setTrack (track) {
const { video } = this.$refs
if (track.mode === 'showing') {
this.volume = newVolume
this.$refs.video.volume = newVolume / 100
}
},
onMouseMove (e) {
if (Math.abs(e.movementX) > 1 || Math.abs(e.movementY) > 1) { this.showControls() }
},
showControls () {
this.controlsHidden = false
if (this.timeoutID) clearTimeout(this.timeoutID)
this.timeoutID = setTimeout(() => (this.controlsHidden = true), 3000)
},
setTrack (track) {
const { video } = this.$refs
if (track.mode === 'showing') {
track.mode = 'hidden'
} else {
for (const track of video.textTracks) {
track.mode = 'hidden'
} else {
for (const track of video.textTracks) {
track.mode = 'hidden'
}
track.mode = 'showing'
}
},
actOnWindow (type) {
this.$parent[type]()
},
addToHistory () {
if (!this.hasAppendedToHistory) {
this.$store.dispatch('history/append', {
type: this.isMagnet ? 'Stream' : 'Play',
text: this.videoTitle
})
this.hasAppendedToHistory = true
}
track.mode = 'showing'
}
},
actOnWindow (type) {
this.$parent[type]()
},
addToHistory () {
if (!this.hasAppendedToHistory) {
this.$store.dispatch('history/append', {
type: this.isMagnet ? 'Stream' : 'Play',
text: this.videoTitle
})
this.hasAppendedToHistory = true
}
}
}
}
</script>
<style lang="stylus">

View File

@ -19,9 +19,9 @@
"cloc": "cloc $(git ls-files | grep -vE \".mkv|mp4|m4a|mp3|lock\")",
"test:server": "nyc ava --verbose --serial test/server.test.js",
"test:front": "npm run build && cross-env NODE_ENV=KawAnime-test nightwatch",
"test": "standard --fix && npm run test:front && npm run test:server",
"test": "npm run lint && npm run test:front && npm run test:server",
"coverage": "nyc report --reporter=text-lcov > coverage.lcov && codecov",
"lint": "standard --fix --verbose --plugin vue '**/*.{js,vue}' | snazzy",
"lint": "eslint --fix --ext .js,.vue pages",
"pack": "build --dir",
"dist:linux": "build --linux deb AppImage",
"dist:win": "build --win --x64 --ia32",
@ -92,13 +92,16 @@
"electron-builder": "^20.24.4",
"env2": "^2.2.2",
"es6-promise": "^4.2.4",
"eslint": "^5.1.0",
"eslint-config-standard": "^11.0.0",
"eslint-plugin-import": "^2.13.0",
"eslint-plugin-node": "^7.0.1",
"eslint-plugin-promise": "^3.8.0",
"eslint-plugin-react": "^7.10.0",
"eslint-plugin-vue": "^2.1.0",
"eventsource-polyfill": "^0.9.6",
"eslint-plugin-standard": "^3.1.0",
"eslint-plugin-vue": "^4.7.0",
"file-loader": "^1.1.11",
"friendly-errors-webpack-plugin": "^1.6.1",
"highlight.js": "^9.12.0",
"html-webpack-plugin": "^3.1.0",
"mini-css-extract-plugin": "^0.4.1",
"nightwatch": "^1.0.6",
"nyc": "^12.0.2",
@ -107,10 +110,7 @@
"progress-bar-webpack-plugin": "^1.11.0",
"pug": "^2.0.3",
"rimraf": "^2.6.2",
"script-ext-html-webpack-plugin": "^2.0.1",
"selenium-download": "^2.0.12",
"snazzy": "^7.1.1",
"standard": "^11.0.1",
"style-loader": "^0.21.0",
"stylus": "^0.54.5",
"stylus-loader": "^3.0.2",
@ -151,13 +151,6 @@
"allowToChangeInstallationDirectory": true
}
},
"standard": {
"parser": "babel-eslint",
"ignore": [
"test/front.test.js",
"public"
]
},
"nyc": {
"exclude": [
"test",

View File

@ -51,72 +51,72 @@
</template>
<script>
export default {
data () {
return {
modalText: '',
nameRules: [
() => this.formValues.name.length > 2 || 'Please enter at least 3 characters.'
]
export default {
data () {
return {
modalText: '',
nameRules: [
() => this.formValues.name.length > 2 || 'Please enter at least 3 characters.'
]
}
},
computed: {
formValues () {
return this.$store.state.downloader.form
},
quality: {
get () {
return this.formValues.quality
},
set (val) {
this.$store.commit('downloader/setQuality', val)
}
}
},
methods: {
isDownloadable () {
this.formValues.name.length > 2
? this.download()
: this.$refs.name.focus()
},
download () {
this.$store.dispatch('downloader/download')
},
next (number) {
switch (number) {
case 1:
document.getElementsByName('from-ep-input')[0].focus()
break
case 2:
document.getElementsByName('until-ep-input')[0].focus()
break
case 3:
document.getElementById('download-btn').click()
document.getElementsByName('name-input')[0].focus()
break
default:
break
}
},
computed: {
formValues () {
return this.$store.state.downloader.form
},
quality: {
get () {
return this.formValues.quality
},
set (val) {
this.$store.commit('downloader/setQuality', val)
}
}
},
methods: {
isDownloadable () {
this.formValues.name.length > 2
? this.download()
: this.$refs.name.focus()
},
download () {
this.$store.dispatch('downloader/download')
},
next (number) {
switch (number) {
case 1:
document.getElementsByName('from-ep-input')[0].focus()
break
previous (number) {
switch (number) {
case 2:
if (!this.formValues.fromEp) document.getElementsByName('name-input')[0].focus()
break
case 2:
document.getElementsByName('until-ep-input')[0].focus()
break
case 3:
if (!this.formValues.untilEp) document.getElementsByName('from-ep-input')[0].focus()
break
case 3:
document.getElementById('download-btn').click()
document.getElementsByName('name-input')[0].focus()
break
default:
break
}
},
previous (number) {
switch (number) {
case 2:
if (!this.formValues.fromEp) document.getElementsByName('name-input')[0].focus()
break
case 3:
if (!this.formValues.untilEp) document.getElementsByName('from-ep-input')[0].focus()
break
default:
break
}
default:
break
}
}
}
}
</script>
<style lang="stylus" scoped>

View File

@ -106,108 +106,108 @@
</template>
<script>
export default {
mounted () {
setTimeout(() => { this.emptyBg = true }, 300)
export default {
mounted () {
setTimeout(() => { this.emptyBg = true }, 300)
this.inside = this.$store.state.config.config.video.inside
this.inside = this.$store.state.config.config.video.inside
this.refresh()
this.refresh()
},
beforeDestroy () {
this.emptyBg = false
},
data () {
return {
inside: true,
emptyBg: false
}
},
computed: {
files () {
return this.$store.state.localFiles.files
},
beforeDestroy () {
this.emptyBg = false
nbEps () {
return this.files.length
},
data () {
return {
inside: true,
emptyBg: false
episodeLabel () {
return this.nbEps === 1
? 'episode'
: 'episodes'
}
},
methods: {
async playThis (item) {
this.$log(`Requested to play ${item.name} - ${item.ep}. Sending...`)
const name = `${item.name} - ${item.ep}`
if (this.inside) {
this.$store.commit('streaming/play', {
show: true,
link: {
link: item.path,
name
}
})
} else {
const { status } = await this.$axios.get(`openThis`, {
params: {
type: 'video',
path: item.path,
dir: this.$store.state.localFiles.dir
}
})
this.$store.dispatch('history/append', {
type: 'Play',
text: name
})
if (status !== 200) this.$log(`An error occurred: request to open file ended with a status ${status}.`)
}
},
computed: {
files () {
return this.$store.state.localFiles.files
},
nbEps () {
return this.files.length
},
episodeLabel () {
return this.nbEps === 1
? 'episode'
: 'episodes'
}
},
methods: {
async playThis (item) {
this.$log(`Requested to play ${item.name} - ${item.ep}. Sending...`)
const name = `${item.name} - ${item.ep}`
delThis (item) {
this.$log(`[${(new Date()).toLocaleTimeString()}]: Requested to delete ${item.path} - ${item.ep}. Sending...`)
if (this.inside) {
this.$store.commit('streaming/play', {
show: true,
link: {
link: item.path,
name
}
})
} else {
const { status } = await this.$axios.get(`openThis`, {
params: {
type: 'video',
path: item.path,
dir: this.$store.state.localFiles.dir
}
})
this.$store.commit('localFiles/updateFiles', {
type: 'delete',
path: item.path
})
this.$store.dispatch('history/append', {
type: 'Play',
text: name
})
if (status !== 200) this.$log(`An error occurred: request to open file ended with a status ${status}.`)
}
},
delThis (item) {
this.$log(`[${(new Date()).toLocaleTimeString()}]: Requested to delete ${item.path} - ${item.ep}. Sending...`)
this.$store.commit('localFiles/updateFiles', {
this.$axios.get(`openThis`, {
params: {
type: 'delete',
path: item.path
})
this.$axios.get(`openThis`, {
params: {
type: 'delete',
path: item.path
}
}).then((res) => {
this.$store.commit('setInfoSnackbar', `${item.name} ${item.ep} was successfully sent to Trash.`)
this.$store.dispatch('history/append', {
type: 'Delete',
text: `${item.name} - ${item.ep}`
}).catch(err => { void (err) })
}).catch(() => {
this.$store.commit('setInfoSnackbar', `Error while trying to delete ${item.name} ${item.ep}. Please try again later.`)
})
},
refresh () {
this.$store.dispatch('localFiles/refresh')
},
changePath () {
this.$store.dispatch('localFiles/changePath')
},
resetLocal () {
if (this.$store.state.isConnected) {
this.$store.dispatch('localFiles/reset')
} else {
this.$store.commit('setInfoSnackbar', 'You are offline.')
}
},
showChoices (name) {
this.$store.commit('setAddToChoiceTitle', name)
this.$store.commit('setAddToChoice', true)
}).then((res) => {
this.$store.commit('setInfoSnackbar', `${item.name} ${item.ep} was successfully sent to Trash.`)
this.$store.dispatch('history/append', {
type: 'Delete',
text: `${item.name} - ${item.ep}`
}).catch(err => { void (err) })
}).catch(() => {
this.$store.commit('setInfoSnackbar', `Error while trying to delete ${item.name} ${item.ep}. Please try again later.`)
})
},
refresh () {
this.$store.dispatch('localFiles/refresh')
},
changePath () {
this.$store.dispatch('localFiles/changePath')
},
resetLocal () {
if (this.$store.state.isConnected) {
this.$store.dispatch('localFiles/reset')
} else {
this.$store.commit('setInfoSnackbar', 'You are offline.')
}
},
showChoices (name) {
this.$store.commit('setAddToChoiceTitle', name)
this.$store.commit('setAddToChoice', true)
}
}
}
</script>
<style lang="stylus" scoped>

View File

@ -58,95 +58,95 @@
</template>
<script>
import Vuex from 'vuex'
import Vuex from 'vuex'
export default {
data () {
return {
search: '',
rowsPerPage: [10, 15, 25, 50, 100, { text: 'All', value: -1 }],
headers: [
{
text: 'Image',
align: 'center',
sortable: false,
value: 'image'
}, {
text: 'Title',
align: 'left',
sortable: true,
value: 'title'
}, {
text: 'Score',
align: 'center',
sortable: true,
value: 'score'
}, {
text: 'Type',
align: 'center',
sortable: true,
value: 'type'
}, {
text: 'Progress',
align: 'center',
sortable: true,
value: 'progressDec'
}, {
text: 'Status',
align: 'center',
sortable: true,
value: 'status'
}, {
text: 'Tags',
align: 'center',
sortable: false,
value: 'tags'
}
]
}
},
computed: {
...Vuex.mapGetters('mal', [
'lists'
]),
isLoading () {
return this.$store.state.mal.isLoading
},
tagsFilter: {
get () {
return this.$store.state.mal.tagsFilter
},
set (tags) {
this.$store.commit('mal/setTagsFilter', tags)
export default {
data () {
return {
search: '',
rowsPerPage: [10, 15, 25, 50, 100, { text: 'All', value: -1 }],
headers: [
{
text: 'Image',
align: 'center',
sortable: false,
value: 'image'
}, {
text: 'Title',
align: 'left',
sortable: true,
value: 'title'
}, {
text: 'Score',
align: 'center',
sortable: true,
value: 'score'
}, {
text: 'Type',
align: 'center',
sortable: true,
value: 'type'
}, {
text: 'Progress',
align: 'center',
sortable: true,
value: 'progressDec'
}, {
text: 'Status',
align: 'center',
sortable: true,
value: 'status'
}, {
text: 'Tags',
align: 'center',
sortable: false,
value: 'tags'
}
]
}
},
computed: {
...Vuex.mapGetters('mal', [
'lists'
]),
isLoading () {
return this.$store.state.mal.isLoading
},
tagsFilter: {
get () {
return this.$store.state.mal.tagsFilter
},
customTags: {
get () {
return this.$store.state.mal.customTags
},
set () {}
set (tags) {
this.$store.commit('mal/setTagsFilter', tags)
}
},
methods: {
showInfo (name, url) {
this.$store.dispatch('search/fromUrl', {
name,
url
})
customTags: {
get () {
return this.$store.state.mal.customTags
},
showForm (id) {
this.$store.commit('mal/setEntry', id)
this.$store.commit('mal/showForm', true)
},
showSearch () {
this.$store.commit('mal/isAdding', true)
this.$store.commit('search/show', true)
},
refresh () {
this.$store.dispatch('mal/getWatchLists', this.$store.state.config.config.malUsername)
}
set () {}
}
},
methods: {
showInfo (name, url) {
this.$store.dispatch('search/fromUrl', {
name,
url
})
},
showForm (id) {
this.$store.commit('mal/setEntry', id)
this.$store.commit('mal/showForm', true)
},
showSearch () {
this.$store.commit('mal/isAdding', true)
this.$store.commit('search/show', true)
},
refresh () {
this.$store.dispatch('mal/getWatchLists', this.$store.state.config.config.malUsername)
}
}
}
</script>
<style lang="stylus" scoped>

View File

@ -13,18 +13,18 @@
</template>
<script>
export default {
methods: {
refresh () {
this.$store.dispatch('news/refresh')
}
},
computed: {
news () {
return this.$store.state.news.data
}
export default {
methods: {
refresh () {
this.$store.dispatch('news/refresh')
}
},
computed: {
news () {
return this.$store.state.news.data
}
}
}
</script>
<style lang="stylus" scoped>

View File

@ -85,122 +85,121 @@
</template>
<script>
export default {
mounted () {
export default {
mounted () {
if (this.releases.length) {
this.updateTime()
}
setInterval(() => {
if (this.releases.length) {
this.updateTime()
}
setInterval(() => {
if (this.releases.length) {
this.updateTime()
}
}, 15 * 1000)
}, 15 * 1000)
},
data () {
return {
modalTitle: '',
modalText: '',
qualityList: ['480p', '720p', '1080p'],
lastUpdateTime: 'a few seconds ago'
}
},
computed: {
releases () {
return this.$store.state.releases.releases
},
data () {
return {
modalTitle: '',
modalText: '',
qualityList: ['480p', '720p', '1080p'],
lastUpdateTime: 'a few seconds ago'
fansubList () {
return this.$store.state.releases.fansubs
},
notLoaded () {
return this.$store.state.releases.notLoaded
}
},
methods: {
epLabel (ep, isTooltip = false) {
// HorribleSubs specific atm
return /\[[0-9]{3,4}p\]/.test(ep)
? 'Batch'
: `${isTooltip ? 'Episode' : 'Ep'} ${ep}`
},
downloadAll (name) {
console.log(`[${(new Date()).toLocaleTimeString()}]: Sending a request to download all episodes of ${name}.`)
const {quality, fansub} = this.$store.state.releases.params
this.$store.dispatch('downloader/download', {
name,
quality,
fansub,
fromEp: 0,
untilEp: 20000,
choice: 'si'
})
},
async refresh () {
await this.$store.dispatch('releases/refresh')
this.updateTime()
},
print (item) {
console.log(`[${(new Date()).toLocaleTimeString()}]: Downloading ${item.rawName} ep. ${item.ep}.`)
},
showChoices (name) {
this.$store.commit('setAddToChoiceTitle', name)
this.$store.commit('setAddToChoice', true)
},
showMal (item) {
const {url} = item
item.id = +url.split('/').splice(-2, 1)[0]
this.$store.commit('mal/setEntry', item)
this.$store.commit('mal/showForm', true)
},
updateTime () {
const updated = this.$store.state.releases.updateTime
if (updated) {
this.lastUpdateTime = updated.fromNow()
}
},
computed: {
releases () {
return this.$store.state.releases.releases
},
fansubList () {
return this.$store.state.releases.fansubs
},
notLoaded () {
return this.$store.state.releases.notLoaded
}
searchThis (item) {
this.$store.commit('search/setInfo', item)
this.$store.commit('search/setInfoTerm', item.title)
this.$store.commit('search/setInfoLoading', false)
this.$store.commit('search/showInfo', true)
},
methods: {
epLabel (ep, isTooltip = false) {
// HorribleSubs specific atm
return /\[[0-9]{3,4}p\]/.test(ep)
? 'Batch'
: `${isTooltip ? 'Episode' : 'Ep'} ${ep}`
},
downloadAll (name) {
console.log(`[${(new Date()).toLocaleTimeString()}]: Sending a request to download all episodes of ${name}.`)
const {quality, fansub} = this.$store.state.releases.params
this.$store.dispatch('downloader/download', {
name,
quality,
fansub,
fromEp: 0,
untilEp: 20000,
choice: 'si'
})
},
async refresh () {
await this.$store.dispatch('releases/refresh')
this.updateTime()
},
print (item) {
console.log(`[${(new Date()).toLocaleTimeString()}]: Downloading ${item.rawName} ep. ${item.ep}.`)
},
showChoices (name) {
this.$store.commit('setAddToChoiceTitle', name)
this.$store.commit('setAddToChoice', true)
},
showMal (item) {
const {url} = item
item.id = +url.split('/').splice(-2, 1)[0]
item.episodes = item.episodes
this.$store.commit('mal/setEntry', item)
this.$store.commit('mal/showForm', true)
},
updateTime () {
const updated = this.$store.state.releases.updateTime
if (updated) {
this.lastUpdateTime = updated.fromNow()
}
},
searchThis (item) {
this.$store.commit('search/setInfo', item)
this.$store.commit('search/setInfoTerm', item.title)
this.$store.commit('search/setInfoLoading', false)
this.$store.commit('search/showInfo', true)
},
isFollowed (name) {
const malLists = this.$store.state.mal.watchLists
const localLists = {
watching: this.$store.state.watchLists.lists.watching,
watchList: this.$store.state.watchLists.lists.watchList
}
const isWatching = localLists.watching.includes(name) || this.$_.find(malLists, (o) => o.anime_title === name && o.status === 1)
const isPlanned = localLists.watchList.includes(name) || this.$_.find(malLists, (o) => o.anime_title === name && o.status === 2)
// If it's in both, it should say `watching`
if (isWatching && isPlanned) {
return 'Watching'
}
return isPlanned
? 'Watch List'
: isWatching
? 'Watching'
: ''
},
watch (item) {
this.$store.commit('streaming/play', {
show: true,
link: {
link: item.magnetLink,
name: `${item.title} - ${item.ep}`
}
})
isFollowed (name) {
const malLists = this.$store.state.mal.watchLists
const localLists = {
watching: this.$store.state.watchLists.lists.watching,
watchList: this.$store.state.watchLists.lists.watchList
}
const isWatching = localLists.watching.includes(name) || this.$_.find(malLists, (o) => o.anime_title === name && o.status === 1)
const isPlanned = localLists.watchList.includes(name) || this.$_.find(malLists, (o) => o.anime_title === name && o.status === 2)
// If it's in both, it should say `watching`
if (isWatching && isPlanned) {
return 'Watching'
}
return isPlanned
? 'Watch List'
: isWatching
? 'Watching'
: ''
},
watch (item) {
this.$store.commit('streaming/play', {
show: true,
link: {
link: item.magnetLink,
name: `${item.title} - ${item.ep}`
}
})
}
}
}
</script>
<style lang="stylus" scoped>

View File

@ -92,121 +92,121 @@
</template>
<script>
export default {
data () {
return {
query: '',
choices: [],
modalTitle: '',
modalText: '',
modal: false,
seasonChoices: [
{name: 'Winter', value: 'winter'},
{name: 'Spring', value: 'spring'},
{name: 'Summer', value: 'summer'},
{name: 'Fall', value: 'fall'}
]
}
export default {
data () {
return {
query: '',
choices: [],
modalTitle: '',
modalText: '',
modal: false,
seasonChoices: [
{name: 'Winter', value: 'winter'},
{name: 'Spring', value: 'spring'},
{name: 'Summer', value: 'summer'},
{name: 'Fall', value: 'fall'}
]
}
},
computed: {
seasons () {
return this.$store.state.seasons.seasons
},
computed: {
seasons () {
return this.$store.state.seasons.seasons
},
stats () {
return this.$store.state.seasons.seasonsStats
},
TVs () {
return this.seasons.TV
},
OVAs () {
return this.seasons.OVAs
},
ONAs () {
return this.seasons.ONAs
},
Specials () {
return this.seasons.Specials
},
Movies () {
return this.seasons.Movies
},
season () {
return [
'',
{name: 'TV', items: this.TVs},
{name: 'OVA', items: this.OVAs},
{name: 'ONA', items: this.ONAs},
{name: 'Specials', items: this.Specials},
{name: 'Movies', items: this.Movies}
]
},
computedSeason () {
const query = this.query.toLowerCase()
return query === ''
? this.season
: this.season.map((list) => {
if (list.items) {
return {
name: list.name,
items: list.items.filter((elem) => {
return elem.title.toLowerCase().indexOf(query) !== -1
})
}
} else return ''
})
}
stats () {
return this.$store.state.seasons.seasonsStats
},
methods: {
getDate (string) {
return string.split(' ').slice(0, 3).join(' ').split(',').slice(0, 2).join(', ')
},
episode (item) {
const nbEp = parseInt(item.nbEp)
if (nbEp > 0) {
if (nbEp === 1) return '1 episode'
else return `${nbEp} episodes`
} else return ''
},
refreshSeason () {
this.$store.dispatch('seasons/refresh')
},
openModal (title, text) {
console.log(`[${(new Date()).toLocaleTimeString()}]Opening modal for ${title}`)
this.modalTitle = title
this.modalText = text
this.modal = true
},
showChoices (name) {
this.$store.commit('setAddToChoiceTitle', name)
this.$store.commit('setAddToChoice', true)
},
downloadAll (name) {
console.log(`[${(new Date()).toLocaleTimeString()}]: Sending a request to download all episodes of ${name}.`)
const {quality, fansub} = this.$store.state.releases.params
this.$store.dispatch('downloader/download', {
name,
quality,
fansub,
fromEp: 0,
untilEp: 20000,
choice: 'si'
TVs () {
return this.seasons.TV
},
OVAs () {
return this.seasons.OVAs
},
ONAs () {
return this.seasons.ONAs
},
Specials () {
return this.seasons.Specials
},
Movies () {
return this.seasons.Movies
},
season () {
return [
'',
{name: 'TV', items: this.TVs},
{name: 'OVA', items: this.OVAs},
{name: 'ONA', items: this.ONAs},
{name: 'Specials', items: this.Specials},
{name: 'Movies', items: this.Movies}
]
},
computedSeason () {
const query = this.query.toLowerCase()
return query === ''
? this.season
: this.season.map((list) => {
if (list.items) {
return {
name: list.name,
items: list.items.filter((elem) => {
return elem.title.toLowerCase().indexOf(query) !== -1
})
}
} else return ''
})
},
showMal (item) {
const {link} = item
}
},
methods: {
getDate (string) {
return string.split(' ').slice(0, 3).join(' ').split(',').slice(0, 2).join(', ')
},
episode (item) {
const nbEp = parseInt(item.nbEp)
if (nbEp > 0) {
if (nbEp === 1) return '1 episode'
else return `${nbEp} episodes`
} else return ''
},
refreshSeason () {
this.$store.dispatch('seasons/refresh')
},
openModal (title, text) {
console.log(`[${(new Date()).toLocaleTimeString()}]Opening modal for ${title}`)
item.id = +link.split('/').splice(-2, 1)[0]
item.episodes = item.nbEp
this.modalTitle = title
this.modalText = text
this.$store.commit('mal/setEntry', item)
this.$store.commit('mal/showForm', true)
}
this.modal = true
},
showChoices (name) {
this.$store.commit('setAddToChoiceTitle', name)
this.$store.commit('setAddToChoice', true)
},
downloadAll (name) {
console.log(`[${(new Date()).toLocaleTimeString()}]: Sending a request to download all episodes of ${name}.`)
const {quality, fansub} = this.$store.state.releases.params
this.$store.dispatch('downloader/download', {
name,
quality,
fansub,
fromEp: 0,
untilEp: 20000,
choice: 'si'
})
},
showMal (item) {
const {link} = item
item.id = +link.split('/').splice(-2, 1)[0]
item.episodes = item.nbEp
this.$store.commit('mal/setEntry', item)
this.$store.commit('mal/showForm', true)
}
}
}
</script>
<style lang="stylus" scoped>
@ -229,7 +229,6 @@
font-size 16px
white-space pre-wrap
.refresh-button
display flex
align-items center

View File

@ -111,269 +111,269 @@
</template>
<script>
import _ from 'lodash'
import { mapGetters } from 'vuex'
import _ from 'lodash'
import { mapGetters } from 'vuex'
export default {
mounted () {
this.infos = this.$store.state.streaming.page.infos
this.currentEps = this.$store.state.streaming.page.eps
this.hasInfo = Object.keys(this.infos)
export default {
mounted () {
this.infos = this.$store.state.streaming.page.infos
this.currentEps = this.$store.state.streaming.page.eps
this.hasInfo = Object.keys(this.infos)
const { name } = this.$route.query
const { name } = this.$route.query
if (name) this.term = name
if (name) this.term = name
this.setEpsQuality()
},
this.setEpsQuality()
},
beforeDestroy () {
this.$store.commit('streaming/setInfos', this.infos)
this.$store.commit('streaming/setEps', this.currentEps)
},
beforeDestroy () {
this.$store.commit('streaming/setInfos', this.infos)
this.$store.commit('streaming/setEps', this.currentEps)
},
data: () => ({
animePerPage: 8,
isSearching: false,
downloadAllName: '',
qualityEp: {},
quality: '',
qualityModal: false,
qualityList: [],
pageIndex: 1,
infos: {},
currentEps: {},
hasInfo: []
}),
data: () => ({
animePerPage: 8,
isSearching: false,
downloadAllName: '',
qualityEp: {},
quality: '',
qualityModal: false,
qualityList: [],
pageIndex: 1,
infos: {},
currentEps: {},
hasInfo: []
}),
computed: {
...mapGetters('streaming', [
'files'
]),
term: {
set (val) {
this.$store.commit('streaming/setTerm', val)
},
get () {
return this.$store.state.streaming.page.term
}
computed: {
...mapGetters('streaming', [
'files'
]),
term: {
set (val) {
this.$store.commit('streaming/setTerm', val)
},
current: {
set (val) {
this.$store.commit('streaming/setCurrent', val)
},
get () {
return this.$store.state.streaming.page.current
}
},
animes () {
return Object.keys(this.files)
},
pageLength () {
return Math.ceil(this.animes.length / this.animePerPage)
},
fileRange () {
const index = this.pageIndex - 1
return {
inf: index * this.animePerPage,
sup: (index + 1) * this.animePerPage - 1
}
},
visibleAnimes () {
return this.animes.slice(this.fileRange.inf, this.fileRange.sup + 1)
},
currentInfo () {
return (this.current && this.infos[this.current]) || {}
get () {
return this.$store.state.streaming.page.term
}
},
current: {
set (val) {
this.$store.commit('streaming/setCurrent', val)
},
get () {
return this.$store.state.streaming.page.current
}
},
animes () {
return Object.keys(this.files)
},
pageLength () {
return Math.ceil(this.animes.length / this.animePerPage)
},
fileRange () {
const index = this.pageIndex - 1
methods: {
async search () {
if (!this.isSearching) {
if (!this.$store.state.isConnected) return
return {
inf: index * this.animePerPage,
sup: (index + 1) * this.animePerPage - 1
}
},
visibleAnimes () {
return this.animes.slice(this.fileRange.inf, this.fileRange.sup + 1)
},
currentInfo () {
return (this.current && this.infos[this.current]) || {}
}
},
this.isSearching = true
methods: {
async search () {
if (!this.isSearching) {
if (!this.$store.state.isConnected) return
this.pageIndex = 1
this.isSearching = true
await this.$store.dispatch('streaming/watch', {
name: this.term
})
this.pageIndex = 1
this.isSearching = false
await this.$store.dispatch('streaming/watch', {
name: this.term
})
this.isSearching = false
}
},
getLabel (anime) {
const len = this.$_.size(this.files[anime])
const totalLen = (this.infos[anime] && this.infos[anime].episodes) || 'XX'
return `${len} / ${totalLen} episode${len !== 1 ? 's' : ''}`
},
removeSub (name) {
return name.split(']').slice(1).join('')
},
play ({link, name}) {
this.$store.commit('streaming/play', {
show: true,
link: {
link,
name
}
},
getLabel (anime) {
const len = this.$_.size(this.files[anime])
const totalLen = (this.infos[anime] && this.infos[anime].episodes) || 'XX'
})
},
setCurrent (anime = '') {
this.current = anime
},
showQualityModal (anime) {
const files = this.files[anime]
this.qualityList = this.$_.map(files, (file) => file.quality)[0]
const prefQuality = this.$store.state.config.config.video.quality
this.downloadAllName = anime
this.quality = this.qualityList.includes(prefQuality)
? prefQuality
: this.qualityList[Math.floor(this.qualityList.length / 2)]
this.qualityModal = true
},
downloadAll () {
this.qualityModal = false
const name = this.downloadAllName
const quality = this.quality
const torrents = this.$_.filter(this.$store.state.streaming.page.torrents.magnets, (file) => {
return file.name.includes(name) && file.name.includes(quality)
}).map(({link}) => link)
torrents.forEach((link) => {
this.$axios.get('openThis', {
params: {
type: 'link',
link
}
})
})
},
async getEps () {
if (!this.currentEps[this.current]) {
const { id, title: name } = this.currentInfo
this.$log('Looking for episode information of', name)
const { data } = await this.$axios.get('searchEpsOnMal', {
params: {
id, name
}
})
this.$log('Received episode information of', name)
this.$set(this.currentEps, this.current, data)
} else {
this.$log('Cached episode information of', this.current)
}
},
getEpisodeTitle ({name}) {
const epNum = +name.split(' ').slice(-2, -1)[0] // nyanparser pls
if (this.currentEps[this.current] && this.currentEps[this.current].length) {
const info = this.currentEps[this.current].filter(({epNumber}) => epNumber === epNum)[0]
return info
? `${info.title} ${info.japaneseTitle ? '/ ' + info.japaneseTitle : ''}`
: 'No Data'
}
return 'No data.'
},
getEpNumber (name) {
return name.split(' ').slice(-2, -1)[0] // nyanparser pls
},
getEpAired (ep) {
if (this.currentEps[this.current] && this.currentEps[this.current].length) {
const epNum = +ep.name.split(' ').slice(-2, -1)[0] // nyanparser pls
const info = this.currentEps[this.current].filter(({epNumber}) => epNumber === epNum)[0]
return info
? (info && info.aired) || 'N/A'
: 'N/A'
}
return 'No data.'
},
setEpsQuality () {
const eps = this.$_.map(this.files[this.current], (ep, epNumber) => ep)
const prefQuality = this.$store.state.config.config.video.quality
eps.forEach((ep) => {
this.qualityEp[ep.name] = ep.quality.includes(prefQuality)
? prefQuality
: ep.quality[Math.floor(ep.quality.length / 2)]
})
},
act (action, { name: anime }) {
const quality = this.qualityEp[anime]
const ep = anime.split(' ').slice(-2, -1)[0] // nyanparser pls
const { link, name } = this.$store.state.streaming.page.torrents.magnets.filter((magnet) => {
return magnet.name.includes(this.current) && magnet.name.includes(ep) && magnet.name.includes(quality)
})[0]
if (action === 'play') {
const text = name.split(' ').slice(1, -1).join(' ') // nyanparser pls
return `${len} / ${totalLen} episode${len !== 1 ? 's' : ''}`
},
removeSub (name) {
return name.split(']').slice(1).join('')
},
play ({link, name}) {
this.$store.commit('streaming/play', {
show: true,
link: {
link,
name
name: text
}
})
},
setCurrent (anime = '') {
this.current = anime
},
showQualityModal (anime) {
const files = this.files[anime]
this.qualityList = this.$_.map(files, (file) => file.quality)[0]
const prefQuality = this.$store.state.config.config.video.quality
this.downloadAllName = anime
this.quality = this.qualityList.includes(prefQuality)
? prefQuality
: this.qualityList[Math.floor(this.qualityList.length / 2)]
this.qualityModal = true
},
downloadAll () {
this.qualityModal = false
const name = this.downloadAllName
const quality = this.quality
const torrents = this.$_.filter(this.$store.state.streaming.page.torrents.magnets, (file) => {
return file.name.includes(name) && file.name.includes(quality)
}).map(({link}) => link)
torrents.forEach((link) => {
this.$axios.get('openThis', {
params: {
type: 'link',
link
}
})
} else {
this.$axios.get('openThis', {
params: {
type: 'link',
link
}
})
},
async getEps () {
if (!this.currentEps[this.current]) {
const { id, title: name } = this.currentInfo
this.$log('Looking for episode information of', name)
const { data } = await this.$axios.get('searchEpsOnMal', {
params: {
id, name
}
})
this.$log('Received episode information of', name)
this.$set(this.currentEps, this.current, data)
} else {
this.$log('Cached episode information of', this.current)
}
},
getEpisodeTitle ({name}) {
const epNum = +name.split(' ').slice(-2, -1)[0] // nyanparser pls
if (this.currentEps[this.current] && this.currentEps[this.current].length) {
const info = this.currentEps[this.current].filter(({epNumber}) => epNumber === epNum)[0]
return info
? `${info.title} ${info.japaneseTitle ? '/ ' + info.japaneseTitle : ''}`
: 'No Data'
}
return 'No data.'
},
getEpNumber (name) {
return name.split(' ').slice(-2, -1)[0] // nyanparser pls
},
getEpAired (ep) {
if (this.currentEps[this.current] && this.currentEps[this.current].length) {
const epNum = +ep.name.split(' ').slice(-2, -1)[0] // nyanparser pls
const info = this.currentEps[this.current].filter(({epNumber}) => epNumber === epNum)[0]
return info
? (info && info.aired) || 'N/A'
: 'N/A'
}
return 'No data.'
},
setEpsQuality () {
const eps = this.$_.map(this.files[this.current], (ep, epNumber) => ep)
const prefQuality = this.$store.state.config.config.video.quality
eps.forEach((ep) => {
this.qualityEp[ep.name] = ep.quality.includes(prefQuality)
? prefQuality
: ep.quality[Math.floor(ep.quality.length / 2)]
})
},
act (action, { name: anime }) {
const quality = this.qualityEp[anime]
const ep = anime.split(' ').slice(-2, -1)[0] // nyanparser pls
const { link, name } = this.$store.state.streaming.page.torrents.magnets.filter((magnet) => {
return magnet.name.includes(this.current) && magnet.name.includes(ep) && magnet.name.includes(quality)
})[0]
if (action === 'play') {
const text = name.split(' ').slice(1, -1).join(' ') // nyanparser pls
this.$store.commit('streaming/play', {
show: true,
link: {
link,
name: text
}
})
} else {
this.$axios.get('openThis', {
params: {
type: 'link',
link
}
})
}
}
},
}
},
watch: {
term: _.debounce(async function () {
this.term.length > 2 && await this.search()
}, 750),
visibleAnimes (animes) {
animes.forEach(async (name) => {
if (!this.hasInfo.includes(name)) {
const term = name.split(' ').slice(1).join(' ')
watch: {
term: _.debounce(async function () {
this.term.length > 2 && await this.search()
}, 750),
visibleAnimes (animes) {
animes.forEach(async (name) => {
if (!this.hasInfo.includes(name)) {
const term = name.split(' ').slice(1).join(' ')
this.$log(`Looking for infos about ${term}.`)
this.$log(`Looking for infos about ${term}.`)
const { data } = await this.$axios.get(`getInfoFromMal`, {
params: {term}
})
const { data } = await this.$axios.get(`getInfoFromMal`, {
params: {term}
})
this.$log(`Received infos for ${term}.`)
this.$log(`Received infos for ${term}.`)
this.infos[name] = data
this.hasInfo.push(name)
}
})
},
async current (val) {
if (val) {
// Setting quality models for all episodes
this.setEpsQuality()
await this.getEps()
this.infos[name] = data
this.hasInfo.push(name)
}
})
},
async current (val) {
if (val) {
// Setting quality models for all episodes
this.setEpsQuality()
await this.getEps()
}
}
}
}
</script>
<style lang="stylus" scoped>
@ -493,7 +493,6 @@
overflow-y auto
overflow-x hidden
// Episode display
.ep-container
background-color rgba(30, 30, 30, 0.3)

View File

@ -59,186 +59,183 @@
</template>
<script>
const removeSelectedClasses = () => {
const elems = document.getElementsByClassName('elem')
const removeSelectedClasses = () => {
const elems = document.getElementsByClassName('elem')
// Remove all selected class
for (let j = 0, l = elems.length; j < l; ++j) elems[j].children[0].classList.remove('selected')
}
// Remove all selected class
for (let j = 0, l = elems.length; j < l; ++j) elems[j].children[0].classList.remove('selected')
}
export default {
components: {
'list-entry': () => import('components/listEntry.vue')
export default {
data () {
return {
selected: {
1: [],
2: [],
3: [],
4: [],
5: []
},
entries: {
1: '',
2: '',
3: '',
4: '',
5: ''
},
actionsList: [{
name: 'Watch list',
list: 'watchList',
icon: 'watch_later'
}, {
name: 'Watching',
list: 'watching',
icon: 'tv'
}, {
name: 'Seen',
list: 'seen',
icon: 'done_all'
}, {
name: 'On hold',
list: 'onHold',
icon: 'av_timer'
}, {
name: 'Dropped',
list: 'dropped',
icon: 'visibility_off'
}],
allSelected: {
1: false,
2: false,
3: false,
4: false,
5: false
},
listNames: {
1: 'watchList',
2: 'watching',
3: 'seen',
4: 'onHold',
5: 'dropped'
}
}
},
computed: {
watchList () {
return this.$store.state.watchLists.lists.watchList
},
data () {
return {
selected: {
1: [],
2: [],
3: [],
4: [],
5: []
},
entries: {
1: '',
2: '',
3: '',
4: '',
5: ''
},
actionsList: [{
name: 'Watch list',
list: 'watchList',
icon: 'watch_later'
}, {
name: 'Watching',
list: 'watching',
icon: 'tv'
}, {
name: 'Seen',
list: 'seen',
icon: 'done_all'
}, {
name: 'On hold',
list: 'onHold',
icon: 'av_timer'
}, {
name: 'Dropped',
list: 'dropped',
icon: 'visibility_off'
}],
allSelected: {
1: false,
2: false,
3: false,
4: false,
5: false
},
listNames: {
1: 'watchList',
2: 'watching',
3: 'seen',
4: 'onHold',
5: 'dropped'
}
seen () {
return this.$store.state.watchLists.lists.seen
},
watching () {
return this.$store.state.watchLists.lists.watching
},
onHold () {
return this.$store.state.watchLists.lists.onHold
},
dropped () {
return this.$store.state.watchLists.lists.dropped
},
lists () {
return [
this.watchList,
this.watching,
this.seen,
this.onHold,
this.dropped
]
}
},
methods: {
actions (i) {
return this.actionsList.filter((x) => { return x !== this.actionsList[i - 1] })
},
addEntry (i) {
if (this.entries[i] !== '') {
console.log(`[${(new Date()).toLocaleTimeString()}]: Adding ${this.entries[i]} to list.`)
this.$store.dispatch('watchLists/updateList', {
entry: this.entries[i],
listName: this.listNames[i]
})
}
this.entries[i] = ''
},
deleteEntry (name, i) {
removeSelectedClasses()
this.$store.dispatch('watchLists/removeFromList', {
listName: this.actionsList[i - 1].list,
entry: name
})
},
select (item, i) {
const elem = document.getElementsByClassName(item.split(' ').join('-'))[0].children[0]
if (elem.classList.contains('selected') === true) {
elem.classList.remove('selected')
this.selected[i] = this.selected[i].filter((x) => { return !(x === item) })
this.allSelected[i] = false
} else {
elem.className += ' selected'
this.selected[i].push(item)
if (this.selected[i].length === this.lists[[i - 1]]) this.allSelected[i] = true
}
},
computed: {
watchList () {
return this.$store.state.watchLists.lists.watchList
},
seen () {
return this.$store.state.watchLists.lists.seen
},
watching () {
return this.$store.state.watchLists.lists.watching
},
onHold () {
return this.$store.state.watchLists.lists.onHold
},
dropped () {
return this.$store.state.watchLists.lists.dropped
},
lists () {
return [
this.watchList,
this.watching,
this.seen,
this.onHold,
this.dropped
]
selectAll (i) {
const list = this.lists[i - 1]
if (this.selected[i].length === list.length) {
const elems = document.getElementsByClassName('elem')
this.selected[i] = []
for (let j = 0, l = elems.length; j < l; ++j) { elems[j].children[0].classList.remove('selected') }
this.allSelected[i] = false
} else {
list.forEach((elem) => {
// Color element
const tmpElem = document.getElementsByClassName(elem.split(' ').join('-'))[0].children[0]
if (!tmpElem.classList.contains('selected') === true) tmpElem.className += ' selected'
})
// Add all elements to selected
this.selected[i] = [...list]
this.allSelected[i] = true
}
},
methods: {
actions (i) {
return this.actionsList.filter((x) => { return x !== this.actionsList[i - 1] })
},
addEntry (i) {
if (this.entries[i] !== '') {
console.log(`[${(new Date()).toLocaleTimeString()}]: Adding ${this.entries[i]} to list.`)
this.$store.dispatch('watchLists/updateList', {
entry: this.entries[i],
listName: this.listNames[i]
})
}
this.entries[i] = ''
},
deleteEntry (name, i) {
removeSelectedClasses()
selectLabel (i) {
return this.allSelected[i] ? 'Unselect all' : 'Select all'
},
moveTo (name, i) {
this.selected[i].forEach((anime) => {
this.$store.dispatch('watchLists/updateList', {
listName: name,
entry: anime
})
this.$store.dispatch('watchLists/removeFromList', {
listName: this.actionsList[i - 1].list,
entry: name
entry: anime
})
},
select (item, i) {
const elem = document.getElementsByClassName(item.split(' ').join('-'))[0].children[0]
})
if (elem.classList.contains('selected') === true) {
elem.classList.remove('selected')
this.selected[i] = this.selected[i].filter((x) => { return !(x === item) })
this.allSelected[i] = false
} else {
elem.className += ' selected'
this.selected[i].push(item)
if (this.selected[i].length === this.lists[[i - 1]]) this.allSelected[i] = true
}
},
selectAll (i) {
const list = this.lists[i - 1]
if (this.selected[i].length === list.length) {
const elems = document.getElementsByClassName('elem')
this.selected[i] = []
for (let j = 0, l = elems.length; j < l; ++j) { elems[j].children[0].classList.remove('selected') }
this.allSelected[i] = false
} else {
list.forEach((elem) => {
// Color element
const tmpElem = document.getElementsByClassName(elem.split(' ').join('-'))[0].children[0]
if (!tmpElem.classList.contains('selected') === true) tmpElem.className += ' selected'
})
// Add all elements to selected
this.selected[i] = [...list]
this.allSelected[i] = true
}
},
selectLabel (i) {
return this.allSelected[i] ? 'Unselect all' : 'Select all'
},
moveTo (name, i) {
this.selected[i].forEach((anime) => {
this.$store.dispatch('watchLists/updateList', {
listName: name,
entry: anime
})
this.$store.dispatch('watchLists/removeFromList', {
listName: this.actionsList[i - 1].list,
entry: anime
})
removeSelectedClasses()
},
deleteSelected (i) {
this.selected[i].forEach((anime) => {
this.$store.dispatch('watchLists/removeFromList', {
listName: this.actionsList[i - 1].list,
entry: anime
})
})
removeSelectedClasses()
},
deleteSelected (i) {
this.selected[i].forEach((anime) => {
this.$store.dispatch('watchLists/removeFromList', {
listName: this.actionsList[i - 1].list,
entry: anime
})
})
removeSelectedClasses()
}
removeSelectedClasses()
}
}
}
</script>
<style lang="stylus" scoped>