@@ -11,8 +11,8 @@ import RealmSwift
1111import SwiftyJSON
1212
1313extension Notification . Name {
14- public static let TranscriptIndexingDidStart = Notification . Name ( " TranscriptIndexingDidStartNotification " )
15- public static let TranscriptIndexingDidStop = Notification . Name ( " TranscriptIndexingDidStopNotification " )
14+ public static let TranscriptIndexingDidStart = Notification . Name ( " io.wwdc.app. TranscriptIndexingDidStartNotification" )
15+ public static let TranscriptIndexingDidStop = Notification . Name ( " io.wwdc.app. TranscriptIndexingDidStopNotification" )
1616}
1717
1818public final class TranscriptIndexer {
@@ -23,35 +23,12 @@ public final class TranscriptIndexer {
2323 self . storage = storage
2424 }
2525
26- /// Whether transcripts are currently being indexed
27- public var isIndexingTranscripts = false {
28- didSet {
29- guard oldValue != isIndexingTranscripts else { return }
30-
31- let notificationName : Notification . Name = isIndexingTranscripts ? . TranscriptIndexingDidStart : . TranscriptIndexingDidStop
32-
33- DispatchQueue . main. async {
34- NotificationCenter . default. post ( name: notificationName, object: nil )
35- }
36- }
37- }
38-
3926 /// The progress when the transcripts are being downloaded/indexed
40- public var transcriptIndexingProgress : Progress ? {
41- didSet {
42- isIndexingTranscripts = ( transcriptIndexingProgress != nil )
43-
44- transcriptIndexingStartedCallback ? ( )
45- }
46- }
47-
48- /// Called when transcript downloading/indexing starts,
49- /// use `transcriptIndexingProgress` to track progress
50- public var transcriptIndexingStartedCallback : ( ( ) -> Void ) ?
27+ public var transcriptIndexingProgress : Progress ?
5128
5229 private let asciiWWDCURL = " http://asciiwwdc.com/ "
5330
54- fileprivate let bgThread = DispatchQueue . global ( qos: . background )
31+ fileprivate let bgThread = DispatchQueue . global ( qos: . utility )
5532
5633 fileprivate lazy var backgroundOperationQueue : OperationQueue = {
5734 let q = OperationQueue ( )
@@ -63,17 +40,16 @@ public final class TranscriptIndexer {
6340 } ( )
6441
6542 /// Try to download transcripts for sessions that don't have transcripts yet
66- func downloadTranscriptsIfNeeded( ) {
43+ public func downloadTranscriptsIfNeeded( ) {
6744
68- let transcriptedSessions = storage. realm. objects ( Session . self) . filter ( " transcript == nil AND SUBQUERY(assets, $asset, $asset.rawAssetType == %@).@count > 0 " , SessionAssetType . streamingVideo. rawValue)
45+ let transcriptedSessions = storage. realm. objects ( Session . self) . filter ( " year > 2012 AND transcript == nil AND SUBQUERY(assets, $asset, $asset.rawAssetType == %@).@count > 0" , SessionAssetType . streamingVideo. rawValue)
6946
7047 let sessionKeys : [ String ] = transcriptedSessions. map ( { $0. identifier } )
7148
7249 self . indexTranscriptsForSessionsWithKeys ( sessionKeys)
7350 }
7451
7552 func indexTranscriptsForSessionsWithKeys( _ sessionKeys: [ String ] ) {
76- guard !isIndexingTranscripts else { return }
7753 guard sessionKeys. count > 0 else { return }
7854
7955 transcriptIndexingProgress = Progress ( totalUnitCount: Int64 ( sessionKeys. count) )
@@ -87,6 +63,8 @@ public final class TranscriptIndexer {
8763 }
8864 }
8965
66+ fileprivate var downloadedTranscripts : [ Transcript ] = [ ]
67+
9068 fileprivate func indexTranscript( for sessionNumber: String , in year: Int , primaryKey: String ) {
9169 guard let url = URL ( string: " \( asciiWWDCURL) \( year) //sessions/ \( sessionNumber) " ) else { return }
9270
@@ -95,52 +73,93 @@ public final class TranscriptIndexer {
9573
9674 let task = URLSession . shared. dataTask ( with: request) { [ unowned self] data, response, error in
9775 guard let jsonData = data else {
98- print ( " No data returned from ASCIIWWDC for \( primaryKey) " )
76+ self . transcriptIndexingProgress? . completedUnitCount += 1
77+ self . checkForCompletion ( )
78+
79+ NSLog ( " No data returned from ASCIIWWDC for \( primaryKey) " )
80+
9981 return
10082 }
10183
10284 self . backgroundOperationQueue. addOperation {
103- do {
104- let bgRealm = try Realm ( configuration: self . storage. realmConfig)
105-
106- guard let session = bgRealm. object ( ofType: Session . self, forPrimaryKey: primaryKey) else { return }
107-
108- let result = TranscriptsJSONAdapter ( ) . adapt ( JSON ( data: jsonData) )
109-
110- guard case . success( let transcript) = result else {
111- NSLog ( " Error parsing transcript for \( primaryKey) " )
112- return
113- }
114-
115- bgRealm. beginWrite ( )
116- bgRealm. add ( transcript)
117- session. transcript = transcript
118-
119- try bgRealm. commitWrite ( )
120-
85+ defer {
12186 self . transcriptIndexingProgress? . completedUnitCount += 1
122- } catch let error {
123- NSLog ( " Error indexing transcript for \( primaryKey ) : \( error ) " )
87+
88+ self . checkForCompletion ( )
12489 }
12590
126- if let progress = self . transcriptIndexingProgress {
127- #if DEBUG
128- NSLog ( " Completed: \( progress. completedUnitCount) Total: \( progress. totalUnitCount) " )
129- #endif
130-
131- if progress. completedUnitCount >= progress. totalUnitCount - 1 {
132- DispatchQueue . main. async {
133- #if DEBUG
134- NSLog ( " Transcript indexing finished " )
135- #endif
136- self . isIndexingTranscripts = false
137- }
138- }
91+ let result = TranscriptsJSONAdapter ( ) . adapt ( JSON ( data: jsonData) )
92+
93+ guard case . success( let transcript) = result else {
94+ NSLog ( " Error parsing transcript for \( primaryKey) " )
95+ return
96+ }
97+
98+ DispatchQueue . main. sync {
99+ self . downloadedTranscripts. append ( transcript)
139100 }
140101 }
141102 }
142103
143104 task. resume ( )
144105 }
145106
107+ private func checkForCompletion( ) {
108+ guard let progress = self . transcriptIndexingProgress else { return }
109+
110+ #if DEBUG
111+ NSLog ( " Completed: \( progress. completedUnitCount) Total: \( progress. totalUnitCount) " )
112+ #endif
113+
114+ if progress. completedUnitCount >= progress. totalUnitCount - 1 {
115+ DispatchQueue . main. async {
116+ #if DEBUG
117+ NSLog ( " Transcript indexing finished " )
118+ #endif
119+
120+ self . storeDownloadedTranscripts ( )
121+ }
122+ }
123+ }
124+
125+ private var isStoring = false
126+
127+ private func storeDownloadedTranscripts( ) {
128+ guard !isStoring else { return }
129+ isStoring = true
130+
131+ DispatchQueue . main. async {
132+ DistributedNotificationCenter . default ( ) . post ( name: . TranscriptIndexingDidStart, object: nil )
133+ }
134+
135+ self . backgroundOperationQueue. addOperation { [ unowned self] in
136+ guard let realm = try ? Realm ( configuration: self . storage. realmConfig) else { return }
137+
138+ realm. beginWrite ( )
139+
140+ self . downloadedTranscripts. forEach { transcript in
141+ guard let session = realm. object ( ofType: Session . self, forPrimaryKey: transcript. identifier) else {
142+ NSLog ( " Session not found for \( transcript. identifier) " )
143+ return
144+ }
145+
146+ session. transcript = transcript
147+
148+ realm. add ( transcript)
149+ }
150+
151+ self . downloadedTranscripts. removeAll ( )
152+
153+ do {
154+ try realm. commitWrite ( )
155+
156+ DispatchQueue . main. async {
157+ DistributedNotificationCenter . default ( ) . post ( name: . TranscriptIndexingDidStop, object: nil )
158+ }
159+ } catch {
160+ NSLog ( " Error writing indexed transcripts to storage: \( error) " )
161+ }
162+ }
163+ }
164+
146165}
0 commit comments