Channel playlists support

This commit is contained in:
Arkadiusz Fal
2021-10-23 01:04:03 +02:00
parent 4307da57c5
commit 734bb31260
22 changed files with 402 additions and 89 deletions

View File

@@ -95,8 +95,7 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI {
if type == "channel" {
return ContentItem(channel: InvidiousAPI.extractChannel(from: $0))
} else if type == "playlist" {
// TODO: fix playlists
return ContentItem(playlist: Playlist(JSON(parseJSON: "{}")))
return ContentItem(playlist: InvidiousAPI.extractChannelPlaylist(from: $0))
}
return ContentItem(video: InvidiousAPI.extractVideo($0))
}
@@ -143,6 +142,10 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI {
content.json.arrayValue.map(InvidiousAPI.extractVideo)
}
configureTransformer(pathPattern("playlists/*"), requestMethods: [.get]) { (content: Entity<JSON>) -> ChannelPlaylist in
InvidiousAPI.extractChannelPlaylist(from: content.json)
}
configureTransformer(pathPattern("videos/*"), requestMethods: [.get]) { (content: Entity<JSON>) -> Video in
InvidiousAPI.extractVideo(content.json)
}
@@ -214,6 +217,10 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI {
playlist(playlistID)?.child("videos").child(videoID)
}
func channelPlaylist(_ id: String) -> Resource? {
resource(baseURL: account.url, path: basePathAppending("playlists/\(id)"))
}
func search(_ query: SearchQuery) -> Resource {
var resource = resource(baseURL: account.url, path: basePathAppending("search"))
.withParam("q", searchQuery(query.query))
@@ -325,6 +332,21 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI {
)
}
static func extractChannelPlaylist(from json: JSON) -> ChannelPlaylist {
let details = json.dictionaryValue
return ChannelPlaylist(
id: details["playlistId"]!.stringValue,
title: details["title"]!.stringValue,
thumbnailURL: details["playlistThumbnail"]?.url,
channel: extractChannel(from: json),
videos: details["videos"]?.arrayValue.compactMap(InvidiousAPI.extractVideo) ?? []
)
}
static func extractChannelPlaylists(from json: JSON) -> [ChannelPlaylist] {
json.arrayValue.map(InvidiousAPI.extractChannelPlaylist)
}
private static func extractThumbnails(from details: JSON) -> [Thumbnail] {
details["videoThumbnails"].arrayValue.map { json in
Thumbnail(url: json["url"].url!, quality: .init(rawValue: json["quality"].string!)!)

View File

@@ -35,6 +35,10 @@ final class PipedAPI: Service, ObservableObject, VideosAPI {
PipedAPI.extractChannel(content.json)
}
configureTransformer(pathPattern("playlists/*")) { (content: Entity<JSON>) -> ChannelPlaylist? in
PipedAPI.extractChannelPlaylist(from: content.json)
}
configureTransformer(pathPattern("streams/*")) { (content: Entity<JSON>) -> Video? in
PipedAPI.extractVideo(content.json)
}
@@ -56,6 +60,10 @@ final class PipedAPI: Service, ObservableObject, VideosAPI {
resource(baseURL: account.url, path: "channel/\(id)")
}
func channelPlaylist(_ id: String) -> Resource? {
resource(baseURL: account.url, path: "playlists/\(id)")
}
func trending(country: Country, category _: TrendingCategory? = nil) -> Resource {
resource(baseURL: account.instance.url, path: "trending")
.withParam("region", country.rawValue)
@@ -118,7 +126,9 @@ final class PipedAPI: Service, ObservableObject, VideosAPI {
}
case .playlist:
return nil
if let playlist = PipedAPI.extractChannelPlaylist(from: content) {
return ContentItem(playlist: playlist)
}
case .channel:
if let channel = PipedAPI.extractChannel(content) {
@@ -136,7 +146,7 @@ final class PipedAPI: Service, ObservableObject, VideosAPI {
private static func extractChannel(_ content: JSON) -> Channel? {
let attributes = content.dictionaryValue
guard let id = attributes["id"]?.stringValue ??
attributes["url"]?.stringValue.components(separatedBy: "/").last
(attributes["url"] ?? attributes["uploaderUrl"])?.stringValue.components(separatedBy: "/").last
else {
return nil
}
@@ -157,6 +167,28 @@ final class PipedAPI: Service, ObservableObject, VideosAPI {
)
}
static func extractChannelPlaylist(from json: JSON) -> ChannelPlaylist? {
let details = json.dictionaryValue
let id = details["url"]?.stringValue.components(separatedBy: "?list=").last ?? UUID().uuidString
let thumbnailURL = details["thumbnail"]?.url ?? details["thumbnailUrl"]?.url
var videos = [Video]()
if let relatedStreams = details["relatedStreams"] {
videos = PipedAPI.extractVideos(relatedStreams)
}
return ChannelPlaylist(
id: id,
title: details["name"]!.stringValue,
thumbnailURL: thumbnailURL,
channel: extractChannel(json)!,
videos: videos,
videosCount: details["videos"]?.int
)
}
static func extractChannelPlaylists(from json: JSON) -> [ChannelPlaylist] {
json.arrayValue.compactMap(PipedAPI.extractChannelPlaylist)
}
private static func extractVideo(_ content: JSON) -> Video? {
let details = content.dictionaryValue
let url = details["url"]?.string

View File

@@ -21,4 +21,6 @@ protocol VideosAPI {
func playlistVideo(_ playlistID: String, _ videoID: String) -> Resource?
func playlistVideos(_ id: String) -> Resource?
func channelPlaylist(_ id: String) -> Resource?
}