aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAstound <kirito@disroot.org>2024-01-26 01:12:54 +0800
committerAstound <kirito@disroot.org>2024-01-26 01:12:54 +0800
commit629c811e841a7647027e58103f191990732d2b02 (patch)
tree0605d891fe75ecfa8cfc90acb55a730bdb8e8cdd
parent284024433b3707677cf757aa0cf728229ee52d55 (diff)
downloadyt-local-629c811e841a7647027e58103f191990732d2b02.tar.lz
yt-local-629c811e841a7647027e58103f191990732d2b02.tar.xz
yt-local-629c811e841a7647027e58103f191990732d2b02.zip
av-merge: Retry failed requests
Should reduce playback stalling
-rw-r--r--youtube/static/js/av-merge.js48
1 files changed, 37 insertions, 11 deletions
diff --git a/youtube/static/js/av-merge.js b/youtube/static/js/av-merge.js
index 865c96b..3226244 100644
--- a/youtube/static/js/av-merge.js
+++ b/youtube/static/js/av-merge.js
@@ -204,6 +204,7 @@ Stream.prototype.setup = async function(){
this.url,
this.initRange.start,
this.indexRange.end,
+ 'Initialization+index segments',
).then(
(buffer) => {
let init_end = this.initRange.end - this.initRange.start + 1;
@@ -219,6 +220,7 @@ Stream.prototype.setup = async function(){
this.url,
this.initRange.start,
this.initRange.end,
+ 'Initialization segment',
).then(this.setupInitSegment.bind(this));
// sidx (segment index) table
@@ -226,6 +228,7 @@ Stream.prototype.setup = async function(){
this.url,
this.indexRange.start,
this.indexRange.end,
+ 'Index segment',
).then(this.setupSegmentIndex.bind(this));
}
}
@@ -485,6 +488,7 @@ Stream.prototype.fetchSegment = function(segmentIdx) {
this.url,
entry.start,
entry.end,
+ String(this.streamType) + ' segment ' + String(segmentIdx),
).then(this.appendSegment.bind(this, segmentIdx));
}
Stream.prototype.fetchSegmentIfNeeded = function(segmentIdx) {
@@ -523,27 +527,49 @@ Stream.prototype.reportError = function(...args) {
// https://gomakethings.com/promise-based-xhr/
// https://stackoverflow.com/a/30008115
-function fetchRange(url, start, end) {
+// http://lofi.limo/blog/retry-xmlhttprequest-carefully
+function fetchRange(url, start, end, debugInfo) {
return new Promise((resolve, reject) => {
+ let retryCount = 0;
let xhr = new XMLHttpRequest();
+ function onFailure(err, message, maxRetries=5){
+ message = debugInfo + ': ' + message + ' - Err: ' + String(err);
+ retryCount++;
+ if (retryCount > maxRetries || xhr.status == 403){
+ reportError('fetchRange error while fetching ' + message);
+ reject(message);
+ return;
+ } else {
+ reportWarning('Failed to fetch ' + message
+ + '. Attempting retry '
+ + String(retryCount) +'/' + String(maxRetries));
+ }
+
+ // Retry in 1 second, doubled for each next retry
+ setTimeout(function(){
+ xhr.open('get',url);
+ xhr.send();
+ }, 1000*Math.pow(2,(retryCount-1)));
+ }
xhr.open('get', url);
+ xhr.timeout = 15000;
xhr.responseType = 'arraybuffer';
xhr.setRequestHeader('Range', 'bytes=' + start + '-' + end);
- xhr.onload = function () {
+ xhr.onload = function (e) {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response);
} else {
- reject({
- status: xhr.status,
- statusText: xhr.statusText
- });
+ onFailure(e,
+ 'Status '
+ + String(xhr.status) + ' ' + String(xhr.statusText)
+ );
}
};
- xhr.onerror = function () {
- reject({
- status: xhr.status,
- statusText: xhr.statusText
- });
+ xhr.onerror = function (event) {
+ onFailure(e, 'Network error');
+ };
+ xhr.ontimeout = function (event){
+ onFailure(null, 'Timeout (15s)', maxRetries=1);
};
xhr.send();
});