mirror of
https://github.com/lifegpc/eh-downloader.git
synced 2026-07-03 03:41:42 +08:00
add webp thumbnail support
This commit is contained in:
20
Dockerfile
20
Dockerfile
@@ -25,22 +25,32 @@ RUN apt-get update && apt-get install -y \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN cd ~ && \
|
||||
curl -L "https://github.com/FFmpeg/FFmpeg/archive/refs/tags/n7.0.1.tar.gz" -o ffmpeg.tar.gz && \
|
||||
curl -L "https://github.com/webmproject/libwebp/archive/refs/tags/v1.4.0.tar.gz" -o libwebp.tar.gz && \
|
||||
tar -xzvf libwebp.tar.gz && \
|
||||
cd libwebp-1.4.0 && \
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON \
|
||||
-DWEBP_LINK_STATIC=OFF -DCMAKE_INSTALL_PREFIX=/clib ../ && \
|
||||
make -j$(grep -c ^processor /proc/cpuinfo) && make install && \
|
||||
cd ~ && rm -rf libwebp-1.4.0 libwebp.tar.gz
|
||||
|
||||
RUN cd ~ && \
|
||||
curl -L "https://github.com/FFmpeg/FFmpeg/archive/refs/tags/n7.1.tar.gz" -o ffmpeg.tar.gz && \
|
||||
tar -xzvf ffmpeg.tar.gz && \
|
||||
cd FFmpeg-n7.0.1 && \
|
||||
cd FFmpeg-n7.1 && \
|
||||
./configure --enable-pic --prefix=/clib --enable-shared --disable-static \
|
||||
--enable-gpl --enable-version3 --disable-doc --disable-ffplay \
|
||||
--disable-network --disable-autodetect --enable-zlib \
|
||||
--disable-encoders --enable-encoder=mjpeg \
|
||||
--disable-encoders --enable-encoder=mjpeg,libwebp \
|
||||
--disable-muxers --enable-muxer=image2,image2pipe \
|
||||
--disable-decoders --enable-decoder=mjpeg,png,gif \
|
||||
--disable-demuxers --enable-demuxer=image_jpeg_pipe,image_png_pipe,image_gif_pipe \
|
||||
--disable-parsers --enable-parser=h264,png,gif \
|
||||
--disable-bsfs --enable-bsf=dts2pts,null \
|
||||
--disable-protocols --enable-protocol=async,concat,concatf,data,fd,file,md5,pipe,subfile \
|
||||
--disable-devices --disable-filters --enable-filter=crop,pad,scale && \
|
||||
--disable-devices --disable-filters --enable-filter=crop,pad,scale \
|
||||
--enable-libwebp && \
|
||||
make -j$(grep -c ^processor /proc/cpuinfo) && make install && \
|
||||
cd ~ && rm -rf FFmpeg-n7.0.1 ffmpeg.tar.gz
|
||||
cd ~ && rm -rf FFmpeg-n7.1 ffmpeg.tar.gz
|
||||
|
||||
RUN cd ~ && \
|
||||
curl -L "https://github.com/curl/curl/releases/download/curl-8_8_0/curl-8.8.0.tar.gz" -o curl-8.8.0.tar.gz && \
|
||||
|
||||
13
api.yml
13
api.yml
@@ -188,6 +188,8 @@ components:
|
||||
enable_server_timing:
|
||||
type: boolean
|
||||
description: Whether to enable server time tracking
|
||||
thumbnail_format:
|
||||
$ref: "#/components/schemas/ThumbnailFormat"
|
||||
Config:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/ConfigOptional"
|
||||
@@ -223,6 +225,7 @@ components:
|
||||
- import_method
|
||||
- max_import_img_count
|
||||
- enable_server_timing
|
||||
- thumbnail_format
|
||||
ConfigUpdated:
|
||||
description: result of updateConfig
|
||||
type: object
|
||||
@@ -1004,6 +1007,16 @@ components:
|
||||
const: 4
|
||||
- title: UpdateTagTranslation
|
||||
const: 5
|
||||
ThumbnailFormat:
|
||||
description: Thumbnail format
|
||||
type: integer
|
||||
oneOf:
|
||||
- title: JPEG
|
||||
const: 0
|
||||
description: MJPEG
|
||||
- title: WEBP
|
||||
const: 1
|
||||
description: WEBP
|
||||
ThumbnailMethod:
|
||||
description: Thumbnail method
|
||||
type: integer
|
||||
|
||||
12
config.ts
12
config.ts
@@ -40,6 +40,7 @@ export type ConfigType = {
|
||||
import_method: ImportMethod;
|
||||
max_import_img_count: number;
|
||||
enable_server_timing: boolean;
|
||||
thumbnail_format: ThumbnailFormat;
|
||||
};
|
||||
|
||||
export enum ThumbnailMethod {
|
||||
@@ -47,6 +48,11 @@ export enum ThumbnailMethod {
|
||||
FFMPEG_API,
|
||||
}
|
||||
|
||||
export enum ThumbnailFormat {
|
||||
JPEG,
|
||||
WEBP,
|
||||
}
|
||||
|
||||
export enum ImportMethod {
|
||||
Copy,
|
||||
CopyThenDelete,
|
||||
@@ -173,6 +179,11 @@ export class Config {
|
||||
get thumbnail_dir() {
|
||||
return this._return_string("thumbnail_dir") || "./thumbnails";
|
||||
}
|
||||
get thumbnail_format() {
|
||||
const n = this._return_number("thumbnail_format") || 0;
|
||||
if (n < 0 || n > 1) return ThumbnailFormat.JPEG;
|
||||
return n as ThumbnailFormat;
|
||||
}
|
||||
get remove_previous_gallery() {
|
||||
return this._return_bool("remove_previous_gallery") || false;
|
||||
}
|
||||
@@ -282,6 +293,7 @@ export class Config {
|
||||
import_method: this.import_method,
|
||||
max_import_img_count: this.max_import_img_count,
|
||||
enable_server_timing: this.enable_server_timing,
|
||||
thumbnail_format: this.thumbnail_format,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
ThumbnailGenMethod,
|
||||
} from "../../../thumbnail/base.ts";
|
||||
import { compareNum, isNumNaN, parseBigInt, sure_dir } from "../../../utils.ts";
|
||||
import { ThumbnailMethod } from "../../../config.ts";
|
||||
import { ThumbnailFormat, ThumbnailMethod } from "../../../config.ts";
|
||||
import { fb_generate_thumbnail } from "../../../thumbnail/ffmpeg_binary.ts";
|
||||
import {
|
||||
get_file_response,
|
||||
@@ -130,7 +130,11 @@ export const handler: Handlers = {
|
||||
);
|
||||
}
|
||||
}
|
||||
const output = generate_filename(b, f, cfg);
|
||||
let fmt = m.cfg.thumbnail_format;
|
||||
if (method == ThumbnailMethod.FFMPEG_API) {
|
||||
fmt = ThumbnailFormat.JPEG;
|
||||
}
|
||||
const output = generate_filename(b, f, cfg, fmt);
|
||||
if (!(await exists(output))) {
|
||||
if (method === ThumbnailMethod.FFMPEG_BINARY) {
|
||||
cfg.input = {
|
||||
@@ -142,6 +146,7 @@ export const handler: Handlers = {
|
||||
f.path,
|
||||
output,
|
||||
cfg,
|
||||
fmt,
|
||||
);
|
||||
if (!re) {
|
||||
return new Response("Failed to generate thumbnail.", {
|
||||
@@ -171,7 +176,7 @@ export const handler: Handlers = {
|
||||
const verify = u.searchParams.get("verify");
|
||||
if (verify === null) {
|
||||
const bs = new SortableURLSearchParams(
|
||||
gen_thumbnail_config_params(cfg),
|
||||
gen_thumbnail_config_params(cfg, fmt),
|
||||
["verify"],
|
||||
);
|
||||
const tverify = encode(
|
||||
@@ -188,8 +193,9 @@ export const handler: Handlers = {
|
||||
const b = new URLSearchParams(bs.toString());
|
||||
b.append("verify", tverify);
|
||||
if (m.cfg.use_path_based_img_url) {
|
||||
const ext = fmt == ThumbnailFormat.WEBP ? "webp" : "jpg";
|
||||
return Response.redirect(
|
||||
`${get_host(req)}/thumbnail/${b}/${f.id}.jpg`,
|
||||
`${get_host(req)}/thumbnail/${b}/${f.id}.${ext}`,
|
||||
);
|
||||
}
|
||||
return Response.redirect(
|
||||
|
||||
@@ -47,6 +47,7 @@ export const handler: Handlers = {
|
||||
const quality = await parse_int(u.searchParams.get("quality"), null);
|
||||
const method = await parse_int(u.searchParams.get("method"), null);
|
||||
const align = await parse_int(u.searchParams.get("align"), null);
|
||||
const fmt = await parse_int(u.searchParams.get("fmt"), 0);
|
||||
if (
|
||||
width === null || height === null || quality === null ||
|
||||
method === null || align === null
|
||||
@@ -64,7 +65,7 @@ export const handler: Handlers = {
|
||||
method,
|
||||
align,
|
||||
};
|
||||
const output = generate_filename(b, f, cfg);
|
||||
const output = generate_filename(b, f, cfg, fmt);
|
||||
if (!(await exists(output))) {
|
||||
return new Response("file not exists.", { status: 500 });
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ export const handler: Handlers = {
|
||||
const quality = await parse_int(search.get("quality"), null);
|
||||
const method = await parse_int(search.get("method"), null);
|
||||
const align = await parse_int(search.get("align"), null);
|
||||
const fmt = await parse_int(search.get("fmt"), 0);
|
||||
if (
|
||||
width === null || height === null || quality === null ||
|
||||
method === null || align === null
|
||||
@@ -66,7 +67,7 @@ export const handler: Handlers = {
|
||||
method,
|
||||
align,
|
||||
};
|
||||
const output = generate_filename(b, f, cfg);
|
||||
const output = generate_filename(b, f, cfg, fmt);
|
||||
if (!(await exists(output))) {
|
||||
return new Response("file not exists.", { status: 500 });
|
||||
}
|
||||
|
||||
@@ -37,7 +37,10 @@ export async function update_tag_translation(
|
||||
}
|
||||
sendEvent();
|
||||
const file = isDocker() ? "/tmp/utt.lock" : "./utt.lock";
|
||||
await Deno.writeTextFile(file, "", { create: true, signal: manager.aborts });
|
||||
await Deno.writeTextFile(file, "", {
|
||||
create: true,
|
||||
signal: manager.aborts,
|
||||
});
|
||||
for (const d of f.data) {
|
||||
await asyncForEach(Object.getOwnPropertyNames(d.data), async (name) => {
|
||||
const tag = `${d.namespace}:${name}`;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { join } from "@std/path";
|
||||
import { filterFilename } from "../utils.ts";
|
||||
import type { EhFile } from "../db.ts";
|
||||
import { ThumbnailFormat } from "../config.ts";
|
||||
|
||||
export enum ThumbnailGenMethod {
|
||||
Unknown,
|
||||
@@ -26,13 +27,17 @@ export type ThumbnailConfig = {
|
||||
input?: { width: number; height: number };
|
||||
};
|
||||
|
||||
export function gen_thumbnail_config_params(cfg: ThumbnailConfig) {
|
||||
export function gen_thumbnail_config_params(
|
||||
cfg: ThumbnailConfig,
|
||||
fmt: ThumbnailFormat,
|
||||
) {
|
||||
return {
|
||||
width: cfg.width.toString(),
|
||||
height: cfg.height.toString(),
|
||||
quality: cfg.quality.toString(),
|
||||
method: cfg.method.toString(),
|
||||
align: cfg.align.toString(),
|
||||
fmt: fmt.toString(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -69,10 +74,12 @@ export function generate_filename(
|
||||
base: string,
|
||||
f: EhFile,
|
||||
cfg: ThumbnailConfig,
|
||||
fmt: ThumbnailFormat,
|
||||
) {
|
||||
let method = "";
|
||||
let balign = "";
|
||||
let align = "";
|
||||
const ext = fmt == ThumbnailFormat.JPEG ? "jpg" : "webp";
|
||||
switch (cfg.align) {
|
||||
case ThumbnailAlign.Left:
|
||||
balign = "-left";
|
||||
@@ -100,7 +107,7 @@ export function generate_filename(
|
||||
return join(
|
||||
base,
|
||||
filterFilename(
|
||||
`${f.id}-${f.token}-${cfg.width}x${cfg.height}-q${cfg.quality}${method}${align}.jpg`,
|
||||
`${f.id}-${f.token}-${cfg.width}x${cfg.height}-q${cfg.quality}${method}${align}.${ext}`,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { ThumbnailFormat } from "../config.ts";
|
||||
import { ThumbnailAlign } from "./base.ts";
|
||||
import { type ThumbnailConfig, ThumbnailGenMethod } from "./base.ts";
|
||||
|
||||
@@ -45,8 +46,10 @@ export async function fb_generate_thumbnail(
|
||||
i: string,
|
||||
o: string,
|
||||
cfg: ThumbnailConfig,
|
||||
fmt: ThumbnailFormat,
|
||||
) {
|
||||
let add = "";
|
||||
const codec = fmt == ThumbnailFormat.WEBP ? "libwebp" : "mjpeg";
|
||||
if (cfg.method == ThumbnailGenMethod.Cover) {
|
||||
const size = cfg.input ?? await fb_get_size(i);
|
||||
if (!size) return false;
|
||||
@@ -90,6 +93,8 @@ export async function fb_generate_thumbnail(
|
||||
"-n",
|
||||
"-i",
|
||||
i,
|
||||
"-c",
|
||||
codec,
|
||||
"-vf",
|
||||
add,
|
||||
"-qmin",
|
||||
|
||||
Reference in New Issue
Block a user