2021-10-23 22:19:45 +05:30
import Alamofire
import Defaults
import Foundation
import Logging
import SwiftyJSON
final class SponsorBlockAPI : ObservableObject {
2024-04-23 14:30:27 +05:30
static let categories = [ " sponsor " , " selfpromo " , " interaction " , " intro " , " outro " , " preview " , " filler " , " music_offtopic " ]
2021-10-23 22:19:45 +05:30
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 ? {
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 " :
2024-04-23 14:30:27 +05:30
return " Unpaid/Self Promotion " . localized ( )
case " interaction " :
return " Interaction Reminder (Subscribe) " . localized ( )
2022-09-04 20:58:30 +05:30
case " intro " :
2024-04-23 14:30:27 +05:30
return " Intermission/Intro Animation " . localized ( )
2022-09-04 20:58:30 +05:30
case " outro " :
2024-04-23 14:30:27 +05:30
return " Endcards/Credits " . localized ( )
case " preview " :
return " Preview/Recap/Hook " . localized ( )
case " filler " :
return " Filler Tangent/Jokes " . localized ( )
2021-10-23 22:19:45 +05:30
case " music_offtopic " :
2024-04-23 14:30:27 +05:30
return " Music: Non-Music Section " . 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 " :
2024-04-23 14:30:27 +05:30
return ( " The creator will not receive any payment in exchange for this promotion. " +
" This includes charity drives or free shout outs for products or other people they like. \n \n " +
" Promoting a product or service that is directly related to the creator themselves. " +
2022-09-04 20:58:30 +05:30
" This usually includes merchandise or promotion of monetized platforms. " ) . localized ( )
2022-01-08 00:16:47 +05:30
2024-04-23 14:30:27 +05:30
case " interaction " :
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 " 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
2024-04-23 14:30:27 +05:30
case " preview " :
return " Collection of clips that show what is coming up in in this video or other videos in a series where all information is repeated later in the video " . localized ( )
case " filler " :
return " Filler Tangent/ Jokes is only for tangential scenes added only for filler or humor that are not required to understand the main content of the 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
}
}
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
2023-05-27 02:54:00 +05:30
DispatchQueue . main . async { [ weak self ] in
2021-12-30 00:25:41 +05:30
self ? . requestSegments ( categories : categories , completionHandler : completionHandler )
}
2021-10-23 22:19:45 +05:30
}
2022-12-04 05:05:07 +05:30
func reset ( ) {
videoID = nil
segments = [ ]
}
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
}
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 {
2021-12-18 01:25:52 +05:30
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 " )
2024-04-23 14:30:27 +05:30
for segment in self . segments {
self . logger . info ( " \( segment . start ) -> \( segment . end ) " )
2021-10-23 22:19:45 +05:30
}
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
]
}
}