Shaders: Anime4K presets in-session and in Settings
Vendored Anime4K v4.0.1 GLSL (MIT), extracted to app support once per version. Presets A/B/C/A+A/B+B/C+A in HQ and Fast per Anime4K's mpv templates, plus custom files. Shader button in the video controls (works in fullscreen), Ctrl+1..6 / Ctrl+0, live apply with read-back, failures fall back to Off with a toast. Render mode detected from mpv's GL log; warns when on the software path. Docs include the Jellyfin client section. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4814bfb561
commit
fb2927c094
28 files changed
+6516
-53
No files matched your search
@@ -0,0 +1,74 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
import 'shader_presets.dart';
|
||||
|
||||
const anime4kAssetDir = 'assets/shaders/anime4k';
|
||||
|
||||
/// mpv needs real files: copies the shipped Anime4K shaders out of the
|
||||
/// asset bundle into `<supportDir>/shaders/anime4k-<version>`, once per
|
||||
/// version (a `.complete` marker is written last, so a cut-short copy is
|
||||
/// redone). Returns that directory.
|
||||
Future<Directory> extractAnime4k(
|
||||
Directory supportDir, {
|
||||
AssetBundle? bundle,
|
||||
}) async {
|
||||
final dir = Directory(
|
||||
'${supportDir.path}${Platform.pathSeparator}shaders'
|
||||
'${Platform.pathSeparator}anime4k-$anime4kVersion');
|
||||
final marker = File('${dir.path}${Platform.pathSeparator}.complete');
|
||||
final files = anime4kAllFiles;
|
||||
if (await marker.exists() &&
|
||||
files.every((f) => File(_join(dir, f)).existsSync())) {
|
||||
return dir;
|
||||
}
|
||||
await dir.create(recursive: true);
|
||||
final b = bundle ?? rootBundle;
|
||||
for (final name in [...files, 'LICENSE']) {
|
||||
final data = await b.load('$anime4kAssetDir/$name');
|
||||
await File(_join(dir, name)).writeAsBytes(
|
||||
data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes),
|
||||
flush: true);
|
||||
}
|
||||
await marker.writeAsString(anime4kVersion, flush: true);
|
||||
return dir;
|
||||
}
|
||||
|
||||
/// Absolute paths of [preset]'s Anime4K files inside [dir].
|
||||
List<String> anime4kPaths(
|
||||
Directory dir, ShaderPreset preset, ShaderQuality quality) =>
|
||||
[for (final f in anime4kFiles(preset, quality)) _join(dir, f)];
|
||||
|
||||
String _join(Directory dir, String name) =>
|
||||
'${dir.path}${Platform.pathSeparator}$name';
|
||||
|
||||
/// Where the shipped shaders get extracted; swapped in tests.
|
||||
Future<Directory> Function() shaderSupportDir = getApplicationSupportDirectory;
|
||||
|
||||
/// Absolute `glsl-shaders` entries for a choice, extracting the shipped
|
||||
/// files first when needed. Empty for [ShaderPreset.off].
|
||||
Future<List<String>> shaderPathsFor(
|
||||
ShaderPreset preset,
|
||||
ShaderQuality quality,
|
||||
List<String> custom,
|
||||
) async {
|
||||
if (preset == ShaderPreset.off) return const [];
|
||||
if (preset == ShaderPreset.custom) return [...custom];
|
||||
final dir = await extractAnime4k(await shaderSupportDir());
|
||||
return anime4kPaths(dir, preset, quality);
|
||||
}
|
||||
|
||||
/// Why [paths] can't go to mpv (a missing file, or a path holding the
|
||||
/// list separator), or null when they can.
|
||||
String? shaderPathsProblem(List<String> paths, {bool? windows}) {
|
||||
final sep = shaderListSeparator(windows: windows);
|
||||
for (final p in paths) {
|
||||
final name = p.split(RegExp(r'[/\\]')).last;
|
||||
// Windows drive letters ("C:\") are fine: there the separator is ';'.
|
||||
if (p.contains(sep)) return '"$name" has "$sep" in its path';
|
||||
if (!File(p).existsSync()) return '"$name" not found';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
Reference in new issue
Block a user