Sfoglia il codice sorgente

feat(EditPlaylist): you can now search for Musare songs

Jonathan Graham 3 anni fa
parent
commit
495b44ad61

+ 1 - 5
frontend/src/App.vue

@@ -684,6 +684,7 @@ a {
 				}
 
 				.slider {
+					width: 100%;
 					position: absolute;
 					cursor: pointer;
 					top: 0;
@@ -971,11 +972,6 @@ h4.section-title {
 			cursor: pointer;
 			// color: var(--dark-grey);
 
-			&:hover,
-			&:focus {
-				filter: brightness(90%);
-			}
-
 			&:not(:first-child) {
 				margin-left: 5px;
 			}

+ 116 - 65
frontend/src/components/modals/EditPlaylist/Tabs/AddSongs.vue

@@ -1,66 +1,112 @@
 <template>
 	<div class="youtube-tab section">
-		<label class="label"> Search for a song from YouTube </label>
-		<div class="control is-grouped input-with-button">
-			<p class="control is-expanded">
-				<input
-					class="input"
-					type="text"
-					placeholder="Enter your YouTube query here..."
-					v-model="search.songs.query"
-					autofocus
-					@keyup.enter="searchForSongs()"
+		<div class="musare-songs">
+			<label class="label"> Search for a song on Musare </label>
+			<div class="control is-grouped input-with-button">
+				<p class="control is-expanded">
+					<input
+						class="input"
+						type="text"
+						placeholder="Enter your song query here..."
+						v-model="musareSearch.query"
+						@keyup.enter="searchForMusareSongs(1)"
+					/>
+				</p>
+				<p class="control">
+					<a class="button is-info" @click="searchForMusareSongs(1)"
+						><i class="material-icons icon-with-button">search</i
+						>Search</a
+					>
+				</p>
+			</div>
+			<div v-if="musareSearch.results.length > 0">
+				<song-item
+					v-for="song in musareSearch.results"
+					:key="song._id"
+					:song="song"
 				/>
-			</p>
-			<p class="control">
-				<a
-					class="button is-info"
-					@click.prevent="searchForSongs()"
-					href="#"
-					><i class="material-icons icon-with-button">search</i
-					>Search</a
+				<button
+					v-if="resultsLeftCount > 0"
+					class="button is-primary load-more-button"
+					@click="searchForMusareSongs(musareSearch.page + 1)"
 				>
-			</p>
+					Load {{ nextPageResultsCount }} more results
+				</button>
+			</div>
 		</div>
 
-		<div v-if="search.songs.results.length > 0" id="song-query-results">
-			<search-query-item
-				v-for="(result, index) in search.songs.results"
-				:key="result.id"
-				:result="result"
-			>
-				<template #actions>
-					<transition name="search-query-actions" mode="out-in">
-						<a
-							class="button is-success"
-							v-if="result.isAddedToQueue"
-							href="#"
-							key="added-to-playlist"
-						>
-							<i class="material-icons icon-with-button">done</i>
-							Added to playlist
-						</a>
-						<a
-							class="button is-dark"
-							v-else
-							@click.prevent="addSongToPlaylist(result.id, index)"
-							href="#"
-							key="add-to-playlist"
-						>
-							<i class="material-icons icon-with-button">add</i>
-							Add to playlist
-						</a>
-					</transition>
-				</template>
-			</search-query-item>
+		<div>
+			<label class="label"> Search for a song from YouTube </label>
+			<div class="control is-grouped input-with-button">
+				<p class="control is-expanded">
+					<input
+						class="input"
+						type="text"
+						placeholder="Enter your YouTube query here..."
+						v-model="youtubeSearch.songs.query"
+						autofocus
+						@keyup.enter="searchForSongs()"
+					/>
+				</p>
+				<p class="control">
+					<a
+						class="button is-info"
+						@click.prevent="searchForSongs()"
+						href="#"
+						><i class="material-icons icon-with-button">search</i
+						>Search</a
+					>
+				</p>
+			</div>
 
-			<a
-				class="button is-primary load-more-button"
-				@click.prevent="loadMoreSongs()"
-				href="#"
+			<div
+				v-if="youtubeSearch.songs.results.length > 0"
+				id="song-query-results"
 			>
-				Load more...
-			</a>
+				<search-query-item
+					v-for="(result, index) in youtubeSearch.songs.results"
+					:key="result.id"
+					:result="result"
+				>
+					<template #actions>
+						<transition name="search-query-actions" mode="out-in">
+							<a
+								class="button is-success"
+								v-if="result.isAddedToQueue"
+								href="#"
+								key="added-to-playlist"
+							>
+								<i class="material-icons icon-with-button"
+									>done</i
+								>
+								Added to playlist
+							</a>
+							<a
+								class="button is-dark"
+								v-else
+								@click.prevent="
+									addSongToPlaylist(result.id, index)
+								"
+								href="#"
+								key="add-to-playlist"
+							>
+								<i class="material-icons icon-with-button"
+									>add</i
+								>
+								Add to playlist
+							</a>
+						</transition>
+					</template>
+				</search-query-item>
+
+				<a
+					class="button is-primary load-more-button"
+					@click.prevent="loadMoreSongs()"
+					href="#"
+				>
+					Load more...
+				</a>
+			</div>
 		</div>
 	</div>
 </template>
@@ -69,15 +115,14 @@
 import { mapState, mapGetters } from "vuex";
 
 import SearchYoutube from "@/mixins/SearchYoutube.vue";
+import SearchMusare from "@/mixins/SearchMusare.vue";
 
+import SongItem from "@/components/SongItem.vue";
 import SearchQueryItem from "../../../SearchQueryItem.vue";
 
 export default {
-	components: { SearchQueryItem },
-	mixins: [SearchYoutube],
-	data() {
-		return {};
-	},
+	components: { SearchQueryItem, SongItem },
+	mixins: [SearchYoutube, SearchMusare],
 	computed: {
 		...mapState("modals/editPlaylist", {
 			playlist: state => state.playlist
@@ -87,22 +132,28 @@ export default {
 		})
 	},
 	watch: {
-		"search.songs.results": function checkIfSongInPlaylist(songs) {
+		"youtubeSearch.songs.results": function checkIfSongInPlaylist(songs) {
 			songs.forEach((searchItem, index) =>
 				this.playlist.songs.find(song => {
 					if (song.youtubeId === searchItem.id)
-						this.search.songs.results[index].isAddedToQueue = true;
+						this.youtubeSearch.songs.results[
+							index
+						].isAddedToQueue = true;
 
 					return song.youtubeId === searchItem.id;
 				})
 			);
 		},
 		"playlist.songs": function checkIfSongInPlaylist() {
-			this.search.songs.results.forEach((searchItem, index) =>
+			this.youtubeSearch.songs.results.forEach((searchItem, index) =>
 				this.playlist.songs.find(song => {
-					this.search.songs.results[index].isAddedToQueue = false;
+					this.youtubeSearch.songs.results[
+						index
+					].isAddedToQueue = false;
 					if (song.youtubeId === searchItem.id)
-						this.search.songs.results[index].isAddedToQueue = true;
+						this.youtubeSearch.songs.results[
+							index
+						].isAddedToQueue = true;
 
 					return song.youtubeId === searchItem.id;
 				})

+ 9 - 7
frontend/src/components/modals/EditPlaylist/Tabs/ImportPlaylists.vue

@@ -7,13 +7,15 @@
 					class="input"
 					type="text"
 					placeholder="Enter YouTube Playlist URL here..."
-					v-model="search.playlist.query"
+					v-model="youtubeSearch.playlist.query"
 					@keyup.enter="importPlaylist()"
 				/>
 			</p>
 			<p class="control has-addons">
 				<span class="select" id="playlist-import-type">
-					<select v-model="search.playlist.isImportingOnlyMusic">
+					<select
+						v-model="youtubeSearch.playlist.isImportingOnlyMusic"
+					>
 						<option :value="false">Import all</option>
 						<option :value="true">Import only music</option>
 					</select>
@@ -54,11 +56,11 @@ export default {
 			let isImportingPlaylist = true;
 
 			// import query is blank
-			if (!this.search.playlist.query)
+			if (!this.youtubeSearch.playlist.query)
 				return new Toast("Please enter a YouTube playlist URL.");
 
 			const regex = new RegExp(`[\\?&]list=([^&#]*)`);
-			const splitQuery = regex.exec(this.search.playlist.query);
+			const splitQuery = regex.exec(this.youtubeSearch.playlist.query);
 
 			if (!splitQuery) {
 				return new Toast({
@@ -78,14 +80,14 @@ export default {
 
 			return this.socket.dispatch(
 				"playlists.addSetToPlaylist",
-				this.search.playlist.query,
+				this.youtubeSearch.playlist.query,
 				this.playlist._id,
-				this.search.playlist.isImportingOnlyMusic,
+				this.youtubeSearch.playlist.isImportingOnlyMusic,
 				res => {
 					new Toast({ content: res.message, timeout: 20000 });
 					if (res.status === "success") {
 						isImportingPlaylist = false;
-						if (this.search.playlist.isImportingOnlyMusic) {
+						if (this.youtubeSearch.playlist.isImportingOnlyMusic) {
 							new Toast({
 								content: `${res.data.stats.songsInPlaylistTotal} of the ${res.data.stats.videosInPlaylistTotal} videos in the playlist were songs.`,
 								timeout: 20000

+ 6 - 6
frontend/src/components/modals/EditSong/Tabs/Youtube.vue

@@ -7,7 +7,7 @@
 					class="input"
 					type="text"
 					placeholder="Enter your YouTube query here..."
-					v-model="search.songs.query"
+					v-model="youtubeSearch.songs.query"
 					autofocus
 					@keyup.enter="searchForSongs()"
 				/>
@@ -23,9 +23,12 @@
 			</p>
 		</div>
 
-		<div v-if="search.songs.results.length > 0" id="song-query-results">
+		<div
+			v-if="youtubeSearch.songs.results.length > 0"
+			id="song-query-results"
+		>
 			<search-query-item
-				v-for="result in search.songs.results"
+				v-for="result in youtubeSearch.songs.results"
 				:key="result.id"
 				:result="result"
 			>
@@ -86,9 +89,6 @@ export default {
 </script>
 
 <style lang="scss" scoped>
-.night-mode {
-}
-
 .youtube-tab {
 	height: calc(100% - 32px);
 

+ 12 - 62
frontend/src/components/modals/ManageStation/Tabs/Songs.vue

@@ -84,6 +84,7 @@
 						</button>
 					</div>
 				</div>
+
 				<div class="youtube-search">
 					<label class="label"> Search for a song on YouTube </label>
 					<div class="control is-grouped input-with-button">
@@ -92,7 +93,7 @@
 								class="input"
 								type="text"
 								placeholder="Enter your YouTube query here..."
-								v-model="search.songs.query"
+								v-model="youtubeSearch.songs.query"
 								autofocus
 								@keyup.enter="searchForSongs()"
 							/>
@@ -109,11 +110,12 @@
 					</div>
 
 					<div
-						v-if="search.songs.results.length > 0"
+						v-if="youtubeSearch.songs.results.length > 0"
 						id="song-query-results"
 					>
 						<search-query-item
-							v-for="(result, index) in search.songs.results"
+							v-for="(result, index) in youtubeSearch.songs
+								.results"
 							:key="result.id"
 							:result="result"
 						>
@@ -221,6 +223,7 @@ import { mapState, mapGetters } from "vuex";
 
 import Toast from "toasters";
 import SearchYoutube from "@/mixins/SearchYoutube.vue";
+import SearchMusare from "@/mixins/SearchMusare.vue";
 
 import SongItem from "@/components/SongItem.vue";
 import SearchQueryItem from "../../../SearchQueryItem.vue";
@@ -232,28 +235,14 @@ export default {
 		SongItem,
 		SearchQueryItem
 	},
-	mixins: [SearchYoutube],
+	mixins: [SearchYoutube, SearchMusare],
 	data() {
 		return {
 			utils,
-			tab: "search",
-			musareSearch: {
-				query: "",
-				searchedQuery: "",
-				page: 0,
-				count: 0,
-				resultsLeft: 0,
-				results: []
-			}
+			tab: "search"
 		};
 	},
 	computed: {
-		resultsLeftCount() {
-			return this.musareSearch.count - this.musareSearch.results.length;
-		},
-		nextPageResultsCount() {
-			return Math.min(this.musareSearch.pageSize, this.resultsLeftCount);
-		},
 		excludedSongs() {
 			return this.excludedPlaylists
 				.map(playlist => playlist.songs)
@@ -344,7 +333,7 @@ export default {
 							new Toast(`Error: ${res.message}`);
 						else {
 							if (index)
-								this.search.songs.results[
+								this.youtubeSearch.songs.results[
 									index
 								].isAddedToQueue = true;
 
@@ -357,53 +346,14 @@ export default {
 					if (res.status !== "success")
 						new Toast(`Error: ${res.message}`);
 					else {
-						this.search.songs.results[index].isAddedToQueue = true;
+						this.youtubeSearch.songs.results[
+							index
+						].isAddedToQueue = true;
 
 						new Toast(res.message);
 					}
 				});
 			}
-		},
-		searchForMusareSongs(page) {
-			if (
-				this.musareSearch.page >= page ||
-				this.musareSearch.searchedQuery !== this.musareSearch.query
-			) {
-				this.musareSearch.results = [];
-				this.musareSearch.page = 0;
-				this.musareSearch.count = 0;
-				this.musareSearch.resultsLeft = 0;
-				this.musareSearch.pageSize = 0;
-			}
-
-			this.musareSearch.searchedQuery = this.musareSearch.query;
-			this.socket.dispatch(
-				"songs.searchOfficial",
-				this.musareSearch.query,
-				page,
-				res => {
-					const { data } = res;
-					const { count, pageSize, songs } = data;
-					if (res.status === "success") {
-						this.musareSearch.results = [
-							...this.musareSearch.results,
-							...songs
-						];
-						this.musareSearch.page = page;
-						this.musareSearch.count = count;
-						this.musareSearch.resultsLeft =
-							count - this.musareSearch.results.length;
-						this.musareSearch.pageSize = pageSize;
-					} else if (res.status === "error") {
-						this.musareSearch.results = [];
-						this.musareSearch.page = 0;
-						this.musareSearch.count = 0;
-						this.musareSearch.resultsLeft = 0;
-						this.musareSearch.pageSize = 0;
-						new Toast(res.message);
-					}
-				}
-			);
 		}
 	}
 };

+ 16 - 11
frontend/src/components/modals/RequestSong.vue

@@ -17,7 +17,7 @@
 							class="input"
 							type="text"
 							placeholder="Enter your YouTube query here..."
-							v-model="search.songs.query"
+							v-model="youtubeSearch.songs.query"
 							autofocus
 							@keyup.enter="searchForSongs()"
 						/>
@@ -38,10 +38,10 @@
 
 				<div
 					id="song-query-results"
-					v-if="search.songs.results.length > 0"
+					v-if="youtubeSearch.songs.results.length > 0"
 				>
 					<search-query-item
-						v-for="(result, index) in search.songs.results"
+						v-for="(result, index) in youtubeSearch.songs.results"
 						:key="result.id"
 						:result="result"
 					>
@@ -106,7 +106,7 @@
 								class="input"
 								type="text"
 								placeholder="YouTube Playlist URL"
-								v-model="search.playlist.query"
+								v-model="youtubeSearch.playlist.query"
 								@keyup.enter="importPlaylist()"
 							/>
 						</p>
@@ -114,7 +114,8 @@
 							<span class="select" id="playlist-import-type">
 								<select
 									v-model="
-										search.playlist.isImportingOnlyMusic
+										youtubeSearch.playlist
+											.isImportingOnlyMusic
 									"
 								>
 									<option :value="false">Import all</option>
@@ -172,7 +173,9 @@ export default {
 						if (res.status !== "success")
 							new Toast(`Error: ${res.message}`);
 						else {
-							this.search.songs.results[index].isRequested = true;
+							this.youtubeSearch.songs.results[
+								index
+							].isRequested = true;
 
 							new Toast(res.message);
 						}
@@ -183,7 +186,9 @@ export default {
 					if (res.status !== "success")
 						new Toast(`Error: ${res.message}`);
 					else {
-						this.search.songs.results[index].isRequested = true;
+						this.youtubeSearch.songs.results[
+							index
+						].isRequested = true;
 
 						new Toast(res.message);
 					}
@@ -194,11 +199,11 @@ export default {
 			let isImportingPlaylist = true;
 
 			// import query is blank
-			if (!this.search.playlist.query)
+			if (!this.youtubeSearch.playlist.query)
 				return new Toast("Please enter a YouTube playlist URL.");
 
 			const regex = new RegExp(`[\\?&]list=([^&#]*)`);
-			const splitQuery = regex.exec(this.search.playlist.query);
+			const splitQuery = regex.exec(this.youtubeSearch.playlist.query);
 
 			if (!splitQuery) {
 				return new Toast({
@@ -218,8 +223,8 @@ export default {
 
 			return this.socket.dispatch(
 				"songs.requestSet",
-				this.search.playlist.query,
-				this.search.playlist.isImportingOnlyMusic,
+				this.youtubeSearch.playlist.query,
+				this.youtubeSearch.playlist.isImportingOnlyMusic,
 				false,
 				res => {
 					isImportingPlaylist = false;

+ 72 - 0
frontend/src/mixins/SearchMusare.vue

@@ -0,0 +1,72 @@
+<script>
+import Toast from "toasters";
+
+export default {
+	data() {
+		return {
+			musareSearch: {
+				query: "",
+				searchedQuery: "",
+				page: 0,
+				count: 0,
+				resultsLeft: 0,
+				results: []
+			}
+		};
+	},
+	computed: {
+		resultsLeftCount() {
+			return this.musareSearch.count - this.musareSearch.results.length;
+		},
+		nextPageResultsCount() {
+			return Math.min(this.musareSearch.pageSize, this.resultsLeftCount);
+		}
+	},
+	methods: {
+		searchForMusareSongs(page) {
+			if (
+				this.musareSearch.page >= page ||
+				this.musareSearch.searchedQuery !== this.musareSearch.query
+			) {
+				this.musareSearch.results = [];
+				this.musareSearch.page = 0;
+				this.musareSearch.count = 0;
+				this.musareSearch.resultsLeft = 0;
+				this.musareSearch.pageSize = 0;
+			}
+
+			this.musareSearch.searchedQuery = this.musareSearch.query;
+			this.socket.dispatch(
+				"songs.searchOfficial",
+				this.musareSearch.query,
+				page,
+				res => {
+					const { data } = res;
+					const { count, pageSize, songs } = data;
+
+					if (res.status === "success") {
+						this.musareSearch.results = [
+							...this.musareSearch.results,
+							...songs
+						];
+						console.log(this.musareSearch.results);
+
+						this.musareSearch.page = page;
+						this.musareSearch.count = count;
+						this.musareSearch.resultsLeft =
+							count - this.musareSearch.results.length;
+						this.musareSearch.pageSize = pageSize;
+					} else if (res.status === "error") {
+						this.musareSearch.results = [];
+						this.musareSearch.page = 0;
+						this.musareSearch.count = 0;
+						this.musareSearch.resultsLeft = 0;
+						this.musareSearch.pageSize = 0;
+						new Toast(res.message);
+					}
+				}
+			);
+		}
+	}
+};
+</script>

+ 13 - 10
frontend/src/mixins/SearchYoutube.vue

@@ -4,7 +4,7 @@ import Toast from "toasters";
 export default {
 	data() {
 		return {
-			search: {
+			youtubeSearch: {
 				songs: {
 					results: [],
 					query: "",
@@ -19,7 +19,7 @@ export default {
 	},
 	methods: {
 		searchForSongs() {
-			let { query } = this.search.songs;
+			let { query } = this.youtubeSearch.songs;
 
 			if (query.indexOf("&index=") !== -1) {
 				query = query.split("&index=");
@@ -35,11 +35,12 @@ export default {
 
 			this.socket.dispatch("apis.searchYoutube", query, res => {
 				if (res.status === "success") {
-					this.search.songs.nextPageToken = res.data.nextPageToken;
-					this.search.songs.results = [];
+					this.youtubeSearch.songs.nextPageToken =
+						res.data.nextPageToken;
+					this.youtubeSearch.songs.results = [];
 
 					res.data.items.forEach(result => {
-						this.search.songs.results.push({
+						this.youtubeSearch.songs.results.push({
 							id: result.id.videoId,
 							url: `https://www.youtube.com/watch?v=${this.id}`,
 							title: result.snippet.title,
@@ -55,15 +56,15 @@ export default {
 		loadMoreSongs() {
 			this.socket.dispatch(
 				"apis.searchYoutubeForPage",
-				this.search.songs.query,
-				this.search.songs.nextPageToken,
+				this.youtubeSearch.songs.query,
+				this.youtubeSearch.songs.nextPageToken,
 				res => {
 					if (res.status === "success") {
-						this.search.songs.nextPageToken =
+						this.youtubeSearch.songs.nextPageToken =
 							res.data.nextPageToken;
 
 						res.data.items.forEach(result => {
-							this.search.songs.results.push({
+							this.youtubeSearch.songs.results.push({
 								id: result.id.videoId,
 								url: `https://www.youtube.com/watch?v=${this.id}`,
 								title: result.snippet.title,
@@ -87,7 +88,9 @@ export default {
 				res => {
 					new Toast(res.message);
 					if (res.status === "success")
-						this.search.songs.results[index].isAddedToQueue = true;
+						this.youtubeSearch.songs.results[
+							index
+						].isAddedToQueue = true;
 				}
 			);
 		}