QueueSongs.vue 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. <template>
  2. <div>
  3. <div class="container">
  4. <input
  5. v-model="searchQuery"
  6. type="text"
  7. class="input"
  8. placeholder="Search for Songs"
  9. />
  10. <br />
  11. <br />
  12. <table class="table is-striped">
  13. <thead>
  14. <tr>
  15. <td>Thumbnail</td>
  16. <td>Title</td>
  17. <td>ID</td>
  18. <td>YouTube ID</td>
  19. <td>Artists</td>
  20. <td>Genres</td>
  21. <td>Requested By</td>
  22. <td>Options</td>
  23. </tr>
  24. </thead>
  25. <tbody>
  26. <tr v-for="(song, index) in filteredSongs" :key="index">
  27. <td>
  28. <img
  29. class="song-thumbnail"
  30. :src="song.thumbnail"
  31. onerror="this.src='/assets/notes-transparent.png'"
  32. />
  33. </td>
  34. <td>
  35. <strong>{{ song.title }}</strong>
  36. </td>
  37. <td>{{ song._id }}</td>
  38. <td>
  39. <a
  40. :href="
  41. 'https://www.youtube.com/watch?v=' +
  42. `${song.songId}`
  43. "
  44. target="_blank"
  45. >
  46. {{ song.songId }}</a
  47. >
  48. </td>
  49. <td>{{ song.artists.join(", ") }}</td>
  50. <td>{{ song.genres.join(", ") }}</td>
  51. <td>
  52. <user-id-to-username
  53. :userId="song.requestedBy"
  54. :link="true"
  55. />
  56. </td>
  57. <td class="optionsColumn">
  58. <button
  59. class="button is-primary"
  60. @click="edit(song, index)"
  61. >
  62. <i class="material-icons">edit</i>
  63. </button>
  64. <button
  65. class="button is-success"
  66. @click="add(song)"
  67. >
  68. <i class="material-icons">add</i>
  69. </button>
  70. <button
  71. class="button is-danger"
  72. @click="remove(song._id, index)"
  73. >
  74. <i class="material-icons">cancel</i>
  75. </button>
  76. </td>
  77. </tr>
  78. </tbody>
  79. </table>
  80. </div>
  81. <nav class="pagination">
  82. <a
  83. v-if="position > 1"
  84. class="button"
  85. href="#"
  86. @click="getSet(position - 1)"
  87. >
  88. <i class="material-icons">navigate_before</i>
  89. </a>
  90. <a
  91. v-if="maxPosition > position"
  92. class="button"
  93. href="#"
  94. @click="getSet(position + 1)"
  95. >
  96. <i class="material-icons">navigate_next</i>
  97. </a>
  98. </nav>
  99. <edit-song v-if="modals.editSong" />
  100. </div>
  101. </template>
  102. <script>
  103. import { mapState, mapActions } from "vuex";
  104. import { Toast } from "vue-roaster";
  105. import EditSong from "../Modals/EditSong.vue";
  106. import UserIdToUsername from "../UserIdToUsername.vue";
  107. import io from "../../io";
  108. export default {
  109. components: { EditSong, UserIdToUsername },
  110. data() {
  111. return {
  112. position: 1,
  113. maxPosition: 1,
  114. searchQuery: "",
  115. songs: []
  116. };
  117. },
  118. computed: {
  119. filteredSongs: function() {
  120. return this.songs;
  121. // return this.songs.filter(song => song.indexOf(song.searchQuery) !== -1);
  122. },
  123. ...mapState("modals", {
  124. modals: state => state.modals.admin
  125. })
  126. },
  127. // watch: {
  128. // "modals.editSong": function(value) {
  129. // console.log(value);
  130. // if (value === false) this.stopVideo();
  131. // }
  132. // },
  133. methods: {
  134. getSet: function(position) {
  135. let _this = this;
  136. this.socket.emit("queueSongs.getSet", position, data => {
  137. _this.songs = data;
  138. this.position = position;
  139. });
  140. },
  141. edit: function(song, index) {
  142. let newSong = {};
  143. for (let n in song) newSong[n] = song[n];
  144. this.editSong({ index, song: newSong, type: "queueSongs" });
  145. this.openModal({ sector: "admin", modal: "editSong" });
  146. },
  147. add: function(song) {
  148. this.socket.emit("songs.add", song, res => {
  149. if (res.status == "success")
  150. Toast.methods.addToast(res.message, 2000);
  151. else Toast.methods.addToast(res.message, 4000);
  152. });
  153. },
  154. remove: function(id) {
  155. this.socket.emit("queueSongs.remove", id, res => {
  156. if (res.status == "success")
  157. Toast.methods.addToast(res.message, 2000);
  158. else Toast.methods.addToast(res.message, 4000);
  159. });
  160. },
  161. init: function() {
  162. let _this = this;
  163. _this.socket.emit("queueSongs.index", data => {
  164. _this.songs = data.songs;
  165. _this.maxPosition = Math.round(data.maxLength / 50);
  166. });
  167. _this.socket.emit("apis.joinAdminRoom", "queue", () => {});
  168. },
  169. ...mapActions("admin/songs", ["stopVideo", "editSong"]),
  170. ...mapActions("modals", ["openModal"])
  171. },
  172. mounted: function() {
  173. let _this = this;
  174. io.getSocket(socket => {
  175. _this.socket = socket;
  176. if (_this.socket.connected) {
  177. _this.init();
  178. _this.socket.on("event:admin.queueSong.added", queueSong => {
  179. _this.songs.push(queueSong);
  180. });
  181. _this.socket.on("event:admin.queueSong.removed", songId => {
  182. _this.songs = _this.songs.filter(function(song) {
  183. return song._id !== songId;
  184. });
  185. });
  186. _this.socket.on(
  187. "event:admin.queueSong.updated",
  188. updatedSong => {
  189. for (let i = 0; i < _this.songs.length; i++) {
  190. let song = _this.songs[i];
  191. if (song._id === updatedSong._id) {
  192. _this.songs.$set(i, updatedSong);
  193. }
  194. }
  195. }
  196. );
  197. }
  198. io.onConnect(() => {
  199. _this.init();
  200. });
  201. });
  202. }
  203. };
  204. </script>
  205. <style lang="scss" scoped>
  206. .optionsColumn {
  207. width: 140px;
  208. button {
  209. width: 35px;
  210. }
  211. }
  212. .song-thumbnail {
  213. display: block;
  214. max-width: 50px;
  215. margin: 0 auto;
  216. }
  217. td {
  218. vertical-align: middle;
  219. }
  220. .is-primary:focus {
  221. background-color: #029ce3 !important;
  222. }
  223. </style>