Skip to content
This repository has been archived by the owner on Apr 26, 2023. It is now read-only.

Added parsing of skip offset for VAST ad #62

Merged
merged 2 commits into from
Feb 12, 2019
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
2 changes: 1 addition & 1 deletion PlayerCore
8 changes: 4 additions & 4 deletions VerizonVideoPartnerSDK.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1070,15 +1070,15 @@
DE1685D71CE7308500492A90 /* vast parser */ = {
isa = PBXGroup;
children = (
DEF02B511D1EC0AD001F64EE /* VASTModel.swift */,
DE1685DC1CE732D600492A90 /* VASTParser.swift */,
DE1685E61CE76A5D00492A90 /* VASTParserTests.swift */,
DE1685E41CE768E600492A90 /* VASTExampleCDATA.xml */,
DE1FD9CE1CE7737900C0B7BC /* VASTMissedCorrectType.xml */,
DE4539411D09644D00317632 /* XMLParser.swift */,
DEF02B511D1EC0AD001F64EE /* VASTModel.swift */,
DEF02B581D22970A001F64EE /* VAST1.xml */,
06BF541620A062E300B98A6D /* VASTVpaid.xml */,
DE1685E41CE768E600492A90 /* VASTExampleCDATA.xml */,
DE1FD9CE1CE7737900C0B7BC /* VASTMissedCorrectType.xml */,
067209D921B6BE710086CDBE /* VASTVerificationInExtension.xml */,
06BF541620A062E300B98A6D /* VASTVpaid.xml */,
B418F5461ECB267B00C9131D /* VASTWrapper.xml */,
067209DA21B6BE710086CDBE /* VASTWrapperWithExtension.xml */,
);
Expand Down
1 change: 1 addition & 0 deletions sources/advertisements/MidrollDetectorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class MidrollDetectorTests: QuickSpec {
scalable: true,
maintainAspectRatio: true)],
vpaidMediaFiles: [],
skipOffset: .none,
clickthrough: nil,
adParameters: nil,
pixels: .init(),
Expand Down
4 changes: 2 additions & 2 deletions sources/advertisements/VAST1.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
<Impression><![CDATA[http://localhost:3000/0/pixels/pixel.php?name=noname_impression&random=[CACHE_BUSTER]]]></Impression>
<Creatives>
<Creative id="55414">
<Linear>
<Duration>00:00:30</Duration>
<Linear skipoffset="01:01:03.123">
<Duration>02:00:30</Duration>
<TrackingEvents>
<Tracking event="creativeView"><![CDATA[http://localhost:3000/6/beacons/vast/creativeView.gif]]></Tracking>
<Tracking event="start"><![CDATA[http://localhost:3000/6/beacons/vast/start.gif]]></Tracking>
Expand Down
1 change: 1 addition & 0 deletions sources/advertisements/VASTModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ extension PlayerCore.Ad.VASTModel {
adVerifications: self.adVerifications + verifications,
mp4MediaFiles: mp4MediaFiles,
vpaidMediaFiles: vpaidMediaFiles,
skipOffset: skipOffset,
clickthrough: clickthrough,
adParameters: adParameters,
pixels: self.pixels.merge(with: pixels),
Expand Down
71 changes: 71 additions & 0 deletions sources/advertisements/VASTParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ enum VASTParser {
var adParameters: String?
var mp4MediaFiles: [PlayerCore.Ad.VASTModel.MP4MediaFile] = []
var vpaidMediaFiles: [PlayerCore.Ad.VASTModel.VPAIDMediaFile] = []
var skipOffset: PlayerCore.Ad.VASTModel.SkipOffset = .none
}

struct AdVerification {
Expand Down Expand Up @@ -134,6 +135,18 @@ enum VASTParser {
}

delegate.didStartElement = .some { (name, attr) -> Void in
if let skipOffset = attr["skipoffset"] {
if skipOffset.contains("%") {
if let value = Int(skipOffset.replacingOccurrences(of: "%", with: "")) {
inlineContext.skipOffset = .percentage(value)
}
} else if skipOffset.contains(":") {
if let value = VASTTime(with: skipOffset)?.seconds {
inlineContext.skipOffset = .time(Double(value))
}
}
}

switch name {
case "Extensions":
delegateStack.push(XML.Delegate(setup: { delegate in
Expand Down Expand Up @@ -449,6 +462,7 @@ enum VASTParser {
with: adId,
to: { context in
delegateStack.pop()

guard result == nil else { fatalError("Result overwrite detected") }
guard !context.vpaidMediaFiles.isEmpty || !context.mp4MediaFiles.isEmpty else { return }

Expand All @@ -466,6 +480,7 @@ enum VASTParser {
let model = PlayerCore.Ad.VASTModel(adVerifications: adVerifications,
mp4MediaFiles: context.mp4MediaFiles,
vpaidMediaFiles: context.vpaidMediaFiles,
skipOffset: context.skipOffset,
clickthrough: context.clickthroughURL,
adParameters: context.adParameters,
pixels: context.pixels,
Expand All @@ -491,6 +506,62 @@ enum VASTParser {

return delegateStack
}

struct VASTTime {
enum Time {
case hours([String])
case minutes([String])
case seconds([String])

private var maxValue: Int {
switch self {
case .hours: return 99
case .minutes, .seconds: return 59
}
}
private var multiplier: Int {
switch self {
case .hours: return 3600
case .minutes: return 60
case .seconds: return 1
}
}
private var index: Int {
switch self {
case .hours: return 0
case .minutes: return 1
case .seconds: return 2
}
}
private var stringTime: String {
switch self {
case .hours(let value): return value[self.index]
case .minutes(let value): return value[self.index]
case .seconds(let value): return value[self.index]
}
}

var resultInSeconds: Int? {
guard let roundedSeconds = Double(self.stringTime)?.rounded() else { return nil }
let result = Int(roundedSeconds)
guard result <= maxValue else { return nil }
return result * multiplier
}

}

let seconds: Int

init?(with time: String) {
let components = time.components(separatedBy: ":")
guard components.count == 3,
let hours = Time.hours(components).resultInSeconds,
let minutes = Time.minutes(components).resultInSeconds,
let seconds = Time.seconds(components).resultInSeconds else { return nil }
self.seconds = hours + minutes + seconds
}
}

//swiftlint:disable line_length
//swiftlint:enable function_body_length
//swiftlint:enable cyclomatic_complexity
Expand Down
25 changes: 23 additions & 2 deletions sources/advertisements/VASTParserTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class VASTParserTests: XCTestCase {
guard case let .inline(inlineModel) = model else { return XCTFail() }
guard let url = inlineModel.mp4MediaFiles.first?.url.absoluteString else { return XCTFail() }
XCTAssertEqual(url,
"https://dev.example.com/videos/2018/video_example_1280x720.mp4")
"https://dev.example.com/videos/2018/video_example_1280x720.mp4")
XCTAssertEqual(inlineModel.id, "4203085")
}

Expand Down Expand Up @@ -69,7 +69,7 @@ class VASTParserTests: XCTestCase {
let vast = getVAST(atPath: "VAST1")
guard let model = VASTParser.parseFrom(string: vast) else { return XCTFail() }
guard case .inline(let inlineModel) = model else { return XCTFail() }

XCTAssertEqual(inlineModel.adVerifications.count, 1)
guard let adVerification = inlineModel.adVerifications.first else { return XCTFail("Missing AdVerification") }

Expand Down Expand Up @@ -124,4 +124,25 @@ class VASTParserTests: XCTestCase {
XCTAssertEqual(vpaidModel.pixels.close.first?.absoluteString, url + "close.gif")
XCTAssertEqual(vpaidModel.pixels.collapse.first?.absoluteString, url + "collapse.gif")
}

func testParseSkipOffsetInTime() {
let vast = getVAST(atPath: "VAST1")
guard let model = VASTParser.parseFrom(string: vast) else { return XCTFail("Failed to parse VAST VPAID xml") }
guard case let .inline(vpaidModel) = model else { return XCTFail() }
XCTAssertEqual(vpaidModel.skipOffset, .time(3663))
}

func testParseSkipOffsetInPersentage() {
let vast = getVAST(atPath: "VASTExampleCDATA")
guard let model = VASTParser.parseFrom(string: vast) else { return XCTFail("Failed to parse VAST VPAID xml") }
guard case let .inline(vpaidModel) = model else { return XCTFail() }
XCTAssertEqual(vpaidModel.skipOffset, .percentage(32))
}

func testParseNotValidSkipOffsetInTime() {
let vast = getVAST(atPath: "VASTVerificationInExtension")
guard let model = VASTParser.parseFrom(string: vast) else { return XCTFail("Failed to parse VAST VPAID xml") }
guard case let .inline(vpaidModel) = model else { return XCTFail() }
XCTAssertEqual(vpaidModel.skipOffset, .none)
}
}
2 changes: 1 addition & 1 deletion sources/advertisements/VASTVerificationInExtension.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<Impression><![CDATA[http://localhost:3000/6/beacons/vast/impression.gif?int=123&str=abc&macro=[HELLO]&url=https%3A%2F%2Fexample.com%2Fpath]]></Impression>
<Creatives>
<Creative>
<Linear>
<Linear skipoffset="01.5:60:64.123">
<Duration>
<![CDATA[00:00:30]]>
</Duration>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class FinishVRMGroupProcessingControllerTest: XCTestCase {
adModel = .init(adVerifications: [],
mp4MediaFiles: [],
vpaidMediaFiles: [],
skipOffset: .none,
clickthrough: nil,
adParameters: nil,
pixels: .init(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class ParseVRMItemControllerTest: XCTestCase {
let result = PlayerCore.Ad.VASTModel(adVerifications: [],
mp4MediaFiles: [],
vpaidMediaFiles: [],
skipOffset: .none,
clickthrough: nil,
adParameters: nil,
pixels: AdPixels(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class VRMProcessingControllerTest: XCTestCase {
adModel = .init(adVerifications: [],
mp4MediaFiles: [],
vpaidMediaFiles: [],
skipOffset: .none,
clickthrough: nil,
adParameters: nil,
pixels: .init(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,16 @@ class VRMSelectFinalResultControllerTest: XCTestCase {
adModel1 = .init(adVerifications: [],
mp4MediaFiles: [],
vpaidMediaFiles: [],
clickthrough: nil,
adParameters: nil,
pixels: .init(),
id: "id1")
skipOffset: .none,
clickthrough: nil,
adParameters: nil,
pixels: .init(),
id: "id1")

adModel2 = .init(adVerifications: [],
mp4MediaFiles: [],
vpaidMediaFiles: [],
skipOffset: .none,
clickthrough: nil,
adParameters: nil,
pixels: .init(),
Expand Down
1 change: 1 addition & 0 deletions sources/advertisements/VerifyBuldTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class VerifyBuldTests: XCTestCase {
vpaidMediaFiles: [Ad.VASTModel.VPAIDMediaFile(url: url,
scalable: false,
maintainAspectRatio: true)],
skipOffset: .none,
clickthrough: nil,
adParameters: "",
pixels: AdPixels(),
Expand Down