mirror of
https://github.com/mmjee/Piped-Material.git
synced 2024-12-06 19:26:36 +01:00
Merge pull request 'Restructuring and Refactor' (#5) from feature-structural_improvements into master
Reviewed-on: https://git.maharshi.ninja/root/Piped-redesign/pulls/5
This commit is contained in:
@@ -9,6 +9,8 @@
|
||||
"dependencies": {
|
||||
"@babel/eslint-parser": "^7.15.0",
|
||||
"@fontsource/hind-siliguri": "^4.5.0",
|
||||
"@mdi/font": "^6.4.95",
|
||||
"axios": "^0.23.0",
|
||||
"core-js": "^3.16.1",
|
||||
"dompurify": "^2.3.1",
|
||||
"hotkeys-js": "^3.8.7",
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@5.x/css/materialdesignicons.min.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
|
||||
+5
-4
@@ -4,10 +4,9 @@
|
||||
app
|
||||
color="primary"
|
||||
dark
|
||||
class="pt-3"
|
||||
v-if="$vuetify.breakpoint.mdAndUp"
|
||||
>
|
||||
<v-row dense>
|
||||
<v-row dense align="center" justify="center">
|
||||
<v-col md="1" v-for="link in links" :key="link.id">
|
||||
<v-btn
|
||||
text
|
||||
@@ -18,8 +17,9 @@
|
||||
{{ $t(link.name) }}
|
||||
</v-btn>
|
||||
</v-col>
|
||||
<v-col md="2">
|
||||
<v-col md="2" class="mx-3">
|
||||
<v-select
|
||||
class="mt-6"
|
||||
dense
|
||||
:items="languageOptions"
|
||||
label="Language"
|
||||
@@ -133,7 +133,8 @@ export default {
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.$store.dispatch('loadState')
|
||||
this.$store.dispatch('prefs/loadState')
|
||||
this.$store.dispatch('auth/initializeAuth')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -55,7 +55,7 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
shouldAutoPlay () {
|
||||
return this.$store.getters.getPreferenceBoolean('playerAutoPlay', true)
|
||||
return this.$store.getters['prefs/getPreferenceBoolean']('playerAutoPlay', true)
|
||||
},
|
||||
|
||||
preferredVideoCodecs () {
|
||||
@@ -142,7 +142,7 @@ export default {
|
||||
|
||||
localPlayer.configure(
|
||||
'streaming.bufferingGoal',
|
||||
Math.max(this.$store.getters.getPreferenceNumber('bufferGoal', 10), 10)
|
||||
this.$store.getters['prefs/getPreferenceNumber']('bufferGoal', 10)
|
||||
)
|
||||
|
||||
this.setPlayerAttrs(localPlayer, videoEl, uri, mime, shaka)
|
||||
@@ -166,14 +166,14 @@ export default {
|
||||
})
|
||||
|
||||
videoEl.addEventListener('volumechange', () => {
|
||||
this.$store.commit('setPrefs', {
|
||||
this.$store.commit('prefs/setPrefs', {
|
||||
id: 'volume',
|
||||
value: videoEl.volume
|
||||
})
|
||||
})
|
||||
|
||||
videoEl.addEventListener('ratechange', () => {
|
||||
this.$store.commit('setPrefs', {
|
||||
this.$store.commit('prefs/setPrefs', {
|
||||
id: 'rate',
|
||||
value: videoEl.playbackRate
|
||||
})
|
||||
@@ -206,7 +206,7 @@ export default {
|
||||
|
||||
this.player = player
|
||||
|
||||
const disableVideo = this.$store.getters.getPreferenceBoolean('listen', false) && !this.video.livestream
|
||||
const disableVideo = this.$store.getters['prefs/getPreferenceBoolean']('listen', false) && !this.video.livestream
|
||||
|
||||
this.player.configure({
|
||||
preferredVideoCodecs: this.preferredVideoCodecs,
|
||||
@@ -216,9 +216,8 @@ export default {
|
||||
}
|
||||
})
|
||||
|
||||
const quality = this.$store.getters.getPreferenceNumber('quality', 0)
|
||||
const qualityConds =
|
||||
quality > 0 && (this.video.audioStreams.length > 0 || this.video.livestream) && !disableVideo
|
||||
const quality = this.$store.getters['prefs/getPreferenceNumber']('quality', 0)
|
||||
const qualityConds = quality > 0 && (this.video.audioStreams.length > 0 || this.video.livestream) && !disableVideo
|
||||
if (qualityConds) this.player.configure('abr.enabled', false)
|
||||
|
||||
player.load(uri, 0, mime).then(() => {
|
||||
@@ -248,8 +247,8 @@ export default {
|
||||
subtitle.name
|
||||
)
|
||||
})
|
||||
videoEl.volume = this.$store.getters.getPreferenceNumber('volume', 1)
|
||||
videoEl.playbackRate = videoEl.defaultPlaybackRate = this.$store.getters.getPreferenceNumber('rate', 1)
|
||||
videoEl.volume = this.$store.getters['prefs/getPreferenceNumber']('volume', 1)
|
||||
videoEl.playbackRate = videoEl.defaultPlaybackRate = this.$store.getters['prefs/getPreferenceNumber']('rate', 1)
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,29 +1,26 @@
|
||||
<template>
|
||||
<v-card class="pa-1" elevation="2" outlined>
|
||||
<v-row align="center" justify="center">
|
||||
<v-col md="1">
|
||||
<v-avatar size="96" class="mx-3">
|
||||
<v-img :src="comment.thumbnail"></v-img>
|
||||
</v-avatar>
|
||||
</v-col>
|
||||
<v-col md="11">
|
||||
<v-card-title class="subtitle-1">
|
||||
<v-icon v-if="comment.pinned" class="mx-2">mdi-pin</v-icon>
|
||||
<router-link :to="comment.commentorUrl" class="text-decoration-none black--text">
|
||||
<b>{{ comment.author }}</b><v-icon v-if="comment.verified">mdi-account-check</v-icon>
|
||||
</router-link>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<div v-html="renderedCommentTxt" />
|
||||
<v-row align="center" justify="center" no-gutters>
|
||||
<v-col md="1">
|
||||
<v-avatar size="96" class="mx-3">
|
||||
<v-img :src="comment.thumbnail" />
|
||||
</v-avatar>
|
||||
</v-col>
|
||||
<v-col md="11">
|
||||
<v-card-text>
|
||||
<v-icon v-if="comment.pinned" class="mx-2">mdi-pin</v-icon>
|
||||
<router-link :to="comment.commentorUrl" class="text-decoration-none black--text">
|
||||
<b>{{ comment.author }}</b><v-icon v-if="comment.verified">mdi-account-check</v-icon>
|
||||
</router-link>
|
||||
|
||||
<v-divider class="my-2" />
|
||||
<div v-html="renderedCommentTxt" />
|
||||
|
||||
<v-icon>mdi-thumb-up</v-icon> {{ numberFormat(comment.likeCount) }}
|
||||
<v-icon v-if="comment.hearted" class="ml-4">mdi-heart</v-icon>
|
||||
</v-card-text>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card>
|
||||
<v-divider class="my-2" />
|
||||
|
||||
<v-icon>mdi-thumb-up</v-icon> {{ numberFormat(comment.likeCount) }}
|
||||
<v-icon v-if="comment.hearted" class="ml-4">mdi-heart</v-icon>
|
||||
</v-card-text>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import Vue from 'vue'
|
||||
import App from './App.vue'
|
||||
|
||||
import '@fontsource/hind-siliguri/latin.css'
|
||||
import '@mdi/font/css/materialdesignicons.min.css'
|
||||
import '@/styles/main.scss'
|
||||
|
||||
import { i18n } from '@/plugins/i18n'
|
||||
|
||||
+5
-3
@@ -65,10 +65,12 @@ export async function changeLocale (lang) {
|
||||
}
|
||||
|
||||
function initializeLocalLocale () {
|
||||
const lang = window.localStorage.getItem('LOCALE')
|
||||
if (lang != null) {
|
||||
changeLocale(lang).catch(e => console.error(e))
|
||||
let lang = window.localStorage.getItem('LOCALE')
|
||||
if (lang == null) {
|
||||
// Default language
|
||||
lang = 'en'
|
||||
}
|
||||
changeLocale(lang).catch(e => console.error(e))
|
||||
}
|
||||
|
||||
initializeLocalLocale()
|
||||
|
||||
@@ -55,7 +55,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
async fetchChannel () {
|
||||
return this.$store.dispatch('fetchJson', {
|
||||
return this.$store.dispatch('auth/makeRequest', {
|
||||
path: '/' + this.$route.params.path + '/' + this.$route.params.channelId
|
||||
})
|
||||
},
|
||||
@@ -71,7 +71,7 @@ export default {
|
||||
},
|
||||
|
||||
fetchMoreVideos () {
|
||||
this.$store.dispatch('fetchJson', {
|
||||
this.$store.dispatch('auth/makeRequest', {
|
||||
path: '/nextpage/channel/' + this.channel.id,
|
||||
params: {
|
||||
nextpage: this.channel.nextpage
|
||||
|
||||
@@ -61,7 +61,7 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
getRssUrl () {
|
||||
return this.$store.getters.apiUrl + '/rss/playlists/' + this.$route.query.list
|
||||
return this.$store.getters['prefs/apiUrl'] + '/rss/playlists/' + this.$route.query.list
|
||||
},
|
||||
|
||||
chunkedByFour () {
|
||||
@@ -70,7 +70,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
async fetchPlaylist () {
|
||||
return this.$store.dispatch('fetchJson', {
|
||||
return this.$store.dispatch('auth/makeRequest', {
|
||||
path: '/playlists/' + this.$route.query.list
|
||||
})
|
||||
},
|
||||
|
||||
@@ -3,8 +3,24 @@
|
||||
<h1 class="text-h4 text-center">{{ $t('titles.preferences') }}</h1>
|
||||
<v-divider class="ma-4" />
|
||||
<div style="display: flex;" v-for="(opt, optId) in options" :key="optId">
|
||||
<v-simple-checkbox v-if="opt.type === 'bool'" :value="$store.getters.getPreferenceBoolean(opt.id, opt.default)" @input="setValue(opt.id, $event)" />
|
||||
<v-select v-else-if="opt.type === 'select'" :label="$t('preferences.' + opt.id)" :value="$store.getters.getPreferenceString(opt.id, opt.default)" @input="setValue(opt.id, $event)" :items="opt.options" />
|
||||
<v-simple-checkbox
|
||||
v-if="opt.type === 'bool'"
|
||||
:value="$store.getters['prefs/getPreferenceBoolean'](opt.id, opt.default)"
|
||||
@input="setValue(opt.id, $event)"
|
||||
/>
|
||||
<v-text-field
|
||||
v-else-if="opt.type === 'number'"
|
||||
type="number"
|
||||
:label="$t('preferences.' + opt.id)"
|
||||
:value="$store.getters['prefs/getPreferenceNumber'](opt.id, opt.default)"
|
||||
@input="setValue(opt.id, Number($event))"
|
||||
/>
|
||||
<v-select
|
||||
v-else-if="opt.type === 'select'"
|
||||
:label="$t('preferences.' + opt.id)"
|
||||
:value="$store.getters['prefs/getPreference'](opt.id, opt.default)"
|
||||
@input="setValue(opt.id, $event)" :items="opt.options"
|
||||
/>
|
||||
<p v-if="opt.type === 'bool'">{{ $t('preferences.' + opt.id) }}</p><br />
|
||||
</div>
|
||||
<h5 class="text-h5">{{ $t('actions.instances_list') }}</h5>
|
||||
@@ -47,6 +63,11 @@ export default {
|
||||
})))
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'bufferGoal',
|
||||
type: 'number',
|
||||
default: 10
|
||||
},
|
||||
{
|
||||
id: 'region',
|
||||
type: 'select',
|
||||
@@ -139,7 +160,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
setValue (k, v) {
|
||||
this.$store.commit('setPrefs', {
|
||||
this.$store.commit('prefs/setPrefs', {
|
||||
id: k,
|
||||
value: v
|
||||
})
|
||||
|
||||
@@ -54,7 +54,7 @@ export default {
|
||||
methods: {
|
||||
async refreshSuggestions () {
|
||||
this.requestInProgress = true
|
||||
this.searchSuggestions = await this.$store.dispatch('fetchJson', {
|
||||
this.searchSuggestions = await this.$store.dispatch('auth/makeRequest', {
|
||||
path: '/suggestions',
|
||||
params: {
|
||||
query: this.searchText
|
||||
|
||||
@@ -98,7 +98,7 @@ export default {
|
||||
},
|
||||
|
||||
async fetchResults () {
|
||||
return this.$store.dispatch('fetchJson', {
|
||||
return this.$store.dispatch('auth/makeRequest', {
|
||||
path: 'search',
|
||||
params: {
|
||||
q: this.$route.query.search_query,
|
||||
@@ -127,7 +127,7 @@ export default {
|
||||
},
|
||||
|
||||
fetchMoreResults () {
|
||||
this.$store.dispatch('fetchJson', {
|
||||
this.$store.dispatch('auth/makeRequest', {
|
||||
path: '/nextpage/search',
|
||||
params: {
|
||||
nextpage: this.results.nextpage,
|
||||
|
||||
@@ -31,16 +31,16 @@ export default {
|
||||
},
|
||||
|
||||
mounted () {
|
||||
const region = this.$store.getters.getPreferenceString('region', 'US')
|
||||
const region = this.$store.getters['prefs/getPreference']('region', 'US')
|
||||
|
||||
this.fetchTrending(region).then(videos => (this.videos = videos))
|
||||
},
|
||||
methods: {
|
||||
async fetchTrending (region) {
|
||||
return this.$store.dispatch('fetchJson', {
|
||||
return this.$store.dispatch('auth/makeRequest', {
|
||||
path: '/trending',
|
||||
params: {
|
||||
region: region || 'US'
|
||||
region: region
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
+20
-31
@@ -5,7 +5,7 @@
|
||||
:video="video"
|
||||
:skip-to-time="'t' in $route.query ? Number($route.query.t) : null"
|
||||
:sponsors="sponsors"
|
||||
:selectedAutoPlay="this.$store.getters.getPreferenceBoolean('autoplay')"
|
||||
:selectedAutoPlay="$store.getters['prefs/getPreferenceBoolean']('autoplay')"
|
||||
:selectedAutoLoop="selectedAutoLoop"
|
||||
@videoEnded="videoEnded"
|
||||
/>
|
||||
@@ -47,12 +47,12 @@
|
||||
<div>
|
||||
<v-img :src="video.uploaderAvatar" height="48" width="48" class="rounded-circle" />
|
||||
</div>
|
||||
<div class="text-h5 ml-4">
|
||||
<a :href="video.uploaderUrl" class="text-h5 ml-4 text-decoration-none">
|
||||
{{ video.uploader }}
|
||||
</div>
|
||||
</a>
|
||||
<div class="ml-4">
|
||||
<v-btn
|
||||
v-if="$store.state.isAuthenticated"
|
||||
v-if="$store.state['auth/isAuthenticated']"
|
||||
@click="subscribeHandler"
|
||||
color="primary"
|
||||
>
|
||||
@@ -135,7 +135,7 @@ export default {
|
||||
initialize () {
|
||||
this.getVideoData()
|
||||
this.getSponsors()
|
||||
if (this.$store.getters.getPreferenceBoolean('comments', true)) this.getComments()
|
||||
if (this.$store.getters['prefs/getPreferenceBoolean']('comments', true)) this.getComments()
|
||||
},
|
||||
|
||||
videoEnded () {
|
||||
@@ -158,18 +158,19 @@ export default {
|
||||
},
|
||||
|
||||
fetchVideo () {
|
||||
return this.$store.dispatch('fetchJson', {
|
||||
return this.$store.dispatch('auth/makeRequest', {
|
||||
method: 'GET',
|
||||
path: '/streams/' + this.getVideoId()
|
||||
})
|
||||
},
|
||||
|
||||
async fetchSponsors () {
|
||||
return this.$store.dispatch('fetchJson', {
|
||||
return this.$store.dispatch('auth/makeRequest', {
|
||||
path: '/sponsors/' + this.getVideoId(),
|
||||
params: {
|
||||
category:
|
||||
'["' +
|
||||
this.$store.getters.getPreferenceString('selectedSkip', 'sponsor,interaction,selfpromo,music_offtopic').replaceAll(
|
||||
this.$store.getters['prefs/getPreference']('selectedSkip', 'sponsor,interaction,selfpromo,music_offtopic').replaceAll(
|
||||
',',
|
||||
'","'
|
||||
) +
|
||||
@@ -178,7 +179,7 @@ export default {
|
||||
})
|
||||
},
|
||||
fetchComments () {
|
||||
return this.$store.dispatch('fetchJson', {
|
||||
return this.$store.dispatch('auth/makeRequest', {
|
||||
path: '/comments/' + this.getVideoId()
|
||||
})
|
||||
},
|
||||
@@ -190,7 +191,7 @@ export default {
|
||||
},
|
||||
|
||||
fetchMoreComments () {
|
||||
this.$store.dispatch('fetchJson', {
|
||||
this.$store.dispatch('auth/makeRequest', {
|
||||
path: '/nextpage/comments/' + this.getVideoId(),
|
||||
params: {
|
||||
nextpage: this.comments.nextpage
|
||||
@@ -202,7 +203,7 @@ export default {
|
||||
},
|
||||
|
||||
onAutoplayChg (ev) {
|
||||
this.$store.commit('setPrefs', {
|
||||
this.$store.commit('prefs/setPrefs', {
|
||||
id: 'autoplay',
|
||||
value: ev
|
||||
})
|
||||
@@ -231,41 +232,29 @@ export default {
|
||||
})
|
||||
},
|
||||
async getSponsors () {
|
||||
if (this.$store.getters.getPreferenceString('sponsorblock', true)) { this.fetchSponsors().then(data => (this.sponsors = data)) }
|
||||
if (this.$store.getters['prefs/getPreference']('sponsorblock', true)) { this.fetchSponsors().then(data => (this.sponsors = data)) }
|
||||
},
|
||||
async getComments () {
|
||||
this.fetchComments().then(data => (this.comments = data))
|
||||
},
|
||||
async fetchSubscribedStatus () {
|
||||
if (!this.channelId) return
|
||||
if (!this.channelId || !this.$store.state['auth/isAuthenticated']) return
|
||||
|
||||
this.$store.dispatch('fetchJson', {
|
||||
this.$store.dispatch('auth/makeRequest', {
|
||||
path: '/subscribed',
|
||||
params: {
|
||||
channelId: this.channelId
|
||||
},
|
||||
options: {
|
||||
headers: {
|
||||
Authorization: this.$store.getters.getAuthToken
|
||||
}
|
||||
}
|
||||
}).then(json => {
|
||||
this.subscribed = json.subscribed
|
||||
})
|
||||
},
|
||||
subscribeHandler () {
|
||||
this.$store.dispatch('fetchJson', {
|
||||
this.$store.dispatch('auth/makeRequest', {
|
||||
method: 'POST',
|
||||
path: (this.subscribed ? '/unsubscribe' : '/subscribe'),
|
||||
params: null,
|
||||
options: {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
channelId: this.channelId
|
||||
}),
|
||||
headers: {
|
||||
Authorization: this.$store.getters.getAuthToken,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
data: {
|
||||
channelId: this.channelId
|
||||
}
|
||||
})
|
||||
this.subscribed = !this.subscribed
|
||||
@@ -277,7 +266,7 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
isAutoplayEnabled () {
|
||||
return this.$store.getters.getPreferenceBoolean('autoplay')
|
||||
return this.$store.getters['prefs/getPreferenceBoolean']('autoplay')
|
||||
}
|
||||
},
|
||||
components: {
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import axios from 'axios'
|
||||
import { isPlainObject } from 'lodash-es'
|
||||
|
||||
const AuthenticationStore = {
|
||||
namespaced: true,
|
||||
|
||||
state: () => ({
|
||||
isAuthenticated: false,
|
||||
authToken: null
|
||||
}),
|
||||
|
||||
mutations: {
|
||||
replaceAuth (state, data) {
|
||||
state.isAuthenticated = data.isAuthenticated ?? state.isAuthenticated
|
||||
state.authToken = data.authToken ?? state.authToken
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
initializeAuth ({ commit }) {
|
||||
const data = window.localStorage.getItem('AUTH')
|
||||
if (data != null) {
|
||||
commit('replaceAuth', data)
|
||||
}
|
||||
},
|
||||
|
||||
async makeRequest ({
|
||||
commit,
|
||||
state,
|
||||
rootGetters
|
||||
}, {
|
||||
path,
|
||||
method,
|
||||
data,
|
||||
params
|
||||
}) {
|
||||
if (state.isAuthenticated) {
|
||||
if (isPlainObject(params)) {
|
||||
params.authToken = state.authToken
|
||||
} else {
|
||||
params = {
|
||||
authToken: state.authToken
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const { data: resp } = await axios({
|
||||
baseURL: rootGetters['prefs/apiUrl'],
|
||||
method,
|
||||
url: path,
|
||||
params,
|
||||
headers: state.isAuthenticated
|
||||
? {
|
||||
Authorization: state.authToken
|
||||
}
|
||||
: undefined
|
||||
})
|
||||
|
||||
return resp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
AuthenticationStore
|
||||
}
|
||||
+4
-130
@@ -1,141 +1,15 @@
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
|
||||
import { get as _get, keys as _keys, set as _set, cloneDeep as _cloneDeep, isPlainObject, isString } from 'lodash-es'
|
||||
import { PrefsStore } from '@/store/prefs-store'
|
||||
import { AuthenticationStore } from '@/store/authentication-store'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
const store = new Vuex.Store({
|
||||
state: {
|
||||
isAuthenticated: false,
|
||||
prefs: {}
|
||||
},
|
||||
mutations: {
|
||||
setAuthenticated (state, authStatus) {
|
||||
state.isAuthenticated = authStatus
|
||||
},
|
||||
setPrefs (state, {
|
||||
id,
|
||||
value
|
||||
}) {
|
||||
const clonedPrefs = _cloneDeep(state.prefs)
|
||||
_set(clonedPrefs, id, value)
|
||||
state.prefs = clonedPrefs
|
||||
},
|
||||
|
||||
replacePrefs (state, nextPrefs) {
|
||||
state.prefs = nextPrefs
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
loadState ({ commit }) {
|
||||
try {
|
||||
const jv = window.localStorage.getItem('PREFERENCES')
|
||||
if (isString(jv) && jv.length !== 0) {
|
||||
const p = JSON.parse(jv)
|
||||
commit('replacePrefs', p)
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Error:', e)
|
||||
}
|
||||
},
|
||||
|
||||
fetchJson ({ getters }, {
|
||||
path,
|
||||
params = {},
|
||||
options = {}
|
||||
}) {
|
||||
const url = new URL(getters.apiUrl)
|
||||
|
||||
url.pathname = path
|
||||
if (params) {
|
||||
for (const param of _keys(params)) {
|
||||
url.searchParams.set(param, params[param])
|
||||
}
|
||||
|
||||
const at = getters.getAuthToken
|
||||
if (at) {
|
||||
url.searchParams.set('authToken', at)
|
||||
}
|
||||
}
|
||||
|
||||
return fetch(url.href, options).then(response => {
|
||||
return response.json()
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
getters: {
|
||||
getPreferenceString: state => (id, default_) => {
|
||||
return _get(state.prefs, id, default_)
|
||||
},
|
||||
|
||||
getPreferenceBoolean: (_, getters) => (...args) => {
|
||||
const v = getters.getPreferenceString(...args)
|
||||
|
||||
switch (v) {
|
||||
case 'true':
|
||||
case true:
|
||||
case '1':
|
||||
case 'on':
|
||||
case 'yes':
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
},
|
||||
|
||||
getPreferenceNumber: (_, getters) => (id, default_) => {
|
||||
const v = getters.getPreferenceString(id, default_)
|
||||
|
||||
const n = Number(v)
|
||||
if (!Number.isFinite(n)) {
|
||||
return default_
|
||||
} else {
|
||||
return n
|
||||
}
|
||||
},
|
||||
|
||||
getEffectiveTheme (state, getters) {
|
||||
let theme = getters.getPreferenceString('theme', 'light')
|
||||
if (theme === 'auto') {
|
||||
theme = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
|
||||
}
|
||||
return theme
|
||||
},
|
||||
|
||||
backgroundColor (state, getters) {
|
||||
return getters.getEffectiveTheme === 'light' ? '#fff' : '#0b0e0f'
|
||||
},
|
||||
secondaryBackgroundColor (state, getters) {
|
||||
return getters.getEffectiveTheme === 'light' ? '#e5e5e5' : '#242727'
|
||||
},
|
||||
foregroundColor (state, getters) {
|
||||
return getters.getEffectiveTheme === 'light' ? '#15191a' : '#0b0e0f'
|
||||
},
|
||||
secondaryForegroundColor (state, getters) {
|
||||
return getters.getEffectiveTheme === 'light' ? '#666' : '#393d3d'
|
||||
},
|
||||
|
||||
getAuthToken (state, getters) {
|
||||
return getters.getPreferenceString(['authToken', getters])
|
||||
},
|
||||
|
||||
apiUrl (state, getters) {
|
||||
return getters.getPreferenceString('instance', 'https://pipedapi.kavin.rocks')
|
||||
},
|
||||
|
||||
authenticated (state, getters) {
|
||||
return getters.getAuthToken !== undefined
|
||||
}
|
||||
},
|
||||
modules: {
|
||||
}
|
||||
})
|
||||
|
||||
store.watch(state => state.prefs, (nextPrefs) => {
|
||||
if (isPlainObject(nextPrefs)) {
|
||||
window.localStorage.setItem('PREFERENCES', JSON.stringify(nextPrefs))
|
||||
prefs: PrefsStore,
|
||||
auth: AuthenticationStore
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import { get as _get, isString, set as _set } from 'lodash-es'
|
||||
|
||||
const PrefsStore = {
|
||||
namespaced: true,
|
||||
state: () => ({
|
||||
prefs: {}
|
||||
}),
|
||||
mutations: {
|
||||
setPrefs (state, {
|
||||
id,
|
||||
value
|
||||
}) {
|
||||
_set(state.prefs, id, value)
|
||||
window.localStorage.setItem('PREFERENCES', JSON.stringify(state.prefs))
|
||||
},
|
||||
|
||||
replacePrefs (state, nextPrefs) {
|
||||
state.prefs = nextPrefs
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
loadState ({ commit }) {
|
||||
try {
|
||||
const jv = window.localStorage.getItem('PREFERENCES')
|
||||
if (isString(jv) && jv.length !== 0) {
|
||||
const p = JSON.parse(jv)
|
||||
commit('replacePrefs', p)
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Error:', e)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getters: {
|
||||
getPreference: state => (id, default_) => {
|
||||
return _get(state.prefs, id, default_)
|
||||
},
|
||||
|
||||
getPreferenceBoolean: (_, getters) => (...args) => {
|
||||
const v = getters.getPreference(...args)
|
||||
|
||||
switch (v) {
|
||||
case 'true':
|
||||
case true:
|
||||
case '1':
|
||||
case 'on':
|
||||
case 'yes':
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
},
|
||||
|
||||
getPreferenceNumber: (_, getters) => (id, default_) => {
|
||||
const v = getters.getPreference(id, default_)
|
||||
|
||||
const n = Number(v)
|
||||
if (!Number.isFinite(n)) {
|
||||
return default_
|
||||
} else {
|
||||
return n
|
||||
}
|
||||
},
|
||||
|
||||
apiUrl (state, getters) {
|
||||
return getters.getPreference('instance', 'https://pipedapi.kavin.rocks')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
PrefsStore
|
||||
}
|
||||
@@ -12,4 +12,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
@include addFonts('Hind Siliguri');
|
||||
.latin {
|
||||
@include addFonts('Helvetica Neue');
|
||||
}
|
||||
|
||||
.bengali {
|
||||
@include addFonts('Hind Silliguri')
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
},
|
||||
"preferences": {
|
||||
"playerAutoplay": "Autoplay Video",
|
||||
"bufferGoal": "Buffering Goal",
|
||||
"listen": "Audio Only",
|
||||
"quality": "Default Quality",
|
||||
"region": "Country Selection",
|
||||
|
||||
@@ -1001,6 +1001,11 @@
|
||||
cssnano-preset-default "^4.0.0"
|
||||
postcss "^7.0.0"
|
||||
|
||||
"@mdi/font@^6.4.95":
|
||||
version "6.4.95"
|
||||
resolved "https://registry.yarnpkg.com/@mdi/font/-/font-6.4.95.tgz#d3b7a615c4c82ba2a9c29b2b59b158dced4f9b0e"
|
||||
integrity sha512-jCQdXCD339EXirWYFbZv1Ansthm9j6O3FSQLsfi/mKamnGYxqbUBm5D4UjcVr6HVYIPNwTQQ46HNHlswPD8RcQ==
|
||||
|
||||
"@mrmlnc/readdir-enhanced@^2.2.1":
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
|
||||
@@ -1998,6 +2003,13 @@ aws4@^1.8.0:
|
||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
|
||||
integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
|
||||
|
||||
axios@^0.23.0:
|
||||
version "0.23.0"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.23.0.tgz#b0fa5d0948a8d1d75e3d5635238b6c4625b05149"
|
||||
integrity sha512-NmvAE4i0YAv5cKq8zlDoPd1VLKAqX5oLuZKs8xkJa4qi6RGn0uhCYFjWtHHC9EM/MwOwYWOs53W+V0aqEXq1sg==
|
||||
dependencies:
|
||||
follow-redirects "^1.14.4"
|
||||
|
||||
babel-extract-comments@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-extract-comments/-/babel-extract-comments-1.0.0.tgz#0a2aedf81417ed391b85e18b4614e693a0351a21"
|
||||
@@ -4390,6 +4402,11 @@ follow-redirects@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.1.tgz#d9114ded0a1cfdd334e164e6662ad02bfd91ff43"
|
||||
integrity sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==
|
||||
|
||||
follow-redirects@^1.14.4:
|
||||
version "1.14.4"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.4.tgz#838fdf48a8bbdd79e52ee51fb1c94e3ed98b9379"
|
||||
integrity sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==
|
||||
|
||||
for-in@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
|
||||
|
||||
Reference in New Issue
Block a user