mirror of
https://github.com/openvk/openvk
synced 2024-12-22 16:42:32 +03:00
Repair playlists
This commit is contained in:
parent
5bc306ebf9
commit
187250b22f
12 changed files with 326 additions and 307 deletions
|
@ -343,17 +343,15 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
$this->template->club = $club;
|
||||
}
|
||||
|
||||
$this->template->owner = $owner;
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
$title = $this->postParam("title");
|
||||
$description = $this->postParam("description");
|
||||
$is_unlisted = (int)$this->postParam('is_unlisted');
|
||||
|
||||
$audios = !empty($this->postParam("audios")) ? array_slice(explode(",", $this->postParam("audios")), 0, 1000) : [];
|
||||
$is_ajax = (int)$this->postParam('ajax') == 1;
|
||||
$audios = array_slice(explode(",", $this->postParam("audios")), 0, 1000);
|
||||
|
||||
if(empty($title) || iconv_strlen($title) < 1)
|
||||
$this->flashFail("err", tr("error"), tr("set_playlist_name"));
|
||||
$this->flashFail("err", tr("error"), tr("set_playlist_name"), NULL, $is_ajax);
|
||||
|
||||
$playlist = new Playlist;
|
||||
$playlist->setOwner($owner);
|
||||
|
@ -364,12 +362,12 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
|
||||
if($_FILES["cover"]["error"] === UPLOAD_ERR_OK) {
|
||||
if(!str_starts_with($_FILES["cover"]["type"], "image"))
|
||||
$this->flashFail("err", tr("error"), tr("not_a_photo"));
|
||||
$this->flashFail("err", tr("error"), tr("not_a_photo"), NULL, $is_ajax);
|
||||
|
||||
try {
|
||||
$playlist->fastMakeCover($this->user->id, $_FILES["cover"]);
|
||||
} catch(\Throwable $e) {
|
||||
$this->flashFail("err", tr("error"), tr("invalid_cover_photo"));
|
||||
$this->flashFail("err", tr("error"), tr("invalid_cover_photo"), NULL, $is_ajax);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -377,25 +375,22 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
|
||||
foreach($audios as $audio) {
|
||||
$audio = $this->audios->get((int)$audio);
|
||||
|
||||
if(!$audio || $audio->isDeleted() || !$audio->canBeViewedBy($this->user->identity))
|
||||
if(!$audio || $audio->isDeleted())
|
||||
continue;
|
||||
|
||||
$playlist->add($audio);
|
||||
}
|
||||
|
||||
$playlist->bookmark(isset($club) ? $club : $this->user->identity);
|
||||
if($is_ajax) {
|
||||
$this->returnJson([
|
||||
'success' => true,
|
||||
'redirect' => '/playlist' . $owner . "_" . $playlist->getId()
|
||||
]);
|
||||
}
|
||||
$this->redirect("/playlist" . $owner . "_" . $playlist->getId());
|
||||
} else {
|
||||
if(isset($club)) {
|
||||
$this->template->audios = iterator_to_array($this->audios->getByClub($club, 1, 10));
|
||||
$count = (new Audios)->getClubCollectionSize($club);
|
||||
} else {
|
||||
$this->template->audios = iterator_to_array($this->audios->getByUser($this->user->identity, 1, 10));
|
||||
$count = (new Audios)->getUserCollectionSize($this->user->identity);
|
||||
}
|
||||
|
||||
$this->template->pagesCount = ceil($count / 10);
|
||||
$this->template->owner = $owner;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -451,28 +446,20 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
$this->willExecuteWriteAction();
|
||||
|
||||
$playlist = $this->audios->getPlaylistByOwnerAndVID($owner_id, $virtual_id);
|
||||
$page = (int)($this->queryParam("p") ?? 1);
|
||||
if (!$playlist || $playlist->isDeleted() || !$playlist->canBeModifiedBy($this->user->identity))
|
||||
$this->notFound();
|
||||
|
||||
$this->template->playlist = $playlist;
|
||||
$this->template->page = $page;
|
||||
|
||||
$audios = iterator_to_array($playlist->fetch(1, $playlist->size()));
|
||||
$this->template->audios = array_slice($audios, 0, 10);
|
||||
$audiosIds = [];
|
||||
|
||||
foreach($audios as $aud)
|
||||
$audiosIds[] = $aud->getId();
|
||||
|
||||
$this->template->audiosIds = implode(",", array_unique($audiosIds)) . ",";
|
||||
$this->template->audios = array_slice($audios, 0, 1000);
|
||||
$this->template->ownerId = $owner_id;
|
||||
$this->template->owner = $playlist->getOwner();
|
||||
$this->template->pagesCount = $pagesCount = ceil($playlist->size() / 10);
|
||||
|
||||
if($_SERVER["REQUEST_METHOD"] !== "POST")
|
||||
return;
|
||||
|
||||
$is_ajax = (int)$this->postParam('ajax') == 1;
|
||||
$title = $this->postParam("title");
|
||||
$description = $this->postParam("description");
|
||||
$is_unlisted = (int)$this->postParam('is_unlisted');
|
||||
|
@ -487,12 +474,12 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
$playlist->resetLength();
|
||||
$playlist->setUnlisted((bool)$is_unlisted);
|
||||
|
||||
if($_FILES["new_cover"]["error"] === UPLOAD_ERR_OK) {
|
||||
if(!str_starts_with($_FILES["new_cover"]["type"], "image"))
|
||||
if($_FILES["cover"]["error"] === UPLOAD_ERR_OK) {
|
||||
if(!str_starts_with($_FILES["cover"]["type"], "image"))
|
||||
$this->flashFail("err", tr("error"), tr("not_a_photo"));
|
||||
|
||||
try {
|
||||
$playlist->fastMakeCover($this->user->id, $_FILES["new_cover"]);
|
||||
$playlist->fastMakeCover($this->user->id, $_FILES["cover"]);
|
||||
} catch(\Throwable $e) {
|
||||
$this->flashFail("err", tr("error"), tr("invalid_cover_photo"));
|
||||
}
|
||||
|
@ -506,13 +493,18 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
|
||||
foreach ($new_audios as $new_audio) {
|
||||
$audio = (new Audios)->get((int)$new_audio);
|
||||
|
||||
if(!$audio || $audio->isDeleted())
|
||||
continue;
|
||||
|
||||
$playlist->add($audio);
|
||||
}
|
||||
|
||||
if($is_ajax) {
|
||||
$this->returnJson([
|
||||
'success' => true,
|
||||
'redirect' => '/playlist' . $playlist->getPrettyId()
|
||||
]);
|
||||
}
|
||||
$this->redirect("/playlist".$playlist->getPrettyId());
|
||||
}
|
||||
|
||||
|
|
|
@ -13,61 +13,44 @@
|
|||
{/block}
|
||||
|
||||
{block content}
|
||||
<div class="playlistBlock" style="display: flex;margin-top: 0px;">
|
||||
<div class="playlistCover">
|
||||
<a>
|
||||
<img src="{$playlist->getCoverURL('normal')}" alt="{_playlist_cover}">
|
||||
</a>
|
||||
|
||||
<div class="profile_links" style="width: 139px;">
|
||||
<a class="profile_link" style="width: 98%;" id="_deletePlaylist" data-id="{$playlist->getId()}">{_delete_playlist}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="padding-left: 13px;width:75%">
|
||||
<div class="playlistInfo">
|
||||
<input value="{$playlist->getName()}" type="text" name="title" maxlength="125">
|
||||
</div>
|
||||
|
||||
<div class="moreInfo">
|
||||
<textarea placeholder="{_description}" name="description" maxlength="2045" style="margin-top: 11px;">{$playlist->getDescription()}</textarea>
|
||||
</div>
|
||||
|
||||
<label>
|
||||
<input type='checkbox' name='is_unlisted' n:attr='checked => $playlist->isUnlisted()'>
|
||||
{_playlist_hide_from_search}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 19px;">
|
||||
<input id="playlist_query" type="text" style="height: 26px;" placeholder="{_header_search}">
|
||||
<div class="playlistAudiosContainer editContainer">
|
||||
<div id="newPlaylistAudios" n:foreach="$audios as $audio">
|
||||
<div class="playerContainer">
|
||||
{include "player.xml", audio => $audio, hideButtons => true}
|
||||
<div class='PE_wrapper'>
|
||||
<div class='PE_playlistEditPage'>
|
||||
<div class="playlistCover">
|
||||
<a onclick="document.querySelector(`input[name='cover']`).click()">
|
||||
<input type='file' name='cover' style='display:none;' accept=".jpg,.png">
|
||||
<img src="{$playlist->getCoverURL('normal')}" alt="{_playlist_cover}">
|
||||
</a>
|
||||
<div class="profile_links" style="width: 139px;">
|
||||
<a class="profile_link" style="width: 98%;" id="_deletePlaylist" data-id="{$playlist->getId()}">{_delete_playlist}</a>
|
||||
</div>
|
||||
<div class="attachAudio addToPlaylist" data-id="{$audio->getId()}">
|
||||
<span>{_remove_from_playlist}</span>
|
||||
</div>
|
||||
|
||||
<div class="PE_playlistInfo">
|
||||
<div>
|
||||
<input value='{$playlist->getName()}' type="text" name="title" placeholder="{_title}" maxlength="125" />
|
||||
</div>
|
||||
<div class="moreInfo">
|
||||
<textarea placeholder="{_description}" name="description" maxlength="2045">{$playlist->getDescription()}</textarea>
|
||||
</div>
|
||||
<label>
|
||||
<input type='checkbox' name='is_unlisted' value='1' n:attr='checked => $playlist->isUnlisted()'>
|
||||
{_playlist_hide_from_search}
|
||||
</label>
|
||||
<a id='_playlistAppendTracks'>{_add_audio_verb}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class='PE_audios generic_audio_list'>
|
||||
<div n:foreach='$audios as $audio' class='vertical-attachment upload-item' data-id='{$audio->getId()}'>
|
||||
<div class='vertical-attachment-content'>
|
||||
{include 'player.xml', audio => $audio, hideButtons => true}
|
||||
</div>
|
||||
<div class="vertical-attachment-remove">
|
||||
<div id="small_remove_button"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="showMoreAudiosPlaylist" data-page="2" data-playlist="{$playlist->getId()}" n:if="$pagesCount > 1">
|
||||
{_show_more_audios}
|
||||
<div class='PE_end'>
|
||||
<input class="button" type="button" id='playlist_edit' value="{_save}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="post" id="editPlaylistForm" data-id="{$playlist->getId()}" enctype="multipart/form-data">
|
||||
<input type="hidden" name="title" maxlength="128" />
|
||||
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||
<input type="hidden" name="is_unlisted" value="0" />
|
||||
<textarea style="display:none;" name="description" maxlength="2048" />
|
||||
<input type="hidden" name="audios">
|
||||
<input type="file" style="display:none;" name="new_cover" accept=".jpg,.png">
|
||||
|
||||
<div style="float:right;margin-top: 8px;">
|
||||
<button class="button" type="submit">{_save}</button>
|
||||
</div>
|
||||
</form>
|
||||
{/block}
|
||||
|
|
|
@ -19,48 +19,32 @@
|
|||
{/block}
|
||||
|
||||
{block content}
|
||||
<style>
|
||||
textarea[name='description'] {
|
||||
padding: 4px;
|
||||
}
|
||||
<div class='PE_wrapper'>
|
||||
<div class='PE_playlistEditPage'>
|
||||
<div class="playlistCover" onclick="document.querySelector(`input[name='cover']`).click()">
|
||||
<a>
|
||||
<input type='file' name='cover' style='display:none;' accept=".jpg,.png">
|
||||
<img src="/assets/packages/static/openvk/img/song.jpg" alt="{_playlist_cover}">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
.playlistInfo {
|
||||
width: 76%;
|
||||
margin-left: 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div style="display:flex;">
|
||||
<div class="playlistCover" onclick="document.querySelector(`#newPlaylistForm input[name='cover']`).click()">
|
||||
<a>
|
||||
<img src="/assets/packages/static/openvk/img/song.jpg" alt="{_playlist_cover}">
|
||||
</a>
|
||||
<div class="PE_playlistInfo">
|
||||
<div>
|
||||
<input type="text" name="title" placeholder="{_title}" maxlength="125" />
|
||||
</div>
|
||||
<div class="moreInfo">
|
||||
<textarea placeholder="{_description}" name="description" maxlength="2045" />
|
||||
</div>
|
||||
<label>
|
||||
<input type='checkbox' name='is_unlisted' value='1'>
|
||||
{_playlist_hide_from_search}
|
||||
</label>
|
||||
<a id='_playlistAppendTracks'>{_add_audio_verb}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="padding-left: 17px;width: 75%;" class="plinfo">
|
||||
<div>
|
||||
<input type="text" name="title" placeholder="{_title}" maxlength="125" />
|
||||
</div>
|
||||
<div class="moreInfo" style="margin-top: 11px;">
|
||||
<textarea placeholder="{_description}" name="description" maxlength="2045" />
|
||||
</div>
|
||||
<label>
|
||||
<input type='checkbox' name='is_unlisted'>
|
||||
{_playlist_hide_from_search}
|
||||
</label>
|
||||
<div class='PE_audios generic_audio_list'></div>
|
||||
<div class='PE_end'>
|
||||
<input class="button" type="button" id='playlist_create' value="{_create}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="post" id="newPlaylistForm" enctype="multipart/form-data">
|
||||
<input type="hidden" name="title" maxlength="125" />
|
||||
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||
<input type="hidden" name="is_unlisted" value="0" />
|
||||
<textarea style="display:none;" name="description" maxlength="2045" />
|
||||
<input type="hidden" name="audios">
|
||||
<input type="file" style="display:none;" name="cover" accept=".jpg,.png">
|
||||
|
||||
<div style="float: right;margin-top: 9px;">
|
||||
<button class="button" type="submit">{_create}</button>
|
||||
</div>
|
||||
</form>
|
||||
{/block}
|
||||
|
|
|
@ -605,6 +605,28 @@
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
.PE_playlistEditPage {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.PE_playlistEditPage .PE_playlistInfo {
|
||||
width: 76%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.PE_playlistEditPage textarea[name='description'] {
|
||||
padding: 4px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.PE_end {
|
||||
text-align: right;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/* playlist listview */
|
||||
|
||||
.playlistListView {
|
||||
|
|
|
@ -2573,55 +2573,55 @@ a.poll-retract-vote {
|
|||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.post-vertical .vertical-attachment {
|
||||
.vertical-attachment {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 0fr;
|
||||
}
|
||||
|
||||
.post-vertical .vertical-attachment:first-of-type {
|
||||
.vertical-attachment:first-of-type {
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
.post-vertical .vertical-attachment .audioEntry {
|
||||
.vertical-attachment .audioEntry {
|
||||
max-height: 28px;
|
||||
min-height: 18px;
|
||||
}
|
||||
|
||||
.post-vertical .vertical-attachment .audioEntry:hover {
|
||||
.vertical-attachment .audioEntry:hover {
|
||||
background: unset !important;
|
||||
}
|
||||
|
||||
.post-vertical .vertical-attachment .audioEntry .buttons {
|
||||
.vertical-attachment .audioEntry .buttons {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.post-vertical .vertical-attachment .audioEntry .status {
|
||||
.vertical-attachment .audioEntry .status {
|
||||
margin-top: 1px;
|
||||
margin-left: 2px;
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
.post-vertical .vertical-attachment .audioEntry .nobold {
|
||||
.vertical-attachment .audioEntry .nobold {
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.post-vertical .vertical-attachment .audioEntry .subTracks {
|
||||
padding-bottom: 2px;
|
||||
padding-left: 3px;
|
||||
.vertical-attachment .audioEntry .subTracks {
|
||||
padding-left: 0px;
|
||||
padding-right: 0px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.post-vertical .vertical-attachment .audioEntry .audioEntryWrapper {
|
||||
.vertical-attachment .audioEntry .audioEntryWrapper {
|
||||
height: 14px;
|
||||
padding: 0px 4px 0px 0px;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.post-vertical .vertical-attachment .vertical-attachment-content {
|
||||
.vertical-attachment .vertical-attachment-content {
|
||||
max-height: 27px;
|
||||
}
|
||||
|
||||
.post-vertical .vertical-attachment .vertical-attachment-content .overflowedName {
|
||||
.vertical-attachment .vertical-attachment-content .overflowedName {
|
||||
position: initial;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
|
|
@ -336,14 +336,14 @@ window.player = new class {
|
|||
return this.__findTrack(id, true) != -1
|
||||
}
|
||||
|
||||
play() {
|
||||
async play() {
|
||||
if(!this.currentTrack) {
|
||||
return
|
||||
}
|
||||
|
||||
document.querySelectorAll('audio').forEach(el => el.pause())
|
||||
|
||||
this.audioPlayer.play()
|
||||
await this.audioPlayer.play()
|
||||
this.__setFavicon()
|
||||
this.__updateFace()
|
||||
navigator.mediaSession.playbackState = "playing"
|
||||
|
@ -374,7 +374,7 @@ window.player = new class {
|
|||
this.playPreviousTrack()
|
||||
}
|
||||
|
||||
this.play()
|
||||
await this.play()
|
||||
}
|
||||
|
||||
async playNextTrack() {
|
||||
|
@ -391,14 +391,14 @@ window.player = new class {
|
|||
this.playNextTrack()
|
||||
}
|
||||
|
||||
this.play()
|
||||
await this.play()
|
||||
}
|
||||
|
||||
// fake shuffle
|
||||
async shuffle() {
|
||||
this.tracks.sort(() => Math.random() - 0.59)
|
||||
await this.setTrack(this.tracks.at(0).id)
|
||||
this.play()
|
||||
await this.play()
|
||||
}
|
||||
|
||||
isAtAudiosPage() {
|
||||
|
@ -489,15 +489,15 @@ window.player = new class {
|
|||
}
|
||||
|
||||
__setMediaSessionActions() {
|
||||
navigator.mediaSession.setActionHandler('play', () => {
|
||||
window.player.play()
|
||||
navigator.mediaSession.setActionHandler('play', async () => {
|
||||
await window.player.play()
|
||||
});
|
||||
navigator.mediaSession.setActionHandler('pause', () => {
|
||||
window.player.pause()
|
||||
});
|
||||
navigator.mediaSession.setActionHandler('previoustrack', () => { window.player.playPreviousTrack() });
|
||||
navigator.mediaSession.setActionHandler('nexttrack', () => { window.player.playNextTrack() });
|
||||
navigator.mediaSession.setActionHandler("seekto", (details) => {
|
||||
navigator.mediaSession.setActionHandler('previoustrack', async () => { await window.player.playPreviousTrack() });
|
||||
navigator.mediaSession.setActionHandler('nexttrack', async () => { await window.player.playNextTrack() });
|
||||
navigator.mediaSession.setActionHandler("seekto", async (details) => {
|
||||
window.player.audioPlayer.currentTime = details.seekTime
|
||||
});
|
||||
}
|
||||
|
@ -560,14 +560,19 @@ window.player = new class {
|
|||
}
|
||||
}
|
||||
|
||||
this.uiPlayer.find('.trackInfo .trackName span').html(escapeHtml(_c.name))
|
||||
this.uiPlayer.find('.trackInfo .trackPerformers').html('')
|
||||
const performers = _c.performer.split(', ')
|
||||
const lastPerformer = performers[performers.length - 1]
|
||||
performers.forEach(performer => {
|
||||
this.uiPlayer.find('.trackInfo .trackPerformers').append(
|
||||
`<a href='/search?section=audios&order=listens&only_performers=on&q=${encodeURIComponent(performer.escapeHtml())}'>${performer.escapeHtml()}${(performer != lastPerformer ? ', ' : '')}</a>`)
|
||||
})
|
||||
if(_c) {
|
||||
this.uiPlayer.find('.trackInfo .trackName span').html(escapeHtml(_c.name))
|
||||
this.uiPlayer.find('.trackInfo .trackPerformers').html('')
|
||||
const performers = _c.performer.split(', ')
|
||||
const lastPerformer = performers[performers.length - 1]
|
||||
performers.forEach(performer => {
|
||||
this.uiPlayer.find('.trackInfo .trackPerformers').append(
|
||||
`<a href='/search?section=audios&order=listens&only_performers=on&q=${encodeURIComponent(performer.escapeHtml())}'>${performer.escapeHtml()}${(performer != lastPerformer ? ', ' : '')}</a>`)
|
||||
})
|
||||
} else {
|
||||
this.uiPlayer.find('.trackInfo .trackName span').html(tr('track_noname'))
|
||||
this.uiPlayer.find('.trackInfo .trackPerformers').html(`<a>${tr('track_unknown')}</a>`)
|
||||
}
|
||||
|
||||
if(this.ajaxPlayer.length > 0) {
|
||||
this.ajaxPlayer.find('#aj_player_track_title b').html(escapeHtml(_c.performer))
|
||||
|
@ -637,6 +642,9 @@ window.player = new class {
|
|||
|
||||
ajReveal() {
|
||||
this.is_closed = false
|
||||
if(u('#ajax_audio_player').length == 0) {
|
||||
this.ajCreate()
|
||||
}
|
||||
u('#ajax_audio_player').removeClass('hidden')
|
||||
}
|
||||
|
||||
|
@ -731,8 +739,15 @@ u(document).on('click', '.audioEntry .playerButton > .playIcon', async (e) => {
|
|||
} else if(u(e.target).closest('.content_list').length > 0) {
|
||||
window.player.connectionType = '.content_list'
|
||||
_nodes = u(e.target).closest('.content_list').find('.audioEmbed').nodes
|
||||
} else if(u(e.target).closest('.generic_audio_list').length > 0) {
|
||||
window.player.connectionType = '.generic_audio_list'
|
||||
_nodes = u(e.target).closest('.generic_audio_list').find('.audioEmbed').nodes
|
||||
} else if(u(e.target).closest('.audiosInsert').length > 0) {
|
||||
window.player.connectionType = '.audiosInsert'
|
||||
_nodes = u(e.target).closest('.audiosInsert').find('.audioEmbed').nodes
|
||||
}
|
||||
|
||||
window.player.tracks = []
|
||||
_nodes.forEach(el => {
|
||||
const tempAudio = u(el)
|
||||
const name = tempAudio.attr('data-name').split(' — ')
|
||||
|
@ -753,7 +768,7 @@ u(document).on('click', '.audioEntry .playerButton > .playIcon', async (e) => {
|
|||
}
|
||||
|
||||
if(window.player.audioPlayer.paused) {
|
||||
window.player.play()
|
||||
await window.player.play()
|
||||
|
||||
if(!window.player.isAtAudiosPage()) {
|
||||
u('.audioEntry .playerButton .playIcon.paused').removeClass('paused')
|
||||
|
@ -772,9 +787,9 @@ u(document).on('click', '.audioEntry .playerButton > .playIcon', async (e) => {
|
|||
}
|
||||
})
|
||||
|
||||
u(document).on('click', '.bigPlayer .playButton, #ajax_audio_player #aj_player_play_btn', (e) => {
|
||||
u(document).on('click', '.bigPlayer .playButton, #ajax_audio_player #aj_player_play_btn', async (e) => {
|
||||
if(window.player.audioPlayer.paused) {
|
||||
window.player.play()
|
||||
await window.player.play()
|
||||
} else {
|
||||
window.player.pause()
|
||||
}
|
||||
|
@ -1066,6 +1081,8 @@ u(document).on('contextmenu', '.bigPlayer, .audioEmbed, #ajax_audio_player', (e)
|
|||
` : ''}
|
||||
<a id='audio_ctx_add_to_group'>${tr('audio_ctx_add_to_group')}</a>
|
||||
<a id='audio_ctx_add_to_playlist'>${tr('audio_ctx_add_to_playlist')}</a>
|
||||
${ctx_type == 'main_player' ? `
|
||||
<a id='audio_ctx_clear_context'>${tr('audio_ctx_clear_context')}</a>` : ''}
|
||||
${ctx_type == 'main_player' ? `<a href='https://github.com/mrilyew' target='_blank'>BigPlayer v1.1 by MrIlyew</a>` : ''}
|
||||
</div>
|
||||
`)
|
||||
|
@ -1156,6 +1173,13 @@ u(document).on('contextmenu', '.bigPlayer, .audioEmbed, #ajax_audio_player', (e)
|
|||
moving_track_player.remove()
|
||||
}
|
||||
})
|
||||
ctx_u.find('#audio_ctx_clear_context').on('click', (ev) => {
|
||||
const old_url = window.player.context.object.url
|
||||
window.player.pause()
|
||||
window.player.__resetContext()
|
||||
window.player.__updateFace()
|
||||
window.router.route(old_url)
|
||||
})
|
||||
})
|
||||
|
||||
u(document).on("click", ".musicIcon.edit-icon", (e) => {
|
||||
|
@ -1641,9 +1665,11 @@ $(document).on("click", "#_deletePlaylist", (e) => {
|
|||
}, Function.noop])
|
||||
})
|
||||
|
||||
$(document).on("click", "#__audioAttachment", (e) => {
|
||||
const form = e.target.closest("form")
|
||||
let body = `
|
||||
function showAudioAttachment(type = 'form', form = null)
|
||||
{
|
||||
const msg = new CMessageBox({
|
||||
title: tr("select_audio"),
|
||||
body: `
|
||||
<div class="searchBox">
|
||||
<input name="query" type="text" maxlength="50" placeholder="${tr("header_search")}">
|
||||
<select name="perf">
|
||||
|
@ -1653,13 +1679,12 @@ $(document).on("click", "#__audioAttachment", (e) => {
|
|||
</div>
|
||||
|
||||
<div class="audiosInsert"></div>
|
||||
`
|
||||
MessageBox(tr("select_audio"), body, [tr("close")], [Function.noop])
|
||||
|
||||
document.querySelector(".ovk-diag-body").style.padding = "0"
|
||||
document.querySelector(".ovk-diag-cont").style.width = "580px"
|
||||
document.querySelector(".ovk-diag-body").style.height = "335px"
|
||||
|
||||
`,
|
||||
buttons: [tr('close')],
|
||||
callbacks: [Function.noop],
|
||||
})
|
||||
msg.getNode().find('.ovk-diag-body').attr('style', 'padding:0px;height:335px')
|
||||
msg.getNode().attr('style', 'width:580px')
|
||||
let searcher = new playersSearcher("entity_audios", 0)
|
||||
searcher.successCallback = (response, thisc) => {
|
||||
let domparser = new DOMParser()
|
||||
|
@ -1674,8 +1699,18 @@ $(document).on("click", "#__audioAttachment", (e) => {
|
|||
}
|
||||
|
||||
result.querySelectorAll(".audioEmbed").forEach(el => {
|
||||
let id = el.dataset.prettyid
|
||||
const is_attached = (u(form).find(`.post-vertical .vertical-attachment[data-id='${id}']`)).length > 0
|
||||
let id = 0
|
||||
if(type == 'form') {
|
||||
id = el.dataset.prettyid
|
||||
} else {
|
||||
id = el.dataset.realid
|
||||
}
|
||||
let is_attached = false
|
||||
if(type == 'form') {
|
||||
is_attached = (u(form).find(`.post-vertical .vertical-attachment[data-id='${id}']`)).length > 0
|
||||
} else {
|
||||
is_attached = (u(form).find(`.PE_audios .vertical-attachment[data-id='${id}']`)).length > 0
|
||||
}
|
||||
|
||||
document.querySelector(".audiosInsert").insertAdjacentHTML("beforeend", `
|
||||
<div class='audio_attachment_header' style="display: flex;width: 100%;">
|
||||
|
@ -1717,7 +1752,7 @@ $(document).on("click", "#__audioAttachment", (e) => {
|
|||
searcher.movePage(Number(e.currentTarget.dataset.page))
|
||||
})
|
||||
|
||||
$(".searchBox input").on("change", async (e) => {
|
||||
u(".searchBox input").on("change", async (e) => {
|
||||
if(e.currentTarget.value === document.querySelector(".searchBox input").value) {
|
||||
searcher.clearContainer()
|
||||
|
||||
|
@ -1740,7 +1775,7 @@ $(document).on("click", "#__audioAttachment", (e) => {
|
|||
}
|
||||
})
|
||||
|
||||
$(".searchBox select").on("change", async (e) => {
|
||||
u(".searchBox select").on("change", async (e) => {
|
||||
searcher.clearContainer()
|
||||
searcher.searchType = e.currentTarget.value
|
||||
|
||||
|
@ -1750,14 +1785,24 @@ $(document).on("click", "#__audioAttachment", (e) => {
|
|||
|
||||
u(".audiosInsert").on("click", ".attachAudio", (ev) => {
|
||||
const id = ev.currentTarget.dataset.attachmentdata
|
||||
const is_attached = u(form).find(`.post-vertical .vertical-attachment[data-id='${id}']`).length > 0
|
||||
let is_attached = false
|
||||
if(type == 'form') {
|
||||
is_attached = u(form).find(`.post-vertical .vertical-attachment[data-id='${id}']`).length > 0
|
||||
} else {
|
||||
is_attached = u(form).find(`.PE_audios .vertical-attachment[data-id='${id}']`).length > 0
|
||||
}
|
||||
|
||||
// 04.11.2024 19:03
|
||||
// 30.11.2024 19:03
|
||||
if(is_attached) {
|
||||
u(form).find(`.post-vertical .vertical-attachment[data-id='${id}']`).remove()
|
||||
if(type == 'form') {
|
||||
u(form).find(`.post-vertical .vertical-attachment[data-id='${id}']`).remove()
|
||||
} else {
|
||||
u(form).find(`.PE_audios .vertical-attachment[data-id='${id}']`).remove()
|
||||
}
|
||||
u(ev.currentTarget).find("span").html(tr("attach_audio"))
|
||||
} else {
|
||||
if(u(form).find(`.upload-item`).length > window.openvk.max_attachments) {
|
||||
if(type == 'form' && u(form).find(`.upload-item`).length > window.openvk.max_attachments) {
|
||||
makeError(tr('too_many_attachments'), 'Red', 10000, 1)
|
||||
return
|
||||
}
|
||||
|
@ -1766,7 +1811,7 @@ $(document).on("click", "#__audioAttachment", (e) => {
|
|||
|
||||
const header = u(ev.currentTarget).closest('.audio_attachment_header')
|
||||
const player = header.find('.player_part')
|
||||
u(form).find(".post-vertical").append(`
|
||||
u(form).find(type == 'form' ? ".post-vertical" : '.PE_audios').append(`
|
||||
<div class="vertical-attachment upload-item" data-type='audio' data-id="${ev.currentTarget.dataset.attachmentdata}">
|
||||
<div class='vertical-attachment-content'>
|
||||
${player.html()}
|
||||
|
@ -1778,6 +1823,11 @@ $(document).on("click", "#__audioAttachment", (e) => {
|
|||
`)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
$(document).on("click", "#__audioAttachment", (e) => {
|
||||
const form = e.target.closest("form")
|
||||
showAudioAttachment('form', form)
|
||||
})
|
||||
|
||||
$(document).on("click", ".audioEmbed.processed .playerButton", (e) => {
|
||||
|
@ -1876,6 +1926,7 @@ u(document).on('click', '.upload_container_element #small_remove_button', (e) =>
|
|||
|
||||
u(document).on('click', `#upload_container #uploadMusic`, async (e) => {
|
||||
const current_upload_page = location.href
|
||||
let error = null
|
||||
let end_redir = ''
|
||||
u('#lastStepButtons').addClass('lagged')
|
||||
for(const elem of u('#lastStepContainers .upload_container_element').nodes) {
|
||||
|
@ -1901,13 +1952,21 @@ u(document).on('click', `#upload_container #uploadMusic`, async (e) => {
|
|||
body: fd,
|
||||
})
|
||||
const result_text = await result.json()
|
||||
if(result_text.success && result_text.redirect_link) {
|
||||
if(result_text.success) {
|
||||
end_redir = result_text.redirect_link
|
||||
} else {
|
||||
makeError(escapeHtml(result_text.flash.message))
|
||||
}
|
||||
await sleep(6000)
|
||||
elem_u.remove()
|
||||
}
|
||||
|
||||
if(!end_redir) {
|
||||
u('#lastStepButtons').removeClass('lagged')
|
||||
window.__audio_upload_page.showFirstPage()
|
||||
return
|
||||
}
|
||||
|
||||
if(current_upload_page == location.href) {
|
||||
window.router.route(end_redir)
|
||||
}
|
||||
|
@ -1920,3 +1979,77 @@ u(document).on("drop", "#upload_container", function (e) {
|
|||
document.getElementById("audio_input").files = e.dataTransfer.files
|
||||
u("#audio_input").trigger("change")
|
||||
})
|
||||
|
||||
u(document).on('click', '#_playlistAppendTracks', (e) => {
|
||||
// 1984
|
||||
showAudioAttachment('playlist', u('.PE_wrapper').nodes[0])
|
||||
})
|
||||
|
||||
u(document).on('drop', '.PE_audios .vertical-attachment', (e) => {
|
||||
const current = u('.upload-item.currently_dragging')
|
||||
if(e.dataTransfer.types.length < 1 || e.dataTransfer.types.includes('text/uri-list')) {
|
||||
e.preventDefault()
|
||||
|
||||
const target = u(e.target).closest('.upload-item')
|
||||
u('.dragged').removeClass('dragged')
|
||||
current.removeClass('currently_dragging')
|
||||
|
||||
if(!current.closest('.vertical-attachment').length < 1 && target.closest('.vertical-attachment').length < 1
|
||||
|| current.closest('.vertical-attachment').length < 1 && !target.closest('.vertical-attachment').length < 1) {
|
||||
return
|
||||
}
|
||||
|
||||
const first_html = target.nodes[0].outerHTML
|
||||
const second_html = current.nodes[0].outerHTML
|
||||
|
||||
current.nodes[0].outerHTML = first_html
|
||||
target.nodes[0].outerHTML = second_html
|
||||
}
|
||||
})
|
||||
|
||||
u(document).on("change", `input[name='cover']`, (e) => {
|
||||
const file = e.target.files[0]
|
||||
if(!file.type.startsWith("image/")) {
|
||||
makeError(tr("not_a_photo"))
|
||||
return
|
||||
}
|
||||
|
||||
const image = URL.createObjectURL(file)
|
||||
u(".playlistCover img").attr('src', image).attr('style', 'display:block')
|
||||
})
|
||||
|
||||
u(document).on("drop", `.playlistCover`, (e) => {
|
||||
e.preventDefault()
|
||||
e.dataTransfer.dropEffect = 'move';
|
||||
|
||||
document.querySelector(`input[name='cover']`).files = e.dataTransfer.files
|
||||
u(`input[name='cover']`).trigger("change")
|
||||
})
|
||||
|
||||
u(document).on('click', '.PE_end #playlist_create, .PE_end #playlist_edit', async (e) => {
|
||||
const ids = []
|
||||
u('.PE_audios .vertical-attachment').nodes.forEach(vatch => {
|
||||
ids.push(vatch.dataset.id)
|
||||
})
|
||||
if(!ids || ids.length < 1) {
|
||||
makeError(tr('error_playlist_creating_too_small'), 'Red', 5000, 77)
|
||||
return
|
||||
}
|
||||
|
||||
u(e.target).addClass('lagged')
|
||||
const fd = serializeForm(u('.PE_playlistEditPage').nodes[0])
|
||||
fd.append('hash', window.router.csrf)
|
||||
fd.append('ajax', 1)
|
||||
fd.append('audios', ids)
|
||||
const req = await fetch(location.href, {
|
||||
method: 'POST',
|
||||
body: fd,
|
||||
})
|
||||
const req_json = await req.json()
|
||||
if(req_json.success) {
|
||||
window.router.route(req_json.redirect)
|
||||
} else {
|
||||
makeError(req_json.flash.message)
|
||||
}
|
||||
u(e.target).removeClass('lagged')
|
||||
})
|
||||
|
|
|
@ -1,113 +0,0 @@
|
|||
let context_type = "entity_audios"
|
||||
let context_id = 0
|
||||
|
||||
if(document.querySelector("#editPlaylistForm")) {
|
||||
context_type = "playlist_context"
|
||||
context_id = document.querySelector("#editPlaylistForm").dataset.id
|
||||
}
|
||||
|
||||
if(document.querySelector(".showMoreAudiosPlaylist") && document.querySelector(".showMoreAudiosPlaylist").dataset.club != null) {
|
||||
context_type = "entity_audios"
|
||||
context_id = Number(document.querySelector(".showMoreAudiosPlaylist").dataset.club) * -1
|
||||
}
|
||||
|
||||
let searcher = new playersSearcher(context_type, context_id)
|
||||
|
||||
searcher.successCallback = (response, thisc) => {
|
||||
let domparser = new DOMParser()
|
||||
let result = domparser.parseFromString(response, "text/html")
|
||||
let pagesCount = Number(result.querySelector("input[name='pagesCount']").value)
|
||||
let count = Number(result.querySelector("input[name='count']").value)
|
||||
|
||||
result.querySelectorAll(".audioEmbed").forEach(el => {
|
||||
let id = Number(el.dataset.realid)
|
||||
let isAttached = (document.querySelector("input[name='audios']").value.includes(`${id},`))
|
||||
|
||||
document.querySelector(".playlistAudiosContainer").insertAdjacentHTML("beforeend", `
|
||||
<div id="newPlaylistAudios">
|
||||
<div class="playerContainer">
|
||||
${el.outerHTML}
|
||||
</div>
|
||||
<div class="attachAudio addToPlaylist" data-id="${id}">
|
||||
<span>${isAttached ? tr("remove_from_playlist") : tr("add_to_playlist")}</span>
|
||||
</div>
|
||||
</div>
|
||||
`)
|
||||
})
|
||||
|
||||
if(count < 1)
|
||||
document.querySelector(".playlistAudiosContainer").insertAdjacentHTML("beforeend", `
|
||||
${tr("no_results")}
|
||||
`)
|
||||
|
||||
if(Number(thisc.page) >= pagesCount)
|
||||
u(".showMoreAudiosPlaylist").remove()
|
||||
else {
|
||||
if(document.querySelector(".showMoreAudiosPlaylist") != null) {
|
||||
document.querySelector(".showMoreAudiosPlaylist").setAttribute("data-page", thisc.page + 1)
|
||||
|
||||
if(thisc.query != "") {
|
||||
document.querySelector(".showMoreAudiosPlaylist").setAttribute("data-query", thisc.query)
|
||||
}
|
||||
|
||||
document.querySelector(".showMoreAudiosPlaylist").style.display = "block"
|
||||
} else {
|
||||
document.querySelector(".playlistAudiosContainer").parentNode.insertAdjacentHTML("beforeend", `
|
||||
<div class="showMoreAudiosPlaylist" data-page="2"
|
||||
${thisc.query != "" ? `"data-query="${thisc.query}"` : ""}
|
||||
${thisc.context_type == "entity_audios" ? `"data-playlist="${thisc.context_id}"` : ""}
|
||||
${thisc.context_id < 0 ? `"data-club="${thisc.context_id}"` : ""}>
|
||||
${tr("show_more_audios")}
|
||||
</div>
|
||||
`)
|
||||
}
|
||||
}
|
||||
|
||||
u("#loader").remove()
|
||||
}
|
||||
|
||||
searcher.beforesendCallback = () => {
|
||||
document.querySelector(".playlistAudiosContainer").parentNode.insertAdjacentHTML("beforeend", `<img id="loader" src="/assets/packages/static/openvk/img/loading_mini.gif">`)
|
||||
|
||||
if(document.querySelector(".showMoreAudiosPlaylist") != null)
|
||||
document.querySelector(".showMoreAudiosPlaylist").style.display = "none"
|
||||
}
|
||||
|
||||
searcher.errorCallback = () => {
|
||||
fastError("Error when loading players")
|
||||
}
|
||||
|
||||
searcher.clearContainer = () => {
|
||||
document.querySelector(".playlistAudiosContainer").innerHTML = ""
|
||||
}
|
||||
|
||||
$(document).on("click", ".showMoreAudiosPlaylist", (e) => {
|
||||
searcher.movePage(Number(e.currentTarget.dataset.page))
|
||||
})
|
||||
|
||||
$(document).on("change", "input#playlist_query", async (e) => {
|
||||
e.preventDefault()
|
||||
|
||||
await new Promise(r => setTimeout(r, 500));
|
||||
|
||||
if(e.currentTarget.value === document.querySelector("input#playlist_query").value) {
|
||||
searcher.clearContainer()
|
||||
|
||||
if(e.currentTarget.value == "") {
|
||||
searcher.context_type = "entity_audios"
|
||||
searcher.context_id = 0
|
||||
searcher.query = ""
|
||||
|
||||
searcher.movePage(1)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
searcher.context_type = "search_context"
|
||||
searcher.context_id = 0
|
||||
searcher.query = e.currentTarget.value
|
||||
|
||||
searcher.movePage(1)
|
||||
return;
|
||||
}
|
||||
})
|
|
@ -1101,14 +1101,14 @@ u(document).on('paste', '#write .small-textarea', (e) => {
|
|||
}
|
||||
})
|
||||
|
||||
u(document).on('dragstart', '#write .post-horizontal .upload-item, .post-vertical .upload-item', (e) => {
|
||||
u(document).on('dragstart', '#write .post-horizontal .upload-item, .post-vertical .upload-item, .PE_audios .vertical-attachment', (e) => {
|
||||
//e.preventDefault()
|
||||
//console.log(e)
|
||||
u(e.target).closest('.upload-item').addClass('currently_dragging')
|
||||
return
|
||||
})
|
||||
|
||||
u(document).on('dragover', '#write .post-horizontal .upload-item, .post-vertical .upload-item', (e) => {
|
||||
u(document).on('dragover', '#write .post-horizontal .upload-item, .post-vertical .upload-item, .PE_audios .vertical-attachment', (e) => {
|
||||
e.preventDefault()
|
||||
|
||||
const target = u(e.target).closest('.upload-item')
|
||||
|
@ -1130,7 +1130,7 @@ u(document).on("dragover drop", async (e) => {
|
|||
return false;
|
||||
})
|
||||
|
||||
u(document).on('dragleave dragend', '#write .post-horizontal .upload-item, .post-vertical .upload-item', (e) => {
|
||||
u(document).on('dragleave dragend', '#write .post-horizontal .upload-item, .post-vertical .upload-item, .PE_audios .vertical-attachment', (e) => {
|
||||
//console.log(e)
|
||||
u(e.target).closest('.upload-item').removeClass('dragged')
|
||||
return
|
||||
|
@ -1792,7 +1792,7 @@ u(document).on('click', `.post-horizontal .upload-item .upload-delete`, (e) => {
|
|||
u(e.target).closest('.upload-item').remove()
|
||||
})
|
||||
|
||||
u(document).on('click', `.post-vertical .vertical-attachment #small_remove_button`, (e) => {
|
||||
u(document).on('click', `.vertical-attachment #small_remove_button`, (e) => {
|
||||
e.preventDefault()
|
||||
u(e.target).closest('.vertical-attachment').remove()
|
||||
})
|
||||
|
|
|
@ -7,7 +7,7 @@ window.router = new class {
|
|||
if(script.src) {
|
||||
const script_url = new URL(script.src)
|
||||
const script_main_part = script_url.pathname
|
||||
console.log(script_main_part)
|
||||
|
||||
return u(`script[src^='${script_main_part}']`).length > 0
|
||||
}
|
||||
|
||||
|
@ -62,6 +62,7 @@ window.router = new class {
|
|||
const page_body = u(parsed_content.querySelector('.page_body'))
|
||||
const sidebar = u(parsed_content.querySelector('.sidebar'))
|
||||
const page_header = u(parsed_content.querySelector('.page_header'))
|
||||
const backdrop = u(parsed_content.querySelector('#backdrop'))
|
||||
if(page_body.length < 1) {
|
||||
throw new Error('Invalid page has been loaded')
|
||||
return
|
||||
|
@ -77,6 +78,15 @@ window.router = new class {
|
|||
})
|
||||
u('.page_body').html(page_body.html())
|
||||
u('.sidebar').html(sidebar.html())
|
||||
if(backdrop.length > 0) {
|
||||
if(u('#backdrop').length == 0) {
|
||||
u('body').append(`<div id="backdrop"></div>`)
|
||||
}
|
||||
u('#backdrop').nodes[0].outerHTML = (backdrop.nodes[0].outerHTML)
|
||||
} else {
|
||||
u('#backdrop').remove()
|
||||
}
|
||||
|
||||
if(u('.page_header #search_box select').length > 0 && page_header.find('#search_box select').length > 0) {
|
||||
u('.page_header #search_box select').nodes[0].value = page_header.find('#search_box select').nodes[0].value
|
||||
}
|
||||
|
@ -285,7 +295,7 @@ u(document).on('submit', 'form', async (e) => {
|
|||
return
|
||||
}
|
||||
|
||||
const form_data = serializeForm(form)
|
||||
const form_data = serializeForm(form, e.submitter)
|
||||
const request_object = {
|
||||
method: method,
|
||||
headers: {
|
||||
|
|
|
@ -182,11 +182,10 @@ function getRemainingTime(fullTime, time) {
|
|||
return "-" + fmtTime(timer)
|
||||
}
|
||||
|
||||
function serializeForm(form)
|
||||
function serializeForm(form, submitter = null)
|
||||
{
|
||||
const u_ = u(form)
|
||||
const inputs = u_.find('input, textarea')
|
||||
|
||||
const inputs = u_.find('input, textarea, button')
|
||||
let fd = new FormData()
|
||||
inputs.nodes.forEach(inp => {
|
||||
if(!inp || !inp.name) {
|
||||
|
@ -194,16 +193,17 @@ function serializeForm(form)
|
|||
}
|
||||
|
||||
if(inp.type == 'submit') {
|
||||
return
|
||||
if(inp !== submitter) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
switch(inp.type) {
|
||||
case 'submit':
|
||||
return
|
||||
case 'hidden':
|
||||
case 'text':
|
||||
case 'textarea':
|
||||
case 'select':
|
||||
case 'submit':
|
||||
fd.append(inp.name, inp.value)
|
||||
break
|
||||
case 'checkbox':
|
||||
|
@ -213,8 +213,13 @@ function serializeForm(form)
|
|||
|
||||
break
|
||||
case 'file':
|
||||
for(const __file of inp.files) {
|
||||
fd.append(inp.name, __file)
|
||||
if(!inp.multiple) {
|
||||
if(inp.files[0]) {
|
||||
fd.append(inp.name, inp.files[0])
|
||||
} else {
|
||||
const emptyFile = new Blob([], { type: 'application/octet-stream' })
|
||||
fd.append(inp.name, emptyFile, '')
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
|
|
@ -949,12 +949,11 @@
|
|||
"add_to_playlist" = "Add to playlist";
|
||||
"remove_from_playlist" = "Remove from playlist";
|
||||
"delete_playlist" = "Delete playlist";
|
||||
"playlist_cover" = "Playlist cover";
|
||||
|
||||
"playlists_user" = "User's playlists";
|
||||
"playlists_club" = "Group's playlists";
|
||||
"change_cover" = "Change cover";
|
||||
"playlist_cover" = "Playlist's cover";
|
||||
"playlist_cover" = "Playlist cover";
|
||||
|
||||
"minutes_count_zero" = "Lasts no minutes";
|
||||
"minutes_count_one" = "Lasts one minute";
|
||||
|
@ -1004,6 +1003,7 @@
|
|||
"audio_ctx_add_to_group" = "Add to group";
|
||||
"audio_ctx_add_to_playlist" = "Add to playlist";
|
||||
"audio_ctx_play_next" = "Play next";
|
||||
"audio_ctx_clear_context" = "Clear tracks list";
|
||||
|
||||
/* Notifications */
|
||||
|
||||
|
@ -1603,6 +1603,7 @@
|
|||
"error_adding_source_regex" = "Error adding source: incorrect link.";
|
||||
"error_adding_source_long" = "Error adding source: link is too long.";
|
||||
"error_adding_source_sus" = "Error adding source: suspicious link.";
|
||||
"error_playlist_creating_too_small" = "Add at least one audio";
|
||||
|
||||
/* Admin actions */
|
||||
|
||||
|
|
|
@ -908,7 +908,7 @@
|
|||
"playlists_user" = "Плейлисты пользователя";
|
||||
"playlists_club" = "Плейлисты группы";
|
||||
"change_cover" = "Сменить обложку";
|
||||
"playlist_cover" = "Обложка плейлиста";
|
||||
"add_audio_verb" = "Добавить аудиозаписи";
|
||||
|
||||
"minutes_count_zero" = "длится ноль минут";
|
||||
"minutes_count_one" = "длится одну минуту";
|
||||
|
@ -959,6 +959,7 @@
|
|||
"audio_ctx_add_to_group" = "Добавить в группу";
|
||||
"audio_ctx_add_to_playlist" = "Добавить в плейлист";
|
||||
"audio_ctx_play_next" = "Воспроизвести следующим";
|
||||
"audio_ctx_clear_context" = "Очистить список треков";
|
||||
|
||||
/* Notifications */
|
||||
|
||||
|
@ -1505,6 +1506,7 @@
|
|||
"error_adding_source_regex" = "Ошибка добавления источника: некорректная ссылка.";
|
||||
"error_adding_source_long" = "Ошибка добавления источника: слишком длинная ссылка.";
|
||||
"error_adding_source_sus" = "Ошибка добавления источника: гиперссылка заблокирована.";
|
||||
"error_playlist_creating_too_small" = "Добавь хотя бы одну аудиозапись.";
|
||||
|
||||
/* Admin actions */
|
||||
|
||||
|
|
Loading…
Reference in a new issue