From 6694998985e98326ca4ca0a0724cfd4901be2430 Mon Sep 17 00:00:00 2001
From: exci <76759714+icxes@users.noreply.github.com>
Date: Tue, 3 Feb 2026 00:45:17 +0200
Subject: [PATCH] audioplayer: add skip-silence feature (#1265)
* add skip silence option
---
copyparty/web/browser.css | 6 +-
copyparty/web/browser.js | 164 +++++++++++++++++++++++++++++++++++++-
2 files changed, 167 insertions(+), 3 deletions(-)
diff --git a/copyparty/web/browser.css b/copyparty/web/browser.css
index aa2e1fba..e2e9173a 100644
--- a/copyparty/web/browser.css
+++ b/copyparty/web/browser.css
@@ -1456,7 +1456,8 @@ html.dz input {
width: calc(100% - 16.2em);
}
input.drc_v,
-input.eq_gain {
+input.eq_gain,
+input.ssconf_v {
width: 3em;
text-align: center;
margin: 0 .6em;
@@ -1466,7 +1467,8 @@ input.eq_gain {
border-collapse: collapse;
}
#audio_drc td,
-#audio_eq td {
+#audio_eq td,
+#audio_ss td {
text-align: center;
}
#audio_eq a.eq_step {
diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js
index 70c62356..eb6d2a65 100644
--- a/copyparty/web/browser.js
+++ b/copyparty/web/browser.js
@@ -290,6 +290,7 @@ if (1)
"ml_tint": "tint",
"ml_eq": "audio equalizer",
"ml_drc": "dynamic range compressor",
+ "ml_ss": "skip silence",
"mt_loop": "loop/repeat one song\">🔁",
"mt_one": "stop after one song\">1️⃣",
@@ -326,7 +327,13 @@ if (1)
"mt_xowa": "there are bugs in iOS preventing background playback using this format; please use caf or mp3 instead",
"mt_tint": "background level (0-100) on the seekbar$Nto make buffering less distracting",
"mt_eq": "enables the equalizer and gain control;$N$Nboost <code>0</code> = standard 100% volume (unmodified)$N$Nwidth <code>1 </code> = standard stereo (unmodified)$Nwidth <code>0.5</code> = 50% left-right crossfeed$Nwidth <code>0 </code> = mono$N$Nboost <code>-0.8</code> & width <code>10</code> = vocal removal :^)$N$Nenabling the equalizer makes gapless albums fully gapless, so leave it on with all the values at zero (except width = 1) if you care about that",
- "mt_drc": "enables the dynamic range compressor (volume flattener / brickwaller); will also enable EQ to balance the spaghetti, so set all EQ fields except for 'width' to 0 if you don't want it$N$Nlowers the volume of audio above THRESHOLD dB; for every RATIO dB past THRESHOLD there is 1 dB of output, so default values of tresh -24 and ratio 12 means it should never get louder than -22 dB and it is safe to increase the equalizer boost to 0.8, or even 1.8 with ATK 0 and a huge RLS like 90 (only works in firefox; RLS is max 1 in other browsers)$N$N(see wikipedia, they explain it much better)",
+ "mt_drc": "enables the dynamic range compressor (volume flattener / brickwaller); will also enable EQ to balance the spaghetti, so set all EQ fields except for 'width' to 0 if you don't want it$N$Nlowers the volume of audio above THRESHOLD dB; for every RATIO dB past THRESHOLD there is 1 dB of output, so default values of 'tresh' -24 and 'ratio' 12 means it should never get louder than -22 dB and it is safe to increase the equalizer boost to 0.8, or even 1.8 with ATK 0 and a huge RLS like 90 (only works in firefox; RLS is max 1 in other browsers)$N$N(see wikipedia, they explain it much better)",
+ "mt_ss": "enables skip silence; multiplies playback speed by <code>sspeed</code>$Nat the start/end of audio tracks when volume is under <code>vthresh</code>$Nand the track is within 0 to <code>sthresh</code>% of the start$Nor <code>100-ethresh</code> to 100% of the end of the track",
+ "mt_ssvt": "skip silence volume threshold (0-255)",
+ "mt_ssts": "skip silence active threshold (% of track, start)",
+ "mt_sste": "skip silence active threshold (% of track, end)",
+ "mt_ssrt": "skip silence volume/speed ramp up/down time",
+ "mt_sssm": "skip silence playback speed multiplier",
"mb_play": "play",
"mm_hashplay": "play this audio file?",
@@ -1313,6 +1320,7 @@ var mpl = (function () {
'
' + L.ml_drc + '
' +
'
' + L.ml_eq + '
' +
+ '
' + L.ml_ss + '
' +
'');
var r = {
@@ -2583,6 +2591,8 @@ var mpui = (function () {
// occasionally draw buffered regions
if (nth % 5 == 0)
pbar.drawbuf();
+
+ if (!IE && afilt.ssen) skipSilence();
}
// preload next song
@@ -2690,11 +2700,15 @@ var afilt = (function () {
var r = {
"eqen": false,
"drcen": false,
+ "ssen": false,
"bands": [31.25, 62.5, 125, 250, 500, 1000, 2000, 4000, 8000, 16000],
"gains": [4, 3, 2, 1, 0, 0, 1, 2, 3, 4],
"drcv": [-24, 30, 12, 0.01, 0.25],
"drch": ['tresh', 'knee', 'ratio', 'atk', 'rls'],
"drck": ['threshold', 'knee', 'ratio', 'attack', 'release'],
+ "sscl": ['vthresh', "sthresh", "ethresh", 'sspeed', 'rspeed'],
+ "sstt": [L.mt_ssvt, L.mt_ssts, L.mt_sste, L.mt_ssrt, L.mt_sssm],
+ "sscv": [1, 5, 5, 5.0, 0.2],
"drcn": null,
"filters": [],
"filterskip": [],
@@ -2769,6 +2783,7 @@ var afilt = (function () {
r.gains = gains;
r.drcv = jread('au_drcv', r.drcv);
+ r.sscv = jread('au_sscv', r.sscv);
}
catch (ex) { }
@@ -2998,6 +3013,28 @@ var afilt = (function () {
clmod(this, 'err', err);
}
+ function adj_ss() {
+ var err = false;
+ try {
+ var n = this.getAttribute('k'),
+ ov = r.sscv[n],
+ vs = this.value,
+ v = parseFloat(vs);
+ if (!isNum(v) || v + '' != vs)
+ throw new Error('inval v');
+
+ if (v == ov)
+ return;
+
+ r.sscv[n] = v;
+ jwrite('au_sscv', r.sscv);
+ }
+ catch (ex) {
+ err = true;
+ }
+ clmod(this, 'err', err);
+ }
+
function eq_mod(e) {
ev(e);
adj_band(this, 0);
@@ -3057,6 +3094,19 @@ var afilt = (function () {
html += h2.join('\n') + '