ImportArtist.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. <script setup lang="ts">
  2. import {
  3. defineAsyncComponent,
  4. reactive,
  5. onMounted,
  6. onBeforeUnmount
  7. } from "vue";
  8. import { useYoutubeChannel } from "@/composables/useYoutubeChannel";
  9. import { useSoundcloudArtist } from "@/composables/useSoundcloudArtist";
  10. import { useSpotifyArtist } from "@/composables/useSpotifyArtist";
  11. const Modal = defineAsyncComponent(() => import("@/components/Modal.vue"));
  12. const ArtistItem = defineAsyncComponent(
  13. () => import("@/components/ArtistItem.vue")
  14. );
  15. defineProps({
  16. modalUuid: { type: String, required: true }
  17. });
  18. const { youtubeChannelURLOrID, getYoutubeChannel, getYoutubeChannelVideos } =
  19. useYoutubeChannel();
  20. const {
  21. soundcloudArtistURLOrPermalink,
  22. getSoundcloudArtist,
  23. getSoundcloudArtistTracks
  24. } = useSoundcloudArtist();
  25. const { spotifyArtistURLOrID, getSpotifyArtist } = useSpotifyArtist();
  26. const youtubeChannels = reactive([]);
  27. const soundcloudArtists = reactive([]);
  28. const spotifyArtists = reactive([]);
  29. const selectYoutubeChannel = async () => {
  30. const youtubeChannel = await getYoutubeChannel();
  31. youtubeChannels.push(youtubeChannel);
  32. };
  33. const selectSoundcloudArtist = async () => {
  34. const soundcloudArtist = await getSoundcloudArtist();
  35. soundcloudArtists.push(soundcloudArtist);
  36. };
  37. const selectSpotifyArtist = async () => {
  38. const spotifyArtist = await getSpotifyArtist();
  39. spotifyArtists.push(spotifyArtist);
  40. };
  41. const songs = reactive([]);
  42. const importSongs = async () => {
  43. console.log(32111);
  44. const promises = [];
  45. youtubeChannels.forEach(youtubeChannel => {
  46. promises.push(async () => {
  47. const videos = await getYoutubeChannelVideos(
  48. youtubeChannel.channelId
  49. );
  50. console.log(321, videos);
  51. videos.forEach(video => {
  52. songs.push({ ...video, type: "youtube" });
  53. });
  54. });
  55. });
  56. soundcloudArtists.forEach(soundcloudArtist => {
  57. promises.push(
  58. new Promise<void>(resolve => {
  59. console.log(555, soundcloudArtist);
  60. getSoundcloudArtistTracks(soundcloudArtist.artistId)
  61. .then(tracks => {
  62. console.log(123, tracks);
  63. tracks.forEach(track => {
  64. songs.push({ ...track, type: "soundcloud" });
  65. });
  66. })
  67. .finally(() => {
  68. resolve();
  69. });
  70. })
  71. );
  72. });
  73. console.log(promises.length);
  74. await Promise.allSettled(promises);
  75. };
  76. onMounted(() => {
  77. // localSpotifyTracks.value = props.spotifyTracks;
  78. // if (props.youtubePlaylistId) importPlaylist();
  79. // else if (props.youtubeChannelUrl) importChannel();
  80. });
  81. onBeforeUnmount(() => {});
  82. </script>
  83. <template>
  84. <div>
  85. <modal title="Import artist" class="import-artist-modal" size="wide">
  86. <template #body>
  87. <main>
  88. <div class="artist-row">
  89. <div class="artist-source-container">
  90. <label class="label"
  91. >YouTube channel URL or ID</label
  92. >
  93. <p class="control is-grouped">
  94. <span class="control is-expanded">
  95. <input
  96. v-model="youtubeChannelURLOrID"
  97. class="input"
  98. type="text"
  99. placeholder="Enter YouTube channel URL or ID..."
  100. @keyup.enter="selectYoutubeChannel()"
  101. />
  102. </span>
  103. <span class="control">
  104. <a
  105. class="button is-info"
  106. @click="selectYoutubeChannel()"
  107. >Select</a
  108. >
  109. </span>
  110. </p>
  111. <label class="label"
  112. >Soundcloud artist URL or permalink</label
  113. >
  114. <p class="control is-grouped">
  115. <span class="control is-expanded">
  116. <input
  117. v-model="soundcloudArtistURLOrPermalink"
  118. class="input"
  119. type="text"
  120. placeholder="Enter Soundcloud channel URL or permalink..."
  121. @keyup.enter="selectSoundcloudArtist()"
  122. />
  123. </span>
  124. <span class="control">
  125. <a
  126. class="button is-info"
  127. @click="selectSoundcloudArtist()"
  128. >Select</a
  129. >
  130. </span>
  131. </p>
  132. <div
  133. class="youtube-channels"
  134. v-if="youtubeChannels.length > 0"
  135. >
  136. <artist-item
  137. v-for="youtubeChannel in youtubeChannels"
  138. :key="youtubeChannel.channelId"
  139. type="youtube"
  140. :data="youtubeChannel"
  141. >
  142. </artist-item>
  143. </div>
  144. <div
  145. class="soundcloud-artists"
  146. v-if="soundcloudArtists.length > 0"
  147. >
  148. <artist-item
  149. v-for="soundcloudArtist in soundcloudArtists"
  150. :key="soundcloudArtist.artistId"
  151. type="soundcloud"
  152. :data="soundcloudArtist"
  153. ></artist-item>
  154. </div>
  155. <button @click="importSongs()">Import songs</button>
  156. </div>
  157. <div class="artist-data-container">
  158. <label class="label"
  159. >Spotify artist URL or ID</label
  160. >
  161. <p class="control is-grouped">
  162. <span class="control is-expanded">
  163. <input
  164. v-model="spotifyArtistURLOrID"
  165. class="input"
  166. type="text"
  167. placeholder="Enter Spotify channel URL or ID..."
  168. @keyup.enter="selectSpotifyArtist()"
  169. />
  170. </span>
  171. <span class="control">
  172. <a
  173. class="button is-info"
  174. @click="selectSpotifyArtist()"
  175. >Select</a
  176. >
  177. </span>
  178. </p>
  179. <div
  180. class="spotify-artists"
  181. v-if="spotifyArtists.length > 0"
  182. >
  183. <artist-item
  184. v-for="spotifyArtist in spotifyArtists"
  185. :key="spotifyArtist.artistId"
  186. type="spotify"
  187. :data="spotifyArtist"
  188. ></artist-item>
  189. </div>
  190. </div>
  191. </div>
  192. <div class="song-row">
  193. <div class="song-source-container">
  194. <!-- <div>
  195. Showing all songs / showing songs for channel X
  196. </div> -->
  197. <div class="song-source-settings">
  198. <label for="">Search</label>
  199. <input type="text" />
  200. </div>
  201. <div class="songs"></div>
  202. </div>
  203. <div class="song-data-container"></div>
  204. </div>
  205. </main>
  206. <!-- <div class="playlist-songs">
  207. <h4>YouTube songs</h4>
  208. <p v-if="isImportingPlaylist">Importing playlist...</p>
  209. <draggable-list
  210. v-if="playlistSongs.length > 0"
  211. v-model:list="playlistSongs"
  212. item-key="mediaSource"
  213. :group="`replace-spotify-album-${modalUuid}-songs`"
  214. >
  215. <template #item="{ element }">
  216. <media-item
  217. :key="`playlist-song-${element.mediaSource}`"
  218. :song="element"
  219. >
  220. </media-item>
  221. </template>
  222. </draggable-list>
  223. </div> -->
  224. <!-- <div class="track-boxes">
  225. <div
  226. class="track-box"
  227. v-for="(track, index) in localSpotifyTracks"
  228. :key="track.trackId"
  229. >
  230. <div class="track-position-title">
  231. <p>
  232. {{ track.name }} -
  233. {{ track.artists.join(", ") }}
  234. </p>
  235. </div>
  236. <div class="track-box-songs-drag-area">
  237. <draggable-list
  238. v-model:list="trackSongs[index]"
  239. item-key="mediaSource"
  240. :group="`replace-spotify-album-${modalUuid}-songs`"
  241. >
  242. <template #item="{ element }">
  243. <media-item
  244. :key="`track-song-${element.mediaSource}`"
  245. :song="element"
  246. >
  247. </media-item>
  248. <button
  249. class="button is-primary is-fullwidth"
  250. @click="
  251. replaceSpotifySong(
  252. `spotify:${track.trackId}`,
  253. element.mediaSource
  254. )
  255. "
  256. >
  257. Replace Spotify song with this song
  258. </button>
  259. </template>
  260. </draggable-list>
  261. </div>
  262. </div>
  263. </div> -->
  264. </template>
  265. <template #footer>
  266. <!-- <button class="button is-primary" @click="tryToAutoMove()">
  267. Try to auto move
  268. </button>
  269. <button
  270. class="button is-primary"
  271. @click="replaceAllSpotifySongs()"
  272. >
  273. Replace all songs
  274. </button> -->
  275. </template>
  276. </modal>
  277. </div>
  278. </template>
  279. <style lang="less">
  280. // .night-mode {
  281. // .spotify-album-container,
  282. // .playlist-songs,
  283. // .track-boxes {
  284. // background-color: var(--dark-grey-3) !important;
  285. // border: 0 !important;
  286. // .tab {
  287. // border: 0 !important;
  288. // }
  289. // }
  290. // .api-result {
  291. // background-color: var(--dark-grey-3) !important;
  292. // }
  293. // .api-result .tracks .track:hover,
  294. // .api-result .tracks .track:focus,
  295. // .discogs-album .tracks .track:hover,
  296. // .discogs-album .tracks .track:focus {
  297. // background-color: var(--dark-grey-2) !important;
  298. // }
  299. // .api-result .bottom-row img,
  300. // .discogs-album .bottom-row img {
  301. // filter: invert(100%);
  302. // }
  303. // .label,
  304. // p,
  305. // strong {
  306. // color: var(--light-grey-2);
  307. // }
  308. // }
  309. // .replace-spotify-songs-modal {
  310. // .modal-card-title {
  311. // text-align: center;
  312. // margin-left: 24px;
  313. // }
  314. // .modal-card {
  315. // width: 100%;
  316. // height: 100%;
  317. // .modal-card-body {
  318. // padding: 16px;
  319. // display: flex;
  320. // flex-direction: row;
  321. // flex-wrap: wrap;
  322. // justify-content: space-evenly;
  323. // }
  324. // .modal-card-foot {
  325. // .button {
  326. // margin: 0;
  327. // &:not(:first-of-type) {
  328. // margin-left: 5px;
  329. // }
  330. // }
  331. // div div {
  332. // margin-right: 5px;
  333. // }
  334. // .right {
  335. // display: flex;
  336. // margin-left: auto;
  337. // margin-right: 0;
  338. // }
  339. // }
  340. // }
  341. // }
  342. //
  343. </style>
  344. //
  345. <style lang="less" scoped>
  346. main {
  347. display: flex;
  348. flex-direction: column;
  349. gap: 8px;
  350. }
  351. .artist-row,
  352. .song-row {
  353. display: flex;
  354. gap: 8px;
  355. .artist-source-container,
  356. .artist-data-container,
  357. .song-source-container,
  358. .song-data-container {
  359. flex: 1;
  360. display: flex;
  361. flex-direction: column;
  362. border: 1px solid white;
  363. padding: 8px;
  364. border-radius: 4px;
  365. gap: 8px;
  366. }
  367. }
  368. .youtube-channels {
  369. display: flex;
  370. flex-direction: column;
  371. gap: 8px;
  372. }
  373. // .break {
  374. // flex-basis: 100%;
  375. // height: 0;
  376. // border: 1px solid var(--dark-grey);
  377. // margin-top: 16px;
  378. // margin-bottom: 16px;
  379. // }
  380. // .spotify-album-container,
  381. // .playlist-songs {
  382. // width: 500px;
  383. // background-color: var(--light-grey);
  384. // border: 1px rgba(163, 224, 255, 0.75) solid;
  385. // border-radius: @border-radius;
  386. // padding: 16px;
  387. // overflow: auto;
  388. // height: 100%;
  389. // h4 {
  390. // margin: 0;
  391. // margin-bottom: 16px;
  392. // }
  393. // button {
  394. // margin: 5px 0;
  395. // }
  396. // }
  397. // .track-boxes {
  398. // width: 500px;
  399. // background-color: var(--light-grey);
  400. // border: 1px rgba(163, 224, 255, 0.75) solid;
  401. // border-radius: @border-radius;
  402. // padding: 16px;
  403. // overflow: auto;
  404. // height: 100%;
  405. // .track-box:first-child {
  406. // margin-top: 0;
  407. // border-radius: @border-radius @border-radius 0 0;
  408. // }
  409. // .track-box:last-child {
  410. // border-radius: 0 0 @border-radius @border-radius;
  411. // }
  412. // .track-box {
  413. // border: 0.5px solid var(--black);
  414. // margin-top: -1px;
  415. // line-height: 16px;
  416. // display: flex;
  417. // flex-flow: column;
  418. // .track-position-title {
  419. // display: flex;
  420. // span {
  421. // font-weight: 600;
  422. // display: inline-block;
  423. // margin-top: 7px;
  424. // margin-bottom: 7px;
  425. // margin-left: 7px;
  426. // }
  427. // p {
  428. // display: inline-block;
  429. // margin: 7px;
  430. // flex: 1;
  431. // }
  432. // }
  433. // .track-box-songs-drag-area {
  434. // flex: 1;
  435. // min-height: 100px;
  436. // display: flex;
  437. // flex-direction: column;
  438. // }
  439. // }
  440. // }
  441. </style>