diff --git a/vrtnu/vrtnu.xcodeproj/project.pbxproj b/vrtnu/vrtnu.xcodeproj/project.pbxproj index 3c72224..927d8bb 100644 --- a/vrtnu/vrtnu.xcodeproj/project.pbxproj +++ b/vrtnu/vrtnu.xcodeproj/project.pbxproj @@ -7,7 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - B408F0D7251F6B760043E3A4 /* Tools.swift in Sources */ = {isa = PBXBuildFile; fileRef = B408F0D6251F6B760043E3A4 /* Tools.swift */; }; B408F0DD251F6D180043E3A4 /* AsyncImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = B408F0DC251F6D180043E3A4 /* AsyncImage.swift */; }; B408F0E5251F7AC50043E3A4 /* Just.swift in Sources */ = {isa = PBXBuildFile; fileRef = B408F0E4251F7AC50043E3A4 /* Just.swift */; }; B408F0ED251F9D2C0043E3A4 /* loading.jpg in Resources */ = {isa = PBXBuildFile; fileRef = B408F0EC251F9D2C0043E3A4 /* loading.jpg */; }; @@ -39,7 +38,6 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - B408F0D6251F6B760043E3A4 /* Tools.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tools.swift; sourceTree = ""; }; B408F0DC251F6D180043E3A4 /* AsyncImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncImage.swift; sourceTree = ""; }; B408F0E4251F7AC50043E3A4 /* Just.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Just.swift; sourceTree = ""; }; B408F0EC251F9D2C0043E3A4 /* loading.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = loading.jpg; sourceTree = ""; }; @@ -125,7 +123,6 @@ B4F0CC80251BE62F00E9EA74 /* Preview Content */, B4F0CCA9251BFD6F00E9EA74 /* video.swift */, B4F0CCB6251D6B5400E9EA74 /* VrtNuLayout.swift */, - B408F0D6251F6B760043E3A4 /* Tools.swift */, ); path = vrtnu; sourceTree = ""; @@ -292,7 +289,6 @@ B4F0CC7B251BE62B00E9EA74 /* vrtnuApp.swift in Sources */, B4F0CCAA251BFD6F00E9EA74 /* video.swift in Sources */, B408F0DD251F6D180043E3A4 /* AsyncImage.swift in Sources */, - B408F0D7251F6B760043E3A4 /* Tools.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/vrtnu/vrtnu/ContentView.swift b/vrtnu/vrtnu/ContentView.swift index 40331f4..8e1d9bd 100644 --- a/vrtnu/vrtnu/ContentView.swift +++ b/vrtnu/vrtnu/ContentView.swift @@ -15,12 +15,7 @@ import TVUIKit struct ContentView: View { @ViewBuilder var body: some View { - let vrtNu = VRTNu() - if vrtNu.loggedIN() { - VRTNuView(vrtNu: vrtNu) - }else{ - LoginView(vrtNu: vrtNu) - } + VRTNuView(vrtNu: VRTNu()) } } @@ -28,12 +23,31 @@ struct LoginView: View{ var vrtNu: VRTNu @State private var password: String = "" @State private var username: String = "" + @State var authenticationDidFail: Bool = false + // needed to update parent view when login was succesful + @Binding var loginaction: Bool + var body: some View { + + if authenticationDidFail { + Text("Information not correct. Try again.") + .offset(y: -10) + .foregroundColor(.red) + } TextField("VRTNu username", text: $username) SecureField("VRTNu password", text: $password) Button("Inloggen", action: { - vrtNu.login(username: username, password: password) + + let loginok = vrtNu.login(username: username, password: password) + if loginok{ + // reload parent view here + withAnimation { + self.loginaction.toggle() + } + }else{ + authenticationDidFail = true + } }) } } @@ -114,18 +128,21 @@ struct SeasonView: View { struct VideoView: View { var episode: Episode - - + @State var loginaction: Bool = false + + var body: some View { - let url = episode.getVideo().hlsUrl - let player = AVPlayer(url: url); - VideoPlayer(player: player).fixedSize().onAppear(){ - player.play() + if episode.authenticated() || loginaction { + let player = AVPlayer(url: episode.getVideo().hlsUrl); + VideoPlayer(player: player).fixedSize().onAppear(){ + player.play() + } + }else{ + LoginView(vrtNu: episode.season.show.vrtNu, loginaction: $loginaction) } }; - - } + struct ContentView_Previews: PreviewProvider { static var previews: some View { SeasonView(season: VRTNu().getShows()[0].getSeasons()[0]) diff --git a/vrtnu/vrtnu/Tools.swift b/vrtnu/vrtnu/Tools.swift deleted file mode 100644 index be13b24..0000000 --- a/vrtnu/vrtnu/Tools.swift +++ /dev/null @@ -1,9 +0,0 @@ -// -// Tools.swift -// vrtnu -// -// Created by Jens Timmerman on 26/09/2020. -// - -import Foundation - diff --git a/vrtnu/vrtnu/VrtNuLayout.swift b/vrtnu/vrtnu/VrtNuLayout.swift index e8b5bca..19a2a65 100644 --- a/vrtnu/vrtnu/VrtNuLayout.swift +++ b/vrtnu/vrtnu/VrtNuLayout.swift @@ -1,6 +1,11 @@ // // VrtNuLayout.swift -// vrtnu +// vrtnu website scrapping (not gui layout but website scrapping layout) +// The VRTNu object is built up as: +// VRTNu -> Shows -> Seasons -> Episodes +// An episode has a reference to it's season, a season has a reference to it's show and a show has a reference to the VRTNu main struct +// Most of this is implemented as lazy vars to only parse the webpages that the user realy wants +// We use a global just object so we just have one session and we can remain logged in over all our requests // // Created by Jens Timmerman on 25/09/2020. // @@ -18,15 +23,57 @@ struct Episode: Hashable, Comparable{ let name: String let season: Season let imageURL: URL + let metadataurl: URL + func authenticated() -> Bool{ + //check if current token is valid + let videojson = getVideoJson() + print(videojson) + if videojson.object(forKey: "code") != nil{ + if videojson.value(forKey: "code") as! String == "AUTHENTICATION_REQUIRED" + { + print("not authenticated") + return false + } + print("maybe vrt authentication logic changed? please report this") + } + print("authenticated") + + return true + } lazy var video: Video = { - let token = self.season.show.vrtNu.getToken() - //`requests.get('https://www.vrt.be/vrtnu/a-z/%s/%s/%s.mssecurevideo.json' % (show, season, episode)).json()` - let url = "https://www.vrt.be/vrtnu/a-z/" + season.show.showName + "/" + season.seasonName + "/" + name + ".mssecurevideo.json" - print(url) + let videojson = getVideoJson() + print(videojson) - let msecjson = just.get(url).json! + let duration = videojson.value(forKey: "duration") as! Double + let title = videojson.value(forKey: "title") as! String + let targetURLs = videojson.value(forKey: "targetUrls") as! [NSDictionary] + let videourl = targetURLs[0].value(forKey: "url") as! String + print(videourl) + //session.get('https://media-services-public.vrt.be/vualto-video-aggregator-web/rest/external/v1/videos/%s?vrtPlayerToken=%s&client=%s@PROD' %(video_id, token, clientid)).json() + var video = Video(hlsUrl: URL(string: videourl)!, + title: title, + duration: duration) + return video + }() + + init(season: Season, episodeName: String, imageURL: URL){ + self.name = episodeName + self.season = season + self.imageURL = imageURL + self.metadataurl = URL(string: "https://www.vrt.be/vrtnu/a-z/" + season.show.showName + "/" + season.seasonName + "/" + episodeName + ".mssecurevideo.json")! + } + + func getVideo() -> Video{ + var lazyself = self + return lazyself.video + } + + func getVideoJson() -> NSDictionary{ + //`requests.get('https://www.vrt.be/vrtnu/a-z/%s/%s/%s.mssecurevideo.json' % (show, season, episode)).json()` + + let msecjson = just.get(metadataurl).json! let mssecdict = msecjson as! NSDictionary print(msecjson) let intmssecdict = mssecdict.allValues[0] as! NSDictionary @@ -38,29 +85,8 @@ struct Episode: Hashable, Comparable{ mediaurl = mediaurl + self.season.show.vrtNu.getToken() + "&client=" mediaurl = mediaurl + clientid + "@PROD" print(mediaurl) - let videojson = just.get(mediaurl).json! - print(videojson) - let videodict = videojson as! NSDictionary - let duration = videodict.value(forKey: "duration") as! Double - let title = videodict.value(forKey: "title") as! String - let targetURLs = videodict.value(forKey: "targetUrls") as! [NSDictionary] - let videourl = targetURLs[0].value(forKey: "url") as! String - print(videourl) - //session.get('https://media-services-public.vrt.be/vualto-video-aggregator-web/rest/external/v1/videos/%s?vrtPlayerToken=%s&client=%s@PROD' %(video_id, token, clientid)).json() - return Video(hlsUrl: URL(string: videourl)!, - title: title, - duration: duration) - }() - - init(season: Season, episodeName: String, imageURL: URL){ - self.name = episodeName - self.season = season - self.imageURL = imageURL - } - - func getVideo() -> Video{ - var lazyself = self - return lazyself.video + let videojson = just.get(mediaurl).json! as! NSDictionary + return videojson } } @@ -197,7 +223,6 @@ extension NSTextCheckingResult { } struct VRTNu: Hashable { - lazy var loggedin: Bool = loggedIN() lazy var shows: [Show] = { let regexPattern = "a href=\"/vrtnu/a-z/(.*).relevant" @@ -230,24 +255,8 @@ struct VRTNu: Hashable { return token } - func loggedIN() -> Bool{ - - //check if current token is valid - let testtoken = self.getToken() - let testurl = URL(string: "https://media-services-public.vrt.be/vualto-video-aggregator-web/rest/external/v1/videos/pbs-pub-414bb095-6c5c-4c0e-b998-649fe03f07d7$vid-7ed5d7e0-e284-4df0-a76d-ff497e667d04?vrtPlayerToken=" + testtoken + "&client=vrtvideo@PROD")! - let videojson = just.get(testurl).json! as! NSDictionary - if videojson.object(forKey: "code") != nil{ - if videojson.value(forKey: "code") as! String == "AUTHENTICATION_REQUIRED" - { - print("not authenticated") - return false - } - print("maybe vrt authentication logic changed? please report this") - } - return true - - } + func login(username: String, password:String) -> Bool { let auth_data = [ "ApiKey": "3_0Z2HujMtiWq_pkAjgnS2Md2E11a1AwZjYiBETtwNE-EoEHDINgtnvcAOpNgmrVGy", @@ -280,7 +289,8 @@ struct VRTNu: Hashable { ] ) - return loggedIN() + print("authenticated") + return true } diff --git a/vrtnu/vrtnu/video.swift b/vrtnu/vrtnu/video.swift index df435ae..67afaaa 100644 --- a/vrtnu/vrtnu/video.swift +++ b/vrtnu/vrtnu/video.swift @@ -30,17 +30,3 @@ struct Video: Hashable { } } -extension Video { - - static func makeVideos() -> [Video] { - return [ - Video(hlsUrl: URL(string: "https://remix-cf.lwc.vrtcdn.be/remix/ecd69313-4a39-4297-95b1-aede167725b7/remix.ism/.m3u8")!, - title: "best of dinges", - duration: 2946), - Video(hlsUrl: URL(string: "https://remix-cf.lwc.vrtcdn.be/remix/ecd69313-4a39-4297-95b1-aede167725b7/remix.ism/.m3u8")!, - title: "best of dinges 2", - duration: 2946), - - ] - } -}