Skip to content
Open
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 Pantomime.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
27EDFCB21E9061B400945246 /* media3.m3u8 in Resources */ = {isa = PBXBuildFile; fileRef = 27EDFCB11E9061B400945246 /* media3.m3u8 */; };
5ED0327E1D6F1710006DE1F3 /* ManifestBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5ED032791D6F1710006DE1F3 /* ManifestBuilder.swift */; };
5ED0327F1D6F1710006DE1F3 /* MediaSegment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5ED0327A1D6F1710006DE1F3 /* MediaSegment.swift */; };
5ED032801D6F1710006DE1F3 /* MediaPlaylist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5ED0327B1D6F1710006DE1F3 /* MediaPlaylist.swift */; };
Expand Down Expand Up @@ -69,6 +70,7 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
27EDFCB11E9061B400945246 /* media3.m3u8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = media3.m3u8; sourceTree = "<group>"; };
5ED032791D6F1710006DE1F3 /* ManifestBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ManifestBuilder.swift; path = sources/ManifestBuilder.swift; sourceTree = "<group>"; };
5ED0327A1D6F1710006DE1F3 /* MediaSegment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MediaSegment.swift; path = sources/MediaSegment.swift; sourceTree = "<group>"; };
5ED0327B1D6F1710006DE1F3 /* MediaPlaylist.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MediaPlaylist.swift; path = sources/MediaPlaylist.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -188,6 +190,7 @@
9EDCE3F31C09D211002FA4A7 /* PantomimeTests.swift */,
7FBCA10A0EB4EAA0CD4AB5EF /* ReaderTests.swift */,
7FBCAFC77C9DA4C80FAEA0C2 /* PlaylistTests.swift */,
27EDFCB11E9061B400945246 /* media3.m3u8 */,
);
path = PantomimeTests;
sourceTree = "<group>";
Expand Down Expand Up @@ -354,6 +357,7 @@
buildActionMask = 2147483647;
files = (
5ED0328F1D6F17BF006DE1F3 /* media2.m3u8 in Resources */,
27EDFCB21E9061B400945246 /* media3.m3u8 in Resources */,
5ED032961D6F7618006DE1F3 /* master.m3u8 in Resources */,
5ED032901D6F17BF006DE1F3 /* media.m3u8 in Resources */,
);
Expand Down
14 changes: 13 additions & 1 deletion PantomimeTests/PantomimeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@ import XCTest
@testable import Pantomime

class PantomimeTests: XCTestCase {

func test3ParseMediaPlaylist() {
let bundle = Bundle(for: type(of: self))
let path = bundle.path(forResource: "media3", ofType: "m3u8")!

let manifestBuilder = ManifestBuilder()
let mediaPlaylist = manifestBuilder.parseMediaPlaylistFromFile(path)

XCTAssert(mediaPlaylist.segments.count == 1)
XCTAssert(mediaPlaylist.segments[0].title == "Hey this is working!")
XCTAssert(mediaPlaylist.segments[0].properties?["tvg-name"] == "example")
}

func testParseMediaPlaylist() {
let bundle = Bundle(for: type(of: self))
Expand All @@ -23,7 +35,7 @@ class PantomimeTests: XCTestCase {

XCTAssert(mediaPlaylist.targetDuration == 10)
XCTAssert(mediaPlaylist.mediaSequence == 0)
XCTAssert(mediaPlaylist.segments.count == 3)
XCTAssert(mediaPlaylist.segments.count == 4)
XCTAssert(mediaPlaylist.segments[0].title == " no desc")
XCTAssert(mediaPlaylist.segments[0].subrangeLength == 100)
XCTAssert(mediaPlaylist.segments[0].subrangeStart == 40)
Expand Down
2 changes: 2 additions & 0 deletions PantomimeTests/ReaderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class ReaderTests: XCTestCase {
for _ in 1...10 {
_ = fileReader.readLine()!
}
XCTAssertEqual("#EXTINF:-1 tvg-ID=\"\" tvg-name=\"example\" custom-attribute=\"\" group-title=\"another example\",title: of channel", fileReader.readLine())
XCTAssertEqual("http://media.example.com/fourth.ts", fileReader.readLine())
XCTAssertNil(fileReader.readLine())

let httpReader = try ReaderBuilder.createReader(.httpreader, reference: "http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8")
Expand Down
4 changes: 3 additions & 1 deletion PantomimeTests/media.m3u8
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ http://media.example.com/first.ts
#EXT-X-BYTERANGE:100
http://media.example.com/second.ts
#EXTINF:3.003,
http://media.example.com/third.ts
http://media.example.com/third.ts
#EXTINF:-1 tvg-ID="" tvg-name="example" custom-attribute="" group-title="another example",title: of channel
http://media.example.com/fourth.ts
6 changes: 6 additions & 0 deletions PantomimeTests/media3.m3u8
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#EXTM3U
#This is a comment
#EXTINF:-1 tvg-ID="" tvg-name="example" custom-attribute="" group-title="another example",Hey this is working!
http://media.example.com/fourth.ts
#EXTINF:-1 tvg-ID="" tvg-name="Kingsman: The Secret Service" tvg-logo="https://images-na.ssl-images-amazon.com/images/M/MV5BMTkxMjgwMDM4Ml5BMl5BanBnXkFtZTgwMTk3NTIwNDE@._V1_SY1000_CR0,0,675,1000_AL_.jpg" group-title="VOD: Action",Kingsman: The Secret Service
http://client-proiptv.com:8080/movie/AwC7WSEgSy/C1IxqxuT2k/9745.mkv
27 changes: 25 additions & 2 deletions sources/ManifestBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,12 @@ open class ManifestBuilder {
} else if line.hasPrefix("#EXTINF") {
currentSegment = MediaSegment()
do {
let segmentDurationString = try line.replace("(.*):(\\d.*),(.*)", replacement: "$2")
let segmentTitle = try line.replace("(.*):(\\d.*),(.*)", replacement: "$3")
let generalRegex = "(.*):(-?[0-9]\\d*(\\.\\d+)?)(.*),(.*)"
let segmentDurationString = try line.replace(generalRegex, replacement: "$2")
let rawProperties = try line.replace(generalRegex, replacement: "$4")
let segmentTitle = try line.replace(generalRegex, replacement: "$5")

currentSegment!.properties = getProperties(in: rawProperties)
currentSegment!.duration = Float(segmentDurationString)
currentSegment!.title = segmentTitle
} catch {
Expand Down Expand Up @@ -172,6 +176,25 @@ open class ManifestBuilder {
return mediaPlaylist
}

func getProperties(in text: String) -> [String:String]? {
do {
let regex = try NSRegularExpression(pattern: "([a-zA-z-]*)=\"(.*?)\"")
let nsString = text as NSString
let results = regex.matches(in: text, range: NSRange(location: 0, length: nsString.length))
let keys = results.map { nsString.substring(with: $0.rangeAt(1))}
let values = results.map { nsString.substring(with: $0.rangeAt(2))}
var result = [String:String]()
for (index, value) in values.enumerated() {
result[keys[index]] = value
}
return result
// return results.map { nsString.substring(with: $0.range)}
} catch let error {
print("Error: \(error.localizedDescription)")
return nil
}
}

/**
* Parses the master playlist manifest from a string document.
*
Expand Down
3 changes: 3 additions & 0 deletions sources/MediaPlaylist.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ open class MediaPlaylist {
open func duration() -> Float {
var dur: Float = 0.0
for item in segments {
if item.duration == nil || item.duration! <= 0 {
continue
}
dur = dur + item.duration!
}
return dur
Expand Down
1 change: 1 addition & 0 deletions sources/MediaSegment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ open class MediaSegment {
open var title: String?
open var discontinuity: Bool = false
open var path: String?
open var properties: [String:String]?

public init() {

Expand Down