index.jsx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. import React, { Component } from "react";
  2. import { NavLink } from "react-router-dom";
  3. import PropTypes from "prop-types";
  4. import { translate, Trans } from "react-i18next";
  5. import Player from "./Player";
  6. import Seekerbar from "./Seekerbar";
  7. import VolumeSlider from "./VolumeSlider";
  8. import Ratings from "./Ratings";
  9. import Time from "./Time";
  10. import Overlays from "./Views/Overlays";
  11. import { actionCreators as stationCurrentSongActionCreators } from "ducks/stationCurrentSong";
  12. import { bindActionCreators } from "redux";
  13. //import { changeVolume } from "actions/volume";
  14. //import { changeSong, setTimeElapsed, timePaused, receivedRatings, receivedOwnRatings } from "actions/songPlayer";
  15. //import { pauseStation, resumeStation } from "actions/station";
  16. import { openOverlay1 } from "actions/stationOverlay";
  17. //import { addSong } from "actions/playlistQueue";
  18. //import { updateTimePaused } from "../../actions/songPlayer";
  19. import { connect } from "react-redux";
  20. import io from "io";
  21. import config from "config";
  22. @connect(state => ({
  23. user: {
  24. userId: state.session.get("userId"),
  25. role: state.session.get("role"),
  26. loggedIn: state.session.get("loggedIn"),
  27. },
  28. /*
  29. //queueLocked: state.station.get("locked"),
  30. //partyEnabled: state.station.get("partyMode"),*/
  31. song: {
  32. exists: state.station.currentSong.get("songId") !== "",
  33. songId: state.station.currentSong.get("songId"),
  34. title: state.station.currentSong.get("title"),
  35. artists: state.station.currentSong.get("artists"),
  36. },
  37. station: {
  38. stationId: state.station.info.get("stationId"),
  39. name: state.station.info.get("name"),
  40. displayName: state.station.info.get("displayName"),
  41. paused: state.station.info.get("paused"),
  42. pausedAt: state.station.info.get("pausedAt"),
  43. ownerId: state.station.info.get("ownerId"),
  44. },/*
  45. selectedPlaylistObject: {
  46. addedSongId: state.playlistQueue.get("addedSongId"),
  47. selectedPlaylistId: state.playlistQueue.get("playlistSelected"),
  48. },*/
  49. }),
  50. (dispatch) => ({
  51. onNextSong: bindActionCreators(stationCurrentSongActionCreators.nextSong, dispatch),
  52. onLikeUpdate: bindActionCreators(stationCurrentSongActionCreators.likeUpdate, dispatch),
  53. onDislikeUpdate: bindActionCreators(stationCurrentSongActionCreators.dislikeUpdate, dispatch),
  54. onLikedUpdate: bindActionCreators(stationCurrentSongActionCreators.likedUpdate, dispatch),
  55. onDislikedUpdate: bindActionCreators(stationCurrentSongActionCreators.dislikedUpdate, dispatch),
  56. onPauseTime: bindActionCreators(stationCurrentSongActionCreators.pauseTime, dispatch),
  57. onResumeTime: bindActionCreators(stationCurrentSongActionCreators.resumeTime, dispatch),
  58. openOverlay1: bindActionCreators(openOverlay1, dispatch),
  59. }))
  60. @translate(["station"], { wait: true })
  61. export default class Station extends Component {
  62. static propTypes = {
  63. t: PropTypes.func,
  64. };
  65. static defaultProps = {
  66. t: () => {},
  67. };
  68. constructor(props) {
  69. super();
  70. /*this.state = {
  71. mode: this.getModeTemp(props.partyEnabled, props.queueLocked),
  72. };*/
  73. io.getSocket(socket => {
  74. socket.emit("stations.join", props.station.name, res => {
  75. if (res.status === "success") {
  76. if (res.data.currentSong) {
  77. let song = {
  78. songId: res.data.currentSong.songId,
  79. timings: {
  80. duration: res.data.currentSong.duration,
  81. skipDuration: res.data.currentSong.skipDuration,
  82. // timeElapsed?
  83. timePaused: res.data.timePaused,
  84. // pausedAt?
  85. startedAt: res.data.startedAt,
  86. },
  87. title: res.data.currentSong.title,
  88. artists: res.data.currentSong.artists,
  89. ratings: {
  90. enabled: !(res.data.currentSong.likes === -1 && res.data.currentSong.dislikes === -1),
  91. likes: res.data.currentSong.likes,
  92. dislikes: res.data.currentSong.dislikes,
  93. },
  94. };
  95. this.props.onNextSong(song);
  96. this.fetchOwnRatings();
  97. } else {
  98. // TODO This will probably need to be handled
  99. this.props.onNextSong(null);
  100. }
  101. }
  102. socket.on("event:songs.next", data => {
  103. //this.addTopToQueue();
  104. if (data.currentSong) {
  105. let song = {
  106. songId: data.currentSong.songId,
  107. timings: {
  108. duration: data.currentSong.duration,
  109. skipDuration: data.currentSong.skipDuration,
  110. // timeElapsed?
  111. timePaused: data.timePaused,
  112. // pausedAt?
  113. startedAt: data.startedAt,
  114. },
  115. title: data.currentSong.title,
  116. artists: data.currentSong.artists,
  117. ratings: {
  118. enabled: !(data.currentSong.likes === -1 && data.currentSong.dislikes === -1),
  119. likes: data.currentSong.likes,
  120. dislikes: data.currentSong.dislikes,
  121. },
  122. };
  123. this.props.onNextSong(song);
  124. this.fetchOwnRatings();
  125. } else {
  126. this.props.onNextSong(null);
  127. }
  128. });
  129. socket.on("event:stations.pause", pausedAt => {
  130. // TODO Dispatch to station info
  131. this.props.onPauseTime(pausedAt);
  132. });
  133. socket.on("event:stations.resume", data => {
  134. // TODO Dispatch to station info
  135. this.props.onResumeTime(data.timePaused);
  136. });
  137. socket.on("event:song.like", data => {
  138. if (data.songId === this.props.song.songId) {
  139. this.props.onLikeUpdate(data.likes);
  140. this.props.onDislikeUpdate(data.dislikes);
  141. }
  142. });
  143. socket.on("event:song.dislike", data => {
  144. if (data.songId === this.props.song.songId) {
  145. this.props.onLikeUpdate(data.likes);
  146. this.props.onDislikeUpdate(data.dislikes);
  147. }
  148. });
  149. socket.on("event:song.unlike", data => {
  150. if (data.songId === this.props.song.songId) {
  151. this.props.onLikeUpdate(data.likes);
  152. this.props.onDislikeUpdate(data.dislikes);
  153. }
  154. });
  155. socket.on("event:song.undislike", data => {
  156. if (data.songId === this.props.song.songId) {
  157. this.props.onLikeUpdate(data.likes);
  158. this.props.onDislikeUpdate(data.dislikes);
  159. }
  160. });
  161. socket.on("event:song.newRatings", data => {
  162. if (data.songId === this.props.song.songId) {
  163. this.props.onLikedUpdate(data.liked);
  164. this.props.onDislikedUpdate(data.disliked);
  165. }
  166. });
  167. });
  168. });
  169. /*setInterval(() => {
  170. if (this.props.song.exists) {
  171. this.props.dispatch(setTimeElapsed(this.props.station.paused, this.props.station.pausedAt)); // TODO Fix
  172. }
  173. }, 1000);*/
  174. }
  175. /*isInQueue = (songId, cb) => {
  176. io.getSocket((socket) => {
  177. socket.emit('stations.getQueue', this.props.stationId, data => {
  178. if (data.status === 'success') {
  179. data.queue.forEach((song) => {
  180. if (song._id === songId) {
  181. return cb(true);
  182. }
  183. });
  184. }
  185. return cb(false);
  186. });
  187. });
  188. };*/
  189. /*checkIfCanAdd = (cb) => {
  190. if (this.state.mode === "normal") return cb(false);
  191. let playlistId = this.props.selectedPlaylistObject.selectedPlaylistId;
  192. let songId = this.props.selectedPlaylistObject.addedSongId;
  193. console.log(playlistId, songId, this.props.song.songId);
  194. if (playlistId) {
  195. if (songId === this.props.song.songId) return cb(true);
  196. else if (songId === null) return cb(true);
  197. else {
  198. this.isInQueue(songId, (res) => {
  199. return cb(res);
  200. });
  201. }
  202. }
  203. }*/
  204. /*addTopToQueue = () => {
  205. console.log("ADD TOP TO QUEUE!!!");
  206. this.checkIfCanAdd((can) => {
  207. if (!can) return;
  208. let playlistId = this.props.selectedPlaylistObject.selectedPlaylistId;
  209. console.log(can);
  210. io.getSocket((socket) => {
  211. socket.emit('playlists.getFirstSong', this.props.selectedPlaylistObject.selectedPlaylistId, data => {
  212. if (data.status === 'success') {
  213. let songId = data.song.songId;
  214. if (data.song.duration < 15 * 60) {
  215. this.props.dispatch(addSong(songId));
  216. socket.emit('stations.addToQueue', this.props.station.stationId, songId, data2 => {
  217. if (data2.status === 'success') {
  218. this.moveToBottom(playlistId, songId, (data3) => {
  219. if (data3.status === 'success') {
  220. }
  221. });
  222. } else {
  223. this.messages.clearAddError("Could not automatically add top song of playlist to queue.", data2.message);
  224. }
  225. });
  226. } else {
  227. this.messages.clearAddError("Top song in playlist was too long to be added. Moving to the next song.");
  228. this.moveToBottom(playlistId, songId, (data3) => {
  229. if (data3.status === 'success') {
  230. setTimeout(() => {
  231. this.addTopToQueue();
  232. }, 2000);
  233. }
  234. });
  235. }
  236. }
  237. });
  238. });
  239. });
  240. };*/
  241. /*moveToBottom = (playlistId, songId, cb) => {
  242. io.getSocket((socket) => {
  243. socket.emit('playlists.moveSongToBottom', playlistId, songId, data => {
  244. cb(data);
  245. });
  246. });
  247. }*/
  248. /*getModeTemp = (partyEnabled, queueLocked) => {
  249. // If party enabled
  250. // If queue locked
  251. // Mode is DJ
  252. // If queue not locked
  253. // Mode party
  254. // If party not enabled
  255. // Mode is normal
  256. if (partyEnabled) {
  257. if (queueLocked) return "dj";
  258. else return "party";
  259. } else return "normal";
  260. }*/
  261. fetchOwnRatings = () => {
  262. io.getSocket((socket) => {
  263. if (!this.props.song.exists) return;
  264. socket.emit("songs.getOwnSongRatings", this.props.song.songId, (data) => {
  265. if (this.props.song.songId === data.songId) {
  266. this.props.onLikedUpdate(data.liked);
  267. this.props.onDislikedUpdate(data.disliked);
  268. }
  269. });
  270. });
  271. };
  272. isOwner = () => {
  273. if (this.props.user.loggedIn) {
  274. if (this.props.user.role === "admin") return true;
  275. if (this.props.user.userId === this.props.station.ownerId) return true;
  276. }
  277. return false;
  278. };
  279. addSongTemp = () => {
  280. io.getSocket(socket => {
  281. socket.emit('stations.addToQueue', this.props.station.stationId, '60ItHLz5WEA', data => {
  282. console.log("ATQ Res", data);
  283. });
  284. });
  285. };
  286. resumeStation = () => {
  287. io.getSocket(socket => {
  288. socket.emit("stations.resume", this.props.station.stationId, data => {
  289. // TODO Handle error/success
  290. });
  291. });
  292. };
  293. pauseStation = () => {
  294. io.getSocket(socket => {
  295. socket.emit("stations.pause", this.props.station.stationId, data => {
  296. // TODO Handle error/success
  297. });
  298. });
  299. };
  300. skipStation = () => {
  301. io.getSocket(socket => {
  302. socket.emit("stations.forceSkip", this.props.station.stationId, data => {});
  303. });
  304. }
  305. render() {
  306. const { t } = this.props;
  307. //TODO Make this not re-render a lot
  308. return (
  309. <main id="station">
  310. <Overlays t={ this.props.t } />
  311. <div id="sidebar">
  312. <button onClick={ () => { this.props.openOverlay1("users") } }><i className="material-icons">people</i></button>
  313. <button onClick={ () => { this.props.openOverlay1("queueList") } }><i className="material-icons">queue_music</i></button>
  314. <button onClick={ () => { this.props.openOverlay1("playlists") } }><i className="material-icons">library_music</i></button>
  315. <hr/>
  316. {
  317. (this.isOwner())
  318. ? (this.props.station.paused)
  319. ? <button onClick={ this.resumeStation }><i className="material-icons">play_arrow</i></button>
  320. : <button onClick={ this.pauseStation }><i className="material-icons">pause</i></button>
  321. : null
  322. }
  323. {
  324. (this.isOwner())
  325. ? <button onClick={ this.skipStation }><i className="material-icons">skip_next</i></button>
  326. : null
  327. }
  328. {
  329. (this.isOwner())
  330. ? <button onClick={ () => { this.props.openOverlay1("settings") } }><i className="material-icons">settings</i></button>
  331. : null
  332. }
  333. </div>
  334. <h1 onClick={ this.addSongTemp }>{ this.props.station.displayName }</h1>
  335. <div className={(!this.props.song.exists) ? "player-container hidden" : "player-container"}>
  336. <div className="iframe-container">
  337. <Player onRef={ ref => (this.player = ref) }/>
  338. { (this.props.station.paused) ? <div className="paused-overlay"><span>Paused</span><i className="material-icons">pause</i></div> : null }
  339. </div>
  340. <Seekerbar/>
  341. </div>
  342. { (this.props.song.exists) ? (
  343. [
  344. <div key="content" className="content">
  345. <span className="title">{ this.props.song.title }</span>
  346. <span className="artists">{ this.props.song.artists.join(", ") }</span>
  347. <Time/>
  348. <VolumeSlider/>
  349. <Ratings/>
  350. </div>,
  351. ]) : (
  352. <h1>No song playing</h1>
  353. ) }
  354. </main>
  355. );
  356. }
  357. }