From 7d450c18fdf1c9b2c3372327c418b4e8cd6c6d26 Mon Sep 17 00:00:00 2001 From: mrilyew <99399973+mrilyew@users.noreply.github.com> Date: Sat, 7 Dec 2024 17:18:29 +0300 Subject: [PATCH] feat: ajax, audio refactor (#1164) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Make audio player pizdatey * Simple ajax routing (scripts are broken) * Fix most common script problems pt1 * Add ajax player Осталось пофиксить скрипты и создание плейлистов! Ну и ещё некоторые хуйни по аудиозаписям которые я задумал. * Add context menu for audios * Refactor audio upload page * Repair playlists * Fix main problems * Midnight teme adaptation * Stupid bug fix * Save audios list in da localstorage and fix msgbox * Fix time setting * add beforeUnload event * Stupid bugs fix * update page footer on transition * fix wall publihing * fix 500 on non existent page --- Web/Models/Entities/Audio.php | 5 + Web/Models/Repositories/Audios.php | 8 +- Web/Presenters/AudioPresenter.php | 112 +- Web/Presenters/AuthPresenter.php | 1 + Web/Presenters/MessengerPresenter.php | 1 + Web/Presenters/NoSpamPresenter.php | 2 + Web/Presenters/OpenVKPresenter.php | 8 +- Web/Presenters/ReportPresenter.php | 2 + Web/Presenters/UserPresenter.php | 2 +- Web/Presenters/templates/@layout.xml | 20 +- Web/Presenters/templates/Apps/Edit.xml | 8 +- Web/Presenters/templates/Apps/Play.xml | 26 +- .../templates/Audio/EditPlaylist.xml | 106 +- Web/Presenters/templates/Audio/List.xml | 38 +- .../templates/Audio/NewPlaylist.xml | 105 +- Web/Presenters/templates/Audio/Playlist.xml | 8 +- Web/Presenters/templates/Audio/Upload.xml | 337 ++- Web/Presenters/templates/Audio/bigplayer.xml | 42 +- Web/Presenters/templates/Audio/player.xml | 22 +- Web/Presenters/templates/Audio/tabs.xml | 11 +- Web/Presenters/templates/Gifts/Pick.xml | 19 +- Web/Presenters/templates/Group/Followers.xml | 23 +- Web/Presenters/templates/Group/View.xml | 32 +- Web/Presenters/templates/Notes/List.xml | 4 +- Web/Presenters/templates/Notes/View.xml | 2 +- .../templates/Photos/UploadPhoto.xml | 8 +- Web/Presenters/templates/Search/Index.xml | 14 +- Web/Presenters/templates/Topics/Create.xml | 7 - Web/Presenters/templates/User/Edit.xml | 11 - Web/Presenters/templates/User/Settings.xml | 24 - Web/Presenters/templates/User/View.xml | 78 +- Web/Presenters/templates/User/private.xml | 27 +- .../templates/components/comment.xml | 25 +- .../templates/components/textArea.xml | 22 +- Web/routes.yml | 8 +- Web/static/css/audios.css | 578 +++-- Web/static/css/dialog.css | 2 +- Web/static/css/main.css | 92 +- Web/static/img/audios_controls.png | Bin 4287 -> 4621 bytes Web/static/js/al_despacito_wall.js | 9 +- Web/static/js/al_feed.js | 2 +- Web/static/js/al_music.js | 2051 +++++++++++------ Web/static/js/al_photos.js | 18 +- Web/static/js/al_playlists.js | 113 - Web/static/js/al_suggestions.js | 1 + Web/static/js/al_wall.js | 403 +++- Web/static/js/messagebox.js | 6 +- Web/static/js/openvk.cls.js | 120 - Web/static/js/router.js | 383 +++ Web/static/js/utils.js | 106 + locales/en.strings | 14 +- locales/ru.strings | 13 +- themepacks/midnight/stylesheet.css | 21 +- 53 files changed, 3107 insertions(+), 1993 deletions(-) delete mode 100644 Web/static/js/al_playlists.js create mode 100644 Web/static/js/router.js diff --git a/Web/Models/Entities/Audio.php b/Web/Models/Entities/Audio.php index 3b998f329..23941f4c4 100644 --- a/Web/Models/Entities/Audio.php +++ b/Web/Models/Entities/Audio.php @@ -147,6 +147,11 @@ function getPerformer(): string return $this->getRecord()->performer; } + function getPerformers(): array + { + return explode(", ", $this->getRecord()->performer); + } + function getName(): string { return $this->getPerformer() . " — " . $this->getTitle(); diff --git a/Web/Models/Repositories/Audios.php b/Web/Models/Repositories/Audios.php index 73f5ac293..1b8b174dd 100644 --- a/Web/Models/Repositories/Audios.php +++ b/Web/Models/Repositories/Audios.php @@ -248,15 +248,17 @@ function find(string $query, array $params = [], array $order = ['type' => 'id', { $query = "%$query%"; $result = $this->audios->where([ - "unlisted" => 0, - "deleted" => 0, + "unlisted" => 0, + "deleted" => 0, + /*"withdrawn" => 0, + "processed" => 1,*/ ]); $order_str = (in_array($order['type'], ['id', 'length', 'listens']) ? $order['type'] : 'id') . ' ' . ($order['invert'] ? 'ASC' : 'DESC');; if($params["only_performers"] == "1") { $result->where("performer LIKE ?", $query); } else { - $result->where("name LIKE ? OR performer LIKE ?", $query, $query); + $result->where("CONCAT_WS(' ', performer, name) LIKE ?", $query); } foreach($params as $paramName => $paramValue) { diff --git a/Web/Presenters/AudioPresenter.php b/Web/Presenters/AudioPresenter.php index ae38d1d00..aa8801f51 100644 --- a/Web/Presenters/AudioPresenter.php +++ b/Web/Presenters/AudioPresenter.php @@ -97,9 +97,12 @@ function renderList(?int $owner = NULL, ?string $mode = "list"): void $this->template->club = $owner < 0 ? $entity : NULL; $this->template->isMy = ($owner > 0 && ($entity->getId() === $this->user->id)); $this->template->isMyClub = ($owner < 0 && $entity->canBeModifiedBy($this->user->identity)); - } else { - $audios = $this->audios->getPopular(); - $audiosCount = $audios->size(); + } else if ($mode === 'alone_audio') { + $audios = [$this->template->alone_audio]; + $audiosCount = 1; + + $this->template->owner = $this->user->identity; + $this->template->ownerId = $this->user->id; } // $this->renderApp("owner=$owner"); @@ -271,6 +274,19 @@ function renderUpload(): void } } + function renderAloneAudio(int $owner_id, int $audio_id): void + { + $this->assertUserLoggedIn(); + + $found_audio = $this->audios->get($audio_id); + if(!$found_audio || $found_audio->isDeleted() || !$found_audio->canBeViewedBy($this->user->identity)) { + $this->notFound(); + } + + $this->template->alone_audio = $found_audio; + $this->renderList(NULL, 'alone_audio'); + } + function renderListen(int $id): void { if ($_SERVER["REQUEST_METHOD"] === "POST") { @@ -327,17 +343,15 @@ function renderNewPlaylist(): void $this->template->club = $club; } - $this->template->owner = $owner; - if ($_SERVER["REQUEST_METHOD"] === "POST") { $title = $this->postParam("title"); $description = $this->postParam("description"); $is_unlisted = (int)$this->postParam('is_unlisted'); - - $audios = !empty($this->postParam("audios")) ? array_slice(explode(",", $this->postParam("audios")), 0, 1000) : []; + $is_ajax = (int)$this->postParam('ajax') == 1; + $audios = array_slice(explode(",", $this->postParam("audios")), 0, 1000); if(empty($title) || iconv_strlen($title) < 1) - $this->flashFail("err", tr("error"), tr("set_playlist_name")); + $this->flashFail("err", tr("error"), tr("set_playlist_name"), NULL, $is_ajax); $playlist = new Playlist; $playlist->setOwner($owner); @@ -348,12 +362,12 @@ function renderNewPlaylist(): void if($_FILES["cover"]["error"] === UPLOAD_ERR_OK) { if(!str_starts_with($_FILES["cover"]["type"], "image")) - $this->flashFail("err", tr("error"), tr("not_a_photo")); + $this->flashFail("err", tr("error"), tr("not_a_photo"), NULL, $is_ajax); try { $playlist->fastMakeCover($this->user->id, $_FILES["cover"]); } catch(\Throwable $e) { - $this->flashFail("err", tr("error"), tr("invalid_cover_photo")); + $this->flashFail("err", tr("error"), tr("invalid_cover_photo"), NULL, $is_ajax); } } @@ -361,25 +375,22 @@ function renderNewPlaylist(): void foreach($audios as $audio) { $audio = $this->audios->get((int)$audio); - - if(!$audio || $audio->isDeleted() || !$audio->canBeViewedBy($this->user->identity)) + if(!$audio || $audio->isDeleted()) continue; $playlist->add($audio); } $playlist->bookmark(isset($club) ? $club : $this->user->identity); + if($is_ajax) { + $this->returnJson([ + 'success' => true, + 'redirect' => '/playlist' . $owner . "_" . $playlist->getId() + ]); + } $this->redirect("/playlist" . $owner . "_" . $playlist->getId()); } else { - if(isset($club)) { - $this->template->audios = iterator_to_array($this->audios->getByClub($club, 1, 10)); - $count = (new Audios)->getClubCollectionSize($club); - } else { - $this->template->audios = iterator_to_array($this->audios->getByUser($this->user->identity, 1, 10)); - $count = (new Audios)->getUserCollectionSize($this->user->identity); - } - - $this->template->pagesCount = ceil($count / 10); + $this->template->owner = $owner; } } @@ -435,28 +446,20 @@ function renderEditPlaylist(int $owner_id, int $virtual_id) $this->willExecuteWriteAction(); $playlist = $this->audios->getPlaylistByOwnerAndVID($owner_id, $virtual_id); - $page = (int)($this->queryParam("p") ?? 1); if (!$playlist || $playlist->isDeleted() || !$playlist->canBeModifiedBy($this->user->identity)) $this->notFound(); $this->template->playlist = $playlist; - $this->template->page = $page; $audios = iterator_to_array($playlist->fetch(1, $playlist->size())); - $this->template->audios = array_slice($audios, 0, 10); - $audiosIds = []; - - foreach($audios as $aud) - $audiosIds[] = $aud->getId(); - - $this->template->audiosIds = implode(",", array_unique($audiosIds)) . ","; + $this->template->audios = array_slice($audios, 0, 1000); $this->template->ownerId = $owner_id; $this->template->owner = $playlist->getOwner(); - $this->template->pagesCount = $pagesCount = ceil($playlist->size() / 10); if($_SERVER["REQUEST_METHOD"] !== "POST") return; + $is_ajax = (int)$this->postParam('ajax') == 1; $title = $this->postParam("title"); $description = $this->postParam("description"); $is_unlisted = (int)$this->postParam('is_unlisted'); @@ -471,12 +474,12 @@ function renderEditPlaylist(int $owner_id, int $virtual_id) $playlist->resetLength(); $playlist->setUnlisted((bool)$is_unlisted); - if($_FILES["new_cover"]["error"] === UPLOAD_ERR_OK) { - if(!str_starts_with($_FILES["new_cover"]["type"], "image")) + if($_FILES["cover"]["error"] === UPLOAD_ERR_OK) { + if(!str_starts_with($_FILES["cover"]["type"], "image")) $this->flashFail("err", tr("error"), tr("not_a_photo")); try { - $playlist->fastMakeCover($this->user->id, $_FILES["new_cover"]); + $playlist->fastMakeCover($this->user->id, $_FILES["cover"]); } catch(\Throwable $e) { $this->flashFail("err", tr("error"), tr("invalid_cover_photo")); } @@ -490,13 +493,18 @@ function renderEditPlaylist(int $owner_id, int $virtual_id) foreach ($new_audios as $new_audio) { $audio = (new Audios)->get((int)$new_audio); - if(!$audio || $audio->isDeleted()) continue; $playlist->add($audio); } + if($is_ajax) { + $this->returnJson([ + 'success' => true, + 'redirect' => '/playlist' . $playlist->getPrettyId() + ]); + } $this->redirect("/playlist".$playlist->getPrettyId()); } @@ -762,6 +770,15 @@ function renderApiGetContext() $audios = $stream->page($page, 10); $audiosCount = $stream->size(); break; + case 'alone_audio': + $found_audio = $this->audios->get($ctx_id); + if(!$found_audio || $found_audio->isDeleted() || !$found_audio->canBeViewedBy($this->user->identity)) { + $this->flashFail("err", "Error", "Not found", 89, true); + } + + $audios = [$found_audio]; + $audiosCount = 1; + break; } $pagesCount = ceil($audiosCount / $perPage); @@ -779,16 +796,21 @@ function renderApiGetContext() $audiosArr = []; foreach($audios as $audio) { - $audiosArr[] = [ - "id" => $audio->getId(), - "name" => $audio->getTitle(), - "performer" => $audio->getPerformer(), - "keys" => $audio->getKeys(), - "url" => $audio->getUrl(), - "length" => $audio->getLength(), - "available" => $audio->isAvailable(), - "withdrawn" => $audio->isWithdrawn(), - ]; + $output_array = []; + $output_array['id'] = $audio->getId(); + $output_array['name'] = $audio->getTitle(); + $output_array['performer'] = $audio->getPerformer(); + + if(!$audio->isWithdrawn()) { + $output_array['keys'] = $audio->getKeys(); + $output_array['url'] = $audio->getUrl(); + } + + $output_array['length'] = $audio->getLength(); + $output_array['available'] = $audio->isAvailable(); + $output_array['withdrawn'] = $audio->isWithdrawn(); + + $audiosArr[] = $output_array; } $resultArr = [ diff --git a/Web/Presenters/AuthPresenter.php b/Web/Presenters/AuthPresenter.php index 7edcda7c2..6db7758c7 100644 --- a/Web/Presenters/AuthPresenter.php +++ b/Web/Presenters/AuthPresenter.php @@ -228,6 +228,7 @@ function renderFinishRestoringPassword(): void return; } + $this->template->disable_ajax = 1; $this->template->is2faEnabled = $request->getUser()->is2faEnabled(); if($_SERVER["REQUEST_METHOD"] === "POST") { diff --git a/Web/Presenters/MessengerPresenter.php b/Web/Presenters/MessengerPresenter.php index e04e1adc6..cec99cff5 100644 --- a/Web/Presenters/MessengerPresenter.php +++ b/Web/Presenters/MessengerPresenter.php @@ -63,6 +63,7 @@ function renderApp(int $sel): void $this->flash("err", tr("warning"), tr("user_may_not_reply")); } + $this->template->disable_ajax = 1; $this->template->selId = $sel; $this->template->correspondent = $correspondent; } diff --git a/Web/Presenters/NoSpamPresenter.php b/Web/Presenters/NoSpamPresenter.php index 8164d05e0..714cac93c 100644 --- a/Web/Presenters/NoSpamPresenter.php +++ b/Web/Presenters/NoSpamPresenter.php @@ -38,6 +38,7 @@ function renderIndex(): void if ($mode === "form") { $this->template->_template = "NoSpam/Index"; + $this->template->disable_ajax = 1; $foundClasses = []; foreach (Finder::findFiles('*.php')->from($targetDir) as $file) { $content = file_get_contents($file->getPathname()); @@ -67,6 +68,7 @@ function renderIndex(): void $this->template->models = $models; } else if ($mode === "templates") { $this->template->_template = "NoSpam/Templates.xml"; + $this->template->disable_ajax = 1; $filter = []; if ($this->queryParam("id")) { $filter["id"] = (int)$this->queryParam("id"); diff --git a/Web/Presenters/OpenVKPresenter.php b/Web/Presenters/OpenVKPresenter.php index 6df21bd24..1d03a1c28 100644 --- a/Web/Presenters/OpenVKPresenter.php +++ b/Web/Presenters/OpenVKPresenter.php @@ -282,11 +282,11 @@ function onStartup(): void $this->redirect("/maintenances/"); } } - - /*if($this->queryParam('al') == '1') { - $this->assertNoCSRF(); + + if($_SERVER['HTTP_X_OPENVK_AJAX_QUERY'] == '1' && $this->user->identity) { + error_reporting(0); header('Content-Type: text/plain; charset=UTF-8'); - }*/ + } parent::onStartup(); } diff --git a/Web/Presenters/ReportPresenter.php b/Web/Presenters/ReportPresenter.php index 0c4cbd83a..a627efa4c 100644 --- a/Web/Presenters/ReportPresenter.php +++ b/Web/Presenters/ReportPresenter.php @@ -43,6 +43,7 @@ function renderList(): void "perPage" => 15, ]; $this->template->mode = $act ?? "all"; + $this->template->disable_ajax = 1; if ($_SERVER["REQUEST_METHOD"] === "POST") { $reports = []; @@ -78,6 +79,7 @@ function renderView(int $id): void $this->notFound(); $this->template->report = $report; + $this->template->disable_ajax = 1; } function renderCreate(int $id): void diff --git a/Web/Presenters/UserPresenter.php b/Web/Presenters/UserPresenter.php index 4c6bb0dd3..6120bfec5 100644 --- a/Web/Presenters/UserPresenter.php +++ b/Web/Presenters/UserPresenter.php @@ -34,7 +34,7 @@ function renderView(int $id): void $this->template->_template = "User/deactivated.xml"; $this->template->user = $user; - } else if(!$user->canBeViewedBy($this->user->identity)) { + } else if(!is_null($user) && !$user->canBeViewedBy($this->user->identity)) { $this->template->_template = "User/private.xml"; $this->template->user = $user; diff --git a/Web/Presenters/templates/@layout.xml b/Web/Presenters/templates/@layout.xml index 0e514bb86..b7d84b96d 100644 --- a/Web/Presenters/templates/@layout.xml +++ b/Web/Presenters/templates/@layout.xml @@ -20,7 +20,6 @@ {script "js/utils.js"} {script "js/node_modules/dashjs/dist/dash.all.min.js"} - {script "js/al_music.js"} {css "js/node_modules/tippy.js/dist/backdrop.css"} {css "js/node_modules/cropperjs/dist/cropper.css"} @@ -31,6 +30,10 @@ {script "js/node_modules/@popperjs/core/dist/umd/popper.min.js"} {script "js/node_modules/tippy.js/dist/tippy-bundle.umd.min.js"} {script "js/node_modules/handlebars/dist/handlebars.min.js"} + {script "js/node_modules/react/dist/react-with-addons.min.js"} + {script "js/node_modules/react-dom/dist/react-dom.min.js"} + {script "js/vnd_literallycanvas.js"} + {css "js/node_modules/literallycanvas/lib/css/literallycanvas.css"} {if $isTimezoned == NULL} {script "js/timezone.js"} @@ -199,18 +202,18 @@ {var $canAccessHelpdesk = $thisUser->getChandlerUser()->can("write")->model('openvk\Web\Models\Entities\TicketReply')->whichBelongsTo(0)} {var $menuLinksAvaiable = sizeof(OPENVK_ROOT_CONF['openvk']['preferences']['menu']['links']) > 0 && $thisUser->getLeftMenuItemStatus('links')}
- {_admin} - {_helpdesk} + {_admin} + {_helpdesk} {if $helpdeskTicketNotAnsweredCount > 0} ({$helpdeskTicketNotAnsweredCount}) {/if} - {tr("reports")} + {tr("reports")} {if $reportNotAnsweredCount > 0} ({$reportNotAnsweredCount}) {/if} - + noSpam - {ifset bodyScripts} {include bodyScripts} {/ifset} + {script "js/router.js"}