Merge pull request #23 from CyberShadow/pull-20190727-205645

More fixes
This commit is contained in:
Ali Zemani 2019-08-03 11:06:21 +04:30 committed by GitHub
commit 114d029e18
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 84 additions and 84 deletions

View file

@ -34,6 +34,11 @@ var segmentGroups = bv.segmentGroups;
// Persistent state // Persistent state
var ls = window.localStorage || {}; var ls = window.localStorage || {};
if (!('initialized' in ls)) {
for (let k in bv.stateHistory)
ls["persistentState_" + k] = JSON.stringify(bv.stateHistory[k]);
ls['initialized'] = 't';
}
function msToString(ms) { function msToString(ms) {
return new Date(ms).toUTCString().split(' ')[4]; return new Date(ms).toUTCString().split(' ')[4];
@ -55,9 +60,9 @@ function preconditionToJS(cond) {
} else if (cond[0] == 'eql' && cond.length == 3) { } else if (cond[0] == 'eql' && cond.length == 3) {
return '(' + cond.slice(1).map(preconditionToJS).join(' == ') + ')'; return '(' + cond.slice(1).map(preconditionToJS).join(' == ') + ')';
} else if (cond === false) { } else if (cond === false) {
return false; return 'false';
} else if (cond === true) { } else if (cond === true) {
return true; return 'true';
} else if (typeof cond === 'string') { } else if (typeof cond === 'string') {
return JSON.stringify(cond); return JSON.stringify(cond);
} else { } else {
@ -91,10 +96,6 @@ function resolveSegmentGroup(sg) {
if (v.segmentGroup) { if (v.segmentGroup) {
results.push(resolveSegmentGroup(v.segmentGroup)); results.push(resolveSegmentGroup(v.segmentGroup));
} else if (v.segment) { } else if (v.segment) {
// TODO: does the included precondition override or
// complement the segment precondition?
if (!checkPrecondition(v.segment))
continue;
results.push(v.segment); results.push(v.segment);
} else { } else {
if (!checkPrecondition(v)) if (!checkPrecondition(v))
@ -110,7 +111,7 @@ function resolveSegmentGroup(sg) {
/// There will be exactly one segment for any timestamp within the video file. /// There will be exactly one segment for any timestamp within the video file.
function getSegmentId(ms) { function getSegmentId(ms) {
for (const [k, v] of Object.entries(segmentMap.segments)) { for (const [k, v] of Object.entries(segmentMap.segments)) {
if (ms >= v.startTimeMs && ms < v.endTimeMs) { if (ms >= v.startTimeMs && (!v.endTimeMs || ms < v.endTimeMs)) {
return k; return k;
} }
} }
@ -154,25 +155,15 @@ function addItem(ul, text, url) {
var nextChoice = -1; var nextChoice = -1;
var nextSegment = null; var nextSegment = null;
function setNextSegment(segmentId, comment) {
console.log('setNextSegment', segmentId, comment);
nextSegment = segmentId;
nextChoice = -1;
var ul = newList("nextSegment");
var caption = 'nextSegment: ' + segmentId;
addItem(ul, comment ? caption + ' (' + comment + ')' : caption,
'javascript:playSegment("' + segmentId + '")');
}
function addZones(segmentId) { function addZones(segmentId) {
var ul = newList("interactionZones"); var ul = newList("interactionZones");
let caption = 'currentSegment(' + segmentId + ')'; let caption = 'currentSegment(' + segmentId + ')';
addItem(ul, caption, 'javascript:playSegment("' + segmentId + '")'); addItem(ul, caption, 'javascript:playSegment("' + segmentId + '")');
var v = segmentMap.segments[segmentId]; var segment = segmentMap.segments[segmentId];
if (v && v.ui && v.ui.interactionZones) { if (segment && segment.ui && segment.ui.interactionZones) {
var index = 0; var index = 0;
for (var z of v.ui.interactionZones) { for (var z of segment.ui.interactionZones) {
var startMs = z[0]; var startMs = z[0];
var stopMs = z[1]; var stopMs = z[1];
let caption = segmentId + ' interactionZone ' + index; let caption = segmentId + ' interactionZone ' + index;
@ -182,16 +173,14 @@ function addZones(segmentId) {
} }
ul = newList("nextSegments"); ul = newList("nextSegments");
let defaultSegmentId = null; if (segment) {
for (const [k, v] of Object.entries(segmentMap.segments[segmentId].next)) { for (const [k, v] of Object.entries(segment.next)) {
let caption = k; let caption = k;
if (segmentMap.segments[segmentId].defaultNext == k) { if (segment.defaultNext == k)
caption = '[' + caption + ']'; caption = '[' + caption + ']';
defaultSegmentId = k; addItem(ul, caption, 'javascript:playSegment("' + k + '")');
} }
addItem(ul, caption, 'javascript:playSegment("' + k + '")');
} }
setNextSegment(defaultSegmentId);
} }
var currentChoiceMoment = null; var currentChoiceMoment = null;
@ -245,12 +234,14 @@ var timerId = 0;
var lastMs = 0; var lastMs = 0;
var currentSegment; var currentSegment;
var lastSegment = null; var lastSegment = null;
var prevSegment = null; // for breadcrumbs
var segmentTransition = false; var segmentTransition = false;
var lastMoments = []; var lastMoments = [];
function ontimeupdate(evt) { function ontimeupdate(evt) {
var ms = getCurrentMs(); var ms = getCurrentMs();
currentSegment = getSegmentId(ms); currentSegment = getSegmentId(ms);
let segment = segmentMap.segments[currentSegment];
if (timerId) { if (timerId) {
clearTimeout(timerId); clearTimeout(timerId);
@ -269,9 +260,10 @@ function ontimeupdate(evt) {
// Handle segment change // Handle segment change
if (lastSegment != currentSegment) { if (lastSegment != currentSegment) {
console.log('ontimeupdate', lastSegment, '->', currentSegment, ms, msToString(ms), seeked); console.log('ontimeupdate', lastSegment, '->', currentSegment, ms, msToString(ms), seeked);
prevSegment = lastSegment;
lastSegment = currentSegment; lastSegment = currentSegment;
if (!seeked) { if (!seeked && prevSegment) {
if (playNextSegment()) { if (playNextSegment(prevSegment)) {
// playSegment decided to seek, which means that this // playSegment decided to seek, which means that this
// currentSegment is invalid, and a recursive // currentSegment is invalid, and a recursive
// ontimeupdate invocation should have taken care of // ontimeupdate invocation should have taken care of
@ -318,7 +310,7 @@ function ontimeupdate(evt) {
let hash = currentSegment; let hash = currentSegment;
// Pick the moment which starts closer to the current timestamp. // Pick the moment which starts closer to the current timestamp.
let bestMomentStart = segmentMap.segments[currentSegment].startTimeMs; let bestMomentStart = segment ? segment.startTimeMs : 0;
for (let k in currentMoments) { for (let k in currentMoments) {
let m = currentMoments[k]; let m = currentMoments[k];
if (m.startMs > bestMomentStart) { if (m.startMs > bestMomentStart) {
@ -333,7 +325,7 @@ function ontimeupdate(evt) {
} }
// ontimeupdate resolution is about a second. Augment it using timer. // ontimeupdate resolution is about a second. Augment it using timer.
let nextEvent = segmentMap.segments[currentSegment].endTimeMs; let nextEvent = segment ? segment.endTimeMs : 0;
for (let k in currentMoments) { for (let k in currentMoments) {
let m = currentMoments[k]; let m = currentMoments[k];
if (m.endMs < nextEvent) if (m.endMs < nextEvent)
@ -347,7 +339,8 @@ function ontimeupdate(evt) {
timerId = setTimeout(ontimeupdate, timeLeft); timerId = setTimeout(ontimeupdate, timeLeft);
} }
function playNextSegment() { function playNextSegment(prevSegment) {
let nextSegment = null;
if (nextChoice >= 0) { if (nextChoice >= 0) {
let x = currentChoiceMoment.choices[nextChoice]; let x = currentChoiceMoment.choices[nextChoice];
if (x.segmentId) if (x.segmentId)
@ -357,19 +350,25 @@ function playNextSegment() {
else else
nextSegment = null; nextSegment = null;
console.log('choice', nextChoice, 'nextSegment', nextSegment); console.log('choice', nextChoice, 'nextSegment', nextSegment);
nextChoice = -1;
applyImpression(x.impressionData); applyImpression(x.impressionData);
} }
if (!nextSegment && prevSegment && prevSegment in segmentGroups)
nextSegment = resolveSegmentGroup(prevSegment);
if (!nextSegment && prevSegment && segmentMap.segments[prevSegment].defaultNext)
nextSegment = segmentMap.segments[prevSegment].defaultNext;
if (!nextSegment)
return false;
let breadcrumb = 'breadcrumb_' + nextSegment; let breadcrumb = 'breadcrumb_' + nextSegment;
if (!(breadcrumb in ls)) if (!(breadcrumb in ls))
ls[breadcrumb] = lastSegment; ls[breadcrumb] = prevSegment;
segmentTransition = true; segmentTransition = true;
let segment = nextSegment; return playSegment(nextSegment, true);
nextSegment = null;
if (segment)
return playSegment(segment, true);
return false;
} }
function jumpForward() { function jumpForward() {
@ -387,7 +386,7 @@ function jumpForward() {
if (interactionMs) { if (interactionMs) {
seek(interactionMs); seek(interactionMs);
} else { } else {
playNextSegment(); playNextSegment(segmentId);
} }
} }
@ -544,14 +543,15 @@ function choice(choiceIndex) {
nextChoice = choiceIndex; nextChoice = choiceIndex;
newList("choices"); newList("choices");
if (!currentChoiceMoment.config.disableImmediateSceneTransition) if (!currentChoiceMoment.config.disableImmediateSceneTransition)
playNextSegment(); playNextSegment(prevSegment);
} }
function applyImpression(impressionData) { function applyImpression(impressionData) {
if (impressionData && impressionData.type == 'userState') { if (impressionData && impressionData.type == 'userState') {
for (const [variable, value] of Object.entries(impressionData.data.persistent)) { for (const [variable, value] of Object.entries(impressionData.data.persistent)) {
console.log('persistentState set', variable, '=', value); let key = "persistentState_" + variable;
ls["persistentState_" + variable] = JSON.stringify(value); console.log('persistentState set', variable, '=', value, '(was', key in ls ? ls[key] : 'unset', ')');
ls[key] = JSON.stringify(value);
} }
} }
} }
@ -569,6 +569,12 @@ function playSegment(segmentId, noSeek) {
return false; return false;
} }
function reset() {
ls.clear();
location.hash = '';
location.reload();
}
var lastHash = ''; var lastHash = '';
function playHash(hash) { function playHash(hash) {
// console.log('playHash', lastHash, '->', hash); // console.log('playHash', lastHash, '->', hash);

View file

@ -262,7 +262,7 @@ ul.controls-tips {
padding: 16px; padding: 16px;
width: inherit; width: inherit;
margin: 0; margin: 0;
margin: 29px auto; margin: 15px auto;
text-align: left; text-align: left;
} }
@ -271,8 +271,8 @@ h2 {
font-size: 1em; font-size: 1em;
} }
ul.file-tips li, ul.file-tips > li,
ul.controls-tips li { ul.controls-tips > li {
font-size: .45em; font-size: .45em;
} }

View file

@ -34,22 +34,19 @@
<title>Bandersnatch Interactive Player</title> <title>Bandersnatch Interactive Player</title>
<meta name="description" <meta name="description"
content="With this online(html) video player you can watch Bandersnatch episode of Black Mirror interactively." /> content="Stand-alone open-source interactive HTML player for Black Mirror - Bandersnatch" />
<meta name="keywords" content="Bandersnatch,Bandersnatch Interactive Player,Interactive Player,whatch," /> <meta name="keywords" content="Bandersnatch,Bandersnatch Interactive Player,Interactive Player,watch," />
<script src="assets/bandersnatch.js"></script> <script src="assets/bandersnatch.js"></script>
<script src="assets/SegmentMap.js"></script> <script src="assets/SegmentMap.js"></script>
<script src="assets/scripts.js"></script> <script src="assets/scripts.js"></script>
<link rel="stylesheet" type="text/css" href="assets/styles.css">
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-132739093-1"></script>
<script> <script>
window.dataLayer = window.dataLayer || []; // keep localizable strings out of scripts.js
function gtag() { dataLayer.push(arguments); } function askReset() {
gtag('js', new Date()); if (confirm('Are you sure you want to reset all choices, breadcrumbs, and watched scenes?'))
reset();
gtag('config', 'UA-132739093-1'); }
</script> </script>
<link rel="stylesheet" type="text/css" href="assets/styles.css">
</head> </head>
<body> <body>
@ -60,12 +57,12 @@
<div class="file-area"> <div class="file-area">
<div class="contact"> <div class="contact">
<p> <p>
Developed by <a href="https://github.com/mehotkhan" target="_blank">Mehotkhan</a> ,for Authors:
info <a href="https://github.com/mehotkhan/BandersnatchInteractive" <a href="https://github.com/joric/bandersnatch/">Original version</a> - <a href="https://github.com/joric/">joric</a> |
target="_blank">https://github.com/mehotkhan/BandersnatchInteractive</a> Web page, subtitles - <a href="https://github.com/mehotkhan">Mehotkhan</a> (<a href="bitcoin:1CxaCJbh4VMNicnpktsBVfnVU5xq4QYyHW">donate</a>) |
Many fixes, improvements, and everything else - <a href="https://github.com/CyberShadow">CyberShadow</a>
,<b>if you want some donation : my bitcoin wallet :</b> <br>
<pr>1CxaCJbh4VMNicnpktsBVfnVU5xq4QYyHW</pr> This player remembers your choices and watch history. <a href="javascript:askReset()">Click here to reset and start from scratch.</a>
</p> </p>
</div> </div>
<input id="fileinput" type="file"> <input id="fileinput" type="file">
@ -74,31 +71,30 @@
<span class="default">Select Bandersnatch video file ( 5:12:14 ) </span> <span class="default">Select Bandersnatch video file ( 5:12:14 ) </span>
<span class="success">Great, your file is selected</span> <span class="success">Great, your file is selected</span>
<ul class="file-tips"> <ul class="file-tips">
<li>this player only work on google chrome ( on firefox dont work , codec problem,test <li>This player is known to work only on Google Chrome or Chromium.</li>
other browser ?)</li> <li>Obtain the Bandersnatch video file (duration should be 5:12:14).<br>
<li>download Bandersnatch video file ( 5:12:14 )</li> Tested with <code>Black.Mirror.Bandersnatch.2018.720p.WEB-DL.x264.DUAL.mkv</code>.</li>
<li>drag it on white box on page :)</li> <li>Drag it on top of this box (or click here to select it).</li>
<li>Persian , English , Arabic , Spanish , Hebrew ,Portuguese ,Greek ,Turkish ,Polish ,Indonesian <li>Subtitles in many languages are available.</li>
subtitle available , if you want add another language <li>To change the subtitle:
subtitle , tell me</li> <ol>
<li>to change subtitle : right click on video , enable show controls , after that . on <li>Right click on the video</li>
bottom,right you see <li>Enable "Show controls"</li>
<span class="menu-item"></span> ,then you can subtitle section </li> <li>Click on the <span class="menu-item"></span> in the bottom-right</li>
<li>Note : after change subtitle , disable show controls ,if dont disable it on full <li>Select the desired subtitle</li>
screen video,you cant see <li>You can now hide the player controls in the same way as step 1-2.</li>
option selector</li> </ol></li>
<li>tested with Black.Mirror.Bandersnatch.2018.720p.WEB-DL.x264.DUAL.mkv file</li> <li>Note: do not use the "full screen" button in the video player if you enable "Show controls".
Choice selection interface will not be visible if you do this.</li>
</ul> </ul>
<ul class="controls-tips"> <ul class="controls-tips">
<h6>controls tips</h6> <h6>Keyboard controls</h6>
<li><kbd>F</kbd> - Toggle fullscreen</li> <li><kbd>F</kbd> - Toggle fullscreen</li>
<li><kbd>R</kbd> - Restart video</li> <li><kbd>R</kbd> - Restart video</li>
<li><kbd></kbd> - Jump to the next segment (or to the next interaction zone)</li> <li><kbd></kbd> / <kbd></kbd> - Jump to the next / previous segment (or interaction zone)</li>
<li><kbd></kbd> - Jump to the previous segment (or interaction zone)</li> <li><kbd></kbd> / <kbd></kbd> - Speed up / slow down playback</li>
<li><kbd>Space</kbd> - Toggle play and pause</li> <li><kbd>Space</kbd> - Toggle play and pause</li>
</ul> </ul>
</div> </div>
</div> </div>
@ -127,8 +123,6 @@
src="subtitle/Czarne.lustro_.Bandersnatch.WEBRip.Netflix.pl.vtt"> src="subtitle/Czarne.lustro_.Bandersnatch.WEBRip.Netflix.pl.vtt">
<track label="Indonesian" kind="subtitles" srclang="en" <track label="Indonesian" kind="subtitles" srclang="en"
src="subtitle/Black.Mirror.Bandersnatch.2018.WEBRip.x264-NoGRP-Indonesian-vtt-sharp.vtt"> src="subtitle/Black.Mirror.Bandersnatch.2018.WEBRip.x264-NoGRP-Indonesian-vtt-sharp.vtt">
</video> </video>
<div class="controls"> <div class="controls">
<div id="choiceCaption"></div> <div id="choiceCaption"></div>