1
0
mirror of https://github.com/yattee/yattee.git synced 2024-12-15 06:40:32 +05:30
yattee/Model/SponsorBlock/SponsorBlockAPI.swift

128 lines
4.3 KiB
Swift
Raw Normal View History

2021-10-23 22:19:45 +05:30
import Alamofire
import Defaults
import Foundation
import Logging
import SwiftyJSON
final class SponsorBlockAPI: ObservableObject {
static let categories = ["sponsor", "selfpromo", "intro", "outro", "interaction", "music_offtopic"]
let logger = Logger(label: "stream.yattee.app.sb")
2021-10-24 14:46:04 +05:30
2021-10-23 22:19:45 +05:30
@Published var videoID: String?
@Published var segments = [Segment]()
static func categoryDescription(_ name: String) -> String? {
2023-09-23 18:37:27 +05:30
guard categories.contains(name) else {
2021-10-23 22:19:45 +05:30
return nil
}
switch name {
2022-09-04 20:58:30 +05:30
case "sponsor":
return "Sponsor".localized()
2021-10-23 22:19:45 +05:30
case "selfpromo":
2022-09-04 20:58:30 +05:30
return "Self-promotion".localized()
case "intro":
return "Intro".localized()
case "outro":
return "Outro".localized()
case "interaction":
return "Interaction".localized()
2021-10-23 22:19:45 +05:30
case "music_offtopic":
2022-09-04 20:58:30 +05:30
return "Offtopic in Music Videos".localized()
2021-10-23 22:19:45 +05:30
default:
return name.capitalized
}
}
2022-01-08 00:16:47 +05:30
static func categoryDetails(_ name: String) -> String? {
2023-09-23 18:37:27 +05:30
guard categories.contains(name) else {
2022-01-08 00:16:47 +05:30
return nil
}
switch name {
case "sponsor":
2022-09-04 20:58:30 +05:30
return ("Part of a video promoting a product or service not directly related to the creator. " +
"The creator will receive payment or compensation in the form of money or free products.").localized()
2022-01-08 00:16:47 +05:30
case "selfpromo":
2022-09-04 20:58:30 +05:30
return ("Promoting a product or service that is directly related to the creator themselves. " +
"This usually includes merchandise or promotion of monetized platforms.").localized()
2022-01-08 00:16:47 +05:30
case "intro":
2022-09-04 20:58:30 +05:30
return ("Segments typically found at the start of a video that include an animation, " +
"still frame or clip which are also seen in other videos by the same creator.").localized()
2022-01-08 00:16:47 +05:30
case "outro":
2023-04-22 14:26:18 +05:30
return "Typically near or at the end of the video when the credits pop up and/or endcards are shown.".localized()
2022-01-08 00:16:47 +05:30
case "interaction":
2023-04-22 14:26:18 +05:30
return "Explicit reminders to like, subscribe or interact with them on any paid or free platform(s) (e.g. click on a video).".localized()
2022-01-08 00:16:47 +05:30
case "music_offtopic":
2023-04-22 14:26:18 +05:30
return "For videos which feature music as the primary content.".localized()
2022-01-08 00:16:47 +05:30
default:
return nil
}
}
func loadSegments(videoID: String, categories: Set<String>, completionHandler: @escaping () -> Void = {}) {
2021-10-23 22:19:45 +05:30
guard !skipSegmentsURL.isNil, self.videoID != videoID else {
completionHandler()
2021-10-23 22:19:45 +05:30
return
}
self.videoID = videoID
DispatchQueue.main.async { [weak self] in
self?.requestSegments(categories: categories, completionHandler: completionHandler)
}
2021-10-23 22:19:45 +05:30
}
func reset() {
videoID = nil
segments = []
}
private func requestSegments(categories: Set<String>, completionHandler: @escaping () -> Void = {}) {
guard let url = skipSegmentsURL, !categories.isEmpty else {
2021-10-23 22:19:45 +05:30
return
}
2022-01-07 04:30:55 +05:30
AF.request(url, parameters: parameters(categories: categories)).responseDecodable(of: JSON.self) { [weak self] response in
2022-09-28 19:57:01 +05:30
guard let self else {
return
}
2021-10-23 22:19:45 +05:30
switch response.result {
case let .success(value):
self.segments = JSON(value).arrayValue.map(SponsorBlockSegment.init).sorted { $0.end < $1.end }
self.logger.info("loaded \(self.segments.count) SponsorBlock segments")
self.segments.forEach {
self.logger.info("\($0.start) -> \($0.end)")
}
case let .failure(error):
self.segments = []
self.logger.error("failed to load SponsorBlock segments: \(error.localizedDescription)")
}
completionHandler()
2021-10-23 22:19:45 +05:30
}
}
private var skipSegmentsURL: String? {
let url = Defaults[.sponsorBlockInstance]
return url.isEmpty ? nil : "\(url)/api/skipSegments"
}
private func parameters(categories: Set<String>) -> [String: String] {
2021-10-23 22:19:45 +05:30
[
"videoID": videoID!,
"categories": JSON(Array(categories)).rawString(String.Encoding.utf8)!
2021-10-23 22:19:45 +05:30
]
}
}