mirror of
https://github.com/mehotkhan/BandersnatchInteractive.git
synced 2025-07-27 17:23:22 +00:00
Merge pull request #23 from CyberShadow/pull-20190727-205645
More fixes
This commit is contained in:
commit
114d029e18
3 changed files with 84 additions and 84 deletions
|
@ -34,6 +34,11 @@ var segmentGroups = bv.segmentGroups;
|
|||
|
||||
// Persistent state
|
||||
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) {
|
||||
return new Date(ms).toUTCString().split(' ')[4];
|
||||
|
@ -55,9 +60,9 @@ function preconditionToJS(cond) {
|
|||
} else if (cond[0] == 'eql' && cond.length == 3) {
|
||||
return '(' + cond.slice(1).map(preconditionToJS).join(' == ') + ')';
|
||||
} else if (cond === false) {
|
||||
return false;
|
||||
return 'false';
|
||||
} else if (cond === true) {
|
||||
return true;
|
||||
return 'true';
|
||||
} else if (typeof cond === 'string') {
|
||||
return JSON.stringify(cond);
|
||||
} else {
|
||||
|
@ -91,10 +96,6 @@ function resolveSegmentGroup(sg) {
|
|||
if (v.segmentGroup) {
|
||||
results.push(resolveSegmentGroup(v.segmentGroup));
|
||||
} else if (v.segment) {
|
||||
// TODO: does the included precondition override or
|
||||
// complement the segment precondition?
|
||||
if (!checkPrecondition(v.segment))
|
||||
continue;
|
||||
results.push(v.segment);
|
||||
} else {
|
||||
if (!checkPrecondition(v))
|
||||
|
@ -110,7 +111,7 @@ function resolveSegmentGroup(sg) {
|
|||
/// There will be exactly one segment for any timestamp within the video file.
|
||||
function getSegmentId(ms) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -154,25 +155,15 @@ function addItem(ul, text, url) {
|
|||
var nextChoice = -1;
|
||||
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) {
|
||||
var ul = newList("interactionZones");
|
||||
let caption = 'currentSegment(' + segmentId + ')';
|
||||
addItem(ul, caption, 'javascript:playSegment("' + segmentId + '")');
|
||||
|
||||
var v = segmentMap.segments[segmentId];
|
||||
if (v && v.ui && v.ui.interactionZones) {
|
||||
var segment = segmentMap.segments[segmentId];
|
||||
if (segment && segment.ui && segment.ui.interactionZones) {
|
||||
var index = 0;
|
||||
for (var z of v.ui.interactionZones) {
|
||||
for (var z of segment.ui.interactionZones) {
|
||||
var startMs = z[0];
|
||||
var stopMs = z[1];
|
||||
let caption = segmentId + ' interactionZone ' + index;
|
||||
|
@ -182,16 +173,14 @@ function addZones(segmentId) {
|
|||
}
|
||||
|
||||
ul = newList("nextSegments");
|
||||
let defaultSegmentId = null;
|
||||
for (const [k, v] of Object.entries(segmentMap.segments[segmentId].next)) {
|
||||
let caption = k;
|
||||
if (segmentMap.segments[segmentId].defaultNext == k) {
|
||||
caption = '[' + caption + ']';
|
||||
defaultSegmentId = k;
|
||||
if (segment) {
|
||||
for (const [k, v] of Object.entries(segment.next)) {
|
||||
let caption = k;
|
||||
if (segment.defaultNext == k)
|
||||
caption = '[' + caption + ']';
|
||||
addItem(ul, caption, 'javascript:playSegment("' + k + '")');
|
||||
}
|
||||
addItem(ul, caption, 'javascript:playSegment("' + k + '")');
|
||||
}
|
||||
setNextSegment(defaultSegmentId);
|
||||
}
|
||||
|
||||
var currentChoiceMoment = null;
|
||||
|
@ -245,12 +234,14 @@ var timerId = 0;
|
|||
var lastMs = 0;
|
||||
var currentSegment;
|
||||
var lastSegment = null;
|
||||
var prevSegment = null; // for breadcrumbs
|
||||
var segmentTransition = false;
|
||||
var lastMoments = [];
|
||||
|
||||
function ontimeupdate(evt) {
|
||||
var ms = getCurrentMs();
|
||||
currentSegment = getSegmentId(ms);
|
||||
let segment = segmentMap.segments[currentSegment];
|
||||
|
||||
if (timerId) {
|
||||
clearTimeout(timerId);
|
||||
|
@ -269,9 +260,10 @@ function ontimeupdate(evt) {
|
|||
// Handle segment change
|
||||
if (lastSegment != currentSegment) {
|
||||
console.log('ontimeupdate', lastSegment, '->', currentSegment, ms, msToString(ms), seeked);
|
||||
prevSegment = lastSegment;
|
||||
lastSegment = currentSegment;
|
||||
if (!seeked) {
|
||||
if (playNextSegment()) {
|
||||
if (!seeked && prevSegment) {
|
||||
if (playNextSegment(prevSegment)) {
|
||||
// playSegment decided to seek, which means that this
|
||||
// currentSegment is invalid, and a recursive
|
||||
// ontimeupdate invocation should have taken care of
|
||||
|
@ -318,7 +310,7 @@ function ontimeupdate(evt) {
|
|||
|
||||
let hash = currentSegment;
|
||||
// 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) {
|
||||
let m = currentMoments[k];
|
||||
if (m.startMs > bestMomentStart) {
|
||||
|
@ -333,7 +325,7 @@ function ontimeupdate(evt) {
|
|||
}
|
||||
|
||||
// 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) {
|
||||
let m = currentMoments[k];
|
||||
if (m.endMs < nextEvent)
|
||||
|
@ -347,7 +339,8 @@ function ontimeupdate(evt) {
|
|||
timerId = setTimeout(ontimeupdate, timeLeft);
|
||||
}
|
||||
|
||||
function playNextSegment() {
|
||||
function playNextSegment(prevSegment) {
|
||||
let nextSegment = null;
|
||||
if (nextChoice >= 0) {
|
||||
let x = currentChoiceMoment.choices[nextChoice];
|
||||
if (x.segmentId)
|
||||
|
@ -357,19 +350,25 @@ function playNextSegment() {
|
|||
else
|
||||
nextSegment = null;
|
||||
console.log('choice', nextChoice, 'nextSegment', nextSegment);
|
||||
nextChoice = -1;
|
||||
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;
|
||||
if (!(breadcrumb in ls))
|
||||
ls[breadcrumb] = lastSegment;
|
||||
ls[breadcrumb] = prevSegment;
|
||||
|
||||
segmentTransition = true;
|
||||
let segment = nextSegment;
|
||||
nextSegment = null;
|
||||
if (segment)
|
||||
return playSegment(segment, true);
|
||||
return false;
|
||||
return playSegment(nextSegment, true);
|
||||
}
|
||||
|
||||
function jumpForward() {
|
||||
|
@ -387,7 +386,7 @@ function jumpForward() {
|
|||
if (interactionMs) {
|
||||
seek(interactionMs);
|
||||
} else {
|
||||
playNextSegment();
|
||||
playNextSegment(segmentId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -544,14 +543,15 @@ function choice(choiceIndex) {
|
|||
nextChoice = choiceIndex;
|
||||
newList("choices");
|
||||
if (!currentChoiceMoment.config.disableImmediateSceneTransition)
|
||||
playNextSegment();
|
||||
playNextSegment(prevSegment);
|
||||
}
|
||||
|
||||
function applyImpression(impressionData) {
|
||||
if (impressionData && impressionData.type == 'userState') {
|
||||
for (const [variable, value] of Object.entries(impressionData.data.persistent)) {
|
||||
console.log('persistentState set', variable, '=', value);
|
||||
ls["persistentState_" + variable] = JSON.stringify(value);
|
||||
let key = "persistentState_" + variable;
|
||||
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;
|
||||
}
|
||||
|
||||
function reset() {
|
||||
ls.clear();
|
||||
location.hash = '';
|
||||
location.reload();
|
||||
}
|
||||
|
||||
var lastHash = '';
|
||||
function playHash(hash) {
|
||||
// console.log('playHash', lastHash, '->', hash);
|
||||
|
|
|
@ -262,7 +262,7 @@ ul.controls-tips {
|
|||
padding: 16px;
|
||||
width: inherit;
|
||||
margin: 0;
|
||||
margin: 29px auto;
|
||||
margin: 15px auto;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
|
@ -271,8 +271,8 @@ h2 {
|
|||
font-size: 1em;
|
||||
}
|
||||
|
||||
ul.file-tips li,
|
||||
ul.controls-tips li {
|
||||
ul.file-tips > li,
|
||||
ul.controls-tips > li {
|
||||
font-size: .45em;
|
||||
}
|
||||
|
||||
|
|
70
index.html
70
index.html
|
@ -34,22 +34,19 @@
|
|||
|
||||
<title>Bandersnatch Interactive Player</title>
|
||||
<meta name="description"
|
||||
content="With this online(html) video player you can watch Bandersnatch episode of Black Mirror interactively." />
|
||||
<meta name="keywords" content="Bandersnatch,Bandersnatch Interactive Player,Interactive Player,whatch," />
|
||||
content="Stand-alone open-source interactive HTML player for Black Mirror - Bandersnatch" />
|
||||
<meta name="keywords" content="Bandersnatch,Bandersnatch Interactive Player,Interactive Player,watch," />
|
||||
<script src="assets/bandersnatch.js"></script>
|
||||
<script src="assets/SegmentMap.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>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag() { dataLayer.push(arguments); }
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'UA-132739093-1');
|
||||
// keep localizable strings out of scripts.js
|
||||
function askReset() {
|
||||
if (confirm('Are you sure you want to reset all choices, breadcrumbs, and watched scenes?'))
|
||||
reset();
|
||||
}
|
||||
</script>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="assets/styles.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
@ -60,12 +57,12 @@
|
|||
<div class="file-area">
|
||||
<div class="contact">
|
||||
<p>
|
||||
Developed by <a href="https://github.com/mehotkhan" target="_blank">Mehotkhan</a> ,for
|
||||
info <a href="https://github.com/mehotkhan/BandersnatchInteractive"
|
||||
target="_blank">https://github.com/mehotkhan/BandersnatchInteractive</a>
|
||||
|
||||
,<b>if you want some donation : my bitcoin wallet :</b>
|
||||
<pr>1CxaCJbh4VMNicnpktsBVfnVU5xq4QYyHW</pr>
|
||||
Authors:
|
||||
<a href="https://github.com/joric/bandersnatch/">Original version</a> - <a href="https://github.com/joric/">joric</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>
|
||||
<br>
|
||||
This player remembers your choices and watch history. <a href="javascript:askReset()">Click here to reset and start from scratch.</a>
|
||||
</p>
|
||||
</div>
|
||||
<input id="fileinput" type="file">
|
||||
|
@ -74,31 +71,30 @@
|
|||
<span class="default">Select Bandersnatch video file ( 5:12:14 ) </span>
|
||||
<span class="success">Great, your file is selected</span>
|
||||
<ul class="file-tips">
|
||||
<li>this player only work on google chrome ( on firefox dont work , codec problem,test
|
||||
other browser ?)</li>
|
||||
<li>download Bandersnatch video file ( 5:12:14 )</li>
|
||||
<li>drag it on white box on page :)</li>
|
||||
<li>Persian , English , Arabic , Spanish , Hebrew ,Portuguese ,Greek ,Turkish ,Polish ,Indonesian
|
||||
subtitle available , if you want add another language
|
||||
subtitle , tell me</li>
|
||||
<li>to change subtitle : right click on video , enable show controls , after that . on
|
||||
bottom,right you see
|
||||
<span class="menu-item"></span> ,then you can subtitle section </li>
|
||||
<li>Note : after change subtitle , disable show controls ,if dont disable it on full
|
||||
screen video,you cant see
|
||||
option selector</li>
|
||||
<li>tested with Black.Mirror.Bandersnatch.2018.720p.WEB-DL.x264.DUAL.mkv file</li>
|
||||
|
||||
<li>This player is known to work only on Google Chrome or Chromium.</li>
|
||||
<li>Obtain the Bandersnatch video file (duration should be 5:12:14).<br>
|
||||
Tested with <code>Black.Mirror.Bandersnatch.2018.720p.WEB-DL.x264.DUAL.mkv</code>.</li>
|
||||
<li>Drag it on top of this box (or click here to select it).</li>
|
||||
<li>Subtitles in many languages are available.</li>
|
||||
<li>To change the subtitle:
|
||||
<ol>
|
||||
<li>Right click on the video</li>
|
||||
<li>Enable "Show controls"</li>
|
||||
<li>Click on the <span class="menu-item"></span> in the bottom-right</li>
|
||||
<li>Select the desired subtitle</li>
|
||||
<li>You can now hide the player controls in the same way as step 1-2.</li>
|
||||
</ol></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 class="controls-tips">
|
||||
<h6>controls tips</h6>
|
||||
<h6>Keyboard controls</h6>
|
||||
<li><kbd>F</kbd> - Toggle fullscreen</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> - Jump to the previous segment (or interaction zone)</li>
|
||||
<li><kbd>→</kbd> / <kbd>←</kbd> - Jump to the next / 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>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -127,8 +123,6 @@
|
|||
src="subtitle/Czarne.lustro_.Bandersnatch.WEBRip.Netflix.pl.vtt">
|
||||
<track label="Indonesian" kind="subtitles" srclang="en"
|
||||
src="subtitle/Black.Mirror.Bandersnatch.2018.WEBRip.x264-NoGRP-Indonesian-vtt-sharp.vtt">
|
||||
|
||||
|
||||
</video>
|
||||
<div class="controls">
|
||||
<div id="choiceCaption"></div>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue