execute($error); if ($error !== 0) { throw new \DomainException("$filename is not a valid video file"); } elseif (empty($streams) || ctype_space($streams)) { throw new \DomainException("$filename does not contain any video streams"); } $durations = []; preg_match_all('%duration=([0-9\.]++)%', $streams, $durations); if (sizeof($durations[1]) === 0) { throw new \DomainException("$filename does not contain any meaningful video streams"); } $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)))) { 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 } catch (ShellUnavailableException $suex) { exit(OPENVK_ROOT_CONF["openvk"]["debug"] ? "Shell is unavailable" : VIDEOS_FRIENDLY_ERROR); } catch (UnknownCommandException $ucex) { exit(OPENVK_ROOT_CONF["openvk"]["debug"] ? "bash is not installed" : VIDEOS_FRIENDLY_ERROR); } usleep(200100); return true; } protected function checkIfFileIsProcessed(): bool { if ($this->getType() != Video::TYPE_DIRECT) { return true; } if (!file_exists($this->getFileName())) { if ((time() - $this->getRecord()->last_checked) > 3600) { # TODO notify that video processor is probably dead } return false; } return true; } public function getName(): string { return $this->getRecord()->name; } public function getType(): int { if (!is_null($this->getRecord()->hash)) { return Video::TYPE_DIRECT; } elseif (!is_null($this->getRecord()->link)) { return Video::TYPE_EMBED; } } public function getVideoDriver(): ?VideoDriver { if ($this->getType() !== Video::TYPE_EMBED) { return null; } [$videoDriver, $pointer] = explode(":", $this->getRecord()->link); $videoDriver = "openvk\\Web\\Models\\VideoDrivers\\$videoDriver" . "VideoDriver"; if (!class_exists($videoDriver)) { return null; } return new $videoDriver($pointer); } public function getThumbnailURL(): string { if ($this->getType() === Video::TYPE_DIRECT) { if (!$this->isProcessed()) { return "/assets/packages/static/openvk/video/rendering.apng"; } return preg_replace("%\.[A-z0-9]++$%", ".gif", $this->getURL()); } else { return $this->getVideoDriver()->getThumbnailURL(); } } public function getOwnerVideo(): int { return $this->getRecord()->owner; } public 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_repost" => 1, "can_subscribe" => 1, "can_add_to_faves" => 0, "can_add" => 0, "comments" => $this->getCommentsCount(), "date" => $this->getPublicationTime()->timestamp(), "description" => $this->getDescription(), "duration" => $this->getLength(), "image" => [ [ "url" => $this->getThumbnailURL(), "width" => 320, "height" => 240, "with_padding" => 1, ], ], "width" => $dimensions ? $dimensions[0] : 640, "height" => $dimensions ? $dimensions[1] : 480, "id" => $this->getVirtualId(), "owner_id" => $this->getOwner()->getId(), "user_id" => $this->getOwner()->getId(), "title" => $this->getName(), "is_favorite" => false, "player" => !$fromYoutube ? $this->getURL() : $this->getVideoDriver()->getURL(), "files" => !$fromYoutube ? [ "mp4_480" => $this->getURL(), ] : null, "platform" => $fromYoutube ? "youtube" : null, "added" => 0, "repeat" => 0, "type" => "video", "views" => 0, "is_processed" => $this->isProcessed(), "reposts" => [ "count" => 0, "user_reposted" => 0, ], ], ]; if (!is_null($user)) { $res->video["likes"] = [ "count" => $this->getLikesCount(), "user_likes" => $this->hasLikeFrom($user), ]; } return $res; } public function toVkApiStruct(?User $user): object { return $this->getApiStructure($user); } public function setLink(string $link): string { if (preg_match(file_get_contents(__DIR__ . "/../VideoDrivers/regex/youtube.txt"), $link, $matches)) { $pointer = "YouTube:$matches[1]"; /*} else if(preg_match(file_get_contents(__DIR__ . "/../VideoDrivers/regex/vimeo.txt"), $link, $matches)) { $pointer = "Vimeo:$matches[1]";*/ } else { throw new ISE("Invalid link"); } $this->stateChanges("link", $pointer); return $pointer; } public function isDeleted(): bool { if ($this->getRecord()->deleted == 1) { return true; } else { return false; } } public function deleteVideo(): void { $this->setDeleted(1); $this->unwire(); $this->save(); } public static function fastMake(int $owner, string $name = "Unnamed Video.ogv", string $description = "", array $file, bool $unlisted = true, bool $anon = false): Video { if (OPENVK_ROOT_CONF['openvk']['preferences']['videos']['disableUploading']) { exit(VIDEOS_FRIENDLY_ERROR); } $video = new Video(); $video->setOwner($owner); $video->setName(ovk_proc_strtr($name, 61)); $video->setDescription(ovk_proc_strtr($description, 300)); $video->setAnonymous($anon); $video->setCreated(time()); $video->setFile($file); $video->setUnlisted($unlisted); $video->save(); return $video; } public 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; } public 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; } public function getLength() { return $this->getRecord()->length; } public 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) ); } public function getPageURL(): string { return "/video" . $this->getPrettyId(); } public function canBeViewedBy(?User $user = null): bool { if ($this->isDeleted() || $this->getOwner()->isDeleted()) { return false; } if (get_class($this->getOwner()) == "openvk\\Web\\Models\\Entities\\User") { return $this->getOwner()->canBeViewedBy($user) && $this->getOwner()->getPrivacyPermission('videos.read', $user); } else { # Groups doesn't have videos but ok return $this->getOwner()->canBeViewedBy($user); } } public function toNotifApiStruct() { $fromYoutube = $this->getType() == Video::TYPE_EMBED; $res = (object) []; $res->id = $this->getVirtualId(); $res->owner_id = $this->getOwner()->getId(); $res->title = $this->getName(); $res->description = $this->getDescription(); $res->duration = $this->getLength(); $res->link = "/video" . $this->getOwner()->getId() . "_" . $this->getVirtualId(); $res->image = $this->getThumbnailURL(); $res->date = $this->getPublicationTime()->timestamp(); $res->views = 0; $res->player = !$fromYoutube ? $this->getURL() : $this->getVideoDriver()->getURL(); return $res; } }