mirror of
https://github.com/openvk/openvk
synced 2024-11-11 01:19:53 +03:00
Videos: add window player (#951)
* De#910fy * Fiksez * newlines --------- Co-authored-by: Dmitry Tretyakov <76806170+tretdm@users.noreply.github.com>
This commit is contained in:
parent
9fbf7f5bf5
commit
0f0d3ee950
29 changed files with 1208 additions and 125 deletions
156
ServiceAPI/Video.php
Normal file
156
ServiceAPI/Video.php
Normal file
|
@ -0,0 +1,156 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\ServiceAPI;
|
||||
|
||||
use openvk\Web\Models\Entities\{User, Post};
|
||||
use openvk\Web\Models\Repositories\{Videos, Comments, Clubs};
|
||||
use Chandler\MVC\Routing\Router;
|
||||
|
||||
class Video implements Handler
|
||||
{
|
||||
protected $user;
|
||||
protected $videos;
|
||||
protected $comments;
|
||||
protected $groups;
|
||||
|
||||
function __construct(?User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->videos = new Videos;
|
||||
$this->comments = new Comments;
|
||||
$this->groups = new Clubs;
|
||||
}
|
||||
|
||||
function getVideo(int $id, callable $resolve, callable $reject)
|
||||
{
|
||||
$video = $this->videos->get($id);
|
||||
|
||||
if(!$video || $video->isDeleted()) {
|
||||
$reject(2, "Video does not exists");
|
||||
}
|
||||
|
||||
if(method_exists($video, "canBeViewedBy") && !$video->canBeViewedBy($this->user)) {
|
||||
$reject(4, "Access to video denied");
|
||||
}
|
||||
|
||||
if(!$video->getOwner()->getPrivacyPermission('videos.read', $this->user)) {
|
||||
$reject(8, "Access to video denied: this user chose to hide his videos");
|
||||
}
|
||||
|
||||
$prevVideo = NULL;
|
||||
$nextVideo = NULL;
|
||||
$lastVideo = $this->videos->getLastVideo($video->getOwner());
|
||||
|
||||
if($video->getVirtualId() - 1 != 0) {
|
||||
for($i = $video->getVirtualId(); $i != 0; $i--) {
|
||||
$maybeVideo = (new Videos)->getByOwnerAndVID($video->getOwner()->getId(), $i);
|
||||
|
||||
if(!is_null($maybeVideo) && !$maybeVideo->isDeleted() && $maybeVideo->getId() != $video->getId()) {
|
||||
if(method_exists($maybeVideo, "canBeViewedBy") && !$maybeVideo->canBeViewedBy($this->user)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$prevVideo = $maybeVideo;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(is_null($lastVideo) || $lastVideo->getId() == $video->getId()) {
|
||||
$nextVideo = NULL;
|
||||
} else {
|
||||
for($i = $video->getVirtualId(); $i <= $lastVideo->getVirtualId(); $i++) {
|
||||
$maybeVideo = (new Videos)->getByOwnerAndVID($video->getOwner()->getId(), $i);
|
||||
|
||||
if(!is_null($maybeVideo) && !$maybeVideo->isDeleted() && $maybeVideo->getId() != $video->getId()) {
|
||||
if(method_exists($maybeVideo, "canBeViewedBy") && !$maybeVideo->canBeViewedBy($this->user)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$nextVideo = $maybeVideo;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$res = [
|
||||
"id" => $video->getId(),
|
||||
"title" => $video->getName(),
|
||||
"owner" => $video->getOwner()->getId(),
|
||||
"commentsCount" => $video->getCommentsCount(),
|
||||
"description" => $video->getDescription(),
|
||||
"type" => $video->getType(),
|
||||
"name" => $video->getOwner()->getCanonicalName(),
|
||||
"pretty_id" => $video->getPrettyId(),
|
||||
"virtual_id" => $video->getVirtualId(),
|
||||
"published" => (string)$video->getPublicationTime(),
|
||||
"likes" => $video->getLikesCount(),
|
||||
"has_like" => $video->hasLikeFrom($this->user),
|
||||
"author" => $video->getOwner()->getCanonicalName(),
|
||||
"canBeEdited" => $video->getOwner()->getId() == $this->user->getId(),
|
||||
"isProcessing" => $video->getType() == 0 && $video->getURL() == "/assets/packages/static/openvk/video/rendering.mp4",
|
||||
"prevVideo" => !is_null($prevVideo) ? $prevVideo->getId() : null,
|
||||
"nextVideo" => !is_null($nextVideo) ? $nextVideo->getId() : null,
|
||||
];
|
||||
|
||||
if($video->getType() == 1) {
|
||||
$res["embed"] = $video->getVideoDriver()->getEmbed();
|
||||
} else {
|
||||
$res["url"] = $video->getURL();
|
||||
}
|
||||
|
||||
$resolve($res);
|
||||
}
|
||||
|
||||
function shareVideo(int $owner, int $vid, int $type, string $message, int $club, bool $signed, bool $asGroup, callable $resolve, callable $reject)
|
||||
{
|
||||
$video = $this->videos->getByOwnerAndVID($owner, $vid);
|
||||
|
||||
if(!$video || $video->isDeleted()) {
|
||||
$reject(16, "Video does not exists");
|
||||
}
|
||||
|
||||
if(method_exists($video, "canBeViewedBy") && !$video->canBeViewedBy($this->user)) {
|
||||
$reject(32, "Access to video denied");
|
||||
}
|
||||
|
||||
if(!$video->getOwner()->getPrivacyPermission('videos.read', $this->user)) {
|
||||
$reject(8, "Access to video denied: this user chose to hide his videos");
|
||||
}
|
||||
|
||||
$flags = 0;
|
||||
|
||||
$nPost = new Post;
|
||||
$nPost->setOwner($this->user->getId());
|
||||
|
||||
if($type == 0) {
|
||||
$nPost->setWall($this->user->getId());
|
||||
} else {
|
||||
$club = $this->groups->get($club);
|
||||
|
||||
if(!$club || $club->isDeleted() || !$club->canBeModifiedBy($this->user)) {
|
||||
$reject(64, "Can't do repost to this club");
|
||||
}
|
||||
|
||||
if($asGroup)
|
||||
$flags |= 0b10000000;
|
||||
|
||||
if($signed)
|
||||
$flags |= 0b01000000;
|
||||
|
||||
$nPost->setWall($club->getId() * -1);
|
||||
}
|
||||
|
||||
$nPost->setContent($message);
|
||||
$nPost->setFlags($flags);
|
||||
$nPost->save();
|
||||
|
||||
$nPost->attach($video);
|
||||
|
||||
$res = [
|
||||
"id" => $nPost->getId(),
|
||||
"pretty_id" => $nPost->getPrettyId(),
|
||||
];
|
||||
|
||||
$resolve($res);
|
||||
}
|
||||
}
|
|
@ -1,72 +1,157 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\VKAPI\Handlers;
|
||||
use openvk\Web\Models\Repositories\Users as UsersRepo;
|
||||
use openvk\Web\Models\Repositories\{Posts as PostsRepo, Comments as CommentsRepo, Photos as PhotosRepo, Videos as VideosRepo};
|
||||
use openvk\Web\Models\Repositories\Posts as PostsRepo;
|
||||
use openvk\Web\Models\Repositories\Comments as CommentsRepo;
|
||||
use openvk\Web\Models\Repositories\Videos as VideosRepo;
|
||||
use openvk\Web\Models\Repositories\Photos as PhotosRepo;
|
||||
use openvk\Web\Models\Repositories\Notes as NotesRepo;
|
||||
|
||||
|
||||
final class Likes extends VKAPIRequestHandler
|
||||
{
|
||||
function add(string $type, int $owner_id, int $item_id): object
|
||||
{
|
||||
$this->requireUser();
|
||||
function add(string $type, int $owner_id, int $item_id): object
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$postable = NULL;
|
||||
switch($type) {
|
||||
case "post":
|
||||
$post = (new PostsRepo)->getPostById($owner_id, $item_id);
|
||||
if(is_null($post))
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: object not found");
|
||||
|
||||
$post->setLike(true, $this->getUser());
|
||||
|
||||
return (object) [
|
||||
"likes" => $post->getLikesCount()
|
||||
];
|
||||
$postable = $post;
|
||||
break;
|
||||
case "comment":
|
||||
$comment = (new CommentsRepo)->get($item_id);
|
||||
$postable = $comment;
|
||||
break;
|
||||
case "video":
|
||||
$video = (new VideosRepo)->getByOwnerAndVID($owner_id, $item_id);
|
||||
$postable = $video;
|
||||
break;
|
||||
case "photo":
|
||||
$photo = (new PhotosRepo)->getByOwnerAndVID($owner_id, $item_id);
|
||||
$postable = $photo;
|
||||
break;
|
||||
case "note":
|
||||
$note = (new NotesRepo)->getNoteById($owner_id, $item_id);
|
||||
$postable = $note;
|
||||
break;
|
||||
default:
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: incorrect type");
|
||||
}
|
||||
}
|
||||
|
||||
function delete(string $type, int $owner_id, int $item_id): object
|
||||
{
|
||||
$this->requireUser();
|
||||
if(is_null($postable) || $postable->isDeleted())
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: object not found");
|
||||
|
||||
if(method_exists($postable, "canBeViewedBy") && !$postable->canBeViewedBy($this->getUser() ?? NULL)) {
|
||||
$this->fail(2, "Access to postable denied");
|
||||
}
|
||||
|
||||
$postable->setLike(true, $this->getUser());
|
||||
|
||||
return (object) [
|
||||
"likes" => $postable->getLikesCount()
|
||||
];
|
||||
}
|
||||
|
||||
function delete(string $type, int $owner_id, int $item_id): object
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$postable = NULL;
|
||||
switch($type) {
|
||||
case "post":
|
||||
$post = (new PostsRepo)->getPostById($owner_id, $item_id);
|
||||
if (is_null($post))
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: object not found");
|
||||
|
||||
$post->setLike(false, $this->getUser());
|
||||
return (object) [
|
||||
"likes" => $post->getLikesCount()
|
||||
];
|
||||
$postable = $post;
|
||||
break;
|
||||
case "comment":
|
||||
$comment = (new CommentsRepo)->get($item_id);
|
||||
$postable = $comment;
|
||||
break;
|
||||
case "video":
|
||||
$video = (new VideosRepo)->getByOwnerAndVID($owner_id, $item_id);
|
||||
$postable = $video;
|
||||
break;
|
||||
case "photo":
|
||||
$photo = (new PhotosRepo)->getByOwnerAndVID($owner_id, $item_id);
|
||||
$postable = $photo;
|
||||
break;
|
||||
case "note":
|
||||
$note = (new NotesRepo)->getNoteById($owner_id, $item_id);
|
||||
$postable = $note;
|
||||
break;
|
||||
default:
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: incorrect type");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(is_null($postable) || $postable->isDeleted())
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: object not found");
|
||||
|
||||
if(method_exists($postable, "canBeViewedBy") && !$postable->canBeViewedBy($this->getUser() ?? NULL)) {
|
||||
$this->fail(2, "Access to postable denied");
|
||||
}
|
||||
|
||||
if(!is_null($postable)) {
|
||||
$postable->setLike(false, $this->getUser());
|
||||
|
||||
return (object) [
|
||||
"likes" => $postable->getLikesCount()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
function isLiked(int $user_id, string $type, int $owner_id, int $item_id): object
|
||||
{
|
||||
$this->requireUser();
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$user = (new UsersRepo)->get($user_id);
|
||||
|
||||
if(is_null($user) || $user->isDeleted())
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: user not found");
|
||||
|
||||
if(method_exists($user, "canBeViewedBy") && !$user->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(1984, "Access denied: you can't see this user");
|
||||
}
|
||||
|
||||
$postable = NULL;
|
||||
switch($type) {
|
||||
case "post":
|
||||
$user = (new UsersRepo)->get($user_id);
|
||||
if (is_null($user))
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: user not found");
|
||||
|
||||
$post = (new PostsRepo)->getPostById($owner_id, $item_id);
|
||||
if (is_null($post))
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: object not found");
|
||||
|
||||
return (object) [
|
||||
"liked" => (int) $post->hasLikeFrom($user),
|
||||
"copied" => 0 # TODO: handle this
|
||||
];
|
||||
$postable = $post;
|
||||
break;
|
||||
case "comment":
|
||||
$comment = (new CommentsRepo)->get($item_id);
|
||||
$postable = $comment;
|
||||
break;
|
||||
case "video":
|
||||
$video = (new VideosRepo)->getByOwnerAndVID($owner_id, $item_id);
|
||||
$postable = $video;
|
||||
break;
|
||||
case "photo":
|
||||
$photo = (new PhotosRepo)->getByOwnerAndVID($owner_id, $item_id);
|
||||
$postable = $photo;
|
||||
break;
|
||||
case "note":
|
||||
$note = (new NotesRepo)->getNoteById($owner_id, $item_id);
|
||||
$postable = $note;
|
||||
break;
|
||||
default:
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: incorrect type");
|
||||
}
|
||||
|
||||
if(is_null($postable) || $postable->isDeleted())
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: object not found");
|
||||
|
||||
if(!$postable->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(665, "Access to postable denied");
|
||||
}
|
||||
|
||||
return (object) [
|
||||
"liked" => (int) $postable->hasLikeFrom($user),
|
||||
"copied" => 0
|
||||
];
|
||||
}
|
||||
|
||||
function getList(string $type, int $owner_id, int $item_id, bool $extended = false, int $offset = 0, int $count = 10, bool $skip_own = false)
|
||||
|
|
|
@ -26,7 +26,7 @@ final class Video extends VKAPIRequestHandler
|
|||
|
||||
$video = (new VideosRepo)->getByOwnerAndVID(intval($id[0]), intval($id[1]));
|
||||
if($video) {
|
||||
$items[] = $video->getApiStructure();
|
||||
$items[] = $video->getApiStructure($this->getUser());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,14 +38,18 @@ final class Video extends VKAPIRequestHandler
|
|||
if ($owner_id > 0)
|
||||
$user = (new UsersRepo)->get($owner_id);
|
||||
else
|
||||
$this->fail(1, "Not implemented");
|
||||
$this->fail(1, "Not implemented");
|
||||
|
||||
if(!$user->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);
|
||||
|
||||
$items = [];
|
||||
foreach ($videos as $video) {
|
||||
$items[] = $video->getApiStructure();
|
||||
$items[] = $video->getApiStructure($this->getUser());
|
||||
}
|
||||
|
||||
return (object) [
|
||||
|
|
|
@ -57,7 +57,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
} else if($attachment instanceof \openvk\Web\Models\Entities\Poll) {
|
||||
$attachments[] = $this->getApiPoll($attachment, $this->getUser());
|
||||
} else if ($attachment instanceof \openvk\Web\Models\Entities\Video) {
|
||||
$attachments[] = $attachment->getApiStructure();
|
||||
$attachments[] = $attachment->getApiStructure($this->getUser());
|
||||
} else if ($attachment instanceof \openvk\Web\Models\Entities\Note) {
|
||||
$attachments[] = $attachment->toVkApiStruct();
|
||||
} else if ($attachment instanceof \openvk\Web\Models\Entities\Audio) {
|
||||
|
@ -237,7 +237,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
} else if($attachment instanceof \openvk\Web\Models\Entities\Poll) {
|
||||
$attachments[] = $this->getApiPoll($attachment, $user);
|
||||
} else if ($attachment instanceof \openvk\Web\Models\Entities\Video) {
|
||||
$attachments[] = $attachment->getApiStructure();
|
||||
$attachments[] = $attachment->getApiStructure($this->getUser());
|
||||
} else if ($attachment instanceof \openvk\Web\Models\Entities\Note) {
|
||||
$attachments[] = $attachment->toVkApiStruct();
|
||||
} else if ($attachment instanceof \openvk\Web\Models\Entities\Audio) {
|
||||
|
|
|
@ -74,8 +74,12 @@ class Comment extends Post
|
|||
foreach($this->getChildren() as $attachment) {
|
||||
if($attachment->isDeleted())
|
||||
continue;
|
||||
|
||||
$res->attachments[] = $attachment->toVkApiStruct();
|
||||
|
||||
if($attachment instanceof \openvk\Web\Models\Entities\Photo) {
|
||||
$res->attachments[] = $attachment->toVkApiStruct();
|
||||
} else if($attachment instanceof \openvk\Web\Models\Entities\Video) {
|
||||
$res->attachments[] = $attachment->toVkApiStruct($this->getUser());
|
||||
}
|
||||
}
|
||||
|
||||
if($need_likes) {
|
||||
|
|
|
@ -131,10 +131,15 @@ abstract class Postable extends Attachable
|
|||
"target" => $this->getRecord()->id,
|
||||
];
|
||||
|
||||
if($liked)
|
||||
DB::i()->getContext()->table("likes")->insert($searchData);
|
||||
else
|
||||
DB::i()->getContext()->table("likes")->where($searchData)->delete();
|
||||
if($liked) {
|
||||
if(!$this->hasLikeFrom($user)) {
|
||||
DB::i()->getContext()->table("likes")->insert($searchData);
|
||||
}
|
||||
} else {
|
||||
if($this->hasLikeFrom($user)) {
|
||||
DB::i()->getContext()->table("likes")->where($searchData)->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function hasLikeFrom(User $user): bool
|
||||
|
|
|
@ -115,15 +115,15 @@ class Video extends Media
|
|||
return $this->getRecord()->owner;
|
||||
}
|
||||
|
||||
function getApiStructure(): object
|
||||
function getApiStructure(?User $user = NULL): object
|
||||
{
|
||||
$fromYoutube = $this->getType() == Video::TYPE_EMBED;
|
||||
return (object)[
|
||||
$res = (object)[
|
||||
"type" => "video",
|
||||
"video" => [
|
||||
"can_comment" => 1,
|
||||
"can_like" => 0, // we don't h-have wikes in videos
|
||||
"can_repost" => 0,
|
||||
"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,
|
||||
|
@ -155,21 +155,26 @@ class Video extends Media
|
|||
"repeat" => 0,
|
||||
"type" => "video",
|
||||
"views" => 0,
|
||||
"likes" => [
|
||||
"count" => 0,
|
||||
"user_likes" => 0
|
||||
],
|
||||
"reposts" => [
|
||||
"count" => 0,
|
||||
"user_reposted" => 0
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
if(!is_null($user)) {
|
||||
$res->video["likes"] = [
|
||||
"count" => $this->getLikesCount(),
|
||||
"user_likes" => $this->hasLikeFrom($user)
|
||||
];
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
function toVkApiStruct(): object
|
||||
function toVkApiStruct(?User $user): object
|
||||
{
|
||||
return $this->getApiStructure();
|
||||
return $this->getApiStructure($user);
|
||||
}
|
||||
|
||||
function setLink(string $link): string
|
||||
|
|
|
@ -77,4 +77,11 @@ class Videos
|
|||
|
||||
return new Util\EntityStream("Video", $result->order("$sort"));
|
||||
}
|
||||
|
||||
function getLastVideo(User $user)
|
||||
{
|
||||
$video = $this->videos->where("owner", $user->getId())->where(["deleted" => 0, "unlisted" => 0])->order("id DESC")->fetch();
|
||||
|
||||
return new Video($video);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,18 +74,18 @@ final class VideosPresenter extends OpenVKPresenter
|
|||
else if(!empty($this->postParam("link")))
|
||||
$video->setLink($this->postParam("link"));
|
||||
else
|
||||
$this->flashFail("err", tr("no_video"), tr("no_video_desc"));
|
||||
$this->flashFail("err", tr("no_video_error"), tr("no_video_description"));
|
||||
} catch(\DomainException $ex) {
|
||||
$this->flashFail("err", tr("error_occured"), tr("error_video_damaged_file"));
|
||||
$this->flashFail("err", tr("error_video"), tr("file_corrupted"));
|
||||
} catch(ISE $ex) {
|
||||
$this->flashFail("err", tr("error_occured"), tr("error_video_incorrect_link"));
|
||||
$this->flashFail("err", tr("error_video"), tr("link_incorrect"));
|
||||
}
|
||||
|
||||
$video->save();
|
||||
|
||||
$this->redirect("/video" . $video->getPrettyId());
|
||||
} else {
|
||||
$this->flashFail("err", tr("error_occured"), tr("error_video_no_title"));
|
||||
$this->flashFail("err", tr("error_video"), tr("no_name_error"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -99,14 +99,14 @@ final class VideosPresenter extends OpenVKPresenter
|
|||
if(!$video)
|
||||
$this->notFound();
|
||||
if(is_null($this->user) || $this->user->id !== $owner)
|
||||
$this->flashFail("err", tr("error_access_denied_short"), tr("error_access_denied"));
|
||||
$this->flashFail("err", tr("access_denied_error"), tr("access_denied_error_description"));
|
||||
|
||||
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
$video->setName(empty($this->postParam("name")) ? NULL : $this->postParam("name"));
|
||||
$video->setDescription(empty($this->postParam("desc")) ? NULL : $this->postParam("desc"));
|
||||
$video->save();
|
||||
|
||||
$this->flash("succ", tr("changes_saved"), tr("new_data_video"));
|
||||
$this->flash("succ", tr("changes_saved"), tr("changes_saved_video_comment"));
|
||||
$this->redirect("/video" . $video->getPrettyId());
|
||||
}
|
||||
|
||||
|
@ -128,9 +128,29 @@ final class VideosPresenter extends OpenVKPresenter
|
|||
$video->deleteVideo($owner, $vid);
|
||||
}
|
||||
} else {
|
||||
$this->flashFail("err", tr("error_deleting_video"), tr("login_please"));
|
||||
$this->flashFail("err", tr("cant_delete_video"), tr("cant_delete_video_comment"));
|
||||
}
|
||||
|
||||
$this->redirect("/videos" . $owner);
|
||||
}
|
||||
|
||||
function renderLike(int $owner, int $video_id): void
|
||||
{
|
||||
$this->assertUserLoggedIn();
|
||||
$this->willExecuteWriteAction();
|
||||
$this->assertNoCSRF();
|
||||
|
||||
$video = $this->videos->getByOwnerAndVID($owner, $video_id);
|
||||
if(!$video || $video->isDeleted() || $video->getOwner()->isDeleted()) $this->notFound();
|
||||
|
||||
if(method_exists($video, "canBeViewedBy") && !$video->canBeViewedBy($this->user->identity)) {
|
||||
$this->flashFail("err", tr("error"), tr("forbidden"));
|
||||
}
|
||||
|
||||
if(!is_null($this->user)) {
|
||||
$video->toggleLike($this->user->identity);
|
||||
}
|
||||
|
||||
$this->redirect("$_SERVER[HTTP_REFERER]");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
<script src="/language/{php echo getLanguage()}.js" crossorigin="anonymous"></script>
|
||||
{script "js/node_modules/jquery/dist/jquery.min.js"}
|
||||
{script "js/node_modules/jquery-ui/dist/jquery-ui.min.js"}
|
||||
{script "js/node_modules/umbrellajs/umbrella.min.js"}
|
||||
{script "js/l10n.js"}
|
||||
{script "js/openvk.cls.js"}
|
||||
|
@ -370,6 +371,10 @@
|
|||
</p>
|
||||
</div>
|
||||
|
||||
<div id="ajloader" class="loader">
|
||||
<img src="/assets/packages/static/openvk/img/loading_mini.gif" style="width: 40px;">
|
||||
</div>
|
||||
|
||||
{include "components/cookies.xml"}
|
||||
|
||||
{script "js/node_modules/msgpack-lite/dist/msgpack.min.js"}
|
||||
|
|
|
@ -327,13 +327,13 @@
|
|||
</div>
|
||||
<div style="padding: 5px;">
|
||||
<div class="ovk-video" n:foreach="$videos as $video">
|
||||
<a href="/video{$video->getPrettyId()}" class="preview" align="center">
|
||||
<a href="/video{$video->getPrettyId()}" class="preview" align="center" id="videoOpen" data-id="{$video->getId()}">
|
||||
<img
|
||||
src="{$video->getThumbnailURL()}"
|
||||
style="max-width: 170px; max-height: 127px; margin: auto;" />
|
||||
</a>
|
||||
<div>
|
||||
<b><a href="/video{$video->getPrettyId()}">{ovk_proc_strtr($video->getName(), 30)}</a></b><br>
|
||||
<b><a href="/video{$video->getPrettyId()}" id="videoOpen" data-id="{$video->getId()}">{ovk_proc_strtr($video->getName(), 30)}</a></b><br>
|
||||
<span style="font-size: 10px;">{$video->getPublicationTime()} | {_comments} ({$video->getCommentsCount()})</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
{/block}
|
||||
|
||||
{block preview}
|
||||
<div class="video-preview">
|
||||
<div class="video-preview" id="videoOpen" data-id="{$x->getId()}">
|
||||
<img src="{$x->getThumbnailURL()}"
|
||||
alt="{$x->getName()}"
|
||||
style="max-width: 170px; max-height: 127px; margin: auto;" />
|
||||
|
@ -41,7 +41,7 @@
|
|||
{/block}
|
||||
|
||||
{block name}
|
||||
{$x->getName()}
|
||||
<span id="videoOpen" data-id="{$x->getId()}" style="color:unset;">{$x->getName()}</span>
|
||||
{/block}
|
||||
|
||||
{block description}
|
||||
|
@ -51,7 +51,7 @@
|
|||
<span style="color: grey;">{_video_uploaded} {$x->getPublicationTime()}</span><br/>
|
||||
<span style="color: grey;">{_video_updated} {$x->getEditTime() ?? $x->getPublicationTime()}</span>
|
||||
<p>
|
||||
<a href="/video{$x->getPrettyId()}">{_view_video}</a>
|
||||
<a href="/video{$x->getPrettyId()}" id="videoOpen" data-id="{$x->getId()}">{_view_video}</a>
|
||||
{if $x->getCommentsCount() > 0}| <a href="/video{$x->getPrettyId()}#comments">{_comments} ({$x->getCommentsCount()})</a>{/if}
|
||||
</p>
|
||||
{/block}
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
<hr/>
|
||||
|
||||
<div style="width: 100%; min-height: 100px;">
|
||||
<div style="float: left; min-height: 100px; width: 68%; margin-right: 2%;">
|
||||
<div style="float: left; min-height: 100px; width: 68%; margin-right: 2%;" id="comments">
|
||||
{include "../components/comments.xml",
|
||||
comments => $comments,
|
||||
count => $cCount,
|
||||
|
@ -50,13 +50,18 @@
|
|||
{$video->getPublicationTime()}
|
||||
</div>
|
||||
<br/>
|
||||
<div n:if="isset($thisUser) && $thisUser->getId() === $user->getId()">
|
||||
<h4>{_actions}</h4>
|
||||
<a href="/video{$video->getPrettyId()}/edit" class="profile_link" style="display:block;width:96%;">
|
||||
{_edit}
|
||||
</a>
|
||||
<a href="/video{$video->getPrettyId()}/remove" class="profile_link" style="display:block;width:96%;">
|
||||
{_delete}
|
||||
<div>
|
||||
<div n:if="isset($thisUser) && $thisUser->getId() === $user->getId()">
|
||||
<h4>{_actions}</h4>
|
||||
<a href="/video{$video->getPrettyId()}/edit" class="profile_link" style="display:block;width:96%;">
|
||||
{_edit}
|
||||
</a>
|
||||
<a href="/video{$video->getPrettyId()}/remove" class="profile_link" style="display:block;width:96%;">
|
||||
{_delete}
|
||||
</a>
|
||||
</div>
|
||||
<a href="/video{$video->getPrettyId()}" class="profile_link" id="videoOpen" data-id="{$video->getId()}" style="display:block;width:96%;">
|
||||
{_watch_in_window}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
</a>
|
||||
{/if}
|
||||
{elseif $attachment instanceof \openvk\Web\Models\Entities\Video}
|
||||
{if !$attachment->isDeleted()}
|
||||
{if $attachment->getType() === 0}
|
||||
<div class="bsdn media" data-name="{$attachment->getName()}" data-author="{$attachment->getOwner()->getCanonicalName()}">
|
||||
<video class="media" src="{$attachment->getURL()}"></video>
|
||||
|
@ -25,8 +26,12 @@
|
|||
|
||||
<div class="video-wowzer">
|
||||
<img src="/assets/packages/static/openvk/img/videoico.png" />
|
||||
<a href="/video{$attachment->getPrettyId()}">{$attachment->getName()}</a>
|
||||
<a href="/video{$attachment->getPrettyId()}" id="videoOpen" data-id="{$attachment->getId()}">{$attachment->getName()}</a>
|
||||
</div>
|
||||
|
||||
{else}
|
||||
<span style="color:gray;">{_video_is_deleted}</span>
|
||||
{/if}
|
||||
{elseif $attachment instanceof \openvk\Web\Models\Entities\Poll}
|
||||
{presenter "openvk!Poll->view", $attachment->getId()}
|
||||
{elseif $attachment instanceof \openvk\Web\Models\Entities\Note}
|
||||
|
|
|
@ -1,39 +1,37 @@
|
|||
{block content}
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td valign="top">
|
||||
<div class="video-preview">
|
||||
<a href="/video{$video->getPrettyId()}">
|
||||
<div class="video-preview">
|
||||
<img src="{$video->getThumbnailURL()}"
|
||||
style="max-width: 170px; max-height: 127px; margin: auto;" >
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
<td valign="top" style="width: 100%">
|
||||
{ifset infotable}
|
||||
{include infotable, x => $dat}
|
||||
{else}
|
||||
<a href="/video{$video->getPrettyId()}">
|
||||
<b>
|
||||
{$video->getName()}
|
||||
</b>
|
||||
</a>
|
||||
<br/>
|
||||
<p>
|
||||
<span>{$video->getDescription() ?? ""}</span>
|
||||
</p>
|
||||
<span style="color: grey;">{_video_uploaded} {$video->getPublicationTime()}</span><br/>
|
||||
|
||||
<p>
|
||||
<a href="/video{$video->getPrettyId()}">{_view_video}</a>
|
||||
{if $video->getCommentsCount() > 0}| <a href="/video{$video->getPrettyId()}#comments">{_comments} ({$video->getCommentsCount()})</a>{/if}
|
||||
</p>
|
||||
{/ifset}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td valign="top">
|
||||
<div class="video-preview">
|
||||
<a href="/video{$video->getPrettyId()}" id="videoOpen" data-id="{$video->getId()}">
|
||||
<img src="{$video->getThumbnailURL()}"
|
||||
style="max-width: 170px; max-height: 127px; margin: auto;" >
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
<td valign="top" style="width: 100%">
|
||||
{ifset infotable}
|
||||
{include infotable, x => $dat}
|
||||
{else}
|
||||
<a href="/video{$video->getPrettyId()}">
|
||||
<b id="videoOpen" data-id="{$video->getId()}">
|
||||
{$video->getName()}
|
||||
</b>
|
||||
</a>
|
||||
<br/>
|
||||
<p>
|
||||
<span>{$video->getDescription() ?? ""}</span>
|
||||
</p>
|
||||
<span style="color: grey;">{_video_uploaded} {$video->getPublicationTime()}</span><br/>
|
||||
|
||||
<p>
|
||||
<a href="/video{$video->getPrettyId()}" id="videoOpen" data-id="{$video->getId()}">{_view_video}</a>
|
||||
{if $video->getCommentsCount() > 0}| <a href="/video{$video->getPrettyId()}#comments">{_comments} ({$video->getCommentsCount()})</a>{/if}
|
||||
</p>
|
||||
{/ifset}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{/block}
|
||||
|
|
|
@ -187,6 +187,8 @@ routes:
|
|||
handler: "Videos->edit"
|
||||
- url: "/video{num}_{num}/remove"
|
||||
handler: "Videos->remove"
|
||||
- url: "/video{num}_{num}/like"
|
||||
handler: "Videos->like"
|
||||
- url: "/player/upload"
|
||||
handler: "Audio->upload"
|
||||
- url: "/audios{num}"
|
||||
|
|
|
@ -100,14 +100,20 @@ button.bsdn_playButton {
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.bsdn_fullScreenButton {
|
||||
.bsdn_fullScreenButton, .bsdn_repeatButton {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.bsdn_fullScreenButton > img:hover {
|
||||
background: url("/assets/packages/static/openvk/img/bsdn/fullscreen_hover.gif");
|
||||
object-fit: none;
|
||||
object-position: -64px 0;
|
||||
background: url("/assets/packages/static/openvk/img/bsdn/fullscreen_hover.gif");
|
||||
object-fit: none;
|
||||
object-position: -64px 0;
|
||||
}
|
||||
|
||||
.bsdn_repeatButton.pressed > img {
|
||||
background: url("/assets/packages/static/openvk/img/bsdn/repeat_hover.gif");
|
||||
object-fit: none;
|
||||
object-position: -64px 0;
|
||||
}
|
||||
|
||||
.bsdn_teaserWrap {
|
||||
|
@ -215,6 +221,6 @@ time.bsdn_timeFull {
|
|||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.bsdn_fullScreenButton > img, .bsdn_soundIcon {
|
||||
.bsdn_fullScreenButton > img, .bsdn_repeatButton > img, .bsdn_soundIcon {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,3 +58,249 @@ body.dimmed > .dimmer {
|
|||
.ovk-diag-action > .button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
|
||||
/* fullscreen player */
|
||||
|
||||
.ovk-fullscreen-player {
|
||||
top: 9%;
|
||||
left: 50%;
|
||||
margin-right: -50%;
|
||||
transform: translate(-50%, 0%);
|
||||
z-index: 6667;
|
||||
position: absolute;
|
||||
width: 823px;
|
||||
min-height: 400px;
|
||||
box-shadow: 0px 0px 9px 2px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.top-part span {
|
||||
color: #515151;
|
||||
font-size: 13px;
|
||||
transition: color 200ms ease-in-out;
|
||||
}
|
||||
|
||||
.top-part .clickable:hover {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.ovk-fullscreen-player .bsdn_teaserTitleBox span {
|
||||
color: unset;
|
||||
font-size: unset;
|
||||
}
|
||||
|
||||
.ovk-fullscreen-player .bsdn-player {
|
||||
max-width: 80%;
|
||||
max-height: 350px;
|
||||
}
|
||||
|
||||
.inner-player {
|
||||
background: #000000;
|
||||
min-height: 438px;
|
||||
max-height: 439px;
|
||||
position: relative;
|
||||
padding-top: 11px;
|
||||
}
|
||||
|
||||
.top-part-name {
|
||||
font-size: 15px;
|
||||
font-weight: bolder;
|
||||
margin-left: 20px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.top-part-buttons {
|
||||
float: right;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.top-part-buttons span {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.fplayer {
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.top-part-bottom-buttons {
|
||||
position: absolute;
|
||||
margin-left: 20px;
|
||||
bottom: 0;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.top-part-bottom-buttons span {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.top-part .clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.bottom-part {
|
||||
display: none;
|
||||
background: white;
|
||||
padding-bottom: 20px;
|
||||
padding-top: 30px;
|
||||
}
|
||||
|
||||
.left_block {
|
||||
padding-left: 20px;
|
||||
/*padding-top: 20px;*/
|
||||
width: 75%;
|
||||
float: left;
|
||||
background: white;
|
||||
padding-right: 6px;
|
||||
max-height: 400px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
/* Работает только в хроме, потому что в фурифоксе до сих пор нет кастомных скроллбаров лул */
|
||||
.left_block::-webkit-scrollbar {
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.right_block {
|
||||
padding-left: 10px;
|
||||
/*padding-top: 20px;*/
|
||||
width: 20%;
|
||||
border-left: 1px solid gray;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.bottom-part span {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.bottom-part .gray {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.ovk-fullscreen-dimmer {
|
||||
/* спижжено у пулла с несколькими картинками там где просмотрщик фоток */
|
||||
position: fixed;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
overflow: auto;
|
||||
padding-bottom: 20px;
|
||||
z-index: 300;
|
||||
}
|
||||
|
||||
.v_author {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.miniplayer {
|
||||
position: absolute;
|
||||
top:0;
|
||||
background: rgba(54, 54, 54, 0.9);
|
||||
border-radius: 3px;
|
||||
min-width: 299px;
|
||||
min-height: 192px;
|
||||
padding-top: 3px;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.miniplayer .bsdn-player {
|
||||
max-height: 150px;
|
||||
}
|
||||
|
||||
.miniplayer .fplayer {
|
||||
max-width: 286px;
|
||||
margin-left: 6px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.miniplayer-actions {
|
||||
float: right;
|
||||
margin-right: 8px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.miniplayer-name {
|
||||
color: #8a8a8a;
|
||||
font-size: 14px;
|
||||
margin-left: 7px;
|
||||
margin-top: -6px;
|
||||
font-weight: bolder;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.ui-draggable {
|
||||
position:fixed !important;
|
||||
}
|
||||
|
||||
.miniplayer-actions img {
|
||||
max-width: 11px;
|
||||
cursor: pointer;
|
||||
transition: opacity 200ms ease-in-out;
|
||||
opacity: 70%;
|
||||
}
|
||||
|
||||
.miniplayer .fplayer iframe {
|
||||
max-width: 260px;
|
||||
max-height: 160px;
|
||||
}
|
||||
|
||||
.miniplayer-actions img:hover {
|
||||
opacity: 100%;
|
||||
}
|
||||
|
||||
#vidComments {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.showMoreComments {
|
||||
background: #eaeaea;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
user-select: none;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.loader {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: -10%;
|
||||
background: rgba(26, 26, 26, 0.9);;
|
||||
padding-top: 12px;
|
||||
width: 91px;
|
||||
height: 25px;
|
||||
text-align: center;
|
||||
border-radius: 1px;
|
||||
margin: auto;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 5555;
|
||||
}
|
||||
|
||||
.right-arrow, .left-arrow {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
transition: all 200ms ease-in-out;
|
||||
margin-left: -50px;
|
||||
background: none;
|
||||
height: 449px;
|
||||
width: 57px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.right-arrow img, .left-arrow img {
|
||||
user-select: none;
|
||||
opacity: 5%;
|
||||
transition: all 200ms ease-in-out;
|
||||
}
|
||||
|
||||
.right-arrow:hover, .left-arrow:hover {
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.right-arrow img:hover, .left-arrow img:hover {
|
||||
opacity: 50%;
|
||||
}
|
||||
|
|
BIN
Web/static/img/bsdn/repeat.gif
Normal file
BIN
Web/static/img/bsdn/repeat.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 153 B |
BIN
Web/static/img/bsdn/repeat_hover.gif
Normal file
BIN
Web/static/img/bsdn/repeat_hover.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 154 B |
BIN
Web/static/img/left_arr.png
Normal file
BIN
Web/static/img/left_arr.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
BIN
Web/static/img/miniplayer_close.png
Normal file
BIN
Web/static/img/miniplayer_close.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 351 B |
BIN
Web/static/img/miniplayer_open.png
Normal file
BIN
Web/static/img/miniplayer_open.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 153 B |
BIN
Web/static/img/right_arr.png
Normal file
BIN
Web/static/img/right_arr.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
|
@ -22,6 +22,31 @@ function trim(string) {
|
|||
return newStr;
|
||||
}
|
||||
|
||||
function trimNum(string, num) {
|
||||
var newStr = string.substring(0, num);
|
||||
if(newStr.length !== string.length)
|
||||
newStr += "…";
|
||||
|
||||
return newStr;
|
||||
}
|
||||
|
||||
function handleUpload(id) {
|
||||
console.warn("блять...");
|
||||
|
||||
u("#post-buttons" + id + " .postFileSel").not("#" + this.id).each(input => input.value = null);
|
||||
|
||||
var indicator = u("#post-buttons" + id + " .post-upload");
|
||||
var file = this.files[0];
|
||||
if(typeof file === "undefined") {
|
||||
indicator.attr("style", "display: none;");
|
||||
} else {
|
||||
u("span", indicator.nodes[0]).text(trim(file.name) + " (" + humanFileSize(file.size, false) + ")");
|
||||
indicator.attr("style", "display: block;");
|
||||
}
|
||||
|
||||
document.querySelector("#post-buttons" + id + " #wallAttachmentMenu").classList.add("hidden");
|
||||
}
|
||||
|
||||
function initGraffiti(id) {
|
||||
let canvas = null;
|
||||
let msgbox = MessageBox(tr("draw_graffiti"), "<div id='ovkDraw'></div>", [tr("save"), tr("cancel")], [function() {
|
||||
|
@ -52,6 +77,7 @@ function initGraffiti(id) {
|
|||
});
|
||||
}
|
||||
|
||||
$(document).on("click", ".post-like-button", function(e) {
|
||||
function fastUploadImage(textareaId, file) {
|
||||
// uploading images
|
||||
|
||||
|
@ -493,6 +519,395 @@ async function showArticle(note_id) {
|
|||
u("body").addClass("article");
|
||||
}
|
||||
|
||||
// Оконный плеер
|
||||
|
||||
$(document).on("click", "#videoOpen", async (e) => {
|
||||
e.preventDefault()
|
||||
|
||||
document.getElementById("ajloader").style.display = "block"
|
||||
|
||||
if(document.querySelector(".ovk-fullscreen-dimmer") != null) {
|
||||
u(".ovk-fullscreen-dimmer").remove()
|
||||
}
|
||||
|
||||
let target = e.currentTarget
|
||||
let videoId = target.dataset.id
|
||||
let videoObj = null;
|
||||
|
||||
try {
|
||||
videoObj = await API.Video.getVideo(Number(videoId))
|
||||
} catch(e) {
|
||||
console.error(e)
|
||||
document.getElementById("ajloader").style.display = "none"
|
||||
MessageBox(tr("error"), tr("video_access_denied"), [tr("cancel")], [
|
||||
function() {
|
||||
Function.noop
|
||||
}]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
document.querySelector("html").style.overflowY = "hidden"
|
||||
|
||||
let player = null;
|
||||
|
||||
if(target.dataset.dontload == null) {
|
||||
document.querySelectorAll("video").forEach(vid => vid.pause())
|
||||
if(videoObj.type == 0) {
|
||||
if(videoObj.isProcessing) {
|
||||
player = `
|
||||
<span class="gray">${tr("video_processing")}</span>
|
||||
`
|
||||
} else {
|
||||
player = `
|
||||
<div class="bsdn media" data-name="${videoObj.title}" data-author="${videoObj.name}">
|
||||
<video class="media" src="${videoObj.url}"></video>
|
||||
</div>`
|
||||
}
|
||||
} else {
|
||||
player = videoObj.embed
|
||||
}
|
||||
} else {
|
||||
player = ``
|
||||
}
|
||||
|
||||
|
||||
let dialog = u(
|
||||
`
|
||||
<div class="ovk-fullscreen-dimmer">
|
||||
<div class="ovk-fullscreen-player">
|
||||
${videoObj.prevVideo != null ?
|
||||
`<div class="right-arrow" id="videoOpen" data-id="${videoObj.prevVideo}">
|
||||
<img src="/assets/packages/static/openvk/img/right_arr.png" draggable="false">
|
||||
</div>` : ""}
|
||||
${videoObj.nextVideo != null ? `
|
||||
<div class="left-arrow" id="videoOpen" data-id="${videoObj.nextVideo}" style="margin-left: 820px;">
|
||||
<img src="/assets/packages/static/openvk/img/left_arr.png" draggable="false">
|
||||
</div>` : ""}
|
||||
<div class="inner-player">
|
||||
<div class="top-part">
|
||||
<span class="top-part-name">${escapeHtml(videoObj.title)}</span>
|
||||
<div class="top-part-buttons">
|
||||
<span class="clickable" id="minimizePlayer" data-name="${videoObj.title}" data-id="${videoObj.id}">${tr("hide_player")}</span>
|
||||
<span>|</span>
|
||||
<span class="clickable" id="closeFplayer">${tr("close_player")}</span>
|
||||
</div>
|
||||
<div class="top-part-player-subdiv">
|
||||
${target.dataset.dontload == null ?`
|
||||
<div class="fplayer">
|
||||
${player}
|
||||
</div>` : ""}
|
||||
</div>
|
||||
<div class="top-part-bottom-buttons">
|
||||
<span class="clickable" id="showComments" data-id="${videoObj.id}" data-owner="${videoObj.owner}" data-pid="${videoObj.pretty_id}">${tr("show_comments")}</span>
|
||||
<span>|</span>
|
||||
<span class="clickable" id="gotopage" data-id="/video${videoObj.pretty_id}">${tr("to_page")}</span>
|
||||
${ videoObj.type == 0 && videoObj.isProcessing == false ? `<span>|</span>
|
||||
<a class="clickable" href="${videoObj.url}" download><span class="clickable">${tr("download_video")}</span></a>` : ""}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom-part">
|
||||
<div class="left_block">
|
||||
<div class="description" style="margin-bottom: 5px;">
|
||||
<span>${videoObj.description != null ? escapeHtml(videoObj.description) : "(" + tr("no_description") + ")"}</span>
|
||||
</div>
|
||||
<div class="bottom-part-info" style="display: flex;">
|
||||
<span class="gray">${tr("added")} ${videoObj.published} </span><span>|</span>
|
||||
<div class="like_wrap" style="float:unset;">
|
||||
<a href="/video${videoObj.pretty_id}/like?hash=${encodeURIComponent(u("meta[name=csrf]").attr("value"))}" class="post-like-button" data-liked="${videoObj.has_like ? 1 : 0}" data-likes="${videoObj.likes}">
|
||||
<div class="heart" id="${videoObj.has_like ? "liked" : ""}"></div>
|
||||
<span class="likeCnt" style="margin-top: -2px;">${videoObj.likes > 0 ? videoObj.likes : ""}</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="vidComments"></div>
|
||||
</div>
|
||||
<div class="right_block">
|
||||
<div class="views">
|
||||
<!--prosmoters are not implemented((-->
|
||||
<span class="gray">${tr("x_views", 0)}</span>
|
||||
</div>
|
||||
|
||||
<div class="v_author">
|
||||
<span class="gray">${tr("video_author")}:</span><br>
|
||||
<a href="/id${videoObj.owner}"><span style="color:unset;">${videoObj.author}</span></a>
|
||||
</div>
|
||||
<div class="actions" style="margin-top: 10px;margin-left: -3px;">
|
||||
${videoObj.canBeEdited ? `
|
||||
<a href="/video${videoObj.pretty_id}/edit" class="profile_link" style="display:block;width:96%;font-size: 13px;">
|
||||
${tr("edit")}
|
||||
</a>
|
||||
<a href="/video${videoObj.pretty_id}/remove" class="profile_link" style="display:block;width:96%;font-size: 13px;">
|
||||
${tr("delete")}
|
||||
</a>`
|
||||
: ""}
|
||||
<a id="shareVideo" class="profile_link" id="shareVideo" data-owner="${videoObj.owner}" data-vid="${videoObj.virtual_id}" style="display:block;width:96%;font-size: 13px;">
|
||||
${tr("share")}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`);
|
||||
|
||||
u("body").addClass("dimmed").append(dialog);
|
||||
|
||||
if(target.dataset.dontload != null) {
|
||||
let oldPlayer = document.querySelector(".miniplayer-video .fplayer")
|
||||
let newPlayer = document.querySelector(".top-part-player-subdiv")
|
||||
|
||||
document.querySelector(".top-part-player-subdiv")
|
||||
|
||||
newPlayer.append(oldPlayer)
|
||||
}
|
||||
|
||||
if(videoObj.type == 0 && videoObj.isProcessing == false) {
|
||||
bsdnInitElement(document.querySelector(".fplayer .bsdn"))
|
||||
}
|
||||
|
||||
document.getElementById("ajloader").style.display = "none"
|
||||
u(".miniplayer").remove()
|
||||
})
|
||||
|
||||
$(document).on("click", "#closeFplayer", async (e) => {
|
||||
u(".ovk-fullscreen-dimmer").remove();
|
||||
document.querySelector("html").style.overflowY = "scroll"
|
||||
u("body").removeClass("dimmed")
|
||||
})
|
||||
|
||||
$(document).on("click", "#minimizePlayer", async (e) => {
|
||||
let targ = e.currentTarget
|
||||
|
||||
let player = document.querySelector(".fplayer")
|
||||
|
||||
let dialog = u(`
|
||||
<div class="miniplayer">
|
||||
<span class="miniplayer-name">${escapeHtml(trimNum(targ.dataset.name, 26))}</span>
|
||||
<div class="miniplayer-actions">
|
||||
<img src="/assets/packages/static/openvk/img/miniplayer_open.png" id="videoOpen" data-dontload="true" data-id="${targ.dataset.id}">
|
||||
<img src="/assets/packages/static/openvk/img/miniplayer_close.png" id="closeMiniplayer">
|
||||
</div>
|
||||
<div class="miniplayer-video">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
|
||||
u("body").append(dialog);
|
||||
$('.miniplayer').draggable({cursor: "grabbing", containment: "body", cancel: ".miniplayer-video"});
|
||||
|
||||
let newPlayer = document.querySelector(".miniplayer-video")
|
||||
newPlayer.append(player)
|
||||
|
||||
document.querySelector(".miniplayer").style.top = window.scrollY;
|
||||
document.querySelector("#closeFplayer").click()
|
||||
})
|
||||
|
||||
$(document).on("click", "#closeMiniplayer", async (e) => {
|
||||
u(".miniplayer").remove()
|
||||
})
|
||||
|
||||
$(document).on("mouseup", "#gotopage", async (e) => {
|
||||
if(e.originalEvent.which === 1) {
|
||||
location.href = e.currentTarget.dataset.id
|
||||
} else if (e.originalEvent.which === 2) {
|
||||
window.open(e.currentTarget.dataset.id, '_blank')
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
$(document).keydown(function(e) {
|
||||
if(document.querySelector(".top-part-player-subdiv .bsdn") != null && document.activeElement.tagName == "BODY") {
|
||||
let video = document.querySelector(".top-part-player-subdiv video")
|
||||
|
||||
switch(e.keyCode) {
|
||||
// Пробел вроде
|
||||
case 32:
|
||||
document.querySelector(".top-part-player-subdiv .bsdn_teaserButton").click()
|
||||
break
|
||||
// Стрелка вниз, уменьшение громкости
|
||||
case 40:
|
||||
oldVolume = video.volume
|
||||
|
||||
if(oldVolume - 0.1 > 0) {
|
||||
video.volume = oldVolume - 0.1
|
||||
} else {
|
||||
video.volume = 0
|
||||
}
|
||||
|
||||
break;
|
||||
// Стрелка вверх, повышение громкости
|
||||
case 38:
|
||||
oldVolume = video.volume
|
||||
|
||||
if(oldVolume + 0.1 < 1) {
|
||||
video.volume = oldVolume + 0.1
|
||||
} else {
|
||||
video.volume = 1
|
||||
}
|
||||
|
||||
break
|
||||
// стрелка влево, отступ на 2 секунды назад
|
||||
case 37:
|
||||
oldTime = video.currentTime
|
||||
video.currentTime = oldTime - 2
|
||||
break
|
||||
// стрелка вправо, отступ на 2 секунды вперёд
|
||||
case 39:
|
||||
oldTime = document.querySelector(".top-part-player-subdiv video").currentTime
|
||||
document.querySelector(".top-part-player-subdiv video").currentTime = oldTime + 2
|
||||
break
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$(document).keyup(function(e) {
|
||||
if(document.querySelector(".top-part-player-subdiv .bsdn") != null && document.activeElement.tagName == "BODY") {
|
||||
let video = document.querySelector(".top-part-player-subdiv video")
|
||||
|
||||
switch(e.keyCode) {
|
||||
// Escape, закрытие плеера
|
||||
case 27:
|
||||
document.querySelector("#closeFplayer").click()
|
||||
break
|
||||
// Блять, я перепутал лево и право, пиздец я долбаёб конечно
|
||||
// Ну короче стрелка влево
|
||||
case 65:
|
||||
if(document.querySelector(".right-arrow") != null) {
|
||||
document.querySelector(".right-arrow").click()
|
||||
} else {
|
||||
console.info("No left arrow bro")
|
||||
}
|
||||
break
|
||||
// Фуллскрин
|
||||
case 70:
|
||||
document.querySelector(".top-part-player-subdiv .bsdn_fullScreenButton").click()
|
||||
break
|
||||
// стрелка вправо
|
||||
case 68:
|
||||
if(document.querySelector(".left-arrow") != null) {
|
||||
document.querySelector(".left-arrow").click()
|
||||
} else {
|
||||
console.info("No right arrow bro")
|
||||
}
|
||||
break;
|
||||
// S: Показать инфо о видео (не комментарии)
|
||||
case 83:
|
||||
document.querySelector(".top-part-player-subdiv #showComments").click()
|
||||
break
|
||||
// Мут (M)
|
||||
case 77:
|
||||
document.querySelector(".top-part-player-subdiv .bsdn_soundIcon").click()
|
||||
break;
|
||||
// Escape, выход из плеера
|
||||
case 192:
|
||||
document.querySelector(".top-part-buttons #minimizePlayer").click()
|
||||
break
|
||||
// Бля не помню сори
|
||||
case 75:
|
||||
document.querySelector(".top-part-player-subdiv .bsdn_playButton").click()
|
||||
break
|
||||
// Home, переход в начало видосика
|
||||
case 36:
|
||||
video.currentTime = 0
|
||||
break
|
||||
// End, переход в конец видосика
|
||||
case 35:
|
||||
video.currentTime = video.duration
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on("click", "#showComments", async (e) => {
|
||||
if(document.querySelector(".bottom-part").style.display == "none" || document.querySelector(".bottom-part").style.display == "") {
|
||||
if(document.getElementById("vidComments").innerHTML == "") {
|
||||
let xhr = new XMLHttpRequest
|
||||
xhr.open("GET", "/video"+e.currentTarget.dataset.pid)
|
||||
xhr.onloadstart = () => {
|
||||
document.getElementById("vidComments").innerHTML = `<img src="/assets/packages/static/openvk/img/loading_mini.gif">`
|
||||
}
|
||||
|
||||
xhr.timeout = 10000;
|
||||
|
||||
xhr.onload = () => {
|
||||
let parser = new DOMParser();
|
||||
let body = parser.parseFromString(xhr.responseText, "text/html");
|
||||
let comms = body.getElementById("comments")
|
||||
let commsHTML = comms.innerHTML.replace("expand_wall_textarea(11)", "expand_wall_textarea(999)")
|
||||
.replace("wall-post-input11", "wall-post-input999")
|
||||
.replace("post-buttons11", "post-buttons999")
|
||||
.replace("toggleMenu(11)", "toggleMenu(999)")
|
||||
.replace("toggleMenu(11)", "toggleMenu(999)")
|
||||
.replace(/ons11/g, "ons999")
|
||||
document.getElementById("vidComments").innerHTML = commsHTML
|
||||
}
|
||||
|
||||
xhr.onerror = () => {
|
||||
document.getElementById("vidComments").innerHTML = `<span>${tr("comments_load_timeout")}</span>`
|
||||
}
|
||||
|
||||
xhr.ontimeout = () => {
|
||||
document.getElementById("vidComments").innerHTML = `<span>${tr("comments_load_timeout")}</span>`
|
||||
};
|
||||
|
||||
xhr.send()
|
||||
}
|
||||
|
||||
document.querySelector(".bottom-part").style.display = "flex"
|
||||
e.currentTarget.innerHTML = tr("close_comments")
|
||||
} else {
|
||||
document.querySelector(".bottom-part").style.display = "none"
|
||||
e.currentTarget.innerHTML = tr("show_comments")
|
||||
}
|
||||
})
|
||||
|
||||
$(document).on("click", "#shareVideo", async (e) => {
|
||||
let owner_id = e.currentTarget.dataset.owner
|
||||
let virtual_id = e.currentTarget.dataset.vid
|
||||
let body = `
|
||||
<b>${tr('auditory')}:</b> <br/>
|
||||
<input type="radio" name="type" onchange="signs.setAttribute('hidden', 'hidden');document.getElementById('groupId').setAttribute('hidden', 'hidden')" value="0" checked>${tr("in_wall")}<br/>
|
||||
<input type="radio" name="type" onchange="signs.removeAttribute('hidden');document.getElementById('groupId').removeAttribute('hidden')" value="1" id="group">${tr("in_group")}<br/>
|
||||
<select style="width:50%;" id="groupId" name="groupId" hidden>
|
||||
</select><br/>
|
||||
<b>${tr('your_comment')}:</b>
|
||||
<textarea id='uRepostMsgInput'></textarea>
|
||||
<div id="signs" hidden>
|
||||
<label><input onchange="signed.checked ? signed.checked = false : null" type="checkbox" id="asgroup" name="asGroup">${tr('post_as_group')}</label><br>
|
||||
<label><input onchange="asgroup.checked = true" type="checkbox" id="signed" name="signed">${tr('add_signature')}</label>
|
||||
</div>
|
||||
`
|
||||
MessageBox(tr("share_video"), body, [tr("share"), tr("cancel")], [
|
||||
(async function() {
|
||||
let type = $('input[name=type]:checked').val()
|
||||
let club = document.getElementById("groupId").value
|
||||
|
||||
let asGroup = document.getElementById("asgroup").checked
|
||||
let signed = document.getElementById("signed").checked
|
||||
|
||||
let repost = null;
|
||||
|
||||
try {
|
||||
repost = await API.Video.shareVideo(Number(owner_id), Number(virtual_id), Number(type), uRepostMsgInput.value, Number(club), signed, asGroup)
|
||||
NewNotification(tr('information_-1'), tr('shared_succ_video'), null, () => {window.location.href = "/wall" + repost.pretty_id});
|
||||
} catch(e) {
|
||||
console.log("tudu")
|
||||
}
|
||||
}), (function() {
|
||||
Function.noop
|
||||
})], false);
|
||||
|
||||
try {
|
||||
clubs = await API.Groups.getWriteableClubs();
|
||||
for(const el of clubs) {
|
||||
document.getElementById("groupId").insertAdjacentHTML("beforeend", `<option value="${el.id}">${escapeHtml(el.name)}</option>`)
|
||||
}
|
||||
} catch(rejection) {
|
||||
console.error(rejection)
|
||||
document.getElementById("group").setAttribute("disabled", "disabled")
|
||||
}
|
||||
|
||||
$(document).on("click", "#videoAttachment", async (e) => {
|
||||
e.preventDefault()
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
Function.noop = () => {};
|
||||
|
||||
function MessageBox(title, body, buttons, callbacks) {
|
||||
function MessageBox(title, body, buttons, callbacks, removeDimmedOnExit = true) {
|
||||
if(u(".ovk-diag-cont").length > 0) return false;
|
||||
|
||||
document.querySelector("html").style.overflowY = "hidden"
|
||||
|
@ -20,11 +20,11 @@ function MessageBox(title, body, buttons, callbacks) {
|
|||
|
||||
button.on("click", function(e) {
|
||||
let __closeDialog = () => {
|
||||
if(document.querySelector(".ovk-photo-view-dimmer") == null) {
|
||||
|
||||
if(removeDimmedOnExit) {
|
||||
u("body").removeClass("dimmed");
|
||||
document.querySelector("html").style.overflowY = "scroll"
|
||||
}
|
||||
|
||||
|
||||
u(".ovk-diag-cont").remove();
|
||||
};
|
||||
|
||||
|
|
|
@ -68,6 +68,12 @@ function _bsdnTpl(name, author) {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="bsdn_repeatButton">
|
||||
<img src="/assets/packages/static/openvk/img/bsdn/repeat.gif" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="bsdn_fullScreenButton">
|
||||
<img src="/assets/packages/static/openvk/img/bsdn/fullscreen.gif" />
|
||||
|
@ -252,6 +258,26 @@ function _bsdnEventListenerFactory(el, v) {
|
|||
]
|
||||
},
|
||||
|
||||
".bsdn_repeatButton": {
|
||||
click: [
|
||||
() => {
|
||||
if(!v.loop) {
|
||||
v.loop = true
|
||||
el.querySelector(".bsdn_repeatButton").classList.add("pressed")
|
||||
|
||||
if(v.currentTime == v.duration) {
|
||||
v.currentTime = 0
|
||||
v.play()
|
||||
}
|
||||
|
||||
} else {
|
||||
v.loop = false
|
||||
el.querySelector(".bsdn_repeatButton").classList.remove("pressed")
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
".bsdn_fullScreenButton": {
|
||||
click: [
|
||||
() => {
|
||||
|
|
|
@ -1972,6 +1972,50 @@
|
|||
"mobile_user_info_hide" = "Hide";
|
||||
"mobile_user_info_show_details" = "Show details";
|
||||
|
||||
/* Fullscreen player */
|
||||
|
||||
"hide_player" = "Minimize";
|
||||
"close_player" = "Close";
|
||||
"show_comments" = "Show info";
|
||||
"close_comments" = "Hide info";
|
||||
"to_page" = "Go to page";
|
||||
"download_video" = "Download";
|
||||
"added" = "Added";
|
||||
"x_views" = "$1 views";
|
||||
|
||||
"video_author" = "Video's author";
|
||||
"video_delete" = "Delete";
|
||||
"no_description" = "no description";
|
||||
|
||||
"show_more_comments" = "Show more comments";
|
||||
"video_processing" = "Video is succefully uploaded and now is processed.";
|
||||
"video_access_denied" = "Access to video denied";
|
||||
"open_page_to_read_comms" = "To read the comments, open <a href=\"$1\">page</a>.";
|
||||
|
||||
"no_video_error" = "No videofile";
|
||||
"no_video_description" = "Select file or specify link.";
|
||||
|
||||
"error_video" = "An error has occurred";
|
||||
"file_corrupted" = "File is corrupted or does not have video.";
|
||||
"link_incorrect" = "Maybe, the link is wrong.";
|
||||
|
||||
"no_name_error" = "Video can't be published without name";
|
||||
"access_denied_error" = "Access denied";
|
||||
"access_denied_error_description" = "You are not allowed to edit this resource";
|
||||
|
||||
"changes_saved_video_comment" = "Updated data will appear on the video page";
|
||||
"cant_delete_video" = "Failed to delete video";
|
||||
"cant_delete_video_comment" = "You are not logged in.";
|
||||
|
||||
"change_video" = "Change video";
|
||||
|
||||
"video_is_deleted" = "Video was deleted.";
|
||||
"share_video" = "Share video";
|
||||
"shared_succ_video" = "Video will appear at your wall. Click on this notification to move to post.";
|
||||
"watch_in_window" = "Watch in window";
|
||||
|
||||
"comments_load_timeout" = "The instance may have fallen";
|
||||
|
||||
"my" = "My";
|
||||
"enter_a_name_or_artist" = "Enter a name or artist...";
|
||||
|
||||
|
|
|
@ -1858,6 +1858,50 @@
|
|||
"mobile_user_info_hide" = "Скрыть";
|
||||
"mobile_user_info_show_details" = "Показать подробнее";
|
||||
|
||||
/* Fullscreen player */
|
||||
|
||||
"hide_player" = "Скрыть";
|
||||
"close_player" = "Закрыть";
|
||||
"show_comments" = "Показать информацию";
|
||||
"close_comments" = "Скрыть информацию";
|
||||
"to_page" = "Перейти на страницу";
|
||||
"download_video" = "Скачать";
|
||||
"added" = "Добавлено";
|
||||
"x_views" = "$1 просмотров";
|
||||
|
||||
"video_author" = "Автор видео";
|
||||
"video_delete" = "Удалить";
|
||||
"no_description" = "описания нет";
|
||||
|
||||
"show_more_comments" = "Показать больше комментариев";
|
||||
"video_processing" = "Видео успешно загружено и на данный момент обрабатывается.";
|
||||
"video_access_denied" = "Доступ к видео запрещён";
|
||||
"open_page_to_read_comms" = "Для чтения комментариев откройте <a href=\"$1\">страницу</a>.";
|
||||
|
||||
"no_video_error" = "Нету видеозаписи";
|
||||
"no_video_description" = "Выберите файл или укажите ссылку.";
|
||||
|
||||
"error_video" = "Произошла ошибка";
|
||||
"file_corrupted" = "Файл повреждён или не содержит видео.";
|
||||
"link_incorrect" = "Возможно, ссылка некорректна.";
|
||||
|
||||
"no_name_error" = "Видео не может быть опубликовано без названия";
|
||||
"access_denied_error" = "Ошибка доступа";
|
||||
"access_denied_error_description" = "Вы не имеете права редактировать этот ресурс";
|
||||
|
||||
"changes_saved_video_comment" = "Обновлённые данные появятся на странице с видео";
|
||||
"cant_delete_video" = "Не удалось удалить видео";
|
||||
"cant_delete_video_comment" = "Вы не вошли в аккаунт.";
|
||||
|
||||
"change_video" = "Изменить видеозапись";
|
||||
|
||||
"video_is_deleted" = "Видео удалено.";
|
||||
"share_video" = "Поделиться видеороликом";
|
||||
"shared_succ_video" = "Видео появится на вашей стене. Нажмите на уведомление, чтобы перейти к записи.";
|
||||
"watch_in_window" = "Смотреть в окне";
|
||||
|
||||
"comments_load_timeout" = "Возможно, инстанция упала.";
|
||||
|
||||
"my" = "Мои";
|
||||
"enter_a_name_or_artist" = "Введите название или автора...";
|
||||
|
||||
|
@ -1897,3 +1941,4 @@
|
|||
|
||||
"roll_back" = "откатить";
|
||||
"roll_backed" = "откачено";
|
||||
|
||||
|
|
Loading…
Reference in a new issue