Compare commits

..

1 commit

Author SHA1 Message Date
mrilyew
dc184d06fe
Merge 874a654bd4 into bbef3a8518 2024-09-23 06:16:28 +03:00
71 changed files with 1945 additions and 3301 deletions

76
ServiceAPI/Search.php Normal file
View file

@ -0,0 +1,76 @@
<?php declare(strict_types=1);
namespace openvk\ServiceAPI;
use openvk\Web\Models\Entities\{User, Club};
use openvk\Web\Models\Repositories\{Users, Clubs, Videos};
use Chandler\Database\DatabaseConnection;
class Search implements Handler
{
protected $user;
private $users;
private $clubs;
private $videos;
function __construct(?User $user)
{
$this->user = $user;
$this->users = new Users;
$this->clubs = new Clubs;
$this->videos = new Videos;
}
function fastSearch(string $query, string $type = "users", callable $resolve, callable $reject)
{
if($query == "" || strlen($query) < 3)
$reject(12, "No input or input < 3");
$repo;
$sort;
switch($type) {
default:
case "users":
$repo = (new Users);
$sort = "rating DESC";
break;
case "groups":
$repo = (new Clubs);
$sort = "id ASC";
break;
case "videos":
$repo = (new Videos);
$sort = "created ASC";
break;
}
$res = $repo->find($query, ["doNotSearchMe" => $this->user->getId(), "doNotSearchPrivate" => true,], $sort);
$results = array_slice(iterator_to_array($res), 0, 5);
$count = sizeof($results);
$arr = [
"count" => $count,
"items" => []
];
if(sizeof($results) < 1) {
$reject(2, "No results");
}
foreach($results as $res) {
$arr["items"][] = [
"id" => $res->getId(),
"name" => $type == "users" ? $res->getCanonicalName() : $res->getName(),
"avatar" => $type != "videos" ? $res->getAvatarUrl() : $res->getThumbnailURL(),
"url" => $type != "videos" ? $res->getUrl() : "/video".$res->getPrettyId(),
"description" => ovk_proc_strtr($res->getDescription() ?? "...", 40)
];
}
$resolve($arr);
}
}

View file

@ -7,32 +7,20 @@ final class Account extends VKAPIRequestHandler
function getProfileInfo(): object function getProfileInfo(): object
{ {
$this->requireUser(); $this->requireUser();
$user = $this->getUser();
$return_object = (object) [ return (object) [
"first_name" => $user->getFirstName(), "first_name" => $this->getUser()->getFirstName(),
"photo_200" => $user->getAvatarURL("normal"), "id" => $this->getUser()->getId(),
"nickname" => $user->getPseudo(), "last_name" => $this->getUser()->getLastName(),
"is_service_account" => false, "home_town" => $this->getUser()->getHometown(),
"id" => $user->getId(), "status" => $this->getUser()->getStatus(),
"is_verified" => $user->isVerified(), "audio_status" => is_null($this->getUser()->getCurrentAudioStatus()) ? NULL : $this->getUser()->getCurrentAudioStatus()->toVkApiStruct($this->getUser()),
"verification_status" => $user->isVerified() ? 'verified' : 'unverified', "bdate" => is_null($this->getUser()->getBirthday()) ? '01.01.1970' : $this->getUser()->getBirthday()->format('%e.%m.%Y'),
"last_name" => $user->getLastName(), "bdate_visibility" => $this->getUser()->getBirthdayPrivacy(),
"home_town" => $user->getHometown(),
"status" => $user->getStatus(),
"bdate" => is_null($user->getBirthday()) ? '01.01.1970' : $user->getBirthday()->format('%e.%m.%Y'),
"bdate_visibility" => $user->getBirthdayPrivacy(),
"phone" => "+420 ** *** 228", # TODO "phone" => "+420 ** *** 228", # TODO
"relation" => $user->getMaritalStatus(), "relation" => $this->getUser()->getMaritalStatus(),
"screen_name" => $user->getShortCode(), "sex" => $this->getUser()->isFemale() ? 1 : 2
"sex" => $user->isFemale() ? 1 : 2,
#"email" => $user->getEmail(),
]; ];
$audio_status = $user->getCurrentAudioStatus();
if(!is_null($audio_status))
$return_object->audio_status = $audio_status->toVkApiStruct($user);
return $return_object;
} }
function getInfo(): object function getInfo(): object
@ -164,30 +152,4 @@ final class Account extends VKAPIRequestHandler
return (object) $output; return (object) $output;
} }
function getBalance(): object
{
$this->requireUser();
if(!OPENVK_ROOT_CONF['openvk']['preferences']['commerce'])
$this->fail(105, "Commerce is disabled on this instance");
return (object) ['votes' => $this->getUser()->getCoins()];
}
function getOvkSettings(): object
{
$this->requireUser();
$user = $this->getUser();
$settings_list = (object)[
'avatar_style' => $user->getStyleAvatar(),
'style' => $user->getStyle(),
'show_rating' => !$user->prefersNotToSeeRating(),
'nsfw_tolerance' => $user->getNsfwTolerance(),
'post_view' => $user->hasMicroblogEnabled() ? 'microblog' : 'old',
'main_page' => $user->getMainPage() == 0 ? 'my_page' : 'news',
];
return $settings_list;
}
} }

View file

@ -581,18 +581,13 @@ final class Audio extends VKAPIRequestHandler
]; ];
} }
function searchAlbums(string $query = '', int $offset = 0, int $limit = 25, int $drop_private = 0, int $order = 0, int $from_me = 0): object function searchAlbums(string $query, int $offset = 0, int $limit = 25, int $drop_private = 0): object
{ {
$this->requireUser(); $this->requireUser();
$playlists = []; $playlists = [];
$params = []; $search = (new Audios)->searchPlaylists($query)->offsetLimit($offset, $limit);
$order_str = (['id', 'length', 'listens'][$order] ?? 'id'); foreach($search as $playlist) {
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;
@ -604,7 +599,7 @@ final class Audio extends VKAPIRequestHandler
} }
return (object) [ return (object) [
"count" => $search->size(), "count" => sizeof($playlists),
"items" => $playlists, "items" => $playlists,
]; ];
} }

View file

@ -6,18 +6,15 @@ use openvk\Web\Models\Entities\Notifications\GiftNotification;
final class Gifts extends VKAPIRequestHandler final class Gifts extends VKAPIRequestHandler
{ {
function get(int $user_id = NULL, int $count = 10, int $offset = 0) function get(int $user_id, int $count = 10, int $offset = 0)
{ {
$this->requireUser(); $this->requireUser();
$i = 0; $i = 0;
$i += $offset;
$server_url = ovk_scheme(true) . $_SERVER["HTTP_HOST"];
if($user_id) $i += $offset;
$user = (new UsersRepo)->get($user_id);
else $user = (new UsersRepo)->get($user_id);
$user = $this->getUser();
if(!$user || $user->isDeleted()) if(!$user || $user->isDeleted())
$this->fail(177, "Invalid user"); $this->fail(177, "Invalid user");
@ -50,9 +47,9 @@ final class Gifts extends VKAPIRequestHandler
"date" => $gift->sent->timestamp(), "date" => $gift->sent->timestamp(),
"gift" => [ "gift" => [
"id" => $gift->gift->getId(), "id" => $gift->gift->getId(),
"thumb_256" => $server_url. $gift->gift->getImage(2), "thumb_256" => $gift->gift->getImage(2),
"thumb_96" => $server_url . $gift->gift->getImage(2), "thumb_96" => $gift->gift->getImage(2),
"thumb_48" => $server_url . $gift->gift->getImage(2) "thumb_48" => $gift->gift->getImage(2)
], ],
"privacy" => 0 "privacy" => 0
]; ];
@ -128,13 +125,12 @@ final class Gifts extends VKAPIRequestHandler
$this->fail(501, "Not implemented"); $this->fail(501, "Not implemented");
} }
# в vk кстати называется gifts.getCatalog # этих методов не было в ВК, но я их добавил чтобы можно было отобразить список подарков
function getCategories(bool $extended = false, int $page = 1) function getCategories(bool $extended = false, int $page = 1)
{ {
$cats = (new GiftsRepo)->getCategories($page); $cats = (new GiftsRepo)->getCategories($page);
$categ = []; $categ = [];
$i = 0; $i = 0;
$server_url = ovk_scheme(true) . $_SERVER["HTTP_HOST"];
if(!OPENVK_ROOT_CONF['openvk']['preferences']['commerce']) if(!OPENVK_ROOT_CONF['openvk']['preferences']['commerce'])
$this->fail(105, "Commerce is disabled on this instance"); $this->fail(105, "Commerce is disabled on this instance");
@ -144,8 +140,8 @@ final class Gifts extends VKAPIRequestHandler
"name" => $cat->getName(), "name" => $cat->getName(),
"description" => $cat->getDescription(), "description" => $cat->getDescription(),
"id" => $cat->getId(), "id" => $cat->getId(),
"thumbnail" => $server_url . $cat->getThumbnailURL(), "thumbnail" => $cat->getThumbnailURL(),
]; ];
if($extended == true) { if($extended == true) {
$categ[$i]["localizations"] = []; $categ[$i]["localizations"] = [];
@ -182,7 +178,7 @@ final class Gifts extends VKAPIRequestHandler
"name" => $gift->getName(), "name" => $gift->getName(),
"image" => $gift->getImage(2), "image" => $gift->getImage(2),
"usages_left" => (int)$gift->getUsagesLeft($this->getUser()), "usages_left" => (int)$gift->getUsagesLeft($this->getUser()),
"price" => $gift->getPrice(), "price" => $gift->getPrice(), # голосов
"is_free" => $gift->isFree() "is_free" => $gift->isFree()
]; ];
} }

View file

@ -88,10 +88,6 @@ final class Groups extends VKAPIRequestHandler
case "can_suggest": case "can_suggest":
$rClubs[$i]->can_suggest = !$usr->canBeModifiedBy($this->getUser()) && $usr->getWallType() == 2; $rClubs[$i]->can_suggest = !$usr->canBeModifiedBy($this->getUser()) && $usr->getWallType() == 2;
break; break;
case "background":
$backgrounds = $usr->getBackDropPictureURLs();
$rClubs[$i]->background = $backgrounds;
break;
# unstandard feild # unstandard feild
case "suggested_count": case "suggested_count":
if($usr->getWallType() != 2) { if($usr->getWallType() != 2) {
@ -212,10 +208,6 @@ final class Groups extends VKAPIRequestHandler
case "can_suggest": case "can_suggest":
$response[$i]->can_suggest = !$clb->canBeModifiedBy($this->getUser()) && $clb->getWallType() == 2; $response[$i]->can_suggest = !$clb->canBeModifiedBy($this->getUser()) && $clb->getWallType() == 2;
break; break;
case "background":
$backgrounds = $clb->getBackDropPictureURLs();
$response[$i]->background = $backgrounds;
break;
# unstandard feild # unstandard feild
case "suggested_count": case "suggested_count":
if($clb->getWallType() != 2) { if($clb->getWallType() != 2) {
@ -252,30 +244,23 @@ final class Groups extends VKAPIRequestHandler
return $response; return $response;
} }
function search(string $q, int $offset = 0, int $count = 100, string $fields = "screen_name,is_admin,is_member,is_advertiser,photo_50,photo_100,photo_200") function search(string $q, int $offset = 0, int $count = 100)
{ {
if($count > 100) {
$this->fail(100, "One of the parameters specified was missing or invalid: count should be less or equal to 100");
}
$clubs = new ClubsRepo; $clubs = new ClubsRepo;
$array = []; $array = [];
$find = $clubs->find($q); $find = $clubs->find($q);
foreach ($find->offsetLimit($offset, $count) as $group) foreach ($find as $group)
$array[] = $group->getId(); $array[] = $group->getId();
if(!$array || sizeof($array) < 1) {
return (object) [
"count" => 0,
"items" => [],
];
}
return (object) [ return (object) [
"count" => $find->size(), "count" => $find->size(),
"items" => $this->getById(implode(',', $array), "", $fields) "items" => $this->getById(implode(',', $array), "", "is_admin,is_member,is_advertiser,photo_50,photo_100,photo_200", $offset, $count)
/*
* As there is no thing as "fields" by the original documentation
* i'll just bake this param by the example shown here: https://dev.vk.com/method/groups.search
*/
]; ];
} }

View file

@ -151,6 +151,7 @@ final class Users extends VKAPIRequestHandler
} }
case "music": case "music":
if(!$canView) { if(!$canView) {
$response[$i]->music = "secret";
break; break;
} }
@ -158,6 +159,7 @@ final class Users extends VKAPIRequestHandler
break; break;
case "movies": case "movies":
if(!$canView) { if(!$canView) {
$response[$i]->movies = "secret";
break; break;
} }
@ -165,6 +167,7 @@ final class Users extends VKAPIRequestHandler
break; break;
case "tv": case "tv":
if(!$canView) { if(!$canView) {
$response[$i]->tv = "secret";
break; break;
} }
@ -172,6 +175,7 @@ final class Users extends VKAPIRequestHandler
break; break;
case "books": case "books":
if(!$canView) { if(!$canView) {
$response[$i]->books = "secret";
break; break;
} }
@ -179,6 +183,7 @@ final class Users extends VKAPIRequestHandler
break; break;
case "city": case "city":
if(!$canView) { if(!$canView) {
$response[$i]->city = "Воскресенск";
break; break;
} }
@ -186,6 +191,7 @@ final class Users extends VKAPIRequestHandler
break; break;
case "interests": case "interests":
if(!$canView) { if(!$canView) {
$response[$i]->interests = "secret";
break; break;
} }
@ -193,6 +199,7 @@ final class Users extends VKAPIRequestHandler
break; break;
case "quotes": case "quotes":
if(!$canView) { if(!$canView) {
$response[$i]->quotes = "secret";
break; break;
} }
@ -200,6 +207,7 @@ final class Users extends VKAPIRequestHandler
break; break;
case "email": case "email":
if(!$canView) { if(!$canView) {
$response[$i]->email = "secret@gmail.com";
break; break;
} }
@ -207,6 +215,7 @@ final class Users extends VKAPIRequestHandler
break; break;
case "telegram": case "telegram":
if(!$canView) { if(!$canView) {
$response[$i]->telegram = "@secret";
break; break;
} }
@ -214,6 +223,7 @@ final class Users extends VKAPIRequestHandler
break; break;
case "about": case "about":
if(!$canView) { if(!$canView) {
$response[$i]->about = "secret";
break; break;
} }
@ -221,6 +231,7 @@ final class Users extends VKAPIRequestHandler
break; break;
case "rating": case "rating":
if(!$canView) { if(!$canView) {
$response[$i]->rating = 22;
break; break;
} }
@ -235,37 +246,9 @@ final class Users extends VKAPIRequestHandler
"notes_count" => (new Notes)->getUserNotesCount($usr) "notes_count" => (new Notes)->getUserNotesCount($usr)
]; ];
break; break;
case "correct_counters":
$response[$i]->counters = (object) [
"friends" => $usr->getFriendsCount(),
"photos" => (new Photos)->getUserPhotosCount($usr),
"videos" => (new Videos)->getUserVideosCount($usr),
"audios" => (new Audios)->getUserCollectionSize($usr),
"notes" => (new Notes)->getUserNotesCount($usr),
"groups" => $usr->getClubCount(),
"online_friends" => $usr->getFriendsOnlineCount(),
];
break;
case "guid": case "guid":
$response[$i]->guid = $usr->getChandlerGUID(); $response[$i]->guid = $usr->getChandlerGUID();
break; break;
case 'background':
$backgrounds = $usr->getBackDropPictureURLs();
$response[$i]->background = $backgrounds;
break;
case 'reg_date':
if(!$canView) {
break;
}
$response[$i]->reg_date = $usr->getRegistrationTime()->timestamp();
break;
case 'is_dead':
$response[$i]->is_dead = $usr->isDead();
break;
case 'nickname':
$response[$i]->nickname = $usr->getPseudo();
break;
} }
} }
@ -317,90 +300,89 @@ final class Users extends VKAPIRequestHandler
int $count = 100, int $count = 100,
string $city = "", string $city = "",
string $hometown = "", string $hometown = "",
int $sex = 3, int $sex = 2,
int $status = 0, # marital_status int $status = 0, # это про marital status
bool $online = false, bool $online = false,
# non standart params: # дальше идут параметры которых нету в vkapi но есть на сайте
string $profileStatus = "", # а это уже нормальный статус
int $sort = 0, int $sort = 0,
int $polit_views = 0, int $before = 0,
int $politViews = 0,
int $after = 0,
string $interests = "",
string $fav_music = "", string $fav_music = "",
string $fav_films = "", string $fav_films = "",
string $fav_shows = "", string $fav_shows = "",
string $fav_books = "" string $fav_books = "",
string $fav_quotes = ""
) )
{ {
if($count > 100) {
$this->fail(100, "One of the parameters specified was missing or invalid: count should be less or equal to 100");
}
$users = new UsersRepo; $users = new UsersRepo;
$output_sort = ['type' => 'id', 'invert' => false];
$output_params = [ $sortg = "id ASC";
"ignore_private" => true,
]; $nfilds = $fields;
switch($sort) { switch($sort) {
default:
case 0: case 0:
$output_sort = ['type' => 'id', 'invert' => false]; $sortg = "id DESC";
break; break;
case 1: case 1:
$output_sort = ['type' => 'id', 'invert' => true]; $sortg = "id ASC";
break;
case 2:
$sortg = "first_name DESC";
break;
case 3:
$sortg = "first_name ASC";
break; break;
case 4: case 4:
$output_sort = ['type' => 'rating', 'invert' => false]; $sortg = "rating DESC";
if(!str_contains($nfilds, "rating")) {
$nfilds .= "rating";
}
break;
case 5:
$sortg = "rating DESC";
if(!str_contains($nfilds, "rating")) {
$nfilds .= "rating";
}
break; break;
} }
if(!empty($city))
$output_params['city'] = $city;
if(!empty($hometown))
$output_params['hometown'] = $hometown;
if($sex != 3)
$output_params['gender'] = $sex;
if($status != 0)
$output_params['marital_status'] = $status;
if($polit_views != 0)
$output_params['polit_views'] = $polit_views;
if(!empty($interests))
$output_params['interests'] = $interests;
if(!empty($fav_music))
$output_params['fav_music'] = $fav_music;
if(!empty($fav_films))
$output_params['fav_films'] = $fav_films;
if(!empty($fav_shows))
$output_params['fav_shows'] = $fav_shows;
if(!empty($fav_books))
$output_params['fav_books'] = $fav_books;
if($online)
$output_params['is_online'] = 1;
$array = []; $array = [];
$find = $users->find($q, $output_params, $output_sort);
foreach ($find->offsetLimit($offset, $count) as $user) $parameters = [
"city" => !empty($city) ? $city : NULL,
"hometown" => !empty($hometown) ? $hometown : NULL,
"gender" => $sex < 2 ? $sex : NULL,
"maritalstatus" => (bool)$status ? $status : NULL,
"politViews" => (bool)$politViews ? $politViews : NULL,
"is_online" => $online ? 1 : NULL,
"status" => !empty($profileStatus) ? $profileStatus : NULL,
"before" => $before != 0 ? $before : NULL,
"after" => $after != 0 ? $after : NULL,
"interests" => !empty($interests) ? $interests : NULL,
"fav_music" => !empty($fav_music) ? $fav_music : NULL,
"fav_films" => !empty($fav_films) ? $fav_films : NULL,
"fav_shows" => !empty($fav_shows) ? $fav_shows : NULL,
"fav_books" => !empty($fav_books) ? $fav_books : NULL,
"fav_quotes" => !empty($fav_quotes) ? $fav_quotes : NULL,
"doNotSearchPrivate" => true,
];
$find = $users->find($q, $parameters, $sortg);
foreach ($find as $user)
$array[] = $user->getId(); $array[] = $user->getId();
if(!$array || sizeof($array) < 1) {
return (object) [
"count" => 0,
"items" => [],
];
}
return (object) [ return (object) [
"count" => $find->size(), "count" => $find->size(),
"items" => $this->get(implode(',', $array), $fields) "items" => $this->get(implode(',', $array), $nfilds, $offset, $count)
]; ];
} }

View file

@ -60,60 +60,4 @@ final class Video extends VKAPIRequestHandler
]; ];
} }
} }
function search(string $q = '', int $sort = 0, int $offset = 0, int $count = 10, bool $extended = false, string $fields = ''): object
{
$this->requireUser();
$params = [];
$db_sort = ['type' => 'id', 'invert' => false];
$videos = (new VideosRepo)->find($q, $params, $db_sort);
$items = iterator_to_array($videos->offsetLimit($offset, $count));
$count = $videos->size();
$return_items = [];
$profiles = [];
$groups = [];
foreach($items as $item)
$return_item = $item->getApiStructure($this->getUser());
$return_item = $return_item->video;
$return_items[] = $return_item;
if($return_item['owner_id']) {
if($return_item['owner_id'] > 0)
$profiles[] = $return_item['owner_id'];
else
$groups[] = abs($return_item['owner_id']);
}
if($extended) {
$profiles = array_unique($profiles);
$groups = array_unique($groups);
$profilesFormatted = [];
$groupsFormatted = [];
foreach($profiles as $prof) {
$profile = (new UsersRepo)->get($prof);
$profilesFormatted[] = $profile->toVkApiStruct($this->getUser(), $fields);
}
foreach($groups as $gr) {
$group = (new ClubsRepo)->get($gr);
$groupsFormatted[] = $group->toVkApiStruct($this->getUser(), $fields);
}
return (object) [
"count" => $count,
"items" => $return_items,
"profiles" => $profilesFormatted,
"groups" => $groupsFormatted,
];
}
return (object) [
"count" => $count,
"items" => $return_items,
];
}
} }

View file

@ -126,41 +126,65 @@ final class Wall extends VKAPIRequestHandler
else else
$profiles[] = $attachment->getOwner()->getId(); $profiles[] = $attachment->getOwner()->getId();
$post_source = [];
if($attachment->getPlatform(true) === NULL) {
$post_source = (object)["type" => "vk"];
} else {
$post_source = (object)[
"type" => "api",
"platform" => $attachment->getPlatform(true)
];
}
$repost[] = [ $repost[] = [
"id" => $attachment->getVirtualId(), "id" => $attachment->getVirtualId(),
"owner_id" => $attachment->isPostedOnBehalfOfGroup() ? $attachment->getOwner()->getId() * -1 : $attachment->getOwner()->getId(), "owner_id" => $attachment->isPostedOnBehalfOfGroup() ? $attachment->getOwner()->getId() * -1 : $attachment->getOwner()->getId(),
"from_id" => $attachment->isPostedOnBehalfOfGroup() ? $attachment->getOwner()->getId() * -1 : $attachment->getOwner()->getId(), "from_id" => $attachment->isPostedOnBehalfOfGroup() ? $attachment->getOwner()->getId() * -1 : $attachment->getOwner()->getId(),
"date" => $attachment->getPublicationTime()->timestamp(), "date" => $attachment->getPublicationTime()->timestamp(),
"post_type" => $attachment->getVkApiType(), "post_type" => "post",
"text" => $attachment->getText(false), "text" => $attachment->getText(false),
"attachments" => $repostAttachments, "attachments" => $repostAttachments,
"post_source" => $attachment->getPostSourceInfo(), "post_source" => $post_source,
]; ];
if ($attachment->getTargetWall() > 0) if ($attachment->getVirtualId() > 0)
$profiles[] = $attachment->getTargetWall(); $profiles[] = $attachment->getVirtualId();
else else
$groups[] = abs($attachment->getTargetWall()); $groups[] = $attachment->getVirtualId();
if($post->isSigned()) if($post->isSigned())
$profiles[] = $attachment->getOwner()->getId(); $profiles[] = $attachment->getOwner()->getId();
} }
} }
$post_source = [];
if($post->getPlatform(true) === NULL) {
$post_source = (object)["type" => "vk"];
} else {
$post_source = (object)[
"type" => "api",
"platform" => $post->getPlatform(true)
];
}
$postType = "post";
$signerId = NULL; $signerId = NULL;
if($post->getSuggestionType() != 0)
$postType = "suggest";
if($post->isSigned()) { if($post->isSigned()) {
$actualAuthor = $post->getOwner(false); $actualAuthor = $post->getOwner(false);
$signerId = $actualAuthor->getId(); $signerId = $actualAuthor->getId();
} }
# TODO "can_pin", "copy_history" и прочее не должны возвращаться, если равны null или false $items[] = (object)[
# Ну и ещё всё надо перенести в toVkApiStruct, а то слишком много дублированного кода
$post_temp_obj = (object)[
"id" => $post->getVirtualId(), "id" => $post->getVirtualId(),
"from_id" => $from_id, "from_id" => $from_id,
"owner_id" => $post->getTargetWall(), "owner_id" => $post->getTargetWall(),
"date" => $post->getPublicationTime()->timestamp(), "date" => $post->getPublicationTime()->timestamp(),
"post_type" => $post->getVkApiType(), "post_type" => $postType,
"text" => $post->getText(false), "text" => $post->getText(false),
"copy_history" => $repost, "copy_history" => $repost,
"can_edit" => $post->canBeEditedBy($this->getUser()), "can_edit" => $post->canBeEditedBy($this->getUser()),
@ -171,7 +195,8 @@ final class Wall extends VKAPIRequestHandler
"is_pinned" => $post->isPinned(), "is_pinned" => $post->isPinned(),
"is_explicit" => $post->isExplicit(), "is_explicit" => $post->isExplicit(),
"attachments" => $attachments, "attachments" => $attachments,
"post_source" => $post->getPostSourceInfo(), "post_source" => $post_source,
"signer_id" => $signerId,
"comments" => (object)[ "comments" => (object)[
"count" => $post->getCommentsCount(), "count" => $post->getCommentsCount(),
"can_post" => 1 "can_post" => 1
@ -188,14 +213,6 @@ final class Wall extends VKAPIRequestHandler
] ]
]; ];
if($signerId)
$post_temp_obj->signer_id = $signerId;
if($post->isDeactivationMessage())
$post_temp_obj->final_post = 1;
$items[] = $post_temp_obj;
if ($from_id > 0) if ($from_id > 0)
$profiles[] = $from_id; $profiles[] = $from_id;
else else
@ -315,6 +332,17 @@ final class Wall extends VKAPIRequestHandler
else else
$profiles[] = $attachment->getOwner()->getId(); $profiles[] = $attachment->getOwner()->getId();
$post_source = [];
if($attachment->getPlatform(true) === NULL) {
$post_source = (object)["type" => "vk"];
} else {
$post_source = (object)[
"type" => "api",
"platform" => $attachment->getPlatform(true)
];
}
$repost[] = [ $repost[] = [
"id" => $attachment->getVirtualId(), "id" => $attachment->getVirtualId(),
"owner_id" => $attachment->isPostedOnBehalfOfGroup() ? $attachment->getOwner()->getId() * -1 : $attachment->getOwner()->getId(), "owner_id" => $attachment->isPostedOnBehalfOfGroup() ? $attachment->getOwner()->getId() * -1 : $attachment->getOwner()->getId(),
@ -323,29 +351,47 @@ final class Wall extends VKAPIRequestHandler
"post_type" => "post", "post_type" => "post",
"text" => $attachment->getText(false), "text" => $attachment->getText(false),
"attachments" => $repostAttachments, "attachments" => $repostAttachments,
"post_source" => $attachment->getPostSourceInfo(), "post_source" => $post_source,
]; ];
if ($attachment->getTargetWall() > 0) if ($attachment->getVirtualId() > 0)
$profiles[] = $attachment->getTargetWall(); $profiles[] = $attachment->getVirtualId();
else else
$groups[] = abs($attachment->getTargetWall()); $groups[] = $attachment->getVirtualId();
if($post->isSigned()) if($post->isSigned())
$profiles[] = $attachment->getOwner()->getId(); $profiles[] = $attachment->getOwner()->getId();
} }
} }
$post_source = [];
if($post->getPlatform(true) === NULL) {
$post_source = (object)["type" => "vk"];
} else {
$post_source = (object)[
"type" => "api",
"platform" => $post->getPlatform(true)
];
}
# TODO: $post->getVkApiType()
$postType = "post";
$signerId = NULL;
if($post->getSuggestionType() != 0)
$postType = "suggest";
if($post->isSigned()) { if($post->isSigned()) {
$actualAuthor = $post->getOwner(false); $actualAuthor = $post->getOwner(false);
$signerId = $actualAuthor->getId(); $signerId = $actualAuthor->getId();
} }
$post_temp_obj = (object)[ $items[] = (object)[
"id" => $post->getVirtualId(), "id" => $post->getVirtualId(),
"from_id" => $from_id, "from_id" => $from_id,
"owner_id" => $post->getTargetWall(), "owner_id" => $post->getTargetWall(),
"date" => $post->getPublicationTime()->timestamp(), "date" => $post->getPublicationTime()->timestamp(),
"post_type" => $post->getVkApiType(), "post_type" => $postType,
"text" => $post->getText(false), "text" => $post->getText(false),
"copy_history" => $repost, "copy_history" => $repost,
"can_edit" => $post->canBeEditedBy($this->getUser()), "can_edit" => $post->canBeEditedBy($this->getUser()),
@ -355,7 +401,8 @@ final class Wall extends VKAPIRequestHandler
"is_archived" => false, "is_archived" => false,
"is_pinned" => $post->isPinned(), "is_pinned" => $post->isPinned(),
"is_explicit" => $post->isExplicit(), "is_explicit" => $post->isExplicit(),
"post_source" => $post->getPostSourceInfo(), "post_source" => $post_source,
"signer_id" => $signerId,
"attachments" => $attachments, "attachments" => $attachments,
"comments" => (object)[ "comments" => (object)[
"count" => $post->getCommentsCount(), "count" => $post->getCommentsCount(),
@ -373,14 +420,6 @@ final class Wall extends VKAPIRequestHandler
] ]
]; ];
if($signerId)
$post_temp_obj->signer_id = $signerId;
if($post->isDeactivationMessage())
$post_temp_obj->final_post = 1;
$items[] = $post_temp_obj;
if ($from_id > 0) if ($from_id > 0)
$profiles[] = $from_id; $profiles[] = $from_id;
else else
@ -753,9 +792,6 @@ final class Wall extends VKAPIRequestHandler
] ]
]; ];
if($comment->isFromPostAuthor($post))
$item['is_from_post_author'] = true;
if($need_likes == true) if($need_likes == true)
$item['likes'] = [ $item['likes'] = [
"can_like" => 1, "can_like" => 1,
@ -839,9 +875,6 @@ final class Wall extends VKAPIRequestHandler
] ]
]; ];
if($comment->isFromPostAuthor())
$item['is_from_post_author'] = true;
if($extended == true) if($extended == true)
$profiles[] = $comment->getOwner()->getId(); $profiles[] = $comment->getOwner()->getId();
@ -857,6 +890,8 @@ final class Wall extends VKAPIRequestHandler
$response['profiles'] = (!empty($profiles) ? (new Users)->get(implode(',', $profiles), $fields) : []); $response['profiles'] = (!empty($profiles) ? (new Users)->get(implode(',', $profiles), $fields) : []);
} }
return $response; return $response;
} }

View file

@ -152,11 +152,6 @@ class Audio extends Media
return $this->getPerformer() . "" . $this->getTitle(); return $this->getPerformer() . "" . $this->getTitle();
} }
function getDownloadName(): string
{
return preg_replace('/[\\/:*?"<>|]/', '_', str_replace(' ', '_', $this->getName()));
}
function getGenre(): ?string function getGenre(): ?string
{ {
return $this->getRecord()->genre; return $this->getRecord()->genre;

View file

@ -437,7 +437,7 @@ class Club extends RowModel
return (new \openvk\Web\Models\Repositories\Audios)->getClubCollectionSize($this); return (new \openvk\Web\Models\Repositories\Audios)->getClubCollectionSize($this);
} }
function toVkApiStruct(?User $user = NULL, string $fields = ''): object function toVkApiStruct(?User $user = NULL): object
{ {
$res = (object) []; $res = (object) [];

View file

@ -103,22 +103,6 @@ class Comment extends Post
return $this->getTarget()->canBeViewedBy($user); return $this->getTarget()->canBeViewedBy($user);
} }
function isFromPostAuthor($target = NULL)
{
if(!$target)
$target = $this->getTarget();
$target_owner = $target->getOwner();
$comment_owner = $this->getOwner();
if($target_owner->getRealId() === $comment_owner->getRealId())
return true;
# TODO: make it work with signer_id
return false;
}
function toNotifApiStruct() function toNotifApiStruct()
{ {
@ -140,31 +124,4 @@ class Comment extends Post
return $user->getId() == $this->getOwner(false)->getId(); return $user->getId() == $this->getOwner(false)->getId();
} }
function getTargetURL(): string
{
$target = $this->getTarget();
$target_name = 'wall';
if(!$target) {
return '/404';
}
switch(get_class($target)) {
case 'openvk\Web\Models\Entities\Note':
$target_name = 'note';
break;
case 'openvk\Web\Models\Entities\Photo':
$target_name = 'photo';
break;
case 'openvk\Web\Models\Entities\Video':
$target_name = 'video';
break;
case 'openvk\Web\Models\Entities\Topic':
$target_name = 'topic';
break;
}
return $target_name . $target->getPrettyId();
}
} }

View file

@ -41,21 +41,6 @@ class Playlist extends MediaCollection
{ {
return $this->getRecord()->length; return $this->getRecord()->length;
} }
function fetchClassic(int $offset = 0, ?int $limit = NULL): \Traversable
{
$related = $this->getRecord()->related("$this->relTableName.collection")
->limit($limit ?? OPENVK_DEFAULT_PER_PAGE, $offset)
->order("index ASC");
foreach($related as $rel) {
$media = $rel->ref($this->entityTableName, "media");
if(!$media)
continue;
yield new $this->entityClassName($media);
}
}
function getAudios(int $offset = 0, ?int $limit = NULL, ?int $shuffleSeed = NULL): \Traversable function getAudios(int $offset = 0, ?int $limit = NULL, ?int $shuffleSeed = NULL): \Traversable
{ {
@ -177,7 +162,6 @@ class Playlist extends MediaCollection
"bookmarked" => $this->isBookmarkedBy($user), "bookmarked" => $this->isBookmarkedBy($user),
"listens" => $this->getListens(), "listens" => $this->getListens(),
"cover_url" => $this->getCoverURL(), "cover_url" => $this->getCoverURL(),
"searchable" => !$this->isUnlisted(),
]; ];
} }
@ -215,11 +199,6 @@ class Playlist extends MediaCollection
{ {
return $this->getRecord()->cover_photo_id; return $this->getRecord()->cover_photo_id;
} }
function getCoverPhoto(): ?Photo
{
return (new Photos)->get((int) $this->getRecord()->cover_photo_id);
}
function canBeModifiedBy(User $user): bool function canBeModifiedBy(User $user): bool
{ {
@ -274,9 +253,4 @@ class Playlist extends MediaCollection
return implode("", $props); return implode("", $props);
} }
function isUnlisted(): bool
{
return (bool)$this->getRecord()->unlisted;
}
} }

View file

@ -179,31 +179,6 @@ class Post extends Postable
"img" => NULL "img" => NULL
]; ];
} }
function getPostSourceInfo(): array
{
$post_source = ["type" => "vk"];
if($this->getPlatform(true) !== NULL) {
$post_source = [
"type" => "api",
"platform" => $this->getPlatform(true)
];
}
if($this->isUpdateAvatarMessage())
$post_source['data'] = 'profile_photo';
return $post_source;
}
function getVkApiType(): string
{
$type = 'post';
if($this->getSuggestionType() != 0)
$type = 'suggest';
return $type;
}
function pin(): void function pin(): void
{ {

View file

@ -123,7 +123,7 @@ trait TRichText
$text = preg_replace_callback("%([\n\r\s]|^)(\#([\p{L}_0-9][\p{L}_0-9\(\)\-\']+[\p{L}_0-9\(\)]|[\p{L}_0-9]{1,2}))%Xu", function($m) { $text = preg_replace_callback("%([\n\r\s]|^)(\#([\p{L}_0-9][\p{L}_0-9\(\)\-\']+[\p{L}_0-9\(\)]|[\p{L}_0-9]{1,2}))%Xu", function($m) {
$slug = rawurlencode($m[3]); $slug = rawurlencode($m[3]);
return "$m[1]<a href='/search?section=posts&q=%23$slug'>$m[2]</a>"; return "$m[1]<a href='/feed/hashtag/$slug'>$m[2]</a>";
}, $text); }, $text);
$text = $this->formatEmojis($text); $text = $this->formatEmojis($text);

View file

@ -1224,11 +1224,6 @@ class User extends RowModel
return (bool) $this->getRecord()->activated; return (bool) $this->getRecord()->activated;
} }
function isDead(): bool
{
return $this->onlineStatus() == 2;
}
function getUnbanTime(): ?string function getUnbanTime(): ?string
{ {
$ban = (new Bans)->get((int) $this->getRecord()->block_reason); $ban = (new Bans)->get((int) $this->getRecord()->block_reason);
@ -1321,22 +1316,17 @@ class User extends RowModel
return true; return true;
} }
function isClosed(): bool function isClosed()
{ {
return (bool) $this->getProfileType(); return (bool) $this->getProfileType();
} }
function isHideFromGlobalFeedEnabled(): bool
{
return $this->isClosed();
}
function getRealId() function getRealId()
{ {
return $this->getId(); return $this->getId();
} }
function toVkApiStruct(?User $user = NULL, string $fields = ''): object function toVkApiStruct(?User $user = NULL): object
{ {
$res = (object) []; $res = (object) [];
@ -1348,21 +1338,12 @@ class User extends RowModel
$res->photo_100 = $this->getAvatarURL("tiny"); $res->photo_100 = $this->getAvatarURL("tiny");
$res->photo_200 = $this->getAvatarURL("normal"); $res->photo_200 = $this->getAvatarURL("normal");
$res->photo_id = !is_null($this->getAvatarPhoto()) ? $this->getAvatarPhoto()->getPrettyId() : NULL; $res->photo_id = !is_null($this->getAvatarPhoto()) ? $this->getAvatarPhoto()->getPrettyId() : NULL;
# TODO: Perenesti syuda vsyo ostalnoyie
$res->is_closed = $this->isClosed(); $res->is_closed = $this->isClosed();
if(!is_null($user)) if(!is_null($user)) {
$res->can_access_closed = (bool)$this->canBeViewedBy($user); $res->can_access_closed = (bool)$this->canBeViewedBy($user);
if(!is_array($fields))
$fields = explode(',', $fields);
foreach($fields as $field) {
switch($field) {
case 'is_dead':
$res->is_dead = $user->isDead();
break;
}
} }
return $res; return $res;

View file

@ -181,8 +181,8 @@ class Video extends Media
{ {
if(preg_match(file_get_contents(__DIR__ . "/../VideoDrivers/regex/youtube.txt"), $link, $matches)) { if(preg_match(file_get_contents(__DIR__ . "/../VideoDrivers/regex/youtube.txt"), $link, $matches)) {
$pointer = "YouTube:$matches[1]"; $pointer = "YouTube:$matches[1]";
/*} else if(preg_match(file_get_contents(__DIR__ . "/../VideoDrivers/regex/vimeo.txt"), $link, $matches)) { } else if(preg_match(file_get_contents(__DIR__ . "/../VideoDrivers/regex/vimeo.txt"), $link, $matches)) {
$pointer = "Vimeo:$matches[1]";*/ $pointer = "Vimeo:$matches[1]";
} else { } else {
throw new ISE("Invalid link"); throw new ISE("Invalid link");
} }

View file

@ -67,21 +67,11 @@ class Applications
return sizeof($this->appRels->where("user", $user->getId())); return sizeof($this->appRels->where("user", $user->getId()));
} }
function find(string $query = "", array $params = [], array $order = ['type' => 'id', 'invert' => false]): Util\EntityStream function find(string $query, array $pars = [], string $sort = "id"): Util\EntityStream
{ {
$query = "%$query%"; $query = "%$query%";
$result = $this->apps->where("CONCAT_WS(' ', name, description) LIKE ?", $query)->where("enabled", 1); $result = $this->apps->where("CONCAT_WS(' ', name, description) LIKE ?", $query)->where("enabled", 1);
$order_str = 'id';
switch($order['type']) {
case 'id':
$order_str = 'id ' . ($order['invert'] ? 'ASC' : 'DESC');
break;
}
if($order_str)
$result->order($order_str);
return new Util\EntityStream("Application", $result); return new Util\EntityStream("Application", $result->order("$sort"));
} }
} }

View file

@ -208,7 +208,7 @@ class Audios
$search = $this->audios->where([ $search = $this->audios->where([
"unlisted" => 0, "unlisted" => 0,
"deleted" => 0, "deleted" => 0,
])->where("MATCH ($columns) AGAINST (? IN BOOLEAN MODE)", "%$query%")->order($order); ])->where("MATCH ($columns) AGAINST (? WITH QUERY EXPANSION)", $query)->order($order);
if($withLyrics) if($withLyrics)
$search = $search->where("lyrics IS NOT NULL"); $search = $search->where("lyrics IS NOT NULL");
@ -219,7 +219,6 @@ class Audios
function searchPlaylists(string $query): EntityStream function searchPlaylists(string $query): EntityStream
{ {
$search = $this->playlists->where([ $search = $this->playlists->where([
"unlisted" => 0,
"deleted" => 0, "deleted" => 0,
])->where("MATCH (`name`, `description`) AGAINST (? IN BOOLEAN MODE)", $query); ])->where("MATCH (`name`, `description`) AGAINST (? IN BOOLEAN MODE)", $query);
@ -244,72 +243,53 @@ class Audios
])->fetch()); ])->fetch());
} }
function find(string $query, array $params = [], array $order = ['type' => 'id', 'invert' => false], int $page = 1, ?int $perPage = NULL): \Traversable function find(string $query, array $pars = [], string $sort = "id DESC", int $page = 1, ?int $perPage = NULL): \Traversable
{ {
$query = "%$query%"; $query = "%$query%";
$result = $this->audios->where([ $result = $this->audios->where([
"unlisted" => 0, "unlisted" => 0,
"deleted" => 0, "deleted" => 0,
]); ]);
$order_str = (in_array($order['type'], ['id', 'length', 'listens']) ? $order['type'] : 'id') . ' ' . ($order['invert'] ? 'ASC' : 'DESC');;
if($params["only_performers"] == "1") { $notNullParams = [];
foreach($pars as $paramName => $paramValue)
if($paramName != "before" && $paramName != "after" && $paramName != "only_performers")
$paramValue != NULL ? $notNullParams+=["$paramName" => "%$paramValue%"] : NULL;
else
$paramValue != NULL ? $notNullParams+=["$paramName" => "$paramValue"] : NULL;
$nnparamsCount = sizeof($notNullParams);
if($notNullParams["only_performers"] == "1") {
$result->where("performer LIKE ?", $query); $result->where("performer LIKE ?", $query);
} else { } else {
$result->where("name LIKE ? OR performer LIKE ?", $query, $query); $result->where("name LIKE ? OR performer LIKE ?", $query, $query);
} }
foreach($params as $paramName => $paramValue) { if($nnparamsCount > 0) {
if(is_null($paramValue) || $paramValue == '') continue; foreach($notNullParams as $paramName => $paramValue) {
switch($paramName) {
switch($paramName) { case "before":
case "before": $result->where("created < ?", $paramValue);
$result->where("created < ?", $paramValue); break;
break; case "after":
case "after": $result->where("created > ?", $paramValue);
$result->where("created > ?", $paramValue); break;
break; case "with_lyrics":
case "with_lyrics": $result->where("lyrics IS NOT NULL");
$result->where("lyrics IS NOT NULL"); break;
break; }
case 'genre':
if($paramValue == 'any') break;
$result->where("genre", $paramValue);
break;
} }
} }
if($order_str) return new Util\EntityStream("Audio", $result->order($sort));
$result->order($order_str);
return new Util\EntityStream("Audio", $result);
} }
function findPlaylists(string $query, array $params = [], array $order = ['type' => 'id', 'invert' => false]): \Traversable function findPlaylists(string $query, int $page = 1, ?int $perPage = NULL): \Traversable
{ {
$query = "%$query%"; $query = "%$query%";
$result = $this->playlists->where([ $result = $this->playlists->where("name LIKE ?", $query);
"deleted" => 0,
])->where("CONCAT_WS(' ', name, description) LIKE ?", $query);
$order_str = (in_array($order['type'], ['id', 'length', 'listens']) ? $order['type'] : 'id') . ' ' . ($order['invert'] ? 'ASC' : 'DESC');
if(is_null($params['from_me']) || empty($params['from_me']))
$result->where(["unlisted" => 0]);
foreach($params as $paramName => $paramValue) {
if(is_null($paramValue) || $paramValue == '') continue;
switch($paramName) {
# БУДЬ МАКСИМАЛЬНО АККУРАТЕН С ДАННЫМ ПАРАМЕТРОМ
case "from_me":
$result->where("owner", $paramValue);
break;
}
}
if($order_str)
$result->order($order_str);
return new Util\EntityStream("Playlist", $result); return new Util\EntityStream("Playlist", $result);
} }

View file

@ -42,25 +42,13 @@ class Clubs
{ {
return $this->toClub($this->clubs->get($id)); return $this->toClub($this->clubs->get($id));
} }
function find(string $query, array $params = [], array $order = ['type' => 'id', 'invert' => false], int $page = 1, ?int $perPage = NULL): \Traversable function find(string $query, array $pars = [], string $sort = "id DESC", int $page = 1, ?int $perPage = NULL): \Traversable
{ {
$query = "%$query%"; $query = "%$query%";
$result = $this->clubs; $result = $this->clubs->where("name LIKE ? OR about LIKE ?", $query, $query);
$order_str = 'id';
return new Util\EntityStream("Club", $result->order($sort));
switch($order['type']) {
case 'id':
$order_str = 'id ' . ($order['invert'] ? 'ASC' : 'DESC');
break;
}
$result = $result->where("name LIKE ? OR about LIKE ?", $query, $query);
if($order_str)
$result->order($order_str);
return new Util\EntityStream("Club", $result);
} }
function getCount(): int function getCount(): int

View file

@ -60,31 +60,34 @@ class Comments
])); ]));
} }
function find(string $query, array $params = [], array $order = ['type' => 'id', 'invert' => false]): Util\EntityStream function find(string $query = "", array $pars = [], string $sort = "id"): Util\EntityStream
{ {
$result = $this->comments->where("content LIKE ?", "%$query%")->where("deleted", 0); $query = "%$query%";
$order_str = 'id';
switch($order['type']) { $notNullParams = [];
case 'id':
$order_str = 'created ' . ($order['invert'] ? 'ASC' : 'DESC');
break;
}
foreach($params as $paramName => $paramValue) { foreach($pars as $paramName => $paramValue)
switch($paramName) { if($paramName != "before" && $paramName != "after")
case "before": $paramValue != NULL ? $notNullParams+=["$paramName" => "%$paramValue%"] : NULL;
$result->where("created < ?", $paramValue); else
break; $paramValue != NULL ? $notNullParams+=["$paramName" => "$paramValue"] : NULL;
case "after":
$result->where("created > ?", $paramValue); $result = $this->comments->where("content LIKE ?", $query)->where("deleted", 0);
break; $nnparamsCount = sizeof($notNullParams);
if($nnparamsCount > 0) {
foreach($notNullParams as $paramName => $paramValue) {
switch($paramName) {
case "before":
$result->where("created < ?", $paramValue);
break;
case "after":
$result->where("created > ?", $paramValue);
break;
}
} }
} }
if($order_str) return new Util\EntityStream("Comment", $result->order("$sort"));
$result->order($order_str);
return new Util\EntityStream("Comment", $result);
} }
} }

View file

@ -154,45 +154,36 @@ class Posts
} }
function find(string $query = "", array $params = [], array $order = ['type' => 'id', 'invert' => false]): Util\EntityStream function find(string $query = "", array $pars = [], string $sort = "id"): Util\EntityStream
{ {
$query = "%$query%"; $query = "%$query%";
$notNullParams = [];
foreach($pars as $paramName => $paramValue)
if($paramName != "before" && $paramName != "after")
$paramValue != NULL ? $notNullParams+=["$paramName" => "%$paramValue%"] : NULL;
else
$paramValue != NULL ? $notNullParams+=["$paramName" => "$paramValue"] : NULL;
$result = $this->posts->where("content LIKE ?", $query)->where("deleted", 0)->where("suggested", 0); $result = $this->posts->where("content LIKE ?", $query)->where("deleted", 0)->where("suggested", 0);
$order_str = 'id'; $nnparamsCount = sizeof($notNullParams);
switch($order['type']) { if($nnparamsCount > 0) {
case 'id': foreach($notNullParams as $paramName => $paramValue) {
$order_str = 'created ' . ($order['invert'] ? 'ASC' : 'DESC'); switch($paramName) {
break; case "before":
} $result->where("created < ?", $paramValue);
break;
foreach($params as $paramName => $paramValue) { case "after":
if(is_null($paramValue) || $paramValue == '') continue; $result->where("created > ?", $paramValue);
break;
switch($paramName) { }
case "before":
$result->where("created < ?", $paramValue);
break;
case "after":
$result->where("created > ?", $paramValue);
break;
/*case 'die_in_agony':
$result->where("nsfw", 1);
break;
case 'ads':
$result->where("ad", 1);
break;*/
# БУДЬ МАКСИМАЛЬНО АККУРАТЕН С ДАННЫМ ПАРАМЕТРОМ
case 'from_me':
$result->where("owner", $paramValue);
break;
} }
} }
if($order_str)
$result->order($order_str);
return new Util\EntityStream("Post", $result); return new Util\EntityStream("Post", $result->order("$sort"));
} }
function getPostCountOnUserWall(int $user): int function getPostCountOnUserWall(int $user): int

View file

@ -54,76 +54,94 @@ class Users
return $user ? $this->getByChandlerUserId($user->getId()) : NULL; return $user ? $this->getByChandlerUserId($user->getId()) : NULL;
} }
function find(string $query, array $params = [], array $order = ['type' => 'id', 'invert' => false]): Util\EntityStream function find(string $query, array $pars = [], string $sort = "id DESC"): Util\EntityStream
{ {
$query = "%$query%"; $query = "%$query%";
$result = $this->users->where("CONCAT_WS(' ', first_name, last_name, pseudo, shortcode) LIKE ?", $query)->where("deleted", 0); $result = $this->users->where("CONCAT_WS(' ', first_name, last_name, pseudo, shortcode) LIKE ?", $query)->where("deleted", 0);
$order_str = 'id';
$notNullParams = [];
$nnparamsCount = 0;
foreach($pars as $paramName => $paramValue)
if($paramName != "before" && $paramName != "after" && $paramName != "gender" && $paramName != "maritalstatus" && $paramName != "politViews" && $paramName != "doNotSearchMe")
$paramValue != NULL ? $notNullParams += ["$paramName" => "%$paramValue%"] : NULL;
else
$paramValue != NULL ? $notNullParams += ["$paramName" => "$paramValue"] : NULL;
switch($order['type']) { $nnparamsCount = sizeof($notNullParams);
case 'id':
case 'reg_date':
$order_str = 'id ' . ($order['invert'] ? 'ASC' : 'DESC');
break;
case 'rating':
$order_str = 'rating DESC';
break;
}
foreach($params as $paramName => $paramValue) { if($nnparamsCount > 0) {
if(is_null($paramValue) || $paramValue == '') continue; foreach($notNullParams as $paramName => $paramValue) {
switch($paramName) {
switch($paramName) { case "hometown":
case "hometown": $result->where("hometown LIKE ?", $paramValue);
$result->where("hometown LIKE ?", "%$paramValue%"); break;
break; case "city":
case "city": $result->where("city LIKE ?", $paramValue);
$result->where("city LIKE ?", "%$paramValue%"); break;
break; case "maritalstatus":
case "marital_status": $result->where("marital_status ?", $paramValue);
$result->where("marital_status ?", $paramValue); break;
break; case "status":
case "polit_views": $result->where("status LIKE ?", $paramValue);
$result->where("polit_views ?", $paramValue); break;
break; case "politViews":
case "is_online": $result->where("polit_views ?", $paramValue);
$result->where("online >= ?", time() - 900); break;
break; case "email":
case "fav_mus": $result->where("email_contact LIKE ?", $paramValue);
$result->where("fav_music LIKE ?", "%$paramValue%"); break;
break; case "telegram":
case "fav_films": $result->where("telegram LIKE ?", $paramValue);
$result->where("fav_films LIKE ?", "%$paramValue%"); break;
break; case "site":
case "fav_shows": $result->where("telegram LIKE ?", $paramValue);
$result->where("fav_shows LIKE ?", "%$paramValue%"); break;
break; case "address":
case "fav_books": $result->where("address LIKE ?", $paramValue);
$result->where("fav_books LIKE ?", "%$paramValue%"); break;
break; case "is_online":
case "before": $result->where("online >= ?", time() - 900);
$result->where("UNIX_TIMESTAMP(since) < ?", $paramValue); break;
break; case "interests":
case "after": $result->where("interests LIKE ?", $paramValue);
$result->where("UNIX_TIMESTAMP(since) > ?", $paramValue); break;
break; case "fav_mus":
case "gender": $result->where("fav_music LIKE ?", $paramValue);
if((int) $paramValue == 3) break; break;
$result->where("sex ?", (int) $paramValue); case "fav_films":
break; $result->where("fav_films LIKE ?", $paramValue);
case "ignore_id": break;
$result->where("id != ?", $paramValue); case "fav_shows":
break; $result->where("fav_shows LIKE ?", $paramValue);
case "ignore_private": break;
$result->where("profile_type", 0); case "fav_books":
break; $result->where("fav_books LIKE ?", $paramValue);
break;
case "fav_quote":
$result->where("fav_quote LIKE ?", $paramValue);
break;
case "before":
$result->where("UNIX_TIMESTAMP(since) < ?", $paramValue);
break;
case "after":
$result->where("UNIX_TIMESTAMP(since) > ?", $paramValue);
break;
case "gender":
$result->where("sex ?", $paramValue);
break;
case "doNotSearchMe":
$result->where("id !=", $paramValue);
break;
case "doNotSearchPrivate":
$result->where("profile_type", 0);
break;
}
} }
} }
if($order_str)
$result->order($order_str);
return new Util\EntityStream("User", $result); return new Util\EntityStream("User", $result->order($sort));
} }
function getStatistics(): object function getStatistics(): object

View file

@ -46,37 +46,36 @@ class Videos
return sizeof($this->videos->where("owner", $user->getId())->where(["deleted" => 0, "unlisted" => 0])); return sizeof($this->videos->where("owner", $user->getId())->where(["deleted" => 0, "unlisted" => 0]));
} }
function find(string $query = "", array $params = [], array $order = ['type' => 'id', 'invert' => false]): Util\EntityStream function find(string $query = "", array $pars = [], string $sort = "id"): Util\EntityStream
{ {
$query = "%$query%"; $query = "%$query%";
$notNullParams = [];
foreach($pars as $paramName => $paramValue)
if($paramName != "before" && $paramName != "after")
$paramValue != NULL ? $notNullParams+=["$paramName" => "%$paramValue%"] : NULL;
else
$paramValue != NULL ? $notNullParams+=["$paramName" => "$paramValue"] : NULL;
$result = $this->videos->where("CONCAT_WS(' ', name, description) LIKE ?", $query)->where("deleted", 0); $result = $this->videos->where("CONCAT_WS(' ', name, description) LIKE ?", $query)->where("deleted", 0);
$order_str = 'id'; $nnparamsCount = sizeof($notNullParams);
switch($order['type']) { if($nnparamsCount > 0) {
case 'id': foreach($notNullParams as $paramName => $paramValue) {
$order_str = 'id ' . ($order['invert'] ? 'ASC' : 'DESC'); switch($paramName) {
break; case "before":
} $result->where("created < ?", $paramValue);
break;
foreach($params as $paramName => $paramValue) { case "after":
switch($paramName) { $result->where("created > ?", $paramValue);
case "before": break;
$result->where("created < ?", $paramValue); }
break;
case "after":
$result->where("created > ?", $paramValue);
break;
case 'only_youtube':
if((int) $paramValue != 1) break;
$result->where("link != ?", 'NULL');
break;
} }
} }
if($order_str)
$result->order($order_str);
return new Util\EntityStream("Video", $result); return new Util\EntityStream("Video", $result->order("$sort"));
} }
function getLastVideo(User $user) function getLastVideo(User $user)

View file

@ -75,7 +75,7 @@ final class AudioPresenter extends OpenVKPresenter
if (!$entity || $entity->isBanned()) if (!$entity || $entity->isBanned())
$this->redirect("/playlists" . $this->user->id); $this->redirect("/playlists" . $this->user->id);
$playlists = $this->audios->getPlaylistsByClub($entity, $page, OPENVK_DEFAULT_PER_PAGE); $playlists = $this->audios->getPlaylistsByClub($entity, $page, 10);
$playlistsCount = $this->audios->getClubPlaylistsCount($entity); $playlistsCount = $this->audios->getClubPlaylistsCount($entity);
} else { } else {
$entity = (new Users)->get($owner); $entity = (new Users)->get($owner);
@ -85,7 +85,7 @@ final class AudioPresenter extends OpenVKPresenter
if(!$entity->getPrivacyPermission("audios.read", $this->user->identity)) if(!$entity->getPrivacyPermission("audios.read", $this->user->identity))
$this->flashFail("err", tr("forbidden"), tr("forbidden_comment")); $this->flashFail("err", tr("forbidden"), tr("forbidden_comment"));
$playlists = $this->audios->getPlaylistsByUser($entity, $page, OPENVK_DEFAULT_PER_PAGE); $playlists = $this->audios->getPlaylistsByUser($entity, $page, 9);
$playlistsCount = $this->audios->getUserPlaylistsCount($entity); $playlistsCount = $this->audios->getUserPlaylistsCount($entity);
} }
@ -109,8 +109,8 @@ final class AudioPresenter extends OpenVKPresenter
$this->template->mode = $mode; $this->template->mode = $mode;
$this->template->page = $page; $this->template->page = $page;
if(in_array($mode, ["list", "new", "popular"]) && $this->user->identity && $page < 2) if(in_array($mode, ["list", "new", "popular"]) && $this->user->identity)
$this->template->friendsAudios = $this->user->identity->getBroadcastList("all", true); $this->template->friendsAudios = $this->user->identity->getBroadcastList("all", true);
} }
@ -142,13 +142,7 @@ final class AudioPresenter extends OpenVKPresenter
$this->assertUserLoggedIn(); $this->assertUserLoggedIn();
$group = NULL; $group = NULL;
$playlist = NULL;
$isAjax = $this->postParam("ajax", false) == 1; $isAjax = $this->postParam("ajax", false) == 1;
if(!is_null($this->queryParam("gid")) && !is_null($this->queryParam("playlist"))) {
$this->flashFail("err", tr("forbidden"), tr("not_enough_permissions_comment"), null, $isAjax);
}
if(!is_null($this->queryParam("gid"))) { if(!is_null($this->queryParam("gid"))) {
$gid = (int) $this->queryParam("gid"); $gid = (int) $this->queryParam("gid");
$group = (new Clubs)->get($gid); $group = (new Clubs)->get($gid);
@ -159,19 +153,6 @@ final class AudioPresenter extends OpenVKPresenter
$this->flashFail("err", tr("forbidden"), tr("not_enough_permissions_comment"), null, $isAjax); $this->flashFail("err", tr("forbidden"), tr("not_enough_permissions_comment"), null, $isAjax);
} }
if(!is_null($this->queryParam("playlist"))) {
$playlist_id = (int)$this->queryParam("playlist");
$playlist = (new Audios)->getPlaylist($playlist_id);
if(!$playlist || $playlist->isDeleted())
$this->flashFail("err", tr("forbidden"), tr("not_enough_permissions_comment"), null, $isAjax);
if(!$playlist->canBeModifiedBy($this->user->identity))
$this->flashFail("err", tr("forbidden"), tr("not_enough_permissions_comment"), null, $isAjax);
$this->template->playlist = $playlist;
$this->template->owner = $playlist->getOwner();
}
$this->template->group = $group; $this->template->group = $group;
if($_SERVER["REQUEST_METHOD"] !== "POST") if($_SERVER["REQUEST_METHOD"] !== "POST")
@ -215,8 +196,6 @@ final class AudioPresenter extends OpenVKPresenter
$lyrics = $this->postParam("lyrics"); $lyrics = $this->postParam("lyrics");
$genre = empty($this->postParam("genre")) ? "Other" : $this->postParam("genre"); $genre = empty($this->postParam("genre")) ? "Other" : $this->postParam("genre");
$nsfw = ($this->postParam("explicit") ?? "off") === "on"; $nsfw = ($this->postParam("explicit") ?? "off") === "on";
$is_unlisted = ($this->postParam("unlisted") ?? "off") === "on";
if(empty($performer) || empty($name) || iconv_strlen($performer . $name) > 128) # FQN of audio must not be more than 128 chars if(empty($performer) || empty($name) || iconv_strlen($performer . $name) > 128) # FQN of audio must not be more than 128 chars
$this->flashFail("err", tr("error"), tr("error_insufficient_info"), null, $isAjax); $this->flashFail("err", tr("error"), tr("error_insufficient_info"), null, $isAjax);
@ -227,7 +206,6 @@ final class AudioPresenter extends OpenVKPresenter
$audio->setLyrics(empty($lyrics) ? NULL : $lyrics); $audio->setLyrics(empty($lyrics) ? NULL : $lyrics);
$audio->setGenre($genre); $audio->setGenre($genre);
$audio->setExplicit($nsfw); $audio->setExplicit($nsfw);
$audio->setUnlisted($is_unlisted);
try { try {
$audio->setFile($upload); $audio->setFile($upload);
@ -237,18 +215,13 @@ final class AudioPresenter extends OpenVKPresenter
} catch(\RuntimeException $ex) { } catch(\RuntimeException $ex) {
$this->flashFail("err", tr("error"), tr("ffmpeg_timeout"), null, $isAjax); $this->flashFail("err", tr("error"), tr("ffmpeg_timeout"), null, $isAjax);
} catch(\BadMethodCallException $ex) { } catch(\BadMethodCallException $ex) {
$this->flashFail("err", tr("error"), "хз", null, $isAjax); $this->flashFail("err", tr("error"), "Загрузка аудио под Linux на данный момент не реализована. Следите за обновлениями: <a href='https://github.com/openvk/openvk/pull/512/commits'>https://github.com/openvk/openvk/pull/512/commits</a>", null, $isAjax);
} catch(\Exception $ex) { } catch(\Exception $ex) {
$this->flashFail("err", tr("error"), tr("ffmpeg_not_installed"), null, $isAjax); $this->flashFail("err", tr("error"), tr("ffmpeg_not_installed"), null, $isAjax);
} }
$audio->save(); $audio->save();
$audio->add($group ?? $this->user->identity);
if($playlist) {
$playlist->add($audio);
} else {
$audio->add($group ?? $this->user->identity);
}
if(!$isAjax) if(!$isAjax)
$this->redirect(is_null($group) ? "/audios" . $this->user->id : "/audios-" . $group->getId()); $this->redirect(is_null($group) ? "/audios" . $this->user->id : "/audios-" . $group->getId());
@ -260,9 +233,9 @@ final class AudioPresenter extends OpenVKPresenter
else else
$redirectLink .= $this->user->id; $redirectLink .= $this->user->id;
if($playlist) $pagesCount = (int)ceil((new Audios)->getCollectionSizeByEntityId(isset($group) ? $group->getRealId() : $this->user->id) / 10);
$redirectLink = "/playlist" . $playlist->getPrettyId(); $redirectLink .= "?p=".$pagesCount;
$this->returnJson([ $this->returnJson([
"success" => true, "success" => true,
"redirect_link" => $redirectLink, "redirect_link" => $redirectLink,
@ -306,7 +279,7 @@ final class AudioPresenter extends OpenVKPresenter
function renderSearch(): void function renderSearch(): void
{ {
$this->redirect("/search?section=audios"); $this->redirect("/search?type=audios");
} }
function renderNewPlaylist(): void function renderNewPlaylist(): void
@ -331,8 +304,6 @@ final class AudioPresenter extends OpenVKPresenter
if ($_SERVER["REQUEST_METHOD"] === "POST") { if ($_SERVER["REQUEST_METHOD"] === "POST") {
$title = $this->postParam("title"); $title = $this->postParam("title");
$description = $this->postParam("description"); $description = $this->postParam("description");
$is_unlisted = (int)$this->postParam('is_unlisted');
$audios = !empty($this->postParam("audios")) ? array_slice(explode(",", $this->postParam("audios")), 0, 1000) : []; $audios = !empty($this->postParam("audios")) ? array_slice(explode(",", $this->postParam("audios")), 0, 1000) : [];
if(empty($title) || iconv_strlen($title) < 1) if(empty($title) || iconv_strlen($title) < 1)
@ -342,9 +313,7 @@ final class AudioPresenter extends OpenVKPresenter
$playlist->setOwner($owner); $playlist->setOwner($owner);
$playlist->setName(substr($title, 0, 125)); $playlist->setName(substr($title, 0, 125));
$playlist->setDescription(substr($description, 0, 2045)); $playlist->setDescription(substr($description, 0, 2045));
if($is_unlisted == 1)
$playlist->setUnlisted(true);
if($_FILES["cover"]["error"] === UPLOAD_ERR_OK) { if($_FILES["cover"]["error"] === UPLOAD_ERR_OK) {
if(!str_starts_with($_FILES["cover"]["type"], "image")) 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"));
@ -458,7 +427,6 @@ final class AudioPresenter extends OpenVKPresenter
$title = $this->postParam("title"); $title = $this->postParam("title");
$description = $this->postParam("description"); $description = $this->postParam("description");
$is_unlisted = (int)$this->postParam('is_unlisted');
$new_audios = !empty($this->postParam("audios")) ? explode(",", rtrim($this->postParam("audios"), ",")) : []; $new_audios = !empty($this->postParam("audios")) ? explode(",", rtrim($this->postParam("audios"), ",")) : [];
if(empty($title) || iconv_strlen($title) < 1) if(empty($title) || iconv_strlen($title) < 1)
@ -468,7 +436,6 @@ final class AudioPresenter extends OpenVKPresenter
$playlist->setDescription(ovk_proc_strtr($description, 2045)); $playlist->setDescription(ovk_proc_strtr($description, 2045));
$playlist->setEdited(time()); $playlist->setEdited(time());
$playlist->resetLength(); $playlist->resetLength();
$playlist->setUnlisted((bool)$is_unlisted);
if($_FILES["new_cover"]["error"] === UPLOAD_ERR_OK) { if($_FILES["new_cover"]["error"] === UPLOAD_ERR_OK) {
if(!str_starts_with($_FILES["new_cover"]["type"], "image")) if(!str_starts_with($_FILES["new_cover"]["type"], "image"))
@ -508,15 +475,12 @@ final class AudioPresenter extends OpenVKPresenter
$this->template->playlist = $playlist; $this->template->playlist = $playlist;
$this->template->page = $page; $this->template->page = $page;
$this->template->cover = $playlist->getCoverPhoto();
$this->template->cover_url = $this->template->cover ? $this->template->cover->getURL() : "/assets/packages/static/openvk/img/song.jpg";
$this->template->audios = iterator_to_array($playlist->fetch($page, 10)); $this->template->audios = iterator_to_array($playlist->fetch($page, 10));
$this->template->ownerId = $owner_id; $this->template->ownerId = $owner_id;
$this->template->owner = $playlist->getOwner(); $this->template->owner = $playlist->getOwner();
$this->template->isBookmarked = $this->user->identity && $playlist->isBookmarkedBy($this->user->identity); $this->template->isBookmarked = $this->user->identity && $playlist->isBookmarkedBy($this->user->identity);
$this->template->isMy = $this->user->identity && $playlist->getOwner()->getId() === $this->user->id; $this->template->isMy = $this->user->identity && $playlist->getOwner()->getId() === $this->user->id;
$this->template->canEdit = $this->user->identity && $playlist->canBeModifiedBy($this->user->identity); $this->template->canEdit = $this->user->identity && $playlist->canBeModifiedBy($this->user->identity);
$this->template->count = $playlist->size();
} }
function renderAction(int $audio_id): void function renderAction(int $audio_id): void
@ -567,65 +531,16 @@ final class AudioPresenter extends OpenVKPresenter
break; break;
case "add_to_club": case "add_to_club":
$detailed = []; $club = (new Clubs)->get((int)$this->postParam("club"));
if($audio->isWithdrawn())
$this->flashFail("err", "error", tr("invalid_audio"), null, true); if(!$club || !$club->canBeModifiedBy($this->user->identity))
$this->flashFail("err", "error", tr("access_denied"), null, true);
if(empty($this->postParam("clubs")))
$this->flashFail("err", "error", 'clubs not passed', null, true); if(!$audio->isInLibraryOf($club))
$audio->add($club);
$clubs_arr = explode(',', $this->postParam("clubs")); else
$count = sizeof($clubs_arr); $this->flashFail("err", "error", tr("group_has_audio"), null, true);
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))
@ -738,28 +653,6 @@ final class AudioPresenter extends OpenVKPresenter
$audios = $stream->page($page, 10); $audios = $stream->page($page, 10);
$audiosCount = $stream->size(); $audiosCount = $stream->size();
break; break;
case "classic_search_context":
$data = json_decode($this->postParam("context_entity"), true);
$params = [];
$order = [
"type" => $data['order'] ?? 'id',
"invert" => (int)$data['invert'] == 1 ? true : false
];
if($data['genre'] && $data['genre'] != 'any')
$params['genre'] = $data['genre'];
if($data['only_performers'] && (int)$data['only_performers'] == 1)
$params['only_performers'] = '1';
if($data['with_lyrics'] && (int)$data['with_lyrics'] == 1)
$params['with_lyrics'] = '1';
$stream = $this->audios->find($data['query'], $params, $order);
$audios = $stream->page($page, 10);
$audiosCount = $stream->size();
break;
} }
$pagesCount = ceil($audiosCount / $perPage); $pagesCount = ceil($audiosCount / $perPage);

View file

@ -282,99 +282,48 @@ final class GroupPresenter extends OpenVKPresenter
function renderSetAvatar(int $id) function renderSetAvatar(int $id)
{ {
$this->assertUserLoggedIn(); $photo = new Photo;
$this->willExecuteWriteAction();
$club = $this->clubs->get($id); $club = $this->clubs->get($id);
if ($club->isBanned()) $this->flashFail("err", tr("error"), tr("forbidden"));
if(!$club || $club->isBanned() || !$club->canBeModifiedBy($this->user->identity)) if($_SERVER["REQUEST_METHOD"] === "POST" && $_FILES["ava"]["error"] === UPLOAD_ERR_OK) {
$this->flashFail("err", tr("error"), tr("forbidden"), NULL, true);
if($_SERVER["REQUEST_METHOD"] === "POST" && $_FILES["blob"]["error"] === UPLOAD_ERR_OK) {
try { try {
$photo = new Photo;
$anon = OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["anonymousPosting"]["enable"]; $anon = OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["anonymousPosting"]["enable"];
if($anon && $this->user->id === $club->getOwner()->getId()) if($anon && $this->user->id === $club->getOwner()->getId())
$anon = $club->isOwnerHidden(); $anon = $club->isOwnerHidden();
else if($anon) else if($anon)
$anon = $club->getManager($this->user->identity)->isHidden(); $anon = $club->getManager($this->user->identity)->isHidden();
$photo->setOwner($this->user->id); $photo->setOwner($this->user->id);
$photo->setDescription("Club image"); $photo->setDescription("Club image");
$photo->setFile($_FILES["blob"]); $photo->setFile($_FILES["ava"]);
$photo->setCreated(time()); $photo->setCreated(time());
$photo->setAnonymous($anon); $photo->setAnonymous($anon);
$photo->save(); $photo->save();
(new Albums)->getClubAvatarAlbum($club)->addPhoto($photo); (new Albums)->getClubAvatarAlbum($club)->addPhoto($photo);
if($this->postParam("on_wall") == 1) { $flags = 0;
$post = new Post; $flags |= 0b00010000;
$flags |= 0b10000000;
$post->setOwner($this->user->id);
$post->setWall($club->getId() * -1);
$post->setCreated(time());
$post->setContent("");
$flags = 0; $post = new Post;
$flags |= 0b00010000; $post->setOwner($this->user->id);
$flags |= 0b10000000; $post->setWall($club->getId()*-1);
$post->setCreated(time());
$post->setContent("");
$post->setFlags($flags);
$post->save();
$post->attach($photo);
$post->setFlags($flags); } catch(ISE $ex) {
$post->save(); $name = $album->getName();
$this->flashFail("err", tr("error"), tr("error_when_uploading_photo"));
$post->attach($photo);
}
} catch(\Throwable $ex) {
$this->flashFail("err", tr("error"), tr("error_when_uploading_photo"), NULL, true);
} }
$this->returnJson([
"success" => true,
"new_photo" => $photo->getPrettyId(),
"url" => $photo->getURL(),
]);
} else {
return " ";
} }
$this->returnJson([
"url" => $photo->getURL(),
"id" => $photo->getPrettyId()
]);
} }
function renderDeleteAvatar(int $id) {
$this->assertUserLoggedIn();
$this->willExecuteWriteAction();
$club = $this->clubs->get($id);
if(!$club || $club->isBanned() || !$club->canBeModifiedBy($this->user->identity))
$this->flashFail("err", tr("error"), tr("forbidden"), NULL, true);
$avatar = $club->getAvatarPhoto();
if(!$avatar)
$this->flashFail("succ", tr("error"), "no avatar bro", NULL, true);
$avatar->isolate();
$newAvatar = $club->getAvatarPhoto();
if(!$newAvatar)
$this->returnJson([
"success" => true,
"has_new_photo" => false,
"new_photo" => NULL,
"url" => "/assets/packages/static/openvk/img/camera_200.png",
]);
else
$this->returnJson([
"success" => true,
"has_new_photo" => true,
"new_photo" => $newAvatar->getPrettyId(),
"url" => $newAvatar->getURL(),
]);
}
function renderEditBackdrop(int $id): void function renderEditBackdrop(int $id): void
{ {
$this->assertUserLoggedIn(); $this->assertUserLoggedIn();

View file

@ -1,7 +1,7 @@
<?php declare(strict_types=1); <?php declare(strict_types=1);
namespace openvk\Web\Presenters; namespace openvk\Web\Presenters;
use openvk\Web\Models\Entities\{User, Club}; use openvk\Web\Models\Entities\{User, Club};
use openvk\Web\Models\Repositories\{Users, Clubs, Posts, Videos, Applications, Audios}; use openvk\Web\Models\Repositories\{Users, Clubs, Posts, Comments, Videos, Applications, Notes, Audios};
use Chandler\Database\DatabaseConnection; use Chandler\Database\DatabaseConnection;
final class SearchPresenter extends OpenVKPresenter final class SearchPresenter extends OpenVKPresenter
@ -9,17 +9,21 @@ final class SearchPresenter extends OpenVKPresenter
private $users; private $users;
private $clubs; private $clubs;
private $posts; private $posts;
private $comments;
private $videos; private $videos;
private $apps; private $apps;
private $notes;
private $audios; private $audios;
function __construct() function __construct(Users $users, Clubs $clubs)
{ {
$this->users = new Users; $this->users = $users;
$this->clubs = new Clubs; $this->clubs = $clubs;
$this->posts = new Posts; $this->posts = new Posts;
$this->comments = new Comments;
$this->videos = new Videos; $this->videos = new Videos;
$this->apps = new Applications; $this->apps = new Applications;
$this->notes = new Notes;
$this->audios = new Audios; $this->audios = new Audios;
parent::__construct(); parent::__construct();
@ -29,101 +33,85 @@ final class SearchPresenter extends OpenVKPresenter
{ {
$this->assertUserLoggedIn(); $this->assertUserLoggedIn();
$query = $this->queryParam("q") ?? ""; $query = $this->queryParam("query") ?? "";
$section = $this->queryParam("section") ?? "users"; $type = $this->queryParam("type") ?? "users";
$order = $this->queryParam("order") ?? "id"; $sorter = $this->queryParam("sort") ?? "id";
$invert = (int) ($this->queryParam("invert") ?? 0) == 1; $invert = $this->queryParam("invert") == 1 ? "ASC" : "DESC";
$page = (int) ($this->queryParam("p") ?? 1); $page = (int) ($this->queryParam("p") ?? 1);
# https://youtu.be/pSAWM5YuXx8 # https://youtu.be/pSAWM5YuXx8
# https://youtu.be/FfNZRhIn2Vk
$repos = [ $repos = [
"groups" => "clubs", "groups" => "clubs",
"users" => "users", "users" => "users",
"posts" => "posts", "posts" => "posts",
"comments" => "comments",
"videos" => "videos", "videos" => "videos",
"audios" => "audios", "audios" => "audios",
"apps" => "apps", "apps" => "apps",
"audios_playlists" => "audios" "notes" => "notes"
];
$parameters = [
"ignore_private" => true,
]; ];
foreach($_REQUEST as $param_name => $param_value) { switch($sorter) {
if(is_null($param_value)) continue;
switch($param_name) {
default:
$parameters[$param_name] = $param_value;
break;
case 'marital_status':
case 'polit_views':
if((int) $param_value == 0) continue;
$parameters[$param_name] = $param_value;
break;
case 'is_online':
if((int) $param_value == 1)
$parameters['is_online'] = 1;
break;
case 'only_performers':
if((int) $param_value == 1 || $param_value == 'on')
$parameters['only_performers'] = true;
break;
case 'with_lyrics':
if($param_value == 'on' || $param_value == '1')
$parameters['with_lyrics'] = true;
break;
# дай бог работал этот case
case 'from_me':
if((int) $param_value != 1) continue;
$parameters['from_me'] = $this->user->id;
break;
}
}
$repo = $repos[$section] or $this->throwError(400, "Bad Request", "Invalid search entity $section.");
$results = NULL;
switch($section) {
default: default:
$results = $this->{$repo}->find($query, $parameters, ['type' => $order, 'invert' => $invert]); case "id":
$sort = "id " . $invert;
break; break;
case 'audios_playlists': case "name":
$results = $this->{$repo}->findPlaylists($query, $parameters, ['type' => $order, 'invert' => $invert]); $sort = "first_name " . $invert;
break;
case "rating":
$sort = "rating " . $invert;
break; break;
case "length":
if($type != "audios") break;
$sort = "length " . $invert;
break;
case "listens":
if($type != "audios") break;
$sort = "listens " . $invert;
break;
} }
$parameters = [
"type" => $this->queryParam("type"),
"city" => $this->queryParam("city") != "" ? $this->queryParam("city") : NULL,
"maritalstatus" => $this->queryParam("maritalstatus") != 0 ? $this->queryParam("maritalstatus") : NULL,
"with_photo" => $this->queryParam("with_photo"),
"status" => $this->queryParam("status") != "" ? $this->queryParam("status") : NULL,
"politViews" => $this->queryParam("politViews") != 0 ? $this->queryParam("politViews") : NULL,
"email" => $this->queryParam("email"),
"telegram" => $this->queryParam("telegram"),
"site" => $this->queryParam("site") != "" ? "https://".$this->queryParam("site") : NULL,
"address" => $this->queryParam("address"),
"is_online" => $this->queryParam("is_online") == 1 ? 1 : NULL,
"interests" => $this->queryParam("interests") != "" ? $this->queryParam("interests") : NULL,
"fav_mus" => $this->queryParam("fav_mus") != "" ? $this->queryParam("fav_mus") : NULL,
"fav_films" => $this->queryParam("fav_films") != "" ? $this->queryParam("fav_films") : NULL,
"fav_shows" => $this->queryParam("fav_shows") != "" ? $this->queryParam("fav_shows") : NULL,
"fav_books" => $this->queryParam("fav_books") != "" ? $this->queryParam("fav_books") : NULL,
"fav_quote" => $this->queryParam("fav_quote") != "" ? $this->queryParam("fav_quote") : NULL,
"hometown" => $this->queryParam("hometown") != "" ? $this->queryParam("hometown") : NULL,
"before" => $this->queryParam("datebefore") != "" ? strtotime($this->queryParam("datebefore")) : NULL,
"after" => $this->queryParam("dateafter") != "" ? strtotime($this->queryParam("dateafter")) : NULL,
"gender" => $this->queryParam("gender") != "" && $this->queryParam("gender") != 2 ? $this->queryParam("gender") : NULL,
"doNotSearchPrivate" => true,
"only_performers" => $this->queryParam("only_performers") == "on" ? "1" : NULL,
"with_lyrics" => $this->queryParam("with_lyrics") == "on" ? true : NULL,
];
$repo = $repos[$type] or $this->throwError(400, "Bad Request", "Invalid search entity $type.");
$iterator = $results->page($page, OPENVK_DEFAULT_PER_PAGE); $results = $this->{$repo}->find($query, $parameters, $sort);
$iterator = $results->page($page, 14);
$count = $results->size(); $count = $results->size();
$this->template->order = $order; $this->template->iterator = iterator_to_array($iterator);
$this->template->invert = $invert;
$this->template->data = $this->template->iterator = iterator_to_array($iterator);
$this->template->count = $count; $this->template->count = $count;
$this->template->section = $section; $this->template->type = $type;
$this->template->page = $page; $this->template->page = $page;
$this->template->perPage = OPENVK_DEFAULT_PER_PAGE; $this->template->perPage = 14;
$this->template->query = $query;
$this->template->atSearch = true;
$this->template->paginatorConf = (object) [
"page" => $page,
"count" => $count,
"amount" => sizeof($this->template->data),
"perPage" => $this->template->perPage,
"atBottom" => false,
"tidy" => true,
"space" => 6,
'pageCount' => ceil($count / $this->template->perPage),
];
$this->template->extendedPaginatorConf = clone $this->template->paginatorConf;
$this->template->extendedPaginatorConf->space = 11;
} }
} }

View file

@ -337,7 +337,8 @@ final class UserPresenter extends OpenVKPresenter
$this->redirect($_SERVER['HTTP_REFERER']); $this->redirect($_SERVER['HTTP_REFERER']);
} }
function renderSetAvatar() { function renderSetAvatar()
{
$this->assertUserLoggedIn(); $this->assertUserLoggedIn();
$this->willExecuteWriteAction(); $this->willExecuteWriteAction();
@ -348,8 +349,8 @@ final class UserPresenter extends OpenVKPresenter
$photo->setFile($_FILES["blob"]); $photo->setFile($_FILES["blob"]);
$photo->setCreated(time()); $photo->setCreated(time());
$photo->save(); $photo->save();
} catch(\Throwable $ex) { } catch(ISE $ex) {
$this->flashFail("err", tr("error"), tr("error_upload_failed"), NULL, (int)$this->postParam("ajax", true) == 1); $this->flashFail("err", tr("error"), tr("error_upload_failed"));
} }
$album = (new Albums)->getUserAvatarAlbum($this->user->identity); $album = (new Albums)->getUserAvatarAlbum($this->user->identity);
@ -360,57 +361,23 @@ final class UserPresenter extends OpenVKPresenter
$flags = 0; $flags = 0;
$flags |= 0b00010000; $flags |= 0b00010000;
if($this->postParam("on_wall") == 1) { $post = new Post;
$post = new Post; $post->setOwner($this->user->id);
$post->setOwner($this->user->id); $post->setWall($this->user->id);
$post->setWall($this->user->id); $post->setCreated(time());
$post->setCreated(time()); $post->setContent("");
$post->setContent(""); $post->setFlags($flags);
$post->setFlags($flags); $post->save();
$post->save(); $post->attach($photo);
if($this->postParam("ava", true) == (int)1) {
$post->attach($photo);
}
if((int)$this->postParam("ajax", true) == 1) {
$this->returnJson([ $this->returnJson([
"success" => true, "url" => $photo->getURL(),
"new_photo" => $photo->getPrettyId(), "id" => $photo->getPrettyId()
"url" => $photo->getURL(),
]); ]);
} else { } else {
$this->flashFail("succ", tr("photo_saved"), tr("photo_saved_comment")); $this->flashFail("succ", tr("photo_saved"), tr("photo_saved_comment"));
} }
} }
function renderDeleteAvatar() {
$this->assertUserLoggedIn();
$this->willExecuteWriteAction();
$avatar = $this->user->identity->getAvatarPhoto();
if(!$avatar)
$this->flashFail("succ", tr("error"), "no avatar bro", NULL, true);
$avatar->isolate();
$newAvatar = $this->user->identity->getAvatarPhoto();
if(!$newAvatar)
$this->returnJson([
"success" => true,
"has_new_photo" => false,
"new_photo" => NULL,
"url" => "/assets/packages/static/openvk/img/camera_200.png",
]);
else
$this->returnJson([
"success" => true,
"has_new_photo" => true,
"new_photo" => $newAvatar->getPrettyId(),
"url" => $newAvatar->getURL(),
]);
}
function renderSettings(): void function renderSettings(): void
{ {

View file

@ -186,12 +186,8 @@ final class VKAPIPresenter extends OpenVKPresenter
function renderRoute(string $object, string $method): void function renderRoute(string $object, string $method): void
{ {
$callback = $this->queryParam("callback");
$authMechanism = $this->queryParam("auth_mechanism") ?? "token"; $authMechanism = $this->queryParam("auth_mechanism") ?? "token";
if($authMechanism === "roaming") { if($authMechanism === "roaming") {
if($callback)
$this->fail(-1, "User authorization failed: roaming mechanism is unavailable with jsonp.", $object, $method);
if(!$this->user->identity) if(!$this->user->identity)
$this->fail(5, "User authorization failed: roaming mechanism is selected, but user is not logged in.", $object, $method); $this->fail(5, "User authorization failed: roaming mechanism is selected, but user is not logged in.", $object, $method);
else else
@ -263,16 +259,10 @@ final class VKAPIPresenter extends OpenVKPresenter
$result = json_encode([ $result = json_encode([
"response" => $res, "response" => $res,
]); ]);
if($callback) {
$result = $callback . '(' . $result . ')';
header('Content-Type: application/javascript');
} else
header("Content-Type: application/json");
$size = strlen($result); $size = strlen($result);
header("Content-Type: application/json");
header("Content-Length: $size"); header("Content-Length: $size");
exit($result); exit($result);
} }

View file

@ -18,11 +18,9 @@
{script "js/l10n.js"} {script "js/l10n.js"}
{script "js/openvk.cls.js"} {script "js/openvk.cls.js"}
{script "js/node_modules/dashjs/dist/dash.all.min.js"} {script "js/node_modules/dashjs/dist/dash.all.min.js"}
<script src="/assets/packages/static/openvk/js/node_modules/cropperjs/dist/cropper.js" type="module"></script>
{script "js/al_music.js"} {script "js/al_music.js"}
{css "js/node_modules/tippy.js/dist/backdrop.css"} {css "js/node_modules/tippy.js/dist/backdrop.css"}
{css "js/node_modules/cropperjs/dist/cropper.css"}
{css "js/node_modules/tippy.js/dist/border.css"} {css "js/node_modules/tippy.js/dist/border.css"}
{css "js/node_modules/tippy.js/dist/svg-arrow.css"} {css "js/node_modules/tippy.js/dist/svg-arrow.css"}
{css "js/node_modules/tippy.js/themes/light.css"} {css "js/node_modules/tippy.js/themes/light.css"}
@ -87,7 +85,7 @@
<div class="layout"> <div class="layout">
<div id="xhead" class="dm"></div> <div id="xhead" class="dm"></div>
<div class="page_header{if $instance_name != OPENVK_DEFAULT_INSTANCE_NAME} page_custom_header{/if}{if $atSearch} search_expanded search_expanded_at_all{/if}"> <div class="page_header{if $instance_name != OPENVK_DEFAULT_INSTANCE_NAME} page_custom_header{/if}">
<a href="/" class="home_button{if $instance_name != OPENVK_DEFAULT_INSTANCE_NAME} home_button_custom{/if}" title="{$instance_name}">{if $instance_name != OPENVK_DEFAULT_INSTANCE_NAME}{$instance_name}{/if}</a> <a href="/" class="home_button{if $instance_name != OPENVK_DEFAULT_INSTANCE_NAME} home_button_custom{/if}" title="{$instance_name}">{if $instance_name != OPENVK_DEFAULT_INSTANCE_NAME}{$instance_name}{/if}</a>
<div n:if="isset($thisUser) ? (!$thisUser->isBanned() XOR !$thisUser->isActivated()) : true" class="header_navigation"> <div n:if="isset($thisUser) ? (!$thisUser->isBanned() XOR !$thisUser->isActivated()) : true" class="header_navigation">
{ifset $thisUser} {ifset $thisUser}
@ -96,45 +94,67 @@
<a href="/logout?hash={urlencode($csrfToken)}">{_header_log_out}</a> <a href="/logout?hash={urlencode($csrfToken)}">{_header_log_out}</a>
</div> </div>
{else} {else}
<div class="link"> <div class="link dec">
<a href="/">{_header_home}</a> <a href="/">{_header_home}</a>
</div> </div>
<div class="link"> <div class="link dec">
<a href="/search?section=groups">{_header_groups}</a> <a href="/search?type=groups">{_header_groups}</a>
</div> </div>
<div class="link"> <div class="link dec">
<a href="/search?q=&section=users&order=rating">{_header_search}</a> <a href="/search">{_header_search}</a>
</div> </div>
<div class="link"> <div class="link dec">
<a href="/invite">{_header_invite}</a> <a href="/invite">{_header_invite}</a>
</div> </div>
<div class="link"> <div class="link dec">
<a href="/support">{_header_help} <b n:if="$ticketAnsweredCount > 0">({$ticketAnsweredCount})</b></a> <a href="/support">{_header_help} <b n:if="$ticketAnsweredCount > 0">({$ticketAnsweredCount})</b></a>
</div> </div>
<div class="link"> <div class="link dec">
<a href="/logout?hash={urlencode($csrfToken)}">{_header_log_out}</a> <a href="/logout?hash={urlencode($csrfToken)}">{_header_log_out}</a>
</div> </div>
<div id="search_box" class='header_divider_stick'> {var $atSearch = str_contains($_SERVER['REQUEST_URI'], "/search")}
<div id="search_box_fr"> <div id="srch" class="{if $atSearch}nodivider{else}link{/if}">
<form id='search_form' action="/search" method="get">
<div id='search_and_one_more_wrapper'> {if !$atSearch}
<input n:attr="value => $_REQUEST['q'] ? $_REQUEST['q'] : NULL" autocomplete="off" type="search" maxlength="79" name="q" placeholder="{_header_search}" title="{_header_search} [Alt+Shift+F]" accesskey="f" /> <form action="/search" method="get" id="searcher" style="position:relative;">
<select name="section"> <input autocomplete="off" id="searchInput" oninput="checkSearchTips()" onfocus="expandSearch()" onblur="decreaseSearch()" class="sr" type="search" name="query" placeholder="{_header_search}" style="height: 20px;background: url('/assets/packages/static/openvk/img/search_icon.png') no-repeat 3px 4px; background-color: #fff; padding-left: 18px;width: 120px;" title="{_header_search} [Alt+Shift+F]" accesskey="f" />
<option n:attr="selected => $_REQUEST['section'] == 'users'" value="users">{_s_by_people}</option> <select onchange="checkSearchTips()" id="typer" name="type" class="whatFind" style="display:none;top: 0px;">
<option n:attr="selected => $_REQUEST['section'] == 'groups'" value="groups">{_s_by_groups}</option> <option value="users">{_s_by_people}</option>
<option n:attr="selected => $_REQUEST['section'] == 'posts'" value="posts">{_s_by_posts}</option> <option value="groups">{_s_by_groups}</option>
<option n:attr="selected => $_REQUEST['section'] == 'videos'" value="videos">{_s_by_videos}</option> <option value="posts">{_s_by_posts}</option>
<option n:attr="selected => $_REQUEST['section'] == 'apps'" value="apps">{_s_by_apps}</option> <option value="comments">{_s_by_comments}</option>
<option n:attr="selected => $_REQUEST['section'] == 'audios'" value="audios">{_s_by_audios}</option> <option value="videos">{_s_by_videos}</option>
<option n:attr="selected => $_REQUEST['section'] == 'audios_playlists'" value="audios_playlists">{_s_by_audios_playlists}</option> <option value="apps">{_s_by_apps}</option>
</select> <option value="audios">{_s_by_audios}</option>
</div> </select>
<button class="search_box_button">
<span>{_header_search}</span>
</button>
</form> </form>
</div> <div class="searchTips" id="srcht" hidden>
<div id="searchBoxFastTips"></div> <table style="border:none;border-spacing: 0;">
<tbody id="srchrr">
</tbody>
</table>
</div>
{else}
<form action="/search" method="get" id="searcher" style="margin-top: -1px;position:relative;">
<input id="searchInput" value="{$_GET['query'] ?? ''}" type="search" class="sr" name="query" placeholder="{_header_search}" style="height: 20px; background-color: #fff; padding-left: 6px;width: 555px;" title="{_header_search} [Alt+Shift+F]" accesskey="f" />
<select name="type" class="whatFind">
<option value="users" {if str_contains($_SERVER['REQUEST_URI'], "type=users")}selected{/if}>{_s_by_people}</option>
<option value="groups" {if str_contains($_SERVER['REQUEST_URI'], "type=groups")}selected{/if}>{_s_by_groups}</option>
<option value="posts" {if str_contains($_SERVER['REQUEST_URI'], "type=posts")}selected{/if}>{_s_by_posts}</option>
<option value="comments" {if str_contains($_SERVER['REQUEST_URI'], "type=comments")}selected{/if}>{_s_by_comments}</option>
<option value="videos" {if str_contains($_SERVER['REQUEST_URI'], "type=videos")}selected{/if}>{_s_by_videos}</option>
<option value="apps" {if str_contains($_SERVER['REQUEST_URI'], "type=apps")}selected{/if}>{_s_by_apps}</option>
<option value="audios" {if str_contains($_SERVER['REQUEST_URI'], "type=audios")}selected{/if}>{_s_by_audios}</option>
</select>
<button class="searchBtn"><span style="color:white;font-weight: 600;font-size:12px;">{_header_search}</span></button>
</form>
<script>
let els = document.querySelectorAll("div.dec")
for(const element of els) {
element.style.display = "none"
}
</script>
{/if}
</div> </div>
{/if} {/if}
{else} {else}
@ -378,7 +398,6 @@
{script "js/al_mentions.js"} {script "js/al_mentions.js"}
{script "js/al_polls.js"} {script "js/al_polls.js"}
{script "js/al_suggestions.js"} {script "js/al_suggestions.js"}
{script "js/al_navigation.js"}
{ifset $thisUser} {ifset $thisUser}
{script "js/al_notifs.js"} {script "js/al_notifs.js"}
@ -422,8 +441,7 @@
<script> <script>
window.openvk = { window.openvk = {
"audio_genres": {\openvk\Web\Models\Entities\Audio::genres}, "audio_genres": {\openvk\Web\Models\Entities\Audio::genres}
"at_search": {$atSearch ?? false},
} }
</script> </script>

View file

@ -5,7 +5,7 @@
{block header} {block header}
<a href="{$owner->getURL()}">{$owner->getCanonicalName()}</a> <a href="{$owner->getURL()}">{$owner->getCanonicalName()}</a>
» »
<a href="/playlists{$ownerId}">{_playlists}</a> <a href="/audios{$ownerId}">{_audios}</a>
» »
<a href="/playlist{$playlist->getPrettyId()}">{_playlist}</a> <a href="/playlist{$playlist->getPrettyId()}">{_playlist}</a>
» »
@ -30,13 +30,8 @@
</div> </div>
<div class="moreInfo"> <div class="moreInfo">
<textarea placeholder="{_description}" name="description" maxlength="2045" style="margin-top: 11px;">{$playlist->getDescription()}</textarea> <textarea name="description" maxlength="2045" style="margin-top: 11px;">{$playlist->getDescription()}</textarea>
</div> </div>
<label>
<input type='checkbox' name='is_unlisted' n:attr='checked => $playlist->isUnlisted()'>
{_playlist_hide_from_search}
</label>
</div> </div>
</div> </div>
@ -61,7 +56,6 @@
<form method="post" id="editPlaylistForm" data-id="{$playlist->getId()}" enctype="multipart/form-data"> <form method="post" id="editPlaylistForm" data-id="{$playlist->getId()}" enctype="multipart/form-data">
<input type="hidden" name="title" maxlength="128" /> <input type="hidden" name="title" maxlength="128" />
<input type="hidden" name="hash" value="{$csrfToken}" /> <input type="hidden" name="hash" value="{$csrfToken}" />
<input type="hidden" name="is_unlisted" value="0" />
<textarea style="display:none;" name="description" maxlength="2048" /> <textarea style="display:none;" name="description" maxlength="2048" />
<input type="hidden" name="audios"> <input type="hidden" name="audios">
<input type="file" style="display:none;" name="new_cover" accept=".jpg,.png"> <input type="file" style="display:none;" name="new_cover" accept=".jpg,.png">
@ -77,7 +71,6 @@
u("#editPlaylistForm").on("submit", (e) => { u("#editPlaylistForm").on("submit", (e) => {
document.querySelector("#editPlaylistForm input[name='title']").value = document.querySelector(".playlistInfo input[name='title']").value document.querySelector("#editPlaylistForm input[name='title']").value = document.querySelector(".playlistInfo input[name='title']").value
document.querySelector("#editPlaylistForm textarea[name='description']").value = document.querySelector(".playlistBlock textarea[name='description']").value document.querySelector("#editPlaylistForm textarea[name='description']").value = document.querySelector(".playlistBlock textarea[name='description']").value
document.querySelector("#editPlaylistForm input[name='is_unlisted']").value = document.querySelector("input[name='is_unlisted']").checked ? 1 : 0
}) })
u("#editPlaylistForm input[name='new_cover']").on("change", (e) => { u("#editPlaylistForm input[name='new_cover']").on("change", (e) => {

View file

@ -59,47 +59,66 @@
<input n:if="$mode == 'popular'" type="hidden" name="bigplayer_context" data-type="popular_audios" data-entity="0" data-page="1"> <input n:if="$mode == 'popular'" type="hidden" name="bigplayer_context" data-type="popular_audios" data-entity="0" data-page="1">
<div class="bigPlayerDetector"></div> <div class="bigPlayerDetector"></div>
<div class="audiosDiv"> <div style="width: 100%;display: flex;margin-bottom: -10px;" class="audiosDiv">
<div style="width: 74%;" class="audiosContainer audiosPaddingContainer" n:if="$mode != 'playlists'"> <div style="width: 74%;" class="audiosContainer" n:if="$mode != 'playlists'">
<div n:if="$audiosCount <= 0" style='height: 50%;'> <div style="padding: 8px;">
{include "../components/content_error.xml", description => $ownerId > 0 ? ($ownerId == $thisUser->getId() ? tr("no_audios_thisuser") : tr("no_audios_user")) : tr("no_audios_club")} <div n:if="$audiosCount <= 0">
</div> {include "../components/error.xml", description => $ownerId > 0 ? ($ownerId == $thisUser->getId() ? tr("no_audios_thisuser") : tr("no_audios_user")) : tr("no_audios_club")}
<div n:if="$audiosCount > 0" class="infContainer"> </div>
<div class="infObj" n:foreach="$audios as $audio"> <div n:if="$audiosCount > 0" class="infContainer">
{include "player.xml", audio => $audio, club => $club} <div class="infObj" n:foreach="$audios as $audio">
{include "player.xml", audio => $audio, club => $club}
</div>
</div> </div>
</div>
<div n:if="$mode != 'new' && $mode != 'popular'"> <div n:if="$mode != 'new' && $mode != 'popular'">
{include "../components/paginator.xml", conf => (object) [ {include "../components/paginator.xml", conf => (object) [
"page" => $page, "page" => $page,
"count" => $audiosCount, "count" => $audiosCount,
"amount" => sizeof($audios), "amount" => sizeof($audios),
"perPage" => $perPage ?? OPENVK_DEFAULT_PER_PAGE, "perPage" => $perPage ?? OPENVK_DEFAULT_PER_PAGE,
"atBottom" => true, "atBottom" => true,
]} ]}
</div>
</div> </div>
</div> </div>
<div style="width: 71.8%;" class="audiosPaddingContainer audiosPaddingContainer" n:if="$mode == 'playlists'"> <div style="width: 74%;" n:if="$mode == 'playlists'">
<div n:if="$playlistsCount <= 0" style='height: 100%;'> <div style="padding: 8px;">
{include "../components/content_error.xml", description => $ownerId > 0 ? ($ownerId == $thisUser->getId() ? tr("no_playlists_thisuser") : tr("no_playlists_user")) : tr("no_playlists_club")} <div n:if="$playlistsCount <= 0">
</div> {include "../components/error.xml", description => $ownerId > 0 ? ($ownerId == $thisUser->getId() ? tr("no_playlists_thisuser") : tr("no_playlists_user")) : tr("no_playlists_club")}
</div>
<div class="infContainer playlistContainer" n:if="$playlistsCount > 0"> <div class="infContainer playlistContainer" n:if="$playlistsCount > 0">
{foreach $playlists as $playlist} <div class="infObj" n:foreach="$playlists as $playlist">
{include 'playlistListView.xml', playlist => $playlist} <a href="/playlist{$playlist->getPrettyId()}">
{/foreach} <div class="playlistCover">
</div> <img src="{$playlist->getCoverURL()}" alt="{_playlist_cover}">
</div>
</a>
<div>
{include "../components/paginator.xml", conf => (object) [ <div class="playlistInfo">
"page" => $page, <a href="/playlist{$playlist->getPrettyId()}">
"count" => $playlistsCount, <span style="font-size: 12px" class="playlistName">
"amount" => sizeof($playlists), {ovk_proc_strtr($playlist->getName(), 15)}
"perPage" => $perPage ?? OPENVK_DEFAULT_PER_PAGE, </span>
"atBottom" => true, </a>
]}
<a href="{$playlist->getOwner()->getURL()}">{ovk_proc_strtr($playlist->getOwner()->getCanonicalName(), 20)}</a>
</div>
</div>
</div>
<div>
{include "../components/paginator.xml", conf => (object) [
"page" => $page,
"count" => $playlistsCount,
"amount" => sizeof($playlists),
"perPage" => $perPage ?? OPENVK_DEFAULT_PER_PAGE,
"atBottom" => true,
]}
</div>
</div> </div>
</div> </div>
{include "tabs.xml"} {include "tabs.xml"}

View file

@ -8,11 +8,11 @@
{if !$_GET["gid"]} {if !$_GET["gid"]}
<a href="{$thisUser->getURL()}">{$thisUser->getCanonicalName()}</a> <a href="{$thisUser->getURL()}">{$thisUser->getCanonicalName()}</a>
» »
<a href="/playlists{$thisUser->getId()}">{_playlists}</a> <a href="/audios{$thisUser->getId()}">{_audios}</a>
{else} {else}
<a href="{$club->getURL()}">{$club->getCanonicalName()}</a> <a href="{$club->getURL()}">{$club->getCanonicalName()}</a>
» »
<a href="/playlists-{$club->getId()}">{_playlists}</a> <a href="/audios-{$club->getId()}">{_audios}</a>
{/if} {/if}
» »
{_new_playlist} {_new_playlist}
@ -44,10 +44,6 @@
<div class="moreInfo" style="margin-top: 11px;"> <div class="moreInfo" style="margin-top: 11px;">
<textarea placeholder="{_description}" name="description" maxlength="2045" /> <textarea placeholder="{_description}" name="description" maxlength="2045" />
</div> </div>
<label>
<input type='checkbox' name='is_unlisted'>
{_playlist_hide_from_search}
</label>
</div> </div>
</div> </div>
@ -72,7 +68,6 @@
<form method="post" id="newPlaylistForm" enctype="multipart/form-data"> <form method="post" id="newPlaylistForm" enctype="multipart/form-data">
<input type="hidden" name="title" maxlength="125" /> <input type="hidden" name="title" maxlength="125" />
<input type="hidden" name="hash" value="{$csrfToken}" /> <input type="hidden" name="hash" value="{$csrfToken}" />
<input type="hidden" name="is_unlisted" value="0" />
<textarea style="display:none;" name="description" maxlength="2045" /> <textarea style="display:none;" name="description" maxlength="2045" />
<input type="hidden" name="audios"> <input type="hidden" name="audios">
<input type="file" style="display:none;" name="cover" accept=".jpg,.png"> <input type="file" style="display:none;" name="cover" accept=".jpg,.png">
@ -88,7 +83,6 @@
u("#newPlaylistForm").on("submit", (e) => { u("#newPlaylistForm").on("submit", (e) => {
document.querySelector("#newPlaylistForm input[name='title']").value = document.querySelector(".plinfo input[name='title']").value document.querySelector("#newPlaylistForm input[name='title']").value = document.querySelector(".plinfo input[name='title']").value
document.querySelector("#newPlaylistForm textarea[name='description']").value = document.querySelector(".plinfo textarea[name='description']").value document.querySelector("#newPlaylistForm textarea[name='description']").value = document.querySelector(".plinfo textarea[name='description']").value
document.querySelector("#newPlaylistForm input[name='is_unlisted']").value = document.querySelector(".plinfo input[name='is_unlisted']").checked ? 1 : 0
}) })
u("#newPlaylistForm input[name='cover']").on("change", (e) => { u("#newPlaylistForm input[name='cover']").on("change", (e) => {

View file

@ -1,16 +1,13 @@
{extends "../@layout.xml"} {extends "../@layout.xml"}
{block title} {block title}{_playlist}{/block}
{_playlist}
{$playlist->getName()}
{/block}
{block headIncludes} {block headIncludes}
<meta property="og:type" content="music.album"> <meta property="og:type" content="music.album">
<meta property="og:title" content="{$playlist->getName()}"> <meta property="og:title" content="{$playlist->getName()}">
<meta property="og:url" content="{$playlist->getURL()}"> <meta property="og:url" content="{$playlist->getURL()}">
<meta property="og:description" content="{$playlist->getDescription()}"> <meta property="og:description" content="{$playlist->getDescription()}">
<meta property="og:image" content="{$cover_url}"> <meta property="og:image" content="{$playlist->getCoverURL()}">
<script type="application/ld+json"> <script type="application/ld+json">
{ {
@ -25,36 +22,31 @@
{block header} {block header}
<a href="{$owner->getURL()}">{$owner->getCanonicalName()}</a> <a href="{$owner->getURL()}">{$owner->getCanonicalName()}</a>
» »
<a href="/playlists{$ownerId}">{_playlists}</a> <a href="/audios{$ownerId}">{_audios}</a>
» »
{_playlist} {_playlist}
{/block} {/block}
{block content} {block content}
{include "bigplayer.xml"} {include "bigplayer.xml"}
{php $count = $playlist->size()}
<input type="hidden" name="bigplayer_context" data-type="playlist_context" data-entity="{$playlist->getId()}" data-page="{$page}"> <input type="hidden" name="bigplayer_context" data-type="playlist_context" data-entity="{$playlist->getId()}" data-page="{$page}">
<div class="playlistBlock"> <div class="playlistBlock">
<div class="playlistCover" style="float: left;"> <div class="playlistCover" style="float: left;">
{if $cover} <a href="{$playlist->getCoverURL()}" target="_blank">
<a href="{$cover_url}" target="_blank"> <img src="{$playlist->getCoverURL('normal')}" alt="{_playlist_cover}">
<img onclick="OpenMiniature(event, {$cover_url}, null, {$cover->getPrettyId()}, null)" src="{$cover_url}" alt="{_playlist_cover}">
</a> </a>
{else}
<a>
<img src="{$cover_url}" alt="{_playlist_cover}">
</a>
{/if}
<div class="profile_links" n:if="isset($thisUser)"> <div class="profile_links" style="width: 139px;" n:if="isset($thisUser)">
<a class="profile_link" href="/player/upload?playlist={$playlist->getId()}" n:if="$canEdit">{_upload_audio}</a> <a class="profile_link" style="width: 98%;" href="/playlist{$playlist->getPrettyId()}/edit" n:if="$playlist->canBeModifiedBy($thisUser)">{_edit_playlist}</a>
<a class="profile_link" href="/playlist{$playlist->getPrettyId()}/edit" n:if="$canEdit">{_edit_playlist}</a> <a class="profile_link" style="width: 98%;" id="bookmarkPlaylist" data-id="{$playlist->getId()}" n:if="!$isBookmarked">{_bookmark}</a>
<a class="profile_link" id="bookmarkPlaylist" data-id="{$playlist->getId()}" n:if="!$isBookmarked">{_bookmark}</a> <a class="profile_link" style="width: 98%;" id="unbookmarkPlaylist" data-id="{$playlist->getId()}" n:if="$isBookmarked">{_unbookmark}</a>
<a class="profile_link" id="unbookmarkPlaylist" data-id="{$playlist->getId()}" n:if="$isBookmarked">{_unbookmark}</a>
</div> </div>
</div> </div>
<div class='playlistWrapper'> <div style="float: left;padding-left: 13px;width:75%">
<div class="playlistInfo"> <div class="playlistInfo">
<h4 style="border-bottom:unset;">{$playlist->getName()}</h4> <h4 style="border-bottom:unset;">{$playlist->getName()}</h4>

View file

@ -5,22 +5,14 @@
{/block} {/block}
{block header} {block header}
{if !$playlist} {if !is_null($group)}
{if !is_null($group)} <a href="{$group->getURL()}">{$group->getCanonicalName()}</a>
<a href="{$group->getURL()}">{$group->getCanonicalName()}</a> »
» <a href="/audios-{$group->getId()}">{_audios}</a>
<a href="/audios-{$group->getId()}">{_audios}</a>
{else}
<a href="{$thisUser->getURL()}">{$thisUser->getCanonicalName()}</a>
»
<a href="/audios{$thisUser->getId()}">{_audios}</a>
{/if}
{else} {else}
<a href="{$owner->getURL()}">{$owner->getCanonicalName()}</a> <a href="{$thisUser->getURL()}">{$thisUser->getCanonicalName()}</a>
» »
<a href="/playlists{$ownerId}">{_playlists}</a> <a href="/audios{$thisUser->getId()}">{_audios}</a>
»
<a href="/playlist{$playlist->getPrettyId()}">{_playlist}</a>
{/if} {/if}
» »
@ -44,7 +36,6 @@
<input type="hidden" name="lyrics" /> <input type="hidden" name="lyrics" />
<input type="hidden" name="genre" /> <input type="hidden" name="genre" />
<input type="hidden" name="explicit" /> <input type="hidden" name="explicit" />
<input type="hidden" name="unlisted" />
<input type="hidden" name="hash" value="{$csrfToken}" /> <input type="hidden" name="hash" value="{$csrfToken}" />
<input id="audio_input" type="file" name="blob" accept="audio/*" style="display:none" /> <input id="audio_input" type="file" name="blob" accept="audio/*" style="display:none" />
@ -52,20 +43,20 @@
</form> </form>
</div><br/> </div><br/>
<span>{_you_can_also_add_audio_using} <b><a href="/search?section=audios">{_search_audio_inst}</a></b>.<span> <span>{_you_can_also_add_audio_using} <b><a href="/search?type=audios">{_search_audio_inst}</a></b>.<span>
</div> </div>
<div id="lastStep" style="display:none;"> <div id="lastStep" style="display:none;">
<table cellspacing="7" cellpadding="0" border="0" align="center"> <table cellspacing="7" cellpadding="0" border="0" align="center">
<tbody> <tbody>
<tr>
<td width="120" valign="top"><span class="nobold">{_performer}:</span></td>
<td><input name="performer" type="text" autocomplete="off" maxlength="80" /></td>
</tr>
<tr> <tr>
<td width="120" valign="top"><span class="nobold">{_audio_name}:</span></td> <td width="120" valign="top"><span class="nobold">{_audio_name}:</span></td>
<td><input type="text" name="name" autocomplete="off" maxlength="80" /></td> <td><input type="text" name="name" autocomplete="off" maxlength="80" /></td>
</tr> </tr>
<tr>
<td width="120" valign="top"><span class="nobold">{_performer}:</span></td>
<td><input name="performer" type="text" autocomplete="off" maxlength="80" /></td>
</tr>
<tr> <tr>
<td width="120" valign="top"><span class="nobold">{_genre}:</span></td> <td width="120" valign="top"><span class="nobold">{_genre}:</span></td>
<td> <td>
@ -83,8 +74,7 @@
<tr> <tr>
<td width="120" valign="top"></td> <td width="120" valign="top"></td>
<td> <td>
<label style='display:block'><input type="checkbox" name="explicit">{_audios_explicit}</label> <label><input type="checkbox" name="explicit">{_audios_explicit}</label>
<label><input type="checkbox" name="unlisted">{_audios_unlisted}</label>
</td> </td>
</tr> </tr>
<tr> <tr>
@ -110,24 +100,8 @@
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");
}
let tags = null let tags = await id3.fromFile(files[0]);
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...");
@ -142,31 +116,17 @@
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 there are more than one genre if(document.querySelector("#lastStep select[name=genre] > option[value='" + tags.genre + "']") != null) {
if(tags.genre.split(', ').length > 1) { document.querySelector("#lastStep select[name=genre]").value = tags.genre;
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 {
if(document.querySelector("#lastStep select[name=genre] > option[value='" + tags.genre + "']") != null) { console.warn("Unknown genre: " + tags.genre);
document.querySelector("#lastStep select[name=genre]").value = tags.genre; document.querySelector("#lastStep select[name=genre]").value = "Other"
} else {
console.warn("Unknown genre: " + tags.genre);
document.querySelector("#lastStep select[name=genre]").value = "Other"
}
} }
} else {
document.querySelector("#lastStep select[name=genre]").value = "Other"
} }
if(tags.comments != null)
document.querySelector("#lastStep textarea[name=lyrics]").value = tags.comments
} else { } else {
fallback() 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");
} }
}); });
@ -187,14 +147,12 @@
var genre_ = document.querySelector("#audio_upload input[name=genre]"); var genre_ = document.querySelector("#audio_upload input[name=genre]");
var lyrics_ = document.querySelector("#audio_upload input[name=lyrics]"); var lyrics_ = document.querySelector("#audio_upload input[name=lyrics]");
var explicit_ = document.querySelector("#audio_upload input[name=explicit]"); var explicit_ = document.querySelector("#audio_upload input[name=explicit]");
var unlisted_ = document.querySelector("#audio_upload input[name=unlisted]");
name_.value = document.querySelector("#lastStep input[name=name]").value name_.value = document.querySelector("#lastStep input[name=name]").value
perf_.value = document.querySelector("#lastStep input[name=performer]").value perf_.value = document.querySelector("#lastStep input[name=performer]").value
genre_.value = document.querySelector("#lastStep select[name=genre]").value genre_.value = document.querySelector("#lastStep select[name=genre]").value
lyrics_.value = document.querySelector("#lastStep textarea[name=lyrics]").value lyrics_.value = document.querySelector("#lastStep textarea[name=lyrics]").value
explicit_.value = document.querySelector("#lastStep input[name=explicit]").checked ? "on" : "off" explicit_.value = document.querySelector("#lastStep input[name=explicit]").checked ? "on" : "off"
unlisted_.value = document.querySelector("#lastStep input[name=unlisted]").checked ? "on" : "off"
$("#audio_upload > form").trigger("submit"); $("#audio_upload > form").trigger("submit");
}) })

View file

@ -1,4 +1,4 @@
<div n:class="bigPlayer, $tidy ? tidy"> <div class="bigPlayer">
<audio class="audio" /> <audio class="audio" />
<div class="paddingLayer"> <div class="paddingLayer">
<div class="playButtons"> <div class="playButtons">
@ -18,21 +18,21 @@
<div class="trackPanel"> <div class="trackPanel">
<div class="trackInfo"> <div class="trackInfo">
<div class="trackName"> <div class="trackName">
<a>{_track_unknown}</a> — <b>{_track_unknown}</b> —
<span>{_track_noname}</span> <span>{_track_noname}</span>
</div> </div>
<div class="timer" style="float:right"> <div class="timer" style="float:right">
<span class="time">00:00</span> <span class="time">00:00</span>
<span>/</span> <span>/</span>
<span class="elapsedTime">-00:00</span> <span class="elapsedTime" style="cursor:pointer">-00:00</span>
</div> </div>
</div> </div>
<div class="track" style="margin-top: -2px;"> <div class="track" style="margin-top: -2px;">
<div class="bigPlayerTip">00:00</div> <div class="bigPlayerTip">00:00</div>
<div class="selectableTrack"> <div class="selectableTrack">
<div id='bigPlayerLengthSliderWrapper'>&nbsp; <div style="width: 95%;position: relative;">&nbsp;
<div class="slider"></div> <div class="slider"></div>
</div> </div>
</div> </div>
@ -41,7 +41,7 @@
<div class="volumePanel"> <div class="volumePanel">
<div class="selectableTrack"> <div class="selectableTrack">
<div id='bigPlayerVolumeSliderWrapper'>&nbsp; <div style="position: relative;width:72%">&nbsp;
<div class="slider"></div> <div class="slider"></div>
</div> </div>
</div> </div>

View file

@ -1,8 +1,7 @@
{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 !$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 !$audio->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;">
@ -12,32 +11,29 @@
</div> </div>
<div class="status" style="margin-top: 12px;"> <div class="status" style="margin-top: 12px;">
<div class="mediaInfo noOverflow"> <div class="mediaInfo noOverflow" style="margin-bottom: -8px; cursor: pointer;display:flex;width: 85%;">
<div class="info"> <div class="info">
<strong class="performer"> <strong class="performer">
<a href="/search?query=&section=audios&order=listens&only_performers=on&q={$audio->getPerformer()}">{$audio->getPerformer()}</a> <a href="/search?query=&type=audios&sort=id&only_performers=on&query={$audio->getPerformer()}">{$audio->getPerformer()}</a>
</strong> </strong>
<span class="title {if !empty($audio->getLyrics())}withLyrics{/if}">{$audio->getTitle()}</span> <span class="title {if !empty($audio->getLyrics())}withLyrics{/if}">{$audio->getTitle()}</span>
</div> </div>
<svg n:if="$audio->isExplicit()" class="explicitMark" xmlns="http://www.w3.org/2000/svg" height="11" viewBox="0 0 11 11" width="11"> <div class="explicitMark" n:if="$audio->isExplicit()"></div>
<path d="m1 2.506v5.988a1.5 1.5 0 0 0 1.491 1.506h6.019c.827 0 1.49-.674 1.49-1.506v-5.988a1.5 1.5 0 0 0 -1.491-1.506h-6.019c-.827 0-1.49.674-1.49 1.506zm4 2.494v-1h2v-1h-3v5h3v-1h-2v-1h2v-1zm-5-2.494a2.496 2.496 0 0 1 2.491-2.506h6.019a2.5 2.5 0 0 1 2.49 2.506v5.988a2.496 2.496 0 0 1 -2.491 2.506h-6.019a2.5 2.5 0 0 1 -2.49-2.506z" />
</svg>
</div> </div>
</div> </div>
<div class="volume" style="display: flex; flex-direction: column;width:14%;"> <div class="volume" style="display: flex; flex-direction: column;width:14%;">
<span class="nobold {if !$hideButtons}hideOnHover{/if}" data-unformatted="{$audio->getLength()}" style="text-align: center;margin-top: 12px;">{$audio->getFormattedLength()}</span> <span class="nobold {if !$hideButtons}hideOnHover{/if}" data-unformatted="{$audio->getLength()}" style="text-align: center;margin-top: 12px;">{$audio->getFormattedLength()}</span>
<div class="buttons"> <div class="buttons" style="margin-top: 8px;">
{php $hasAudio = isset($thisUser) && $audio->isInLibraryOf($thisUser)} {php $hasAudio = isset($thisUser) && $audio->isInLibraryOf($thisUser)}
{if !$hideButtons} {if !$hideButtons}
<div class="remove-icon musicIcon" data-id="{$audio->getId()}" n:if="isset($thisUser) && $hasAudio" ></div> <div class="remove-icon musicIcon" data-id="{$audio->getId()}" n:if="isset($thisUser) && $hasAudio" ></div>
<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" data-id="{$audio->getId()}" n:if="isset($thisUser) && !$isWithdrawn" ></div>
<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}
@ -45,20 +41,20 @@
</div> </div>
</div> </div>
<div class="subTracks"> <div class="subTracks">
<div class="lengthTrackWrapper"> <div style="width: 100%;">
<div class="track lengthTrack"> <div class="track lengthTrack" style="margin-top: 3px;display:none">
<div class="selectableTrack" n:attr="style => $isWithdrawn ? 'display: none;' : ''"> <div class="selectableTrack" style="width: 100%;" n:attr="style => $isWithdrawn ? 'display: none;' : ''">
<div class="selectableTrackSlider"> <div style="position: relative;width: calc(100% - 18px);">
<div class="slider"></div> <div class="slider"></div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="volumeTrackWrapper"> <div style="width: 81px;margin-left: 16px;">
<div class="track volumeTrack"> <div class="track volumeTrack" style="margin-top: 3px;display:none">
<div class="selectableTrack" n:attr="style => $isWithdrawn ? 'display: none;' : ''"> <div class="selectableTrack" style="width: 100%;" n:attr="style => $isWithdrawn ? 'display: none;' : ''">
<div class="selectableTrackSlider"> <div style="position: relative;width: calc(100% - 18px);">
<div class="slider"></div> <div class="slider"></div>
</div> </div>
</div> </div>

View file

@ -1,20 +0,0 @@
<a href="/playlist{$playlist->getPrettyId()}" class='playlistListView'>
<div class="playlistCover">
<img src="{$playlist->getCoverURL('normal')}" alt="{_playlist_cover}">
</div>
<div class="playlistInfo">
<div class="playlistInfoTopPart">
<span class="playlistName noOverflow">
{$playlist->getName()}
</span>
<span n:if='!empty($playlist->getDescription())' class="playlistDesc noOverflow">
{$playlist->getDescription()}
</span>
</div>
<span class="playlistMeta">
{$playlist->getMetaDescription()|noescape}
</span>
</div>
</a>

View file

@ -1,35 +1,35 @@
<div class='verticalGrayTabsWrapper'> <div class="searchOptions newer">
<div class="verticalGrayTabs"> <div class="searchList" style="margin-top:10px">
<div class='with_padding'> <a n:attr="id => $mode === 'list' && $isMy ? 'used' : 'ki'" href="/audios{$thisUser->getId()}" n:if="isset($thisUser)">{_my_music}</a>
<a n:if="isset($thisUser)" n:attr="id => $mode === 'list' && $isMy ? 'used' : 'ki'" href="/audios{$thisUser->getId()}">{_my_music}</a> <a href="/player/upload{if $isMyClub}?gid={abs($ownerId)}{/if}" n:if="isset($thisUser)">{_upload_audio}</a>
<a n:if="isset($thisUser)" href="/player/upload{if $isMyClub}?gid={abs($ownerId)}{/if}">{_upload_audio}</a> <a n:attr="id => $mode === 'new' ? 'used' : 'ki'" href="/audios/new">{_audio_new}</a>
<a n:if="isset($thisUser)" n:attr="id => $mode === 'new' ? 'used' : 'ki'" href="/search?section=audios">{_audio_new}</a> <a n:attr="id => $mode === 'popular' ? 'used' : 'ki'" href="/audios/popular">{_audio_popular}</a>
<a n:if="isset($thisUser)" n:attr="id => $mode === 'popular' ? 'used' : 'ki'" href="/search?section=audios&order=listens">{_audio_popular}</a> <a href="/search?type=audios" n:if="isset($thisUser)">{_audio_search}</a>
<hr n:if="isset($thisUser)"> <hr n:if="isset($thisUser)">
<a n:attr="id => $mode === 'playlists' && $ownerId == $thisUser->getId() ? 'used' : 'ki'" href="/playlists{$thisUser->getId()}" n:if="isset($thisUser)">{_my_playlists}</a> <a n:attr="id => $mode === 'playlists' && $ownerId == $thisUser->getId() ? 'used' : 'ki'" href="/playlists{$thisUser->getId()}" n:if="isset($thisUser)">{_my_playlists}</a>
<a n:if="isset($thisUser)" href="/audios/newPlaylist">{_new_playlist}</a> <a n:if="isset($thisUser)" href="/audios/newPlaylist">{_new_playlist}</a>
{if !$isMy && $mode !== 'popular' && $mode !== 'new'} {if !$isMy && $mode !== 'popular' && $mode !== 'new'}
<hr> <hr>
<a n:if="!$isMy" n:attr="id => $mode === 'list' ? 'used' : 'ki'" href="/audios{$ownerId}">{if $ownerId > 0}{_music_user}{else}{_music_club}{/if}</a> <a n:if="!$isMy" n:attr="id => $mode === 'list' ? 'used' : 'ki'" href="/audios{$ownerId}">{if $ownerId > 0}{_music_user}{else}{_music_club}{/if}</a>
<a href="/player/upload?gid={abs($ownerId)}" n:if="isset($thisUser) && isset($club) && $club->canUploadAudio($thisUser)">{_upload_audio}</a> <a href="/player/upload?gid={abs($ownerId)}" n:if="isset($thisUser) && isset($club) && $club->canUploadAudio($thisUser)">{_upload_audio}</a>
<a n:attr="id => $mode === 'playlists' && $ownerId != $thisUser->getId() ? 'used' : 'ki'" href="/playlists{$ownerId}" n:if="isset($thisUser) && isset($ownerId) && !$isMy">{if $ownerId > 0}{_playlists_user}{else}{_playlists_club}{/if}</a> <a n:attr="id => $mode === 'playlists' && $ownerId != $thisUser->getId() ? 'used' : 'ki'" href="/playlists{$ownerId}" n:if="isset($thisUser) && isset($ownerId) && !$isMy">{if $ownerId > 0}{_playlists_user}{else}{_playlists_club}{/if}</a>
<a href="/audios/newPlaylist{if $isMyClub}?gid={abs($ownerId)}{/if}" n:if="isset($thisUser) && $isMyClub">{_new_playlist}</a> <a href="/audios/newPlaylist{if $isMyClub}?gid={abs($ownerId)}{/if}" n:if="isset($thisUser) && $isMyClub">{_new_playlist}</a>
{/if} {/if}
</div>
{if $friendsAudios} {if $friendsAudios}
<div class="friendsAudiosList"> <div class="friendsAudiosList">
<a href="/audios{$fr->getRealId()}" n:foreach="$friendsAudios as $fr"> <a href="/audios{$fr->getRealId()}" style="width: 94%;padding-left: 10px;" n:foreach="$friendsAudios as $fr">
<div class="elem"> <div class="elem">
<img src="{$fr->getAvatarURL()}" /> <img src="{$fr->getAvatarURL()}" />
<div class="additionalInfo"> <div class="additionalInfo">
<span class="name noOverflow">{$fr->getCanonicalName()}</span> {php $audioStatus = $fr->getCurrentAudioStatus()}
<span class="name">{$fr->getCanonicalName()}</span>
<span class="desc">{$audioStatus ? $audioStatus->getName() : tr("audios_count", $fr->getAudiosCollectionSize())}</span> <span class="desc">{$audioStatus ? $audioStatus->getName() : tr("audios_count", $fr->getAudiosCollectionSize())}</span>
</div> </div>
</div> </div>

View file

@ -127,19 +127,25 @@
<div class="right_small_block"> <div class="right_small_block">
{var $avatarPhoto = $club->getAvatarPhoto()} {var $avatarPhoto = $club->getAvatarPhoto()}
{var $avatarLink = ((is_null($avatarPhoto) ? FALSE : $avatarPhoto->isAnonymous()) ? "/photo" . ("s/" . base_convert((string) $avatarPhoto->getId(), 10, 32)) : $club->getAvatarLink())} {var $avatarLink = ((is_null($avatarPhoto) ? FALSE : $avatarPhoto->isAnonymous()) ? "/photo" . ("s/" . base_convert((string) $avatarPhoto->getId(), 10, 32)) : $club->getAvatarLink())}
<div class="avatar_block" style="position:relative;" data-club="{$club->getId()}"> <div class="avatar_block" style="position:relative;">
{if $thisUser && $club->canBeModifiedBy($thisUser)} {var $hasAvatar = !str_contains($club->getAvatarUrl('miniscule'), "/assets/packages/static/openvk/img/camera_200.png")}
<a {if $avatarPhoto}style="display:none"{/if} class="add_image_text" id="add_image">{_add_image}</a> {if !is_null($thisUser) && $hasAvatar == false && $club->canBeModifiedBy($thisUser)}
<div {if !$avatarPhoto}style="display:none"{/if} class="avatar_controls"> <a href="javascript:addAvatarImage(true, {$club->getId()})" class="text_add_image">{_add_image_group}</a>
<div class="avatarDelete hoverable"></div> {elseif !is_null($thisUser) && $hasAvatar == true && $club->canBeModifiedBy($thisUser)}
<div class="avatar_controls">
<div class="avatarDelete">
<a id="upl" href="javascript:deleteAvatar('{$club->getAvatarPhoto()->getPrettyId()}')"><img src="/assets/packages/static/openvk/img/delete.png"/></a>
</div>
<div class="avatar_variants"> <div class="avatar_variants">
<a class="_add_image hoverable" id="add_image"><span>{_upload_new_picture}</span></a> <div class="variant">
<img src="/assets/packages/static/openvk/img/upload.png" style="margin-left:15px;height: 10px;">
<a href="javascript:addAvatarImage(true, {$club->getId()})"><p>{_upload_new_picture}</p></a>
</div>
</div> </div>
</div> </div>
{/if} {/if}
<a href="{$avatarLink|nocheck}"> <a href="{$avatarLink|nocheck}">
<img src="{$club->getAvatarUrl('normal')}" id="bigAvatar" style="width: 100%; image-rendering: -webkit-optimize-contrast;" /> <img src="{$club->getAvatarUrl('normal')}" id="thisGroupAvatar" style="width: 100%; image-rendering: -webkit-optimize-contrast;" />
</a> </a>
</div> </div>
<div n:ifset="$thisUser" id="profile_links"> <div n:ifset="$thisUser" id="profile_links">

View file

@ -1,405 +1,378 @@
{extends "../@layout.xml"} {extends "../@layout.xml"}
{block title} {block title}
{tr("search_for_$section")} {tr("search_for_$type")}
{if $_REQUEST['q']} {if $_GET['query']}
- {$_REQUEST['q']} - {$_GET['query']}
{/if} {/if}
{/block} {/block}
{block header} {block header}
{tr("search_for_$section")} {=OPENVK_ROOT_CONF["openvk"]["appearance"]["name"]} »
{tr("search_for_$type")}
{/block} {/block}
{block wrap} {* BEGIN ELEMENTS DESCRIPTION *}
<div class="wrap2">
<div class="wrap1">
<div class="page_wrap">
{if $section == 'audios' && $count > 1}
{include "../Audio/bigplayer.xml", tidy => true}
<input type="hidden" name="bigplayer_context" data-type="classic_search_context" data-entity='{"order":"{$order}","query":"{$query}","invert":{$invert ? 1 : 0},"only_performers":{$_REQUEST['only_performers'] ? 1 : 0},"genre":"{$_REQUEST['genre']}","with_lyrics":"{$_REQUEST['with_lyrics'] ? 1 : 0}"}' data-page="{$page}"> {block link|strip|stripHtml}
{if $type != "apps"}
{$x->getURL()}
{else}
/app{$x->getId()}
{/if}
{/block}
{block preview}
<img src="{$x->getAvatarUrl('miniscule')}" width="75" alt="{_photo}" loading=lazy />
{/block}
{block name}
{if $type != "apps"}
<text style="overflow: hidden;">&nbsp;{$x->getCanonicalName()}
{if $_GET['sort'] == "rating"}({$x->getRating()}%)
{elseif $_GET['sort'] == "id"}(id{$x->getId()}){/if}</text>
<img n:if="$x->isVerified()"
class="name-checkmark"
src="/assets/packages/static/openvk/img/checkmark.png"
/>
{else}
{$x->getName()}
{/if}
{/block}
{block description}
<table class="ugc-table">
<tbody>
{if $type === "users"}
{if !is_null($_GET['status']) && $_GET['status'] != ""}
<tr>
<td><span class="nobold">{_status}:</span></td>
<td>{$x->getStatus()}</td>
</tr>
{/if} {/if}
<div class='summaryBar summaryBarFlex padding'> {if !is_null($_GET['city']) && $_GET['city'] != "" && $x->getPrivacySetting("page.info.read") > 1}
<div class='summary'> <tr>
<b>{tr("results", $count)} {tr("showing_x_y", $page, $count)}</b> <td><span class="nobold">{_city}:</span></td>
</div> <td>{$x->getCity()}</td>
</tr>
{/if}
{if !is_null($_GET['city']) && $_GET['hometown'] != "" && $x->getPrivacySetting("page.info.read") > 1}
<tr>
<td><span class="nobold">{_hometown}:</span></td>
<td>{$x->getHometown()}</td>
</tr>
{/if}
{if !is_null($_GET['politViews']) && $_GET['politViews'] != 0 && $x->getPrivacySetting("page.info.read") > 1}
<tr>
<td><span class="nobold">{_politViews}:</span></td>
<td>{tr("politViews_".$x->getPoliticalViews())}</td>
</tr>
{/if}
{if !is_null($_GET['email']) && $_GET['email'] != "" && $x->getPrivacySetting("page.info.read") > 1}
<tr>
<td><span class="nobold">{_email}:</span></td>
<td>{$x->getContactEmail()}</td>
</tr>
{/if}
{if !is_null($_GET['telegram']) && $_GET['telegram'] != "" && $x->getPrivacySetting("page.info.read") > 1}
<tr>
<td><span class="nobold">{_telegram}:</span></td>
<td><a href="tg://resolve?domain={$x->getTelegram()}">@{$x->getTelegram()}</a></td>
</tr>
{/if}
{if !is_null($_GET['site']) && $_GET['site'] != "" && $x->getPrivacySetting("page.info.read") > 1}
<tr>
<td><span class="nobold">{_personal_website}:</span></td>
<td><a href="{$x->getWebsite()}">{$x->getWebsite()}</a></td>
</tr>
{/if}
{if !is_null($_GET['address']) && $_GET['address'] != "" && $x->getPrivacySetting("page.info.read") > 1}
<tr>
<td><span class="nobold">{_address}:</span></td>
<td>{$x->getPhysicalAddress()}</td>
</tr>
{/if}
{if $x->getPrivacySetting("page.info.read") > 1}
<tr>
<td><span class="nobold">{_pronouns}: </span></td>
<td>{$x->isFemale() ? tr("female") : ($x->isNeutral() ? tr("neutral") : tr("male"))}</td>
</tr>
<tr>
<td><span class="nobold">{_relationship}:</span></td>
<td>{$x->getLocalizedMaritalStatus()}</td>
</tr>
<tr>
<td><span class="nobold">{_registration_date}: </span></td>
<td>{$x->getRegistrationTime()}</td>
</tr>
{/if}
{/if}
<tr>
{if !empty($x->getDescription())}
{if $type != "apps"}
<td>
<span class="nobold">{_description}:</span>
</td>
{/if}
<td {if $type == "apps"}style="width:400px"{/if}>
{$x->getDescription() ?? '(' . tr("none") . ')'}
</td>
</tr>
{/if}
{if $type == "groups"}
<td>
<span class="nobold">{_size}:</span>
</td>
<td>
{tr("participants", $x->getFollowersCount())}
</td>
{/if}
</tbody>
</table>
{/block}
{include "../components/paginator.xml", conf => $paginatorConf} {block content}
</div> <style>
.comment, .post-divider
{
border:none;
}
</style>
<div style="margin-top:-7px">
{var $data = is_array($iterator) ? $iterator : iterator_to_array($iterator)}
<div class='page_wrap_content' id='search_page'> {include "../components/paginator.xml", conf => (object) [
<div n:class='page_wrap_content_main, $section == "audios" && $count > 0 ? audios_padding'> "page" => $page,
{if $count > 0} "count" => $count,
{if $section === 'users'} "amount" => sizeof($data),
<div class='search_content content def_row_content' n:foreach="$data as $dat"> "perPage" => $perPage ?? OPENVK_DEFAULT_PER_PAGE,
<table> "atBottom" => false,
<tbody> ]}
<tr>
<td valign="top">
<a href="{$dat->getURL()}">
<img src="{$dat->getAvatarUrl('tiny')}" width="75" alt="{_photo}" loading='lazy' />
</a>
</td>
<td valign="top" style="width: 100%">
<a href="{$dat->getURL()}">
<b>
<text style="overflow: hidden;">&nbsp;{$dat->getCanonicalName()}
{if $order == "rating"}
({$dat->getProfileCompletenessReport()->total}%)
{/if}
</text>
<img n:if="$dat->isVerified()"
class="name-checkmark"
src="/assets/packages/static/openvk/img/checkmark.png"
/>
</b>
{if $dat->getId() == $thisUser->getId()}
({_s_it_is_you})
{/if}
</a>
<table class="ugc-table">
<tbody>
{if $_REQUEST["order"] == "id"}
<tr>
<td><span class="nobold">ID:</span></td>
<td>{$dat->getId()}</td>
</tr>
{/if}
{if $dat->getPrivacySetting("page.info.read") > 1}
<tr>
<td><span class="nobold">{_pronouns}: </span></td>
<td>{$dat->isFemale() ? tr("female") : ($dat->isNeutral() ? tr("neutral") : tr("male"))}</td>
</tr>
<tr>
<td><span class="nobold">{_relationship}:</span></td>
<td>{$dat->getLocalizedMaritalStatus()}</td>
</tr>
<tr>
<td><span class="nobold">{_registration_date}: </span></td>
<td>{$dat->getRegistrationTime()}</td>
</tr>
{if !empty($dat->getDescription())}
<tr>
<td>
<span class="nobold">{_description}:</span>
</td>
<td>
{$dat->getDescription() ?? '(' . tr("none") . ')'}
</td>
</tr>
{/if}
{if !empty($_REQUEST["fav_mus"])}
<tr>
<td><span class="nobold">{_favorite_music}:</span></td>
<td>{$dat->getFavoriteMusic()}</td>
</tr>
{/if}
{if !empty($_REQUEST["fav_films"])}
<tr>
<td><span class="nobold">{_favorite_films}:</span></td>
<td>{$dat->getFavoriteFilms()}</td>
</tr>
{/if}
{if !empty($_REQUEST["fav_shows"])}
<tr>
<td><span class="nobold">{_favorite_shows}:</span></td>
<td>{$dat->getFavoriteShows()}</td>
</tr>
{/if}
{if !empty($_REQUEST["fav_books"])}
<tr>
<td><span class="nobold">{_favorite_books}:</span></td>
<td>{$dat->getFavoriteBooks()}</td>
</tr>
{/if}
{/if}
</tbody>
</table>
<br/>
</td>
</tr>
</tbody>
</table>
</div>
<script n:if='$count > 0 && !empty($query)'>
highlightText({$query}, '.page_wrap_content_main', ['text'])
</script>
{elseif $section === 'groups'}
<div class='search_content content def_row_content' n:foreach="$data as $dat">
<table>
<tbody>
<tr>
<td valign="top">
<a href="{$dat->getURL()}">
<img src="{$dat->getAvatarUrl('tiny')}" width="75" alt="{_photo}" loading='lazy' />
</a>
</td>
<td valign="top" style="width: 100%">
<a href="{$dat->getURL()}">
<b>
<text style="overflow: hidden;">&nbsp;{$dat->getCanonicalName()}
{if $order == "id"}
(id{$dat->getId()})
{/if}
</text>
<img n:if="$dat->isVerified()"
class="name-checkmark"
src="/assets/packages/static/openvk/img/checkmark.png"
/>
</b>
</a>
<table class="ugc-table">
<tbody>
{if !empty($dat->getDescription())}
<tr>
<td>
<span class="nobold">{_description}:</span>
</td>
<td data-highlight='_clubDesc'>
{$dat->getDescription() ?? '(' . tr("none") . ')'}
</td>
</tr>
{/if}
<td>
<span class="nobold">{_size}:</span>
</td>
<td>
{tr("participants", $dat->getFollowersCount())}
</td>
</tbody>
</table>
<br/>
</td>
</tr>
</tbody>
</table>
</div>
<script n:if='$count > 0 && !empty($query)'>
highlightText({$query}, '.page_wrap_content_main', ['text', "td[data-highlight='_clubDesc']"])
</script>
{elseif $section === 'apps'}
<div class='search_content content def_row_content' n:foreach="$data as $dat">
<table>
<tbody>
<tr>
<td valign="top">
<a href="/app{$dat->getId()}">
<img src="{$dat->getAvatarUrl('miniscule')}" width="75" alt="{_photo}" loading='lazy' />
</a>
</td>
<td valign="top" style="width: 100%">
<a href="/app{$dat->getId()}">
<b>
<text style="overflow: hidden;">
&nbsp;{$dat->getName()}
</text>
</b>
</a><br/>
<span style='margin-left: 2px;' data-highlight='_appDesc'>
{$dat->getDescription() ?? '(' . tr("none") . ')'}
</span>
</td>
</tr>
</tbody>
</table>
</div>
<script n:if='$count > 0 && !empty($query)'>
highlightText({$query}, '.page_wrap_content_main', ['text', "span[data-highlight='_appDesc']"])
</script>
{elseif $section === 'posts'}
<div class='search_content' n:foreach="$data as $dat">
{if !$dat || $dat->getWallOwner()->isHideFromGlobalFeedEnabled()}
{_closed_group_post}.
{else}
{include "../components/post.xml", post => $dat, commentSection => true, onWallOf => true}
{/if}
</div>
<script n:if='$count > 0 && !empty($query)'>
highlightText({$query}, '.page_wrap_content_main', [".post:not(.comment) > tbody > tr > td > .post-content > .text .really_text"])
</script>
{elseif $section === 'videos'}
<div class='search_content' n:foreach="$data as $dat">
{include "../components/video.xml", video => $dat}
</div>
<script n:if='$count > 0 && !empty($query)'>
highlightText({$query}, '.page_wrap_content_main', [".video_name", ".video_description"])
</script>
{elseif $section === 'audios'}
<div class='search_content' n:foreach="$data as $dat">
{include "../Audio/player.xml", audio => $dat}
</div>
<script n:if="$count > 0 && !empty($query) && empty($_REQUEST['only_performers'])">
highlightText({$query}, '.page_wrap_content_main', [".mediaInfo .performer a", ".mediaInfo .title"])
</script>
{elseif $section === 'audios_playlists'}
<div class='search_content' n:foreach="$data as $dat">
{include "../Audio/playlistListView.xml", playlist => $dat}
</div>
<script n:if="$count > 0 && !empty($query) && empty($_REQUEST['only_performers'])">
highlightText({$query}, '.page_wrap_content_main', [".playlistName", ".playlistDesc"])
</script>
{/if}
{else}
{include "../components/content_error.xml", description => tr("no_results_by_this_query")}
{/if}
</div>
<div class='page_wrap_content_options verticalGrayTabsWrapper'>
<div class="page_wrap_content_options_list verticalGrayTabs with_padding">
<a n:attr="id => $section === 'users' ? 'used'" href="/search?section=users&q={urlencode($query)}"> {_s_people}</a>
<a n:attr="id => $section === 'groups' ? 'used'" href="/search?section=groups&q={urlencode($query)}"> {_s_groups}</a>
<a n:attr="id => $section === 'posts' ? 'used'" href="/search?section=posts&q={urlencode($query)}"> {_s_posts}</a>
<a n:attr="id => $section === 'videos' ? 'used'" href="/search?section=videos&q={urlencode($query)}"> {_s_videos}</a>
<a n:attr="id => $section === 'apps' ? 'used'" href="/search?section=apps&q={urlencode($query)}"> {_s_apps}</a>
<a n:attr="id => $section === 'audios' ? 'used'" href="/search?section=audios&q={urlencode($query)}"> {_s_audios}</a>
<a n:attr="id => $section === 'audios_playlists' ? 'used'" href="/search?section=audios_playlists&q={urlencode($query)}">{_s_audios_playlists}</a>
</div>
<div class='page_search_options'>
{include searchOptions}
</div>
</div>
</div>
<div n:if='$paginatorConf->pageCount > 1' class='page_content_paginator_bottom'>
{include "../components/paginator.xml", conf => $extendedPaginatorConf}
</div>
</div>
</div>
</div> </div>
<p style="margin-left: 15px; margin-top: 0;">
<b>{tr("results", $count)}</b>
</p>
<div>
{include searchOptions}
<div class="container_gray borderup" style="float:left;width:73.3%;">
{if sizeof($data) > 0}
{if $type == "users" || $type == "groups" || $type == "apps"}
<div class="content" n:foreach="$data as $dat">
<table>
<tbody>
<tr>
<td valign="top">
<a href="{include link, x => $dat}">
{include preview, x => $dat}
</a>
</td>
<td valign="top" style="width: 100%">
{ifset infotable}
{include infotable, x => $dat}
{else}
<a href="{include link, x => $dat}">
<b>
{include name, x => $dat}
</b>
</a>
<br/>
{include description, x => $dat}
{/ifset}
</td>
<td n:ifset="actions" valign="top" class="action_links" style="width: 150px;">
{include actions, x => $dat}
</td>
</tr>
</tbody>
</table>
</div>
{elseif $type == "posts"}
<div n:foreach="$data as $dat" class="content">
{if !$dat || $dat->getTargetWall() < 0 && $dat->getWallOwner()->isHideFromGlobalFeedEnabled() || !$dat->canBeViewedBy($thisUser)}
{_closed_group_post}.
{else}
{include "../components/post.xml", post => $dat, commentSection => true, onWallOf => true}
{/if}
</div>
{elseif $type == "comments"}
<div n:foreach="$data as $dat" class="content">
{if !$dat->getTarget() || $dat->getTarget()->isDeleted()}
{_deleted_target_comment}.
{else}
{include "../components/comment.xml", comment => $dat, linkW => true}
{/if}
</div>
{elseif $type == "videos"}
{foreach $data as $dat}
<div class="content">
{include "../components/video.xml", video => $dat}
</div>
{/foreach}
{elseif $type == "audios"}
{foreach $data as $dat}
{include "../Audio/player.xml", audio => $dat}
{/foreach}
{/if}
{else}
{ifset customErrorMessage}
{include customErrorMessage}
{else}
{include "../components/nothing.xml"}
{/ifset}
{/if}
</div>
<script>
window.addEventListener("load", (event) => {
document.getElementsByClassName("container_gray")[0].style.minHeight = document.getElementsByClassName("searchOptions")[0].clientHeight+"px";
document.getElementsByClassName("searchOptions")[0].style.minHeight = document.getElementsByClassName("container_gray")[0].clientHeight-3+"px";
})
</script>
{/block} {/block}
{block searchOptions} {block searchOptions}
<div class="search_option"> <div class="searchOptions">
<div class="search_option_name"> <ul class="searchList">
<div class='search_option_name_ico'></div> <a {if $type === "users"} id="used"{/if} href="/search?type=users{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id"> {_s_people} {if $type === "users"} ({$count}){/if}</a>
{_s_order_by} <a {if $type === "groups"} id="used"{/if} href="/search?type=groups{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id"> {_s_groups} {if $type === "groups"} ({$count}){/if}</a>
</div> <a {if $type === "comments"}id="used"{/if} href="/search?type=comments{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id">{_s_comments} {if $type === "comments"}({$count}){/if}</a>
<div class="search_option_content"> <a {if $type === "posts"} id="used"{/if} href="/search?type=posts{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id"> {_s_posts} {if $type === "posts"} ({$count}){/if}</a>
<select name="order" form="search_form" data-default='id'> <a {if $type === "videos"} id="used"{/if} href="/search?type=videos{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id"> {_s_videos} {if $type === "videos"} ({$count}){/if}</a>
{if $section == "users"} <a {if $type === "apps"} id="used"{/if} href="/search?type=apps{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id"> {_s_apps} {if $type === "apps"} ({$count}){/if}</a>
<option value="id" n:attr="selected => $order == 'id'">{_s_order_by_reg_date}</option> <a {if $type === "audios"} id="used"{/if} href="/search?type=audios{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id"> {_s_audios} {if $type === "audios"} ({$count}){/if}</a>
</ul>
{if OPENVK_ROOT_CONF["openvk"]["preferences"]["commerce"]}
<option value="rating" n:attr="selected => $order == 'rating'">{_s_order_by_rating}</option> <div class="searchOption">
<div class="searchOptionName" id="n_sort" onclick="hideParams('sort')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_s_order_by}</div>
<div class="searchOptionBlock" id="s_sort">
<select name="sort" form="searcher" id="sortyor">
<option value="id" {if $_GET["sort"] == "name"}selected{/if}>{_s_order_by_id}</option>
{if $type == "users"}
<option value="name" {if $_GET["sort"] == "name"}selected{/if}>{_s_order_by_name}</option>
{if OPENVK_ROOT_CONF["openvk"]["preferences"]["commerce"]}
<option value="rating" {if $_GET["sort"] == "rating"}selected{/if}>{_s_order_by_rating}</option>
{/if}
{/if} {/if}
{elseif $section == "posts"}
<option value="id" n:attr="selected => $order == 'id'">{_s_order_by_publishing_date}</option>
{elseif $section == "audios"}
<option value="id" n:attr="selected => $order == 'id'">{_s_order_by_upload_date}</option>
{else}
<option value="id" n:attr="selected => $order == 'id'">{_s_order_by_creation_date}</option>
{/if}
{if $section == "audios" || $section == "audios_playlists"} {if $type == "audios"}
<option value="length" n:attr="selected => $order == 'length'">{_s_order_by_length}</option> <option value="length" n:attr="selected => $_GET['sort'] == 'length'">{_s_order_by_length}</option>
<option value="listens" n:attr="selected => $order == 'listens'">{_s_order_by_listens}</option> <option value="listens" n:attr="selected => $_GET['sort'] == 'listens'">{_s_order_by_listens}</option>
{/if} {/if}
</select>
<label n:if="$order != 'rating'">
<input type="checkbox" name="invert" value="1" form="search_form" n:attr="checked => $_REQUEST['invert'] == '1'">
{_s_order_invert}
</label>
</div>
</div>
<div n:if="$section == 'users'" class="search_option">
<div class="search_option_name">
<div class='search_option_name_ico'></div>
{_main}
</div>
<div class="search_option_content">
<input type="text" n:attr="value => $_REQUEST['city']" form="search_form" placeholder="{_city}" name="city">
<input type="text" n:attr="value => $_REQUEST['hometown']" form="search_form" placeholder="{_hometown}" name="hometown">
<label>
<input name="is_online" type="checkbox" n:attr="checked => $_REQUEST['is_online'] == '1'" form="search_form" value="1">
{_s_now_on_site}
</label>
</div>
</div>
<div n:if="$section == 'users'" class="search_option">
<div class="search_option_name">
<div class='search_option_name_ico'></div>
{_pronouns}
</div>
<div class="search_option_content">
<label><input type="radio" form="search_form" n:attr="checked => $_REQUEST['gender'] == 0" name="gender" value="0">{_male}</label>
<label><input type="radio" form="search_form" n:attr="checked => $_REQUEST['gender'] == 1" name="gender" value="1">{_female}</label>
<label><input type="radio" form="search_form" n:attr="checked => $_REQUEST['gender'] == 2" name="gender" value="2">{_neutral}</label>
<label><input type="radio" form="search_form" n:attr="checked => is_null($_REQUEST['gender']) || $_REQUEST['gender'] == 3" name="gender" data-default='1' value="3">{_s_any}</label>
</div>
</div>
<div n:if="$section == 'users'" n:class="search_option, !isset($_REQUEST['polit_views']) && !isset($_REQUEST['marital_status']) ? search_option_hidden">
<div class="search_option_name">
<div class='search_option_name_ico'></div>
{_s_additional}
</div>
<div class="search_option_content">
<label>
{_politViews}
<select name="polit_views" form="search_form" data-default='0'>
<option n:foreach="range(0, 9) as $i" value="{$i}" n:attr="selected => $_REQUEST['polit_views'] == $i">
{tr("politViews_".$i)}
</option>
</select> </select>
</label> <div id="invertor">
<input type="checkbox" name="invert" value="1" form="searcher" {if !is_null($_GET['invert']) && $_GET['invert'] == "1"}checked{/if}>{_s_order_invert}
</div>
</div>
</div>
<label> {if $type !== "groups" && $type !== "apps"} {* В OpenVK не сохраняется дата создания групп и приложений *}
{_relationship} <div class="searchOption">
<select name="marital_status" form="search_form" data-default='0'> <div class="searchOptionName" id="n_dates" onclick="hideParams('dates')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_s_by_date}</div>
<option n:foreach="range(0, 8) as $i" value="{$i}" n:attr="selected => $_REQUEST['marital_status'] == $i"> <div class="searchOptionBlock" id="s_dates">
{if $type != "users"}
<p id="bydate">{_s_date_before}:<br>
{else}
<p id="bydate">{_s_registered_before}:<br>
{/if}
<input type="date" name="datebefore"
form="searcher"
id="bydate"
style="width:100%"
value="{if !is_null($_GET['datebefore'])}{$_GET['datebefore']}{/if}"
min="2019-11-19"
max={date('Y-m-d')}></p>
{if $type != "users"}
<p id="bydate">{_s_date_after}:<br>
{else}
<p id="bydate">{_s_registered_after}:<br>
{/if}
<input type="date" name="dateafter"
form="searcher"
style="width:100%"
id="bydate"
value="{if !is_null($_GET['dateafter'])}{$_GET['dateafter']}{/if}"
min="2019-11-18"
max={date('Y-m-d')}></p>
</div>
</div>
{/if}
{if $type === "users"}
<div class="searchOption">
<div class="searchOptionName" id="n_main" onclick="hideParams('main')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_main}</div>
<div class="searchOptionBlock" id="s_main">
<input type="text" value="{if !is_null($_GET['status'])}{$_GET['status']}{/if}" form="searcher" placeholder="{_status}" name="status">
<input type="text" value="{if !is_null($_GET['city'])}{$_GET['city']}{/if}" form="searcher" placeholder="{_city}" name="city">
<input type="text" value="{if !is_null($_GET['hometown'])}{$_GET['hometown']}{/if}" form="searcher" placeholder="{_hometown}" name="hometown">
<input name="is_online" type="checkbox" {if !is_null($_GET['is_online']) && $_GET['is_online'] == "1"}checked{/if} form="searcher" value="1">{_s_now_on_site}
</div>
</div>
<!-- <div class="searchOption">
<div class="searchOptionName" id="n_gender" onclick="hideParams('gender')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_gender}</div>
<div class="searchOptionBlock" id="s_gender">
<p><input type="radio" form="searcher" id="gend" {if $_GET['gender'] == 0}checked{/if} name="gender" value="0">{_male}</p>
<p><input type="radio" form="searcher" id="gend1"{if $_GET['gender'] == 1}checked{/if} name="gender" value="1">{_female}</p>
<p><input type="radio" form="searcher" id="gend2"{if $_GET['gender'] == 2 || is_null($_GET['gender'])}checked{/if} name="gender" value="2">{_s_any}</p>
</div>
</div> -->
<div class="searchOption">
<div class="searchOptionName" id="n_relationship" onclick="hideParams('relationship')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{ovk_proc_strtr(tr("relationship"), 14)}</div>
<div class="searchOptionBlock" id="s_relationship">
<select name="maritalstatus" form="searcher">
<option n:foreach="range(0, 8) as $i" value="{$i}" {if $_GET['maritalstatus'] == $i}selected{/if} form="searcher">
{tr("relationship_".$i)} {tr("relationship_".$i)}
</option> </option>
</select> </select>
</label> </div>
</div> </div>
</div>
<div n:if="$section == 'videos'" class="search_option"> <div class="searchOption">
<div class="search_option_name"> <div class="searchOptionName" id="n_politViews" onclick="hideParams('politViews')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_politViews}</div>
<div class='search_option_name_ico'></div> <div class="searchOptionBlock" id="s_politViews">
{_s_main} <select name="politViews" form="searcher">
</div> <option n:foreach="range(0, 9) as $i" value="{$i}" {if $_GET['politViews'] == $i}selected{/if} form="searcher">
<div class="search_option_content"> {tr("politViews_".$i)}
<label>
<input type="checkbox" value='1' name="only_youtube" n:attr="checked => !empty($_REQUEST['only_youtube'])" form="search_form">{_s_only_youtube}
</label>
</div>
</div>
<div n:if="$section == 'audios'" class="search_option">
<div class="search_option_name">
<div class='search_option_name_ico'></div>
{_s_main}
</div>
<div class="search_option_content">
<label>
<input type="checkbox" name="only_performers" n:attr="checked => !empty($_REQUEST['only_performers'])" form="search_form">{_s_only_performers}
</label>
<label>
<input type="checkbox" name="with_lyrics" n:attr="checked => !empty($_REQUEST['with_lyrics'])" form="search_form">{_s_with_lyrics}
</label>
<label>
{_genre}
<select name='genre' form="search_form" data-default='any'>
<option n:attr="selected: empty($_REQUEST['genre'])" value="any">{_s_any_single}</option>
<option n:foreach='\openvk\Web\Models\Entities\Audio::genres as $genre' n:attr="selected: $_REQUEST['genre'] == $genre" value="{$genre}">
{$genre}
</option> </option>
</select> </select>
</label> </div>
</div> </div>
<div class="searchOption">
<div class="searchOptionName" id="n_contacts" onclick="hideParams('contacts')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_contacts}</div>
<div class="searchOptionBlock" id="s_contacts">
<input type="text" name="email" value="{if !is_null($_GET['email'])}{$_GET['email']}{/if}" form="searcher" placeholder="{_email}">
<input type="text" name="telegram" value="{if !is_null($_GET['telegram'])}{$_GET['telegram']}{/if}" form="searcher" placeholder="{_telegram}"><br id="contacts">
<input type="text" name="site" value="{if !is_null($_GET['site'])}{$_GET['site']}{/if}" form="searcher" placeholder="{_personal_website}"><br id="contacts">
<input type="text" name="address" value="{if !is_null($_GET['address'])}{$_GET['address']}{/if}" form="searcher" placeholder="{_address}">
</div>
</div>
<div class="searchOption">
<div class="searchOptionName" id="n_interests" onclick="hideParams('interests')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_interests}</div>
<div class="searchOptionBlock" id="s_interests">
<input type="text" value="{if !is_null($_GET['interests'])}{$_GET['interests']}{/if}" form="searcher" placeholder="{_interests}" name="interests">
<input type="text" value="{if !is_null($_GET['fav_mus'])}{$_GET['fav_mus']}{/if}" form="searcher" placeholder="{_favorite_music}" name="fav_mus">
<input type="text" value="{if !is_null($_GET['fav_films'])}{$_GET['fav_films']}{/if}" form="searcher" placeholder="{_favorite_films}" name="fav_films">
<input type="text" value="{if !is_null($_GET['fav_shows'])}{$_GET['fav_shows']}{/if}" form="searcher" placeholder="{_favorite_shows}" name="fav_shows">
<input type="text" value="{if !is_null($_GET['fav_books'])}{$_GET['fav_books']}{/if}" form="searcher" placeholder="{_favorite_books}" name="fav_books">
<input type="text" value="{if !is_null($_GET['fav_quote'])}{$_GET['fav_quote']}{/if}" form="searcher" placeholder="{_favorite_quotes}" name="fav_quote">
</div>
</div>
{/if}
{if $type == "audios"}
<div class="searchOption">
<div class="searchOptionName" id="n_main_audio" onclick="hideParams('main_audio')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_s_main}</div>
<div class="searchOptionBlock" id="s_main_audio">
<label><input type="checkbox" name="only_performers" n:attr="checked => !empty($_GET['only_performers'])" form="searcher">{_s_only_performers}</label><br>
<label><input type="checkbox" name="with_lyrics" n:attr="checked => !empty($_GET['with_lyrics'])" form="searcher">{_s_with_lyrics}</label>
</div>
</div>
{/if}
<input class="button" type="button" id="dnt" value="{_reset}" onclick="resetSearch()">
</div> </div>
<input class="button" id="search_reset" type="button" value="{_reset}">
{/block} {/block}

View file

@ -69,22 +69,27 @@
{else} {else}
<div class="left_small_block"> <div class="left_small_block">
<div class="avatar_block"> <div style="margin-left: auto;margin-right: auto;display: table;position:relative;" class="avatar_block" id="av">
{var $hasAvatar = !str_contains($user->getAvatarUrl('miniscule'), "/assets/packages/static/openvk/img/camera_200.png")} {var $hasAvatar = !str_contains($user->getAvatarUrl('miniscule'), "/assets/packages/static/openvk/img/camera_200.png")}
{if !is_null($thisUser) && $hasAvatar == false && $user->getId() == $thisUser->getId()}
{if $thisUser && $user->getId() == $thisUser->getId()} <a href="javascript:addAvatarImage(false)" class="text_add_image">{_add_image}</a>
<a {if $hasAvatar}style="display:none"{/if} class="add_image_text" id="add_image">{_add_image}</a> {elseif !is_null($thisUser) && $user && $hasAvatar == true && $user->getId() == $thisUser->getId()}
<div {if !$hasAvatar}style="display:none"{/if} class="avatar_controls"> <div class="avatar_controls">
<div class="avatarDelete hoverable"></div> <div class="avatarDelete">
<a id="upl" href="javascript:deleteAvatar('{$user->getAvatarPhoto()->getPrettyId()}')"><img src="/assets/packages/static/openvk/img/delete.png"/></a>
</div>
<div class="avatar_variants"> <div class="avatar_variants">
<a class="_add_image hoverable" id="add_image"><span>{_upload_new_picture}</span></a> <div class="variant">
<img src="/assets/packages/static/openvk/img/upload.png" style="margin-left:15px;height: 10px;">
<a href="javascript:addAvatarImage(false)"><p>{_upload_new_picture}</p></a>
</div>
</div> </div>
</div> </div>
{/if} {/if}
<a href="{$user->getAvatarLink()|nocheck}"> <a href="{$user->getAvatarLink()|nocheck}">
<img src="{$user->getAvatarUrl('normal')}" <img src="{$user->getAvatarUrl('normal')}"
alt="{$user->getCanonicalName()}" alt="{$user->getCanonicalName()}"
id="bigAvatar" id="thisUserAvatar"
style="width: 100%; image-rendering: -webkit-optimize-contrast;" /> style="width: 100%; image-rendering: -webkit-optimize-contrast;" />
</a> </a>
</div> </div>
@ -470,11 +475,11 @@
</tr> </tr>
<tr n:if="!is_null($user->getHometown())"> <tr n:if="!is_null($user->getHometown())">
<td class="label"><span class="nobold">{_hometown}:</span></td> <td class="label"><span class="nobold">{_hometown}:</span></td>
<td class="data"><a href="/search?section=users&q=&hometown={urlencode($user->getHometown())}">{$user->getHometown()}</a></td> <td class="data"><a href="/search?type=users&query=&hometown={urlencode($user->getHometown())}">{$user->getHometown()}</a></td>
</tr> </tr>
<tr> <tr>
<td class="label"><span class="nobold">{_politViews}:</span></td> <td class="label"><span class="nobold">{_politViews}:</span></td>
<td class="data">{var $pviews = $user->getPoliticalViews()}{_"politViews_$pviews"}</td> <td class="data"><a {if $user->getPoliticalViews() != 0}href="/search?type=users&query=&politViews={$user->getPoliticalViews()}"{/if}>{var $pviews = $user->getPoliticalViews()}{_"politViews_$pviews"}</a></td>
</tr> </tr>
<tr n:if="!is_null($user->getBirthday())"> <tr n:if="!is_null($user->getBirthday())">
<td class="label"><span class="nobold">{_birth_date}:</span></td> <td class="label"><span class="nobold">{_birth_date}:</span></td>
@ -520,7 +525,7 @@
</tr> </tr>
<tr n:if="!is_null($user->getCity())"> <tr n:if="!is_null($user->getCity())">
<td class="label"><span class="nobold">{_city}:</span></td> <td class="label"><span class="nobold">{_city}:</span></td>
<td class="data"><a href="/search?type=section&q=&city={$user->getCity()}">{$user->getCity()}</a></td> <td class="data"><a href="/search?type=users&query=&city={$user->getCity()}">{$user->getCity()}</a></td>
</tr> </tr>
<tr n:if="!is_null($user->getPhysicalAddress())"> <tr n:if="!is_null($user->getPhysicalAddress())">
<td class="label"><span class="nobold">{_address}:</span></td> <td class="label"><span class="nobold">{_address}:</span></td>
@ -538,7 +543,7 @@
{var $interests = explode(", ", $user->getInterests())} {var $interests = explode(", ", $user->getInterests())}
{foreach $interests as $interest} {foreach $interests as $interest}
<span>{$interest}</span>{if $interest != end($interests)},{/if} <a href="/search?type=users&query=&interests={urlencode($interest)}">{$interest}</a>{if $interest != end($interests)},{/if}
{/foreach} {/foreach}
</td> </td>
</tr> </tr>
@ -549,7 +554,7 @@
{var $musics = explode(", ", $user->getFavoriteMusic())} {var $musics = explode(", ", $user->getFavoriteMusic())}
{foreach $musics as $music} {foreach $musics as $music}
<a href="/search?section=audios&q={urlencode($music)}">{$music}</a>{if $music != end($musics)},{/if} <a href="/search?type=audios&query={urlencode($music)}">{$music}</a>{if $music != end($musics)},{/if}
{/foreach} {/foreach}
</td> </td>
</tr> </tr>
@ -559,7 +564,7 @@
{var $films = explode(", ", $user->getFavoriteFilms())} {var $films = explode(", ", $user->getFavoriteFilms())}
{foreach $films as $film} {foreach $films as $film}
<a href="/search?section=users&q=&fav_films={urlencode($film)}">{$film}</a>{if $film != end($films)},{/if} <a href="/search?type=users&query=&fav_films={urlencode($film)}">{$film}</a>{if $film != end($films)},{/if}
{/foreach} {/foreach}
</td> </td>
</tr> </tr>
@ -569,7 +574,7 @@
{var $shows = explode(", ", $user->getFavoriteShows())} {var $shows = explode(", ", $user->getFavoriteShows())}
{foreach $shows as $show} {foreach $shows as $show}
<a href="/search?section=users&q=&fav_shows={urlencode($show)}">{$show}</a>{if $show != end($shows)},{/if} <a href="/search?type=users&query=&fav_shows={urlencode($show)}">{$show}</a>{if $show != end($shows)},{/if}
{/foreach} {/foreach}
</td> </td>
</tr> </tr>
@ -579,7 +584,7 @@
{var $books = explode(", ", $user->getFavoriteBooks())} {var $books = explode(", ", $user->getFavoriteBooks())}
{foreach $books as $book} {foreach $books as $book}
<a href="/search?section=users&q=&fav_books={urlencode($book)}">{$book}</a>{if $book != end($books)},{/if} <a href="/search?type=users&query=&fav_books={urlencode($book)}">{$book}</a>{if $book != end($books)},{/if}
{/foreach} {/foreach}
</td> </td>
</tr> </tr>

View file

@ -33,7 +33,7 @@
{/block} {/block}
{block preview} {block preview}
<div class="video-preview" data-id="{$x->getId()}"> <div class="video-preview" id="videoOpen" data-id="{$x->getId()}">
<img src="{$x->getThumbnailURL()}" <img src="{$x->getThumbnailURL()}"
alt="{$x->getName()}" alt="{$x->getName()}"
style="max-width: 170px; max-height: 127px; margin: auto;" /> style="max-width: 170px; max-height: 127px; margin: auto;" />
@ -41,7 +41,7 @@
{/block} {/block}
{block name} {block name}
<span data-id="{$x->getId()}" style="color:unset;">{$x->getName()}</span> <span id="videoOpen" data-id="{$x->getId()}" style="color:unset;">{$x->getName()}</span>
{/block} {/block}
{block description} {block description}
@ -51,7 +51,7 @@
<span style="color: grey;">{_video_uploaded} {$x->getPublicationTime()}</span><br/> <span style="color: grey;">{_video_uploaded} {$x->getPublicationTime()}</span><br/>
<span style="color: grey;">{_video_updated} {$x->getEditTime() ?? $x->getPublicationTime()}</span> <span style="color: grey;">{_video_updated} {$x->getEditTime() ?? $x->getPublicationTime()}</span>
<p> <p>
<a href="/video{$x->getPrettyId()}" data-id="{$x->getId()}">{_view_video}</a> <a href="/video{$x->getPrettyId()}" id="videoOpen" data-id="{$x->getId()}">{_view_video}</a>
{if $x->getCommentsCount() > 0}| <a href="/video{$x->getPrettyId()}#comments">{_comments} ({$x->getCommentsCount()})</a>{/if} {if $x->getCommentsCount() > 0}| <a href="/video{$x->getPrettyId()}#comments">{_comments} ({$x->getCommentsCount()})</a>{/if}
</p> </p>
{/block} {/block}

View file

@ -9,7 +9,7 @@
{css "css/bsdn.css"} {css "css/bsdn.css"}
{css "css/dialog.css"} {css "css/dialog.css"}
{css "css/notifications.css"} {css "css/notifications.css"}
{css "css/avatar-edit.css"} {css "css/avataredit.css"}
{css "css/audios.css"} {css "css/audios.css"}
{if $isXmas} {if $isXmas}
@ -27,7 +27,7 @@
{css "css/bsdn.css"} {css "css/bsdn.css"}
{css "css/dialog.css"} {css "css/dialog.css"}
{css "css/notifications.css"} {css "css/notifications.css"}
{css "css/avatar-edit.css"} {css "css/avataredit.css"}
{css "css/audios.css"} {css "css/audios.css"}
{if $isXmas} {if $isXmas}

View file

@ -36,26 +36,21 @@
</div> </div>
</div> </div>
<div n:if="isset($thisUser) &&! ($compact ?? false)" class="post-menu"> <div n:if="isset($thisUser) &&! ($compact ?? false)" class="post-menu">
<a href="{if $correctLink}{$comment->getTargetURL()}{/if}#_comment{$comment->getId()}" class="date">{$comment->getPublicationTime()} <a href="#_comment{$comment->getId()}" class="date">{$comment->getPublicationTime()}
<span n:if="$comment->getEditTime()" class="edited editedMark">({_edited_short})</span> <span n:if="$comment->getEditTime()" class="edited editedMark">({_edited_short})</span>
</a> </a>
{if !$timeOnly} {if !$timeOnly}
&nbsp;| &nbsp;|
{if $comment->canBeDeletedBy($thisUser)} {if $comment->canBeDeletedBy($thisUser)}
<a href="/comment{$comment->getId()}/delete">{_delete}</a> <a href="/comment{$comment->getId()}/delete">{_delete}</a>&nbsp;|
{/if} {/if}
{if $comment->canBeEditedBy($thisUser)} {if $comment->canBeEditedBy($thisUser)}
| <a id="editPost" data-id="{$comment->getId()}">{_edit}</a>&nbsp;|
<a id="editPost" data-id="{$comment->getId()}">{_edit}</a>
{/if} {/if}
{if !$no_reply_button} <a class="comment-reply">{_reply}</a>
| {if $thisUser->getId() != $comment->getOwner()->getId()}
<a class="comment-reply">{_reply}</a>
{/if}
{if $thisUser->getId() != $author->getRealId()}
|
{var $canReport = true} {var $canReport = true}
<a href="javascript:reportComment()">{_report}</a> | <a href="javascript:reportComment()">{_report}</a>
{/if} {/if}
<div style="float: right; font-size: .7rem;"> <div style="float: right; font-size: .7rem;">
<a class="post-like-button" href="/comment{$comment->getId()}/like?hash={rawurlencode($csrfToken)}"> <a class="post-like-button" href="/comment{$comment->getId()}/like?hash={rawurlencode($csrfToken)}">
@ -64,11 +59,29 @@
</a> </a>
</div> </div>
{/if} {/if}
{var $target = "wall"}
{if get_class($comment->getTarget()) == "openvk\Web\Models\Entities\Note"}
{php $target = "note"}
{elseif get_class($comment->getTarget()) == "openvk\Web\Models\Entities\Post"}
{php $target = "wall"}
{elseif get_class($comment->getTarget()) == "openvk\Web\Models\Entities\Photo"}
{php $target = "photo"}
{elseif get_class($comment->getTarget()) == "openvk\Web\Models\Entities\Video"}
{php $target = "video"}
{elseif get_class($comment->getTarget()) == "openvk\Web\Models\Entities\Topic"}
{php $target = "topic"}
{/if}
<span n:if="$compact ?? false"> <span n:if="$compact ?? false">
|&nbsp;<a |&nbsp;<a
href="#_comment{$comment->getId()}" {if is_null($linkW)}
href="#_comment{$comment->getId()}"
{else}
href="{$target}{!is_null($comment->getTarget()) ? $comment->getTarget()->getPrettyId() : $comment->getOwner()->getId()}#_comment{$comment->getId()}"
{/if}
class="date" class="date"
>{$comment->getPublicationTime()}</a> >{$comment->getPublicationTime()}</a>

View file

@ -1,6 +0,0 @@
<div class='content_page_error'>
<span>
<b n:if="!empty($title)">{$title}<br><br></b>
{$description}
</span>
</div>

View file

@ -1,8 +1,8 @@
{var $space = $conf->space ?? 3} {var $space = 3}
{var $pageCount = ceil($conf->count / $conf->perPage)} {var $pageCount = ceil($conf->count / $conf->perPage)}
<div n:if="!($conf->page === 1 && $conf->count <= $conf->perPage)" n:attr="style => (!$conf->tidy ? 'padding: 8px;')"> <div n:if="!($conf->page === 1 && $conf->count <= $conf->perPage)" style="padding: 8px;">
<div n:class="paginator, ($conf->atBottom ?? false) ? paginator-at-bottom, ($conf->tidy ? 'tidy')"> <div n:class="paginator, ($conf->atBottom ?? false) ? paginator-at-bottom">
<a n:if="$conf->page > $space" n:attr="class => ($conf->page === 1 ? 'active')" href="?{http_build_query(array_merge($_GET, ['p' => 1]), 'k', '&', PHP_QUERY_RFC3986)}">&laquo;</a> <a n:if="$conf->page > $space" n:attr="class => ($conf->page === 1 ? 'active')" href="?{http_build_query(array_merge($_GET, ['p' => 1]), 'k', '&', PHP_QUERY_RFC3986)}">&laquo;</a>
{for $j = $conf->page - ($space-1); $j <= $conf->page + ($space-1); $j++} {for $j = $conf->page - ($space-1); $j <= $conf->page + ($space-1); $j++}
<a n:if="$j > 0 && $j <= $pageCount" n:attr="class => ($conf->page === $j ? 'active')" href="?{http_build_query(array_merge($_GET, ['p' => $j]), 'k', '&', PHP_QUERY_RFC3986)}">{$j}</a> <a n:if="$j > 0 && $j <= $pageCount" n:attr="class => ($conf->page === $j ? 'active')" href="?{http_build_query(array_merge($_GET, ['p' => $j]), 'k', '&', PHP_QUERY_RFC3986)}">{$j}</a>

View file

@ -3,30 +3,30 @@
<tbody> <tbody>
<tr> <tr>
<td valign="top"> <td valign="top">
<a href="/video{$video->getPrettyId()}" data-id="{$video->getId()}"> <div class="video-preview">
<div class="video-preview"> <a href="/video{$video->getPrettyId()}" id="videoOpen" data-id="{$video->getId()}">
<img src="{$video->getThumbnailURL()}" <img src="{$video->getThumbnailURL()}"
style="max-width: 170px; max-height: 127px; margin: auto;" > style="max-width: 170px; max-height: 127px; margin: auto;" >
</div> </a>
</a> </div>
</td> </td>
<td valign="top" style="width: 100%"> <td valign="top" style="width: 100%">
{ifset infotable} {ifset infotable}
{include infotable, x => $dat} {include infotable, x => $dat}
{else} {else}
<a href="/video{$video->getPrettyId()}"> <a href="/video{$video->getPrettyId()}">
<b class='video_name' {$videoModal ? "id='videoOpen'" : ''} data-id="{$video->getId()}"> <b id="videoOpen" data-id="{$video->getId()}">
{$video->getName()} {$video->getName()}
</b> </b>
</a> </a>
<br/> <br/>
<p> <p>
<span class='video_description'>{$video->getDescription() ?? ""}</span> <span>{$video->getDescription() ?? ""}</span>
</p> </p>
<span style="color: grey;">{_video_uploaded} {$video->getPublicationTime()}</span><br/> <span style="color: grey;">{_video_uploaded} {$video->getPublicationTime()}</span><br/>
<p> <p>
<a href="/video{$video->getPrettyId()}" {$videoModal ? "id='videoOpen'" : ''} data-id="{$video->getId()}">{_view_video}</a> <a href="/video{$video->getPrettyId()}" id="videoOpen" data-id="{$video->getId()}">{_view_video}</a>
{if $video->getCommentsCount() > 0}| <a href="/video{$video->getPrettyId()}#comments">{_comments} ({$video->getCommentsCount()})</a>{/if} {if $video->getCommentsCount() > 0}| <a href="/video{$video->getPrettyId()}#comments">{_comments} ({$video->getCommentsCount()})</a>{/if}
</p> </p>
{/ifset} {/ifset}

View file

@ -162,7 +162,7 @@ class Makima
$result->tiles = [ $result->tiles = [
new ThumbTile(1, 3, $wCover, $maxHeight), new ThumbTile(1, 1, $w, $h0), new ThumbTile(1, 3, $wCover, $maxHeight), new ThumbTile(1, 1, $w, $h0),
new ThumbTile(1, 1, $w, $h1), new ThumbTile(1, 1, $w, $h1),
new ThumbTile(1, 1, $w, $h2), new ThumbTile(1, 1, $w, $h1),
]; ];
} }
break; break;

View file

@ -183,8 +183,6 @@ routes:
handler: "Photos->deletePhoto" handler: "Photos->deletePhoto"
- url: "/al_avatars" - url: "/al_avatars"
handler: "User->setAvatar" handler: "User->setAvatar"
- url: "/delete_avatar"
handler: "User->deleteAvatar"
- url: "/videos{num}" - url: "/videos{num}"
handler: "Videos->list" handler: "Videos->list"
- url: "/videos/upload" - url: "/videos/upload"
@ -233,8 +231,6 @@ routes:
handler: "Group->edit" handler: "Group->edit"
- url: "/club{num}/al_avatar" - url: "/club{num}/al_avatar"
handler: "Group->setAvatar" handler: "Group->setAvatar"
- url: "/club{num}/delete_avatar"
handler: "Group->deleteAvatar"
- url: "/club{num}/backdrop" - url: "/club{num}/backdrop"
handler: "Group->editBackdrop" handler: "Group->editBackdrop"
- url: "/club{num}/stats" - url: "/club{num}/stats"

View file

@ -4,8 +4,9 @@
white-space: nowrap; white-space: nowrap;
} }
.audiosPaddingContainer { .overflowedName {
padding: 8px; position: absolute;
z-index: 99;
} }
.musicIcon { .musicIcon {
@ -14,6 +15,10 @@
cursor: pointer; cursor: pointer;
} }
.musicIcon:hover {
filter: brightness(99%);
}
.musicIcon.pressed { .musicIcon.pressed {
filter: brightness(150%); filter: brightness(150%);
} }
@ -26,15 +31,7 @@
height: 46px; height: 46px;
border-bottom: 1px solid #d8d8d8; border-bottom: 1px solid #d8d8d8;
box-shadow: 1px 0px 8px 0px rgba(34, 60, 80, 0.2); box-shadow: 1px 0px 8px 0px rgba(34, 60, 80, 0.2);
position: sticky; position: relative;
top: 0px;
z-index: 1;
}
.bigPlayer.tidy {
width: 100%;
margin-left: unset;
margin-top: unset;
} }
.bigPlayer.floating { .bigPlayer.floating {
@ -174,16 +171,11 @@
font-size: 10px; font-size: 10px;
} }
.bigPlayer .paddingLayer .trackInfo .timer .elapsedTime {
cursor: pointer;
}
.bigPlayer .paddingLayer .trackInfo .trackName { .bigPlayer .paddingLayer .trackInfo .trackName {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
width: 81%; width: 81%;
height: 13px;
display: inline-block; display: inline-block;
} }
@ -191,26 +183,11 @@
font-size: 10px; font-size: 10px;
} }
.bigPlayer .paddingLayer .trackInfo a { .bigPlayer .paddingLayer .trackInfo b:hover {
font-weight: bold;
color: black;
}
.bigPlayer .paddingLayer .trackInfo a:hover {
text-decoration: underline; text-decoration: underline;
cursor: pointer; cursor: pointer;
} }
.bigPlayer .paddingLayer .trackPanel .track .selectableTrack > div {
width: 95%;
position: relative;
}
.bigPlayer .paddingLayer .volumePanel .selectableTrack > div {
position: relative;
width:72%
}
.audioEmbed .track > .selectableTrack, .bigPlayer .selectableTrack { .audioEmbed .track > .selectableTrack, .bigPlayer .selectableTrack {
margin-top: 3px; margin-top: 3px;
width: calc(100% - 8px); width: calc(100% - 8px);
@ -237,7 +214,7 @@
.audioEntry.nowPlaying { .audioEntry.nowPlaying {
background: #606060; background: #606060;
outline: 1px solid #4f4f4f; border: 1px solid #4f4f4f;
box-sizing: border-box; box-sizing: border-box;
} }
@ -247,7 +224,6 @@
.audioEntry.nowPlaying:hover { .audioEntry.nowPlaying:hover {
background: #4e4e4e !important; background: #4e4e4e !important;
border-radius: inherit !important;
} }
.audioEntry.nowPlaying .performer a { .audioEntry.nowPlaying .performer a {
@ -270,32 +246,8 @@
color: white !important; color: white !important;
} }
.audioEntry.nowPlaying .explicitMark path { .audioEntry.nowPlaying .buttons .musicIcon, .audioEntry.nowPlaying .explicitMark {
fill: #ffffff; filter: brightness(187%) opacity(72%);
}
.audioEntry.nowPlaying .buttons .musicIcon.edit-icon {
background-position: -152px -51px;
}
.audioEntry.nowPlaying .buttons .musicIcon.download-icon {
background-position: -151px -67px;
}
.audioEntry.nowPlaying .buttons .musicIcon.add-icon {
background-position: -94px -52px;
}
.audioEntry.nowPlaying .buttons .musicIcon.report-icon {
background-position: -66px -67px;
}
.audioEntry.nowPlaying .buttons .musicIcon.remove-icon-group {
background-position: -122px -67px;
}
.audioEntry.nowPlaying .buttons .musicIcon.remove-icon {
background-position: -108px -67px;
} }
.audioEntry { .audioEntry {
@ -312,16 +264,12 @@
} }
.audioEntry .subTracks { .audioEntry .subTracks {
display: none; display: flex;
padding-bottom: 5px; padding-bottom: 5px;
padding-left: 8px; padding-left: 8px;
padding-right: 12px; padding-right: 12px;
} }
.audioEntry .subTracks.shown {
display: flex;
}
.audioEntry .playerButton .playIcon { .audioEntry .playerButton .playIcon {
background-image: url('/assets/packages/static/openvk/img/play_buttons.gif'); background-image: url('/assets/packages/static/openvk/img/play_buttons.gif');
cursor: pointer; cursor: pointer;
@ -342,45 +290,16 @@
height: 23px; height: 23px;
} }
.audioEntry .status .mediaInfo {
cursor: pointer;
display: flex;
width: 100%;
}
.overflowedName {
position: absolute;
z-index: 99;
width: 80% !important;
}
.audioEntry .status strong { .audioEntry .status strong {
color: #4C4C4C; color: #4C4C4C;
} }
.audioEmbed .track { .audioEmbed .track {
padding: 0px 0; display: none;
padding: 4px 0;
} }
.audioEmbed .track .selectableTrack { .audioEmbed .track, .audioEmbed.playing .track {
width: 100%;
}
.audioEmbed .track .selectableTrack .selectableTrackSlider {
position: relative;
width: calc(100% - 18px);
}
.audioEmbed .subTracks .lengthTrackWrapper {
width: 100%;
}
.audioEmbed .subTracks .volumeTrackWrapper {
width: 81px;
margin-left: 16px;
}
.audioEmbed.playing .track {
display: unset; display: unset;
} }
@ -390,7 +309,7 @@
} }
.audioEntry:hover .buttons { .audioEntry:hover .buttons {
display: flex; display: block;
} }
.audioEntry:hover .volume .hideOnHover { .audioEntry:hover .volume .hideOnHover {
@ -399,16 +318,11 @@
.audioEntry .buttons { .audioEntry .buttons {
display: none; display: none;
flex-direction: row-reverse;
gap: 5px;
align-items: center;
justify-content: flex-start;
width: 62px; width: 62px;
height: 20px; height: 20px;
position: absolute; position: absolute;
right: 3%; right: 3%;
top: 2px; top: 2px;
margin-top: 7px;
/* чтоб избежать заедания во время ховера кнопки добавления */ /* чтоб избежать заедания во время ховера кнопки добавления */
clip-path: inset(0 0 0 0); clip-path: inset(0 0 0 0);
} }
@ -417,21 +331,18 @@
width: 11px; width: 11px;
height: 11px; height: 11px;
float: right; float: right;
margin-right: 4px;
margin-top: 3px;
background-position: -137px -51px; background-position: -137px -51px;
} }
.audioEntry .buttons .download-icon {
width: 11px;
height: 11px;
float: right;
background-position: -136px -67px;
}
.audioEntry .buttons .add-icon { .audioEntry .buttons .add-icon {
width: 11px; width: 11px;
height: 11px; height: 11px;
float: right; float: right;
background-position: -80px -52px; background-position: -80px -52px;
margin-top: 3px;
margin-left: 2px;
} }
.audioEntry .buttons .add-icon-group { .audioEntry .buttons .add-icon-group {
@ -439,6 +350,7 @@
height: 11px; height: 11px;
float: right; float: right;
background-position: -94px -52px; background-position: -94px -52px;
margin-top: 3px;
transition: margin-right 0.1s ease-out, opacity 0.1s ease-out; transition: margin-right 0.1s ease-out, opacity 0.1s ease-out;
} }
@ -446,7 +358,9 @@
width: 12px; width: 12px;
height: 11px; height: 11px;
float: right; float: right;
background-position: -50px -67px; background-position: -67px -51px;
margin-top: 3px;
margin-right: 3px;
} }
.add-icon-noaction { .add-icon-noaction {
@ -460,17 +374,22 @@
} }
.audioEntry .buttons .remove-icon { .audioEntry .buttons .remove-icon {
margin-top: 3px;
width: 11px; width: 11px;
height: 11px; height: 11px;
margin-left: 2px;
float: right; float: right;
background-position: -108px -52px; background-position: -108px -52px;
} }
.audioEntry .buttons .remove-icon-group { .audioEntry .buttons .remove-icon-group {
margin-top: 3px;
width: 13px; width: 13px;
height: 11px; height: 11px;
float: right; float: right;
background-position: -122px -52px; background-position: -122px -52px;
margin-left: 3px;
margin-right: 3px;
} }
.audioEmbed .lyrics { .audioEmbed .lyrics {
@ -491,12 +410,12 @@
text-decoration: underline; text-decoration: underline;
} }
.audioEmbed.withdrawn .status > *, .audioEmbed.processed .playerButton > *, .audioEmbed.withdrawn .playerButton > * { .audioEmbed.withdrawn .status > *, .audioEmbed.processed .status > *, .audioEmbed.withdrawn .playerButton > *, .audioEmbed.processed .playerButton > * {
pointer-events: none; pointer-events: none;
} }
.audioEmbed.withdrawn { .audioEmbed.withdrawn {
opacity: 0.8; filter: opacity(0.8);
} }
.playlistCover img { .playlistCover img {
@ -508,56 +427,25 @@
margin-top: 14px; margin-top: 14px;
} }
.playlistBlock .playlistWrapper { .playlistContainer {
float: left; display: grid;
padding-left: 13px; grid-template-columns: repeat(3, 146px);
width:75% gap: 18px 10px;
} }
.playlistCover .profile_links .profile_link { .playlistContainer .playlistCover {
width: 100%; width: 111px;
} height: 111px;
/* playlist listview */
.playlistListView {
display: flex; display: flex;
padding: 7px; background: #c4c4c4;
gap: 9px;
cursor: pointer;
} }
.playlistListView:hover, .playlistListView .playlistCover { .playlistContainer .playlistCover img {
background: #ebebeb; max-width: 111px;
max-height: 111px;
margin: auto;
} }
.playlistListView .playlistCover img {
width: 100px;
height: 100px;
object-fit: contain;
}
.playlistListView .playlistInfo, .playlistListView .playlistInfo .playlistInfoTopPart {
display: flex;
flex-direction: column;
}
.playlistListView .playlistInfo {
gap: 2px;
overflow: hidden;
}
.playlistListView .playlistInfo .playlistName {
font-weight: 600;
line-height: 12px;
}
.playlistListView .playlistInfo .playlistMeta, .playlistListView .playlistInfo .playlistMeta span {
color: #676767;
}
/* other */
.ovk-diag-body .searchBox { .ovk-diag-body .searchBox {
background: #e6e6e6; background: #e6e6e6;
padding-top: 10px; padding-top: 10px;
@ -602,16 +490,17 @@
cursor: pointer; cursor: pointer;
} }
.playlistCover img {
cursor: pointer;
}
.explicitMark { .explicitMark {
margin-top: 2px; margin-top: 2px;
margin-left: 3px; margin-left: 3px;
width: 11px; width: 11px;
height: 11px; height: 11px;
} background: url('/assets/packages/static/openvk/img/explicit.svg');
background-repeat: no-repeat;
.explicitMark path {
fill: #828a99;
fill-opacity: .7;
} }
.audioStatus span { .audioStatus span {
@ -628,14 +517,8 @@
padding-bottom: 3px; padding-bottom: 3px;
} }
.audiosDiv {
width: 103.1%;
display: flex;
margin: 0px 0px -10px -12px;
}
/* <center> 🤣🤣🤣🤣🤣🤣🤣🤣🤣🤣*/ /* <center> 🤣🤣🤣🤣🤣🤣🤣🤣🤣🤣*/
.audiosDiv center span, .error_full_wrapper center span { .audiosDiv center span {
color: #707070; color: #707070;
margin: 120px 0px !important; margin: 120px 0px !important;
display: block; display: block;
@ -645,6 +528,15 @@
margin-left: -10px; margin-left: -10px;
} }
.playlistInfo {
display: flex;
flex-direction: column;
}
.playlistInfo .playlistName {
font-weight: 600;
}
.searchList.floating { .searchList.floating {
position: fixed; position: fixed;
z-index: 199; z-index: 199;
@ -691,13 +583,10 @@
} }
.friendsAudiosList { .friendsAudiosList {
margin-left: -7px;
margin-top: 8px; margin-top: 8px;
} }
.friendsAudiosList > a {
padding-left: 8px;
}
.friendsAudiosList .elem { .friendsAudiosList .elem {
display: flex; display: flex;
padding: 1px 1px; padding: 1px 1px;
@ -770,27 +659,3 @@
.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

@ -1,182 +0,0 @@
.avatar_block {
position: relative;
clip-path: inset(0 0 0.7% 0);
}
.avatar_block .add_image_text {
position: absolute;
font-size: 12px;
color: #2B587A;
text-align: center;
width: 100%;
left: 0px;
bottom: 30px;
}
.avatar_block .add_image_text:hover {
text-decoration: underline;
}
#temp_uploadPic {
width: 40%;
margin-left: auto;
margin-right: auto;
display: block;
}
.hoverable {
transition: all 200ms ease-in-out;
opacity: 0.6;
cursor: pointer;
}
.hoverable:hover {
opacity: 1;
}
.avatar_block *, .avatar_block .avatarDelete::before {
-webkit-transition: all 200ms ease-in-out;
-moz-transition: all 200ms ease-in-out;
-o-transition: all 200ms ease-in-out;
transition: all 200ms ease-in-out;
}
._add_image::before {
margin-top: 2px;
content: ' ';
background: url('/assets/packages/static/openvk/img/upload.png');
width: 10px;
height: 10px;
display: inline-block;
margin-left: 15px;
}
.avatarDelete {
position: absolute;
right: 0%;
background-color: rgba(0, 0, 0, 0.75);
padding: 1px 0px 4px 3px;
border-radius: 0px 0px 0px 5px;
opacity: 0;
cursor: pointer;
width: 15px;
height: 13px;
}
.avatarDelete::before {
content: ' ';
background: url('/assets/packages/static/openvk/img/upload.png');
background-position: -10px 2px;
background-repeat: no-repeat;
width: 12px;
height: 14px;
display: inline-block;
opacity: 0.6;
}
div.avatar_block:hover .avatarDelete {
opacity: 1 !important;
}
div.avatar_block:hover .avatar_variants {
opacity: 1 !important;
margin-bottom: 1px;
}
.avatar_controls .avatar_variants {
opacity:0;
position:absolute;
background-color: rgba(0, 0, 0, 0.75);
width:100%;
bottom:0;
margin-bottom:-8px;
color:white;
padding-top: 2px;
padding-bottom: 2px;
}
.avatar_controls .avatar_variants a {
opacity: 60%;
display: flex;
user-select: none;
padding: 5px 0px;
}
.avatar_controls .avatar_variants span {
color: white;
margin-left: 6px;
}
.avatar_controls .avatar_variants a:hover, .avatarDelete:hover::before {
opacity: 100%;
}
.cropper-container.moving .cropper-point {
opacity: 1;
}
.cropper-modal {
opacity: 0.7;
background-color: #000;
}
.cropper-point {
transition: opacity 200ms ease-in-out;
background-color: #fff !important;
height: 7px !important;
width: 9px !important;
opacity: 0.6;
box-shadow: black 0px 0px 2px;
}
.cropper-line {
opacity: 0;
}
.cropper-container {
width: 421px;
height: 279px;
}
.cropper-view-box {
outline: none;
outline-color: unset;
}
.cropper-image-cont {
height: 100vh;
}
.cropper-image-cont img {
max-width: 100%;
}
.cropper-image-cont .rotateButtons {
height: 20px;
margin-top: -31px;
margin-right: 5px;
width: 45px;
float: right;
position: relative;
display: flex;
padding: 3px 5px 3px 2px;
background: rgba(0,0,0,0.5);
}
.cropper-image-cont .rotateButtons div {
background-repeat: no-repeat;
}
.cropper-image-cont .rotateButtons ._rotateLeft {
background: url(/assets/packages/static/openvk/img/upload.png);
height: 20px;
width: 23px;
background-position: -23px 0px;
}
.cropper-image-cont .rotateButtons ._rotateRight {
background: url(/assets/packages/static/openvk/img/upload.png);
height: 18px;
width: 22px;
background-position: -46px 0px;
}

View file

@ -0,0 +1,88 @@
.text_add_image
{
position:absolute;
font-size:12px;
color: #2B587A;
text-align:center;
width: 100%;
left: 0px;
bottom:30px;
}
.text_add_image:hover
{
color:rgb(48, 41, 141);
}
.text_add_image, .avatarDelete img, .avatarDelete, .avatar_variants, .variant {
-webkit-transition: all 200ms ease-in-out;
-moz-transition: all 200ms ease-in-out;
-o-transition: all 200ms ease-in-out;
transition: all 200ms ease-in-out;
}
.avatarDelete
{
position:absolute;
right:0%;
background-color: rgba(0, 0, 0, 0.75);
padding: 1px 0px 4px 3px;
border-radius: 0px 0px 0px 5px;
opacity:0;
cursor:pointer;
}
.avatarDelete img
{
width:77%;
opacity:60%;
vertical-align:middle;
}
.avatarDelete img:hover
{
opacity:100%
}
div.avatar_block:hover .avatarDelete
{
opacity:1 !important;
}
div.avatar_block:hover .avatar_variants
{
opacity:1 !important;
margin-bottom:1px;
}
.avatar_variants
{
opacity:0;
position:absolute;
background-color: rgba(0, 0, 0, 0.75);
width:100%;
bottom:0;
margin-bottom:-8px;
color:white;
padding-top: 2px;
padding-bottom: 2px;
}
.variant
{
opacity:60%;
display:flex;
user-select:none;
}
.variant p
{
color:white;
margin-left: 6px;
}
.variant img
{
color:white;
margin-top: 7px;
}
.variant:hover
{
opacity:100%;
}

View file

@ -97,15 +97,16 @@ h1 {
display: inline-block; display: inline-block;
height: 29px; height: 29px;
padding: 11px 4px 0 7px; padding: 11px 4px 0 7px;
}
.header_navigation .link, .header_navigation .header_divider_stick {
background: url('../img/divider.png') no-repeat; background: url('../img/divider.png') no-repeat;
background-size: 1.5px 41px; background-size: 1.5px 41px;
} }
.page_header.search_expanded .header_navigation .header_divider_stick { .header_navigation .nodivider {
background: unset; display: inline-block;
height: 29px;
padding: 11px 4px 0 7px;
background: none;
background-size: 1.5px 41px;
} }
.header_navigation .link a { .header_navigation .link a {
@ -1851,10 +1852,6 @@ body.scrolled .toTop:hover {
margin-top: -1px; margin-top: -1px;
} }
.paginator.tidy {
float: unset;
}
.paginator-at-bottom { .paginator-at-bottom {
margin-top: -6px; margin-top: -6px;
} }
@ -1998,18 +1995,6 @@ body.scrolled .toTop:hover {
line-height: normal; line-height: normal;
} }
.summaryBar.summaryBarFlex {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.summaryBar.padding {
padding-top: 10px;
padding-bottom: 8px;
height: 23px;
}
.summaryBar .summary { .summaryBar .summary {
color: #45688E; color: #45688E;
font-weight: bold; font-weight: bold;
@ -2102,13 +2087,12 @@ table td[width="120"] {
border-radius: 2px; border-radius: 2px;
} }
.mb_tab div, .mb_tab > a { .mb_tab div {
padding: 5px 9px; padding: 5px 9px;
display: block;
} }
.mb_tab#active { .mb_tab#active {
background-color: #606060; background-color: #898989;
} }
.mb_tab#active a { .mb_tab#active a {
@ -2514,332 +2498,159 @@ a.poll-retract-vote {
display: none; display: none;
} }
/* Da search */ .searchOptions {
overflow: hidden;
/* Header part */ width:25.5%;
border-top:1px solid #E5E7E6;
.header_navigation #search_box { float:right;
display: inline-block; scrollbar-width: none;
height: 29px; font-size:12px;
padding: 11px 4px 0 7px; background-color:#f7f7f7;
margin-right: -7px;
} }
.header_navigation #search_box input[type='search'] { .searchBtn {
height: 20px;
background: url('/assets/packages/static/openvk/img/search_icon.png') no-repeat 3px 4px;
background-color: #fff;
padding-left: 18px;
width: 120px;
}
.header_navigation #search_box input[type='search']::-webkit-search-cancel-button {
display: none;
}
.header_navigation #search_box #search_box_fr form, .header_navigation #search_box #search_box_fr #search_and_one_more_wrapper {
display: flex;
}
.header_navigation #search_box #searchBoxFastTips {
display: none;
position: absolute;
background: #fff;
border: 1px solid #d8d8d8;
border-top: unset;
margin-top: -1px;
box-shadow: 2px 3px 4px -1px rgba(34, 60, 80, 0.2);
}
.header_navigation #search_box #searchBoxFastTips a {
display: flex;
flex-direction: row;
gap: 6px;
padding: 5px;
cursor: pointer;
}
.header_navigation #search_box #searchBoxFastTips a b, .header_navigation #search_box #searchBoxFastTips a span {
display: block;
text-transform: initial;
line-height: 12px;
}
.header_navigation #search_box #searchBoxFastTips a:hover, .header_navigation #search_box #searchBoxFastTips a:focus {
background: #f3f3f3;
}
.header_navigation #search_box #searchBoxFastTips a .search_tip_info_block {
display: flex;
justify-content: center;
flex-direction: column;
align-items: baseline;
gap: 4px;
}
.header_navigation #search_box #searchBoxFastTips a img {
width: 33px;
height: 33px;
object-fit: cover;
}
.page_header.search_expanded .header_navigation #search_box #searchBoxFastTips.shown {
display: flex;
flex-direction: column;
z-index: 2;
}
.page_header.search_expanded .link {
display: none;
}
.page_header.search_expanded #search_and_one_more_wrapper {
width: 627px;
position: relative;
}
/* не говновёрстка, а пиксель-пёрфект) */
.page_header.search_expanded.search_expanded_at_all #search_and_one_more_wrapper {
width: 547px;
}
.page_header.search_expanded #search_box input[type='search'] {
width: 100%;
}
.header_navigation #search_box select[name='section'], .header_navigation #search_box .search_box_button {
display: none;
}
.page_header.search_expanded select[name='section'] {
display: inline-block !important;
}
.page_header.search_expanded_at_all .search_box_button {
display: inline-block !important;
}
.page_header select[name='section'] {
width: auto;
height: 20px;
position: absolute;
padding: 0px 0px;
right: 0;
text-align: right;
border-left: 0px;
background: transparent;
}
.header_navigation #search_box .search_box_button {
border: solid 1px #575757; border: solid 1px #575757;
background-color: #696969; background-color: #696969;
color: #ffffff; color:white;
padding: 1px 0px 1px 0px; margin-left: -11px;
width: 80px; padding-bottom:2px;
width:80px;
cursor: pointer; cursor: pointer;
box-shadow: 0px 2px 0px 0px rgba(255, 255, 255, 0.18) inset; box-shadow: 0px 2px 0px 0px rgba(255, 255, 255, 0.18) inset;
margin-top: 1px;
} }
.header_navigation #search_box .search_box_button span { .searchBtn:active {
color: white;
font-weight: 600;
font-size: 12px;
}
.header_navigation #search_box .search_box_button:active {
border: solid 1px #666666; border: solid 1px #666666;
background-color: #696969; background-color: #696969;
color:white; color:white;
box-shadow: 0px -2px 0px 0px rgba(255, 255, 255, 0.18) inset; box-shadow: 0px -2px 0px 0px rgba(255, 255, 255, 0.18) inset;
} }
.searchList {
list-style: none;
user-select: none;
padding-left:0px;
}
.searchList #used {
margin-left:0px;
color: white !important;
padding:2px;
padding-top:5px;
padding-bottom:5px;
border: solid 0.125rem #4F4F4F;
background: #606060;
margin-bottom:2px;
padding-left:9px;
width:87%;
}
.searchList #used a {
color: white;
}
.sr:focus {
outline:none;
}
.searchHide { .searchHide {
padding-right: 5px; padding-right: 5px;
} }
/* Search layout */ .searchList li, .searchList a
#search_page { {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.page_content_paginator_bottom {
background: #f7f7f7;
border-top: 1px solid #d8d8d8;
padding: 8px 8px;
display: flex;
justify-content: right;
}
.page_wrap_content_main {
padding: 3px 3px;
width: 74%;
}
.page_wrap_content_main.audios_padding {
padding: 8px 8px;
}
.page_wrap_content_main .def_row_content {
border-bottom: #ECECEC solid 1px;
padding: 3px 1px;
}
.page_wrap_content_main .def_row_content:first-of-type {
padding: 0px 1px 3px 1px;
}
.page_wrap_content_main .search_content:first-of-type .post {
border-top: unset;
padding-top: unset;
}
.page_wrap_content_main .search_content:last-of-type .post, .page_wrap_content_main .def_row_content:last-of-type {
border-bottom: unset;
padding-bottom: unset;
}
.verticalGrayTabsWrapper {
width: 158px;
border-top: 1px solid #E5E7E6;
border-left: 1px solid #d8d8d8;
scrollbar-width: none;
font-size: 12px;
background-color:#f7f7f7;
}
.searchList, .verticalGrayTabs {
list-style: none;
user-select: none;
padding-left: 0px;
display: flex;
flex-direction: column;
gap: 1px;
}
.searchList hr, .verticalGrayTabs hr {
width: 153px;
margin-left: 0px;
margin-top: 6px;
}
.verticalGrayTabs.with_padding, .verticalGrayTabs > .with_padding {
padding: 4px 4px 4px 4px;
}
.searchList #used, .verticalGrayTabs #used {
color: #ffffff !important;
padding: 5px 9px 5px 9px;
border: solid 0.125rem #4F4F4F;
background: #606060;
}
.searchList #used a, .verticalGrayTabs #used a {
color: white;
}
.searchList li, .searchList a, .verticalGrayTabs a {
display: block; display: block;
font-size: 12px; margin-left:0px;
color: #2B587A !important; color: #2B587A !important;
cursor: pointer; cursor:pointer;
padding: 5px 9px 5px 9px; padding:2px;
padding-top:5px;
padding-bottom:5px;
margin-bottom:2px;
padding-left:9px;
} }
.searchList a:hover, .verticalGrayTabs a:hover { .searchList li a {
min-width:100%;
}
.searchList a {
min-width: 88%;
}
.searchList a:hover {
margin-left: 0px; margin-left: 0px;
color: #2B587A !important; color: #2B587A !important;
background: #ebebeb; background: #ebebeb;
padding: 2px;
padding-top: 5px;
padding-bottom: 5px;
margin-bottom: 2px;
padding-left: 9px;
width: 89.9%;
} }
.highlight { .whatFind {
background: #ffea6d; color:rgb(128, 128, 128);
border-bottom: 1px solid #c7c727; background:none;
font-weight: bolder; border:none;
padding: 0px 1px; position:absolute;
width:150px;
cursor:pointer;
right:80px;
text-align:right;
margin-top: 0.5px;
} }
/* Options */ .searchOptionName {
cursor:pointer;
.page_wrap_content .page_search_options {
padding: 0px 4px 4px 4px;
}
.page_wrap_content .page_search_options .search_option {
user-select: none;
}
.page_wrap_content .page_search_options .search_option .search_option_name_ico {
width: 9px;
height: 8px;
display: inline-block;
background-repeat: no-repeat;
background: url('/assets/packages/static/openvk/img/arrows.png');
}
.page_wrap_content .page_search_options .search_option.search_option_hidden .search_option_name_ico {
background-position: -9px 0px;
}
.page_wrap_content .page_search_options .search_option.search_option_hidden .search_option_content {
display: none;
}
.page_wrap_content .page_search_options .search_option .search_option_name {
cursor: pointer;
background-color: #EAEAEA; background-color: #EAEAEA;
padding: 5px 5px 5px 5px; padding-left:5px;
padding-top:5px;
padding-bottom:5px;
width: 90%;
font-weight: 600; font-weight: 600;
color: #585858; color: #585858;
border-bottom: 2px solid #E4E4E4; border-bottom: 2px solid #E4E4E4;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
} }
.page_wrap_content .page_search_options .search_option .search_option_content { .searchOption {
user-select: none;
}
.searchOptionBlock
{
margin-top: -5px; margin-top: -5px;
padding-top: 10px; padding-top:10px;
padding-bottom: 6px; max-width:92%;
padding-bottom:6px;
} }
.page_wrap_content .page_search_options .search_option .search_option_content label { .searchOptionBlock select
display: block; {
padding-left:7px;
padding-top:3px;
padding-bottom:3px;
cursor:pointer;
} }
.page_wrap_content .page_search_options .search_option .search_option_content select { .searchOptionBlock input[type=text], input[type=date]
padding-left: 3px; {
padding-top: 3px; margin-bottom:5px;
padding-bottom: 3px;
width: 100%;
} }
.page_wrap_content .page_search_options #search_reset { .borderup
margin-top: 5px; {
border-top:1px solid #E5E7E6;
} }
.page_wrap_content .page_search_options .search_option .search_option_content input[type=text], .page_wrap_content .page_search_options .search_option .search_option_content input[type=date] { #searchInput
margin-bottom: 5px; {
transition: .3s linear;
} }
.content_page_error {
background: white;
border: #DEDEDE solid 1px;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.content_page_error span {
color: #707070;
display: block;
}
/* Da search end. */
#standaloneCommentBox { #standaloneCommentBox {
position: sticky; position: sticky;
top: 0; top: 0;
@ -2857,6 +2668,52 @@ a.poll-retract-vote {
width: 100%; width: 100%;
} }
.searchTips
{
position: absolute;
background: white;
padding-left: 6px;
padding-right: 6px;
padding-bottom: 6px;
border: 1px solid #C0CAD5;
border-top: 0px;
width: fit-content;
z-index: 666666;
margin-top: -2px;
}
.searchTips td
{
color: black;
padding: 3px;
font-weight: lighter;
position:relative;
}
.searchTips td .desq
{
margin-top: -9px;
}
.restip td a:hover
{
color: black;
font-weight: lighter;
text-decoration: none;
}
.searchTips .restip
{
padding-right: 10px;
cursor: pointer;
user-select: none;
}
.searchTips .restip:hover
{
background: rgb(236, 235, 235);
}
.attachment_note_icon { .attachment_note_icon {
max-width: 9px; max-width: 9px;
} }
@ -3231,6 +3088,12 @@ hr {
height: 1px; height: 1px;
} }
.searchList hr {
width: 153px;
margin-left: 0px;
margin-top: 6px;
}
.showMore, .showMoreAudiosPlaylist { .showMore, .showMoreAudiosPlaylist {
width: 100%; width: 100%;
text-align: center; text-align: center;
@ -3248,54 +3111,3 @@ hr {
background-repeat: no-repeat !important; background-repeat: no-repeat !important;
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;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 219 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
Web/static/img/delete.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 B

BIN
Web/static/img/hide.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 B

BIN
Web/static/img/show.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 923 B

After

Width:  |  Height:  |  Size: 165 B

View file

@ -313,14 +313,10 @@ class bigPlayer {
}) })
u(".bigPlayer .trackInfo b").on("click", (e) => { u(".bigPlayer .trackInfo b").on("click", (e) => {
window.location.assign(`/search?q=${e.currentTarget.innerHTML}&section=audios&only_performers=on`) window.location.assign(`/search?query=${e.currentTarget.innerHTML}&type=audios&only_performers=on`)
}) })
u(document).on("keydown", (e) => { u(document).on("keydown", (e) => {
if(document.activeElement.closest('.page_header')) {
return
}
if(["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", " "].includes(e.key)) { if(["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", " "].includes(e.key)) {
if(document.querySelector(".ovk-diag-cont") != null) if(document.querySelector(".ovk-diag-cont") != null)
return return
@ -353,10 +349,6 @@ class bigPlayer {
}) })
u(document).on("keyup", (e) => { u(document).on("keyup", (e) => {
if(document.activeElement.closest('.page_header')) {
return
}
if([87, 65, 83, 68, 82, 77].includes(e.keyCode)) { if([87, 65, 83, 68, 82, 77].includes(e.keyCode)) {
if(document.querySelector(".ovk-diag-cont") != null) if(document.querySelector(".ovk-diag-cont") != null)
return return
@ -544,8 +536,7 @@ class bigPlayer {
} }
this.nodes["thisPlayer"].querySelector(".trackInfo span").innerHTML = escapeHtml(obj.name) this.nodes["thisPlayer"].querySelector(".trackInfo span").innerHTML = escapeHtml(obj.name)
this.nodes["thisPlayer"].querySelector(".trackInfo a").innerHTML = escapeHtml(obj.performer) this.nodes["thisPlayer"].querySelector(".trackInfo b").innerHTML = escapeHtml(obj.performer)
this.nodes["thisPlayer"].querySelector(".trackInfo a").href = `/search?query=&section=audios&order=listens&only_performers=on&q=${encodeURIComponent(obj.performer.escapeHtml())}`
this.nodes["thisPlayer"].querySelector(".trackInfo .time").innerHTML = fmtTime(obj.length) this.nodes["thisPlayer"].querySelector(".trackInfo .time").innerHTML = fmtTime(obj.length)
this.tracks["currentTrack"] = obj this.tracks["currentTrack"] = obj
@ -653,10 +644,34 @@ document.addEventListener("DOMContentLoaded", function() {
let type = context.dataset.type let type = context.dataset.type
let entity = context.dataset.entity let entity = context.dataset.entity
window.player = new bigPlayer(type, entity, context.dataset.page) window.player = new bigPlayer(type, entity, context.dataset.page)
let bigplayer = document.querySelector('.bigPlayerDetector')
let bigPlayerObserver = new IntersectionObserver(entries => {
entries.forEach(x => {
if(x.isIntersecting) {
document.querySelector('.bigPlayer').classList.remove("floating")
//document.querySelector('.searchOptions .searchList').classList.remove("floating")
document.querySelector('.bigPlayerDetector').style.marginTop = "0px"
} else {
//document.querySelector('.searchOptions .searchList').classList.add("floating")
document.querySelector('.bigPlayer').classList.add("floating")
document.querySelector('.bigPlayerDetector').style.marginTop = "46px"
}
});
}, {
root: null,
rootMargin: "0px",
threshold: 0
});
if(bigplayer != null)
bigPlayerObserver.observe(bigplayer);
} }
$(document).on("mouseover mouseleave", `.audioEntry .mediaInfo`, (e) => { $(document).on("mouseover mouseleave", `.audioEntry .mediaInfo`, (e) => {
const info = e.currentTarget.closest(".mediaInfo") const info = e.currentTarget.closest(".mediaInfo")
const overfl = info.querySelector(".info")
if(e.originalEvent.type == "mouseleave" || e.originalEvent.type == "mouseout") { if(e.originalEvent.type == "mouseleave" || e.originalEvent.type == "mouseout") {
info.classList.add("noOverflow") info.classList.add("noOverflow")
@ -750,15 +765,12 @@ function initPlayer(id, keys, url, length) {
playButton.removeClass("paused") playButton.removeClass("paused")
document.querySelector('link[rel="icon"], link[rel="shortcut icon"]').setAttribute("href", "/assets/packages/static/openvk/img/favicons/favicon24_playing.png") document.querySelector('link[rel="icon"], link[rel="shortcut icon"]').setAttribute("href", "/assets/packages/static/openvk/img/favicons/favicon24_playing.png")
} }
u('.subTracks').nodes.forEach(el => {
el.classList.remove('shown')
})
u(`#audioEmbed-${ id} .subTracks`).addClass('shown')
if(!$(`#audioEmbed-${ id}`).hasClass("havePlayed")) { if(!$(`#audioEmbed-${ id}`).hasClass("havePlayed")) {
$(`#audioEmbed-${ id}`).addClass("havePlayed") $(`#audioEmbed-${ id}`).addClass("havePlayed")
$(`#audioEmbed-${ id} .track`).toggle()
$.post(`/audio${playerObject.dataset.realid}/listen`, { $.post(`/audio${playerObject.dataset.realid}/listen`, {
hash: u("meta[name=csrf]").attr("value") hash: u("meta[name=csrf]").attr("value")
}); });
@ -766,14 +778,14 @@ function initPlayer(id, keys, url, length) {
}; };
const hideTracks = () => { const hideTracks = () => {
$(`#audioEmbed-${ id} .track`).removeClass('shown') $(`#audioEmbed-${ id} .track`).toggle()
$(`#audioEmbed-${ id}`).removeClass("havePlayed") $(`#audioEmbed-${ id}`).removeClass("havePlayed")
} }
u(audio).on("play", playButtonImageUpdate); u(audio).on("play", playButtonImageUpdate);
u(audio).on(["pause", "suspended"], playButtonImageUpdate); u(audio).on(["pause", "suspended"], playButtonImageUpdate);
u(audio).on("ended", (e) => { u(audio).on("ended", (e) => {
let thisPlayer = playerObject let thisPlayer = e.target.closest(".audioEmbed")
let nextPlayer = null let nextPlayer = null
if(thisPlayer.closest(".attachment") != null) { if(thisPlayer.closest(".attachment") != null) {
try { try {
@ -783,10 +795,6 @@ function initPlayer(id, keys, url, length) {
try { try {
nextPlayer = thisPlayer.closest(".audio").nextElementSibling.querySelector(".audioEmbed") nextPlayer = thisPlayer.closest(".audio").nextElementSibling.querySelector(".audioEmbed")
} catch(e) {return} } catch(e) {return}
} else if(thisPlayer.closest(".search_content") != null) {
try {
nextPlayer = thisPlayer.closest(".search_content").nextElementSibling.querySelector(".audioEmbed")
} catch(e) {return}
} else { } else {
nextPlayer = thisPlayer.nextElementSibling nextPlayer = thisPlayer.nextElementSibling
} }
@ -804,13 +812,7 @@ function initPlayer(id, keys, url, length) {
hideTracks() hideTracks()
}) })
u(`#audioEmbed-${ id} .lengthTrack > div`).on("click mouseup mousemove", (e) => { u(`#audioEmbed-${ id} .lengthTrack > div`).on("click", (e) => {
if(e.type == "mousemove") {
let buttonsPresseed = _bsdnUnwrapBitMask(e.buttons)
if(!buttonsPresseed[0])
return;
}
let rect = document.querySelector("#audioEmbed-" + id + " .selectableTrack").getBoundingClientRect(); let rect = document.querySelector("#audioEmbed-" + id + " .selectableTrack").getBoundingClientRect();
const width = e.clientX - rect.left; const width = e.clientX - rect.left;
const time = Math.ceil((width * length) / (rect.right - rect.left)); const time = Math.ceil((width * length) / (rect.right - rect.left));
@ -830,7 +832,7 @@ function initPlayer(id, keys, url, length) {
const width = e.clientX - rect.left; const width = e.clientX - rect.left;
const volume = (width * 1) / (rect.right - rect.left); const volume = (width * 1) / (rect.right - rect.left);
audio.volume = Math.max(0, volume); audio.volume = volume;
}); });
audio.volume = localStorage.volume ?? 0.75 audio.volume = localStorage.volume ?? 0.75
@ -897,7 +899,7 @@ $(document).on("click", ".musicIcon.edit-icon", (e) => {
if(response.success) { if(response.success) {
let perf = player.querySelector(".performer a") let perf = player.querySelector(".performer a")
perf.innerHTML = escapeHtml(response.new_info.performer) perf.innerHTML = escapeHtml(response.new_info.performer)
perf.setAttribute("href", "/search?q=&section=audios&order=listens&only_performers=on&q="+response.new_info.performer) perf.setAttribute("href", "/search?query=&type=audios&sort=id&only_performers=on&query="+response.new_info.performer)
e.target.setAttribute("data-performer", escapeHtml(response.new_info.performer)) e.target.setAttribute("data-performer", escapeHtml(response.new_info.performer))
@ -963,29 +965,28 @@ $(document).on("click", ".musicIcon.edit-icon", (e) => {
u(".ovk-diag-body #_fullyDeleteAudio").on("click", (e) => { u(".ovk-diag-body #_fullyDeleteAudio").on("click", (e) => {
u("body").removeClass("dimmed"); u("body").removeClass("dimmed");
u(".ovk-diag-cont").remove();
document.querySelector("html").style.overflowY = "scroll" document.querySelector("html").style.overflowY = "scroll"
MessageBox(tr('confirm'), tr('confirm_deleting_audio'), [tr('yes'), tr('no')], [() => { u(".ovk-diag-cont").remove();
$.ajax({
type: "POST", $.ajax({
url: `/audio${id}/action?act=delete`, type: "POST",
data: { url: `/audio${id}/action?act=delete`,
hash: u("meta[name=csrf]").attr("value") data: {
}, hash: u("meta[name=csrf]").attr("value")
success: (response) => { },
if(response.success) success: (response) => {
u(player).remove() if(response.success)
else u(player).remove()
fastError(response.flash.message) else
} fastError(response.flash.message)
}); }
}, () => {Function.noop}]) });
}) })
}) })
$(document).on("click", ".title.withLyrics", (e) => { $(document).on("click", ".title.withLyrics", (e) => {
const parent = e.currentTarget.closest(".audioEmbed") let parent = e.currentTarget.closest(".audioEmbed")
parent.querySelector(".lyrics").classList.toggle("showed") parent.querySelector(".lyrics").classList.toggle("showed")
}) })
@ -993,12 +994,7 @@ $(document).on("click", ".title.withLyrics", (e) => {
$(document).on("click", ".musicIcon.remove-icon", (e) => { $(document).on("click", ".musicIcon.remove-icon", (e) => {
e.stopImmediatePropagation() e.stopImmediatePropagation()
const id = e.currentTarget.dataset.id let id = e.currentTarget.dataset.id
if(e.detail > 1 || e.altKey) {
const player = e.target.closest('.audioEmbed')
player.querySelector('.add-icon-group').click()
return
}
let formdata = new FormData() let formdata = new FormData()
formdata.append("hash", u("meta[name=csrf]").attr("value")) formdata.append("hash", u("meta[name=csrf]").attr("value"))
@ -1035,7 +1031,7 @@ $(document).on("click", ".musicIcon.remove-icon-group", (e) => {
e.stopImmediatePropagation() e.stopImmediatePropagation()
let id = e.currentTarget.dataset.id let id = e.currentTarget.dataset.id
let formdata = new FormData() let formdata = new FormData()
formdata.append("hash", u("meta[name=csrf]").attr("value")) formdata.append("hash", u("meta[name=csrf]").attr("value"))
formdata.append("club", e.currentTarget.dataset.club) formdata.append("club", e.currentTarget.dataset.club)
@ -1062,218 +1058,59 @@ $(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 current_tab = 'club'; let body = `
const id = Number(ev.target.dataset.id) ${tr("what_club_add")}
const body = ` <div style="margin-top: 4px;">
<div id='_addAudioAdditional'> <select id="addIconsWindow" style="width: 59%;"></select>
<div id='_tabs'> <input name="addButton" type="button" class="button" value="${tr("add")}">
<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])
MessageBox(tr("add_audio"), body, [tr("cancel"), tr("add")], [Function.noop, () => { document.querySelector(".ovk-diag-body").style.padding = "11px"
const ids = []
u('#_content .entity_vertical_list_item').nodes.forEach(item => { if(window.openvk.writeableClubs == null) {
const _checkbox = item.querySelector(`input[type='checkbox'][name='add_to']`) try {
if(_checkbox.checked) { window.openvk.writeableClubs = await API.Groups.getWriteableClubs()
ids.push(item.dataset.id) } catch (e) {
} 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
}
} }
switchTab(current_tab) window.openvk.writeableClubs.forEach(el => {
document.querySelector("#addIconsWindow").insertAdjacentHTML("beforeend", `
u("#_addAudioAdditional").on("click", ".mb_tab a", async (e) => { <option value="${el.id}">${ovk_proc_strtr(el.name, 20)}</option>
await switchTab(u(e.target).closest('.mb_tab').attr('data-name')) `)
}) })
u("#_addAudioAdditional").on("click", "input[name='add_to']", async (e) => { $(".ovk-diag-body").on("click", "input[name='addButton']", (e) => {
if(u(`input[name='add_to']:checked`).length > 10) { $.ajax({
e.preventDefault() type: "POST",
} 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 let id = e.currentTarget.dataset.id
if(e.detail > 1 || e.altKey) {
const player = e.target.closest('.audioEmbed')
player.querySelector('.add-icon-group').click()
return
}
let formdata = new FormData() let formdata = new FormData()
formdata.append("hash", u("meta[name=csrf]").attr("value")) formdata.append("hash", u("meta[name=csrf]").attr("value"))
@ -1475,7 +1312,7 @@ $(document).on("click", "#_audioAttachment", (e) => {
}) })
}) })
$(document).on("click", ".audioEmbed.processed .playerButton", (e) => { $(document).on("click", ".audioEmbed.processed", (e) => {
MessageBox(tr("error"), tr("audio_embed_processing"), [tr("ok")], [Function.noop]) MessageBox(tr("error"), tr("audio_embed_processing"), [tr("ok")], [Function.noop])
}) })

View file

@ -1,190 +0,0 @@
u(`#search_box form input[type="search"]`).on('focus', (e) => {
u('.page_header').addClass('search_expanded')
})
u(`#search_box form input[type="search"]`).on('blur', (e) => {
if(window.openvk.at_search) {
return
}
setTimeout(() => {
if(document.activeElement.closest('.page_header')) {
return
}
u('.page_header').removeClass('search_expanded')
}, 4000)
})
u(document).on('click', '.search_option_name', (e) => {
const target = e.target.closest('.search_option')
// 🤪
$(target.querySelector('.search_option_content')).slideToggle(250, "swing");
setTimeout(() => {
u(target).toggleClass('search_option_hidden')
}, 250)
})
u(document).on('click', '#search_reset', (e) => {
u(`.page_search_options input[type='text']`).nodes.forEach(inp => {
inp.value = ''
})
u(`.page_search_options input[type='checkbox']`).nodes.forEach(chk => {
chk.checked = false
})
u(`.page_search_options input[type='radio']`).nodes.forEach(rad => {
if(rad.dataset.default) {
rad.checked = true
return
}
rad.checked = false
})
u(`.page_search_options select`).nodes.forEach(sel => {
sel.value = sel.dataset.default
})
})
u(`#search_box input[type='search']`).on('input', async (e) => {
if(window.openvk.at_search) {
return
}
const query = u(`#search_box input[type='search']`).nodes[0].value
await new Promise(r => setTimeout(r, 1000));
const current_query = u(`#search_box input[type='search']`).nodes[0].value
const section = u(`#search_box select[name='section']`).nodes[0].value
let results = null
if(/*query.length < 2 || */query != current_query || ['users', 'groups', 'videos', 'audios_playlists'].indexOf(section) == -1) {
return
}
console.info('Ok, getting tips.')
switch(section) {
case 'users':
results = await fetch(`/method/users.search?auth_mechanism=roaming&q=${query}&count=10&sort=4&fields=photo_50,status,nickname`)
break
case 'groups':
results = await fetch(`/method/groups.search?auth_mechanism=roaming&q=${query}&count=10&sort=4&fields=photo_50,description`)
break
case 'videos':
results = await fetch(`/method/video.search?auth_mechanism=roaming&q=${query}&count=10&sort=4&extended=1`)
break
case 'audios_playlists':
results = await fetch(`/method/audio.searchAlbums?auth_mechanism=roaming&query=${query}&limit=10`)
break
}
json_result = await results.json()
if(!json_result || json_result.error) {
console.error(json_result.error)
return
}
json_result = json_result.response
if(json_result.count < 1) {
console.info('No tips available.')
return
}
switch(section) {
case 'users':
json_result['items'].forEach(item => {
item['name'] = `${item['first_name']}${item['nickname'] ? ` (${item['nickname']})` : ''} ${item['last_name']}`
item['description'] = item['status']
item['url'] = '/id' + item['id']
item['preview'] = item['photo_50']
})
break
case 'groups':
json_result['items'].forEach(item => {
item['url'] = '/club' + item['id']
item['preview'] = item['photo_50']
})
break
case 'audios_playlists':
json_result['items'].forEach(item => {
item['name'] = item['title']
item['url'] = '/playlist' + item['owner_id'] + '_' + item['id']
item['preview'] = item['cover_url']
})
break
case 'videos':
const profiles = json_result['profiles']
const groups = json_result['groups']
json_result['items'].forEach(item => {
item['name'] = item['title']
item['url'] = `/video${item['owner_id']}_${item['id']}`
item['preview'] = item['image'][0]['url']
if(item['owner_id'] > 0) {
const profile = profiles.find(prof => prof.id == item['owner_id'])
if(!profile) { return }
item['description'] = profile['first_name'] + ' ' + profile['last_name']
} else {
const group = groups.find(grou => grou.id == Math.abs(item['owner_id']))
if(!group) { return }
item['description'] = group['name']
}
})
break
}
u('#searchBoxFastTips').addClass('shown')
u('#searchBoxFastTips').html('')
json_result.items.forEach(item => {
u('#searchBoxFastTips').append(`
<a href='${item['url']}'>
<img src='${item['preview']}' class='search_tip_preview_block'>
<div class='search_tip_info_block'>
<b>${ovk_proc_strtr(item['name'].escapeHtml(), 50)}</b>
<span>${ovk_proc_strtr((item['description'] ?? '').escapeHtml(), 60)}</span>
</div>
</a>
`)
})
})
u(document).on('keydown', `#search_box input[type='search'], #searchBoxFastTips a`, (e) => {
const u_tips = u('#searchBoxFastTips a')
if(u_tips.length < 1) {
return
}
const focused = u('#searchBoxFastTips a:focus').nodes[0]
// up
switch(e.keyCode) {
case 38:
e.preventDefault()
if(!focused) {
u_tips.nodes[0].focus()
return
}
if(focused.previousSibling) {
focused.previousSibling.focus()
}
break
// down
case 40:
e.preventDefault()
if(!focused) {
u_tips.nodes[0].focus()
return
}
if(focused.nextSibling) {
focused.nextSibling.focus()
} else {
u_tips.nodes[0].focus()
}
break
}
})

View file

@ -279,7 +279,7 @@ function OpenMiniature(e, photo, post, photo_id, type = "post") {
tempDetailsSection[index] = element.innerHTML; tempDetailsSection[index] = element.innerHTML;
if(index == imagesIndex) { if(index == imagesIndex) {
u(".ovk-photo-details").last().innerHTML = element.innerHTML ?? ''; u(".ovk-photo-details").last().innerHTML = element.innerHTML;
} }
document.querySelectorAll(".ovk-photo-details .bsdn").forEach(bsdnInitElement) document.querySelectorAll(".ovk-photo-details .bsdn").forEach(bsdnInitElement)
@ -342,38 +342,31 @@ function OpenMiniature(e, photo, post, photo_id, type = "post") {
let data = new FormData() let data = new FormData()
data.append('parentType', type); data.append('parentType', type);
ky.post("/iapi/getPhotosFromPost/" + (type == "post" ? post : "1_"+post), {
if(type) { hooks: {
ky.post("/iapi/getPhotosFromPost/" + (type == "post" ? post : "1_"+post), { afterResponse: [
hooks: { async (_request, _options, response) => {
afterResponse: [ json = await response.json();
async (_request, _options, response) => {
json = await response.json(); imagesCount = json.body.length;
imagesIndex = 0;
imagesCount = json.body.length; // Это всё придётся правда на 1 прибавлять
imagesIndex = 0;
// Это всё придётся правда на 1 прибавлять json.body.every(element => {
imagesIndex++;
json.body.every(element => { if(element.id == photo_id) {
imagesIndex++; return false;
if(element.id == photo_id) { } else {
return false; return true;
} else { }
return true; });
}
}); __reloadTitleBar();
__loadDetails(json.body[imagesIndex - 1].id, imagesIndex); }
__reloadTitleBar(); ]
__loadDetails(json.body[imagesIndex - 1].id, imagesIndex); } },
] body: data
}, });
body: data
});
} else {
imagesCount = 1
__reloadTitleBar()
__loadDetails(photo_id, imagesIndex)
}
return u(".ovk-photo-view-dimmer"); return u(".ovk-photo-view-dimmer");
} }
@ -1381,265 +1374,3 @@ $(document).on("click", "#photosAttachments", async (e) => {
xhr.send(formdata) xhr.send(formdata)
}) })
}) })
$(document).on("click", "#add_image", (e) => {
let isGroup = e.currentTarget.closest(".avatar_block").dataset.club != null
let group = isGroup ? e.currentTarget.closest(".avatar_block").dataset.club : 0
let body = `
<div id="avatarUpload">
<p>${isGroup == true ? tr('groups_avatar') : tr('friends_avatar')}</p>
<p>${tr('formats_avatar')}</p><br>
<label class="button" style="margin-left:45%;user-select:none" id="uploadbtn">
${tr("browse")}
<input accept="image/*" type="file" id="_avaInput" name="blob" hidden style="display: none;">
</label>
<br><br>
<p>${tr('troubles_avatar')}</p>
<p>${tr('webcam_avatar')}</p>
</div>
`
let msg = MessageBox(tr('uploading_new_image'), body, [
tr('cancel')
], [
(function() {
u("#tmpPhDelF").remove();
}),
]);
msg.attr("style", "width: 600px;");
document.querySelector(".ovk-diag-body").style.padding = "13px"
$("#avatarUpload input").on("change", (ev) => {
let image = URL.createObjectURL(ev.currentTarget.files[0])
$(".ovk-diag-body")[0].innerHTML = `
<span>${!isGroup ? tr("selected_area_user") : tr("selected_area_club")}</span>
<p style="margin-bottom: 10px;">${tr("selected_area_rotate")}</p>
<div class="cropper-image-cont" style="max-height: 274px;">
<img src="${image}" id="temp_uploadPic">
<div class="rotateButtons">
<div class="_rotateLeft hoverable"></div>
<div class="_rotateRight hoverable"></div>
</div>
</div>
<label style="margin-top: 14px;display: block;">
<input id="publish_on_wall" type="checkbox" checked>${tr("publish_on_wall")}
</label>
`
document.querySelector(".ovk-diag-action").insertAdjacentHTML("beforeend", `
<button class="button" style="margin-left: 4px;" id="_uploadImg">${tr("upload_button")}</button>
`)
const image_div = document.getElementById('temp_uploadPic');
const cropper = new Cropper(image_div, {
aspectRatio: NaN,
zoomable: true,
minCropBoxWidth: 150,
minCropBoxHeight: 150,
dragMode: 'move',
background: false,
center: false,
guides: false,
modal: true,
viewMode: 2,
cropstart(event) {
document.querySelector(".cropper-container").classList.add("moving")
},
cropend(event) {
document.querySelector(".cropper-container").classList.remove("moving")
},
});
msg.attr("style", "width: 487px;");
document.querySelector("#_uploadImg").onclick = (evv) => {
cropper.getCroppedCanvas({
fillColor: '#fff',
imageSmoothingEnabled: false,
imageSmoothingQuality: 'high',
}).toBlob((blob) => {
document.querySelector("#_uploadImg").classList.add("lagged")
let formdata = new FormData()
formdata.append("blob", blob)
formdata.append("ajax", 1)
formdata.append("on_wall", Number(document.querySelector("#publish_on_wall").checked))
formdata.append("hash", u("meta[name=csrf]").attr("value"))
$.ajax({
type: "POST",
url: isGroup ? "/club" + group + "/al_avatar" : "/al_avatars",
data: formdata,
processData: false,
contentType: false,
error: (response) => {
fastError(response.flash.message)
},
success: (response) => {
document.querySelector("#_uploadImg").classList.remove("lagged")
u("body").removeClass("dimmed");
document.querySelector("html").style.overflowY = "scroll"
u(".ovk-diag-cont").remove();
if(!response.success) {
fastError(response.flash.message)
return
}
document.querySelector("#bigAvatar").src = response.url
document.querySelector("#bigAvatar").parentNode.href = "/photo" + response.new_photo
document.querySelector(".add_image_text").style.display = "none"
document.querySelector(".avatar_controls").style.display = "block"
}
})
})
}
$(".ovk-diag-body ._rotateLeft").on("click", (e) => {
cropper.rotate(90)
})
$(".ovk-diag-body ._rotateRight").on("click", (e) => {
cropper.rotate(-90)
})
})
$(".ovk-diag-body #_takeSelfie").on("click", (e) => {
$("#avatarUpload")[0].style.display = "none"
$(".ovk-diag-body")[0].insertAdjacentHTML("beforeend", `
<div id="_takeSelfieFrame" style="text-align: center;">
<video style="max-width: 100%;max-height: 479px;"></video>
<canvas id="_tempCanvas" style="position: absolute;">
</div>
`)
let video = document.querySelector("#_takeSelfieFrame video")
if(!navigator.mediaDevices) {
// ех вот бы месседжбоксы были бы классами
u("body").removeClass("dimmed");
document.querySelector("html").style.overflowY = "scroll"
u(".ovk-diag-cont").remove();
fastError(tr("your_browser_doesnt_support_webcam"))
return
}
navigator.mediaDevices
.getUserMedia({ video: true, audio: false })
.then((stream) => {
video.srcObject = stream;
video.play()
window._cameraStream = stream
})
.catch((err) => {
u("body").removeClass("dimmed");
document.querySelector("html").style.overflowY = "scroll"
u(".ovk-diag-cont").remove();
fastError(err)
});
function __closeConnection() {
window._cameraStream.getTracks().forEach(track => track.stop())
}
document.querySelector(".ovk-diag-action").insertAdjacentHTML("beforeend", `
<button class="button" style="margin-left: 4px;" id="_takeSnap">${tr("take_snapshot")}</button>
`)
document.querySelector(".ovk-diag-action button").onclick = (evv) => {
__closeConnection()
}
document.querySelector("#_takeSnap").onclick = (evv) => {
let canvas = document.getElementById('_tempCanvas')
let context = canvas.getContext('2d')
canvas.setAttribute("width", video.clientWidth)
canvas.setAttribute("height", video.clientHeight)
context.drawImage(video, 0, 0, video.clientWidth, video.clientHeight);
canvas.toBlob((blob) => {
$("#_takeSnap").remove()
let file = new File([blob], "snapshot.jpg", {type: "image/jpeg", lastModified: new Date().getTime()})
let dt = new DataTransfer();
dt.items.add(file);
$("#_avaInput")[0].files = dt.files
$("#_avaInput").trigger("change")
$("#_takeSelfieFrame").remove()
__closeConnection()
})
}
})
})
$(document).on("click", ".avatarDelete", (e) => {
let isGroup = e.currentTarget.closest(".avatar_block").dataset.club != null
let group = isGroup ? e.currentTarget.closest(".avatar_block").dataset.club : 0
let body = `
<span>${tr("deleting_avatar_sure")}</span>
`
let msg = MessageBox(tr('deleting_avatar'), body, [
tr('yes'),
tr('no')
], [
(function() {
let formdata = new FormData()
formdata.append("hash", u("meta[name=csrf]").attr("value"))
$.ajax({
type: "POST",
url: isGroup ? "/club" + group + "/delete_avatar" : "/delete_avatar",
data: formdata,
processData: false,
contentType: false,
beforeSend: () => {
document.querySelector(".avatarDelete").classList.add("lagged")
},
error: (response) => {
fastError(response.flash.message)
},
success: (response) => {
if(!response.success) {
fastError(response.flash.message)
return
}
document.querySelector(".avatarDelete").classList.remove("lagged")
u("body").removeClass("dimmed");
document.querySelector("html").style.overflowY = "scroll"
u(".ovk-diag-cont").remove();
document.querySelector("#bigAvatar").src = response.url
document.querySelector("#bigAvatar").parentNode.href = response.new_photo ? ("/photo" + response.new_photo) : "javascript:void(0)"
if(!response.has_new_photo) {
document.querySelector(".avatar_controls").style.display = "none"
document.querySelector(".add_image_text").style.display = "block"
}
}
})
}),
(function() {
u("#tmpPhDelF").remove();
}),
]);
})

View file

@ -500,42 +500,201 @@ function escapeHtml(text) {
return text.replace(/[&<>"']/g, function(m) { return map[m]; }); return text.replace(/[&<>"']/g, function(m) { return map[m]; });
} }
function highlightText(searchText, container_selector, selectors = []) { function addAvatarImage(groupStrings = false, groupId = 0)
const container = u(container_selector) {
const regexp = new RegExp(`(${searchText})`, 'gi') let inputname = groupStrings == true ? 'ava' : 'blob';
let body = `
<div id="avatarUpload">
<p>${groupStrings == true ? tr('groups_avatar') : tr('friends_avatar')}</p>
<p>${tr('formats_avatar')}</p><br>
<img style="margin-left:46.3%;display:none" id="loader" src="/assets/packages/static/openvk/img/loading_mini.gif">
<label class="button" style="margin-left:45%;user-select:none" id="uploadbtn">${tr("browse")}
<input accept="image/*" type="file" name="${inputname}" hidden id="${inputname}" style="display: none;" onchange="uploadAvatar(${groupStrings}, ${groupStrings == true ? groupId : null})">
</label><br><br>
<p>${tr('troubles_avatar')}</p>
</div>
`
let msg = MessageBox(tr('uploading_new_image'), body, [
tr('cancel')
], [
(function() {
u("#tmpPhDelF").remove();
}),
]);
msg.attr("style", "width: 600px;");
}
function highlightNode(node) { function uploadAvatar(group = false, group_id = 0)
if(node.nodeType == 3) { {
let newNode = escapeHtml(node.nodeValue) loader.style.display = "block";
newNode = newNode.replace(regexp, (match, ...args) => { uploadbtn.setAttribute("hidden", "hidden")
return `<span class='highlight'>${escapeHtml(match)}</span>` let xhr = new XMLHttpRequest();
}) let formData = new FormData();
let bloborava = group == false ? "blob" : "ava"
const tempDiv = document.createElement('div') formData.append(bloborava, document.getElementById(bloborava).files[0]);
tempDiv.innerHTML = newNode formData.append("ava", 1)
formData.append("hash", u("meta[name=csrf]").attr("value"))
xhr.open("POST", group == true ? "/club"+group_id+"/al_avatar" : "/al_avatars")
xhr.onload = () => {
let json = JSON.parse(xhr.responseText);
document.getElementById(group == false ? "thisUserAvatar" : "thisGroupAvatar").src = json["url"];
u("body").removeClass("dimmed");
u(".ovk-diag-cont").remove();
if(document.getElementsByClassName("text_add_image")[0] == undefined)
{
document.getElementById("upl").href = "javascript:deleteAvatar('"+json["id"]+"', '"+u("meta[name=csrf]").attr("value")+"')"
}
//console.log(json["id"])
NewNotification(tr("update_avatar_notification"), tr("update_avatar_description"), json["url"], () => {window.location.href = "/photo" + json["id"]});
if(document.getElementsByClassName("text_add_image")[0] != undefined)
{
//ожидание чтобы в уведомлении была аватарка
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
location.reload()
}, 500);
});
}
}
xhr.send(formData)
}
while(tempDiv.firstChild) { function deleteAvatar(avatar)
node.parentNode.insertBefore(tempDiv.firstChild, node) {
let body = `
<p>${tr("deleting_avatar_sure")}</p>
`
let msg = MessageBox(tr('deleting_avatar'), body, [
tr('yes'),
tr('cancel')
], [
(function() {
let xhr = new XMLHttpRequest();
xhr.open("POST", "/photo"+avatar+"/delete")
xhr.onload = () => {
//не люблю формы
NewNotification(tr("deleted_avatar_notification"), "");
location.reload()
} }
node.parentNode.removeChild(node) xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
} else if(node.nodeType === 1 && node.tagName !== 'SCRIPT' && node.tagName !== 'BR' && node.tagName !== 'STYLE') { xhr.send("hash="+u("meta[name=csrf]").attr("value"))
Array.from(node.childNodes).forEach(highlightNode); }),
(function() {
u("#tmpPhDelF").remove();
}),
]);
}
function expandSearch()
{
// console.log("search expanded")
let els = document.querySelectorAll("div.dec")
for(const element of els)
{
element.style.display = "none"
}
document.querySelector(".whatFind").style.display = "block";
document.querySelector(".whatFind").style.marginRight = "-80px";
document.getElementById("searchInput").style.width = "627px";
document.getElementById("searchInput").style.background = "none";
document.getElementById("searchInput").style.backgroundColor = "#fff";
document.getElementById("searchInput").style.paddingLeft = "6px";
srch.classList.add("nodivider")
}
async function decreaseSearch()
{
// чтобы люди успели выбрать что искать и поиск не скрывался сразу
await new Promise(r => setTimeout(r, 4000));
// console.log("search decreased")
if(document.activeElement !== searchInput && document.activeElement !== typer)
{
srcht.setAttribute("hidden", "hidden")
document.getElementById("searchInput").style.background = "url('/assets/packages/static/openvk/img/search_icon.png') no-repeat 3px 4px";
document.getElementById("searchInput").style.backgroundColor = "#fff";
document.getElementById("searchInput").style.paddingLeft = "18px";
document.getElementById("searchInput").style.width = "120px";
document.querySelector(".whatFind").style.display = "none";
await new Promise(r => setTimeout(r, 300));
srch.classList.remove("nodivider")
let els = document.querySelectorAll("div.dec")
for(const element of els)
{
element.style.display = "inline-block"
}
}
}
function hideParams(name)
{
$("#s_"+name).slideToggle(250, "swing");
if($(`#n_${name} img`).attr("src") == "/assets/packages/static/openvk/img/hide.png")
{
$("#n_"+name+" img").attr("src", "/assets/packages/static/openvk/img/show.png");
} else {
$("#n_"+name+" img").attr("src", "/assets/packages/static/openvk/img/hide.png");
}
}
function resetSearch()
{
let inputs = document.querySelectorAll("input")
let selects = document.querySelectorAll("select")
for(const input of inputs)
{
if(input != dnt && input != gend && input != gend1 && input != gend2) {
input.value = ""
} }
} }
selectors.forEach(selector => { for(const select of selects)
elements = container.find(selector) {
if(!elements || elements.length < 1) return; if(select != sortyor && select != document.querySelector(".whatFind")) {
select.value = 0
elements.nodes.forEach(highlightNode) }
}) }
} }
String.prototype.escapeHtml = function() { async function checkSearchTips()
try { {
return escapeHtml(this) let query = searchInput.value;
} catch(e) {
return '' await new Promise(r => setTimeout(r, 1000));
let type = typer.value;
let smt = type == "users" || type == "groups" || type == "videos";
if(query.length > 3 && query == searchInput.value && smt) {
srcht.removeAttribute("hidden")
let etype = type
try {
let results = await API.Search.fastSearch(escapeHtml(query), etype)
srchrr.innerHTML = ""
for(const el of results["items"]) {
srchrr.insertAdjacentHTML("beforeend", `
<tr class="restip" onmouseup="if (event.which === 2) { window.open('${el.url}', '_blank'); } else {location.href='${el.url}'}">
<td>
<img src="${el.avatar}" width="30">
</td>
<td valign="top">
<p class="nameq" style="margin-top: -2px;text-transform:none;">${escapeHtml(el.name)}</p>
<p class="desq" style="text-transform:none;">${escapeHtml(el.description)}</p>
</td>
</tr>
`)
}
} catch(rejection) {
srchrr.innerHTML = tr("no_results")
}
} }
} }

View file

@ -2,7 +2,6 @@
"dependencies": { "dependencies": {
"@atlassian/aui": "^9.6.0", "@atlassian/aui": "^9.6.0",
"create-react-class": "^15.7.0", "create-react-class": "^15.7.0",
"cropperjs": "^1.6.1",
"dashjs": "^4.3.0", "dashjs": "^4.3.0",
"id3js": "^2.1.1", "id3js": "^2.1.1",
"handlebars": "^4.7.7", "handlebars": "^4.7.7",

View file

@ -59,16 +59,16 @@ create-react-class@^15.7.0:
loose-envify "^1.3.1" loose-envify "^1.3.1"
object-assign "^4.1.1" object-assign "^4.1.1"
cropperjs@^1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/cropperjs/-/cropperjs-1.6.1.tgz#fd132021d93b824b1b0f2c2c3b763419fb792d89"
integrity sha512-F4wsi+XkDHCOMrHMYjrTEE4QBOrsHHN5/2VsVAaRq8P7E5z7xQpT75S+f/9WikmBEailas3+yo+6zPIomW+NOA==
css.escape@1.5.1: css.escape@1.5.1:
version "1.5.1" version "1.5.1"
resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb" resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb"
integrity sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg== integrity sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==
dompurify@2.4.5:
version "2.4.5"
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.4.5.tgz#0e89a27601f0bad978f9a924e7a05d5d2cccdd87"
integrity sha512-jggCCd+8Iqp4Tsz0nIvpcb22InKEBrGz5dw3EQJMs8HPJDsKbFIO3STYtAvCfDx26Muevn1MHVI0XxjgFfmiSA==
dashjs@^4.3.0: dashjs@^4.3.0:
version "4.3.0" version "4.3.0"
resolved "https://registry.yarnpkg.com/dashjs/-/dashjs-4.3.0.tgz#cccda5a490cabf6c3b48aa887ec8c8ac0df1a233" resolved "https://registry.yarnpkg.com/dashjs/-/dashjs-4.3.0.tgz#cccda5a490cabf6c3b48aa887ec8c8ac0df1a233"
@ -81,11 +81,6 @@ dashjs@^4.3.0:
imsc "^1.0.2" imsc "^1.0.2"
localforage "^1.7.1" localforage "^1.7.1"
dompurify@2.4.5:
version "2.4.5"
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.4.5.tgz#0e89a27601f0bad978f9a924e7a05d5d2cccdd87"
integrity sha512-jggCCd+8Iqp4Tsz0nIvpcb22InKEBrGz5dw3EQJMs8HPJDsKbFIO3STYtAvCfDx26Muevn1MHVI0XxjgFfmiSA==
encoding@^0.1.11: encoding@^0.1.11:
version "0.1.13" version "0.1.13"
resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9"
@ -126,6 +121,10 @@ fbjs@^0.8.0:
setimmediate "^1.0.5" setimmediate "^1.0.5"
ua-parser-js "^0.7.18" ua-parser-js "^0.7.18"
html-entities@^1.2.1:
version "1.4.0"
resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.4.0.tgz#cfbd1b01d2afaf9adca1b10ae7dffab98c71d2dc"
integrity sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==
handlebars@^4.7.7: handlebars@^4.7.7:
version "4.7.7" version "4.7.7"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1"
@ -138,11 +137,6 @@ handlebars@^4.7.7:
optionalDependencies: optionalDependencies:
uglify-js "^3.1.4" uglify-js "^3.1.4"
html-entities@^1.2.1:
version "1.4.0"
resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.4.0.tgz#cfbd1b01d2afaf9adca1b10ae7dffab98c71d2dc"
integrity sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==
iconv-lite@^0.6.2: iconv-lite@^0.6.2:
version "0.6.3" version "0.6.3"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"

View file

@ -1 +0,0 @@
ALTER TABLE `playlists` ADD `unlisted` TINYINT(1) UNSIGNED DEFAULT '0' AFTER `deleted`;

View file

@ -265,8 +265,6 @@
"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";
@ -486,18 +484,16 @@
"groups_avatar" = "Good photo can make your group more recognizable."; "groups_avatar" = "Good photo can make your group more recognizable.";
"formats_avatar" = "You can upload an image in JPG, GIF or PNG format."; "formats_avatar" = "You can upload an image in JPG, GIF or PNG format.";
"troubles_avatar" = "If you're having trouble uploading, try selecting a smaller photo."; "troubles_avatar" = "If you're having trouble uploading, try selecting a smaller photo.";
"webcam_avatar" = "If your computer has a webcam, you can <a id='_takeSelfie'>take a snapshot »</a>"; "webcam_avatar" = "If your computer is equipped with a webcam, you can <a href='javascript:'>take a snapshot</a>.";
"publish_on_wall" = "Make post on wall";
"take_snapshot" = "Take snapshot";
"your_browser_doesnt_support_webcam" = "Your browser does not support webcam video capture.";
"selected_area_user" = "The selected area will be shown on your page."; "update_avatar_notification" = "Profile photo was updated";
"selected_area_club" = "The selected area will be shown on the group page."; "update_avatar_description" = "Click to watch";
"selected_area_rotate" = "If the image is not oriented correctly, the photo can be rotated.";
"deleting_avatar" = "Deleting photo"; "deleting_avatar" = "Deleting photo";
"deleting_avatar_sure" = "Do you sure you want to delete avatar?"; "deleting_avatar_sure" = "Do you sure you want to delete avatar?";
"deleted_avatar_notification" = "Picture successfully deleted";
"save_changes" = "Save changes"; "save_changes" = "Save changes";
"upd_m" = "updated his profile picture"; "upd_m" = "updated his profile picture";
@ -656,14 +652,13 @@
"apply_style_for_this_device" = "Apply style only for this device"; "apply_style_for_this_device" = "Apply style only for this device";
"search_for_groups" = "Search for groups"; "search_for_groups" = "Search for groups";
"search_for_users" = "Search for users"; "search_for_users" = "Search for people";
"search_for_posts" = "Search for posts"; "search_for_posts" = "Search for posts";
"search_for_comments" = "Search for comments"; "search_for_comments" = "Search for comments";
"search_for_videos" = "Search for videos"; "search_for_videos" = "Search for videos";
"search_for_apps" = "Search for apps"; "search_for_apps" = "Search for apps";
"search_for_notes" = "Search for notes"; "search_for_notes" = "Search for notes";
"search_for_audios" = "Search for music"; "search_for_audios" = "Search for music";
"search_for_audios_playlists" = "Search for playlists";
"search_button" = "Find"; "search_button" = "Find";
"search_placeholder" = "Start typing any name, title or word"; "search_placeholder" = "Start typing any name, title or word";
"results_zero" = "No results"; "results_zero" = "No results";
@ -895,7 +890,6 @@
"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";
@ -919,7 +913,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" = "Delete audio"; "fully_delete_audio" = "Fully delete audio";
"attach_audio" = "Attach audio"; "attach_audio" = "Attach audio";
"detach_audio" = "Detach audio"; "detach_audio" = "Detach audio";
@ -947,12 +941,6 @@
"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.";
@ -960,7 +948,6 @@
"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";
@ -973,8 +960,6 @@
"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 */
@ -1571,7 +1556,6 @@
"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 */
@ -2013,23 +1997,24 @@
/* Search */ /* Search */
"s_people" = "Users"; "s_people" = "People";
"s_groups" = "Clubs"; "s_groups" = "Clubs";
"s_events" = "Events";
"s_apps" = "Applications"; "s_apps" = "Applications";
"s_questions" = "Questions";
"s_notes" = "Notes";
"s_themes" = "Themes";
"s_posts" = "Posts"; "s_posts" = "Posts";
"s_comments" = "Comments"; "s_comments" = "Comments";
"s_videos" = "Videos"; "s_videos" = "Videos";
"s_audios" = "Music"; "s_audios" = "Music";
"s_audios_playlists" = "Playlists"; "s_by_people" = "for people";
"s_by_people" = "for users";
"s_by_groups" = "for groups"; "s_by_groups" = "for groups";
"s_by_posts" = "for posts"; "s_by_posts" = "for posts";
"s_by_comments" = "for comments"; "s_by_comments" = "for comments";
"s_by_videos" = "for videos"; "s_by_videos" = "for videos";
"s_by_apps" = "for apps"; "s_by_apps" = "for apps";
"s_by_audios" = "for audios"; "s_by_audios" = "for musics";
"s_by_audios_playlists" = "for playlists";
"s_order_by" = "Order by..."; "s_order_by" = "Order by...";
@ -2040,10 +2025,6 @@
"s_order_by_length" = "By length"; "s_order_by_length" = "By length";
"s_order_by_listens" = "By listens count"; "s_order_by_listens" = "By listens count";
"s_order_invert" = "Invert"; "s_order_invert" = "Invert";
"s_order_by_reg_date" = "By reg date";
"s_order_by_creation_date" = "By creation date";
"s_order_by_publishing_date" = "By publication date";
"s_order_by_upload_date" = "By upload date";
"s_by_date" = "By date"; "s_by_date" = "By date";
"s_registered_before" = "Registered before"; "s_registered_before" = "Registered before";
@ -2056,24 +2037,17 @@
"s_now_on_site" = "now on site"; "s_now_on_site" = "now on site";
"s_with_photo" = "with photo"; "s_with_photo" = "with photo";
"s_only_in_names" = "only in names"; "s_only_in_names" = "only in names";
"s_only_youtube" = "only from YouTube";
"s_any" = "any"; "s_any" = "any";
"s_any_single" = "any";
"reset" = "Reset"; "reset" = "Reset";
"closed_group_post" = "This post was published in a private group"; "closed_group_post" = "This post was published in a private group";
"deleted_target_comment" = "This comment belongs to deleted post"; "deleted_target_comment" = "This comment belongs to deleted post";
"no_results" = "No results"; "no_results" = "No results";
"s_only_performers" = "By performers"; "s_only_performers" = "Performers only";
"s_with_lyrics" = "With lyrics"; "s_with_lyrics" = "With lyrics";
"showing_x_y" = "(showing $1—$2)";
"no_results_by_this_query" = "Nothing was found by this query.";
"s_additional" = "Additional";
"s_it_is_you" = "it is you";
/* BadBrowser */ /* BadBrowser */
"deprecated_browser" = "Deprecated Browser"; "deprecated_browser" = "Deprecated Browser";

View file

@ -243,7 +243,6 @@
"users_posts" = "Записи $1"; "users_posts" = "Записи $1";
"clubs_posts" = "Записи сообщества"; "clubs_posts" = "Записи сообщества";
"others_posts" = "Чужие записи"; "others_posts" = "Чужие записи";
"show_more" = "Показать больше";
/* Friends */ /* Friends */
@ -470,18 +469,16 @@
"groups_avatar" = "Хорошее фото сделает Ваше сообщество более узнаваемым."; "groups_avatar" = "Хорошее фото сделает Ваше сообщество более узнаваемым.";
"formats_avatar" = "Вы можете загрузить изображение в формате JPG, GIF или PNG."; "formats_avatar" = "Вы можете загрузить изображение в формате JPG, GIF или PNG.";
"troubles_avatar" = "Если возникают проблемы с загрузкой, попробуйте выбрать фотографию меньшего размера."; "troubles_avatar" = "Если возникают проблемы с загрузкой, попробуйте выбрать фотографию меньшего размера.";
"webcam_avatar" = "Если ваш компьютер оснащён веб-камерой, Вы можете <a id='_takeSelfie'>сделать моментальную фотографию »</a>"; "webcam_avatar" = "Если ваш компьютер оснащён веб-камерой, Вы можете <a href='javascript:'>сделать моментальную фотографию »</a>";
"publish_on_wall" = "Опубликовать запись на стене";
"take_snapshot" = "Сделать снимок";
"your_browser_doesnt_support_webcam" = "Ваш браузер не поддерживает съёмку видео с веб-камеры.";
"selected_area_user" = "Выбранная область будет показываться на вашей странице."; "update_avatar_notification" = "Фотография профиля обновлена";
"selected_area_club" = "Выбранная область будет показываться на странице сообщества."; "update_avatar_description" = "Нажмите сюда, чтобы перейти к просмотру";
"selected_area_rotate" = "Если изображение ориентировано неправильно, фотографию можно повернуть.";
"deleting_avatar" = "Удаление фотографии"; "deleting_avatar" = "Удаление фотографии";
"deleting_avatar_sure" = "Вы действительно хотите удалить аватар?"; "deleting_avatar_sure" = "Вы действительно хотите удалить аватар?";
"deleted_avatar_notification" = "Фотография успешно удалена";
"save_changes" = "Сохранить изменения"; "save_changes" = "Сохранить изменения";
"upd_m" = "обновил фотографию на своей странице"; "upd_m" = "обновил фотографию на своей странице";
@ -636,7 +633,6 @@
"search_for_apps" = "Поиск приложений"; "search_for_apps" = "Поиск приложений";
"search_for_notes" = "Поиск записок"; "search_for_notes" = "Поиск записок";
"search_for_audios" = "Поиск музыки"; "search_for_audios" = "Поиск музыки";
"search_for_audios_playlists" = "Поиск плейлистов";
"search_button" = "Найти"; "search_button" = "Найти";
"search_placeholder" = "Начните вводить любое имя, название или слово"; "search_placeholder" = "Начните вводить любое имя, название или слово";
"results_zero" = "Ни одного результата"; "results_zero" = "Ни одного результата";
@ -851,7 +847,6 @@
"my_playlists" = "Мои плейлисты"; "my_playlists" = "Мои плейлисты";
"playlists" = "Плейлисты"; "playlists" = "Плейлисты";
"audios_explicit" = "Содержит нецензурную лексику"; "audios_explicit" = "Содержит нецензурную лексику";
"audios_unlisted" = "Скрыто из поиска";
"withdrawn" = "Изъято"; "withdrawn" = "Изъято";
"deleted" = "Удалено"; "deleted" = "Удалено";
"owner" = "Владелец"; "owner" = "Владелец";
@ -902,13 +897,6 @@
"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" = "У группы нет этой песни.";
@ -916,7 +904,6 @@
"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" = "Транслировать аудио в статус";
@ -929,8 +916,6 @@
"repeat_tip" = "Повторение"; "repeat_tip" = "Повторение";
"shuffle_tip" = "Перемешать"; "shuffle_tip" = "Перемешать";
"mute_tip" = "Заглушить"; "mute_tip" = "Заглушить";
"playlist_hide_from_search" = "Не показывать в поиске";
"confirm_deleting_audio" = "Вы действительно хотите полностью удалить аудиозапись?";
/* Notifications */ /* Notifications */
@ -1432,7 +1417,7 @@
"no_video_desc" = "Выберите файл или укажите ссылку."; "no_video_desc" = "Выберите файл или укажите ссылку.";
"error_occured" = "Произошла ошибка"; "error_occured" = "Произошла ошибка";
"error_video_damaged_file" = "Файл повреждён или не содержит видео."; "error_video_damaged_file" = "Файл повреждён или не содержит видео.";
"error_video_incorrect_link" = "Возможно, ссылка некорректна"; "error_video_incorrect_link" = "Возможно, ссылка некорректна.";
"error_video_no_title" = "Видео не может быть опубликовано без названия."; "error_video_no_title" = "Видео не может быть опубликовано без названия.";
"new_data_video" = "Обновлённое описание появится на странице с видео."; "new_data_video" = "Обновлённое описание появится на странице с видео.";
@ -1474,7 +1459,6 @@
"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 */
@ -1904,23 +1888,24 @@
/* Search */ /* Search */
"s_people" = "Пользователи"; "s_people" = "Люди";
"s_groups" = "Группы"; "s_groups" = "Группы";
"s_events" = "События";
"s_apps" = "Приложения"; "s_apps" = "Приложения";
"s_questions" = "Вопросы";
"s_notes" = "Заметки";
"s_themes" = "Темы";
"s_posts" = "Записи"; "s_posts" = "Записи";
"s_comments" = "Комментарии"; "s_comments" = "Комментарии";
"s_videos" = "Видео"; "s_videos" = "Видео";
"s_audios" = "Аудио"; "s_audios" = "Аудио";
"s_audios_playlists" = "Плейлисты"; "s_by_people" = "по людям";
"s_by_people" = "по пользователям";
"s_by_groups" = "по группам"; "s_by_groups" = "по группам";
"s_by_posts" = "по записям"; "s_by_posts" = "по записям";
"s_by_comments" = "по комментариям"; "s_by_comments" = "по комментариям";
"s_by_videos" = "по видео"; "s_by_videos" = "по видео";
"s_by_apps" = "по приложениям"; "s_by_apps" = "по приложениям";
"s_by_audios" = "по аудиозаписям"; "s_by_audios" = "по музыке";
"s_by_audios_playlists" = "по плейлистам";
"s_order_by" = "Порядок"; "s_order_by" = "Порядок";
@ -1931,10 +1916,6 @@
"s_order_by_length" = "По длине"; "s_order_by_length" = "По длине";
"s_order_by_listens" = "По числу прослушиваний"; "s_order_by_listens" = "По числу прослушиваний";
"s_order_invert" = "Инвертировать"; "s_order_invert" = "Инвертировать";
"s_order_by_reg_date" = "По дате регистрации";
"s_order_by_creation_date" = "По дате создания";
"s_order_by_publishing_date" = "По дате публикации";
"s_order_by_upload_date" = "По дате загрузки";
"s_by_date" = "По дате"; "s_by_date" = "По дате";
"s_registered_before" = "Зарегистрирован до"; "s_registered_before" = "Зарегистрирован до";
@ -1947,24 +1928,17 @@
"s_now_on_site" = "cейчас на сайте"; "s_now_on_site" = "cейчас на сайте";
"s_with_photo" = "с фото"; "s_with_photo" = "с фото";
"s_only_in_names" = "только в именах"; "s_only_in_names" = "только в именах";
"s_only_youtube" = "только с YouTube";
"s_any" = "любые"; "s_any" = "любой";
"s_any_single" = "любой";
"reset" = "Сброс"; "reset" = "Сброс";
"closed_group_post" = "Запись с закрытой стены"; "closed_group_post" = "Эта запись из закрытой группы";
"deleted_target_comment" = "Этот комментарий принадлежит к удалённой записи"; "deleted_target_comment" = "Этот комментарий принадлежит к удалённой записи";
"no_results" = "Результатов нет"; "no_results" = "Результатов нет";
"s_only_performers" = "По исполнителям"; "s_only_performers" = "Только исполнители";
"s_with_lyrics" = "С текстом"; "s_with_lyrics" = "С текстом";
"showing_x_y" = "(показывается $1—$2)";
"no_results_by_this_query" = "По данному запросу ничего не найдено.";
"s_additional" = "Дополнительно";
"s_it_is_you" = "это вы";
/* BadBrowser */ /* BadBrowser */
"deprecated_browser" = "Устаревший браузер"; "deprecated_browser" = "Устаревший браузер";
@ -2042,7 +2016,7 @@
"error_video" = "Произошла ошибка"; "error_video" = "Произошла ошибка";
"file_corrupted" = "Файл повреждён или не содержит видео."; "file_corrupted" = "Файл повреждён или не содержит видео.";
"link_incorrect" = "Возможно, ссылка некорректна (попробуй убрать параметры по типу &t= или &si=)"; "link_incorrect" = "Возможно, ссылка некорректна.";
"no_name_error" = "Видео не может быть опубликовано без названия"; "no_name_error" = "Видео не может быть опубликовано без названия";
"access_denied_error" = "Ошибка доступа"; "access_denied_error" = "Ошибка доступа";

View file

@ -368,7 +368,7 @@
"groups_avatar" = "Гарне фото зробить Вашу спільноту більш популярним."; "groups_avatar" = "Гарне фото зробить Вашу спільноту більш популярним.";
"formats_avatar" = "Ви можете завантажити зображення у форматі JPG, GIF або PNG."; "formats_avatar" = "Ви можете завантажити зображення у форматі JPG, GIF або PNG.";
"troubles_avatar" = "Якщо виникають проблеми із завантаженням, спробуйте вибрати фотографію меншого розміру."; "troubles_avatar" = "Якщо виникають проблеми із завантаженням, спробуйте вибрати фотографію меншого розміру.";
"webcam_avatar" = "Якщо ваш комп'ютер оснащений веб-камерою, Ви можете <a id='_takeSelfie'>зробити миттєву фотографію »</a>"; "webcam_avatar" = "Якщо ваш комп'ютер оснащений веб-камерою, Ви можете <a href='javascript:'>зробити миттєву фотографію»</a>";
"update_avatar_notification" = "Фотографію профілю оновлено"; "update_avatar_notification" = "Фотографію профілю оновлено";
"update_avatar_description" = "Натисніть, щоб перейти до перегляду"; "update_avatar_description" = "Натисніть, щоб перейти до перегляду";
@ -1758,7 +1758,11 @@
"s_people" = "Люди"; "s_people" = "Люди";
"s_groups" = "Спільноти"; "s_groups" = "Спільноти";
"s_events" = "Події";
"s_apps" = "Застосунки"; "s_apps" = "Застосунки";
"s_questions" = "Запитання";
"s_notes" = "Нотатки";
"s_themes" = "Теми";
"s_posts" = "Дописи"; "s_posts" = "Дописи";
"s_comments" = "Коментарі"; "s_comments" = "Коментарі";
"s_videos" = "Відео"; "s_videos" = "Відео";

View file

@ -124,13 +124,14 @@ th,
.tippy-box[data-theme~="vk"], .tippy-box[data-theme~="vk"],
.poll, .poll,
#standaloneCommentBox, #standaloneCommentBox,
#search_box_button, .searchBtn,
.verticalGrayTabs #used, .searchList #used,
.search_option_name, .searchOptionName,
.borderup, .borderup,
#tour, #tour,
#auth, #auth,
.ovk-photo-view { .ovk-photo-view,
.searchOptions {
border-color: #2c2640 !important; border-color: #2c2640 !important;
} }
@ -154,15 +155,11 @@ hr {
.messagebox-content-header, .messagebox-content-header,
.accent-box, .accent-box,
.button_search, .button_search,
.search_box_button { .searchBtn,
.searchOptionName {
background-color: #383052; background-color: #383052;
} }
.search_option_name {
background-color: #383052 !important;
color: lightgrey !important;
}
.tab:hover { .tab:hover {
background-color: #40375e; background-color: #40375e;
} }
@ -179,7 +176,7 @@ hr {
} }
.bsdn_contextMenuElement:hover, .bsdn_contextMenuElement:hover,
.verticalGrayTabs li:hover { .searchList li:hover {
background-color: #29223a; background-color: #29223a;
} }
@ -211,7 +208,7 @@ a,
.paginator a:hover, .paginator a:hover,
.post-share-button:hover, .post-share-button:hover,
.post-like-button:hover, .post-like-button:hover,
#search_box_button:active { .searchBtn:active {
background-color: #272138 !important; background-color: #272138 !important;
} }
@ -264,9 +261,7 @@ center[style="background: white;border: #DEDEDE solid 1px;"],
.album-photo img, .album-photo img,
#faqhead, #faqhead,
td.e, td.e,
tr.e, tr.e {
.playlistListView:hover,
.playlistListView .playlistCover {
background-color: #231e33 !important; background-color: #231e33 !important;
} }
@ -381,7 +376,7 @@ input[type="radio"] {
background-image: url("/themepack/midnight/0.0.2.9/resource/radio.png") !important; background-image: url("/themepack/midnight/0.0.2.9/resource/radio.png") !important;
} }
.header_navigation .link, .header_navigation .header_divider_stick { .header_navigation .link {
background: unset; background: unset;
} }
@ -408,26 +403,15 @@ input[type="radio"] {
border-color: #514534; border-color: #514534;
} }
#search_box_button { .searchBtn {
box-shadow: 0px 2px 0px 0px rgba(111, 111, 111, 0.18) inset; box-shadow: 0px 2px 0px 0px rgba(111, 111, 111, 0.18) inset;
} }
#search_box_button:active { .searchBtn:active {
box-shadow: 0px -2px 0px 0px rgba(255, 255, 255, 0.18) inset; box-shadow: 0px -2px 0px 0px rgba(255, 255, 255, 0.18) inset;
} }
.verticalGrayTabsWrapper { .searchList #used {
background: #1e1a2b;
border-top: 1px solid #2c2640;
border-left: 1px solid #2a2841;
}
.page_content_paginator_bottom {
background: #1e1a2b;
border-top: 1px solid #2c2640;
}
.verticalGrayTabs #used {
background: #463f60 !important; background: #463f60 !important;
} }
@ -463,9 +447,13 @@ input[type="radio"] {
background: #b9b9b9 !important; background: #b9b9b9 !important;
} }
.musicIcon {
filter: invert(81%) !important;
}
.audioEntry.nowPlaying { .audioEntry.nowPlaying {
background: #463f60 !important; background: #463f60 !important;
outline: 1px solid #645a86 !important; border: 1px solid #645a86 !important;
} }
.preformer { .preformer {
@ -497,11 +485,11 @@ input[type="radio"] {
color: black !important; color: black !important;
} }
.verticalGrayTabs a { .searchList a {
color: #bbb !important; color: #bbb !important;
} }
.verticalGrayTabs a:hover { .searchList a:hover {
color: #eeeeee !important; color: #eeeeee !important;
background: #332d46 !important; background: #332d46 !important;
} }
@ -524,7 +512,7 @@ img[src$='/assets/packages/static/openvk/img/song.jpg'] {
} }
.audioEntry .withLyrics { .audioEntry .withLyrics {
color: #9481d9 !important; color: #6f6497 !important;
} }
#listensCount { #listensCount {
@ -548,8 +536,7 @@ ul {
/* вот бы css в овк был бы написан на var()'ах( */ /* вот бы css в овк был бы написан на var()'ах( */
#upload_container.uploading { #upload_container.uploading {
background-color: #312b3f !important; background: #121017 url('/assets/packages/static/openvk/img/progressbar.gif') !important;
background-image: url('/assets/packages/static/openvk/img/progressbar.gif') !important;
} }
.musicIcon.pressed { .musicIcon.pressed {
@ -582,12 +569,3 @@ ul {
.tabcontent { .tabcontent {
background: #2c2640 !important; background: #2c2640 !important;
} }
.add_image_text {
z-index: 999;
}
.content_page_error {
background: #28223a;
border: #2c2640 solid 1px;
}

View file

@ -24,8 +24,8 @@ body {
text-shadow: none; text-shadow: none;
} }
.header_navigation .link, .header_navigation .header_divider_stick { .header_navigation .link {
background: unset !important; background: unset;
} }
.header_navigation .link a:hover { .header_navigation .link a:hover {
@ -252,30 +252,87 @@ ul {
background-color:#3c3c3c background-color:#3c3c3c
} }
.search_box_button { .searchOptions
{
overflow-y: hidden;
overflow-x:hidden;
width:25.5%;
border-top:1px solid #2B2B2B;
float:right;
scrollbar-width: none;
font-size:12px;
background-color:#F6F6F6;
margin-right: -7px;
}
.searchBtn
{
border: none;
background-color: #555555;
color: #ffffff;
margin-left: -3px;
padding-bottom: 2px;
width: 80px;
cursor: pointer;
box-shadow: none; box-shadow: none;
} }
.search_box_button:active { .searchBtn:active
{
border: none;
background-color: rgb(77, 77, 77);
color: white;
box-shadow: none; box-shadow: none;
} }
.verticalGrayTabs #used { .searchList #used {
background: #3c3c3c !important; background: #3c3c3c !important;
border: 1px solid #3c3c3c; border: unset !important;
} }
.verticalGrayTabs #used a { .searchList #used a
{
color: white; color: white;
} }
.search_option_name { .searchHide
background-color: #a4a4a4; {
border-bottom: unset; padding-right: 5px;
} }
.verticalGrayTabsWrapper { .searchList li:hover
border-top: unset; {
margin-left: 0px;
color: #2B587A !important;
background: #eeeeee;
padding: 2px;
padding-top: 5px;
padding-bottom: 5px;
margin-bottom: 2px;
padding-left: 5px;
width: 91%;
}
.searchOptionName
{
cursor: pointer;
background-color: #a4a4a4;
padding-left: 5px;
padding-top: 5px;
padding-bottom: 5px;
width: 90%;
font-weight: 600;
color: #fff;
}
.searchOptionName img
{
display: none;
}
.borderup
{
border-top: 1px solid #2f2f2f;
} }
.sugglist { .sugglist {
@ -314,8 +371,3 @@ ul {
.musicIcon.lagged { .musicIcon.lagged {
opacity: 50%; opacity: 50%;
} }
.bigPlayer {
position: sticky;
top: 42px;
}