I made a Tampermonkey script that can scrape the tvtv.us guide for Channel Call Sign and Gracenote ID, saving it to a json file. If anyone wants it, I'll paste it here in a little while.
Download Tampermonkey from the Chrome Web Store
1: Enable User Scripts in the Extension Settings
- Right-click the Tampermonkey icon located on your browser's toolbar.
- Select Manage extensions from the drop-down menu. This will open a new browser settings tab specifically for the Tampermonkey extension.
- Scroll through the options and find the toggle labeled Allow User Scripts (recent browser security updates require this permission to be explicitly granted so Tampermonkey can inject your custom code). Click the toggle to turn it on.
- You can now close the extension settings tab.
2: Add the Custom Script
- Left-click the Tampermonkey icon on your browser's toolbar.
- Select Create a new script... from the menu.
- A text editor will open containing some default template code. Delete everything in this editor so it is completely blank.
- Paste the entire JavaScript code into the editor.
- Click File in the top menu of the Tampermonkey editor and select Save (or simply press Ctrl + S on your keyboard).
3: Run the Scraper
- Navigate to the tvtv.us lineup page of your choice.
- You will now see the blue Scrape Stations button floating in the top right corner of the page.
- Browse the site, select your local provider, and click the button whenever you are ready to let the script scroll and harvest the Gracenote IDs.
// ==UserScript==
// @name tvtv.us Gracenote Scraper (Button Trigger)
// @namespace http://tampermonkey.net/
// @version 1.2
// @description Adds a floating button to scrape Gracenote IDs on demand.
// @match *://*.tvtv.us/*
// @grant GM_addStyle
// ==/UserScript==
(function() {
'use strict';
// 1. Inject the floating button into the page
const btnContainer = document.createElement('div');
btnContainer.innerHTML = '<button id="tm-scrape-btn">Scrape Stations</button>';
document.body.appendChild(btnContainer);
// 2. Style the button so it sits in the top right corner
GM_addStyle(`
#tm-scrape-btn {
position: fixed;
top: 80px; /* Moved to the top, offset by 80px to clear the site header */
right: 20px;
z-index: 99999;
padding: 12px 20px;
background-color: #2196F3;
color: white;
border: none;
border-radius: 8px;
font-size: 16px;
font-weight: bold;
cursor: pointer;
box-shadow: 0px 4px 6px rgba(0,0,0,0.3);
}
#tm-scrape-btn:hover {
background-color: #1976D2;
}
`);
// 3. Attach the scraping logic to the button click
document.getElementById("tm-scrape-btn").addEventListener("click", function() {
this.innerText = "Scraping... (Do not touch)";
this.style.backgroundColor = "#FF9800";
scrapeLazyLoadedGrid(this);
});
async function scrapeLazyLoadedGrid(btnElement) {
const stations = new Map();
let retries = 0;
const maxRetries = 3;
window.scrollTo(0, 0);
while (true) {
const links = Array.from(document.querySelectorAll('a[href*="/stn"]'));
links.forEach(a => {
const match = a.href.match(/\/stn(\d+)(?:-[0-9.]+)?(?:-([a-zA-Z0-9_-]+))?/);
if (match) {
const gracenoteId = match[1];
const callSign = match[2] || "UNKNOWN";
if (!stations.has(gracenoteId)) {
stations.set(gracenoteId, {
callSign: callSign,
gracenoteId: gracenoteId
});
}
}
});
window.scrollBy(0, window.innerHeight);
await new Promise(resolve => setTimeout(resolve, 800));
let currentScroll = Math.ceil(document.documentElement.scrollTop + window.innerHeight);
let scrollHeight = document.documentElement.scrollHeight;
if (currentScroll >= scrollHeight) {
retries++;
if (retries >= maxRetries) {
break;
}
await new Promise(resolve => setTimeout(resolve, 1000));
} else {
retries = 0;
}
}
const stationList = Array.from(stations.values());
const jsonString = JSON.stringify(stationList, null, 2);
let fileName = "gracenote_stations.json";
const urlMatch = window.location.pathname.match(/\/lu([^/]+)/);
if (urlMatch && urlMatch[1]) {
fileName = `${urlMatch[1]}_stations.json`;
}
const blob = new Blob([jsonString], { type: "application/json" });
const url = URL.createObjectURL(blob);
const downloadLink = document.createElement('a');
downloadLink.href = url;
downloadLink.download = fileName;
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
URL.revokeObjectURL(url);
// Reset button
btnElement.innerText = "Scrape Stations";
btnElement.style.backgroundColor = "#2196F3";
alert(`Scraping complete! Downloaded ${stationList.length} stations.`);
}
})();
Very cool!
Maybe this could be used to create a shared list with all channels. People could run this script and add missing channels to the list.
Nice use of Tampermonkey! Anyone who's using Project WebUI+ will already have the extension installed. Chrome or Firefox.
Don't we already have a decent list here?
I'm not in the US, so don't know how complete it is for you lot.
This is awesome and I totally stole this for the project I am working on. Here is a tip though if you add /faves to the url for example https://www.tvtv.us/us/lineups/luUSA-YTBE544-X/faves and scrape that, it will give you Callsign, Channel Name, Gracenote ID, and logo url 
Thanks to the insights from @Bobby_Vaughn and @slampman, I can now say I have a functioning scraper for this!
The headline is this:
2026-08-31 18:29:00.856395: INFO: For Gracenote maps, found 6,044 unique stations across all providers.
2026-08-31 18:29:01.217596: INFO: Finished process to get Gracenote maps in 0 hours | 50 minutes | 16 seconds.
"All providers" in this case means anything on tvtv's U.S. national feeds (22 at this time, automatically updates if/when they do, also includes FAST), plus any local OTA stations a user may want based on zip code (of which there can be many).
Sample of complete logs for some more details...
2026-08-31 17:38:44.407221: INFO: Beginning process to get Gracenote maps...
2026-08-31 17:38:44.409244: INFO: For Gracenote maps, gathering U.S. national provider list...
2026-08-31 17:38:46.181190: INFO: For Gracenote maps, found 22 U.S. national provider(s) and combined them with the 1 local provider(s).
2026-08-31 17:38:46.181190: INFO: For Gracenote maps, checking provider 'luUSA-OTA02906' for stations...
2026-08-31 17:39:10.506971: INFO: In provider 'luUSA-OTA02906' added 28 new records. So far have found 28 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 0 skipped due to a previous entry.
2026-08-31 17:39:12.824583: INFO: In provider 'luUSA-OTA02906' added 28 new records. So far have found 56 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 0 skipped due to a previous entry.
2026-08-31 17:39:18.735103: INFO: In provider 'luUSA-OTA02906' added 28 new records. So far have found 84 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 0 skipped due to a previous entry.
2026-08-31 17:39:23.414166: INFO: In provider 'luUSA-OTA02906' added 17 new records. So far have found 101 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 0 skipped due to a previous entry.
2026-08-31 17:39:28.693313: INFO: For Gracenote maps, provider 'luUSA-OTA02906' returned 101 stations, with 0 skipped due to missing Gracenote IDs and 0 skipped due to a previous entry.
2026-08-31 17:39:28.693313: INFO: With provider 'luUSA-OTA02906', added 101 unique Gracenote IDs added to final map.
2026-08-31 17:39:28.693313: INFO: For Gracenote maps, checking provider 'luUSA-AFN-X' for stations...
2026-08-31 17:39:48.773617: INFO: In provider 'luUSA-AFN-X' added 14 new records. So far have found 14 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 0 skipped due to a previous entry.
2026-08-31 17:39:53.904559: INFO: For Gracenote maps, provider 'luUSA-AFN-X' returned 14 stations, with 0 skipped due to missing Gracenote IDs and 0 skipped due to a previous entry.
2026-08-31 17:39:53.904559: INFO: With provider 'luUSA-AFN-X', added 14 unique Gracenote IDs added to final map.
2026-08-31 17:39:53.904559: INFO: For Gracenote maps, checking provider 'luUSA-DITV-X' for stations...
2026-08-31 17:40:17.841673: INFO: In provider 'luUSA-DITV-X' added 26 new records. So far have found 26 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 2 skipped due to a previous entry.
2026-08-31 17:40:19.577507: INFO: In provider 'luUSA-DITV-X' added 27 new records. So far have found 53 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 3 skipped due to a previous entry.
2026-08-31 17:40:26.274065: INFO: In provider 'luUSA-DITV-X' added 28 new records. So far have found 81 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 3 skipped due to a previous entry.
2026-08-31 17:40:32.204965: INFO: In provider 'luUSA-DITV-X' added 28 new records. So far have found 109 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 3 skipped due to a previous entry.
2026-08-31 17:40:37.881685: INFO: In provider 'luUSA-DITV-X' added 26 new records. So far have found 135 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 5 skipped due to a previous entry.
2026-08-31 17:40:43.546353: INFO: In provider 'luUSA-DITV-X' added 28 new records. So far have found 163 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 5 skipped due to a previous entry.
2026-08-31 17:40:49.245750: INFO: In provider 'luUSA-DITV-X' added 24 new records. So far have found 187 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 9 skipped due to a previous entry.
2026-08-31 17:40:55.037308: INFO: In provider 'luUSA-DITV-X' added 28 new records. So far have found 215 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 9 skipped due to a previous entry.
2026-08-31 17:41:00.563541: INFO: In provider 'luUSA-DITV-X' added 24 new records. So far have found 239 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 13 skipped due to a previous entry.
2026-08-31 17:41:06.501880: INFO: In provider 'luUSA-DITV-X' added 26 new records. So far have found 265 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 15 skipped due to a previous entry.
2026-08-31 17:41:16.910209: INFO: In provider 'luUSA-DITV-X' added 27 new records. So far have found 292 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 16 skipped due to a previous entry.
2026-08-31 17:41:23.155450: INFO: In provider 'luUSA-DITV-X' added 21 new records. So far have found 313 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 23 skipped due to a previous entry.
2026-08-31 17:41:29.176511: INFO: In provider 'luUSA-DITV-X' added 27 new records. So far have found 340 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 24 skipped due to a previous entry.
2026-08-31 17:41:34.738832: INFO: In provider 'luUSA-DITV-X' added 28 new records. So far have found 368 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 24 skipped due to a previous entry.
2026-08-31 17:41:41.541998: INFO: In provider 'luUSA-DITV-X' added 28 new records. So far have found 396 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 24 skipped due to a previous entry.
2026-08-31 17:41:52.268666: INFO: In provider 'luUSA-DITV-X' added 28 new records. So far have found 424 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 24 skipped due to a previous entry.
2026-08-31 17:41:58.793256: INFO: In provider 'luUSA-DITV-X' added 28 new records. So far have found 452 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 24 skipped due to a previous entry.
2026-08-31 17:42:04.513368: INFO: In provider 'luUSA-DITV-X' added 27 new records. So far have found 479 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 25 skipped due to a previous entry.
2026-08-31 17:42:10.510054: INFO: In provider 'luUSA-DITV-X' added 28 new records. So far have found 507 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 25 skipped due to a previous entry.
2026-08-31 17:42:16.646891: INFO: In provider 'luUSA-DITV-X' added 28 new records. So far have found 535 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 25 skipped due to a previous entry.
2026-08-31 17:42:23.397531: INFO: In provider 'luUSA-DITV-X' added 28 new records. So far have found 563 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 25 skipped due to a previous entry.
2026-08-31 17:42:28.984481: INFO: In provider 'luUSA-DITV-X' added 22 new records. So far have found 585 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 31 skipped due to a previous entry.
2026-08-31 17:42:34.719136: INFO: In provider 'luUSA-DITV-X' added 28 new records. So far have found 613 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 31 skipped due to a previous entry.
2026-08-31 17:42:40.950854: INFO: In provider 'luUSA-DITV-X' added 28 new records. So far have found 641 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 31 skipped due to a previous entry.
2026-08-31 17:42:46.910057: INFO: In provider 'luUSA-DITV-X' added 28 new records. So far have found 669 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 31 skipped due to a previous entry.
2026-08-31 17:42:52.605378: INFO: In provider 'luUSA-DITV-X' added 28 new records. So far have found 697 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 31 skipped due to a previous entry.
2026-08-31 17:42:58.507980: INFO: In provider 'luUSA-DITV-X' added 28 new records. So far have found 725 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 31 skipped due to a previous entry.
2026-08-31 17:43:05.687046: INFO: In provider 'luUSA-DITV-X' added 28 new records. So far have found 753 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 31 skipped due to a previous entry.
2026-08-31 17:43:11.572469: INFO: In provider 'luUSA-DITV-X' added 27 new records. So far have found 780 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 32 skipped due to a previous entry.
2026-08-31 17:43:17.109714: INFO: In provider 'luUSA-DITV-X' added 28 new records. So far have found 808 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 32 skipped due to a previous entry.
2026-08-31 17:43:22.295440: INFO: In provider 'luUSA-DITV-X' added 21 new records. So far have found 829 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 39 skipped due to a previous entry.
2026-08-31 17:43:26.413645: INFO: In provider 'luUSA-DITV-X' added 6 new records. So far have found 835 Gracenote IDs, with 0 skipped due to missing Gracenote IDs and 55 skipped due to a previous entry.
2026-08-31 17:43:31.727885: INFO: For Gracenote maps, provider 'luUSA-DITV-X' returned 835 stations, with 0 skipped due to missing Gracenote IDs and 55 skipped due to a previous entry.
2026-08-31 17:43:31.729898: INFO: With provider 'luUSA-DITV-X', added 834 unique Gracenote IDs added to final map.
...
2026-08-31 18:29:00.853803: INFO: With provider 'luUSA-YOUTUBE-X', added 107 unique Gracenote IDs added to final map.
2026-08-31 18:29:00.856395: INFO: For Gracenote maps, found 6,044 unique stations across all providers.
2026-08-31 18:29:01.217596: INFO: Finished process to get Gracenote maps in 0 hours | 50 minutes | 16 seconds.
I will be adding this into Media Tools Manager's Gracenote Search in the very near future so users will have the ability to search either using the default method through the Channels API or by doing this scrape, storing locally, and being able to filter on any of the data fields against the total list. For instance, @chDVRuser, here's a Gracenote ID for The Masked Singer: 191048. You'll have to let me know if this has the correct guide information!
There is a limitation in that the scrape does not know if Gracenote is no longer receiving input data, so you get this:
Therefore, it is something to look out for, as it is now. In other words, you still have to double check. Also, this is limited to U.S. stations at this time, though theoretically I could also do Canada, but nowhere else.
@KineticMan, I'm not sure if you'd want to include a scraper like this in FastChannels or just stick with the community version or what, but the code will be readily available in a little while for review. Even if you do, I don't think you want it to run automatically, but be something users kick off manually.
Very cool. That is going to help a lot of users find those hard to get channels.
It’s how my lookup works. Bout time you guys caught on 
Same 1hr block listings as FMSC stationId "192070".
Should work for Tubi and Roku, but not for the Fox One channel (which airs back-back ad-less episodes).
Ah, hadn't looked at the code in a bit, so missed that! Just assumed it was using the community maps + Channels DVR API for suggestions.
Oh well! Unfortunately, they don't have a FoxOne provider yet, but maybe someday?

