thrimbletrimmer: Add button to download current frame

It always uses source quality and downloads as a PNG.

We use the browser.downloads api to construct the URL on demand.

Note we might not always get the exact right frame in 60fps streams,
we might get one before or after (and "frame seek" in the editor skips 2 frames in this case).
mike/download-frame-2
Mike Lang 2 years ago
parent ffae321d04
commit 8a0705c927

@ -231,6 +231,7 @@
<option value="mpegts">MPEG-TS (slow, consumes server resources)</option>
</select>
<a id="download-link">Download Video</a>
<a href="#" id="download-frame">Download Current Frame as Image</a>
</div>
<div id="data-correction">

@ -125,6 +125,7 @@
</div>
</div>
<a href="#" id="download">Download Video</a>
<a href="#" id="download-frame">Download Current Frame as Image</a>
<a href="#" id="time-converter-link">Convert Times</a>
<form id="time-converter" class="hidden">
<h2>Time Converter</h2>

@ -439,3 +439,37 @@ function videoPlayerTimeFromVideoHumanTime(videoHumanTime) {
return hours * 3600 + minutes * 60 + seconds;
}
function getSegmentList() {
return globalPlayer.latencyController.levelDetails.fragments;
}
function dateTimeFromVideoPlayerTime(videoPlayerTime) {
const segmentList = getSegmentList();
let segmentStartTime;
let segmentStartISOTime;
for (const segment of segmentList) {
const segmentEndTime = segment.start + segment.duration;
if (videoPlayerTime >= segment.start && videoPlayerTime < segmentEndTime) {
segmentStartTime = segment.start;
segmentStartISOTime = segment.rawProgramDateTime;
break;
}
}
if (segmentStartISOTime === undefined) {
return null;
}
const wubloaderDateTime = DateTime.fromISO(segmentStartISOTime);
const offset = videoPlayerTime - segmentStartTime;
return wubloaderDateTime.plus({ seconds: offset });
}
function downloadFrame() {
const videoElement = document.getElementById("video");
const dateTime = dateTimeFromVideoPlayerTime(videoElement.currentTime);
const url = `/frame/${globalStreamName}/source.png?timestamp=${wubloaderTimeFromDateTime(dateTime)}`;
// Avoid : as it causes problems on Windows
const filename = `${dateTime.toFormat("yyyy-LL-dd'T'HH-mm-ss.SSS")}.png`;
// TODO REPLACE WITH CORRECT CALL
console.log(`Would download ${url} as ${filename}`);
}

@ -220,6 +220,10 @@ window.addEventListener("DOMContentLoaded", async (event) => {
updateDownloadLink();
});
document.getElementById("download-frame").addEventListener("click", (_event) => {
downloadFrame();
});
document.getElementById("manual-link-update").addEventListener("click", (_event) => {
const manualLinkDataContainer = document.getElementById("data-correction-manual-link");
manualLinkDataContainer.classList.toggle("hidden");
@ -1431,26 +1435,6 @@ function videoPlayerTimeFromWubloaderTime(wubloaderTime) {
return null;
}
function dateTimeFromVideoPlayerTime(videoPlayerTime) {
const segmentList = getSegmentList();
let segmentStartTime;
let segmentStartISOTime;
for (const segment of segmentList) {
const segmentEndTime = segment.start + segment.duration;
if (videoPlayerTime >= segment.start && videoPlayerTime < segmentEndTime) {
segmentStartTime = segment.start;
segmentStartISOTime = segment.rawProgramDateTime;
break;
}
}
if (segmentStartISOTime === undefined) {
return null;
}
const wubloaderDateTime = DateTime.fromISO(segmentStartISOTime);
const offset = videoPlayerTime - segmentStartTime;
return wubloaderDateTime.plus({ seconds: offset });
}
function videoPlayerTimeFromDateTime(dateTime) {
const segmentList = getSegmentList();
for (const segment of segmentList) {
@ -1496,7 +1480,3 @@ function wubloaderTimeFromVideoHumanTime(videoHumanTime) {
}
return wubloaderTimeFromVideoPlayerTime(videoPlayerTime);
}
function getSegmentList() {
return globalPlayer.latencyController.levelDetails.fragments;
}

@ -28,6 +28,10 @@ window.addEventListener("DOMContentLoaded", async (event) => {
updateTimeSettings();
});
document.getElementById("download-frame").addEventListener("click", (_event) => {
downloadFrame();
});
const timeConversionForm = document.getElementById("time-converter");
timeConversionForm.addEventListener("submit", (event) => {
event.preventDefault();

Loading…
Cancel
Save