animejanai support

- Adjusted mpv config path to protable_config to support animejanai
- Adjusted readme to the new path
- Fixed installer not removing webengine cached data
- Added build scripts for animejanai and anime4k
- Now Anime4k is included by default in stremio
- For Animejanai it must be provided as release after making the custom build using the build script
This commit is contained in:
Zarg 2025-01-07 05:04:50 +01:00
parent 63fc8f21cb
commit 8296fe342d
9 changed files with 584 additions and 466 deletions

View file

@ -61,10 +61,10 @@ Enhance your Stremio experience by customizing the MPV player settings. Below ar
- 📁 **`mpv.conf` Location**
- The ``mpv.conf`` file can be found in the following location:
- **Installation Path:** ``%localAppData%\Programs\LNV\Stremio-5\mpv.conf``
- **Shaders Folder:** Located within the installation directory ``..\Stremio-5\shaders``.
- **Installation Path:** ``%localAppData%\Programs\LNV\Stremio-5\portable_config\mpv.conf``
- **Shaders Folder:** Located within the installation directory ``..\Stremio-5\portable_config\shaders``.
> **⏳ Note:** Any other configuration files can be just dropped into ``%localAppData%\Programs\LNV\Stremio-5\`` as this is the mpv ``config-dir`` like ``input.conf``
> **⏳ Note:** Any other configuration files can be just dropped into ``%localAppData%\Programs\LNV\Stremio-5\portable_config`` as this is the mpv ``config-dir`` like ``input.conf``
- **🎹 Usage example in `input.conf` using Anime4k:**
```shell
@ -80,6 +80,26 @@ Enhance your Stremio experience by customizing the MPV player settings. Below ar
```
> **⏳ Note:** Some keys might not work as key presses are converted from js event.codes to literal values for mpv
## 🔍 **Mpv Upscalers**
- 🎥 **Anime4k**
- ✅ Included by default.
- 🔢 Use `CTRL+1` - `CTRL+6` to enable shaders.
- ❌ Use `CTRL+0` to disable.
- 🎨 **AnimeJaNai**
- ❌ Not included by default.
- 📥 Download from the **Stremio-Desktop-v5** [release tab](https://github.com/Zaarrg/stremio-desktop-v5) the adjusted version for Stremio.
- 🛠️ **Changes made:**
- Removed `mpvnet.exe` as Stremio is used as the player.
- Adjusted `mpv.conf` to work with Stremio.
- Adjusted `input.conf` to work with Stremio.
- 🚀 **Nvidia RTX and Intel VSR Scaling**
- 🔜 Coming soon!
## 📚 **Guide / Docs**
If you want to build this app yourself, check the “docs” folder in this repository for setup instructions and additional information.

197
build/build_anime4k.js Normal file
View file

@ -0,0 +1,197 @@
#!/usr/bin/env node
/**
* build_anime4k.js
*
* This script performs the following: (Needed for deploy_windows to include Anime4k in installer)
* 1. Determines the latest Anime4K version from bloc97/Anime4K releases.
* 2. Downloads the corresponding GLSL_Windows_High-end.zip from Tama47/Anime4K.
* 3. Auto-detects 7z.exe on the system.
* 4. Saves the downloaded zip as anime4k-High-end.zip in utils/mpv.
* 5. Extracts the zip into the anime4k folder.
* 6. Cleans up temporary files.
*
* Usage:
* node build_anime4k.js
*/
const fs = require('fs');
const path = require('path');
const https = require('https');
const { execSync } = require('child_process');
const os = require('os');
// Configuration
const BLOC97_API_URL = 'https://api.github.com/repos/bloc97/Anime4K/releases/latest';
const TEMP_DIR = path.join(os.tmpdir(), 'anime4k_build_temp');
const OUTPUT_DIR = path.resolve(__dirname, '..', 'utils', 'mpv');
const OUTPUT_ZIP_NAME = 'anime4k-High-end.zip';
const EXTRACTION_DIR = path.join(OUTPUT_DIR, 'anime4k');
// Common 7z.exe installation paths on Windows
const COMMON_7Z_PATHS = [
path.join(process.env.PROGRAMFILES || 'C:\\Program Files', '7-Zip', '7z.exe'),
path.join(process.env['PROGRAMFILES(X86)'] || 'C:\\Program Files (x86)', '7-Zip', '7z.exe'),
path.join(process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local'), '7-Zip', '7z.exe')
];
// Maximum number of redirects to follow
const MAX_REDIRECTS = 5;
// Helper Functions
function httpsGet(url, headers = {}, redirectCount = 0) {
return new Promise((resolve, reject) => {
if (redirectCount > MAX_REDIRECTS) return reject(new Error('Too many redirects'));
const options = {
headers: {
'User-Agent': 'Node.js Script',
...headers
}
};
https.get(url, options, (res) => {
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
return resolve(httpsGet(res.headers.location, headers, redirectCount + 1));
}
if (res.statusCode !== 200) {
res.resume();
return reject(new Error(`Request Failed. Status Code: ${res.statusCode}`));
}
let data = '';
res.setEncoding('utf8');
res.on('data', chunk => data += chunk);
res.on('end', () => resolve(data));
}).on('error', e => reject(e));
});
}
function downloadFile(url, dest, headers = {}, redirectCount = 0) {
return new Promise((resolve, reject) => {
if (redirectCount > MAX_REDIRECTS) return reject(new Error('Too many redirects'));
const options = {
headers: {
'User-Agent': 'Node.js Script',
...headers
}
};
https.get(url, options, (res) => {
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
console.log(`Redirecting to ${res.headers.location}`);
return resolve(downloadFile(res.headers.location, dest, headers, redirectCount + 1));
}
if (res.statusCode !== 200) {
res.resume();
return reject(new Error(`Failed to get '${url}' (${res.statusCode})`));
}
const totalSize = parseInt(res.headers['content-length'], 10);
let downloadedSize = 0;
const file = fs.createWriteStream(dest);
res.pipe(file);
res.on('data', chunk => {
downloadedSize += chunk.length;
if (totalSize) {
const percent = ((downloadedSize / totalSize) * 100).toFixed(2);
process.stdout.write(`Downloading... ${percent}%\r`);
} else {
process.stdout.write(`Downloading... ${downloadedSize} bytes\r`);
}
});
file.on('finish', () => {
file.close(() => {
process.stdout.write('\n');
resolve();
});
});
file.on('error', err => {
fs.unlink(dest, () => reject(err));
});
}).on('error', err => reject(err));
});
}
function execCommand(command, cwd = process.cwd()) {
try {
execSync(command, { stdio: 'inherit', cwd });
} catch (error) {
throw new Error(`Command failed: ${command}\n${error.message}`);
}
}
function commandExists(command) {
try {
execSync(`where ${command}`, { stdio: 'ignore' });
return true;
} catch {
return false;
}
}
function find7zExecutable() {
if (commandExists('7z')) {
console.log('Found 7z.exe in PATH.');
return '7z';
}
for (const potentialPath of COMMON_7Z_PATHS) {
if (fs.existsSync(potentialPath)) {
console.log(`Found 7z.exe at: ${potentialPath}`);
return `"${potentialPath}"`;
}
}
throw new Error('7z.exe not found. Please install 7-Zip.');
}
// Main Build Function
(async function buildAnime4K() {
try {
console.log('=== Build Anime4K Script Started ===');
const sevenZipPath = find7zExecutable();
if (fs.existsSync(TEMP_DIR)) fs.rmSync(TEMP_DIR, { recursive: true, force: true });
fs.mkdirSync(TEMP_DIR, { recursive: true });
console.log(`Created temporary directory at ${TEMP_DIR}`);
console.log('Fetching latest Anime4K version information...');
const releaseData = await httpsGet(BLOC97_API_URL);
const releaseJson = JSON.parse(releaseData);
const version = releaseJson.tag_name;
console.log(`Latest version: ${version}`);
const downloadUrl = `https://github.com/Tama47/Anime4K/releases/download/${version}/GLSL_Windows_High-end.zip`;
const downloadedFilePath = path.join(TEMP_DIR, 'GLSL_Windows_High-end.zip');
console.log(`Downloading GLSL_Windows_High-end.zip for version ${version}...`);
await downloadFile(downloadUrl, downloadedFilePath);
console.log(`Downloaded to ${downloadedFilePath}`);
// Ensure output directory exists
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
const outputZipPath = path.join(OUTPUT_DIR, OUTPUT_ZIP_NAME);
fs.copyFileSync(downloadedFilePath, outputZipPath);
console.log(`Saved zip as ${outputZipPath}`);
// Extract the zip to the anime4k folder
fs.mkdirSync(EXTRACTION_DIR, { recursive: true });
console.log(`Extracting ${outputZipPath} to ${EXTRACTION_DIR}...`);
execCommand(`${sevenZipPath} x "${outputZipPath}" -o"${EXTRACTION_DIR}" -y`);
console.log('Extraction complete.');
// Cleanup
console.log(`Cleaning up temporary files at ${TEMP_DIR}...`);
fs.rmSync(TEMP_DIR, { recursive: true, force: true });
console.log('Cleanup complete.');
console.log('=== Build Anime4K Script Completed Successfully ===');
} catch (error) {
console.error('Error during build:', error.message);
process.exit(1);
}
})();

353
build/build_animejanai.js Normal file
View file

@ -0,0 +1,353 @@
#!/usr/bin/env node
/**
* build_animejanai.js
*
* This script performs the following:
* 1. Downloads the latest 'full-package' .7z release from Animejanai GitHub.
* 2. Extracts the archive.
* 3. Deletes specified files and folders.
* 4. Modifies configuration files as per stremio requirements.
* 5. Repackages the modified files into a new .7z archive with maximum compression.
* 6. Places the final archive in utils/mpv.
* 7. Cleans up temporary files.
*
* Usage:
* node build_animejanai.js
*/
const fs = require('fs');
const path = require('path');
const https = require('https');
const { execSync } = require('child_process');
const os = require('os');
// Configuration
const GITHUB_API_URL = 'https://api.github.com/repos/the-database/mpv-upscale-2x_animejanai/releases/latest';
const TEMP_DIR = path.join(os.tmpdir(), 'animejanai_build_temp');
const OUTPUT_DIR = path.resolve(__dirname, '..', 'utils', 'mpv');
const OUTPUT_FILENAME_TEMPLATE = 'stremio-animejanai-{version}.7z';
// Files and directories to delete
const FILES_TO_DELETE = [
'libmpv-2.dll',
'libmpvnet.pdb',
'MediaInfo.dll',
'mpvnet.com',
'mpvnet.dll.config',
'mpvnet.exe',
'mpvnet.pdb',
'NGettext.Wpf.pdb'
];
const FOLDERS_TO_DELETE = [
'Locale'
];
// Configuration for input.conf replacement
const NEW_INPUT_CONF_CONTENT = `
Ctrl+E show-text "Launching AnimeJaNaiConfEditor..."; run "~~\\..\\animejanai\\AnimeJaNaiConfEditor.exe" #menu: AnimeJaNai > Launch AnimeJaNaiConfEditor
Ctrl+J script-binding "show_animejanai_stats" #menu: AnimeJaNai > Toggle AnimeJaNai Stats
) show-text "2x_AnimeJaNai_V3 Off"; apply-profile upscale-off;
Ctrl+0 show-text "2x_AnimeJaNai_V3 Off"; apply-profile upscale-off;
SHIFT+1 show-text "2x_AnimeJaNai_V3 Quality"; apply-profile upscale-on-quality;
SHIFT+2 show-text "2x_AnimeJaNai_V3 Balanced"; apply-profile upscale-on-balanced;
SHIFT+3 show-text "2x_AnimeJaNai_V3 Performance"; apply-profile upscale-on-performance;
Ctrl+1 show-text "2x_AnimeJaNai_V3 Custom Profile 1"; apply-profile upscale-on-1;
Ctrl+2 show-text "2x_AnimeJaNai_V3 Custom Profile 2"; apply-profile upscale-on-2;
Ctrl+3 show-text "2x_AnimeJaNai_V3 Custom Profile 3"; apply-profile upscale-on-3;
Ctrl+4 show-text "2x_AnimeJaNai_V3 Custom Profile 4"; apply-profile upscale-on-4;
Ctrl+5 show-text "2x_AnimeJaNai_V3 Custom Profile 5"; apply-profile upscale-on-5;
Ctrl+6 show-text "2x_AnimeJaNai_V3 Custom Profile 6"; apply-profile upscale-on-6;
Ctrl+7 show-text "2x_AnimeJaNai_V3 Custom Profile 7"; apply-profile upscale-on-7;
Ctrl+8 show-text "2x_AnimeJaNai_V3 Custom Profile 8"; apply-profile upscale-on-8;
Ctrl+9 show-text "2x_AnimeJaNai_V3 Custom Profile 9"; apply-profile upscale-on-9;
`;
// Lines to delete from mpv.conf
const LINES_TO_DELETE_IN_MPV_CONF = [
'save-position-on-quit=yes',
'watch-later-options=start',
'reset-on-next-file=pause'
];
// Common 7z.exe installation paths on Windows
const COMMON_7Z_PATHS = [
path.join(process.env.PROGRAMFILES || 'C:\\Program Files', '7-Zip', '7z.exe'),
path.join(process.env['PROGRAMFILES(X86)'] || 'C:\\Program Files (x86)', '7-Zip', '7z.exe'),
path.join(process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local'), '7-Zip', '7z.exe')
];
// Maximum number of redirects to follow
const MAX_REDIRECTS = 5;
// Function to make HTTPS GET requests with GitHub API headers
function httpsGet(url, headers = {}, redirectCount = 0) {
return new Promise((resolve, reject) => {
if (redirectCount > MAX_REDIRECTS) {
return reject(new Error('Too many redirects'));
}
const options = {
headers: {
'User-Agent': 'Node.js Script',
...headers
}
};
https.get(url, options, (res) => {
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
// Handle redirects
resolve(httpsGet(res.headers.location, headers, redirectCount + 1));
return;
}
if (res.statusCode !== 200) {
reject(new Error(`Request Failed. Status Code: ${res.statusCode}`));
res.resume(); // Consume response data to free up memory
return;
}
let data = '';
res.setEncoding('utf8');
res.on('data', (chunk) => data += chunk);
res.on('end', () => resolve(data));
}).on('error', (e) => reject(e));
});
}
// Function to download a file from a URL, handling redirects and showing progress
function downloadFile(url, dest, headers = {}, redirectCount = 0) {
return new Promise((resolve, reject) => {
if (redirectCount > MAX_REDIRECTS) {
return reject(new Error('Too many redirects'));
}
const options = {
headers: {
'User-Agent': 'Node.js Script',
...headers
}
};
https.get(url, options, (res) => {
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
// Handle redirects
console.log(`Redirecting to ${res.headers.location}`);
downloadFile(res.headers.location, dest, headers, redirectCount + 1).then(resolve).catch(reject);
return;
}
if (res.statusCode !== 200) {
reject(new Error(`Failed to get '${url}' (${res.statusCode})`));
res.resume();
return;
}
const totalSize = parseInt(res.headers['content-length'], 10);
let downloadedSize = 0;
const file = fs.createWriteStream(dest);
res.pipe(file);
res.on('data', (chunk) => {
downloadedSize += chunk.length;
if (totalSize) {
const percent = ((downloadedSize / totalSize) * 100).toFixed(2);
process.stdout.write(`Downloading... ${percent}%\r`);
} else {
process.stdout.write(`Downloading... ${downloadedSize} bytes\r`);
}
});
file.on('finish', () => {
file.close(() => {
process.stdout.write('\n');
resolve();
});
});
file.on('error', (err) => {
fs.unlink(dest, () => reject(err));
});
}).on('error', (err) => {
reject(err);
});
});
}
// Function to execute a shell command synchronously
function execCommand(command, cwd = process.cwd()) {
try {
execSync(command, { stdio: 'inherit', cwd });
} catch (error) {
throw new Error(`Command failed: ${command}\n${error.message}`);
}
}
// Function to check if a command exists
function commandExists(command) {
try {
execSync(`where ${command}`, { stdio: 'ignore' });
return true;
} catch {
return false;
}
}
// Function to find 7z.exe in common installation paths
function find7zExecutable() {
// First, check if 7z is in PATH
if (commandExists('7z')) {
console.log('Found 7z.exe in PATH.');
return '7z';
}
// Search in common installation directories
for (const potentialPath of COMMON_7Z_PATHS) {
if (fs.existsSync(potentialPath)) {
console.log(`Found 7z.exe at: ${potentialPath}`);
return `"${potentialPath}"`; // Quote the path in case it contains spaces
}
}
// If not found, throw an error
throw new Error('7z.exe not found. Please install 7-Zip and ensure 7z.exe is in your PATH or installed in a common directory.');
}
// Main Build Function
(async function buildAnimeJanai() {
try {
console.log('=== Build AnimeJaNai Script Started ===');
// Locate 7z.exe
const sevenZipPath = find7zExecutable();
// Create temporary directory
if (fs.existsSync(TEMP_DIR)) {
fs.rmSync(TEMP_DIR, { recursive: true, force: true });
}
fs.mkdirSync(TEMP_DIR, { recursive: true });
console.log(`Created temporary directory at ${TEMP_DIR}`);
// Step 1: Fetch latest release info from GitHub
console.log('Fetching latest release information from GitHub...');
const releaseData = await httpsGet(GITHUB_API_URL);
const releaseJson = JSON.parse(releaseData);
const version = releaseJson.tag_name || 'latest';
console.log(`Latest version: ${version}`);
// Step 2: Find the 'full-package' .7z asset
const assets = releaseJson.assets;
const fullPackageAsset = assets.find(asset => asset.name.includes('full-package') && asset.name.endsWith('.7z'));
if (!fullPackageAsset) {
throw new Error("No 'full-package' .7z asset found in the latest release.");
}
const downloadUrl = fullPackageAsset.browser_download_url;
const assetName = fullPackageAsset.name;
const downloadedFilePath = path.join(TEMP_DIR, assetName);
console.log(`Downloading asset: ${assetName}`);
await downloadFile(downloadUrl, downloadedFilePath);
console.log(`Downloaded to ${downloadedFilePath}`);
// Step 3: Extract the .7z archive
const extractDir = path.join(TEMP_DIR, 'extracted');
fs.mkdirSync(extractDir, { recursive: true });
console.log(`Extracting ${downloadedFilePath} to ${extractDir}...`);
execCommand(`${sevenZipPath} x "${downloadedFilePath}" -o"${extractDir}" -y`, TEMP_DIR);
console.log('Extraction complete.');
// Step 4: Identify the root directory inside the extracted folder
const extractedItems = fs.readdirSync(extractDir);
let rootDir = extractDir;
if (extractedItems.length === 1 && fs.lstatSync(path.join(extractDir, extractedItems[0])).isDirectory()) {
rootDir = path.join(extractDir, extractedItems[0]);
console.log(`Detected root directory: ${rootDir}`);
} else {
console.log('No single root directory detected. Proceeding with extracted contents.');
}
// Step 5: Delete specified files
console.log('Deleting specified files...');
FILES_TO_DELETE.forEach(file => {
const filePath = path.join(rootDir, file);
if (fs.existsSync(filePath)) {
fs.unlinkSync(filePath);
console.log(`Deleted file: ${filePath}`);
} else {
console.log(`File not found (skipped): ${filePath}`);
}
});
// Step 6: Delete specified folders
console.log('Deleting specified folders...');
FOLDERS_TO_DELETE.forEach(folder => {
const folderPath = path.join(rootDir, folder);
if (fs.existsSync(folderPath)) {
fs.rmSync(folderPath, { recursive: true, force: true });
console.log(`Deleted folder: ${folderPath}`);
} else {
console.log(`Folder not found (skipped): ${folderPath}`);
}
});
// Step 7: Modify portable_config/input.conf
const portableConfigDir = path.join(rootDir, 'portable_config');
const inputConfPath = path.join(portableConfigDir, 'input.conf');
if (fs.existsSync(inputConfPath)) {
fs.writeFileSync(inputConfPath, NEW_INPUT_CONF_CONTENT, 'utf8');
console.log(`Modified input.conf at ${inputConfPath}`);
} else {
console.warn(`input.conf not found at ${inputConfPath}. Skipping modification.`);
}
// Step 8: Modify mpv.conf
const mpvConfPath = path.join(portableConfigDir, 'mpv.conf'); // Corrected path
if (fs.existsSync(mpvConfPath)) {
let mpvConfContent = fs.readFileSync(mpvConfPath, 'utf8');
// Replace vo={something} with vo=libmpv
mpvConfContent = mpvConfContent.replace(/^vo=.*/m, 'vo=libmpv');
// Remove specified lines
LINES_TO_DELETE_IN_MPV_CONF.forEach(line => {
const regex = new RegExp(`^${line}$`, 'm');
mpvConfContent = mpvConfContent.replace(regex, '');
});
// Write the modified content back
fs.writeFileSync(mpvConfPath, mpvConfContent, 'utf8');
console.log(`Modified mpv.conf at ${mpvConfPath}`);
} else {
console.warn(`mpv.conf not found at ${mpvConfPath}. Skipping modification.`);
}
// Step 9: Repack the modified files into a new .7z archive
const outputVersion = version.startsWith('v') ? version.slice(1) : version;
const outputFilename = OUTPUT_FILENAME_TEMPLATE.replace('{version}', outputVersion);
const outputFilePath = path.join(OUTPUT_DIR, outputFilename);
// Ensure output directory exists
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
console.log(`Packing modified files into ${outputFilePath} with maximum compression...`);
// Change working directory to rootDir to ensure files are added directly
execCommand(`${sevenZipPath} a -t7z "${outputFilePath}" * -mx=9`, rootDir);
console.log(`Packaged archive created at ${outputFilePath}`);
// Step 10: Cleanup temporary directory
console.log(`Cleaning up temporary files at ${TEMP_DIR}...`);
fs.rmSync(TEMP_DIR, { recursive: true, force: true });
console.log('Cleanup complete.');
console.log('=== Build AnimeJaNai Script Completed Successfully ===');
} catch (error) {
console.error('Error during build:', error.message);
process.exit(1);
}
})();

View file

@ -29,7 +29,7 @@ const NODE_EXE = path.join(SOURCE_DIR, 'utils', 'windows', 'node.exe');
const DS_FOLDER = path.join(SOURCE_DIR, 'utils', 'windows', 'DS');
const STREMIO_RUNTIME_EXE = path.join(SOURCE_DIR, 'utils', 'windows', 'stremio-runtime.exe');
const FFMPEG_FOLDER = path.join(SOURCE_DIR, 'utils', 'windows', 'ffmpeg');
const MPV_FOLDER = path.join(SOURCE_DIR, 'utils', 'mpv');
const MPV_FOLDER = path.join(SOURCE_DIR, 'utils', 'mpv', 'anime4k');
// Default Paths
const DEFAULT_OPENSSL_BIN = 'C:\\Program Files\\OpenSSL-Win64\\bin';

View file

@ -5,6 +5,7 @@
#include <QObject>
#include <QJsonObject>
#include <QDir>
#include <QtGlobal>
#include <QOpenGLContext>
@ -142,8 +143,14 @@ void MpvObject::initialize_mpv() {
// terminal=yes brings us all the terminal logs; on windows it's much better with winpty (https://github.com/mpv-player/mpv/blob/master/DOCS/compile-windows.md)
mpv_set_option_string(mpv, "terminal", "yes");
mpv_set_option_string(mpv, "msg-level", "all=v");
// Set mpv.conf path to appDirPath. Can be used by users to apply mpv profiles using Conditional auto profiles with profile-cond property
QString configPath = QCoreApplication::applicationDirPath();
// Set mpv.conf path to appDirPath/portable_config. Can be used by users to apply mpv profiles using Conditional auto profiles with profile-cond property
QString appDirPath = QCoreApplication::applicationDirPath();
QString configPath = appDirPath + QDir::separator() + "portable_config";
bool success = QDir().mkpath(configPath);
if (!success) {
qWarning("Failed to create portable_config directory.");
}
// Set the "config-dir" option for mpv
mpv_set_option_string(mpv, "config-dir", configPath.toUtf8().constData());
mpv_set_option_string(mpv, "config", "yes");

View file

@ -1,46 +0,0 @@
[stremio-default]
# Default Stremio Profile uncomment below line to customize / overwrite defaullt settings
# profile-cond=width >= 1
profile-desc=Stremio Profile
# Shorten probe size and analyzeduration to reduce initial demux overhead. (Faster playback start)
demuxer-lavf-probesize=524288
demuxer-lavf-analyzeduration=0.5f
# Increase max bytes/packets to allow for 60s cache-secs. Default 150mb/75mb
demuxer-max-bytes=300000000
demuxer-max-packets=150000000
# Buffer / Cache Settings
cache=yes
cache-pause=no
cache-secs=60 # Limited by demuxer-max-bytes
# More threads for decoding
vd-lavc-threads=0
ad-lavc-threads=0
[stremio-anime]
# Example profile following this guide https://kokomins.wordpress.com/2019/10/14/mpv-config-guide/#advanced-video-scaling-config
profile-desc=Anime Profile
# See mpv docs for conditional auto profiles https://mpv.io/manual/stable/#conditional-auto-profiles .To enable uncomment the line below:
# profile-cond=filename ~= "(?i)anime|fansub|horriblesubs|ttga|lulu|ozr|thighs|mtbb|ember|lostyears|breeze|yuisubs|almighty|bigfoot|neohevc|cleo|judas|anime time|golumpa|legion|nokou|usagi|av1ary|yameii|metaljerk|gbr|sam|scy|salieri|anipakku|cbm|db|valenciano|suki desu|hakata ramen|trix|jacobswaggedup|sokudo"
profile=gpu-hq
# Deband filter. Always turn on for anime.
deband=yes # Default values are 1:64:16:48
# Deband parameters configuration.
deband-iterations=2 # Range 1-16.
deband-threshold=35 # Range 0-4096.
deband-range=20 # Range 1-64.
deband-grain=5 # Range 0-4096.
dither-depth=auto
volume=100
volume-max=100
demuxer-mkv-subtitle-preroll=yes
sub-auto=fuzzy
# Source https://gist.github.com/igv/2364ffa6e81540f29cb7ab4c9bc05b6b
glsl-shader="~~/shaders/SSimSuperResMitchell.glsl"
scale=ewa_lanczossharp
# Source https://github.com/awused/dotfiles/blob/master/mpv/.config/mpv/shaders/KrigBilateral.glsl
glsl-shader="~~/shaders/KrigBilateral.glsl" # High quality chroma upscaler.

View file

@ -1,211 +0,0 @@
// KrigBilateral by Shiandow
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3.0 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library.
//!HOOK CHROMA
//!BIND HOOKED
//!BIND LUMA
//!SAVE LOWRES_Y
//!WIDTH LUMA.w
//!WHEN CHROMA.w LUMA.w <
//!DESC KrigBilateral Downscaling Y pass 1
#define lumaOffset (-vec2(0.0, 0.0)*LUMA_size*CHROMA_pt)
#define axis 1
#define Kernel(x) (1. - abs(x))
vec4 hook() {
// Calculate bounds
float low = ceil((LUMA_pos - 0.5*CHROMA_pt) * LUMA_size - lumaOffset - 0.5)[axis];
float high = floor((LUMA_pos + 0.5*CHROMA_pt) * LUMA_size - lumaOffset - 0.5)[axis];
float W = 0.0;
vec4 avg = vec4(0);
vec2 pos = LUMA_pos;
for (float k = low; k <= high; k++) {
pos[axis] = LUMA_pt[axis] * (k - lumaOffset[axis] + 0.5);
float rel = (pos[axis] - LUMA_pos[axis])*CHROMA_size[axis];
float w = Kernel(rel);
vec4 y = textureLod(LUMA_raw, pos, 0.0).xxxx * LUMA_mul;
y.y *= y.y;
avg += w * y;
W += w;
}
avg /= W;
avg.y = abs(avg.y - pow(avg.x, 2.0));
return avg;
}
//!HOOK CHROMA
//!BIND HOOKED
//!BIND LOWRES_Y
//!SAVE LOWRES_Y
//!WHEN CHROMA.w LUMA.w <
//!DESC KrigBilateral Downscaling Y pass 2
#define lumaOffset (-vec2(0.0, 0.0)*LOWRES_Y_size*CHROMA_pt)
#define axis 0
#define Kernel(x) (1. - abs(x))
vec4 hook() {
// Calculate bounds
float low = ceil((LOWRES_Y_pos - 0.5*CHROMA_pt) * LOWRES_Y_size - lumaOffset - 0.5)[axis];
float high = floor((LOWRES_Y_pos + 0.5*CHROMA_pt) * LOWRES_Y_size - lumaOffset - 0.5)[axis];
float W = 0.0;
vec4 avg = vec4(0);
vec2 pos = LOWRES_Y_pos;
for (float k = low; k <= high; k++) {
pos[axis] = LOWRES_Y_pt[axis] * (k - lumaOffset[axis] + 0.5);
float rel = (pos[axis] - LOWRES_Y_pos[axis])*CHROMA_size[axis];
float w = Kernel(rel);
vec4 y = textureLod(LOWRES_Y_raw, pos, 0.0).xxxx * LOWRES_Y_mul;
y.y *= y.y;
avg += w * y;
W += w;
}
avg /= W;
avg.y = abs(avg.y - pow(avg.x, 2.0)) + LOWRES_Y_texOff(0).y;
return avg;
}
//!HOOK CHROMA
//!BIND HOOKED
//!BIND LUMA
//!BIND LOWRES_Y
//!WIDTH LUMA.w
//!HEIGHT LUMA.h
//!WHEN CHROMA.w LUMA.w <
//!OFFSET ALIGN
//!DESC KrigBilateral Upscaling UV
// -- Convenience --
#define sqr(x) dot(x,x)
#define bitnoise 1.0/(2.0*255.0)
#define noise 0.05//5.0*bitnoise
#define chromaOffset vec2(0.0, 0.0)
// -- Window Size --
#define taps 3
#define even (float(taps) - 2.0 * floor(float(taps) / 2.0) == 0.0)
#define minX int(1.0-ceil(float(taps)/2.0))
#define maxX int(floor(float(taps)/2.0))
#define Kernel(x) (cos(acos(-1.0)*(x)/float(taps))) // Hann kernel
// -- Input processing --
#define GetY(coord) LOWRES_Y_tex(LOWRES_Y_pt*(pos+coord+vec2(0.5))).xy
#define GetUV(coord) CHROMA_tex(CHROMA_pt*(pos+coord+vec2(0.5))).xy
#define N (taps*taps - 1)
#define M(i,j) Mx[min(i,j)*N + max(i,j) - min(i,j)*(min(i,j)+1)/2]
#define C(i,j) (inversesqrt(1.0 + (X[i].y + X[j].y)/localVar) * exp(-0.5*(sqr(X[i].x - X[j].x)/(localVar + X[i].y + X[j].y) + sqr((coords[i] - coords[j])/radius))) + (X[i].x - y) * (X[j].x - y) / localVar)
#define c(i) (inversesqrt(1.0 + X[i].y/localVar) * exp(-0.5*(sqr(X[i].x - y)/(localVar + X[i].y) + sqr((coords[i] - offset)/radius))))
vec4 hook() {
vec2 pos = CHROMA_pos * HOOKED_size - chromaOffset - vec2(0.5);
vec2 offset = pos - (even ? floor(pos) : round(pos));
pos -= offset;
vec2 coords[N+1];
vec4 X[N+1];
float y = LUMA_texOff(0).x;
vec4 total = vec4(0);
coords[0] = vec2(-1,-1); coords[1] = vec2(-1, 0); coords[2] = vec2(-1, 1);
coords[3] = vec2( 0,-1); coords[4] = vec2( 0, 1); coords[5] = vec2( 1,-1);
coords[6] = vec2( 1, 0); coords[7] = vec2( 1, 1); coords[8] = vec2( 0, 0);
for (int i=0; i<N+1; i++) {
X[i] = vec4(GetY(coords[i]), GetUV(coords[i]));
vec2 w = clamp(1.5 - abs(coords[i] - offset), 0.0, 1.0);
total += w.x*w.y*vec4(X[i].x, pow(X[i].x, 2.0), X[i].y, 1.0);
}
total.xyz /= total.w;
float localVar = sqr(noise) + abs(total.y - pow(total.x, 2.0)) + total.z;
float radius = 1.0;
float Mx[N*(N+1)/2];
float b[N];
vec4 interp = X[N];
b[0] = c(0) - c(N) - C(0,N) + C(N,N); M(0, 0) = C(0,0) - C(0,N) - C(0,N) + C(N,N); M(0, 1) = C(0,1) - C(1,N) - C(0,N) + C(N,N); M(0, 2) = C(0,2) - C(2,N) - C(0,N) + C(N,N); M(0, 3) = C(0,3) - C(3,N) - C(0,N) + C(N,N); M(0, 4) = C(0,4) - C(4,N) - C(0,N) + C(N,N); M(0, 5) = C(0,5) - C(5,N) - C(0,N) + C(N,N); M(0, 6) = C(0,6) - C(6,N) - C(0,N) + C(N,N); M(0, 7) = C(0,7) - C(7,N) - C(0,N) + C(N,N);
b[1] = c(1) - c(N) - C(1,N) + C(N,N); M(1, 1) = C(1,1) - C(1,N) - C(1,N) + C(N,N); M(1, 2) = C(1,2) - C(2,N) - C(1,N) + C(N,N); M(1, 3) = C(1,3) - C(3,N) - C(1,N) + C(N,N); M(1, 4) = C(1,4) - C(4,N) - C(1,N) + C(N,N); M(1, 5) = C(1,5) - C(5,N) - C(1,N) + C(N,N); M(1, 6) = C(1,6) - C(6,N) - C(1,N) + C(N,N); M(1, 7) = C(1,7) - C(7,N) - C(1,N) + C(N,N);
b[2] = c(2) - c(N) - C(2,N) + C(N,N); M(2, 2) = C(2,2) - C(2,N) - C(2,N) + C(N,N); M(2, 3) = C(2,3) - C(3,N) - C(2,N) + C(N,N); M(2, 4) = C(2,4) - C(4,N) - C(2,N) + C(N,N); M(2, 5) = C(2,5) - C(5,N) - C(2,N) + C(N,N); M(2, 6) = C(2,6) - C(6,N) - C(2,N) + C(N,N); M(2, 7) = C(2,7) - C(7,N) - C(2,N) + C(N,N);
b[3] = c(3) - c(N) - C(3,N) + C(N,N); M(3, 3) = C(3,3) - C(3,N) - C(3,N) + C(N,N); M(3, 4) = C(3,4) - C(4,N) - C(3,N) + C(N,N); M(3, 5) = C(3,5) - C(5,N) - C(3,N) + C(N,N); M(3, 6) = C(3,6) - C(6,N) - C(3,N) + C(N,N); M(3, 7) = C(3,7) - C(7,N) - C(3,N) + C(N,N);
b[4] = c(4) - c(N) - C(4,N) + C(N,N); M(4, 4) = C(4,4) - C(4,N) - C(4,N) + C(N,N); M(4, 5) = C(4,5) - C(5,N) - C(4,N) + C(N,N); M(4, 6) = C(4,6) - C(6,N) - C(4,N) + C(N,N); M(4, 7) = C(4,7) - C(7,N) - C(4,N) + C(N,N);
b[5] = c(5) - c(N) - C(5,N) + C(N,N); M(5, 5) = C(5,5) - C(5,N) - C(5,N) + C(N,N); M(5, 6) = C(5,6) - C(6,N) - C(5,N) + C(N,N); M(5, 7) = C(5,7) - C(7,N) - C(5,N) + C(N,N);
b[6] = c(6) - c(N) - C(6,N) + C(N,N); M(6, 6) = C(6,6) - C(6,N) - C(6,N) + C(N,N); M(6, 7) = C(6,7) - C(7,N) - C(6,N) + C(N,N);
b[7] = c(7) - c(N) - C(7,N) + C(N,N); M(7, 7) = C(7,7) - C(7,N) - C(7,N) + C(N,N);
b[1] -= b[0] * M(1, 0) / M(0, 0); M(1, 1) -= M(0, 1) * M(1, 0) / M(0, 0); M(1, 2) -= M(0, 2) * M(1, 0) / M(0, 0); M(1, 3) -= M(0, 3) * M(1, 0) / M(0, 0); M(1, 4) -= M(0, 4) * M(1, 0) / M(0, 0); M(1, 5) -= M(0, 5) * M(1, 0) / M(0, 0); M(1, 6) -= M(0, 6) * M(1, 0) / M(0, 0); M(1, 7) -= M(0, 7) * M(1, 0) / M(0, 0);
b[2] -= b[0] * M(2, 0) / M(0, 0); M(2, 2) -= M(0, 2) * M(2, 0) / M(0, 0); M(2, 3) -= M(0, 3) * M(2, 0) / M(0, 0); M(2, 4) -= M(0, 4) * M(2, 0) / M(0, 0); M(2, 5) -= M(0, 5) * M(2, 0) / M(0, 0); M(2, 6) -= M(0, 6) * M(2, 0) / M(0, 0); M(2, 7) -= M(0, 7) * M(2, 0) / M(0, 0);
b[3] -= b[0] * M(3, 0) / M(0, 0); M(3, 3) -= M(0, 3) * M(3, 0) / M(0, 0); M(3, 4) -= M(0, 4) * M(3, 0) / M(0, 0); M(3, 5) -= M(0, 5) * M(3, 0) / M(0, 0); M(3, 6) -= M(0, 6) * M(3, 0) / M(0, 0); M(3, 7) -= M(0, 7) * M(3, 0) / M(0, 0);
b[4] -= b[0] * M(4, 0) / M(0, 0); M(4, 4) -= M(0, 4) * M(4, 0) / M(0, 0); M(4, 5) -= M(0, 5) * M(4, 0) / M(0, 0); M(4, 6) -= M(0, 6) * M(4, 0) / M(0, 0); M(4, 7) -= M(0, 7) * M(4, 0) / M(0, 0);
b[5] -= b[0] * M(5, 0) / M(0, 0); M(5, 5) -= M(0, 5) * M(5, 0) / M(0, 0); M(5, 6) -= M(0, 6) * M(5, 0) / M(0, 0); M(5, 7) -= M(0, 7) * M(5, 0) / M(0, 0);
b[6] -= b[0] * M(6, 0) / M(0, 0); M(6, 6) -= M(0, 6) * M(6, 0) / M(0, 0); M(6, 7) -= M(0, 7) * M(6, 0) / M(0, 0);
b[7] -= b[0] * M(7, 0) / M(0, 0); M(7, 7) -= M(0, 7) * M(7, 0) / M(0, 0);
b[2] -= b[1] * M(2, 1) / M(1, 1); M(2, 2) -= M(1, 2) * M(2, 1) / M(1, 1); M(2, 3) -= M(1, 3) * M(2, 1) / M(1, 1); M(2, 4) -= M(1, 4) * M(2, 1) / M(1, 1); M(2, 5) -= M(1, 5) * M(2, 1) / M(1, 1); M(2, 6) -= M(1, 6) * M(2, 1) / M(1, 1); M(2, 7) -= M(1, 7) * M(2, 1) / M(1, 1);
b[3] -= b[1] * M(3, 1) / M(1, 1); M(3, 3) -= M(1, 3) * M(3, 1) / M(1, 1); M(3, 4) -= M(1, 4) * M(3, 1) / M(1, 1); M(3, 5) -= M(1, 5) * M(3, 1) / M(1, 1); M(3, 6) -= M(1, 6) * M(3, 1) / M(1, 1); M(3, 7) -= M(1, 7) * M(3, 1) / M(1, 1);
b[4] -= b[1] * M(4, 1) / M(1, 1); M(4, 4) -= M(1, 4) * M(4, 1) / M(1, 1); M(4, 5) -= M(1, 5) * M(4, 1) / M(1, 1); M(4, 6) -= M(1, 6) * M(4, 1) / M(1, 1); M(4, 7) -= M(1, 7) * M(4, 1) / M(1, 1);
b[5] -= b[1] * M(5, 1) / M(1, 1); M(5, 5) -= M(1, 5) * M(5, 1) / M(1, 1); M(5, 6) -= M(1, 6) * M(5, 1) / M(1, 1); M(5, 7) -= M(1, 7) * M(5, 1) / M(1, 1);
b[6] -= b[1] * M(6, 1) / M(1, 1); M(6, 6) -= M(1, 6) * M(6, 1) / M(1, 1); M(6, 7) -= M(1, 7) * M(6, 1) / M(1, 1);
b[7] -= b[1] * M(7, 1) / M(1, 1); M(7, 7) -= M(1, 7) * M(7, 1) / M(1, 1);
b[3] -= b[2] * M(3, 2) / M(2, 2); M(3, 3) -= M(2, 3) * M(3, 2) / M(2, 2); M(3, 4) -= M(2, 4) * M(3, 2) / M(2, 2); M(3, 5) -= M(2, 5) * M(3, 2) / M(2, 2); M(3, 6) -= M(2, 6) * M(3, 2) / M(2, 2); M(3, 7) -= M(2, 7) * M(3, 2) / M(2, 2);
b[4] -= b[2] * M(4, 2) / M(2, 2); M(4, 4) -= M(2, 4) * M(4, 2) / M(2, 2); M(4, 5) -= M(2, 5) * M(4, 2) / M(2, 2); M(4, 6) -= M(2, 6) * M(4, 2) / M(2, 2); M(4, 7) -= M(2, 7) * M(4, 2) / M(2, 2);
b[5] -= b[2] * M(5, 2) / M(2, 2); M(5, 5) -= M(2, 5) * M(5, 2) / M(2, 2); M(5, 6) -= M(2, 6) * M(5, 2) / M(2, 2); M(5, 7) -= M(2, 7) * M(5, 2) / M(2, 2);
b[6] -= b[2] * M(6, 2) / M(2, 2); M(6, 6) -= M(2, 6) * M(6, 2) / M(2, 2); M(6, 7) -= M(2, 7) * M(6, 2) / M(2, 2);
b[7] -= b[2] * M(7, 2) / M(2, 2); M(7, 7) -= M(2, 7) * M(7, 2) / M(2, 2);
b[4] -= b[3] * M(4, 3) / M(3, 3); M(4, 4) -= M(3, 4) * M(4, 3) / M(3, 3); M(4, 5) -= M(3, 5) * M(4, 3) / M(3, 3); M(4, 6) -= M(3, 6) * M(4, 3) / M(3, 3); M(4, 7) -= M(3, 7) * M(4, 3) / M(3, 3);
b[5] -= b[3] * M(5, 3) / M(3, 3); M(5, 5) -= M(3, 5) * M(5, 3) / M(3, 3); M(5, 6) -= M(3, 6) * M(5, 3) / M(3, 3); M(5, 7) -= M(3, 7) * M(5, 3) / M(3, 3);
b[6] -= b[3] * M(6, 3) / M(3, 3); M(6, 6) -= M(3, 6) * M(6, 3) / M(3, 3); M(6, 7) -= M(3, 7) * M(6, 3) / M(3, 3);
b[7] -= b[3] * M(7, 3) / M(3, 3); M(7, 7) -= M(3, 7) * M(7, 3) / M(3, 3);
b[5] -= b[4] * M(5, 4) / M(4, 4); M(5, 5) -= M(4, 5) * M(5, 4) / M(4, 4); M(5, 6) -= M(4, 6) * M(5, 4) / M(4, 4); M(5, 7) -= M(4, 7) * M(5, 4) / M(4, 4);
b[6] -= b[4] * M(6, 4) / M(4, 4); M(6, 6) -= M(4, 6) * M(6, 4) / M(4, 4); M(6, 7) -= M(4, 7) * M(6, 4) / M(4, 4);
b[7] -= b[4] * M(7, 4) / M(4, 4); M(7, 7) -= M(4, 7) * M(7, 4) / M(4, 4);
b[6] -= b[5] * M(6, 5) / M(5, 5); M(6, 6) -= M(5, 6) * M(6, 5) / M(5, 5); M(6, 7) -= M(5, 7) * M(6, 5) / M(5, 5);
b[7] -= b[5] * M(7, 5) / M(5, 5); M(7, 7) -= M(5, 7) * M(7, 5) / M(5, 5);
b[7] -= b[6] * M(7, 6) / M(6, 6); M(7, 7) -= M(6, 7) * M(7, 6) / M(6, 6);
for (int i=0; i<N; i++) {
if(i > 6) b[N-1-i] -= M(N-1-i, 1) * b[1];
if(i > 5) b[N-1-i] -= M(N-1-i, 2) * b[2];
if(i > 4) b[N-1-i] -= M(N-1-i, 3) * b[3];
if(i > 3) b[N-1-i] -= M(N-1-i, 4) * b[4];
if(i > 2) b[N-1-i] -= M(N-1-i, 5) * b[5];
if(i > 1) b[N-1-i] -= M(N-1-i, 6) * b[6];
if(i > 0) b[N-1-i] -= M(N-1-i, 7) * b[7];
b[N-1-i] /= M(N-1-i, N-1-i);
interp += b[N-1-i] * (X[N-1-i] - X[N]);
}
return interp.zwxx;
}

View file

@ -1,203 +0,0 @@
// SSimSuperRes by Shiandow
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3.0 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library.
//!HOOK POSTKERNEL
//!BIND HOOKED
//!SAVE LOWRES
//!HEIGHT NATIVE_CROPPED.h
//!WHEN NATIVE_CROPPED.h OUTPUT.h <
//!COMPONENTS 4
//!DESC SSSR Downscaling I
#define axis 1
#define offset vec2(0,0)
#define MN(B,C,x) (x < 1.0 ? ((2.-1.5*B-(C))*x + (-3.+2.*B+C))*x*x + (1.-(B)/3.) : (((-(B)/6.-(C))*x + (B+5.*C))*x + (-2.*B-8.*C))*x+((4./3.)*B+4.*C))
#define Kernel(x) MN(0.334, 0.333, abs(x))
#define taps 2.0
#define Luma(rgb) dot(rgb*rgb, vec3(0.2126, 0.7152, 0.0722))
vec4 hook() {
float low = ceil((HOOKED_pos - taps/input_size) * HOOKED_size - offset - 0.5)[axis];
float high = floor((HOOKED_pos + taps/input_size) * HOOKED_size - offset - 0.5)[axis];
float W = 0.0;
vec4 avg = vec4(0);
vec2 pos = HOOKED_pos;
vec4 tex;
for (float k = low; k <= high; k++) {
pos[axis] = HOOKED_pt[axis] * (k - offset[axis] + 0.5);
float rel = (pos[axis] - HOOKED_pos[axis])*input_size[axis];
float w = Kernel(rel);
tex.rgb = textureLod(HOOKED_raw, pos, 0.0).rgb * HOOKED_mul;
tex.a = Luma(tex.rgb);
avg += w * tex;
W += w;
}
avg /= W;
return vec4(avg.rgb, max(abs(avg.a - Luma(avg.rgb)), 5e-7));
}
//!HOOK POSTKERNEL
//!BIND LOWRES
//!SAVE LOWRES
//!WIDTH NATIVE_CROPPED.w
//!HEIGHT NATIVE_CROPPED.h
//!WHEN NATIVE_CROPPED.w OUTPUT.w <
//!COMPONENTS 4
//!DESC SSSR Downscaling II
#define axis 0
#define offset vec2(0,0)
#define MN(B,C,x) (x < 1.0 ? ((2.-1.5*B-(C))*x + (-3.+2.*B+C))*x*x + (1.-(B)/3.) : (((-(B)/6.-(C))*x + (B+5.*C))*x + (-2.*B-8.*C))*x+((4./3.)*B+4.*C))
#define Kernel(x) MN(0.334, 0.333, abs(x))
#define taps 2.0
#define Luma(rgb) dot(rgb*rgb, vec3(0.2126, 0.7152, 0.0722))
vec4 hook() {
float low = ceil((LOWRES_pos - taps/input_size) * LOWRES_size - offset - 0.5)[axis];
float high = floor((LOWRES_pos + taps/input_size) * LOWRES_size - offset - 0.5)[axis];
float W = 0.0;
vec4 avg = vec4(0);
vec2 pos = LOWRES_pos;
vec4 tex;
for (float k = low; k <= high; k++) {
pos[axis] = LOWRES_pt[axis] * (k - offset[axis] + 0.5);
float rel = (pos[axis] - LOWRES_pos[axis])*input_size[axis];
float w = Kernel(rel);
tex.rgb = textureLod(LOWRES_raw, pos, 0.0).rgb * LOWRES_mul;
tex.a = Luma(tex.rgb);
avg += w * tex;
W += w;
}
avg /= W;
return vec4(avg.rgb, max(abs(avg.a - Luma(avg.rgb)), 5e-7) + LOWRES_texOff(0).a);
}
//!HOOK POSTKERNEL
//!BIND PREKERNEL
//!BIND LOWRES
//!SAVE var
//!WIDTH NATIVE_CROPPED.w
//!HEIGHT NATIVE_CROPPED.h
//!WHEN NATIVE_CROPPED.h OUTPUT.h <
//!COMPONENTS 2
//!DESC SSSR var
#define spread 1.0 / 4.0
#define GetL(x,y) PREKERNEL_tex(PREKERNEL_pt * (PREKERNEL_pos * input_size + tex_offset + vec2(x,y))).rgb
#define GetH(x,y) LOWRES_texOff(vec2(x,y)).rgb
#define Luma(rgb) dot(rgb*rgb, vec3(0.2126, 0.7152, 0.0722))
#define diff(x,y) vec2(Luma((GetL(x,y) - meanL)), Luma((GetH(x,y) - meanH)))
vec4 hook() {
vec3 meanL = GetL(0,0);
vec3 meanH = GetH(0,0);
for (int X=-1; X<=1; X+=2) {
meanL += GetL(X,0) * spread;
meanH += GetH(X,0) * spread;
}
for (int Y=-1; Y<=1; Y+=2) {
meanL += GetL(0,Y) * spread;
meanH += GetH(0,Y) * spread;
}
meanL /= (1.0 + 4.0*spread);
meanH /= (1.0 + 4.0*spread);
vec2 var = diff(0,0);
for (int X=-1; X<=1; X+=2)
var += diff(X,0) * spread;
for (int Y=-1; Y<=1; Y+=2)
var += diff(0,Y) * spread;
return vec4(max(var / (1.0 + 4.0*spread), vec2(1e-6)), 0, 0);
}
//!HOOK POSTKERNEL
//!BIND HOOKED
//!BIND PREKERNEL
//!BIND LOWRES
//!BIND var
//!WHEN NATIVE_CROPPED.h OUTPUT.h <
//!DESC SSSR final pass
#define oversharp 0.5
// -- Window Size --
#define taps 3.0
#define even (taps - 2.0 * floor(taps / 2.0) == 0.0)
#define minX int(1.0-ceil(taps/2.0))
#define maxX int(floor(taps/2.0))
#define Kernel(x) cos(acos(-1.0)*(x)/taps) // Hann kernel
// -- Input processing --
#define var(x,y) var_tex(var_pt * (pos + vec2(x,y) + 0.5)).rg
#define GetL(x,y) PREKERNEL_tex(PREKERNEL_pt * (pos + tex_offset + vec2(x,y) + 0.5)).rgb
#define GetH(x,y) LOWRES_tex(LOWRES_pt * (pos + vec2(x,y) + 0.5))
#define Luma(rgb) dot(rgb*rgb, vec3(0.2126, 0.7152, 0.0722))
vec4 hook() {
vec4 c0 = HOOKED_texOff(0);
vec2 pos = HOOKED_pos * LOWRES_size - vec2(0.5);
vec2 offset = pos - (even ? floor(pos) : round(pos));
pos -= offset;
vec2 mVar = vec2(0.0);
for (int X=-1; X<=1; X++)
for (int Y=-1; Y<=1; Y++) {
vec2 w = clamp(1.5 - abs(vec2(X,Y)), 0.0, 1.0);
mVar += w.r * w.g * vec2(GetH(X,Y).a, 1.0);
}
mVar.r /= mVar.g;
// Calculate faithfulness force
float weightSum = 0.0;
vec3 diff = vec3(0);
for (int X = minX; X <= maxX; X++)
for (int Y = minX; Y <= maxX; Y++)
{
float R = (-1.0 - oversharp) * sqrt(var(X,Y).r / (var(X,Y).g + mVar.r));
vec2 krnl = Kernel(vec2(X,Y) - offset);
float weight = krnl.r * krnl.g / (Luma((c0.rgb - GetH(X,Y).rgb)) + GetH(X,Y).a);
diff += weight * (GetL(X,Y) + GetH(X,Y).rgb * R + (-1.0 - R) * (c0.rgb));
weightSum += weight;
}
diff /= weightSum;
c0.rgb = ((c0.rgb) + diff);
return c0;
}

View file

@ -309,6 +309,7 @@ Section "uninstall"
IfErrors 0 KeepUserData
notsilent:
RMDir /r "$LOCALAPPDATA\${COMPANY_NAME}"
RMDir /r "$APPDATA\${COMPANY_NAME}"
RMDir /r "$APPDATA\${DATA_FOLDER}"
KeepUserData: