Dreamio turn document · 2026-05-24 23:18 EDT · Beads issue dreamio-l68

Native Direct-Stream Playback for Debrid Files

Added a production WebKit-to-native playback path for direct-file debrid streams, with MKV, AVI, and WebM candidates routed into a new MobileVLCKit-backed player while ordinary HLS and MP4 web playback stay in Stremio Web.

WKWebView bridge Stream classification MobileVLCKit backend Sanitized diagnostics

Summary

This change keeps Stremio Web as Dreamio's main browsing and account UI, but intercepts direct-file stream URLs that iOS WebKit is likely to reject. Matching streams now open in a native fullscreen-style player with a close button and failure state.

Changes Made

Context

Dreamio started as a thin UIKit wrapper around hosted Stremio Web. That remains the product shape: login, browsing, addon setup, stream selection, popups, and compatible web media playback still belong to the web app. This work adds a native escape hatch only for direct-file streams that are likely to fail in iOS WebKit.

Important Implementation Details

Relevant Diff Snippets

Repository instructions prefer @pierre/diffs output. The package is installed as a library, but npx @pierre/diffs --help failed because it exposes no executable in this repo. This section uses a clearly labeled plain diff fallback.

diff --git a/Dreamio/DreamioWebViewController.swift b/Dreamio/DreamioWebViewController.swift
+ static let streamCandidateMessageHandler = "dreamioStreamCandidate"
+ configuration.userContentController.add(
+     WeakScriptMessageHandler(delegate: self),
+     name: Constants.streamCandidateMessageHandler
+ )
+ configuration.userContentController.addUserScript(Self.streamCandidateScript)
+
+ const nativePatterns = [
+   /\/\/addon\.debridio\.com\/play\//i,
+   /\/\/torrentio\.strem\.fun\/resolve\//i,
+   /\/\/download\.real-debrid\.com\//i,
+   /\.(mkv|avi|webm)(?:[?#]|$)/i
+ ];
+
+ private func handleStreamCandidate(_ candidate: StreamCandidate) {
+     guard let request = StreamClassifier.playbackRequest(from: candidate, userAgent: userAgent) else {
+         return
+     }
+     let player = NativePlayerViewController(request: request)
+     present(player, animated: true)
+ }

diff --git a/Dreamio/StreamCandidate.swift b/Dreamio/StreamCandidate.swift
+ enum StreamClassifier {
+     static func playbackRequest(
+         from candidate: StreamCandidate,
+         userAgent: String?
+     ) -> NativePlaybackRequest? {
+         let classification = classify(candidate: candidate)
+         guard classification.shouldIntercept else { return nil }
+         return NativePlaybackRequest(
+             playbackURL: candidate.resolverURL ?? candidate.observedURL,
+             observedURL: candidate.observedURL,
+             resolverURL: candidate.resolverURL,
+             pageURL: candidate.pageURL,
+             userAgent: userAgent,
+             referer: "https://web.stremio.com/",
+             classification: classification
+         )
+     }
+ }

diff --git a/Podfile b/Podfile
+ platform :ios, '16.0'
+ target 'Dreamio' do
+   use_frameworks!
+   pod 'MobileVLCKit'
+ end

Expected Impact for End-Users

Users should keep using Dreamio through the Stremio Web interface, but direct debrid MKV, AVI, and WebM streams should now open in native playback instead of falling through to WebKit's unsupported media failure path. Closing the native player returns to the same web session.

Validation

Issues, Limitations, and Mitigations

Follow-up Work