Skip to content

Commit

Permalink
Added error recovery for downloads & support for stepping down qualit…
Browse files Browse the repository at this point in the history
…y automatically
  • Loading branch information
Inrixia committed Mar 14, 2021
1 parent 8ca697f commit 564f3ce
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 9 deletions.
20 changes: 17 additions & 3 deletions src/downloader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { settings } from "./lib/helpers";

import { fApi } from "./lib/FloatplaneAPI";

import { Resolution } from "./lib/types";

type promiseFunction = (f: Promise<void>) => void;
const videoQueue: {video: Video, res: promiseFunction }[] = [];
let videosProcessing = 0;
Expand All @@ -31,7 +33,7 @@ export const processVideos = (videos: Video[]): Array<Promise<void>> => {
return videos.map(video => new Promise<void>(res => videoQueue.push({video, res })));
};

const processVideo = async (video: Video) => {
const processVideo = async (video: Video, retries = 0, quality: Resolution = settings.floatplane.videoResolution) => {
const coloredTitle = `${video.channel.title} - ${video.title}`.slice(0, 32);
mpb.addTask(coloredTitle, {
type: "percentage",
Expand All @@ -41,7 +43,7 @@ const processVideo = async (video: Video) => {
// If the video is already downloaded then just mux its metadata
if (!await video.isDownloaded()) {
const startTime = Date.now();
const downloadRequest = await video.download(fApi);
const downloadRequest = await video.download(fApi, quality);
downloadRequest.on("downloadProgress", downloadProgress => {
const totalMB = downloadProgress.total/1024000;
const downloadedMB = (downloadProgress.transferred/1024000);
Expand All @@ -51,7 +53,7 @@ const processVideo = async (video: Video) => {
mpb.updateTask(coloredTitle, {
percentage: downloadProgress.percent,
message: `${downloadedMB.toFixed(2)}/${totalMB.toFixed(2)}MB, ${(downloadSpeed/1024000).toFixed(2)}Mb/s ETA: ${Math.floor(downloadETA / 60)}m ${Math.floor(downloadETA) % 60}s`
});
});
});
await new Promise((res, rej) => {
downloadRequest.on("end", res);
Expand All @@ -67,5 +69,17 @@ const processVideo = async (video: Video) => {
} catch (error) {
// Handle errors when downloading nicely
mpb.updateTask(coloredTitle, { message: `\u001b[31m\u001b[1mERR\u001b[0m: ${error.message}` });

// Retry downloading the video if this is the first failure.
if (retries === 0) await processVideo(video, retries++);

// If the server aborted the request retry up to 3 times.
if (error.message.includes("The server aborted pending request") && retries < 3) await processVideo(video, retries++);

if (error.message.includes("Response code 400") || error.message.includes("Response code 404")) {
// Drop down the qualities until one works or give up
const currentResIndex = settings.floatplane._avalibleResolutions.indexOf(quality);
if (currentResIndex !== 0) await processVideo(video, retries, settings.floatplane._avalibleResolutions[currentResIndex-1]);
}
}
};
4 changes: 2 additions & 2 deletions src/lib/Video.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export default class Video {
public muxedBytes = async (): Promise<number> => Video.getFileBytes(`${this.filePath}.mp4`);
public isMuxed = async (): Promise<boolean> => await this.muxedBytes() === this.expectedSize;

public download = async (fApi: FloatplaneAPI,): Promise<Request> => {
public download = async (fApi: FloatplaneAPI, quality: string): Promise<Request> => {
if (await this.isDownloaded()) throw new Error(`Attempting to download "${this.title}" video already downloaded!`);

// Make sure the folder for the video exists
Expand Down Expand Up @@ -100,7 +100,7 @@ export default class Video {
const [writeStreamOptions, requestOptions] = [undefined, undefined];

// Send download request video
const downloadRequest = await fApi.video.download(this.guid, settings.floatplane.videoResolution.toString(), requestOptions);
const downloadRequest = await fApi.video.download(this.guid, quality, requestOptions);
// Pipe the download to the file once response starts
downloadRequest.pipe(createWriteStream(`${this.filePath}`, writeStreamOptions));
// Set the videos expectedSize once we know how big it should be for download validation.
Expand Down
5 changes: 3 additions & 2 deletions src/lib/defaults.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Resolutions, SubChannels, Settings } from "./types";

export const defaultResoulutions: Resolutions = [360, 720, 1080, 2160];
export const defaultResoulutions: Resolutions = ["360", "720", "1080", "2160"];
export const defaultSubChannels: { [key: string]: SubChannels } = {
"Linus Tech Tips": {
"_default": {
Expand Down Expand Up @@ -71,7 +71,8 @@ export const defaultSettings: Settings = {
downloadThreads: -1,
floatplane: {
findClosestEdge: true,
videoResolution: 1080,
videoResolution: "1080",
_avalibleResolutions: defaultResoulutions,
edge: "edge02-na.floatplane.com",
videosToSearch: 5,
},
Expand Down
6 changes: 4 additions & 2 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export type Resolutions = [360, 720, 1080, 2160];
export type Resolution = Resolutions[keyof Resolutions];

export type Resolution = "360" | "720" | "1080" | "2160";
export type Resolutions = ["360", "720", "1080", "2160"];

import type { Video as fApiVideo } from "floatplane/creator";

Expand Down Expand Up @@ -39,6 +40,7 @@ export type Settings = {
floatplane: {
findClosestEdge: boolean;
videoResolution: Resolution;
_avalibleResolutions: Resolutions;
edge: string;
videosToSearch: number;
};
Expand Down

0 comments on commit 564f3ce

Please sign in to comment.