mirror of
https://github.com/openvk/openvk
synced 2024-12-23 17:12:01 +03:00
Compare commits
4 commits
5436656aed
...
c6a77de234
Author | SHA1 | Date | |
---|---|---|---|
|
c6a77de234 | ||
|
4845f8f318 | ||
|
934bc9b25c | ||
|
344ba53acd |
17 changed files with 587 additions and 13 deletions
|
@ -13,7 +13,7 @@ class Video extends Media
|
||||||
const TYPE_EMBED = 1;
|
const TYPE_EMBED = 1;
|
||||||
|
|
||||||
protected $tableName = "videos";
|
protected $tableName = "videos";
|
||||||
protected $fileExtension = "ogv";
|
protected $fileExtension = "mp4";
|
||||||
|
|
||||||
protected $processingPlaceholder = "video/rendering";
|
protected $processingPlaceholder = "video/rendering";
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ class Video extends Media
|
||||||
if(!$this->isProcessed())
|
if(!$this->isProcessed())
|
||||||
return "/assets/packages/static/openvk/video/rendering.apng";
|
return "/assets/packages/static/openvk/video/rendering.apng";
|
||||||
|
|
||||||
return preg_replace("%\.[A-z]++$%", ".gif", $this->getURL());
|
return preg_replace("%\.[A-z0-9]++$%", ".gif", $this->getURL());
|
||||||
} else {
|
} else {
|
||||||
return $this->getVideoDriver()->getThumbnailURL();
|
return $this->getVideoDriver()->getThumbnailURL();
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,8 @@ Move-Item $file $temp
|
||||||
|
|
||||||
# video stub logic was implicitly deprecated, so we start processing at once
|
# 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 -ss 00:00:01.000 -vframes 1 "$dir$hashT/$hash.gif"
|
||||||
ffmpeg -i $temp -c:v libtheora -q:v 7 -c:a libvorbis -q:a 4 -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 -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
|
||||||
|
|
||||||
Move-Item $temp2 "$dir$hashT/$hash.ogv"
|
Move-Item $temp2 "$dir$hashT/$hash.mp4"
|
||||||
Remove-Item $temp
|
Remove-Item $temp
|
||||||
Remove-Item $temp2
|
Remove-Item $temp2
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
tmpfile="$RANDOM-$(date +%s%N)"
|
tmpfile="$RANDOM-$(date +%s%N)"
|
||||||
|
|
||||||
cp $2 "/tmp/vid_$tmpfile.bin"
|
cp $2 "/tmp/vid_$tmpfile.bin"
|
||||||
cp ../files/video/rendering.apng $3${4:0:2}/$4.gif
|
|
||||||
cp ../files/video/rendering.ogv $3/${4:0:2}/$4.ogv
|
|
||||||
|
|
||||||
nice ffmpeg -i "/tmp/vid_$tmpfile.bin" -ss 00:00:01.000 -vframes 1 $3${4:0:2}/$4.gif
|
nice ffmpeg -i "/tmp/vid_$tmpfile.bin" -ss 00:00:01.000 -vframes 1 $3${4:0:2}/$4.gif
|
||||||
nice -n 20 ffmpeg -i "/tmp/vid_$tmpfile.bin" -c:v libtheora -q:v 7 -c:a libvorbis -q:a 4 -vf "scale=640:480:force_original_aspect_ratio=decrease,pad=640:480:(ow-iw)/2:(oh-ih)/2,setsar=1" -y "/tmp/ffmOi$tmpfile.ogv"
|
nice -n 20 ffmpeg -i "/tmp/vid_$tmpfile.bin" -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 "/tmp/ffmOi$tmpfile.mp4"
|
||||||
|
|
||||||
rm -rf $3${4:0:2}/$4.ogv
|
rm -rf $3${4:0:2}/$4.mp4
|
||||||
mv "/tmp/ffmOi$tmpfile.ogv" $3${4:0:2}/$4.ogv
|
mv "/tmp/ffmOi$tmpfile.mp4" $3${4:0:2}/$4.mp4
|
||||||
|
|
||||||
rm -f "/tmp/ffmOi$tmpfile.ogv"
|
rm -f "/tmp/ffmOi$tmpfile.mp4"
|
||||||
rm -f "/tmp/vid_$tmpfile.bin"
|
rm -f "/tmp/vid_$tmpfile.bin"
|
||||||
|
|
|
@ -294,6 +294,7 @@
|
||||||
{script "js/messagebox.js"}
|
{script "js/messagebox.js"}
|
||||||
{script "js/notifications.js"}
|
{script "js/notifications.js"}
|
||||||
{script "js/scroll.js"}
|
{script "js/scroll.js"}
|
||||||
|
{script "js/player.js"}
|
||||||
{script "js/al_wall.js"}
|
{script "js/al_wall.js"}
|
||||||
{script "js/al_api.js"}
|
{script "js/al_api.js"}
|
||||||
{script "js/al_mentions.js"}
|
{script "js/al_mentions.js"}
|
||||||
|
@ -310,6 +311,8 @@
|
||||||
</script>
|
</script>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
<script>bsdnHydrate();</script>
|
||||||
|
|
||||||
<script n:if="OPENVK_ROOT_CONF['openvk']['telemetry']['plausible']['enable']" async defer data-domain="{php echo OPENVK_ROOT_CONF['openvk']['telemetry']['plausible']['domain']}" src="{php echo OPENVK_ROOT_CONF['openvk']['telemetry']['plausible']['server']}js/plausible.js"></script>
|
<script n:if="OPENVK_ROOT_CONF['openvk']['telemetry']['plausible']['enable']" async defer data-domain="{php echo OPENVK_ROOT_CONF['openvk']['telemetry']['plausible']['domain']}" src="{php echo OPENVK_ROOT_CONF['openvk']['telemetry']['plausible']['server']}js/plausible.js"></script>
|
||||||
|
|
||||||
<script n:if="OPENVK_ROOT_CONF['openvk']['telemetry']['piwik']['enable']">
|
<script n:if="OPENVK_ROOT_CONF['openvk']['telemetry']['piwik']['enable']">
|
||||||
|
|
|
@ -13,7 +13,9 @@
|
||||||
{block content}
|
{block content}
|
||||||
<center style="margin-bottom: 8pt;">
|
<center style="margin-bottom: 8pt;">
|
||||||
{if $video->getType() === 0}
|
{if $video->getType() === 0}
|
||||||
<video width="610" src="{$video->getURL()}" controls></video>
|
<div class="bsdn" data-name="{$video->getName()}" data-author="{$user->getCanonicalName()}">
|
||||||
|
<video width="610" src="{$video->getURL()}"></video>
|
||||||
|
</div>
|
||||||
{else}
|
{else}
|
||||||
{var $driver = $video->getVideoDriver()}
|
{var $driver = $video->getVideoDriver()}
|
||||||
{if !$driver}
|
{if !$driver}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
{if $theme !== NULL}
|
{if $theme !== NULL}
|
||||||
{if $theme->inheritDefault()}
|
{if $theme->inheritDefault()}
|
||||||
|
{css "css/bsdn.css"}
|
||||||
{css "css/style.css"}
|
{css "css/style.css"}
|
||||||
{css "css/dialog.css"}
|
{css "css/dialog.css"}
|
||||||
{css "css/notifications.css"}
|
{css "css/notifications.css"}
|
||||||
|
@ -20,6 +21,7 @@
|
||||||
<link rel="stylesheet" href="/themepack/{$theme->getId()}/{$theme->getVersion()}/resource/xmas.css" />
|
<link rel="stylesheet" href="/themepack/{$theme->getId()}/{$theme->getVersion()}/resource/xmas.css" />
|
||||||
{/if}
|
{/if}
|
||||||
{else}
|
{else}
|
||||||
|
{css "css/bsdn.css"}
|
||||||
{css "css/style.css"}
|
{css "css/style.css"}
|
||||||
{css "css/dialog.css"}
|
{css "css/dialog.css"}
|
||||||
{css "css/notifications.css"}
|
{css "css/notifications.css"}
|
||||||
|
@ -41,6 +43,7 @@
|
||||||
{css "css/microblog.css"}
|
{css "css/microblog.css"}
|
||||||
{/if}
|
{/if}
|
||||||
{else}
|
{else}
|
||||||
|
{css "css/bsdn.css"}
|
||||||
{css "css/style.css"}
|
{css "css/style.css"}
|
||||||
{css "css/dialog.css"}
|
{css "css/dialog.css"}
|
||||||
{css "css/nsfw-posts.css"}
|
{css "css/nsfw-posts.css"}
|
||||||
|
|
|
@ -10,7 +10,13 @@
|
||||||
</a>
|
</a>
|
||||||
{/if}
|
{/if}
|
||||||
{elseif $attachment instanceof \openvk\Web\Models\Entities\Video}
|
{elseif $attachment instanceof \openvk\Web\Models\Entities\Video}
|
||||||
<video class="media" src="{$attachment->getURL()}" controls="controls"></video>
|
<div class="bsdn media" data-name="{$attachment->getName()}" data-author="{$attachment->getOwner()->getCanonicalName()}">
|
||||||
|
<video class="media" src="{$attachment->getURL()}"></video>
|
||||||
|
</div>
|
||||||
|
<div class="video-wowzer">
|
||||||
|
<img src="/assets/packages/static/openvk/img/videoico.png" />
|
||||||
|
<a href="/video{$attachment->getPrettyId()}">{$attachment->getName()}</a>
|
||||||
|
</div>
|
||||||
{elseif $attachment instanceof \openvk\Web\Models\Entities\Poll}
|
{elseif $attachment instanceof \openvk\Web\Models\Entities\Poll}
|
||||||
{presenter "openvk!Poll->view", $attachment->getId()}
|
{presenter "openvk!Poll->view", $attachment->getId()}
|
||||||
{elseif $attachment instanceof \openvk\Web\Models\Entities\Post}
|
{elseif $attachment instanceof \openvk\Web\Models\Entities\Post}
|
||||||
|
|
213
Web/static/css/bsdn.css
Normal file
213
Web/static/css/bsdn.css
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
.bsdn-player {
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
display: inline-flex;
|
||||||
|
font-family: sans-serif;
|
||||||
|
user-select: none;
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bsdn-player > .bsdn_controls, .bsdn-player > .bsdn_teaserWrap, .bsdn-player > .bsdn_contextMenu {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bsdn_controls {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: hsl(0deg 0% 0% / 59%);
|
||||||
|
border-top: 1px solid hsl(0deg 0% 100% / 70%);
|
||||||
|
padding: 7px 12px;
|
||||||
|
color: #fff;
|
||||||
|
align-items: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
gap: 6px;
|
||||||
|
z-index: 2;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bsdn-player.bsdn-dirty > .bsdn_controls {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bsdn_video {
|
||||||
|
width: 100%;
|
||||||
|
display: inline-flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bsdn_terebilkaUpperWrap {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bsdn_terebilkaWrap {
|
||||||
|
flex-grow: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bsdn_logo {
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.bsdn_timeWrap {
|
||||||
|
display: inline;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bsdn_terebilkaLowerWrap, .bsdn_soundControlSubWrap {
|
||||||
|
position: relative;
|
||||||
|
height: 6px;
|
||||||
|
border-top: 1px solid white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bsdn_terebilkaBrick, .bsdn_soundControlBrick {
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
width: 15px;
|
||||||
|
background-color: #fff;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bsdn_soundIcon {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bsdn_soundControl {
|
||||||
|
width: 64px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bsdn_soundControlBrick {
|
||||||
|
width: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bsdn_soundControlPadding {
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.bsdn_playButton {
|
||||||
|
appearance: none;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: #fff;
|
||||||
|
padding: 0 8px;
|
||||||
|
padding-left: 0;
|
||||||
|
font-size: 22px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bsdn_fullScreenButton {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bsdn_teaserWrap {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 1;
|
||||||
|
color: #fff;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background-color: hsl(0deg 0% 0% / 10%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bsdn_teaser {
|
||||||
|
display: flex;
|
||||||
|
padding: 10px 20px;
|
||||||
|
width: 266px;
|
||||||
|
background-color: hsl(0deg 0% 14.17% / 74.12%);
|
||||||
|
border-radius: 10px;
|
||||||
|
align-items: stretch;
|
||||||
|
justify-content: space-between;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bsdn_teaserTitleBox {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-around;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bsdn_teaserButton {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
time.bsdn_timeFull {
|
||||||
|
margin-left: 10px;
|
||||||
|
color: #b1b1b1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bsdn-player._bsdn_playing .bsdn_controls {
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: 1s opacity ease-in-out;
|
||||||
|
transition-delay: 2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bsdn-player._bsdn_playing:hover .bsdn_controls {
|
||||||
|
opacity: 1;
|
||||||
|
pointer-events: unset;
|
||||||
|
transition: .2s opacity ease-in-out;
|
||||||
|
transition-delay: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.bsdn_video > video {
|
||||||
|
height: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.bsdn_contextMenu {
|
||||||
|
z-index: 3;
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
padding: 6px;
|
||||||
|
border: 1px solid #908f90;
|
||||||
|
width: 232px;
|
||||||
|
height: 169px;
|
||||||
|
font-size: 15px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bsdn_contextMenuElement {
|
||||||
|
display: block;
|
||||||
|
color: #666294;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 3px 0 3px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bsdn_contextMenu hr {
|
||||||
|
margin: 5px 0;
|
||||||
|
border-color: #878f8e;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.bsdn_contextMenuElement:hover, .bsdn_contextMenuElement:active {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.bsdn_contextMenuElement:hover {
|
||||||
|
background-color: #9797c8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bsdn_contextMenuElement:active {
|
||||||
|
background-color: #5a5a8f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.bsdn_teaserWrap span {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bsdn_teaserButton > img {
|
||||||
|
max-height: 69px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bsdn_fullScreenButton > img, .bsdn_soundIcon {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
|
@ -2277,3 +2277,21 @@ a.poll-retract-vote {
|
||||||
.tour div {
|
.tour div {
|
||||||
font-size: 11px; color:#000;
|
font-size: 11px; color:#000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.video-wowzer > img {
|
||||||
|
vertical-align: bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-wowzer {
|
||||||
|
font-weight: bolder;
|
||||||
|
font-size: 12px;
|
||||||
|
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;
|
||||||
|
}
|
BIN
Web/static/img/bsdn/fullscreen.gif
Normal file
BIN
Web/static/img/bsdn/fullscreen.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 333 B |
BIN
Web/static/img/bsdn/pause.gif
Normal file
BIN
Web/static/img/bsdn/pause.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 248 B |
BIN
Web/static/img/bsdn/play.png
Normal file
BIN
Web/static/img/bsdn/play.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.7 KiB |
BIN
Web/static/img/bsdn/speaker.gif
Normal file
BIN
Web/static/img/bsdn/speaker.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 240 B |
BIN
Web/static/img/bsdn/speaker_muted.gif
Normal file
BIN
Web/static/img/bsdn/speaker_muted.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 88 B |
BIN
Web/static/img/videoico.png
Normal file
BIN
Web/static/img/videoico.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 130 B |
331
Web/static/js/player.js
Normal file
331
Web/static/js/player.js
Normal file
|
@ -0,0 +1,331 @@
|
||||||
|
function _bsdnUnwrapBitMask(number) {
|
||||||
|
return number.toString(2).split("").reverse().map(x => x === "1");
|
||||||
|
}
|
||||||
|
|
||||||
|
function _bsdnToHumanTime(time) {
|
||||||
|
time = Math.ceil(time);
|
||||||
|
let mins = Math.floor(time / 60);
|
||||||
|
let secs = (time - (mins * 60));
|
||||||
|
|
||||||
|
if(secs < 10)
|
||||||
|
secs = "0" + secs;
|
||||||
|
if(mins < 10)
|
||||||
|
mins = "0" + mins;
|
||||||
|
|
||||||
|
return mins + ":" + secs;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _bsdnTpl(name, author) {
|
||||||
|
return `
|
||||||
|
<div class="bsdn_contextMenu" style="display: none;">
|
||||||
|
<span class="bsdn_contextMenuElement bsdn_copyVideoUrl">Copy video link to clipboard</span>
|
||||||
|
<hr/>
|
||||||
|
<span class="bsdn_contextMenuElement">OpenVK BSDN///Player 0.1</span>
|
||||||
|
<hr/>
|
||||||
|
<span class="bsdn_contextMenuElement">Developers:</span>
|
||||||
|
<span class="bsdn_contextMenuElement" onclick="window.location.assign('https://github.com/celestora');">
|
||||||
|
- celstora
|
||||||
|
</span>
|
||||||
|
<span class="bsdn_contextMenuElement" onclick="window.location.assign('https://github.com/openvk/openvk/issues');">
|
||||||
|
- Report a problem...
|
||||||
|
</span>
|
||||||
|
<hr/>
|
||||||
|
<span class="bsdn_contextMenuElement" onclick="confirm('эм это шутка');">About Adobe Flash Player...</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bsdn_controls">
|
||||||
|
<div>
|
||||||
|
<button class="bsdn_playButton">▶</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bsdn_terebilkaWrap">
|
||||||
|
<div class="bsdn_terebilkaUpperWrap">
|
||||||
|
<img class="bsdn_logo" src="/assets/packages/static/openvk/img/bsdn/logo.gif" style="opacity: 0; /* TODO add logo xdd */" />
|
||||||
|
<p class="bsdn_timeWrap">
|
||||||
|
<time class="bsdn_timeReal">--:--</time>
|
||||||
|
<time class="bsdn_timeFull">--:--</time>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bsdn_terebilkaLowerWrap">
|
||||||
|
<div class="bsdn_terebilkaBrick"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<img class="bsdn_soundIcon" src="/assets/packages/static/openvk/img/bsdn/speaker.gif" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bsdn_soundControl">
|
||||||
|
<div class="bsdn_soundControlPadding"></div>
|
||||||
|
<div class="bsdn_soundControlSubWrap">
|
||||||
|
<div class="bsdn_soundControlBrick" style="left: calc(100% - 10px);"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="bsdn_fullScreenButton">
|
||||||
|
<img src="/assets/packages/static/openvk/img/bsdn/fullscreen.gif" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bsdn_teaserWrap">
|
||||||
|
<div class="bsdn_teaser">
|
||||||
|
<div class="bsdn_teaserTitleBox">
|
||||||
|
<b>${name}</b>
|
||||||
|
<span>${author}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bsdn_teaserButton">
|
||||||
|
<img src="/assets/packages/static/openvk/img/bsdn/play.png" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _bsdnTerebilkaEventFactory(el, terebilka, callback, otherListeners) {
|
||||||
|
let terebilkaSize = () => el.querySelector(terebilka).getBoundingClientRect().width; // чтобы просралось
|
||||||
|
|
||||||
|
let listeners = {
|
||||||
|
mousemove: [
|
||||||
|
e => {
|
||||||
|
let buttonsPresseed = _bsdnUnwrapBitMask(e.buttons);
|
||||||
|
if(!buttonsPresseed[0])
|
||||||
|
return; // user doesn't click so nothing should be done
|
||||||
|
|
||||||
|
let offset = e.offsetX;
|
||||||
|
let percents = Math.max(0, Math.min(100, offset / (terebilkaSize() / 100)));
|
||||||
|
|
||||||
|
return callback(percents);
|
||||||
|
}
|
||||||
|
],
|
||||||
|
mousedown: [
|
||||||
|
e => {
|
||||||
|
let offset = e.offsetX;
|
||||||
|
let percents = Math.max(0, Math.min(100, offset / (terebilkaSize() / 100)));
|
||||||
|
|
||||||
|
return callback(percents);
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
for(eventName in (otherListeners || {})) {
|
||||||
|
if(listeners.hasOwnProperty(eventName))
|
||||||
|
listeners[eventName] = otherListeners[eventName].concat(listeners[eventName]);
|
||||||
|
else
|
||||||
|
listeners[eventName] = otherListeners[eventName];
|
||||||
|
}
|
||||||
|
|
||||||
|
return listeners;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _bsdnEventListenerFactory(el, v) {
|
||||||
|
return {
|
||||||
|
".bsdn-player": {
|
||||||
|
click: [
|
||||||
|
e => {
|
||||||
|
if(el.querySelector(".bsdn_controls").contains(e.target) || el.querySelector(".bsdn_teaser").contains(e.target) || el.querySelector(".bsdn_contextMenu").contains(e.target))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(el.querySelector(".bsdn_contextMenu").style.display !== "none") {
|
||||||
|
el.querySelector(".bsdn_contextMenu").style.display = "none";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(v.paused)
|
||||||
|
v.play();
|
||||||
|
else
|
||||||
|
v.pause();
|
||||||
|
}
|
||||||
|
],
|
||||||
|
contextmenu: [
|
||||||
|
e => {
|
||||||
|
e.preventDefault();
|
||||||
|
if(el.querySelector(".bsdn_controls").contains(e.target) || el.querySelector(".bsdn_contextMenu").contains(e.target))
|
||||||
|
return;
|
||||||
|
|
||||||
|
let rect = el.querySelector(".bsdn-player").getBoundingClientRect();
|
||||||
|
let h = rect.height, w = rect.width;
|
||||||
|
let x, y;
|
||||||
|
if(document.fullscreen) {
|
||||||
|
x = e.screenX;
|
||||||
|
y = e.screenY;
|
||||||
|
} else {
|
||||||
|
let rx = rect.x + window.scrollX, ry = rect.y + window.scrollY;
|
||||||
|
x = e.pageX - rx;
|
||||||
|
y = e.pageY - ry;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(h - y < 169)
|
||||||
|
y = Math.max(0, y - 169);
|
||||||
|
|
||||||
|
if(w - x < 238)
|
||||||
|
x = Math.max(0, x - 238);
|
||||||
|
|
||||||
|
let menu = el.querySelector(".bsdn_contextMenu");
|
||||||
|
menu.style.top = y + "px";
|
||||||
|
menu.style.left = x + "px";
|
||||||
|
menu.style.display = "unset";
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
".bsdn_contextMenuElement": {
|
||||||
|
click: [ () => el.querySelector(".bsdn_contextMenu").style.display = "none" ]
|
||||||
|
},
|
||||||
|
|
||||||
|
".bsdn_video > video": {
|
||||||
|
play: [
|
||||||
|
() => {
|
||||||
|
if(!el.querySelector(".bsdn-player").classList.contains("bsdn-dirty"))
|
||||||
|
el.querySelector(".bsdn-player").classList.add("bsdn-dirty")
|
||||||
|
|
||||||
|
el.querySelector(".bsdn_playButton").innerHTML = "<img src='/assets/packages/static/openvk/img/bsdn/pause.gif' style='padding-right: 3px; padding-top: 3px;' />";
|
||||||
|
el.querySelector(".bsdn-player").classList.add("_bsdn_playing");
|
||||||
|
el.querySelector(".bsdn_teaserWrap").style.display = "none";
|
||||||
|
}
|
||||||
|
],
|
||||||
|
pause: [
|
||||||
|
() => {
|
||||||
|
el.querySelector(".bsdn_playButton").innerHTML = "▶";
|
||||||
|
el.querySelector(".bsdn-player").classList.remove("_bsdn_playing");
|
||||||
|
el.querySelector(".bsdn_teaserWrap").style.display = "flex";
|
||||||
|
}
|
||||||
|
],
|
||||||
|
timeupdate: [
|
||||||
|
() => {
|
||||||
|
el.querySelector(".bsdn_timeReal").innerHTML = _bsdnToHumanTime(v.currentTime);
|
||||||
|
|
||||||
|
let terebilkaSize = el.querySelector(".bsdn_terebilkaLowerWrap").getBoundingClientRect().width;
|
||||||
|
let brickSize = 15;
|
||||||
|
let percents = Math.ceil(v.currentTime / (v.duration / 100));
|
||||||
|
let offset = ((terebilkaSize - brickSize) / 100) * percents;
|
||||||
|
el.querySelector(".bsdn_terebilkaBrick").style.left = `min(calc(100% - 15px), ${offset}px`; // смешной мясной костыль ибо мне лень делать onresize
|
||||||
|
}
|
||||||
|
],
|
||||||
|
volumechange: [
|
||||||
|
() => {
|
||||||
|
if(v.volume === 0)
|
||||||
|
el.querySelector(".bsdn_soundIcon").src = "/assets/packages/static/openvk/img/bsdn/speaker_muted.gif";
|
||||||
|
else
|
||||||
|
el.querySelector(".bsdn_soundIcon").src = "/assets/packages/static/openvk/img/bsdn/speaker.gif";
|
||||||
|
|
||||||
|
let scSize = el.querySelector(".bsdn_soundControlSubWrap").getBoundingClientRect().width;
|
||||||
|
let brickSize = 10;
|
||||||
|
let offset = (scSize - brickSize) * v.volume;
|
||||||
|
el.querySelector(".bsdn_soundControlBrick").style.left = offset + "px";
|
||||||
|
}
|
||||||
|
],
|
||||||
|
loadedmetadata: [
|
||||||
|
() => {
|
||||||
|
el.querySelector(".bsdn_timeFull").innerHTML = _bsdnToHumanTime(v.duration);
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
".bsdn_fullScreenButton": {
|
||||||
|
click: [
|
||||||
|
() => {
|
||||||
|
if(document.fullscreen) {
|
||||||
|
document.exitFullscreen();
|
||||||
|
} else {
|
||||||
|
el.querySelector(".bsdn-player").requestFullscreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
".bsdn_teaserButton|.bsdn_playButton": {
|
||||||
|
click: [
|
||||||
|
() => {
|
||||||
|
if(v.paused)
|
||||||
|
v.play();
|
||||||
|
else
|
||||||
|
v.pause();
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
".bsdn_terebilkaLowerWrap": _bsdnTerebilkaEventFactory(el, ".bsdn_terebilkaLowerWrap", function(p) {
|
||||||
|
let time = (v.duration / 100) * p;
|
||||||
|
setTimeout(() => {
|
||||||
|
v.currentTime = time;
|
||||||
|
if(v.currentTime === 0) {
|
||||||
|
console.warn("[!] Хромог момент");
|
||||||
|
console.warn("Теребилка не работает в хроме если сервер не реализует HTTP полностью.");
|
||||||
|
console.warn("Встроенный сервер РНР не возвращает заголовки Accept-Range из-за чего хром отказывается seek'ать. Google как всегда.");
|
||||||
|
console.warn("Установите Firefox для лучшей безопасности в сети: https://www.mozilla.org/ru/firefox/enterprise/#download");
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
}, {
|
||||||
|
mousedown: [
|
||||||
|
e => v.pause()
|
||||||
|
],
|
||||||
|
mouseup: [
|
||||||
|
e => v.play()
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
|
||||||
|
".bsdn_soundControlSubWrap": _bsdnTerebilkaEventFactory(el, ".bsdn_soundControlSubWrap", function(p) {
|
||||||
|
let volume = p / 100;
|
||||||
|
v.volume = volume;
|
||||||
|
}),
|
||||||
|
|
||||||
|
".bsdn_soundIcon": {
|
||||||
|
click: [
|
||||||
|
e => v.volume = v.volume === 0 ? 0.75 : 0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _bsdnApplyBindings(el, v) {
|
||||||
|
let listeners = _bsdnEventListenerFactory(el, v);
|
||||||
|
|
||||||
|
for(key in listeners) {
|
||||||
|
let selectors = key.split("|");
|
||||||
|
selectors.forEach(sel => {
|
||||||
|
for(eventName in listeners[key]) {
|
||||||
|
listeners[key][eventName].forEach(listener => {
|
||||||
|
el.querySelectorAll(sel).forEach(target => {
|
||||||
|
target.addEventListener(eventName, listener, {
|
||||||
|
passive: (["contextmenu"]).indexOf(eventName) === -1
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function bsdnInitElement(el) {
|
||||||
|
if(el.querySelector(".bdsn-hydrated") != null) {
|
||||||
|
console.debug(el, " is already hydrated.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let video = el.querySelector("video");
|
||||||
|
if(!video) {
|
||||||
|
console.warning(el, " does not contain any <video>s.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
el.innerHTML = `
|
||||||
|
<div class="bsdn-player bdsn-hydrated">
|
||||||
|
${_bsdnTpl(el.dataset.name, el.dataset.author)}
|
||||||
|
<div class="bsdn_video">
|
||||||
|
${video.outerHTML}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
video = el.querySelector(".bsdn_video > video");
|
||||||
|
_bsdnApplyBindings(el, video);
|
||||||
|
video.volume = 0.75;
|
||||||
|
}
|
||||||
|
|
||||||
|
function bsdnHydrate() {
|
||||||
|
document.querySelectorAll(".bsdn").forEach(bsdnInitElement);
|
||||||
|
}
|
Loading…
Reference in a new issue