diff --git a/vrtnu/.DS_Store b/vrtnu/.DS_Store index 1726d69..f2e656a 100644 Binary files a/vrtnu/.DS_Store and b/vrtnu/.DS_Store differ diff --git a/vrtnu/vrtnu.xcodeproj/project.pbxproj b/vrtnu/vrtnu.xcodeproj/project.pbxproj index 8d2335a..3c72224 100644 --- a/vrtnu/vrtnu.xcodeproj/project.pbxproj +++ b/vrtnu/vrtnu.xcodeproj/project.pbxproj @@ -9,6 +9,8 @@ /* 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 */; }; B4F0CC7B251BE62B00E9EA74 /* vrtnuApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4F0CC7A251BE62B00E9EA74 /* vrtnuApp.swift */; }; B4F0CC7D251BE62B00E9EA74 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4F0CC7C251BE62B00E9EA74 /* ContentView.swift */; }; B4F0CC7F251BE62F00E9EA74 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B4F0CC7E251BE62F00E9EA74 /* Assets.xcassets */; }; @@ -39,6 +41,8 @@ /* 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 = ""; }; B4F0CC77251BE62B00E9EA74 /* vrtnu.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = vrtnu.app; sourceTree = BUILT_PRODUCTS_DIR; }; B4F0CC7A251BE62B00E9EA74 /* vrtnuApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = vrtnuApp.swift; sourceTree = ""; }; B4F0CC7C251BE62B00E9EA74 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; @@ -80,17 +84,19 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - B408F0DB251F6D030043E3A4 /* AscyncImage */ = { + B408F0DB251F6D030043E3A4 /* dependencies */ = { isa = PBXGroup; children = ( B408F0DC251F6D180043E3A4 /* AsyncImage.swift */, + B408F0E4251F7AC50043E3A4 /* Just.swift */, ); - path = AscyncImage; + path = dependencies; sourceTree = ""; }; B4F0CC6E251BE62B00E9EA74 = { isa = PBXGroup; children = ( + B408F0EC251F9D2C0043E3A4 /* loading.jpg */, B4F0CC79251BE62B00E9EA74 /* vrtnu */, B4F0CC8B251BE62F00E9EA74 /* vrtnuTests */, B4F0CC96251BE62F00E9EA74 /* vrtnuUITests */, @@ -111,7 +117,7 @@ B4F0CC79251BE62B00E9EA74 /* vrtnu */ = { isa = PBXGroup; children = ( - B408F0DB251F6D030043E3A4 /* AscyncImage */, + B408F0DB251F6D030043E3A4 /* dependencies */, B4F0CC7A251BE62B00E9EA74 /* vrtnuApp.swift */, B4F0CC7C251BE62B00E9EA74 /* ContentView.swift */, B4F0CC7E251BE62F00E9EA74 /* Assets.xcassets */, @@ -253,6 +259,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + B408F0ED251F9D2C0043E3A4 /* loading.jpg in Resources */, B4F0CC82251BE62F00E9EA74 /* Preview Assets.xcassets in Resources */, B4F0CC7F251BE62F00E9EA74 /* Assets.xcassets in Resources */, ); @@ -279,6 +286,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + B408F0E5251F7AC50043E3A4 /* Just.swift in Sources */, B4F0CC7D251BE62B00E9EA74 /* ContentView.swift in Sources */, B4F0CCB7251D6B5400E9EA74 /* VrtNuLayout.swift in Sources */, B4F0CC7B251BE62B00E9EA74 /* vrtnuApp.swift in Sources */, diff --git a/vrtnu/vrtnu/AscyncImage/AsyncImage.swift b/vrtnu/vrtnu/AscyncImage/AsyncImage.swift deleted file mode 100644 index d8271bc..0000000 --- a/vrtnu/vrtnu/AscyncImage/AsyncImage.swift +++ /dev/null @@ -1,122 +0,0 @@ -// -// AsyncImage.swift -// AsyncImage -// -// Created by Vadym Bulavin on 2/13/20. -// Copyright © 2020 Vadym Bulavin. All rights reserved. -// -import SwiftUI -import UIKit -import Combine - -protocol ImageCache { - subscript(_ url: URL) -> UIImage? { get set } -} - -struct TemporaryImageCache: ImageCache { - private let cache = NSCache() - - subscript(_ key: URL) -> UIImage? { - get { cache.object(forKey: key as NSURL) } - set { newValue == nil ? cache.removeObject(forKey: key as NSURL) : cache.setObject(newValue!, forKey: key as NSURL) } - } -} - -struct ImageCacheKey: EnvironmentKey { - static let defaultValue: ImageCache = TemporaryImageCache() -} - -extension EnvironmentValues { - var imageCache: ImageCache { - get { self[ImageCacheKey.self] } - set { self[ImageCacheKey.self] = newValue } - } -} - -struct AsyncImage: View { - @StateObject private var loader: ImageLoader - private let placeholder: Placeholder - private let image: (UIImage) -> Image - - init( - url: URL, - @ViewBuilder placeholder: () -> Placeholder, - @ViewBuilder image: @escaping (UIImage) -> Image = Image.init(uiImage:) - ) { - self.placeholder = placeholder() - self.image = image - _loader = StateObject(wrappedValue: ImageLoader(url: url, cache: Environment(\.imageCache).wrappedValue)) - } - - var body: some View { - content - .onAppear(perform: loader.load) - } - - private var content: some View { - Group { - if loader.image != nil { - image(loader.image!) - } else { - placeholder - } - } - } -} - -class ImageLoader: ObservableObject { - @Published var image: UIImage? - - private(set) var isLoading = false - - private let url: URL - private var cache: ImageCache? - private var cancellable: AnyCancellable? - - private static let imageProcessingQueue = DispatchQueue(label: "image-processing") - - init(url: URL, cache: ImageCache? = nil) { - self.url = url - self.cache = cache - } - - deinit { - cancel() - } - - func load() { - guard !isLoading else { return } - - if let image = cache?[url] { - self.image = image - return - } - - cancellable = URLSession.shared.dataTaskPublisher(for: url) - .map { UIImage(data: $0.data) } - .replaceError(with: nil) - .handleEvents(receiveSubscription: { [weak self] _ in self?.onStart() }, - receiveOutput: { [weak self] in self?.cache($0) }, - receiveCompletion: { [weak self] _ in self?.onFinish() }, - receiveCancel: { [weak self] in self?.onFinish() }) - .subscribe(on: Self.imageProcessingQueue) - .receive(on: DispatchQueue.main) - .sink { [weak self] in self?.image = $0 } - } - - func cancel() { - cancellable?.cancel() - } - - private func onStart() { - isLoading = true - } - - private func onFinish() { - isLoading = false - } - - private func cache(_ image: UIImage?) { - image.map { cache?[url] = $0 } - } -} diff --git a/vrtnu/vrtnu/ContentView.swift b/vrtnu/vrtnu/ContentView.swift index 3a4df32..8e836d0 100644 --- a/vrtnu/vrtnu/ContentView.swift +++ b/vrtnu/vrtnu/ContentView.swift @@ -11,45 +11,50 @@ import AVFoundation import Combine - struct ContentView: View { var body: some View { - NavigationView{ - VStack { - ForEach(VRTNu().shows, id: \.self){ show in - VStack{ + NavigationView(){ + List(VRTNu().shows, id: \.self){ show in + NavigationLink(destination: ShowView(show: show)){ Text(show.title) - HStack{ - ForEach(show.seasons, id:\.self){ season in - ForEach(season.episodes, id:\.self){ episode in - NavigationLink(destination: VideoView(url: episode.video.hlsUrl)){VStack{ - Text(season.seasonName) - Text(episode.name) - AsyncImage( - url: episode.imageurl, - placeholder: { Text("Loading ...") }, - image: { Image(uiImage: $0).resizable() } - ) - }} - } - } - } - } } } - .navigationTitle("VRT Nu") - .listStyle(GroupedListStyle()) } } } -/*struct SeasonView: View{ - var body: some View{ - +struct ShowView: View { + var show: Show + var body: some View { + NavigationView(){ + List(show.getSeasons(), id: \.self){ season in + NavigationLink(destination: SeasonView(season: season)){ + Text(season.seasonName) + } + } + } } - URL(string: "https://remix-cf.lwc.vrtcdn.be/remix/ecd69313-4a39-4297-95b1-aede167725b7/remix.ism/.m3u8")! -}*/ +} + +struct SeasonView: View { + var season: Season + var body: some View { + NavigationView(){ + List(season.episodes, id:\.self){ episode in + NavigationLink(destination: VideoView(url: episode.video.hlsUrl)){ + VStack{ + Text(episode.name) + AsyncImage(url: episode.imageurl,placeholder: { + //Image(name: "loading") + Text("Loading...") + },image:{Image(uiImage:$0)}) + } + } + } + } + } +} struct VideoView: View { var url: URL @@ -63,6 +68,51 @@ struct VideoView: View { } struct ContentView_Previews: PreviewProvider { static var previews: some View { - ContentView() + SeasonView(season: VRTNu().shows[0].getSeasons()[0]) } } + + + + +/*struct OldContentView: View { +var body: some View { +NavigationView(){ + VStack(alignment: .leading) { + ForEach(VRTNu().shows, id: \.self){ show in + VStack{ + Text(show.title) + HStack{ + + ForEach(show.seasons, id:\.self){ season in + + List(season.episodes, id:\.self){ episode in + NavigationLink(destination: VideoView(url: episode.video.hlsUrl)){ + VStack{ + Text(season.seasonName) + Text(episode.name) + AsyncImage(url: episode.imageurl,placeholder: { + //Image(name: "loading") + Text("Loading...") + Text("Loading...") + Text("Loading...") + Text("Loading...") + Text("Loading...") + Text("Loading...") + Text("Loading...") + Text("Loading...") + Text("Loading...") + Text("Loading...") + Text("Loading...") + },image:{Image(uiImage:$0).resizable()}) + }} + } + } + } + } + } + } +} +} +}*/ + diff --git a/vrtnu/vrtnu/VrtNuLayout.swift b/vrtnu/vrtnu/VrtNuLayout.swift index 0a065c7..a509a3b 100644 --- a/vrtnu/vrtnu/VrtNuLayout.swift +++ b/vrtnu/vrtnu/VrtNuLayout.swift @@ -28,17 +28,22 @@ struct Season: Hashable{ return lhs.seasonUrl == rhs.seasonUrl } - + let title: String + let showName: String let seasonName: String let seasonUrl: URL let episodes: [Episode] - init(seasonUrl: URL){ - self.seasonUrl = seasonUrl + init(showName: String, seasonName: String, title: String){ + self.showName = showName + self.title = title + self.seasonName = seasonName + print(seasonName) + print(showName) + self.seasonUrl = URL(string: "https://www.vrt.be/vrtnu/a-z/" + showName + "/" + seasonName)! self.episodes = [ Episode(episodeurl: URL(string: "https://www.vrt.be/vrtnu/a-z/het-peulengaleis/2005-hm/het-peulengaleis-s2005-hma1/")!) ] - self.seasonName = "Best of" } } @@ -47,23 +52,49 @@ struct Show: Hashable{ return lhs.showUrl == rhs.showUrl } - + let showName: String let showUrl: URL let title: String - let seasons: [Season] + lazy var seasons: [Season] = { + //`re.findall('value="#parsys_container_banner_%s_(.*)">' % show, requests.get('https://www.vrt.be/vrtnu/a-z/%s/' % show).text)` + let seasonsdata = Just.get(showUrl).text! + print(seasonsdata) + + let range = NSRange(location: 0, length: seasonsdata.count) + let regex = try! NSRegularExpression(pattern: "value=\"#parsys_container_banner_" + + showName + "_(.*)\">") + let seasons = regex.matches(in: seasonsdata, range: range) + let nsString = seasonsdata as NSString + + let output = Array(Set(seasons.map {nsString.substring(with: $0.range)})) + + print(output) + var season: String + var myseasons: [Season] + myseasons = [] + for i in 0 ..< output.count{ + season = output[i].replacingOccurrences(of: "value=\"#parsys_container_banner_" + + showName + "_", with: "").replacingOccurrences(of: "\">", with: "") + print(season) + print(showName) + myseasons.append(Season(showName: showName, seasonName: season, title: season)) + } + return myseasons + }() let imageUrl: URL - init(showUrl: URL, title: String) { - self.showUrl = showUrl + init(showName: String, title: String) { + self.showUrl = URL(string: "https://www.vrt.be/vrtnu/a-z/" + showName)! + self.showName = showName self.title = title + //TODO: get image urls for shows self.imageUrl = URL(string: "https://images.vrt.be/w320hx/2019/05/02/dbc03914-6cbc-11e9-abcc-02b7b76bf47f.jpg")! - //TODO: fetch seasons - self.seasons = [ - Season(seasonUrl: URL(string: "https://www.vrt.be/vrtnu/a-z/het-peulengaleis/2005-hm/")!), - Season(seasonUrl: URL(string: "https://www.vrt.be/vrtnu/a-z/het-peulengaleis/3/")!), - Season(seasonUrl: URL(string: "https://www.vrt.be/vrtnu/a-z/het-peulengaleis/4/")!), - Season(seasonUrl: URL(string: "https://www.vrt.be/vrtnu/a-z/het-peulengaleis/5/")!) - ] + + } + + func getSeasons() -> [Season]{ + var mutableself = self + return mutableself.seasons } func getimageurl() -> URL{ @@ -72,14 +103,56 @@ struct Show: Hashable{ } } +extension NSTextCheckingResult { + func groups(testedString:String) -> [String] { + var groups = [String]() + for i in 0 ..< self.numberOfRanges + { + let group = String(testedString[Range(self.range(at: i), in: testedString)!]) + groups.append(group) + } + return groups + } +} + struct VRTNu { let shows: [Show] init() { + print("init") //TODO: fetch shows - self.shows = [ - Show(showUrl: URL(string: "https://www.vrt.be/vrtnu/a-z/het-peulengaleis/")!, title: "Het Peulengaleis"), + let showsdata = Just.get("https://www.vrt.be/vrtnu/a-z/").text! + //print(showsdata) + let range = NSRange(location: 0, length: showsdata.count) + + let regex = try! NSRegularExpression(pattern: "/a-z/(.*).relevant") + let shows = regex.matches(in: showsdata, range: range) + let nsString = showsdata as NSString + + let output = Array(Set(shows.map {nsString.substring(with: $0.range)})) + + //print(output) + var show: String + var myshows: [Show] + myshows = [] + for i in 0 ..< output.count{ + show = output[i].replacingOccurrences(of: ".relevant", with: "").replacingOccurrences(of: "/a-z/", with: "") + myshows.append(Show(showName: show, title: show)) + } + self.shows = myshows + //print(self.shows) + + + /*self.shows = [ + Show(showUrl: URL(string: "a-z/het-peulengaleis/")!, title: "Het Peulengaleis"), Show(showUrl: URL(string: "https://www.vrt.be/vrtnu/a-z/het-peulengaleis2/")!, title: "Het Peulengaleis 2"), - ] + Show(showUrl: URL(string: "https://www.vrt.be/vrtnu/a-z/het-peulengaleis3/")!, title: "Het Peulengaleis 3"), + Show(showUrl: URL(string: "https://www.vrt.be/vrtnu/a-z/het-peulengaleis4/")!, title: "Het Peulengaleis 4"), + // Show(showUrl: URL(string: "https://www.vrt.be/vrtnu/a-z/het-peulengaleis5/")!, title: "Het Peulengaleis 5"), + //Show(showUrl: URL(string: "https://www.vrt.be/vrtnu/a-z/het-peulengaleis6/")!, title: "Het Peulengaleis 6"), + //Show(showUrl: URL(string: "https://www.vrt.be/vrtnu/a-z/het-peulengaleis7/")!, title: "Het Peulengaleis 7"), + //Show(showUrl: URL(string: "https://www.vrt.be/vrtnu/a-z/het-peulengaleis8/")!, title: "Het Peulengaleis 8"), + + ]*/ } }