# Streambert New Episode Notification System: How TV Series Updates Work

> Learn how Streambert's new episode notification system provides TV series updates using Electron IPC, localStorage caching, and TMDB polling. Get timely alerts without external services.

- Repository: [true_lock/streambert](https://github.com/truelockmc/streambert)
- Tags: how-to-guide
- Published: 2026-05-21

---

**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`](https://github.com/truelockmc/streambert/blob/main/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.

```javascript
// 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.

```javascript
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`](https://github.com/truelockmc/streambert/blob/main/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 alerts
- **`NOTIFY_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`](https://github.com/truelockmc/streambert/blob/main/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.

```javascript
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`](https://github.com/truelockmc/streambert/blob/main/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:

```javascript
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`](https://github.com/truelockmc/streambert/blob/main/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`](https://github.com/truelockmc/streambert/blob/main/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:

```javascript
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:

```javascript
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:

```javascript
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 `contextBridge` in [`src/preload.js`](https://github.com/truelockmc/streambert/blob/main/src/preload.js) and `ipcMain.handle` in [`src/index.js`](https://github.com/truelockmc/streambert/blob/main/src/index.js) to securely bridge notification requests between renderer and main processes.
- **Persistent Preferences**: Notification toggles are stored in `localStorage` via `STORAGE_KEYS.NOTIFY_NEW_EPISODE` in [`src/utils/storage.js`](https://github.com/truelockmc/streambert/blob/main/src/utils/storage.js), with the `streambert_` prefix ensuring proper namespacing.
- **Duplicate Prevention**: The `EPISODE_RELEASE_CACHE` tracks 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`](https://github.com/truelockmc/streambert/blob/main/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`](https://github.com/truelockmc/streambert/blob/main/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.