mirror of
https://github.com/snobu/destreamer.git
synced 2026-01-26 18:02:19 +00:00
Title template (#194)
* added template option and validation * update comment link to element list * get author info when fetching video info * added template elements to video object * minor function naming changes * better exit message for template error * changed template elements for better substitution * implemented video title template * removed trailing decimals on duration * added template description * removed hashing from uniqueId removed debug logger.warn() * fixed typos in default template added elements to template fail message * moved ffmpeg version logging to verbose
This commit is contained in:
@@ -5,10 +5,9 @@ import { Video, Session } from './Types';
|
||||
|
||||
import { AxiosResponse } from 'axios';
|
||||
import fs from 'fs';
|
||||
import { parse } from 'iso8601-duration';
|
||||
import { parse as parseDuration, Duration } from 'iso8601-duration';
|
||||
import path from 'path';
|
||||
import sanitize from 'sanitize-filename';
|
||||
|
||||
import sanitizeWindowsName from 'sanitize-filename';
|
||||
|
||||
function publishedDateToString(date: string): string {
|
||||
const dateJs: Date = new Date(date);
|
||||
@@ -19,8 +18,25 @@ function publishedDateToString(date: string): string {
|
||||
}
|
||||
|
||||
|
||||
function publishedTimeToString(date: string): string {
|
||||
const dateJs: Date = new Date(date);
|
||||
const hours: string = dateJs.getHours().toString();
|
||||
const minutes: string = dateJs.getMinutes().toString();
|
||||
const seconds: string = dateJs.getSeconds().toString();
|
||||
|
||||
return `${hours}:${minutes}:${seconds}`;
|
||||
}
|
||||
|
||||
|
||||
function isoDurationToString(time: string): string {
|
||||
const duration: Duration = parseDuration(time);
|
||||
|
||||
return `${duration.hours ?? '00'}:${duration.minutes ?? '00'}:${duration.seconds?.toFixed(0) ?? '00'}`;
|
||||
}
|
||||
|
||||
|
||||
function durationToTotalChunks(duration: string): number {
|
||||
const durationObj: any = parse(duration);
|
||||
const durationObj: any = parseDuration(duration);
|
||||
const hrs: number = durationObj.hours ?? 0;
|
||||
const mins: number = durationObj.minutes ?? 0;
|
||||
const secs: number = Math.ceil(durationObj.seconds ?? 0);
|
||||
@@ -32,7 +48,13 @@ function durationToTotalChunks(duration: string): number {
|
||||
export async function getVideoInfo(videoGuids: Array<string>, session: Session, subtitles?: boolean): Promise<Array<Video>> {
|
||||
let metadata: Array<Video> = [];
|
||||
let title: string;
|
||||
let date: string;
|
||||
let duration: string;
|
||||
let publishDate: string;
|
||||
let publishTime: string;
|
||||
let author: string;
|
||||
let authorEmail: string;
|
||||
let uniqueId: string;
|
||||
const outPath = '';
|
||||
let totalChunks: number;
|
||||
let playbackUrl: string;
|
||||
let posterImageUrl: string;
|
||||
@@ -40,10 +62,28 @@ export async function getVideoInfo(videoGuids: Array<string>, session: Session,
|
||||
|
||||
const apiClient: ApiClient = ApiClient.getInstance(session);
|
||||
|
||||
for (const GUID of videoGuids) {
|
||||
let response: AxiosResponse<any> | undefined= await apiClient.callApi('videos/' + GUID, 'get');
|
||||
/* TODO: change this to a single guid at a time to ease our footprint on the
|
||||
MSS servers or we get throttled after 10 sequential reqs */
|
||||
for (const guid of videoGuids) {
|
||||
let response: AxiosResponse<any> | undefined =
|
||||
await apiClient.callApi('videos/' + guid + '?$expand=creator', 'get');
|
||||
|
||||
title = sanitizeWindowsName(response?.data['name']);
|
||||
|
||||
duration = isoDurationToString(response?.data.media['duration']);
|
||||
|
||||
publishDate = publishedDateToString(response?.data['publishedDate']);
|
||||
|
||||
publishTime = publishedTimeToString(response?.data['publishedDate']);
|
||||
|
||||
author = response?.data['creator'].name;
|
||||
|
||||
authorEmail = response?.data['creator'].mail;
|
||||
|
||||
uniqueId = '#' + guid.split('-')[0];
|
||||
|
||||
totalChunks = durationToTotalChunks(response?.data.media['duration']);
|
||||
|
||||
title = sanitize(response?.data['name']);
|
||||
playbackUrl = response?.data['playbackUrls']
|
||||
.filter((item: { [x: string]: string; }) =>
|
||||
item['mimeType'] == 'application/vnd.apple.mpegurl')
|
||||
@@ -52,11 +92,9 @@ export async function getVideoInfo(videoGuids: Array<string>, session: Session,
|
||||
})[0];
|
||||
|
||||
posterImageUrl = response?.data['posterImage']['medium']['url'];
|
||||
date = publishedDateToString(response?.data['publishedDate']);
|
||||
totalChunks = durationToTotalChunks(response?.data.media['duration']);
|
||||
|
||||
if (subtitles) {
|
||||
let captions: AxiosResponse<any> | undefined = await apiClient.callApi(`videos/${GUID}/texttracks`, 'get');
|
||||
let captions: AxiosResponse<any> | undefined = await apiClient.callApi(`videos/${guid}/texttracks`, 'get');
|
||||
|
||||
if (!captions?.data.value.length) {
|
||||
captionsUrl = undefined;
|
||||
@@ -74,10 +112,15 @@ export async function getVideoInfo(videoGuids: Array<string>, session: Session,
|
||||
}
|
||||
|
||||
metadata.push({
|
||||
date: date,
|
||||
totalChunks: totalChunks,
|
||||
title: title,
|
||||
outPath: '',
|
||||
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
|
||||
@@ -88,18 +131,29 @@ export async function getVideoInfo(videoGuids: Array<string>, session: Session,
|
||||
}
|
||||
|
||||
|
||||
export function createUniquePath(videos: Array<Video>, outDirs: Array<string>, format: string, skip?: boolean): Array<Video> {
|
||||
export function createUniquePath(videos: Array<Video>, outDirs: Array<string>, template: string, format: string, skip?: boolean): Array<Video> {
|
||||
|
||||
videos.forEach((video: Video, index: number) => {
|
||||
let title = `${video.title} - ${video.date}`;
|
||||
let i = 0;
|
||||
let title: string = template;
|
||||
let finalTitle: string;
|
||||
const elementRegEx = RegExp(/{(.*?)}/g);
|
||||
let match = elementRegEx.exec(template);
|
||||
|
||||
while (!skip && fs.existsSync(path.join(outDirs[index], title + '.' + format))) {
|
||||
title = `${video.title} - ${video.date}_${++i}`;
|
||||
while (match) {
|
||||
let value = video[match[1] as keyof Video] as string;
|
||||
title = title.replace(match[0], value);
|
||||
match = elementRegEx.exec(template);
|
||||
}
|
||||
|
||||
let i = 0;
|
||||
finalTitle = title;
|
||||
|
||||
while (!skip && fs.existsSync(path.join(outDirs[index], finalTitle + '.' + format))) {
|
||||
finalTitle = `${title}.${++i}`;
|
||||
}
|
||||
|
||||
|
||||
video.outPath = path.join(outDirs[index], title + '.' + format);
|
||||
video.outPath = path.join(outDirs[index], finalTitle + '.' + format);
|
||||
});
|
||||
|
||||
return videos;
|
||||
|
||||
Reference in New Issue
Block a user