upload page changes, add playlist add menu

This commit is contained in:
mrilyew 2024-10-21 22:01:11 +03:00
parent 933c4ee45a
commit d165307993
13 changed files with 431 additions and 72 deletions

View file

@ -581,13 +581,31 @@ final class Audio extends VKAPIRequestHandler
]; ];
} }
function searchAlbums(string $query, int $offset = 0, int $limit = 25, int $drop_private = 0): object function searchAlbums(string $query = '', int $offset = 0, int $limit = 25, int $drop_private = 0, int $order = 0, int $from_me = 0): object
{ {
$this->requireUser(); $this->requireUser();
$playlists = []; $playlists = [];
$search = (new Audios)->searchPlaylists($query)->offsetLimit($offset, $limit); $params = [];
foreach($search as $playlist) { $order_str = 'id';
switch($order) {
default:
case 0:
$order_str = 'id';
break;
case 1:
$order_str = 'length';
break;
case 2:
$order_str = 'listens';
break;
}
if($from_me === 1)
$params['from_me'] = $this->getUser()->getId();
$search = (new Audios)->findPlaylists($query, $params, ['type' => $order_str, 'invert' => false]);
foreach($search->offsetLimit($offset, $limit) as $playlist) {
if(!$playlist->canBeViewedBy($this->getUser())) { if(!$playlist->canBeViewedBy($this->getUser())) {
if($drop_private == 0) if($drop_private == 0)
$playlists[] = NULL; $playlists[] = NULL;
@ -599,7 +617,7 @@ final class Audio extends VKAPIRequestHandler
} }
return (object) [ return (object) [
"count" => sizeof($playlists), "count" => $search->size(),
"items" => $playlists, "items" => $playlists,
]; ];
} }

View file

@ -300,11 +300,13 @@ class Audios
function findPlaylists(string $query, array $params = [], array $order = ['type' => 'id', 'invert' => false]): \Traversable function findPlaylists(string $query, array $params = [], array $order = ['type' => 'id', 'invert' => false]): \Traversable
{ {
$result = $this->playlists->where([ $result = $this->playlists->where([
"unlisted" => 0,
"deleted" => 0, "deleted" => 0,
])->where("CONCAT_WS(' ', name, description) LIKE ?", "%$query%"); ])->where("CONCAT_WS(' ', name, description) LIKE ?", "%$query%");
$order_str = 'id'; $order_str = 'id';
if(is_null($params['from_me']) || empty($params['from_me']))
$result->where(["unlisted" => 0]);
switch($order['type']) { switch($order['type']) {
case 'id': case 'id':
$order_str = 'id ' . ($order['invert'] ? 'ASC' : 'DESC'); $order_str = 'id ' . ($order['invert'] ? 'ASC' : 'DESC');
@ -317,6 +319,17 @@ class Audios
break; break;
} }
foreach($params as $paramName => $paramValue) {
if(is_null($paramValue) || $paramValue == '') continue;
switch($paramName) {
# БУДЬ МАКСИМАЛЬНО АККУРАТЕН С ДАННЫМ ПАРАМЕТРОМ
case "from_me":
$result->where("owner", $paramValue);
break;
}
}
if($order_str) if($order_str)
$result->order($order_str); $result->order($order_str);

View file

@ -181,6 +181,7 @@ class Posts
case 'ads': case 'ads':
$result->where("ad", 1); $result->where("ad", 1);
break;*/ break;*/
# БУДЬ МАКСИМАЛЬНО АККУРАТЕН С ДАННЫМ ПАРАМЕТРОМ
case 'from_me': case 'from_me':
$result->where("owner", $paramValue); $result->where("owner", $paramValue);
break; break;

View file

@ -567,16 +567,65 @@ final class AudioPresenter extends OpenVKPresenter
break; break;
case "add_to_club": case "add_to_club":
$club = (new Clubs)->get((int)$this->postParam("club")); $detailed = [];
if($audio->isWithdrawn())
if(!$club || !$club->canBeModifiedBy($this->user->identity)) $this->flashFail("err", "error", tr("invalid_audio"), null, true);
$this->flashFail("err", "error", tr("access_denied"), null, true);
if(empty($this->postParam("clubs")))
if(!$audio->isInLibraryOf($club)) $this->flashFail("err", "error", 'clubs not passed', null, true);
$audio->add($club);
else $clubs_arr = explode(',', $this->postParam("clubs"));
$this->flashFail("err", "error", tr("group_has_audio"), null, true); $count = sizeof($clubs_arr);
if($count < 1 || $count > 10) {
$this->flashFail("err", "error", tr('too_many_or_to_lack'), null, true);
}
foreach($clubs_arr as $club_id) {
$club = (new Clubs)->get((int)$club_id);
if(!$club || !$club->canBeModifiedBy($this->user->identity))
continue;
if(!$audio->isInLibraryOf($club)) {
$detailed[$club_id] = true;
$audio->add($club);
} else {
$detailed[$club_id] = false;
continue;
}
}
$this->returnJson(["success" => true, 'detailed' => $detailed]);
break;
case "add_to_playlist":
$detailed = [];
if($audio->isWithdrawn())
$this->flashFail("err", "error", tr("invalid_audio"), null, true);
if(empty($this->postParam("playlists")))
$this->flashFail("err", "error", 'playlists not passed', null, true);
$playlists_arr = explode(',', $this->postParam("playlists"));
$count = sizeof($playlists_arr);
if($count < 1 || $count > 10) {
$this->flashFail("err", "error", tr('too_many_or_to_lack'), null, true);
}
foreach($playlists_arr as $playlist_id) {
$pid = explode('_', $playlist_id);
$playlist = (new Audios)->getPlaylistByOwnerAndVID((int)$pid[0], (int)$pid[1]);
if(!$playlist || !$playlist->canBeModifiedBy($this->user->identity))
continue;
if(!$playlist->hasAudio($audio)) {
$playlist->add($audio);
$detailed[$playlist_id] = true;
} else {
$detailed[$playlist_id] = false;
continue;
}
}
$this->returnJson(["success" => true, 'detailed' => $detailed]);
break; break;
case "delete": case "delete":
if($audio->canBeModifiedBy($this->user->identity)) if($audio->canBeModifiedBy($this->user->identity))

View file

@ -83,6 +83,7 @@ final class SearchPresenter extends OpenVKPresenter
$parameters['with_lyrics'] = true; $parameters['with_lyrics'] = true;
break; break;
# дай бог работал этот case
case 'from_me': case 'from_me':
if((int) $param_value != 1) continue; if((int) $param_value != 1) continue;
$parameters['from_me'] = $this->user->id; $parameters['from_me'] = $this->user->id;

View file

@ -110,8 +110,24 @@
document.querySelector("#firstStep").style.display = "none" document.querySelector("#firstStep").style.display = "none"
document.querySelector("#lastStep").style.display = "block" document.querySelector("#lastStep").style.display = "block"
function fallback() {
console.info('Tags not found, setting default values.')
document.querySelector("#lastStep input[name=name]").value = files[0].name
document.querySelector("#lastStep select[name=genre]").value = "Other"
document.querySelector("#lastStep input[name=performer]").value = tr("track_unknown");
}
const tags = await id3.fromFile(files[0]); let tags = null
try {
tags = await id3.fromFile(files[0]);
} catch(e) {
console.error(e)
}
console.log(tags)
if(tags != null) { if(tags != null) {
console.log("ID" + tags.kind + " detected, setting values..."); console.log("ID" + tags.kind + " detected, setting values...");
@ -126,11 +142,22 @@
document.querySelector("#lastStep input[name=performer]").value = tr("track_unknown"); document.querySelector("#lastStep input[name=performer]").value = tr("track_unknown");
if(tags.genre != null) { if(tags.genre != null) {
if(document.querySelector("#lastStep select[name=genre] > option[value='" + tags.genre + "']") != null) { // if there are more than one genre
document.querySelector("#lastStep select[name=genre]").value = tags.genre; if(tags.genre.split(', ').length > 1) {
const genres = tags.genre.split(', ')
genres.forEach(genre => {
if(document.querySelector("#lastStep select[name=genre] > option[value='" + genre + "']") != null) {
document.querySelector("#lastStep select[name=genre]").value = genre;
}
})
} else { } else {
console.warn("Unknown genre: " + tags.genre); if(document.querySelector("#lastStep select[name=genre] > option[value='" + tags.genre + "']") != null) {
document.querySelector("#lastStep select[name=genre]").value = "Other" document.querySelector("#lastStep select[name=genre]").value = tags.genre;
} else {
console.warn("Unknown genre: " + tags.genre);
document.querySelector("#lastStep select[name=genre]").value = "Other"
}
} }
} else { } else {
document.querySelector("#lastStep select[name=genre]").value = "Other" document.querySelector("#lastStep select[name=genre]").value = "Other"
@ -139,9 +166,7 @@
if(tags.comments != null) if(tags.comments != null)
document.querySelector("#lastStep textarea[name=lyrics]").value = tags.comments document.querySelector("#lastStep textarea[name=lyrics]").value = tags.comments
} else { } else {
document.querySelector("#lastStep input[name=name]").value = files[0].name fallback()
document.querySelector("#lastStep select[name=genre]").value = "Other"
document.querySelector("#lastStep input[name=performer]").value = tr("track_unknown");
} }
}); });

View file

@ -1,7 +1,8 @@
{php $id = $audio->getId() . rand(0, 1000)} {php $id = $audio->getId() . rand(0, 1000)}
{php $isWithdrawn = $audio->isWithdrawn()} {php $isWithdrawn = $audio->isWithdrawn()}
{php $isAvailable = $audio->isAvailable()}
{php $editable = isset($thisUser) && $audio->canBeModifiedBy($thisUser)} {php $editable = isset($thisUser) && $audio->canBeModifiedBy($thisUser)}
<div id="audioEmbed-{$id}" data-realid="{$audio->getId()}" {if $hideButtons}data-prettyid="{$audio->getPrettyId()}" data-name="{$audio->getName()}"{/if} data-genre="{$audio->getGenre()}" class="audioEmbed {if !$audio->isAvailable()}processed{/if} {if $isWithdrawn}withdrawn{/if}" data-length="{$audio->getLength()}" data-keys="{json_encode($audio->getKeys())}" data-url="{$audio->getURL()}"> <div id="audioEmbed-{$id}" data-realid="{$audio->getId()}" {if $hideButtons}data-prettyid="{$audio->getPrettyId()}" data-name="{$audio->getName()}"{/if} data-genre="{$audio->getGenre()}" class="audioEmbed {if !$isAvailable}processed{/if} {if $isWithdrawn}withdrawn{/if}" data-length="{$audio->getLength()}" data-keys="{json_encode($audio->getKeys())}" data-url="{$audio->getURL()}">
<audio class="audio" /> <audio class="audio" />
<div id="miniplayer" class="audioEntry" style="min-height: 39px;"> <div id="miniplayer" class="audioEntry" style="min-height: 39px;">
@ -36,7 +37,7 @@
<div class="add-icon musicIcon hovermeicon" data-id="{$audio->getId()}" n:if="isset($thisUser) && !$hasAudio && !$isWithdrawn" ></div> <div class="add-icon musicIcon hovermeicon" data-id="{$audio->getId()}" n:if="isset($thisUser) && !$hasAudio && !$isWithdrawn" ></div>
<div class="remove-icon-group musicIcon" data-id="{$audio->getId()}" data-club="{$club->getId()}" n:if="isset($thisUser) && isset($club) && $club->canBeModifiedBy($thisUser)" ></div> <div class="remove-icon-group musicIcon" data-id="{$audio->getId()}" data-club="{$club->getId()}" n:if="isset($thisUser) && isset($club) && $club->canBeModifiedBy($thisUser)" ></div>
<div class="add-icon-group musicIcon hidden" data-id="{$audio->getId()}" n:if="isset($thisUser) && !$isWithdrawn" ></div> <div class="add-icon-group musicIcon hidden" data-id="{$audio->getId()}" n:if="isset($thisUser) && !$isWithdrawn" ></div>
<a class="download-icon musicIcon" n:if='isset($thisUser) && !$isWithdrawn && OPENVK_ROOT_CONF["openvk"]["preferences"]["music"]["exposeOriginalURLs"]' href="{$audio->getOriginalURL()}" download="{$audio->getDownloadName()}"></a> <a class="download-icon musicIcon" n:if='isset($thisUser) && !$isWithdrawn && $isAvailable && OPENVK_ROOT_CONF["openvk"]["preferences"]["music"]["exposeOriginalURLs"]' href="{$audio->getOriginalURL()}" download="{$audio->getDownloadName()}"></a>
<div class="edit-icon musicIcon" data-lyrics="{$audio->getLyrics()}" data-title="{$audio->getTitle()}" data-performer="{$audio->getPerformer()}" data-explicit="{(int)$audio->isExplicit()}" data-searchable="{(int)!$audio->isUnlisted()}" n:if="isset($thisUser) && $editable && !$isWithdrawn" ></div> <div class="edit-icon musicIcon" data-lyrics="{$audio->getLyrics()}" data-title="{$audio->getTitle()}" data-performer="{$audio->getPerformer()}" data-explicit="{(int)$audio->isExplicit()}" data-searchable="{(int)!$audio->isUnlisted()}" n:if="isset($thisUser) && $editable && !$isWithdrawn" ></div>
<div class="report-icon musicIcon" data-id="{$audio->getId()}" n:if="isset($thisUser) && !$editable && !$isWithdrawn" ></div> <div class="report-icon musicIcon" data-id="{$audio->getId()}" n:if="isset($thisUser) && !$editable && !$isWithdrawn" ></div>
{/if} {/if}

View file

@ -213,7 +213,6 @@
highlightText({$query}, '.page_wrap_content_main', ['text', "span[data-highlight='_appDesc']"]) highlightText({$query}, '.page_wrap_content_main', ['text', "span[data-highlight='_appDesc']"])
</script> </script>
{elseif $section === 'posts'} {elseif $section === 'posts'}
{* шмалим дурь курим шмаль дуем коку пиво пьём *}
<div class='search_content' n:foreach="$data as $dat"> <div class='search_content' n:foreach="$data as $dat">
{if !$dat || $dat->getWallOwner()->isHideFromGlobalFeedEnabled()} {if !$dat || $dat->getWallOwner()->isHideFromGlobalFeedEnabled()}
{_closed_group_post}. {_closed_group_post}.

View file

@ -764,3 +764,27 @@
.addToPlaylist { .addToPlaylist {
width: 22%; width: 22%;
} }
#_addAudioAdditional {
padding: 6px;
}
#_addAudioAdditional #_tabs {
margin: 0px -6px;
}
#_addAudioAdditional #_tabs .mb_tabs {
background-color: unset;
border-bottom: unset;
padding: 0px 5px;
}
#_addAudioAdditional #_tip {
margin: 5px 0px;
display: block;
}
#_addAudioAdditional #_content {
margin-top: 6px;
padding: 1px;
}

View file

@ -2102,12 +2102,13 @@ table td[width="120"] {
border-radius: 2px; border-radius: 2px;
} }
.mb_tab div { .mb_tab div, .mb_tab > a {
padding: 5px 9px; padding: 5px 9px;
display: block;
} }
.mb_tab#active { .mb_tab#active {
background-color: #898989; background-color: #606060;
} }
.mb_tab#active a { .mb_tab#active a {
@ -2584,7 +2585,7 @@ a.poll-retract-vote {
.page_header.search_expanded .header_navigation #search_box #searchBoxFastTips.shown { .page_header.search_expanded .header_navigation #search_box #searchBoxFastTips.shown {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
z-index: 1; z-index: 2;
} }
.page_header.search_expanded .link { .page_header.search_expanded .link {
@ -3211,3 +3212,53 @@ hr {
background-position: 50% !important; background-position: 50% !important;
} }
.entity_vertical_list {
display: flex;
flex-direction: column;
gap: 3px;
height: 197px;
overflow-y: auto;
}
.entity_vertical_list .entity_vertical_list_item {
display: flex;
flex-direction: row;
justify-content: space-between;
gap: 4px;
}
.entity_vertical_list .entity_vertical_list_item .first_column {
display: flex;
flex-direction: row;
gap: 4px;
}
.entity_vertical_list .entity_vertical_list_item .avatar {
display: block;
}
.entity_vertical_list .entity_vertical_list_item img {
width: 50px;
height: 50px;
object-fit: cover;
}
.entity_vertical_list .entity_vertical_list_item .info {
width: 300px;
display: flex;
flex-direction: column;
justify-content: space-around;
}
.entity_vertical_list.mini .entity_vertical_list_item img {
width: 35px;
height: 35px;
}
#gif_loader {
content: "";
display: inline-block;
background-image: url('/assets/packages/static/openvk/img/loading_mini.gif');
width: 30px;
height: 7px;
}

View file

@ -993,7 +993,7 @@ $(document).on("click", ".musicIcon.remove-icon", (e) => {
e.stopImmediatePropagation() e.stopImmediatePropagation()
const id = e.currentTarget.dataset.id const id = e.currentTarget.dataset.id
if(e.altKey) { if(e.detail > 1 || e.altKey) {
const player = e.target.closest('.audioEmbed') const player = e.target.closest('.audioEmbed')
player.querySelector('.add-icon-group').click() player.querySelector('.add-icon-group').click()
return return
@ -1061,60 +1061,214 @@ $(document).on("click", ".musicIcon.remove-icon-group", (e) => {
}) })
$(document).on("click", ".musicIcon.add-icon-group", async (ev) => { $(document).on("click", ".musicIcon.add-icon-group", async (ev) => {
let body = ` let current_tab = 'club';
${tr("what_club_add")} const id = Number(ev.target.dataset.id)
<div style="margin-top: 4px;"> const body = `
<select id="addIconsWindow" style="width: 59%;"></select> <div id='_addAudioAdditional'>
<input name="addButton" type="button" class="button" value="${tr("add")}"> <div id='_tabs'>
<div class="mb_tabs">
<div class="mb_tab" data-name='club'>
<a>
${tr('to_club')}
</a>
</div>
<div class="mb_tab" data-name='playlist'>
<a>
${tr('to_playlist')}
</a>
</div>
</div>
</div>
<span id='_tip'>${tr('add_audio_limitations')}</span>
<div id='_content'></div>
</div> </div>
<span class="errorPlace"></span>
` `
MessageBox(tr("add_audio_to_club"), body, [tr("close")], [Function.noop])
document.querySelector(".ovk-diag-body").style.padding = "11px" MessageBox(tr("add_audio"), body, [tr("cancel"), tr("add")], [Function.noop, () => {
const ids = []
if(window.openvk.writeableClubs == null) { u('#_content .entity_vertical_list_item').nodes.forEach(item => {
try { const _checkbox = item.querySelector(`input[type='checkbox'][name='add_to']`)
window.openvk.writeableClubs = await API.Groups.getWriteableClubs() if(_checkbox.checked) {
} catch (e) { ids.push(item.dataset.id)
document.querySelector(".errorPlace").innerHTML = tr("no_access_clubs") }
document.querySelector(".ovk-diag-body input[name='addButton']").classList.add("lagged") })
if(ids.length < 1 || ids.length > 10) {
return return
} }
console.log(ids)
switch(current_tab) {
case 'club':
$.ajax({
type: "POST",
url: `/audio${id}/action?act=add_to_club`,
data: {
hash: u("meta[name=csrf]").attr("value"),
clubs: ids.join(',')
},
success: (response) => {
if(!response.success)
fastError(response.flash.message)
else
NewNotification(tr("audio_was_successfully_added"), '')
}
})
break
case 'playlist':
$.ajax({
type: "POST",
url: `/audio${id}/action?act=add_to_playlist`,
data: {
hash: u("meta[name=csrf]").attr("value"),
playlists: ids.join(',')
},
success: (response) => {
if(!response.success)
fastError(response.flash.message)
else
NewNotification(tr("audio_was_successfully_added"), '')
}
})
break
}
}])
u(".ovk-diag-body").attr('style', 'padding:0px;height: 260px;')
async function switchTab(tab = 'club') {
current_tab = tab
u(`#_addAudioAdditional .mb_tab`).attr('id', 'ki')
u(`#_addAudioAdditional .mb_tab[data-name='${tab}']`).attr('id', 'active')
switch(tab) {
case 'club':
u("#_content").html(`<div class='entity_vertical_list mini'></div>`)
if(window.openvk.writeableClubs == null) {
u('.entity_vertical_list').append(`<div id='gif_loader'></div>`)
try {
window.openvk.writeableClubs = await API.Groups.getWriteableClubs()
} catch (e) {
u("#_content").html(tr("no_access_clubs"))
return
}
u('.entity_vertical_list #gif_loader').remove()
}
window.openvk.writeableClubs.forEach(el => {
u("#_content .entity_vertical_list").append(`
<label class='entity_vertical_list_item with_third_column' data-id='${el.id}'>
<div class='first_column'>
<a href='/club${el.id}' class='avatar'>
<img src='${el.avatar}' alt='avatar'>
</a>
<div class='info'>
<b class='noOverflow' value="${el.id}">${ovk_proc_strtr(escapeHtml(el.name), 100)}</b>
</div>
</div>
<div class='third_column'>
<input type='checkbox' name='add_to'>
</div>
</label>
`)
})
break
case 'playlist':
const per_page = 10
let page = 0
u("#_content").html(`<div class='entity_vertical_list mini'></div>`)
async function recievePlaylists(s_page) {
res = await fetch(`/method/audio.searchAlbums?auth_mechanism=roaming&query=&limit=10&offset=${s_page * per_page}&from_me=1`)
res = await res.json()
return res
}
function appendPlaylists(response) {
response.items.forEach(el => {
u("#_content .entity_vertical_list").append(`
<label class='entity_vertical_list_item with_third_column' data-id='${el.owner_id}_${el.id}'>
<div class='first_column'>
<a href='/playlist${el.owner_id}_${el.id}' class='avatar'>
<img src='${el.cover_url}' alt='cover'>
</a>
<div class='info'>
<b class='noOverflow' value="${el.owner_id}_${el.id}">${ovk_proc_strtr(escapeHtml(el.title), 100)}</b>
</div>
</div>
<div class='third_column'>
<input type='checkbox' name='add_to'>
</div>
</label>
`)
})
if(response.count > per_page * page) {
u("#_content .entity_vertical_list").append(`<a id='_pladdwinshowmore'>${tr('show_more')}</a>`)
}
}
if(window.openvk.writeablePlaylists == null) {
u('.entity_vertical_list').append(`<div id='gif_loader'></div>`)
try {
res = await recievePlaylists(page)
page += 1
window.openvk.writeablePlaylists = res.response
if(!window.openvk.writeablePlaylists || window.openvk.writeablePlaylists.count < 1) {
throw new Error
}
} catch (e) {
u("#_content").html(tr("no_access_playlists"))
return
}
u('.entity_vertical_list #gif_loader').remove()
}
appendPlaylists(window.openvk.writeablePlaylists)
u('#_addAudioAdditional').on('click', '#_pladdwinshowmore', async (e) => {
e.target.outerHTML = ''
res = await recievePlaylists(page)
page += 1
appendPlaylists(res.response)
})
break
}
} }
window.openvk.writeableClubs.forEach(el => { switchTab(current_tab)
document.querySelector("#addIconsWindow").insertAdjacentHTML("beforeend", `
<option value="${el.id}">${ovk_proc_strtr(escapeHtml(el.name), 50)}</option> u("#_addAudioAdditional").on("click", ".mb_tab a", async (e) => {
`) await switchTab(u(e.target).closest('.mb_tab').attr('data-name'))
}) })
$(".ovk-diag-body").on("click", "input[name='addButton']", (e) => { u("#_addAudioAdditional").on("click", "input[name='add_to']", async (e) => {
$.ajax({ if(u(`input[name='add_to']:checked`).length > 10) {
type: "POST", e.preventDefault()
url: `/audio${ev.target.dataset.id}/action?act=add_to_club`, }
data: {
hash: u("meta[name=csrf]").attr("value"),
club: document.querySelector("#addIconsWindow").value
},
beforeSend: () => {
e.target.classList.add("lagged")
document.querySelector(".errorPlace").innerHTML = ""
},
success: (response) => {
if(!response.success)
document.querySelector(".errorPlace").innerHTML = response.flash.message
e.currentTarget.classList.remove("lagged")
}
})
}) })
}) })
$(document).on("click", ".musicIcon.add-icon", (e) => { $(document).on("click", ".musicIcon.add-icon", (e) => {
const id = e.currentTarget.dataset.id const id = e.currentTarget.dataset.id
if(e.altKey) { if(e.detail > 1 || e.altKey) {
const player = e.target.closest('.audioEmbed') const player = e.target.closest('.audioEmbed')
player.querySelector('.add-icon-group').click() player.querySelector('.add-icon-group').click()
return return

View file

@ -250,6 +250,8 @@
"clubs_posts" = "Group's posts"; "clubs_posts" = "Group's posts";
"others_posts" = "Others posts"; "others_posts" = "Others posts";
"show_more" = "Show more";
/* Friends */ /* Friends */
"friends" = "Friends"; "friends" = "Friends";
@ -878,6 +880,7 @@
"my_playlists" = "My playlists"; "my_playlists" = "My playlists";
"playlists" = "Playlists"; "playlists" = "Playlists";
"audios_explicit" = "Contains obscene language"; "audios_explicit" = "Contains obscene language";
"audios_unlisted" = "Unlisted";
"withdrawn" = "Withdrawn"; "withdrawn" = "Withdrawn";
"deleted" = "Deleted"; "deleted" = "Deleted";
"owner" = "Owner"; "owner" = "Owner";
@ -901,7 +904,7 @@
"edit_playlist" = "Edit playlist"; "edit_playlist" = "Edit playlist";
"unable_to_load_queue" = "Error when loading queue."; "unable_to_load_queue" = "Error when loading queue.";
"fully_delete_audio" = "Fully delete audio"; "fully_delete_audio" = "Delete audio";
"attach_audio" = "Attach audio"; "attach_audio" = "Attach audio";
"detach_audio" = "Detach audio"; "detach_audio" = "Detach audio";
@ -929,6 +932,12 @@
"listens_count_other" = "$1 listens"; "listens_count_other" = "$1 listens";
"add_audio_to_club" = "Add audio to group"; "add_audio_to_club" = "Add audio to group";
"add_audio" = "Adding audio";
"add_audio_limitations" = "You can select up to 10 groups/playlists.";
"to_club" = "To club";
"to_playlist" = "To playlist";
"audio_was_successfully_added" = "Audios was successfully added.";
"what_club_add" = "Which group do you want to add the song to?"; "what_club_add" = "Which group do you want to add the song to?";
"group_has_audio" = "This group already has this song."; "group_has_audio" = "This group already has this song.";
"group_hasnt_audio" = "This group doesn't have this song."; "group_hasnt_audio" = "This group doesn't have this song.";
@ -936,6 +945,7 @@
"by_name" = "by name"; "by_name" = "by name";
"by_performer" = "by performer"; "by_performer" = "by performer";
"no_access_clubs" = "There are no groups where you are an administrator."; "no_access_clubs" = "There are no groups where you are an administrator.";
"no_access_playlists" = "You haven't created any playlists.";
"audio_successfully_uploaded" = "Audio has been successfully uploaded and is currently being processed."; "audio_successfully_uploaded" = "Audio has been successfully uploaded and is currently being processed.";
"broadcast_audio" = "Broadcast audio to status"; "broadcast_audio" = "Broadcast audio to status";
@ -948,6 +958,8 @@
"repeat_tip" = "Repeat"; "repeat_tip" = "Repeat";
"shuffle_tip" = "Shuffle"; "shuffle_tip" = "Shuffle";
"mute_tip" = "Mute"; "mute_tip" = "Mute";
"playlist_hide_from_search" = "Unlisted";
"confirm_deleting_audio" = "Do you sure want to delete this audio?";
/* Notifications */ /* Notifications */
@ -1539,6 +1551,7 @@
"error_code" = "Error code: $1."; "error_code" = "Error code: $1.";
"ffmpeg_timeout" = "Timed out waiting ffmpeg. Try to upload file again."; "ffmpeg_timeout" = "Timed out waiting ffmpeg. Try to upload file again.";
"ffmpeg_not_installed" = "Failed to proccess the file. It looks like ffmpeg is not installed on this server."; "ffmpeg_not_installed" = "Failed to proccess the file. It looks like ffmpeg is not installed on this server.";
"too_many_or_to_lack" = "Too few or too many sources.";
/* Admin actions */ /* Admin actions */
@ -2009,7 +2022,7 @@
"s_order_invert" = "Invert"; "s_order_invert" = "Invert";
"s_order_by_reg_date" = "By reg date"; "s_order_by_reg_date" = "By reg date";
"s_order_by_creation_date" = "By creation date"; "s_order_by_creation_date" = "By creation date";
"s_order_by_publishing_date" = "By publication date; "s_order_by_publishing_date" = "By publication date";
"s_order_by_upload_date" = "By upload date"; "s_order_by_upload_date" = "By upload date";
"s_by_date" = "By date"; "s_by_date" = "By date";

View file

@ -229,6 +229,7 @@
"users_posts" = "Записи $1"; "users_posts" = "Записи $1";
"clubs_posts" = "Записи сообщества"; "clubs_posts" = "Записи сообщества";
"others_posts" = "Чужие записи"; "others_posts" = "Чужие записи";
"show_more" = "Показать больше";
/* Friends */ /* Friends */
@ -887,6 +888,13 @@
"listens_count_other" = "$1 прослушиваний"; "listens_count_other" = "$1 прослушиваний";
"add_audio_to_club" = "Добавить аудио в группу"; "add_audio_to_club" = "Добавить аудио в группу";
"add_audio" = "Добавление аудио";
"add_audio_limitations" = "Можно выбрать до 10 групп/плейлистов.";
"to_club" = "В группу";
"to_playlist" = "В плейлист";
"audio_was_successfully_added" = "Аудио были успешно добавлены.";
"what_club_add" = "В какую группу вы хотите добавить песню?"; "what_club_add" = "В какую группу вы хотите добавить песню?";
"group_has_audio" = "У группы уже есть эта песня."; "group_has_audio" = "У группы уже есть эта песня.";
"group_hasnt_audio" = "У группы нет этой песни."; "group_hasnt_audio" = "У группы нет этой песни.";
@ -894,6 +902,7 @@
"by_name" = "по композициям"; "by_name" = "по композициям";
"by_performer" = "по исполнителю"; "by_performer" = "по исполнителю";
"no_access_clubs" = "Нет групп, где вы являетесь администратором."; "no_access_clubs" = "Нет групп, где вы являетесь администратором.";
"no_access_playlists" = "Вы ещё не создавали плейлистов.";
"audio_successfully_uploaded" = "Аудио успешно загружено и на данный момент обрабатывается."; "audio_successfully_uploaded" = "Аудио успешно загружено и на данный момент обрабатывается.";
"broadcast_audio" = "Транслировать аудио в статус"; "broadcast_audio" = "Транслировать аудио в статус";
@ -1444,6 +1453,7 @@
"error_code" = "Код ошибки: $1."; "error_code" = "Код ошибки: $1.";
"ffmpeg_timeout" = "Превышено время ожидания обработки ffmpeg. Попробуйте загрузить файл снова."; "ffmpeg_timeout" = "Превышено время ожидания обработки ffmpeg. Попробуйте загрузить файл снова.";
"ffmpeg_not_installed" = "Не удалось обработать файл. Похоже, на сервере не установлен ffmpeg."; "ffmpeg_not_installed" = "Не удалось обработать файл. Похоже, на сервере не установлен ffmpeg.";
"too_many_or_to_lack" = "Слишком мало либо слишком много источников.";
/* Admin actions */ /* Admin actions */