Skip to content

Commit

Permalink
Add something related with videos
Browse files Browse the repository at this point in the history
- Теперь видосы работают как аудио, пользователи могут добавлять и удалять видео из коллекции. Но, правда, после обновления пользователи потеряют все свои видео, потом подумаю как исправить
- Ещё теперь видео можно загружать в группу, жесть. И на странице группы теперь показывается 2 случайных видео из группы
- Возможно, исправлена загрузка видео под виндовс (а может я её сломал)
- У видосов теперь сохраняется ширина и высота, а так же длина
- У прикреплённого видео рядом с названием показывается его длина
- Видео теперь размещаются в masonry layout. Если помимо видео у поста есть другие фотографии или другие видео, то показывается только обложка видео и кнопка проигрывания
- В класс video в api добавлена поддержка просмотра видеозаписей из групп
  • Loading branch information
mrilyew committed Nov 21, 2023
1 parent 93bfe6e commit 791c364
Show file tree
Hide file tree
Showing 20 changed files with 363 additions and 67 deletions.
17 changes: 9 additions & 8 deletions VKAPI/Handlers/Video.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,22 @@ function get(int $owner_id, string $videos = "", int $offset = 0, int $count = 3
];
} 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,
Expand Down
13 changes: 13 additions & 0 deletions Web/Models/Entities/Club.php
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,11 @@ function isEveryoneCanUploadAudios(): bool
return (bool) $this->getRecord()->everyone_can_upload_audios;
}

function isEveryoneCanUploadVideos(): bool
{
return false;
}

function canUploadAudio(?User $user): bool
{
if(!$user)
Expand All @@ -422,6 +427,14 @@ function canUploadAudio(?User $user): bool
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);
Expand Down
7 changes: 4 additions & 3 deletions Web/Models/Entities/Traits/TAttachmentHost.php
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -36,10 +36,10 @@ function getChildrenWithLayout(int $w, int $h = -1): object
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;
}
Expand Down Expand Up @@ -68,6 +68,7 @@ function getChildrenWithLayout(int $w, int $h = -1): object
"height" => $height . "px",
"tiles" => $result,
"extras" => $skipped,
"count" => sizeof($children),
];
}

Expand Down
166 changes: 154 additions & 12 deletions Web/Models/Entities/Video.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
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);

Expand Down Expand Up @@ -34,18 +35,37 @@ protected function saveFile(string $filename, string $hash): bool
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);

$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) {
Expand Down Expand Up @@ -118,19 +138,20 @@ function getOwnerVideo(): int
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,
"can_add" => 0,
"comments" => $this->getCommentsCount(),
"date" => $this->getPublicationTime()->timestamp(),
"description" => $this->getDescription(),
"duration" => 0, // я хуй знает как получить длину видео
"duration" => $this->getLength(),
"image" => [
[
"url" => $this->getThumbnailURL(),
Expand All @@ -139,8 +160,8 @@ function getApiStructure(?User $user = NULL): object
"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(),
Expand Down Expand Up @@ -194,17 +215,16 @@ function setLink(string $link): string

function isDeleted(): bool
{
if ($this->getRecord()->deleted == 1)
return TRUE;
else
return FALSE;
return $this->getRecord()->deleted == 1;
}

function deleteVideo(): void
{
$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
Expand All @@ -221,7 +241,7 @@ static function fastMake(int $owner, string $name = "Unnamed Video.ogv", string
$video->setFile($file);
$video->setUnlisted($unlisted);
$video->save();

return $video;
}

Expand All @@ -243,4 +263,126 @@ function toNotifApiStruct()

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);
}
}
Loading

0 comments on commit 791c364

Please sign in to comment.