# Streambert Download Progress Tracking and Completion Notification

> Streambert download progress tracking and completion notification. Monitor your video downloads in real-time with Streambert. Get notified when your downloads are complete.

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

---

**Streambert tracks video downloads by spawning the vid-dl-cli-only binary in the main process, parsing its real-time stdout/stderr output into structured progress objects, and broadcasting completion status to the renderer via Electron's `download-progress` IPC channel.**

Streambert is an Electron-based streaming application that manages video downloads through external CLI tools. Understanding how Streambert implements download progress tracking and completion notification requires examining the IPC architecture that bridges binary execution in the main process with the React-based user interface.

## Architecture Overview

The download tracking system spans three architectural layers. The **main process** handles binary execution and output parsing in [[`src/ipc/downloads.js`](https://github.com/truelockmc/streambert/blob/main/src/ipc/downloads.js)](https://github.com/truelockmc/streambert/blob/main/src/ipc/downloads.js). The **preload script** ([[`preload.js`](https://github.com/truelockmc/streambert/blob/main/preload.js)](https://github.com/truelockmc/streambert/blob/main/preload.js)) creates a secure bridge between main and renderer processes. Finally, **React components** like [[`DownloadModal.jsx`](https://github.com/truelockmc/streambert/blob/main/DownloadModal.jsx)](https://github.com/truelockmc/streambert/blob/main/src/components/DownloadModal.jsx) consume these events to update the user interface.

## Initiating Downloads

### The run-download IPC Handler

When a user starts a download, the renderer invokes the `run-download` channel through the exposed `window.ipc` API. The handler in [`src/ipc/downloads.js`](https://github.com/truelockmc/streambert/blob/main/src/ipc/downloads.js) generates a unique UUID for the download entry, creates a temporary log file, and spawns the vid-dl-cli-only binary using `child_process.spawn`.

```javascript
// Renderer process invocation
const result = await window.ipc.invoke('run-download', {
  binaryPath: '/usr/local/bin/vid-dl-cli-only',
  m3u8Url: playlistUrl,
  name: 'Movie Title',
  downloadPath: '/home/user/Videos',
  mediaId: '12345',
  mediaType: 'movie',
  season: null,
  episode: null,
  tmdbId: '67890',
  subtitles: [{ url: subtitleUrl, lang: 'en', name: 'English' }]
});

```

The IPC handler tracks the active process in an internal array, associates it with the generated UUID, and begins monitoring the streams.

## Real-Time Progress Parsing

### Binary Output Parsing

The vid-dl-cli-only binary writes status information to stdout and stderr in human-readable formats such as `(frag 12/200)`, `[download] 45% of 1.2 GiB at 3.5MiB/s`, and `size= 35.4MiB time=00:02:30.12`. The [`downloads.js`](https://github.com/truelockmc/streambert/blob/main/downloads.js) handler buffers this output, splits it into lines, and applies regular expressions to extract quantitative metrics.

Each parsed line updates a **partial progress object** containing:

- **`progress`**: Integer percentage (0-99) calculated from fragment counts or download percentage
- **`totalFragments`** and **`completedFragments`**: HLS segment counters
- **`size`**: Human-readable file size (e.g., "1.2 GiB")
- **`speed`**: Transfer rate (e.g., "3.5 MiB/s")
- **`lastMessage`**: Human-readable status line for UI display
- **`status`**: String value `"downloading"` while active

### Emitting Progress Updates

After processing each line, the handler calls `sendProgress()`, which broadcasts the update to all renderer processes via `webContents.send()`:

```javascript
function sendProgress(update) {
  const mw = _getMainWindow();
  if (mw && !mw.isDestroyed()) {
    mw.webContents.send('download-progress', update);
  }
}

```

This function ensures the main window receives the payload even if multiple downloads run concurrently.

## Completion Notification Flow

### Process Exit Handling

When the binary process closes, the exit code determines the final status. In the process close handler within [`src/ipc/downloads.js`](https://github.com/truelockmc/streambert/blob/main/src/ipc/downloads.js), the code evaluates the exit status:

```javascript
const status = code === 0 ? 'completed' : 'error';
downloads[idx].status = status;
downloads[idx].completedAt = Date.now();

if (code === 0) {
  downloads[idx].progress = 100;
  fs.unlinkSync(logPath); // Clean up temporary log
}

```

A **zero exit code** triggers the completion sequence, setting the progress to 100% and recording the completion timestamp. Non-zero codes mark the entry as an error state.

### Finalization and Cleanup

For successful downloads, the completion handler performs several finalization steps:

1. **File Resolution**: Locates the generated video file by scanning the destination directory if the "Destination" line was missed in output
2. **Renaming**: Sanitizes the filename to match the user-supplied title
3. **Size Calculation**: Determines the final on-disk file size
4. **Subtitle Processing**: Downloads requested subtitles via the `downloadSubtitleFile` helper function
5. **Store Update**: Persists the completed entry to the downloads store

The final broadcast payload sent via `sendProgress()` includes:

```json
{
  "id": "a1b2c3d4-...",
  "status": "completed",
  "progress": 100,
  "filePath": "/home/user/Videos/Movie Title.mp4",
  "size": "1.35 GiB",
  "lastMessage": "Completed"
}

```

## UI Integration

### Subscribing to Progress Events

The [[`preload.js`](https://github.com/truelockmc/streambert/blob/main/preload.js)](https://github.com/truelockmc/streambert/blob/main/preload.js) script exposes the `ipcRenderer` to the renderer process, forwarding the `download-progress` event through a safe API bridge. Components subscribe using `window.ipc.on()` and unsubscribe on unmount to prevent memory leaks.

```javascript
// In DownloadModal.jsx or any component
useEffect(() => {
  const onProgress = (_, update) => {
    setDownload(prev => ({ ...prev, [update.id]: update }));
  };
  
  window.ipc.on('download-progress', onProgress);
  
  return () => {
    window.ipc.removeListener('download-progress', onProgress);
  };
}, []);

```

### Displaying Status in Components

The **DownloadModal** component renders a progress bar using the `progress` field and conditionally displays completion UI when `status === 'completed'`. The **DownloadsPage** component maintains the list of all downloads by invoking `window.ipc.invoke('get-downloads')` on mount and merging real-time updates from the progress channel.

```jsx
{Object.values(downloads).map(item => (
  <div key={item.id} className="download-item">
    <h4>{item.name}</h4>
    <ProgressBar value={item.progress} />
    <p>{item.lastMessage}</p>
    
    {item.status === 'completed' && (
      <button onClick={() => window.ipc.invoke('show-in-folder', item.filePath)}>
        Open Folder
      </button>
    )}
    
    {item.status === 'error' && (
      <span className="error-text">Error: {item.lastMessage}</span>
    )}
  </div>
))}

```

## Persisting Download State

Download metadata persists to a JSON file ([`downloads.json`](https://github.com/truelockmc/streambert/blob/main/downloads.json)) in the Electron user data directory. The `loadDownloads()` function initializes the store on application startup, deduplicating entries and sorting by recent activity. The `saveDownloads()` function writes only completed or errored entries to disk, ensuring interrupted downloads do not leave stale data.

The UI retrieves the current list via the `get-downloads` IPC channel, while ongoing downloads receive live updates through the `download-progress` broadcast system, maintaining synchronization between the persistent store and the active interface.

## Summary

- **Streambert's download tracking** relies entirely on the IPC layer in [`src/ipc/downloads.js`](https://github.com/truelockmc/streambert/blob/main/src/ipc/downloads.js) to manage binary execution and output parsing.
- **Progress parsing** uses regular expressions against the vid-dl-cli-only binary's stdout/stderr, converting text lines into structured data objects.
- **Completion detection** occurs when the child process exits with code 0, triggering finalization steps including file renaming, subtitle downloads, and cleanup.
- **Renderer updates** flow through a single unified event (`download-progress`) consumed by components like [`DownloadModal.jsx`](https://github.com/truelockmc/streambert/blob/main/DownloadModal.jsx) and [`DownloadsPage.jsx`](https://github.com/truelockmc/streambert/blob/main/DownloadsPage.jsx).
- **State persistence** uses a local JSON store updated only when downloads reach terminal states (completed or error).

## Frequently Asked Questions

### How does Streambert parse download progress from the binary output?

Streambert parses progress by buffering the vid-dl-cli-only binary's stdout and stderr streams in [`src/ipc/downloads.js`](https://github.com/truelockmc/streambert/blob/main/src/ipc/downloads.js). The handler splits incoming data by lines and matches them against regular expressions to extract fragment counts, percentages, file sizes, and transfer speeds. Each match updates a progress object that is immediately broadcast to the renderer via the `download-progress` IPC event.

### What triggers the completion notification in Streambert?

Completion triggers when the spawned child process exits with code 0, detected in the process close handler within [`src/ipc/downloads.js`](https://github.com/truelockmc/streambert/blob/main/src/ipc/downloads.js). The handler sets the download status to `"completed"`, updates the progress to 100%, records the completion timestamp, and performs finalization tasks such as file renaming and subtitle downloading before broadcasting the final state to the UI.

### Where does Streambert store download progress data?

Streambert stores completed download metadata in a JSON file named [`downloads.json`](https://github.com/truelockmc/streambert/blob/main/downloads.json) located in the Electron user data directory. The `loadDownloads()` and `saveDownloads()` functions in the IPC handler manage this persistence. Active downloads exist only in memory and the IPC broadcast channel until they reach a terminal state (completed or error).

### Can I track download progress in a custom Streambert component?

Yes, any React component can track progress by subscribing to the `download-progress` event exposed through `window.ipc` in the preload script. Import `useEffect` from React, register a listener with `window.ipc.on('download-progress', handler)`, and remove it in the cleanup function to avoid memory leaks. The handler receives the update payload containing progress percentage, status, and file metadata.