Merge pull request #2553 from Bnyro/local-playlists

Playlists without an account
This commit is contained in:
Bnyro
2023-06-19 14:34:32 +02:00
committed by GitHub
7 changed files with 288 additions and 112 deletions

View File

@@ -23,6 +23,10 @@ export default {
ModalComponent,
},
props: {
videoInfo: {
type: Object,
required: true,
},
videoId: {
type: String,
required: true,
@@ -62,28 +66,14 @@ export default {
this.$refs.addButton.disabled = true;
this.processing = true;
this.fetchJson(this.authApiUrl() + "/user/playlists/add", null, {
method: "POST",
body: JSON.stringify({
playlistId: playlistId,
videoId: this.videoId,
}),
headers: {
Authorization: this.getAuthToken(),
"Content-Type": "application/json",
},
}).then(json => {
this.addVideosToPlaylist(playlistId, [this.videoId], [this.videoInfo]).then(json => {
this.setPreference("selectedPlaylist" + this.hashCode(this.authApiUrl()), playlistId);
this.$emit("close");
if (json.error) alert(json.error);
});
},
async fetchPlaylists() {
this.fetchJson(this.authApiUrl() + "/user/playlists", null, {
headers: {
Authorization: this.getAuthToken(),
},
}).then(json => {
this.getPlaylists().then(json => {
this.playlists = json;
});
},

View File

@@ -86,14 +86,11 @@ export default {
mounted() {
const playlistId = this.$route.query.list;
if (this.authenticated && playlistId?.length == 36)
this.fetchJson(this.authApiUrl() + "/user/playlists", null, {
headers: {
Authorization: this.getAuthToken(),
},
}).then(json => {
this.getPlaylists().then(json => {
if (json.error) alert(json.error);
else if (json.some(playlist => playlist.id === playlistId)) this.admin = true;
});
else if (playlistId.startsWith("local")) this.admin = true;
this.isPlaylistBookmarked();
},
activated() {
@@ -106,6 +103,11 @@ export default {
},
methods: {
async fetchPlaylist() {
const playlistId = this.$route.query.list;
if (playlistId.startsWith("local")) {
return this.getPlaylist(playlistId);
}
return await await this.fetchJson(this.authApiUrl() + "/playlists/" + this.$route.query.list);
},
async getPlaylistData() {

View File

@@ -1,7 +1,7 @@
<template>
<h2 v-if="authenticated" class="font-bold my-4" v-t="'titles.playlists'" />
<h2 class="font-bold my-4" v-t="'titles.playlists'" />
<div v-if="authenticated" class="flex justify-between mb-3">
<div class="flex justify-between mb-3">
<button v-t="'actions.create_playlist'" class="btn" @click="onCreatePlaylist" />
<div class="flex">
<button
@@ -63,7 +63,7 @@
v-if="playlistToDelete == playlist.id"
:message="$t('actions.delete_playlist_confirm')"
@close="playlistToDelete = null"
@confirm="deletePlaylist(playlist.id)"
@confirm="onDeletePlaylist(playlist.id)"
/>
</div>
</div>
@@ -115,7 +115,7 @@ export default {
};
},
mounted() {
if (this.authenticated) this.fetchPlaylists();
this.fetchPlaylists();
this.loadPlaylistBookmarks();
},
activated() {
@@ -123,11 +123,7 @@ export default {
},
methods: {
fetchPlaylists() {
this.fetchJson(this.authApiUrl() + "/user/playlists", null, {
headers: {
Authorization: this.getAuthToken(),
},
}).then(json => {
this.getPlaylists().then(json => {
this.playlists = json;
});
},
@@ -141,50 +137,21 @@ export default {
const newName = this.newPlaylistName;
const newDescription = this.newPlaylistDescription;
if (newName != selectedPlaylist.name) {
this.fetchJson(this.authApiUrl() + "/user/playlists/rename", null, {
method: "POST",
body: JSON.stringify({
playlistId: selectedPlaylist.id,
newName: newName,
}),
headers: {
Authorization: this.getAuthToken(),
"Content-Type": "application/json",
},
}).then(json => {
this.renamePlaylist(selectedPlaylist.id, newName).then(json => {
if (json.error) alert(json.error);
else selectedPlaylist.name = newName;
});
}
if (newDescription != selectedPlaylist.description) {
this.fetchJson(this.authApiUrl() + "/user/playlists/description", null, {
method: "PATCH",
body: JSON.stringify({
playlistId: selectedPlaylist.id,
description: newDescription,
}),
headers: {
Authorization: this.getAuthToken(),
"Content-Type": "application/json",
},
}).then(json => {
this.changePlaylistDescription(selectedPlaylist.id, newDescription).then(json => {
if (json.error) alert(json.error);
else selectedPlaylist.description = newDescription;
});
}
this.playlistToEdit = null;
},
deletePlaylist(id) {
this.fetchJson(this.authApiUrl() + "/user/playlists/delete", null, {
method: "POST",
body: JSON.stringify({
playlistId: id,
}),
headers: {
Authorization: this.getAuthToken(),
"Content-Type": "application/json",
},
}).then(json => {
onDeletePlaylist(id) {
this.deletePlaylist(id).then(json => {
if (json.error) alert(json.error);
else this.playlists = this.playlists.filter(playlist => playlist.id !== id);
});
@@ -198,19 +165,6 @@ export default {
else this.fetchPlaylists();
});
},
async createPlaylist(name) {
let json = await this.fetchJson(this.authApiUrl() + "/user/playlists/create", null, {
method: "POST",
body: JSON.stringify({
name: name,
}),
headers: {
Authorization: this.getAuthToken(),
"Content-Type": "application/json",
},
});
return json;
},
async exportPlaylists() {
if (!this.playlists) return;
let json = {
@@ -223,8 +177,8 @@ export default {
this.download(JSON.stringify(json), "playlists.json", "application/json");
},
async fetchPlaylistJson(playlistId) {
let playlist = await this.fetchJson(this.authApiUrl() + "/playlists/" + playlistId);
let playlistJson = {
let playlist = await this.getPlaylist(playlistId);
return {
name: playlist.name,
// possible other types: history, watch later, ...
type: "playlist",
@@ -233,7 +187,6 @@ export default {
// list of the videos, starting with "https://youtube.com" to clarify that those are YT videos
videos: playlist.relatedStreams.map(stream => "https://youtube.com" + stream.url),
};
return playlistJson;
},
async importPlaylists() {
const files = this.$refs.fileSelector.files;
@@ -252,8 +205,8 @@ export default {
alert(this.$t("actions.no_valid_playlists"));
return;
}
for (var i = 0; i < playlists.length; i++) {
tasks.push(this.createPlaylistWithVideos(playlists[i]));
for (let playlist of playlists) {
tasks.push(this.createPlaylistWithVideos(playlist));
}
// CSV from Google Takeout
} else if (file.name.slice(-4).toLowerCase() == ".csv") {
@@ -277,19 +230,6 @@ export default {
let videoIds = playlist.videos.map(url => url.substr(-11));
await this.addVideosToPlaylist(newPlaylist.playlistId, videoIds);
},
async addVideosToPlaylist(playlistId, videoIds) {
await this.fetchJson(this.authApiUrl() + "/user/playlists/add", null, {
method: "POST",
body: JSON.stringify({
playlistId: playlistId,
videoIds: videoIds,
}),
headers: {
Authorization: this.getAuthToken(),
"Content-Type": "application/json",
},
});
},
async loadPlaylistBookmarks() {
if (!window.db) return;
var tx = window.db.transaction("playlist_bookmarks", "readonly");
@@ -298,8 +238,7 @@ export default {
cursorRequest.onsuccess = e => {
const cursor = e.target.result;
if (cursor) {
const bookmark = cursor.value;
this.bookmarks.push(bookmark);
this.bookmarks.push(cursor.value);
cursor.continue();
}
};

View File

@@ -107,7 +107,7 @@
>
<font-awesome-icon icon="headphones" />
</router-link>
<button v-if="authenticated" :title="$t('actions.add_to_playlist')" @click="showModal = !showModal">
<button :title="$t('actions.add_to_playlist')" @click="showModal = !showModal">
<font-awesome-icon icon="circle-plus" />
</button>
<button
@@ -124,7 +124,12 @@
@confirm="removeVideo(item.url.substr(-11))"
:message="$t('actions.delete_playlist_video_confirm')"
/>
<PlaylistAddModal v-if="showModal" :video-id="item.url.substr(-11)" @close="showModal = !showModal" />
<PlaylistAddModal
v-if="showModal"
:video-id="item.url.substr(-11)"
:video-info="item"
@close="showModal = !showModal"
/>
</div>
</div>
</div>
@@ -172,17 +177,7 @@ export default {
methods: {
removeVideo() {
this.$refs.removeButton.disabled = true;
this.fetchJson(this.authApiUrl() + "/user/playlists/remove", null, {
method: "POST",
body: JSON.stringify({
playlistId: this.playlistId,
index: this.index,
}),
headers: {
Authorization: this.getAuthToken(),
"Content-Type": "application/json",
},
}).then(json => {
this.removeVideoFromPlaylist(this.playlistId, this.index).then(json => {
if (json.error) alert(json.error);
else this.$emit("remove");
});

View File

@@ -78,7 +78,12 @@
<!-- Verified Badge -->
<font-awesome-icon class="ml-1" v-if="video.uploaderVerified" icon="check" />
</div>
<PlaylistAddModal v-if="showModal" :video-id="getVideoId()" @close="showModal = !showModal" />
<PlaylistAddModal
v-if="showModal"
:video-id="getVideoId()"
:video-info="video"
@close="showModal = !showModal"
/>
<ShareModal
v-if="showShareModal"
:video-id="getVideoId()"
@@ -89,7 +94,7 @@
/>
<div class="flex flex-wrap gap-1 ml-auto">
<!-- Subscribe Button -->
<button class="btn flex items-center" v-if="authenticated" @click="showModal = !showModal">
<button class="btn flex items-center" @click="showModal = !showModal">
{{ $t("actions.add_to_playlist") }}<font-awesome-icon class="ml-1" icon="circle-plus" />
</button>
<button