SongThumbnail.vue 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. <script setup lang="ts">
  2. import { ref, computed, watch } from "vue";
  3. const props = defineProps({
  4. song: { type: Object, default: () => {} },
  5. fallback: { type: Boolean, default: true }
  6. });
  7. const emit = defineEmits(["loadError"]);
  8. const loadError = ref(0);
  9. const isYoutubeThumbnail = computed(
  10. () =>
  11. props.song.youtubeId &&
  12. ((props.song.thumbnail &&
  13. (props.song.thumbnail.lastIndexOf("i.ytimg.com") !== -1 ||
  14. props.song.thumbnail.lastIndexOf("img.youtube.com") !== -1)) ||
  15. (props.fallback &&
  16. (!props.song.thumbnail ||
  17. (props.song.thumbnail &&
  18. (props.song.thumbnail.lastIndexOf(
  19. "notes-transparent"
  20. ) !== -1 ||
  21. props.song.thumbnail.lastIndexOf(
  22. "/assets/notes.png"
  23. ) !== -1 ||
  24. props.song.thumbnail === "empty")) ||
  25. loadError.value === 1)))
  26. );
  27. const onLoadError = () => {
  28. // Error codes
  29. // -1 - Error occured, fallback disabled
  30. // 0 - No errors
  31. // 1 - Error occured with thumbnail, fallback enabled
  32. // 2 - Error occured with youtube thumbnail, fallback enabled
  33. if (!props.fallback) loadError.value = -1;
  34. else if (loadError.value === 0 && !isYoutubeThumbnail.value)
  35. loadError.value = 1;
  36. else loadError.value = 2;
  37. emit("loadError", loadError.value);
  38. };
  39. watch(
  40. () => props.song,
  41. () => {
  42. loadError.value = 0;
  43. emit("loadError", loadError.value);
  44. }
  45. );
  46. </script>
  47. <template>
  48. <div
  49. :class="{
  50. thumbnail: true,
  51. 'youtube-thumbnail': isYoutubeThumbnail
  52. }"
  53. >
  54. <slot name="icon" />
  55. <div
  56. v-if="-1 < loadError && loadError < 2 && isYoutubeThumbnail"
  57. class="yt-thumbnail-bg"
  58. :style="{
  59. 'background-image':
  60. 'url(' +
  61. `https://img.youtube.com/vi/${song.youtubeId}/mqdefault.jpg` +
  62. ')'
  63. }"
  64. ></div>
  65. <img
  66. v-if="-1 < loadError && loadError < 2 && isYoutubeThumbnail"
  67. loading="lazy"
  68. :src="`https://img.youtube.com/vi/${song.youtubeId}/mqdefault.jpg`"
  69. @error="onLoadError"
  70. />
  71. <img
  72. v-else-if="loadError <= 0"
  73. loading="lazy"
  74. :src="song.thumbnail"
  75. @error="onLoadError"
  76. />
  77. <img v-else loading="lazy" src="/assets/notes-transparent.png" />
  78. </div>
  79. </template>
  80. <style lang="less">
  81. .thumbnail {
  82. min-width: 130px;
  83. height: 130px;
  84. position: relative;
  85. margin-top: -15px;
  86. margin-bottom: -15px;
  87. margin-left: -10px;
  88. .yt-thumbnail-bg {
  89. display: none;
  90. }
  91. img {
  92. height: 100%;
  93. width: 100%;
  94. margin-top: auto;
  95. margin-bottom: auto;
  96. z-index: 1;
  97. position: absolute;
  98. top: 0;
  99. bottom: 0;
  100. left: 0;
  101. right: 0;
  102. }
  103. &.youtube-thumbnail {
  104. .yt-thumbnail-bg {
  105. height: 100%;
  106. width: 100%;
  107. display: block;
  108. position: absolute;
  109. top: 0;
  110. filter: blur(1px);
  111. background: url("/assets/notes-transparent.png") no-repeat center
  112. center;
  113. }
  114. img {
  115. height: auto;
  116. }
  117. }
  118. }
  119. </style>