mirror of
https://github.com/TeamPiped/Piped.git
synced 2026-03-15 04:57:00 +00:00
Merge pull request #2553 from Bnyro/local-playlists
Playlists without an account
This commit is contained in:
239
src/main.js
239
src/main.js
@@ -293,6 +293,245 @@ const mixin = {
|
||||
var store = tx.objectStore("channel_groups");
|
||||
store.delete(groupName);
|
||||
},
|
||||
async getLocalPlaylist(playlistId) {
|
||||
return await new Promise(resolve => {
|
||||
var tx = window.db.transaction("playlists", "readonly");
|
||||
var store = tx.objectStore("playlists");
|
||||
const req = store.openCursor(playlistId);
|
||||
let playlist = null;
|
||||
req.onsuccess = e => {
|
||||
playlist = e.target.result.value;
|
||||
playlist.videos = JSON.parse(playlist.videoIds).length;
|
||||
resolve(playlist);
|
||||
};
|
||||
});
|
||||
},
|
||||
createOrUpdateLocalPlaylist(playlist) {
|
||||
var tx = window.db.transaction("playlists", "readwrite");
|
||||
var store = tx.objectStore("playlists");
|
||||
store.put(playlist);
|
||||
},
|
||||
// needs to handle both, streamInfo items and streams items
|
||||
createLocalPlaylistVideo(videoId, videoInfo) {
|
||||
if (videoInfo === undefined || videoId === null || videoInfo?.error) return;
|
||||
|
||||
var tx = window.db.transaction("playlist_videos", "readwrite");
|
||||
var store = tx.objectStore("playlist_videos");
|
||||
const video = {
|
||||
videoId: videoId,
|
||||
title: videoInfo.title,
|
||||
type: "stream",
|
||||
shortDescription: videoInfo.shortDescription ?? videoInfo.description,
|
||||
url: `/watch?v=${videoId}`,
|
||||
thumbnail: videoInfo.thumbnail ?? videoInfo.thumbnailUrl,
|
||||
uploaderVerified: videoInfo.uploaderVerified,
|
||||
duration: videoInfo.duration,
|
||||
uploaderAvatar: videoInfo.uploaderAvatar,
|
||||
uploaderUrl: videoInfo.uploaderUrl,
|
||||
uploaderName: videoInfo.uploaderName ?? videoInfo.uploader,
|
||||
};
|
||||
store.put(video);
|
||||
},
|
||||
async getLocalPlaylistVideo(videoId) {
|
||||
return await new Promise(resolve => {
|
||||
var tx = window.db.transaction("playlist_videos", "readonly");
|
||||
var store = tx.objectStore("playlist_videos");
|
||||
const req = store.openCursor(videoId);
|
||||
req.onsuccess = e => {
|
||||
resolve(e.target.result.value);
|
||||
};
|
||||
});
|
||||
},
|
||||
async getPlaylists() {
|
||||
if (!this.authenticated) {
|
||||
if (!window.db) return [];
|
||||
return await new Promise(resolve => {
|
||||
let playlists = [];
|
||||
var tx = window.db.transaction("playlists", "readonly");
|
||||
var store = tx.objectStore("playlists");
|
||||
const cursorRequest = store.openCursor();
|
||||
cursorRequest.onsuccess = e => {
|
||||
const cursor = e.target.result;
|
||||
if (cursor) {
|
||||
let playlist = cursor.value;
|
||||
playlist.videos = JSON.parse(playlist.videoIds).length;
|
||||
playlists.push(playlist);
|
||||
cursor.continue();
|
||||
} else {
|
||||
resolve(playlists);
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
return await this.fetchJson(this.authApiUrl() + "/user/playlists", null, {
|
||||
headers: {
|
||||
Authorization: this.getAuthToken(),
|
||||
},
|
||||
});
|
||||
},
|
||||
async getPlaylist(playlistId) {
|
||||
if (!this.authenticated) {
|
||||
const playlist = await this.getLocalPlaylist(playlistId);
|
||||
const videoIds = JSON.parse(playlist.videoIds);
|
||||
const videosFuture = videoIds.map(videoId => this.getLocalPlaylistVideo(videoId));
|
||||
playlist.relatedStreams = await Promise.all(videosFuture);
|
||||
return playlist;
|
||||
}
|
||||
|
||||
return await this.fetchJson(this.authApiUrl() + "/playlists/" + playlistId);
|
||||
},
|
||||
async createPlaylist(name) {
|
||||
if (!this.authenticated) {
|
||||
const uuid = crypto.randomUUID();
|
||||
const playlistId = `local-${uuid}`;
|
||||
this.createOrUpdateLocalPlaylist({
|
||||
playlistId: playlistId,
|
||||
// remapping needed for the playlists page
|
||||
id: playlistId,
|
||||
name: name,
|
||||
description: "",
|
||||
thumbnail: "https://pipedproxy.kavin.rocks/?host=i.ytimg.com",
|
||||
videoIds: "[]", // empty list
|
||||
});
|
||||
return { playlistId: playlistId };
|
||||
}
|
||||
|
||||
return await this.fetchJson(this.authApiUrl() + "/user/playlists/create", null, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
name: name,
|
||||
}),
|
||||
headers: {
|
||||
Authorization: this.getAuthToken(),
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
},
|
||||
async deletePlaylist(playlistId) {
|
||||
if (!this.authenticated) {
|
||||
const playlist = await this.getLocalPlaylist(playlistId);
|
||||
var tx = window.db.transaction("playlists", "readwrite");
|
||||
var store = tx.objectStore("playlists");
|
||||
store.delete(playlistId);
|
||||
// delete videos that don't need to be store anymore
|
||||
const playlists = await this.getPlaylists();
|
||||
const usedVideoIds = playlists
|
||||
.filter(playlist => playlist.id != playlistId)
|
||||
.map(playlist => JSON.parse(playlist.videoIds))
|
||||
.flat();
|
||||
const potentialDeletableVideos = JSON.parse(playlist.videoIds);
|
||||
var videoTx = window.db.transaction("playlist_videos", "readwrite");
|
||||
var videoStore = videoTx.objectStore("playlist_videos");
|
||||
for (let videoId of potentialDeletableVideos) {
|
||||
if (!usedVideoIds.includes(videoId)) videoStore.delete(videoId);
|
||||
}
|
||||
return { message: "ok" };
|
||||
}
|
||||
|
||||
return await this.fetchJson(this.authApiUrl() + "/user/playlists/delete", null, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
playlistId: playlistId,
|
||||
}),
|
||||
headers: {
|
||||
Authorization: this.getAuthToken(),
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
},
|
||||
async renamePlaylist(playlistId, newName) {
|
||||
if (!this.authenticated) {
|
||||
const playlist = await this.getLocalPlaylist(playlistId);
|
||||
playlist.name = newName;
|
||||
this.createOrUpdateLocalPlaylist(playlist);
|
||||
return { message: "ok" };
|
||||
}
|
||||
|
||||
return await this.fetchJson(this.authApiUrl() + "/user/playlists/rename", null, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
playlistId: playlistId,
|
||||
newName: newName,
|
||||
}),
|
||||
headers: {
|
||||
Authorization: this.getAuthToken(),
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
},
|
||||
async changePlaylistDescription(playlistId, newDescription) {
|
||||
if (!this.authenticated) {
|
||||
const playlist = await this.getLocalPlaylist(playlistId);
|
||||
playlist.description = newDescription;
|
||||
this.createOrUpdateLocalPlaylist(playlist);
|
||||
return { message: "ok" };
|
||||
}
|
||||
|
||||
return await this.fetchJson(this.authApiUrl() + "/user/playlists/description", null, {
|
||||
method: "PATCH",
|
||||
body: JSON.stringify({
|
||||
playlistId: playlistId,
|
||||
description: newDescription,
|
||||
}),
|
||||
headers: {
|
||||
Authorization: this.getAuthToken(),
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
},
|
||||
async addVideosToPlaylist(playlistId, videoIds, videoInfos) {
|
||||
if (!this.authenticated) {
|
||||
const playlist = await this.getLocalPlaylist(playlistId);
|
||||
const currentVideoIds = JSON.parse(playlist.videoIds);
|
||||
if (currentVideoIds.length == 0) playlist.thumbnail = videoInfos[0].thumbnail;
|
||||
currentVideoIds.push(...videoIds);
|
||||
playlist.videoIds = JSON.stringify(currentVideoIds);
|
||||
this.createOrUpdateLocalPlaylist(playlist);
|
||||
let streamInfos =
|
||||
videoInfos ??
|
||||
(await Promise.all(videoIds.map(videoId => this.fetchJson(this.apiUrl() + "/streams/" + videoId))));
|
||||
for (let i in videoIds) {
|
||||
this.createLocalPlaylistVideo(videoIds[i], streamInfos[i]);
|
||||
}
|
||||
return { message: "ok" };
|
||||
}
|
||||
|
||||
return 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 removeVideoFromPlaylist(playlistId, index) {
|
||||
if (!this.authenticated) {
|
||||
const playlist = await this.getLocalPlaylist(playlistId);
|
||||
const videoIds = JSON.parse(playlist.videoIds);
|
||||
videoIds.splice(index, 1);
|
||||
playlist.videoIds = JSON.stringify(videoIds);
|
||||
if (videoIds.length == 0) playlist.thumbnail = "https://pipedproxy.kavin.rocks/?host=i.ytimg.com";
|
||||
this.createOrUpdateLocalPlaylist(playlist);
|
||||
return { message: "ok" };
|
||||
}
|
||||
|
||||
return await this.fetchJson(this.authApiUrl() + "/user/playlists/remove", null, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
playlistId: playlistId,
|
||||
index: index,
|
||||
}),
|
||||
headers: {
|
||||
Authorization: this.getAuthToken(),
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
authenticated(_this) {
|
||||
|
||||
Reference in New Issue
Block a user