import Foundation /// 旅拍相册 OTG 照片落盘实现:写入 scoped 本地目录并通知传输管道。 @MainActor final class TravelAlbumOTGPhotoSink: OTGPhotoSink { private let albumId: Int private let accountKey: String private let pipeline: WiredCameraTransferPipeline private let existingObjectIDsProvider: () async -> Set private let autoUploadProvider: () -> Bool /// 初始化旅拍相册 OTG 落盘实现。 init( albumId: Int, accountKey: String, pipeline: WiredCameraTransferPipeline, existingObjectIDsProvider: @escaping () async -> Set, autoUploadProvider: @escaping () -> Bool ) { self.albumId = albumId self.accountKey = accountKey self.pipeline = pipeline self.existingObjectIDsProvider = existingObjectIDsProvider self.autoUploadProvider = autoUploadProvider } /// 保存边拍边传图像数据。 func saveLiveShot( data: Data, filename: String, capturedAt: Date, cameraObjectID: String ) async throws -> SavedOTGPhoto { let fileURL = try OTGPhotoFileWriter.writeImage( data, filename: filename, accountKey: accountKey, albumID: albumId ) return ingestSavedFile( fileURL: fileURL, filename: filename, capturedAt: capturedAt, cameraObjectID: cameraObjectID ) } /// 保存历史导入已下载文件。 func saveDownloadedFile( at url: URL, filename: String, capturedAt: Date, cameraObjectID: String ) async throws -> SavedOTGPhoto { let fileURL = try OTGPhotoFileWriter.moveDownloadedFile( from: url, filename: filename, accountKey: accountKey, albumID: albumId ) return ingestSavedFile( fileURL: fileURL, filename: filename, capturedAt: capturedAt, cameraObjectID: cameraObjectID ) } /// 返回当前相册已导入的相机对象 ID。 func existingCameraObjectIDs() async -> Set { await existingObjectIDsProvider() } private func ingestSavedFile( fileURL: URL, filename: String, capturedAt: Date, cameraObjectID: String ) -> SavedOTGPhoto { let relativePath = OTGPhotoFileWriter.relativePath(for: fileURL) let autoUpload = autoUploadProvider() pipeline.ingestDownloadedAsset( assetID: cameraObjectID, filename: filename, localPath: relativePath, capturedAt: capturedAt, autoUpload: autoUpload ) return SavedOTGPhoto( assetID: cameraObjectID, relativeLocalPath: relativePath, filename: filename, capturedAt: capturedAt ) } }