station.ts 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. import { defineStore, storeToRefs } from "pinia";
  2. import { Playlist } from "@/types/playlist";
  3. import { Song, CurrentSong } from "@/types/song";
  4. import { Station } from "@/types/station";
  5. import { User } from "@/types/user";
  6. import { StationHistory } from "@/types/stationHistory";
  7. import { useWebsocketsStore } from "@/stores/websockets";
  8. import { useUserPreferencesStore } from "@/stores/userPreferences";
  9. import { useConfigStore } from "@/stores/config";
  10. import { useSortablePlaylists } from "@/composables/useSortablePlaylists";
  11. const userPreferencesStore = useUserPreferencesStore();
  12. const configStore = useConfigStore();
  13. const { autoSkipDisliked } = storeToRefs(userPreferencesStore);
  14. const { experimental } = storeToRefs(configStore);
  15. const { playlists } = useSortablePlaylists();
  16. export const useStationStore = defineStore("station", {
  17. state: (): {
  18. station: Station;
  19. autoRequest: Playlist[];
  20. autoRequestLock: boolean;
  21. userCount: number;
  22. users: {
  23. loggedIn: User[];
  24. loggedOut: User[];
  25. };
  26. currentSong: CurrentSong | undefined;
  27. nextSong: Song | undefined | null;
  28. songsList: Song[];
  29. stationPaused: boolean;
  30. localPaused: boolean;
  31. noSong: boolean;
  32. autofill: Playlist[];
  33. blacklist: Playlist[];
  34. mediaModalPlayingAudio: boolean;
  35. permissions: Record<string, boolean>;
  36. history: StationHistory[];
  37. } => ({
  38. station: {},
  39. autoRequest: [],
  40. autoRequestLock: false,
  41. userCount: 0,
  42. users: {
  43. loggedIn: [],
  44. loggedOut: []
  45. },
  46. currentSong: {},
  47. nextSong: null,
  48. songsList: [],
  49. stationPaused: true,
  50. localPaused: false,
  51. noSong: true,
  52. autofill: [],
  53. blacklist: [],
  54. mediaModalPlayingAudio: false,
  55. permissions: {},
  56. history: []
  57. }),
  58. getters: {
  59. dislikedPlaylist() {
  60. return playlists.value.find(
  61. playlist => playlist.type === "user-disliked"
  62. );
  63. },
  64. // List of media sources that will not be allowed to be autorequested
  65. autorequestExcludedMediaSources() {
  66. const mediaSources = new Set();
  67. // Exclude the current song
  68. if (this.currentSong && this.currentSong.mediaSource)
  69. mediaSources.add(this.currentSong.mediaSource);
  70. // Exclude songs in the queue
  71. if (this.songsList) {
  72. this.songsList.forEach(song => {
  73. mediaSources.add(song.mediaSource);
  74. });
  75. }
  76. // If auto skip disliked preference is enabled, exclude all songs in the disliked playlist
  77. if (autoSkipDisliked.value && this.dislikedPlaylist) {
  78. this.dislikedPlaylist.songs.forEach(song => {
  79. mediaSources.add(song.mediaSource);
  80. });
  81. }
  82. // If no history exists, just stop here
  83. if (!this.history) Array.from(mediaSources);
  84. const {
  85. autorequestDisallowRecentlyPlayedEnabled,
  86. autorequestDisallowRecentlyPlayedNumber
  87. } = this.station.requests;
  88. // If the station is set to disallow recently played songs, and station history is enabled, exclude the last X history songs
  89. if (
  90. autorequestDisallowRecentlyPlayedEnabled &&
  91. experimental.value.station_history
  92. ) {
  93. this.history.forEach((historyItem, index) => {
  94. if (index < autorequestDisallowRecentlyPlayedNumber)
  95. mediaSources.add(historyItem.payload.song.mediaSource);
  96. });
  97. }
  98. return Array.from(mediaSources);
  99. }
  100. },
  101. actions: {
  102. joinStation(station) {
  103. this.station = { ...station };
  104. },
  105. leaveStation() {
  106. this.station = {};
  107. this.autoRequest = [];
  108. this.autoRequestLock = false;
  109. this.editing = {};
  110. this.userCount = 0;
  111. this.users = {
  112. loggedIn: [],
  113. loggedOut: []
  114. };
  115. this.currentSong = {};
  116. this.nextSong = null;
  117. this.songsList = [];
  118. this.stationPaused = true;
  119. this.localPaused = false;
  120. this.noSong = true;
  121. this.autofill = [];
  122. this.blacklist = [];
  123. this.permissions = {};
  124. },
  125. editStation(station) {
  126. this.editing = { ...station };
  127. },
  128. updateStation(station) {
  129. this.station = { ...this.station, ...station };
  130. },
  131. updateUserCount(userCount) {
  132. this.userCount = userCount;
  133. },
  134. updateUsers(users) {
  135. this.users = users;
  136. },
  137. updateCurrentSong(currentSong) {
  138. this.currentSong = currentSong;
  139. },
  140. updateNextSong(nextSong) {
  141. this.nextSong = nextSong;
  142. },
  143. updateSongsList(songsList) {
  144. this.songsList = songsList;
  145. },
  146. reorderSongsList(songsOrder) {
  147. this.songsList.sort((songA, songB) => {
  148. const indexA = songsOrder.findIndex(
  149. mediaSource => mediaSource === songA.mediaSource
  150. );
  151. const indexB = songsOrder.findIndex(
  152. mediaSource => mediaSource === songB.mediaSource
  153. );
  154. if (indexA > indexB) return 1;
  155. if (indexA < indexB) return -1;
  156. return 0;
  157. });
  158. },
  159. updateStationPaused(stationPaused) {
  160. this.stationPaused = stationPaused;
  161. },
  162. updateLocalPaused(localPaused) {
  163. this.localPaused = localPaused;
  164. },
  165. updateNoSong(noSong) {
  166. this.noSong = noSong;
  167. },
  168. updateAutoRequest(playlists) {
  169. this.autoRequest = playlists;
  170. },
  171. updateAutoRequestLock(lock) {
  172. this.autoRequestLock = lock;
  173. },
  174. updateIfStationIsFavorited(isFavorited) {
  175. this.station.isFavorited = isFavorited;
  176. },
  177. setAutofillPlaylists(autofillPlaylists) {
  178. this.autofill = JSON.parse(JSON.stringify(autofillPlaylists));
  179. },
  180. setBlacklist(blacklist) {
  181. this.blacklist = JSON.parse(JSON.stringify(blacklist));
  182. },
  183. updateCurrentSongRatings(songRatings) {
  184. this.currentSong.likes = songRatings.likes;
  185. this.currentSong.dislikes = songRatings.dislikes;
  186. },
  187. updateOwnCurrentSongRatings(ownSongRatings) {
  188. this.currentSong.liked = ownSongRatings.liked;
  189. this.currentSong.disliked = ownSongRatings.disliked;
  190. },
  191. updateCurrentSongSkipVotes({ skipVotes, skipVotesCurrent, voted }) {
  192. this.currentSong.skipVotes = skipVotes;
  193. if (skipVotesCurrent !== null)
  194. this.currentSong.skipVotesCurrent = skipVotesCurrent;
  195. this.currentSong.voted = voted;
  196. },
  197. addAutorequestPlaylists(playlists) {
  198. playlists.forEach(playlist => {
  199. this.autoRequest.push(playlist);
  200. });
  201. this.updateAutorequestLocalStorage();
  202. },
  203. addPlaylistToAutoRequest(playlist) {
  204. this.autoRequest.push(playlist);
  205. this.updateAutorequestLocalStorage();
  206. },
  207. removePlaylistFromAutoRequest(playlistId) {
  208. this.autoRequest.forEach((playlist, index) => {
  209. if (playlist._id === playlistId) {
  210. this.autoRequest.splice(index, 1);
  211. }
  212. });
  213. this.updateAutorequestLocalStorage();
  214. },
  215. updateAutorequestLocalStorage() {
  216. const key = `autorequest-${this.station._id}`;
  217. const playlistIds = Array.from(
  218. new Set(this.autoRequest.map(playlist => playlist._id))
  219. );
  220. const value = {
  221. updatedAt: new Date(),
  222. playlistIds
  223. };
  224. localStorage.setItem(key, JSON.stringify(value));
  225. },
  226. updateMediaModalPlayingAudio(mediaModalPlayingAudio) {
  227. this.mediaModalPlayingAudio = mediaModalPlayingAudio;
  228. },
  229. hasPermission(permission) {
  230. return !!(this.permissions && this.permissions[permission]);
  231. },
  232. updatePermissions() {
  233. return new Promise(resolve => {
  234. const { socket } = useWebsocketsStore();
  235. socket.dispatch(
  236. "api.getUserModelPermissions",
  237. { modelName: "stations", modelId: this.station._id },
  238. res => {
  239. this.permissions = res.data;
  240. resolve(this.permissions);
  241. }
  242. );
  243. });
  244. },
  245. addDj(user) {
  246. this.station.djs.push(user);
  247. },
  248. removeDj(user) {
  249. this.station.djs.forEach((dj, index) => {
  250. if (dj._id === user._id) {
  251. this.station.djs.splice(index, 1);
  252. }
  253. });
  254. },
  255. setHistory(history: StationHistory[]) {
  256. this.history = history;
  257. },
  258. addHistoryItem(historyItem: StationHistory) {
  259. this.history.unshift(historyItem);
  260. }
  261. }
  262. });