From 791c36416d4787fdc403f2851e529930ef153f21 Mon Sep 17 00:00:00 2001 From: lalka2018 <99399973+lalka2016@users.noreply.github.com> Date: Tue, 21 Nov 2023 20:14:38 +0300 Subject: [PATCH] Add something related with videos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Теперь видосы работают как аудио, пользователи могут добавлять и удалять видео из коллекции. Но, правда, после обновления пользователи потеряют все свои видео, потом подумаю как исправить - Ещё теперь видео можно загружать в группу, жесть. И на странице группы теперь показывается 2 случайных видео из группы - Возможно, исправлена загрузка видео под виндовс (а может я её сломал) - У видосов теперь сохраняется ширина и высота, а так же длина - У прикреплённого видео рядом с названием показывается его длина - Видео теперь размещаются в masonry layout. Если помимо видео у поста есть другие фотографии или другие видео, то показывается только обложка видео и кнопка проигрывания - В класс video в api добавлена поддержка просмотра видеозаписей из групп --- VKAPI/Handlers/Video.php | 17 +- Web/Models/Entities/Club.php | 13 ++ .../Entities/Traits/TAttachmentHost.php | 7 +- Web/Models/Entities/Video.php | 166 ++++++++++++++++-- Web/Models/Repositories/Videos.php | 61 ++++++- Web/Models/shell/processVideo.ps1 | 8 +- Web/Presenters/GroupPresenter.php | 4 +- Web/Presenters/VideosPresenter.php | 29 ++- Web/Presenters/templates/Group/View.xml | 26 +++ Web/Presenters/templates/Videos/List.xml | 8 +- Web/Presenters/templates/Videos/Upload.xml | 4 +- .../templates/components/attachment.xml | 42 +++-- .../templates/components/comment.xml | 2 +- .../components/post/microblogpost.xml | 2 +- .../templates/components/post/oldpost.xml | 2 +- Web/Util/Makima/Makima.php | 2 +- Web/static/css/main.css | 29 +++ Web/static/img/video_controls.png | Bin 0 -> 2466 bytes install/sqls/00043-better-videos.sql | 10 ++ locales/ru.strings | 2 + 20 files changed, 365 insertions(+), 69 deletions(-) create mode 100644 Web/static/img/video_controls.png create mode 100644 install/sqls/00043-better-videos.sql diff --git a/VKAPI/Handlers/Video.php b/VKAPI/Handlers/Video.php index 5d0967c7..b2124615 100755 --- a/VKAPI/Handlers/Video.php +++ b/VKAPI/Handlers/Video.php @@ -36,21 +36,22 @@ final class Video extends VKAPIRequestHandler ]; } else { if ($owner_id > 0) - $user = (new UsersRepo)->get($owner_id); + $owner = (new UsersRepo)->get($owner_id); else - $this->fail(1, "Not implemented"); + $owner = (new ClubsRepo)->get(abs($owner_id)); - if(!$user->getPrivacyPermission('videos.read', $this->getUser())) { + if(!$owner) + $this->fail(20, "Invalid user"); + + if($owner_id > 0 && !$owner->getPrivacyPermission('videos.read', $this->getUser())) $this->fail(20, "Access denied: this user chose to hide his videos"); - } - $videos = (new VideosRepo)->getByUser($user, $offset + 1, $count); - $videosCount = (new VideosRepo)->getUserVideosCount($user); + $videos = (new VideosRepo)->getByEntityId($owner_id, $offset, $count); + $videosCount = (new VideosRepo)->getVideosCountByEntityId($owner_id); $items = []; - foreach ($videos as $video) { + foreach ($videos as $video) $items[] = $video->getApiStructure($this->getUser()); - } return (object) [ "count" => $videosCount, diff --git a/Web/Models/Entities/Club.php b/Web/Models/Entities/Club.php index 5324efb6..8d908011 100644 --- a/Web/Models/Entities/Club.php +++ b/Web/Models/Entities/Club.php @@ -414,6 +414,11 @@ class Club extends RowModel return (bool) $this->getRecord()->everyone_can_upload_audios; } + function isEveryoneCanUploadVideos(): bool + { + return false; + } + function canUploadAudio(?User $user): bool { if(!$user) @@ -422,6 +427,14 @@ class Club extends RowModel return $this->isEveryoneCanUploadAudios() || $this->canBeModifiedBy($user); } + function canUploadVideo(?User $user): bool + { + if(!$user) + return NULL; + + return $this->isEveryoneCanUploadAudios() || $this->canBeModifiedBy($user); + } + function getAudiosCollectionSize() { return (new \openvk\Web\Models\Repositories\Audios)->getClubCollectionSize($this); diff --git a/Web/Models/Entities/Traits/TAttachmentHost.php b/Web/Models/Entities/Traits/TAttachmentHost.php index db814cce..7d7c6eb6 100644 --- a/Web/Models/Entities/Traits/TAttachmentHost.php +++ b/Web/Models/Entities/Traits/TAttachmentHost.php @@ -1,6 +1,6 @@ getChildren(); + $children = iterator_to_array($this->getChildren()); $skipped = $photos = $result = []; foreach($children as $child) { - if($child instanceof Photo) { + if($child instanceof Photo || $child instanceof Video && $child->getDimensions()) { $photos[] = $child; continue; } @@ -68,6 +68,7 @@ trait TAttachmentHost "height" => $height . "px", "tiles" => $result, "extras" => $skipped, + "count" => sizeof($children), ]; } diff --git a/Web/Models/Entities/Video.php b/Web/Models/Entities/Video.php index fa54392e..aa6c0bd7 100644 --- a/Web/Models/Entities/Video.php +++ b/Web/Models/Entities/Video.php @@ -4,6 +4,7 @@ use openvk\Web\Util\Shell\Shell; use openvk\Web\Util\Shell\Exceptions\{ShellUnavailableException, UnknownCommandException}; use openvk\Web\Models\VideoDrivers\VideoDriver; use Nette\InvalidStateException as ISE; +use Chandler\Database\DatabaseConnection; define("VIDEOS_FRIENDLY_ERROR", "Uploads are disabled on this instance :<", false); @@ -34,10 +35,25 @@ class Video extends Media if(sizeof($durations[1]) === 0) throw new \DomainException("$filename does not contain any meaningful video streams"); - foreach($durations[1] as $duration) - if(floatval($duration) < 1.0) + $length = 0; + foreach($durations[1] as $duration) { + $duration = floatval($duration); + if($duration < 1.0) throw new \DomainException("$filename does not contain any meaningful video streams"); + else + $length = max($length, $duration); + } + + $this->stateChanges("length", (int) round($length, 0, PHP_ROUND_HALF_EVEN)); + preg_match('%width=([0-9\.]++)%', $streams, $width); + preg_match('%height=([0-9\.]++)%', $streams, $height); + + if(!empty($width) && !empty($height)) { + $this->stateChanges("width", $width[1]); + $this->stateChanges("width", $height[1]); + } + try { if(!is_dir($dirId = dirname($this->pathFromHash($hash)))) mkdir($dirId); @@ -45,7 +61,11 @@ class Video extends Media $dir = $this->getBaseDir(); $ext = Shell::isPowershell() ? "ps1" : "sh"; $cmd = Shell::isPowershell() ? "powershell" : "bash"; - Shell::$cmd(__DIR__ . "/../shell/processVideo.$ext", OPENVK_ROOT, $filename, $dir, $hash)->start(); #async :DDD + + if($cmd == "bash") + Shell::$cmd(__DIR__ . "/../shell/processVideo.$ext", OPENVK_ROOT, $filename, $dir, $hash)->start(); # async :DDD + else + Shell::$cmd(__DIR__ . "/../shell/processVideo.$ext", OPENVK_ROOT, $filename, $dir, $hash)->execute($err); # под виндой только execute } catch(ShellUnavailableException $suex) { exit(OPENVK_ROOT_CONF["openvk"]["debug"] ? "Shell is unavailable" : VIDEOS_FRIENDLY_ERROR); } catch(UnknownCommandException $ucex) { @@ -118,11 +138,12 @@ class Video extends Media function getApiStructure(?User $user = NULL): object { $fromYoutube = $this->getType() == Video::TYPE_EMBED; + $dimensions = $this->getDimensions(); $res = (object)[ "type" => "video", "video" => [ "can_comment" => 1, - "can_like" => 1, // we don't h-have wikes in videos + "can_like" => 1, "can_repost" => 1, "can_subscribe" => 1, "can_add_to_faves" => 0, @@ -130,7 +151,7 @@ class Video extends Media "comments" => $this->getCommentsCount(), "date" => $this->getPublicationTime()->timestamp(), "description" => $this->getDescription(), - "duration" => 0, // я хуй знает как получить длину видео + "duration" => $this->getLength(), "image" => [ [ "url" => $this->getThumbnailURL(), @@ -139,8 +160,8 @@ class Video extends Media "with_padding" => 1 ] ], - "width" => 640, - "height" => 480, + "width" => $dimensions ? NULL : $dimensions[0], + "height" => $dimensions ? NULL : $dimensions[1], "id" => $this->getVirtualId(), "owner_id" => $this->getOwner()->getId(), "user_id" => $this->getOwner()->getId(), @@ -194,10 +215,7 @@ class Video extends Media function isDeleted(): bool { - if ($this->getRecord()->deleted == 1) - return TRUE; - else - return FALSE; + return $this->getRecord()->deleted == 1; } function deleteVideo(): void @@ -205,6 +223,8 @@ class Video extends Media $this->setDeleted(1); $this->unwire(); $this->save(); + + $ctx->table("video_relations")->where("video", $this->getId())->delete(); } static function fastMake(int $owner, string $name = "Unnamed Video.ogv", string $description = "", array $file, bool $unlisted = true, bool $anon = false): Video @@ -221,7 +241,7 @@ class Video extends Media $video->setFile($file); $video->setUnlisted($unlisted); $video->save(); - + return $video; } @@ -243,4 +263,126 @@ class Video extends Media return $res; } + + function isInLibraryOf($entity): bool + { + return sizeof(DatabaseConnection::i()->getContext()->table("video_relations")->where([ + "entity" => $entity->getId() * ($entity instanceof Club ? -1 : 1), + "video" => $this->getId(), + ])) != 0; + } + + function add($entity): bool + { + if($this->isInLibraryOf($entity)) + return false; + + $entityId = $entity->getId() * ($entity instanceof Club ? -1 : 1); + $audioRels = DatabaseConnection::i()->getContext()->table("video_relations"); + + $audioRels->insert([ + "entity" => $entityId, + "video" => $this->getId(), + ]); + + return true; + } + + function remove($entity): bool + { + if(!$this->isInLibraryOf($entity)) + return false; + + DatabaseConnection::i()->getContext()->table("video_relations")->where([ + "entity" => $entity->getId() * ($entity instanceof Club ? -1 : 1), + "video" => $this->getId(), + ])->delete(); + + return true; + } + + function getLength() + { + return $this->getRecord()->length; + } + + function getFormattedLength(): string + { + $len = $this->getLength(); + if(!$len) return "00:00"; + + $mins = floor($len / 60); + $secs = $len - ($mins * 60); + + return ( + str_pad((string) $mins, 2, "0", STR_PAD_LEFT) + . ":" . + str_pad((string) $secs, 2, "0", STR_PAD_LEFT) + ); + } + + function fillDimensions() + { + $hash = $this->getRecord()->hash; + $path = $this->pathFromHash($hash); + + if(!file_exists($path)) { + $this->stateChanges("width", 0); + $this->stateChanges("height", 0); + $this->stateChanges("length", 0); + + $this->save(); + + return false; + } + + $streams = Shell::ffprobe("-i", $path, "-show_streams", "-select_streams v", "-loglevel error")->execute($error); + + $durations = []; + + preg_match_all('%duration=([0-9\.]++)%', $streams, $durations); + + $length = 0; + foreach($durations[1] as $duration) { + $duration = floatval($duration); + if($duration < 1.0) + continue; + else + $length = max($length, $duration); + } + + $this->stateChanges("length", (int) round($length, 0, PHP_ROUND_HALF_EVEN)); + + preg_match('%width=([0-9\.]++)%', $streams, $width); + preg_match('%height=([0-9\.]++)%', $streams, $height); + + #exit(var_dump($path)); + if(!empty($width) && !empty($height)) { + $this->stateChanges("width", $width[1]); + $this->stateChanges("height", $height[1]); + } + + $this->save(); + + return true; + } + + function getDimensions() + { + if($this->getType() == Video::TYPE_EMBED) return NULL; + + $width = $this->getRecord()->width; + $height = $this->getRecord()->height; + if(!$width) $this->fillDimensions(); + + return $width != 0 ? [$width, $height] : NULL; + } + + function delete(bool $softly = true): void + { + $ctx = DatabaseConnection::i()->getContext(); + $ctx->table("video_relations")->where("video", $this->getId())->delete(); + + parent::delete($softly); + } } diff --git a/Web/Models/Repositories/Videos.php b/Web/Models/Repositories/Videos.php index 2d41c3f9..93097e7c 100644 --- a/Web/Models/Repositories/Videos.php +++ b/Web/Models/Repositories/Videos.php @@ -1,6 +1,6 @@ context = DatabaseConnection::i()->getContext(); $this->videos = $this->context->table("videos"); + $this->rels = $this->context->table("video_relations"); } function get(int $id): ?Video @@ -33,17 +35,66 @@ class Videos return new Video($videos); } + + function getByEntityId(int $entity, int $offset = 0, ?int $limit = NULL): \Traversable + { + $limit ??= OPENVK_DEFAULT_PER_PAGE; + $iter = $this->rels->where("entity", $entity)->limit($limit, $offset)->order("id DESC"); + foreach($iter as $rel) { + $vid = $this->get($rel->video); + if(!$vid || $vid->isDeleted()) { + continue; + } + + yield $vid; + } + } + + function getVideosCountByEntityId(int $id) + { + return sizeof($this->rels->where("entity", $id)); + } function getByUser(User $user, int $page = 1, ?int $perPage = NULL): \Traversable { - $perPage = $perPage ?? OPENVK_DEFAULT_PER_PAGE; - foreach($this->videos->where("owner", $user->getId())->where(["deleted" => 0, "unlisted" => 0])->page($page, $perPage)->order("created DESC") as $video) - yield new Video($video); + return $this->getByEntityId($user->getId(), ($perPage * ($page - 1)), $perPage); + } + + function getByClub(Club $club, int $page = 1, ?int $perPage = NULL): \Traversable + { + return $this->getByEntityId($club->getRealId(), ($perPage * ($page - 1)), $perPage); } function getUserVideosCount(User $user): int { - return sizeof($this->videos->where("owner", $user->getId())->where(["deleted" => 0, "unlisted" => 0])); + return sizeof($this->rels->where("entity", $user->getId())); + } + + function getRandomTwoVideosByEntityId(int $id): Array + { + $iter = $this->rels->where("entity", $id); + $ids = []; + + foreach($iter as $it) + $ids[] = $it->video; + + $shuffleSeed = openssl_random_pseudo_bytes(6); + $shuffleSeed = hexdec(bin2hex($shuffleSeed)); + + $ids = knuth_shuffle($ids, $shuffleSeed); + $ids = array_slice($ids, 0, 3); + $videos = []; + + foreach($ids as $id) { + $video = $this->get((int)$id); + + if(!$video || $video->isDeleted()) + continue; + + $videos[] = $video; + } + + return $videos; } function find(string $query = "", array $pars = [], string $sort = "id"): Util\EntityStream diff --git a/Web/Models/shell/processVideo.ps1 b/Web/Models/shell/processVideo.ps1 index f2cc9918..4e752487 100644 --- a/Web/Models/shell/processVideo.ps1 +++ b/Web/Models/shell/processVideo.ps1 @@ -9,12 +9,12 @@ $temp2 = [System.IO.Path]::GetTempFileName() $shell = Get-WmiObject Win32_process -filter "ProcessId = $PID" $shell.SetPriority(16384) +Remove-Item $temp Move-Item $file $temp # video stub logic was implicitly deprecated, so we start processing at once -ffmpeg -i $temp -ss 00:00:01.000 -vframes 1 "$dir$hashT/$hash.gif" -ffmpeg -i $temp -c:v libx264 -q:v 7 -c:a libmp3lame -q:a 4 -tune zerolatency -vf "scale=640:480:force_original_aspect_ratio=decrease,pad=640:480:(ow-iw)/2:(oh-ih)/2,setsar=1" -y $temp2 +ffmpeg -i $temp -ss 00:00:01.000 -y -vframes 1 "$dir$hashT/$hash.gif" +ffmpeg -i $temp -c:v libx264 -f mp4 -q:v 7 -c:a libmp3lame -q:a 4 -tune zerolatency -vf "scale=640:480:force_original_aspect_ratio=decrease,pad=640:480:(ow-iw)/2:(oh-ih)/2,setsar=1" -y $temp2 -Move-Item $temp2 "$dir$hashT/$hash.mp4" -Remove-Item $temp +Move-Item $temp2 "$dir$hashT/$hash.mp4" -Force Remove-Item $temp2 diff --git a/Web/Presenters/GroupPresenter.php b/Web/Presenters/GroupPresenter.php index beeede13..b2ec52aa 100644 --- a/Web/Presenters/GroupPresenter.php +++ b/Web/Presenters/GroupPresenter.php @@ -3,7 +3,7 @@ namespace openvk\Web\Presenters; use openvk\Web\Models\Entities\{Club, Photo, Post}; use Nette\InvalidStateException; use openvk\Web\Models\Entities\Notifications\ClubModeratorNotification; -use openvk\Web\Models\Repositories\{Clubs, Users, Albums, Managers, Topics, Audios, Posts}; +use openvk\Web\Models\Repositories\{Clubs, Users, Albums, Managers, Topics, Audios, Posts, Videos}; use Chandler\Security\Authenticator; final class GroupPresenter extends OpenVKPresenter @@ -31,6 +31,8 @@ final class GroupPresenter extends OpenVKPresenter $this->template->albumsCount = (new Albums)->getClubAlbumsCount($club); $this->template->topics = (new Topics)->getLastTopics($club, 3); $this->template->topicsCount = (new Topics)->getClubTopicsCount($club); + $this->template->videos = (new Videos)->getRandomTwoVideosByEntityId($club->getRealId()); + $this->template->videosCount = (new Videos)->getVideosCountByEntityId($club->getRealId()); $this->template->audios = (new Audios)->getRandomThreeAudiosByEntityId($club->getRealId()); $this->template->audiosCount = (new Audios)->getClubCollectionSize($club); } diff --git a/Web/Presenters/VideosPresenter.php b/Web/Presenters/VideosPresenter.php index 6f92891c..a30d7051 100644 --- a/Web/Presenters/VideosPresenter.php +++ b/Web/Presenters/VideosPresenter.php @@ -1,7 +1,7 @@ users->get($id); - if(!$user) $this->notFound(); - if(!$user->getPrivacyPermission('videos.read', $this->user->identity ?? NULL)) + if($id > 0) + $owner = $this->users->get($id); + else + $owner = (new Clubs)->get(abs($id)); + + if(!$owner) $this->notFound(); + if($id > 0 && !$owner->getPrivacyPermission('videos.read', $this->user->identity ?? NULL)) $this->flashFail("err", tr("forbidden"), tr("forbidden_comment")); - $this->template->user = $user; - $this->template->videos = $this->videos->getByUser($user, (int) ($this->queryParam("p") ?? 1)); - $this->template->count = $this->videos->getUserVideosCount($user); + $this->template->owner = $owner; + $this->template->canUpload = $id > 0 ? $id == $this->user->id : $owner->canBeModifiedBy($this->user->identity); + $this->template->videos = $id > 0 ? $this->videos->getByUser($owner, (int) ($this->queryParam("p") ?? 1)) : $this->videos->getByClub($owner, (int) ($this->queryParam("p") ?? 1)); + $this->template->count = $this->videos->getVideosCountByEntityId($owner->getRealId()); $this->template->paginatorConf = (object) [ "count" => $this->template->count, "page" => (int) ($this->queryParam("p") ?? 1), @@ -60,6 +65,14 @@ final class VideosPresenter extends OpenVKPresenter if(OPENVK_ROOT_CONF['openvk']['preferences']['videos']['disableUploading']) $this->flashFail("err", tr("error"), tr("video_uploads_disabled")); + if($this->queryParam("gid")) { + $club = (new Clubs)->get((int)$this->queryParam("gid")); + + if(!$club || !$club->canUploadVideo($this->user->identity)) + $this->notFound(); + } + + $this->template->owner = $club ?: $this->user->identity; if($_SERVER["REQUEST_METHOD"] === "POST") { if(!empty($this->postParam("name"))) { $video = new Video; @@ -82,6 +95,8 @@ final class VideosPresenter extends OpenVKPresenter } $video->save(); + + $video->add(!isset($club) ? $this->user->identity : $club); $this->redirect("/video" . $video->getPrettyId()); } else { diff --git a/Web/Presenters/templates/Group/View.xml b/Web/Presenters/templates/Group/View.xml index 7d2066c2..f45fe73a 100644 --- a/Web/Presenters/templates/Group/View.xml +++ b/Web/Presenters/templates/Group/View.xml @@ -299,6 +299,32 @@ +
+
+ {_videos} +
+
+
+ {tr("videos", $videosCount)} +
+ {_all_title} +
+
+
+
+ + + +
+ {ovk_proc_strtr($video->getName(), 30)}
+ {$video->getPublicationTime()} | {_comments} ({$video->getCommentsCount()}) +
+
+
+
+
{_discussions} diff --git a/Web/Presenters/templates/Videos/List.xml b/Web/Presenters/templates/Videos/List.xml index 57db0b8f..61928732 100644 --- a/Web/Presenters/templates/Videos/List.xml +++ b/Web/Presenters/templates/Videos/List.xml @@ -3,10 +3,10 @@ {var $count = $paginatorConf->count} {var $page = $paginatorConf->page} -{block title}{_videos} {$user->getCanonicalName()}{/block} +{block title}{_videos} {$owner->getRealId() > 0 ? $owner->getCanonicalName() : tr("group_genetive")}{/block} {block header} - {$user->getCanonicalName()} + {$owner->getCanonicalName()} » {_videos} {/block} @@ -14,9 +14,9 @@
{tr("videos", $count)} - +  |  - {_upload_video} + {_upload_video}
diff --git a/Web/Presenters/templates/Videos/Upload.xml b/Web/Presenters/templates/Videos/Upload.xml index 230d8bd8..383c39fe 100644 --- a/Web/Presenters/templates/Videos/Upload.xml +++ b/Web/Presenters/templates/Videos/Upload.xml @@ -2,9 +2,9 @@ {block title}{_upload_video}{/block} {block header} - {$thisUser->getCanonicalName()} + {$owner->getCanonicalName()} » - {_videos} + {_videos} » {_upload_video} {/block} diff --git a/Web/Presenters/templates/components/attachment.xml b/Web/Presenters/templates/components/attachment.xml index fbc36ede..fb122f24 100644 --- a/Web/Presenters/templates/components/attachment.xml +++ b/Web/Presenters/templates/components/attachment.xml @@ -10,27 +10,31 @@ {/if} {elseif $attachment instanceof \openvk\Web\Models\Entities\Video} - {if !$attachment->isDeleted()} - {if $attachment->getType() === 0} -
- + {if $count && $count < 2} + {if $attachment->getType() === 0} +
+ +
+ {else} + {var $driver = $attachment->getVideoDriver()} + {if !$driver} + {_version_incompatibility} + {else} + {$driver->getEmbed("100%")|noescape} + {/if} + {/if} + +
+ + {$attachment->getName()} + {if $attachment->getLength()} + ({$attachment->getFormattedLength()}) + {/if}
{else} - {var $driver = $attachment->getVideoDriver()} - {if !$driver} - {_version_incompatibility} - {else} - {$driver->getEmbed("100%")|noescape} - {/if} - {/if} - - - - {else} - {_video_is_deleted} +
+ {$attachment->getName()} +
{/if} {elseif $attachment instanceof \openvk\Web\Models\Entities\Poll} {presenter "openvk!Poll->view", $attachment->getId()} diff --git a/Web/Presenters/templates/components/comment.xml b/Web/Presenters/templates/components/comment.xml index 461b8307..c91d6544 100644 --- a/Web/Presenters/templates/components/comment.xml +++ b/Web/Presenters/templates/components/comment.xml @@ -25,7 +25,7 @@ {var $attachmentsLayout = $comment->getChildrenWithLayout(288)}
- {include "attachment.xml", attachment => $attachment[2], parent => $comment, parentType => "comment"} + {include "attachment.xml", attachment => $attachment[2], parent => $comment, parentType => "comment", count => $attachmentsLayout->count}
diff --git a/Web/Presenters/templates/components/post/microblogpost.xml b/Web/Presenters/templates/components/post/microblogpost.xml index 0b0978bc..4ad24a9a 100644 --- a/Web/Presenters/templates/components/post/microblogpost.xml +++ b/Web/Presenters/templates/components/post/microblogpost.xml @@ -81,7 +81,7 @@ {var $attachmentsLayout = $post->getChildrenWithLayout($width)}
- {include "../attachment.xml", attachment => $attachment[2], parent => $post, parentType => "post"} + {include "../attachment.xml", attachment => $attachment[2], parent => $post, parentType => "post", count => $attachmentsLayout->count}
diff --git a/Web/Presenters/templates/components/post/oldpost.xml b/Web/Presenters/templates/components/post/oldpost.xml index 6f5e16d8..e9c50bea 100644 --- a/Web/Presenters/templates/components/post/oldpost.xml +++ b/Web/Presenters/templates/components/post/oldpost.xml @@ -73,7 +73,7 @@ {var $attachmentsLayout = $post->getChildrenWithLayout($width)}
- {include "../attachment.xml", attachment => $attachment[2], parent => $post, parentType => "post"} + {include "../attachment.xml", attachment => $attachment[2], parent => $post, parentType => "post", count => $attachmentsLayout->count}
diff --git a/Web/Util/Makima/Makima.php b/Web/Util/Makima/Makima.php index e31bfa42..57c2a7a5 100644 --- a/Web/Util/Makima/Makima.php +++ b/Web/Util/Makima/Makima.php @@ -18,7 +18,7 @@ class Makima $this->photos = $photos; } - private function getOrientation(Photo $photo, &$ratio): int + private function getOrientation($photo, &$ratio): int { [$width, $height] = $photo->getDimensions(); $ratio = $width / $height; diff --git a/Web/static/css/main.css b/Web/static/css/main.css index 0e8b06d9..8aaa29ae 100644 --- a/Web/static/css/main.css +++ b/Web/static/css/main.css @@ -3056,3 +3056,32 @@ hr { background-position: 50% !important; } +.compactVideo { + object-fit: contain; + cursor: pointer; + background: black; + width: calc(100% - 2px); + height: calc(100% - 2px); /* kostyls */ + display: flex; + position: relative; + min-height: 28px; +} + +.compactVideo img { + object-fit: contain; + margin-left: auto; + margin-right: auto; +} + +.compactVideo::before { + content: " "; + background: url("/assets/packages/static/openvk/img/video_controls.png"); + width: 28px; + height: 28px; + position: absolute; + left: 0; + right: 0; + margin: auto; + top: 0; + bottom: 0; +} \ No newline at end of file diff --git a/Web/static/img/video_controls.png b/Web/static/img/video_controls.png new file mode 100644 index 0000000000000000000000000000000000000000..b1966dc457ba753a57a1c9a7704238569685650f GIT binary patch literal 2466 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|SkfJR z9T^xl_H+M9WCij$3p^r=85sBugD~Uq{1qucF>_BB$B>G+w|5P*g99bl9$dTOVA9vr z(JjEPsOszy+r+lK?Cr7#@-HrJU6Sqn^4eN^ha($j@8a0VD-xZ}yiFuVMkZ#Cj*wLD z>%9d=S5M{MiqWc+tN8gqy6E}zV*hsn3=9rYZHHw#Kbf3btg*AA@Zhb$u*G{iK554R z9n`EY{A{zvFf#JY|okD3fpC-1oCo%y&xgy%(*T-8|?=Sf( z!@%%B=#?1I(1v}%4nXpXh62!nEFtj;Teoh_S{P8!&dk8@BJvSa(Au!~Ir;hiXU?6w zCoA`^&W?qFL1Cxy-lnPNpKmTMF6K8gH_twr^sy=es6pk@W!VWuJ8QC&larI`>i)&4 zO)iuH+N^Tvv+9=^z4EPb>!(Mrz4q8^X_4|8Mg|7ItHq2jwZyv3XP_N535tm@d66>6iZ2;Nact?CkD|ybKHlPUl&d+|BzR7ZdZx!piDbS#9lKcaRh3tXj^rY3tUn zxj8v+zMeUA=K0~nhaYbMM*NTE#-bDc{{8E>H?BT@Wyrm^Z{Gaj$p%{C0t^(l#UHnZ zXzh)Pi1<-d^X3B39E;uW%B|ztX11w=gZ9~-|4qP@F<}Z5(7Q|A7=fM(x~!}4*5J49 z+UG#WPY>AMu%_*1{#gS?h6ctdoW