UNPKG

youtube-likes-downloader

Version:
112 lines (88 loc) 3.63 kB
import { randomUUID } from 'crypto'; import fs from 'fs'; import os from 'os'; import path from 'path'; import { open } from 'out-url'; import { z } from 'zod'; import type { dataSchema } from './types/schema'; import { durationSchema, epochSchema, fileSchema, inputDataSchema, resolutionSchema, stringSchema, youtubeIdSchema } from './types/schema'; import '@anmiles/prototypes'; import { Cli } from './utils/cli'; import { formatJSON } from './utils/formatJSON'; import { formatTitle } from './utils/formatTitle'; import { getDownloadArchive, getOutputDir } from './utils/paths'; type InputData = z.infer<typeof inputDataSchema>; type Data = z.infer<typeof dataSchema>; export async function addVideo(profile: string): Promise<void> { const cli = new Cli(); const { id, title, channel, duration, resolution, epoch, videoFile, imageFile, descriptionFile, } = await getData(cli); cli.close(); const ext = path.extname(videoFile).slice(1); const outputDir = getOutputDir(profile); fs.ensureDir(outputDir, { create: true }); const filename = path.join(outputDir, `${formatTitle({ id, title, channel }).toFilename()}`); const json = formatJSON({ id, title, channel, duration, resolution, epoch, ext }); await fs.promises.writeFile(`${filename}.info.json`, JSON.stringify(json)); await fs.promises.copyFile(path.resolve(videoFile), filename + path.extname(videoFile)); await fs.promises.copyFile(path.resolve(imageFile), filename + path.extname(imageFile)); await fs.promises.copyFile(path.resolve(descriptionFile), `${filename}.description`); await fs.promises.appendFile(getDownloadArchive(profile), `youtube ${id}\n`); } async function getData(cli: Cli): Promise<Data> { const data = await getJSONData(cli); if (data) { return data; } return { id : await cli.getAnswer('Youtube link', youtubeIdSchema), title : await cli.getAnswer('Title', stringSchema), channel : await cli.getAnswer('Channel', stringSchema), duration : await cli.getAnswer('Duration', durationSchema), resolution : await cli.getAnswer('Resolution', resolutionSchema), epoch : await cli.getAnswer('Date', epochSchema), videoFile : await cli.getAnswer('Video file', fileSchema), imageFile : await cli.getAnswer('Image file', fileSchema), descriptionFile: await cli.getAnswer('Description file', fileSchema), }; } async function getJSONData(cli: Cli): Promise<Data | undefined> { const inputData = await cli.getAnswer('Input JSON (optional)', inputDataSchema.or(z.undefined()), JSON.parse); if (!inputData) { return undefined; } const videoFile = await cli.getAnswer('Video file', fileSchema); cli.say('Opening thumbnail; please download it as an image file'); await open(inputData.thumbnail.split('?')[0]!); const imageFile = await cli.getAnswer('Image file', fileSchema); const descriptionFile = createTempFilePath('txt'); await fs.promises.writeFile(descriptionFile, inputData.description); return transformInputData(inputData, videoFile, imageFile, descriptionFile); } function createTempFilePath(ext: string): string { const tmp = os.tmpdir(); const filename = randomUUID(); return path.join(tmp, `${filename}.${ext}`); } function transformInputData(inputData: InputData, videoFile: string, imageFile: string, descriptionFile: string): Data { return { id : inputData.id, title : inputData.title, channel : inputData.channel, duration : inputData.duration, resolution: inputData.resolution, epoch : inputData.epoch, videoFile, imageFile, descriptionFile, }; }