Streambert New Episode Notification System: How TV Series Updates Work
Streambert detects and notifies users about new TV series episodes using Electron IPC channels, localStorage-based caching, and periodic TMDB polling without relying on external notification services.
Streambert, an open-source Electron-based media application maintained at truelockmc/streambert, implements a privacy-respecting new episode notification system that alerts users when tracked TV series release fresh content. The architecture performs all detection locally using the TMDB API and native OS notification APIs, ensuring user viewing data never leaves the application. This system combines a robust caching mechanism with user-configurable preferences to deliver timely alerts while maintaining complete data sovereignty.
Architecture of the Notification System
The notification pipeline operates across three distinct layers that separate concerns between the main process, renderer process, and data persistence. According to the truelockmc/streambert source code, this design ensures that sensitive API operations and background polling remain isolated from the web frontend while allowing seamless user interaction through secure IPC bridges.
Electron IPC Bridge (src/preload.js)
The src/preload.js file creates a secure communication channel between the renderer and main process using Electron's contextBridge. It exposes a showNotification function to the renderer window that safely forwards notification requests without granting unrestricted Node.js access.
// Exposed via contextBridge.exposeInMainWorld('electron', ...)
const showNotification = (options) => {
ipcRenderer.invoke("show-notification", options);
};
Main Process Handler (src/index.js)
The main process registers an IPC handler named show-notification that instantiates Electron's native Notification class. When the renderer or background jobs trigger this channel, the application displays native OS toast notifications with customizable titles, bodies, and sound settings.
ipcMain.handle("show-notification", async (_, { title, body, silent }) => {
new Notification({ title, body, silent }).show();
});
Configuring TV Series Update Notifications
User control over notification behavior is managed through a persistent storage layer that maintains preferences across application restarts.
Storage Layer and Preferences
All notification settings reside in src/utils/storage.js under the STORAGE_KEYS object. The system uses two specific keys for this feature:
NOTIFY_NEW_EPISODE– Boolean toggle enabling or disabling new-episode alertsNOTIFY_DOWNLOAD_COMPLETE– Separate toggle for download completion alerts
These values persist in localStorage with the streambert_ prefix, ensuring they remain scoped to the application domain.
Enabling Notifications in the UI
The Settings page (src/pages/SettingsPage.jsx) provides a toggle interface that reads and writes the NOTIFY_NEW_EPISODE key. When users interact with the checkbox, the application immediately persists the preference without requiring a restart.
import { storage, STORAGE_KEYS } from "../utils/storage";
function onToggleNewEpisode(e) {
storage.set(STORAGE_KEYS.NOTIFY_NEW_EPISODE, e.target.checked);
}
// Within JSX:
<input
type="checkbox"
checked={storage.get(STORAGE_KEYS.NOTIFY_NEW_EPISODE) ?? true}
onChange={onToggleNewEpisode}
/>
Detecting New Episodes Automatically
The background detection logic runs independently of user interaction, querying external APIs and comparing results against cached state to identify fresh releases.
The Episode Release Cache
To prevent duplicate alerts, the system maintains an EPISODE_RELEASE_CACHE in src/utils/storage.js. This cache stores the last-seen episode ID for each tracked TMDB series ID, allowing the application to distinguish between previously notified episodes and genuine new releases.
The cache structure maps TMDB IDs to episode metadata:
const cache = JSON.parse(localStorage.getItem("streambert_episodeReleaseCache") || "{}");
// Schema: { "1399": { "id": 12345, "season_number": 2, "episode_number": 5 }, ... }
TMDB Polling Logic
In src/index.js, a periodic job executes every 6 hours to poll the TMDB API for updates on tracked shows. The pollNewEpisodes() function retrieves the latest episode information using the tmdbFetch helper from src/utils/api.js, compares it against the cached data, and triggers notifications only when NOTIFY_NEW_EPISODE is enabled and a newer episode exists.
When the main process detects a new episode, it sends a message to the renderer via window.webContents.send, which then invokes the notification IPC channel:
if (notifyNewEpisode) {
window.webContents.send(
"show-notification",
{
title: "New episode available",
body: `${showName} – S${season}E${episode}`,
silent: false,
}
);
}
Complete Implementation Examples
Triggering Notifications from the Renderer
Any component in the React frontend can trigger notifications by calling the exposed bridge method:
if (window.electron?.showNotification) {
window.electron.showNotification({
title: "New episode released!",
body: "The latest episode of 'Stranger Things' is now available.",
silent: false,
});
}
Background Polling Implementation
The complete detection logic combines storage retrieval, API calls, and conditional notification dispatch:
async function pollNewEpisodes() {
const shows = getTrackedShows(); // stored TMDB ids
const cache = JSON.parse(localStorage.getItem("streambert_episodeReleaseCache") || "{}");
const notify = storage.get(STORAGE_KEYS.NOTIFY_NEW_EPISODE);
for (const { tmdbId, name } of shows) {
const latest = await fetchLatestEpisode(tmdbId); // TMDB "/tv/{id}/season/latest"
const cached = cache[tmdbId];
if (latest && (!cached || latest.id > cached.id)) {
cache[tmdbId] = latest;
if (notify) {
window.webContents.send("show-notification", {
title: "New episode released",
body: `${name} – S${latest.season_number}E${latest.episode_number}`,
silent: false,
});
}
}
}
localStorage.setItem("streambert_episodeReleaseCache", JSON.stringify(cache));
}
setInterval(pollNewEpisodes, 6 * 60 * 60 * 1000); // every 6h
Summary
- Electron IPC Architecture: The system uses
contextBridgeinsrc/preload.jsandipcMain.handleinsrc/index.jsto securely bridge notification requests between renderer and main processes. - Persistent Preferences: Notification toggles are stored in
localStorageviaSTORAGE_KEYS.NOTIFY_NEW_EPISODEinsrc/utils/storage.js, with thestreambert_prefix ensuring proper namespacing. - Duplicate Prevention: The
EPISODE_RELEASE_CACHEtracks the last-seen episode ID for each TMDB series, preventing redundant alerts when polling every 6 hours. - Privacy-First Design: All episode detection occurs locally using the TMDB API; no viewing history or notification data transmits to external analytics or cloud services.
- Native OS Integration: Notifications render as native system toasts with optional sound alerts, providing a seamless user experience without browser-style notification limitations.
Frequently Asked Questions
How does Streambert detect new episodes without missing releases?
The application polls the TMDB API every 6 hours for each tracked series, comparing the latest episode ID against the EPISODE_RELEASE_CACHE stored in localStorage. If the ID is newer than the cached value or no cache exists for that series, the system treats it as a new release and triggers the notification workflow.
Can users disable new episode notifications while keeping download notifications?
Yes. The STORAGE_KEYS object in src/utils/storage.js maintains separate boolean flags for NOTIFY_NEW_EPISODE and NOTIFY_DOWNLOAD_COMPLETE. Users can toggle these independently through the Settings interface, and each preference persists with its own streambert_ prefixed key in localStorage.
Why does Streambert use Electron's IPC instead of standard web notifications?
Standard web notifications require the renderer process to request permissions and cannot run when the application window is closed or backgrounded. By using ipcMain.handle in the main process (src/index.js) with contextBridge exposure, Streambert enables background polling to trigger native OS notifications even when the UI is not active, while maintaining security isolation between untrusted web content and Node.js APIs.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →