1
0
mirror of https://github.com/snobu/destreamer.git synced 2026-01-17 05:22:18 +00:00

videoInfo fetching per videorather then in bulk

fixed side effects in main function of this change
This commit is contained in:
Luca Armaroli
2020-08-12 18:45:14 +01:00
parent 6d99ae7d85
commit f4a9934efd
2 changed files with 79 additions and 86 deletions

View File

@@ -45,8 +45,8 @@ function durationToTotalChunks(duration: string): number {
} }
export async function getVideoInfo(videoGuids: Array<string>, session: Session, subtitles?: boolean): Promise<Array<Video>> { export async function getVideoInfo(videoGuid: string, session: Session, subtitles?: boolean): Promise<Video> {
let metadata: Array<Video> = []; // template elements
let title: string; let title: string;
let duration: string; let duration: string;
let publishDate: string; let publishDate: string;
@@ -54,107 +54,101 @@ export async function getVideoInfo(videoGuids: Array<string>, session: Session,
let author: string; let author: string;
let authorEmail: string; let authorEmail: string;
let uniqueId: string; let uniqueId: string;
// final video path (here for consistency with typedef)
const outPath = ''; const outPath = '';
// ffmpeg magic (abstraction of FFmpeg timemark)
let totalChunks: number; let totalChunks: number;
// various sources
let playbackUrl: string; let playbackUrl: string;
let posterImageUrl: string; let posterImageUrl: string;
let captionsUrl: string | undefined; let captionsUrl: string | undefined;
const apiClient: ApiClient = ApiClient.getInstance(session); const apiClient: ApiClient = ApiClient.getInstance(session);
/* TODO: change this to a single guid at a time to ease our footprint on the let response: AxiosResponse<any> | undefined =
MSS servers or we get throttled after 10 sequential reqs */ await apiClient.callApi('videos/' + videoGuid + '?$expand=creator', 'get');
for (const guid of videoGuids) {
let response: AxiosResponse<any> | undefined =
await apiClient.callApi('videos/' + guid + '?$expand=creator', 'get');
title = sanitizeWindowsName(response?.data['name']); title = sanitizeWindowsName(response?.data['name']);
duration = isoDurationToString(response?.data.media['duration']); duration = isoDurationToString(response?.data.media['duration']);
publishDate = publishedDateToString(response?.data['publishedDate']); publishDate = publishedDateToString(response?.data['publishedDate']);
publishTime = publishedTimeToString(response?.data['publishedDate']); publishTime = publishedTimeToString(response?.data['publishedDate']);
author = response?.data['creator'].name; author = response?.data['creator'].name;
authorEmail = response?.data['creator'].mail; authorEmail = response?.data['creator'].mail;
uniqueId = '#' + guid.split('-')[0]; uniqueId = '#' + videoGuid.split('-')[0];
totalChunks = durationToTotalChunks(response?.data.media['duration']); totalChunks = durationToTotalChunks(response?.data.media['duration']);
playbackUrl = response?.data['playbackUrls'] playbackUrl = response?.data['playbackUrls']
.filter((item: { [x: string]: string; }) => .filter((item: { [x: string]: string; }) =>
item['mimeType'] == 'application/vnd.apple.mpegurl') item['mimeType'] == 'application/vnd.apple.mpegurl')
.map((item: { [x: string]: string }) => { .map((item: { [x: string]: string }) => {
return item['playbackUrl']; return item['playbackUrl'];
})[0]; })[0];
posterImageUrl = response?.data['posterImage']['medium']['url']; posterImageUrl = response?.data['posterImage']['medium']['url'];
if (subtitles) { if (subtitles) {
let captions: AxiosResponse<any> | undefined = await apiClient.callApi(`videos/${guid}/texttracks`, 'get'); let captions: AxiosResponse<any> | undefined = await apiClient.callApi(`videos/${videoGuid}/texttracks`, 'get');
if (!captions?.data.value.length) { if (!captions?.data.value.length) {
captionsUrl = undefined; captionsUrl = undefined;
} }
else if (captions?.data.value.length === 1) { else if (captions?.data.value.length === 1) {
logger.info(`Found subtitles for ${title}. \n`); logger.info(`Found subtitles for ${title}. \n`);
captionsUrl = captions?.data.value.pop().url; captionsUrl = captions?.data.value.pop().url;
} }
else { else {
const index: number = promptUser(captions.data.value.map((item: { language: string; autoGenerated: string; }) => { const index: number = promptUser(captions.data.value.map((item: { language: string; autoGenerated: string; }) => {
return `[${item.language}] autogenerated: ${item.autoGenerated}`; return `[${item.language}] autogenerated: ${item.autoGenerated}`;
})); }));
captionsUrl = captions.data.value[index].url; captionsUrl = captions.data.value[index].url;
}
} }
metadata.push({
title: title,
duration: duration,
publishDate: publishDate,
publishTime: publishTime,
author: author,
authorEmail: authorEmail,
uniqueId: uniqueId,
outPath: outPath,
totalChunks: totalChunks, // Abstraction of FFmpeg timemark
playbackUrl: playbackUrl,
posterImageUrl: posterImageUrl,
captionsUrl: captionsUrl
});
} }
return metadata; return {
title: title,
duration: duration,
publishDate: publishDate,
publishTime: publishTime,
author: author,
authorEmail: authorEmail,
uniqueId: uniqueId,
outPath: outPath,
totalChunks: totalChunks,
playbackUrl: playbackUrl,
posterImageUrl: posterImageUrl,
captionsUrl: captionsUrl
};
} }
export function createUniquePath(videos: Array<Video>, outDirs: Array<string>, template: string, format: string, skip?: boolean): Array<Video> { export function createUniquePath(video: Video, outDir: string, template: string, format: string, skip?: boolean): Video {
videos.forEach((video: Video, index: number) => { let title: string = template;
let title: string = template; let finalTitle: string;
let finalTitle: string; const elementRegEx = RegExp(/{(.*?)}/g);
const elementRegEx = RegExp(/{(.*?)}/g); let match = elementRegEx.exec(template);
let match = elementRegEx.exec(template);
while (match) { while (match) {
let value = video[match[1] as keyof Video] as string; let value = video[match[1] as keyof Video] as string;
title = title.replace(match[0], value); title = title.replace(match[0], value);
match = elementRegEx.exec(template); match = elementRegEx.exec(template);
} }
let i = 0; let i = 0;
finalTitle = title; finalTitle = title;
while (!skip && fs.existsSync(path.join(outDirs[index], finalTitle + '.' + format))) { while (!skip && fs.existsSync(path.join(outDir, finalTitle + '.' + format))) {
finalTitle = `${title}.${++i}`; finalTitle = `${title}.${++i}`;
} }
video.outPath = path.join(outDir, finalTitle + '.' + format);
video.outPath = path.join(outDirs[index], finalTitle + '.' + format); return video;
});
return videos;
} }

View File

@@ -119,16 +119,17 @@ async function DoInteractiveLogin(url: string, username?: string): Promise<Sessi
} }
async function downloadVideo(videoGUIDs: Array<string>, outputDirectories: Array<string>, session: Session): Promise<void> { async function downloadVideo(videoGuidArray: Array<string>, outputDirectoryArray: Array<string>, session: Session): Promise<void> {
logger.info('Fetching videos info... \n'); for (const [index, videoGuid] of videoGuidArray.entries()) {
const videos: Array<Video> = createUniquePath ( logger.info(`Fetching video's #${index} info... \n`);
await getVideoInfo(videoGUIDs, session, argv.closedCaptions),
outputDirectories, argv.outputTemplate, argv.format, argv.skip const video: Video = createUniquePath (
await getVideoInfo(videoGuid, session, argv.closedCaptions),
outputDirectoryArray[index], argv.outputTemplate, argv.format, argv.skip
); );
if (argv.simulate) { if (argv.simulate) {
videos.forEach((video: Video) => {
logger.info( logger.info(
'\nTitle: '.green + video.title + '\nTitle: '.green + video.title +
'\nOutPath: '.green + video.outPath + '\nOutPath: '.green + video.outPath +
@@ -136,21 +137,19 @@ async function downloadVideo(videoGUIDs: Array<string>, outputDirectories: Array
'\nPlayback URL: '.green + video.playbackUrl + '\nPlayback URL: '.green + video.playbackUrl +
((video.captionsUrl) ? ('\nCC URL: '.green + video.captionsUrl) : '') ((video.captionsUrl) ? ('\nCC URL: '.green + video.captionsUrl) : '')
); );
});
return; continue;
} }
for (const [index, video] of videos.entries()) {
if (argv.skip && fs.existsSync(video.outPath)) { if (argv.skip && fs.existsSync(video.outPath)) {
logger.info(`File already exists, skipping: ${video.outPath} \n`); logger.info(`File already exists, skipping: ${video.outPath} \n`);
continue; continue;
} }
if (argv.keepLoginCookies && index !== 0) { if (argv.keepLoginCookies && index !== 0) {
logger.info('Trying to refresh token...'); logger.info('Trying to refresh token...');
session = await refreshSession('https://web.microsoftstream.com/video/' + videoGUIDs[index]); session = await refreshSession('https://web.microsoftstream.com/video/' + videoGuidArray[index]);
} }
const pbar: cliProgress.SingleBar = new cliProgress.SingleBar({ const pbar: cliProgress.SingleBar = new cliProgress.SingleBar({