| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666 | <template>	<div>		<official-header v-if="type == 'official'" />		<community-header v-if="type == 'community'" />		<song-queue v-if="modals.addSongToQueue" />		<add-to-playlist v-if="modals.addSongToPlaylist" />		<edit-playlist v-if="modals.editPlaylist" />		<create-playlist v-if="modals.createPlaylist" />		<edit-station v-show="modals.editStation" />		<report v-if="modals.report" />		<songs-list-sidebar v-if="sidebars.songslist" />		<playlist-sidebar v-if="sidebars.playlist" />		<users-sidebar v-if="sidebars.users" />		<div v-show="loading" class="progress" />		<div v-show="!loading && exists" class="station">			<div v-show="noSong" class="no-song">				<h1>No song is currently playing</h1>				<h4					v-if="						type === 'community' &&							station.partyMode &&							(!station.locked ||								(station.locked &&									$parent.loggedIn &&									$parent.userId === station.owner))					"				>					<a						href="#"						class="no-song"						@click="							toggleModal({								sector: 'station',								modal: 'addSongToQueue'							})						"						>Add a song to the queue</a					>				</h4>				<h4					v-if="						type === 'community' &&							!station.partyMode &&							$parent.userId === station.owner &&							!station.privatePlaylist					"				>					<a						href="#"						class="no-song"						@click="sidebars.playlist = true"						>Play a private playlist</a					>				</h4>				<h1					v-if="						type === 'community' &&							!station.partyMode &&							$parent.userId === station.owner &&							station.privatePlaylist					"				>					Maybe you can add some songs to your selected private					playlist and then press the skip button				</h1>			</div>			<div v-show="!noSong" class="columns">				<div					class="column is-8-desktop is-offset-2-desktop is-12-mobile"				>					<div class="video-container">						<div id="player" />					</div>					<div						id="preview-progress"						class="seeker-bar-container white"					>						<div class="seeker-bar light-blue" style="width: 0%;" />					</div>				</div>				<div					class="desktop-only column is-3-desktop card playlistCard experimental"				>					<div v-if="type === 'community'" class="title">						Queue					</div>					<div v-else class="title">						Playlist					</div>					<article v-if="!noSong" class="media">						<figure class="media-left">							<p class="image is-64x64">								<img									:src="currentSong.thumbnail"									onerror="this.src='/assets/notes-transparent.png'"								/>							</p>						</figure>						<div class="media-content">							<div class="content">								<p>									Current Song:									<br />									<strong>{{ currentSong.title }}</strong>									<br />									<small>{{ currentSong.artists }}</small>								</p>							</div>						</div>						<div class="media-right">							{{ formatTime(currentSong.duration) }}						</div>					</article>					<p v-if="noSong" class="center">						There is currently no song playing.					</p>					<article						v-for="(song, index) in songsList"						:key="index"						class="media"					>						<div class="media-content">							<div class="content">								<strong class="songTitle">{{									song.title								}}</strong>								<br />								<small>{{ song.artists.join(", ") }}</small>								<br />								<div v-if="station.partyMode">									<br />									<small>										Requested by										<b>											<user-id-to-username												:userId="song.requestedBy"												:link="true"											/>										</b>									</small>									<button										v-if="isOwnerOnly() || isAdminOnly()"										class="button"										@click="removeFromQueue(song.songId)"									>										REMOVE									</button>								</div>							</div>						</div>						<div class="media-right">							{{ formatTime(song.duration) }}						</div>					</article>					<a						v-if="type === 'community' && $parent.loggedIn"						class="button add-to-queue"						href="#"						@click="							toggleModal({								sector: 'station',								modal: 'addSongToQueue'							})						"						>Add Song to Queue</a					>				</div>			</div>			<div v-show="!noSong" class="desktop-only columns is-mobile">				<div					class="column is-8-desktop is-offset-2-desktop is-12-mobile"				>					<div class="columns is-mobile">						<div class="column is-12-desktop">							<h4 id="time-display">								{{ timeElapsed }} /								{{ formatTime(currentSong.duration) }}							</h4>							<h3>{{ currentSong.title }}</h3>							<h4 class="thin" style="margin-left: 0">								{{ currentSong.artists }}							</h4>							<div class="columns is-mobile">								<form									style="margin-top: 12px; margin-bottom: 0;"									action="#"									class="column is-7-desktop is-4-mobile"								>									<p class="volume-slider-wrapper">										<i											v-if="muted"											class="material-icons"											@click="toggleMute()"											>volume_mute</i										>										<i											v-else											class="material-icons"											@click="toggleMute()"											>volume_down</i										>										<input											id="volumeSlider"											type="range"											min="0"											max="10000"											class="active"											@change="changeVolume()"											@input="changeVolume()"										/>										<i											class="material-icons"											@click="increaseVolume()"											>volume_up</i										>									</p>								</form>								<div									class="column is-8-mobile is-5-desktop"									style="float: right;"								>									<ul										v-if="											currentSong.likes !== -1 &&												currentSong.dislikes !== -1										"										id="ratings"									>										<li											id="like"											class="right"											@click="toggleLike()"										>											<span class="flow-text">{{												currentSong.likes											}}</span>											<i												id="thumbs_up"												class="material-icons grey-text"												:class="{ liked: liked }"												>thumb_up</i											>											<a												class="absolute-a behind"												href="#"												@click="toggleLike()"											/>										</li>										<li											id="dislike"											style="margin-right: 10px;"											class="right"											@click="toggleDislike()"										>											<span class="flow-text">{{												currentSong.dislikes											}}</span>											<i												id="thumbs_down"												class="material-icons grey-text"												:class="{													disliked: disliked												}"												>thumb_down</i											>											<a												class="absolute-a behind"												href="#"												@click="toggleDislike()"											/>										</li>									</ul>								</div>							</div>						</div>						<div							v-if="!simpleSong"							class="column is-3-desktop experimental"						>							<img								class="image"								:src="currentSong.thumbnail"								alt="Song Thumbnail"								onerror="this.src='/assets/notes-transparent.png'"							/>						</div>					</div>				</div>			</div>			<div v-show="!noSong" class="mobile-only">				<div>					<div>						<div>							<h3>{{ currentSong.title }}</h3>							<h4 class="thin">								{{ currentSong.artists }}							</h4>							<h5>								{{ timeElapsed }} /								{{ formatTime(currentSong.duration) }}							</h5>							<div>								<form class="columns" action="#">									<p										class="column is-11-mobile volume-slider-wrapper"									>										<i											v-if="muted"											class="material-icons"											@click="toggleMute()"											>volume_mute</i										>										<i											v-else											class="material-icons"											@click="toggleMute()"											>volume_down</i										>										<input											id="volumeSlider"											type="range"											min="0"											max="10000"											class="active"											@change="changeVolume()"											@input="changeVolume()"										/>										<i											class="material-icons"											@click="increaseVolume()"											>volume_up</i										>									</p>								</form>								<div>									<ul										v-if="											currentSong.likes !== -1 &&												currentSong.dislikes !== -1										"										id="ratings"										style="display: inline-block;"									>										<li											id="dislike"											style="display: inline-block;margin-right: 10px;"											@click="toggleDislike()"										>											<span class="flow-text">{{												currentSong.dislikes											}}</span>											<i												id="thumbs_down"												class="material-icons grey-text"												:class="{													disliked: disliked												}"												>thumb_down</i											>											<a												class="absolute-a behind"												href="#"												@click="toggleDislike()"											/>										</li>										<li											id="like"											style="display: inline-block;"											@click="toggleLike()"										>											<span class="flow-text">{{												currentSong.likes											}}</span>											<i												id="thumbs_up"												class="material-icons grey-text"												:class="{ liked: liked }"												>thumb_up</i											>											<a												class="absolute-a behind"												href="#"												@click="toggleLike()"											/>										</li>									</ul>								</div>							</div>						</div>					</div>				</div>			</div>		</div>		<Z404 v-if="!exists"></Z404>	</div></template><script>import { mapState, mapActions } from "vuex";import { Toast } from "vue-roaster";import SongQueue from "../Modals/AddSongToQueue.vue";import AddToPlaylist from "../Modals/AddSongToPlaylist.vue";import EditPlaylist from "../Modals/Playlists/Edit.vue";import CreatePlaylist from "../Modals/Playlists/Create.vue";import EditStation from "../Modals/EditStation.vue";import Report from "../Modals/Report.vue";import SongsListSidebar from "../Sidebars/SongsList.vue";import PlaylistSidebar from "../Sidebars/Playlist.vue";import UsersSidebar from "../Sidebars/UsersList.vue";import OfficialHeader from "./OfficialHeader.vue";import CommunityHeader from "./CommunityHeader.vue";import UserIdToUsername from "../UserIdToUsername.vue";import Z404 from "../404.vue";import io from "../../io";export default {	data() {		return {			loading: true,			ready: false,			exists: true,			type: "",			playerReady: false,			previousSong: null,			currentSong: {},			player: undefined,			timePaused: 0,			paused: false,			muted: false,			timeElapsed: "0:00",			liked: false,			disliked: false,			sidebars: {				songslist: false,				users: false,				playlist: false			},			noSong: false,			simpleSong: false,			songsList: [],			timeBeforePause: 0,			skipVotes: 0,			privatePlaylistQueueSelected: null,			automaticallyRequestedSongId: null,			systemDifference: 0,			users: [],			userCount: 0		};	},	computed: {		...mapState("modals", {			modals: state => state.modals.station		}),		...mapState("station", {			station: state => state.station		})	},	methods: {		isOwnerOnly: function() {			return (				this.$parent.loggedIn &&				this.$parent.userId === this.station.owner			);		},		isAdminOnly: function() {			return this.$parent.loggedIn && this.$parent.role === "admin";		},		removeFromQueue: function(songId) {			window.socket.emit(				"stations.removeFromQueue",				this.station._id,				songId,				res => {					if (res.status === "success") {						Toast.methods.addToast(							"Successfully removed song from the queue.",							4000						);					} else Toast.methods.addToast(res.message, 8000);				}			);		},		toggleSidebar: function(type) {			Object.keys(this.sidebars).forEach(sidebar => {				if (sidebar !== type) this.sidebars[sidebar] = false;				else this.sidebars[type] = !this.sidebars[type];			});		},		youtubeReady: function() {			let local = this;			if (!local.player) {				local.player = new window.YT.Player("player", {					height: 270,					width: 480,					videoId: local.currentSong.songId,					startSeconds:						local.getTimeElapsed() / 1000 +						local.currentSong.skipDuration,					playerVars: {						controls: 0,						iv_load_policy: 3,						rel: 0,						showinfo: 0					},					events: {						onReady: function() {							local.playerReady = true;							let volume = parseInt(								localStorage.getItem("volume")							);							volume = typeof volume === "number" ? volume : 20;							local.player.setVolume(volume);							if (volume > 0) local.player.unMute();							local.playVideo();						},						onError: function(err) {							console.log("iframe error", err);							local.voteSkipStation();						},						onStateChange: function(event) {							if (								event.data === 1 &&								local.videoLoading === true							) {								local.videoLoading = false;								local.player.seekTo(									local.getTimeElapsed() / 1000 +										local.currentSong.skipDuration,									true								);								if (local.paused) local.player.pauseVideo();							} else if (event.data === 1 && local.paused) {								local.player.seekTo(									local.timeBeforePause / 1000,									true								);								local.player.pauseVideo();							}							if (								event.data === 2 &&								!local.paused &&								!local.noSong &&								local.player.getDuration() / 1000 <									local.currentSong.duration							) {								local.player.seekTo(									local.getTimeElapsed() / 1000 +										local.currentSong.skipDuration,									true								);								local.player.playVideo();							}						}					}				});			}		},		getTimeElapsed: function() {			let local = this;			if (local.currentSong) {				let timePaused = local.timePaused;				if (local.paused)					timePaused += Date.currently() - local.pausedAt;				return Date.currently() - local.startedAt - timePaused;			} else return 0;		},		playVideo: function() {			let local = this;			if (local.playerReady) {				local.videoLoading = true;				local.player.loadVideoById(					local.currentSong.songId,					local.getTimeElapsed() / 1000 +						local.currentSong.skipDuration				);				if (local.currentSong.artists)					local.currentSong.artists = local.currentSong.artists.join(						", "					);				if (window.stationInterval !== 0)					clearInterval(window.stationInterval);				window.stationInterval = setInterval(function() {					local.resizeSeekerbar();					local.calculateTimeElapsed();				}, 150);			}		},		resizeSeekerbar: function() {			let local = this;			if (!local.paused) {				document.getElementsByClassName("seeker-bar")[0].style.width =					parseFloat(						(local.getTimeElapsed() /							1000 /							local.currentSong.duration) *							100					) + "%";			}		},		formatTime: function(duration) {			let d = moment.duration(duration, "seconds");			if (duration < 0) return "0:00";			return (				(d.hours() > 0					? d.hours() < 10						? "0" + d.hours() + ":"						: d.hours() + ":"					: "") +				(d.minutes() + ":") +				(d.seconds() < 10 ? "0" + d.seconds() : d.seconds())			);		},		calculateTimeElapsed: function() {			let local = this;			if (				local.playerReady &&				local.currentSong &&				local.player.getPlayerState() === -1			) {				local.player.playVideo();			}			if (!local.paused) {				let timeElapsed = local.getTimeElapsed();				let currentPlayerTime = local.player.getCurrentTime() * 1000;				let difference = timeElapsed - currentPlayerTime;				//console.log(difference123);				if (difference < -200) {					//console.log("Difference0.8");					local.player.setPlaybackRate(0.8);				} else if (difference < -50) {					//console.log("Difference0.9");					local.player.setPlaybackRate(0.9);				} else if (difference < -25) {					//console.log("Difference0.99");					local.player.setPlaybackRate(0.99);				} else if (difference > 200) {					//console.log("Difference1.2");					local.player.setPlaybackRate(1.2);				} else if (difference > 50) {					//console.log("Difference1.1");					local.player.setPlaybackRate(1.1);				} else if (difference > 25) {					//console.log("Difference1.01");					local.player.setPlaybackRate(1.01);				} else if (local.player.getPlaybackRate !== 1.0) {					//console.log("NDifference1.0");					local.player.setPlaybackRate(1.0);				}			}			/*if (local.currentTime !== undefined && local.paused) {				local.timePaused += Date.currently() - local.currentTime;				local.currentTime = undefined;			}*/			let timePaused = local.timePaused;			if (local.paused) timePaused += Date.currently() - local.pausedAt;			let duration =				(Date.currently() - local.startedAt - timePaused) / 1000;			let songDuration = local.currentSong.duration;			if (songDuration <= duration) local.player.pauseVideo();			if (!local.paused && duration <= songDuration)				local.timeElapsed = local.formatTime(duration);		},		toggleLock: function() {			window.socket.emit("stations.toggleLock", this.station._id, res => {				if (res.status === "success") {					Toast.methods.addToast(						"Successfully toggled the queue lock.",						4000					);				} else Toast.methods.addToast(res.message, 8000);			});		},		changeVolume: function() {			let local = this;			let volume = document.getElementById("volumeSlider").value;			localStorage.setItem("volume", volume / 100);			if (local.playerReady) {				local.player.setVolume(volume / 100);				if (volume > 0) local.player.unMute();			}		},		resumeLocalStation: function() {			this.paused = false;			if (!this.noSong) {				if (this.playerReady) {					this.player.seekTo(						this.getTimeElapsed() / 1000 +							this.currentSong.skipDuration					);					this.player.playVideo();				}			}		},		pauseLocalStation: function() {			console.log("pause locally");			this.paused = true;			if (!this.noSong) {				this.timeBeforePause = this.getTimeElapsed();				if (this.playerReady) this.player.pauseVideo();			}		},		skipStation: function() {			let _this = this;			_this.socket.emit("stations.forceSkip", _this.station._id, data => {				if (data.status !== "success")					Toast.methods.addToast(`Error: ${data.message}`, 8000);				else					Toast.methods.addToast(						"Successfully skipped the station's current song.",						4000					);			});		},		voteSkipStation: function() {			let _this = this;			_this.socket.emit("stations.voteSkip", _this.station._id, data => {				if (data.status !== "success")					Toast.methods.addToast(`Error: ${data.message}`, 8000);				else					Toast.methods.addToast(						"Successfully voted to skip the current song.",						4000					);			});		},		resumeStation: function() {			let _this = this;			_this.socket.emit("stations.resume", _this.station._id, data => {				if (data.status !== "success")					Toast.methods.addToast(`Error: ${data.message}`, 8000);				else					Toast.methods.addToast(						"Successfully resumed the station.",						4000					);			});		},		pauseStation: function() {			let _this = this;			_this.socket.emit("stations.pause", _this.station._id, data => {				if (data.status !== "success")					Toast.methods.addToast(`Error: ${data.message}`, 8000);				else					Toast.methods.addToast(						"Successfully paused the station.",						4000					);			});		},		toggleMute: function() {			if (this.playerReady) {				let previousVolume = parseFloat(localStorage.getItem("volume"));				let volume =					this.player.getVolume() * 100 <= 0 ? previousVolume : 0;				this.muted = !this.muted;				document.getElementById("volumeSlider").value = volume * 100;				this.player.setVolume(volume);				if (!this.muted) localStorage.setItem("volume", volume);			}		},		increaseVolume: function() {			if (this.playerReady) {				let previousVolume = parseInt(localStorage.getItem("volume"));				let volume = previousVolume + 5;				if (previousVolume === 0) this.muted = false;				if (volume > 100) volume = 100;				document.getElementById("volumeSlider").value = volume * 100;				this.player.setVolume(volume);				localStorage.setItem("volume", volume);			}		},		toggleLike: function() {			let _this = this;			if (_this.liked)				_this.socket.emit(					"songs.unlike",					_this.currentSong.songId,					data => {						if (data.status !== "success")							Toast.methods.addToast(								`Error: ${data.message}`,								8000							);					}				);			else				_this.socket.emit(					"songs.like",					_this.currentSong.songId,					data => {						if (data.status !== "success")							Toast.methods.addToast(								`Error: ${data.message}`,								8000							);					}				);		},		toggleDislike: function() {			let _this = this;			if (_this.disliked)				return _this.socket.emit(					"songs.undislike",					_this.currentSong.songId,					data => {						if (data.status !== "success")							Toast.methods.addToast(								`Error: ${data.message}`,								8000							);					}				);			_this.socket.emit(				"songs.dislike",				_this.currentSong.songId,				data => {					if (data.status !== "success")						Toast.methods.addToast(`Error: ${data.message}`, 8000);				}			);		},		addFirstPrivatePlaylistSongToQueue: function() {			let _this = this;			let isInQueue = false;			let userId = _this.$parent.userId;			if (_this.type === "community") {				_this.songsList.forEach(queueSong => {					if (queueSong.requestedBy === userId) isInQueue = true;				});				if (!isInQueue && _this.privatePlaylistQueueSelected) {					_this.socket.emit(						"playlists.getFirstSong",						_this.privatePlaylistQueueSelected,						data => {							if (data.status === "success") {								if (data.song.duration < 15 * 60) {									_this.automaticallyRequestedSongId =										data.song.songId;									_this.socket.emit(										"stations.addToQueue",										_this.station._id,										data.song.songId,										data2 => {											if (data2.status === "success") {												_this.socket.emit(													"playlists.moveSongToBottom",													_this.privatePlaylistQueueSelected,													data.song.songId,													data3 => {														if (															data3.status ===															"success"														) {} // eslint-disable-line													}												);											}										}									);								} else {									Toast.methods.addToast(										`Top song in playlist was too long to be added.`,										3000									);									_this.socket.emit(										"playlists.moveSongToBottom",										_this.privatePlaylistQueueSelected,										data.song.songId,										data3 => {											if (data3.status === "success") {												setTimeout(() => {													this.addFirstPrivatePlaylistSongToQueue();												}, 3000);											}										}									);								}							}						}					);				}			}		},		join: function() {			let _this = this;			_this.socket.emit("stations.join", _this.stationName, res => {				if (res.status === "success") {					_this.loading = false;					const {						_id,						displayName,						description,						privacy,						locked,						partyMode,						owner,						privatePlaylist					} = res.data;					document.title = `Musare - ${displayName}`;					_this.joinStation({						_id,						name: _this.stationName,						displayName,						description,						privacy,						locked,						partyMode,						owner,						privatePlaylist					});					_this.currentSong = res.data.currentSong						? res.data.currentSong						: {};					_this.type = res.data.type;					_this.startedAt = res.data.startedAt;					_this.paused = res.data.paused;					_this.timePaused = res.data.timePaused;					_this.userCount = res.data.userCount;					_this.users = res.data.users;					_this.pausedAt = res.data.pausedAt;					if (res.data.currentSong) {						_this.noSong = false;						_this.simpleSong =							res.data.currentSong.likes === -1 &&							res.data.currentSong.dislikes === -1;						if (_this.simpleSong) {							_this.currentSong.skipDuration = 0;						}						_this.youtubeReady();						_this.playVideo();						_this.socket.emit(							"songs.getOwnSongRatings",							res.data.currentSong.songId,							data => {								if (_this.currentSong.songId === data.songId) {									_this.liked = data.liked;									_this.disliked = data.disliked;								}							}						);					} else {						if (_this.playerReady) _this.player.pauseVideo();						_this.noSong = true;					}					// UNIX client time before ping					let beforePing = Date.now();					_this.socket.emit("apis.ping", res => {						// UNIX client time after ping						let afterPing = Date.now();						// Average time in MS it took between the server responding and the client receiving						let connectionLatency = (afterPing - beforePing) / 2;						console.log(connectionLatency, beforePing - afterPing);						// UNIX server time						let serverDate = res.date;						// Difference between the server UNIX time and the client UNIX time after ping, with the connectionLatency added to the server UNIX time						let difference =							serverDate + connectionLatency - afterPing;						console.log("Difference: ", difference);						if (difference > 3000 || difference < -3000) {							console.log(								"System time difference is bigger than 3 seconds."							);						}						_this.systemDifference = difference;					});				}			});		},		...mapActions("modals", ["toggleModal"]),		...mapActions("station", ["joinStation"])	},	mounted: function() {		let _this = this;		Date.currently = () => {			return new Date().getTime() + _this.systemDifference;		};		_this.stationName = _this.$route.params.id;		window.stationInterval = 0;		io.getSocket(socket => {			_this.socket = socket;			io.removeAllListeners();			if (_this.socket.connected) _this.join();			io.onConnect(_this.join);			_this.socket.emit("stations.findByName", _this.stationName, res => {				if (res.status === "failure") {					_this.loading = false;					_this.exists = false;				} else {					_this.exists = true;				}			});			_this.socket.on("event:songs.next", data => {				_this.previousSong = _this.currentSong.songId					? _this.currentSong					: null;				_this.currentSong = data.currentSong ? data.currentSong : {};				_this.startedAt = data.startedAt;				_this.paused = data.paused;				_this.timePaused = data.timePaused;				if (data.currentSong) {					_this.noSong = false;					_this.simpleSong =						data.currentSong.likes === -1 &&						data.currentSong.dislikes === -1;					if (_this.simpleSong) _this.currentSong.skipDuration = 0;					if (!_this.playerReady) _this.youtubeReady();					else _this.playVideo();					_this.socket.emit(						"songs.getOwnSongRatings",						data.currentSong.songId,						data => {							if (_this.currentSong.songId === data.songId) {								_this.liked = data.liked;								_this.disliked = data.disliked;							}						}					);				} else {					if (_this.playerReady) _this.player.pauseVideo();					_this.noSong = true;				}				let isInQueue = false;				let userId = _this.$parent.userId;				_this.songsList.forEach(queueSong => {					if (queueSong.requestedBy === userId) isInQueue = true;				});				if (					!isInQueue &&					_this.privatePlaylistQueueSelected &&					(_this.automaticallyRequestedSongId !==						_this.currentSong.songId ||						!_this.currentSong.songId)				) {					_this.addFirstPrivatePlaylistSongToQueue();				}			});			_this.socket.on("event:stations.pause", data => {				_this.pausedAt = data.pausedAt;				_this.pauseLocalStation();				console.log("local pause");			});			_this.socket.on("event:stations.resume", data => {				_this.timePaused = data.timePaused;				_this.resumeLocalStation();			});			_this.socket.on(				"event:stations.remove",				() => (location.href = "/")			);			_this.socket.on("event:song.like", data => {				if (!this.noSong) {					if (data.songId === _this.currentSong.songId) {						_this.currentSong.dislikes = data.dislikes;						_this.currentSong.likes = data.likes;					}				}			});			_this.socket.on("event:song.dislike", data => {				if (!this.noSong) {					if (data.songId === _this.currentSong.songId) {						_this.currentSong.dislikes = data.dislikes;						_this.currentSong.likes = data.likes;					}				}			});			_this.socket.on("event:song.unlike", data => {				if (!this.noSong) {					if (data.songId === _this.currentSong.songId) {						_this.currentSong.dislikes = data.dislikes;						_this.currentSong.likes = data.likes;					}				}			});			_this.socket.on("event:song.undislike", data => {				if (!this.noSong) {					if (data.songId === _this.currentSong.songId) {						_this.currentSong.dislikes = data.dislikes;						_this.currentSong.likes = data.likes;					}				}			});			_this.socket.on("event:song.newRatings", data => {				if (!this.noSong) {					if (data.songId === _this.currentSong.songId) {						_this.liked = data.liked;						_this.disliked = data.disliked;					}				}			});			_this.socket.on("event:queue.update", queue => {				if (this.type === "community") this.songsList = queue;			});			_this.socket.on("event:song.voteSkipSong", () => {				if (this.currentSong) this.currentSong.skipVotes++;			});			_this.socket.on("event:privatePlaylist.selected", playlistId => {				if (this.type === "community") {					this.station.privatePlaylist = playlistId;				}			});			_this.socket.on("event:partyMode.updated", partyMode => {				if (this.type === "community") {					this.station.partyMode = partyMode;				}			});			_this.socket.on("event:newOfficialPlaylist", playlist => {				if (this.type === "official") {					this.songsList = playlist;				}			});			_this.socket.on("event:users.updated", users => {				_this.users = users;			});			_this.socket.on("event:userCount.updated", userCount => {				_this.userCount = userCount;			});			_this.socket.on("event:queueLockToggled", locked => {				_this.station.locked = locked;			});		});		let volume = parseFloat(localStorage.getItem("volume"));		volume = typeof volume === "number" && !isNaN(volume) ? volume : 20;		localStorage.setItem("volume", volume);		document.getElementById("volumeSlider").value = volume * 100;	},	components: {		OfficialHeader,		CommunityHeader,		SongQueue,		AddToPlaylist,		EditPlaylist,		CreatePlaylist,		EditStation,		Report,		SongsListSidebar,		PlaylistSidebar,		UsersSidebar,		UserIdToUsername,		Z404	}};</script><style lang="scss">.no-song {	color: #03a9f4;	text-align: center;}#volumeSlider {	padding: 0 15px;	background: transparent;}.volume-slider-wrapper {	margin-top: 0;	position: relative;	display: flex;	align-items: center;	.material-icons {		user-select: none;	}}.material-icons {	cursor: pointer;}.stationDisplayName {	color: white !important;}.add-to-playlist {	display: flex;	align-items: center;	justify-content: center;}.slideout {	top: 50px;	height: 100%;	position: fixed;	right: 0;	width: 350px;	background-color: white;	box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16),		0 2px 10px 0 rgba(0, 0, 0, 0.12);	.slideout-header {		text-align: center;		background-color: rgb(3, 169, 244) !important;		margin: 0;		padding-top: 5px;		padding-bottom: 7px;		color: white;	}	.slideout-content {		height: 100%;	}}.modal-large {	width: 75%;}.station {	flex: 1 0 auto;	padding-top: 0.5vw;	transition: all 0.1s;	margin: 0 auto;	max-width: 100%;	width: 90%;	@media only screen and (min-width: 993px) {		width: 70%;	}	@media only screen and (min-width: 601px) {		width: 85%;	}	@media (min-width: 999px) {		.mobile-only {			display: none;		}		.desktop-only {			display: block;		}	}	@media (max-width: 998px) {		.mobile-only {			display: block;		}		.desktop-only {			display: none;			visibility: hidden;		}	}	.mobile-only {		text-align: center;	}	.playlistCard {		margin: 10px;		position: relative;		padding-bottom: calc(31.25% + 7px);		height: 0;		overflow-y: scroll;		.title {			background-color: rgb(3, 169, 244);			text-align: center;			padding: 10px;			color: white;			font-weight: 600;		}		.media {			padding: 0 25px;		}		.media-content .content {			min-height: 64px;			max-height: 64px;			display: flex;			align-items: center;		}		.content p strong {			word-break: break-word;		}		.content p small {			word-break: break-word;		}		.add-to-queue {			width: 100%;			margin-top: 25px;			height: 40px;			border-radius: 0;			background: rgb(3, 169, 244);			color: #fff !important;			border: 0;			&:active,			&:focus {				border: 0;			}		}		.add-to-queue:focus {			background: #029ce3;		}		.media-right {			line-height: 64px;		}		.songTitle {			word-wrap: break-word;			overflow: hidden;			text-overflow: ellipsis;			display: -webkit-box;			-webkit-box-orient: vertical;			-webkit-line-clamp: 2;			line-height: 20px;			max-height: 40px;			width: 100%;		}	}	input[type="range"] {		-webkit-appearance: none;		width: 100%;		margin: 7.3px 0;	}	input[type="range"]:focus {		outline: none;	}	input[type="range"]::-webkit-slider-runnable-track {		width: 100%;		height: 5.2px;		cursor: pointer;		box-shadow: 0;		background: #c2c0c2;		border-radius: 0;		border: 0;	}	input[type="range"]::-webkit-slider-thumb {		box-shadow: 0;		border: 0;		height: 19px;		width: 19px;		border-radius: 15px;		background: #03a9f4;		cursor: pointer;		-webkit-appearance: none;		margin-top: -6.5px;	}	input[type="range"]::-moz-range-track {		width: 100%;		height: 5.2px;		cursor: pointer;		box-shadow: 0;		background: #c2c0c2;		border-radius: 0;		border: 0;	}	input[type="range"]::-moz-range-thumb {		box-shadow: 0;		border: 0;		height: 19px;		width: 19px;		border-radius: 15px;		background: #03a9f4;		cursor: pointer;		-webkit-appearance: none;		margin-top: -6.5px;	}	input[type="range"]::-ms-track {		width: 100%;		height: 5.2px;		cursor: pointer;		box-shadow: 0;		background: #c2c0c2;		border-radius: 1.3px;	}	input[type="range"]::-ms-fill-lower {		background: #c2c0c2;		border: 0;		border-radius: 0;		box-shadow: 0;	}	input[type="range"]::-ms-fill-upper {		background: #c2c0c2;		border: 0;		border-radius: 0;		box-shadow: 0;	}	input[type="range"]::-ms-thumb {		box-shadow: 0;		border: 0;		height: 15px;		width: 15px;		border-radius: 15px;		background: #03a9f4;		cursor: pointer;		-webkit-appearance: none;		margin-top: 1.5px;	}	.video-container {		position: relative;		padding-bottom: 56.25%;		height: 0;		overflow: hidden;		iframe {			position: absolute;			top: 0;			left: 0;			width: 100%;			height: 100%;		}	}	.video-col {		padding-right: 0.75rem;		padding-left: 0.75rem;	}}.room-title {	left: 50%;	-webkit-transform: translateX(-50%);	transform: translateX(-50%);	font-size: 2.1em;}#ratings {	span {		font-size: 1.68rem;	}	i {		color: #9e9e9e !important;		cursor: pointer;		transition: 0.1s color;	}}#time-display {	margin-top: 30px;	float: right;}#thumbs_up:hover,#thumbs_up.liked {	color: #87d37c !important;}#thumbs_down:hover,#thumbs_down.disliked {	color: #ec644b !important;}#song-thumbnail {	max-width: 100%;	width: 85%;}.seeker-bar-container {	position: relative;	height: 7px;	display: block;	width: 100%;	overflow: hidden;}.seeker-bar {	top: 0;	left: 0;	bottom: 0;	position: absolute;}ul {	list-style: none;	margin: 0;	display: block;}h1,h2,h3,h4,h5,h6 {	font-weight: 400;	line-height: 1.1;}h1 a,h2 a,h3 a,h4 a,h5 a,h6 a {	font-weight: inherit;}h1 {	font-size: 4.2rem;	line-height: 110%;	margin: 2.1rem 0 1.68rem 0;}h2 {	font-size: 3.56rem;	line-height: 110%;	margin: 1.78rem 0 1.424rem 0;}h3 {	font-size: 2.92rem;	line-height: 110%;	margin: 1.46rem 0 1.168rem 0;}h4 {	font-size: 2.28rem;	line-height: 110%;	margin: 1.14rem 0 0.912rem 0;}h5 {	font-size: 1.64rem;	line-height: 110%;	margin: 0.82rem 0 0.656rem 0;}h6 {	font-size: 1rem;	line-height: 110%;	margin: 0.5rem 0 0.4rem 0;}.thin {	font-weight: 200;}.left {	float: left !important;}.right {	float: right !important;}.light-blue {	background-color: #03a9f4 !important;}.white {	background-color: #ffffff !important;}.btn-search {	font-size: 14px;}.menu {	padding: 0 10px;}.menu-list li a:hover {	color: #000 !important;}.menu-list li {	display: flex;	justify-content: space-between;}.menu-list a {	/*padding: 0 10px !important;*/}.menu-list a:hover {	background-color: transparent;}.icons-group {	display: flex;}#like,#dislike {	position: relative;}.behind {	z-index: -1;}.behind:focus {	z-index: 0;}.progress {	width: 50px;	animation: rotate 0.8s infinite linear;	border: 8px solid #03a9f4;	border-right-color: transparent;	height: 50px;	position: absolute;	top: 50%;	left: 50%;}@keyframes rotate {	0% {		transform: rotate(0deg);	}	100% {		transform: rotate(360deg);	}}.experimental {	display: none !important;}</style>
 |