Skip to content
This repository has been archived by the owner on Jun 15, 2024. It is now read-only.

Commit

Permalink
Add walking over a playlist (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
omaralbeik authored Apr 19, 2022
1 parent e2c12e1 commit 8406caf
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 10 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ The [Swift Package Manager](https://swift.org/package-manager/) is a tool for ma

```swift
dependencies: [
.package(url: "https://github.com/omaralbeik/M3UKit.git", from: "0.4.0")
.package(url: "https://github.com/omaralbeik/M3UKit.git", from: "0.5.0")
]
```

Expand All @@ -121,15 +121,15 @@ $ swift build
To integrate M3UKit into your Xcode project using [CocoaPods](https://cocoapods.org), specify it in your Podfile:

```rb
pod 'M3UKit', :git => 'https://github.com/omaralbeik/M3UKit.git', :tag => '0.4.0'
pod 'M3UKit', :git => 'https://github.com/omaralbeik/M3UKit.git', :tag => '0.5.0'
```

### Carthage

To integrate M3UKit into your Xcode project using [Carthage](https://github.com/Carthage/Carthage), specify it in your Cartfile:

```
github "omaralbeik/M3UKit" ~> 0.4.0
github "omaralbeik/M3UKit" ~> 0.5.0
```

### Manually
Expand Down
64 changes: 57 additions & 7 deletions Sources/M3UKit/Parsers/PlaylistParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,7 @@ public final class PlaylistParser: Parser {
/// - Parameter input: source.
/// - Returns: playlist.
public func parse(_ input: PlaylistSource) throws -> Playlist {
guard let rawString = input.rawString else {
throw ParsingError.invalidSource
}

guard rawString.starts(with: "#EXTM3U") else {
throw ParsingError.invalidSource
}
let rawString = try extractRawString(from: input)

var channels: [Playlist.Channel] = []

Expand Down Expand Up @@ -85,6 +79,48 @@ public final class PlaylistParser: Parser {
return Playlist(channels: channels)
}

/// Walk over a playlist and return its channels one-by-one.
/// - Parameters:
/// - input: source.
/// - handler: Handler to be called with the parsed channel.
public func walk(
_ input: PlaylistSource,
handler: @escaping (Playlist.Channel) -> Void
) throws {
let rawString = try extractRawString(from: input)

let metadataParser = ChannelMetadataParser()
var lastMetadataLine: String?
var lastURL: URL?
var channelMetadataParsingError: Error?
var lineNumber = 0

rawString.enumerateLines { line, stop in
if metadataParser.isInfoLine(line) {
lastMetadataLine = line
} else if let url = URL(string: line) {
lastURL = url
}

if let metadataLine = lastMetadataLine, let url = lastURL {
do {
let metadata = try metadataParser.parse((lineNumber, metadataLine))
handler(.init(metadata: metadata, url: url))
lastMetadataLine = nil
lastURL = nil
} catch {
channelMetadataParsingError = error
stop = true
}
}
lineNumber += 1
}

if let error = channelMetadataParsingError {
throw error
}
}

/// Parse a playlist on a queue with a completion handler.
/// - Parameters:
/// - input: source.
Expand Down Expand Up @@ -118,4 +154,18 @@ public final class PlaylistParser: Parser {
}
}
}

// MARK: - Helpers

private func extractRawString(from input: PlaylistSource) throws -> String {
guard let rawString = input.rawString else {
throw ParsingError.invalidSource
}

guard rawString.starts(with: "#EXTM3U") else {
throw ParsingError.invalidSource
}

return rawString
}
}
26 changes: 26 additions & 0 deletions Tests/M3UKitTests/PlaylistTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,32 @@ final class PlaylistTests: XCTestCase {
XCTAssertThrowsError(try parser.parse(InvalidSource()))
}

func testWalking() throws {
let parser = PlaylistParser()
var channels: [Playlist.Channel] = []

let exp = expectation(description: "Walking succeeded")
let validURL = Bundle.module.url(forResource: "valid", withExtension: "m3u")!
try parser.walk(validURL) { channel in
channels.append(channel)
if channels.count == 105 {
exp.fulfill()
}
}

waitForExpectations(timeout: 1)
XCTAssertEqual(channels.count, 105)
}

func testWalkingInvalidSource() {
let parser = PlaylistParser()
XCTAssertThrowsError(try parser.walk("") { _ in })

let invalidURL = Bundle.module.url(forResource: "invalid", withExtension: "m3u")!
XCTAssertThrowsError(try parser.walk(invalidURL) { _ in })
}


func testErrorDescription() {
let error = PlaylistParser.ParsingError.invalidSource
XCTAssertEqual(error.errorDescription, "The playlist is invalid")
Expand Down

0 comments on commit 8406caf

Please sign in to comment.