1
0
mirror of https://github.com/yattee/yattee.git synced 2024-12-15 14:50:32 +05:30
yattee/Model/Applications/VideosAPI.swift

182 lines
5.8 KiB
Swift
Raw Normal View History

2021-11-03 01:10:49 +05:30
import AVFoundation
2021-10-21 03:51:50 +05:30
import Foundation
import Siesta
protocol VideosAPI {
2021-10-27 04:29:59 +05:30
var account: Account! { get }
2021-10-21 03:51:50 +05:30
var signedIn: Bool { get }
func channel(_ id: String) -> Resource
2022-06-25 04:18:57 +05:30
func channelByName(_ name: String) -> Resource?
2022-06-30 05:01:51 +05:30
func channelByUsername(_ username: String) -> Resource?
2021-11-02 03:26:18 +05:30
func channelVideos(_ id: String) -> Resource
2021-10-21 03:51:50 +05:30
func trending(country: Country, category: TrendingCategory?) -> Resource
func search(_ query: SearchQuery, page: String?) -> Resource
2021-10-21 03:51:50 +05:30
func searchSuggestions(query: String) -> Resource
func video(_ id: Video.ID) -> Resource
var subscriptions: Resource? { get }
var feed: Resource? { get }
var home: Resource? { get }
var popular: Resource? { get }
var playlists: Resource? { get }
func subscribe(_ channelID: String, onCompletion: @escaping () -> Void)
func unsubscribe(_ channelID: String, onCompletion: @escaping () -> Void)
2021-10-21 03:51:50 +05:30
2021-11-02 03:26:18 +05:30
func playlist(_ id: String) -> Resource?
2021-10-21 03:51:50 +05:30
func playlistVideo(_ playlistID: String, _ videoID: String) -> Resource?
func playlistVideos(_ id: String) -> Resource?
2021-10-23 04:34:03 +05:30
func addVideoToPlaylist(
_ videoID: String,
_ playlistID: String,
onFailure: @escaping (RequestError) -> Void,
onSuccess: @escaping () -> Void
)
func removeVideoFromPlaylist(
_ index: String,
_ playlistID: String,
onFailure: @escaping (RequestError) -> Void,
onSuccess: @escaping () -> Void
)
func playlistForm(
_ name: String,
_ visibility: String,
playlist: Playlist?,
onFailure: @escaping (RequestError) -> Void,
onSuccess: @escaping (Playlist?) -> Void
)
func deletePlaylist(
_ playlist: Playlist,
onFailure: @escaping (RequestError) -> Void,
onSuccess: @escaping () -> Void
)
2021-10-23 04:34:03 +05:30
func channelPlaylist(_ id: String) -> Resource?
2022-06-30 04:14:32 +05:30
func loadDetails(
_ item: PlayerQueueItem,
failureHandler: ((RequestError) -> Void)?,
completionHandler: @escaping (PlayerQueueItem) -> Void
)
2021-11-03 01:10:49 +05:30
func shareURL(_ item: ContentItem, frontendHost: String?, time: CMTime?) -> URL?
2021-12-05 01:05:41 +05:30
func comments(_ id: Video.ID, page: String?) -> Resource?
}
extension VideosAPI {
2022-06-30 04:14:32 +05:30
func loadDetails(
_ item: PlayerQueueItem,
failureHandler: ((RequestError) -> Void)? = nil,
completionHandler: @escaping (PlayerQueueItem) -> Void = { _ in }
) {
guard (item.video?.streams ?? []).isEmpty else {
completionHandler(item)
return
}
2022-07-05 22:56:03 +05:30
video(item.videoID).load()
.onSuccess { response in
guard let video: Video = response.typedContent() else {
return
}
2022-07-05 22:56:03 +05:30
var newItem = item
newItem.video = video
2022-07-05 22:56:03 +05:30
completionHandler(newItem)
}
.onFailure { failureHandler?($0) }
}
2021-10-27 04:29:59 +05:30
2021-11-03 01:10:49 +05:30
func shareURL(_ item: ContentItem, frontendHost: String? = nil, time: CMTime? = nil) -> URL? {
2021-12-18 01:31:05 +05:30
guard let frontendHost = frontendHost ?? account?.instance?.frontendHost,
var urlComponents = account?.instance?.urlComponents
else {
2021-10-28 22:44:55 +05:30
return nil
}
urlComponents.host = frontendHost
2021-10-28 02:41:38 +05:30
2021-11-03 01:10:49 +05:30
var queryItems = [URLQueryItem]()
2021-10-27 04:29:59 +05:30
switch item.contentType {
case .video:
urlComponents.path = "/watch"
2021-11-03 01:10:49 +05:30
queryItems.append(.init(name: "v", value: item.video.videoID))
2021-10-27 04:29:59 +05:30
case .channel:
urlComponents.path = "/channel/\(item.channel.id)"
case .playlist:
urlComponents.path = "/playlist"
2021-11-03 01:10:49 +05:30
queryItems.append(.init(name: "list", value: item.playlist.id))
2022-03-27 16:19:57 +05:30
default:
return nil
2021-11-03 01:10:49 +05:30
}
if !time.isNil, time!.seconds.isFinite {
queryItems.append(.init(name: "t", value: "\(Int(time!.seconds))s"))
}
if !queryItems.isEmpty {
urlComponents.queryItems = queryItems
2021-10-27 04:29:59 +05:30
}
2021-11-13 21:15:47 +05:30
return urlComponents.url
2021-10-27 04:29:59 +05:30
}
func extractChapters(from description: String) -> [Chapter] {
guard let chaptersRegularExpression = try? NSRegularExpression(
pattern: "(?<start>(?:[0-9]+:){1,}(?:[0-9]+))(?:\\s)+(?:- ?)?(?<title>.*)",
options: .caseInsensitive
) else { return [] }
let chapterLines = chaptersRegularExpression.matches(
in: description,
range: NSRange(description.startIndex..., in: description)
)
return chapterLines.compactMap { line in
let titleRange = line.range(withName: "title")
let startRange = line.range(withName: "start")
guard let titleSubstringRange = Range(titleRange, in: description),
let startSubstringRange = Range(startRange, in: description),
let titleCapture = String(description[titleSubstringRange]),
let startCapture = String(description[startSubstringRange]) else { return nil }
let startComponents = startCapture.components(separatedBy: ":")
guard startComponents.count <= 3 else { return nil }
var hours: Double?
var minutes: Double?
var seconds: Double?
if startComponents.count == 3 {
hours = Double(startComponents[0])
minutes = Double(startComponents[1])
seconds = Double(startComponents[2])
} else if startComponents.count == 2 {
minutes = Double(startComponents[0])
seconds = Double(startComponents[1])
}
guard var startSeconds = seconds else { return nil }
if let minutes = minutes {
startSeconds += 60 * minutes
}
if let hours = hours {
startSeconds += 60 * 60 * hours
}
return .init(title: titleCapture, start: startSeconds)
}
}
2021-10-21 03:51:50 +05:30
}