Skip to content

Sniff audio clips #403

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ All notable changes to this project will be documented in this file. Take a look
* Fixed starting the TTS from the current EPUB position.
* [#396](https://github.com/readium/swift-toolkit/issues/396) Ensure we stop the activity indicator when an EPUB resource fails to load correctly (contributed by [@ettore](https://github.com/readium/swift-toolkit/pull/397)).

#### Streamer

* [#399](https://github.com/readium/swift-toolkit/discussions/399) Zipped Audio Books and standalone audio files are now recognized.


## [2.6.1]

Expand Down
5 changes: 4 additions & 1 deletion Sources/Shared/Toolkit/Media Type/MediaType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ public struct MediaType: Hashable, Loggable {
public static let divina = MediaType("application/divina+zip", name: "Digital Visual Narratives", fileExtension: "divina")!
public static let divinaManifest = MediaType("application/divina+json", name: "Digital Visual Narratives", fileExtension: "json")!
public static let epub = MediaType("application/epub+zip", name: "EPUB", fileExtension: "epub")!
public static let flac = MediaType("audio/flac", fileExtension: "flac")!
public static let gif = MediaType("image/gif", fileExtension: "gif")!
public static let gz = MediaType("application/gzip", fileExtension: "gz")!
public static let html = MediaType("text/html", fileExtension: "html")!
Expand All @@ -266,7 +267,9 @@ public struct MediaType: Hashable, Loggable {
public static let lcpStatusDocument = MediaType("application/vnd.readium.license.status.v1.0+json")!
public static let lpf = MediaType("application/lpf+zip", fileExtension: "lpf")!
public static let mp3 = MediaType("audio/mpeg", fileExtension: "mp3")!
public static let mpeg = MediaType("video/mpeg", fileExtension: "mpeg")!
public static let mp4 = MediaType("audio/mp4", fileExtension: "mp4")!
public static let mpegAudio = MediaType("audio/mpeg", fileExtension: "mpeg")!
public static let mpegVideo = MediaType("video/mpeg", fileExtension: "mpeg")!
public static let ncx = MediaType("application/x-dtbncx+xml", fileExtension: "ncx")!
public static let ogg = MediaType("audio/ogg", fileExtension: "oga")!
public static let ogv = MediaType("video/ogg", fileExtension: "ogv")!
Expand Down
37 changes: 36 additions & 1 deletion Sources/Shared/Toolkit/Media Type/MediaTypeSniffer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ public extension MediaType {
/// You can register additional sniffers globally by modifying this list.
/// The sniffers order is important, because some media types are subsets of other media types.
static var sniffers: [Sniffer] = [
sniffHTML, sniffOPDS, sniffLCPLicense, sniffBitmap,
sniffHTML, sniffOPDS, sniffLCPLicense, sniffBitmap, sniffAudio,
sniffWebPub, sniffW3CWPUB, sniffEPUB, sniffLPF, sniffArchive, sniffPDF,
]

Expand Down Expand Up @@ -392,6 +392,41 @@ public extension MediaType {
return nil
}

/// Sniffs an audio clip.
private static func sniffAudio(context: MediaTypeSnifferContext) -> MediaType? {
if context.hasFileExtension("aac") || context.hasMediaType("audio/aac") {
return .aac
}
if context.hasFileExtension("aiff", "aif", "aifc") || context.hasMediaType("audio/aiff", "audio/x-aiff") {
return .aiff
}
if context.hasFileExtension("flac") || context.hasMediaType("audio/flac") {
return .flac
}
if context.hasFileExtension("mp3") {
return .mp3
}
if context.hasFileExtension("mp4", "m4a", "m4b", "m4p", "m4r", "alac") || context.hasMediaType("audio/mp4") {
return .mp4
}
if context.hasMediaType("audio/mpeg") {
return .mpegAudio
}
if context.hasFileExtension("ogg", "oga", "mogg") || context.hasMediaType("audio/ogg") {
return .ogg
}
if context.hasFileExtension("opus") || context.hasMediaType("audio/opus") {
return .opus
}
if context.hasFileExtension("wav", "wave") || context.hasMediaType("audio/wav", "audio/x-wav", "audio/wave") {
return .wav
}
if context.hasFileExtension("webm") || context.hasMediaType("audio/webm") {
return .webmAudio
}
return nil
}

/// Sniffs the media types declared in the Document Types section of the app's `Info.plist`.
private static func sniffDocumentTypes(_ context: MediaTypeSnifferContext) -> MediaType? {
func sniff(_ documentType: DocumentType) -> MediaType? {
Expand Down
61 changes: 61 additions & 0 deletions Tests/SharedTests/Toolkit/Media Type/MediaTypeSnifferTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,19 @@ class MediaTypeSnifferTests: XCTestCase {
XCTAssertEqual(MediaType.of(fixtures.url(for: "audiobook-wrongtype.json")), .readiumAudiobookManifest)
}

func testSniffAAC() {
XCTAssertEqual(MediaType.of(fileExtension: "aac"), .aac)
XCTAssertEqual(MediaType.of(mediaType: "audio/aac"), .aac)
}

func testSniffAIFF() {
XCTAssertEqual(MediaType.of(fileExtension: "aiff"), .aiff)
XCTAssertEqual(MediaType.of(fileExtension: "aif"), .aiff)
XCTAssertEqual(MediaType.of(fileExtension: "aifc"), .aiff)
XCTAssertEqual(MediaType.of(mediaType: "audio/aiff"), .aiff)
XCTAssertEqual(MediaType.of(mediaType: "audio/x-aiff"), .aiff)
}

func testSniffBMP() {
XCTAssertEqual(MediaType.of(fileExtension: "bmp"), .bmp)
XCTAssertEqual(MediaType.of(fileExtension: "dib"), .bmp)
Expand Down Expand Up @@ -98,6 +111,11 @@ class MediaTypeSnifferTests: XCTestCase {
XCTAssertEqual(MediaType.of(fixtures.url(for: "epub.unknown")), .epub)
}

func testSniffFLAC() {
XCTAssertEqual(MediaType.of(fileExtension: "flac"), .flac)
XCTAssertEqual(MediaType.of(mediaType: "audio/flac"), .flac)
}

func testSniffGIF() {
XCTAssertEqual(MediaType.of(fileExtension: "gif"), .gif)
XCTAssertEqual(MediaType.of(mediaType: "image/gif"), .gif)
Expand Down Expand Up @@ -176,6 +194,36 @@ class MediaTypeSnifferTests: XCTestCase {
XCTAssertEqual(MediaType.of(fixtures.url(for: "lpf-index-html.unknown")), .lpf)
}

func testSniffMP3() {
XCTAssertEqual(MediaType.of(fileExtension: "mp3"), .mp3)
}

func testSniffMP4() {
XCTAssertEqual(MediaType.of(fileExtension: "mp4"), .mp4)
XCTAssertEqual(MediaType.of(fileExtension: "m4a"), .mp4)
XCTAssertEqual(MediaType.of(fileExtension: "m4b"), .mp4)
XCTAssertEqual(MediaType.of(fileExtension: "m4p"), .mp4)
XCTAssertEqual(MediaType.of(fileExtension: "m4r"), .mp4)
XCTAssertEqual(MediaType.of(fileExtension: "alac"), .mp4)
XCTAssertEqual(MediaType.of(mediaType: "audio/mp4"), .mp4)
}

func testSniffMPEG() {
XCTAssertEqual(MediaType.of(mediaType: "audio/mpeg"), .mpegAudio)
}

func testSniffOGG() {
XCTAssertEqual(MediaType.of(fileExtension: "ogg"), .ogg)
XCTAssertEqual(MediaType.of(fileExtension: "oga"), .ogg)
XCTAssertEqual(MediaType.of(fileExtension: "mogg"), .ogg)
XCTAssertEqual(MediaType.of(mediaType: "audio/ogg"), .ogg)
}

func testSniffOPUS() {
XCTAssertEqual(MediaType.of(fileExtension: "opus"), .opus)
XCTAssertEqual(MediaType.of(mediaType: "audio/opus"), .opus)
}

func testSniffPDF() {
XCTAssertEqual(MediaType.of(fileExtension: "pdf"), .pdf)
XCTAssertEqual(MediaType.of(mediaType: "application/pdf"), .pdf)
Expand All @@ -194,11 +242,24 @@ class MediaTypeSnifferTests: XCTestCase {
XCTAssertEqual(MediaType.of(mediaType: "image/tiff-fx"), .tiff)
}

func testSniffWAV() {
XCTAssertEqual(MediaType.of(fileExtension: "wav"), .wav)
XCTAssertEqual(MediaType.of(fileExtension: "wave"), .wav)
XCTAssertEqual(MediaType.of(mediaType: "audio/wav"), .wav)
XCTAssertEqual(MediaType.of(mediaType: "audio/x-wav"), .wav)
XCTAssertEqual(MediaType.of(mediaType: "audio/wave"), .wav)
}

func testSniffWebP() {
XCTAssertEqual(MediaType.of(fileExtension: "webp"), .webp)
XCTAssertEqual(MediaType.of(mediaType: "image/webp"), .webp)
}

func testSniffWebM() {
XCTAssertEqual(MediaType.of(fileExtension: "webm"), .webmAudio)
XCTAssertEqual(MediaType.of(mediaType: "audio/webm"), .webmAudio)
}

func testSniffWebPub() {
XCTAssertEqual(MediaType.of(fileExtension: "webpub"), .readiumWebPub)
XCTAssertEqual(MediaType.of(mediaType: "application/webpub+zip"), .readiumWebPub)
Expand Down