Browse Source

Merge branch 'polishing' of github.com:Musare/MusareNode into polishing

Jonathan 3 years ago
parent
commit
e6d8b9a8e6

+ 13 - 9
backend/logic/actions/playlists.js

@@ -985,15 +985,19 @@ export default {
 		async.waterfall(
 			[
 				next => {
-					YouTubeModule.runJob("GET_PLAYLIST", { url, musicOnly }, this).then(res => {
-						if (res.filteredSongs) {
-							videosInPlaylistTotal = res.songs.length;
-							songsInPlaylistTotal = res.filteredSongs.length;
-						} else {
-							songsInPlaylistTotal = videosInPlaylistTotal = res.songs.length;
-						}
-						next(null, res.songs);
-					});
+					YouTubeModule.runJob("GET_PLAYLIST", { url, musicOnly }, this)
+						.then(res => {
+							if (res.filteredSongs) {
+								videosInPlaylistTotal = res.songs.length;
+								songsInPlaylistTotal = res.filteredSongs.length;
+							} else {
+								songsInPlaylistTotal = videosInPlaylistTotal = res.songs.length;
+							}
+							next(null, res.songs);
+						})
+						.catch(err => {
+							next(err);
+						});
 				},
 				(songIds, next) => {
 					let successful = 0;

+ 5 - 4
backend/logic/youtube.js

@@ -196,9 +196,7 @@ class _YouTubeModule extends CoreClass {
 	 */
 	GET_PLAYLIST(payload) {
 		return new Promise((resolve, reject) => {
-			const name = "list".replace(/[\\[]/, "\\[").replace(/[\]]/, "\\]");
-
-			const regex = new RegExp(`[\\?&]${name}=([^&#]*)`);
+			const regex = new RegExp(`[\\?&]list=([^&#]*)`);
 			const splitQuery = regex.exec(payload.url);
 
 			if (!splitQuery) {
@@ -255,7 +253,7 @@ class _YouTubeModule extends CoreClass {
 				(err, response) => {
 					if (err && err !== true) {
 						YouTubeModule.log("ERROR", "GET_PLAYLIST", "Some error has occurred.", err.message);
-						reject(new Error("Some error has occurred."));
+						reject(new Error(err.message));
 					} else {
 						resolve({ songs: response.filteredSongs ? response.filteredSongs.songIds : response.songs });
 					}
@@ -305,6 +303,9 @@ class _YouTubeModule extends CoreClass {
 					})
 					.catch(err => {
 						YouTubeModule.log("ERROR", "GET_PLAYLIST_PAGE", `${err.message}`);
+						if (err.message === "Request failed with status code 404") {
+							return reject(new Error("Playlist not found. Is the playlist public/unlisted?"));
+						}
 						return reject(new Error("An error has occured. Please try again later."));
 					});
 			});

+ 3 - 1
frontend/src/components/SongItem.vue

@@ -7,7 +7,9 @@
 				<h4
 					class="item-title"
 					:style="
-						song.artists.length < 1 ? { fontSize: '16px' } : null
+						song.artists && song.artists.length < 1
+							? { fontSize: '16px' }
+							: null
 					"
 					:title="song.title"
 				>

+ 10 - 0
frontend/src/components/modals/AddSongToQueue.vue

@@ -292,6 +292,16 @@ export default {
 			if (!this.search.playlist.query)
 				return new Toast("Please enter a YouTube playlist URL.");
 
+			const regex = new RegExp(`[\\?&]list=([^&#]*)`);
+			const splitQuery = regex.exec(this.search.playlist.query);
+
+			if (!splitQuery) {
+				return new Toast({
+					content: "Please enter a valid YouTube playlist URL.",
+					timeout: 4000
+				});
+			}
+
 			// don't give starting import message instantly in case of instant error
 			setTimeout(() => {
 				if (isImportingPlaylist) {

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

@@ -481,6 +481,16 @@ export default {
 			if (!this.search.playlist.query)
 				return new Toast("Please enter a YouTube playlist URL.");
 
+			const regex = new RegExp(`[\\?&]list=([^&#]*)`);
+			const splitQuery = regex.exec(this.search.playlist.query);
+
+			if (!splitQuery) {
+				return new Toast({
+					content: "Please enter a valid YouTube playlist URL.",
+					timeout: 4000
+				});
+			}
+
 			// don't give starting import message instantly in case of instant error
 			setTimeout(() => {
 				if (isImportingPlaylist) {

+ 16 - 8
frontend/src/components/modals/EditStation.vue

@@ -474,7 +474,7 @@
 			<save-button ref="saveButton" @clicked="saveChanges()" />
 
 			<button
-				v-if="station.type === 'community'"
+				v-if="station && station.type === 'community'"
 				class="button is-danger"
 				@click="deleteStation()"
 			>
@@ -592,15 +592,15 @@ export default {
 					this.stationId,
 					res => {
 						if (res.status === "success") {
-							this.station.genres = res.playlists.map(
-								playlist => {
+							this.setGenres(
+								res.playlists.map(playlist => {
 									if (playlist) {
 										if (playlist.type === "genre")
 											return playlist.createdFor;
 										return `Playlist: ${playlist.name}`;
 									}
 									return "Unknown/Error";
-								}
+								})
 							);
 							this.originalStation.genres = JSON.parse(
 								JSON.stringify(this.station.genres)
@@ -614,15 +614,15 @@ export default {
 					this.stationId,
 					res => {
 						if (res.status === "success") {
-							this.station.blacklistedGenres = res.playlists.map(
-								playlist => {
+							this.setBlacklistedGenres(
+								res.playlists.map(playlist => {
 									if (playlist) {
 										if (playlist.type === "genre")
 											return playlist.createdFor;
 										return `Playlist: ${playlist.name}`;
 									}
 									return "Unknown/Error";
-								}
+								})
 							);
 							this.originalStation.blacklistedGenres = JSON.parse(
 								JSON.stringify(this.station.blacklistedGenres)
@@ -646,6 +646,9 @@ export default {
 			}
 		});
 	},
+	beforeDestroy() {
+		this.clearStation();
+	},
 	methods: {
 		saveChanges() {
 			const nameChanged = this.originalStation.name !== this.station.name;
@@ -1068,7 +1071,12 @@ export default {
 			else if (type === "blacklist-genres")
 				this.station.blacklistedGenres.splice(index, 1);
 		},
-		...mapActions("modals/editStation", ["editStation"]),
+		...mapActions("modals/editStation", [
+			"editStation",
+			"setGenres",
+			"setBlacklistedGenres",
+			"clearStation"
+		]),
 		...mapActions("modalVisibility", ["closeModal"])
 	}
 };

+ 14 - 53
frontend/src/components/modals/Report.vue

@@ -2,10 +2,7 @@
 	<modal title="Report">
 		<div slot="body">
 			<div class="columns song-types">
-				<div
-					v-if="previousSong !== null && localSong === null"
-					class="column song-type"
-				>
+				<div v-if="previousSong !== null" class="column song-type">
 					<div
 						class="card is-fullwidth"
 						:class="{ 'is-highlight-active': isPreviousSongActive }"
@@ -44,35 +41,32 @@
 						/>
 					</div>
 				</div>
-				<div
-					v-if="currentSong !== {} && localSong === null"
-					class="column song-type"
-				>
+				<div v-if="localSong !== null" class="column song-type">
 					<div
 						class="card is-fullwidth"
-						:class="{ 'is-highlight-active': isCurrentSongActive }"
-						@click="highlight('currentSong')"
+						:class="{ 'is-highlight-active': isLocalSongActive }"
+						@click="highlight('localSong')"
 					>
 						<header class="card-header">
-							<p class="card-header-title">Current Song</p>
+							<p class="card-header-title">Selected Song</p>
 						</header>
 						<div class="card-content">
 							<article class="media">
 								<figure class="media-left">
 									<song-thumbnail
 										class="image is-64x64"
-										:song="currentSong"
+										:song="localSong"
 									/>
 								</figure>
 								<div class="media-content">
 									<div class="content">
 										<p>
 											<strong>{{
-												currentSong.title
+												localSong.title
 											}}</strong>
 											<br />
 											<small>{{
-												currentSong.artists.join(", ")
+												localSong.artists.join(", ")
 											}}</small>
 										</p>
 									</div>
@@ -82,40 +76,10 @@
 						<a
 							href="#"
 							class="absolute-a"
-							@click="highlight('currentSong')"
+							@click="highlight('localSong')"
 						/>
 					</div>
 				</div>
-				<div v-if="localSong !== null" class="column song-type">
-					<div class="card is-fullwidth">
-						<header class="card-header">
-							<p class="card-header-title">Song</p>
-						</header>
-						<div class="card-content">
-							<article class="media">
-								<figure class="media-left">
-									<song-thumbnail
-										class="image is-64x64"
-										:song="localSong"
-									/>
-								</figure>
-								<div class="media-content">
-									<div class="content">
-										<p>
-											<strong>{{
-												localSong.title
-											}}</strong>
-											<br />
-											<small>{{
-												localSong.artists.join(", ")
-											}}</small>
-										</p>
-									</div>
-								</div>
-							</article>
-						</div>
-					</div>
-				</div>
 			</div>
 			<div class="edit-report-wrapper">
 				<div class="columns is-multiline">
@@ -187,7 +151,7 @@ export default {
 	data() {
 		return {
 			isPreviousSongActive: false,
-			isCurrentSongActive: true,
+			isLocalSongActive: true,
 			localSong: null,
 			report: {
 				resolved: false,
@@ -240,7 +204,6 @@ export default {
 			return 400 - this.report.description.length;
 		},
 		...mapState({
-			currentSong: state => state.station.currentSong,
 			previousSong: state => state.station.previousSong,
 			song: state => state.modals.report.song
 		}),
@@ -249,8 +212,6 @@ export default {
 		})
 	},
 	mounted() {
-		this.report.songId = this.currentSong.songId;
-
 		if (this.song !== null) {
 			this.localSong = this.song;
 			this.report.songId = this.song.songId;
@@ -269,13 +230,13 @@ export default {
 			});
 		},
 		highlight(type) {
-			if (type === "currentSong") {
-				this.report.songId = this.currentSong.songId;
+			if (type === "localSong") {
+				this.report.songId = this.localSong.songId;
 				this.isPreviousSongActive = false;
-				this.isCurrentSongActive = true;
+				this.isLocalSongActive = true;
 			} else if (type === "previousSong") {
 				this.report.songId = this.previousSong.songId;
-				this.isCurrentSongActive = false;
+				this.isLocalSongActive = false;
 				this.isPreviousSongActive = true;
 			}
 		},

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

@@ -24,7 +24,7 @@
 						<td>
 							<profile-picture
 								:avatar="user.avatar"
-								:name="user.name"
+								:name="user.name ? user.name : user.username"
 							/>
 						</td>
 						<td>{{ user._id }}</td>

+ 15 - 4
frontend/src/pages/Profile/index.vue

@@ -9,9 +9,12 @@
 		<div class="container">
 			<div class="info-section">
 				<div class="picture-name-row">
-					<profile-picture :avatar="user.avatar" :name="user.name" />
+					<profile-picture
+						:avatar="user.avatar"
+						:name="user.name ? user.name : user.username"
+					/>
 					<div>
-						<div class="name-role-row">
+						<div class="name-row" v-if="user.name">
 							<p class="name">{{ user.name }}</p>
 							<span
 								class="role admin"
@@ -19,7 +22,14 @@
 								>admin</span
 							>
 						</div>
-						<h2 class="username">@{{ user.username }}</h2>
+						<div class="username-row">
+							<h2 class="username">@{{ user.username }}</h2>
+							<span
+								class="role admin"
+								v-if="user.role === 'admin' && !user.name"
+								>admin</span
+							>
+						</div>
 					</div>
 				</div>
 				<div
@@ -233,7 +243,8 @@ export default {
 		}
 	}
 
-	.name-role-row {
+	.name-row,
+	.username-row {
 		display: flex;
 		flex-direction: row;
 		align-items: center;

+ 5 - 1
frontend/src/pages/Settings/tabs/Profile.vue

@@ -15,7 +15,11 @@
 			<div id="avatar-selection-inner-container">
 				<profile-picture
 					:avatar="modifiedUser.avatar"
-					:name="modifiedUser.name"
+					:name="
+						modifiedUser.name
+							? modifiedUser.name
+							: modifiedUser.username
+					"
 				/>
 				<div class="select">
 					<select v-model="modifiedUser.avatar.type">

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

@@ -44,7 +44,7 @@
 					>
 						<profile-picture
 							:avatar="user.avatar"
-							:name="user.name"
+							:name="user.name ? user.name : user.username"
 						/>
 
 						{{ user.username }}

+ 25 - 1
frontend/src/store/modules/modals/editStation.js

@@ -1,5 +1,7 @@
 /* eslint no-param-reassign: 0 */
 
+import Vue from "vue";
+
 export default {
 	namespaced: true,
 	state: {
@@ -8,12 +10,34 @@ export default {
 	},
 	getters: {},
 	actions: {
-		editStation: ({ commit }, station) => commit("editStation", station)
+		editStation: ({ commit }, station) => commit("editStation", station),
+		setGenres: ({ commit }, genres) => commit("setGenres", genres),
+		setBlacklistedGenres: ({ commit }, blacklistedGenres) =>
+			commit("setBlacklistedGenres", blacklistedGenres),
+		clearStation: ({ commit }) => commit("clearStation")
 	},
 	mutations: {
 		editStation(state, station) {
 			state.originalStation = JSON.parse(JSON.stringify(station));
 			state.station = JSON.parse(JSON.stringify(station));
+		},
+		setGenres(state, genres) {
+			Vue.set(
+				state.station,
+				"genres",
+				JSON.parse(JSON.stringify(genres))
+			);
+		},
+		setBlacklistedGenres(state, blacklistedGenres) {
+			Vue.set(
+				state.station,
+				"blacklistedGenres",
+				JSON.parse(JSON.stringify(blacklistedGenres))
+			);
+		},
+		clearStation(state) {
+			state.originalStation = null;
+			state.station = null;
 		}
 	}
 };