mirror of
https://github.com/mmjee/Piped-Material.git
synced 2024-12-06 19:26:36 +01:00
Refactoring and importing/exporting subscriptions
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
"@fontsource/roboto": "^4.5.8",
|
||||
"@formatjs/intl-localematcher": "^0.2.32",
|
||||
"@mdi/js": "^6.9.96",
|
||||
"@mojee/file-utils": "https://cf-ipfs.com/ipfs/QmYEtpbjQqWYJDbcoixZvcccXkRFKBcTuRw5aa3hb8BWt8?filename=js-file-utils.tgz",
|
||||
"antar-hinted": "https://cf-ipfs.com/ipfs/QmZxWPvQmFGZucKB2U1oChGpKYAAWdrbbSTj2RAQqL7gEd",
|
||||
"axios": "^0.27.2",
|
||||
"core-js": "^3.30.2",
|
||||
|
||||
@@ -1,33 +1,43 @@
|
||||
<template>
|
||||
<v-progress-linear v-if="!loaded" />
|
||||
<v-container fluid v-else>
|
||||
<v-row v-for="(chunk, chunkId) in data" :key="chunkId">
|
||||
<v-col md="2" v-for="channel in chunk" :key="channel.name">
|
||||
<v-card min-height="100%" outlined link :to="channel.url">
|
||||
<v-img :src="channel.avatar" />
|
||||
<v-card-title>{{ channel.name }}</v-card-title>
|
||||
<v-card-actions>
|
||||
<!-- Encapsulate into own item -->
|
||||
<SubscriptionButton :channel-id="channel.id" />
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-btn outlined color="primary" @click.stop="exportSubs" class="mr-2" v-if="$store.getters['auth/isCurrentlyAuthenticated']">{{ $t('actions.export_subscriptions') }}</v-btn>
|
||||
<v-btn outlined color="primary" @click.stop="importSubs" v-if="$store.getters['auth/isCurrentlyAuthenticated']">{{ $t('actions.import_subscriptions') }}</v-btn>
|
||||
<v-divider class="my-4" v-if="$store.getters['auth/isCurrentlyAuthenticated']" />
|
||||
<GridRow>
|
||||
<GridCol v-for="(channel, chid) in data" :key="chid">
|
||||
<v-card min-height="100%" outlined link :to="channel.url">
|
||||
<v-img :src="channel.avatar" />
|
||||
<v-card-title>{{ channel.name }}</v-card-title>
|
||||
<v-card-actions>
|
||||
<SubscriptionButton :channel-id="channel.id" />
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</GridCol>
|
||||
</GridRow>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { chunk as _chunk } from 'lodash-es'
|
||||
|
||||
import SubscriptionButton from '@/components/SubscriptionButton'
|
||||
import SubscriptionButton from '@/components/SubscriptionButton.vue'
|
||||
import GridRow from '@/components/Grid/GridRow.vue'
|
||||
import GridCol from '@/components/Grid/GridCol.vue'
|
||||
import { LibPiped } from '@/tools/libpiped'
|
||||
|
||||
import { pick as pickFile, save as saveFile } from '@mojee/file-utils'
|
||||
|
||||
export default {
|
||||
name: 'Subscriptions',
|
||||
components: { SubscriptionButton },
|
||||
components: {
|
||||
SubscriptionButton,
|
||||
GridRow,
|
||||
GridCol
|
||||
},
|
||||
data: () => ({
|
||||
loaded: false,
|
||||
data: null
|
||||
data: null,
|
||||
importDialogOpen: false,
|
||||
importSubscriptions: []
|
||||
}),
|
||||
methods: {
|
||||
async loadData () {
|
||||
@@ -42,10 +52,80 @@ export default {
|
||||
path: '/subscriptions'
|
||||
})
|
||||
this.loaded = true
|
||||
this.data = _chunk(resp.map(r => {
|
||||
this.data = resp.map(r => {
|
||||
r.id = LibPiped.determineVideoIdFromChannelURL(r.url)
|
||||
return r
|
||||
}), 6)
|
||||
})
|
||||
},
|
||||
exportSubs () {
|
||||
const encoded = JSON.stringify({
|
||||
app_version: '',
|
||||
app_version_int: 0,
|
||||
subscriptions: this.data.map((sub) => ({
|
||||
url: 'https://www.youtube.com' + sub.url,
|
||||
name: sub.name,
|
||||
service_id: 0
|
||||
}))
|
||||
})
|
||||
const blob = new Blob([encoded], {
|
||||
type: 'application/json'
|
||||
})
|
||||
saveFile(blob, this.$t('actions.subscriptions_filename'))
|
||||
},
|
||||
async importSubs () {
|
||||
const file = await pickFile()
|
||||
const data = await file.text()
|
||||
|
||||
// NewPipe
|
||||
if (file.name?.endsWith('.pipedsubs.json') || data.indexOf('app_version') !== -1) {
|
||||
const json = JSON.parse(data)
|
||||
json.subscriptions
|
||||
.filter(item => item.service_id === 0)
|
||||
.forEach(item => {
|
||||
const url = item.url
|
||||
const id = url.slice(-24)
|
||||
this.importSubscriptions.push(id)
|
||||
})
|
||||
// Invidious
|
||||
} else if (data.indexOf('opml') !== -1) {
|
||||
const parser = new DOMParser()
|
||||
const xmlDoc = parser.parseFromString(data, 'text/xml')
|
||||
xmlDoc.querySelectorAll('outline[xmlUrl]').forEach(item => {
|
||||
const url = item.getAttribute('xmlUrl')
|
||||
const id = url.slice(-24)
|
||||
this.importSubscriptions.push(id)
|
||||
})
|
||||
// Invidious JSON
|
||||
} else if (data.indexOf('thin_mode') !== -1) {
|
||||
const json = JSON.parse(data)
|
||||
this.importSubscriptions = json.subscriptions
|
||||
// FreeTube DB
|
||||
} else if (data.indexOf('allChannels') !== -1) {
|
||||
const json = JSON.parse(data)
|
||||
json.subscriptions.forEach(item => {
|
||||
this.importSubscriptions.push(item.id)
|
||||
})
|
||||
// Google Takeout JSON
|
||||
} else if (data.indexOf('contentDetails') !== -1) {
|
||||
const json = JSON.parse(data)
|
||||
json.forEach(item => {
|
||||
const id = item.snippet.resourceId.channelId
|
||||
this.importSubscriptions.push(id)
|
||||
})
|
||||
// Google Takeout CSV
|
||||
} else if (file.name.length >= 5 && file.name.slice(-4).toLowerCase() === '.csv') {
|
||||
const lines = data.split('\n')
|
||||
for (let i = 1; i < lines.length; i++) {
|
||||
const line = lines[i]
|
||||
const id = line.slice(0, line.indexOf(','))
|
||||
if (id.length === 24) this.importSubscriptions.push(id)
|
||||
}
|
||||
}
|
||||
await this.$store.dispatch('auth/makeRequest', {
|
||||
method: 'POST',
|
||||
path: '/import',
|
||||
data: this.importSubscriptions
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
|
||||
@@ -145,7 +145,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { throttle } from 'lodash-es'
|
||||
import throttle from 'lodash-es/throttle'
|
||||
import { mdiThumbUp, mdiShareVariant, mdiLinkPlus } from '@mdi/js'
|
||||
|
||||
import { PMDB, addWatchedVideo, updateWatchedVideoProgress, findLastWatch } from '@/store/watched-videos-db'
|
||||
|
||||
@@ -40,12 +40,12 @@ const AuthenticationStore = {
|
||||
},
|
||||
|
||||
getters: {
|
||||
isCurrentlyAuthenticated (state, getters, rootState, rootGetters) {
|
||||
isCurrentlyAuthenticated (state, _, _2, rootGetters) {
|
||||
const s = state.authStateByInstance[rootGetters['prefs/apiUrl']]
|
||||
return s ? (s.isAuthenticated === true) : false
|
||||
},
|
||||
|
||||
authToken (state, getters, rootState, rootGetters) {
|
||||
authToken (state, _, _2, rootGetters) {
|
||||
const authState = state.authStateByInstance[rootGetters['prefs/apiUrl']] || {}
|
||||
return authState.authToken
|
||||
}
|
||||
@@ -97,7 +97,6 @@ const AuthenticationStore = {
|
||||
},
|
||||
|
||||
async makeRequest ({
|
||||
commit,
|
||||
state,
|
||||
rootGetters
|
||||
}, {
|
||||
|
||||
@@ -119,7 +119,10 @@
|
||||
"related_comments": "Comments",
|
||||
"autoplay_next_video": "Proceed to the first related video once this video ends",
|
||||
"loop_this_video": "Loop this video",
|
||||
"unauthenticated_rss": "RSS (unauthenticated)"
|
||||
"unauthenticated_rss": "RSS (unauthenticated)",
|
||||
"import_subscriptions": "Import Subscriptions",
|
||||
"export_subscriptions": "Export Subscriptions",
|
||||
"subscriptions_filename": "subs.pipedsubs.json"
|
||||
},
|
||||
"preferences": {
|
||||
"colorScheme": "Color Scheme",
|
||||
|
||||
@@ -1156,6 +1156,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@mdi/js/-/js-6.9.96.tgz#90e8fadef05a975df384f0505b2100a795881873"
|
||||
integrity sha512-rK0/vLFaiItYS2W7uVmaKPKnhNQE4XVkylpk5njtVwENnp8elwY5uRL6qvdj2esuvUHG7DwygE4Qu3eKxxuJiQ==
|
||||
|
||||
"@mojee/file-utils@https://cf-ipfs.com/ipfs/QmYEtpbjQqWYJDbcoixZvcccXkRFKBcTuRw5aa3hb8BWt8?filename=js-file-utils.tgz":
|
||||
version "1.0.0"
|
||||
resolved "https://cf-ipfs.com/ipfs/QmYEtpbjQqWYJDbcoixZvcccXkRFKBcTuRw5aa3hb8BWt8?filename=js-file-utils.tgz#050fca0bccf5dbb23a0a7037c6c9fdeb125170bf"
|
||||
|
||||
"@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1":
|
||||
version "5.1.1-v1"
|
||||
resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129"
|
||||
|
||||
Reference in New Issue
Block a user