Skip to content

Commit 82a2be4

Browse files
committed
v2.0.1(117)
fix bugs, player, converter, image view
1 parent 8be23d3 commit 82a2be4

File tree

23 files changed

+503
-342
lines changed

23 files changed

+503
-342
lines changed

CryptCloudViewer/CryptCloudViewer.xcodeproj/project.pbxproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@
325325
CLANG_ENABLE_MODULES = YES;
326326
CODE_SIGN_ENTITLEMENTS = CryptCloudViewer/CryptCloudViewer.entitlements;
327327
CODE_SIGN_STYLE = Automatic;
328-
CURRENT_PROJECT_VERSION = 115;
328+
CURRENT_PROJECT_VERSION = 117;
329329
DEAD_CODE_STRIPPING = YES;
330330
DEVELOPMENT_TEAM = 7A9X38B4YU;
331331
ENABLE_APP_SANDBOX = YES;
@@ -354,7 +354,7 @@
354354
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
355355
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
356356
MACOSX_DEPLOYMENT_TARGET = 26.0;
357-
MARKETING_VERSION = 2.0.0;
357+
MARKETING_VERSION = 2.0.1;
358358
PRODUCT_BUNDLE_IDENTIFIER = info.lithium03.ccViewer;
359359
PRODUCT_NAME = "$(TARGET_NAME)";
360360
REGISTER_APP_GROUPS = YES;
@@ -384,7 +384,7 @@
384384
CLANG_ENABLE_MODULES = YES;
385385
CODE_SIGN_ENTITLEMENTS = CryptCloudViewer/CryptCloudViewer.entitlements;
386386
CODE_SIGN_STYLE = Automatic;
387-
CURRENT_PROJECT_VERSION = 115;
387+
CURRENT_PROJECT_VERSION = 117;
388388
DEAD_CODE_STRIPPING = YES;
389389
DEVELOPMENT_TEAM = 7A9X38B4YU;
390390
ENABLE_APP_SANDBOX = YES;
@@ -413,7 +413,7 @@
413413
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
414414
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
415415
MACOSX_DEPLOYMENT_TARGET = 26.0;
416-
MARKETING_VERSION = 2.0.0;
416+
MARKETING_VERSION = 2.0.1;
417417
PRODUCT_BUNDLE_IDENTIFIER = info.lithium03.ccViewer;
418418
PRODUCT_NAME = "$(TARGET_NAME)";
419419
REGISTER_APP_GROUPS = YES;

CryptCloudViewer/CryptCloudViewer/CastPlay.swift

Lines changed: 131 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import Foundation
99
import RemoteCloud
1010
import ffconverter
1111
import GoogleCast
12+
internal import UniformTypeIdentifiers
1213

1314
class 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 done() 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
}

CryptCloudViewer/CryptCloudViewer/ImageShowUIView.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import SwiftUI
99
import RemoteCloud
10+
internal import UniformTypeIdentifiers
1011

1112
struct ImageShowUIView: View {
1213
let storage: String
@@ -230,12 +231,20 @@ struct ImageShowUIView: View {
230231
imageIdx = 0
231232
image = im
232233
}
234+
else {
235+
return
236+
}
233237
}
234238
}
235239

236240
await Task.yield()
237241
guard let remoteItem else { return }
238-
let files = await CloudFactory.shared.data.listData(storage: remoteItem.storage, parentID: remoteItem.parent).filter{ OpenfileUIView.pict_exts.contains($0.ext ?? "") }.sorted(by: { ($0.name ?? "").localizedStandardCompare($1.name ?? "") == .orderedAscending })
242+
let files = await CloudFactory.shared.data.listData(storage: remoteItem.storage, parentID: remoteItem.parent).filter({ item in
243+
if let uti = UTType(filenameExtension: item.ext ?? "") {
244+
return uti.conforms(to: .image)
245+
}
246+
return false
247+
}).sorted(by: { ($0.name ?? "").localizedStandardCompare($1.name ?? "") == .orderedAscending })
239248
totalImages = files.count
240249
guard let curIdx = files.firstIndex(where: { $0.id == remoteItem.id }) else { return }
241250
guard files.count > 1 else { return }

0 commit comments

Comments
 (0)