mirror of
https://github.com/yattee/yattee.git
synced 2026-11-03 10:27:19 +00:00
Restore 1.x yattee:// links and harden URL scheme routing
- Route legacy yattee://watch?v=, yattee://youtube.com/..., yattee://https://... links like their web equivalents (only natively handled destinations) - Unwrap yattee://open?url= inside route() so every caller keeps the inner URL's own query items - Never route file:// URLs as direct media - Support source/instance on yattee://playlist and PeerTube /w/p/ and /video-playlists/ URLs - Leave open sheets alone and show a toast for links that go nowhere
This commit is contained in:
@@ -178,6 +178,78 @@ struct URLRouterTests {
|
||||
#expect(router.unwrapped(scheme) == scheme)
|
||||
}
|
||||
|
||||
@Test("route() unwraps yattee://open itself, keeping inner query items")
|
||||
func routeUnwrapsOpenWrapper() {
|
||||
let wrapper = URL(string: "yattee://open?url=https://www.youtube.com/watch?list=PLtest123&index=2")!
|
||||
if case .playlist(.remote(let id, _, _, _)) = router.route(wrapper) {
|
||||
#expect(id.playlistID == "PLtest123")
|
||||
} else {
|
||||
Issue.record("Expected playlist destination")
|
||||
}
|
||||
}
|
||||
|
||||
@Test("yattee://open with no inner URL routes nowhere")
|
||||
func emptyOpenWrapper() {
|
||||
#expect(router.route(URL(string: "yattee://open")!) == nil)
|
||||
#expect(router.route(URL(string: "yattee://open?url=")!) == nil)
|
||||
}
|
||||
|
||||
// MARK: - Local File Rejection
|
||||
|
||||
@Test("File URLs never route, directly or wrapped")
|
||||
func fileURLsRejected() {
|
||||
#expect(router.route(URL(string: "file:///private/var/mobile/movie.mp4")!) == nil)
|
||||
#expect(router.route(URL(string: "yattee://open?url=file:///private/var/mobile/movie.mp4")!) == nil)
|
||||
}
|
||||
|
||||
@Test("Remote direct media still routes")
|
||||
func remoteDirectMedia() {
|
||||
let url = URL(string: "https://example.com/video.mp4")!
|
||||
if case .directMedia(let media) = router.route(url) {
|
||||
#expect(media == url)
|
||||
} else {
|
||||
Issue.record("Expected directMedia destination")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Legacy (1.x) Scheme Tests
|
||||
|
||||
@Test("Legacy yattee:// links route like their web equivalents", arguments: [
|
||||
"yattee://watch?v=dQw4w9WgXcQ",
|
||||
"yattee://www.youtube.com/watch?v=dQw4w9WgXcQ",
|
||||
"yattee://youtube.com/watch?v=dQw4w9WgXcQ&t=30",
|
||||
"yattee://youtu.be/dQw4w9WgXcQ",
|
||||
"yattee://https://www.youtube.com/watch?v=dQw4w9WgXcQ",
|
||||
"yattee://shorts/dQw4w9WgXcQ",
|
||||
])
|
||||
func legacyVideoLinks(_ string: String) {
|
||||
if case .video(let source, _) = router.route(URL(string: string)!), case .id(let videoID) = source {
|
||||
#expect(videoID.videoID == "dQw4w9WgXcQ")
|
||||
} else {
|
||||
Issue.record("Expected video destination for \(string)")
|
||||
}
|
||||
}
|
||||
|
||||
@Test("Legacy playlist and channel links")
|
||||
func legacyPlaylistAndChannel() {
|
||||
if case .playlist(.remote(let id, _, _, _)) = router.route(URL(string: "yattee://playlist?list=PLtest123")!) {
|
||||
#expect(id.playlistID == "PLtest123")
|
||||
} else {
|
||||
Issue.record("Expected playlist destination")
|
||||
}
|
||||
if case .channel(let id, _) = router.route(URL(string: "yattee://www.youtube.com/@somehandle")!) {
|
||||
#expect(id == "@somehandle")
|
||||
} else {
|
||||
Issue.record("Expected channel destination")
|
||||
}
|
||||
}
|
||||
|
||||
@Test("Unknown yattee:// hosts still route nowhere")
|
||||
func unknownCustomHost() {
|
||||
#expect(router.route(URL(string: "yattee://nonsense")!) == nil)
|
||||
#expect(router.route(URL(string: "yattee://example.com/page")!) == nil)
|
||||
}
|
||||
|
||||
// MARK: - PeerTube URL Tests
|
||||
|
||||
@Test("Parse PeerTube /w/ video URL")
|
||||
@@ -514,6 +586,32 @@ struct URLRouterTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test("Parse yattee:// playlist URL with PeerTube source")
|
||||
func customSchemePeerTubePlaylist() {
|
||||
let url = URL(string: "yattee://playlist/abc123?source=peertube&instance=https://peertube.social")!
|
||||
if case .playlist(.remote(let id, _, _, _)) = router.route(url),
|
||||
case .federated(_, let instance) = id.source {
|
||||
#expect(id.playlistID == "abc123")
|
||||
#expect(instance.host == "peertube.social")
|
||||
} else {
|
||||
Issue.record("Expected federated playlist destination")
|
||||
}
|
||||
}
|
||||
|
||||
@Test("PeerTube playlist web URLs route to playlists, not videos", arguments: [
|
||||
"https://framatube.org/w/p/abc123",
|
||||
"https://framatube.org/video-playlists/abc123",
|
||||
])
|
||||
func peertubePlaylistURLs(_ string: String) {
|
||||
if case .playlist(.remote(let id, _, _, _)) = router.route(URL(string: string)!),
|
||||
case .federated(_, let instance) = id.source {
|
||||
#expect(id.playlistID == "abc123")
|
||||
#expect(instance.host == "framatube.org")
|
||||
} else {
|
||||
Issue.record("Expected federated playlist destination for \(string)")
|
||||
}
|
||||
}
|
||||
|
||||
@Test("Parse yattee:// channel URL with PeerTube source but no instance falls back to Global")
|
||||
func customSchemeChannelURLPeerTubeNoInstance() {
|
||||
// If source=peertube but no instance is provided, should fall back to Global
|
||||
|
||||
Reference in New Issue
Block a user