mirror of
https://github.com/dirtydishes/dreamio.git
synced 2026-06-06 13:37:24 +00:00
trace stremio subtitle discovery
This commit is contained in:
parent
ff0ee65538
commit
c571eb8873
4 changed files with 145 additions and 8 deletions
|
|
@ -19,3 +19,4 @@
|
|||
{"id":"int-c7246990","kind":"field_change","created_at":"2026-05-25T14:07:13.774172Z","actor":"dirtydishes","issue_id":"dreamio-e9p","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Added DEBUG-only subtitle pipeline proof logging and documented validation."}}
|
||||
{"id":"int-45781aa3","kind":"field_change","created_at":"2026-05-25T14:19:19.141163Z","actor":"dirtydishes","issue_id":"dreamio-c1m","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Added DEBUG-only logs for captions menu actions and VLC subtitle selection results."}}
|
||||
{"id":"int-6343b773","kind":"field_change","created_at":"2026-05-25T14:25:59.50764Z","actor":"dirtydishes","issue_id":"dreamio-bd9","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Stopped rebuilding the captions menu on every progress refresh and validated the build."}}
|
||||
{"id":"int-26b872a1","kind":"field_change","created_at":"2026-05-25T14:31:46.83464Z","actor":"dirtydishes","issue_id":"dreamio-ese","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Added subtitle-shaped fetch/XHR inspection diagnostics and validated the build."}}
|
||||
|
|
|
|||
|
|
@ -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-ese","title":"Discover Stremio external subtitle payloads","description":"Extend and instrument the injected web subtitle discovery path so Stremio/OpenSubtitles addon responses can be captured when native playback only sees embedded VLC subtitle tracks.","status":"closed","priority":1,"issue_type":"bug","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-25T14:29:57Z","created_by":"dirtydishes","updated_at":"2026-05-25T14:31:47Z","started_at":"2026-05-25T14:30:03Z","closed_at":"2026-05-25T14:31:47Z","close_reason":"Added subtitle-shaped fetch/XHR inspection diagnostics and validated the build.","dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||
{"_type":"issue","id":"dreamio-bd9","title":"Stabilize captions menu refresh","description":"Stop rebuilding the captions UIMenu on every playback progress refresh so embedded subtitle actions can remain stable long enough to fire, while keeping DEBUG logs for menu state and selection.","status":"closed","priority":1,"issue_type":"bug","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-25T14:24:45Z","created_by":"dirtydishes","updated_at":"2026-05-25T14:25:59Z","started_at":"2026-05-25T14:24:50Z","closed_at":"2026-05-25T14:25:59Z","close_reason":"Stopped rebuilding the captions menu on every progress refresh and validated the build.","dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||
{"_type":"issue","id":"dreamio-h5q","title":"Resolve OpenSubtitles API subtitle URLs before VLC attachment","description":"OpenSubtitles V3 can surface API/download endpoints that are not subtitle files themselves. Dreamio should resolve those endpoints to playable subtitle file URLs before handing them to VLC so Stremio does not show failed subtitle loads after native playback opens.","status":"closed","priority":1,"issue_type":"bug","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-25T13:47:17Z","created_by":"dirtydishes","updated_at":"2026-05-25T13:50:43Z","started_at":"2026-05-25T13:47:21Z","closed_at":"2026-05-25T13:50:43Z","close_reason":"Resolved OpenSubtitles V3 API-style subtitle download URLs to direct subtitle files before VLC attachment; added parser/resolver coverage and simulator build validation.","dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||
{"_type":"issue","id":"dreamio-lw6","title":"forward late opensubtitles subtitles to native player","description":"Native playback only receives subtitle candidates discovered before the stream candidate is posted. OpenSubtitles V3 candidates can arrive later through addon/network responses, so the active native player needs an append path for newly discovered external subtitles.","status":"closed","priority":1,"issue_type":"bug","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-25T10:40:28Z","created_by":"dirtydishes","updated_at":"2026-05-25T10:43:22Z","started_at":"2026-05-25T10:40:36Z","closed_at":"2026-05-25T10:43:22Z","close_reason":"Implemented late subtitle forwarding into active native playback, added VLC append path and parser tests.","dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ final class DreamioWebViewController: UIViewController {
|
|||
const subtitleCandidates = [];
|
||||
const postedSubtitleURLs = new Set();
|
||||
const subtitleURLPattern = /https?:\/\/[^\s"'<>]+(?:\.srt|\.vtt|\.ass|\.ssa|\.sub|opensubtitles|subtitle)[^\s"'<>]*/ig;
|
||||
const subtitleSignalPattern = /subtitle|subtitles|opensubtitles|vtt|srt|ass|ssa/i;
|
||||
|
||||
const looksNative = (url) => {
|
||||
if (!url || typeof url !== "string") {
|
||||
|
|
@ -126,7 +127,7 @@ final class DreamioWebViewController: UIViewController {
|
|||
} catch (_) {}
|
||||
};
|
||||
|
||||
const postSubtitleCandidates = (candidates) => {
|
||||
const postSubtitleCandidates = (candidates, debug = {}) => {
|
||||
const discoveredCount = candidates.length;
|
||||
const fresh = candidates.filter((candidate) => {
|
||||
if (postedSubtitleURLs.has(candidate.url)) {
|
||||
|
|
@ -143,7 +144,8 @@ final class DreamioWebViewController: UIViewController {
|
|||
debug: {
|
||||
discovered: discoveredCount,
|
||||
deduped: 0,
|
||||
forwarded: 0
|
||||
forwarded: 0,
|
||||
...debug
|
||||
}
|
||||
});
|
||||
} catch (_) {}
|
||||
|
|
@ -156,14 +158,28 @@ final class DreamioWebViewController: UIViewController {
|
|||
debug: {
|
||||
discovered: discoveredCount,
|
||||
deduped: fresh.length,
|
||||
forwarded: fresh.length
|
||||
forwarded: fresh.length,
|
||||
...debug
|
||||
}
|
||||
});
|
||||
} catch (_) {}
|
||||
};
|
||||
|
||||
const addSubtitleCandidate = (entry) => {
|
||||
const rawURL = typeof entry === "string" ? entry : entry && (entry.url || entry.href || entry.src || entry.file || entry.download);
|
||||
const rawURL = typeof entry === "string"
|
||||
? entry
|
||||
: entry && (
|
||||
entry.url ||
|
||||
entry.href ||
|
||||
entry.src ||
|
||||
entry.link ||
|
||||
entry.file ||
|
||||
entry.download ||
|
||||
entry.externalUrl ||
|
||||
entry.externalURL ||
|
||||
entry.fileUrl ||
|
||||
entry.fileURL
|
||||
);
|
||||
const url = absoluteURL(rawURL);
|
||||
subtitleURLPattern.lastIndex = 0;
|
||||
if (!url || !subtitleURLPattern.test(url)) {
|
||||
|
|
@ -183,6 +199,19 @@ final class DreamioWebViewController: UIViewController {
|
|||
postSubtitleCandidates([candidate]);
|
||||
};
|
||||
|
||||
const postSubtitleInspection = (source, url, beforeCount, afterCount, payloadLength) => {
|
||||
if (afterCount > beforeCount) {
|
||||
return;
|
||||
}
|
||||
postSubtitleCandidates([], {
|
||||
source,
|
||||
inspected: true,
|
||||
url: url || "",
|
||||
payloadLength: payloadLength || 0,
|
||||
totalKnown: subtitleCandidates.length
|
||||
});
|
||||
};
|
||||
|
||||
const inspectSubtitlePayload = (payload) => {
|
||||
if (!payload) {
|
||||
return;
|
||||
|
|
@ -206,6 +235,12 @@ final class DreamioWebViewController: UIViewController {
|
|||
}
|
||||
};
|
||||
|
||||
const inspectSubtitleText = (source, url, text) => {
|
||||
const beforeCount = subtitleCandidates.length;
|
||||
inspectSubtitlePayload(text);
|
||||
postSubtitleInspection(source, url, beforeCount, subtitleCandidates.length, text ? text.length : 0);
|
||||
};
|
||||
|
||||
const originalFetch = window.fetch;
|
||||
if (originalFetch) {
|
||||
window.fetch = async (...args) => {
|
||||
|
|
@ -216,10 +251,13 @@ final class DreamioWebViewController: UIViewController {
|
|||
subtitleURLPattern.lastIndex = 0;
|
||||
const shouldInspect = !contentType
|
||||
|| /json|text|javascript|xml|subtitle|vtt|srt/i.test(contentType)
|
||||
|| subtitleURLPattern.test(url);
|
||||
|| subtitleURLPattern.test(url)
|
||||
|| subtitleSignalPattern.test(url);
|
||||
if (shouldInspect) {
|
||||
subtitleURLPattern.lastIndex = 0;
|
||||
response.clone().text().then(inspectSubtitlePayload).catch(() => {});
|
||||
response.clone().text().then((text) => {
|
||||
inspectSubtitleText("fetch", url, text);
|
||||
}).catch(() => {});
|
||||
}
|
||||
} catch (_) {}
|
||||
return response;
|
||||
|
|
@ -235,7 +273,13 @@ final class DreamioWebViewController: UIViewController {
|
|||
if (responseType && responseType !== "text") {
|
||||
return;
|
||||
}
|
||||
inspectSubtitlePayload(this.responseText);
|
||||
const url = this.responseURL || "";
|
||||
const text = this.responseText || "";
|
||||
if (subtitleSignalPattern.test(url) || subtitleSignalPattern.test(text)) {
|
||||
inspectSubtitleText("xhr", url, text);
|
||||
} else {
|
||||
inspectSubtitlePayload(text);
|
||||
}
|
||||
} catch (_) {}
|
||||
});
|
||||
} catch (_) {}
|
||||
|
|
@ -685,8 +729,13 @@ final class DreamioWebViewController: UIViewController {
|
|||
let discovered = debug?["discovered"] as? Int ?? parsedCandidates.count
|
||||
let deduped = debug?["deduped"] as? Int ?? parsedCandidates.count
|
||||
let posted = debug?["forwarded"] as? Int ?? parsedCandidates.count
|
||||
let source = debug?["source"] as? String ?? "bridge"
|
||||
let inspected = debug?["inspected"] as? Bool ?? false
|
||||
let inspectedURL = (debug?["url"] as? String).map(redactedURLString) ?? "none"
|
||||
let payloadLength = debug?["payloadLength"] as? Int ?? 0
|
||||
let totalKnown = debug?["totalKnown"] as? Int ?? parsedCandidates.count
|
||||
let pageURL = dictionary?["pageUrl"] as? String
|
||||
print("[DreamioSubtitles] bridge discovered=\(discovered) deduped=\(deduped) posted=\(posted) parsed=\(parsedCandidates.count) playerActive=\(currentNativePlayer != nil) page=\(pageURL.map(redactedURLString) ?? "unknown") candidates=\(SubtitleDebugFormatter.candidateSummary(parsedCandidates))")
|
||||
print("[DreamioSubtitles] bridge source=\(source) inspected=\(inspected) discovered=\(discovered) deduped=\(deduped) posted=\(posted) parsed=\(parsedCandidates.count) totalKnown=\(totalKnown) payloadLength=\(payloadLength) playerActive=\(currentNativePlayer != nil) inspectedURL=\(inspectedURL) page=\(pageURL.map(redactedURLString) ?? "unknown") candidates=\(SubtitleDebugFormatter.candidateSummary(parsedCandidates))")
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue