bvcx
This commit is contained in:
+62
-13
@@ -41,10 +41,10 @@
|
|||||||
--posts-meta-bg: #000000b8;
|
--posts-meta-bg: #000000b8;
|
||||||
--x2154: #215483;
|
--x2154: #215483;
|
||||||
--bg-canvas-opacity: 1.0;
|
--bg-canvas-opacity: 1.0;
|
||||||
--bg-canvas-blur: 300px;
|
--bg-canvas-blur: 30px;
|
||||||
--onara-bg-opacity: 0.84;
|
--onara-bg-opacity: 0.7;
|
||||||
--onara-backdrop-blur: 5px;
|
--onara-backdrop-blur: 5px;
|
||||||
--onara-grid-dim-opacity: 0.15;
|
--onara-grid-dim-opacity: 0.38;
|
||||||
}
|
}
|
||||||
|
|
||||||
html:not([theme]), html[theme=""] {
|
html:not([theme]), html[theme=""] {
|
||||||
@@ -3716,6 +3716,50 @@ body.sidebar-right-hidden #sidebar-drag-zone {
|
|||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.f0ck-tuner-btn-save-default {
|
||||||
|
background: color-mix(in srgb, var(--accent, #99ff00) 18%, rgba(0, 0, 0, 0.4));
|
||||||
|
border: 1px solid color-mix(in srgb, var(--accent, #99ff00) 45%, transparent);
|
||||||
|
color: var(--accent, #99ff00);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 5px 8px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.f0ck-tuner-btn-save-default:hover {
|
||||||
|
background: var(--accent, #99ff00);
|
||||||
|
border-color: var(--accent, #99ff00);
|
||||||
|
color: #000;
|
||||||
|
box-shadow: 0 2px 8px color-mix(in srgb, var(--accent, #99ff00) 35%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.f0ck-tuner-btn-factory-reset {
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||||
|
color: #aaa;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 5px 8px;
|
||||||
|
font-size: 11px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.f0ck-tuner-btn-factory-reset:hover {
|
||||||
|
background: rgba(255, 100, 100, 0.18);
|
||||||
|
border-color: rgba(255, 100, 100, 0.4);
|
||||||
|
color: #ff7777;
|
||||||
|
}
|
||||||
|
|
||||||
.f0ck-tuner-btn-import-preset:hover {
|
.f0ck-tuner-btn-import-preset:hover {
|
||||||
background: rgba(255, 255, 255, 0.2);
|
background: rgba(255, 255, 255, 0.2);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
@@ -3738,13 +3782,13 @@ body.sidebar-right-hidden #sidebar-drag-zone {
|
|||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 5px;
|
gap: 4px;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
color: #8e8e93;
|
color: #8e8e93;
|
||||||
font-size: 11px;
|
font-size: 10.5px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
padding: 5px 8px;
|
padding: 5px 5px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.15s ease;
|
transition: all 0.15s ease;
|
||||||
@@ -10314,14 +10358,13 @@ div.favs div.posts {
|
|||||||
right: 0;
|
right: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
/* blur is applied in canvas 2D context at draw time — no CSS filter needed.
|
transform: translate3d(0, 0, 0) scale(var(--bg-canvas-zoom, 1.12));
|
||||||
CSS filter: blur() on a full-screen fixed element forces Chromium to run
|
transform-origin: center center;
|
||||||
a GPU blur pass on every compositor frame (incl. during the fade transition),
|
|
||||||
which is extremely expensive. Firefox uses a cheaper path for this. */
|
|
||||||
transform: translate3d(0, 0, 0);
|
|
||||||
z-index: -2;
|
z-index: -2;
|
||||||
transition: opacity 1.5s cubic-bezier(0.4, 0, 0.2, 1);
|
transition: opacity 1.5s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
opacity: var(--bg-canvas-opacity, 1.0);
|
opacity: var(--bg-canvas-opacity, 1.0);
|
||||||
|
filter: var(--bg-canvas-filter, none);
|
||||||
|
-webkit-filter: var(--bg-canvas-filter, none);
|
||||||
}
|
}
|
||||||
|
|
||||||
button#togglebg {
|
button#togglebg {
|
||||||
@@ -20624,9 +20667,14 @@ a.lazy-thumb.filtered-upload-ghost:hover::after {
|
|||||||
}
|
}
|
||||||
.user-infobox-username[contenteditable="true"] {
|
.user-infobox-username[contenteditable="true"] {
|
||||||
border-bottom: 1px dashed rgba(255, 255, 255, 0.3);
|
border-bottom: 1px dashed rgba(255, 255, 255, 0.3);
|
||||||
padding: 1px 4px;
|
padding: 1px 6px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
|
min-width: 80px;
|
||||||
|
max-width: 320px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: visible;
|
||||||
|
cursor: text;
|
||||||
}
|
}
|
||||||
.user-infobox-username[contenteditable="true"]:hover {
|
.user-infobox-username[contenteditable="true"]:hover {
|
||||||
border-bottom-color: var(--accent);
|
border-bottom-color: var(--accent);
|
||||||
@@ -20636,6 +20684,7 @@ a.lazy-thumb.filtered-upload-ghost:hover::after {
|
|||||||
outline: none;
|
outline: none;
|
||||||
border-bottom: 2px solid var(--accent);
|
border-bottom: 2px solid var(--accent);
|
||||||
background: rgba(0, 0, 0, 0.3);
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
min-width: 120px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.color-picker-badge {
|
.color-picker-badge {
|
||||||
@@ -20821,7 +20870,7 @@ body.onara-modal-open .admin-bar.open {
|
|||||||
z-index: 10050 !important;
|
z-index: 10050 !important;
|
||||||
display: none;
|
display: none;
|
||||||
flex-direction: column !important;
|
flex-direction: column !important;
|
||||||
background: rgba(0, 0, 0, var(--onara-bg-opacity, 0.84)) !important;
|
background: rgba(0, 0, 0, var(--onara-bg-opacity, 0.7)) !important;
|
||||||
backdrop-filter: blur(var(--onara-backdrop-blur, 5px)) saturate(130%) !important;
|
backdrop-filter: blur(var(--onara-backdrop-blur, 5px)) saturate(130%) !important;
|
||||||
-webkit-backdrop-filter: blur(var(--onara-backdrop-blur, 5px)) saturate(130%) !important;
|
-webkit-backdrop-filter: blur(var(--onara-backdrop-blur, 5px)) saturate(130%) !important;
|
||||||
overflow-y: auto !important;
|
overflow-y: auto !important;
|
||||||
|
|||||||
+630
-62
File diff suppressed because it is too large
Load Diff
+13
-6
@@ -1561,10 +1561,10 @@
|
|||||||
const valSpan = document.getElementById(valId);
|
const valSpan = document.getElementById(valId);
|
||||||
if (!slider) return;
|
if (!slider) return;
|
||||||
|
|
||||||
let currentTuning = {};
|
let currentTuning = (window.audioVisualizerTuning && Object.keys(window.audioVisualizerTuning).length > 0) ? window.audioVisualizerTuning : {};
|
||||||
try {
|
try {
|
||||||
const raw = localStorage.getItem('f0ck_audio_tuning');
|
const raw = localStorage.getItem('f0ck_audio_tuning');
|
||||||
if (raw) currentTuning = JSON.parse(raw);
|
if (raw) currentTuning = Object.assign({}, currentTuning, JSON.parse(raw));
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
|
||||||
const initialVal = currentTuning[tuningKey] !== undefined ? Number(currentTuning[tuningKey]) : defaultVal;
|
const initialVal = currentTuning[tuningKey] !== undefined ? Number(currentTuning[tuningKey]) : defaultVal;
|
||||||
@@ -1585,12 +1585,19 @@
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
setupAudioTuningSlider('onara_bg_opacity_slider', 'onara_bg_opacity_val', 'onaraBgOpacity', 0.84, v => Math.round(v * 100) + '%');
|
setupAudioTuningSlider('onara_bg_opacity_slider', 'onara_bg_opacity_val', 'onaraBgOpacity', 0.70, v => Math.round(v * 100) + '%');
|
||||||
setupAudioTuningSlider('onara_backdrop_blur_slider', 'onara_backdrop_blur_val', 'onaraBackdropBlur', 5, v => Math.round(v) + 'px');
|
setupAudioTuningSlider('onara_backdrop_blur_slider', 'onara_backdrop_blur_val', 'onaraBackdropBlur', 5, v => Math.round(v) + 'px');
|
||||||
setupAudioTuningSlider('onara_grid_dim_slider', 'onara_grid_dim_val', 'onaraGridDim', 0.15, v => Math.round(v * 100) + '%');
|
setupAudioTuningSlider('onara_grid_dim_slider', 'onara_grid_dim_val', 'onaraGridDim', 0.38, v => Math.round(v * 100) + '%');
|
||||||
setupAudioTuningSlider('bg_canvas_opacity_slider', 'bg_canvas_opacity_val', 'bgCanvasOpacity', 1.00, v => Math.round(v * 100) + '%');
|
setupAudioTuningSlider('bg_canvas_opacity_slider', 'bg_canvas_opacity_val', 'bgCanvasOpacity', 1.00, v => Math.round(v * 100) + '%');
|
||||||
setupAudioTuningSlider('bg_canvas_blur_slider', 'bg_canvas_blur_val', 'bgCanvasBlur', 300, v => Math.round(v) + 'px');
|
setupAudioTuningSlider('bg_canvas_blur_slider', 'bg_canvas_blur_val', 'bgCanvasBlur', 30, v => Math.round(v) + 'px');
|
||||||
setupAudioTuningSlider('bg_canvas_brightness_slider', 'bg_canvas_brightness_val', 'bgCanvasBrightness', 1.00, v => Math.round(v * 100) + '%');
|
setupAudioTuningSlider('bg_canvas_brightness_slider', 'bg_canvas_brightness_val', 'bgCanvasBrightness', 0.45, v => Number(v).toFixed(2) + 'x');
|
||||||
|
setupAudioTuningSlider('bg_canvas_saturate_slider', 'bg_canvas_saturate_val', 'bgCanvasSaturate', 1.8, v => Number(v).toFixed(2) + 'x');
|
||||||
|
setupAudioTuningSlider('bg_canvas_contrast_slider', 'bg_canvas_contrast_val', 'bgCanvasContrast', 1.1, v => Number(v).toFixed(2) + 'x');
|
||||||
|
setupAudioTuningSlider('bg_canvas_zoom_slider', 'bg_canvas_zoom_val', 'bgCanvasZoom', 1.12, v => Number(v).toFixed(2) + 'x');
|
||||||
|
|
||||||
|
// Blur Engine slider — shows friendly label text instead of raw number
|
||||||
|
const blurMethodNames = ['Canvas 2D', 'GPU CSS Filter', 'Hybrid'];
|
||||||
|
setupAudioTuningSlider('bg_blur_method_slider', 'bg_blur_method_val', 'bgBlurMethod', 0, v => blurMethodNames[Math.round(v)] || String(Math.round(v)), v => Math.round(Number(v)));
|
||||||
|
|
||||||
// Quote Emojis Toggle
|
// Quote Emojis Toggle
|
||||||
const quoteEmojisToggle = document.getElementById('quote_emojis_toggle');
|
const quoteEmojisToggle = document.getElementById('quote_emojis_toggle');
|
||||||
|
|||||||
@@ -411,6 +411,11 @@ export default new class queue {
|
|||||||
}
|
}
|
||||||
if (!fetched) {
|
if (!fetched) {
|
||||||
console.error(`[QUEUE] YouTube thumbnail extraction failed for ${itemid}: all quality levels failed or returned placeholder`);
|
console.error(`[QUEUE] YouTube thumbnail extraction failed for ${itemid}: all quality levels failed or returned placeholder`);
|
||||||
|
} else {
|
||||||
|
// Pre-warm dynamic ambient timeline in background
|
||||||
|
import('./routes/apiv2/ambient.mjs')
|
||||||
|
.then(m => m.getOrExtractYoutubeAmbient(videoId))
|
||||||
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,155 @@
|
|||||||
|
import { promises as fs } from "fs";
|
||||||
|
import path from "path";
|
||||||
|
import os from "os";
|
||||||
|
import { execFile } from "child_process";
|
||||||
|
import { promisify } from "util";
|
||||||
|
import cfg from "../../config.mjs";
|
||||||
|
|
||||||
|
const execFileAsync = promisify(execFile);
|
||||||
|
|
||||||
|
// Memory cache for in-flight requests to avoid concurrent yt-dlp calls for the same video
|
||||||
|
const pendingRequests = new Map();
|
||||||
|
|
||||||
|
export async function getOrExtractYoutubeAmbient(videoId) {
|
||||||
|
// Validate videoId: YouTube IDs are 11 chars containing [a-zA-Z0-9_-]
|
||||||
|
if (!videoId || !/^[a-zA-Z0-9_-]{6,15}$/.test(videoId)) {
|
||||||
|
throw new Error("Invalid YouTube video ID");
|
||||||
|
}
|
||||||
|
|
||||||
|
let tDir = cfg.paths?.t || 'public/t';
|
||||||
|
try { tDir = await fs.realpath(tDir); } catch (_) {}
|
||||||
|
const cacheFile = path.join(tDir, `ambient_${videoId}.json`);
|
||||||
|
|
||||||
|
// 1. Check disk cache
|
||||||
|
try {
|
||||||
|
const cached = await fs.readFile(cacheFile, 'utf8');
|
||||||
|
return JSON.parse(cached);
|
||||||
|
} catch (_) {
|
||||||
|
// Not cached yet
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. De-duplicate concurrent requests
|
||||||
|
if (pendingRequests.has(videoId)) {
|
||||||
|
return pendingRequests.get(videoId);
|
||||||
|
}
|
||||||
|
|
||||||
|
const promise = (async () => {
|
||||||
|
try {
|
||||||
|
const ytUrl = `https://www.youtube.com/watch?v=${videoId}`;
|
||||||
|
const proxyArgs = (cfg.main?.socks && cfg.main.socks !== 'undefined' && cfg.main.socks !== '')
|
||||||
|
? ['--proxy', cfg.main.socks.includes('://') ? cfg.main.socks : `socks5h://${cfg.main.socks}`]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
// Run yt-dlp to inspect formats
|
||||||
|
const { stdout } = await execFileAsync('yt-dlp', [
|
||||||
|
'-j',
|
||||||
|
'--skip-download',
|
||||||
|
'--no-playlist',
|
||||||
|
...proxyArgs,
|
||||||
|
ytUrl
|
||||||
|
], { timeout: 15000 });
|
||||||
|
|
||||||
|
const info = JSON.parse(stdout);
|
||||||
|
const duration = Number(info.duration) || 0;
|
||||||
|
|
||||||
|
// Find storyboard format (prefer sb3, fallback to sb2/sb1/sb0)
|
||||||
|
const sbFormats = (info.formats || []).filter(f => f.format_id && f.format_id.startsWith('sb'));
|
||||||
|
const sb = sbFormats.find(f => f.format_id === 'sb3') ||
|
||||||
|
sbFormats.find(f => f.format_id === 'sb2') ||
|
||||||
|
sbFormats[sbFormats.length - 1];
|
||||||
|
|
||||||
|
let colors = [];
|
||||||
|
|
||||||
|
if (sb && (sb.url || (sb.fragments && sb.fragments[0]?.url))) {
|
||||||
|
const imgUrl = (sb.fragments && sb.fragments[0]?.url)
|
||||||
|
? sb.fragments[0].url
|
||||||
|
: sb.url.replace('$M', '0');
|
||||||
|
|
||||||
|
const tmpImg = path.join(os.tmpdir(), `sb_${videoId}_${Date.now()}.jpg`);
|
||||||
|
const tmpRgb = path.join(os.tmpdir(), `sb_${videoId}_${Date.now()}.rgb`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const curlProxyArgs = (cfg.main?.socks && cfg.main.socks !== 'undefined' && cfg.main.socks !== '')
|
||||||
|
? ['--proxy', cfg.main.socks.includes('://') ? cfg.main.socks : `socks5h://${cfg.main.socks}`]
|
||||||
|
: [];
|
||||||
|
await execFileAsync('curl', ['-s', '-L', imgUrl, '-o', tmpImg, ...curlProxyArgs], { timeout: 10000 });
|
||||||
|
await execFileAsync('magick', [tmpImg, '-scale', '10x10!', `rgb:${tmpRgb}`], { timeout: 5000 });
|
||||||
|
|
||||||
|
const buf = await fs.readFile(tmpRgb);
|
||||||
|
for (let i = 0; i < buf.length; i += 3) {
|
||||||
|
colors.push([buf[i], buf[i + 1], buf[i + 2]]);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
await fs.unlink(tmpImg).catch(() => {});
|
||||||
|
await fs.unlink(tmpRgb).catch(() => {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If storyboard wasn't available or yielded no colors, fallback to thumbnail sampling
|
||||||
|
if (!colors.length) {
|
||||||
|
// Fallback: download thumbnail and sample a 3x3 palette
|
||||||
|
const thumbUrl = `https://img.youtube.com/vi/${videoId}/hqdefault.jpg`;
|
||||||
|
const tmpImg = path.join(os.tmpdir(), `sb_thumb_${videoId}_${Date.now()}.jpg`);
|
||||||
|
const tmpRgb = path.join(os.tmpdir(), `sb_thumb_${videoId}_${Date.now()}.rgb`);
|
||||||
|
try {
|
||||||
|
await execFileAsync('curl', ['-s', '-L', thumbUrl, '-o', tmpImg], { timeout: 10000 });
|
||||||
|
await execFileAsync('magick', [tmpImg, '-scale', '3x3!', `rgb:${tmpRgb}`], { timeout: 5000 });
|
||||||
|
const buf = await fs.readFile(tmpRgb);
|
||||||
|
for (let i = 0; i < buf.length; i += 3) {
|
||||||
|
colors.push([buf[i], buf[i + 1], buf[i + 2]]);
|
||||||
|
}
|
||||||
|
} catch (_) {
|
||||||
|
// Minimal fallback
|
||||||
|
colors = [[30, 30, 35]];
|
||||||
|
} finally {
|
||||||
|
await fs.unlink(tmpImg).catch(() => {});
|
||||||
|
await fs.unlink(tmpRgb).catch(() => {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = {
|
||||||
|
videoId,
|
||||||
|
duration,
|
||||||
|
colors
|
||||||
|
};
|
||||||
|
|
||||||
|
// Cache to disk
|
||||||
|
try {
|
||||||
|
await fs.writeFile(cacheFile, JSON.stringify(result), 'utf8');
|
||||||
|
} catch (err) {
|
||||||
|
console.warn(`[AMBIENT] Failed to write cache for ${videoId}:`, err.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} finally {
|
||||||
|
pendingRequests.delete(videoId);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
pendingRequests.set(videoId, promise);
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default (router) => {
|
||||||
|
router.get(/^\/api\/v2\/ambient\/yt\/([a-zA-Z0-9_-]+)/, async (req, res) => {
|
||||||
|
const videoId = req.url.pathname.split('/')[5];
|
||||||
|
if (!videoId) {
|
||||||
|
return res.writeHead(400, { 'Content-Type': 'application/json' })
|
||||||
|
.end(JSON.stringify({ error: 'Missing video ID' }));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = await getOrExtractYoutubeAmbient(videoId);
|
||||||
|
return res.writeHead(200, {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Cache-Control': 'public, max-age=86400, stale-while-revalidate=604800'
|
||||||
|
}).end(JSON.stringify(data));
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`[AMBIENT ERROR] Failed for ${videoId}:`, err.message);
|
||||||
|
return res.writeHead(500, { 'Content-Type': 'application/json' })
|
||||||
|
.end(JSON.stringify({ error: err.message }));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return router;
|
||||||
|
};
|
||||||
@@ -1837,6 +1837,7 @@ process.on('uncaughtException', err => {
|
|||||||
nsfl_tag_id: cfg.nsfl_tag_id || 3,
|
nsfl_tag_id: cfg.nsfl_tag_id || 3,
|
||||||
scroller_mime_cats: Array.isArray(cfg.allowedMimes) ? cfg.allowedMimes.filter(c => ['video','image','audio'].includes(c)) : ['video','image','audio'],
|
scroller_mime_cats: Array.isArray(cfg.allowedMimes) ? cfg.allowedMimes.filter(c => ['video','image','audio'].includes(c)) : ['video','image','audio'],
|
||||||
themes_json: JSON.stringify(cfg.websrv.themes || []),
|
themes_json: JSON.stringify(cfg.websrv.themes || []),
|
||||||
|
audio_tuner_json: JSON.stringify(cfg.audio_tuner || cfg.audio_visualizer || cfg.websrv?.audio_tuner || null),
|
||||||
enable_profile_description: !!cfg.websrv.enable_profile_description,
|
enable_profile_description: !!cfg.websrv.enable_profile_description,
|
||||||
expose_repost_links_to_guests: !!(cfg.websrv.expose_repost_links_to_guests || cfg.websrv.expose_repost_links),
|
expose_repost_links_to_guests: !!(cfg.websrv.expose_repost_links_to_guests || cfg.websrv.expose_repost_links),
|
||||||
get private_messages() { return getPrivateMessages(); },
|
get private_messages() { return getPrivateMessages(); },
|
||||||
|
|||||||
+48
-12
@@ -255,9 +255,9 @@
|
|||||||
<div class="setting-item" style="margin-top: 15px; padding-left: 25px;">
|
<div class="setting-item" style="margin-top: 15px; padding-left: 25px;">
|
||||||
<div style="display: flex; align-items: center; justify-content: space-between; max-width: 380px;">
|
<div style="display: flex; align-items: center; justify-content: space-between; max-width: 380px;">
|
||||||
<label for="onara_bg_opacity_slider" style="font-size: 0.9em; margin-bottom: 0; font-weight: bold;">Onara Backdrop Darkness</label>
|
<label for="onara_bg_opacity_slider" style="font-size: 0.9em; margin-bottom: 0; font-weight: bold;">Onara Backdrop Darkness</label>
|
||||||
<span id="onara_bg_opacity_val" style="font-size: 0.85em; opacity: 0.8;">84%</span>
|
<span id="onara_bg_opacity_val" style="font-size: 0.85em; opacity: 0.8;">70%</span>
|
||||||
</div>
|
</div>
|
||||||
<input type="range" id="onara_bg_opacity_slider" min="0" max="1" step="0.01" value="0.84" style="max-width: 380px; width: 100%; margin-top: 4px;">
|
<input type="range" id="onara_bg_opacity_slider" min="0" max="1" step="0.01" value="0.70" style="max-width: 380px; width: 100%; margin-top: 4px;">
|
||||||
<small class="text-muted" style="display: block;">Overlay darkness in Onara mode (lower values allow background canvas to shine through).</small>
|
<small class="text-muted" style="display: block;">Overlay darkness in Onara mode (lower values allow background canvas to shine through).</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -273,9 +273,9 @@
|
|||||||
<div class="setting-item" style="margin-top: 15px; padding-left: 25px;">
|
<div class="setting-item" style="margin-top: 15px; padding-left: 25px;">
|
||||||
<div style="display: flex; align-items: center; justify-content: space-between; max-width: 380px;">
|
<div style="display: flex; align-items: center; justify-content: space-between; max-width: 380px;">
|
||||||
<label for="onara_grid_dim_slider" style="font-size: 0.9em; margin-bottom: 0; font-weight: bold;">Onara Background Grid Opacity</label>
|
<label for="onara_grid_dim_slider" style="font-size: 0.9em; margin-bottom: 0; font-weight: bold;">Onara Background Grid Opacity</label>
|
||||||
<span id="onara_grid_dim_val" style="font-size: 0.85em; opacity: 0.8;">15%</span>
|
<span id="onara_grid_dim_val" style="font-size: 0.85em; opacity: 0.8;">38%</span>
|
||||||
</div>
|
</div>
|
||||||
<input type="range" id="onara_grid_dim_slider" min="0" max="1" step="0.01" value="0.15" style="max-width: 380px; width: 100%; margin-top: 4px;">
|
<input type="range" id="onara_grid_dim_slider" min="0" max="1" step="0.01" value="0.38" style="max-width: 380px; width: 100%; margin-top: 4px;">
|
||||||
<small class="text-muted" style="display: block;">Control how clearly the background thumbnail grid shines through over the ambient canvas in Onara mode.</small>
|
<small class="text-muted" style="display: block;">Control how clearly the background thumbnail grid shines through over the ambient canvas in Onara mode.</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -290,20 +290,56 @@
|
|||||||
|
|
||||||
<div class="setting-item" style="margin-top: 15px; padding-left: 25px;">
|
<div class="setting-item" style="margin-top: 15px; padding-left: 25px;">
|
||||||
<div style="display: flex; align-items: center; justify-content: space-between; max-width: 380px;">
|
<div style="display: flex; align-items: center; justify-content: space-between; max-width: 380px;">
|
||||||
<label for="bg_canvas_blur_slider" style="font-size: 0.9em; margin-bottom: 0; font-weight: bold;">Background Canvas Blur</label>
|
<label for="bg_canvas_blur_slider" style="font-size: 0.9em; margin-bottom: 0; font-weight: bold;">Background Blur Radius</label>
|
||||||
<span id="bg_canvas_blur_val" style="font-size: 0.85em; opacity: 0.8;">300px</span>
|
<span id="bg_canvas_blur_val" style="font-size: 0.85em; opacity: 0.8;">30px</span>
|
||||||
</div>
|
</div>
|
||||||
<input type="range" id="bg_canvas_blur_slider" min="0" max="300" step="1" value="300" style="max-width: 380px; width: 100%; margin-top: 4px;">
|
<input type="range" id="bg_canvas_blur_slider" min="0" max="300" step="1" value="30" style="max-width: 380px; width: 100%; margin-top: 4px;">
|
||||||
<small class="text-muted" style="display: block;">Adjust the ambient blur of the background canvas (higher values create a soft, dreamy ambient glow).</small>
|
<small class="text-muted" style="display: block;">Adjust the ambient blur radius. Higher values = softer, dreamier glow. In GPU CSS mode this goes up to 300px at full resolution.</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-item" style="margin-top: 15px; padding-left: 25px;">
|
<div class="setting-item" style="margin-top: 15px; padding-left: 25px;">
|
||||||
<div style="display: flex; align-items: center; justify-content: space-between; max-width: 380px;">
|
<div style="display: flex; align-items: center; justify-content: space-between; max-width: 380px;">
|
||||||
<label for="bg_canvas_brightness_slider" style="font-size: 0.9em; margin-bottom: 0; font-weight: bold;">Background Brightness Boost</label>
|
<label for="bg_canvas_brightness_slider" style="font-size: 0.9em; margin-bottom: 0; font-weight: bold;">Background Brightness</label>
|
||||||
<span id="bg_canvas_brightness_val" style="font-size: 0.85em; opacity: 0.8;">100%</span>
|
<span id="bg_canvas_brightness_val" style="font-size: 0.85em; opacity: 0.8;">0.45x</span>
|
||||||
</div>
|
</div>
|
||||||
<input type="range" id="bg_canvas_brightness_slider" min="0.5" max="2.5" step="0.05" value="1.00" style="max-width: 380px; width: 100%; margin-top: 4px;">
|
<input type="range" id="bg_canvas_brightness_slider" min="0.1" max="3.0" step="0.05" value="0.45" style="max-width: 380px; width: 100%; margin-top: 4px;">
|
||||||
<small class="text-muted" style="display: block;">Boost background canvas brightness so visuals pop through clearly.</small>
|
<small class="text-muted" style="display: block;">Boost brightness so colors pop. Values < 1 darken, > 1 amplify.</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-item" style="margin-top: 15px; padding-left: 25px;">
|
||||||
|
<div style="display: flex; align-items: center; justify-content: space-between; max-width: 380px;">
|
||||||
|
<label for="bg_blur_method_slider" style="font-size: 0.9em; margin-bottom: 0; font-weight: bold;">Blur Engine</label>
|
||||||
|
<span id="bg_blur_method_val" style="font-size: 0.85em; opacity: 0.8;">Canvas 2D</span>
|
||||||
|
</div>
|
||||||
|
<input type="range" id="bg_blur_method_slider" min="0" max="2" step="1" value="0" style="max-width: 380px; width: 100%; margin-top: 4px;">
|
||||||
|
<small class="text-muted" style="display: block;"><strong>0 = Canvas 2D</strong> (downsampled, fast) | <strong>1 = GPU CSS Filter</strong> (classic look, full-res compositor blur like older versions) | <strong>2 = Hybrid</strong> (CSS blur + canvas color grading)</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-item" style="margin-top: 15px; padding-left: 25px;">
|
||||||
|
<div style="display: flex; align-items: center; justify-content: space-between; max-width: 380px;">
|
||||||
|
<label for="bg_canvas_saturate_slider" style="font-size: 0.9em; margin-bottom: 0; font-weight: bold;">Color Saturation</label>
|
||||||
|
<span id="bg_canvas_saturate_val" style="font-size: 0.85em; opacity: 0.8;">1.80x</span>
|
||||||
|
</div>
|
||||||
|
<input type="range" id="bg_canvas_saturate_slider" min="0.5" max="4.0" step="0.05" value="1.8" style="max-width: 380px; width: 100%; margin-top: 4px;">
|
||||||
|
<small class="text-muted" style="display: block;">Boost color saturation of the background. 1.0 = original, higher = more vivid / neon.</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-item" style="margin-top: 15px; padding-left: 25px;">
|
||||||
|
<div style="display: flex; align-items: center; justify-content: space-between; max-width: 380px;">
|
||||||
|
<label for="bg_canvas_contrast_slider" style="font-size: 0.9em; margin-bottom: 0; font-weight: bold;">Contrast Depth</label>
|
||||||
|
<span id="bg_canvas_contrast_val" style="font-size: 0.85em; opacity: 0.8;">1.10x</span>
|
||||||
|
</div>
|
||||||
|
<input type="range" id="bg_canvas_contrast_slider" min="0.5" max="3.0" step="0.05" value="1.1" style="max-width: 380px; width: 100%; margin-top: 4px;">
|
||||||
|
<small class="text-muted" style="display: block;">Contrast punch. Values > 1.0 darken blacks and pop highlights.</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-item" style="margin-top: 15px; padding-left: 25px;">
|
||||||
|
<div style="display: flex; align-items: center; justify-content: space-between; max-width: 380px;">
|
||||||
|
<label for="bg_canvas_zoom_slider" style="font-size: 0.9em; margin-bottom: 0; font-weight: bold;">Edge Overscan Zoom</label>
|
||||||
|
<span id="bg_canvas_zoom_val" style="font-size: 0.85em; opacity: 0.8;">1.12x</span>
|
||||||
|
</div>
|
||||||
|
<input type="range" id="bg_canvas_zoom_slider" min="1.0" max="1.8" step="0.01" value="1.12" style="max-width: 380px; width: 100%; margin-top: 4px;">
|
||||||
|
<small class="text-muted" style="display: block;">Zoom the background canvas slightly to hide blurry edge bleeding. 1.12 eliminates edge artifacts at typical blur values.</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-item" style="margin-top: 15px;">
|
<div class="setting-item" style="margin-top: 15px;">
|
||||||
|
|||||||
@@ -131,7 +131,7 @@
|
|||||||
<button type="button" class="sidebar-tab" id="sidebar-tab-tag" data-tab="tag" title="Tag Feed" aria-label="Tag Feed" style="display: none;">
|
<button type="button" class="sidebar-tab" id="sidebar-tab-tag" data-tab="tag" title="Tag Feed" aria-label="Tag Feed" style="display: none;">
|
||||||
<i class="fa-solid fa-hashtag"></i>
|
<i class="fa-solid fa-hashtag"></i>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="sidebar-tab" id="sidebar-tab-tuner" data-tab="tuner" title="Tuner & Debug (Audio & Danmaku)" aria-label="Tuner & Debug (Audio & Danmaku)">
|
<button type="button" class="sidebar-tab" id="sidebar-tab-tuner" data-tab="tuner" title="Tuner & Debug (Audio, Danmaku & Background)" aria-label="Tuner & Debug (Audio, Danmaku & Background)">
|
||||||
<i class="fa-solid fa-sliders"></i>
|
<i class="fa-solid fa-sliders"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -67,7 +67,7 @@
|
|||||||
@endif
|
@endif
|
||||||
<link rel="stylesheet" href="/s/css/upload.css?v={{ ts }}">
|
<link rel="stylesheet" href="/s/css/upload.css?v={{ ts }}">
|
||||||
@endif
|
@endif
|
||||||
<script>window.f0ckThemes = {{ themes_json }}; window.f0ckDefaultTheme = "{{ default_theme }}"; window.f0ckDefaultLayout = "{{ default_layout }}"; window.f0ckDomain = "{{ domain }}"; window.f0ckGitHash = "{{ git_hash }}"; window.f0ckAllowedImages = {{ allowed_comment_images_json }}; window.f0ckEmbedYoutubeInComments = {{ embed_youtube_in_comments ? 'true' : 'false' }}; window.f0ckEnableYoutubeUpload = {{ enable_youtube_upload ? 'true' : 'false' }}; window.f0ckBrandImages = {{ custom_brand_images_json }}; window.f0ckMediaBase = "{{ paths_images }}"; window.f0ckShitpostMode = {{ shitpost_mode ? 'true' : 'false' }}; window.f0ckShitpostRequireRating = {{ shitpost_require_rating ? 'true' : 'false' }}; window.f0ckShitpostMinTags = {{ shitpost_min_tags || 0 }}; window.f0ckEnableItemTitle = {{ enable_item_title ? 'true' : 'false' }}; window.f0ckCommentBannerEnabled = @if(comment_banner_enabled) true @else false @endif;</script>
|
<script>window.f0ckThemes = {{ themes_json }}; window.f0ckDefaultTheme = "{{ default_theme }}"; window.f0ckDefaultLayout = "{{ default_layout }}"; window.f0ckDomain = "{{ domain }}"; window.f0ckGitHash = "{{ git_hash }}"; window.f0ckAllowedImages = {{ allowed_comment_images_json }}; window.f0ckEmbedYoutubeInComments = {{ embed_youtube_in_comments ? 'true' : 'false' }}; window.f0ckEnableYoutubeUpload = {{ enable_youtube_upload ? 'true' : 'false' }}; window.f0ckBrandImages = {{ custom_brand_images_json }}; window.f0ckMediaBase = "{{ paths_images }}"; window.f0ckShitpostMode = {{ shitpost_mode ? 'true' : 'false' }}; window.f0ckShitpostRequireRating = {{ shitpost_require_rating ? 'true' : 'false' }}; window.f0ckShitpostMinTags = {{ shitpost_min_tags || 0 }}; window.f0ckEnableItemTitle = {{ enable_item_title ? 'true' : 'false' }}; window.f0ckCommentBannerEnabled = @if(comment_banner_enabled) true @else false @endif; window.f0ckServerAudioTuner = {{ audio_tuner_json || 'null' }};</script>
|
||||||
@if(!private_society || session)
|
@if(!private_society || session)
|
||||||
<script src="/s/js/marked.min.js" defer></script>
|
<script src="/s/js/marked.min.js" defer></script>
|
||||||
<script src="/s/js/comments.js?v={{ ts }}" defer></script>
|
<script src="/s/js/comments.js?v={{ ts }}" defer></script>
|
||||||
|
|||||||
@@ -59,7 +59,7 @@
|
|||||||
</div>
|
</div>
|
||||||
@elseif(item.mime === 'video/youtube')
|
@elseif(item.mime === 'video/youtube')
|
||||||
<div class="embed-responsive embed-responsive-16by9">
|
<div class="embed-responsive embed-responsive-16by9">
|
||||||
<iframe id="yt-embed" class="embed-responsive-item" width="640" height="360" src="https://www.youtube.com/embed/{!! item.dest.replace('yt:', '') !!}" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
|
<iframe id="yt-embed" class="embed-responsive-item" width="640" height="360" data-yt-id="{!! item.dest.replace('yt:', '') !!}" src="https://www.youtube.com/embed/{!! item.dest.replace('yt:', '') !!}?enablejsapi=1" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
|
||||||
</div>
|
</div>
|
||||||
@elseif(item.mime.startsWith("video"))
|
@elseif(item.mime.startsWith("video"))
|
||||||
<div class="embed-responsive embed-responsive-16by9">
|
<div class="embed-responsive embed-responsive-16by9">
|
||||||
|
|||||||
Reference in New Issue
Block a user