Skip to content

Commit ba6d8c0

Browse files
authored
Add LCPService.injectLicense() (#664)
1 parent 7c0436c commit ba6d8c0

File tree

3 files changed

+46
-12
lines changed

3 files changed

+46
-12
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ All notable changes to this project will be documented in this file. Take a look
1818
* Added an initializer parameter for providing a custom device identifier (contributed by [@dewantawsif](https://github.com/readium/swift-toolkit/pull/661)).
1919
* You must ensure the identifier is unique and stable for the device (persist and reuse across app launches).
2020
* Recommended: generate an app-scoped UUID and store it securely (e.g., in the Keychain); avoid hardware or advertising identifiers.
21+
* You can use `LCPService.injectLicenseDocument(_:in)` to insert an LCPL into a package, if you downloaded it manually instead of using `LCPService.acquirePublication()`.
2122

2223
### Changed
2324

Sources/LCP/LCPService.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,18 @@ public final class LCPService: Loggable {
8080
}
8181
}
8282

83+
/// Injects a `licenseDocument` into a publication package at `url`.
84+
///
85+
/// This is useful if you downloaded the publication yourself instead of using `acquirePublication`.
86+
public func injectLicenseDocument(
87+
_ license: LicenseDocument,
88+
in url: FileURL
89+
) async -> Result<Void, LCPError> {
90+
await wrap {
91+
try await licenses.injectLicenseDocument(license, in: url)
92+
}
93+
}
94+
8395
/// Opens the LCP license of a protected publication, to access its DRM
8496
/// metadata and decipher its content.
8597
///

Sources/LCP/Services/LicensesService.swift

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -120,26 +120,47 @@ final class LicensesService: Loggable {
120120
onProgress: { onProgress(.percent(Float($0))) }
121121
).get()
122122

123-
var hints = FormatHints()
124-
if let type = license.link(for: .publication)?.mediaType {
125-
hints.mediaTypes.append(type)
123+
let format = try await injectLicenseAndGetFormat(
124+
license,
125+
in: download.location,
126+
mediaTypeHint: download.mediaType
127+
)
128+
129+
return LCPAcquiredPublication(
130+
localURL: download.location,
131+
format: format,
132+
suggestedFilename: format.fileExtension.appendedToFilename(license.id),
133+
licenseDocument: license
134+
)
135+
}
136+
137+
func injectLicenseDocument(
138+
_ license: LicenseDocument,
139+
in url: FileURL
140+
) async throws {
141+
let _ = try await injectLicenseAndGetFormat(license, in: url, mediaTypeHint: nil)
142+
}
143+
144+
private func injectLicenseAndGetFormat(
145+
_ license: LicenseDocument,
146+
in url: FileURL,
147+
mediaTypeHint: MediaType? = nil
148+
) async throws -> Format {
149+
var formatHints = FormatHints()
150+
if let type = license.publicationLink.mediaType {
151+
formatHints.mediaTypes.append(type)
126152
}
127-
if let type = download.mediaType {
128-
hints.mediaTypes.append(type)
153+
if let type = mediaTypeHint {
154+
formatHints.mediaTypes.append(type)
129155
}
130156

131-
let asset = try await assetRetriever.retrieve(url: download.location, hints: hints)
157+
let asset = try await assetRetriever.retrieve(url: url, hints: formatHints)
132158
.mapError { LCPError.licenseContainer(ContainerError.openFailed($0)) }
133159
.get()
134160

135161
try await injectLicense(license, in: asset)
136162

137-
return LCPAcquiredPublication(
138-
localURL: download.location,
139-
format: asset.format,
140-
suggestedFilename: asset.format.fileExtension.appendedToFilename(license.id),
141-
licenseDocument: license
142-
)
163+
return asset.format
143164
}
144165

145166
private func readLicense(from lcpl: LicenseDocumentSource) async throws -> LicenseDocument? {

0 commit comments

Comments
 (0)