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:
@@ -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;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
Reference in New Issue
Block a user