Skip to content

Commit

Permalink
First pass at identifying ITV from current web page, and caching one-…
Browse files Browse the repository at this point in the history
…off shows/films
  • Loading branch information
skovatch committed Jan 9, 2019
1 parent 4459fc4 commit 9e304e8
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 21 deletions.
19 changes: 14 additions & 5 deletions GetCurrentWebpage.swift
Expand Up @@ -12,9 +12,10 @@ import ScriptingBridge

@objcMembers public class GetCurrentWebpage : NSObject {

private class func extractMetadata(url: String, tabTitle: String, pageSource: String?) -> (pid: String?, showName: String?) {
private class func extractMetadata(url: String, tabTitle: String, pageSource: String?) -> (pid: String?, showName: String?, network: String?) {
var pid: String?
var showName: String?
var network: String?

if url.hasPrefix("https://www.bbc.co.uk/iplayer/episode/") {
// PID is always the second-to-last element in the URL.
Expand All @@ -25,11 +26,13 @@ import ScriptingBridge
let nameScanner = Scanner(string: tabTitle)
nameScanner.scanString("BBC iPlayer - ")
showName = nameScanner.scanUpToString( " - ")
network = "BBC"
// TODO: Get the series/episode info from the tail.
} else if url.hasPrefix("https://www.bbc.co.uk/radio/play/") || url.hasPrefix("https://www.bbc.co.uk/sounds/play/") {
// PID is always the last element in the URL.
if let nsUrl = URL(string: url) {
pid = nsUrl.lastPathComponent
network = "BBC"
}

// Program title is buried in the page HTML.
Expand All @@ -38,6 +41,7 @@ import ScriptingBridge
// PID is the last element in the URL, but it could be a program or series page.
if let nsUrl = URL(string: url) {
pid = nsUrl.lastPathComponent
network = "BBC"
}

if let pid = pid, let pageSource = pageSource {
Expand All @@ -62,7 +66,7 @@ import ScriptingBridge
invalidPage.informativeText = "Please ensure the frontmost browser tab is open to an iPlayer episode page or programme clip page. Get iPlayer Automator doesn't support downloading all available shows from a series."
invalidPage.alertStyle = .warning
invalidPage.runModal()
return (nil, nil)
return (nil, nil, nil)
}
}

Expand All @@ -72,9 +76,10 @@ import ScriptingBridge
}

showName = tabTitle.replacingOccurrences(of: " - ITV Hub", with: "")
network = "ITV"
}

return (pid, showName)
return (pid, showName, network)
}

public class func getCurrentWebpage(_ logger: LogController) -> Programme? {
Expand All @@ -89,6 +94,9 @@ import ScriptingBridge
// Program ID of found show
var pid: String? = nil

// Network of found show.
var network: String? = nil

//Prepare Alert in Case the Browser isn't Open
let browserNotOpen = NSAlert()
browserNotOpen.addButton(withTitle: "OK")
Expand All @@ -105,7 +113,7 @@ import ScriptingBridge

let orderedWindows = safariWindows.sorted { $0.index! < $1.index! }
if let frontWindow = orderedWindows.first, let tab = frontWindow.currentTab, let url = tab.URL, let name = tab.name, let source = tab.source {
(pid, newShowName) = extractMetadata(url: url, tabTitle: name, pageSource: source)
(pid, newShowName, network) = extractMetadata(url: url, tabTitle: name, pageSource: source)
}
} else if (browser == "Chrome") {
guard let chrome : ChromeApplication = SBApplication(bundleIdentifier: "com.google.Chrome"), chrome.isRunning, let chromeWindows = chrome.windows?().compactMap({ $0 as? ChromeWindow }) else {
Expand All @@ -116,7 +124,7 @@ import ScriptingBridge
let orderedWindows = chromeWindows.sorted { $0.index! < $1.index! }
if let frontWindow = orderedWindows.first, let tab = frontWindow.activeTab, let url = tab.URL, let title = tab.title {
let source = tab.executeJavascript?("document.documentElement.outerHTML") as? String
(pid, newShowName) = extractMetadata(url: url, tabTitle: title, pageSource: source)
(pid, newShowName, network) = extractMetadata(url: url, tabTitle: title, pageSource: source)
}
} else {
let unsupportedBrowser = NSAlert()
Expand All @@ -142,6 +150,7 @@ import ScriptingBridge
newProg.pid = foundPID
newProg.showName = newShowName ?? ""
newProg.status = "Processing..."
newProg.tvNetwork = network ?? ""
newProg.performSelector(inBackground: #selector(Programme.getName), with: nil)
return newProg
}
Expand Down
88 changes: 72 additions & 16 deletions GetITVListings.swift
Expand Up @@ -84,13 +84,13 @@ public class GetITVShows: NSObject, URLSessionDelegate, URLSessionTaskDelegate,
}
}

func requestProgrammeEpisodes(_ myProgramme: ProgrammeData?) {
func requestProgrammeEpisodes(_ myProgramme: ProgrammeData) {
/* Get all episodes for the programme name identified in MyProgramme */
usleep(1)
if let aURL = myProgramme?.programmeURL, let aURL1 = URL(string: aURL) {
mySession?.dataTask(with: aURL1, completionHandler: {(_ data: Data?, _ response: URLResponse?, _ error: Error?) -> Void in
if let url = URL(string: myProgramme.programmeURL) {
mySession?.dataTask(with: url, completionHandler: {(_ data: Data?, _ response: URLResponse?, _ error: Error?) -> Void in
if let error = error {
let errorMessage = "GetITVListings (Error(\(error))): Unable to retreive programme episodes for \(myProgramme?.programmeURL ?? "missing!")"
let errorMessage = "GetITVListings (Error(\(error))): Unable to retreive programme episodes for \(myProgramme.programmeURL)"
self.logger?.add(toLog: errorMessage)
// NSAlert(messageText: "GetITVShows: Unable to retreive programme episode data", defaultButton: "OK", alternateButton: nil, otherButton: nil, informativeTextWithFormat: "If problem persists, please submit a bug report and include the log file.").runModal()
} else if let data = data {
Expand All @@ -101,21 +101,77 @@ public class GetITVShows: NSObject, URLSessionDelegate, URLSessionTaskDelegate,
return
}

func processProgrammeEpisodesData(_ aProgramme: ProgrammeData?, pageData: Data) {
func processProgramDataElement(program: ProgrammeData, show: Kanna.XMLElement) {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mmZ"
dateFormatter.timeZone = TimeZone(secondsFromGMT:0)

var dateAiredUTC: Date? = nil
let dateTimeString = show.at_xpath(".//@datetime")?.text

if let dateTimeString = dateTimeString{
dateAiredUTC = dateFormatter.date(from: dateTimeString)
}

let description = show.at_xpath(".//p[@class='tout__summary theme__subtle']")?.content?.trimmingCharacters(in: .whitespacesAndNewlines)

var episodeNumber: Int? = 0
if let episode = show.at_xpath(".//h3[@class='tout__title complex-link__target theme__target ']")?.content?.trimmingCharacters(in: .whitespacesAndNewlines) {
let episodeScanner = Scanner(string: episode)
episodeScanner.scanString("Episode ")
episodeNumber = episodeScanner.scanInteger()
}

var seriesNumber: Int? = 0
if let series = show.at_xpath(".//h2[@class='module__heading']")?.content?.trimmingCharacters(in: .whitespacesAndNewlines) {
let seriesScanner = Scanner(string: series)
seriesScanner.scanString("Series ")
seriesNumber = seriesScanner.scanInteger()
}

var productionID: String? = ""
var showURL: URL? = nil
if let showURLString = show.at_xpath("@href")?.text {
showURL = URL(string: showURLString)
productionID = showURL?.lastPathComponent
}

print("Program: \(program.programmeName)")
print("Show URL: \(showURL?.absoluteString ?? "")")
print("Episode number: \(episodeNumber ?? 0)")
print("Series number: \(seriesNumber ?? 0)")
print("productionID: \(productionID ?? "")")
print("Date aired: \(dateTimeString ?? "Unknown")")
print("=================")

// Make sure the URL matches the show listing -- ITV likes to sneak other shows on a program page.
if let showURLBase = showURL?.deletingLastPathComponent(), showURLBase.absoluteString == programURL?.absoluteString {

/* Create ProgrammeData Object and store in array */
let myProgramme = ProgrammeData(name: program.programmeName, pid: productionID ?? "", url: showURL?.absoluteString ?? "", numberEpisodes: program.numberEpisodes , timeDateLastAired: dateAiredUTC, programDescription: description ?? "", thumbnailURL: "")

myProgramme.addProgrammeSeriesInfo(seriesNumber ?? 0, aEpisodeNumber: episodeNumber ?? 0)
self.episodes.append(myProgramme)
}

}

func processProgrammeEpisodesData(_ aProgramme: ProgrammeData, pageData: Data) {

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mmZ"
dateFormatter.timeZone = TimeZone(secondsFromGMT:0)

var programURL: URL? = nil
if let programURLString = aProgramme?.programmeURL {
if let programURLString = aProgramme.programmeURL {
programURL = URL(string: programURLString)?.deletingLastPathComponent()
}

if let showPageHTML = try? HTML(html: pageData, encoding: .utf8) {
let showElements = showPageHTML.xpath("//a[@data-content-type='episode']")

let showElements = showPageHTML.xpath("//a[@data-content-type=\"episode\"]")
print("page has \(showElements.count) elements for \(aProgramme.programmeURL)")
for show in showElements {
processProgramDataElement(program: aProgramme, show: show)
var dateAiredUTC: Date? = nil
let dateTimeString = show.at_xpath(".//@datetime")?.text

Expand Down Expand Up @@ -146,19 +202,19 @@ public class GetITVShows: NSObject, URLSessionDelegate, URLSessionTaskDelegate,
productionID = showURL?.lastPathComponent
}

// print("Program: \(aProgramme?.programmeName ?? "")")
// print("Show URL: \(showURL?.absoluteString ?? "")")
// print("Episode number: \(episodeNumber ?? 0)")
// print("Series number: \(seriesNumber ?? 0)")
// print("productionID: \(productionID ?? "")")
// print("Date aired: \(dateTimeString ?? "Unknown")")
// print("=================")
print("Program: \(aProgramme.programmeName)")
print("Show URL: \(showURL?.absoluteString ?? "")")
print("Episode number: \(episodeNumber ?? 0)")
print("Series number: \(seriesNumber ?? 0)")
print("productionID: \(productionID ?? "")")
print("Date aired: \(dateTimeString ?? "Unknown")")
print("=================")

// Make sure the URL matches the show listing -- ITV likes to sneak other shows on a program page.
if let showURLBase = showURL?.deletingLastPathComponent(), showURLBase.absoluteString == programURL?.absoluteString {

/* Create ProgrammeData Object and store in array */
let myProgramme = ProgrammeData(name: aProgramme?.programmeName ?? "", pid: productionID ?? "", url: showURL?.absoluteString ?? "", numberEpisodes: aProgramme?.numberEpisodes ?? 0, timeDateLastAired: dateAiredUTC, programDescription: description ?? "", thumbnailURL: "")
let myProgramme = ProgrammeData(name: aProgramme.programmeName, pid: productionID ?? "", url: showURL?.absoluteString ?? "", numberEpisodes: aProgramme.numberEpisodes, timeDateLastAired: dateAiredUTC, programDescription: description ?? "", thumbnailURL: "")

myProgramme.addProgrammeSeriesInfo(seriesNumber ?? 0, aEpisodeNumber: episodeNumber ?? 0)
self.episodes.append(myProgramme)
Expand Down

0 comments on commit 9e304e8

Please sign in to comment.