@@ -9,6 +9,7 @@ import Foundation
99import RemoteCloud
1010import ffconverter
1111import GoogleCast
12+ internal import UniformTypeIdentifiers
1213
1314class CastConverter : NSObject , GCKRemoteMediaClientListener {
1415 static let shared = CastConverter ( )
@@ -25,8 +26,36 @@ class CastConverter: NSObject, GCKRemoteMediaClientListener {
2526 }
2627
2728 var items : [ RemoteItem ] = [ ]
29+ var itemIDMap : [ Int : String ] = [ : ]
2830 var durations : [ String : ( Double , String , String , String ) ] = [ : ]
2931 var currentIdx = - 1
32+ var currentItemID : Int = - 1 {
33+ didSet {
34+ print ( " currentItemID change " , currentItemID, oldValue)
35+ if currentItemID == oldValue {
36+ return
37+ }
38+ if oldValue < 0 { return }
39+ for i in 0 ... oldValue {
40+ if let path = itemIDMap [ i] {
41+ Task {
42+ print ( " Convert done " , i, path)
43+ await Converter . Done ( targetPath: path)
44+ }
45+ }
46+ }
47+ }
48+ }
49+
50+ func setItemID( _ id: Int , path: String ) {
51+ print ( " setItemID " , id, path)
52+ itemIDMap [ id] = path
53+ }
54+
55+ func setCurrentItemID( _ id: Int ) {
56+ print ( " setCurrentItemID " , id)
57+ currentItemID = id
58+ }
3059
3160 func playDone( url: URL , sec: Double ) async {
3261 let randID = url. deletingLastPathComponent ( ) . lastPathComponent
@@ -59,21 +88,15 @@ class CastConverter: NSObject, GCKRemoteMediaClientListener {
5988 }
6089 }
6190
62- func do ne( ) async {
63- if currentIdx < 1 { return }
64- for i in 0 ..< currentIdx {
65- await Converter . Done ( targetPath: items [ i] . path)
66- }
67- }
68-
6991 func finish( ) async {
7092 for item in items {
7193 await Converter . Done ( targetPath: item. path)
7294 }
7395 items. removeAll ( )
96+ itemIDMap. removeAll ( )
7497 }
7598
76- func nextItem( ) -> RemoteItem ? {
99+ func nextItem( ) -> ( Int , RemoteItem ) ? {
77100 if currentIdx + 1 < items. count {
78101 currentIdx += 1
79102 }
@@ -88,7 +111,7 @@ class CastConverter: NSObject, GCKRemoteMediaClientListener {
88111 return nil
89112 }
90113 }
91- return items [ currentIdx]
114+ return ( currentIdx , items [ currentIdx] )
92115 }
93116
94117 func setItems( _ items: [ RemoteItem ] ) {
@@ -97,21 +120,54 @@ class CastConverter: NSObject, GCKRemoteMediaClientListener {
97120 }
98121 }
99122 var prop = Items ( )
100- var waiting = false
123+ var waiting : Int64 = 0
101124
102125 var timer : Timer ?
103126 var playlist = false
104127
128+ func remoteMediaClient( _ client: GCKRemoteMediaClient , didUpdate mediaMetadata: GCKMediaMetadata ? ) {
129+ if let itemID = mediaMetadata? . integer ( forKey: kGCKMetadataKeyQueueItemID) {
130+ print ( " itemID " , itemID)
131+ Task {
132+ await prop. setCurrentItemID ( itemID)
133+ }
134+ }
135+ if mediaMetadata == nil {
136+ Task {
137+ await prop. setCurrentItemID ( - 1 )
138+ }
139+ print ( " queue next item immidiaetly " )
140+ Task {
141+ await playNext ( true )
142+ }
143+ }
144+ else {
145+ if waiting < 1 {
146+ OSAtomicIncrement64 ( & waiting)
147+ print ( " queue next item " )
148+ Task {
149+ await playNext ( )
150+ }
151+ }
152+ }
153+ }
154+
105155 func remoteMediaClient( _ client: GCKRemoteMediaClient , didUpdate mediaStatus: GCKMediaStatus ? ) {
156+ if mediaStatus? . nextQueueItem == nil {
157+ myButton. isEnabled = false
158+ }
159+ else {
160+ myButton. isEnabled = true
161+ }
106162 if let url = mediaStatus? . mediaInformation? . contentURL, let sec = mediaStatus? . streamPosition, sec > 0 {
107163 Task {
108164 await prop. playDone ( url: url, sec: sec)
109165 }
110- if ! waiting, mediaStatus? . nextQueueItem == nil {
111- print ( " queue has not next item " )
112- waiting = true
166+ if waiting < 1 , mediaStatus? . nextQueueItem == nil || mediaStatus ? . currentQueueItem == nil {
167+ OSAtomicIncrement64 ( & waiting )
168+ print ( " queue next item " )
113169 Task {
114- await playNext ( client )
170+ await playNext ( )
115171 }
116172 }
117173 }
@@ -124,32 +180,28 @@ class CastConverter: NSObject, GCKRemoteMediaClientListener {
124180 if let remoteClient = castContext. sessionManager. currentSession? . remoteMediaClient {
125181 if let next = remoteClient. mediaStatus? . nextQueueItem {
126182 remoteClient. queueJumpToItem ( withID: next. itemID, playPosition: 0 , customData: nil )
127- Task {
128- await prop. done ( )
129- await removeNextButton ( )
130- }
183+ }
184+ else {
185+ myButton. isEnabled = false
131186 }
132187 }
133188 }
134189 }
135190
136- @MainActor
137- func addNextButton( ) async {
138- let castContext = GCKCastContext . sharedInstance ( )
139- let expandedController = castContext. defaultExpandedMediaControlsViewController
191+ lazy var myButton = {
140192 let myButton = UIButton ( )
141193 let symbolConfiguration = UIImage . SymbolConfiguration ( pointSize: 24.0 , weight: . regular, scale: . default)
142194 myButton. setImage ( UIImage ( systemName: " forward.end.fill " , withConfiguration: symbolConfiguration) , for: . normal)
143195 myButton. addTarget ( self , action: #selector( didTapMyButton) , for: . touchUpInside)
144- expandedController. setButtonType ( . custom, at: 3 )
145- expandedController. setCustomButton ( myButton, at: 3 )
146- }
196+ return myButton
197+ } ( )
147198
148199 @MainActor
149- func removeNextButton ( ) async {
200+ func addNextButton ( ) async {
150201 let castContext = GCKCastContext . sharedInstance ( )
151202 let expandedController = castContext. defaultExpandedMediaControlsViewController
152- expandedController. setButtonType ( . none, at: 3 )
203+ expandedController. setButtonType ( . custom, at: 3 )
204+ expandedController. setCustomButton ( myButton, at: 3 )
153205 }
154206
155207 @MainActor
@@ -159,12 +211,8 @@ class CastConverter: NSObject, GCKRemoteMediaClientListener {
159211 }
160212
161213 @concurrent
162- func playNext( _ client: GCKRemoteMediaClient ) async {
163- defer {
164- Task { @MainActor in
165- waiting = false
166- }
167- }
214+ func playNext( _ immidiate: Bool = false ) async {
215+ await addNextButton ( )
168216 Task { @MainActor in
169217 if timer == nil {
170218 timer = Timer . scheduledTimer ( withTimeInterval: 10 , repeats: true ) { [ weak self] _ in
@@ -180,7 +228,10 @@ class CastConverter: NSObject, GCKRemoteMediaClientListener {
180228 }
181229 }
182230 }
183- guard let item = await prop. nextItem ( ) else {
231+ guard let ( index, item) = await prop. nextItem ( ) else {
232+ Task { @MainActor in
233+ OSAtomicDecrement64 ( & waiting)
234+ }
184235 return
185236 }
186237 let info = ConvertIteminfo ( item: item)
@@ -195,48 +246,75 @@ class CastConverter: NSObject, GCKRemoteMediaClientListener {
195246 print ( item. path)
196247 if let url = await Converter . Play ( item: info) {
197248 let randID = url. deletingLastPathComponent ( ) . lastPathComponent
249+ await prop. setItemID ( index, path: item. path)
198250 if await Converter . start_encode ( randID: randID) {
199251 var sleepCount = 0
200- while Converter . IsCasting ( ) , await !Converter. fileReady ( randID: randID) {
201- try ? await Task . sleep ( for: . seconds ( 1 ) )
252+ while Converter . IsCasting ( ) , await !Converter. fileReady ( randID: randID) , await Converter . runState ( randID : randID ) {
253+ try ? await Task . sleep ( for: . milliseconds ( 100 ) )
202254 sleepCount += 1
203255 print ( " sleep \( sleepCount) " )
204256 }
205- try ? await Task . sleep ( for: . seconds( 1 ) )
257+ }
258+ if await !Converter. runState ( randID: randID) {
259+ print ( " Convert failed. " )
260+ await playNext ( )
261+ return
206262 }
207263
208264 let metadata = GCKMediaMetadata ( )
209265 metadata. setString ( item. name, forKey: kGCKMetadataKeyTitle)
266+ metadata. setInteger ( index, forKey: kGCKMetadataKeyQueueItemID)
210267 let mediaInfoBuilder = GCKMediaInformationBuilder ( contentURL: url)
211- mediaInfoBuilder. streamDuration = . infinity
212268 mediaInfoBuilder. hlsSegmentFormat = . TS
213- mediaInfoBuilder. streamType = . live
214269 mediaInfoBuilder. contentType = " application/vnd.apple.mpegurl "
215270 mediaInfoBuilder. metadata = metadata
216271 let itemBuilder = GCKMediaQueueItemBuilder ( )
217272 itemBuilder. mediaInformation = mediaInfoBuilder. build ( )
218273 itemBuilder. startTime = 0
219- itemBuilder. preloadTime = 0
220274 itemBuilder. autoplay = true
275+ let newItem = itemBuilder. build ( )
221276 if await prop. currentIdx != 0 {
222- client. queueInsert ( itemBuilder. build ( ) , beforeItemWithID: kGCKMediaQueueInvalidItemID)
223- await addNextButton ( )
277+ let castContext = GCKCastContext . sharedInstance ( )
278+ if let client = castContext. sessionManager. currentCastSession? . remoteMediaClient {
279+ if immidiate {
280+ let request = GCKMediaLoadRequestDataBuilder ( )
281+ let queue = GCKMediaQueueDataBuilder ( queueType: . generic)
282+ queue. items = [ newItem]
283+ request. queueData = queue. build ( )
284+ request. startTime = 0
285+ client. loadMedia ( with: request. build ( ) )
286+ }
287+ else {
288+ client. queueInsert ( newItem, beforeItemWithID: kGCKMediaQueueInvalidItemID)
289+ }
290+ }
291+ Task { @MainActor in
292+ myButton. isEnabled = true
293+ }
224294 }
225295 else {
226296 let request = GCKMediaLoadRequestDataBuilder ( )
227297 let queue = GCKMediaQueueDataBuilder ( queueType: . generic)
228- queue. items = [ itemBuilder. build ( ) ]
229- queue. startTime = 0
298+ queue. items = [ newItem]
230299 request. queueData = queue. build ( )
231- client. loadMedia ( with: request. build ( ) )
232- await removeNextButton ( )
300+ request. startTime = 0
301+ let castContext = GCKCastContext . sharedInstance ( )
302+ if let client = castContext. sessionManager. currentCastSession? . remoteMediaClient {
303+ client. loadMedia ( with: request. build ( ) )
304+ }
305+ Task { @MainActor in
306+ myButton. isEnabled = false
307+ }
233308 }
234309
235- try ? await Task . sleep ( for : . seconds ( 2 ) )
236- if Converter . IsCasting ( ) {
310+ let castContext = GCKCastContext . sharedInstance ( )
311+ if Converter . IsCasting ( ) , castContext . castState == . connected || castContext . castState == . connecting {
237312 await showController ( )
238313 }
239314 }
315+ Task { @MainActor in
316+ OSAtomicDecrement64 ( & waiting)
317+ }
240318 }
241319}
242320
@@ -247,11 +325,11 @@ func playConverter(storages: [String], fileids: [String], playlist: Bool = false
247325 var items : [ RemoteItem ] = [ ]
248326 for (storage, fileid) in zip ( storages, fileids) {
249327 if let remoteItem = await CloudFactory . shared. storageList. get ( storage) ? . get ( fileId: fileid) {
250- if remoteItem. ext == " txt " {
328+ if let uti = UTType ( filenameExtension : remoteItem. ext) , uti . conforms ( to : . text ) {
251329 }
252- else if OpenfileUIView . pict_exts . contains ( remoteItem. ext) {
330+ else if let uti = UTType ( filenameExtension : remoteItem. ext) , uti . conforms ( to : . image ) {
253331 }
254- else if remoteItem. ext == " pdf " {
332+ else if let uti = UTType ( filenameExtension : remoteItem. ext) , uti . conforms ( to : . pdf) {
255333 }
256334 else if remoteItem. ext == " cue " {
257335 }
@@ -270,8 +348,8 @@ func playConverter(storages: [String], fileids: [String], playlist: Bool = false
270348 if let remoteClient = castContext. sessionManager. currentSession? . remoteMediaClient, remoteClient. mediaStatus? . queueItemCount ?? 0 == 0 {
271349 await CastConverter . shared. prop. setItems ( items)
272350 remoteClient. add ( CastConverter . shared)
273- CastConverter . shared. waiting = true
274- await CastConverter . shared. playNext ( remoteClient )
351+ OSAtomicIncrement64 ( & CastConverter. shared. waiting)
352+ await CastConverter . shared. playNext ( )
275353 }
276354 }
277355}
0 commit comments