mirror of
https://github.com/yattee/yattee.git
synced 2025-08-06 10:44:06 +00:00
Improve URL handling
This commit is contained in:
@@ -211,6 +211,10 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI {
|
||||
resource(baseURL: account.url, path: basePathAppending("channels/\(id)"))
|
||||
}
|
||||
|
||||
func channelByName(_: String) -> Resource? {
|
||||
nil
|
||||
}
|
||||
|
||||
func channelVideos(_ id: String) -> Resource {
|
||||
resource(baseURL: account.url, path: basePathAppending("channels/\(id)/latest"))
|
||||
}
|
||||
|
@@ -40,6 +40,10 @@ final class PipedAPI: Service, ObservableObject, VideosAPI {
|
||||
self.extractChannel(from: content.json)
|
||||
}
|
||||
|
||||
configureTransformer(pathPattern("c/*")) { (content: Entity<JSON>) -> Channel? in
|
||||
self.extractChannel(from: content.json)
|
||||
}
|
||||
|
||||
configureTransformer(pathPattern("playlists/*")) { (content: Entity<JSON>) -> ChannelPlaylist? in
|
||||
self.extractChannelPlaylist(from: content.json)
|
||||
}
|
||||
@@ -125,6 +129,10 @@ final class PipedAPI: Service, ObservableObject, VideosAPI {
|
||||
resource(baseURL: account.url, path: "channel/\(id)")
|
||||
}
|
||||
|
||||
func channelByName(_ name: String) -> Resource? {
|
||||
resource(baseURL: account.url, path: "c/\(name)")
|
||||
}
|
||||
|
||||
func channelVideos(_ id: String) -> Resource {
|
||||
channel(id)
|
||||
}
|
||||
@@ -362,14 +370,12 @@ final class PipedAPI: Service, ObservableObject, VideosAPI {
|
||||
|
||||
func extractChannelPlaylist(from json: JSON) -> ChannelPlaylist? {
|
||||
let details = json.dictionaryValue
|
||||
let id = details["url"]?.string?.components(separatedBy: "?list=").last ?? UUID().uuidString
|
||||
let thumbnailURL = details["thumbnail"]?.url ?? details["thumbnailUrl"]?.url
|
||||
var videos = [Video]()
|
||||
if let relatedStreams = details["relatedStreams"] {
|
||||
videos = extractVideos(from: relatedStreams)
|
||||
}
|
||||
return ChannelPlaylist(
|
||||
id: id,
|
||||
title: details["name"]?.string ?? "",
|
||||
thumbnailURL: thumbnailURL,
|
||||
channel: extractChannel(from: json),
|
||||
|
@@ -7,6 +7,7 @@ protocol VideosAPI {
|
||||
var signedIn: Bool { get }
|
||||
|
||||
func channel(_ id: String) -> Resource
|
||||
func channelByName(_ name: String) -> Resource?
|
||||
func channelVideos(_ id: String) -> Resource
|
||||
func trending(country: Country, category: TrendingCategory?) -> Resource
|
||||
func search(_ query: SearchQuery, page: String?) -> Resource
|
||||
|
@@ -58,4 +58,8 @@ enum VideosApp: String, CaseIterable {
|
||||
var searchUsesIndexedPages: Bool {
|
||||
self == .invidious
|
||||
}
|
||||
|
||||
var supportsOpeningChannelsByName: Bool {
|
||||
self == .piped
|
||||
}
|
||||
}
|
||||
|
@@ -66,23 +66,23 @@ final class NavigationModel: ObservableObject {
|
||||
@Published var presentingSettings = false
|
||||
@Published var presentingWelcomeScreen = false
|
||||
|
||||
@Published var alert = Alert(title: Text("Error"))
|
||||
@Published var presentingAlert = false
|
||||
@Published var alertTitle = ""
|
||||
@Published var alertMessage = ""
|
||||
#if os(macOS)
|
||||
@Published var presentingAlertInVideoPlayer = false
|
||||
#endif
|
||||
|
||||
static func openChannel(
|
||||
_ channel: Channel,
|
||||
player: PlayerModel,
|
||||
recents: RecentsModel,
|
||||
navigation: NavigationModel,
|
||||
navigationStyle: NavigationStyle,
|
||||
delay: Bool = true
|
||||
navigation: NavigationModel
|
||||
) {
|
||||
guard channel.id != Video.fixtureChannelID else {
|
||||
return
|
||||
}
|
||||
|
||||
player.presentingPlayer = false
|
||||
player.hide()
|
||||
navigation.presentingChannel = false
|
||||
|
||||
let recent = RecentItem(from: channel)
|
||||
@@ -92,23 +92,11 @@ final class NavigationModel: ObservableObject {
|
||||
player.hide()
|
||||
#endif
|
||||
|
||||
let openRecent = {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
|
||||
recents.add(recent)
|
||||
navigation.presentingChannel = true
|
||||
}
|
||||
|
||||
if navigationStyle == .tab {
|
||||
if delay {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
openRecent()
|
||||
}
|
||||
} else {
|
||||
openRecent()
|
||||
}
|
||||
} else if navigationStyle == .sidebar {
|
||||
openRecent()
|
||||
navigation.sidebarSectionChanged.toggle()
|
||||
navigation.tabSelection = .recentlyOpened(recent.tag)
|
||||
navigation.presentingChannel = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,10 +104,9 @@ final class NavigationModel: ObservableObject {
|
||||
_ playlist: ChannelPlaylist,
|
||||
player: PlayerModel,
|
||||
recents: RecentsModel,
|
||||
navigation: NavigationModel,
|
||||
navigationStyle: NavigationStyle,
|
||||
delay: Bool = false
|
||||
navigation: NavigationModel
|
||||
) {
|
||||
navigation.presentingChannel = false
|
||||
navigation.presentingPlaylist = false
|
||||
|
||||
let recent = RecentItem(from: playlist)
|
||||
@@ -129,26 +116,43 @@ final class NavigationModel: ObservableObject {
|
||||
player.hide()
|
||||
#endif
|
||||
|
||||
let openRecent = {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
|
||||
recents.add(recent)
|
||||
navigation.presentingPlaylist = true
|
||||
}
|
||||
|
||||
if navigationStyle == .tab {
|
||||
if delay {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
openRecent()
|
||||
}
|
||||
} else {
|
||||
openRecent()
|
||||
}
|
||||
} else if navigationStyle == .sidebar {
|
||||
openRecent()
|
||||
navigation.sidebarSectionChanged.toggle()
|
||||
navigation.tabSelection = .recentlyOpened(recent.tag)
|
||||
navigation.presentingPlaylist = true
|
||||
}
|
||||
}
|
||||
|
||||
static func openSearchQuery(
|
||||
_ searchQuery: String?,
|
||||
player: PlayerModel,
|
||||
recents: RecentsModel,
|
||||
navigation: NavigationModel,
|
||||
search: SearchModel
|
||||
) {
|
||||
player.hide()
|
||||
navigation.presentingChannel = false
|
||||
navigation.presentingPlaylist = false
|
||||
navigation.tabSelection = .search
|
||||
|
||||
if let searchQuery = searchQuery {
|
||||
let recent = RecentItem(from: searchQuery)
|
||||
recents.add(recent)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
search.queryText = searchQuery
|
||||
search.changeQuery { query in query.query = searchQuery }
|
||||
}
|
||||
}
|
||||
|
||||
#if os(macOS)
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
Windows.main.focus()
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
var tabSelectionBinding: Binding<TabSelection> {
|
||||
Binding<TabSelection>(
|
||||
get: {
|
||||
@@ -187,8 +191,7 @@ final class NavigationModel: ObservableObject {
|
||||
}
|
||||
|
||||
func presentAlert(title: String, message: String) {
|
||||
alertTitle = title
|
||||
alertMessage = message
|
||||
alert = Alert(title: Text(title), message: Text(message))
|
||||
presentingAlert = true
|
||||
}
|
||||
}
|
||||
|
@@ -16,7 +16,7 @@ final class ThumbnailsModel: ObservableObject {
|
||||
}
|
||||
|
||||
func best(_ video: Video) -> URL? {
|
||||
let qualities = [Thumbnail.Quality.default]
|
||||
let qualities = [Thumbnail.Quality.maxresdefault, .medium, .default]
|
||||
|
||||
for quality in qualities {
|
||||
let url = video.thumbnailURL(quality: quality)
|
||||
|
Reference in New Issue
Block a user