mirror of
https://gitlab.science.ru.nl/technicie/MarietjeDjango.git
synced 2025-12-10 09:12:23 +01:00
Marietje in header and fix load times for upload page
This commit is contained in:
@ -15,7 +15,10 @@
|
|||||||
<link href="{% static 'fontawesomefree/css/all.min.css' %}" rel="stylesheet" type="text/css">
|
<link href="{% static 'fontawesomefree/css/all.min.css' %}" rel="stylesheet" type="text/css">
|
||||||
|
|
||||||
<!-- Vue JS -->
|
<!-- Vue JS -->
|
||||||
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
|
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
|
||||||
|
<script>
|
||||||
|
const { createApp } = Vue;
|
||||||
|
</script>
|
||||||
|
|
||||||
<!-- TaTa.js notifications -->
|
<!-- TaTa.js notifications -->
|
||||||
<script src="{% static 'marietje/js/tata.js' %}"></script>
|
<script src="{% static 'marietje/js/tata.js' %}"></script>
|
||||||
@ -26,6 +29,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<nav class="navbar navbar-expand-lg sticky-top navbar-dark bg-primary">
|
<nav class="navbar navbar-expand-lg sticky-top navbar-dark bg-primary">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
<a class="navbar-brand d-block d-lg-none" href="{% url "index" %}">Marietje 4.1</a>
|
||||||
<button class="navbar-toggler ms-auto" type="button" data-bs-toggle="offcanvas"
|
<button class="navbar-toggler ms-auto" type="button" data-bs-toggle="offcanvas"
|
||||||
data-bs-target="#offcanvasNavbar" aria-controls="offcanvasNavbar">
|
data-bs-target="#offcanvasNavbar" aria-controls="offcanvasNavbar">
|
||||||
<span class="navbar-toggler-icon"></span>
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
|||||||
@ -74,22 +74,22 @@
|
|||||||
<tbody class="queuebody">
|
<tbody class="queuebody">
|
||||||
<template v-for="(song, index) in queue">
|
<template v-for="(song, index) in queue">
|
||||||
<tr :class="{ marietjequeue: (song.user === null), currentsong: (index === 0), 'fw-bold': (index === 0) }">
|
<tr :class="{ marietjequeue: (song.user === null), currentsong: (index === 0), 'fw-bold': (index === 0) }">
|
||||||
<td class="artist"><% song.song.artist %></td>
|
<td class="artist">${song.song.artist }$</td>
|
||||||
<td class="title"><% song.song.title %></td>
|
<td class="title">${song.song.title }$</td>
|
||||||
<td class="d-sm-table-cell d-none requested-by">
|
<td class="d-sm-table-cell d-none requested-by">
|
||||||
<template v-if="song.user === null">
|
<template v-if="song.user === null">
|
||||||
Marietje
|
Marietje
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<% song.user.name %>
|
${song.user.name }$
|
||||||
</template>
|
</template>
|
||||||
</td>
|
</td>
|
||||||
<td class="d-sm-table-cell d-none plays-at" style="text-align: right">
|
<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">
|
<template v-if="song.time_until_song_seconds !== null && song.time_until_song_seconds > 0 && playsIn === true">
|
||||||
<% song.time_until_song_seconds.secondsToMMSS() %>
|
${song.time_until_song_seconds.secondsToMMSS() }$
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="playsIn === false && song.plays_at !== null && song.played === false">
|
<template v-else-if="playsIn === false && song.plays_at !== null && song.played === false">
|
||||||
<% song.plays_at.timestampToHHMMSS() %>
|
${song.plays_at.timestampToHHMMSS() }$
|
||||||
</template>
|
</template>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@ -160,7 +160,7 @@
|
|||||||
</select>
|
</select>
|
||||||
<select class="pagenum input-mini" title="Select page number" v-model="page_number">
|
<select class="pagenum input-mini" title="Select page number" v-model="page_number">
|
||||||
<template v-for="(i, index) in number_of_pages">
|
<template v-for="(i, index) in number_of_pages">
|
||||||
<option :value="i"><% i %></option>
|
<option :value="i">${i }$</option>
|
||||||
</template>
|
</template>
|
||||||
</select>
|
</select>
|
||||||
</th>
|
</th>
|
||||||
@ -171,21 +171,21 @@
|
|||||||
<template v-for="(song, index) in songs">
|
<template v-for="(song, index) in songs">
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<% song.artist %>
|
${song.artist }$
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="#" v-on:click="request_song(song.id);"><% song.title %></a>
|
<a href="#" v-on:click="request_song(song.id);">${song.title }$</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<template v-if="song.user === null">
|
<template v-if="song.user === null">
|
||||||
Marietje
|
Marietje
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<% song.user.name %>
|
${song.user.name }$
|
||||||
</template>
|
</template>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<% song.duration.secondsToMMSS() %>
|
${song.duration.secondsToMMSS() }$
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="#" v-on:click="report_song(song.id);">
|
<a href="#" v-on:click="report_song(song.id);">
|
||||||
@ -209,18 +209,19 @@
|
|||||||
const CAN_MOVE = {{ perms.queues.can_move|yesno:"1,0" }};
|
const CAN_MOVE = {{ perms.queues.can_move|yesno:"1,0" }};
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
const queue_vue = new Vue({
|
const queue_vue = createApp({
|
||||||
el: '#queue-container',
|
delimiters: ['${', '}$'],
|
||||||
delimiters: ['<%', '%>'],
|
data() {
|
||||||
data: {
|
return {
|
||||||
current_song: null,
|
current_song: null,
|
||||||
queue: [],
|
queue: [],
|
||||||
user_data: null,
|
user_data: null,
|
||||||
refreshing: true,
|
refreshing: true,
|
||||||
refreshTimer: null,
|
refreshTimer: null,
|
||||||
clockInterval: null,
|
clockInterval: null,
|
||||||
started_at: null,
|
started_at: null,
|
||||||
playsIn: true,
|
playsIn: true,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.clockInterval = setInterval(this.update_song_times, 1000);
|
this.clockInterval = setInterval(this.update_song_times, 1000);
|
||||||
@ -372,19 +373,20 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}).mount('#queue-container');
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
const request_vue = new Vue({
|
const request_vue = createApp({
|
||||||
el: '#request-container',
|
delimiters: ['${', '}$'],
|
||||||
delimiters: ['<%', '%>'],
|
data() {
|
||||||
data: {
|
return {
|
||||||
songs: [],
|
songs: [],
|
||||||
total_songs: 0,
|
total_songs: 0,
|
||||||
search_input: "",
|
search_input: "",
|
||||||
typing_timer: null,
|
typing_timer: null,
|
||||||
page_size: 10,
|
page_size: 10,
|
||||||
page_number: 1,
|
page_number: 1,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
search_input: {
|
search_input: {
|
||||||
@ -542,7 +544,7 @@
|
|||||||
this.page_number = page_number;
|
this.page_number = page_number;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}).mount('#request-container');
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
function volume_down() {
|
function volume_down() {
|
||||||
|
|||||||
@ -84,7 +84,7 @@ class SongUploadAPIView(APIView):
|
|||||||
song = upload_file(file, artist, title, request.user)
|
song = upload_file(file, artist, title, request.user)
|
||||||
upload_counter.inc()
|
upload_counter.inc()
|
||||||
return Response(status=200, data=self.serializer_class(song).data)
|
return Response(status=200, data=self.serializer_class(song).data)
|
||||||
except UploadException:
|
except (UploadException, ConnectionRefusedError):
|
||||||
return Response(
|
return Response(
|
||||||
status=500,
|
status=500,
|
||||||
data={
|
data={
|
||||||
|
|||||||
@ -41,7 +41,7 @@
|
|||||||
</select>
|
</select>
|
||||||
<select class="pagenum input-mini" title="Select page number" v-model="page_number">
|
<select class="pagenum input-mini" title="Select page number" v-model="page_number">
|
||||||
<template v-for="(i, index) in number_of_pages">
|
<template v-for="(i, index) in number_of_pages">
|
||||||
<option :value="i"><% i %></option>
|
<option :value="i">${ i }$</option>
|
||||||
</template>
|
</template>
|
||||||
</select>
|
</select>
|
||||||
</th>
|
</th>
|
||||||
@ -52,10 +52,10 @@
|
|||||||
<template v-for="(song, index) in songs">
|
<template v-for="(song, index) in songs">
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<% song.artist %>
|
${ song.artist }$
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a :href="'/songs/edit/' + song.id + '/'" v-on:click="request_song(song.id);"><% song.title %></a>
|
<a :href="'/songs/edit/' + song.id + '/'" v-on:click="request_song(song.id);">${ song.title }$</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</template>
|
</template>
|
||||||
@ -64,16 +64,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
let manage_vue = new Vue({
|
let manage_vue = createApp({
|
||||||
el: '#request-table',
|
delimiters: ['${', '}$'],
|
||||||
delimiters: ['<%', '%>'],
|
data() {
|
||||||
data: {
|
return {
|
||||||
songs: [],
|
songs: [],
|
||||||
total_songs: 0,
|
total_songs: 0,
|
||||||
search_input: "",
|
search_input: "",
|
||||||
typing_timer: null,
|
typing_timer: null,
|
||||||
page_size: 10,
|
page_size: 10,
|
||||||
page_number: 1,
|
page_number: 1,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
search_input: {
|
search_input: {
|
||||||
@ -168,6 +169,6 @@
|
|||||||
this.page_number = page_number;
|
this.page_number = page_number;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}).mount('#request-table');
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -16,9 +16,12 @@
|
|||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="fileupload fileupload-new" data-provides="fileupload">
|
<div class="fileupload fileupload-new" data-provides="fileupload">
|
||||||
<span class="btn btn-primary btn-file">
|
<span class="btn btn-primary btn-file">
|
||||||
<span v-if="fileObjects.length === 0">
|
<span v-if="fileObjects.length === 0 && !files_loading">
|
||||||
Select files
|
Select files
|
||||||
</span>
|
</span>
|
||||||
|
<span v-else-if="files_loading">
|
||||||
|
Loading new files...
|
||||||
|
</span>
|
||||||
<span v-else>
|
<span v-else>
|
||||||
Change
|
Change
|
||||||
</span>
|
</span>
|
||||||
@ -29,7 +32,7 @@
|
|||||||
<div class="songs">
|
<div class="songs">
|
||||||
<div v-for="fileObject in fileObjects" class="song-container card mb-3">
|
<div v-for="fileObject in fileObjects" class="song-container card mb-3">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h3><% fileObject.name %></h3>
|
<h3>${ fileObject.name }$</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="form-group mb-3">
|
<div class="form-group mb-3">
|
||||||
@ -48,7 +51,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<template v-if="fileObject.upload_finished === true">
|
<template v-if="fileObject.upload_finished === true">
|
||||||
<div v-if="fileObject.success === true" class="alert alert-success">Upload finished successfully.</div>
|
<div v-if="fileObject.success === true" class="alert alert-success">Upload finished successfully.</div>
|
||||||
<div v-else class="alert alert-danger"><% fileObject.error_message %></div>
|
<div v-else class="alert alert-danger">${ fileObject.error_message }$</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -73,17 +76,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<link rel="stylesheet" href="{% static 'songs/css/upload.css' %}"/>
|
<link rel="stylesheet" href="{% static 'songs/css/upload.css' %}"/>
|
||||||
<script type="module">
|
<script src="https://cdn.jsdelivr.net/npm/mp3tag.js@latest/dist/mp3tag.min.js"></script>
|
||||||
import * as id3 from '//unpkg.com/id3js@^2/lib/id3.js';
|
<script>
|
||||||
|
let upload_vue = createApp({
|
||||||
let upload_vue = new Vue({
|
delimiters: ['${', '}$'],
|
||||||
el: '#uploadform',
|
data() {
|
||||||
delimiters: ['<%', '%>'],
|
return {
|
||||||
data: {
|
files: [],
|
||||||
files: [],
|
fileObjects: [],
|
||||||
fileObjects: [],
|
uploaded: false,
|
||||||
uploaded: false,
|
upload_in_progress: false,
|
||||||
upload_in_progress: false,
|
files_loading: false,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
ready_for_upload: function() {
|
ready_for_upload: function() {
|
||||||
@ -158,14 +162,20 @@
|
|||||||
}).then(() => {
|
}).then(() => {
|
||||||
this.fileObjects[i].success = true;
|
this.fileObjects[i].success = true;
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
|
console.log(e);
|
||||||
if (e instanceof Response) {
|
if (e instanceof Response) {
|
||||||
e.json().then(data => {
|
try {
|
||||||
this.fileObjects.error_message = data.errorMessage;
|
e.json().then(data => {
|
||||||
this.fileObjects.success = false;
|
this.fileObjects[i].error_message = data.errorMessage;
|
||||||
});
|
this.fileObjects[i].success = false;
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
this.fileObjects[i].error_message = "An exception occurred while uploading this file, please try again.";
|
||||||
|
this.fileObjects[i].success = false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.fileObjects.error_message = "An exception occurred while uploading this file, please try again.";
|
this.fileObjects[i].error_message = "An exception occurred while uploading this file, please try again.";
|
||||||
this.fileObjects.success = false;
|
this.fileObjects[i].success = false;
|
||||||
}
|
}
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
this.fileObjects[i].upload_finished = true;
|
this.fileObjects[i].upload_finished = true;
|
||||||
@ -177,23 +187,25 @@
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
async set_new_files(event) {
|
async set_new_files(event) {
|
||||||
|
this.files_loading = true;
|
||||||
|
this.uploaded = false;
|
||||||
|
this.upload_in_progress = false;
|
||||||
this.files = event.target.files;
|
this.files = event.target.files;
|
||||||
let newFileObjects = [];
|
let newFileObjects = [];
|
||||||
for (let i = 0; i < this.files.length; i++) {
|
for (let i = 0; i < this.files.length; i++) {
|
||||||
try {
|
await this.parseSong(this.files[i]).then((song) => {
|
||||||
const tags = await this.parseSong(this.files[i]);
|
|
||||||
newFileObjects.push(
|
newFileObjects.push(
|
||||||
{
|
{
|
||||||
"file": this.files[i],
|
"file": this.files[i],
|
||||||
"name": this.files[i].name,
|
"name": this.files[i].name,
|
||||||
"artist": tags.artist,
|
"artist": song.artist,
|
||||||
"title": tags.title,
|
"title": song.title,
|
||||||
"success": null,
|
"success": null,
|
||||||
"error_message": null,
|
"error_message": null,
|
||||||
"upload_finished": false,
|
"upload_finished": false,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} catch {
|
}).catch(() => {
|
||||||
newFileObjects.push(
|
newFileObjects.push(
|
||||||
{
|
{
|
||||||
"file": this.files[i],
|
"file": this.files[i],
|
||||||
@ -205,14 +217,28 @@
|
|||||||
"upload_finished": false,
|
"upload_finished": false,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
this.fileObjects = newFileObjects;
|
this.fileObjects = newFileObjects;
|
||||||
|
this.files_loading = false;
|
||||||
},
|
},
|
||||||
parseSong(file) {
|
async parseSong(file) {
|
||||||
return id3.fromFile(file);
|
const buffer = await new Promise((resolve) => {
|
||||||
|
let fileReader = new FileReader();
|
||||||
|
fileReader.onload = (e) => resolve(fileReader.result);
|
||||||
|
fileReader.readAsArrayBuffer(file);
|
||||||
|
});
|
||||||
|
|
||||||
|
const mp3tag = new MP3Tag(buffer);
|
||||||
|
mp3tag.read()
|
||||||
|
|
||||||
|
if (mp3tag.error !== '') {
|
||||||
|
throw new Error(mp3tag.error);
|
||||||
|
} else {
|
||||||
|
return mp3tag.tags;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}).mount('#uploadform');
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
Reference in New Issue
Block a user