nsfw cover change & add masonry video support

This commit is contained in:
mrilyew 2024-11-05 21:28:48 +03:00
parent ad61a89812
commit 873f00788d
12 changed files with 184 additions and 53 deletions

View file

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace openvk\Web\Models\Entities\Traits;
use openvk\Web\Models\Entities\{Attachable, Photo};
use openvk\Web\Models\Entities\{Attachable, Photo, Video};
use openvk\Web\Util\Makima\Makima;
use Chandler\Database\DatabaseConnection;
@ -36,10 +36,10 @@ trait TAttachmentHost
if($h < 0)
$h = $w;
$children = $this->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;
}

View file

@ -34,9 +34,23 @@ 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("height", $height[1]);
}
try {
if(!is_dir($dirId = dirname($this->pathFromHash($hash))))
@ -118,6 +132,7 @@ class Video extends Media
function getApiStructure(?User $user = NULL): object
{
$fromYoutube = $this->getType() == Video::TYPE_EMBED;
$dimensions = $this->getDimensions();
$res = (object)[
"type" => "video",
"video" => [
@ -130,7 +145,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 +154,8 @@ class Video extends Media
"with_padding" => 1
]
],
"width" => 640,
"height" => 480,
"width" => $dimensions ? $dimensions[0] : 640,
"height" => $dimensions ? $dimensions[1] : 480,
"id" => $this->getVirtualId(),
"owner_id" => $this->getOwner()->getId(),
"user_id" => $this->getOwner()->getId(),
@ -225,6 +240,74 @@ class Video extends Media
return $video;
}
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);
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 [320, 180];
$width = $this->getRecord()->width;
$height = $this->getRecord()->height;
if(!$width) return NULL;
return $width != 0 ? [$width, $height] : NULL;
}
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 canBeViewedBy(?User $user = NULL): bool
{
if($this->isDeleted() || $this->getOwner()->isDeleted()) {
@ -248,7 +331,7 @@ class Video extends Media
$res->owner_id = $this->getOwner()->getId();
$res->title = $this->getName();
$res->description = $this->getDescription();
$res->duration = "22";
$res->duration = $this->getLength();
$res->link = "/video".$this->getOwner()->getId()."_".$this->getVirtualId();
$res->image = $this->getThumbnailURL();
$res->date = $this->getPublicationTime()->timestamp();

View file

@ -10,23 +10,37 @@
</a>
{/if}
{elseif $attachment instanceof \openvk\Web\Models\Entities\Video}
{if $attachment->getType() === 0}
<div class="bsdn media" data-name="{$attachment->getName()}" data-author="{$attachment->getOwner()->getCanonicalName()}">
<video class="media" src="{$attachment->getURL()}"></video>
{if $tilesCount <= 1}
{if $attachment->getType() === 0}
<div class="bsdn media" data-name="{$attachment->getName()}" data-author="{$attachment->getOwner()->getCanonicalName()}">
<video class="media" src="{$attachment->getURL()}"></video>
</div>
{else}
{var $driver = $attachment->getVideoDriver()}
{if !$driver}
<span style="color:red;">{_version_incompatibility}</span>
{else}
{$driver->getEmbed("100%")|noescape}
{/if}
{/if}
<div class="video-wowzer">
<div class="small-video-ico"></div>
<a href="/video{$attachment->getPrettyId()}" id="videoOpen" data-id="{$attachment->getId()}">{$attachment->getName()}</a>
<span class="video-wowzer-length" n:if="$attachment->getLength() != NULL">({$attachment->getFormattedLength()})</span>
</div>
{else}
{var $driver = $attachment->getVideoDriver()}
{if !$driver}
<span style="color:red;">{_version_incompatibility}</span>
{else}
{$driver->getEmbed("100%")|noescape}
{/if}
{/if}
<a class='compact_video' id='videoOpen' data-id='{$attachment->getId()}' href="/video{$attachment->getPrettyId()}">
<div class='play-button'>
<div class='play-button-ico'></div>
</div>
<div class='video-length' n:if="$attachment->getLength() != NULL">
{$attachment->getFormattedLength()}
</div>
<div class="video-wowzer">
<img src="/assets/packages/static/openvk/img/videoico.png" />
<a href="/video{$attachment->getPrettyId()}" id="videoOpen" data-id="{$attachment->getId()}">{$attachment->getName()}</a>
</div>
<img class="media media_makima" src="{$attachment->getThumbnailURL()}" loading=lazy />
</a>
{/if}
{elseif $attachment instanceof \openvk\Web\Models\Entities\Poll}
{presenter "openvk!Poll->view", $attachment->getId()}
{elseif $attachment instanceof \openvk\Web\Models\Entities\Note}

View file

@ -74,7 +74,7 @@
{if $post->getTargetWall() < 0 && $wallOwner->canBeModifiedBy($thisUser)}data-fromgroup="{(int)$post->isPostedOnBehalfOfGroup()}"{/if}></a>
{/if}
</div>
<div class="post-content" id="{$post->getPrettyId()}">
<div class="post-content" id="{$post->getPrettyId()}" data-localized-nsfw-text="{_nsfw_warning}">
<div class="text" id="text{$post->getPrettyId()}">
<span data-text="{$post->getText(false)}" class="really_text">{$post->getText()|noescape}</span>
@ -84,8 +84,8 @@
{/if}
{var $attachmentsLayout = $post->getChildrenWithLayout($width)}
<div n:ifcontent class="attachments attachments_b" style="height: {$attachmentsLayout->height|noescape}; width: {$attachmentsLayout->width|noescape};">
<div class="attachment" n:foreach="$attachmentsLayout->tiles as $attachment" style="float: {$attachment[3]|noescape}; width: {$attachment[0]|noescape}; height: {$attachment[1]|noescape};" data-localized-nsfw-text="{_nsfw_warning}">
{include "../attachment.xml", attachment => $attachment[2], parent => $post, parentType => "post"}
<div class="attachment" n:foreach="$attachmentsLayout->tiles as $attachment" style="float: {$attachment[3]|noescape}; width: {$attachment[0]|noescape}; height: {$attachment[1]|noescape};">
{include "../attachment.xml", attachment => $attachment[2], parent => $post, parentType => "post", tilesCount => sizeof($attachmentsLayout->tiles)}
</div>
</div>

View file

@ -67,7 +67,7 @@
</a>
</a>
</div>
<div class="post-content" id="{$post->getPrettyId()}">
<div class="post-content" id="{$post->getPrettyId()}" data-localized-nsfw-text="{_nsfw_warning}">
<div class="text" id="text{$post->getPrettyId()}">
{var $owner = $author->getId()}
@ -79,8 +79,8 @@
{/if}
{var $attachmentsLayout = $post->getChildrenWithLayout($width)}
<div n:ifcontent class="attachments attachments_b" style="height: {$attachmentsLayout->height|noescape}; width: {$attachmentsLayout->width|noescape};">
<div class="attachment" n:foreach="$attachmentsLayout->tiles as $attachment" style="float: {$attachment[3]|noescape}; width: {$attachment[0]|noescape}; height: {$attachment[1]|noescape};" data-localized-nsfw-text="{_nsfw_warning}">
{include "../attachment.xml", attachment => $attachment[2], parent => $post, parentType => "post"}
<div class="attachment" n:foreach="$attachmentsLayout->tiles as $attachment" style="float: {$attachment[3]|noescape}; width: {$attachment[0]|noescape}; height: {$attachment[1]|noescape};">
{include "../attachment.xml", attachment => $attachment[2], parent => $post, parentType => "post", tilesCount => sizeof($attachmentsLayout->tiles)}
</div>
</div>

View file

@ -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;

View file

@ -2441,7 +2441,7 @@ a.poll-retract-vote {
position: relative;
}
.post-horizontal .upload-item .play-button {
.post-horizontal .upload-item .play-button, .compact_video .play-button {
position: absolute;
height: 30px;
width: 30px;
@ -2452,7 +2452,7 @@ a.poll-retract-vote {
align-items: center;
}
.post-horizontal .upload-item .play-button .play-button-ico {
.post-horizontal .upload-item .play-button .play-button-ico, .compact_video .play-button .play-button-ico {
background: url(/assets/packages/static/openvk/img/wall.png) no-repeat 1px 0;
display: inline-block;
height: 15px;
@ -2648,12 +2648,13 @@ a.poll-retract-vote {
padding: 3px 0;
}
.video-wowzer a::before {
content: "b";
color: transparent;
width: 12px;
background-image: url(/assets/packages/static/openvk/img/videoico.png);
display: none;
.video-wowzer .small-video-ico {
vertical-align: bottom;
display: inline-block;
width: 11px;
height: 14px;
background: url(/assets/packages/static/openvk/img/wall.png?v=2);
background-position: -87px 0px;
}
/* Da search */
@ -3511,3 +3512,26 @@ hr {
width: 30px;
height: 7px;
}
.compact_video {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
height: 100%;
width: 100%;
position: relative;
}
.compact_video .video-length {
text-align: center;
position: absolute;
width: 34px;
height: 14px;
bottom: 5px;
right: 5px;
background: rgba(0,0,0,0.5);
color: white;
}

View file

@ -1,28 +1,28 @@
.post-nsfw .post-content .media {
filter: saturate(0.8) blur(15px);
}
.post-nsfw .post-content .attachment {
overflow: hidden;
.post-nsfw .post-content {
position: relative;
overflow: hidden;
cursor: pointer;
}
.post-nsfw .post-content .attachment:active .media {
filter: none;
.post-nsfw .post-content .text {
filter: saturate(0.8) blur(28px);
pointer-events: none;
}
.post-nsfw .post-content .attachment::after {
.post-nsfw .post-content::after {
position: absolute;
top: calc(50% - 16px);
top: 0;
left: 0;
width: 100%;
padding: 8px 0;
background-color: hsla(0, 0%, 0%, .5);
height: 100%;
z-index: 1;
background-color: hsla(0, 0%, 0%, .7);
color: #fff;
text-align: center;
content: attr(data-localized-nsfw-text);
}
.post-nsfw .post-content .attachment:active::after {
display: none;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -486,6 +486,7 @@ async function __uploadToTextarea(file, textareaNode) {
})
const json_response = await res.json()
if(!json_response.success) {
u(`#temp_filler${rand}`).remove()
fastError((tr("error_uploading_photo") + json_response.flash.message))
return
}
@ -1025,6 +1026,13 @@ u(document).on('click', '.post-buttons .upload-item', (e) => {
e.preventDefault()
})
u(document).on('click', '.post.post-nsfw .post-content', (e) => {
e.preventDefault()
e.stopPropagation()
u(e.target).closest('.post-nsfw').removeClass('post-nsfw')
})
async function repost(id, repost_type = 'post') {
const repostsCount = u(`#repostsCount${id}`)
const previousVal = repostsCount.length > 0 ? Number(repostsCount.html()) : 0;

View file

@ -0,0 +1,2 @@
ALTER TABLE `videos` ADD `length` SMALLINT(5) UNSIGNED NULL DEFAULT NULL AFTER `name`, ADD INDEX `length` (`length`);
ALTER TABLE `videos` ADD `height` SMALLINT(5) UNSIGNED NULL DEFAULT NULL AFTER `length`, ADD `width` SMALLINT(5) UNSIGNED NULL DEFAULT NULL AFTER `height`;