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"]
|
|
|
|
|
2021-12-18 01:25:52 +05:30
|
|
|
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? {
|
|
|
|
guard SponsorBlockAPI.categories.contains(name) else {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
switch name {
|
|
|
|
case "selfpromo":
|
|
|
|
return "Self-promotion"
|
|
|
|
case "music_offtopic":
|
|
|
|
return "Offtopic in Music Videos"
|
|
|
|
default:
|
|
|
|
return name.capitalized
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-18 01:25:52 +05:30
|
|
|
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 {
|
2021-12-18 01:25:52 +05:30
|
|
|
completionHandler()
|
2021-10-23 22:19:45 +05:30
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
self.videoID = videoID
|
|
|
|
|
2021-12-30 00:25:41 +05:30
|
|
|
DispatchQueue.main.async { [weak self] in
|
|
|
|
self?.requestSegments(categories: categories, completionHandler: completionHandler)
|
|
|
|
}
|
2021-10-23 22:19:45 +05:30
|
|
|
}
|
|
|
|
|
2021-12-18 01:25:52 +05:30
|
|
|
private func requestSegments(categories: Set<String>, completionHandler: @escaping () -> Void = {}) {
|
2021-10-29 01:02:03 +05:30
|
|
|
guard let url = skipSegmentsURL, !categories.isEmpty else {
|
2021-10-23 22:19:45 +05:30
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-12-18 01:25:52 +05:30
|
|
|
AF.request(url, parameters: parameters(categories: categories)).responseJSON { [weak self] response in
|
|
|
|
guard let self = 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)")
|
|
|
|
}
|
2021-12-18 01:25:52 +05:30
|
|
|
|
|
|
|
completionHandler()
|
2021-10-23 22:19:45 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private var skipSegmentsURL: String? {
|
|
|
|
let url = Defaults[.sponsorBlockInstance]
|
|
|
|
return url.isEmpty ? nil : "\(url)/api/skipSegments"
|
|
|
|
}
|
|
|
|
|
2021-10-29 01:02:03 +05:30
|
|
|
private func parameters(categories: Set<String>) -> [String: String] {
|
2021-10-23 22:19:45 +05:30
|
|
|
[
|
|
|
|
"videoID": videoID!,
|
2021-10-29 01:02:03 +05:30
|
|
|
"categories": JSON(Array(categories)).rawString(String.Encoding.utf8)!
|
2021-10-23 22:19:45 +05:30
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|