From 2e64c4f003d76925355da39cf3704456dc6c962e Mon Sep 17 00:00:00 2001
From: Bnyro <bnyro@tutanota.com>
Date: Thu, 15 Jun 2023 17:32:32 +0200
Subject: [PATCH] Refactor playlist logic into dedicated functions

---
 src/components/PlaylistAddModal.vue | 24 +++-----
 src/components/PlaylistsPage.vue    | 86 +++++-----------------------
 src/components/VideoItem.vue        |  7 ++-
 src/components/WatchVideo.vue       |  7 ++-
 src/main.js                         | 87 +++++++++++++++++++++++++++++
 5 files changed, 119 insertions(+), 92 deletions(-)

diff --git a/src/components/PlaylistAddModal.vue b/src/components/PlaylistAddModal.vue
index 3e3a4aac..77df9ac1 100644
--- a/src/components/PlaylistAddModal.vue
+++ b/src/components/PlaylistAddModal.vue
@@ -23,8 +23,12 @@ export default {
         ModalComponent,
     },
     props: {
+        videoInfo: {
+            type: Object,
+            required: true,
+        },
         videoId: {
-            type: String,
+            type: Object,
             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;
             });
         },
diff --git a/src/components/PlaylistsPage.vue b/src/components/PlaylistsPage.vue
index 0dda0efe..58c14543 100644
--- a/src/components/PlaylistsPage.vue
+++ b/src/components/PlaylistsPage.vue
@@ -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");
diff --git a/src/components/VideoItem.vue b/src/components/VideoItem.vue
index 918ebb3f..702814e0 100644
--- a/src/components/VideoItem.vue
+++ b/src/components/VideoItem.vue
@@ -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>
diff --git a/src/components/WatchVideo.vue b/src/components/WatchVideo.vue
index 2f34e6e2..6deff7f9 100644
--- a/src/components/WatchVideo.vue
+++ b/src/components/WatchVideo.vue
@@ -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()"
diff --git a/src/main.js b/src/main.js
index 71b916d4..a1ffb6d3 100644
--- a/src/main.js
+++ b/src/main.js
@@ -292,6 +292,93 @@ const mixin = {
             var store = tx.objectStore("channel_groups");
             store.delete(groupName);
         },
+        async getPlaylists() {
+            return await this.fetchJson(this.authApiUrl() + "/user/playlists", null, {
+                headers: {
+                    Authorization: this.getAuthToken(),
+                },
+            });
+        },
+        async getPlaylist(playlistId) {
+            return await this.fetchJson(this.authApiUrl() + "/playlists/" + playlistId);
+        },
+        async createPlaylist(name) {
+            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) {
+            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) {
+            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) {
+            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 (videoInfos == "hallo") return; //TODO, only needed for local vids
+            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, videoId) {
+            return await this.fetchJson(this.authApiUrl() + "/user/playlists/add", null, {
+                method: "POST",
+                body: JSON.stringify({
+                    playlistId: playlistId,
+                    videoId: videoId,
+                }),
+                headers: {
+                    Authorization: this.getAuthToken(),
+                    "Content-Type": "application/json",
+                },
+            });
+        },
     },
     computed: {
         authenticated(_this) {