luci-app-adblock: sync with adblock 4.5.1-3
authorDirk Brenken <redacted>
Fri, 20 Feb 2026 19:25:37 +0000 (20:25 +0100)
committerDirk Brenken <redacted>
Fri, 20 Feb 2026 19:25:53 +0000 (20:25 +0100)
Signed-off-by: Dirk Brenken <redacted>
applications/luci-app-adblock/Makefile
applications/luci-app-adblock/htdocs/luci-static/resources/view/adblock/overview.js

index 256a2be95551bbd68c23f82d91f5e00fffe02cfc..8bfe9cddd6b6cb80875057c49f0427fb95938a65 100644 (file)
@@ -7,7 +7,7 @@ LUCI_TITLE:=LuCI support for Adblock
 LUCI_DEPENDS:=+luci-base +luci-lib-uqr +adblock
 
 PKG_VERSION:=4.5.1
-PKG_RELEASE:=1
+PKG_RELEASE:=3
 PKG_LICENSE:=Apache-2.0
 PKG_MAINTAINER:=Dirk Brenken <dev@brenken.org>
 
index 3d7e3f2d16881d415a48a21deef72a84dec3f447..30aec433f50fd24639792c416d5b80579b64d436 100644 (file)
@@ -13,8 +13,9 @@
        button handling
 */
 function handleAction(ev) {
+       const status = document.getElementById('status');
+       const map = document.querySelector('.cbi-map');
        if (ev === 'restart' || ev === 'reload') {
-               const map = document.querySelector('.cbi-map');
                return dom.callClassMethod(map, 'save')
                        .then(L.bind(ui.changes.apply, ui.changes))
                        .then(function () {
@@ -30,8 +31,7 @@ function handleAction(ev) {
                                btn.disabled = true;
                                btn.blur();
                        });
-                       if (document.getElementById('status') &&
-                               document.getElementById('status').textContent.substring(0, 6) === 'paused') {
+                       if (status && status.textContent.startsWith('paused')) {
                                ev = 'resume';
                        }
                }
@@ -45,15 +45,25 @@ return view.extend({
                        L.resolveDefault(fs.read_direct('/etc/adblock/adblock.custom.feeds'), ''),
                        L.resolveDefault(fs.read_direct('/etc/adblock/adblock.feeds'), ''),
                        L.resolveDefault(fs.read_direct('/etc/adblock/adblock.categories'), ''),
-                       uci.load('adblock'),
+                       uci.load('adblock').catch(() => 0),
                        `https://${window.location.hostname}/cgi-bin/adblock`
                ]);
        },
        render: function (result) {
-               let m, s, o;
+               /*
+                       config check
+               */
+               if (!result[3] || result[3].length === 0) {
+                       ui.addNotification(null, E('p', _('No adblock config found!')), 'error');
+                       return;
+               }
 
+               /*
+                       main map
+               */
+               let m, s, o;
                m = new form.Map('adblock', 'Adblock', _('Configuration of the adblock package to block ad/abuse domains by using DNS. \
-                       For further information %s'.format(`<a style="color:#37c;font-weight:bold;" href="https://github.com/openwrt/packages/blob/master/net/adblock/files/README.md" target="_blank" rel="noreferrer noopener" >${_('check the online documentation')}</a>`)));
+                       For further information please check the %s.'.format(`<a style="color:#37c;font-weight:bold;" href="https://github.com/openwrt/packages/blob/master/net/adblock/files/README.md" target="_blank" rel="noreferrer noopener" >${_('online documentation')}</a>`)));
 
                /*
                        set text content helper function
@@ -68,15 +78,16 @@ return view.extend({
                /*
                        poll runtime information
                */
-               pollData: poll.add(function () {
-                       return L.resolveDefault(fs.read_direct('/var/run/adb_runtime.json'), 'null').then(function (res) {
+               poll.add(function () {
+                       return L.resolveDefault(fs.read_direct('/var/run/adb_runtime.json'), null).then(function (res) {
                                const status = document.getElementById('status');
                                const buttons = document.querySelectorAll('.cbi-page-actions button');
+                               let info = null;
                                try {
-                                       var info = JSON.parse(res);
+                                       info = JSON.parse(res);
                                } catch (e) {
+                                       info = null;
                                        status.textContent = '-';
-                                       poll.stop();
                                        if (status.classList.contains('spinning')) {
                                                buttons.forEach(function (btn) {
                                                        btn.disabled = false;
@@ -84,6 +95,7 @@ return view.extend({
                                                status.classList.remove('spinning');
                                        }
                                        ui.addNotification(null, E('p', _('Unable to parse the runtime information!')), 'error');
+                                       return;
                                }
                                if (status && info) {
                                        status.textContent = `${info.adblock_status || '-'} (frontend: ${info.frontend_ver || '-'} / backend: ${info.backend_ver || '-'})`;
@@ -102,27 +114,18 @@ return view.extend({
                                                        })
                                                        status.classList.remove("spinning");
                                                        if (document.getElementById('btn_suspend')) {
-                                                               if (status.textContent.substring(0, 6) === 'paused') {
+                                                               if (info.adblock_status === 'paused') {
                                                                        document.querySelector('#btn_suspend').textContent = 'Resume';
                                                                }
-                                                               if (document.getElementById('status').textContent.substring(0, 7) === 'enabled') {
+                                                               if (info.adblock_status === 'enabled') {
                                                                        document.querySelector('#btn_suspend').textContent = 'Suspend';
                                                                }
                                                        }
                                                }
                                        }
-                                       if (status.textContent.substring(0, 6) === 'paused' && document.getElementById('btn_suspend')) {
+                                       if (info.adblock_status === 'paused' && document.getElementById('btn_suspend')) {
                                                document.querySelector('#btn_suspend').textContent = 'Resume';
                                        }
-                               } else if (status) {
-                                       status.textContent = '-';
-                                       poll.stop();
-                                       if (status.classList.contains('spinning')) {
-                                               buttons.forEach(function (btn) {
-                                                       btn.disabled = false;
-                                               })
-                                               status.classList.remove('spinning');
-                                       }
                                }
                                if (info) {
                                        setText('domains', info.blocked_domains);
@@ -182,7 +185,6 @@ return view.extend({
                                ])
                        ]);
                }, o, this);
-               this.pollData;
 
                /*
                        tabbed config section
@@ -302,7 +304,7 @@ return view.extend({
 
                o = s.taboption('firewall', form.Flag, 'adb_nftallow', _('Enable Unfiltered DNS Routing'), _('Routes selected MACs or interfaces to an unfiltered external DNS resolver, bypassing local adblock.'));
                o.rmempty = false;
-               
+
                o = s.taboption('firewall', form.DynamicList, 'adb_nftmacallow', _('MAC DNS Filter Targets'), _('Devices with listed MAC addresses will always use the configured unfiltered DNS server.'));
                o.depends('adb_nftallow', '1');
                o.datatype = 'macaddr';
@@ -606,23 +608,24 @@ return view.extend({
                /*
                        feed selection tab
                */
-               let feed, feeds, chain, descr;
-               if (result && Object.keys(result).length) {
-                       if (result[0]) {
-                               try {
-                                       feeds = JSON.parse(result[0]);
-                               } catch (e) {
-                                       ui.addNotification(null, E('p', _('Unable to parse the custom feed file!')), 'error');
-                               }
+               let feed, chain, descr;
+               let feeds = null;
+
+               if (result[0] && result[0].trim() !== "") {
+                       try {
+                               feeds = JSON.parse(result[0]);
+                       } catch (e) {
+                               ui.addNotification(null, E('p', _('Unable to parse the custom feed file!')), 'error');
                        }
-                       if (result[1] && (!feeds || (feeds && !Object.keys(feeds).length))) {
-                               try {
-                                       feeds = JSON.parse(result[1]);
-                               } catch (e) {
-                                       ui.addNotification(null, E('p', _('Unable to parse the default feed file!')), 'error');
-                               }
+               }
+               if (!feeds && result[1] && result[1].trim() !== "") {
+                       try {
+                               feeds = JSON.parse(result[1]);
+                       } catch (e) {
+                               ui.addNotification(null, E('p', _('Unable to parse the default feed file!')), 'error');
                        }
                }
+
                o = s.taboption('feeds', form.DummyValue, '_sub');
                o.rawhtml = true;
                o.default = '<em style="color:#37c;font-weight:bold;">' + _('Changes on this tab needs an adblock service reload to take effect.') + '</em>'
@@ -633,8 +636,8 @@ return view.extend({
                        o = s.taboption('feeds', form.MultiValue, 'adb_feed', _('Blocklist Feed'));
                        for (let i = 0; i < Object.keys(feeds).length; i++) {
                                feed = Object.keys(feeds)[i].trim();
-                               chain = feeds[feed].size.trim() || 'in';
-                               descr = feeds[feed].descr.trim() || '-';
+                               chain = feeds[feed].size?.trim() || 'in';
+                               descr = feeds[feed].descr?.trim() || '-';
                                o.value(feed, feed + ' (' + chain + ', ' + descr + ')');
                        }
                        o.optional = true;
@@ -651,14 +654,19 @@ return view.extend({
 
                o = s.taboption('feeds', form.DummyValue, '_sub');
                o.rawhtml = true;
-               o.default = '<hr style="width: 200px; height: 1px;" /><em style="color:#37c;font-weight:bold;">' + _('UTCapitole Archive Selection') + '</em>';
+               o.default = '<hr style="width: 200px; height: 1px;" /><em style="color:#37c;font-weight:bold;">' + _('1Hosts List Selection') + '</em>';
 
-               o = s.taboption('feeds', form.DynamicList, 'adb_utc_feed', _('Categories'));
-               for (var i = 0; i < categories.length; i++) {
-                       code = categories[i].match(/^(\w+);/)[1].trim();
-                       if (code === 'utc') {
-                               category = categories[i].match(/^\w+;(.*$)/)[1].trim();
-                               o.value(category);
+               o = s.taboption('feeds', form.DynamicList, 'adb_hst_feed', _('Categories'));
+               for (let i = 0; i < categories.length; i++) {
+                       const cat = categories[i].match(/^(\w+);(.*?);(.*)$/);
+                       if (!cat) continue;
+
+                       const code = cat[1].trim();
+                       const list = cat[2].trim();
+                       const path = cat[3].trim();
+
+                       if (code === 'hst') {
+                               o.value(path, list);
                        }
                }
                o.optional = true;
@@ -666,14 +674,18 @@ return view.extend({
 
                o = s.taboption('feeds', form.DummyValue, '_sub');
                o.rawhtml = true;
-               o.default = '<hr style="width: 200px; height: 1px;" /><em style="color:#37c;font-weight:bold;">' + _('StevenBlack List Selection') + '</em>';
+               o.default = '<hr style="width: 200px; height: 1px;" /><em style="color:#37c;font-weight:bold;">' + _('Hagezi List Selection') + '</em>';
 
-               o = s.taboption('feeds', form.DynamicList, 'adb_stb_feed', _('Categories'));
-               for (var i = 0; i < categories.length; i++) {
-                       code = categories[i].match(/^(\w+);/)[1].trim();
-                       if (code === 'stb') {
-                               list = categories[i].match(/^\w+;(.*);/)[1].trim();
-                               path = categories[i].match(/^.*;(.*$)/)[1].trim();
+               o = s.taboption('feeds', form.DynamicList, 'adb_hag_feed', _('Categories'));
+               for (let i = 0; i < categories.length; i++) {
+                       const cat = categories[i].match(/^(\w+);(.*?);(.*)$/);
+                       if (!cat) continue;
+
+                       const code = cat[1].trim();
+                       const list = cat[2].trim();
+                       const path = cat[3].trim();
+
+                       if (code === 'hag') {
                                o.value(path, list);
                        }
                }
@@ -682,14 +694,18 @@ return view.extend({
 
                o = s.taboption('feeds', form.DummyValue, '_sub');
                o.rawhtml = true;
-               o.default = '<hr style="width: 200px; height: 1px;" /><em style="color:#37c;font-weight:bold;">' + _('Hagezi List Selection') + '</em>';
+               o.default = '<hr style="width: 200px; height: 1px;" /><em style="color:#37c;font-weight:bold;">' + _('IPFire List Selection') + '</em>';
 
-               o = s.taboption('feeds', form.DynamicList, 'adb_hag_feed', _('Categories'));
-               for (var i = 0; i < categories.length; i++) {
-                       code = categories[i].match(/^(\w+);/)[1].trim();
-                       if (code === 'hag') {
-                               list = categories[i].match(/^\w+;(.*);/)[1].trim();
-                               path = categories[i].match(/^.*;(.*$)/)[1].trim();
+               o = s.taboption('feeds', form.DynamicList, 'adb_ipf_feed', _('Categories'));
+               for (let i = 0; i < categories.length; i++) {
+                       const cat = categories[i].match(/^(\w+);(.*?);(.*)$/);
+                       if (!cat) continue;
+
+                       const code = cat[1].trim();
+                       const list = cat[2].trim();
+                       const path = cat[3].trim();
+
+                       if (code === 'ipf') {
                                o.value(path, list);
                        }
                }
@@ -698,20 +714,46 @@ return view.extend({
 
                o = s.taboption('feeds', form.DummyValue, '_sub');
                o.rawhtml = true;
-               o.default = '<hr style="width: 200px; height: 1px;" /><em style="color:#37c;font-weight:bold;">' + _('1Hosts List Selection') + '</em>';
+               o.default = '<hr style="width: 200px; height: 1px;" /><em style="color:#37c;font-weight:bold;">' + _('StevenBlack List Selection') + '</em>';
 
-               o = s.taboption('feeds', form.DynamicList, 'adb_hst_feed', _('Categories'));
-               for (var i = 0; i < categories.length; i++) {
-                       code = categories[i].match(/^(\w+);/)[1].trim();
-                       if (code === 'hst') {
-                               list = categories[i].match(/^\w+;(.*);/)[1].trim();
-                               path = categories[i].match(/^.*;(.*$)/)[1].trim();
+               o = s.taboption('feeds', form.DynamicList, 'adb_stb_feed', _('Categories'));
+               for (let i = 0; i < categories.length; i++) {
+                       const cat = categories[i].match(/^(\w+);(.*?);(.*)$/);
+                       if (!cat) continue;
+
+                       const code = cat[1].trim();
+                       const list = cat[2].trim();
+                       const path = cat[3].trim();
+
+                       if (code === 'stb') {
                                o.value(path, list);
                        }
                }
                o.optional = true;
                o.rmempty = true;
 
+               o = s.taboption('feeds', form.DummyValue, '_sub');
+               o.rawhtml = true;
+               o.default = '<hr style="width: 200px; height: 1px;" /><em style="color:#37c;font-weight:bold;">' + _('UTCapitole Archive Selection') + '</em>';
+
+               o = s.taboption('feeds', form.DynamicList, 'adb_utc_feed', _('Categories'));
+               for (let i = 0; i < categories.length; i++) {
+                       const cat = categories[i].match(/^(\w+);(.*)$/);
+                       if (!cat) continue;
+
+                       const code = cat[1].trim();
+                       const category = cat[2].trim();
+
+                       if (code === 'utc') {
+                               o.value(category);
+                       }
+               }
+               o.optional = true;
+               o.rmempty = true;
+
+               /*
+                       action buttons
+               */
                s = m.section(form.NamedSection, 'global');
                s.render = L.bind(function () {
                        return E('div', { 'class': 'cbi-page-actions' }, [
git clone https://git.99rst.org/PROJECT