From 4f0bd8670bf4dbf1dd7d90b3ed730b2db9af9517 Mon Sep 17 00:00:00 2001 From: Nikiroy78 <35032449+Nikiroy78@users.noreply.github.com> Date: Mon, 2 Oct 2023 11:55:35 +0300 Subject: [PATCH] Add frontend --- .gitignore | 1 - api-tests/test.py | 33 ++++ frontend/main.html | 2 + frontend/public/js/api-module.js | 141 ++++++++++++++--- frontend/public/js/main.js | 261 ++++++++++++++++++++----------- frontend/public/js/menu.js | 185 ++++++++++++++++++++++ frontend/public/js/sound.js | 26 ++- page-view.js | 16 +- server.js | 2 +- 9 files changed, 534 insertions(+), 133 deletions(-) create mode 100644 api-tests/test.py create mode 100644 frontend/public/js/menu.js diff --git a/.gitignore b/.gitignore index e06b9f1..bbacba7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ node_modules/ references/ ts.txt -*.py *.log \ No newline at end of file diff --git a/api-tests/test.py b/api-tests/test.py new file mode 100644 index 0000000..23c5832 --- /dev/null +++ b/api-tests/test.py @@ -0,0 +1,33 @@ +import requests as req + + +class CreateItemChecks: + def createAuthor (result): + return 'response' in result + + +class CreateItemActions: + def createAuthor (): + return req.post( + "http://127.0.0.1:8080/api/v/1.0/create-item?response_format=json", + json={ + "type" : "author" + } + ).json() + +createItemActions = CreateItemActions() +createItemChecks = CreateItemChecks() + +def test (id, action, isDone): + try: + print("""Test {id} runned..""") + result = action() + if isDone(result): + print("""Test {id} success!""") + else: + print("""Test {id} ERROR""") + print(result) + except Exception as exc: + print(exc) + +test(1, createItemActions.createAuthor, createItemChecks.createAuthor) \ No newline at end of file diff --git a/frontend/main.html b/frontend/main.html index 93ff254..144d6c4 100644 --- a/frontend/main.html +++ b/frontend/main.html @@ -4,6 +4,7 @@ Kodex Muzic + @@ -33,6 +34,7 @@ + diff --git a/frontend/public/js/api-module.js b/frontend/public/js/api-module.js index 6389f32..e45dab0 100644 --- a/frontend/public/js/api-module.js +++ b/frontend/public/js/api-module.js @@ -1,9 +1,15 @@ class Api { - getAuthors (params, cb) { + getAuthors(params, cb) { const xhr = new XMLHttpRequest(); - params = Object.entries(params).map(([key, value]) => `${key}=${value}`).join('&'); - params = params !== '' ? `&${params}` : ''; - xhr.open("GET", `/api/v/1.0/get-authors?response_format=json${params}`, true); + params = Object.entries(params) + .map(([key, value]) => `${key}=${value}`) + .join("&"); + params = params !== "" ? `&${params}` : ""; + xhr.open( + "GET", + `/api/v/1.0/get-authors?response_format=json${params}`, + true, + ); xhr.onreadystatechange = function (event) { //console.log(event); if (this.readyState != 4) return; @@ -11,11 +17,13 @@ class Api { }; xhr.send(); } - - getMuzic (params, cb) { + + getMuzic(params, cb) { const xhr = new XMLHttpRequest(); - params = Object.entries(params).map(([key, value]) => `${key}=${value}`).join('&'); - params = params !== '' ? `&${params}` : ''; + params = Object.entries(params) + .map(([key, value]) => `${key}=${value}`) + .join("&"); + params = params !== "" ? `&${params}` : ""; xhr.open("GET", `/api/v/1.0/get-muzic?response_format=json${params}`, true); xhr.onreadystatechange = function (event) { //console.log(event); @@ -24,24 +32,121 @@ class Api { }; xhr.send(); } - - createMuzic (author_id, name, data=null, cb) { + + deleteMuzic(id, cb) { + const xhr = new XMLHttpRequest(); + xhr.open("POST", `/api/v/1.0/remove-item?response_format=json`, true); + xhr.setRequestHeader("Content-type", "application/json; charset=utf-8"); + xhr.onreadystatechange = function (event) { + //console.log(event); + if (this.readyState != 4) return; + if (JSON.parse(this.responseText).response === undefined) { + throw this.responseText; + } + cb(JSON.parse(this.responseText).response); + }; + xhr.send( + JSON.stringify({ + type: "muzic", + id, + }), + ); + } + + editMuzic(id, name, data, author_id, cb) { + const xhr = new XMLHttpRequest(); + xhr.open("POST", `/api/v/1.0/edit-item?response_format=json`, true); + xhr.setRequestHeader("Content-type", "application/json; charset=utf-8"); + xhr.onreadystatechange = function (event) { + //console.log(event); + if (this.readyState != 4) return; + if (JSON.parse(this.responseText).response === undefined) { + throw this.responseText; + } + cb(JSON.parse(this.responseText).response); + }; + xhr.send( + JSON.stringify({ + type: "muzic", + id, + name, + author_id, + data, + }), + ); + } + + createMuzic(author_id, name, data = null, cb) { data = data === null ? undefined : data; const xhr = new XMLHttpRequest(); xhr.open("POST", `/api/v/1.0/create-item?response_format=json`, true); - xhr.setRequestHeader('Content-type', 'application/json; charset=utf-8'); + xhr.setRequestHeader("Content-type", "application/json; charset=utf-8"); xhr.onreadystatechange = function (event) { //console.log(event); if (this.readyState != 4) return; cb(JSON.parse(this.responseText).response); }; - xhr.send(JSON.stringify({ - type: 'muzic', - name, - author_id, - data - })); + xhr.send( + JSON.stringify({ + type: "muzic", + name, + author_id, + data, + }), + ); + } + + createAuthor(name, cb) { + const xhr = new XMLHttpRequest(); + xhr.open("POST", `/api/v/1.0/create-item?response_format=json`, true); + xhr.setRequestHeader("Content-type", "application/json; charset=utf-8"); + xhr.onreadystatechange = function (event) { + //console.log(event); + if (this.readyState != 4) return; + cb(JSON.parse(this.responseText).response); + }; + xhr.send( + JSON.stringify({ + type: "author", + name, + }), + ); + } + + removeAuthor(id, cb) { + const xhr = new XMLHttpRequest(); + xhr.open("POST", `/api/v/1.0/remove-item?response_format=json`, true); + xhr.setRequestHeader("Content-type", "application/json; charset=utf-8"); + xhr.onreadystatechange = function (event) { + //console.log(event); + if (this.readyState != 4) return; + cb(JSON.parse(this.responseText).response); + }; + xhr.send( + JSON.stringify({ + type: "author", + id, + }), + ); + } + + editAuthor(id, name, cb) { + const xhr = new XMLHttpRequest(); + xhr.open("POST", `/api/v/1.0/edit-item?response_format=json`, true); + xhr.setRequestHeader("Content-type", "application/json; charset=utf-8"); + xhr.onreadystatechange = function (event) { + //console.log(event); + if (this.readyState != 4) return; + cb(JSON.parse(this.responseText).response); + }; + xhr.send( + JSON.stringify({ + type: "author", + id, + name, + }), + ); } } -const api = new Api(); \ No newline at end of file +const api = new Api(); diff --git a/frontend/public/js/main.js b/frontend/public/js/main.js index 17698af..7c71cf6 100644 --- a/frontend/public/js/main.js +++ b/frontend/public/js/main.js @@ -1,36 +1,86 @@ -document.getElementById('app-window').innerHTML = '

Загрузка произведений...

'; +document.getElementById("app-window").innerHTML = + "

Загрузка произведений...

"; -function toggleShow (authorId) { - document.getElementById(`playlist-author-${authorId}`).hidden = !document.getElementById(`playlist-author-${authorId}`).hidden; +function toggleShow(authorId) { + document.getElementById(`playlist-author-${authorId}`).hidden = + !document.getElementById(`playlist-author-${authorId}`).hidden; } -function showAudio (settingsAuthors, settingsAudio) { +function showAudio(settingsAuthors, settingsAudio) { + showAudio.settingsAuthors = settingsAuthors; + showAudio.settingsAudio = settingsAudio; + const step2 = (muzic) => { //console.log(muzic.items); - const showedAuthors = [...(new Set(muzic.items.map(i => `author-${i.author_id}`)))]; - [...document.getElementsByClassName('author-element')].forEach(el => { + const showedAuthors = [ + ...new Set(muzic.items.map((i) => `author-${i.author_id}`)), + ]; + [...document.getElementsByClassName("author-element")].forEach((el) => { + if ( + JSON.stringify(settingsAuthors) === "{}" && + JSON.stringify(settingsAudio) === "{}" + ) { + if (!showedAuthors.includes(el.id)) { + const id = el.id.slice(7); + document.getElementById(`loader-muzic-${id}`).innerHTML = + "

Пусто. Добавьте произведения

"; + } + return; + } el.hidden = !showedAuthors.includes(el.id); }); - - muzic.items.forEach(muzic => { - document.getElementById(`loader-muzic-${muzic.author_id}`).hidden = true; - if (muzic.is_data_exists) document.getElementById(`playlist-author-${muzic.author_id}`).innerHTML += `

+ + muzic.items + .sort((a, b) => a.date - b.date) + .forEach((muzic) => { + document.getElementById( + `loader-muzic-${muzic.author_id}`, + ).hidden = true; + if (muzic.is_data_exists) + document.getElementById( + `playlist-author-${muzic.author_id}`, + ).innerHTML += `

+
${muzic.name}
+ + + +

`; + else + document.getElementById( + `playlist-author-${muzic.author_id}`, + ).innerHTML += `

${muzic.name}
- - - -

`; - else document.getElementById(`playlist-author-${muzic.author_id}`).innerHTML += `

-

${muzic.name}
- -

`; - }); - } + +

`; + }); + }; api.getAuthors(settingsAuthors, (authors) => { - document.getElementById('app-window').innerHTML = ''; - authors.items.forEach((author) => { - document.getElementById('app-window').innerHTML += `
-

${author.name}

+ document.getElementById("app-window").innerHTML = ""; + authors.items + .sort((a, b) => a.date - b.date) + .forEach((author) => { + document.getElementById( + "app-window", + ).innerHTML += `
+

${author.name}

Произведения


Показать/Скрыть @@ -39,80 +89,111 @@ function showAudio (settingsAuthors, settingsAudio) {
`; - const addMuzicButtonFunct = () => setTimeout( () => - document.getElementById(`add-muzic-button-${author.id}`).onclick = async () => { - // console.log('>>', author.id); - document.getElementById(`add-muzic-${author.id}`).innerHTML = `

+ const addMuzicButtonFunct = () => + setTimeout( + () => + (document.getElementById( + `add-muzic-button-${author.id}`, + ).onclick = async () => { + // console.log('>>', author.id); + document.getElementById( + `add-muzic-${author.id}`, + ).innerHTML = `

-

- `; - setTimeout( - () => { - document.getElementById(`cancel-add-muzic-${author.id}`).onclick = function () { - document.getElementById(`add-muzic-${author.id}`).innerHTML = `
`; - addMuzicButtonFunct(); - }; - - document.getElementById(`add-muzic-${author.id}`).onclick = function () { - if (document.getElementById(`muzic-name-input-${author.id}`).value.length >= 2) { - api.createMuzic( - author.id, - document.getElementById(`muzic-name-input-${author.id}`).value, - document.getElementById(`attach-file-${author.id}`).filedata, - () => { - showAudio(settingsAuthors, settingsAudio); - } - ); - document.getElementById(`add-muzic-${author.id}`).innerHTML = 'Добавление файла...'; - } - }; - - document.getElementById(`attach-file-${author.id}`).onclick = function () { - const input = document.createElement('input'); - input.type = 'file'; - input.accept = 'audio/mpeg'; - input.click(); - input.onchange = function (e) { - function arrayBufferToBase64( buffer ) { - let binary = ''; - let bytes = new Uint8Array( buffer ); - let len = bytes.byteLength; - for (let i = 0; i < len; i++) { - binary += String.fromCharCode( bytes[ i ] ); - } - return window.btoa( binary ); - } - - const file = e.target.files[0]; - // console.log(file); - const reader = new FileReader(); - reader.readAsArrayBuffer(file); - reader.onload = function() { - // console.log('reader.result', reader.result); - if (file.type === 'audio/mpeg') { - document.getElementById(`attach-file-${author.id}`).filedata = arrayBufferToBase64(reader.result); - document.getElementById(`attach-file-${author.id}`).innerText = "Загружен файл: " + file.name; - } - // console.log(arrayBufferToBase64(reader.result)); +

`; + setTimeout(() => { + document.getElementById( + `cancel-add-muzic-${author.id}`, + ).onclick = function () { + document.getElementById( + `add-muzic-${author.id}`, + ).innerHTML = `
`; + addMuzicButtonFunct(); }; - }; - }; - }, 0 + + document.getElementById(`add-muzic-${author.id}`).onclick = + function () { + if ( + document.getElementById(`muzic-name-input-${author.id}`) + .value.length >= 2 + ) { + api.createMuzic( + author.id, + document.getElementById( + `muzic-name-input-${author.id}`, + ).value, + document.getElementById(`attach-file-${author.id}`) + .filedata, + () => { + showAudio(settingsAuthors, settingsAudio); + }, + ); + document.getElementById( + `add-muzic-${author.id}`, + ).innerHTML = "Добавление файла..."; + } + }; + + document.getElementById(`attach-file-${author.id}`).onclick = + function () { + const input = document.createElement("input"); + input.type = "file"; + input.accept = "audio/mpeg"; + input.click(); + input.onchange = function (e) { + function arrayBufferToBase64(buffer) { + let binary = ""; + let bytes = new Uint8Array(buffer); + let len = bytes.byteLength; + for (let i = 0; i < len; i++) { + binary += String.fromCharCode(bytes[i]); + } + return window.btoa(binary); + } + + const file = e.target.files[0]; + // console.log(file); + const reader = new FileReader(); + reader.readAsArrayBuffer(file); + reader.onload = function () { + // console.log('reader.result', reader.result); + if (file.type === "audio/mpeg") { + document.getElementById( + `attach-file-${author.id}`, + ).filedata = arrayBufferToBase64(reader.result); + document.getElementById( + `attach-file-${author.id}`, + ).innerText = "Загружен файл: " + file.name; + } + // console.log(arrayBufferToBase64(reader.result)); + }; + }; + }; + }, 0); + }), + 0, ); - }, 0); - addMuzicButtonFunct(); - }); + addMuzicButtonFunct(); + }); api.getMuzic(settingsAudio, step2); - document.getElementById('app-window').innerHTML += '
' + document.getElementById("app-window").innerHTML += + '
'; }); } setTimeout(() => showAudio({}, {}), 0); -document.getElementById('search-input').onchange = function () { +document.getElementById("search-input").onchange = function () { console.log(this.value); - setTimeout(() => showAudio({}, { - q : this.value - }), 0); -}; \ No newline at end of file + setTimeout( + () => + showAudio( + {}, + { + q: this.value, + }, + ), + 0, + ); +}; diff --git a/frontend/public/js/menu.js b/frontend/public/js/menu.js new file mode 100644 index 0000000..e8df185 --- /dev/null +++ b/frontend/public/js/menu.js @@ -0,0 +1,185 @@ +function removeAuthor(authorId) { + api.removeAuthor(authorId, () => { + showAudio(showAudio.settingsAuthors, showAudio.settingsAudio); + }); +} + +function editAuthor(authorId) { + const name = document.getElementById(`input-author-name-${authorId}`).value; + api.editAuthor(authorId, name, (res) => { + if (res !== undefined) removeAuthorEditor(authorId, name); + }); +} + +function removeAuthorEditor(authorId, authorName) { + document.getElementById( + `author-info-${authorId}`, + ).innerHTML = `

${authorName}

`; + setTimeout(() => { + document.getElementById(`edit-author-${authorId}`).onclick = () => + showAuthorEditor(authorId, authorName); + }, 5); +} + +function showAuthorEditorButtonInit(authorId) { + const authorName = document.getElementById( + `author-info-${authorId}`, + ).lastValue; + document.getElementById(`cancel-edit-author-${authorId}`).onclick = () => + removeAuthorEditor(authorId, authorName); + document.getElementById(`remove-author-${authorId}`).onclick = () => + removeAuthor(authorId); + document.getElementById(`edit-author-${authorId}`).onclick = () => + editAuthor(authorId); + // document.getElementById(`add-author-button`).onclick = addAuthor; +} + +function showAuthorEditor(authorId, lastValue) { + document.getElementById(`author-info-${authorId}`).lastValue = lastValue; + document.getElementById( + `author-info-${authorId}`, + ).innerHTML = `

+ + + +

`; + setTimeout(() => showAuthorEditorButtonInit(authorId), 5); +} + +function addAuthor() { + const name = document.getElementById(`author-name-input`).value; + document.getElementById("add-author").innerHTML = + "

Добавляем..

"; + api.createAuthor(name, () => { + showAudio(showAudio.settingsAuthors, showAudio.settingsAudio); + }); +} + +function rmAuthorMenuButtonInit() { + document.getElementById(`add-author-button`).onclick = addAuthorMenu; +} + +function removeAuthorMenu() { + document.getElementById( + "add-author", + ).innerHTML = `
`; + setTimeout(rmAuthorMenuButtonInit, 5); +} + +function authorMenuButtonInit() { + document.getElementById(`cancel-add-author`).onclick = removeAuthorMenu; + document.getElementById(`add-author-button`).onclick = addAuthor; +} + +function addAuthorMenu() { + document.getElementById( + "add-author", + ).innerHTML = `

+ +

`; + + setTimeout(authorMenuButtonInit, 5); +} + +function selectFile(muzicId) { + const input = document.createElement("input"); + input.type = "file"; + input.accept = "audio/mpeg"; + input.click(); + input.onchange = function (e) { + function arrayBufferToBase64(buffer) { + let binary = ""; + let bytes = new Uint8Array(buffer); + let len = bytes.byteLength; + for (let i = 0; i < len; i++) { + binary += String.fromCharCode(bytes[i]); + } + return window.btoa(binary); + } + + const file = e.target.files[0]; + // console.log(file); + const reader = new FileReader(); + reader.readAsArrayBuffer(file); + reader.onload = function () { + // console.log('reader.result', reader.result); + if (file.type === "audio/mpeg") { + document.getElementById(`edit-attach-file-${muzicId}`).filedata = + arrayBufferToBase64(reader.result); + document.getElementById(`edit-attach-file-${muzicId}`).innerText = + "Загружен файл: " + file.name; + document.getElementById(`delete-attach-${muzicId}`).disabled = false; + } + // console.log(arrayBufferToBase64(reader.result)); + }; + }; +} + +function editMuzic(muzicId, muzicName) { + api.editMuzic( + muzicId, + muzicName, + document.getElementById(`edit-attach-file-${muzicId}`).filedata, + undefined, + (res) => { + showAudio(showAudio.settingsAuthors, showAudio.settingsAudio); + }, + ); +} + +function removeMuzic(muzicId) { + api.deleteMuzic(muzicId, (res) => { + showAudio(showAudio.settingsAuthors, showAudio.settingsAudio); + }); +} + +function bindShowEditMuzicButtons(muzicId, muzicName, dataExists) { + document.getElementById(`cancel-edit-muzic-${muzicId}`).onclick = () => { + document.getElementById(`muzic-item-${muzicId}`).innerHTML = dataExists + ? `
${muzicName}
+ + + ` + : `

+
${muzicName}
+ +

`; + }; + document.getElementById(`edit-attach-file-${muzicId}`).onclick = () => + selectFile(muzicId); + document.getElementById(`delete-attach-${muzicId}`).onclick = () => { + document.getElementById(`edit-attach-file-${muzicId}`).innerText = + "Добавить файл (.mp3)"; + document.getElementById(`edit-attach-file-${muzicId}`).filedata = null; + document.getElementById(`delete-attach-${muzicId}`).disabled = true; + }; + document.getElementById(`edit-muzic-${muzicId}`).onclick = () => + editMuzic(muzicId, muzicName); + document.getElementById(`delete-muzic-${muzicId}`).onclick = () => + removeMuzic(muzicId); +} + +function showEditMuzic(muzicId, muzicName, dataExists) { + document.getElementById( + `muzic-item-${muzicId}`, + ).innerHTML = `

+

+ + + +

`; + + setTimeout(() => bindShowEditMuzicButtons(muzicId, muzicName, dataExists), 5); +} diff --git a/frontend/public/js/sound.js b/frontend/public/js/sound.js index 870a748..7aa70db 100644 --- a/frontend/public/js/sound.js +++ b/frontend/public/js/sound.js @@ -1,4 +1,4 @@ -let audio = new Audio('/api/v/1.0/muzic'); +let audio = new Audio("/api/v/1.0/muzic"); function stopMuzic(id, interval) { audio.pause(); @@ -6,7 +6,7 @@ function stopMuzic(id, interval) { document.getElementById(`play-${id}`).innerText = "Прослушать"; document.getElementById(`pause-${id}`).disabled = true; document.getElementById(`play-${id}`).onclick = () => playMuzic(id); - + clearInterval(interval); document.getElementById(`road-${id}`).value = 0; document.getElementById(`road-${id}`).max = 0; @@ -26,18 +26,15 @@ function resumeMuzic(id) { audio.play(); } -function changeTime (value, id) { +function changeTime(value, id) { audio.currentTime = value; } function playMuzic(id) { audio.pause(); audio.currentTime = 0; - if (audio.muzId !== undefined) stopMuzic( - audio.muzId, - audio.muzTimer - ); - + if (audio.muzId !== undefined) stopMuzic(audio.muzId, audio.muzTimer); + audio = new Audio(`/api/v/1.0/muzic?id=${id}`); audio.onloadedmetadata = function () { audio.muzId = id; @@ -45,17 +42,18 @@ function playMuzic(id) { document.getElementById(`pause-${id}`).disabled = false; document.getElementById(`road-${id}`).max = audio.duration; audio.play(); - + const interval = setInterval(() => { document.getElementById(`road-${id}`).value = audio.currentTime; }, 750); audio.muzTimer = interval; - document.getElementById(`play-${id}`).onclick = () => stopMuzic(id, interval); + document.getElementById(`play-${id}`).onclick = () => + stopMuzic(id, interval); document.getElementById(`pause-${id}`).onclick = () => pauseMuzic(id); - + document.getElementById(`road-${id}`).onchange = function () { // console.log('value', this.value); - changeTime(this.value, id) + changeTime(this.value, id); }; - } -} \ No newline at end of file + }; +} diff --git a/page-view.js b/page-view.js index 5c38b71..a278794 100644 --- a/page-view.js +++ b/page-view.js @@ -1,11 +1,9 @@ -const router = require('express').Router(); -const fs = require('fs'); -router.use(require('express').static('./frontend/public')); +const router = require("express").Router(); +const fs = require("fs"); +router.use(require("express").static("./frontend/public")); -router.get('/', async (req, res) => { - res.send( - fs.readFileSync("./frontend/main.html", { encoding: "utf-8" }) - ); -}) +router.get("/", async (req, res) => { + res.send(fs.readFileSync("./frontend/main.html", { encoding: "utf-8" })); +}); -module.exports = router; \ No newline at end of file +module.exports = router; diff --git a/server.js b/server.js index 07ce737..c95caa9 100644 --- a/server.js +++ b/server.js @@ -90,4 +90,4 @@ server.listen(config().port, config().address, async (err) => { `Kodex Muzic catalog runned at ${config().address}:${config().port}`, ); } -}); \ No newline at end of file +});