mirror of
https://github.com/VueTubeApp/VueTube
synced 2024-12-22 08:20:17 +00:00
player logic reworked
This commit is contained in:
parent
a46b87436c
commit
59b65b7d9e
6 changed files with 183 additions and 182 deletions
|
@ -151,6 +151,8 @@
|
|||
v-if="$refs.player"
|
||||
:video="$refs.player"
|
||||
:fullscreen="isFullscreen"
|
||||
:watched="watched"
|
||||
:duration="duration"
|
||||
/>
|
||||
<v-btn
|
||||
v-if="isFullscreen"
|
||||
|
@ -257,6 +259,7 @@
|
|||
:controls="controls"
|
||||
:fullscreen="isFullscreen"
|
||||
:current-time="$refs.player.currentTime"
|
||||
:buffered="buffered"
|
||||
/>
|
||||
<seekbar
|
||||
v-if="$refs.player"
|
||||
|
@ -266,6 +269,8 @@
|
|||
:sources="sources"
|
||||
:controls="controls"
|
||||
:current-time="$refs.player.currentTime"
|
||||
:progress="progress"
|
||||
:duration="$refs.player.duration"
|
||||
@seeking="seeking = !seeking"
|
||||
/>
|
||||
<sponsorblock
|
||||
|
@ -275,6 +280,7 @@
|
|||
:videoid="videoid"
|
||||
:controls="controls"
|
||||
:fullscreen="isFullscreen"
|
||||
:blocks="blocks"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -327,14 +333,57 @@ export default {
|
|||
controls: false,
|
||||
seeking: false,
|
||||
contain: true,
|
||||
progress: 0,
|
||||
buffered: 0,
|
||||
duration: 0,
|
||||
watched: 0,
|
||||
blocks: [],
|
||||
vidSrc: "",
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
console.log("sources", this.sources);
|
||||
this.vidSrc = this.sources[this.sources.length - 1].url;
|
||||
let vid = this.$refs.player;
|
||||
|
||||
this.$youtube.getSponsorBlock(this.vidSrc, (data) => {
|
||||
console.log("sbreturn", data);
|
||||
if (Array.isArray(data)) {
|
||||
this.blocks = data;
|
||||
}
|
||||
});
|
||||
|
||||
vid.addEventListener("loadeddata", (e) => {
|
||||
// TODO: detect video loading state and send this.loading to play button :loading = loading
|
||||
// console.log(e);
|
||||
if (vid.readyState >= 3) {
|
||||
vid.addEventListener("timeupdate", () => {
|
||||
this.duration = this.$vuetube.humanTime(vid.duration);
|
||||
this.watched = this.$vuetube.humanTime(vid.currentTime);
|
||||
if (!this.seeking) this.progress = vid.currentTime;
|
||||
|
||||
// console.log("sb check", data);
|
||||
// iterate over data.segments array
|
||||
if (this.blocks.length > 0)
|
||||
this.blocks.forEach((sponsor) => {
|
||||
let vidTime = vid.currentTime;
|
||||
|
||||
if (
|
||||
vidTime >= sponsor.segment[0] &&
|
||||
vidTime <= sponsor.segment[1]
|
||||
) {
|
||||
console.log("Skipping the sponsor");
|
||||
this.$youtube.showToast("Skipped sponsor");
|
||||
vid.currentTime = sponsor.segment[1] + 1;
|
||||
}
|
||||
});
|
||||
});
|
||||
vid.addEventListener("progress", () => {
|
||||
this.buffered = (vid.buffered.end(0) / vid.duration) * 100;
|
||||
});
|
||||
}
|
||||
});
|
||||
// TODO: detect orientation change and enter fullscreen
|
||||
// TODO: detect video loading state and send this.loading to play button :loading = loading
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.isFullscreen) this.exitFullscreen();
|
||||
|
|
|
@ -43,19 +43,10 @@ export default {
|
|||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data: () => ({
|
||||
buffered: 0,
|
||||
}),
|
||||
mounted() {
|
||||
this.video.addEventListener("loadeddata", (e) => {
|
||||
if (this.video.readyState >= 3) {
|
||||
this.video.addEventListener("progress", () => {
|
||||
this.buffered =
|
||||
(this.video.buffered.end(0) / this.video.duration) * 100;
|
||||
});
|
||||
}
|
||||
});
|
||||
buffered: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -77,23 +77,21 @@ export default {
|
|||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
progress: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
duration: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data: () => ({
|
||||
scrubbing: false,
|
||||
progress: 0,
|
||||
duration: 0,
|
||||
vidWrs: "",
|
||||
}),
|
||||
mounted() {
|
||||
this.vidWrs = this.sources[1].url;
|
||||
this.video.addEventListener("loadeddata", (e) => {
|
||||
if (this.video.readyState >= 3) {
|
||||
this.video.addEventListener("timeupdate", () => {
|
||||
this.duration = this.video.duration;
|
||||
if (!this.scrubbing) this.progress = this.currentTime;
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
seek(e) {
|
||||
|
@ -114,126 +112,126 @@ export default {
|
|||
scrub(e) {
|
||||
this.video.currentTime = e;
|
||||
},
|
||||
// TODO: better scrubbing preview
|
||||
loadVideoFrames() {
|
||||
// Exit loop if desired number of frames have been extracted
|
||||
if (this.frames.length >= frameCount) {
|
||||
this.visibleFrame = 0;
|
||||
// TODO: better scrubbing preview (don't delet ples 🙏)
|
||||
// loadVideoFrames() {
|
||||
// // Exit loop if desired number of frames have been extracted
|
||||
// if (this.frames.length >= frameCount) {
|
||||
// this.visibleFrame = 0;
|
||||
|
||||
// Append all canvases to container div
|
||||
this.frames.forEach((frame) => {
|
||||
this.frameContainerElement.appendChild(frame);
|
||||
});
|
||||
return;
|
||||
}
|
||||
// // Append all canvases to container div
|
||||
// this.frames.forEach((frame) => {
|
||||
// this.frameContainerElement.appendChild(frame);
|
||||
// });
|
||||
// return;
|
||||
// }
|
||||
|
||||
// If extraction hasn’t started, set desired time for first frame
|
||||
if (this.frames.length === 0) {
|
||||
this.requestedTime = 0;
|
||||
} else {
|
||||
this.requestedTime = this.requestedTime + this.frameTimestep;
|
||||
}
|
||||
// // If extraction hasn’t started, set desired time for first frame
|
||||
// if (this.frames.length === 0) {
|
||||
// this.requestedTime = 0;
|
||||
// } else {
|
||||
// this.requestedTime = this.requestedTime + this.frameTimestep;
|
||||
// }
|
||||
|
||||
// Send seek request to video player for the next frame.
|
||||
this.videoElement.currentTime = this.requestedTime;
|
||||
},
|
||||
extractFrame(videoWidth, videoHeight) {
|
||||
// Create DOM canvas object
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.className = "video-scrubber-frame";
|
||||
canvas.height = videoHeight;
|
||||
canvas.width = videoWidth;
|
||||
// // Send seek request to video player for the next frame.
|
||||
// this.videoElement.currentTime = this.requestedTime;
|
||||
// },
|
||||
// extractFrame(videoWidth, videoHeight) {
|
||||
// // Create DOM canvas object
|
||||
// var canvas = document.createElement("canvas");
|
||||
// canvas.className = "video-scrubber-frame";
|
||||
// canvas.height = videoHeight;
|
||||
// canvas.width = videoWidth;
|
||||
|
||||
// Copy current frame to canvas
|
||||
var context = canvas.getContext("2d");
|
||||
context.drawImage(this.videoElement, 0, 0, videoWidth, videoHeight);
|
||||
this.frames.push(canvas);
|
||||
// // Copy current frame to canvas
|
||||
// var context = canvas.getContext("2d");
|
||||
// context.drawImage(this.videoElement, 0, 0, videoWidth, videoHeight);
|
||||
// this.frames.push(canvas);
|
||||
|
||||
// Load the next frame
|
||||
loadVideoFrames();
|
||||
},
|
||||
prefetch_file(url, fetched_callback, progress_callback, error_callback) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", url, true);
|
||||
xhr.responseType = "blob";
|
||||
// // Load the next frame
|
||||
// loadVideoFrames();
|
||||
// },
|
||||
// prefetch_file(url, fetched_callback, progress_callback, error_callback) {
|
||||
// var xhr = new XMLHttpRequest();
|
||||
// xhr.open("GET", url, true);
|
||||
// xhr.responseType = "blob";
|
||||
|
||||
xhr.addEventListener(
|
||||
"load",
|
||||
function () {
|
||||
if (xhr.status === 200) {
|
||||
var URL = window.URL || window.webkitURL;
|
||||
var blob_url = URL.createObjectURL(xhr.response);
|
||||
fetched_callback(blob_url);
|
||||
} else {
|
||||
error_callback();
|
||||
}
|
||||
},
|
||||
false
|
||||
);
|
||||
// xhr.addEventListener(
|
||||
// "load",
|
||||
// function () {
|
||||
// if (xhr.status === 200) {
|
||||
// var URL = window.URL || window.webkitURL;
|
||||
// var blob_url = URL.createObjectURL(xhr.response);
|
||||
// fetched_callback(blob_url);
|
||||
// } else {
|
||||
// error_callback();
|
||||
// }
|
||||
// },
|
||||
// false
|
||||
// );
|
||||
|
||||
var prev_pc = 0;
|
||||
xhr.addEventListener("progress", function (event) {
|
||||
if (event.lengthComputable) {
|
||||
var pc = Math.round((event.loaded / event.total) * 100);
|
||||
if (pc != prev_pc) {
|
||||
prev_pc = pc;
|
||||
progress_callback(pc);
|
||||
}
|
||||
}
|
||||
});
|
||||
xhr.send();
|
||||
},
|
||||
async extractFramesFromVideo(videoUrl, fps = 25) {
|
||||
// fully download it first (no buffering):
|
||||
console.log(videoUrl);
|
||||
console.log(fps);
|
||||
let videoBlob = await fetch(videoUrl, {
|
||||
headers: { range: "bytes=0-567139" },
|
||||
}).then((r) => r.blob());
|
||||
console.log(videoBlob);
|
||||
let videoObjectUrl = URL.createObjectURL(videoBlob);
|
||||
let video = document.createElement("video");
|
||||
// var prev_pc = 0;
|
||||
// xhr.addEventListener("progress", function (event) {
|
||||
// if (event.lengthComputable) {
|
||||
// var pc = Math.round((event.loaded / event.total) * 100);
|
||||
// if (pc != prev_pc) {
|
||||
// prev_pc = pc;
|
||||
// progress_callback(pc);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// xhr.send();
|
||||
// },
|
||||
// async extractFramesFromVideo(videoUrl, fps = 25) {
|
||||
// // fully download it first (no buffering):
|
||||
// console.log(videoUrl);
|
||||
// console.log(fps);
|
||||
// let videoBlob = await fetch(videoUrl, {
|
||||
// headers: { range: "bytes=0-567139" },
|
||||
// }).then((r) => r.blob());
|
||||
// console.log(videoBlob);
|
||||
// let videoObjectUrl = URL.createObjectURL(videoBlob);
|
||||
// let video = document.createElement("video");
|
||||
|
||||
let seekResolve;
|
||||
video.addEventListener("seeked", async function () {
|
||||
if (seekResolve) seekResolve();
|
||||
});
|
||||
// let seekResolve;
|
||||
// video.addEventListener("seeked", async function () {
|
||||
// if (seekResolve) seekResolve();
|
||||
// });
|
||||
|
||||
video.src = videoObjectUrl;
|
||||
// video.src = videoObjectUrl;
|
||||
|
||||
// workaround chromium metadata bug (https://stackoverflow.com/q/38062864/993683)
|
||||
while (
|
||||
(video.duration === Infinity || isNaN(video.duration)) &&
|
||||
video.readyState < 2
|
||||
) {
|
||||
await new Promise((r) => setTimeout(r, 1000));
|
||||
video.currentTime = 10000000 * Math.random();
|
||||
}
|
||||
let duration = video.duration;
|
||||
// // workaround chromium metadata bug (https://stackoverflow.com/q/38062864/993683)
|
||||
// while (
|
||||
// (video.duration === Infinity || isNaN(video.duration)) &&
|
||||
// video.readyState < 2
|
||||
// ) {
|
||||
// await new Promise((r) => setTimeout(r, 1000));
|
||||
// video.currentTime = 10000000 * Math.random();
|
||||
// }
|
||||
// let duration = video.duration;
|
||||
|
||||
let canvas = document.createElement("canvas");
|
||||
let context = canvas.getContext("2d");
|
||||
let [w, h] = [video.videoWidth, video.videoHeight];
|
||||
canvas.width = w;
|
||||
canvas.height = h;
|
||||
// let canvas = document.createElement("canvas");
|
||||
// let context = canvas.getContext("2d");
|
||||
// let [w, h] = [video.videoWidth, video.videoHeight];
|
||||
// canvas.width = w;
|
||||
// canvas.height = h;
|
||||
|
||||
let interval = 1;
|
||||
let currentTime = 0;
|
||||
// let interval = 1;
|
||||
// let currentTime = 0;
|
||||
|
||||
while (currentTime < duration) {
|
||||
video.currentTime = currentTime;
|
||||
await new Promise((r) => (seekResolve = r));
|
||||
// while (currentTime < duration) {
|
||||
// video.currentTime = currentTime;
|
||||
// await new Promise((r) => (seekResolve = r));
|
||||
|
||||
context.drawImage(video, 0, 0, w, h);
|
||||
let base64ImageData = canvas.toDataURL();
|
||||
console.log(base64ImageData);
|
||||
this.frames.push(base64ImageData);
|
||||
// context.drawImage(video, 0, 0, w, h);
|
||||
// let base64ImageData = canvas.toDataURL();
|
||||
// console.log(base64ImageData);
|
||||
// this.frames.push(base64ImageData);
|
||||
|
||||
currentTime += interval;
|
||||
}
|
||||
console.log("%c frames", "color: #00ff00");
|
||||
console.log(this.frames);
|
||||
},
|
||||
// currentTime += interval;
|
||||
// }
|
||||
// console.log("%c frames", "color: #00ff00");
|
||||
// console.log(this.frames);
|
||||
// },
|
||||
// TODO: scrubbing preview end
|
||||
},
|
||||
};
|
||||
|
|
|
@ -49,41 +49,10 @@ export default {
|
|||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data: () => ({
|
||||
blocks: [],
|
||||
}),
|
||||
mounted() {
|
||||
let vid = this.video;
|
||||
let id = this.videoid;
|
||||
|
||||
vid.addEventListener("loadeddata", (e) => {
|
||||
if (vid.readyState >= 3) {
|
||||
this.$youtube.getSponsorBlock(id, (data) => {
|
||||
console.log("sbreturn", data);
|
||||
if (Array.isArray(data)) {
|
||||
this.blocks = data;
|
||||
|
||||
// iterate over data.segments array
|
||||
vid.addEventListener("timeupdate", () => {
|
||||
// console.log("sb check", data);
|
||||
data.forEach((sponsor) => {
|
||||
let vidTime = vid.currentTime;
|
||||
|
||||
if (
|
||||
vidTime >= sponsor.segment[0] &&
|
||||
vidTime <= sponsor.segment[1]
|
||||
) {
|
||||
console.log("Skipping the sponsor");
|
||||
this.$youtube.showToast("Skipped sponsor");
|
||||
vid.currentTime = sponsor.segment[1] + 1;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
blocks: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -19,18 +19,14 @@ export default {
|
|||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
watched: 0,
|
||||
duration: 0,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.video.addEventListener("timeupdate", () => {
|
||||
this.duration = this.$vuetube.humanTime(this.video.duration);
|
||||
this.watched = this.$vuetube.humanTime(this.video.currentTime);
|
||||
});
|
||||
duration: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
watched: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -352,15 +352,14 @@
|
|||
DEVELOPMENT_TEAM = VRCJ7YWR89;
|
||||
INFOPLIST_FILE = App/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.2;
|
||||
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 14.2;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.Frontesque.vuetube;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2,6";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
|
@ -374,14 +373,13 @@
|
|||
DEVELOPMENT_TEAM = VRCJ7YWR89;
|
||||
INFOPLIST_FILE = App/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.2;
|
||||
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 14.2;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.Frontesque.vuetube;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2,6";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue