mirror of
https://github.com/yattee/yattee.git
synced 2026-08-05 23:01:28 +00:00
Fix timed links resuming at watch position instead of URL timestamp
Timed links arrive wrapped as yattee://open?url=... from the share extension, but the timestamp was parsed from the wrapper URL, where a single-? form like youtu.be/ID?t=N hides t inside the url query item. With no startTime the player fell back to saved watch progress. - Add URLRouter.unwrapped(_:) resolving the wrapper to the inner URL (raw remainder after ?url=, since the share extension does not encode & and URLComponents would drop &t= parts) and use it in handleDeepLink - Thread forceStartTime through openVideo/playPreferringDownloaded/play so explicit link timestamps beat the 90%-watched restart threshold, clamped to just before the end; resume flows keep the old behavior - Carry the parsed timestamp through OpenLinkSheet's play action, which dropped it entirely - Cover timestamp parsing and wrapper unwrapping in NavigationTests
This commit is contained in:
@@ -96,6 +96,32 @@ struct URLRouter: Sendable {
|
||||
return true
|
||||
}
|
||||
|
||||
// MARK: - Wrapper Unwrapping
|
||||
|
||||
/// Resolve a `yattee://open?url={encoded_url}` wrapper (share extension) to the inner URL.
|
||||
/// Returns the input unchanged for any other URL. The wrapper's query holds the full
|
||||
/// original link, so timestamp parsing must run against the unwrapped URL.
|
||||
///
|
||||
/// The share extension encodes with `.urlQueryAllowed`, which leaves `?`, `&`, and `=`
|
||||
/// intact - URLComponents would split the inner URL's own query into separate wrapper
|
||||
/// items (losing e.g. `&t=120`), so take the raw remainder after `?url=` instead.
|
||||
func unwrapped(_ url: URL) -> URL {
|
||||
guard url.scheme?.lowercased() == "yattee", url.host == "open",
|
||||
let range = url.absoluteString.range(of: "?url=") else {
|
||||
return url
|
||||
}
|
||||
let raw = String(url.absoluteString[range.upperBound...])
|
||||
guard let decoded = raw.removingPercentEncoding,
|
||||
let innerURL = URL(string: decoded) else {
|
||||
return url
|
||||
}
|
||||
// Unwrap once more in case the wrapper was itself wrapped
|
||||
if innerURL.scheme?.lowercased() == "yattee", innerURL.host == "open", innerURL != url {
|
||||
return unwrapped(innerURL)
|
||||
}
|
||||
return innerURL
|
||||
}
|
||||
|
||||
// MARK: - Timestamp Parsing
|
||||
|
||||
/// Extract a timestamp (seconds) from a URL's query, supporting `t`, `time`, and `start`.
|
||||
|
||||
Reference in New Issue
Block a user