如果你是和我一样热爱ACG的人,你一定曾经想过收集资源吧
但是大部分收来的
- 音乐都是无损flac的
- 图片是无损JPG的
我不是说他们不好,但是太占地了。试想,你为了人耳几乎听不出来的编码损耗多花了94%的空间
值吗?
然后,你想要转换,却对着大量文件和文件夹干发愁。一个个文件夹转换好麻烦
有没有简单的方法一键转换且简洁方便的呢?
来,我就为此写了一个脚本,不多不多,140行就完美地解决了此问题
- 自带进度条,直观!
- 批量深层扫描,藏在文件夹里再深的文件也可以挖出来
- 使用原生ffmpeg,格式随便转
然后这是我推荐的格式名单,可以去试试看,空间下降80%不是梦
- JPG --> WEBP/AVIF
注:avif兼容性不是很好,编码特别费时消耗资源。但是确实省空间。还是建议使用强兼容的webp
- FLAC --> OPUS
代码自己下载,记得 安装deno 和 下载ffmpeg,还有依赖包 呦
import { ffmpeg } from 'https://deno.land/x/deno_ffmpeg/mod.ts';
import { normalize } from 'https://deno.land/std/path/normalize.ts'
import { globToRegExp } from "https://deno.land/std/path/glob_to_regexp.ts";
import { basename } from "https://deno.land/std/path/basename.ts";
import { dirname } from "https://deno.land/std/path/dirname.ts";
import ProgressBar from "https://deno.land/x/progressbar/progressbar.ts";
import { percentageWidget } from "https://deno.land/x/progressbar/widgets.ts";
import { ensureDir } from "https://deno.land/std/fs/ensure_dir.ts";
import { delay } from "https://deno.land/std/async/delay.ts";
import { tree, ensure, replaceFmt, arg, help } from './_dep.ts';
export default async function main(){
help(`
FFTool V1
扫描全部文件(包括子目录),批量转换指定文件到指定格式
需要预先安装ffmpeg
Args available:
--from <glob>
--to <format>
--delete <size?:sizeString>
--output
--input
--ab
--ac
--vb
--vc
--fps
--thread
`);
if (typeof arg.from != 'string' || typeof arg.to != 'string')
throw new Error('--from --to 必须定义,详见帮助(--help)');
if (arg.delete)
if (!await ensure('将要删除需转换的文件,继续吗?'))
Deno.exit(1);
let size = 0;
if (typeof arg.delete == 'number') size = arg.delete;
let progress = 0;
for await (const file of tree(arg.input || './', globToRegExp(arg.from))) {
const app = ffmpeg({
input: file,
ffmpegDir: 'ffmpeg'
});
if (arg.ab && typeof arg.ab == 'number') app.audioBitrate(arg.ab);
if (arg.vb && typeof arg.vb == 'string') app.videoBitrate(arg.vb);
if (arg.vc && typeof arg.vc == 'string') app.videoCodec(arg.vc);
if (arg.ac && typeof arg.ac == 'string') app.audioCodec(arg.ac);
if (arg.thread && typeof arg.thread == 'number') app.threads(arg.thread);
if (arg.fps && typeof arg.fps == 'number') app.outputFPS(arg.fps);
await ensureDir(dirname(file));
progress++;
console.clear();
console.log(progress, ') ', '任务:', basename(file), '--> (format)', arg.to);
const prog = new ProgressBar({
total: 100,
widgets: [percentageWidget]
}), out = arg.output
? normalize(arg.output + '/' + basename(replaceFmt(file, arg.to)))
: replaceFmt(file, arg.to);
for await (const status of await app.save(out, true))
await prog.update(status.percentage);
if (arg.delete) {
let outSize
try {
outSize = await Deno.stat(out);
} catch {
console.error('<!> 转换失败,文件未输出');
await delay(3000);
continue;
}
if (size && size >= outSize.size)
console.warn('文件大小小于限制,未删除文件');
else await Deno.remove(file);
}
}
}
if(import.meta.main) await main();
本文由 zlh 创作,采用 知识共享署名4.0 国际许可协议进行许可。
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名。