Skip to content

Commit e41551d

Browse files
authored
Merge pull request #713 from insidegui/rambo/new-download-manager
Implements new download manager and HLS downloads (Closes #267)
2 parents be0f654 + 26e1987 commit e41551d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+3052
-872
lines changed

.swiftlint.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ disabled_rules:
1414
- implicit_getter
1515
- for_where
1616
- opening_brace
17+
- vertical_parameter_alignment
1718

1819
opt_in_rules:
1920
- redundant_nil_coalescing

Packages/ConfCore/ConfCore/Session.swift

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ public class Session: Object, Decodable {
146146
// MARK: - Decodable
147147

148148
private enum AssetCodingKeys: String, CodingKey {
149-
case id, year, title, downloadHD, downloadSD, slides, hls, images, shelf, duration
149+
case id, year, title, downloadHD, downloadSD, downloadHLS, slides, hls, images, shelf, duration
150150
}
151151

152152
private enum SessionCodingKeys: String, CodingKey {
@@ -230,6 +230,19 @@ public class Session: Object, Decodable {
230230

231231
self.assets.append(slidesAsset)
232232
}
233+
234+
if let downloadHLS = try assetContainer.decodeIfPresent(String.self, forKey: .downloadHLS) {
235+
let downloadHLSVideo = SessionAsset()
236+
downloadHLSVideo.rawAssetType = SessionAssetType.downloadHLSVideo.rawValue
237+
downloadHLSVideo.remoteURL = downloadHLS
238+
downloadHLSVideo.year = Int(eventYear) ?? -1
239+
downloadHLSVideo.sessionId = downloadHLS
240+
241+
let filename = "\(title).movpkg"
242+
downloadHLSVideo.relativeLocalURL = "\(eventYear)/\(filename)"
243+
244+
self.assets.append(downloadHLSVideo)
245+
}
233246
}
234247

235248
func decodeRelatedIfPresent() throws {

Packages/ConfCore/ConfCore/SessionAsset.swift

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public enum SessionAssetType: String {
1313
case none
1414
case hdVideo = "WWDCSessionAssetTypeHDVideo"
1515
case sdVideo = "WWDCSessionAssetTypeSDVideo"
16+
case downloadHLSVideo = "WWDCSessionAssetTypeDownloadHLSVideo"
1617
case image = "WWDCSessionAssetTypeShelfImage"
1718
case slides = "WWDCSessionAssetTypeSlidesPDF"
1819
case streamingVideo = "WWDCSessionAssetTypeStreamingVideo"
@@ -23,14 +24,7 @@ public enum SessionAssetType: String {
2324
/// Session assets are resources associated with sessions, like videos, PDFs and useful links
2425
public class SessionAsset: Object, Decodable {
2526

26-
/// The type of asset:
27-
///
28-
/// - WWDCSessionAssetTypeHDVideo
29-
/// - WWDCSessionAssetTypeSDVideo
30-
/// - WWDCSessionAssetTypeShelfImage
31-
/// - WWDCSessionAssetTypeSlidesPDF
32-
/// - WWDCSessionAssetTypeStreamingVideo
33-
/// - WWDCSessionAssetTypeWebpageURL
27+
/// The type of asset.
3428
@objc internal dynamic var rawAssetType = "" {
3529
didSet {
3630
identifier = generateIdentifier()

WWDC.xcodeproj/project.pbxproj

Lines changed: 100 additions & 0 deletions
Large diffs are not rendered by default.

WWDC/AppCommandsReceiver.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import OSLog
1313
final class AppCommandsReceiver: Logging {
1414
static let log = makeLogger(subsystem: "io.wwdc.app")
1515

16+
@MainActor
1617
// swiftlint:disable:next cyclomatic_complexity
1718
func handle(_ command: WWDCAppCommand, storage: Storage) -> DeepLink? {
1819
log.debug("\(#function, privacy: .public) \(String(describing: command))")
@@ -40,14 +41,14 @@ final class AppCommandsReceiver: Logging {
4041
return nil
4142
case .download:
4243
guard let session = command.session(in: storage) else { return nil }
43-
44-
DownloadManager.shared.download([session])
45-
44+
45+
MediaDownloadManager.shared.download([session])
46+
4647
return nil
4748
case .cancelDownload:
4849
guard let session = command.session(in: storage) else { return nil }
4950

50-
DownloadManager.shared.cancelDownloads([session])
51+
MediaDownloadManager.shared.cancelDownload(for: [session])
5152

5253
return nil
5354
case .revealVideo:

WWDC/AppCoordinator+SessionActions.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@ import OSLog
1515

1616
extension AppCoordinator: SessionActionsViewControllerDelegate {
1717

18+
@MainActor
1819
func sessionActionsDidSelectCancelDownload(_ sender: NSView?) {
1920
guard let viewModel = activeTabSelectedSessionViewModel else { return }
2021

21-
DownloadManager.shared.cancelDownloads([viewModel.session])
22+
MediaDownloadManager.shared.cancelDownload(for: [viewModel.session])
2223
}
2324

2425
func sessionActionsDidSelectFavorite(_ sender: NSView?) {
@@ -37,10 +38,11 @@ extension AppCoordinator: SessionActionsViewControllerDelegate {
3738
NSWorkspace.shared.open(url)
3839
}
3940

41+
@MainActor
4042
func sessionActionsDidSelectDownload(_ sender: NSView?) {
4143
guard let viewModel = activeTabSelectedSessionViewModel else { return }
4244

43-
DownloadManager.shared.download([viewModel.session])
45+
MediaDownloadManager.shared.download([viewModel.session])
4446
}
4547

4648
func sessionActionsDidSelectDeleteDownload(_ sender: NSView?) {
@@ -63,7 +65,11 @@ extension AppCoordinator: SessionActionsViewControllerDelegate {
6365

6466
switch choice {
6567
case .yes:
66-
DownloadManager.shared.deleteDownloadedFile(for: viewModel.session)
68+
do {
69+
try MediaDownloadManager.shared.removeDownloadedMedia(for: viewModel.session)
70+
} catch {
71+
NSAlert(error: error).runModal()
72+
}
6773
case .no:
6874
break
6975
}

WWDC/AppCoordinator+SessionTableViewContextMenuActions.swift

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ extension AppCoordinator: SessionsTableViewControllerDelegate {
3535
storage.setFavorite(false, onSessionsWithIDs: viewModels.map({ $0.session.identifier }))
3636
}
3737

38+
@MainActor
3839
func sessionTableViewContextMenuActionDownload(viewModels: [SessionViewModel]) {
3940
if viewModels.count > 5 {
4041
// asking to download many videos, warn
@@ -56,27 +57,27 @@ extension AppCoordinator: SessionsTableViewControllerDelegate {
5657
guard case .yes = choice else { return }
5758
}
5859

59-
DownloadManager.shared.download(viewModels.map { $0.session })
60+
MediaDownloadManager.shared.download(viewModels.map(\.session))
6061
}
6162

63+
@MainActor
6264
func sessionTableViewContextMenuActionCancelDownload(viewModels: [SessionViewModel]) {
63-
viewModels.forEach { viewModel in
64-
65-
guard DownloadManager.shared.isDownloading(viewModel.session) else { return }
66-
67-
DownloadManager.shared.deleteDownloadedFile(for: viewModel.session)
68-
}
65+
let cancellableDownloads = viewModels.map(\.session).filter { MediaDownloadManager.shared.isDownloadingMedia(for: $0) }
66+
67+
MediaDownloadManager.shared.cancelDownload(for: cancellableDownloads)
6968
}
7069

70+
@MainActor
7171
func sessionTableViewContextMenuActionRemoveDownload(viewModels: [SessionViewModel]) {
72-
viewModels.forEach { viewModel in
73-
DownloadManager.shared.deleteDownloadedFile(for: viewModel.session)
74-
}
72+
let deletableDownloads = viewModels.map(\.session).filter { MediaDownloadManager.shared.hasDownloadedMedia(for: $0) }
73+
74+
MediaDownloadManager.shared.delete(deletableDownloads)
7575
}
7676

77+
@MainActor
7778
func sessionTableViewContextMenuActionRevealInFinder(viewModels: [SessionViewModel]) {
7879
guard let firstSession = viewModels.first?.session else { return }
79-
guard let localURL = DownloadManager.shared.downloadedFileURL(for: firstSession) else { return }
80+
guard let localURL = MediaDownloadManager.shared.downloadedFileURL(for: firstSession) else { return }
8081

8182
NSWorkspace.shared.selectFile(localURL.path, inFileViewerRootedAtPath: localURL.deletingLastPathComponent().path)
8283
}

WWDC/AppCoordinator.swift

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ final class AppCoordinator: Logging, Signposting {
9696
}
9797
}
9898

99+
private lazy var downloadMonitor = DownloadedContentMonitor()
100+
101+
@MainActor
99102
init(windowController: MainWindowController, storage: Storage, syncEngine: SyncEngine) {
100103
let signpostState = Self.signposter.beginInterval("initialization", id: Self.signposter.makeSignpostID(), "begin init")
101104
self.storage = storage
@@ -112,8 +115,6 @@ final class AppCoordinator: Logging, Signposting {
112115
)
113116
self.searchCoordinator = searchCoordinator
114117

115-
DownloadManager.shared.start(with: storage)
116-
117118
liveObserver = LiveObserver(dateProvider: today, storage: storage, syncEngine: syncEngine)
118119

119120
// Primary UI Initialization
@@ -178,7 +179,7 @@ final class AppCoordinator: Logging, Signposting {
178179
NSApp.isAutomaticCustomizeTouchBarMenuItemEnabled = true
179180

180181
let buttonsController = TitleBarButtonsViewController(
181-
downloadManager: DownloadManager.shared,
182+
downloadManager: .shared,
182183
storage: storage
183184
)
184185
windowController.titleBarViewController.statusViewController = buttonsController
@@ -187,6 +188,9 @@ final class AppCoordinator: Logging, Signposting {
187188
DispatchQueue.main.async { self?.startSharePlay() }
188189
}
189190

191+
MediaDownloadManager.shared.activate()
192+
downloadMonitor.activate(with: storage)
193+
190194
startup()
191195
Self.signposter.endInterval("initialization", signpostState, "end init")
192196
}
@@ -208,8 +212,11 @@ final class AppCoordinator: Logging, Signposting {
208212
self.preferredTranscriptLanguageDidChange($0)
209213
}.store(in: &cancellables)
210214
NotificationCenter.default.publisher(for: .SyncEngineDidSyncSessionsAndSchedule).receive(on: DispatchQueue.main).sink { [weak self] note in
211-
guard self?.checkSyncEngineOperationSucceededAndShowError(note: note) == true else { return }
212-
DownloadManager.shared.syncWithFileSystem()
215+
guard let self else { return }
216+
217+
guard self.checkSyncEngineOperationSucceededAndShowError(note: note) == true else { return }
218+
219+
self.downloadMonitor.syncWithFileSystem()
213220
}.store(in: &cancellables)
214221
NotificationCenter.default.publisher(for: .WWDCEnvironmentDidChange).receive(on: DispatchQueue.main).sink { _ in
215222
self.refresh(nil)

WWDC/AppDelegate.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, Logging {
8888
private var storage: Storage?
8989
private var syncEngine: SyncEngine?
9090

91+
@MainActor
9192
private func startupUI(using storage: Storage, syncEngine: SyncEngine) {
9293
self.storage = storage
9394
self.syncEngine = syncEngine
@@ -157,6 +158,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, Logging {
157158
coordinator?.receiveNotification(with: userInfo)
158159
}
159160

161+
@MainActor
160162
@objc func handleURLEvent(_ event: NSAppleEventDescriptor?, replyEvent: NSAppleEventDescriptor?) {
161163
guard let event = event else { return }
162164
guard let urlString = event.paramDescriptor(forKeyword: UInt32(keyDirectObject))?.stringValue else { return }
@@ -165,6 +167,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, Logging {
165167
openURL(url)
166168
}
167169

170+
@MainActor
168171
private func openURL(_ url: URL) {
169172
if let command = WWDCAppCommand(from: url) {
170173
handle(command)
@@ -277,10 +280,12 @@ extension AppDelegate: SUUpdaterDelegate {
277280
}
278281

279282
extension AppDelegate {
283+
@MainActor
280284
static func run(_ command: WWDCAppCommand) {
281285
(NSApp.delegate as? Self)?.handle(command, assumeSafe: true)
282286
}
283287

288+
@MainActor
284289
func handle(_ command: WWDCAppCommand, assumeSafe: Bool = false) {
285290
if command.isForeground {
286291
DispatchQueue.main.async { NSApp.activate(ignoringOtherApps: true) }

WWDC/Boot.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,3 +237,5 @@ extension NSApplication {
237237
exit(0)
238238
}
239239
}
240+
241+
extension NSWorkspace: @unchecked Sendable { }

0 commit comments

Comments
 (0)