Skip to content

Commit

Permalink
Add the option to shuffle playlists and swap the order of your songs. (
Browse files Browse the repository at this point in the history
…#139)

* Add the ability to choose if your playlists are shuffled upon entering the url

* Also add reordering of your videos within the queue (swaps only between videos of the same user)

* Fix code style issues with ESLint

* Fix code style issues with Prettier

* Fix eslint errors and make it build

* Fix code style issues with Prettier

---------

Co-authored-by: Lint Action <[email protected]>
  • Loading branch information
ysbrandB and lint-action authored Oct 2, 2024
1 parent e334a8d commit eda8051
Show file tree
Hide file tree
Showing 32 changed files with 3,362 additions and 3,928 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module.exports = {
commonjs: true,
es2021: true,
},
extends: ["plugin:vue/vue3-essential", "eslint:recommended"],
extends: ["eslint:recommended", "plugin:vue/vue3-recommended", "prettier"],
overrides: [],
parserOptions: {
ecmaVersion: "latest",
Expand Down
68 changes: 51 additions & 17 deletions client/src/components/CurrentQueue.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@
<label class="text-2xl text-gray-600 dark:text-white">
Queue - {{ queueDuration }}
</label>
<div class="relative" v-if="queue.length >= 1 && admin">
<div v-if="queue.length >= 1 && admin" class="relative">
<div
class="mt-4 flex rounded-md text-center text-white duration-200 md:mt-0">
<button
@click="clearQueue()"
class="bg-proto_blue rounded-l-md px-4 py-0.5 duration-200 hover:-translate-x-1 hover:-translate-y-0.5 hover:opacity-80 hover:shadow-lg">
class="bg-proto_blue rounded-l-md px-4 py-0.5 duration-200 hover:-translate-x-1 hover:-translate-y-0.5 hover:opacity-80 hover:shadow-lg"
@click="clearQueue()">
Clear queue
</button>
<button
class="bg-proto_blue rounded-r-md border-l border-l-white px-4 py-0.5 duration-200 hover:-translate-x-1 hover:-translate-y-0.5 hover:opacity-80 hover:shadow-lg"
@click="removeVideoDropDown = true"
@focusout="hideRemoveVideoDropDown"
class="bg-proto_blue rounded-r-md border-l border-l-white px-4 py-0.5 duration-200 hover:-translate-x-1 hover:-translate-y-0.5 hover:opacity-80 hover:shadow-lg">
@focusout="hideRemoveVideoDropDown">
<font-awesome-icon
:class="removeVideoDropDown ? 'rotate-180' : ''"
class="duration-300"
Expand All @@ -36,8 +36,8 @@
<li
v-for="video in usersInQueue"
:key="video.user.id"
@click="removeVideosForUser(video.user.id)"
class="hover:bg-proto_blue w-full py-1 pl-3 pr-9 text-left text-gray-600 duration-300 hover:cursor-pointer hover:text-white dark:text-white">
class="hover:bg-proto_blue w-full py-1 pl-3 pr-9 text-left text-gray-600 duration-300 hover:cursor-pointer hover:text-white dark:text-white"
@click="removeVideosForUser(video.user.id)">
{{ video.user.name }}
</li>
</ul>
Expand All @@ -46,21 +46,21 @@
</div>
<div v-else-if="!admin && userHasItemsInQueue">
<button
@click="removeVideosForUser(userID)"
class="bg-proto_blue rounded-md px-4 py-0.5 text-white duration-200 hover:-translate-x-1 hover:-translate-y-0.5 hover:opacity-80 hover:shadow-lg">
class="bg-proto_blue rounded-md px-4 py-0.5 text-white duration-200 hover:-translate-x-1 hover:-translate-y-0.5 hover:opacity-80 hover:shadow-lg"
@click="removeVideosForUser(userID)">
Remove all my videos
</button>
</div>
</div>
<div
class="scrollbar-thin scrollbar-thumb-gray-400 scrollbar-track-proto_background_gray dark:scrollbar-thumb-neutral-800 dark:scrollbar-track-proto_background_gray-dark flex max-h-[84vh] justify-center overflow-y-scroll overscroll-contain px-0">
class="scrollbar-thin scrollbar-thumb-gray-400 scrollbar-track-proto_background_gray dark:scrollbar-thumb-neutral-800 dark:scrollbar-track-proto_background_gray-dark flex max-h-[84vh] justify-center overscroll-auto px-0">
<div v-if="skeletonLoading" class="w-full">
<ul class="grid gap-2">
<SkeletonResult v-for="index in 10" :key="index" />
</ul>
</div>
<div v-if="!skeletonLoading" class="w-full">
<ul class="grid gap-2 pr-4">
<TransitionGroup name="list" tag="ul" class="grid gap-2 pr-4">
<VideoCard
v-for="(video, index) in queue"
:key="video.id"
Expand All @@ -70,10 +70,14 @@
:channel="video.channel"
:duration="video.durationFormatted"
:thumbnail="video.thumbnail.url"
:removeButton="admin || video.user.id === userID"
:videoID="video.id"
@remove-clicked="removeFromQueue([video.id])" />
</ul>
:remove-button="props.admin || video.user.id === props.userID"
:can-move-up="canMoveVideoUp(index)"
:can-move-down="canMoveVideoDown(index)"
:video-i-d="video.id"
@remove-clicked="removeFromQueue([video.id])"
@move-clicked-up="moveVideo(video.id, true)"
@move-clicked-down="moveVideo(video.id, false)" />
</TransitionGroup>
<div
v-if="!skeletonLoading && queue.length < 1"
class="mt-4 text-gray-400">
Expand Down Expand Up @@ -110,9 +114,27 @@ const props = defineProps({
type: Boolean,
default: false,
},
userID: Number,
userID: { type: Number, default: null },
});
const canMoveVideoDown = (videoIndex) => {
return queue.value.slice(videoIndex, -1).some((video) => {
return (
video.user.id === queue.value[videoIndex].user.id &&
(props.admin || video.user.id === props.userID)
);
});
};
const canMoveVideoUp = (videoIndex) => {
return queue.value.slice(0, videoIndex).some((video) => {
return (
video.user.id === queue.value[videoIndex].user.id &&
(props.admin || video.user.id === props.userID)
);
});
};
// return array of unique users in queue
const usersInQueue = computed(() => {
return queue.value.filter(
Expand All @@ -128,7 +150,6 @@ const userHasItemsInQueue = computed(() => {
const videosOfUser = queue.value.filter((video) => {
return video.user.id === props.userID;
});
console.log(videosOfUser);
return videosOfUser.length > 0;
});
Expand All @@ -151,6 +172,19 @@ async function removeFromQueue(videoIDs) {
});
}
async function moveVideo(videoID, up) {
const data = await new Promise((resolve) => {
normalSocket.emit("move-video", videoID, up, (callback) => {
resolve(callback);
});
});
emit("display-toast", {
status: data.status ?? enums.STATUS.SUCCESS,
message:
data.message ?? `Successfully moved video` + (up ? " up!" : " down!"),
});
}
async function clearQueue() {
if (!props.admin) return;
const data = await new Promise((resolve) => {
Expand Down
26 changes: 13 additions & 13 deletions client/src/components/HeaderFieldButtons.vue
Original file line number Diff line number Diff line change
@@ -1,38 +1,38 @@
<template>
<div
:class="classes"
class="display-block mr-6 ml-2 mt-auto shrink-0 justify-center">
class="display-block ml-2 mr-6 mt-auto shrink-0 justify-center">
<div v-if="name" class="my-2 text-2xl text-white">Welcome {{ name }}!</div>
<div
class="grid grid-cols-2 gap-2 sm:grid-cols-4 md:grid-cols-2 xl:grid-cols-4">
<router-link
to="/screen/admin"
v-if="adminScreen"
class="bg-proto_blue rounded-md py-2 px-4 text-center text-white duration-200 hover:-translate-x-1 hover:-translate-y-0.5 hover:opacity-80 hover:shadow-lg">
to="/screen/admin"
class="bg-proto_blue rounded-md px-4 py-2 text-center text-white duration-200 hover:-translate-x-1 hover:-translate-y-0.5 hover:opacity-80 hover:shadow-lg">
Admin screen
</router-link>
<router-link
to="/screen"
v-if="screen"
class="bg-proto_blue rounded-md py-2 px-4 text-center text-white duration-200 hover:-translate-x-1 hover:-translate-y-0.5 hover:opacity-80 hover:shadow-lg">
to="/screen"
class="bg-proto_blue rounded-md px-4 py-2 text-center text-white duration-200 hover:-translate-x-1 hover:-translate-y-0.5 hover:opacity-80 hover:shadow-lg">
Screen
</router-link>
<router-link
to="/statistics"
v-if="statistics"
class="bg-proto_blue rounded-md py-2 px-4 text-center text-white duration-200 hover:-translate-x-1 hover:-translate-y-0.5 hover:opacity-80 hover:shadow-lg">
to="/statistics"
class="bg-proto_blue rounded-md px-4 py-2 text-center text-white duration-200 hover:-translate-x-1 hover:-translate-y-0.5 hover:opacity-80 hover:shadow-lg">
Statistics
</router-link>
<router-link
to="/remote"
v-if="remote"
class="bg-proto_blue rounded-md py-2 px-4 text-center text-white duration-200 hover:-translate-x-1 hover:-translate-y-0.5 hover:opacity-80 hover:shadow-lg">
to="/remote"
class="bg-proto_blue rounded-md px-4 py-2 text-center text-white duration-200 hover:-translate-x-1 hover:-translate-y-0.5 hover:opacity-80 hover:shadow-lg">
Remote
</router-link>
<router-link
to="/soundboard"
v-if="soundboard"
class="bg-proto_blue rounded-md py-2 px-4 text-center text-white duration-200 hover:-translate-x-1 hover:-translate-y-0.5 hover:opacity-80 hover:shadow-lg">
to="/soundboard"
class="bg-proto_blue rounded-md px-4 py-2 text-center text-white duration-200 hover:-translate-x-1 hover:-translate-y-0.5 hover:opacity-80 hover:shadow-lg">
Soundboard
</router-link>
</div>
Expand Down Expand Up @@ -67,7 +67,7 @@ defineProps({
type: Boolean,
default: false,
},
name: String,
classes: String,
name: { type: String, default: "" },
classes: { type: String, default: "" },
});
</script>
24 changes: 12 additions & 12 deletions client/src/components/MasterControls.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
Master controls
</h3>
<button
@click="switchTheme"
v-if="!inProduction"
class="ml-auto flex-none rounded-md bg-gray-800 px-4 py-1 text-center text-white duration-200 hover:-translate-x-1 hover:-translate-y-0.5 hover:opacity-80 hover:shadow-lg dark:bg-gray-100 dark:text-gray-800 md:mt-0">
class="ml-auto flex-none rounded-md bg-gray-800 px-4 py-1 text-center text-white duration-200 hover:-translate-x-1 hover:-translate-y-0.5 hover:opacity-80 hover:shadow-lg dark:bg-gray-100 dark:text-gray-800 md:mt-0"
@click="switchTheme">
Switch Theme
</button>
</div>
Expand All @@ -18,12 +18,12 @@
Volume - {{ playerSettings.volume }}
</span>
<input
@change="volumeChange"
class="bg-proto_blue hover:bg-proto_blue/80 h-2 w-full appearance-none rounded-xl border border-gray-500 outline-none"
type="range"
min="0"
max="100"
:value="playerSettings.volume" />
:value="playerSettings.volume"
@change="volumeChange" />
<div class="container mt-2 flex">
<!-- Video/Radio toggle -->
<div class="flex">
Expand All @@ -33,15 +33,15 @@
</span>
</div>
<button
@click="toggleRadioProtube"
type="button"
:class="
playerSettings.playerType === enums.TYPES.RADIO
? 'bg-proto_blue'
: 'bg-proto_green'
"
class="relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
role="switch">
role="switch"
@click="toggleRadioProtube">
<span
:class="
playerSettings.playerType === enums.TYPES.RADIO
Expand All @@ -62,26 +62,26 @@
<!-- TODO: Add back button in admin controls -->
<!--<font-awesome-icon class="cursor-pointer text-2xl mx-2 text-gray-600 dark:text-white" icon="backward" />-->
<font-awesome-icon
@click="playPause"
class="cursor-pointer text-2xl text-gray-600 dark:text-white"
:icon="
playerSettings.playerMode === enums.MODES.PLAYING
? 'pause'
: 'play'
">
"
@click="playPause">
</font-awesome-icon>
<font-awesome-icon
@click="skipVideo"
class="mx-2 cursor-pointer text-2xl text-gray-600 dark:text-white"
icon="forward">
icon="forward"
@click="skipVideo">
</font-awesome-icon>
</div>
<!-- New code button -->
<div class="relative ml-auto">
<div class="absolute -right-full min-w-max">
<button
@click="resetScreenCode"
class="bg-proto_blue hover:bg-proto_blue/80 rounded-md py-1 px-2 text-sm text-white shadow-md duration-200 hover:-translate-x-1 hover:-translate-y-0.5 hover:opacity-80">
class="bg-proto_blue hover:bg-proto_blue/80 rounded-md px-2 py-1 text-sm text-white shadow-md duration-200 hover:-translate-x-1 hover:-translate-y-0.5 hover:opacity-80"
@click="resetScreenCode">
New code
</button>
</div>
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/PincodeComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ onMounted(() => {
});
socket.on("connect_error", (err) => {
if (err.message == "Invalid screencode")
if (err.message === "Invalid screencode")
processPinEntered(false, "Invalid pincode entered!");
processPinEntered(false, err);
// else processPinEntered(false, "Whoops.. Can't do anything with this response..");
Expand Down
6 changes: 3 additions & 3 deletions client/src/components/RadioScreen.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
style="width: 150px"
:src="`https://www.nederland.fm/i/l/${radio.z}.gif`" />
<div
class="from-proto_blue absolute -top-1/2 -left-1/4 -z-10 h-52 w-52 animate-[spin_3s_linear_infinite] bg-gradient-to-r via-white to-white" />
class="from-proto_blue absolute -left-1/4 -top-1/2 -z-10 h-52 w-52 animate-[spin_3s_linear_infinite] bg-gradient-to-r via-white to-white" />
</div>
<br />
<audio
Expand All @@ -19,7 +19,7 @@
height="200"></audio>
<button
v-if="playButton"
class="bg-proto_blue hover:bg-proto_blue/80 my-auto mx-auto mt-5 flex rounded-md py-1 px-2 text-white shadow-md"
class="bg-proto_blue hover:bg-proto_blue/80 mx-auto my-auto mt-5 flex rounded-md px-2 py-1 text-white shadow-md"
@click="playClick">
play audio
</button>
Expand All @@ -31,7 +31,7 @@ import { ref, onMounted, watch } from "vue";
const playButton = ref(true);
const props = defineProps({
radio: Object,
radio: { type: Object, default: null },
volume: {
type: Number,
default: -1,
Expand Down
4 changes: 2 additions & 2 deletions client/src/components/RadioStations.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
:key="radio"
class="inline-block px-3">
<div
@click="setRadio(radio.z, radio.o)"
class="h-[3.75rem] w-24 rounded-lg duration-200 hover:-translate-x-1 hover:-translate-y-0.5 hover:cursor-pointer hover:opacity-80 hover:shadow-lg">
class="h-[3.75rem] w-24 rounded-lg duration-200 hover:-translate-x-1 hover:-translate-y-0.5 hover:cursor-pointer hover:opacity-80 hover:shadow-lg"
@click="setRadio(radio.z, radio.o)">
<img
:alt="radio.o"
class="bg-proto_blue hover:bg-proto_blue/80 overflow-hidden truncate rounded-lg text-white"
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/ReconnectionHandler.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ let stopConnecting = false;
const connectionDelayS = 5;
const props = defineProps({
socket: Object,
socket: { type: Object, default: null },
maxAttempts: {
type: Number,
default: -1,
Expand Down
14 changes: 7 additions & 7 deletions client/src/components/ResultsWrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@
:views="video.viewsFormatted"
:thumbnail="video.thumbnail.url"
:clickable="video?.status === undefined ? 'show' : ''"
:videoID="video.id"
:statusIcon="video.status"
:video-i-d="video.id"
:status-icon="video.status"
@video-clicked="addVideoToQueue" />
</ul>
<button
v-if="videos.length > 17"
class="bg-proto_blue mt-4 flex-none rounded-md py-2 px-4 text-center text-white duration-200 hover:-translate-x-1 hover:-translate-y-0.5 hover:opacity-80 hover:shadow-lg"
class="bg-proto_blue mt-4 flex-none rounded-md px-4 py-2 text-center text-white duration-200 hover:-translate-x-1 hover:-translate-y-0.5 hover:opacity-80 hover:shadow-lg"
@click="$emit('nextPage')">
Get more results
</button>
Expand All @@ -38,12 +38,12 @@ import VideoCard from "@/components/VideoCard.vue";
import enums from "@/js/Enums";
import socket from "@/js/RemoteSocket";
const emit = defineEmits(["display-toast"]);
const emit = defineEmits(["display-toast", "nextPage"]);
const props = defineProps({
videos: Object,
continuationToken: String,
skeletonLoading: Boolean,
videos: { type: Object, default: null },
continuationToken: { type: String, default: "" },
skeletonLoading: { type: Boolean, default: false },
});
async function addVideoToQueue(videoID) {
Expand Down
Loading

0 comments on commit eda8051

Please sign in to comment.