Przeglądaj źródła

Added way to search for YouTube songs.

KrisVos130 7 lat temu
rodzic
commit
426d9eb86a

+ 14 - 0
frontend/app/js/actions/stationOverlay.js

@@ -1,7 +1,9 @@
 export const OPEN_OVERLAY1 = "OPEN_OVERLAY1";
 export const OPEN_OVERLAY2 = "OPEN_OVERLAY2";
+export const OPEN_OVERLAY3 = "OPEN_OVERLAY3";
 export const CLOSE_OVERLAY1 = "CLOSE_OVERLAY1";
 export const CLOSE_OVERLAY2 = "CLOSE_OVERLAY2";
+export const CLOSE_OVERLAY3 = "CLOSE_OVERLAY3";
 
 export function openOverlay1(overlay) {
 	return {
@@ -16,6 +18,13 @@ export function openOverlay2(overlay, extraProps) {
 		extraProps,
 	};
 }
+export function openOverlay3(overlay, callback) {
+	return {
+		type: OPEN_OVERLAY3,
+		overlay,
+		callback,
+	};
+}
 export function closeOverlay1() {
 	return {
 		type: CLOSE_OVERLAY1,
@@ -27,3 +36,8 @@ export function closeOverlay2() {
 		extraValue: null,
 	};
 }
+export function closeOverlay3() {
+	return {
+		type: CLOSE_OVERLAY3,
+	};
+}

+ 4 - 0
frontend/app/js/components/CustomInput.jsx

@@ -117,6 +117,10 @@ const dictionary = {
 			},
 		],
 	},
+	youTubeSearchQuery: {
+		inputType: "text",
+		isInput: true,
+	},
 };
 
 export default class CustomInput extends Component {

+ 16 - 0
frontend/app/js/reducers/stationOverlay.js

@@ -3,13 +3,17 @@ import { Map } from "immutable";
 import {
 	OPEN_OVERLAY1,
 	OPEN_OVERLAY2,
+	OPEN_OVERLAY3,
 	CLOSE_OVERLAY1,
 	CLOSE_OVERLAY2,
+	CLOSE_OVERLAY3,
 } from "actions/stationOverlay";
 
 const initialState = Map({
 	overlay1: null,
 	overlay2: null,
+	overlay3: null,
+	callback: null,
 	extraProps2: null,
 });
 
@@ -25,6 +29,12 @@ const actionsMap = {
 			extraProps2: action.extraProps,
 		});
 	},
+	[OPEN_OVERLAY3]: (state, action) => {
+		return state.merge({
+			overlay3: action.overlay,
+			callback: action.callback,
+		});
+	},
 	[CLOSE_OVERLAY1]: (state, action) => {
 		return state.merge({
 			overlay1: null,
@@ -33,6 +43,12 @@ const actionsMap = {
 	[CLOSE_OVERLAY2]: (state, action) => {
 		return state.merge({
 			overlay2: null,
+			callback: null,
+		});
+	},
+	[CLOSE_OVERLAY3]: (state, action) => {
+		return state.merge({
+			overlay3: null,
 		});
 	},
 };

+ 16 - 3
frontend/app/js/views/Station/Views/EditPlaylist.jsx

@@ -6,7 +6,7 @@ import CustomErrors from "components/CustomMessages.jsx";
 
 import { connect } from "react-redux";
 
-import { closeOverlay2 } from "actions/stationOverlay";
+import { closeOverlay2, openOverlay3 } from "actions/stationOverlay";
 
 import io from "io";
 
@@ -26,10 +26,19 @@ export default class EditPlaylist extends Component {
 		io.getSocket((socket) => {
 
 		});
-
-		console.log("EditPlaylist.jsx props", props);
 	}
 
+	addSongToQueueCallback = (songId) => {
+		io.getSocket((socket) => {
+			// Add song to queue
+			console.log("Add song to queue", songId);
+		});
+	};
+
+	addSongToQueue = () => {
+		this.props.dispatch(openOverlay3("searchYouTube", this.addSongToQueueCallback));
+	};
+
 	close = () => {
 		this.props.dispatch(closeOverlay2());
 	};
@@ -39,6 +48,10 @@ export default class EditPlaylist extends Component {
 			<div className="overlay">
 				<button onClick={ this.close }>Back</button>
 				<h1>Edit Playlist</h1>
+				Song list
+
+
+				<button onClick={ this.addSongToQueue }>Add song to queue</button>
 				<CustomErrors onRef={ ref => (this.messages = ref) } />
 			</div>
 		);

+ 10 - 0
frontend/app/js/views/Station/Views/Overlays.jsx

@@ -6,10 +6,12 @@ import { connect } from "react-redux";
 import Settings from "./Settings";
 import Playlists from "./Playlists";
 import EditPlaylist from "./EditPlaylist";
+import SearchYouTube from "./SearchYouTube";
 
 @connect(state => ({
 	overlay1: state.stationOverlay.get("overlay1"),
 	overlay2: state.stationOverlay.get("overlay2"),
+	overlay3: state.stationOverlay.get("overlay3"),
 	extraProps2: state.stationOverlay.get("extraProps2"),
 }))
 export default class Overlays extends Component {
@@ -19,6 +21,7 @@ export default class Overlays extends Component {
 		this.state = {
 			overlay1: null,
 			overlay2: null,
+			overlay3: null,
 		};
 	}
 
@@ -27,6 +30,7 @@ export default class Overlays extends Component {
 		if (type === "settings") input = <Settings t={ this.props.t } key={ key }/>;
 		else if (type === "playlists") input = <Playlists t={ this.props.t } key={ key }/>;
 		else if (type === "editPlaylist") input = <EditPlaylist t={ this.props.t } key={ key } playlistId={ this.props.extraProps2.get("playlistId") }/>;
+		else if (type === "searchYouTube") input = <SearchYouTube t={ this.props.t } key={ key }/>;
 		return input;
 	};
 
@@ -41,12 +45,18 @@ export default class Overlays extends Component {
 				overlay2: this.getComponent(this.props.overlay2),
 			});
 		}
+		if (this.props.overlay3 !== prevProps.overlay3) {
+			this.setState({
+				overlay3: this.getComponent(this.props.overlay3),
+			});
+		}
 	}
 
 	render() {
 		return <div>
 			{ this.state.overlay1 }
 			{ this.state.overlay2 }
+			{ this.state.overlay3 }
 		</div>;
 	}
 }

+ 103 - 0
frontend/app/js/views/Station/Views/SearchYouTube.jsx

@@ -0,0 +1,103 @@
+import React, { Component } from "react";
+import PropTypes from "prop-types";
+
+import CustomInput from "components/CustomInput.jsx";
+import CustomErrors from "components/CustomMessages.jsx";
+
+import { connect } from "react-redux";
+
+import { closeOverlay3 } from "actions/stationOverlay";
+
+import io from "io";
+
+@connect(state => ({
+	callback: state.stationOverlay.get("callback"),
+}))
+export default class SearchYouTube extends Component {
+	constructor(props) {
+		super(props);
+
+		CustomInput.initialize(this);
+
+		this.state = {
+			results: null,
+			gotResults: false,
+		};
+
+		io.getSocket((socket) => {
+
+		});
+	}
+
+	search = () => {
+		this.messages.clearErrorSuccess();
+		if (CustomInput.hasInvalidInput(this.input, ["query"])) {
+			this.messages.clearAddError(this.props.t("general:someFieldsAreIncorrectError"));
+		} else {
+			io.getSocket(socket => {
+				socket.emit('apis.searchYoutube', this.input.query.getValue(), res => {
+					if (res.status === "success") {
+						let results = res.data.items.map((result) => {
+							return {
+								songId: result.id.videoId,
+								url: `https://www.youtube.com/watch?v=${ result.id.videoId }`,
+								title: result.snippet.title,
+								thumbnail: result.snippet.thumbnails.default.url,
+							};
+						});
+
+						this.setState({
+							gotResults: true,
+							results,
+						});
+					} else {
+						this.messages.addError(res.message);
+					}
+				});
+			});
+		}
+	};
+
+	close = () => {
+		this.props.dispatch(closeOverlay3());
+	};
+
+	render() {
+		return (
+			<div className="overlay">
+				<button onClick={ this.close }>Back</button>
+				<h1>Search</h1>
+
+				<CustomInput type="youTubeSearchQuery" name="query" label="YouTube search query" placeholder="YouTube search query" onRef={ ref => (this.input.query = ref) } />
+				<button onClick={ this.search }>Search</button>
+
+				{
+					(this.state.gotResults)
+					? (
+						<div>
+							<h2>Results</h2>
+							{
+								this.state.results.map((result) => {
+									return (
+										<li key={ this.input.query.getValue() + result.songId }>
+											<img src={ result.thumbnail }/>
+											<a href={ result.url }>{ result.title }</a>
+											<span>12:12</span>
+											<span onClick={ () => { closeOverlay3(); this.props.callback(result.songId) } }>ADD</span>
+										</li>
+									);
+								})
+							}
+						</div>
+					)
+					: null
+				}
+				<ul>
+					{}
+				</ul>
+
+				<CustomErrors onRef={ ref => (this.messages = ref) } />
+			</div>
+		);
+	}
+}