mirror of
https://gitlab.science.ru.nl/technicie/MarietjeDjango.git
synced 2025-12-09 18:52:23 +01:00
752 lines
37 KiB
HTML
752 lines
37 KiB
HTML
{% extends "marietje/base.html" %}
|
|
{% load static %}
|
|
|
|
{% block title %}Queue{% endblock %}
|
|
|
|
{% block content %}
|
|
<nav class="navbar navbar-expand navbar-default navbar-light border-bottom">
|
|
<div class="container-lg">
|
|
<ul class="nav nav-pills" role="tablist">
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link active" id="queue-tab" data-bs-toggle="tab" data-bs-target="#queue"
|
|
type="button" role="tab" aria-controls="queue" aria-selected="true">Queue
|
|
</button>
|
|
</li>
|
|
<li class="nav-item me-3" role="presentation">
|
|
<button onclick="request_vue.select_textinput()" class="nav-link" id="request-tab" data-bs-toggle="tab" data-bs-target="#request"
|
|
type="button" role="tab" aria-controls="request" aria-selected="false">Request
|
|
</button>
|
|
</li>
|
|
<li id="infobar-buttons" class="nav-item d-flex justify-content-center align-items-center">
|
|
{% if perms.queues.can_control_volume %}
|
|
<button type="button" id="mute" class="btn nav-btn btn-sm block-button" onclick="mute();">
|
|
<i class="fa-solid fa-volume-xmark"></i>
|
|
</button>
|
|
<button type="button" id="volume_down" class="btn navbar-btn btn-sm block-button"
|
|
onclick="volume_down();">
|
|
<i class="fa-solid fa-volume-low"></i>
|
|
</button>
|
|
<button type="button" id="volume_up" class="btn navbar-btn btn-sm block-button"
|
|
onclick="volume_up();">
|
|
<i class="fa-solid fa-volume-high"></i>
|
|
</button>
|
|
{% endif %}
|
|
{% if perms.queues.can_skip %}
|
|
<button type="button" id="skip" class="btn navbar-btn btn-sm block-button" onclick="skip();">
|
|
<i class="fa-solid fa-forward-fast"></i>
|
|
</button>
|
|
{% endif %}
|
|
</li>
|
|
</ul>
|
|
|
|
<ul id="personal-queue-container" class="navbar-nav navbar-right hidden-xs">
|
|
<template v-if="infobar !== null && 'start_personal_queue' in infobar && infobar.start_personal_queue !== null">
|
|
<li v-if="infobar.start_personal_queue !== 0" class="nav-item me-3">
|
|
<p v-if="infobar.plays_in" class="navbar-text mb-0 start-queue hidden-sm hidden-xs">
|
|
First song starts in ${ infobar.start_personal_queue.secondsToMMSS() }$
|
|
</p>
|
|
<p v-else class="navbar-text mb-0 start-queue hidden-sm hidden-xs">
|
|
First song starts at ${ (infobar.now_in_seconds + infobar.start_personal_queue).timestampToHHMMSS() }$
|
|
</p>
|
|
</li>
|
|
<li class="nav-item me-3">
|
|
<p v-if="infobar.plays_in" class="navbar-text mb-0 start-queue hidden-sm hidden-xs">
|
|
Last song ends in ${ infobar.end_personal_queue.secondsToMMSS() }$
|
|
</p>
|
|
<p v-else class="navbar-text mb-0 start-queue hidden-sm hidden-xs">
|
|
Last song ends at ${ (infobar.now_in_seconds + infobar.end_personal_queue).timestampToHHMMSS() }$
|
|
</p>
|
|
</li>
|
|
<li class="nav-item">
|
|
<p class="navbar-text mb-0 duration-queue" v-bind:class="{danger: infobar.length_personal_queue > infobar.max_length * 60}">(${ infobar.length_personal_queue.secondsToMMSS() }$)</p>
|
|
</li>
|
|
</template>
|
|
</ul>
|
|
</div>
|
|
</nav>
|
|
<div class="container-lg">
|
|
<br><br>
|
|
<div class="alert-location">
|
|
</div>
|
|
<div class="tab-content">
|
|
<div class="tab-pane fade show active" id="queue" role="tabpanel" aria-labelledby="queue-tab">
|
|
<div id="queue-container">
|
|
<table class="table table-striped">
|
|
<thead>
|
|
<tr class="table-header-style underline_cell">
|
|
<td class="col-md-4">Artist</td>
|
|
<td class="col-md-4">Title</td>
|
|
<td class="col-md-2 d-sm-table-cell d-none">Requested By</td>
|
|
<td class="col-md-1 text-info d-sm-table-cell d-none" style="cursor: pointer;">
|
|
<span v-if="playsIn" class="btn btn-link p-0" v-on:click="playsIn = false">Plays In</span>
|
|
<span v-else class="btn btn-link p-0" v-on:click="playsIn = true">Plays At</span>
|
|
</td>
|
|
<td class="col-md-1">
|
|
<span class="control-icons">Control</span>
|
|
<span v-if="playsIn" class="btn btn-link p-0 d-sm-none" v-on:click="toggle_details(song)">(Plays in)</span>
|
|
<span v-else class="btn btn-link p-0 d-sm-none" v-on:click="toggle_details(song)">(Plays At)</span>
|
|
</td>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="queuebody">
|
|
<template v-for="(song, index) in queue">
|
|
<tr :class="{ marietjequeue: (song.user === null),
|
|
underline_cell: (index === queue[-1]),
|
|
currentsong: (index === 0),
|
|
ownsong: (this.user_data.id === song.user?.id && index !== 0),
|
|
}"
|
|
v-on:click="toggle_details(song)">
|
|
<td>
|
|
<span class="artist">${ song.song.artist }$</span>
|
|
<span v-if="show_details(song)" class="requested-by d-sm-none d-block small mt-3 fw-normal">
|
|
Requested by:<br>
|
|
<template v-if="song.user === null">
|
|
Marietje
|
|
</template>
|
|
<template v-else>
|
|
${ song.user.name }$
|
|
</template>
|
|
</span>
|
|
</td>
|
|
<td>
|
|
<span class="title">${ song.song.title }$</span>
|
|
<span v-if="show_details(song) && song.time_until_song_seconds > 0" class="plays-at d-sm-none d-block small mt-3 fw-normal" style="text-align: right">
|
|
<span v-if="playsIn">Plays In:</span>
|
|
<span v-else>Plays At:</span>
|
|
<br>
|
|
<template v-if="song.time_until_song_seconds !== null && song.time_until_song_seconds > 0 && playsIn === true">
|
|
${ song.time_until_song_seconds.secondsToMMSS() }$
|
|
</template>
|
|
<template v-else-if="playsIn === false && song.plays_at !== null && song.played === false">
|
|
${ song.plays_at.timestampToHHMMSS() }$
|
|
</template>
|
|
</span>
|
|
</td>
|
|
<td class="d-sm-table-cell d-none requested-by">
|
|
<template v-if="song.user === null">
|
|
Marietje
|
|
</template>
|
|
<template v-else>
|
|
${ song.user.name }$
|
|
</template>
|
|
</td>
|
|
<td class="d-sm-table-cell d-none plays-at" style="text-align: right">
|
|
<template v-if="song.time_until_song_seconds !== null && song.time_until_song_seconds > 0 && playsIn === true">
|
|
${ song.time_until_song_seconds.secondsToMMSS() }$
|
|
</template>
|
|
<template v-else-if="playsIn === false && song.plays_at !== null && song.played === false">
|
|
${ song.plays_at.timestampToHHMMSS() }$
|
|
</template>
|
|
</td>
|
|
<td>
|
|
<div class="d-flex flex-column">
|
|
<div class="d-flex flex-row">
|
|
<button v-if="song.can_move_up" v-on:click="move_down(queue[index-1].id)"
|
|
class="btn btn-link p-1 p-md-2"><i class="fa-solid fa-arrow-up"></i></button>
|
|
<button v-else class="btn btn-link invisible p-1 p-md-2"><i class="fa-solid fa-arrow-up"></i></button>
|
|
|
|
<button v-if="song.can_move_down" v-on:click="move_down(song.id)"
|
|
class="btn btn-link p-1 p-md-2"><i class="fa-solid fa-arrow-down"></i></button>
|
|
<button v-else class="btn btn-link invisible p-1 p-md-2"><i class="fa-solid fa-arrow-down"></i></button>
|
|
|
|
<button v-if="song.can_delete" v-on:click="cancel_song(song.id)"
|
|
class="btn btn-link p-1 p-md-2"><i class="fa-solid fa-trash-can"></i></button>
|
|
<button v-else class="btn btn-link invisible p-1 p-md-2"><i class="fa-solid fa-trash-can"></i></button>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</template>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="tab-pane fade" id="request" role="tabpanel" aria-labelledby="request-tab">
|
|
<div id="request-container" class="table-responsive">
|
|
<table id="request-table" class="table table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th>Artist</th>
|
|
<th>Title</th>
|
|
<th>Uploader</th>
|
|
<th>Length</th>
|
|
<th>Report</th>
|
|
</tr>
|
|
<tr>
|
|
<th colspan="5"><input id="search-all" class="search-input" type="text" ref="search_textinput"
|
|
v-model="search_input"/></th>
|
|
</tr>
|
|
</thead>
|
|
<tfoot>
|
|
<tr>
|
|
<th colspan="3" class="ts-pager form-horizontal">
|
|
<button v-if="page_number === 1" type="button" class="btn first disabled"><i
|
|
class="fa-solid fa-backward-fast"></i></button>
|
|
<button v-else v-on:click="update_page(1);" type="button" class="btn first"><i
|
|
class="fa-solid fa-backward-fast"></i></button>
|
|
|
|
<button v-if="page_number === 1" type="button" class="btn prev disabled"><i
|
|
class="fa-solid fa-backward"></i></button>
|
|
<button v-else v-on:click="update_page(page_number - 1);" type="button"
|
|
class="btn prev"><i class="fa-solid fa-backward"></i></button>
|
|
|
|
<button v-if="page_number === number_of_pages" type="button" class="btn next disabled">
|
|
<i class="fa-solid fa-forward"></i></button>
|
|
<button v-else v-on:click="update_page(page_number + 1);" type="button"
|
|
class="btn next"><i class="fa-solid fa-forward"></i></button>
|
|
|
|
<button v-if="page_number === number_of_pages" type="button" class="btn last disabled">
|
|
<i class="fa-solid fa-forward-fast"></i></button>
|
|
<button v-else v-on:click="update_page(number_of_pages);" type="button"
|
|
class="btn last"><i class="fa-solid fa-forward-fast"></i></button>
|
|
|
|
<select class="pagesize input-mini" title="Select page size" v-model="page_size">
|
|
<option value="10">10</option>
|
|
<option value="25">25</option>
|
|
<option value="50">50</option>
|
|
<option value="100">100</option>
|
|
<option value="500">500</option>
|
|
<option value="1000">1000</option>
|
|
</select>
|
|
<select class="pagenum input-mini" title="Select page number" v-model="page_number">
|
|
<template v-for="(i, index) in number_of_pages">
|
|
<option :value="i">${ i }$</option>
|
|
</template>
|
|
</select>
|
|
</th>
|
|
<th colspan="2"></th>
|
|
</tr>
|
|
</tfoot>
|
|
<tbody>
|
|
<template v-for="(song, index) in songs">
|
|
<tr>
|
|
<td>
|
|
${ song.artist }$
|
|
</td>
|
|
<td>
|
|
<button v-on:click="request_song(song.id);" class="btn btn-link p-0 text-decoration-none" style="text-align: left">${ song.title }$</button>
|
|
</td>
|
|
<td>
|
|
<template v-if="song.user === null">
|
|
Marietje
|
|
</template>
|
|
<template v-else>
|
|
${ song.user.name }$
|
|
</template>
|
|
</td>
|
|
<td>
|
|
${ song.duration.secondsToMMSS() }$
|
|
</td>
|
|
<td>
|
|
<button v-on:click="report_song(song.id);" class="btn btn-link p-0 text-decoration-none">
|
|
⚑
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
</template>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block js %}
|
|
<script type="text/javascript">
|
|
const CAN_SKIP = {{ perms.queues.can_skip|yesno:"1,0" }};
|
|
const CAN_CANCEL = {{ perms.queues.can_cancel|yesno:"1,0" }};
|
|
const CAN_MOVE = {{ perms.queues.can_move|yesno:"1,0" }};
|
|
</script>
|
|
<script>
|
|
const personal_queue_vue = createApp({
|
|
delimiters: ['${', '}$'],
|
|
data() {
|
|
return {
|
|
infobar: null,
|
|
}
|
|
},
|
|
}).mount('#personal-queue-container');
|
|
const queue_vue = createApp({
|
|
delimiters: ['${', '}$'],
|
|
data() {
|
|
return {
|
|
current_song: null,
|
|
queue: [],
|
|
user_data: null,
|
|
refreshing: true,
|
|
refreshTimer: null,
|
|
clockInterval: null,
|
|
started_at: null,
|
|
playsIn: true,
|
|
songs_show_details_on_mobile: [],
|
|
}
|
|
},
|
|
watch: {
|
|
playsIn: {
|
|
handler(val, oldVal) {
|
|
setCookie("PLAYS_IN", this.playsIn, 14);
|
|
}
|
|
},
|
|
},
|
|
mounted() {
|
|
this.clockInterval = setInterval(this.update_song_times, 1000);
|
|
|
|
const stored_playsIn = getCookie("PLAYS_IN");
|
|
this.playsIn = (stored_playsIn !== "false");
|
|
},
|
|
unmounted() {
|
|
clearInterval(this.clockInterval);
|
|
},
|
|
created() {
|
|
fetch('/api/v1/users/me/').then(response => {
|
|
if (response.status === 200) {
|
|
return response.json();
|
|
} else {
|
|
throw response;
|
|
}
|
|
}).then(data => {
|
|
this.user_data = data;
|
|
}).then(() => {
|
|
this.refreshing = false;
|
|
this.refresh();
|
|
}).catch(() => {
|
|
tata.error('', 'User details failed to fetch, please reload this page to try again.');
|
|
}).finally(() => {
|
|
this.refreshing = false;
|
|
});
|
|
},
|
|
computed: {
|
|
play_next_song_at() {
|
|
if (this.started_at !== null && this.current_song !== null) {
|
|
return this.started_at + this.current_song.song.duration;
|
|
}
|
|
return null;
|
|
}
|
|
},
|
|
methods: {
|
|
update_song_times() {
|
|
const now_in_seconds = Math.round((new Date()).getTime() / 1000);
|
|
let total_song_length = 0;
|
|
for (let i = 0; i < this.queue.length; i++) {
|
|
if (this.started_at === null) {
|
|
this.queue[i].time_until_song_seconds = null;
|
|
this.queue[i].plays_at = null;
|
|
this.queue[i].played = false;
|
|
} else {
|
|
this.queue[i].time_until_song_seconds = total_song_length;
|
|
this.queue[i].plays_at = now_in_seconds + total_song_length;
|
|
this.queue[i].played = this.queue[i].plays_at <= now_in_seconds;
|
|
if (i === 0) {
|
|
total_song_length += this.queue[i].song.duration - (now_in_seconds - this.started_at);
|
|
} else {
|
|
total_song_length += this.queue[i].song.duration;
|
|
}
|
|
}
|
|
}
|
|
this.update_infobar();
|
|
},
|
|
update_infobar() {
|
|
let infoBar = {
|
|
start_personal_queue: null,
|
|
length_personal_queue: 0,
|
|
length_total_queue: 0,
|
|
end_personal_queue: 0,
|
|
max_length: 45,
|
|
plays_in: this.playsIn,
|
|
now_in_seconds: 0,
|
|
}
|
|
infoBar.now_in_seconds = Math.round((new Date()).getTime() / 1000);
|
|
// If the current song is the current user's, their queue has started.
|
|
if (this.queue[0].user?.id === this.user_data.id) {
|
|
infoBar.start_personal_queue = 0;
|
|
}
|
|
for (let i = 0; i < this.queue.length; i++) {
|
|
const current_song = this.queue[i];
|
|
if (i === 0) {
|
|
const current_song_remaining_seconds = current_song.song.duration - this.queue[1].time_until_song_seconds;
|
|
infoBar['length_personal_queue'] -= current_song_remaining_seconds;
|
|
infoBar['length_total_queue'] -= current_song_remaining_seconds;
|
|
}
|
|
infoBar['length_total_queue'] += current_song.song.duration;
|
|
if (current_song.user !== null && current_song.user.id === this.user_data.id) {
|
|
infoBar['length_personal_queue'] += current_song.song.duration;
|
|
infoBar['end_personal_queue'] = infoBar['length_total_queue'];
|
|
if (infoBar['start_personal_queue'] === null) {
|
|
infoBar['start_personal_queue'] = infoBar['length_total_queue'] - current_song.song.duration - this.queue[1].time_until_song_seconds;
|
|
}
|
|
}
|
|
}
|
|
personal_queue_vue.infobar = infoBar;
|
|
},
|
|
refresh() {
|
|
if (!this.refreshing) {
|
|
this.refreshing = true;
|
|
clearTimeout(this.refreshTimer);
|
|
fetch('/api/v1/queues/current/').then(response => {
|
|
if (response.status === 200) {
|
|
return response.json();
|
|
} else {
|
|
throw response;
|
|
}
|
|
}).then(data => {
|
|
this.current_song = data.current_song;
|
|
this.started_at = Math.round((new Date(data.started_at).getTime()) / 1000);
|
|
let newQueue = data.queue;
|
|
newQueue.unshift(this.current_song);
|
|
newQueue = this.annotateQueue(newQueue);
|
|
clearInterval(this.clockInterval);
|
|
this.queue = newQueue;
|
|
this.update_song_times();
|
|
this.clockInterval = setInterval(this.update_song_times, 1000);
|
|
|
|
}).finally(() => {
|
|
this.refreshing = false;
|
|
this.refreshTimer = setTimeout(this.refresh, 10000);
|
|
});
|
|
}
|
|
},
|
|
annotateQueue(queue) {
|
|
for (let i = 0; i < queue.length; i++) {
|
|
const can_delete_previous = i === 0 || i === 1 ? false : queue[i - 1].can_delete;
|
|
const previous_requested_by_user = i === 0 || i === 1 ? false : queue[i - 1].user !== null;
|
|
const requested_by_marietje = queue[i].user === null;
|
|
const next_is_marietje = i < queue.length - 1 && queue[i].user !== null && queue[i + 1].user === null;
|
|
queue[i].can_delete = i !== 0 && (CAN_MOVE || (queue[i].user !== null && queue[i].user.id === this.user_data.id));
|
|
queue[i].can_move_up = i !== 0 && ((CAN_MOVE && previous_requested_by_user && queue[i].user !== null) ||
|
|
(CAN_MOVE && !previous_requested_by_user && queue[i].user === null) ||
|
|
(can_delete_previous && !requested_by_marietje && previous_requested_by_user));
|
|
queue[i].can_move_down = i !== 0 && ((CAN_MOVE && !next_is_marietje && i < queue.length - 1) ||
|
|
(queue[i].can_delete && requested_by_marietje && next_is_marietje && i < queue.length - 1));
|
|
queue[i].plays_at = null;
|
|
queue[i].time_until_song_seconds = null;
|
|
queue[i].played = false;
|
|
}
|
|
return queue;
|
|
},
|
|
cancel_song(id) {
|
|
fetch(
|
|
'/api/v1/queues/playlist-song/' + id + '/cancel/',
|
|
{
|
|
method: "DELETE",
|
|
headers: {
|
|
"X-CSRFToken": CSRF_TOKEN,
|
|
"Accept": 'application/json',
|
|
"Content-Type": 'application/json',
|
|
},
|
|
}
|
|
).then(() => {
|
|
tata.success("", "Removed song from the queue.");
|
|
}).catch(() => {
|
|
tata.error("", "An error occurred while removing the song, please try again.");
|
|
}).finally(() => {
|
|
this.refresh();
|
|
});
|
|
},
|
|
move_down(id) {
|
|
fetch(
|
|
'/api/v1/queues/playlist-song/' + id + '/move-down/',
|
|
{
|
|
method: "PATCH",
|
|
headers: {
|
|
"X-CSRFToken": CSRF_TOKEN,
|
|
"Accept": 'application/json',
|
|
"Content-Type": 'application/json',
|
|
},
|
|
}
|
|
).then(() => {
|
|
tata.success("", "Song was moved successfully.");
|
|
}).catch(() => {
|
|
tata.error("", "An error occurred while moving the song, please try again.");
|
|
}).finally(() => {
|
|
this.refresh();
|
|
});
|
|
},
|
|
show_details(song) {
|
|
return this.songs_show_details_on_mobile.includes(song.id);
|
|
},
|
|
toggle_details(song) {
|
|
if (!this.show_details(song)) {
|
|
this.songs_show_details_on_mobile.push(song.id);
|
|
} else {
|
|
// Deze filter is gehaat door Kees, gemaakt door Olaf. Bedankt, Olaf. Duurde wel even.
|
|
this.songs_show_details_on_mobile = this.songs_show_details_on_mobile.filter(
|
|
value => value !== song.id
|
|
);
|
|
}
|
|
},
|
|
}
|
|
}).mount("#queue-container");
|
|
</script>
|
|
<script>
|
|
const request_vue = createApp({
|
|
delimiters: ['${', '}$'],
|
|
data() {
|
|
return {
|
|
songs: [],
|
|
total_songs: 0,
|
|
search_input: "",
|
|
typing_timer: null,
|
|
page_size: 10,
|
|
page_number: 1,
|
|
}
|
|
},
|
|
watch: {
|
|
search_input: {
|
|
handler(val, oldVal) {
|
|
clearTimeout(this.typing_timer);
|
|
if (this.search !== "") {
|
|
this.typing_timer = setTimeout(this.search, 200);
|
|
}
|
|
}
|
|
},
|
|
page_number: {
|
|
handler(val, oldVal) {
|
|
if (this.page_number <= 0) {
|
|
this.page_number = 1;
|
|
}
|
|
if (this.page_number > this.number_of_pages) {
|
|
this.page_number = this.number_of_pages;
|
|
}
|
|
this.search();
|
|
}
|
|
},
|
|
page_size: {
|
|
handler(val, oldVal) {
|
|
if (this.page_size <= 0) {
|
|
this.page_size = 10;
|
|
}
|
|
this.page_number = 1;
|
|
setCookie("REQUEST_PAGE_SIZE", this.page_size, 14);
|
|
this.search();
|
|
}
|
|
}
|
|
},
|
|
computed: {
|
|
number_of_pages: function () {
|
|
return Math.ceil(this.total_songs / this.page_size);
|
|
}
|
|
},
|
|
created() {
|
|
fetch(
|
|
`/api/v1/songs/?ordering=artist,title&limit=${this.page_size}&offset=${this.page_size * (this.page_number - 1)}`
|
|
).then(response => {
|
|
if (response.status === 200) {
|
|
return response.json();
|
|
} else {
|
|
throw response;
|
|
}
|
|
}).then(data => {
|
|
this.songs = data.results;
|
|
this.total_songs = data.count;
|
|
}).catch((e) => {
|
|
if (e instanceof Response) {
|
|
e.json().then(data => {
|
|
tata.error("", data.errorMessage);
|
|
});
|
|
} else {
|
|
tata.error("", "An unknown error occurred, please try again.")
|
|
}
|
|
});
|
|
const stored_page_size = parseInt(getCookie("REQUEST_PAGE_SIZE"));
|
|
if (stored_page_size !== Number.NaN && stored_page_size > 0) {
|
|
this.page_size = stored_page_size;
|
|
}
|
|
},
|
|
methods: {
|
|
search() {
|
|
fetch(
|
|
`/api/v1/songs/?ordering=artist,title&limit=${this.page_size}&offset=${this.page_size * (this.page_number - 1)}&search=${this.search_input}`,
|
|
{
|
|
headers: {
|
|
"X-CSRFToken": CSRF_TOKEN,
|
|
}
|
|
}
|
|
).then(response => {
|
|
if (response.status === 200) {
|
|
return response.json();
|
|
} else {
|
|
throw response;
|
|
}
|
|
}).then(data => {
|
|
this.songs = data.results;
|
|
this.total_songs = data.count;
|
|
}).catch((e) => {
|
|
if (e instanceof Response) {
|
|
e.json().then(data => {
|
|
tata.error("", data.errorMessage);
|
|
});
|
|
} else {
|
|
tata.error("", "An unknown error occurred, please try again.")
|
|
}
|
|
});
|
|
},
|
|
|
|
request_song(song_id) {
|
|
fetch('/api/v1/queues/current/request/', {
|
|
method: 'POST',
|
|
body: JSON.stringify({
|
|
song: song_id
|
|
}),
|
|
headers: {
|
|
"X-CSRFToken": CSRF_TOKEN,
|
|
"Accept": 'application/json',
|
|
"Content-Type": 'application/json',
|
|
},
|
|
}).then(response => {
|
|
if (response.status === 200) {
|
|
return response.json();
|
|
} else {
|
|
throw response;
|
|
}
|
|
}).then(() => {
|
|
tata.success('', 'Song added to the queue.');
|
|
queue_vue.refresh();
|
|
}).catch(e => {
|
|
if (e instanceof Response) {
|
|
e.json().then(data => {
|
|
tata.error('', data.errorMessage);
|
|
})
|
|
} else {
|
|
tata.error('', "An unknown exception occurred.")
|
|
}
|
|
});
|
|
},
|
|
|
|
report_song(song_id) {
|
|
let message = prompt("What is wrong with the song?");
|
|
if (message === null) {
|
|
return;
|
|
}
|
|
if (message === "") {
|
|
tata.error('', 'Please enter a message.');
|
|
}
|
|
fetch('/api/v1/songs/report-notes/', {
|
|
method: 'POST',
|
|
headers: {
|
|
"X-CSRFToken": CSRF_TOKEN,
|
|
"Accept": 'application/json',
|
|
"Content-Type": 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
song: song_id,
|
|
note: message,
|
|
}),
|
|
}).then(response => {
|
|
if (response.status === 201) {
|
|
return response.json();
|
|
} else {
|
|
throw response;
|
|
}
|
|
}).then(() => {
|
|
tata.success("", "Successfully submitted report note.")
|
|
}).catch(e => {
|
|
if (e instanceof Response) {
|
|
e.json().then(data => {
|
|
tata.error("", data.errorMessage);
|
|
});
|
|
} else {
|
|
tata.error("", "An unknown error occurred, please try again.")
|
|
}
|
|
});
|
|
},
|
|
|
|
update_page(page_number) {
|
|
this.page_number = page_number;
|
|
},
|
|
|
|
select_textinput() {
|
|
this.$refs.search_textinput.select();
|
|
},
|
|
}
|
|
}).mount('#request-container');
|
|
</script>
|
|
<script>
|
|
function volume_down() {
|
|
fetch('/api/v1/queues/current/volume-down/', {
|
|
method: "POST",
|
|
headers: {
|
|
"X-CSRFToken": CSRF_TOKEN,
|
|
"Accept": 'application/json',
|
|
"Content-Type": 'application/json',
|
|
},
|
|
}).then(response => {
|
|
if (response.status !== 200) {
|
|
throw response;
|
|
}
|
|
}).catch((e) => {
|
|
if (e instanceof Response) {
|
|
tata.error("", e.errorMessage);
|
|
} else {
|
|
tata.error("", "An unknown error occurred.")
|
|
}
|
|
});
|
|
}
|
|
|
|
function volume_up() {
|
|
fetch('/api/v1/queues/current/volume-up/', {
|
|
method: "POST",
|
|
headers: {
|
|
"X-CSRFToken": CSRF_TOKEN,
|
|
"Accept": 'application/json',
|
|
"Content-Type": 'application/json',
|
|
},
|
|
}).then(response => {
|
|
if (response.status !== 200) {
|
|
throw response;
|
|
}
|
|
}).catch((e) => {
|
|
if (e instanceof Response) {
|
|
tata.error("", e.errorMessage);
|
|
} else {
|
|
tata.error("", "An unknown error occurred.")
|
|
}
|
|
});
|
|
}
|
|
|
|
function mute() {
|
|
fetch('/api/v1/queues/current/mute/', {
|
|
method: "POST",
|
|
headers: {
|
|
"X-CSRFToken": CSRF_TOKEN,
|
|
"Accept": 'application/json',
|
|
"Content-Type": 'application/json',
|
|
},
|
|
}).then(response => {
|
|
if (response.status !== 200) {
|
|
throw response;
|
|
}
|
|
}).catch((e) => {
|
|
if (e instanceof Response) {
|
|
tata.error("", e.errorMessage);
|
|
} else {
|
|
tata.error("", "An unknown error occurred.")
|
|
}
|
|
});
|
|
}
|
|
|
|
function skip() {
|
|
fetch('/api/v1/queues/current/skip/', {
|
|
method: "POST",
|
|
headers: {
|
|
"X-CSRFToken": CSRF_TOKEN,
|
|
"Accept": 'application/json',
|
|
"Content-Type": 'application/json',
|
|
},
|
|
}).then(response => {
|
|
if (response.status !== 200) {
|
|
throw response;
|
|
}
|
|
}).then(() => {
|
|
queue_vue.refresh();
|
|
}).catch((e) => {
|
|
if (e instanceof Response) {
|
|
tata.error("", e.errorMessage);
|
|
} else {
|
|
tata.error("", "An unknown error occurred.")
|
|
}
|
|
});
|
|
}
|
|
</script>
|
|
{% endblock %}
|