AddSongToQueue.vue 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. <template>
  2. <modal title="Add Song To Queue">
  3. <div slot="body">
  4. <aside
  5. class="menu"
  6. v-if="$parent.$parent.loggedIn && $parent.type === 'community'"
  7. >
  8. <ul class="menu-list">
  9. <li v-for="(playlist, index) in playlists" :key="index">
  10. <a
  11. href="#"
  12. target="_blank"
  13. v-on:click="$parent.editPlaylist(playlist._id)"
  14. >{{ playlist.displayName }}</a
  15. >
  16. <div class="controls">
  17. <a
  18. href="#"
  19. v-on:click="selectPlaylist(playlist._id)"
  20. v-if="!isPlaylistSelected(playlist._id)"
  21. >
  22. <i class="material-icons">panorama_fish_eye</i>
  23. </a>
  24. <a
  25. href="#"
  26. v-on:click="unSelectPlaylist()"
  27. v-if="isPlaylistSelected(playlist._id)"
  28. >
  29. <i class="material-icons">lens</i>
  30. </a>
  31. </div>
  32. </li>
  33. </ul>
  34. <br />
  35. </aside>
  36. <div class="control is-grouped">
  37. <p class="control is-expanded">
  38. <input
  39. class="input"
  40. type="text"
  41. placeholder="YouTube Query"
  42. v-model="querySearch"
  43. autofocus
  44. @keyup.enter="submitQuery()"
  45. />
  46. </p>
  47. <p class="control">
  48. <a
  49. class="button is-info"
  50. v-on:click="submitQuery()"
  51. href="#"
  52. >Search</a
  53. >
  54. </p>
  55. </div>
  56. <div class="control is-grouped" v-if="$parent.type === 'official'">
  57. <p class="control is-expanded">
  58. <input
  59. class="input"
  60. type="text"
  61. placeholder="YouTube Playlist URL"
  62. v-model="importQuery"
  63. @keyup.enter="importPlaylist()"
  64. />
  65. </p>
  66. <p class="control">
  67. <a
  68. class="button is-info"
  69. v-on:click="importPlaylist()"
  70. href="#"
  71. >Import</a
  72. >
  73. </p>
  74. </div>
  75. <table class="table" v-if="queryResults.length > 0">
  76. <tbody>
  77. <tr v-for="(result, index) in queryResults" :key="index">
  78. <td>
  79. <img :src="result.thumbnail" />
  80. </td>
  81. <td>{{ result.title }}</td>
  82. <td>
  83. <a
  84. class="button is-success"
  85. v-on:click="addSongToQueue(result.id)"
  86. href="#"
  87. >Add</a
  88. >
  89. </td>
  90. </tr>
  91. </tbody>
  92. </table>
  93. </div>
  94. </modal>
  95. </template>
  96. <script>
  97. import { Toast } from "vue-roaster";
  98. import Modal from "./Modal.vue";
  99. import io from "../../io";
  100. export default {
  101. data() {
  102. return {
  103. querySearch: "",
  104. queryResults: [],
  105. playlists: [],
  106. privatePlaylistQueueSelected: null,
  107. importQuery: ""
  108. };
  109. },
  110. methods: {
  111. isPlaylistSelected(playlistId) {
  112. return this.privatePlaylistQueueSelected === playlistId;
  113. },
  114. selectPlaylist(playlistId) {
  115. const _this = this;
  116. if (_this.$parent.type === "community") {
  117. _this.privatePlaylistQueueSelected = playlistId;
  118. _this.$parent.privatePlaylistQueueSelected = playlistId;
  119. _this.$parent.addFirstPrivatePlaylistSongToQueue();
  120. }
  121. },
  122. unSelectPlaylist() {
  123. const _this = this;
  124. if (_this.$parent.type === "community") {
  125. _this.privatePlaylistQueueSelected = null;
  126. _this.$parent.privatePlaylistQueueSelected = null;
  127. }
  128. },
  129. addSongToQueue(songId) {
  130. const _this = this;
  131. if (_this.$parent.type === "community") {
  132. _this.socket.emit(
  133. "stations.addToQueue",
  134. _this.$parent.station._id,
  135. songId,
  136. data => {
  137. if (data.status !== "success")
  138. Toast.methods.addToast(
  139. `Error: ${data.message}`,
  140. 8000
  141. );
  142. else Toast.methods.addToast(`${data.message}`, 4000);
  143. }
  144. );
  145. } else {
  146. _this.socket.emit("queueSongs.add", songId, data => {
  147. if (data.status !== "success")
  148. Toast.methods.addToast(`Error: ${data.message}`, 8000);
  149. else Toast.methods.addToast(`${data.message}`, 4000);
  150. });
  151. }
  152. },
  153. importPlaylist() {
  154. const _this = this;
  155. Toast.methods.addToast(
  156. "Starting to import your playlist. This can take some time to do.",
  157. 4000
  158. );
  159. this.socket.emit(
  160. "queueSongs.addSetToQueue",
  161. _this.importQuery,
  162. res => {
  163. Toast.methods.addToast(res.message, 4000);
  164. }
  165. );
  166. },
  167. submitQuery() {
  168. const _this = this;
  169. let query = _this.querySearch;
  170. if (query.indexOf("&index=") !== -1) {
  171. query = query.split("&index=");
  172. query.pop();
  173. query = query.join("");
  174. }
  175. if (query.indexOf("&list=") !== -1) {
  176. query = query.split("&list=");
  177. query.pop();
  178. query = query.join("");
  179. }
  180. _this.socket.emit("apis.searchYoutube", query, res => {
  181. // check for error
  182. const { data } = res;
  183. _this.queryResults = [];
  184. for (let i = 0; i < data.items.length; i += 1) {
  185. _this.queryResults.push({
  186. id: data.items[i].id.videoId,
  187. url: `https://www.youtube.com/watch?v=${this.id}`,
  188. title: data.items[i].snippet.title,
  189. thumbnail: data.items[i].snippet.thumbnails.default.url
  190. });
  191. }
  192. });
  193. }
  194. },
  195. mounted() {
  196. const _this = this;
  197. io.getSocket(socket => {
  198. _this.socket = socket;
  199. _this.socket.emit("playlists.indexForUser", res => {
  200. if (res.status === "success") _this.playlists = res.data;
  201. });
  202. _this.privatePlaylistQueueSelected =
  203. _this.$parent.privatePlaylistQueueSelected;
  204. });
  205. },
  206. components: { Modal }
  207. };
  208. </script>
  209. <style lang="scss" scoped>
  210. tr td {
  211. vertical-align: middle;
  212. img {
  213. width: 55px;
  214. }
  215. }
  216. .table {
  217. margin-bottom: 0;
  218. }
  219. </style>