From d6dfb7a6ba0feec8d6ada0004ccbcc1e927e84b6 Mon Sep 17 00:00:00 2001
From: Abel <196466003+DisabledAbel@users.noreply.github.com>
Date: Wed, 13 May 2026 21:33:12 -0700
Subject: [PATCH 1/5] Always return official YouTube feed URLs in API responses
---
api/app.py | 5 +++--
rss_scanner.py | 26 +++++++++++++++++++++-----
2 files changed, 24 insertions(+), 7 deletions(-)
diff --git a/api/app.py b/api/app.py
index bf5b252..db73eea 100644
--- a/api/app.py
+++ b/api/app.py
@@ -63,7 +63,7 @@ def api_feed():
include_api_endpoints = False
base_url = request.host_url.rstrip('/')
- youtube_rss, channel_id, channel_name, atom_feed, video_count, _, api_endpoints = rss_scanner.get_rss_feed(
+ youtube_rss, channel_id, channel_name, atom_feed, video_count, _, api_endpoints, official_feeds = rss_scanner.get_rss_feed(
url,
include_api_endpoints=include_api_endpoints,
base_url=base_url,
@@ -94,6 +94,7 @@ def api_feed():
'atom_feed': atom_feed,
'video_count': video_count,
'api_endpoints': api_endpoints,
+ 'official_feeds': official_feeds,
'discord': discord_result
}), mimetype='application/json')
except Exception as e:
@@ -167,7 +168,7 @@ def get_feed(feed_type, channel_url=None):
full_url = channel_url
try:
- _, channel_id, channel_name, atom_feed, video_count, _, _ = rss_scanner.get_rss_feed(full_url, feed_type=feed_type)
+ _, channel_id, channel_name, atom_feed, video_count, _, _, _ = rss_scanner.get_rss_feed(full_url, feed_type=feed_type)
if atom_feed:
# Fix channel name in feed
diff --git a/rss_scanner.py b/rss_scanner.py
index e2d19e2..1467641 100644
--- a/rss_scanner.py
+++ b/rss_scanner.py
@@ -91,7 +91,7 @@ def generate_atom_feed(channel_id: str, channel_name: str, videos: list[dict]) -
return feed
PATTERNS = [
- (r"/channel/([a-zA-Z0-9_-]{22})", "channel"),
+ (r"/channel/(UC[a-zA-Z0-9_-]{22})", "channel"),
(r"/c/([a-zA-Z0-9_-]+)", "custom"),
(r"/user/([a-zA-Z0-9_-]+)", "user"),
(r"/@([a-zA-Z0-9_-]+)", "handle"),
@@ -295,15 +295,31 @@ def build_youtube_feed_url(channel_id: str, feed_type: str = None) -> str:
"""Build a YouTube RSS feed URL for the given channel ID."""
return f"https://www.youtube.com/feeds/videos.xml?channel_id={channel_id}"
+
+
+def build_official_feeds(channel_id: str, feed_type: str = "all") -> dict[str, str]:
+ """Return official YouTube feed URLs keyed by feed type."""
+ all_feed = build_youtube_feed_url(channel_id, feed_type="all")
+ feeds = {
+ "all": all_feed,
+ "videos": all_feed,
+ "shorts": all_feed,
+ "live": all_feed,
+ }
+ selected_type = feed_type if feed_type in feeds else "all"
+ feeds["selected"] = feeds[selected_type]
+ return feeds
+
def get_rss_feed(url: str, include_api_endpoints: bool = False, base_url: str = "http://localhost:8080", feed_type: str = "all") -> tuple:
"""Get RSS feed data for a YouTube channel.
- Returns: (youtube_rss, channel_id, channel_name, atom_feed, video_count, invidious_rss, api_endpoints)
+ Returns: (youtube_rss, channel_id, channel_name, atom_feed, video_count, invidious_rss, api_endpoints, official_feeds)
"""
channel_id, channel_name = extract_channel_id(url)
# YouTube RSS URL (supports hidden filtered variants for shorts/live)
- youtube_rss = build_youtube_feed_url(channel_id, feed_type=feed_type)
+ official_feeds = build_official_feeds(channel_id, feed_type=feed_type)
+ youtube_rss = official_feeds["selected"]
# Try to get videos from the selected YouTube channel page
videos = get_channel_videos(channel_id, feed_type=feed_type)
@@ -337,7 +353,7 @@ def get_rss_feed(url: str, include_api_endpoints: bool = False, base_url: str =
"live_feed": f"{base_url.rstrip('/')}/feed/live/{encoded_url}",
}
- return youtube_rss, channel_id, channel_name, atom_feed, video_count, invidious_rss, api_endpoints
+ return youtube_rss, channel_id, channel_name, atom_feed, video_count, invidious_rss, api_endpoints, official_feeds
def main():
@@ -383,7 +399,7 @@ def main():
url = "https://" + url
try:
- youtube_rss, channel_id, channel_name, atom_feed, video_count, invidious_rss, api_endpoints = get_rss_feed(
+ youtube_rss, channel_id, channel_name, atom_feed, video_count, invidious_rss, api_endpoints, official_feeds = get_rss_feed(
url,
include_api_endpoints=args.include_api_endpoints,
base_url=args.base_url
From e06ca729a1516a7c698abe620c3c1ad727d28c24 Mon Sep 17 00:00:00 2001
From: Abel <196466003+DisabledAbel@users.noreply.github.com>
Date: Wed, 13 May 2026 21:39:32 -0700
Subject: [PATCH 2/5] Add copy buttons for official YouTube feed URLs
---
api/index.html | 9 ++++++++-
index.html | 20 ++++++++++++++++++--
templates/index.html | 9 ++++++++-
3 files changed, 34 insertions(+), 4 deletions(-)
diff --git a/api/index.html b/api/index.html
index f7e5d8d..ba2c36c 100644
--- a/api/index.html
+++ b/api/index.html
@@ -224,7 +224,14 @@
YouTube RSS Scanner
if (data.official_feeds) {
html += 'Official YouTube Feeds:
';
- ['selected','all','videos','shorts','live'].forEach(function(k){ if (data.official_feeds[k]) { html += '
' + k + ': ' + data.official_feeds[k] + '
'; }});
+ ['selected','all','videos','shorts','live'].forEach(function(k){
+ if (!data.official_feeds[k]) return;
+ html += '
';
+ html += '
Official (' + k + '):
';
+ html += '
' + data.official_feeds[k] + '
';
+ html += '
Copy ' + k + ' RSS ';
+ html += '
';
+ });
html += '
';
}
diff --git a/index.html b/index.html
index 044a89c..99d6dd1 100644
--- a/index.html
+++ b/index.html
@@ -270,8 +270,24 @@ YouTube RSS Scanner
['selected','all','videos','shorts','live'].forEach((key) => {
if (!data.official_feeds[key]) return;
const row = document.createElement('div');
- row.className = 'feed-link';
- row.textContent = `${key}: ${data.official_feeds[key]}`;
+ row.className = 'feed-row';
+
+ const feedLabel = document.createElement('div');
+ feedLabel.className = 'feed-label';
+ feedLabel.textContent = `Official (${key}):`;
+ row.appendChild(feedLabel);
+
+ const feedLink = document.createElement('div');
+ feedLink.className = 'feed-link';
+ feedLink.textContent = data.official_feeds[key];
+ row.appendChild(feedLink);
+
+ const copyBtn = document.createElement('button');
+ copyBtn.className = 'copy-btn';
+ copyBtn.textContent = `Copy ${key} RSS`;
+ copyBtn.addEventListener('click', () => copyText(data.official_feeds[key]));
+ row.appendChild(copyBtn);
+
officialBox.appendChild(row);
});
resultDiv.appendChild(officialBox);
diff --git a/templates/index.html b/templates/index.html
index a034472..e32ce67 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -218,7 +218,14 @@ YouTube RSS Scanner
if (data.official_feeds) {
html += 'Official YouTube Feeds:
';
- ['selected','all','videos','shorts','live'].forEach(function(k){ if (data.official_feeds[k]) { html += '
' + k + ': ' + data.official_feeds[k] + '
'; }});
+ ['selected','all','videos','shorts','live'].forEach(function(k){
+ if (!data.official_feeds[k]) return;
+ html += '
';
+ html += '
Official (' + k + '):
';
+ html += '
' + data.official_feeds[k] + '
';
+ html += '
Copy ' + k + ' RSS ';
+ html += '
';
+ });
html += '
';
}
From c99db9e513e87d1c4adc3b3e211fa7fed7f64975 Mon Sep 17 00:00:00 2001
From: Abel <196466003+DisabledAbel@users.noreply.github.com>
Date: Wed, 13 May 2026 21:48:31 -0700
Subject: [PATCH 3/5] Stop duplicating official feed URLs in the UI
---
api/index.html | 9 +++++----
index.html | 7 +++----
rss_scanner.py | 12 ++++--------
templates/index.html | 9 +++++----
4 files changed, 17 insertions(+), 20 deletions(-)
diff --git a/api/index.html b/api/index.html
index ba2c36c..b070aed 100644
--- a/api/index.html
+++ b/api/index.html
@@ -224,12 +224,13 @@ YouTube RSS Scanner
if (data.official_feeds) {
html += 'Official YouTube Feeds:
';
- ['selected','all','videos','shorts','live'].forEach(function(k){
- if (!data.official_feeds[k]) return;
+ Object.entries(data.official_feeds).forEach(function(entry){
+ var k = entry[0];
+ var v = entry[1];
html += '
';
html += '
Official (' + k + '):
';
- html += '
' + data.official_feeds[k] + '
';
- html += '
Copy ' + k + ' RSS ';
+ html += '
' + v + '
';
+ html += '
Copy ' + k + ' RSS ';
html += '
';
});
html += '
';
diff --git a/index.html b/index.html
index 99d6dd1..a873bad 100644
--- a/index.html
+++ b/index.html
@@ -267,8 +267,7 @@ YouTube RSS Scanner
label.className = 'feed-label';
label.textContent = 'Official YouTube Feeds:';
officialBox.appendChild(label);
- ['selected','all','videos','shorts','live'].forEach((key) => {
- if (!data.official_feeds[key]) return;
+ Object.entries(data.official_feeds).forEach(([key, value]) => {
const row = document.createElement('div');
row.className = 'feed-row';
@@ -279,13 +278,13 @@ YouTube RSS Scanner
const feedLink = document.createElement('div');
feedLink.className = 'feed-link';
- feedLink.textContent = data.official_feeds[key];
+ feedLink.textContent = value;
row.appendChild(feedLink);
const copyBtn = document.createElement('button');
copyBtn.className = 'copy-btn';
copyBtn.textContent = `Copy ${key} RSS`;
- copyBtn.addEventListener('click', () => copyText(data.official_feeds[key]));
+ copyBtn.addEventListener('click', () => copyText(value));
row.appendChild(copyBtn);
officialBox.appendChild(row);
diff --git a/rss_scanner.py b/rss_scanner.py
index 1467641..38233e3 100644
--- a/rss_scanner.py
+++ b/rss_scanner.py
@@ -298,16 +298,12 @@ def build_youtube_feed_url(channel_id: str, feed_type: str = None) -> str:
def build_official_feeds(channel_id: str, feed_type: str = "all") -> dict[str, str]:
- """Return official YouTube feed URLs keyed by feed type."""
- all_feed = build_youtube_feed_url(channel_id, feed_type="all")
+ """Return official YouTube feed URLs without duplicating identical links."""
+ youtube_feed = build_youtube_feed_url(channel_id, feed_type="all")
feeds = {
- "all": all_feed,
- "videos": all_feed,
- "shorts": all_feed,
- "live": all_feed,
+ "youtube": youtube_feed,
+ "selected": youtube_feed,
}
- selected_type = feed_type if feed_type in feeds else "all"
- feeds["selected"] = feeds[selected_type]
return feeds
def get_rss_feed(url: str, include_api_endpoints: bool = False, base_url: str = "http://localhost:8080", feed_type: str = "all") -> tuple:
diff --git a/templates/index.html b/templates/index.html
index e32ce67..18c7b15 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -218,12 +218,13 @@ YouTube RSS Scanner
if (data.official_feeds) {
html += 'Official YouTube Feeds:
';
- ['selected','all','videos','shorts','live'].forEach(function(k){
- if (!data.official_feeds[k]) return;
+ Object.entries(data.official_feeds).forEach(function(entry){
+ var k = entry[0];
+ var v = entry[1];
html += '
';
html += '
Official (' + k + '):
';
- html += '
' + data.official_feeds[k] + '
';
- html += '
Copy ' + k + ' RSS ';
+ html += '
' + v + '
';
+ html += '
Copy ' + k + ' RSS ';
html += '
';
});
html += '
';
From 8723ad702141dd0bdac7a6630e60a74b8d5fd92f Mon Sep 17 00:00:00 2001
From: "coderabbitai[bot]"
<136622811+coderabbitai[bot]@users.noreply.github.com>
Date: Thu, 14 May 2026 04:56:42 +0000
Subject: [PATCH 4/5] fix: apply CodeRabbit auto-fixes
Fixed 2 file(s) based on 2 unresolved review comments.
Co-authored-by: CodeRabbit
---
api/index.html | 10 ++++++++++
rss_scanner.py | 6 +++++-
2 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/api/index.html b/api/index.html
index b070aed..2d53dc1 100644
--- a/api/index.html
+++ b/api/index.html
@@ -267,6 +267,16 @@ YouTube RSS Scanner
document.getElementById('channelUrl').addEventListener('keypress', function(e) {
if (e.key === 'Enter') getFeed();
});
+
+ // Event delegation for dynamically added copy buttons
+ document.addEventListener('click', function(e) {
+ if (e.target && e.target.classList.contains('copy-btn')) {
+ const encoded = e.target.getAttribute('data-encoded');
+ if (encoded) {
+ copyEncodedText(encoded);
+ }
+ }
+ });