[READ-ONLY] Mirror of https://github.com/andrioid/ublproxy. andrioid.github.io/ublproxy
adblock adblock-plus-list adblocker privacy-tools proxy-server self-hosted
Something went wrong. Try again.
HTML
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Subscriptions - ublproxy</title><link rel="stylesheet" href="/static/shared.css"></head><body><nav class="nav"> <a href="/" class="nav-brand">ublproxy</a> <ul class="nav-links"> <li><a href="/" class="nav-link">Dashboard</a></li> <li><a href="/rules" class="nav-link" data-auth>Rules</a></li> <li><a href="/subscriptions" class="nav-link" data-auth>Subscriptions</a></li> <li><a href="/activity" class="nav-link" data-admin>Activity</a></li> <li><a href="/users" class="nav-link" data-admin>Users</a></li> </ul> <div class="nav-right"> <span class="nav-status" id="nav-status">Checking…</span> <a href="#" class="btn btn-ghost btn-sm hidden" id="nav-logout">Sign out</a> </div></nav>
<main class="main"> <div id="unauth-view" class="hidden"> <div class="card auth-card"> <p class="page-subtitle">You need to <a href="/" style="color:var(--color-primary)">sign in</a> to manage subscriptions.</p> </div> </div>
<div id="auth-view" class="hidden"> <div class="page-header"> <h1 class="page-title">Subscriptions <span class="card-count" id="subs-count"></span></h1> <p class="page-subtitle">Blocklist subscriptions provide blocking rules from community-maintained lists.</p> </div>
<!-- Suggested lists — prominent for new users --> <div class="card" id="suggested-card"> <div class="card-header"> <h3 class="card-title">Popular Lists</h3> </div> <p class="help-text" style="margin-top:0;margin-bottom:0.75rem"> Click to add a community-maintained blocklist. These lists are updated periodically and contain thousands of rules. </p> <div style="display:flex;flex-wrap:wrap;gap:0.5rem"> <button class="btn btn-primary btn-sm suggest-link" data-url="https://easylist.to/easylist/easylist.txt" data-name="EasyList">+ EasyList</button> <button class="btn btn-primary btn-sm suggest-link" data-url="https://easylist.to/easylist/easyprivacy.txt" data-name="EasyPrivacy">+ EasyPrivacy</button> <button class="btn btn-secondary btn-sm suggest-link" data-url="https://easylist.to/easylist/fanboy-social.txt" data-name="Fanboy Social">+ Fanboy Social</button> <button class="btn btn-secondary btn-sm suggest-link" data-url="https://secure.fanboy.co.nz/fanboy-annoyance.txt" data-name="Fanboy Annoyances">+ Fanboy Annoyances</button> <button class="btn btn-secondary btn-sm suggest-link" data-url="https://raw.githubusercontent.com/nickspaargaren/no-google/refs/heads/master/pihole-google.txt" data-name="No Google">+ No Google</button> </div> <div class="msg" id="suggest-msg"></div> </div>
<!-- Subscription list + add form --> <div class="card"> <div class="card-header"> <h3 class="card-title">Your Subscriptions</h3> <button class="btn btn-secondary btn-sm" id="btn-refresh-subs">Refresh All</button> </div> <ul class="item-list" id="subs-list"></ul> <div class="empty-state hidden" id="subs-empty">No subscriptions yet. Add one from the popular lists above, or enter a custom URL below.</div>
<div class="form-row"> <input type="text" class="form-input" id="sub-url" placeholder="Blocklist URL (e.g. https://easylist.to/easylist/easylist.txt)"> <input type="text" class="form-input form-input-narrow" id="sub-name" placeholder="Name (optional)"> <button class="btn btn-primary btn-sm" id="btn-add-sub">Add</button> </div>
<div class="msg" id="subs-msg"></div> </div> </div></main>
<script src="/static/shared.js"></script><script>(function() { 'use strict'; var U = window.ublproxy;
var subsList = document.getElementById('subs-list'); var subsEmpty = document.getElementById('subs-empty'); var subsCount = document.getElementById('subs-count'); var subsMsgEl = document.getElementById('subs-msg'); var suggestMsgEl = document.getElementById('suggest-msg'); var subUrl = document.getElementById('sub-url'); var subName = document.getElementById('sub-name');
function onAuth() { U.show(document.getElementById('auth-view')); U.hide(document.getElementById('unauth-view')); loadSubscriptions(); }
function onUnauth() { U.hide(document.getElementById('auth-view')); U.show(document.getElementById('unauth-view')); }
async function loadSubscriptions() { try { var resp = await fetch('/api/subscriptions', { headers: U.authHeaders() }); if (!resp.ok) return; var subs = await resp.json(); renderSubscriptions(subs); } catch (_) {} }
function renderSubscriptions(subs) { subsCount.textContent = '(' + subs.length + ')'; subsList.innerHTML = '';
if (subs.length === 0) { U.show(subsEmpty); return; } U.hide(subsEmpty);
subs.forEach(function(s) { var li = document.createElement('li'); li.className = 'item';
var toggle = document.createElement('label'); toggle.className = 'toggle'; toggle.innerHTML = '<input type="checkbox"' + (s.enabled ? ' checked' : '') + '><span class="toggle-slider"></span>'; toggle.querySelector('input').addEventListener('change', function() { toggleSubscription(s.id, this.checked); });
var info = document.createElement('div'); info.className = 'item-info';
var nameRow = document.createElement('div'); nameRow.className = 'item-name'; nameRow.textContent = s.name || s.url; info.appendChild(nameRow);
if (s.name) { var urlRow = document.createElement('div'); urlRow.className = 'item-url'; urlRow.textContent = s.url; info.appendChild(urlRow); }
var del = document.createElement('button'); del.className = 'btn btn-danger btn-sm'; del.textContent = 'Delete'; del.addEventListener('click', function() { deleteSubscription(s.id); });
li.appendChild(toggle); li.appendChild(info); li.appendChild(del); subsList.appendChild(li); }); }
async function addSubscription(url, name, msgEl) { U.clearMsg(msgEl); if (!url) { U.showMsg(msgEl, 'URL is required.', 'error'); return; } try { var resp = await fetch('/api/subscriptions', { method: 'POST', headers: U.authHeaders(), body: JSON.stringify({ url: url, name: name || '' }) }); if (!resp.ok) { var e = await resp.json(); throw new Error(e.error || 'Failed to add subscription'); } subUrl.value = ''; subName.value = ''; U.showMsg(msgEl, 'Subscription added.', 'success'); loadSubscriptions(); } catch (err) { U.showMsg(msgEl, 'Failed: ' + err.message, 'error'); } }
async function toggleSubscription(id, enabled) { try { await fetch('/api/subscriptions/' + id, { method: 'PATCH', headers: U.authHeaders(), body: JSON.stringify({ enabled: enabled }) }); } catch (_) {} }
async function deleteSubscription(id) { try { await fetch('/api/subscriptions/' + id, { method: 'DELETE', headers: U.authHeaders() }); loadSubscriptions(); } catch (_) {} }
async function refreshSubscriptions() { U.clearMsg(subsMsgEl); var btn = document.getElementById('btn-refresh-subs'); btn.disabled = true; btn.textContent = 'Refreshing\u2026'; try { var resp = await fetch('/api/subscriptions/refresh', { method: 'POST', headers: U.authHeaders() }); if (!resp.ok) { var e = await resp.json(); throw new Error(e.error || 'Refresh failed'); } U.showMsg(subsMsgEl, 'All blocklists refreshed.', 'success'); } catch (err) { U.showMsg(subsMsgEl, 'Refresh failed: ' + err.message, 'error'); } finally { btn.disabled = false; btn.textContent = 'Refresh All'; } }
document.getElementById('btn-add-sub').addEventListener('click', function() { addSubscription(subUrl.value.trim(), subName.value.trim(), subsMsgEl); }); subUrl.addEventListener('keydown', function(e) { if (e.key === 'Enter') addSubscription(subUrl.value.trim(), subName.value.trim(), subsMsgEl); }); document.getElementById('btn-refresh-subs').addEventListener('click', refreshSubscriptions);
document.querySelectorAll('.suggest-link').forEach(function(link) { link.addEventListener('click', function(e) { e.preventDefault(); addSubscription(this.dataset.url, this.dataset.name, suggestMsgEl); }); });
U.checkSession(onAuth, onUnauth);})();</script></body></html>