AddSongs.vue 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. <script setup lang="ts">
  2. import { defineAsyncComponent, ref, watch, onMounted } from "vue";
  3. import { storeToRefs } from "pinia";
  4. import { useSearchYoutube } from "@/composables/useSearchYoutube";
  5. import { useSearchMusare } from "@/composables/useSearchMusare";
  6. import { useYoutubeDirect } from "@/composables/useYoutubeDirect";
  7. import { useEditPlaylistStore } from "@/stores/editPlaylist";
  8. const SongItem = defineAsyncComponent(
  9. () => import("@/components/SongItem.vue")
  10. );
  11. const SearchQueryItem = defineAsyncComponent(
  12. () => import("@/components/SearchQueryItem.vue")
  13. );
  14. const props = defineProps({
  15. modalUuid: { type: String, required: true }
  16. });
  17. const editPlaylistStore = useEditPlaylistStore({ modalUuid: props.modalUuid });
  18. const { playlist } = storeToRefs(editPlaylistStore);
  19. const sitename = ref("Musare");
  20. const {
  21. youtubeSearch,
  22. searchForSongs,
  23. loadMoreSongs,
  24. addYouTubeSongToPlaylist
  25. } = useSearchYoutube();
  26. const {
  27. musareSearch,
  28. resultsLeftCount,
  29. nextPageResultsCount,
  30. searchForMusareSongs,
  31. addMusareSongToPlaylist
  32. } = useSearchMusare();
  33. const { youtubeDirect, addToPlaylist } = useYoutubeDirect();
  34. watch(
  35. () => youtubeSearch.value.songs.results,
  36. songs => {
  37. songs.forEach((searchItem, index) =>
  38. playlist.value.songs.find(song => {
  39. if (song.youtubeId === searchItem.id)
  40. youtubeSearch.value.songs.results[index].isAddedToQueue =
  41. true;
  42. return song.youtubeId === searchItem.id;
  43. })
  44. );
  45. }
  46. );
  47. watch(
  48. () => musareSearch.value.results,
  49. songs => {
  50. songs.forEach((searchItem, index) =>
  51. playlist.value.songs.find(song => {
  52. if (song._id === searchItem._id)
  53. musareSearch.value.results[index].isAddedToQueue = true;
  54. return song._id === searchItem._id;
  55. })
  56. );
  57. }
  58. );
  59. watch(
  60. () => playlist.value.songs,
  61. () => {
  62. youtubeSearch.value.songs.results.forEach((searchItem, index) =>
  63. playlist.value.songs.find(song => {
  64. youtubeSearch.value.songs.results[index].isAddedToQueue = false;
  65. if (song.youtubeId === searchItem.id)
  66. youtubeSearch.value.songs.results[index].isAddedToQueue =
  67. true;
  68. return song.youtubeId === searchItem.id;
  69. })
  70. );
  71. musareSearch.value.results.forEach((searchItem, index) =>
  72. playlist.value.songs.find(song => {
  73. musareSearch.value.results[index].isAddedToQueue = false;
  74. if (song.youtubeId === searchItem.youtubeId)
  75. musareSearch.value.results[index].isAddedToQueue = true;
  76. return song.youtubeId === searchItem.youtubeId;
  77. })
  78. );
  79. }
  80. );
  81. onMounted(async () => {
  82. sitename.value = await lofig.get("siteSettings.sitename");
  83. });
  84. </script>
  85. <template>
  86. <div class="youtube-tab section">
  87. <div>
  88. <label class="label"> Search for a song on {{ sitename }}</label>
  89. <div class="control is-grouped input-with-button">
  90. <p class="control is-expanded">
  91. <input
  92. class="input"
  93. type="text"
  94. placeholder="Enter your song query here..."
  95. v-model="musareSearch.query"
  96. @keyup.enter="searchForMusareSongs(1)"
  97. />
  98. </p>
  99. <p class="control">
  100. <a class="button is-info" @click="searchForMusareSongs(1)"
  101. ><i class="material-icons icon-with-button">search</i
  102. >Search</a
  103. >
  104. </p>
  105. </div>
  106. <div
  107. v-if="musareSearch.results.length > 0"
  108. class="song-query-results"
  109. >
  110. <song-item
  111. v-for="(song, index) in musareSearch.results"
  112. :key="song._id"
  113. :song="song"
  114. >
  115. <template #actions>
  116. <transition
  117. name="musare-search-query-actions"
  118. mode="out-in"
  119. >
  120. <i
  121. v-if="song.isAddedToQueue"
  122. class="material-icons added-to-playlist-icon"
  123. content="Song is already in playlist"
  124. v-tippy
  125. >done</i
  126. >
  127. <i
  128. v-else
  129. class="material-icons add-to-playlist-icon"
  130. content="Add Song to Playlist"
  131. v-tippy
  132. @click="
  133. addMusareSongToPlaylist(
  134. playlist._id,
  135. song.youtubeId,
  136. index
  137. )
  138. "
  139. >playlist_add</i
  140. >
  141. </transition>
  142. </template>
  143. </song-item>
  144. <button
  145. v-if="resultsLeftCount > 0"
  146. class="button is-primary load-more-button"
  147. @click="searchForMusareSongs(musareSearch.page + 1)"
  148. >
  149. Load {{ nextPageResultsCount }} more results
  150. </button>
  151. </div>
  152. </div>
  153. <br v-if="musareSearch.results.length > 0" />
  154. <label class="label"> Add a YouTube song from a URL </label>
  155. <div class="control is-grouped input-with-button">
  156. <p class="control is-expanded">
  157. <input
  158. class="input"
  159. type="text"
  160. placeholder="Enter your YouTube song URL here..."
  161. v-model="youtubeDirect"
  162. @keyup.enter="addToPlaylist(playlist._id)"
  163. />
  164. </p>
  165. <p class="control">
  166. <a class="button is-info" @click="addToPlaylist(playlist._id)"
  167. ><i class="material-icons icon-with-button">add</i>Add</a
  168. >
  169. </p>
  170. </div>
  171. <div>
  172. <label class="label"> Search for a song from YouTube </label>
  173. <div class="control is-grouped input-with-button">
  174. <p class="control is-expanded">
  175. <input
  176. class="input"
  177. type="text"
  178. placeholder="Enter your YouTube query here..."
  179. v-model="youtubeSearch.songs.query"
  180. autofocus
  181. @keyup.enter="searchForSongs()"
  182. />
  183. </p>
  184. <p class="control">
  185. <button
  186. class="button is-info"
  187. @click.prevent="searchForSongs()"
  188. >
  189. <i class="material-icons icon-with-button">search</i
  190. >Search
  191. </button>
  192. </p>
  193. </div>
  194. <div
  195. v-if="youtubeSearch.songs.results.length > 0"
  196. class="song-query-results"
  197. >
  198. <search-query-item
  199. v-for="(result, index) in youtubeSearch.songs.results"
  200. :key="result.id"
  201. :result="result"
  202. >
  203. <template #actions>
  204. <transition
  205. name="youtube-search-query-actions"
  206. mode="out-in"
  207. >
  208. <i
  209. v-if="result.isAddedToQueue"
  210. class="material-icons added-to-playlist-icon"
  211. content="Song is already in playlist"
  212. v-tippy
  213. >done</i
  214. >
  215. <i
  216. v-else
  217. class="material-icons add-to-playlist-icon"
  218. content="Add Song to Playlist"
  219. v-tippy
  220. @click="
  221. addYouTubeSongToPlaylist(
  222. playlist._id,
  223. result.id,
  224. index
  225. )
  226. "
  227. >playlist_add</i
  228. >
  229. </transition>
  230. </template>
  231. </search-query-item>
  232. <button
  233. class="button is-primary load-more-button"
  234. @click.prevent="loadMoreSongs()"
  235. >
  236. Load more...
  237. </button>
  238. </div>
  239. </div>
  240. </div>
  241. </template>
  242. <style lang="less" scoped>
  243. .youtube-tab {
  244. .song-query-results {
  245. margin-top: 10px;
  246. max-width: 565px;
  247. .search-query-item:not(:last-of-type) {
  248. margin-bottom: 10px;
  249. }
  250. }
  251. .load-more-button {
  252. width: 100%;
  253. margin-top: 10px;
  254. }
  255. }
  256. @media screen and (max-width: 1300px) {
  257. .youtube-tab .song-query-results,
  258. .section {
  259. max-width: 100% !important;
  260. }
  261. }
  262. </style>