Sfoglia il codice sorgente

Merge pull request #71 from Musare/kris-youtube-id-migration

Youtube id migration
Vos 3 anni fa
parent
commit
42a5f9072c
36 ha cambiato i file con 750 aggiunte e 508 eliminazioni
  1. 43 42
      backend/logic/actions/playlists.js
  2. 11 7
      backend/logic/actions/reports.js
  3. 83 79
      backend/logic/actions/songs.js
  4. 32 24
      backend/logic/actions/stations.js
  5. 1 1
      backend/logic/activities.js
  6. 5 5
      backend/logic/db/index.js
  7. 2 2
      backend/logic/db/schemas/activity.js
  8. 2 2
      backend/logic/db/schemas/playlist.js
  9. 2 2
      backend/logic/db/schemas/report.js
  10. 2 2
      backend/logic/db/schemas/song.js
  11. 3 3
      backend/logic/db/schemas/station.js
  12. 215 0
      backend/logic/migration/migrations/migration8.js
  13. 15 15
      backend/logic/playlists.js
  14. 56 55
      backend/logic/songs.js
  15. 14 14
      backend/logic/stations.js
  16. 8 8
      backend/logic/youtube.js
  17. 12 6
      frontend/src/components/ActivityItem.vue
  18. 3 3
      frontend/src/components/AddToPlaylistDropdown.vue
  19. 4 2
      frontend/src/components/SongItem.vue
  20. 4 4
      frontend/src/components/SongThumbnail.vue
  21. 3 3
      frontend/src/components/modals/AddSongToQueue.vue
  22. 12 10
      frontend/src/components/modals/EditPlaylist.vue
  23. 120 132
      frontend/src/components/modals/EditSong.vue
  24. 4 4
      frontend/src/components/modals/Report.vue
  25. 3 3
      frontend/src/components/modals/RequestSong.vue
  26. 2 2
      frontend/src/components/modals/ViewReport.vue
  27. 4 4
      frontend/src/pages/Admin/tabs/HiddenSongs.vue
  28. 1 1
      frontend/src/pages/Admin/tabs/Reports.vue
  29. 5 5
      frontend/src/pages/Admin/tabs/UnverifiedSongs.vue
  30. 5 5
      frontend/src/pages/Admin/tabs/VerifiedSongs.vue
  31. 2 2
      frontend/src/pages/Home.vue
  32. 1 1
      frontend/src/pages/Profile/tabs/Playlists.vue
  33. 1 1
      frontend/src/pages/Station/Sidebar/Playlists.vue
  34. 4 4
      frontend/src/pages/Station/Sidebar/Queue.vue
  35. 65 54
      frontend/src/pages/Station/index.vue
  36. 1 1
      frontend/src/store/modules/station.js

+ 43 - 42
backend/logic/actions/playlists.js

@@ -92,7 +92,7 @@ CacheModule.runJob("SUB", {
 			sockets.forEach(socket => {
 				socket.dispatch("event:playlist.removeSong", {
 					playlistId: res.playlistId,
-					songId: res.songId
+					youtubeId: res.youtubeId
 				});
 			});
 		});
@@ -104,7 +104,7 @@ CacheModule.runJob("SUB", {
 					"event:playlist.removeSong",
 					{
 						playlistId: res.playlistId,
-						songId: res.songId
+						youtubeId: res.youtubeId
 					}
 				]
 			});
@@ -688,7 +688,7 @@ export default {
 	 *
 	 * @param {object} session - the session object automatically added by the websocket
 	 * @param {string} playlistId - the id of the playlist we are targeting
-	 * @param {Array} songsBeingChanged - the songs to be repositioned, each element contains "songId" and "position" properties
+	 * @param {Array} songsBeingChanged - the songs to be repositioned, each element contains "youtubeId" and "position" properties
 	 * @param {Function} cb - gets called with the result
 	 */
 	repositionSongs: isLoginRequired(async function repositionSongs(session, playlistId, songsBeingChanged, cb) {
@@ -702,7 +702,7 @@ export default {
 						songsBeingChanged,
 						(song, nextSong) =>
 							playlistModel.updateOne(
-								{ _id: playlistId, "songs.songId": song.songId },
+								{ _id: playlistId, "songs.youtubeId": song.youtubeId },
 								{
 									$set: {
 										"songs.$.position": song.position
@@ -764,10 +764,10 @@ export default {
 	 *
 	 * @param {object} session - the session object automatically added by the websocket
 	 * @param {string} playlistId - the id of the playlist we are moving the song to the bottom from
-	 * @param {string} songId - the id of the song we are moving to the bottom of the list
+	 * @param {string} youtubeId - the youtube id of the song we are moving to the bottom of the list
 	 * @param {Function} cb - gets called with the result
 	 */
-	moveSongToBottom: isLoginRequired(async function moveSongToBottom(session, playlistId, songId, cb) {
+	moveSongToBottom: isLoginRequired(async function moveSongToBottom(session, playlistId, youtubeId, cb) {
 		async.waterfall(
 			[
 				next => {
@@ -783,10 +783,10 @@ export default {
 					// sort array by position
 					playlist.songs.sort((a, b) => a.position - b.position);
 
-					// find index of songId
+					// find index of youtubeId
 					playlist.songs.forEach((song, index) => {
 						// reorder array (simulates what would be done with a drag and drop interface)
-						if (song.songId === songId)
+						if (song.youtubeId === youtubeId)
 							playlist.songs.splice(playlist.songs.length, 0, playlist.songs.splice(index, 1)[0]);
 					});
 
@@ -796,7 +796,7 @@ export default {
 						// check if position needs updated based on index
 						if (song.position !== index + 1)
 							songsBeingChanged.push({
-								songId: song.songId,
+								youtubeId: song.youtubeId,
 								position: index + 1
 							});
 					});
@@ -825,7 +825,7 @@ export default {
 					this.log(
 						"ERROR",
 						"PLAYLIST_MOVE_SONG_TO_BOTTOM",
-						`Moving song "${songId}" to the bottom for private playlist "${playlistId}" failed for user "${session.userId}". "${err}"`
+						`Moving song "${youtubeId}" to the bottom for private playlist "${playlistId}" failed for user "${session.userId}". "${err}"`
 					);
 					return cb({ status: "failure", message: err });
 				}
@@ -833,7 +833,7 @@ export default {
 				this.log(
 					"SUCCESS",
 					"PLAYLIST_MOVE_SONG_TO_BOTTOM",
-					`Successfully moved song "${songId}" to the bottom for private playlist "${playlistId}" for user "${session.userId}".`
+					`Successfully moved song "${youtubeId}" to the bottom for private playlist "${playlistId}" for user "${session.userId}".`
 				);
 
 				return cb({
@@ -849,11 +849,11 @@ export default {
 	 *
 	 * @param {object} session - the session object automatically added by the websocket
 	 * @param {boolean} isSet - is the song part of a set of songs to be added
-	 * @param {string} songId - the id of the song we are trying to add
+	 * @param {string} youtubeId - the youtube id of the song we are trying to add
 	 * @param {string} playlistId - the id of the playlist we are adding the song to
 	 * @param {Function} cb - gets called with the result
 	 */
-	addSongToPlaylist: isLoginRequired(async function addSongToPlaylist(session, isSet, songId, playlistId, cb) {
+	addSongToPlaylist: isLoginRequired(async function addSongToPlaylist(session, isSet, youtubeId, playlistId, cb) {
 		const playlistModel = await DBModule.runJob("GET_MODEL", { modelName: "playlist" }, this);
 
 		async.waterfall(
@@ -867,7 +867,8 @@ export default {
 							return async.each(
 								playlist.songs,
 								(song, nextSong) => {
-									if (song.songId === songId) return next("That song is already in the playlist");
+									if (song.youtubeId === youtubeId)
+										return next("That song is already in the playlist");
 									return nextSong();
 								},
 								err => next(err)
@@ -890,9 +891,9 @@ export default {
 
 				(user, next) => {
 					SongsModule.runJob(
-						"ENSURE_SONG_EXISTS_BY_SONG_ID",
+						"ENSURE_SONG_EXISTS_BY_YOUTUBE_ID",
 						{
-							songId,
+							youtubeId,
 							userId: user.preferences.anonymousSongRequests ? null : session.userId,
 							automaticallyRequested: true
 						},
@@ -903,7 +904,7 @@ export default {
 							const { _id, title, thumbnail, duration, status } = song;
 							next(null, {
 								_id,
-								songId,
+								youtubeId,
 								title,
 								thumbnail,
 								duration,
@@ -932,7 +933,7 @@ export default {
 					this.log(
 						"ERROR",
 						"PLAYLIST_ADD_SONG",
-						`Adding song "${songId}" to private playlist "${playlistId}" failed for user "${session.userId}". "${err}"`
+						`Adding song "${youtubeId}" to private playlist "${playlistId}" failed for user "${session.userId}". "${err}"`
 					);
 					return cb({ status: "failure", message: err });
 				}
@@ -940,7 +941,7 @@ export default {
 				this.log(
 					"SUCCESS",
 					"PLAYLIST_ADD_SONG",
-					`Successfully added song "${songId}" to private playlist "${playlistId}" for user "${session.userId}".`
+					`Successfully added song "${youtubeId}" to private playlist "${playlistId}" for user "${session.userId}".`
 				);
 
 				if (!isSet && playlist.displayName !== "Liked Songs" && playlist.displayName !== "Disliked Songs") {
@@ -952,10 +953,10 @@ export default {
 						userId: session.userId,
 						type: "playlist__add_song",
 						payload: {
-							message: `Added <songId>${songName}</songId> to playlist <playlistId>${playlist.displayName}</playlistId>`,
+							message: `Added <youtubeId>${songName}</youtubeId> to playlist <playlistId>${playlist.displayName}</playlistId>`,
 							thumbnail: newSong.thumbnail,
 							playlistId,
-							songId
+							youtubeId
 						}
 					});
 				}
@@ -1020,33 +1021,33 @@ export default {
 							next(err);
 						});
 				},
-				(songIds, next) => {
+				(youtubeIds, next) => {
 					let successful = 0;
 					let failed = 0;
 					let alreadyInPlaylist = 0;
 
-					if (songIds.length === 0) next();
+					if (youtubeIds.length === 0) next();
 
-					console.log(songIds);
+					console.log(youtubeIds);
 
 					async.eachLimit(
-						songIds,
+						youtubeIds,
 						1,
-						(songId, next) => {
+						(youtubeId, next) => {
 							WSModule.runJob(
 								"RUN_ACTION2",
 								{
 									session,
 									namespace: "playlists",
 									action: "addSongToPlaylist",
-									args: [true, songId, playlistId]
+									args: [true, youtubeId, playlistId]
 								},
 								this
 							)
 								.then(res => {
 									if (res.status === "success") {
 										successful += 1;
-										addedSongs.push(songId);
+										addedSongs.push(youtubeId);
 									} else failed += 1;
 									if (res.message === "That song is already in the playlist") alreadyInPlaylist += 1;
 								})
@@ -1118,17 +1119,17 @@ export default {
 	 * Removes a song from a private playlist
 	 *
 	 * @param {object} session - the session object automatically added by the websocket
-	 * @param {string} songId - the id of the song we are removing from the private playlist
+	 * @param {string} youtubeId - the youtube id of the song we are removing from the private playlist
 	 * @param {string} playlistId - the id of the playlist we are removing the song from
 	 * @param {Function} cb - gets called with the result
 	 */
-	removeSongFromPlaylist: isLoginRequired(async function removeSongFromPlaylist(session, songId, playlistId, cb) {
+	removeSongFromPlaylist: isLoginRequired(async function removeSongFromPlaylist(session, youtubeId, playlistId, cb) {
 		const playlistModel = await DBModule.runJob("GET_MODEL", { modelName: "playlist" }, this);
 
 		async.waterfall(
 			[
 				next => {
-					if (!songId || typeof songId !== "string") return next("Invalid song id.");
+					if (!youtubeId || typeof youtubeId !== "string") return next("Invalid song id.");
 					if (!playlistId) return next("Invalid playlist id.");
 					return next();
 				},
@@ -1145,10 +1146,10 @@ export default {
 					// sort array by position
 					playlist.songs.sort((a, b) => a.position - b.position);
 
-					// find index of songId
+					// find index of youtubeId
 					playlist.songs.forEach((song, ind) => {
 						// remove song from array
-						if (song.songId === songId) playlist.songs.splice(ind, 1);
+						if (song.youtubeId === youtubeId) playlist.songs.splice(ind, 1);
 					});
 
 					const songsBeingChanged = [];
@@ -1157,7 +1158,7 @@ export default {
 						// check if position needs updated based on index
 						if (song.position !== index + 1)
 							songsBeingChanged.push({
-								songId: song.songId,
+								youtubeId: song.youtubeId,
 								position: index + 1
 							});
 					});
@@ -1180,7 +1181,7 @@ export default {
 						.catch(next);
 				},
 
-				next => playlistModel.updateOne({ _id: playlistId }, { $pull: { songs: { songId } } }, next),
+				next => playlistModel.updateOne({ _id: playlistId }, { $pull: { songs: { youtubeId } } }, next),
 
 				(res, next) => {
 					PlaylistsModule.runJob("UPDATE_PLAYLIST", { playlistId }, this)
@@ -1197,7 +1198,7 @@ export default {
 						})
 						.catch();
 
-					SongsModule.runJob("GET_SONG_FROM_ID", { songId }, this)
+					SongsModule.runJob("GET_SONG_FROM_YOUTUBE_ID", { youtubeId }, this)
 						.then(res =>
 							next(null, playlist, {
 								title: res.song.title,
@@ -1206,7 +1207,7 @@ export default {
 							})
 						)
 						.catch(() => {
-							YouTubeModule.runJob("GET_SONG", { songId }, this)
+							YouTubeModule.runJob("GET_SONG", { youtubeId }, this)
 								.then(response => next(null, playlist, response.song))
 								.catch(next);
 						});
@@ -1222,10 +1223,10 @@ export default {
 							userId: session.userId,
 							type: "playlist__remove_song",
 							payload: {
-								message: `Removed <songId>${songName}</songId> from playlist <playlistId>${playlist.displayName}</playlistId>`,
+								message: `Removed <youtubeId>${songName}</youtubeId> from playlist <playlistId>${playlist.displayName}</playlistId>`,
 								thumbnail: youtubeSong.thumbnail,
 								playlistId,
-								songId
+								youtubeId
 							}
 						});
 					}
@@ -1239,7 +1240,7 @@ export default {
 					this.log(
 						"ERROR",
 						"PLAYLIST_REMOVE_SONG",
-						`Removing song "${songId}" from private playlist "${playlistId}" failed for user "${session.userId}". "${err}"`
+						`Removing song "${youtubeId}" from private playlist "${playlistId}" failed for user "${session.userId}". "${err}"`
 					);
 					return cb({ status: "failure", message: err });
 				}
@@ -1247,14 +1248,14 @@ export default {
 				this.log(
 					"SUCCESS",
 					"PLAYLIST_REMOVE_SONG",
-					`Successfully removed song "${songId}" from private playlist "${playlistId}" for user "${session.userId}".`
+					`Successfully removed song "${youtubeId}" from private playlist "${playlistId}" for user "${session.userId}".`
 				);
 
 				CacheModule.runJob("PUB", {
 					channel: "playlist.removeSong",
 					value: {
 						playlistId: playlist._id,
-						songId,
+						youtubeId,
 						userId: session.userId,
 						privacy: playlist.privacy
 					}

+ 11 - 7
backend/logic/actions/reports.js

@@ -121,7 +121,7 @@ export default {
 	}),
 
 	/**
-	 * Gets all reports for a songId (_id)
+	 * Gets all reports for a songId
 	 *
 	 * @param {object} session - the session object automatically added by the websocket
 	 * @param {string} songId - the id of the song to index reports for
@@ -231,13 +231,13 @@ export default {
 		async.waterfall(
 			[
 				next => {
-					songModel.findOne({ songId: data.songId }).exec(next);
+					songModel.findOne({ youtubeId: data.youtubeId }).exec(next);
 				},
 
 				(song, next) => {
 					if (!song) return next("Song not found.");
 
-					return SongsModule.runJob("GET_SONG", { id: song._id }, this)
+					return SongsModule.runJob("GET_SONG", { songId: song._id }, this)
 						.then(res => next(null, res.song))
 						.catch(next);
 				},
@@ -245,10 +245,10 @@ export default {
 				(song, next) => {
 					if (!song) return next("Song not found.");
 
-					delete data.songId;
+					delete data.youtubeId;
 					data.song = {
 						_id: song._id,
-						songId: song.songId
+						youtubeId: song.youtubeId
 					};
 
 					for (let z = 0; z < data.issues.length; z += 1) {
@@ -314,13 +314,17 @@ export default {
 					userId: report.createdBy,
 					type: "song__report",
 					payload: {
-						message: `Reported song <songId>${song.title} by ${song.artists.join(", ")}</songId>`,
+						message: `Reported song <youtubeId>${song.title} by ${song.artists.join(", ")}</youtubeId>`,
 						songId: data.song._id,
 						thumbnail: song.thumbnail
 					}
 				});
 
-				this.log("SUCCESS", "REPORTS_CREATE", `User "${session.userId}" created report for "${data.songId}".`);
+				this.log(
+					"SUCCESS",
+					"REPORTS_CREATE",
+					`User "${session.userId}" created report for "${data.youtubeId}".`
+				);
 
 				return cb({
 					status: "success",

+ 83 - 79
backend/logic/actions/songs.js

@@ -310,14 +310,14 @@ export default {
 	 * Gets a song from the YouTube song id
 	 *
 	 * @param {object} session - the session object automatically added by the websocket
-	 * @param {string} songId - the YouTube song id
+	 * @param {string} youtubeId - the YouTube song id
 	 * @param {Function} cb
 	 */
-	getSong: isAdminRequired(function getSong(session, songId, cb) {
+	getSong: isAdminRequired(function getSong(session, youtubeId, cb) {
 		async.waterfall(
 			[
 				next => {
-					SongsModule.runJob("GET_SONG_FROM_ID", { songId }, this)
+					SongsModule.runJob("GET_SONG_FROM_YOUTUBE_ID", { youtubeId }, this)
 						.then(song => {
 							next(null, song);
 						})
@@ -329,10 +329,10 @@ export default {
 			async (err, song) => {
 				if (err) {
 					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
-					this.log("ERROR", "SONGS_GET_SONG", `Failed to get song ${songId}. "${err}"`);
+					this.log("ERROR", "SONGS_GET_SONG", `Failed to get song ${youtubeId}. "${err}"`);
 					return cb({ status: "failure", message: err });
 				}
-				this.log("SUCCESS", "SONGS_GET_SONG", `Got song ${songId} successfully.`);
+				this.log("SUCCESS", "SONGS_GET_SONG", `Got song ${youtubeId} successfully.`);
 				return cb({ status: "success", data: song });
 			}
 		);
@@ -342,14 +342,14 @@ export default {
 	 * Gets a song from the Musare song id
 	 *
 	 * @param {object} session - the session object automatically added by the websocket
-	 * @param {string} songId - the Musare song id
+	 * @param {string} songId - the song id
 	 * @param {Function} cb
 	 */
-	getSongFromMusareId: isAdminRequired(function getSong(session, songId, cb) {
+	getSongFromSongId: isAdminRequired(function getSong(session, songId, cb) {
 		async.waterfall(
 			[
 				next => {
-					SongsModule.runJob("GET_SONG", { id: songId }, this)
+					SongsModule.runJob("GET_SONG", { songId }, this)
 						.then(response => next(null, response.song))
 						.catch(err => next(err));
 				}
@@ -370,14 +370,14 @@ export default {
 	 * Obtains basic metadata of a song in order to format an activity
 	 *
 	 * @param {object} session - the session object automatically added by the websocket
-	 * @param {string} songId - the song id
+	 * @param {string} youtubeId - the youtube song id
 	 * @param {Function} cb - callback
 	 */
-	getSongForActivity(session, songId, cb) {
+	getSongForActivity(session, youtubeId, cb) {
 		async.waterfall(
 			[
 				next => {
-					SongsModule.runJob("GET_SONG_FROM_ID", { songId }, this)
+					SongsModule.runJob("GET_SONG_FROM_YOUTUBE_ID", { youtubeId }, this)
 						.then(response => next(null, response.song))
 						.catch(next);
 				}
@@ -389,7 +389,7 @@ export default {
 					this.log(
 						"ERROR",
 						"SONGS_GET_SONG_FOR_ACTIVITY",
-						`Failed to obtain metadata of song ${songId} for activity formatting. "${err}"`
+						`Failed to obtain metadata of song ${youtubeId} for activity formatting. "${err}"`
 					);
 
 					return cb({ status: "failure", message: err });
@@ -399,7 +399,7 @@ export default {
 					this.log(
 						"SUCCESS",
 						"SONGS_GET_SONG_FOR_ACTIVITY",
-						`Obtained metadata of song ${songId} for activity formatting successfully.`
+						`Obtained metadata of song ${youtubeId} for activity formatting successfully.`
 					);
 
 					return cb({
@@ -414,7 +414,7 @@ export default {
 				this.log(
 					"ERROR",
 					"SONGS_GET_SONG_FOR_ACTIVITY",
-					`Song ${songId} does not exist so failed to obtain for activity formatting.`
+					`Song ${youtubeId} does not exist so failed to obtain for activity formatting.`
 				);
 
 				return cb({ status: "failure" });
@@ -570,16 +570,16 @@ export default {
 	 * Requests a song
 	 *
 	 * @param {object} session - the session object automatically added by the websocket
-	 * @param {string} songId - the id of the song that gets requested
+	 * @param {string} youtubeId - the youtube id of the song that gets requested
 	 * @param {Function} cb - gets called with the result
 	 */
-	request: isLoginRequired(async function add(session, songId, cb) {
-		SongsModule.runJob("REQUEST_SONG", { songId, userId: session.userId }, this)
+	request: isLoginRequired(async function add(session, youtubeId, cb) {
+		SongsModule.runJob("REQUEST_SONG", { youtubeId, userId: session.userId }, this)
 			.then(() => {
 				this.log(
 					"SUCCESS",
 					"SONGS_REQUEST",
-					`User "${session.userId}" successfully requested song "${songId}".`
+					`User "${session.userId}" successfully requested song "${youtubeId}".`
 				);
 				return cb({
 					status: "success",
@@ -591,7 +591,7 @@ export default {
 				this.log(
 					"ERROR",
 					"SONGS_REQUEST",
-					`Requesting song "${songId}" failed for user ${session.userId}. "${err}"`
+					`Requesting song "${youtubeId}" failed for user ${session.userId}. "${err}"`
 				);
 				return cb({ status: "failure", message: err });
 			});
@@ -601,7 +601,7 @@ export default {
 	 * Hides a song
 	 *
 	 * @param {object} session - the session object automatically added by the websocket
-	 * @param {string} songId - the Musare id of the song that gets hidden
+	 * @param {string} songId - the song id of the song that gets hidden
 	 * @param {Function} cb - gets called with the result
 	 */
 	hide: isLoginRequired(async function add(session, songId, cb) {
@@ -624,7 +624,7 @@ export default {
 	 * Unhides a song
 	 *
 	 * @param {object} session - the session object automatically added by the websocket
-	 * @param {string} songId - the Musare id of the song that gets hidden
+	 * @param {string} songId - the song id of the song that gets hidden
 	 * @param {Function} cb - gets called with the result
 	 */
 	unhide: isLoginRequired(async function add(session, songId, cb) {
@@ -651,15 +651,15 @@ export default {
 	 * Verifies a song
 	 *
 	 * @param session
-	 * @param song - the song object
+	 * @param youtubeId - the youtube id
 	 * @param cb
 	 */
-	verify: isAdminRequired(async function add(session, songId, cb) {
+	verify: isAdminRequired(async function add(session, youtubeId, cb) {
 		const SongModel = await DBModule.runJob("GET_MODEL", { modelName: "song" }, this);
 		async.waterfall(
 			[
 				next => {
-					SongModel.findOne({ songId }, next);
+					SongModel.findOne({ youtubeId }, next);
 				},
 
 				(song, next) => {
@@ -697,7 +697,11 @@ export default {
 					return cb({ status: "failure", message: err });
 				}
 
-				this.log("SUCCESS", "SONGS_VERIFY", `User "${session.userId}" successfully verified song "${songId}".`);
+				this.log(
+					"SUCCESS",
+					"SONGS_VERIFY",
+					`User "${session.userId}" successfully verified song "${youtubeId}".`
+				);
 
 				CacheModule.runJob("PUB", {
 					channel: "song.newVerifiedSong",
@@ -751,7 +755,7 @@ export default {
 							.catch(() => {});
 					});
 
-					SongsModule.runJob("UPDATE_SONG", { songId: song._id });
+					SongsModule.runJob("UPDATE_SONG", { songId });
 
 					next(null);
 				}
@@ -815,24 +819,24 @@ export default {
 						})
 						.catch(next);
 				},
-				(songIds, next) => {
+				(youtubeIds, next) => {
 					let successful = 0;
 					let failed = 0;
 					let alreadyInDatabase = 0;
 
-					if (songIds.length === 0) next();
+					if (youtubeIds.length === 0) next();
 
 					async.eachLimit(
-						songIds,
+						youtubeIds,
 						1,
-						(songId, next) => {
+						(youtubeId, next) => {
 							WSModule.runJob(
 								"RUN_ACTION2",
 								{
 									session,
 									namespace: "songs",
 									action: "request",
-									args: [songId]
+									args: [youtubeId]
 								},
 								this
 							)
@@ -889,7 +893,7 @@ export default {
 	// 	async.waterfall(
 	// 		[
 	// 			next => {
-	// 				SongModel.findOne({ songId: song.songId }, next);
+	// 				SongModel.findOne({ youtubeId: song.youtubeId }, next);
 	// 			},
 
 	// 			(existingSong, next) => {
@@ -936,11 +940,11 @@ export default {
 	// 				return cb({ status: "failure", message: err });
 	// 			}
 
-	// 			this.log("SUCCESS", "SONGS_ADD", `User "${session.userId}" successfully added song "${song.songId}".`);
+	// 			this.log("SUCCESS", "SONGS_ADD", `User "${session.userId}" successfully added song "${song.youtubeId}".`);
 
 	// 			CacheModule.runJob("PUB", {
 	// 				channel: "song.added",
-	// 				value: song.songId
+	// 				value: song.youtubeId
 	// 			});
 
 	// 			return cb({
@@ -956,16 +960,16 @@ export default {
 	 * Likes a song
 	 *
 	 * @param session
-	 * @param musareSongId - the song id
+	 * @param youtubeId - the youtube id
 	 * @param cb
 	 */
-	like: isLoginRequired(async function like(session, musareSongId, cb) {
+	like: isLoginRequired(async function like(session, youtubeId, cb) {
 		const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" }, this);
 		const songModel = await DBModule.runJob("GET_MODEL", { modelName: "song" }, this);
 
 		async.waterfall(
 			[
-				next => songModel.findOne({ songId: musareSongId }, next),
+				next => songModel.findOne({ youtubeId }, next),
 
 				(song, next) => {
 					if (!song) return next("No song found with that id.");
@@ -984,7 +988,7 @@ export default {
 								session,
 								namespace: "playlists",
 								action: "addSongToPlaylist",
-								args: [false, musareSongId, user.likedSongsPlaylist]
+								args: [false, youtubeId, user.likedSongsPlaylist]
 							},
 							this
 						)
@@ -1004,7 +1008,7 @@ export default {
 								session,
 								namespace: "playlists",
 								action: "removeSongFromPlaylist",
-								args: [musareSongId, dislikedSongsPlaylist]
+								args: [youtubeId, dislikedSongsPlaylist]
 							},
 							this
 						)
@@ -1017,7 +1021,7 @@ export default {
 				},
 
 				(song, next) => {
-					SongsModule.runJob("RECALCULATE_SONG_RATINGS", { songId: song._id, musareSongId })
+					SongsModule.runJob("RECALCULATE_SONG_RATINGS", { songId: song._id, youtubeId })
 						.then(ratings => next(null, song, ratings))
 						.catch(err => next(err));
 				}
@@ -1028,7 +1032,7 @@ export default {
 					this.log(
 						"ERROR",
 						"SONGS_LIKE",
-						`User "${session.userId}" failed to like song ${musareSongId}. "${err}"`
+						`User "${session.userId}" failed to like song ${youtubeId}. "${err}"`
 					);
 					return cb({ status: "failure", message: err });
 				}
@@ -1038,7 +1042,7 @@ export default {
 				CacheModule.runJob("PUB", {
 					channel: "song.like",
 					value: JSON.stringify({
-						songId: musareSongId,
+						youtubeId,
 						userId: session.userId,
 						likes,
 						dislikes
@@ -1049,7 +1053,7 @@ export default {
 					userId: session.userId,
 					type: "song__like",
 					payload: {
-						message: `Liked song <songId>${song.title} by ${song.artists.join(", ")}</songId>`,
+						message: `Liked song <youtubeId>${song.title} by ${song.artists.join(", ")}</youtubeId>`,
 						songId: song._id,
 						thumbnail: song.thumbnail
 					}
@@ -1069,17 +1073,17 @@ export default {
 	 * Dislikes a song
 	 *
 	 * @param session
-	 * @param musareSongId - the song id
+	 * @param youtubeId - the youtube id
 	 * @param cb
 	 */
-	dislike: isLoginRequired(async function dislike(session, musareSongId, cb) {
+	dislike: isLoginRequired(async function dislike(session, youtubeId, cb) {
 		const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" }, this);
 		const songModel = await DBModule.runJob("GET_MODEL", { modelName: "song" }, this);
 
 		async.waterfall(
 			[
 				next => {
-					songModel.findOne({ songId: musareSongId }, next);
+					songModel.findOne({ youtubeId }, next);
 				},
 
 				(song, next) => {
@@ -1099,7 +1103,7 @@ export default {
 								session,
 								namespace: "playlists",
 								action: "addSongToPlaylist",
-								args: [false, musareSongId, user.dislikedSongsPlaylist]
+								args: [false, youtubeId, user.dislikedSongsPlaylist]
 							},
 							this
 						)
@@ -1119,7 +1123,7 @@ export default {
 								session,
 								namespace: "playlists",
 								action: "removeSongFromPlaylist",
-								args: [musareSongId, likedSongsPlaylist]
+								args: [youtubeId, likedSongsPlaylist]
 							},
 							this
 						)
@@ -1132,7 +1136,7 @@ export default {
 				},
 
 				(song, next) => {
-					SongsModule.runJob("RECALCULATE_SONG_RATINGS", { songId: song._id, musareSongId })
+					SongsModule.runJob("RECALCULATE_SONG_RATINGS", { songId: song._id, youtubeId })
 						.then(ratings => next(null, song, ratings))
 						.catch(err => next(err));
 				}
@@ -1143,7 +1147,7 @@ export default {
 					this.log(
 						"ERROR",
 						"SONGS_DISLIKE",
-						`User "${session.userId}" failed to dislike song ${musareSongId}. "${err}"`
+						`User "${session.userId}" failed to dislike song ${youtubeId}. "${err}"`
 					);
 					return cb({ status: "failure", message: err });
 				}
@@ -1153,7 +1157,7 @@ export default {
 				CacheModule.runJob("PUB", {
 					channel: "song.dislike",
 					value: JSON.stringify({
-						songId: musareSongId,
+						youtubeId,
 						userId: session.userId,
 						likes,
 						dislikes
@@ -1164,7 +1168,7 @@ export default {
 					userId: session.userId,
 					type: "song__dislike",
 					payload: {
-						message: `Disliked song <songId>${song.title} by ${song.artists.join(", ")}</songId>`,
+						message: `Disliked song <youtubeId>${song.title} by ${song.artists.join(", ")}</youtubeId>`,
 						songId: song._id,
 						thumbnail: song.thumbnail
 					}
@@ -1182,17 +1186,17 @@ export default {
 	 * Undislikes a song
 	 *
 	 * @param session
-	 * @param musareSongId - the song id
+	 * @param youtubeId - the youtube id
 	 * @param cb
 	 */
-	undislike: isLoginRequired(async function undislike(session, musareSongId, cb) {
+	undislike: isLoginRequired(async function undislike(session, youtubeId, cb) {
 		const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" }, this);
 		const songModel = await DBModule.runJob("GET_MODEL", { modelName: "song" }, this);
 
 		async.waterfall(
 			[
 				next => {
-					songModel.findOne({ songId: musareSongId }, next);
+					songModel.findOne({ youtubeId }, next);
 				},
 
 				(song, next) => {
@@ -1212,7 +1216,7 @@ export default {
 								session,
 								namespace: "playlists",
 								action: "removeSongFromPlaylist",
-								args: [musareSongId, user.dislikedSongsPlaylist]
+								args: [youtubeId, user.dislikedSongsPlaylist]
 							},
 							this
 						)
@@ -1232,7 +1236,7 @@ export default {
 								session,
 								namespace: "playlists",
 								action: "removeSongFromPlaylist",
-								args: [musareSongId, likedSongsPlaylist]
+								args: [youtubeId, likedSongsPlaylist]
 							},
 							this
 						)
@@ -1245,7 +1249,7 @@ export default {
 				},
 
 				(song, next) => {
-					SongsModule.runJob("RECALCULATE_SONG_RATINGS", { songId: song._id, musareSongId })
+					SongsModule.runJob("RECALCULATE_SONG_RATINGS", { songId: song._id, youtubeId })
 						.then(ratings => next(null, song, ratings))
 						.catch(err => next(err));
 				}
@@ -1256,7 +1260,7 @@ export default {
 					this.log(
 						"ERROR",
 						"SONGS_UNDISLIKE",
-						`User "${session.userId}" failed to undislike song ${musareSongId}. "${err}"`
+						`User "${session.userId}" failed to undislike song ${youtubeId}. "${err}"`
 					);
 					return cb({ status: "failure", message: err });
 				}
@@ -1266,7 +1270,7 @@ export default {
 				CacheModule.runJob("PUB", {
 					channel: "song.undislike",
 					value: JSON.stringify({
-						songId: musareSongId,
+						youtubeId,
 						userId: session.userId,
 						likes,
 						dislikes
@@ -1277,9 +1281,9 @@ export default {
 					userId: session.userId,
 					type: "song__undislike",
 					payload: {
-						message: `Removed <songId>${song.title} by ${song.artists.join(
+						message: `Removed <youtubeId>${song.title} by ${song.artists.join(
 							", "
-						)}</songId> from your Disliked Songs`,
+						)}</youtubeId> from your Disliked Songs`,
 						songId: song._id,
 						thumbnail: song.thumbnail
 					}
@@ -1297,17 +1301,17 @@ export default {
 	 * Unlikes a song
 	 *
 	 * @param session
-	 * @param musareSongId - the song id
+	 * @param youtubeId - the youtube id
 	 * @param cb
 	 */
-	unlike: isLoginRequired(async function unlike(session, musareSongId, cb) {
+	unlike: isLoginRequired(async function unlike(session, youtubeId, cb) {
 		const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" }, this);
 		const songModel = await DBModule.runJob("GET_MODEL", { modelName: "song" }, this);
 
 		async.waterfall(
 			[
 				next => {
-					songModel.findOne({ songId: musareSongId }, next);
+					songModel.findOne({ youtubeId }, next);
 				},
 
 				(song, next) => {
@@ -1327,7 +1331,7 @@ export default {
 								session,
 								namespace: "playlists",
 								action: "removeSongFromPlaylist",
-								args: [musareSongId, user.dislikedSongsPlaylist]
+								args: [youtubeId, user.dislikedSongsPlaylist]
 							},
 							this
 						)
@@ -1347,7 +1351,7 @@ export default {
 								session,
 								namespace: "playlists",
 								action: "removeSongFromPlaylist",
-								args: [musareSongId, likedSongsPlaylist]
+								args: [youtubeId, likedSongsPlaylist]
 							},
 							this
 						)
@@ -1360,7 +1364,7 @@ export default {
 				},
 
 				(song, next) => {
-					SongsModule.runJob("RECALCULATE_SONG_RATINGS", { songId: song._id, musareSongId })
+					SongsModule.runJob("RECALCULATE_SONG_RATINGS", { songId: song._id, youtubeId })
 						.then(ratings => next(null, song, ratings))
 						.catch(err => next(err));
 				}
@@ -1371,7 +1375,7 @@ export default {
 					this.log(
 						"ERROR",
 						"SONGS_UNLIKE",
-						`User "${session.userId}" failed to unlike song ${musareSongId}. "${err}"`
+						`User "${session.userId}" failed to unlike song ${youtubeId}. "${err}"`
 					);
 					return cb({ status: "failure", message: err });
 				}
@@ -1381,7 +1385,7 @@ export default {
 				CacheModule.runJob("PUB", {
 					channel: "song.unlike",
 					value: JSON.stringify({
-						songId: musareSongId,
+						youtubeId,
 						userId: session.userId,
 						likes,
 						dislikes
@@ -1392,9 +1396,9 @@ export default {
 					userId: session.userId,
 					type: "song__unlike",
 					payload: {
-						message: `Removed <songId>${song.title} by ${song.artists.join(
+						message: `Removed <youtubeId>${song.title} by ${song.artists.join(
 							", "
-						)}</songId> from your Liked Songs`,
+						)}</youtubeId> from your Liked Songs`,
 						songId: song._id,
 						thumbnail: song.thumbnail
 					}
@@ -1412,18 +1416,18 @@ export default {
 	 * Gets user's own song ratings
 	 *
 	 * @param session
-	 * @param musareSongId - the song id
+	 * @param youtubeId - the youtube id
 	 * @param cb
 	 */
 
-	getOwnSongRatings: isLoginRequired(async function getOwnSongRatings(session, musareSongId, cb) {
+	getOwnSongRatings: isLoginRequired(async function getOwnSongRatings(session, youtubeId, cb) {
 		const playlistModel = await DBModule.runJob("GET_MODEL", { modelName: "playlist" }, this);
 		const songModel = await DBModule.runJob("GET_MODEL", { modelName: "song" }, this);
 
 		async.waterfall(
 			[
 				next => {
-					songModel.findOne({ songId: musareSongId }, next);
+					songModel.findOne({ youtubeId }, next);
 				},
 
 				(song, next) => {
@@ -1442,7 +1446,7 @@ export default {
 
 							Object.values(playlist.songs).forEach(song => {
 								// song is found in 'liked songs' playlist
-								if (song.songId === musareSongId) isLiked = true;
+								if (song.youtubeId === youtubeId) isLiked = true;
 							});
 
 							return next(null, isLiked);
@@ -1460,7 +1464,7 @@ export default {
 
 							Object.values(playlist.songs).forEach(song => {
 								// song is found in 'disliked songs' playlist
-								if (song.songId === musareSongId) ratings.isDisliked = true;
+								if (song.youtubeId === youtubeId) ratings.isDisliked = true;
 							});
 
 							return next(null, ratings);
@@ -1473,7 +1477,7 @@ export default {
 					this.log(
 						"ERROR",
 						"SONGS_GET_OWN_RATINGS",
-						`User "${session.userId}" failed to get ratings for ${musareSongId}. "${err}"`
+						`User "${session.userId}" failed to get ratings for ${youtubeId}. "${err}"`
 					);
 					return cb({ status: "failure", message: err });
 				}
@@ -1482,7 +1486,7 @@ export default {
 
 				return cb({
 					status: "success",
-					songId: musareSongId,
+					youtubeId,
 					liked: isLiked,
 					disliked: isDisliked
 				});

+ 32 - 24
backend/logic/actions/stations.js

@@ -791,12 +791,16 @@ export default {
 
 					WSModule.runJob("SOCKET_JOIN_SONG_ROOM", {
 						socketId: session.socketId,
-						room: `song.${data.currentSong.songId}`
+						room: `song.${data.currentSong.youtubeId}`
 					});
 
 					data.currentSong.skipVotes = data.currentSong.skipVotes.length;
 
-					return SongsModule.runJob("GET_SONG_FROM_ID", { songId: data.currentSong.songId }, this)
+					return SongsModule.runJob(
+						"GET_SONG_FROM_YOUTUBE_ID",
+						{ youtubeId: data.currentSong.youtubeId },
+						this
+					)
 						.then(response => {
 							const { song } = response;
 							if (song) {
@@ -2773,10 +2777,10 @@ export default {
 	 *
 	 * @param session
 	 * @param stationId - the station id
-	 * @param songId - the song id
+	 * @param youtubeId - the song id
 	 * @param cb
 	 */
-	addToQueue: isLoginRequired(async function addToQueue(session, stationId, songId, cb) {
+	addToQueue: isLoginRequired(async function addToQueue(session, stationId, youtubeId, cb) {
 		const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" }, this);
 
 		const stationModel = await DBModule.runJob(
@@ -2831,13 +2835,13 @@ export default {
 				},
 
 				(station, next) => {
-					if (station.currentSong && station.currentSong.songId === songId)
+					if (station.currentSong && station.currentSong.youtubeId === youtubeId)
 						return next("That song is currently playing.");
 
 					return async.each(
 						station.queue,
 						(queueSong, next) => {
-							if (queueSong.songId === songId) return next("That song is already in the queue.");
+							if (queueSong.youtubeId === youtubeId) return next("That song is already in the queue.");
 							return next();
 						},
 						err => next(err, station)
@@ -2858,9 +2862,9 @@ export default {
 
 				(station, user, next) => {
 					SongsModule.runJob(
-						"ENSURE_SONG_EXISTS_BY_SONG_ID",
+						"ENSURE_SONG_EXISTS_BY_YOUTUBE_ID",
 						{
-							songId,
+							youtubeId,
 							userId: user.preferences.anonymousSongRequests ? null : session.userId,
 							automaticallyRequested: true
 						},
@@ -2873,7 +2877,7 @@ export default {
 								null,
 								{
 									_id,
-									songId,
+									youtubeId,
 									title,
 									thumbnail,
 									duration,
@@ -2961,7 +2965,7 @@ export default {
 					this.log(
 						"ERROR",
 						"STATIONS_ADD_SONG_TO_QUEUE",
-						`Adding song "${songId}" to station "${stationId}" queue failed. "${err}"`
+						`Adding song "${youtubeId}" to station "${stationId}" queue failed. "${err}"`
 					);
 					return cb({ status: "failure", message: err });
 				}
@@ -2969,7 +2973,7 @@ export default {
 				this.log(
 					"SUCCESS",
 					"STATIONS_ADD_SONG_TO_QUEUE",
-					`Added song "${songId}" to station "${stationId}" successfully.`
+					`Added song "${youtubeId}" to station "${stationId}" successfully.`
 				);
 
 				CacheModule.runJob("PUB", {
@@ -2990,16 +2994,16 @@ export default {
 	 *
 	 * @param session
 	 * @param stationId - the station id
-	 * @param songId - the song id
+	 * @param youtubeId - the youtube id
 	 * @param cb
 	 */
-	removeFromQueue: isOwnerRequired(async function removeFromQueue(session, stationId, songId, cb) {
+	removeFromQueue: isOwnerRequired(async function removeFromQueue(session, stationId, youtubeId, cb) {
 		const stationModel = await DBModule.runJob("GET_MODEL", { modelName: "station" }, this);
 
 		async.waterfall(
 			[
 				next => {
-					if (!songId) return next("Invalid song id.");
+					if (!youtubeId) return next("Invalid youtube id.");
 					return StationsModule.runJob("GET_STATION", { stationId }, this)
 						.then(station => next(null, station))
 						.catch(next);
@@ -3011,7 +3015,7 @@ export default {
 					return async.each(
 						station.queue,
 						(queueSong, next) => {
-							if (queueSong.songId === songId) return next(true);
+							if (queueSong.youtubeId === youtubeId) return next(true);
 							return next();
 						},
 						err => {
@@ -3022,7 +3026,7 @@ export default {
 				},
 
 				next => {
-					stationModel.updateOne({ _id: stationId }, { $pull: { queue: { songId } } }, next);
+					stationModel.updateOne({ _id: stationId }, { $pull: { queue: { youtubeId } } }, next);
 				},
 
 				(res, next) => {
@@ -3037,7 +3041,7 @@ export default {
 					this.log(
 						"ERROR",
 						"STATIONS_REMOVE_SONG_TO_QUEUE",
-						`Removing song "${songId}" from station "${stationId}" queue failed. "${err}"`
+						`Removing song "${youtubeId}" from station "${stationId}" queue failed. "${err}"`
 					);
 					return cb({ status: "failure", message: err });
 				}
@@ -3045,7 +3049,7 @@ export default {
 				this.log(
 					"SUCCESS",
 					"STATIONS_REMOVE_SONG_TO_QUEUE",
-					`Removed song "${songId}" from station "${stationId}" successfully.`
+					`Removed song "${youtubeId}" from station "${stationId}" successfully.`
 				);
 
 				CacheModule.runJob("PUB", {
@@ -3123,7 +3127,7 @@ export default {
 	 *
 	 * @param {object} session - user session
 	 * @param {object} song - contains details about the song that is to be repositioned
-	 * @param {string} song.songId - the id of the song
+	 * @param {string} song.youtubeId - the youtube id of the song
 	 * @param {number} song.newIndex - the new position for the song in the queue
 	 * @param {number} song.oldIndex - the old position of the song in the queue
 	 * @param {string} stationId - the station id
@@ -3135,13 +3139,17 @@ export default {
 		async.waterfall(
 			[
 				next => {
-					if (!song || !song.songId) return next("You must provide a song to reposition.");
+					if (!song || !song.youtubeId) return next("You must provide a song to reposition.");
 					return next();
 				},
 
 				// remove song from queue
 				next => {
-					stationModel.updateOne({ _id: stationId }, { $pull: { queue: { songId: song.songId } } }, next);
+					stationModel.updateOne(
+						{ _id: stationId },
+						{ $pull: { queue: { youtubeId: song.youtubeId } } },
+						next
+					);
 				},
 
 				// add song back to queue (in new position)
@@ -3168,7 +3176,7 @@ export default {
 					this.log(
 						"ERROR",
 						"STATIONS_REPOSITION_SONG_IN_QUEUE",
-						`Repositioning song ${song.songId} in queue of station "${stationId}" failed. "${err}"`
+						`Repositioning song ${song.youtubeId} in queue of station "${stationId}" failed. "${err}"`
 					);
 					return cb({ status: "failure", message: err });
 				}
@@ -3176,14 +3184,14 @@ export default {
 				this.log(
 					"SUCCESS",
 					"STATIONS_REPOSITION_SONG_IN_QUEUE",
-					`Repositioned song ${song.songId} in queue of station "${stationId}" successfully.`
+					`Repositioned song ${song.youtubeId} in queue of station "${stationId}" successfully.`
 				);
 
 				CacheModule.runJob("PUB", {
 					channel: "station.repositionSongInQueue",
 					value: {
 						song: {
-							songId: song.songId,
+							youtubeId: song.youtubeId,
 							oldIndex: song.oldIndex,
 							newIndex: song.newIndex
 						},

+ 1 - 1
backend/logic/activities.js

@@ -44,7 +44,7 @@ class _ActivitiesModule extends CoreClass {
 	 * @param {object} payload.payload - the details of the activity e.g. an array of songs that were added
 	 * @param {string} payload.payload.message - the main message describing the activity e.g. 50 songs added to playlist 'playlist name'
 	 * @param {string} payload.payload.thumbnail - url to a thumbnail e.g. song album art to be used when display an activity
-	 * @param {string} payload.payload.songId - (optional) if relevant, the id of the song related to the activity
+	 * @param {string} payload.payload.youtubeId - (optional) if relevant, the youtube id of the song related to the activity
 	 * @param {string} payload.payload.playlistId - (optional) if relevant, the id of the playlist related to the activity
 	 * @param {string} payload.payload.stationId - (optional) if relevant, the id of the station related to the activity
 	 * @returns {Promise} - returns promise (reject, resolve)

+ 5 - 5
backend/logic/db/index.js

@@ -6,14 +6,14 @@ import async from "async";
 import CoreClass from "../../core";
 
 const REQUIRED_DOCUMENT_VERSIONS = {
-	activity: 1,
+	activity: 2,
 	news: 1,
-	playlist: 2,
+	playlist: 3,
 	punishment: 1,
 	queueSong: 1,
-	report: 1,
-	song: 3,
-	station: 4,
+	report: 2,
+	song: 4,
+	station: 5,
 	user: 3
 };
 

+ 2 - 2
backend/logic/db/schemas/activity.js

@@ -48,9 +48,9 @@ export default {
 	payload: {
 		message: { type: String, default: "", required: true },
 		thumbnail: { type: String, required: false },
-		songId: { type: String, required: false },
+		youtubeId: { type: String, required: false },
 		stationId: { type: String, required: false },
 		playlistId: { type: String, required: false }
 	},
-	documentVersion: { type: Number, default: 1, required: true }
+	documentVersion: { type: Number, default: 2, required: true }
 };

+ 2 - 2
backend/logic/db/schemas/playlist.js

@@ -6,7 +6,7 @@ export default {
 	songs: [
 		{
 			_id: { type: mongoose.Schema.Types.ObjectId, required: false },
-			songId: { type: String },
+			youtubeId: { type: String },
 			title: { type: String },
 			duration: { type: Number },
 			thumbnail: { type: String, required: false },
@@ -20,5 +20,5 @@ export default {
 	createdFor: { type: String },
 	privacy: { type: String, enum: ["public", "private"], default: "private" },
 	type: { type: String, enum: ["user", "genre", "station"], required: true },
-	documentVersion: { type: Number, default: 2, required: true }
+	documentVersion: { type: Number, default: 3, required: true }
 };

+ 2 - 2
backend/logic/db/schemas/report.js

@@ -2,7 +2,7 @@ export default {
 	resolved: { type: Boolean, default: false, required: true },
 	song: {
 		_id: { type: String, required: true },
-		songId: { type: String, required: true }
+		youtubeId: { type: String, required: true }
 	},
 	description: { type: String },
 	issues: [
@@ -13,5 +13,5 @@ export default {
 	],
 	createdBy: { type: String, required: true },
 	createdAt: { type: Date, default: Date.now, required: true },
-	documentVersion: { type: Number, default: 1, required: true }
+	documentVersion: { type: Number, default: 2, required: true }
 };

+ 2 - 2
backend/logic/db/schemas/song.js

@@ -1,5 +1,5 @@
 export default {
-	songId: { type: String, min: 11, max: 11, required: true, index: true, unique: true },
+	youtubeId: { type: String, min: 11, max: 11, required: true, index: true, unique: true },
 	title: { type: String, required: true },
 	artists: [{ type: String, default: [] }],
 	genres: [{ type: String, default: [] }],
@@ -15,5 +15,5 @@ export default {
 	acceptedAt: { type: Date }, // TODO Should be verifiedAt
 	discogs: { type: Object },
 	status: { type: String, required: true, default: "hidden", enum: ["hidden", "unverified", "verified"] },
-	documentVersion: { type: Number, default: 3, required: true }
+	documentVersion: { type: Number, default: 4, required: true }
 };

+ 3 - 3
backend/logic/db/schemas/station.js

@@ -8,7 +8,7 @@ export default {
 	paused: { type: Boolean, default: false, required: true },
 	currentSong: {
 		_id: { type: String },
-		songId: { type: String },
+		youtubeId: { type: String },
 		title: { type: String },
 		artists: [{ type: String }],
 		duration: { type: Number },
@@ -30,7 +30,7 @@ export default {
 	locked: { type: Boolean, default: false },
 	queue: [
 		{
-			songId: { type: String, required: true },
+			youtubeId: { type: String, required: true },
 			title: { type: String },
 			artists: [{ type: String }],
 			duration: { type: Number },
@@ -49,5 +49,5 @@ export default {
 	theme: { type: String, enum: ["blue", "purple", "teal", "orange"], default: "blue" },
 	includedPlaylists: [{ type: String }],
 	excludedPlaylists: [{ type: String }],
-	documentVersion: { type: Number, default: 4, required: true }
+	documentVersion: { type: Number, default: 5, required: true }
 };

+ 215 - 0
backend/logic/migration/migrations/migration8.js

@@ -0,0 +1,215 @@
+import async from "async";
+
+/**
+ * Migration 8
+ *
+ * Migration for replacing songId with youtubeId whereever it is used, and using songId for any song's _id uses
+ *
+ * @param {object} MigrationModule - the MigrationModule
+ * @returns {Promise} - returns promise
+ */
+export default async function migrate(MigrationModule) {
+	const activityModel = await MigrationModule.runJob("GET_MODEL", { modelName: "activity" }, this);
+	const playlistModel = await MigrationModule.runJob("GET_MODEL", { modelName: "playlist" }, this);
+	const reportModel = await MigrationModule.runJob("GET_MODEL", { modelName: "report" }, this);
+	const songModel = await MigrationModule.runJob("GET_MODEL", { modelName: "song" }, this);
+	const stationModel = await MigrationModule.runJob("GET_MODEL", { modelName: "station" }, this);
+
+	return new Promise((resolve, reject) => {
+		async.waterfall(
+			[
+				next => {
+					// return next("BLOCKED");
+					this.log("INFO", `Migration 8. Finding activities with document version 1.`);
+					activityModel.find({ documentVersion: 1 }, (err, activities) => {
+						if (err) next(err);
+						else {
+							async.eachLimit(
+								activities.map(activity => activity._doc),
+								1,
+								(activity, next) => {
+									const { payload } = activity;
+									if (payload.songId) {
+										payload.youtubeId = payload.songId;
+										delete payload.songId;
+									}
+									if (payload.message)
+										payload.message = payload.message
+											.replaceAll("<songId", "<youtubeId")
+											.replaceAll("</songId", "</youtubeId");
+
+									activityModel.updateOne(
+										{ _id: activity._id },
+										{ $set: { payload, documentVersion: 2 } },
+										next
+									);
+								},
+								err => {
+									if (err) next(err);
+									else {
+										this.log("INFO", `Migration 8. Activities found: ${activities.length}.`);
+										next();
+									}
+								}
+							);
+						}
+					});
+				},
+
+				next => {
+					this.log("INFO", `Migration 8. Finding playlists with document version 2.`);
+					playlistModel.find({ documentVersion: 2 }, (err, playlists) => {
+						if (err) next(err);
+						else {
+							async.eachLimit(
+								playlists.map(playlist => playlist._doc),
+								1,
+								(playlist, next) => {
+									const songs = playlist.songs.map(song => {
+										song.youtubeId = song.songId;
+										delete song.songId;
+										return song;
+									});
+
+									playlistModel.updateOne({ _id: playlist._id }, { $set: { songs } }, next);
+								},
+								err => {
+									if (err) next(err);
+									else {
+										playlistModel.updateMany(
+											{ documentVersion: 2 },
+											{ $set: { documentVersion: 3 } },
+											(err, res) => {
+												if (err) next(err);
+												else {
+													this.log(
+														"INFO",
+														`Migration 8. Matched: ${res.n}, modified: ${res.nModified}, ok: ${res.ok}.`
+													);
+													next();
+												}
+											}
+										);
+									}
+								}
+							);
+						}
+					});
+				},
+
+				next => {
+					this.log("INFO", `Migration 8. Finding reports with document version 1.`);
+					reportModel.updateMany(
+						{ documentVersion: 1 },
+						{ $set: { documentVersion: 2 }, $rename: { "song.songId": "song.youtubeId" } },
+						(err, res) => {
+							if (err) next(err);
+							else {
+								this.log(
+									"INFO",
+									`Migration 8. Matched: ${res.n}, modified: ${res.nModified}, ok: ${res.ok}.`
+								);
+								next();
+							}
+						}
+					);
+				},
+
+				next => {
+					this.log("INFO", `Migration 8. Dropping indexes.`);
+					songModel.collection.dropIndexes((err, res) => {
+						if (err) next(err);
+						else {
+							this.log("INFO", `Migration 8. Dropped indexes: ${res}.`);
+							next();
+						}
+					});
+				},
+
+				next => {
+					this.log("INFO", `Migration 8. Finding spmgs with document version 3.`);
+					songModel.updateMany(
+						{ documentVersion: 3 },
+						{ $set: { documentVersion: 4 }, $rename: { songId: "youtubeId" } },
+						(err, res) => {
+							if (err) next(err);
+							else {
+								this.log(
+									"INFO",
+									`Migration 8. Matched: ${res.n}, modified: ${res.nModified}, ok: ${res.ok}.`
+								);
+								next();
+							}
+						}
+					);
+				},
+
+				next => {
+					this.log("INFO", `Migration 8. Finding stations with document version 3.`);
+					stationModel.find({ documentVersion: 4 }, (err, stations) => {
+						if (err) next(err);
+						else {
+							async.eachLimit(
+								stations.map(station => station._doc),
+								1,
+								(station, next) => {
+									const queue = station.queue.map(song => {
+										song.youtubeId = song.songId;
+										delete song.songId;
+										return song;
+									});
+
+									stationModel.updateOne({ _id: station._id }, { $set: { queue } }, next);
+								},
+								err => {
+									if (err) next(err);
+									else {
+										stationModel.updateMany(
+											{ documentVersion: 4, currentSong: { $ne: null } },
+											{
+												$set: { documentVersion: 5 },
+												$rename: { "currentSong.songId": "currentSong.youtubeId" }
+											},
+											(err, res) => {
+												if (err) next(err);
+												else {
+													this.log(
+														"INFO",
+														`Migration 8. Matched: ${res.n}, modified: ${res.nModified}, ok: ${res.ok}.`
+													);
+													stationModel.updateMany(
+														{ documentVersion: 4, currentSong: null },
+														{
+															$set: { documentVersion: 5 }
+														},
+														(err, res) => {
+															if (err) next(err);
+															else {
+																this.log(
+																	"INFO",
+																	`Migration 8. Matched: ${res.n}, modified: ${res.nModified}, ok: ${res.ok}.`
+																);
+																next();
+															}
+														}
+													);
+												}
+											}
+										);
+									}
+								}
+							);
+						}
+					});
+				}
+			],
+			err => {
+				if (err) {
+					reject(new Error(err));
+				} else {
+					resolve();
+				}
+			}
+		);
+	});
+}

+ 15 - 15
backend/logic/playlists.js

@@ -353,10 +353,10 @@ class _PlaylistsModule extends CoreClass {
 	 */
 	ADD_SONG_TO_PLAYLIST(payload) {
 		return new Promise((resolve, reject) => {
-			const { _id, songId, title, artists, thumbnail, duration, status } = payload.song;
+			const { _id, youtubeId, title, artists, thumbnail, duration, status } = payload.song;
 			const trimmedSong = {
 				_id,
-				songId,
+				youtubeId,
 				title,
 				artists,
 				thumbnail,
@@ -383,18 +383,18 @@ class _PlaylistsModule extends CoreClass {
 	}
 
 	/**
-	 * Deletes a song from a playlist based on the songId
+	 * Deletes a song from a playlist based on the youtube id
 	 *
 	 * @param {object} payload - object that contains the payload
 	 * @param {string} payload.playlistId - the playlist id
-	 * @param {string} payload.songId - the songId
+	 * @param {string} payload.youtubeId - the youtube id
 	 * @returns {Promise} - returns promise (reject, resolve)
 	 */
-	DELETE_SONG_FROM_PLAYLIST_BY_SONGID(payload) {
+	DELETE_SONG_FROM_PLAYLIST_BY_YOUTUBE_ID(payload) {
 		return new Promise((resolve, reject) => {
 			PlaylistsModule.playlistModel.updateOne(
 				{ _id: payload.playlistId },
-				{ $pull: { songs: { songId: payload.songId } } },
+				{ $pull: { songs: { youtubeId: payload.youtubeId } } },
 				err => {
 					if (err) reject(new Error(err));
 					else {
@@ -455,10 +455,10 @@ class _PlaylistsModule extends CoreClass {
 
 					(playlistId, _songs, next) => {
 						const songs = _songs.map(song => {
-							const { _id, songId, title, artists, thumbnail, duration, status } = song;
+							const { _id, youtubeId, title, artists, thumbnail, duration, status } = song;
 							return {
 								_id,
-								songId,
+								youtubeId,
 								title,
 								artists,
 								thumbnail,
@@ -485,12 +485,12 @@ class _PlaylistsModule extends CoreClass {
 					// 	data.songsToAdd = [];
 
 					// 	data.playlist.songs.forEach(playlistSong => {
-					// 		const found = data.songs.find(song => playlistSong.songId === song.songId);
+					// 		const found = data.songs.find(song => playlistSong.youtubeId === song.youtubeId);
 					// 		if (!found) data.songsToDelete.push(playlistSong);
 					// 	});
 
 					// 	data.songs.forEach(song => {
-					// 		const found = data.playlist.songs.find(playlistSong => song.songId === playlistSong.songId);
+					// 		const found = data.playlist.songs.find(playlistSong => song.youtubeId === playlistSong.youtubeId);
 					// 		if (!found) data.songsToAdd.push(song);
 					// 	});
 
@@ -511,10 +511,10 @@ class _PlaylistsModule extends CoreClass {
 					// 	data.songsToDelete.forEach(song => {
 					// 		promises.push(
 					// 			PlaylistsModule.runJob(
-					// 				"DELETE_SONG_FROM_PLAYLIST_BY_SONGID",
+					// 				"DELETE_SONG_FROM_PLAYLIST_BY_YOUTUBE_ID",
 					// 				{
 					// 					playlistId: data.playlist._id,
-					// 					songId: song.songId
+					// 					youtubeId: song.youtubeId
 					// 				},
 					// 				this
 					// 			)
@@ -777,17 +777,17 @@ class _PlaylistsModule extends CoreClass {
 							.flatMap(excludedPlaylist => excludedPlaylist.songs)
 							.reduce(
 								(items, item) =>
-									items.find(x => x.songId === item.songId) ? [...items] : [...items, item],
+									items.find(x => x.youtubeId === item.youtubeId) ? [...items] : [...items, item],
 								[]
 							);
 						const includedSongs = includedPlaylists
 							.flatMap(includedPlaylist => includedPlaylist.songs)
 							.reduce(
 								(songs, song) =>
-									songs.find(x => x.songId === song.songId) ? [...songs] : [...songs, song],
+									songs.find(x => x.youtubeId === song.youtubeId) ? [...songs] : [...songs, song],
 								[]
 							)
-							.filter(song => !excludedSongs.find(x => x.songId === song.songId));
+							.filter(song => !excludedSongs.find(x => x.youtubeId === song.youtubeId));
 
 						next(null, station, includedSongs);
 					},

+ 56 - 55
backend/logic/songs.js

@@ -56,17 +56,17 @@ class _SongsModule extends CoreClass {
 
 						if (!songs) return next();
 
-						const songIds = Object.keys(songs);
+						const youtubeIds = Object.keys(songs);
 
 						return async.each(
-							songIds,
-							(songId, next) => {
-								SongsModule.SongModel.findOne({ songId }, (err, song) => {
+							youtubeIds,
+							(youtubeId, next) => {
+								SongsModule.SongModel.findOne({ youtubeId }, (err, song) => {
 									if (err) next(err);
 									else if (!song)
 										CacheModule.runJob("HDEL", {
 											table: "songs",
-											key: songId
+											key: youtubeId
 										})
 											.then(() => next())
 											.catch(next);
@@ -89,7 +89,7 @@ class _SongsModule extends CoreClass {
 							(song, next) => {
 								CacheModule.runJob("HSET", {
 									table: "songs",
-									key: song.songId,
+									key: song.youtubeId,
 									value: SongsModule.SongSchemaCache(song)
 								})
 									.then(() => next())
@@ -113,7 +113,7 @@ class _SongsModule extends CoreClass {
 	 * Gets a song by id from the cache or Mongo, and if it isn't in the cache yet, adds it the cache
 	 *
 	 * @param {object} payload - object containing the payload
-	 * @param {string} payload.id - the id of the song we are trying to get
+	 * @param {string} payload.songId - the id of the song we are trying to get
 	 * @returns {Promise} - returns a promise (resolve, reject)
 	 */
 	GET_SONG(payload) {
@@ -121,15 +121,16 @@ class _SongsModule extends CoreClass {
 			async.waterfall(
 				[
 					next => {
-						if (!mongoose.Types.ObjectId.isValid(payload.id)) return next("Id is not a valid ObjectId.");
-						return CacheModule.runJob("HGET", { table: "songs", key: payload.id }, this)
+						if (!mongoose.Types.ObjectId.isValid(payload.songId))
+							return next("songId is not a valid ObjectId.");
+						return CacheModule.runJob("HGET", { table: "songs", key: payload.songId }, this)
 							.then(song => next(null, song))
 							.catch(next);
 					},
 
 					(song, next) => {
 						if (song) return next(true, song);
-						return SongsModule.SongModel.findOne({ _id: payload.id }, next);
+						return SongsModule.SongModel.findOne({ _id: payload.songId }, next);
 					},
 
 					(song, next) => {
@@ -138,7 +139,7 @@ class _SongsModule extends CoreClass {
 								"HSET",
 								{
 									table: "songs",
-									key: payload.id,
+									key: payload.songId,
 									value: song
 								},
 								this
@@ -158,23 +159,23 @@ class _SongsModule extends CoreClass {
 	 * Makes sure that if a song is not currently in the songs db, to add it
 	 *
 	 * @param {object} payload - an object containing the payload
-	 * @param {string} payload.songId - the youtube song id of the song we are trying to ensure is in the songs db
+	 * @param {string} payload.youtubeId - the youtube song id of the song we are trying to ensure is in the songs db
 	 * @param {string} payload.userId - the youtube song id of the song we are trying to ensure is in the songs db
 	 * @param {string} payload.automaticallyRequested - whether the song was automatically requested or not
 	 * @returns {Promise} - returns a promise (resolve, reject)
 	 */
-	ENSURE_SONG_EXISTS_BY_SONG_ID(payload) {
+	ENSURE_SONG_EXISTS_BY_YOUTUBE_ID(payload) {
 		return new Promise((resolve, reject) =>
 			async.waterfall(
 				[
 					next => {
-						SongsModule.SongModel.findOne({ songId: payload.songId }, next);
+						SongsModule.SongModel.findOne({ youtubeId: payload.youtubeId }, next);
 					},
 
 					(song, next) => {
 						if (song && song.duration > 0) next(true, song);
 						else {
-							YouTubeModule.runJob("GET_SONG", { songId: payload.songId }, this)
+							YouTubeModule.runJob("GET_SONG", { youtubeId: payload.youtubeId }, this)
 								.then(response => {
 									next(null, song, response.song);
 								})
@@ -182,11 +183,11 @@ class _SongsModule extends CoreClass {
 						}
 
 						// else if (song && song.duration <= 0) {
-						// 	YouTubeModule.runJob("GET_SONG", { songId: payload.songId }, this)
+						// 	YouTubeModule.runJob("GET_SONG", { youtubeId: payload.youtubeId }, this)
 						// 		.then(response => next(null, { ...response.song }, false))
 						// 		.catch(next);
 						// } else {
-						// 	YouTubeModule.runJob("GET_SONG", { songId: payload.songId }, this)
+						// 	YouTubeModule.runJob("GET_SONG", { youtubeId: payload.youtubeId }, this)
 						// 		.then(response => next(null, { ...response.song }, false))
 						// 		.catch(next);
 						// }
@@ -228,18 +229,18 @@ class _SongsModule extends CoreClass {
 	}
 
 	/**
-	 * Gets a song by song id from the cache or Mongo, and if it isn't in the cache yet, adds it the cache
+	 * Gets a song by youtube id
 	 *
 	 * @param {object} payload - an object containing the payload
-	 * @param {string} payload.songId - the mongo id of the song we are trying to get
+	 * @param {string} payload.youtubeId - the youtube id of the song we are trying to get
 	 * @returns {Promise} - returns a promise (resolve, reject)
 	 */
-	GET_SONG_FROM_ID(payload) {
+	GET_SONG_FROM_YOUTUBE_ID(payload) {
 		return new Promise((resolve, reject) =>
 			async.waterfall(
 				[
 					next => {
-						SongsModule.SongModel.findOne({ songId: payload.songId }, next);
+						SongsModule.SongModel.findOne({ youtubeId: payload.youtubeId }, next);
 					}
 				],
 				(err, song) => {
@@ -291,10 +292,10 @@ class _SongsModule extends CoreClass {
 
 					(song, next) => {
 						next(null, song);
-						const { _id, songId, title, artists, thumbnail, duration, status } = song;
+						const { _id, youtubeId, title, artists, thumbnail, duration, status } = song;
 						const trimmedSong = {
 							_id,
-							songId,
+							youtubeId,
 							title,
 							artists,
 							thumbnail,
@@ -324,7 +325,7 @@ class _SongsModule extends CoreClass {
 								{ "queue._id": song._id },
 								{
 									$set: {
-										"queue.$.songId": songId,
+										"queue.$.youtubeId": youtubeId,
 										"queue.$.title": title,
 										"queue.$.artists": artists,
 										"queue.$.thumbnail": thumbnail,
@@ -374,7 +375,7 @@ class _SongsModule extends CoreClass {
 	 * Deletes song from id from Mongo and cache
 	 *
 	 * @param {object} payload - returns an object containing the payload
-	 * @param {string} payload.songId - the id of the song we are trying to delete
+	 * @param {string} payload.youtubeId - the youtube id of the song we are trying to delete
 	 * @returns {Promise} - returns a promise (resolve, reject)
 	 */
 	DELETE_SONG(payload) {
@@ -382,7 +383,7 @@ class _SongsModule extends CoreClass {
 			async.waterfall(
 				[
 					next => {
-						SongsModule.SongModel.deleteOne({ songId: payload.songId }, next);
+						SongsModule.SongModel.deleteOne({ youtubeId: payload.youtubeId }, next);
 					},
 
 					next => {
@@ -390,7 +391,7 @@ class _SongsModule extends CoreClass {
 							"HDEL",
 							{
 								table: "songs",
-								key: payload.songId
+								key: payload.youtubeId
 							},
 							this
 						)
@@ -410,8 +411,8 @@ class _SongsModule extends CoreClass {
 	 * Recalculates dislikes and likes for a song
 	 *
 	 * @param {object} payload - returns an object containing the payload
-	 * @param {string} payload.musareSongId - the (musare) id of the song
-	 * @param {string} payload.songId - the (mongodb) id of the song
+	 * @param {string} payload.youtubeId - the youtube id of the song
+	 * @param {string} payload.songId - the song id of the song
 	 * @returns {Promise} - returns a promise (resolve, reject)
 	 */
 	async RECALCULATE_SONG_RATINGS(payload) {
@@ -422,7 +423,7 @@ class _SongsModule extends CoreClass {
 				[
 					next => {
 						playlistModel.countDocuments(
-							{ songs: { $elemMatch: { songId: payload.musareSongId } }, displayName: "Liked Songs" },
+							{ songs: { $elemMatch: { youtubeId: payload.youtubeId } }, displayName: "Liked Songs" },
 							(err, likes) => {
 								if (err) return next(err);
 								return next(null, likes);
@@ -432,7 +433,7 @@ class _SongsModule extends CoreClass {
 
 					(likes, next) => {
 						playlistModel.countDocuments(
-							{ songs: { $elemMatch: { songId: payload.musareSongId } }, displayName: "Disliked Songs" },
+							{ songs: { $elemMatch: { youtubeId: payload.youtubeId } }, displayName: "Disliked Songs" },
 							(err, dislikes) => {
 								if (err) return next(err);
 								return next(err, { likes, dislikes });
@@ -538,27 +539,27 @@ class _SongsModule extends CoreClass {
 				playlistModel.find({}, (err, playlists) => {
 					if (err) reject(new Error(err));
 					else {
-						SongsModule.SongModel.find({}, { _id: true, songId: true }, (err, songs) => {
+						SongsModule.SongModel.find({}, { _id: true, youtubeId: true }, (err, songs) => {
 							if (err) reject(new Error(err));
 							else {
-								const musareSongIds = songs.map(song => song._id.toString());
-								const orphanedSongIds = new Set();
+								const songIds = songs.map(song => song._id.toString());
+								const orphanedYoutubeIds = new Set();
 								async.eachLimit(
 									playlists,
 									1,
 									(playlist, next) => {
 										playlist.songs.forEach(song => {
 											if (
-												(!song._id || musareSongIds.indexOf(song._id.toString() === -1)) &&
-												!orphanedSongIds.has(song.songId)
+												(!song._id || songIds.indexOf(song._id.toString() === -1)) &&
+												!orphanedYoutubeIds.has(song.youtubeId)
 											) {
-												orphanedSongIds.add(song.songId);
+												orphanedYoutubeIds.add(song.youtubeId);
 											}
 										});
 										next();
 									},
 									() => {
-										resolve({ songIds: Array.from(orphanedSongIds) });
+										resolve({ youtubeIds: Array.from(orphanedYoutubeIds) });
 									}
 								);
 							}
@@ -573,13 +574,13 @@ class _SongsModule extends CoreClass {
 	 * Requests a song, adding it to the DB
 	 *
 	 * @param {object} payload - The payload
-	 * @param {string} payload.songId - The YouTube song id of the song
+	 * @param {string} payload.youtubeId - The YouTube song id of the song
 	 * @param {string} payload.userId - The user id of the person requesting the song
 	 * @returns {Promise} - returns promise (reject, resolve)
 	 */
 	REQUEST_SONG(payload) {
 		return new Promise((resolve, reject) => {
-			const { songId, userId } = payload;
+			const { youtubeId, userId } = payload;
 			const requestedAt = Date.now();
 
 			async.waterfall(
@@ -593,7 +594,7 @@ class _SongsModule extends CoreClass {
 					},
 
 					(user, next) => {
-						SongsModule.SongModel.findOne({ songId }, (err, song) => next(err, user, song));
+						SongsModule.SongModel.findOne({ youtubeId }, (err, song) => next(err, user, song));
 					},
 
 					// Get YouTube data from id
@@ -604,7 +605,7 @@ class _SongsModule extends CoreClass {
 						const requestedBy = user.preferences.anonymousSongRequests ? null : userId;
 						const status = !requestedBy && config.get("hideAnonymousSongs") ? "hidden" : "unverified";
 
-						return YouTubeModule.runJob("GET_SONG", { songId }, this)
+						return YouTubeModule.runJob("GET_SONG", { youtubeId }, this)
 							.then(response => {
 								const { song } = response;
 								song.artists = [];
@@ -663,7 +664,7 @@ class _SongsModule extends CoreClass {
 	 * Hides a song
 	 *
 	 * @param {object} payload - The payload
-	 * @param {string} payload.songId - The Musare song id of the song
+	 * @param {string} payload.songId - The song id of the song
 	 * @returns {Promise} - returns promise (reject, resolve)
 	 */
 	HIDE_SONG(payload) {
@@ -717,7 +718,7 @@ class _SongsModule extends CoreClass {
 	 * Unhides a song
 	 *
 	 * @param {object} payload - The payload
-	 * @param {string} payload.songId - The Musare song id of the song
+	 * @param {string} payload.songId - The song id of the song
 	 * @returns {Promise} - returns promise (reject, resolve)
 	 */
 	UNHIDE_SONG(payload) {
@@ -778,19 +779,19 @@ class _SongsModule extends CoreClass {
 			DBModule.runJob("GET_MODEL", { modelName: "playlist" })
 				.then(playlistModel => {
 					SongsModule.runJob("GET_ORPHANED_PLAYLIST_SONGS", {}, this).then(response => {
-						const { songIds } = response;
+						const { youtubeIds } = response;
 						const playlistsToUpdate = new Set();
 
 						async.eachLimit(
-							songIds,
+							youtubeIds,
 							1,
-							(songId, next) => {
+							(youtubeId, next) => {
 								async.waterfall(
 									[
 										next => {
 											console.log(
-												songId,
-												`this is song ${songIds.indexOf(songId) + 1}/${songIds.length}`
+												youtubeId,
+												`this is song ${youtubeIds.indexOf(youtubeId) + 1}/${youtubeIds.length}`
 											);
 											setTimeout(next, 150);
 										},
@@ -798,12 +799,12 @@ class _SongsModule extends CoreClass {
 										next => {
 											SongsModule.runJob(
 												"ENSURE_SONG_EXISTS_BY_SONG_ID",
-												{ songId, automaticallyRequested: true },
+												{ youtubeId, automaticallyRequested: true },
 												this
 											)
 												.then(() => next())
 												.catch(next);
-											// SongsModule.runJob("REQUEST_SONG", { songId, userId: null }, this)
+											// SongsModule.runJob("REQUEST_SONG", { youtubeId, userId: null }, this)
 											// 	.then(() => {
 											// 		next();
 											// 	})
@@ -811,16 +812,16 @@ class _SongsModule extends CoreClass {
 										},
 
 										next => {
-											console.log(444, songId);
+											console.log(444, youtubeId);
 
-											SongsModule.SongModel.findOne({ songId }, next);
+											SongsModule.SongModel.findOne({ youtubeId }, next);
 										},
 
 										(song, next) => {
 											const { _id, title, artists, thumbnail, duration, status } = song;
 											const trimmedSong = {
 												_id,
-												songId,
+												youtubeId,
 												title,
 												artists,
 												thumbnail,
@@ -828,7 +829,7 @@ class _SongsModule extends CoreClass {
 												status
 											};
 											playlistModel.updateMany(
-												{ "songs.songId": song.songId },
+												{ "songs.youtubeId": song.youtubeId },
 												{ $set: { "songs.$": trimmedSong } },
 												err => {
 													next(err, song);

+ 14 - 14
backend/logic/stations.js

@@ -35,7 +35,7 @@ class _StationsModule extends CoreClass {
 		NotificationsModule = this.moduleManager.modules.notifications;
 
 		// this.defaultSong = {
-		// 	songId: "60ItHLz5WEA",
+		// 	youtubeId: "60ItHLz5WEA",
 		// 	title: "Faded - Alan Walker",
 		// 	duration: 212,
 		// 	skipDuration: 0,
@@ -509,7 +509,7 @@ class _StationsModule extends CoreClass {
 						}
 						const songsStillNeeded = 50 - station.queue.length;
 						const currentSongs = station.queue;
-						const currentSongIds = station.queue.map(song => song.songId);
+						const currentYoutubeIds = station.queue.map(song => song.youtubeId);
 						const songsToAdd = [];
 						let lastSongAdded = null;
 
@@ -518,7 +518,7 @@ class _StationsModule extends CoreClass {
 							.every(song => {
 								if (
 									songsToAdd.length < songsStillNeeded &&
-									currentSongIds.indexOf(song.songId) === -1
+									currentYoutubeIds.indexOf(song.youtubeId) === -1
 								) {
 									lastSongAdded = song;
 									songsToAdd.push(song);
@@ -532,8 +532,8 @@ class _StationsModule extends CoreClass {
 
 						if (station.playMode === "sequential" && lastSongAdded) {
 							const indexOfLastSong = _playlistSongs
-								.map(song => song.songId)
-								.indexOf(lastSongAdded.songId);
+								.map(song => song.youtubeId)
+								.indexOf(lastSongAdded.youtubeId);
 
 							if (indexOfLastSong !== -1) currentSongIndex = indexOfLastSong;
 						}
@@ -607,14 +607,14 @@ class _StationsModule extends CoreClass {
 					(queueSong, next) => {
 						if (!queueSong._id) next(null, queueSong);
 						else
-							SongsModule.runJob("GET_SONG", { id: queueSong._id }, this)
+							SongsModule.runJob("GET_SONG", { songId: queueSong._id }, this)
 								.then(response => {
 									const { song } = response;
 
 									if (song) {
 										const newSong = {
 											_id: song._id,
-											songId: song.songId,
+											youtubeId: song.youtubeId,
 											title: song.title,
 											artists: song.artists,
 											duration: song.duration,
@@ -819,7 +819,7 @@ class _StationsModule extends CoreClass {
 						// 					if (song) return next(null, song, currentSongIndex, station);
 
 						// 					const currentSong = {
-						// 						songId: playlist[currentSongIndex].songId,
+						// 						youtubeId: playlist[currentSongIndex].youtubeId,
 						// 						title: playlist[currentSongIndex].title,
 						// 						duration: playlist[currentSongIndex].duration,
 						// 						likes: -1,
@@ -841,9 +841,9 @@ class _StationsModule extends CoreClass {
 						// 						.then(response => callback(null, response.song))
 						// 						.catch(callback);
 						// 				return SongsModule.runJob(
-						// 					"GET_SONG_FROM_ID",
+						// 					"GET_SONG_FROM_YOUTUBE_ID",
 						// 					{
-						// 						songId: playlist[currentSongIndex].songId
+						// 						youtubeId: playlist[currentSongIndex].youtubeId
 						// 					},
 						// 					this
 						// 				)
@@ -890,7 +890,7 @@ class _StationsModule extends CoreClass {
 						else {
 							$set.currentSong = {
 								_id: song._id,
-								songId: song.songId,
+								youtubeId: song.youtubeId,
 								title: song.title,
 								artists: song.artists,
 								duration: song.duration,
@@ -941,7 +941,7 @@ class _StationsModule extends CoreClass {
 						StationsModule.log("ERROR", `Skipping station "${payload.stationId}" failed. "${err}"`);
 						reject(new Error(err));
 					} else {
-						if (station.currentSong !== null && station.currentSong.songId !== undefined) {
+						if (station.currentSong !== null && station.currentSong.youtubeId !== undefined) {
 							station.currentSong.skipVotes = 0;
 						}
 						// TODO Pub/Sub this
@@ -1018,10 +1018,10 @@ class _StationsModule extends CoreClass {
 						}
 
 						WSModule.runJob("GET_SOCKETS_FOR_ROOM", { room: `station.${station._id}` }).then(sockets => {
-							if (station.currentSong !== null && station.currentSong.songId !== undefined) {
+							if (station.currentSong !== null && station.currentSong.youtubeId !== undefined) {
 								WSModule.runJob("SOCKETS_JOIN_SONG_ROOM", {
 									sockets,
-									room: `song.${station.currentSong.songId}`
+									room: `song.${station.currentSong.youtubeId}`
 								});
 								if (!station.paused) {
 									NotificationsModule.runJob("SCHEDULE", {

+ 8 - 8
backend/logic/youtube.js

@@ -109,14 +109,14 @@ class _YouTubeModule extends CoreClass {
 	 * Gets the details of a song using the YouTube API
 	 *
 	 * @param {object} payload - object that contains the payload
-	 * @param {string} payload.songId - the YouTube API id of the song
+	 * @param {string} payload.youtubeId - the YouTube API id of the song
 	 * @returns {Promise} - returns promise (reject, resolve)
 	 */
 	GET_SONG(payload) {
 		return new Promise((resolve, reject) => {
 			const params = {
 				part: "snippet,contentDetails,statistics,status",
-				id: payload.songId,
+				id: payload.youtubeId,
 				key: config.get("apis.youtube.key")
 			};
 
@@ -167,7 +167,7 @@ class _YouTubeModule extends CoreClass {
 						});
 
 						const song = {
-							songId: res.data.items[0].id,
+							youtubeId: res.data.items[0].id,
 							title: res.data.items[0].snippet.title,
 							thumbnail: res.data.items[0].snippet.thumbnails.default.url,
 							duration
@@ -252,7 +252,7 @@ class _YouTubeModule extends CoreClass {
 						YouTubeModule.log("ERROR", "GET_PLAYLIST", "Some error has occurred.", err.message);
 						reject(new Error(err.message));
 					} else {
-						resolve({ songs: response.filteredSongs ? response.filteredSongs.songIds : response.songs });
+						resolve({ songs: response.filteredSongs ? response.filteredSongs.youtubeIds : response.songs });
 					}
 				}
 			);
@@ -349,14 +349,14 @@ class _YouTubeModule extends CoreClass {
 							return reject(new Error("An error has occured. Please try again later."));
 						}
 
-						const songIds = [];
+						const youtubeIds = [];
 
 						res.data.items.forEach(item => {
-							const songId = item.id;
+							const youtubeId = item.id;
 
 							if (!item.topicDetails) return;
 							if (item.topicDetails.topicCategories.indexOf("https://en.wikipedia.org/wiki/Music") !== -1)
-								songIds.push(songId);
+								youtubeIds.push(youtubeId);
 						});
 
 						return YouTubeModule.runJob(
@@ -364,7 +364,7 @@ class _YouTubeModule extends CoreClass {
 							{ videoIds: payload.videoIds, page: page + 1 },
 							this
 						)
-							.then(result => resolve({ songIds: songIds.concat(result.songIds) }))
+							.then(result => resolve({ youtubeIds: youtubeIds.concat(result.youtubeIds) }))
 							.catch(err => reject(err));
 					})
 					.catch(err => {

+ 12 - 6
frontend/src/components/ActivityItem.vue

@@ -46,11 +46,14 @@ export default {
 	},
 	computed: {
 		formattedMessage() {
-			const { songId, playlistId, stationId } = this.activity.payload;
+			const { youtubeId, playlistId, stationId } = this.activity.payload;
 			let { message } = this.activity.payload;
 
-			if (songId) {
-				message = message.replace(/<songId>(.*)<\/songId>/g, "$1");
+			if (youtubeId) {
+				message = message.replace(
+					/<youtubeId>(.*)<\/youtubeId>/g,
+					"$1"
+				);
 			}
 
 			if (playlistId) {
@@ -73,11 +76,14 @@ export default {
 			};
 		},
 		textOnlyMessage() {
-			const { songId, playlistId, stationId } = this.activity.payload;
+			const { youtubeId, playlistId, stationId } = this.activity.payload;
 			let { message } = this.activity.payload;
 
-			if (songId) {
-				message = message.replace(/<songId>(.*)<\/songId>/g, "$1");
+			if (youtubeId) {
+				message = message.replace(
+					/<youtubeId>(.*)<\/youtubeId>/g,
+					"$1"
+				);
 			}
 
 			if (playlistId) {

+ 3 - 3
frontend/src/components/AddToPlaylistDropdown.vue

@@ -104,7 +104,7 @@ export default {
 				this.socket.dispatch(
 					"playlists.addSongToPlaylist",
 					false,
-					this.song.songId,
+					this.song.youtubeId,
 					playlist._id,
 					res => {
 						new Toast(res.message);
@@ -117,7 +117,7 @@ export default {
 			} else {
 				this.socket.dispatch(
 					"playlists.removeSongFromPlaylist",
-					this.song.songId,
+					this.song.youtubeId,
 					playlist._id,
 					res => {
 						new Toast(res.message);
@@ -125,7 +125,7 @@ export default {
 						if (res.status === "success") {
 							this.playlists[playlistIndex].songs.forEach(
 								(song, songIndex) => {
-									if (song.songId === this.song.songId)
+									if (song.youtubeId === this.song.youtubeId)
 										this.playlists[
 											playlistIndex
 										].songs.splice(songIndex, 1);

+ 4 - 2
frontend/src/components/SongItem.vue

@@ -80,7 +80,9 @@
 					</template>
 					<a
 						target="_blank"
-						:href="`https://www.youtube.com/watch?v=${song.songId}`"
+						:href="
+							`https://www.youtube.com/watch?v=${song.youtubeId}`
+						"
 						content="View on Youtube"
 						v-tippy
 					>
@@ -117,7 +119,7 @@
 				<a
 					v-else
 					target="_blank"
-					:href="`https://www.youtube.com/watch?v=${song.songId}`"
+					:href="`https://www.youtube.com/watch?v=${song.youtubeId}`"
 					content="View on Youtube"
 					v-tippy
 				>

+ 4 - 4
frontend/src/components/SongThumbnail.vue

@@ -2,7 +2,7 @@
 	<div class="thumbnail">
 		<div
 			v-if="
-				song.songId &&
+				song.youtubeId &&
 					(!song.thumbnail ||
 						(song.thumbnail &&
 							(song.thumbnail.lastIndexOf('notes-transparent') !==
@@ -19,13 +19,13 @@
 			:style="{
 				'background-image':
 					'url(' +
-					`https://img.youtube.com/vi/${song.songId}/mqdefault.jpg` +
+					`https://img.youtube.com/vi/${song.youtubeId}/mqdefault.jpg` +
 					')'
 			}"
 		></div>
 		<img
 			v-if="
-				song.songId &&
+				song.youtubeId &&
 					(!song.thumbnail ||
 						(song.thumbnail &&
 							(song.thumbnail.lastIndexOf('notes-transparent') !==
@@ -38,7 +38,7 @@
 						song.thumbnail === 'empty' ||
 						song.thumbnail == null)
 			"
-			:src="`https://img.youtube.com/vi/${song.songId}/mqdefault.jpg`"
+			:src="`https://img.youtube.com/vi/${song.youtubeId}/mqdefault.jpg`"
 			onerror="this.src='/assets/notes-transparent.png'"
 		/>
 		<img

+ 3 - 3
frontend/src/components/modals/AddSongToQueue.vue

@@ -255,12 +255,12 @@ export default {
 				}
 			}
 		},
-		addSongToQueue(songId, index) {
+		addSongToQueue(youtubeId, index) {
 			if (this.station.type === "community") {
 				this.socket.dispatch(
 					"stations.addToQueue",
 					this.station._id,
-					songId,
+					youtubeId,
 					data => {
 						if (data.status !== "success")
 							new Toast(`Error: ${data.message}`);
@@ -274,7 +274,7 @@ export default {
 					}
 				);
 			} else {
-				this.socket.dispatch("songs.request", songId, data => {
+				this.socket.dispatch("songs.request", youtubeId, data => {
 					if (data.status !== "success")
 						new Toast(`Error: ${data.message}`);
 					else {

+ 12 - 10
frontend/src/components/modals/EditPlaylist.vue

@@ -260,7 +260,9 @@
 														!station.locked
 												"
 												@click="
-													addSongToQueue(song.songId)
+													addSongToQueue(
+														song.youtubeId
+													)
 												"
 												content="Add Song to Queue"
 												v-tippy
@@ -274,7 +276,7 @@
 												"
 												@confirm="
 													removeSongFromPlaylist(
-														song.songId
+														song.youtubeId
 													)
 												"
 											>
@@ -422,10 +424,10 @@ export default {
 		"search.songs.results": function checkIfSongInPlaylist(songs) {
 			songs.forEach((searchItem, index) =>
 				this.playlist.songs.find(song => {
-					if (song.songId === searchItem.id)
+					if (song.youtubeId === searchItem.id)
 						this.search.songs.results[index].isAddedToQueue = true;
 
-					return song.songId === searchItem.id;
+					return song.youtubeId === searchItem.id;
 				})
 			);
 		}
@@ -448,13 +450,13 @@ export default {
 			if (this.playlist._id === data.playlistId) {
 				// remove song from array of playlists
 				this.playlist.songs.forEach((song, index) => {
-					if (song.songId === data.songId)
+					if (song.youtubeId === data.youtubeId)
 						this.playlist.songs.splice(index, 1);
 				});
 
 				// if this song is in search results, mark it available to add to the playlist again
 				this.search.songs.results.forEach((searchItem, index) => {
-					if (data.songId === searchItem.id) {
+					if (data.youtubeId === searchItem.id) {
 						this.search.songs.results[index].isAddedToQueue = false;
 					}
 				});
@@ -472,7 +474,7 @@ export default {
 				data.songsBeingChanged.forEach(changedSong => {
 					this.playlist.songs.forEach((song, index) => {
 						// find song locally
-						if (song.songId === changedSong.songId) {
+						if (song.youtubeId === changedSong.youtubeId) {
 							// change song position attribute
 							this.playlist.songs[index].position =
 								changedSong.position;
@@ -551,7 +553,7 @@ export default {
 			this.playlist.songs.forEach((song, index) => {
 				if (song.position !== index + 1)
 					songsBeingChanged.push({
-						songId: song.songId,
+						youtubeId: song.youtubeId,
 						position: index + 1
 					});
 			});
@@ -712,11 +714,11 @@ export default {
 				);
 			}
 		},
-		addSongToQueue(songId) {
+		addSongToQueue(youtubeId) {
 			this.socket.dispatch(
 				"stations.addToQueue",
 				this.station._id,
-				songId,
+				youtubeId,
 				data => {
 					if (data.status !== "success")
 						new Toast({

+ 120 - 132
frontend/src/components/modals/EditSong.vue

@@ -293,7 +293,7 @@
 									<input
 										class="input"
 										type="text"
-										v-model="song.songId"
+										v-model="song.youtubeId"
 									/>
 								</p>
 							</div>
@@ -512,7 +512,7 @@ import SaveButton from "../SaveButton.vue";
 export default {
 	components: { Modal, FloatingBox, SaveButton },
 	props: {
-		songId: { type: String, default: null },
+		youtubeId: { type: String, default: null },
 		// songType: { type: String, default: null },
 		sector: { type: String, default: "admin" }
 	},
@@ -605,7 +605,7 @@ export default {
 		// if (this.modals.editSong = false) this.video.player.stopVideo();
 
 		// this.loadVideoById(
-		//   this.song.songId,
+		//   this.song.youtubeId,
 		//   this.song.skipDuration
 		// );
 
@@ -615,144 +615,132 @@ export default {
 
 		this.useHTTPS = await lofig.get("cookie.secure");
 
-		this.socket.dispatch(
-			`songs.getSongFromMusareId`,
-			this.song._id,
-			res => {
-				if (res.status === "success") {
-					const { song } = res.data;
-					// this.song = { ...song };
-					// if (this.song.discogs === undefined)
-					// 	this.song.discogs = null;
-					this.editSong(song);
-
-					this.songDataLoaded = true;
-
-					// this.edit(res.data.song);
-
-					this.discogsQuery = this.song.title;
-
-					this.interval = setInterval(() => {
-						if (
-							this.song.duration !== -1 &&
-							this.video.paused === false &&
-							this.playerReady &&
-							this.video.player.getCurrentTime() -
-								this.song.skipDuration >
-								this.song.duration
-						) {
-							this.video.paused = true;
-							this.video.player.stopVideo();
-							this.drawCanvas();
-						}
-						if (this.playerReady) {
-							this.youtubeVideoCurrentTime = this.video.player
-								.getCurrentTime()
+		this.socket.dispatch(`songs.getSongFromSongId`, this.song._id, res => {
+			if (res.status === "success") {
+				const { song } = res.data;
+				// this.song = { ...song };
+				// if (this.song.discogs === undefined)
+				// 	this.song.discogs = null;
+				this.editSong(song);
+
+				this.songDataLoaded = true;
+
+				// this.edit(res.data.song);
+
+				this.discogsQuery = this.song.title;
+
+				this.interval = setInterval(() => {
+					if (
+						this.song.duration !== -1 &&
+						this.video.paused === false &&
+						this.playerReady &&
+						this.video.player.getCurrentTime() -
+							this.song.skipDuration >
+							this.song.duration
+					) {
+						this.video.paused = true;
+						this.video.player.stopVideo();
+						this.drawCanvas();
+					}
+					if (this.playerReady) {
+						this.youtubeVideoCurrentTime = this.video.player
+							.getCurrentTime()
+							.toFixed(3);
+					}
+
+					if (this.video.paused === false) this.drawCanvas();
+				}, 200);
+
+				this.video.player = new window.YT.Player("editSongPlayer", {
+					height: 298,
+					width: 530,
+					videoId: this.song.youtubeId,
+					host: "https://www.youtube-nocookie.com",
+					playerVars: {
+						controls: 0,
+						iv_load_policy: 3,
+						rel: 0,
+						showinfo: 0,
+						autoplay: 1
+					},
+					startSeconds: this.song.skipDuration,
+					events: {
+						onReady: () => {
+							let volume = parseInt(
+								localStorage.getItem("volume")
+							);
+							volume = typeof volume === "number" ? volume : 20;
+							console.log(`Seekto: ${this.song.skipDuration}`);
+							this.video.player.seekTo(this.song.skipDuration);
+							this.video.player.setVolume(volume);
+							if (volume > 0) this.video.player.unMute();
+							this.youtubeVideoDuration = this.video.player
+								.getDuration()
 								.toFixed(3);
-						}
+							this.youtubeVideoNote = "(~)";
+							this.playerReady = true;
 
-						if (this.video.paused === false) this.drawCanvas();
-					}, 200);
-
-					this.video.player = new window.YT.Player("editSongPlayer", {
-						height: 298,
-						width: 530,
-						videoId: this.song.songId,
-						host: "https://www.youtube-nocookie.com",
-						playerVars: {
-							controls: 0,
-							iv_load_policy: 3,
-							rel: 0,
-							showinfo: 0,
-							autoplay: 1
+							this.drawCanvas();
 						},
-						startSeconds: this.song.skipDuration,
-						events: {
-							onReady: () => {
-								let volume = parseInt(
-									localStorage.getItem("volume")
-								);
-								volume =
-									typeof volume === "number" ? volume : 20;
-								console.log(
-									`Seekto: ${this.song.skipDuration}`
-								);
-								this.video.player.seekTo(
-									this.song.skipDuration
+						onStateChange: event => {
+							this.drawCanvas();
+
+							if (event.data === 1) {
+								if (!this.video.autoPlayed) {
+									this.video.autoPlayed = true;
+									return this.video.player.stopVideo();
+								}
+
+								this.video.paused = false;
+								let youtubeDuration = this.video.player.getDuration();
+								this.youtubeVideoDuration = youtubeDuration.toFixed(
+									3
 								);
-								this.video.player.setVolume(volume);
-								if (volume > 0) this.video.player.unMute();
-								this.youtubeVideoDuration = this.video.player
-									.getDuration()
-									.toFixed(3);
-								this.youtubeVideoNote = "(~)";
-								this.playerReady = true;
-
-								this.drawCanvas();
-							},
-							onStateChange: event => {
-								this.drawCanvas();
-
-								if (event.data === 1) {
-									if (!this.video.autoPlayed) {
-										this.video.autoPlayed = true;
-										return this.video.player.stopVideo();
-									}
-
-									this.video.paused = false;
-									let youtubeDuration = this.video.player.getDuration();
-									this.youtubeVideoDuration = youtubeDuration.toFixed(
-										3
+								this.youtubeVideoNote = "";
+
+								if (this.song.duration === -1)
+									this.song.duration = youtubeDuration;
+
+								youtubeDuration -= this.song.skipDuration;
+								if (this.song.duration > youtubeDuration + 1) {
+									this.video.player.stopVideo();
+									this.video.paused = true;
+									return new Toast(
+										"Video can't play. Specified duration is bigger than the YouTube song duration."
 									);
-									this.youtubeVideoNote = "";
-
-									if (this.song.duration === -1)
-										this.song.duration = youtubeDuration;
-
-									youtubeDuration -= this.song.skipDuration;
-									if (
-										this.song.duration >
-										youtubeDuration + 1
-									) {
-										this.video.player.stopVideo();
-										this.video.paused = true;
-										return new Toast(
-											"Video can't play. Specified duration is bigger than the YouTube song duration."
-										);
-									}
-									if (this.song.duration <= 0) {
-										this.video.player.stopVideo();
-										this.video.paused = true;
-										return new Toast(
-											"Video can't play. Specified duration has to be more than 0 seconds."
-										);
-									}
-
-									if (
-										this.video.player.getCurrentTime() <
-										this.song.skipDuration
-									) {
-										return this.video.player.seekTo(
-											this.song.skipDuration
-										);
-									}
-								} else if (event.data === 2) {
+								}
+								if (this.song.duration <= 0) {
+									this.video.player.stopVideo();
 									this.video.paused = true;
+									return new Toast(
+										"Video can't play. Specified duration has to be more than 0 seconds."
+									);
 								}
 
-								return false;
+								if (
+									this.video.player.getCurrentTime() <
+									this.song.skipDuration
+								) {
+									return this.video.player.seekTo(
+										this.song.skipDuration
+									);
+								}
+							} else if (event.data === 2) {
+								this.video.paused = true;
 							}
+
+							return false;
 						}
-					});
-				} else {
-					new Toast("Song with that ID not found");
-					this.closeModal({
-						sector: this.sector,
-						modal: "editSong"
-					});
-				}
+					}
+				});
+			} else {
+				new Toast("Song with that ID not found");
+				this.closeModal({
+					sector: this.sector,
+					modal: "editSong"
+				});
 			}
-		);
+		});
 
 		let volume = parseFloat(localStorage.getItem("volume"));
 		volume =
@@ -1387,14 +1375,14 @@ export default {
 					artists: this.song.artists
 						? this.song.artists.join(", ")
 						: null,
-					youtubeId: this.song.songId,
+					youtubeId: this.song.youtubeId,
 					muted: this.muted,
 					volume: this.volumeSliderValue / 100,
 					startedDuration:
 						this.activityWatchVideoLastStartDuration <= 0
 							? 0
 							: this.activityWatchVideoLastStartDuration,
-					source: `editSong#${this.song.songId}`,
+					source: `editSong#${this.song.youtubeId}`,
 					hostname: window.location.hostname
 				};
 

+ 4 - 4
frontend/src/components/modals/Report.vue

@@ -155,7 +155,7 @@ export default {
 			localSong: null,
 			report: {
 				resolved: false,
-				songId: "",
+				youtubeId: "",
 				description: "",
 				issues: [
 					{ name: "Video", reasons: [] },
@@ -214,7 +214,7 @@ export default {
 	mounted() {
 		if (this.song !== null) {
 			this.localSong = this.song;
-			this.report.songId = this.song.songId;
+			this.report.youtubeId = this.song.youtubeId;
 			this.reportSong(null);
 		}
 	},
@@ -231,11 +231,11 @@ export default {
 		},
 		highlight(type) {
 			if (type === "localSong") {
-				this.report.songId = this.localSong.songId;
+				this.report.youtubeId = this.localSong.youtubeId;
 				this.isPreviousSongActive = false;
 				this.isLocalSongActive = true;
 			} else if (type === "previousSong") {
-				this.report.songId = this.previousSong.songId;
+				this.report.youtubeId = this.previousSong.youtubeId;
 				this.isLocalSongActive = false;
 				this.isPreviousSongActive = true;
 			}

+ 3 - 3
frontend/src/components/modals/RequestSong.vue

@@ -162,12 +162,12 @@ export default {
 		})
 	},
 	methods: {
-		addSongToQueue(songId, index) {
+		addSongToQueue(youtubeId, index) {
 			if (this.station.type === "community") {
 				this.socket.dispatch(
 					"stations.addToQueue",
 					this.station._id,
-					songId,
+					youtubeId,
 					data => {
 						if (data.status !== "success")
 							new Toast(`Error: ${data.message}`);
@@ -181,7 +181,7 @@ export default {
 					}
 				);
 			} else {
-				this.socket.dispatch("songs.request", songId, data => {
+				this.socket.dispatch("songs.request", youtubeId, data => {
 					if (data.status !== "success")
 						new Toast(`Error: ${data.message}`);
 					else {

+ 2 - 2
frontend/src/components/modals/ViewReport.vue

@@ -6,7 +6,7 @@
 				class="button is-dark back-to-song"
 				:to="{
 					path: '/admin/songs',
-					query: { id: report.songId }
+					query: { id: report.youtubeId }
 				}"
 			>
 				<i class="material-icons">keyboard_return</i> &nbsp; Edit Song
@@ -15,7 +15,7 @@
 			<article class="message">
 				<div class="message-body">
 					<strong>Song ID:</strong>
-					{{ report.song.songId }} / {{ report.song._id }}
+					{{ report.song.youtubeId }} / {{ report.song._id }}
 					<br />
 					<strong>Author:</strong>
 					<user-id-to-username

+ 4 - 4
frontend/src/pages/Admin/tabs/HiddenSongs.vue

@@ -72,11 +72,11 @@
 							<a
 								:href="
 									'https://www.youtube.com/watch?v=' +
-										`${song.songId}`
+										`${song.youtubeId}`
 								"
 								target="_blank"
 							>
-								{{ song.songId }}</a
+								{{ song.youtubeId }}</a
 							>
 						</td>
 						<td>
@@ -224,8 +224,8 @@ export default {
 			this.addSong(song);
 		});
 
-		this.socket.on("event:admin.hiddenSong.removed", songId => {
-			this.removeSong(songId);
+		this.socket.on("event:admin.hiddenSong.removed", youtubeId => {
+			this.removeSong(youtubeId);
 		});
 
 		this.socket.on("event:admin.hiddenSong.updated", updatedSong => {

+ 1 - 1
frontend/src/pages/Admin/tabs/Reports.vue

@@ -16,7 +16,7 @@
 					<tr v-for="(report, index) in reports" :key="index">
 						<td>
 							<span>
-								{{ report.song.songId }}
+								{{ report.song.youtubeId }}
 								<br />
 								{{ report.song._id }}
 							</span>

+ 5 - 5
frontend/src/pages/Admin/tabs/UnverifiedSongs.vue

@@ -72,11 +72,11 @@
 							<a
 								:href="
 									'https://www.youtube.com/watch?v=' +
-										`${song.songId}`
+										`${song.youtubeId}`
 								"
 								target="_blank"
 							>
-								{{ song.songId }}</a
+								{{ song.youtubeId }}</a
 							>
 						</td>
 						<td>
@@ -237,8 +237,8 @@ export default {
 			this.addSong(song);
 		});
 
-		this.socket.on("event:admin.unverifiedSong.removed", songId => {
-			this.removeSong(songId);
+		this.socket.on("event:admin.unverifiedSong.removed", youtubeId => {
+			this.removeSong(youtubeId);
 		});
 
 		this.socket.on("event:admin.unverifiedSong.updated", updatedSong => {
@@ -254,7 +254,7 @@ export default {
 			this.openModal({ sector: "admin", modal: "editSong" });
 		},
 		verify(song) {
-			this.socket.dispatch("songs.verify", song.songId, res => {
+			this.socket.dispatch("songs.verify", song.youtubeId, res => {
 				new Toast(res.message);
 			});
 		},

+ 5 - 5
frontend/src/pages/Admin/tabs/VerifiedSongs.vue

@@ -101,11 +101,11 @@
 							<a
 								:href="
 									'https://www.youtube.com/watch?v=' +
-										`${song.songId}`
+										`${song.youtubeId}`
 								"
 								target="_blank"
 							>
-								{{ song.songId }}</a
+								{{ song.youtubeId }}</a
 							>
 						</td>
 						<td>
@@ -318,8 +318,8 @@ export default {
 			this.addSong(song)
 		);
 
-		this.socket.on("event:admin.verifiedSong.removed", songId =>
-			this.removeSong(songId)
+		this.socket.on("event:admin.verifiedSong.removed", youtubeId =>
+			this.removeSong(youtubeId)
 		);
 
 		this.socket.on("event:admin.verifiedSong.updated", updatedSong =>
@@ -331,7 +331,7 @@ export default {
 
 		if (this.$route.query.songId) {
 			this.socket.dispatch(
-				"songs.getSongFromMusareId",
+				"songs.getSongFromSongId",
 				this.$route.query.songId,
 				res => {
 					if (res.status === "success") {

+ 2 - 2
frontend/src/pages/Home.vue

@@ -552,7 +552,7 @@ export default {
 						thumbnail: "/assets/notes-transparent.png"
 					};
 				if (station.currentSong && !station.currentSong.thumbnail)
-					station.currentSong.ytThumbnail = `https://img.youtube.com/vi/${station.currentSong.songId}/mqdefault.jpg`;
+					station.currentSong.ytThumbnail = `https://img.youtube.com/vi/${station.currentSong.youtubeId}/mqdefault.jpg`;
 				this.stations.push(station);
 			}
 		});
@@ -701,7 +701,7 @@ export default {
 							modifiableStation.currentSong &&
 							!modifiableStation.currentSong.thumbnail
 						)
-							modifiableStation.currentSong.ytThumbnail = `https://img.youtube.com/vi/${station.currentSong.songId}/mqdefault.jpg`;
+							modifiableStation.currentSong.ytThumbnail = `https://img.youtube.com/vi/${station.currentSong.youtubeId}/mqdefault.jpg`;
 
 						this.stations.push(modifiableStation);
 					});

+ 1 - 1
frontend/src/pages/Profile/tabs/Playlists.vue

@@ -182,7 +182,7 @@ export default {
 			this.playlists.forEach((playlist, index) => {
 				if (playlist._id === data.playlistId) {
 					this.playlists[index].songs.forEach((song, index2) => {
-						if (song.songId === data.songId) {
+						if (song.youtubeId === data.youtubeId) {
 							this.playlists[index].songs.splice(index2, 1);
 						}
 					});

+ 1 - 1
frontend/src/pages/Station/Sidebar/Playlists.vue

@@ -132,7 +132,7 @@ export default {
 			this.playlists.forEach((playlist, index) => {
 				if (playlist._id === data.playlistId) {
 					this.playlists[index].songs.forEach((song, index2) => {
-						if (song.songId === data.songId) {
+						if (song.youtubeId === data.youtubeId) {
 							this.playlists[index].songs.splice(index2, 1);
 						}
 					});

+ 4 - 4
frontend/src/pages/Station/Sidebar/Queue.vue

@@ -18,7 +18,7 @@
 			>
 				<song-item
 					v-for="(song, index) in queue"
-					:key="index + song.songId"
+					:key="index + song.youtubeId"
 					:song="song"
 					:requested-by="
 						station.type === 'community' &&
@@ -35,7 +35,7 @@
 					>
 						<confirm
 							v-if="isOwnerOnly() || isAdminOnly()"
-							@confirm="removeFromQueue(song.songId)"
+							@confirm="removeFromQueue(song.youtubeId)"
 						>
 							<i
 								class="material-icons delete-icon"
@@ -199,11 +199,11 @@ export default {
 		isAdminOnly() {
 			return this.loggedIn && this.userRole === "admin";
 		},
-		removeFromQueue(songId) {
+		removeFromQueue(youtubeId) {
 			this.socket.dispatch(
 				"stations.removeFromQueue",
 				this.station._id,
-				songId,
+				youtubeId,
 				res => {
 					if (res.status === "success") {
 						new Toast("Successfully removed song from the queue.");

+ 65 - 54
frontend/src/pages/Station/index.vue

@@ -37,9 +37,9 @@
 		<ul
 			v-if="
 				currentSong &&
-					(currentSong.songId === 'l9PxOanFjxQ' ||
-						currentSong.songId === 'xKVcVSYmesU' ||
-						currentSong.songId === '60ItHLz5WEA')
+					(currentSong.youtubeId === 'l9PxOanFjxQ' ||
+						currentSong.youtubeId === 'xKVcVSYmesU' ||
+						currentSong.youtubeId === '60ItHLz5WEA')
 			"
 			class="bg-bubbles"
 		>
@@ -209,13 +209,15 @@
 									:class="{
 										nyan:
 											currentSong &&
-											currentSong.songId === 'QH2-TGUlwu4'
+											currentSong.youtubeId ===
+												'QH2-TGUlwu4'
 									}"
 								/>
 								<img
 									v-if="
 										currentSong &&
-											currentSong.songId === 'QH2-TGUlwu4'
+											currentSong.youtubeId ===
+												'QH2-TGUlwu4'
 									"
 									src="https://freepngimg.com/thumb/nyan_cat/1-2-nyan-cat-free-download-png.png"
 									:style="{
@@ -228,13 +230,13 @@
 								<img
 									v-if="
 										currentSong &&
-											(currentSong.songId ===
+											(currentSong.youtubeId ===
 												'DtVBCG6ThDk' ||
-												currentSong.songId ===
+												currentSong.youtubeId ===
 													'sI66hcu9fIs' ||
-												currentSong.songId ===
+												currentSong.youtubeId ===
 													'iYYRH4apXDo' ||
-												currentSong.songId ===
+												currentSong.youtubeId ===
 													'tRcPA7Fzebw')
 									"
 									src="/assets/rocket.svg"
@@ -249,7 +251,8 @@
 								<img
 									v-if="
 										currentSong &&
-											currentSong.songId === 'jofNR_WkoCE'
+											currentSong.youtubeId ===
+												'jofNR_WkoCE'
 									"
 									src="/assets/fox.svg"
 									:style="{
@@ -264,11 +267,11 @@
 								<img
 									v-if="
 										currentSong &&
-											(currentSong.songId ===
+											(currentSong.youtubeId ===
 												'l9PxOanFjxQ' ||
-												currentSong.songId ===
+												currentSong.youtubeId ===
 													'xKVcVSYmesU' ||
-												currentSong.songId ===
+												currentSong.youtubeId ===
 													'60ItHLz5WEA')
 									"
 									src="/assets/old_logo.png"
@@ -586,7 +589,7 @@
 
 		<floating-box id="player-debug-box" ref="playerDebugBox">
 			<template #body>
-				<span><b>YouTube id</b>: {{ currentSong.songId }}</span>
+				<span><b>YouTube id</b>: {{ currentSong.youtubeId }}</span>
 				<span><b>Duration</b>: {{ currentSong.duration }}</span>
 				<span
 					><b>Skip duration</b>: {{ currentSong.skipDuration }}</span
@@ -687,7 +690,7 @@ export default {
 			disliked: false,
 			timeBeforePause: 0,
 			skipVotes: 0,
-			automaticallyRequestedSongId: null,
+			automaticallyRequestedYoutubeId: null,
 			systemDifference: 0,
 			attemptsToPlayVideo: 0,
 			canAutoplay: true,
@@ -771,7 +774,7 @@ export default {
 		);
 
 		this.socket.on("event:songs.next", data => {
-			const previousSong = this.currentSong.songId
+			const previousSong = this.currentSong.youtubeId
 				? this.currentSong
 				: null;
 
@@ -783,7 +786,9 @@ export default {
 
 			let nextSong = null;
 			if (this.songsList[1]) {
-				nextSong = this.songsList[1].songId ? this.songsList[1] : null;
+				nextSong = this.songsList[1].youtubeId
+					? this.songsList[1]
+					: null;
 			}
 			this.updateNextSong(nextSong);
 
@@ -799,9 +804,9 @@ export default {
 
 				this.socket.dispatch(
 					"songs.getOwnSongRatings",
-					data.currentSong.songId,
+					data.currentSong.youtubeId,
 					song => {
-						if (this.currentSong.songId === song.songId) {
+						if (this.currentSong.youtubeId === song.youtubeId) {
 							this.liked = song.liked;
 							this.disliked = song.disliked;
 
@@ -831,9 +836,9 @@ export default {
 			if (
 				!isInQueue &&
 				this.privatePlaylistQueueSelected &&
-				(this.automaticallyRequestedSongId !==
-					this.currentSong.songId ||
-					!this.currentSong.songId)
+				(this.automaticallyRequestedYoutubeId !==
+					this.currentSong.youtubeId ||
+					!this.currentSong.youtubeId)
 			) {
 				this.addFirstPrivatePlaylistSongToQueue();
 			}
@@ -853,9 +858,9 @@ export default {
 			// if (
 			// 	!isInQueue &&
 			// 	this.privatePlaylistQueueSelected &&
-			// 	(this.automaticallyRequestedSongId !==
-			// 		this.currentSong.songId ||
-			// 		!this.currentSong.songId)
+			// 	(this.automaticallyRequestedYoutubeId !==
+			// 		this.currentSong.youtubeId ||
+			// 		!this.currentSong.youtubeId)
 			// ) {
 			// 	this.addFirstPrivatePlaylistSongToQueue();
 			// }
@@ -880,7 +885,7 @@ export default {
 
 		this.socket.on("event:song.like", data => {
 			if (!this.noSong) {
-				if (data.songId === this.currentSong.songId) {
+				if (data.youtubeId === this.currentSong.youtubeId) {
 					this.currentSong.dislikes = data.dislikes;
 					this.currentSong.likes = data.likes;
 				}
@@ -889,7 +894,7 @@ export default {
 
 		this.socket.on("event:song.dislike", data => {
 			if (!this.noSong) {
-				if (data.songId === this.currentSong.songId) {
+				if (data.youtubeId === this.currentSong.youtubeId) {
 					this.currentSong.dislikes = data.dislikes;
 					this.currentSong.likes = data.likes;
 				}
@@ -898,7 +903,7 @@ export default {
 
 		this.socket.on("event:song.unlike", data => {
 			if (!this.noSong) {
-				if (data.songId === this.currentSong.songId) {
+				if (data.youtubeId === this.currentSong.youtubeId) {
 					this.currentSong.dislikes = data.dislikes;
 					this.currentSong.likes = data.likes;
 				}
@@ -907,7 +912,7 @@ export default {
 
 		this.socket.on("event:song.undislike", data => {
 			if (!this.noSong) {
-				if (data.songId === this.currentSong.songId) {
+				if (data.youtubeId === this.currentSong.youtubeId) {
 					this.currentSong.dislikes = data.dislikes;
 					this.currentSong.likes = data.likes;
 				}
@@ -916,7 +921,7 @@ export default {
 
 		this.socket.on("event:song.newRatings", data => {
 			if (!this.noSong) {
-				if (data.songId === this.currentSong.songId) {
+				if (data.youtubeId === this.currentSong.youtubeId) {
 					this.liked = data.liked;
 					this.disliked = data.disliked;
 				}
@@ -928,7 +933,9 @@ export default {
 
 			let nextSong = null;
 			if (this.songsList[0])
-				nextSong = this.songsList[0].songId ? this.songsList[0] : null;
+				nextSong = this.songsList[0].youtubeId
+					? this.songsList[0]
+					: null;
 
 			this.updateNextSong(nextSong);
 		});
@@ -938,7 +945,9 @@ export default {
 
 			let nextSong = null;
 			if (this.songsList[0])
-				nextSong = this.songsList[0].songId ? this.songsList[0] : null;
+				nextSong = this.songsList[0].youtubeId
+					? this.songsList[0]
+					: null;
 
 			this.updateNextSong(nextSong);
 		});
@@ -1067,11 +1076,11 @@ export default {
 		isOwnerOrAdmin() {
 			return this.isOwnerOnly() || this.isAdminOnly();
 		},
-		removeFromQueue(songId) {
+		removeFromQueue(youtubeId) {
 			window.socket.dispatch(
 				"stations.removeFromQueue",
 				this.station._id,
-				songId,
+				youtubeId,
 				res => {
 					if (res.status === "success") {
 						new Toast("Successfully removed song from the queue.");
@@ -1084,7 +1093,7 @@ export default {
 				this.player = new window.YT.Player("stationPlayer", {
 					height: 270,
 					width: 480,
-					videoId: this.currentSong.songId,
+					videoId: this.currentSong.youtubeId,
 					host: "https://www.youtube-nocookie.com",
 					startSeconds:
 						this.getTimeElapsed() / 1000 +
@@ -1132,14 +1141,15 @@ export default {
 								});
 
 								// save current song id
-								const erroredSongId = this.currentSong.songId;
+								const erroredYoutubeId = this.currentSong
+									.youtubeId;
 
 								// remove persistent toast if video has finished
 								window.isSongErroredInterval = setInterval(
 									() => {
 										if (
-											this.currentSong.songId !==
-											erroredSongId
+											this.currentSong.youtubeId !==
+											erroredYoutubeId
 										) {
 											persistentToast.destroy();
 
@@ -1218,7 +1228,7 @@ export default {
 			if (this.playerReady) {
 				this.videoLoading = true;
 				this.player.loadVideoById(
-					this.currentSong.songId,
+					this.currentSong.youtubeId,
 					this.getTimeElapsed() / 1000 + this.currentSong.skipDuration
 				);
 
@@ -1463,7 +1473,7 @@ export default {
 			if (this.liked)
 				this.socket.dispatch(
 					"songs.unlike",
-					this.currentSong.songId,
+					this.currentSong.youtubeId,
 					data => {
 						if (data.status !== "success")
 							new Toast(`Error: ${data.message}`);
@@ -1472,7 +1482,7 @@ export default {
 			else
 				this.socket.dispatch(
 					"songs.like",
-					this.currentSong.songId,
+					this.currentSong.youtubeId,
 					data => {
 						if (data.status !== "success")
 							new Toast(`Error: ${data.message}`);
@@ -1483,7 +1493,7 @@ export default {
 			if (this.disliked)
 				return this.socket.dispatch(
 					"songs.undislike",
-					this.currentSong.songId,
+					this.currentSong.youtubeId,
 					data => {
 						if (data.status !== "success")
 							new Toast(`Error: ${data.message}`);
@@ -1492,7 +1502,7 @@ export default {
 
 			return this.socket.dispatch(
 				"songs.dislike",
-				this.currentSong.songId,
+				this.currentSong.youtubeId,
 				data => {
 					if (data.status !== "success")
 						new Toast(`Error: ${data.message}`);
@@ -1516,19 +1526,19 @@ export default {
 							if (data.status === "success") {
 								if (data.song) {
 									if (data.song.duration < 15 * 60) {
-										this.automaticallyRequestedSongId =
-											data.song.songId;
+										this.automaticallyRequestedYoutubeId =
+											data.song.youtubeId;
 										this.socket.dispatch(
 											"stations.addToQueue",
 											this.station._id,
-											data.song.songId,
+											data.song.youtubeId,
 											data2 => {
 												if (data2.status === "success")
 													this.socket.dispatch(
 														"playlists.moveSongToBottom",
 														this
 															.privatePlaylistQueueSelected,
-														data.song.songId
+														data.song.youtubeId
 													);
 											}
 										);
@@ -1540,7 +1550,7 @@ export default {
 										this.socket.dispatch(
 											"playlists.moveSongToBottom",
 											this.privatePlaylistQueueSelected,
-											data.song.songId,
+											data.song.youtubeId,
 											data3 => {
 												if (data3.status === "success")
 													setTimeout(
@@ -1642,10 +1652,11 @@ export default {
 							this.playVideo();
 							this.socket.dispatch(
 								"songs.getOwnSongRatings",
-								res.data.currentSong.songId,
+								res.data.currentSong.youtubeId,
 								song => {
 									if (
-										this.currentSong.songId === song.songId
+										this.currentSong.youtubeId ===
+										song.youtubeId
 									) {
 										this.liked = song.liked;
 										this.disliked = song.disliked;
@@ -1662,7 +1673,7 @@ export default {
 								this.updateSongsList(res.queue);
 								let nextSong = null;
 								if (this.songsList[0]) {
-									nextSong = this.songsList[0].songId
+									nextSong = this.songsList[0].youtubeId
 										? this.songsList[0]
 										: null;
 								}
@@ -1833,9 +1844,9 @@ export default {
 
 				if (
 					this.activityWatchVideoLastYouTubeId !==
-					this.currentSong.songId
+					this.currentSong.youtubeId
 				) {
-					this.activityWatchVideoLastYouTubeId = this.currentSong.songId;
+					this.activityWatchVideoLastYouTubeId = this.currentSong.youtubeId;
 					this.activityWatchVideoLastStartDuration =
 						this.currentSong.skipDuration + this.getTimeElapsed();
 				}
@@ -1846,7 +1857,7 @@ export default {
 						this.currentSong && this.currentSong.artists
 							? this.currentSong.artists.join(", ")
 							: null,
-					youtubeId: this.currentSong.songId,
+					youtubeId: this.currentSong.youtubeId,
 					muted: this.muted,
 					volume: this.volumeSliderValue / 100,
 					startedDuration:

+ 1 - 1
frontend/src/store/modules/station.js

@@ -93,7 +93,7 @@ const mutations = {
 	repositionSongInList(state, song) {
 		if (
 			state.songsList[song.newIndex] &&
-			state.songsList[song.newIndex].songId === song.songId
+			state.songsList[song.newIndex].youtubeId === song.youtubeId
 		)
 			return;