Browse Source

refactor(SongThumbnail): Use youtube as fallback and make a global component

Owen Diffey 2 years ago
parent
commit
5f19f04f6e

+ 1 - 2
frontend/src/components/SongItem.vue

@@ -161,11 +161,10 @@ import { mapActions, mapState } from "vuex";
 import { formatDistance, parseISO } from "date-fns";
 
 import AddToPlaylistDropdown from "./AddToPlaylistDropdown.vue";
-import SongThumbnail from "./SongThumbnail.vue";
 import utils from "../../js/utils";
 
 export default {
-	components: { AddToPlaylistDropdown, SongThumbnail },
+	components: { AddToPlaylistDropdown },
 	props: {
 		song: {
 			type: Object,

+ 43 - 19
frontend/src/components/SongThumbnail.vue → frontend/src/components/global/SongThumbnail.vue

@@ -7,6 +7,7 @@
 	>
 		<slot name="icon" />
 		<div
+			v-if="loadError < 2 && isYoutubeThumbnail"
 			class="yt-thumbnail-bg"
 			:style="{
 				'background-image':
@@ -16,17 +17,18 @@
 			}"
 		></div>
 		<img
-			v-if="isYoutubeThumbnail"
+			v-if="loadError < 2 && isYoutubeThumbnail"
 			loading="lazy"
 			:src="`https://img.youtube.com/vi/${song.youtubeId}/mqdefault.jpg`"
-			onerror="this.src='/assets/notes-transparent.png'"
+			@error="onerror"
 		/>
 		<img
-			v-else
+			v-else-if="loadError === 0"
 			loading="lazy"
 			:src="song.thumbnail"
-			onerror="this.src='/assets/notes-transparent.png'"
+			@error="onerror"
 		/>
+		<img v-else loading="lazy" src="/assets/notes-transparent.png" />
 	</div>
 </template>
 
@@ -36,29 +38,51 @@ export default {
 		song: {
 			type: Object,
 			default: () => {}
+		},
+		fallback: {
+			type: Boolean,
+			default: true
 		}
 	},
+	data() {
+		return {
+			loadError: 0
+		};
+	},
 	computed: {
 		isYoutubeThumbnail() {
 			return (
 				this.song.youtubeId &&
-				(!this.song.thumbnail ||
-					(this.song.thumbnail &&
-						(this.song.thumbnail.lastIndexOf(
-							"notes-transparent"
-						) !== -1 ||
-							this.song.thumbnail.lastIndexOf(
-								"/assets/notes.png"
-							) !== -1 ||
-							this.song.thumbnail.lastIndexOf("i.ytimg.com") !==
-								-1 ||
-							this.song.thumbnail.lastIndexOf(
-								"img.youtube.com"
-							) !== -1)) ||
-					this.song.thumbnail === "empty" ||
-					this.song.thumbnail == null)
+				((this.song.thumbnail &&
+					(this.song.thumbnail.lastIndexOf("i.ytimg.com") !== -1 ||
+						this.song.thumbnail.lastIndexOf("img.youtube.com") !==
+							-1)) ||
+					(this.fallback &&
+						(!this.song.thumbnail ||
+							(this.song.thumbnail &&
+								(this.song.thumbnail.lastIndexOf(
+									"notes-transparent"
+								) !== -1 ||
+									this.song.thumbnail.lastIndexOf(
+										"/assets/notes.png"
+									) !== -1 ||
+									this.song.thumbnail === "empty")) ||
+							this.loadError === 1)))
 			);
 		}
+	},
+	watch: {
+		song() {
+			this.loadError = 0;
+		}
+	},
+	methods: {
+		onerror() {
+			if (this.fallback)
+				if (this.loadError === 0 && !this.isYoutubeThumbnail)
+					this.loadError = 1;
+				else this.loadError = 2;
+		}
 	}
 };
 </script>

+ 5 - 18
frontend/src/components/modals/EditSong/index.vue

@@ -223,10 +223,11 @@
 						<song-thumbnail
 							v-if="songDataLoaded && !songDeleted"
 							:song="song"
+							:fallback="false"
 							class="thumbnail-preview"
 						/>
 						<img
-							v-if="songDataLoaded && !songDeleted"
+							v-if="!isYoutubeThumbnail && !songDeleted"
 							class="thumbnail-dummy"
 							:src="song.thumbnail"
 							ref="thumbnailElement"
@@ -683,7 +684,6 @@ import keyboardShortcuts from "@/keyboardShortcuts";
 import FloatingBox from "../../FloatingBox.vue";
 import SaveButton from "../../SaveButton.vue";
 import AutoSuggest from "@/components/AutoSuggest.vue";
-import SongThumbnail from "@/components/SongThumbnail.vue";
 
 import Discogs from "./Tabs/Discogs.vue";
 import Reports from "./Tabs/Reports.vue";
@@ -695,7 +695,6 @@ export default {
 		FloatingBox,
 		SaveButton,
 		AutoSuggest,
-		SongThumbnail,
 		Discogs,
 		Reports,
 		Youtube,
@@ -790,21 +789,9 @@ export default {
 			return (
 				this.songDataLoaded &&
 				this.song.youtubeId &&
-				(!this.song.thumbnail ||
-					(this.song.thumbnail &&
-						(this.song.thumbnail.lastIndexOf(
-							"notes-transparent"
-						) !== -1 ||
-							this.song.thumbnail.lastIndexOf(
-								"/assets/notes.png"
-							) !== -1 ||
-							this.song.thumbnail.lastIndexOf("i.ytimg.com") !==
-								-1 ||
-							this.song.thumbnail.lastIndexOf(
-								"img.youtube.com"
-							) !== -1)) ||
-					this.song.thumbnail === "empty" ||
-					this.song.thumbnail == null)
+				this.song.thumbnail &&
+				(this.song.thumbnail.lastIndexOf("i.ytimg.com") !== -1 ||
+					this.song.thumbnail.lastIndexOf("img.youtube.com") !== -1)
 			);
 		},
 		...mapModalState("MODAL_MODULE_PATH", {

+ 5 - 7
frontend/src/pages/Admin/Songs.vue

@@ -81,11 +81,9 @@
 					</div>
 				</template>
 				<template #column-thumbnailImage="slotProps">
-					<img
+					<song-thumbnail
 						class="song-thumbnail"
-						:src="slotProps.item.thumbnail"
-						onerror="this.src='/assets/notes-transparent.png'"
-						loading="lazy"
+						:song="slotProps.item"
 					/>
 				</template>
 				<template #column-thumbnailUrl="slotProps">
@@ -750,12 +748,12 @@ export default {
 </script>
 
 <style lang="less" scoped>
-.song-thumbnail {
-	display: block;
+:deep(.song-thumbnail) {
 	width: 50px;
 	height: 50px;
+	min-width: 50px;
+	min-height: 50px;
 	margin: 0 auto;
-	object-fit: contain;
 }
 
 :deep(.bulk-popup .bulk-actions) {

+ 0 - 3
frontend/src/pages/Home.vue

@@ -519,14 +519,11 @@ import { mapState, mapGetters, mapActions } from "vuex";
 import draggable from "vuedraggable";
 import Toast from "toasters";
 
-import SongThumbnail from "@/components/SongThumbnail.vue";
-
 import ws from "@/ws";
 import keyboardShortcuts from "@/keyboardShortcuts";
 
 export default {
 	components: {
-		SongThumbnail,
 		draggable
 	},
 	data() {