Skip to content

Commit 87315d6

Browse files
authored
Merge develop into master for v5.3.0 release
● ## v5.3.0 Release Merge develop into master for the first release since v5.2.10 (July 2025). ### New features - Name normalization (toggleable via settings) - Log history plugin (persists log tab across reloads) - Tracker Status column - OblivionBlue theme - Dual IPv4/IPv6 port checking - Option to hide trackers from panel - Icon alias system for tracker/label dedup - conf.local.php support for deployment-specific overrides - Right-align count/size in panels with separator ### Bug fixes - PHP 8.2+ deprecation fixes (cache.php, Torrent.php, rss.php, trafic) - GeoIP2/MaxMindDB rewrite (replaces deprecated GeoIP1 extension) - rtorrent 0.16.x compatibility (erasedata, convert.kb, deprecated command aliases) - httprpc trust model fix for rtorrent 0.16.8 - Explorer truncated file listing fix - DnD event handler leak fix - Theme race condition fix - Dialog header CSS fix for flex layout - RSS guid-based duplicate detection - Diskspace tooltip improvement - Directory picker sort fix - Right-align peers/seeds columns - Lookat plugin precedence bug fix - Check port graceful IPv6 handling - hideTrackers plugin load order fix - Various pt-BR translation fixes
2 parents 759e0e5 + 9f7f06d commit 87315d6

253 files changed

Lines changed: 2277 additions & 453 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ This project is released under the GPLv3 license, for more details, take a look
1818

1919
## Download
2020

21-
* [Development version](https://github.com/Novik/ruTorrent/tarball/master)
21+
* [Development version](https://github.com/Novik/ruTorrent/tarball/develop)
2222
* [Stable version](https://github.com/Novik/ruTorrent/releases)
2323

2424
## Getting started

conf/config.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,8 @@
8989
$enableCSRFCheck = false; // If true then Origin and Referer will be checked
9090
$enabledOrigins = array(); // List of enabled domains for CSRF check (only hostnames, without protocols, port etc.).
9191
// If empty, then will retrieve domain from HTTP_HOST / HTTP_X_FORWARDED_HOST
92+
93+
// Load local deployment overrides if present
94+
$configLocalPath = dirname(__FILE__)."/config.local.php";
95+
if(is_file($configLocalPath) && is_readable($configLocalPath))
96+
require($configLocalPath);

css/panel-label.css

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,17 @@ div {
4646

4747
[part="count"],
4848
[part="size"] {
49-
color: var(--badge-color);
5049
background-color: var(--badge-background-color);
5150
padding: var(--badge-padding, 0.1em 0.3em 0.1em 0.3em);
5251
border-radius: var(--badge-border-radius, 0.8em);
5352
white-space: pre;
5453
}
5554

55+
:not(:host([selected])) [part="count"],
56+
:not(:host([selected])) [part="size"] {
57+
color: var(--badge-color);
58+
}
59+
5660
[part="icon"] {
5761
min-width: var(--icon-size);
5862
min-height: var(--icon-size);

css/style.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ button:not(:disabled):active, input[type=button]:not(:disabled):active, a.Button
165165
a.dropdown-item {
166166
width: auto;
167167
}
168-
category-list.rightalign-labelsize panel-label::part(size) {
168+
category-list.rightalign-labelsize panel-label::part(count) {
169169
margin-left: auto;
170170
}
171171
category-list.hide-textoverflow panel-label::part(text) {

index.html

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -21,27 +21,27 @@
2121
<meta name="msapplication-TileColor" content="#FFFFFF" />
2222
<meta name="msapplication-TileImage" content="./images/mstile-144x144.png" />
2323

24-
<link href="./css/bootstrap.min.css?v=5210" rel="stylesheet" type="text/css" />
25-
<link href="./css/style.css?v=5210" rel="stylesheet" type="text/css" />
26-
<link href="./css/stable.css?v=5210" rel="stylesheet" type="text/css" />
27-
<link rel="preload" as="style" href="./css/category-panel.css?v=5210" />
28-
<link rel="preload" as="style" href="./css/panel-label.css?v=5210" />
29-
<script type="text/javascript" src="./js/jquery.js?v=5210"></script>
30-
<script type="text/javascript" src="./js/jquery.flot.js?v=5210"></script>
31-
<script type="text/javascript" src="./js/sanitize.js?v=5210"></script>
32-
<script type="text/javascript" src="./js/sanitize.config.js?v=5210"></script>
33-
<script type="text/javascript" src="./js/custom-elements.js?v=5210"></script>
34-
<script type="text/javascript" src="./lang/langs.js?v=5210"></script>
35-
<link rel="preload" as="script" href="./js/browser.js?v=5210" />
36-
<link rel="preload" as="script" href="./js/common.js?v=5210" />
37-
<link rel="preload" as="script" href="./js/objects.js?v=5210" />
38-
<link rel="preload" as="script" href="./js/options.js?v=5210" />
39-
<link rel="preload" as="script" href="./js/content.js?v=5210" />
40-
<link rel="preload" as="script" href="./js/stable.js?v=5210" />
41-
<link rel="preload" as="script" href="./js/graph.js?v=5210" />
42-
<link rel="preload" as="script" href="./js/plugins.js?v=5210" />
43-
<link rel="preload" as="script" href="./js/rtorrent.js?v=5210" />
44-
<link rel="preload" as="script" href="./js/webui.js?v=5210" />
24+
<link href="./css/bootstrap.min.css?v=530" rel="stylesheet" type="text/css" />
25+
<link href="./css/style.css?v=530" rel="stylesheet" type="text/css" />
26+
<link href="./css/stable.css?v=530" rel="stylesheet" type="text/css" />
27+
<link rel="preload" as="style" href="./css/category-panel.css?v=530" />
28+
<link rel="preload" as="style" href="./css/panel-label.css?v=530" />
29+
<script type="text/javascript" src="./js/jquery.js?v=530"></script>
30+
<script type="text/javascript" src="./js/jquery.flot.js?v=530"></script>
31+
<script type="text/javascript" src="./js/sanitize.js?v=530"></script>
32+
<script type="text/javascript" src="./js/sanitize.config.js?v=530"></script>
33+
<script type="text/javascript" src="./js/custom-elements.js?v=530"></script>
34+
<script type="text/javascript" src="./lang/langs.js?v=530"></script>
35+
<link rel="preload" as="script" href="./js/browser.js?v=530" />
36+
<link rel="preload" as="script" href="./js/common.js?v=530" />
37+
<link rel="preload" as="script" href="./js/objects.js?v=530" />
38+
<link rel="preload" as="script" href="./js/options.js?v=530" />
39+
<link rel="preload" as="script" href="./js/content.js?v=530" />
40+
<link rel="preload" as="script" href="./js/stable.js?v=530" />
41+
<link rel="preload" as="script" href="./js/graph.js?v=530" />
42+
<link rel="preload" as="script" href="./js/plugins.js?v=530" />
43+
<link rel="preload" as="script" href="./js/rtorrent.js?v=530" />
44+
<link rel="preload" as="script" href="./js/webui.js?v=530" />
4545

4646
<script>
4747
loadUILang(() => {
@@ -57,10 +57,10 @@
5757
});
5858
</script>
5959

60-
<script type="module" src="./js/backgroundtask.js?v=5210"></script>
61-
<script type="module" src="./js/category-list.js?v=5210"></script>
62-
<script type="module" src="./js/panel.js?v=5210"></script>
63-
<script type="text/javascript" src="./js/category-list-elements.js?v=5210" defer></script>
60+
<script type="module" src="./js/backgroundtask.js?v=530"></script>
61+
<script type="module" src="./js/category-list.js?v=530"></script>
62+
<script type="module" src="./js/panel.js?v=530"></script>
63+
<script type="text/javascript" src="./js/category-list-elements.js?v=530" defer></script>
6464
</head>
6565
<body>
6666
<div id="preload" class="d-none"></div>
@@ -139,15 +139,16 @@ <h4 class="offcanvas-title" id="offcanvas-sidepanel-label"></h4>
139139
</div>
140140
<div class="p-1 p-md-0 offcanvas-body">
141141
<template id="panel-label-template">
142-
<link href="./css/panel-label.css?v=5210" rel="stylesheet" type="text/css" />
142+
<link href="./css/panel-label.css?v=530" rel="stylesheet" type="text/css" />
143143
<div part="prefix" hidden></div>
144144
<div part="icon"></div>
145145
<div part="text"></div>
146146
<div part="count">0</div>
147+
<div part="separator">/</div>
147148
<div part="size" style="display: none;"></div>
148149
</template>
149150
<template id="category-panel-template">
150-
<link href="./css/category-panel.css?v=5210" rel="stylesheet" type="text/css" />
151+
<link href="./css/category-panel.css?v=530" rel="stylesheet" type="text/css" />
151152
<div part="heading">
152153
<span class="text"></span><slot name="decorator" class="decorator"></slot>
153154
</div>
@@ -303,6 +304,6 @@ <h4 class="offcanvas-title" id="offcanvas-sidepanel-label"></h4>
303304
<div class="graph_tab_legend"></div>
304305
<div id="dialog-container"></div>
305306
<div id="dir-container"></div>
306-
<script type="text/javascript" src="./js/bootstrap.bundle.min.js?v=5210"></script>
307+
<script type="text/javascript" src="./js/bootstrap.bundle.min.js?v=530"></script>
307308
</body>
308309
</html>

js/category-list-elements.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ customElements.define(
3030
"panel-label",
3131
class extends CustomHTMLElement {
3232
static template = document.getElementById("panel-label-template");
33-
static stringAttributeNames = ["prefix", "icon", "text", "count", "size"];
33+
static stringAttributeNames = ["prefix", "icon", "text", "count", "separator", "size"];
3434
static booleanAttributeNames = ["selected"];
3535
static attributeChangeCallbacks = {
3636
prefix: function (_, newValue) {
@@ -78,6 +78,7 @@ customElements.define(
7878
},
7979
size: function (_, newValue) {
8080
this._hideOrSetText(this.parts.size, newValue);
81+
this._hideOrSetText(this.parts.separator, newValue, true);
8182
},
8283
count: function (_, newValue) {
8384
this._hideOrSetText(this.parts.count, newValue);
@@ -91,10 +92,12 @@ customElements.define(
9192
this.customDefineAttributes();
9293
}
9394

94-
_hideOrSetText(el, newValue) {
95+
_hideOrSetText(el, newValue, skipText = null) {
9596
if (newValue != null) {
9697
el.style.display = "block";
97-
el.textContent = newValue;
98+
if (!skipText) {
99+
el.textContent = newValue;
100+
}
98101
} else {
99102
el.style.display = "none";
100103
}

js/common.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,70 @@ var theConverter =
462462
}
463463
};
464464

465+
var theNormalizer = {
466+
encloses: ['[]', '{}', '()'],
467+
getLabel(s) {
468+
let res;
469+
if (s !== null) {
470+
for (const enclose of this.encloses) {
471+
const o = enclose.substr(0, 1);
472+
const c = enclose.substr(1, 1);
473+
const re = new RegExp(`^\\${o}(.*?)\\${c}`, 'i');
474+
const matches = re.exec(s);
475+
if (matches) {
476+
res = [matches[1], s.substr(matches[0].length)];
477+
break;
478+
}
479+
}
480+
}
481+
return res;
482+
},
483+
clean(s, sortable = true) {
484+
if (s !== null && s.length) {
485+
if (sortable) {
486+
// replace dot, underscore, and dash with whitespace
487+
// replace multiple whitespace with single whitespace
488+
s = s
489+
.replace(/(\.|_|\-)/g, ' ')
490+
.replace(/\s{2,}/g, ' ');
491+
} else {
492+
s = s
493+
.replace(/^(\.|_|\-)/g, ' ')
494+
.replace(/(\.|_|\-)$/g, ' ');
495+
}
496+
s = s.trim();
497+
}
498+
return s;
499+
},
500+
normalize(s, sortable = true) {
501+
if (s !== null) {
502+
// get label
503+
const label = this.getLabel(s);
504+
if (label) {
505+
s = label[1];
506+
}
507+
s = this.clean(s, sortable);
508+
if (sortable) {
509+
// ignore 'the' in the beginning text
510+
if (s.length && s.toLowerCase().substr(0, 3) === 'the') {
511+
s = s
512+
.substr(3)
513+
.trim();
514+
}
515+
}
516+
// append label if necessary
517+
if (s.length && label) {
518+
s += ` \`${label[0]}\``;
519+
}
520+
// treat label as string
521+
if (s.length === 0 && label) {
522+
s = label[0];
523+
}
524+
}
525+
return s;
526+
}
527+
}
528+
465529
var theFormatter =
466530
{
467531
torrents: function(table,arr)
@@ -473,6 +537,11 @@ var theFormatter =
473537
else
474538
switch(iv(i))
475539
{
540+
case 0:
541+
if (theWebUI.settings["webui.normalize_torrent_name"]) {
542+
arr[i] = theNormalizer.normalize(arr[i], false);
543+
}
544+
break;
476545
case 3:
477546
arr[i] = (arr[i] / 10) + "%";
478547
break;

js/content.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,27 @@ function correctContent()
851851
"load" : { name: "load.normal", prm: 1 }
852852
});
853853
}
854+
if(theWebUI.systemInfo.rTorrent.iVersion>=0x1002)
855+
{
856+
$.extend(theRequestManager.aliases,
857+
{
858+
"dht" : { name: "dht.mode.set", prm: 1 },
859+
"throttle.max_uploads.div" : { name: "throttle.max_uploads.div._val", prm: 1 },
860+
"throttle.max_uploads.global" : { name: "throttle.max_uploads.global._val", prm: 1 },
861+
"throttle.max_downloads.div" : { name: "throttle.max_downloads.div._val", prm: 1 },
862+
"throttle.max_downloads.global" : { name: "throttle.max_downloads.global._val", prm: 1 },
863+
"ratio.enable" : { name: "group.seeding.ratio.enable", prm: 1 },
864+
"ratio.disable" : { name: "group.seeding.ratio.disable", prm: 1 },
865+
"ratio.min" : { name: "group2.seeding.ratio.min", prm: 0 },
866+
"ratio.max" : { name: "group2.seeding.ratio.max", prm: 0 },
867+
"ratio.upload" : { name: "group2.seeding.ratio.upload", prm: 0 },
868+
"ratio.min.set" : { name: "group2.seeding.ratio.min.set", prm: 1 },
869+
"ratio.max.set" : { name: "group2.seeding.ratio.max.set", prm: 1 },
870+
"ratio.upload.set" : { name: "group2.seeding.ratio.upload.set", prm: 1 },
871+
"connection_leech" : { name: "protocol.connection.leech.set", prm: 1 },
872+
"connection_seed" : { name: "protocol.connection.seed.set", prm: 1 },
873+
});
874+
}
854875
if(theWebUI.systemInfo.rTorrent.iVersion < 0x907) {
855876
const title = theUILang.requiresAtLeastRtorrent.replace('{version}', 'v0.9.7');
856877
$($$('webui.show_open_status')).attr({ disabled: '', title });

js/objects.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ class DnD {
8181
finish(e) {
8282
$("body").css({cursor:""});
8383
const self = e.data;
84-
self.options.onFinish(e);
84+
try { self.options.onFinish(e); } catch(err) { console.error("DnD onFinish error:", err); }
8585
$(document).off("mousemove", self.run);
8686
$(document).off("mouseup", self.finish);
8787
return false;

js/options.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@ const theOptionsWindow = {
3333
['webui.selected_labels.keep', theUILang.KeepSelectedLabels],
3434
['webui.effects', theUILang.UIEffects],
3535
['webui.speedintitle', theUILang.showSpeedInTitle],
36+
['webui.normalize_torrent_name', theUILang.normalizeTorrentName],
3637
].map(([id, label]) => $("<div>").addClass("col-md-6").append(
3738
$("<input>").attr({type: "checkbox", id: id}),
3839
$("<label>").attr({for: id}).text(label),
3940
)),
41+
$("<div>").addClass("col-md-6"),
4042
...[
4143
["webui.update_interval", theUILang.Update_GUI_every + ": ", theUILang.ms, 3000],
4244
["webui.reqtimeout", theUILang.ReqTimeout + ": ", theUILang.ms, 5000],

0 commit comments

Comments
 (0)