From 11b9c6a12ac9dd39aa3e0b50b521fea36a6d4d42 Mon Sep 17 00:00:00 2001 From: dirtydishes Date: Mon, 25 May 2026 12:34:06 -0400 Subject: [PATCH] accept stremio subtitle download urls --- .beads/interactions.jsonl | 1 + .beads/issues.jsonl | 1 + Dreamio/DreamioWebViewController.swift | 15 +- Dreamio/StreamCandidate.swift | 13 + Dreamio/StreamResolver.swift | 14 + Tests/StreamResolverTests.swift | 25 + ...accept-stremio-subtitle-download-urls.html | 472 ++++++++++++++++++ 7 files changed, 540 insertions(+), 1 deletion(-) create mode 100644 docs/turns/2026-05-25-accept-stremio-subtitle-download-urls.html diff --git a/.beads/interactions.jsonl b/.beads/interactions.jsonl index f943500..072f8e3 100644 --- a/.beads/interactions.jsonl +++ b/.beads/interactions.jsonl @@ -32,3 +32,4 @@ {"id":"int-fe1c7364","kind":"field_change","created_at":"2026-05-25T16:04:54.482803Z","actor":"dirtydishes","issue_id":"dreamio-656","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"fixed"}} {"id":"int-f9deecdb","kind":"field_change","created_at":"2026-05-25T16:18:29.458162Z","actor":"dirtydishes","issue_id":"dreamio-urs","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Fixed by rejecting OpenSubtitles manifest.json_N identifiers as playable subtitle URLs, promoting file_id values to API download URLs, and adding parser coverage for the live log shape."}} {"id":"int-569ee372","kind":"field_change","created_at":"2026-05-25T16:22:50.024736Z","actor":"dirtydishes","issue_id":"dreamio-433","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Fixed by tightening OpenSubtitles subtitle URL filtering in the web bridge and Swift parser, plus adding regression coverage for logged artwork and addon endpoint false positives."}} +{"id":"int-eca1f7f8","kind":"field_change","created_at":"2026-05-25T16:33:55.331041Z","actor":"dirtydishes","issue_id":"dreamio-9sp","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Accepted Stremio subtitle download URLs in the bridge, parser, resolver, and regression tests."}} diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 16c6888..179f5e5 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -1,4 +1,5 @@ {"_type":"issue","id":"dreamio-8cz","title":"fix stremio external subtitle loading regression","description":"After adding late subtitle forwarding for native playback, Stremio external subtitle loading is failing. Investigate the injected bridge and native subtitle forwarding path, then adjust behavior so Stremio can still load external subtitles while native playback receives late candidates.","status":"closed","priority":0,"issue_type":"bug","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-25T11:05:42Z","created_by":"dirtydishes","updated_at":"2026-05-25T11:07:35Z","started_at":"2026-05-25T11:05:55Z","closed_at":"2026-05-25T11:07:35Z","close_reason":"Hardened subtitle bridge network observers so non-text Stremio subtitle loads are not touched, and made parser traversal deterministic for metadata preservation.","dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"dreamio-9sp","title":"Accept Stremio subtitle download URLs","description":"Runtime logs show Stremio external subtitle tracks using subs5.strem.io /en/download URLs. The subtitle bridge and Swift parser currently reject those URLs because they do not have a subtitle file extension and are not on an OpenSubtitles host, so native playback receives zero external subtitle candidates.","status":"closed","priority":1,"issue_type":"bug","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-25T16:32:04Z","created_by":"dirtydishes","updated_at":"2026-05-25T16:33:55Z","started_at":"2026-05-25T16:32:10Z","closed_at":"2026-05-25T16:33:55Z","close_reason":"Accepted Stremio subtitle download URLs in the bridge, parser, resolver, and regression tests.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"dreamio-433","title":"Filter false OpenSubtitles subtitle candidates","description":"Dreamio is treating addon artwork and OpenSubtitles addon endpoints as external subtitle candidates, which causes the native player UI to show only embedded subtitles. Tighten subtitle URL detection in the web bridge and Swift parser, and add regression coverage for the logged false positives.","status":"closed","priority":1,"issue_type":"bug","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-25T16:20:47Z","created_by":"dirtydishes","updated_at":"2026-05-25T16:22:50Z","started_at":"2026-05-25T16:20:50Z","closed_at":"2026-05-25T16:22:50Z","close_reason":"Fixed by tightening OpenSubtitles subtitle URL filtering in the web bridge and Swift parser, plus adding regression coverage for logged artwork and addon endpoint false positives.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"dreamio-urs","title":"Fix OpenSubtitles manifest-style subtitle URLs","description":"OpenSubtitles subtitle candidates discovered from Stremio are being resolved as manifest.json_N URLs, producing 404s and leaving only embedded subtitles visible. Preserve and resolve real subtitle URLs so external subtitle tracks can attach in the native player.","status":"closed","priority":1,"issue_type":"bug","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-25T16:16:52Z","created_by":"dirtydishes","updated_at":"2026-05-25T16:18:29Z","started_at":"2026-05-25T16:16:57Z","closed_at":"2026-05-25T16:18:29Z","close_reason":"Fixed by rejecting OpenSubtitles manifest.json_N identifiers as playable subtitle URLs, promoting file_id values to API download URLs, and adding parser coverage for the live log shape.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"dreamio-656","title":"Capture OpenSubtitles candidates from Stremio app-state messages","description":"OpenSubtitlesV3 appears loaded in Stremio before native playback launches, but Dreamio forwards zero external subtitle candidates. The likely failure is not native-player timing; it is that the injected WebKit bridge does not extract Stremio's loaded subtitle metadata/state into URL candidates before opening VLC.","status":"closed","priority":1,"issue_type":"bug","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-25T16:00:09Z","created_by":"dirtydishes","updated_at":"2026-05-25T16:04:54Z","started_at":"2026-05-25T16:00:18Z","closed_at":"2026-05-25T16:04:54Z","close_reason":"fixed","dependency_count":0,"dependent_count":0,"comment_count":0} diff --git a/Dreamio/DreamioWebViewController.swift b/Dreamio/DreamioWebViewController.swift index c45e1d5..7ba97c4 100644 --- a/Dreamio/DreamioWebViewController.swift +++ b/Dreamio/DreamioWebViewController.swift @@ -169,12 +169,25 @@ final class DreamioWebViewController: UIViewController { } }; + const isStremioSubtitleDownloadURL = (url) => { + try { + const parsed = new URL(url, window.location.href); + const host = parsed.hostname.toLowerCase(); + const path = parsed.pathname.toLowerCase(); + return host === "strem.io" || host.endsWith(".strem.io") + ? /\/[a-z]{2,3}\/download(?:\/|$)/i.test(path) || /\/download(?:\/|$)/i.test(path) + : false; + } catch (_) { + return false; + } + }; + const isSubtitleURL = (url) => { if (!url || isOpenSubtitlesManifestID(url)) { return false; } return !isProbablyNonSubtitleAssetURL(url) - && (isDirectSubtitleFileURL(url) || isOpenSubtitlesDownloadURL(url)); + && (isDirectSubtitleFileURL(url) || isOpenSubtitlesDownloadURL(url) || isStremioSubtitleDownloadURL(url)); }; const findResolverURL = () => { diff --git a/Dreamio/StreamCandidate.swift b/Dreamio/StreamCandidate.swift index e735f88..b2345a4 100644 --- a/Dreamio/StreamCandidate.swift +++ b/Dreamio/StreamCandidate.swift @@ -256,6 +256,7 @@ enum SubtitleCandidateParser { } guard isDirectSubtitleFile(url) || isOpenSubtitlesDownloadURL(url) + || isStremioSubtitleDownloadURL(url) else { return nil } @@ -282,6 +283,18 @@ enum SubtitleCandidateParser { || path.range(of: #"(^|/)subtitles?(/|$)"#, options: .regularExpression) != nil } + private static func isStremioSubtitleDownloadURL(_ url: URL) -> Bool { + guard let host = url.host?.lowercased(), + host == "strem.io" || host.hasSuffix(".strem.io") + else { + return false + } + + let path = url.path.lowercased() + return path.range(of: #"^/[a-z]{2,3}/download(/|$)"#, options: .regularExpression) != nil + || path.range(of: #"(^|/)download(/|$)"#, options: .regularExpression) != nil + } + private static func isOpenSubtitlesManifestIdentifier(_ url: URL) -> Bool { guard url.host?.localizedCaseInsensitiveContains("opensubtitles") == true else { return false diff --git a/Dreamio/StreamResolver.swift b/Dreamio/StreamResolver.swift index 6aa7359..ffba9fd 100644 --- a/Dreamio/StreamResolver.swift +++ b/Dreamio/StreamResolver.swift @@ -131,6 +131,7 @@ final class SubtitleResolver: SubtitleResolving { let lowercased = url.absoluteString.lowercased() return ["srt", "vtt", "ass", "ssa", "sub"].contains(url.pathExtension.lowercased()) || [".srt?", ".vtt?", ".ass?", ".ssa?", ".sub?", ".srt&", ".vtt&", ".ass&", ".ssa&", ".sub&"].contains(where: lowercased.contains) + || isStremioSubtitleDownloadURL(url) } private static func shouldResolve(_ url: URL) -> Bool { @@ -138,6 +139,19 @@ final class SubtitleResolver: SubtitleResolving { return lowercased.contains("opensubtitles") || lowercased.contains("/subtitle") || lowercased.contains("subtitle") + || isStremioSubtitleDownloadURL(url) + } + + private static func isStremioSubtitleDownloadURL(_ url: URL) -> Bool { + guard let host = url.host?.lowercased(), + host == "strem.io" || host.hasSuffix(".strem.io") + else { + return false + } + + let path = url.path.lowercased() + return path.range(of: #"^/[a-z]{2,3}/download(/|$)"#, options: .regularExpression) != nil + || path.range(of: #"(^|/)download(/|$)"#, options: .regularExpression) != nil } private static func logRejected(_ candidate: SubtitleCandidate, responseURL: URL?, data: Data) -> SubtitleCandidate? { diff --git a/Tests/StreamResolverTests.swift b/Tests/StreamResolverTests.swift index 39854a8..8fc7c48 100644 --- a/Tests/StreamResolverTests.swift +++ b/Tests/StreamResolverTests.swift @@ -13,6 +13,7 @@ struct StreamResolverTests { testOpenSubtitlesNestedAttributesFilesParsing() testOpenSubtitlesManifestIDsAreNotResolvedAsSubtitles() testOpenSubtitlesArtworkAndAddonEndpointsAreIgnored() + testStremioSubtitleDownloadURLParsing() testOpenSubtitlesV3DownloadResponseResolution() testOpenSubtitlesNestedDownloadResponseResolution() await testSubtitleResolverDownloadJSONReturningLink() @@ -240,6 +241,30 @@ struct StreamResolverTests { assertEqual(candidates[0].label, "English") } + private static func testStremioSubtitleDownloadURLParsing() { + let payload: [String: Any] = [ + "subtitles": [ + [ + "label": "English", + "lang": "eng", + "url": "https://subs5.strem.io/en/download/subencoding-stremio-utf8/src-api/file/1952341941" + ], + [ + "label": "Not a subtitle", + "url": "https://www.strem.io/images/addons/opensubtitles-logo.png" + ] + ] + ] + + let candidates = SubtitleCandidateParser.candidates(in: payload) + + assertEqual(candidates.count, 1) + assertEqual(candidates[0].url.absoluteString, "https://subs5.strem.io/en/download/subencoding-stremio-utf8/src-api/file/1952341941") + assertEqual(candidates[0].label, "English") + assertEqual(candidates[0].language, "eng") + assert(SubtitleResolver.isDirectSubtitleFile(candidates[0].url), "Expected Stremio subtitle downloads to be attachable without another resolver hop") + } + private static func testOpenSubtitlesV3DownloadResponseResolution() { let payload = """ { diff --git a/docs/turns/2026-05-25-accept-stremio-subtitle-download-urls.html b/docs/turns/2026-05-25-accept-stremio-subtitle-download-urls.html new file mode 100644 index 0000000..378cacd --- /dev/null +++ b/docs/turns/2026-05-25-accept-stremio-subtitle-download-urls.html @@ -0,0 +1,472 @@ + + + + + + Accept Stremio Subtitle Download URLs + + + +
+
+

Dreamio turn document

+

Accept Stremio subtitle download URLs

+

External subtitles from Stremio can arrive as subs*.strem.io/en/download/... URLs with no subtitle file extension. Dreamio now recognizes that shape in the injected bridge, Swift parser, and native subtitle resolver so those tracks can reach VLC instead of disappearing before playback.

+
+ Date: 2026-05-25 + Issue: dreamio-9sp + Scope: subtitles, native playback +
+
+ +
+

Summary

+

The pasted logs showed Stremio reporting a failed external subtitle track at https://subs5.strem.io/en/download/subencoding-stremio-utf8/src-api/file/1952341941, while Dreamio logged zero parsed subtitle candidates. The fix adds Stremio subtitle download URL recognition so those URLs are accepted as real external subtitle candidates.

+
+ +
+

Changes Made

+
    +
  • Updated the injected WebKit subtitle bridge to treat strem.io and *.strem.io download paths as subtitle URLs.
  • +
  • Updated SubtitleCandidateParser to parse the same Stremio download URL shape from Stremio payloads.
  • +
  • Updated SubtitleResolver so Stremio subtitle download URLs are considered directly attachable instead of requiring a second resolver response.
  • +
  • Added a focused regression test for the exact subs5.strem.io/en/download/... form from the runtime log.
  • +
+
+ +
+

Context

+

Before this change, Dreamio only accepted direct subtitle file extensions or OpenSubtitles-looking download endpoints. Stremio’s web player can expose external subtitles through a host like subs5.strem.io, where the path identifies a subtitle download but the URL does not end in .srt, .vtt, or similar.

+

That mismatch explains the log pattern: bridge inspection saw likely payload objects, but Swift parsed zero usable candidates and the native player only saw embedded VLC subtitle tracks.

+
+ +
+

Important Implementation Details

+
    +
  • The accepted Stremio pattern is intentionally narrow: hosts must be strem.io or end in .strem.io, and paths must include /download, with language-prefixed forms such as /en/download/... supported.
  • +
  • Image and addon endpoints such as www.strem.io/images/addons/opensubtitles-logo.png are still rejected by the non-subtitle extension filter.
  • +
  • Marking these URLs as direct subtitle files lets VLC receive the URL directly through addPlaybackSlave, which matches the way Stremio labels the track URL.
  • +
+
+ +
+

Relevant Diff Snippets

+

Rendered with @pierre/diffs/ssr using one patch per changed file.

+

Dreamio/DreamioWebViewController.swift

Dreamio/DreamioWebViewController.swift
-1+14
168 unmodified lines
169
170
171
172
173
174
175
176
177
178
179
180
168 unmodified lines
}
};
+
const isSubtitleURL = (url) => {
if (!url || isOpenSubtitlesManifestID(url)) {
return false;
}
return !isProbablyNonSubtitleAssetURL(url)
&& (isDirectSubtitleFileURL(url) || isOpenSubtitlesDownloadURL(url));
};
+
const findResolverURL = () => {
168 unmodified lines
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
168 unmodified lines
}
};
+
const isStremioSubtitleDownloadURL = (url) => {
try {
const parsed = new URL(url, window.location.href);
const host = parsed.hostname.toLowerCase();
const path = parsed.pathname.toLowerCase();
return host === "strem.io" || host.endsWith(".strem.io")
? /\/[a-z]{2,3}\/download(?:\/|$)/i.test(path) || /\/download(?:\/|$)/i.test(path)
: false;
} catch (_) {
return false;
}
};
+
const isSubtitleURL = (url) => {
if (!url || isOpenSubtitlesManifestID(url)) {
return false;
}
return !isProbablyNonSubtitleAssetURL(url)
&& (isDirectSubtitleFileURL(url) || isOpenSubtitlesDownloadURL(url) || isStremioSubtitleDownloadURL(url));
};
+
const findResolverURL = () => {
+

Dreamio/StreamCandidate.swift

Dreamio/StreamCandidate.swift
+13
255 unmodified lines
256
257
258
259
260
261
20 unmodified lines
282
283
284
285
286
287
255 unmodified lines
}
guard isDirectSubtitleFile(url)
|| isOpenSubtitlesDownloadURL(url)
else {
return nil
}
20 unmodified lines
|| path.range(of: #"(^|/)subtitles?(/|$)"#, options: .regularExpression) != nil
}
+
private static func isOpenSubtitlesManifestIdentifier(_ url: URL) -> Bool {
guard url.host?.localizedCaseInsensitiveContains("opensubtitles") == true else {
return false
255 unmodified lines
256
257
258
259
260
261
262
20 unmodified lines
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
255 unmodified lines
}
guard isDirectSubtitleFile(url)
|| isOpenSubtitlesDownloadURL(url)
|| isStremioSubtitleDownloadURL(url)
else {
return nil
}
20 unmodified lines
|| path.range(of: #"(^|/)subtitles?(/|$)"#, options: .regularExpression) != nil
}
+
private static func isStremioSubtitleDownloadURL(_ url: URL) -> Bool {
guard let host = url.host?.lowercased(),
host == "strem.io" || host.hasSuffix(".strem.io")
else {
return false
}
+
let path = url.path.lowercased()
return path.range(of: #"^/[a-z]{2,3}/download(/|$)"#, options: .regularExpression) != nil
|| path.range(of: #"(^|/)download(/|$)"#, options: .regularExpression) != nil
}
+
private static func isOpenSubtitlesManifestIdentifier(_ url: URL) -> Bool {
guard url.host?.localizedCaseInsensitiveContains("opensubtitles") == true else {
return false
+

Dreamio/StreamResolver.swift

Dreamio/StreamResolver.swift
+14
130 unmodified lines
131
132
133
134
135
136
1 unmodified line
138
139
140
141
142
143
130 unmodified lines
let lowercased = url.absoluteString.lowercased()
return ["srt", "vtt", "ass", "ssa", "sub"].contains(url.pathExtension.lowercased())
|| [".srt?", ".vtt?", ".ass?", ".ssa?", ".sub?", ".srt&", ".vtt&", ".ass&", ".ssa&", ".sub&"].contains(where: lowercased.contains)
}
+
private static func shouldResolve(_ url: URL) -> Bool {
1 unmodified line
return lowercased.contains("opensubtitles")
|| lowercased.contains("/subtitle")
|| lowercased.contains("subtitle")
}
+
private static func logRejected(_ candidate: SubtitleCandidate, responseURL: URL?, data: Data) -> SubtitleCandidate? {
130 unmodified lines
131
132
133
134
135
136
137
1 unmodified line
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
130 unmodified lines
let lowercased = url.absoluteString.lowercased()
return ["srt", "vtt", "ass", "ssa", "sub"].contains(url.pathExtension.lowercased())
|| [".srt?", ".vtt?", ".ass?", ".ssa?", ".sub?", ".srt&", ".vtt&", ".ass&", ".ssa&", ".sub&"].contains(where: lowercased.contains)
|| isStremioSubtitleDownloadURL(url)
}
+
private static func shouldResolve(_ url: URL) -> Bool {
1 unmodified line
return lowercased.contains("opensubtitles")
|| lowercased.contains("/subtitle")
|| lowercased.contains("subtitle")
|| isStremioSubtitleDownloadURL(url)
}
+
private static func isStremioSubtitleDownloadURL(_ url: URL) -> Bool {
guard let host = url.host?.lowercased(),
host == "strem.io" || host.hasSuffix(".strem.io")
else {
return false
}
+
let path = url.path.lowercased()
return path.range(of: #"^/[a-z]{2,3}/download(/|$)"#, options: .regularExpression) != nil
|| path.range(of: #"(^|/)download(/|$)"#, options: .regularExpression) != nil
}
+
private static func logRejected(_ candidate: SubtitleCandidate, responseURL: URL?, data: Data) -> SubtitleCandidate? {
+

Tests/StreamResolverTests.swift

Tests/StreamResolverTests.swift
+25
12 unmodified lines
13
14
15
16
17
18
221 unmodified lines
240
241
242
243
244
245
12 unmodified lines
testOpenSubtitlesNestedAttributesFilesParsing()
testOpenSubtitlesManifestIDsAreNotResolvedAsSubtitles()
testOpenSubtitlesArtworkAndAddonEndpointsAreIgnored()
testOpenSubtitlesV3DownloadResponseResolution()
testOpenSubtitlesNestedDownloadResponseResolution()
await testSubtitleResolverDownloadJSONReturningLink()
221 unmodified lines
assertEqual(candidates[0].label, "English")
}
+
private static func testOpenSubtitlesV3DownloadResponseResolution() {
let payload = """
{
12 unmodified lines
13
14
15
16
17
18
19
221 unmodified lines
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
12 unmodified lines
testOpenSubtitlesNestedAttributesFilesParsing()
testOpenSubtitlesManifestIDsAreNotResolvedAsSubtitles()
testOpenSubtitlesArtworkAndAddonEndpointsAreIgnored()
testStremioSubtitleDownloadURLParsing()
testOpenSubtitlesV3DownloadResponseResolution()
testOpenSubtitlesNestedDownloadResponseResolution()
await testSubtitleResolverDownloadJSONReturningLink()
221 unmodified lines
assertEqual(candidates[0].label, "English")
}
+
private static func testStremioSubtitleDownloadURLParsing() {
let payload: [String: Any] = [
"subtitles": [
[
"label": "English",
"lang": "eng",
"url": "https://subs5.strem.io/en/download/subencoding-stremio-utf8/src-api/file/1952341941"
],
[
"label": "Not a subtitle",
"url": "https://www.strem.io/images/addons/opensubtitles-logo.png"
]
]
]
+
let candidates = SubtitleCandidateParser.candidates(in: payload)
+
assertEqual(candidates.count, 1)
assertEqual(candidates[0].url.absoluteString, "https://subs5.strem.io/en/download/subencoding-stremio-utf8/src-api/file/1952341941")
assertEqual(candidates[0].label, "English")
assertEqual(candidates[0].language, "eng")
assert(SubtitleResolver.isDirectSubtitleFile(candidates[0].url), "Expected Stremio subtitle downloads to be attachable without another resolver hop")
}
+
private static func testOpenSubtitlesV3DownloadResponseResolution() {
let payload = """
{
+
+
+ +
+

Expected Impact for End-Users

+

When Stremio exposes external subtitles through subs*.strem.io download URLs, Dreamio should now carry those subtitles into the native VLC player instead of showing only embedded subtitle tracks in the UI.

+
+ +
+

Validation

+
    +
  • Passed: swiftc Dreamio/StreamCandidate.swift Dreamio/StreamResolver.swift Tests/StreamResolverTests.swift -o /tmp/StreamResolverTests && /tmp/StreamResolverTests
  • +
  • Passed: DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer xcodebuild -workspace Dreamio.xcworkspace -scheme Dreamio -configuration Debug -sdk iphonesimulator build
  • +
+
+ +
+

Issues, Limitations, and Mitigations

+
    +
  • This was validated against the URL shape visible in the logs, not by replaying the exact remote Stremio session inside the app.
  • +
  • If Stremio introduces a different subtitle CDN path that does not include /download, another narrow allow-list entry may be needed.
  • +
  • The existing debug logging should now show parsed candidates for this URL form, which makes the next runtime check straightforward.
  • +
+
+ +
+

Follow-up Work

+

No new follow-up issue was filed. The next useful check is runtime validation on the same episode: look for parsed=1, nonzero native subtitle candidates, and a [DreamioVLC] attach accepted subtitle=... line for the Stremio subtitle download URL.

+
+
+ + \ No newline at end of file