diff --git a/.gitignore b/.gitignore index 30bc162..070ad53 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -/node_modules \ No newline at end of file +/node_modules +/uploads/media +/uploads/songs.json \ No newline at end of file diff --git a/README.md b/README.md index abdafca..de54b01 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ Плеер, чтобы слушать свою музыку -Готовность: ~10% +Готовность: ~16% + +На данный момент актуальная и рабочая версия. diff --git a/app old.js b/app old.js deleted file mode 100644 index f89ac16..0000000 --- a/app old.js +++ /dev/null @@ -1,167 +0,0 @@ -let songs = [] - -const getSongs = async () => { - try { - const response = await fetch("http://localhost:7999/songs.json") - songs = await response.json() - renderSongs(songs) - renderPlayer(songs) - } catch (error) { - console.error(error) - } -} - -const renderSongs = (songs) => { - console.log(songs); - - const songsWrapper = document.querySelector(".songsWrapper"); - songsWrapper.innerHTML = songs.map(song => { - return `
-
- Постер музыкальной композиции -
-
-

${song.name}

-

${song.artist}

-
-
- `; - }).join(""); -} - -const renderPlayer = () => { - const myAudio = new Audio(); - - let currentSongIndex = 0; - - myAudio.volume = 0.2; - - // Находим ползунок громкости - const volumeSlider = document.getElementById("volumeSlider"); - // Находим ползунок длительности - const progressSlider = document.getElementById("progressSlider"); - - const playButton = document.querySelector(".player__control__play"); - const prevButton = document.querySelector(".player__control__prev"); - const nextButton = document.querySelector(".player__control__next"); - const coverImage = document.querySelector(".player__cover__img"); - const titleText = document.querySelector(".player__info h3"); - const artistText = document.querySelector(".player__info h4"); - const durationText = document.querySelector(".player__control__duration__2"); - - // Проверка на загрузку песен - if (!songs || songs.length === 0) { - console.error("Список песен пуст или не загружен."); - return; - } - - // Обновление информации о треке - const updatePlayerInfo = (song) =>{ - if (!song) return; - console.log("Обновление информации о треке:", song); - coverImage.src = song.cover; - titleText.textContent = song.name; - artistText.textContent = song.artist; - console.log(titleText); - - myAudio.src = song.link; - } - - // Запуск текущей песни - const playSong = () => { - myAudio.play(); - playButton.textContent = "Пауза"; - } - - // Пауза текущей песни - const pauseSong = () => { - myAudio.pause(); - playButton.textContent = "Играть"; - } - - // Переключение на другую песню - const playNextSong = () => { - currentSongIndex = (currentSongIndex + 1) % songs.length; - updatePlayerInfo(songs[currentSongIndex]); - playSong(); - } - - // Переключение на новую песню - const playPrevSong = () => { - currentSongIndex = (currentSongIndex - 1 + songs.length) % songs.length; - updatePlayerInfo(songs[currentSongIndex]); - playSong(); - } - - // Обработчик событий для кнопки - playButton.addEventListener("click", () => { - if (myAudio.pause){ - playSong(); - } else { - playSong(); - } - }) - - - prevButton.addEventListener("click", playPrevSong); - nextButton.addEventListener("click", playNextSong); - - // Обновление прогресса песни - myAudio.addEventListener("timeupdate", () => { - const progress = (myAudio.currentTime / myAudio.duration) * 100; - progressSlider.value = progress; - - // Обновление отображения длительности - const minute = Math.floor(myAudio.currentTime / 60); - const second = Math.floor(myAudio.currentTime % 60).toString().padStart(2,"0"); - durationText.textContent = `${minute}:${second}` - }); - - - // Перемотка песни - progressSlider.addEventListener('input', (event) => { - const seekTime = (event.target.value / 100) * myAudio.duration; - myAudio.currentTime = seekTime; - }); - - // Загрузка первой песни - updatePlayerInfo(songs[currentSongIndex]); - - // Отладка: проверим, что кнопки рендерятся и клики работают - document.querySelectorAll('.js-music-btn').forEach(songElement => { - songElement.addEventListener('click', (event) => { - const audioUrl = event.currentTarget.getAttribute('data-url'); - console.log("Воспроизведение трека с URL:", audioUrl); - - if (myAudio.src !== audioUrl) { - myAudio.src = audioUrl; - } - myAudio.play().catch(error => console.error("Ошибка воспроизведения:", error)); - }); - }); - - // // Обрабатываем изменение ползунка - // volumeSlider.addEventListener("input", (event) => { - // myAudio.volume = event.target.value; - // console.log("Громкость:", myAudio.volume); // Отладка - // }); - - // // Обновление прогресса ползунка в зависимости от времени воспроизведения - // myAudio.addEventListener("timeupdate", () => { - // const progress = (myAudio.currentTime / myAudio.duration) * 100; - // progressSlider.value = progress; - // }) - - - - // Обновляем ползунок для загрузки новой песни - myAudio.addEventListener("loadedmetadata", () => { - progressSlider.max = 100; - }) -}; - -document.addEventListener('DOMContentLoaded', () => { - getSongs(); -}); - - diff --git a/app.js b/app.js deleted file mode 100644 index 7a68e94..0000000 --- a/app.js +++ /dev/null @@ -1,221 +0,0 @@ -let songs = []; -let currentSongIndex = 0; -let myAudio = new Audio(); -myAudio.volume = localStorage.getItem('volume'); - -const getSongs = async () => { - try { - const response = await fetch("http://localhost:7999/songs.json"); - songs = await response.json(); - console.log("Загруженные песни:", songs); // Проверка загрузки данных - - if (songs && songs.length > 0) { - renderSongs(songs); - updatePlayerInfo(songs[currentSongIndex]); - } else { - console.error("Файл песен пуст или не содержит данных."); - } - } catch (error) { - console.error("Ошибка загрузки песен:", error); - } -}; - -const renderSongs = (songs) => { - const songsWrapper = document.querySelector(".songsWrapper"); - if (!songsWrapper) { - console.error("Контейнер .songsWrapper не найден на странице."); - return; - } - - songsWrapper.innerHTML = songs.map((song, index) => ` -
-
Cover
-
-

${song.name}

${song.artist}

-
-
- `).join(""); - - // Обработчики кликов на каждой песне - document.querySelectorAll(".js-music-btn").forEach(button => { - button.addEventListener("click", (event) => { - currentSongIndex = parseInt(event.currentTarget.dataset.index); - updatePlayerInfo(songs[currentSongIndex]); - playSong(); - console.log("Песня выбрана:", songs[currentSongIndex]); // Проверка выбранной песни - }); - }); -}; - - - - -// Сохранение плеера при переходе между вкладками -// -// -// - -// Сохраняем состояние плеера -const savePlayerState = () => { - const state = { - currentSongIndex, - currentTime: myAudio.currentTime, - isPlaying: !myAudio.paused - }; - localStorage.setItem("playerState", JSON.stringify(state)); -}; - -// Загрузка состояния плеера -const loadPlayerState = () => { - const state = JSON.parse(localStorage.getItem("playerState")); - if (state) { - currentSongIndex = state.currentSongIndex; - updatePlayerInfo(songs[currentSongIndex]); // Обновляем данные плеера - myAudio.currentTime = state.currentTime; - if (state.isPlaying) playSong(); - } -}; - -window.addEventListener("beforeunload", savePlayerState); - -document.addEventListener("DOMContentLoaded", () => { - getSongs().then(() => loadPlayerState()); -}); - -myAudio.addEventListener("timeupdate", savePlayerState); -document.querySelector(".player__control__next").addEventListener("click", () => { - playNextSong(); - savePlayerState(); -}); -document.querySelector(".player__control__prev").addEventListener("click", () => { - playPrevSong(); - savePlayerState(); -}); - -// -// -// -// Конец этой части когда - - -// Функция для сортировки -const sortSongs = (criterion) => { - songs.sort((a, b) => { - if (criterion === "name") { - return a.name.localeCompare(b.name); - } else if (criterion === "artist") { - return a.artist.localeCompare(b.artist); - } else if (criterion === "id") { - return a.id.localeCompare(b.id) // Предполагается, что длительность в секундах или миллисекундах - } - }); - renderSongs(songs); // Перерисовываем список -}; - -// Обработчик изменения выбора сортировки -document.getElementById("sort").addEventListener("change", (event) => { - const selectedCriterion = event.target.value; - sortSongs(selectedCriterion); -}); - - -// Функция для фильтрации песен по запросу -const searchSongs = (query) => { - const filteredSongs = songs.filter(song => - song.name.toLowerCase().includes(query.toLowerCase()) || - song.artist.toLowerCase().includes(query.toLowerCase()) - ); - renderSongs(filteredSongs); // Перерисовываем список с отфильтрованными песнями -}; - -document.getElementById("searchInput").addEventListener("input", (event) => { - const query = event.target.value; - searchSongs(query); -}); - - -// Обновление информации у плеера -const updatePlayerInfo = (song) => { - - document.querySelector(".player__cover_img").src = song.cover; - document.querySelector(".player__info__title").textContent = song.name; - document.querySelector(".player__info__artist").textContent = song.artist; - - console.log('Максимальное время воспроизведения в секундах', myAudio.duration); - - myAudio.src = song.link; - console.log("Информация о текущем треке обновлена:", song); - console.log("Текущий аудиофайл:", song.audio); // Проверка пути к файлу -}; - -const playSong = () => { - myAudio.play(); - document.querySelector(".player__control__play").innerHTML = ``; -}; - -const pauseSong = () => { - myAudio.pause(); - document.querySelector(".player__control__play").innerHTML = ``; -}; - -const playNextSong = () => { - currentSongIndex = (currentSongIndex + 1) % songs.length; - updatePlayerInfo(songs[currentSongIndex]); - playSong(); -}; - -const playPrevSong = () => { - currentSongIndex = (currentSongIndex - 1 + songs.length) % songs.length; - updatePlayerInfo(songs[currentSongIndex]); - playSong(); -}; - -const autoNextSong = () => { - if (myAudio.currentTime == myAudio.duration) { - playNextSong(); - } -} - - -document.querySelector(".player__control__play").addEventListener("click", () => { - if (myAudio.paused) { - playSong(); - } else { - pauseSong(); - } -}); - -// Кнопки переключения песни -document.querySelector(".player__control__next").addEventListener("click", playNextSong); -document.querySelector(".player__control__prev").addEventListener("click", playPrevSong); - -// Ползунок регулеровки громкости -document.getElementById("volumeSlider").addEventListener("input", (event) => { - myAudio.volume = event.target.value; - localStorage.setItem('volume', myAudio.volume); -}); - - -// Цифровое отображение времени песни -myAudio.addEventListener("timeupdate", () => { - const progress = (myAudio.currentTime / myAudio.duration) * 100; - document.getElementById("progressSlider").value = progress; - console.log('Текущее время воспроизведения в секундах', myAudio.currentTime); - - const minutes = Math.floor(myAudio.currentTime / 60); - const seconds = Math.floor(myAudio.currentTime % 60).toString().padStart(2, "0"); - - const minute_2 = Math.floor(myAudio.duration / 60); - const seconds_2 = Math.floor(myAudio.duration % 60).toString().padStart(2,"0"); - - document.querySelector(".player__control__duration__2").textContent = `${minute_2}:${seconds_2}`; - document.querySelector(".player__control__duration__1").textContent = `${minutes}:${seconds}`; - autoNextSong(); -}); - -// Отображение прогресса песни в виде полосы -document.getElementById("progressSlider").addEventListener("input", (event) => { - myAudio.currentTime = (event.target.value / 100) * myAudio.duration; -}); - -document.addEventListener("DOMContentLoaded", getSongs); \ No newline at end of file diff --git a/catalog.html b/catalog.html deleted file mode 100644 index 1439914..0000000 --- a/catalog.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - Заголовок страницы - - - - - - - - -
-
-

- Personal Music -

- -
-
- - - -
-
- -
- - -
-
-
- -
- -
-
-
- Cover трека -
-
-

Название трека

-

Автор трека

-
-
-
-
- - - - -
-
-

Длительность трека

- -

Длительность трека

-
-
-
- -
-
- -
- - - - \ No newline at end of file diff --git a/css/add_songs.css b/css/add_songs.css new file mode 100644 index 0000000..e94b240 --- /dev/null +++ b/css/add_songs.css @@ -0,0 +1,60 @@ +.all { + justify-items: center; + background: rgba(255, 255, 255, 0.3); + box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); + backdrop-filter: blur(10px); + border-radius: 8px; + padding-bottom: 5vh; + padding-top: 4vh; + color: white; + text-shadow: 0 0 5px rgba(0, 0, 0, 0.8); +} + +.mainForm { + margin: auto; + width: 400px; + display: flex; + flex-direction: column; +} + +.input__text { + -webkit-appearance: none; + appearance: none; + border-radius: 4px; + background: rgba(255, 255, 255, 0.5); + box-shadow: 0 0 5px rgba(0, 0, 0, 0.5); + border: none; + height: 2vh; + margin-top: 1vh; +} + +.input__upload { + border-radius: 4px; + background: none; + border: none; + height: 2vh; + margin-top: 1vh; +} + +.input__upload::-webkit-file-upload-button { + -webkit-appearance: none; + appearance: none; + background-color: rgba(255, 255, 255, 0.5); + box-shadow: 0 0 5px rgba(0, 0, 0, 0.5); + border-radius: 4; + height: 2vh; + border: none; + margin-right: 2vh; +} + +.btn__submit { + margin-top: 1vh; + -webkit-appearance: none; + appearance: none; + background: rgba(255, 255, 255, 0.5); + box-shadow: 0 0 5px rgba(0, 0, 0, 0.5); + border: none; + border-radius: 4PX; + height: 2.2vh; + color: rgb(99, 97, 97); +} \ No newline at end of file diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..b689796 --- /dev/null +++ b/css/style.css @@ -0,0 +1,311 @@ +/* Общие стили */ +body { + font-family: Arial, sans-serif; + margin: 0; + padding: 0; + background: rgba(0, 0, 0, 0.87); + color: #fff; + display: flex; + flex-direction: column; + align-items: center; +} + +.header { + min-width: none; + max-width: 80vw; + width: 100%; + margin-top: 1vh; + margin-bottom: 1vh; + border-radius: 20px; + padding: 15px; + background: rgba(255, 69, 0, 0.8); /* Красноватый оттенок с прозрачностью */ + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); + backdrop-filter: blur(10px); + text-align: center; +} + +.header h2 { + font-size: 1.8em; + font-weight: bold; + margin: 0; +} + +.menu a { + color: #fff; + margin: 0 15px; + font-weight: 500; + text-decoration: none; + padding: 5px 10px; + border-radius: 20px; + transition: background 0.3s; +} + +.menu a:hover { + background: rgba(255, 255, 255, 0.2); +} + +#content { + margin: auto; + width: 100%; + max-width: 800px; +} + +/* Стиль для списка треков */ +.songsWrapper { + width: 100%; + margin: 20px 0; + margin-bottom: 130px; + display: flex; + flex-direction: column; + justify-content: space-between; + gap: 15px; +} + +.song { + display: flex; + flex: 1; + align-items: center; + padding: 10px; + background: rgba(255, 255, 255, 0.1); + border-radius: 10px; + cursor: pointer; + transition: background 0.3s; +} + +.song:hover { + background: rgba(255, 255, 255, 0.2); +} + +.song img { + width: 70px; + height: 70px; + border-radius: 10px; + object-fit: cover; + margin-right: 15px; + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3); +} + +.song h3 { + font-size: 1.1em; + margin: 0; + color: #ffd700; +} + +.song h4 { + font-size: 0.9em; + margin: 0; + color: #fff; + opacity: 0.8; +} + +/* Стиль аудиоплеера */ +.audio-player { + position: fixed; + bottom: 20px; + width: 100%; + min-width: 40vw; + max-width: 80vw; + padding: 15px; + background: rgba(255, 255, 255, 0.2); + box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2); + backdrop-filter: blur(10px); + border-radius: 20px; + display: flex; + align-items: center; + justify-content: space-between; + color: #fff; +} + +/* Обложка трека в плеере */ +.player__cover_img { + width: 60px; + height: 60px; + border-radius: 10px; + object-fit: cover; + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3); + margin-right: 15px; +} + +.player__left { + flex: 1; + display: flex; + flex-direction: row; + align-items: center; + min-width: 0; + margin-right: 20px; +} + +/* Информация о треке */ +.player__info { + flex: 1; + display: flex; + flex-direction: column; + min-width: 0; + margin-right: 20px; +} + +.player__info__title { + font-size: 1.2em; + font-weight: bold; + color: #ffd700; + margin: 0; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.player__info__artist { + font-size: 0.9em; + margin: 0; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +/* Общий блок кнопок и полосы прогресса */ +.player__center { + display: flex; + flex: 1; + flex-direction: column; + justify-content: space-between; +} + +/* Полоса прогресса и время */ +.player__progress { + display: flex; + align-items: center; + justify-content: center; + flex: 1; + margin-top: 0.5vh; +} + +#progressSlider { + -webkit-appearance: none; + appearance: none; + height: 6px; + background: rgba(255, 255, 255, 0.5); + border-radius: 5px; + outline: none; + width: 100%; + margin: 0 10px; + cursor: pointer; + transition: border 0.3s; +} + +#progressSlider::-webkit-slider-runnable-track { + background: linear-gradient(to right, #FF5733 0%, #FF5733 var(--value, 50%), #ddd var(--value, 50%), #ddd 100%); + border-radius: 5px; +} + + +#progressSlider::-webkit-slider-thumb { + -webkit-appearance: none; + appearance: none; + width: 0px; + height: 8px; + background: #FF5733; + border-radius: 50%; + cursor: pointer; + box-shadow: 0 0 5px rgba(0, 0, 0, 0.5); + transition: width 0.3s, height 0.3s; +} + +.player__progress span { + font-size: 0.8em; + min-width: 35px; + text-align: center; +} + +/* Управление громкостью */ +.player__volume { + display: flex; + justify-content: flex-end; + align-items: center; + flex: 1; +} + +.player__right { + right: 0; +} + +#volumeSlider { + -webkit-appearance: none; + appearance: none; + height: 6px; + background: rgba(255, 255, 255, 0.5); + border-radius: 5px; + outline: none; + width: 80px; + cursor: pointer; +} + +#volumeSlider::-webkit-slider-thumb { + -webkit-appearance: none; + appearance: none; + width: 12px; + height: 12px; + background: #FF5733; + border-radius: 50%; + cursor: pointer; + box-shadow: 0 0 5px rgba(0, 0, 0, 0.5); +} + +/* Кнопки управления плеером */ +.player__control { + margin: auto; + display: flex; + align-items: center; + gap: 12px; +} + +.player__control button { + background: rgba(255, 87, 51, 0.8); + border: none; + color: #fff; + padding: 8px 15px; + margin: 0 5px; + border-radius: 16px; + cursor: pointer; + font-size: 0.9em; + transition: background 0.3s; +} + +.player__control button:hover { + background: rgba(255, 87, 51, 1); +} + +.player__control button:focus { + outline: none; +} + +.active { + background: rgba(255, 248, 55, 0.5) !important; + border: 1px solid black; +} + +.active:hover { + background: rgba(255, 248, 55, 0.2) !important; +} + +/* -------------------------------------------------- Дальше файл tracks --------------------------------- */ + + +.search { + width: 100%; /* Растягиваем input на всю ширину контейнера */ + height: 30px; + box-sizing: border-box; /* Учитываем отступы и границы в ширину */ + border-radius: 4px; /* Закругленные углы */ + padding: 4px; + background: rgba(255, 255, 255, 0.1); + margin-bottom: 1vh; + transition: background 0.3s; +} + + +.search input{ + appearance: none; + width: 100%; + background: none; + border: none; + outline: none; +} \ No newline at end of file diff --git a/index.html b/index.html index 7182942..d409e85 100644 --- a/index.html +++ b/index.html @@ -1,31 +1,66 @@ - - + + - Заголовок страницы - - - - - + Мой музыкальный плеер + + + +
-
-

- Personal Music -

- -
+

Personal Music

+
- - -
- - + + +
+

Добро пожаловать на страницу с музыкой!

- \ No newline at end of file + + +
+
+
+ Обложка трека +
+
+

Название трека

+

Автор трека

+
+
+
+ +
+ + + + + +
+ + +
+ 0:00 + + 0:00 +
+
+ + +
+
+ + +
+
+
+ + + + diff --git a/js/main.js b/js/main.js new file mode 100644 index 0000000..392dc0c --- /dev/null +++ b/js/main.js @@ -0,0 +1,31 @@ +import { loadTracksPage, loadVisualizerPage, loadAddSongsPage } from './navigation.js'; +import { togglePlayPause, playNextSong, playPreviousSong, } from './player.js'; + + + +// Основная инициализация +document.addEventListener("DOMContentLoaded", () => { + loadTracksPage(); // Загружаем страницу треков при первой загрузке + + // Навигация по страницам + document.addEventListener("click", (e) => { + if (e.target.classList.contains("nav-link-tracks")) { + e.preventDefault(); + console.log('Загрузка страницы с треками'); + loadTracksPage(); + } + else if (e.target.classList.contains("nav-link-visualizer")) { + e.preventDefault(); + loadVisualizerPage(); + } + else if (e.target.classList.contains("nav-link-add-songs")) { + e.preventDefault(); + loadAddSongsPage(); + } + }); + + // Управление плеером + document.getElementById("play-pause").addEventListener("click", togglePlayPause); + document.getElementById("next").addEventListener("click", playNextSong); + document.getElementById("prev").addEventListener("click", playPreviousSong); +}); diff --git a/js/navigation.js b/js/navigation.js new file mode 100644 index 0000000..8812cb4 --- /dev/null +++ b/js/navigation.js @@ -0,0 +1,59 @@ +import { getSongs, searchSongs } from './tracks.js'; +import { AddNewSongs } from './upload.js'; +import { startVisualizer } from './visualizer.js'; + +// Загружаем страницу треков +export const loadTracksPage = async () => { + try { + const response = await fetch("pages/tracks.html"); + if (!response.ok) throw new Error(`Ошибка: ${response.status}`); + const html = await response.text(); + document.getElementById("content").innerHTML = html; + + // Загружаем и отображаем треки + await getSongs(); + console.log("Страница треков загружена"); + + // Привязываем обработчик для поиска после загрузки track.html + const searchInput = document.getElementById("searchInput"); + if (searchInput) { + searchInput.addEventListener("input", (event) => { + searchSongs(event.target.value); + }); + } + } catch (error) { + console.error("Ошибка загрузки страницы треков:", error); + } +}; + +// Загружаем страницу визуализатора +export const loadVisualizerPage = async () => { + try { + const response = await fetch("visualizer.html"); + if (!response.ok) throw new Error(`Ошибка: ${response.status}`); + const html = await response.text(); + document.getElementById("content").innerHTML = html; + + // Инициализируем визуализатор, если canvas доступен + const audioContext = new (window.AudioContext || window.webkitAudioContext)(); + const visualizerAudio = document.querySelector("audio"); + if (visualizerAudio) startVisualizer(visualizerAudio, audioContext); + console.log("Страница визуализатора загружена"); + } catch (error) { + console.error("Ошибка загрузки страницы визуализатора:", error); + } +}; + +// Загружаем страницу добавления треков +export const loadAddSongsPage = async () => { + try { + const response = await fetch("pages/add-songs.html"); + if (!response.ok) throw new Error(`Ошибка: ${response.status}`); + const html = await response.text(); + document.getElementById("content").innerHTML = html; + AddNewSongs(); // Настройка формы для загрузки треков + console.log("Страница добавления треков загружена"); + } catch (error) { + console.error("Ошибка загрузки страницы добавления треков:", error); + } +}; diff --git a/js/player.js b/js/player.js new file mode 100644 index 0000000..837d22f --- /dev/null +++ b/js/player.js @@ -0,0 +1,120 @@ +import { formatTime, updateBackground } from './utils.js'; + +let myAudio = new Audio(); +let currentSongIndex = 0; +let songs = []; +let isPlaying = false; +let rangeInput = document.getElementById('progressSlider'); + +export const initializePlayer = (loadedSongs) => { + songs = loadedSongs; + const savedState = JSON.parse(localStorage.getItem("playerState")); + + // Восстанавливаем состояние плеера, если оно сохранено + if (savedState) { + currentSongIndex = savedState.currentSongIndex; + myAudio.currentTime = savedState.currentTime || 0; + updateBackground(rangeInput); + updatePlayerInfo(songs[currentSongIndex]); + isPlaying = savedState.isPlaying; + if (isPlaying) { + document.getElementById("play-pause").innerHTML = ``; + myAudio.play(); + } + } else { + updatePlayerInfo(songs[currentSongIndex]); + } + + myAudio.volume = localStorage.getItem('volume') || 0.5; + savePlayerState(); // Сохраняем начальное состояние + console.log('Вот он - localeStorage',savedState, localStorage.getItem('volume')); +}; + +export const updatePlayerInfo = (song) => { + document.querySelector(".player__cover_img").src = song.cover; + document.querySelector(".player__info__title").textContent = song.title; + document.querySelector(".player__info__artist").textContent = song.artist; + myAudio.src = song.audio; +}; + +const autoPlay = (currentTime,duration) => { + if (currentTime === duration) { + currentSongIndex = currentSongIndex + 1; + playSong(songs[currentSongIndex]); + } +} + +// Сохранение состояния плеера в localStorage +const savePlayerState = () => { + const state = { + currentSongIndex, + currentTime: myAudio.currentTime, + isPlaying: !myAudio.paused + }; + localStorage.setItem("playerState", JSON.stringify(state)); + console.log("Сохранение в localestorage сработало", state); +}; + +// Добавляем обработчики событий для сохранения состояния +myAudio.addEventListener("timeupdate", savePlayerState); +myAudio.addEventListener("pause", savePlayerState); +myAudio.addEventListener("play", savePlayerState); + +export const getIndex = (index) => { + currentSongIndex = index; + console.log('Получение индекса',index, currentSongIndex); +} + +export const playSong = (song) => { + console.log('Инфа о песне', song); + document.getElementById("play-pause").innerHTML = ``; + updatePlayerInfo(song); + myAudio.play(); +}; + +export const togglePlayPause = () => { + if (myAudio.paused) { + myAudio.play(); + document.getElementById("play-pause").innerHTML = ``; + } else { + myAudio.pause(); + document.getElementById("play-pause").innerHTML = ``; + } +}; + +export const playNextSong = () => { + currentSongIndex = (currentSongIndex + 1) % songs.length; + console.log('Текущий индекс песни в playsong', currentSongIndex); + playSong(songs[currentSongIndex]); +}; + +export const playPreviousSong = () => { + currentSongIndex = (currentSongIndex - 1 + songs.length) % songs.length; + playSong(songs[currentSongIndex]); +}; + +// Обработка изменения прогресса трека +myAudio.addEventListener("timeupdate", () => { + const currentTime = myAudio.currentTime; + const duration = myAudio.duration; + const progress = (currentTime / duration) * 100; + updateBackground(rangeInput); + autoPlay(currentTime, duration); + document.getElementById("progressSlider").value = progress; + document.getElementById("currentTime").textContent = formatTime(currentTime); + document.getElementById("totalTime").textContent = formatTime(duration); +}); + +// Обработка изменения ползунка прогресса +document.getElementById("progressSlider").addEventListener("input", (event) => { + const value = event.target.value; + myAudio.currentTime = (value / 100) * myAudio.duration; +}); + +// Управление громкостью +document.getElementById("volumeSlider").addEventListener("input", (event) => { + myAudio.volume = event.target.value; + localStorage.setItem('volume', myAudio.volume); + console.log('ГРОМКОСТЬ после двигания', localStorage.getItem('volume')); + +}); diff --git a/js/search.js b/js/search.js new file mode 100644 index 0000000..20a7118 --- /dev/null +++ b/js/search.js @@ -0,0 +1,13 @@ +// Функция для фильтрации песен по запросу +export const searchSongs = (songs ,query) => { + const filteredSongs = songs.filter(song => + song.name.toLowerCase().includes(query.toLowerCase()) || + song.artist.toLowerCase().includes(query.toLowerCase()) + ); + renderSongs(filteredSongs); // Перерисовываем список с отфильтрованными песнями +}; + +document.getElementById("searchInput").addEventListener("input", (event) => { + const query = event.target.value; + searchSongs(query); +}); \ No newline at end of file diff --git a/js/tracks.js b/js/tracks.js new file mode 100644 index 0000000..f05f2ca --- /dev/null +++ b/js/tracks.js @@ -0,0 +1,53 @@ +import { playSong, initializePlayer, getIndex } from './player.js'; + +let songs = []; // Полный список треков +let filteredSongs = []; // Отфильтрованный список треков (на основе поиска) + +export const getSongs = async () => { + try { + if (songs.length === 0) { + const response = await fetch("../uploads/songs.json"); + songs = await response.json(); + filteredSongs = songs; + renderSongs(filteredSongs) + initializePlayer(filteredSongs) + } else { + renderSongs(filteredSongs); + } + } catch (error) { + console.error("Ошибка загрузки песен:", error); + } +}; + +export const renderSongs = (songs) => { + const wrapper = document.getElementById("songsWrapper"); + wrapper.innerHTML = songs.map((song, index) => ` +
+ cover +
+

${song.title}

+

${song.artist}

+
+
+ `).join(""); + + document.querySelectorAll(".song").forEach((songElement, index) => { + songElement.addEventListener("click", () => { + getIndex(index) + console.log('индекс', index); + + playSong(songs[index]); + }); + }); +}; + +// Функция для фильтрации треков на основе поискового запроса +export const searchSongs = (query) => { + query = query.toLowerCase(); + filteredSongs = songs.filter(song => + song.title.toLowerCase().includes(query) || + song.artist.toLowerCase().includes(query) + ); + initializePlayer(filteredSongs); + renderSongs(filteredSongs); // Перерисовываем список на основе результатов поиска +}; \ No newline at end of file diff --git a/js/upload.js b/js/upload.js new file mode 100644 index 0000000..2022782 --- /dev/null +++ b/js/upload.js @@ -0,0 +1,28 @@ +export const AddNewSongs = () => { + document.getElementById('uploadForm').addEventListener('submit', function (event) { + event.preventDefault(); + + const title = document.getElementById('title').value; + const artist = document.getElementById('artist').value; + const audioFile = document.getElementById('audio').files[0]; + const cover = document.getElementById('cover').value; + + const formData = new FormData(); + formData.append('title', title); + formData.append('artist', artist); + formData.append('audio', audioFile); + formData.append('cover', cover); + + fetch('http://127.0.0.1:5000/upload', { + method: 'POST', + body: formData + }) + .then(response => response.json()) + .then(data => { + document.getElementById('message').innerText = data.message; + }) + .catch(error => { + document.getElementById('message').innerText = 'Error: ' + error.message; + }); + }); +}; diff --git a/js/utils.js b/js/utils.js new file mode 100644 index 0000000..ac551e1 --- /dev/null +++ b/js/utils.js @@ -0,0 +1,34 @@ +export const formatTime = (time) => { + const minutes = Math.floor(time / 60); + const seconds = Math.floor(time % 60).toString().padStart(2, "0"); + return `${minutes}:${seconds}`; +}; + +export const shuffle = (array) => { + for (let i = array.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [array[i], array[j]] = [array[j], array[i]]; + } + return array; +}; + +// Изменение цвета вслед за точкой на временной шкале + + +// Функция для обновления значения кастомного свойства CSS +export function updateBackground(rangeInput) { + const value = rangeInput.value; + const min = rangeInput.min ? rangeInput.min : 0; + const max = rangeInput.max ? rangeInput.max : 100; + const percentage = (value - min) / (max - min) * 100; + + rangeInput.addEventListener('mousedown', function () { + rangeInput.style.setProperty('--thumb-width', '10px'); + }) + + rangeInput.addEventListener('mouseup', function () { + rangeInput.style.setProperty('--thumb-width', '0px'); + }) + + rangeInput.style.setProperty('--value', `${percentage}%`); +} \ No newline at end of file diff --git a/js/visualizer.js b/js/visualizer.js new file mode 100644 index 0000000..d1bee92 --- /dev/null +++ b/js/visualizer.js @@ -0,0 +1,31 @@ +export const startVisualizer = (VisualizerAudio, audioContext) => { + const analyser = audioContext.createAnalyser(); + analyser.fftSize = 256; + + const source = audioContext.createMediaElementSource(VisualizerAudio); + source.connect(analyser); + analyser.connect(audioContext.destination); + + const canvas = document.getElementById("visualizerCanvas"); + const ctx = canvas.getContext("2d"); + + function renderFrame() { + requestAnimationFrame(renderFrame); + const bufferLength = analyser.frequencyBinCount; + const dataArray = new Uint8Array(bufferLength); + analyser.getByteFrequencyData(dataArray); + + ctx.clearRect(0, 0, canvas.width, canvas.height); + const barWidth = (canvas.width / bufferLength) * 2.5; + let x = 0; + + dataArray.forEach((value) => { + const barHeight = value / 2; + ctx.fillStyle = `rgb(${value + 100}, 50, 150)`; + ctx.fillRect(x, canvas.height - barHeight, barWidth, barHeight); + x += barWidth + 1; + }); + } + + renderFrame(); +}; diff --git a/media/ANNA TSUCHIYA - Rose.mp3 b/media/ANNA TSUCHIYA - Rose.mp3 deleted file mode 100644 index 23aa9a0..0000000 Binary files a/media/ANNA TSUCHIYA - Rose.mp3 and /dev/null differ diff --git a/media/Ado - Odo.mp3 b/media/Ado - Odo.mp3 deleted file mode 100644 index 0355831..0000000 Binary files a/media/Ado - Odo.mp3 and /dev/null differ diff --git a/media/Ado - Show.mp3 b/media/Ado - Show.mp3 deleted file mode 100644 index 09ffac2..0000000 Binary files a/media/Ado - Show.mp3 and /dev/null differ diff --git a/media/Ado - Unravel.mp3 b/media/Ado - Unravel.mp3 deleted file mode 100644 index cd35a97..0000000 Binary files a/media/Ado - Unravel.mp3 and /dev/null differ diff --git a/media/Ado - Usseewa.mp3 b/media/Ado - Usseewa.mp3 deleted file mode 100644 index db52081..0000000 Binary files a/media/Ado - Usseewa.mp3 and /dev/null differ diff --git a/media/Animadrop - Stuck in a Timeloop.mp3 b/media/Animadrop - Stuck in a Timeloop.mp3 deleted file mode 100644 index b16ac65..0000000 Binary files a/media/Animadrop - Stuck in a Timeloop.mp3 and /dev/null differ diff --git a/media/Apashe - Work (ft. Vo Williams).mp3 b/media/Apashe - Work (ft. Vo Williams).mp3 deleted file mode 100644 index 3f8c13d..0000000 Binary files a/media/Apashe - Work (ft. Vo Williams).mp3 and /dev/null differ diff --git a/media/Asper X - Bad Trip.mp3 b/media/Asper X - Bad Trip.mp3 deleted file mode 100644 index 837126f..0000000 Binary files a/media/Asper X - Bad Trip.mp3 and /dev/null differ diff --git a/media/BABYMETAL - BxMxC.mp3 b/media/BABYMETAL - BxMxC.mp3 deleted file mode 100644 index cb305db..0000000 Binary files a/media/BABYMETAL - BxMxC.mp3 and /dev/null differ diff --git a/media/BABYMETAL - Divine Attack - Shingeki.mp3 b/media/BABYMETAL - Divine Attack - Shingeki.mp3 deleted file mode 100644 index 03668cb..0000000 Binary files a/media/BABYMETAL - Divine Attack - Shingeki.mp3 and /dev/null differ diff --git a/media/BABYMETAL - Karate.mp3 b/media/BABYMETAL - Karate.mp3 deleted file mode 100644 index 59efaa6..0000000 Binary files a/media/BABYMETAL - Karate.mp3 and /dev/null differ diff --git a/media/BABYMETAL feat. F.HERO - PA PA YA!!.mp3 b/media/BABYMETAL feat. F.HERO - PA PA YA!!.mp3 deleted file mode 100644 index bb3fc49..0000000 Binary files a/media/BABYMETAL feat. F.HERO - PA PA YA!!.mp3 and /dev/null differ diff --git "a/media/BABYMETAL feat. Joakim Brod\303\251n - Oh! MAJINAI.mp3" "b/media/BABYMETAL feat. Joakim Brod\303\251n - Oh! MAJINAI.mp3" deleted file mode 100644 index 47ee39e..0000000 Binary files "a/media/BABYMETAL feat. Joakim Brod\303\251n - Oh! MAJINAI.mp3" and /dev/null differ diff --git a/media/Bad Omens - THE DEATH OF PEACE OF MIND.mp3 b/media/Bad Omens - THE DEATH OF PEACE OF MIND.mp3 deleted file mode 100644 index e935891..0000000 Binary files a/media/Bad Omens - THE DEATH OF PEACE OF MIND.mp3 and /dev/null differ diff --git "a/media/Creepy Nuts - \343\202\252\343\203\210\343\203\216\343\202\261(Otonoke).mp3" "b/media/Creepy Nuts - \343\202\252\343\203\210\343\203\216\343\202\261(Otonoke).mp3" deleted file mode 100644 index f6281f5..0000000 Binary files "a/media/Creepy Nuts - \343\202\252\343\203\210\343\203\216\343\202\261(Otonoke).mp3" and /dev/null differ diff --git a/media/Eurielle - City of the dead.mp3 b/media/Eurielle - City of the dead.mp3 deleted file mode 100644 index 5a4ad80..0000000 Binary files a/media/Eurielle - City of the dead.mp3 and /dev/null differ diff --git "a/media/FIZICA - \320\223\320\276\321\202\321\215\320\274 2.mp3" "b/media/FIZICA - \320\223\320\276\321\202\321\215\320\274 2.mp3" deleted file mode 100644 index 859f7c7..0000000 Binary files "a/media/FIZICA - \320\223\320\276\321\202\321\215\320\274 2.mp3" and /dev/null differ diff --git "a/media/FIZICA - \320\223\320\276\321\202\321\215\320\274 3.mp3" "b/media/FIZICA - \320\223\320\276\321\202\321\215\320\274 3.mp3" deleted file mode 100644 index 249f671..0000000 Binary files "a/media/FIZICA - \320\223\320\276\321\202\321\215\320\274 3.mp3" and /dev/null differ diff --git "a/media/FIZICA - \320\223\320\276\321\202\321\215\320\274.mp3" "b/media/FIZICA - \320\223\320\276\321\202\321\215\320\274.mp3" deleted file mode 100644 index 4ffcf13..0000000 Binary files "a/media/FIZICA - \320\223\320\276\321\202\321\215\320\274.mp3" and /dev/null differ diff --git "a/media/FIZICA - \320\247\320\276\320\272\320\265\321\200.mp3" "b/media/FIZICA - \320\247\320\276\320\272\320\265\321\200.mp3" deleted file mode 100644 index 58d161d..0000000 Binary files "a/media/FIZICA - \320\247\320\276\320\272\320\265\321\200.mp3" and /dev/null differ diff --git a/media/Falling In Reverse - ZOMBIFIED.mp3 b/media/Falling In Reverse - ZOMBIFIED.mp3 deleted file mode 100644 index ac6ba95..0000000 Binary files a/media/Falling In Reverse - ZOMBIFIED.mp3 and /dev/null differ diff --git "a/media/GroTTesque - \320\241\321\202\320\260\320\273\321\214\320\275\320\276\320\265 \321\201\320\265\321\200\320\264\321\206\320\265.mp3" "b/media/GroTTesque - \320\241\321\202\320\260\320\273\321\214\320\275\320\276\320\265 \321\201\320\265\321\200\320\264\321\206\320\265.mp3" deleted file mode 100644 index 54cb492..0000000 Binary files "a/media/GroTTesque - \320\241\321\202\320\260\320\273\321\214\320\275\320\276\320\265 \321\201\320\265\321\200\320\264\321\206\320\265.mp3" and /dev/null differ diff --git a/media/Halestorm - I Miss The Misery.mp3 b/media/Halestorm - I Miss The Misery.mp3 deleted file mode 100644 index 6aecad6..0000000 Binary files a/media/Halestorm - I Miss The Misery.mp3 and /dev/null differ diff --git a/media/Halsey - Control.mp3 b/media/Halsey - Control.mp3 deleted file mode 100644 index 67804b9..0000000 Binary files a/media/Halsey - Control.mp3 and /dev/null differ diff --git a/media/Hidden Citizens feat. Keeley Bumford - Immortalized.mp3 b/media/Hidden Citizens feat. Keeley Bumford - Immortalized.mp3 deleted file mode 100644 index 0192e3f..0000000 Binary files a/media/Hidden Citizens feat. Keeley Bumford - Immortalized.mp3 and /dev/null differ diff --git "a/media/Hidden Citizens feat. Ra\314\212nya - Let Me Out.mp3" "b/media/Hidden Citizens feat. Ra\314\212nya - Let Me Out.mp3" deleted file mode 100644 index 96118cf..0000000 Binary files "a/media/Hidden Citizens feat. Ra\314\212nya - Let Me Out.mp3" and /dev/null differ diff --git "a/media/Hidden Citizens feat. Ra\314\212nya - Paint It Black.mp3" "b/media/Hidden Citizens feat. Ra\314\212nya - Paint It Black.mp3" deleted file mode 100644 index 8da9941..0000000 Binary files "a/media/Hidden Citizens feat. Ra\314\212nya - Paint It Black.mp3" and /dev/null differ diff --git "a/media/Louna - \320\237\320\276\320\273\321\216\321\201\320\260.mp3" "b/media/Louna - \320\237\320\276\320\273\321\216\321\201\320\260.mp3" deleted file mode 100644 index 435ea2b..0000000 Binary files "a/media/Louna - \320\237\320\276\320\273\321\216\321\201\320\260.mp3" and /dev/null differ diff --git a/media/MIYAVI - Other Side.mp3 b/media/MIYAVI - Other Side.mp3 deleted file mode 100644 index 3efddfc..0000000 Binary files a/media/MIYAVI - Other Side.mp3 and /dev/null differ diff --git "a/media/Norma Tale - \320\232\320\270\321\201\321\202\320\276\321\207\320\272\320\260 II.mp3" "b/media/Norma Tale - \320\232\320\270\321\201\321\202\320\276\321\207\320\272\320\260 II.mp3" deleted file mode 100644 index 579ce25..0000000 Binary files "a/media/Norma Tale - \320\232\320\270\321\201\321\202\320\276\321\207\320\272\320\260 II.mp3" and /dev/null differ diff --git "a/media/RAVANNA - \320\226\320\263\320\270.mp3" "b/media/RAVANNA - \320\226\320\263\320\270.mp3" deleted file mode 100644 index dcca1e0..0000000 Binary files "a/media/RAVANNA - \320\226\320\263\320\270.mp3" and /dev/null differ diff --git "a/media/RAVANNA feat. Ai Mori - \320\232\320\276\320\274\320\260.mp3" "b/media/RAVANNA feat. Ai Mori - \320\232\320\276\320\274\320\260.mp3" deleted file mode 100644 index 58f38b4..0000000 Binary files "a/media/RAVANNA feat. Ai Mori - \320\232\320\276\320\274\320\260.mp3" and /dev/null differ diff --git a/media/RIOT - Overkill.mp3 b/media/RIOT - Overkill.mp3 deleted file mode 100644 index cd044c2..0000000 Binary files a/media/RIOT - Overkill.mp3 and /dev/null differ diff --git a/media/Rammstein - Sonne.mp3 b/media/Rammstein - Sonne.mp3 deleted file mode 100644 index 3219612..0000000 Binary files a/media/Rammstein - Sonne.mp3 and /dev/null differ diff --git a/media/SKYND - Chris Watts.mp3 b/media/SKYND - Chris Watts.mp3 deleted file mode 100644 index 9d9738d..0000000 Binary files a/media/SKYND - Chris Watts.mp3 and /dev/null differ diff --git a/media/SKYND - Elisa Lam.mp3 b/media/SKYND - Elisa Lam.mp3 deleted file mode 100644 index 460fddb..0000000 Binary files a/media/SKYND - Elisa Lam.mp3 and /dev/null differ diff --git a/media/SKYND - Jim Jones(2019).mp3 b/media/SKYND - Jim Jones(2019).mp3 deleted file mode 100644 index 368904d..0000000 Binary files a/media/SKYND - Jim Jones(2019).mp3 and /dev/null differ diff --git a/media/SKYND - Katherine Knight.mp3 b/media/SKYND - Katherine Knight.mp3 deleted file mode 100644 index 9f35337..0000000 Binary files a/media/SKYND - Katherine Knight.mp3 and /dev/null differ diff --git a/media/SKYND - Lay down your life.mp3 b/media/SKYND - Lay down your life.mp3 deleted file mode 100644 index ebbc4f7..0000000 Binary files a/media/SKYND - Lay down your life.mp3 and /dev/null differ diff --git a/media/SKYND - Michelle Carter.mp3 b/media/SKYND - Michelle Carter.mp3 deleted file mode 100644 index d0e1aaa..0000000 Binary files a/media/SKYND - Michelle Carter.mp3 and /dev/null differ diff --git a/media/SKYND - Richard Ramirez.mp3 b/media/SKYND - Richard Ramirez.mp3 deleted file mode 100644 index 3dc7676..0000000 Binary files a/media/SKYND - Richard Ramirez.mp3 and /dev/null differ diff --git a/media/SKYND - Tyler Hadley.mp3 b/media/SKYND - Tyler Hadley.mp3 deleted file mode 100644 index 9338dc6..0000000 Binary files a/media/SKYND - Tyler Hadley.mp3 and /dev/null differ diff --git a/media/SKYND feat. Bill $Aber - Columbine (feat. Bill $Aber).mp3 b/media/SKYND feat. Bill $Aber - Columbine (feat. Bill $Aber).mp3 deleted file mode 100644 index 9a1e2e2..0000000 Binary files a/media/SKYND feat. Bill $Aber - Columbine (feat. Bill $Aber).mp3 and /dev/null differ diff --git a/media/SKYND feat. Jonathan Davis - Gary Heidnik (feat. Jonathan Davis).mp3 b/media/SKYND feat. Jonathan Davis - Gary Heidnik (feat. Jonathan Davis).mp3 deleted file mode 100644 index a99da77..0000000 Binary files a/media/SKYND feat. Jonathan Davis - Gary Heidnik (feat. Jonathan Davis).mp3 and /dev/null differ diff --git a/media/blueberry - EVA 3.mp3 b/media/blueberry - EVA 3.mp3 deleted file mode 100644 index f832717..0000000 Binary files a/media/blueberry - EVA 3.mp3 and /dev/null differ diff --git "a/media/pyrokinesis - \320\233\320\265\320\263\320\265\320\275\320\264\320\260 \320\276 \320\221\320\276\320\263\320\270\320\275\320\265 \320\223\321\200\320\276\320\267.mp3" "b/media/pyrokinesis - \320\233\320\265\320\263\320\265\320\275\320\264\320\260 \320\276 \320\221\320\276\320\263\320\270\320\275\320\265 \320\223\321\200\320\276\320\267.mp3" deleted file mode 100644 index 39bcd18..0000000 Binary files "a/media/pyrokinesis - \320\233\320\265\320\263\320\265\320\275\320\264\320\260 \320\276 \320\221\320\276\320\263\320\270\320\275\320\265 \320\223\321\200\320\276\320\267.mp3" and /dev/null differ diff --git a/pages/add-songs.html b/pages/add-songs.html new file mode 100644 index 0000000..18d5b9f --- /dev/null +++ b/pages/add-songs.html @@ -0,0 +1,20 @@ + + + + +
+

Добавление новой песни

+
+
+ + + + + +
+
+
+
\ No newline at end of file diff --git a/pages/song_page.html b/pages/song_page.html new file mode 100644 index 0000000..e69de29 diff --git a/pages/tracks.html b/pages/tracks.html new file mode 100644 index 0000000..0cf0039 --- /dev/null +++ b/pages/tracks.html @@ -0,0 +1,7 @@ + + +
+ +
diff --git a/pages/visualizer.html b/pages/visualizer.html new file mode 100644 index 0000000..9276491 --- /dev/null +++ b/pages/visualizer.html @@ -0,0 +1,6 @@ + + + diff --git a/songs.json b/songs.json deleted file mode 100644 index 5283312..0000000 --- a/songs.json +++ /dev/null @@ -1,322 +0,0 @@ -[ - { - "id" : 1, - "cover" : "https://repository-images.githubusercontent.com/415407744/50faf33c-1ed7-4b37-be52-bde9decae2c9", - "artist" : "RIOT", - "name" : "Overkill", - "link" : "/media/RIOT - Overkill.mp3" - }, - { - "id" : 2, - "cover" : "https://avatars.mds.yandex.net/i?id=1860210a460d55628ad54c38cb0115b8_l-9783932-images-thumbs&n=13", - "artist" : "Ado", - "name" : "Show", - "link" : "/media/Ado - Show.mp3" - }, - { - "id" : 3, - "cover" : "https://images.genius.com/8daaaa0c73899597c9ff7e0e66b84f13.1000x1000x1.png", - "artist" : "Ado", - "name" : "Usseewa", - "link" : "/media/Ado - Usseewa.mp3" - }, - { - "id" : 4, - "cover" : "https://images.genius.com/57d901243d411351ca34035064a3f608.1000x1000x1.jpg", - "artist" : "BABYMETAL", - "name" : "BxMxC", - "link" : "/media/BABYMETAL - BxMxC.mp3" - }, - { - "id" : 5, - "cover" : "https://upload.wikimedia.org/wikipedia/ru/1/12/Babymetal_Divine_Attack_single_cover.jpg", - "artist" : "BABYMETAL", - "name" : "Divine Attack - Shingeki", - "link" : "/media/BABYMETAL - Divine Attack - Shingeki.mp3" - }, - { - "id" : 6, - "cover" : "https://i.ytimg.com/vi/9XGXzmz53uY/maxresdefault.jpg", - "artist" : "BABYMETAL", - "name" : "Karate", - "link" : "/media/BABYMETAL - Karate.mp3" - }, - { - "id" : 7, - "cover" : "https://avatars.yandex.net/get-music-content/163479/6bd01cd7.a.7797117-1/m1000x1000?webp=false", - "artist" : "BABYMETAL feat. F.HERO", - "name" : "PA PA YA!!", - "link" : "/media/BABYMETAL feat. F.HERO - PA PA YA!!.mp3" - }, - { - "id" : 8, - "cover" : "https://tyumen.pult.ru/upload/iblock/19a/19a55d576dbf62be1b8f1b4af7086048.jpg", - "artist" : "BABYMETAL feat. Joakim Brodén", - "name" : "Oh! MAJINAI", - "link" : "/media/BABYMETAL feat. Joakim Brodén - Oh! MAJINAI.mp3" - }, - { - "id" : 9, - "cover" : "https://upload.wikimedia.org/wikipedia/ru/5/5a/BadOmens_TDOPOM.jpg", - "artist" : "Bad Omens", - "name" : "THE DEATH OF PEACE OF MIND", - "link" : "/media/Bad Omens - THE DEATH OF PEACE OF MIND.mp3" - }, - { - "id" : 10, - "cover" : "https://avatars.yandex.net/get-music-content/118603/8b6699e3.a.7787365-1/m1000x1000?webp=false", - "artist" : "Hidden Citizens feat. Rånya", - "name" : "Paint It Black", - "link" : "/media/Hidden Citizens feat. Rånya - Paint It Black.mp3" - }, - { - "id" : 11, - "cover" : "https://avatars.mds.yandex.net/get-marketpic/5962532/pic6432852efa7e9f3c6d103d9cafc22f0b/orig", - "artist" : "Louna", - "name" : "Полюса", - "link" : "/media/Louna - Полюса.mp3" - }, - { - "id" : 12, - "cover" : "https://avatars.yandex.net/get-music-content/108289/e482d95e.a.8112870-1/m1000x1000?webp=false", - "artist" : "MIYAVI", - "name" : "Other Side", - "link" : "/media/MIYAVI - Other Side.mp3" - }, - { - "id" : 13, - "cover" : "https://avatars.yandex.net/get-music-content/4010467/36fe1a48.a.17779951-1/m1000x1000?webp=false", - "artist" : "pyrokinesis", - "name" : "Легенда о Богине Гроз", - "link" : "/media/pyrokinesis - Легенда о Богине Гроз.mp3" - }, - { - "id" : 14, - "cover" : "https://cdn1.ozone.ru/s3/multimedia-m/6600598942.jpg", - "artist" : "Rammstein", - "name" : "Sonne", - "link" : "/media/Rammstein - Sonne.mp3" - }, - { - "id" : 15, - "cover" : "https://avatars.yandex.net/get-music-content/4384958/1ed003ad.a.16201558-1/m1000x1000?webp=false", - "artist" : "RAVANNA", - "name" : "Жги", - "link" : "/media/RAVANNA - Жги.mp3" - }, - { - "id" : 16, - "cover" : "https://i.ytimg.com/vi/BnK_V_yjy2E/maxresdefault.jpg", - "artist" : "RAVANNA feat. Ai Mori", - "name" : "Кома", - "link" : "/media/RAVANNA feat. Ai Mori - Кома.mp3" - }, - { - "id" : 17, - "cover" : "https://avatars.yandex.net/get-music-content/28589/eba28764.a.3104937-1/m1000x1000?webp=false", - "artist" : "Eurielle", - "name" : "City of the dead", - "link" : "/media/Eurielle - City of the dead.mp3" - }, - { - "id" : 18, - "cover" : "https://res.cloudinary.com/epitaph/image/upload/h_925,w_925/v1/epitaph/releases/88888-X_FallingInReverse_Zombified", - "artist" : "Falling In Reverse", - "name" : "ZOMBIFIED", - "link" : "/media/Falling In Reverse - ZOMBIFIED.mp3" - }, - { - "id" : 19, - "cover" : "https://images.genius.com/e61a18e39814f6dd49f65fcb0e198f40.1000x1000x1.jpg", - "artist" : "FIZICA", - "name" : "Готэм 2", - "link" : "/media/FIZICA - Готэм 2.mp3" - }, - { - "id" : 20, - "cover" : "https://images.genius.com/e61a18e39814f6dd49f65fcb0e198f40.1000x1000x1.jpg", - "artist" : "FIZICA", - "name" : "Готэм 3", - "link" : "/media/FIZICA - Готэм 3.mp3" - }, - { - "id" : 21, - "cover" : "https://images.genius.com/e61a18e39814f6dd49f65fcb0e198f40.1000x1000x1.jpg", - "artist" : "FIZICA", - "name" : "Готэм", - "link" : "/media/FIZICA - Готэм.mp3" - }, - { - "id" : 22, - "cover" : "https://images.genius.com/e61a18e39814f6dd49f65fcb0e198f40.1000x1000x1.jpg", - "artist" : "FIZICA", - "name" : "Чокер", - "link" : "/media/FIZICA - Чокер.mp3" - }, - { - "id" : 23, - "cover" : "https://is1-ssl.mzstatic.com/image/thumb/Music123/v4/ab/8c/13/ab8c1397-5cf9-b078-b797-70229a4303e3/cover.jpg/600x600bf-60.jpg", - "artist" : "GroTTesque", - "name" : "Стальное сердце", - "link" : "/media/GroTTesque - Стальное сердце.mp3" - }, - { - "id" : 24, - "cover" : "https://i.scdn.co/image/ab67616d0000b273b03ce145dfc370474ce2757a", - "artist" : "Halestorm", - "name" : "I Miss The Misery", - "link" : "/media/Halestorm - I Miss The Misery.mp3" - }, - { - "id" : 25, - "cover" : "https://static.wikia.nocookie.net/halsey/images/6/67/Badlands_Album_Cover.png", - "artist" : "Halsey", - "name" : "Control", - "link" : "/media/Halsey - Control.mp3" - }, - { - "id" : 26, - "cover" : "https://cdns-images.dzcdn.net/images/cover/02c28dce05f4590e812c43f3f17d8e49/0x1900-000000-80-0-0.jpg", - "artist" : "Hidden Citizens feat. Keeley Bumford", - "name" : "Immortalized", - "link" : "/media/Hidden Citizens feat. Keeley Bumford - Immortalized.mp3" - }, - { - "id" : 27, - "cover" : "https://t2.genius.com/unsafe/1249x0/https%3A%2F%2Fimages.genius.com%2Fa636627b58d07ad23513b2047cc3cea2.1000x1000x1.jpg", - "artist" : "Hidden Citizens feat. Rånya", - "name" : "Let Me Out", - "link" : "/media/Hidden Citizens feat. Rånya - Let Me Out.mp3" - }, - { - "id" : 28, - "cover" : "https://avatars.yandex.net/get-music-content/10930741/8f124fe5.a.29590705-1/m1000x1000?webp=false", - "artist" : "Ado", - "name" : "Unravel", - "link" : "/media/Ado - Unravel.mp3" - }, - { - "id" : 29, - "cover" : "https://avatars.mds.yandex.net/i?id=39a8810483883253ccfbe3488aa79845_l-4553678-images-thumbs&n=13", - "artist" : "Ado", - "name" : "Odo", - "link" : "/media/Ado - Odo.mp3" - }, - { - "id" : 30, - "cover" : "https://static.wikia.nocookie.net/nana/images/4/4e/Rose.jpg", - "artist" : "ANNA TSUCHIYA", - "name" : "Rose", - "link" : "/media/ANNA TSUCHIYA - Rose.mp3" - }, - { - "id" : 31, - "cover" : "https://cdns-images.dzcdn.net/images/cover/5489ee19bd016cfb2067082274fd3367/0x1900-000000-80-0-0.jpg", - "artist" : "Asper X", - "name" : "Bad Trip", - "link" : "/media/Asper X - Bad Trip.mp3" - }, - { - "id" : 32, - "cover" : "https://avatars.yandex.net/get-music-content/5678677/0c73458f.a.21314673-1/m1000x1000?webp=false", - "artist" : "SKYND", - "name" : "Chris Watts", - "link" : "/media/SKYND - Chris Watts.mp3" - } - , - { - "id" : 33, - "cover" : "https://lastfm.freetls.fastly.net/i/u/ar0/695fbe26f80c429dc8ece78a185d9161.jpg", - "artist" : "SKYND", - "name" : "Elisa Lam", - "link" : "/media/SKYND - Elisa Lam.mp3" - } - , - { - "id" : 34, - "cover" : "https://avatars.mds.yandex.net/i?id=eeecd5da9af4722fca7c7e9f04b020b6_l-8174327-images-thumbs&n=13", - "artist" : "SKYND", - "name" : "Jim Jones", - "link" : "/media/SKYND - Jim Jones(2019).mp3" - } - , - { - "id" : 35, - "cover" : "https://avatars.yandex.net/get-music-content/139444/8f8cb75a.a.7911606-2/m1000x1000?webp=false", - "artist" : "SKYND", - "name" : "Katherine Knight", - "link" : "/media/SKYND - Katherine Knight.mp3" - } - , - { - "id" : 36, - "cover" : "https://avatars.yandex.net/get-music-content/139444/8f8cb75a.a.7911606-2/m1000x1000?webp=false", - "artist" : "SKYND", - "name" : "Lay down your life", - "link" : "/media/SKYND - Lay down your life.mp3" - } - , - { - "id" : 37, - "cover" : "https://avatars.yandex.net/get-music-content/4581417/d46e0552.a.15349549-1/m1000x1000?webp=false", - "artist" : "SKYND", - "name" : "Michelle Carter", - "link" : "/media/SKYND - Michelle Carter.mp3" - } - , - { - "id" : 38, - "cover" : "https://avatars.yandex.net/get-music-content/149669/26c23a6e.a.5511746-1/m1000x1000?webp=false", - "artist" : "SKYND", - "name" : "Richard Ramirez", - "link" : "/media/SKYND - Richard Ramirez.mp3" - } - , - { - "id" : 39, - "cover" : "https://avatars.yandex.net/get-music-content/139444/8f8cb75a.a.7911606-2/m1000x1000?webp=false", - "artist" : "SKYND", - "name" : "Tyler Hadley", - "link" : "/media/SKYND - Tyler Hadley.mp3" - } - , - { - "id" : 40, - "cover" : "https://i.ytimg.com/vi/dWW2zXUOIC0/maxresdefault.jpg", - "artist" : "Norma Tale", - "name" : "Кисточка II", - "link" : "/media/Norma Tale - Кисточка II.mp3" - } - , - { - "id" : 41, - "cover" : "https://i.scdn.co/image/ab67616d0000b2731724b0cef6a23963d21c3b8a", - "artist" : "Creepy Nuts", - "name" : "オトノケ(Otonoke)", - "link" : "/media/Creepy Nuts - オトノケ(Otonoke).mp3" - } - , - { - "id" : 42, - "cover" : "https://i.ytimg.com/vi/hNjeAnwGhzc/hqdefault.jpg", - "artist" : "Apashe ft. Vo Williams", - "name" : "Work", - "link" : "/media/Apashe - Work (ft. Vo Williams).mp3" - } - , - { - "id" : 43, - "cover" : "https://i.ytimg.com/vi/mvzdWgfG1vM/maxresdefault.jpg", - "artist" : "blueberry", - "name" : "EVA 3", - "link" : "/media/blueberry - EVA 3.mp3" - } - , - { - "id" : 44, - "cover" : "https://i.ytimg.com/vi/FWBjzQnDb8o/maxresdefault.jpg", - "artist" : "Animadrop", - "name" : "Stuck in a Timeloop", - "link" : "/media/Animadrop - Stuck in a Timeloop.mp3" - } -] \ No newline at end of file diff --git a/style.css b/style.css deleted file mode 100644 index 901a141..0000000 --- a/style.css +++ /dev/null @@ -1,171 +0,0 @@ -html, body{ - margin: 0; - padding: auto; - justify-content: center; -} - -.color { - color: #F2E8C6; -} - -.header { - display: flex; - padding: 0 12px 12px 12px; - background-color: #800000; - margin: auto; - height: 100px; - width: 50%; -} - -.site_name { - color: #F2E8C6; -} - -.menu a { - color: #F2E8C6; - text-decoration: none; -} - - -.sort { - display: flex; - flex-direction: row; - margin-left: auto; -} - - -.songsWrapper { - display: flex; - flex-wrap: wrap; - margin-top: 24px; - margin-left: 25%; - width: 55%; -} - -.song { - width: 190px; - display: flex; - flex-direction: column; - text-align: center; - border-radius: 5px; - margin-right: 24px; - overflow-wrap: break-word; /* Переносит длинные слова */ - word-wrap: break-word; /* Поддержка для более старых браузеров */ - word-break: break-all; /* Позволяет разбивать длинные слова */ - white-space: normal; /* Позволяет переносу текста */ - cursor: pointer; - transition: transform 0.5s ease, background-color 0.5s ease, border-radius 0.5s ease; - -} - -.song:hover { - transform: scale(1.1); - box-shadow: 0 8px 16px rgba(0, 0, 0, 0.4); /* Более глубокая тень при наведении */ - border-radius: 5px; - background-color: #800000; - color: #F2E8C6; -} - -.song_image { - height: 190px; - width: 190px; -} - -.song_image img { - object-fit: cover; - height: 100%; - width: 100%; - border-radius: 10px; -} - -.player { - border-radius: 4px; - position: fixed; - bottom: -40px; - display: flex; - align-items: center; - justify-content: space-between; /* Размещение элементов по краям */ - box-sizing: border-box; - flex-direction: row; - padding-right: 10px; - background: rgba(128,0,0,0.7); - box-shadow: 20px 20px 40px -6px rgba(0,0,0,0.2); - backdrop-filter: blur(10px); - -webkit-backdrop-filter: blur(10px); - - height: 100px; - width: 52%; - left: 50%; - transform: translate(-50%, -50%); -} - - -.player__info { - display: flex; - justify-content: center; /* Центровка по горизонтали */ - align-items: center; /* Центровка по вертикали */ - text-align: center; - margin-right: auto; - box-sizing: border-box; - padding-right: 10px; - text-align: left; - color: #F2E8C6; -} - - -.player__cover_img { - object-fit: cover; - padding-right: 10px; - border-radius: 4px; - height: 100px; - width: 100px; -} - -.player__info_text { - display: flex; - flex-direction: column; - box-sizing:content-box; -} - - -.player__control { - display: flex; - flex-direction: column; - justify-content: center; - margin: auto; -} - -.player__control button, input{ - cursor: pointer; -} - -.css-button-fully-rounded--green { - min-width: 130px; - height: 40px; - color: #fff; - padding: 5px 10px; - font-weight: bold; - cursor: pointer; - transition: all 0.3s ease; - position: relative; - display: inline-block; - outline: none; - border-radius: 20px; - border: 2px solid #57cc99; - background: #57cc99; - } - .css-button-fully-rounded--green:hover { - background: #fff; - color: #57cc99 - } - - -.player__control__duration { - display: flex; - flex-direction: row; -} - -.player__control__volume { - display: flex; - height: 1005px; -} diff --git a/uploads/app.py b/uploads/app.py new file mode 100644 index 0000000..242318e --- /dev/null +++ b/uploads/app.py @@ -0,0 +1,61 @@ +from flask import Flask, request, jsonify +from werkzeug.utils import secure_filename +import os +import json +import random + +app = Flask(__name__) +app.config['UPLOAD_FOLDER'] = 'media/' +app.config['JSON_FILE'] = 'songs.json' + +# Создаем папку для загрузок, если она не существует +os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True) + +def generate_unique_id(songs): + """Функция для генерации уникального числового ID.""" + while True: + new_id = random.randint(100000, 999999) # Генерируем ID из четырех цифр + if all(song.get('id') != new_id for song in songs): + return new_id + +@app.route('/upload', methods=['POST']) +def upload(): + title = request.form['title'] + artist = request.form['artist'] + audio_file = request.files['audio'] + cover_path = request.form['cover'] + + if audio_file: + # Сохраняем файл аудио + audio_path = os.path.join(app.config['UPLOAD_FOLDER'], secure_filename(audio_file.filename)) + audio_file.save(audio_path) + + # Читаем существующий JSON-файл или создаем новый + try: + with open(app.config['JSON_FILE'], 'r', encoding='utf-8') as f: + songs = json.load(f) + except FileNotFoundError: + songs = [] + + # Генерируем уникальный числовой ID + song_id = generate_unique_id(songs) + + # Добавляем новую песню + songs.append({ + 'id': song_id, + 'title': title, + 'artist': artist, + 'audio': 'uploads/' + audio_path, + 'cover': cover_path + }) + + # Сохраняем обновленный JSON-файл + with open(app.config['JSON_FILE'], 'w', encoding='utf-8') as f: + json.dump(songs, f, ensure_ascii=False, indent=2) + + return jsonify({'message': 'Song uploaded successfully', 'id': song_id}), 200 + else: + return jsonify({'message': 'Failed to upload song'}), 400 + +if __name__ == '__main__': + app.run(debug=True) diff --git a/uploads/songs.json b/uploads/songs.json new file mode 100644 index 0000000..95031a0 --- /dev/null +++ b/uploads/songs.json @@ -0,0 +1,534 @@ +[ + { + "id": 1, + "cover": "https://repository-images.githubusercontent.com/415407744/50faf33c-1ed7-4b37-be52-bde9decae2c9", + "artist": "RIOT", + "title": "Overkill", + "audio": "uploads/media/RIOT - Overkill.mp3" + }, + { + "id": 2, + "cover": "https://avatars.mds.yandex.net/i?id=1860210a460d55628ad54c38cb0115b8_l-9783932-images-thumbs&n=13", + "artist": "Ado", + "title": "Show", + "audio": "uploads/media/Ado - Show.mp3" + }, + { + "id": 3, + "cover": "https://images.genius.com/8daaaa0c73899597c9ff7e0e66b84f13.1000x1000x1.png", + "artist": "Ado", + "title": "Usseewa", + "audio": "uploads/media/Ado - Usseewa.mp3" + }, + { + "id": 4, + "cover": "https://images.genius.com/57d901243d411351ca34035064a3f608.1000x1000x1.jpg", + "artist": "BABYMETAL", + "title": "BxMxC", + "audio": "uploads/media/BABYMETAL - BxMxC.mp3" + }, + { + "id": 5, + "cover": "https://upload.wikimedia.org/wikipedia/ru/1/12/Babymetal_Divine_Attack_single_cover.jpg", + "artist": "BABYMETAL", + "title": "Divine Attack - Shingeki", + "audio": "uploads/media/BABYMETAL - Divine Attack - Shingeki.mp3" + }, + { + "id": 6, + "cover": "https://i.ytimg.com/vi/9XGXzmz53uY/maxresdefault.jpg", + "artist": "BABYMETAL", + "title": "Karate", + "audio": "uploads/media/BABYMETAL - Karate.mp3" + }, + { + "id": 7, + "cover": "https://avatars.yandex.net/get-music-content/163479/6bd01cd7.a.7797117-1/m1000x1000?webp=false", + "artist": "BABYMETAL feat. F.HERO", + "title": "PA PA YA!!", + "audio": "uploads/media/BABYMETAL feat. F.HERO - PA PA YA!!.mp3" + }, + { + "id": 8, + "cover": "https://tyumen.pult.ru/upload/iblock/19a/19a55d576dbf62be1b8f1b4af7086048.jpg", + "artist": "BABYMETAL feat. Joakim Brodén", + "title": "Oh! MAJINAI", + "audio": "uploads/media/BABYMETAL feat. Joakim Brodén - Oh! MAJINAI.mp3" + }, + { + "id": 9, + "cover": "https://upload.wikimedia.org/wikipedia/ru/5/5a/BadOmens_TDOPOM.jpg", + "artist": "Bad Omens", + "title": "THE DEATH OF PEACE OF MIND", + "audio": "uploads/media/Bad Omens - THE DEATH OF PEACE OF MIND.mp3" + }, + { + "id": 10, + "cover": "https://avatars.yandex.net/get-music-content/118603/8b6699e3.a.7787365-1/m1000x1000?webp=false", + "artist": "Hidden Citizens feat. Rånya", + "title": "Paint It Black", + "audio": "uploads/media/Hidden Citizens feat. Rånya - Paint It Black.mp3" + }, + { + "id": 11, + "cover": "https://avatars.mds.yandex.net/get-marketpic/5962532/pic6432852efa7e9f3c6d103d9cafc22f0b/orig", + "artist": "Louna", + "title": "Полюса", + "audio": "uploads/media/Louna - Полюса.mp3" + }, + { + "id": 12, + "cover": "https://avatars.yandex.net/get-music-content/108289/e482d95e.a.8112870-1/m1000x1000?webp=false", + "artist": "MIYAVI", + "title": "Other Side", + "audio": "uploads/media/MIYAVI - Other Side.mp3" + }, + { + "id": 13, + "cover": "https://avatars.yandex.net/get-music-content/4010467/36fe1a48.a.17779951-1/m1000x1000?webp=false", + "artist": "pyrokinesis", + "title": "Легенда о Богине Гроз", + "audio": "uploads/media/pyrokinesis - Легенда о Богине Гроз.mp3" + }, + { + "id": 14, + "cover": "https://cdn1.ozone.ru/s3/multimedia-m/6600598942.jpg", + "artist": "Rammstein", + "title": "Sonne", + "audio": "uploads/media/Rammstein - Sonne.mp3" + }, + { + "id": 15, + "cover": "https://avatars.yandex.net/get-music-content/4384958/1ed003ad.a.16201558-1/m1000x1000?webp=false", + "artist": "RAVANNA", + "title": "Жги", + "audio": "uploads/media/RAVANNA - Жги.mp3" + }, + { + "id": 16, + "cover": "https://i.ytimg.com/vi/BnK_V_yjy2E/maxresdefault.jpg", + "artist": "RAVANNA feat. Ai Mori", + "title": "Кома", + "audio": "uploads/media/RAVANNA feat. Ai Mori - Кома.mp3" + }, + { + "id": 17, + "cover": "https://avatars.yandex.net/get-music-content/28589/eba28764.a.3104937-1/m1000x1000?webp=false", + "artist": "Eurielle", + "title": "City of the dead", + "audio": "uploads/media/Eurielle - City of the dead.mp3" + }, + { + "id": 18, + "cover": "https://res.cloudinary.com/epitaph/image/upload/h_925,w_925/v1/epitaph/releases/88888-X_FallingInReverse_Zombified", + "artist": "Falling In Reverse", + "title": "ZOMBIFIED", + "audio": "uploads/media/Falling In Reverse - ZOMBIFIED.mp3" + }, + { + "id": 19, + "cover": "https://images.genius.com/e61a18e39814f6dd49f65fcb0e198f40.1000x1000x1.jpg", + "artist": "FIZICA", + "title": "Готэм 2", + "audio": "uploads/media/FIZICA - Готэм 2.mp3" + }, + { + "id": 20, + "cover": "https://images.genius.com/e61a18e39814f6dd49f65fcb0e198f40.1000x1000x1.jpg", + "artist": "FIZICA", + "title": "Готэм 3", + "audio": "uploads/media/FIZICA - Готэм 3.mp3" + }, + { + "id": 21, + "cover": "https://images.genius.com/e61a18e39814f6dd49f65fcb0e198f40.1000x1000x1.jpg", + "artist": "FIZICA", + "title": "Готэм", + "audio": "uploads/media/FIZICA - Готэм.mp3" + }, + { + "id": 22, + "cover": "https://images.genius.com/e61a18e39814f6dd49f65fcb0e198f40.1000x1000x1.jpg", + "artist": "FIZICA", + "title": "Чокер", + "audio": "uploads/media/FIZICA - Чокер.mp3" + }, + { + "id": 23, + "cover": "https://is1-ssl.mzstatic.com/image/thumb/Music123/v4/ab/8c/13/ab8c1397-5cf9-b078-b797-70229a4303e3/cover.jpg/600x600bf-60.jpg", + "artist": "GroTTesque", + "title": "Стальное сердце", + "audio": "uploads/media/GroTTesque - Стальное сердце.mp3" + }, + { + "id": 24, + "cover": "https://i.scdn.co/image/ab67616d0000b273b03ce145dfc370474ce2757a", + "artist": "Halestorm", + "title": "I Miss The Misery", + "audio": "uploads/media/Halestorm - I Miss The Misery.mp3" + }, + { + "id": 25, + "cover": "https://static.wikia.nocookie.net/halsey/images/6/67/Badlands_Album_Cover.png", + "artist": "Halsey", + "title": "Control", + "audio": "uploads/media/Halsey - Control.mp3" + }, + { + "id": 26, + "cover": "https://cdns-images.dzcdn.net/images/cover/02c28dce05f4590e812c43f3f17d8e49/0x1900-000000-80-0-0.jpg", + "artist": "Hidden Citizens feat. Keeley Bumford", + "title": "Immortalized", + "audio": "uploads/media/Hidden Citizens feat. Keeley Bumford - Immortalized.mp3" + }, + { + "id": 27, + "cover": "https://t2.genius.com/unsafe/1249x0/https%3A%2F%2Fimages.genius.com%2Fa636627b58d07ad23513b2047cc3cea2.1000x1000x1.jpg", + "artist": "Hidden Citizens feat. Rånya", + "title": "Let Me Out", + "audio": "uploads/media/Hidden Citizens feat. Rånya - Let Me Out.mp3" + }, + { + "id": 28, + "cover": "https://avatars.yandex.net/get-music-content/10930741/8f124fe5.a.29590705-1/m1000x1000?webp=false", + "artist": "Ado", + "title": "Unravel", + "audio": "uploads/media/Ado - Unravel.mp3" + }, + { + "id": 29, + "cover": "https://avatars.mds.yandex.net/i?id=39a8810483883253ccfbe3488aa79845_l-4553678-images-thumbs&n=13", + "artist": "Ado", + "title": "Odo", + "audio": "uploads/media/Ado - Odo.mp3" + }, + { + "id": 30, + "cover": "https://static.wikia.nocookie.net/nana/images/4/4e/Rose.jpg", + "artist": "ANNA TSUCHIYA", + "title": "Rose", + "audio": "uploads/media/ANNA TSUCHIYA - Rose.mp3" + }, + { + "id": 31, + "cover": "https://cdns-images.dzcdn.net/images/cover/5489ee19bd016cfb2067082274fd3367/0x1900-000000-80-0-0.jpg", + "artist": "Asper X", + "title": "Bad Trip", + "audio": "uploads/media/Asper X - Bad Trip.mp3" + }, + { + "id": 32, + "cover": "https://avatars.yandex.net/get-music-content/5678677/0c73458f.a.21314673-1/m1000x1000?webp=false", + "artist": "SKYND", + "title": "Chris Watts", + "audio": "uploads/media/SKYND - Chris Watts.mp3" + }, + { + "id": 33, + "cover": "https://lastfm.freetls.fastly.net/i/u/ar0/695fbe26f80c429dc8ece78a185d9161.jpg", + "artist": "SKYND", + "title": "Elisa Lam", + "audio": "uploads/media/SKYND - Elisa Lam.mp3" + }, + { + "id": 34, + "cover": "https://avatars.mds.yandex.net/i?id=eeecd5da9af4722fca7c7e9f04b020b6_l-8174327-images-thumbs&n=13", + "artist": "SKYND", + "title": "Jim Jones", + "audio": "uploads/media/SKYND - Jim Jones(2019).mp3" + }, + { + "id": 35, + "cover": "https://avatars.yandex.net/get-music-content/139444/8f8cb75a.a.7911606-2/m1000x1000?webp=false", + "artist": "SKYND", + "title": "Katherine Knight", + "audio": "uploads/media/SKYND - Katherine Knight.mp3" + }, + { + "id": 36, + "cover": "https://avatars.yandex.net/get-music-content/139444/8f8cb75a.a.7911606-2/m1000x1000?webp=false", + "artist": "SKYND", + "title": "Lay down your life", + "audio": "uploads/media/SKYND - Lay down your life.mp3" + }, + { + "id": 37, + "cover": "https://avatars.yandex.net/get-music-content/4581417/d46e0552.a.15349549-1/m1000x1000?webp=false", + "artist": "SKYND", + "title": "Michelle Carter", + "audio": "uploads/media/SKYND - Michelle Carter.mp3" + }, + { + "id": 38, + "cover": "https://avatars.yandex.net/get-music-content/149669/26c23a6e.a.5511746-1/m1000x1000?webp=false", + "artist": "SKYND", + "title": "Richard Ramirez", + "audio": "uploads/media/SKYND - Richard Ramirez.mp3" + }, + { + "id": 39, + "cover": "https://avatars.yandex.net/get-music-content/139444/8f8cb75a.a.7911606-2/m1000x1000?webp=false", + "artist": "SKYND", + "title": "Tyler Hadley", + "audio": "uploads/media/SKYND - Tyler Hadley.mp3" + }, + { + "id": 40, + "cover": "https://i.ytimg.com/vi/dWW2zXUOIC0/maxresdefault.jpg", + "artist": "Norma Tale", + "title": "Кисточка II", + "audio": "uploads/media/Norma Tale - Кисточка II.mp3" + }, + { + "id": 41, + "cover": "https://i.scdn.co/image/ab67616d0000b2731724b0cef6a23963d21c3b8a", + "artist": "Creepy Nuts", + "title": "オトノケ(Otonoke)", + "audio": "uploads/media/Creepy Nuts - オトノケ(Otonoke).mp3" + }, + { + "id": 42, + "cover": "https://i.ytimg.com/vi/hNjeAnwGhzc/hqdefault.jpg", + "artist": "Apashe ft. Vo Williams", + "title": "Work", + "audio": "uploads/media/Apashe - Work (ft. Vo Williams).mp3" + }, + { + "id": 43, + "cover": "https://i.ytimg.com/vi/mvzdWgfG1vM/maxresdefault.jpg", + "artist": "blueberry", + "title": "EVA 3", + "audio": "uploads/media/blueberry - EVA 3.mp3" + }, + { + "id": 44, + "cover": "https://i.ytimg.com/vi/FWBjzQnDb8o/maxresdefault.jpg", + "artist": "Animadrop", + "title": "Stuck in a Timeloop", + "audio": "uploads/media/Animadrop - Stuck in a Timeloop.mp3" + }, + { + "id": 45, + "cover": "https://i.ytimg.com/vi/ylIB_Sqm8YM/maxresdefault.jpg", + "artist": "pyrokinesis", + "title": "Легенда о богине Мечей", + "audio": "uploads/media/pyrokinesis - Легенда о Богине Мечей.mp3" + }, + { + "id": 482708, + "title": "Snow Drive", + "artist": "Araki", + "audio": "uploads/media/Araki_-_Snow_Drive_.mp3", + "cover": "https://i.ytimg.com/vi/9w1rsWrzBwY/maxresdefault.jpg" + }, + { + "id": 942880, + "title": "Teo", + "artist": "Omoi", + "audio": "uploads/media/Omoi_-_Teo.mp3", + "cover": "https://i.ytimg.com/vi/bmkY2yc1K7Q/maxresdefault.jpg" + }, + { + "id": 667995, + "title": "Teo", + "artist": "Araki", + "audio": "uploads/media/Araki_-_Teo.mp3", + "cover": "https://i.ytimg.com/vi/WysJSFW0LU8/maxresdefault.jpg" + }, + { + "id": 190369, + "title": "I pray", + "artist": "Denkare", + "audio": "uploads/media/Denkare_-_I_pray.mp3", + "cover": "https://i.ytimg.com/vi/mUARzh2zHDo/maxresdefault.jpg" + }, + { + "id": 816639, + "title": "Amore", + "artist": "BABYMETAL", + "audio": "uploads/media/BABYMETAL_-_05._Amore.mp3", + "cover": "https://i.ytimg.com/vi/uD4QJyWqUiE/maxresdefault.jpg" + }, + { + "id": 962785, + "title": "Storytellers", + "artist": "Foreground Eclipse", + "audio": "uploads/media/Foreground_Eclipse_-_Storytellers.mp3", + "cover": "https://i.ytimg.com/vi/FMvD0-K-hoI/maxresdefault.jpg" + }, + { + "id": 719505, + "title": "Реванш", + "artist": "LASCALA", + "audio": "uploads/media/LASCALA_-_.mp3", + "cover": "https://i.ytimg.com/vi/epSHdRWHxG4/maxresdefault.jpg" + }, + { + "id": 759704, + "title": "How you like that", + "artist": "BLACKPINK", + "audio": "uploads/media/BLACKPINK_-_How_You_Like_That.mp3", + "cover": "https://cokodive.com/cdn/shop/products/apple-music-blackpink-special-edition-how-you-like-that-15622046023760_1600x.jpg?v=1628411100" + }, + { + "id": 194647, + "title": "Revive", + "artist": "UNIONE", + "audio": "uploads/media/UNIONE_-_Revive.mp3", + "cover": "https://cdns-images.dzcdn.net/images/cover/2bab47ee78b6cad51c5634e89518e99a/0x1900-000000-80-0-0.jpg" + }, + { + "id": 398316, + "title": "Savege", + "artist": "Bahari", + "audio": "uploads/media/Bahari_-_Savage.mp3", + "cover": "https://lastfm.freetls.fastly.net/i/u/ar0/f7319a8dfcb2932f065ed34263ce7062.jpg" + }, + { + "id": 490228, + "title": "Yofukashino Uta", + "artist": "Creepy Nuts", + "audio": "uploads/media/Creepy_Nuts_-_Yofukashino_Uta.mp3", + "cover": "https://cdn-image.zvuk.com/pic?type=release&id=11151184&size=300x300&hash=b3064b6f-5ea0-45dd-bd7d-d520df72da03" + }, + { + "id": 489774, + "title": "Hayloft II", + "artist": "Mother Mother", + "audio": "uploads/media/Mother_Mother_-_Hayloft_II.mp3", + "cover": "https://cdn-image.zvuk.com/pic?type=release&id=22125952&size=400x400&hash=09507c10-537c-41f1-b786-4c6a56f2a884" + }, + { + "id": 251677, + "title": "IDOL", + "artist": "YOASOBI", + "audio": "uploads/media/YOASOBI_-_IDOL.mp3", + "cover": "https://upload.wikimedia.org/wikipedia/ru/thumb/3/35/Idol-yoasobi.jpg/1200px-Idol-yoasobi.jpg" + }, + { + "id": 960084, + "title": "Yuusha", + "artist": "YOASOBI", + "audio": "uploads/media/YOASOBI_Official_Music_Video_TV.mp3", + "cover": "https://sun9-12.userapi.com/s/v1/ig2/1pWeH9tXwkjpaynJFDR4opnI3OSDf3QL6cTXoC0R6AxGE9jKD75WAbstrS-DyPmqDXlTKXL0B0qaCQF6sqwAe_pK.jpg?quality=96&as=32x48,48x72,72x109,108x163,160x242,240x362,360x544,480x725,540x816,640x967,720x1087,1080x1631,1280x1933,1356x2048&from=bu&u=zuEFWghv_k0ENDbNAty1SjwXbnUI1TeZUVw60HubRQI&cs=534x807" + }, + { + "id": 292108, + "title": "Hayloft", + "artist": "Mother Mother", + "audio": "uploads/media/Mother_Mother_-_Hayloft_-_LastGangRadio_youtube.mp3", + "cover": "https://lastfm.freetls.fastly.net/i/u/ar0/826cd46695ae445ca9db6ca7d694cdc0.jpg" + }, + { + "id": 627635, + "title": "Skygall", + "artist": "Adele", + "audio": "uploads/media/Adele_Skyfall-original.mp3", + "cover": "https://avatars.yandex.net/get-music-content/2114230/0b7e42bb.a.8953684-1/m1000x1000?webp=false" + }, + { + "id": 520568, + "title": "Ghost Rule", + "artist": "DECO_27", + "audio": "uploads/media/DECO_27_-_Ghost_Rule.mp3", + "cover": "https://i.ytimg.com/vi/PRFoBWsVXws/maxresdefault.jpg" + }, + { + "id": 915302, + "title": "Zombie", + "artist": "Bad Wolves", + "audio": "uploads/media/Bad_Wolves_-_Zombie.mp3", + "cover": "https://lastfm.freetls.fastly.net/i/u/ar0/3a9968f93c6c64d0b888cbfec41c4cc9.jpg" + }, + { + "id": 166503, + "title": "Slowmotion", + "artist": "JOHAN x Goddamn", + "audio": "uploads/media/JOHAN_x_Goddamn_-_Slowmotion.mp3", + "cover": "https://avatars.yandex.net/get-music-content/5502420/c092875b.a.24380375-1/m1000x1000?webp=false" + }, + { + "id": 348291, + "title": "River", + "artist": "Anonymouz", + "audio": "uploads/media/Anonymouz_-_River__VINLAND_SAGA_SEASON_2_OP.mp3", + "cover": "https://images.genius.com/512bb23b64d6cf045e3721688ae1943f.1000x1000x1.jpg" + }, + { + "id": 548170, + "title": "Prove", + "artist": "One Ok Rock", + "audio": "uploads/media/One_Ok_Rock_-_Prove_Official_Audio.mp3", + "cover": "https://avatars.yandex.net/get-music-content/6201394/c980ddcf.a.23430934-1/m1000x1000?webp=false" + }, + { + "id": 612840, + "title": "Outta Sight", + "artist": "One Ok Rock", + "audio": "uploads/media/One_Ok_Rock_-_Outta_Sight_Official_Audio.mp3", + "cover": "https://lastfm.freetls.fastly.net/i/u/ar0/d720deebec038c7dae1d9f72d72a6eb2.jpg" + }, + { + "id": 333702, + "title": "Mukanjyo", + "artist": "Survive Said The Prophet", + "audio": "uploads/media/Survive_Said_The_Prophet_-_Mukanjyo.mp3", + "cover": "https://i.ytimg.com/vi/ZQE6aj5DhYk/maxresdefault.jpg" + }, + { + "id": 942311, + "title": "Kiminosei", + "artist": "the perggies", + "audio": "uploads/media/the_pergies_-_Kiminosei.mp3", + "cover": "https://i.ytimg.com/vi/KbT3JsJmd14/maxresdefault.jpg" + }, + { + "id": 910766, + "title": "My Hero", + "artist": "MAN WITH A MISSION", + "audio": "uploads/media/Inuyashiki_OpeningFULL_My_Hero_-_MAN_WITH_A_MISSION.mp3", + "cover": "https://lastfm.freetls.fastly.net/i/u/ar0/eafb171e2d852ef06313555705fd594e.jpg" + }, + { + "id": 197571, + "title": "Abyss", + "artist": "YUNGBLUD", + "audio": "uploads/media/YUNGBLUD_-_Abyss.mp3", + "cover": "https://avatars.yandex.net/get-music-content/6386858/17e75da3.a.30447850-2/m1000x1000?webp=false" + }, + { + "id": 123760, + "title": "Brave Shine", + "artist": "Aimer", + "audio": "uploads/media/Aimer_-_Brave_Shine.mp3", + "cover": "https://avatars.yandex.net/get-music-content/2359742/7c05cda6.a.10987377-1/m1000x1000?webp=false" + }, + { + "id": 204269, + "title": "Gira Gira (ギラギラ)", + "artist": "Ado", + "audio": "uploads/media/Ado_Gira_Gira_.mp3", + "cover": "https://i.ytimg.com/vi/nSZ36z3_10g/maxresdefault.jpg" + }, + { + "id": 908633, + "title": "Backlight (逆光)", + "artist": "Ado", + "audio": "uploads/media/Ado_-_Backlight.mp3", + "cover": "https://images.genius.com/fd8b5c7f2a03083abe5734ff76509067.1000x1000x1.png" + }, + { + "id": 952950, + "title": "Tot Musica", + "artist": "Ado", + "audio": "uploads/media/Uta_Tot_Musica_AMVMADOne_Piece_Red.mp3", + "cover": "https://images.genius.com/8daaaa0c73899597c9ff7e0e66b84f13.1000x1000x1.png" + }, + { + "id": 145404, + "title": "Rabbit Hole (ラビットホール)", + "artist": "DECO*27 feat. 初音ミク", + "audio": "uploads/media/DECO27_-_feat._.mp3", + "cover": "https://i.ytimg.com/vi/eSW2LVbPThw/maxresdefault.jpg" + } +] \ No newline at end of file