SongThumbnail.vue 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  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="thumbnail-bg"
  58. :style="{
  59. 'background-image':
  60. 'url(' +
  61. `https://img.youtube.com/vi/${song.youtubeId}/mqdefault.jpg` +
  62. ')'
  63. }"
  64. ></div>
  65. <div
  66. v-if="-1 < loadError && loadError < 2 && !isYoutubeThumbnail"
  67. class="thumbnail-bg"
  68. :style="{
  69. 'background-image': `url(${song.thumbnail})`
  70. }"
  71. ></div>
  72. <img
  73. v-if="-1 < loadError && loadError < 2 && isYoutubeThumbnail"
  74. loading="lazy"
  75. :src="`https://img.youtube.com/vi/${song.youtubeId}/mqdefault.jpg`"
  76. @error="onLoadError"
  77. />
  78. <img
  79. v-else-if="loadError <= 0"
  80. loading="lazy"
  81. :src="song.thumbnail"
  82. @error="onLoadError"
  83. />
  84. <img v-else loading="lazy" src="/assets/notes-transparent.png" />
  85. </div>
  86. </template>
  87. <style lang="less">
  88. .thumbnail {
  89. min-width: 130px;
  90. height: 130px;
  91. position: relative;
  92. margin-top: -15px;
  93. margin-bottom: -15px;
  94. margin-left: -10px;
  95. // .yt-thumbnail-bg {
  96. // display: none;
  97. // }
  98. img {
  99. // height: 100%;
  100. width: 100%;
  101. margin-top: auto;
  102. margin-bottom: auto;
  103. z-index: 1;
  104. position: absolute;
  105. top: 0;
  106. bottom: 0;
  107. left: 0;
  108. right: 0;
  109. }
  110. .thumbnail-bg {
  111. height: 100%;
  112. width: 100%;
  113. display: block;
  114. position: absolute;
  115. top: 0;
  116. filter: blur(2px);
  117. background: url("/assets/notes-transparent.png") no-repeat center center;
  118. background-size: cover;
  119. }
  120. // &.youtube-thumbnail {
  121. // img {
  122. // height: auto;
  123. // }
  124. // }
  125. }
  126. </style>