History.vue 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. <script setup lang="ts">
  2. import { defineAsyncComponent, computed, onMounted } from "vue";
  3. import Toast from "toasters";
  4. import { storeToRefs } from "pinia";
  5. import { useWebsocketsStore } from "@/stores/websockets";
  6. import { useStationStore } from "@/stores/station";
  7. import SongItem from "@/components/SongItem.vue";
  8. const stationStore = useStationStore();
  9. const { socket } = useWebsocketsStore();
  10. const { history } = storeToRefs(stationStore);
  11. const station = computed({
  12. get() {
  13. return stationStore.station;
  14. },
  15. set(value) {
  16. stationStore.updateStation(value);
  17. }
  18. });
  19. const songsList = computed({
  20. get() {
  21. return stationStore.songsList;
  22. },
  23. set(value) {
  24. stationStore.updateSongsList(value);
  25. }
  26. });
  27. const songsInQueue = computed(() => {
  28. if (station.value.currentSong)
  29. return songsList.value
  30. .map(song => song.youtubeId)
  31. .concat(station.value.currentSong.youtubeId);
  32. return songsList.value.map(song => song.youtubeId);
  33. });
  34. const formatDate = dateString => {
  35. const skippedAtDate = new Date(dateString);
  36. const now = new Date();
  37. const time = `${skippedAtDate
  38. .getHours()
  39. .toString()
  40. .padStart(2, "0")}:${skippedAtDate
  41. .getMinutes()
  42. .toString()
  43. .padStart(2, "0")}`;
  44. const date = `${skippedAtDate.getFullYear()}-${(
  45. skippedAtDate.getMonth() + 1
  46. )
  47. .toString()
  48. .padStart(2, "0")}-${skippedAtDate
  49. .getDate()
  50. .toString()
  51. .padStart(2, "0")}`;
  52. if (skippedAtDate.toLocaleDateString() === now.toLocaleDateString()) {
  53. return time;
  54. }
  55. return `${date} ${time}`;
  56. };
  57. const formatSkipReason = skipReason => {
  58. if (skipReason === "natural") return "";
  59. if (skipReason === "other") return " - automatically skipped";
  60. if (skipReason === "vote_skip") return " - vote skipped";
  61. if (skipReason === "force_skip") return " - force skipped";
  62. return "";
  63. };
  64. const addSongToQueue = (youtubeId: string) => {
  65. socket.dispatch(
  66. "stations.addToQueue",
  67. station.value._id,
  68. youtubeId,
  69. "manual",
  70. res => {
  71. if (res.status !== "success") new Toast(`Error: ${res.message}`);
  72. else {
  73. new Toast(res.message);
  74. }
  75. }
  76. );
  77. };
  78. onMounted(async () => {});
  79. </script>
  80. <template>
  81. <div class="station-history">
  82. <div v-for="historyItem in history" :key="historyItem._id">
  83. <SongItem
  84. :song="historyItem.payload.song"
  85. :requested-by="true"
  86. :header="`Finished playing at ${formatDate(
  87. historyItem.payload.skippedAt
  88. )}${formatSkipReason(historyItem.payload.skipReason)}`"
  89. >
  90. <template #actions>
  91. <transition
  92. name="musare-history-query-actions"
  93. mode="out-in"
  94. >
  95. <i
  96. v-if="
  97. songsInQueue.indexOf(
  98. historyItem.payload.song.youtubeId
  99. ) !== -1
  100. "
  101. class="material-icons disabled"
  102. content="Song is already in queue"
  103. v-tippy
  104. >queue</i
  105. >
  106. <i
  107. v-else
  108. class="material-icons add-to-queue-icon"
  109. @click="
  110. addSongToQueue(
  111. historyItem.payload.song.youtubeId
  112. )
  113. "
  114. content="Add Song to Queue"
  115. v-tippy
  116. >queue</i
  117. >
  118. </transition>
  119. </template>
  120. </SongItem>
  121. </div>
  122. </div>
  123. </template>
  124. <style lang="less" scoped>
  125. .night-mode {
  126. .station-history {
  127. background-color: var(--dark-grey-3) !important;
  128. border: 0 !important;
  129. }
  130. }
  131. .station-history {
  132. background-color: var(--white);
  133. margin-bottom: 20px;
  134. border-radius: 0 0 @border-radius @border-radius;
  135. max-height: 100%;
  136. padding: 12px;
  137. overflow: auto;
  138. row-gap: 8px;
  139. display: flex;
  140. flex-direction: column;
  141. h1 {
  142. margin: 0;
  143. }
  144. .disabled {
  145. cursor: not-allowed;
  146. }
  147. :deep(.song-item) {
  148. height: 90px;
  149. .thumbnail {
  150. min-width: 90px;
  151. width: 90px;
  152. height: 90px;
  153. }
  154. .song-info {
  155. margin-left: 90px;
  156. }
  157. }
  158. }
  159. </style>