From fdafe0d4012af00e0d9cb613a0146924b8fd8eaf Mon Sep 17 00:00:00 2001 From: Ben Beltran Date: Sun, 14 Apr 2019 16:08:54 +0200 Subject: Update swift files to use Bariloche --- Sources/arguments_source.swift | 18 --- Sources/configuration.swift | 70 ------------ Sources/itunes_source.swift | 61 ----------- Sources/lyricli.swift | 60 ---------- Sources/lyricli/configuration.swift | 70 ++++++++++++ Sources/lyricli/lyricli.swift | 64 +++++++++++ Sources/lyricli/lyricli_command.swift | 38 +++++++ Sources/lyricli/lyrics_engine.swift | 146 +++++++++++++++++++++++++ Sources/lyricli/main.swift | 107 ++++++++++++++++++ Sources/lyricli/source_manager.swift | 51 +++++++++ Sources/lyricli/sources/itunes_source.swift | 61 +++++++++++ Sources/lyricli/sources/source_protocol.swift | 5 + Sources/lyricli/sources/spotify_source.swift | 41 +++++++ Sources/lyricli/track.swift | 15 +++ Sources/lyrics_engine.swift | 146 ------------------------- Sources/main.swift | 151 -------------------------- Sources/source_manager.swift | 52 --------- Sources/source_protocol.swift | 5 - Sources/spotify_source.swift | 41 ------- Sources/track.swift | 15 --- 20 files changed, 598 insertions(+), 619 deletions(-) delete mode 100644 Sources/arguments_source.swift delete mode 100644 Sources/configuration.swift delete mode 100644 Sources/itunes_source.swift delete mode 100644 Sources/lyricli.swift create mode 100644 Sources/lyricli/configuration.swift create mode 100644 Sources/lyricli/lyricli.swift create mode 100644 Sources/lyricli/lyricli_command.swift create mode 100644 Sources/lyricli/lyrics_engine.swift create mode 100644 Sources/lyricli/main.swift create mode 100644 Sources/lyricli/source_manager.swift create mode 100644 Sources/lyricli/sources/itunes_source.swift create mode 100644 Sources/lyricli/sources/source_protocol.swift create mode 100644 Sources/lyricli/sources/spotify_source.swift create mode 100644 Sources/lyricli/track.swift delete mode 100644 Sources/lyrics_engine.swift delete mode 100644 Sources/main.swift delete mode 100644 Sources/source_manager.swift delete mode 100644 Sources/source_protocol.swift delete mode 100644 Sources/spotify_source.swift delete mode 100644 Sources/track.swift diff --git a/Sources/arguments_source.swift b/Sources/arguments_source.swift deleted file mode 100644 index 9615318..0000000 --- a/Sources/arguments_source.swift +++ /dev/null @@ -1,18 +0,0 @@ -// Source that reads track artist and name from the command line -class ArgumentsSource: Source { - - // Returns a track based on the arguments. It assumes the track artist - // will be the first argument, and the name will be the second, excluding - // any flags. - var currentTrack: Track? { - - if CommandLine.arguments.count >= 3 { - // expected usage: $ ./lyricli - let trackName: String = CommandLine.arguments[2] - let trackArtist: String = CommandLine.arguments[1] - - return Track(withName: trackName, andArtist: trackArtist) - } - return nil - } -} diff --git a/Sources/configuration.swift b/Sources/configuration.swift deleted file mode 100644 index 05e2802..0000000 --- a/Sources/configuration.swift +++ /dev/null @@ -1,70 +0,0 @@ -import Foundation - -// Reads and writes the configuration. Config keys are accessed as a dictionary. -class Configuration { - // Location of the global configuration file - private let configurationPath = NSString(string: "~/.lyricli.conf").expandingTildeInPath - - // Default options, will be automatically written to the global config if - // not found. - private var configuration: [String: Any] = [ - "enabled_sources": ["arguments", "itunes", "spotify"] - ] - - // The shared instance of the object - static let shared: Configuration = Configuration() - - private init() { - - // Read the config file and attempt to set any of the values. Otherwise - // don't do anything. - - if let data = try? NSData(contentsOfFile: configurationPath) as Data { - if let parsedConfig = try? JSONSerialization.jsonObject(with: data) { - if let parsedConfig = parsedConfig as? [String: Any] { - for (key, value) in parsedConfig { - - if key == "enabled_sources" { - if let value = value as? [String] { - configuration[key] = value - } - } else { - if let value = value as? String { - configuration[key] = value - } - } - } - } - } - } - - writeConfiguration() - } - - // Write the configuration back to the file - private func writeConfiguration() { - - var error: NSError? - - if let outputStream = OutputStream(toFileAtPath: configurationPath, append: false) { - outputStream.open() - JSONSerialization.writeJSONObject(configuration, - to: outputStream, - options: [JSONSerialization.WritingOptions.prettyPrinted], - error: &error) - outputStream.close() - } - } - - // Allow access to the config properties as a dictionary - subscript(index: String) -> Any? { - get { - return configuration[index] - } - - set(newValue) { - configuration[index] = newValue - writeConfiguration() - } - } -} diff --git a/Sources/itunes_source.swift b/Sources/itunes_source.swift deleted file mode 100644 index 6f4aef9..0000000 --- a/Sources/itunes_source.swift +++ /dev/null @@ -1,61 +0,0 @@ -import ScriptingBridge - -// Protocol to obtain the track from iTunes -@objc protocol iTunesTrack { - @objc optional var name: String {get} - @objc optional var artist: String {get} -} - -// Protocol to interact with iTunes -@objc protocol iTunesApplication { - @objc optional var currentTrack: iTunesTrack? {get} - @objc optional var currentStreamTitle: String? {get} -} - -extension SBApplication : iTunesApplication {} - -// Source that reads track artist and name from current itunes track -class ItunesSource: Source { - - // Calls the spotify API and returns the current track - var currentTrack: Track? { - - if let iTunes: iTunesApplication = SBApplication(bundleIdentifier: "com.apple.iTunes") { - - // Attempt to fetch the title from a stream - if let currentStreamTitle = iTunes.currentStreamTitle { - if let track = currentStreamTitle { - - let trackComponents = track.characters.split(separator: "-").map(String.init) - - if trackComponents.count == 2 { - let artist = trackComponents[0].trimmingCharacters(in: .whitespaces) - let name = trackComponents[1].trimmingCharacters(in: .whitespaces) - - return Track(withName: name, andArtist: artist) - } - - } - } - - // Attempt to fetch the title from a song - if let currentTrack = iTunes.currentTrack { - if let track = currentTrack { - if let name = track.name { - if let artist = track.artist { - - // track properties are empty strings if itunes is closed - if (!(name != "" && artist != "")) { - return nil - } - return Track(withName: name, andArtist: artist) - } - } - } - } - } - - return nil - } - -} diff --git a/Sources/lyricli.swift b/Sources/lyricli.swift deleted file mode 100644 index 8aeb5c0..0000000 --- a/Sources/lyricli.swift +++ /dev/null @@ -1,60 +0,0 @@ -// The main class, handles all the actions that the executable will call -class Lyricli { - - // Version of the application - static var version = "0.3.0" - - // Flag that controls whether we should show the track artist and name before - // the lyrics - static var showTitle = false - - // Obtains the name of the current track from a source, fetches the lyrics - // from an engine and prints them - static func printLyrics() { - - let sourceManager = SourceManager() - - if let currentTrack = sourceManager.currentTrack { - let engine = LyricsEngine(withTrack: currentTrack) - - if let lyrics = engine.lyrics { - if showTitle { - printTitle(currentTrack) - } - - print(lyrics) - } else { - print("Lyrics not found :(") - } - - } else { - print("No Artist/Song could be found :(") - } - } - - // Print the currently available sources - static func printSources() { - print("Listing Sources: Not yet implemented") - } - - // Runs the enable method of a source and writes the configuration to set it - // as enabled - static func enableSource(_ sourceName: String) { - print("Enable source \(sourceName): Not yet implemented") - } - - // Remove a source from the enabled sources configuration - static func disableSource(_ sourceName: String) { - print("Disable source \(sourceName): Not yet implemented") - } - - // Removes any configuration for a source, and disables it - static func resetSource(_ sourceName: String) { - print("Reset source \(sourceName): Not yet implemented") - } - - // Prints the track artist and name - private static func printTitle(_ track: Track) { - print("\(track.artist) - \(track.name)") - } -} diff --git a/Sources/lyricli/configuration.swift b/Sources/lyricli/configuration.swift new file mode 100644 index 0000000..1b01034 --- /dev/null +++ b/Sources/lyricli/configuration.swift @@ -0,0 +1,70 @@ +import Foundation + +// Reads and writes the configuration. Config keys are accessed as a dictionary. +class Configuration { + // Location of the global configuration file + private let configurationPath = NSString(string: "~/.lyricli.conf").expandingTildeInPath + + // Default options, will be automatically written to the global config if + // not found. + private var configuration: [String: Any] = [ + "enabled_sources": ["itunes", "spotify"] + ] + + // The shared instance of the object + static let shared: Configuration = Configuration() + + private init() { + + // Read the config file and attempt to set any of the values. Otherwise + // don't do anything. + + if let data = try? NSData(contentsOfFile: configurationPath) as Data { + if let parsedConfig = try? JSONSerialization.jsonObject(with: data) { + if let parsedConfig = parsedConfig as? [String: Any] { + for (key, value) in parsedConfig { + + if key == "enabled_sources" { + if let value = value as? [String] { + configuration[key] = value + } + } else { + if let value = value as? String { + configuration[key] = value + } + } + } + } + } + } + + writeConfiguration() + } + + // Write the configuration back to the file + private func writeConfiguration() { + + var error: NSError? + + if let outputStream = OutputStream(toFileAtPath: configurationPath, append: false) { + outputStream.open() + JSONSerialization.writeJSONObject(configuration, + to: outputStream, + options: [JSONSerialization.WritingOptions.prettyPrinted], + error: &error) + outputStream.close() + } + } + + // Allow access to the config properties as a dictionary + subscript(index: String) -> Any? { + get { + return configuration[index] + } + + set(newValue) { + configuration[index] = newValue + writeConfiguration() + } + } +} diff --git a/Sources/lyricli/lyricli.swift b/Sources/lyricli/lyricli.swift new file mode 100644 index 0000000..c4136fb --- /dev/null +++ b/Sources/lyricli/lyricli.swift @@ -0,0 +1,64 @@ +// The main class, handles all the actions that the executable will call +class Lyricli { + + // Version of the application + static var version = "0.4.0" + + // Flag that controls whether we should show the track artist and name before + // the lyrics + static var showTitle = false + + // Obtains the name of the current track from a source, fetches the lyrics + // from an engine and prints them + static func printLyrics() { + + let sourceManager = SourceManager() + + if let currentTrack = sourceManager.currentTrack { + printLyrics(currentTrack) + } else { + print("No Artist/Song could be found :(") + } + } + + // fetches the lyrics from an engine and prints them + static func printLyrics(_ currentTrack: Track) { + let engine = LyricsEngine(withTrack: currentTrack) + + if let lyrics = engine.lyrics { + if showTitle { + printTitle(currentTrack) + } + + print(lyrics) + } else { + print("Lyrics not found :(") + } + } + + // Print the currently available sources + static func printSources() { + print("Listing Sources: Not yet implemented") + } + + // Runs the enable method of a source and writes the configuration to set it + // as enabled + static func enableSource(_ sourceName: String) { + print("Enable source \(sourceName): Not yet implemented") + } + + // Remove a source from the enabled sources configuration + static func disableSource(_ sourceName: String) { + print("Disable source \(sourceName): Not yet implemented") + } + + // Removes any configuration for a source, and disables it + static func resetSource(_ sourceName: String) { + print("Reset source \(sourceName): Not yet implemented") + } + + // Prints the track artist and name + private static func printTitle(_ track: Track) { + print("\(track.artist) - \(track.name)") + } +} diff --git a/Sources/lyricli/lyricli_command.swift b/Sources/lyricli/lyricli_command.swift new file mode 100644 index 0000000..28ad44a --- /dev/null +++ b/Sources/lyricli/lyricli_command.swift @@ -0,0 +1,38 @@ +import Bariloche + +class LyricliCommand: Command { + let usage: String? = "Fetch the lyrics for current playing track or the one specified via arguments" + + // Flags + let version = Flag(short: "v", long: "version", help: "Prints the version.") + let showTitle = Flag(short: "t", long: "title", help: "Shows title of song if true") + let listSources = Flag(short: "l", long: "listSources", help: "Lists all sources") + + // Named Arguments + let enableSource = Argument(name: "source", + kind: .named(short: "e", long: "enableSource"), + optional: true, + help: "Enables a source") + let disableSource = Argument(name: "source", + kind: .named(short: "d", long: "disableSource"), + optional: true, + help: "Disables a source") + let resetSource = Argument(name: "source", + kind: .named(short: "r", long: "resetSource"), + optional: true, + help: "Resets a source") + + // Positional Arguments + let artist = Argument(name: "artist", + kind: .positional, + optional: true, + help: "The name of the artist") + let trackName = Argument(name: "trackName", + kind: .positional, + optional: true, + help: "The name of the track") + + func run() -> Bool { + return true + } +} diff --git a/Sources/lyricli/lyrics_engine.swift b/Sources/lyricli/lyrics_engine.swift new file mode 100644 index 0000000..085a61c --- /dev/null +++ b/Sources/lyricli/lyrics_engine.swift @@ -0,0 +1,146 @@ +import Foundation +import HTMLEntities + +// Given a track, attempts to fetch the lyrics from lyricswiki +class LyricsEngine { + + // URL of the API endpoint to use + private let apiURL = "https://lyrics.wikia.com/api.php?action=lyrics&func=getSong&fmt=realjson" + + // Method used to call the API + private let apiMethod = "GET" + + // Regular expxression used to find the lyrics in the lyricswiki HTML + private let lyricsMatcher = "class='lyricbox'>(.+) Void in + lyrics = lyricsResult + requestFinished = true + asyncLock.signal() + }) + + while !requestFinished { + asyncLock.wait() + } + asyncLock.unlock() + } + } + } + + return lyrics + } + + // Initializes with a track + init(withTrack targetTrack: Track) { + + track = targetTrack + } + + // Fetch the lyrics URL from the API, triggers the request to fetch the + // lyrics page + private func fetchLyricsFromAPI(withURL url: URL, completionHandler: @escaping (String?) -> Void) { + + var apiRequest = URLRequest(url: url) + apiRequest.httpMethod = "GET" + + let task = URLSession.shared.dataTask(with: apiRequest, completionHandler: {data, _, _ -> Void in + + // If the response is parseable JSON, and has a url, we'll look for + // the lyrics in there + + if let data = data { + if let jsonResponse = try? JSONSerialization.jsonObject(with: data) { + if let jsonResponse = jsonResponse as? [String: Any] { + if let lyricsUrlString = jsonResponse["url"] as? String { + if let lyricsUrl = URL(string: lyricsUrlString) { + + // At this point we have a valid wiki url + self.fetchLyricsFromPage(withURL: lyricsUrl, completionHandler: completionHandler) + return + } + } + } + } + } + + completionHandler(nil) + }) + task.resume() + } + + // Fetch the lyrics from the page and send it to the parser + private func fetchLyricsFromPage(withURL url: URL, completionHandler: @escaping (String?) -> Void) { + + var pageRequest = URLRequest(url: url) + pageRequest.httpMethod = "GET" + + let task = URLSession.shared.dataTask(with: pageRequest, completionHandler: {data, _, _ -> Void in + + // If the response is parseable JSON, and has a url, we'll look for + // the lyrics in there + + if let data = data { + if let htmlBody = String(data: data, encoding: String.Encoding.utf8) { + self.parseHtmlBody(htmlBody, completionHandler: completionHandler) + return + } + } + + completionHandler(nil) + }) + task.resume() + } + + // Parses the wiki to find the lyrics, decodes the lyrics object + private func parseHtmlBody(_ body: String, completionHandler: @escaping (String?) -> Void) { + + // Look for the lyrics lightbox + + if let regex = try? NSRegularExpression(pattern: lyricsMatcher) { + let matches = regex.matches(in: body, range: NSRange(location: 0, length: body.count)) + + for match in matches { + + let nsBody = body as NSString + let range = match.range(at: 1) + let encodedLyrics = nsBody.substring(with: range) + + let decodedLyrics = decodeLyrics(encodedLyrics) + + completionHandler(decodedLyrics) + return + } + } + + completionHandler(nil) + } + + // Escapes the HTML entities + private func decodeLyrics(_ lyrics: String) -> String { + + let unescapedLyrics = lyrics.htmlUnescape() + return unescapedLyrics.replacingOccurrences(of: "
", with: "\n") + } +} diff --git a/Sources/lyricli/main.swift b/Sources/lyricli/main.swift new file mode 100644 index 0000000..be1c933 --- /dev/null +++ b/Sources/lyricli/main.swift @@ -0,0 +1,107 @@ +import Foundation +import Bariloche + +// Entry point of the application. This is the main executable +private func main() { + + // Bariloche assumes at least one argument, so bypass + // if that's the case. + if CommandLine.arguments.count > 1 { + let parser = Bariloche(command: LyricliCommand()) + let result = parser.parse() + + if result.count == 0 { + exit(EX_USAGE) + } + + if let lyricliCommand = result[0] as? LyricliCommand { + // Flags + checkVersionFlag(lyricliCommand) + checkListSourcesFlag(lyricliCommand) + checkTitleFlag(lyricliCommand) + + // String Options + + checkEnableSourceFlag(lyricliCommand) + checkDisableSourceFlag(lyricliCommand) + checkResetSourceFlag(lyricliCommand) + + checkPositionalArguments(lyricliCommand) + + } + } + + // Run Lyricli + Lyricli.printLyrics() +} + +// Handle the version flag + +private func checkVersionFlag(_ command: LyricliCommand) { + if command.version.value { + print(Lyricli.version) + exit(0) + } +} + +// Handle the list sources flag + +private func checkListSourcesFlag(_ command: LyricliCommand) { + if command.listSources.value { + Lyricli.printSources() + exit(0) + } +} + +// Handle the title flag + +private func checkTitleFlag(_ command: LyricliCommand) { + Lyricli.showTitle = command.showTitle.value +} + +// Handle the enable source flag + +private func checkEnableSourceFlag(_ command: LyricliCommand) { + if let source = command.enableSource.value { + Lyricli.enableSource(source) + exit(0) + } +} + +// Handle the disable source flag + +private func checkDisableSourceFlag(_ command: LyricliCommand) { + if let source = command.disableSource.value { + Lyricli.disableSource(source) + exit(0) + } +} + +// Handle the reset source flag + +private func checkResetSourceFlag(_ command: LyricliCommand) { + if let source = command.resetSource.value { + Lyricli.resetSource(source) + exit(0) + } +} + +// Handle the positional arguments + +private func checkPositionalArguments(_ command: LyricliCommand) { + if let artist = command.artist.value { + + let currentTrack: Track + + if let trackName = command.trackName.value { + currentTrack = Track(withName: trackName, andArtist: artist) + } else { + currentTrack = Track(withName: "", andArtist: artist) + } + + Lyricli.printLyrics(currentTrack) + exit(0) + } +} + +main() diff --git a/Sources/lyricli/source_manager.swift b/Sources/lyricli/source_manager.swift new file mode 100644 index 0000000..2f0b8f4 --- /dev/null +++ b/Sources/lyricli/source_manager.swift @@ -0,0 +1,51 @@ +// Collect and manage the available and enabled source +class SourceManager { + + // List of sources enabled for the crurent platform + private var availableSources: [String: Source] = [ + "itunes": ItunesSource(), + "spotify": SpotifySource() + ] + + // Iterate over the sources until we find a track or run out of sources + var currentTrack: Track? { + for source in enabledSources { + if let currentTrack = source.currentTrack { + return currentTrack + } + } + + return nil + } + + // Return the list of enabled sources based on the configuration + var enabledSources: [Source] { + + // Checks the config and returns an array of sources based on the + // enabled and available ones + + var sources = [Source]() + + if let sourceNames = Configuration.shared["enabled_sources"] as? [String] { + for sourceName in sourceNames { + if let source = availableSources[sourceName] { + sources.append(source) + } + } + } + + return sources + } + + // Given a source name, it will enable it and add it to the enabled sources config + func enable(sourceName: String) { + } + + // Given a source name, it will remove it from the enabled sources config + func disable(sourceName: String) { + } + + // Given a source name, it removes any stored configuration and disables it + func reset(sourceName: String) { + } +} diff --git a/Sources/lyricli/sources/itunes_source.swift b/Sources/lyricli/sources/itunes_source.swift new file mode 100644 index 0000000..4e175c1 --- /dev/null +++ b/Sources/lyricli/sources/itunes_source.swift @@ -0,0 +1,61 @@ +import ScriptingBridge + +// Protocol to obtain the track from iTunes +@objc protocol iTunesTrack { + @objc optional var name: String {get} + @objc optional var artist: String {get} +} + +// Protocol to interact with iTunes +@objc protocol iTunesApplication { + @objc optional var currentTrack: iTunesTrack? {get} + @objc optional var currentStreamTitle: String? {get} +} + +extension SBApplication: iTunesApplication {} + +// Source that reads track artist and name from current itunes track +class ItunesSource: Source { + + // Calls the spotify API and returns the current track + var currentTrack: Track? { + + if let iTunes: iTunesApplication = SBApplication(bundleIdentifier: "com.apple.iTunes") { + + // Attempt to fetch the title from a stream + if let currentStreamTitle = iTunes.currentStreamTitle { + if let track = currentStreamTitle { + + let trackComponents = track.split(separator: "-").map(String.init) + + if trackComponents.count == 2 { + let artist = trackComponents[0].trimmingCharacters(in: .whitespaces) + let name = trackComponents[1].trimmingCharacters(in: .whitespaces) + + return Track(withName: name, andArtist: artist) + } + + } + } + + // Attempt to fetch the title from a song + if let currentTrack = iTunes.currentTrack { + if let track = currentTrack { + if let name = track.name { + if let artist = track.artist { + + // track properties are empty strings if itunes is closed + if name == "" || artist == "" { + return nil + } + return Track(withName: name, andArtist: artist) + } + } + } + } + } + + return nil + } + +} diff --git a/Sources/lyricli/sources/source_protocol.swift b/Sources/lyricli/sources/source_protocol.swift new file mode 100644 index 0000000..0885994 --- /dev/null +++ b/Sources/lyricli/sources/source_protocol.swift @@ -0,0 +1,5 @@ +// All sources should comply with this protocol. The currentTrack computed +// property will return a track if the conditions are met +protocol Source { + var currentTrack: Track? { get } +} diff --git a/Sources/lyricli/sources/spotify_source.swift b/Sources/lyricli/sources/spotify_source.swift new file mode 100644 index 0000000..2e56c8e --- /dev/null +++ b/Sources/lyricli/sources/spotify_source.swift @@ -0,0 +1,41 @@ +import ScriptingBridge + +// Protocol to obtain the track from Spotify +@objc protocol SpotifyTrack { + @objc optional var name: String {get} + @objc optional var artist: String {get} +} + +// Protocol to interact with Spotify +@objc protocol SpotifyApplication { + @objc optional var currentTrack: SpotifyTrack? {get} +} + +extension SBApplication : SpotifyApplication {} + +// Source that reads track artist and name from current Spotify track +class SpotifySource: Source { + + // Calls the spotify API and returns the current track + var currentTrack: Track? { + + if let spotify: SpotifyApplication = SBApplication(bundleIdentifier: "com.spotify.client") { + + // Attempt to fetch the title from a song + if let currentTrack = spotify.currentTrack { + if let track = currentTrack { + if let name = track.name { + if let artist = track.artist { + + return Track(withName: name, andArtist: artist) + } + } + } + } + } + + return nil + } + +} + diff --git a/Sources/lyricli/track.swift b/Sources/lyricli/track.swift new file mode 100644 index 0000000..ead4359 --- /dev/null +++ b/Sources/lyricli/track.swift @@ -0,0 +1,15 @@ +// Holds the name and artist of a track +class Track { + + // The name of the track to search for + let name: String + + // The name of the artist + let artist: String + + init(withName trackName: String, andArtist trackArtist: String) { + + name = trackName + artist = trackArtist + } +} diff --git a/Sources/lyrics_engine.swift b/Sources/lyrics_engine.swift deleted file mode 100644 index 27e0e11..0000000 --- a/Sources/lyrics_engine.swift +++ /dev/null @@ -1,146 +0,0 @@ -import Foundation -import HTMLEntities - -// Given a track, attempts to fetch the lyrics from lyricswiki -class LyricsEngine { - - // URL of the API endpoint to use - private let apiURL = "https://lyrics.wikia.com/api.php?action=lyrics&func=getSong&fmt=realjson" - - // Method used to call the API - private let apiMethod = "GET" - - // Regular expxression used to find the lyrics in the lyricswiki HTML - private let lyricsMatcher = "class='lyricbox'>(.+) Void in - lyrics = lyricsResult - requestFinished = true - asyncLock.signal() - }) - - while !requestFinished { - asyncLock.wait() - } - asyncLock.unlock() - } - } - } - - return lyrics - } - - // Initializes with a track - init(withTrack targetTrack: Track) { - - track = targetTrack - } - - // Fetch the lyrics URL from the API, triggers the request to fetch the - // lyrics page - private func fetchLyricsFromAPI(withURL url: URL, completionHandler: @escaping (String?) -> Void) { - - var apiRequest = URLRequest(url: url) - apiRequest.httpMethod = "GET" - - let task = URLSession.shared.dataTask(with: apiRequest, completionHandler: {data, _, _ -> Void in - - // If the response is parseable JSON, and has a url, we'll look for - // the lyrics in there - - if let data = data { - if let jsonResponse = try? JSONSerialization.jsonObject(with: data) { - if let jsonResponse = jsonResponse as? [String: Any] { - if let lyricsUrlString = jsonResponse["url"] as? String { - if let lyricsUrl = URL(string: lyricsUrlString) { - - // At this point we have a valid wiki url - self.fetchLyricsFromPage(withURL: lyricsUrl, completionHandler: completionHandler) - return - } - } - } - } - } - - completionHandler(nil) - }) - task.resume() - } - - // Fetch the lyrics from the page and send it to the parser - private func fetchLyricsFromPage(withURL url: URL, completionHandler: @escaping (String?) -> Void) { - - var pageRequest = URLRequest(url: url) - pageRequest.httpMethod = "GET" - - let task = URLSession.shared.dataTask(with: pageRequest, completionHandler: {data, _, _ -> Void in - - // If the response is parseable JSON, and has a url, we'll look for - // the lyrics in there - - if let data = data { - if let htmlBody = String(data: data, encoding: String.Encoding.utf8) { - self.parseHtmlBody(htmlBody, completionHandler: completionHandler) - return - } - } - - completionHandler(nil) - }) - task.resume() - } - - // Parses the wiki to find the lyrics, decodes the lyrics object - private func parseHtmlBody(_ body: String, completionHandler: @escaping (String?) -> Void) { - - // Look for the lyrics lightbox - - if let regex = try? NSRegularExpression(pattern: lyricsMatcher) { - let matches = regex.matches(in: body, range: NSRange(location: 0, length: body.characters.count)) - - for match in matches { - - let nsBody = body as NSString - let range = match.rangeAt(1) - let encodedLyrics = nsBody.substring(with: range) - - let decodedLyrics = decodeLyrics(encodedLyrics) - - completionHandler(decodedLyrics) - return - } - } - - completionHandler(nil) - } - - // Escapes the HTML entities - private func decodeLyrics(_ lyrics: String) -> String { - - let unescapedLyrics = lyrics.htmlUnescape() - return unescapedLyrics.replacingOccurrences(of: "
", with: "\n") - } -} diff --git a/Sources/main.swift b/Sources/main.swift deleted file mode 100644 index 9d46e92..0000000 --- a/Sources/main.swift +++ /dev/null @@ -1,151 +0,0 @@ -import CommandLineKit -import Foundation - -// Entry point of the application. This is the main executable -private func main() { - let (flags, parser) = createParser() - - do { - try parser.parse() - } catch { - parser.printUsage(error) - exit(EX_USAGE) - } - - // Boolean Options - - checkHelpFlag(flags["help"], withParser: parser) - checkVersionFlag(flags["version"], withParser: parser) - checkListSourcesFlag(flags["listSources"], withParser: parser) - checkTitleFlag(flags["title"], withParser: parser) - - // String Options - - checkEnableSourceFlag(flags["enableSource"], withParser: parser) - checkDisableSourceFlag(flags["disableSource"], withParser: parser) - checkResetSourceFlag(flags["resetSource"], withParser: parser) - - // Remove any flags so anyone after this gets the unprocessed values - - let programName: [String] = [CommandLine.arguments[0]] - CommandLine.arguments = programName + parser.unparsedArguments - - // Run Lyricli - - Lyricli.printLyrics() -} - -/// Sets up and returns a new options parser -/// -/// - Returns: A Dictionary of Options, and a new CommandLineKit instance -private func createParser() -> ([String:Option], CommandLineKit) { - let parser = CommandLineKit() - var flags: [String:Option] = [:] - - flags["help"] = BoolOption(shortFlag: "h", longFlag: "help", helpMessage: "Prints a help message.") - flags["version"] = BoolOption(shortFlag: "v", longFlag: "version", helpMessage: "Prints the version.") - - flags["enableSource"] = StringOption(shortFlag: "e", longFlag: "enable-source", helpMessage: "Enables a source") - flags["disableSource"] = StringOption(shortFlag: "d", longFlag: "disable-source", helpMessage: "Disables a source") - flags["resetSource"] = StringOption(shortFlag: "r", longFlag: "reset-source", helpMessage: "Resets a source") - flags["listSources"] = BoolOption(shortFlag: "l", longFlag: "list-sources", helpMessage: "Lists all sources") - - flags["title"] = BoolOption(shortFlag: "t", longFlag: "title", helpMessage: "Shows title of song if true") - - parser.addOptions(Array(flags.values)) - - parser.formatOutput = {parseString, type in - - var formattedString: String - - switch type { - case .About: - formattedString = "\(parseString) [ ]" - break - default: - formattedString = parseString - } - - return parser.defaultFormat(formattedString, type: type) - } - - return (flags, parser) -} - -// Handle the Help flag - -private func checkHelpFlag(_ flag: Option?, withParser parser: CommandLineKit) { - if let helpFlag = flag as? BoolOption { - if helpFlag.value { - parser.printUsage() - exit(0) - } - } -} - -// Handle the version flag - -private func checkVersionFlag(_ flag: Option?, withParser parser: CommandLineKit) { - if let versionFlag = flag as? BoolOption { - if versionFlag.value { - print(Lyricli.version) - exit(0) - } - } -} - -// Handle the list sources flag - -private func checkListSourcesFlag(_ flag: Option?, withParser parser: CommandLineKit) { - if let listSourcesFlag = flag as? BoolOption { - if listSourcesFlag.value { - Lyricli.printSources() - exit(0) - } - } -} - -// Handle the title flag - -private func checkTitleFlag(_ flag: Option?, withParser parser: CommandLineKit) { - if let titleFlag = flag as? BoolOption { - if titleFlag.value { - Lyricli.showTitle = true - } - } -} - -// Handle the enable source flag - -private func checkEnableSourceFlag(_ flag: Option?, withParser parser: CommandLineKit) { - if let enableSourceFlag = flag as? StringOption { - if let source = enableSourceFlag.value { - Lyricli.enableSource(source) - exit(0) - } - } -} - -// Handle the disable source flag - -private func checkDisableSourceFlag(_ flag: Option?, withParser parser: CommandLineKit) { - if let disableSourceFlag = flag as? StringOption { - if let source = disableSourceFlag.value { - Lyricli.disableSource(source) - exit(0) - } - } -} - -// Handle the reset source flag - -private func checkResetSourceFlag(_ flag: Option?, withParser parser: CommandLineKit) { - if let resetSourceFlag = flag as? StringOption { - if let source = resetSourceFlag.value { - Lyricli.resetSource(source) - exit(0) - } - } -} - -main() diff --git a/Sources/source_manager.swift b/Sources/source_manager.swift deleted file mode 100644 index e6c42da..0000000 --- a/Sources/source_manager.swift +++ /dev/null @@ -1,52 +0,0 @@ -// Collect and manage the available and enabled source -class SourceManager { - - // List of sources enabled for the crurent platform - private var availableSources: [String: Source] = [ - "arguments": ArgumentsSource(), - "itunes": ItunesSource(), - "spotify": SpotifySource() - ] - - // Iterate over the sources until we find a track or run out of sources - var currentTrack: Track? { - for source in enabledSources { - if let currentTrack = source.currentTrack { - return currentTrack - } - } - - return nil - } - - // Return the list of enabled sources based on the configuration - var enabledSources: [Source] { - - // Checks the config and returns an array of sources based on the - // enabled and available ones - - var sources = [Source]() - - if let sourceNames = Configuration.shared["enabled_sources"] as? [String] { - for sourceName in sourceNames { - if let source = availableSources[sourceName] { - sources.append(source) - } - } - } - - return sources - } - - // Given a source name, it will enable it and add it to the enabled sources config - func enable(sourceName: String) { - } - - // Given a source name, it will remove it from the enabled sources config - func disable(sourceName: String) { - } - - // Given a source name, it removes any stored configuration and disables it - func reset(sourceName: String) { - } -} diff --git a/Sources/source_protocol.swift b/Sources/source_protocol.swift deleted file mode 100644 index 0885994..0000000 --- a/Sources/source_protocol.swift +++ /dev/null @@ -1,5 +0,0 @@ -// All sources should comply with this protocol. The currentTrack computed -// property will return a track if the conditions are met -protocol Source { - var currentTrack: Track? { get } -} diff --git a/Sources/spotify_source.swift b/Sources/spotify_source.swift deleted file mode 100644 index 2e56c8e..0000000 --- a/Sources/spotify_source.swift +++ /dev/null @@ -1,41 +0,0 @@ -import ScriptingBridge - -// Protocol to obtain the track from Spotify -@objc protocol SpotifyTrack { - @objc optional var name: String {get} - @objc optional var artist: String {get} -} - -// Protocol to interact with Spotify -@objc protocol SpotifyApplication { - @objc optional var currentTrack: SpotifyTrack? {get} -} - -extension SBApplication : SpotifyApplication {} - -// Source that reads track artist and name from current Spotify track -class SpotifySource: Source { - - // Calls the spotify API and returns the current track - var currentTrack: Track? { - - if let spotify: SpotifyApplication = SBApplication(bundleIdentifier: "com.spotify.client") { - - // Attempt to fetch the title from a song - if let currentTrack = spotify.currentTrack { - if let track = currentTrack { - if let name = track.name { - if let artist = track.artist { - - return Track(withName: name, andArtist: artist) - } - } - } - } - } - - return nil - } - -} - diff --git a/Sources/track.swift b/Sources/track.swift deleted file mode 100644 index ead4359..0000000 --- a/Sources/track.swift +++ /dev/null @@ -1,15 +0,0 @@ -// Holds the name and artist of a track -class Track { - - // The name of the track to search for - let name: String - - // The name of the artist - let artist: String - - init(withName trackName: String, andArtist trackArtist: String) { - - name = trackName - artist = trackArtist - } -} -- cgit From a2e8f128a03663ee5af4461707ed3af55723ff45 Mon Sep 17 00:00:00 2001 From: Ben Beltran Date: Sun, 14 Apr 2019 16:11:46 +0200 Subject: Update to swift 5 tools --- Package.swift | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 5027708..58b3294 100644 --- a/Package.swift +++ b/Package.swift @@ -1,9 +1,22 @@ +// swift-tools-version:5.0 + import PackageDescription let package = Package( name: "lyricli", dependencies: [ - .Package(url: "https://github.com/rbdr/CommandLineKit", majorVersion: 4, minor: 0), - .Package(url: "https://github.com/IBM-Swift/swift-html-entities.git", majorVersion: 3, minor: 0) + /// 🔡 Tools for working with HTML entities + .package(url: "https://github.com/IBM-Swift/swift-html-entities.git", from: "3.0.11"), + + /// 🚩 Command Line Arguments + .package(url: "https://github.com/Subito-it/Bariloche", from: "1.0.4") + ], + targets: [ + .target( + name: "lyricli", + dependencies: ["HTMLEntities", "Bariloche"]), + .testTarget( + name: "lyricliTests", + dependencies: ["lyricli"]), ] ) -- cgit From aaf058f0d6fa4868e4360780c50aa6e620e0f3db Mon Sep 17 00:00:00 2001 From: Ben Beltran Date: Sun, 14 Apr 2019 16:12:02 +0200 Subject: Update CHANGELOG & Version --- CHANGELOG.md | 15 +++++++++++++++ Makefile | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c63ee9..c6d8525 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,21 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [Unreleased] +### Added +- `printLyrics(_ currentTrack: Track)` allows directly specifying + track in library +- `lyricli_command` specifies the flags + +### Changed +- Flags are now camelCase +- Update to Swift 5 tools +- Replace CommandLineKit with Bariloche +- Reorganize sources folder + +### Removed +- Arguments Source (functionality moved to main) + ## [0.3.0] ### Added - Spotify Source Support diff --git a/Makefile b/Makefile index 6bbe735..8c79c08 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ document: build --author Lyricli \ --author_url https://github.com/lyricli-app \ --github_url https://github.com/lyricli-app/lyricli \ - --module-version 0.3.0 \ + --module-version 0.4.0 \ --module Lyricli \ clean: -- cgit From b9b93267f08b3054ad6eb19b67a95c5d09435cdb Mon Sep 17 00:00:00 2001 From: Ben Beltran Date: Sun, 14 Apr 2019 16:14:38 +0200 Subject: Replace pins file with resolved file --- Package.pins | 18 ------------------ Package.resolved | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 18 deletions(-) delete mode 100644 Package.pins create mode 100644 Package.resolved diff --git a/Package.pins b/Package.pins deleted file mode 100644 index 4bb7a96..0000000 --- a/Package.pins +++ /dev/null @@ -1,18 +0,0 @@ -{ - "autoPin": true, - "pins": [ - { - "package": "CommandeLineKit", - "reason": null, - "repositoryURL": "https://github.com/rbdr/CommandLineKit", - "version": "4.0.0" - }, - { - "package": "HTMLEntities", - "reason": null, - "repositoryURL": "https://github.com/IBM-Swift/swift-html-entities.git", - "version": "3.0.3" - } - ], - "version": 1 -} \ No newline at end of file diff --git a/Package.resolved b/Package.resolved new file mode 100644 index 0000000..a2a49b3 --- /dev/null +++ b/Package.resolved @@ -0,0 +1,34 @@ +{ + "object": { + "pins": [ + { + "package": "Bariloche", + "repositoryURL": "https://github.com/Subito-it/Bariloche", + "state": { + "branch": null, + "revision": "507f4121d2a7479522908dabf83aed78a6e5e268", + "version": "1.0.4" + } + }, + { + "package": "Rainbow", + "repositoryURL": "https://github.com/onevcat/Rainbow", + "state": { + "branch": null, + "revision": "9c52c1952e9b2305d4507cf473392ac2d7c9b155", + "version": "3.1.5" + } + }, + { + "package": "HTMLEntities", + "repositoryURL": "https://github.com/IBM-Swift/swift-html-entities.git", + "state": { + "branch": null, + "revision": "dc15f4d8eba5be23280a561c698fc36ab4fb6c76", + "version": "3.0.12" + } + } + ] + }, + "version": 1 +} -- cgit From f787104e6ae5281ac185a0f8267b23e0a87c4b9e Mon Sep 17 00:00:00 2001 From: Ben Beltran Date: Sun, 14 Apr 2019 16:21:49 +0200 Subject: Fix linting issues in spotify source --- Sources/lyricli/sources/spotify_source.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Sources/lyricli/sources/spotify_source.swift b/Sources/lyricli/sources/spotify_source.swift index 2e56c8e..2cd66f5 100644 --- a/Sources/lyricli/sources/spotify_source.swift +++ b/Sources/lyricli/sources/spotify_source.swift @@ -11,7 +11,7 @@ import ScriptingBridge @objc optional var currentTrack: SpotifyTrack? {get} } -extension SBApplication : SpotifyApplication {} +extension SBApplication: SpotifyApplication {} // Source that reads track artist and name from current Spotify track class SpotifySource: Source { @@ -38,4 +38,3 @@ class SpotifySource: Source { } } - -- cgit From ffca0db7f130be1138844aa22be71493bcf57d26 Mon Sep 17 00:00:00 2001 From: Ben Beltran Date: Sun, 14 Apr 2019 16:48:05 +0200 Subject: Use gitlab links in jazzy docs --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 8c79c08..5cd7660 100644 --- a/Makefile +++ b/Makefile @@ -32,8 +32,8 @@ document: build --readme README.md \ --clean \ --author Lyricli \ - --author_url https://github.com/lyricli-app \ - --github_url https://github.com/lyricli-app/lyricli \ + --author_url https://gitlab.com/lyricli \ + --github_url https://gitlab.com/lyricli/lyricli \ --module-version 0.4.0 \ --module Lyricli \ -- cgit From 8f882a0bccd7f71b5316bfaaaf494e7c34fce71e Mon Sep 17 00:00:00 2001 From: Ben Beltran Date: Mon, 13 May 2019 21:42:27 +0200 Subject: Remove test target --- Package.swift | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Package.swift b/Package.swift index 58b3294..9adbd39 100644 --- a/Package.swift +++ b/Package.swift @@ -14,9 +14,6 @@ let package = Package( targets: [ .target( name: "lyricli", - dependencies: ["HTMLEntities", "Bariloche"]), - .testTarget( - name: "lyricliTests", - dependencies: ["lyricli"]), + dependencies: ["HTMLEntities", "Bariloche"]) ] ) -- cgit From c32d8723eb863a95d821f4dc18281e17965d4025 Mon Sep 17 00:00:00 2001 From: Ben Beltran Date: Mon, 13 May 2019 21:49:00 +0200 Subject: Update clean command --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5cd7660..3066e11 100644 --- a/Makefile +++ b/Makefile @@ -38,6 +38,6 @@ document: build --module Lyricli \ clean: - swift build --clean + swift package clean .PHONY: build install test clean lint -- cgit From f43cbaf08072763aa3abd11736cfc77cd9457637 Mon Sep 17 00:00:00 2001 From: Ben Beltran Date: Mon, 13 May 2019 21:54:42 +0200 Subject: Use single word long options --- README.md | 4 ++-- Sources/lyricli/lyricli_command.swift | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 5e7c995..5614f5d 100644 --- a/README.md +++ b/README.md @@ -28,11 +28,11 @@ song and artist names before the lyrics. In order to configure -* `lrc -l` or `lrc --list-sources` lists the available sources. Enabled +* `lrc -l` or `lrc --list` lists the available sources. Enabled sourcess will have a `*` * `lrc -e` or `lrc --enable ` enables a source * `lrc -d` or `lrc --disable ` disables a source -* `lrc -r` or `lrc --reset-source ` resets the configuration for +* `lrc -r` or `lrc --reset ` resets the configuration for a source and disables it. * `lrc -v` or `lrc --version` prints the version * `lrc -h` or `lrc --help` display built-in help diff --git a/Sources/lyricli/lyricli_command.swift b/Sources/lyricli/lyricli_command.swift index 28ad44a..88f9c7b 100644 --- a/Sources/lyricli/lyricli_command.swift +++ b/Sources/lyricli/lyricli_command.swift @@ -6,19 +6,19 @@ class LyricliCommand: Command { // Flags let version = Flag(short: "v", long: "version", help: "Prints the version.") let showTitle = Flag(short: "t", long: "title", help: "Shows title of song if true") - let listSources = Flag(short: "l", long: "listSources", help: "Lists all sources") + let listSources = Flag(short: "l", long: "list", help: "Lists all sources") // Named Arguments let enableSource = Argument(name: "source", - kind: .named(short: "e", long: "enableSource"), + kind: .named(short: "e", long: "enable"), optional: true, help: "Enables a source") let disableSource = Argument(name: "source", - kind: .named(short: "d", long: "disableSource"), + kind: .named(short: "d", long: "disable"), optional: true, help: "Disables a source") let resetSource = Argument(name: "source", - kind: .named(short: "r", long: "resetSource"), + kind: .named(short: "r", long: "reset"), optional: true, help: "Resets a source") -- cgit From a95769b541e1f6959a11f489e03002d1bc97b7ce Mon Sep 17 00:00:00 2001 From: Ben Beltran Date: Mon, 13 May 2019 21:55:04 +0200 Subject: Update CHANGELOG` --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6d8525..2021ed1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - `lyricli_command` specifies the flags ### Changed -- Flags are now camelCase +- Flags are now single words - Update to Swift 5 tools - Replace CommandLineKit with Bariloche - Reorganize sources folder -- cgit From 1a8c14fd7973468379f8926069b4b0698d9c4ac8 Mon Sep 17 00:00:00 2001 From: Ben Beltran Date: Mon, 13 May 2019 21:55:47 +0200 Subject: Update swift version in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5614f5d..0ee2657 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ In order to configure ## Building -The build has only been tested on OSX using Swift 3.1. Building defaults +The build has only been tested on OSX using Swift 5.0.1. Building defaults to the debug configuration. ``` -- cgit From 3f746cc0beb5756e706e289ab2b92b43de928f74 Mon Sep 17 00:00:00 2001 From: Ben Beltran Date: Mon, 13 May 2019 22:03:51 +0200 Subject: Remove travis config, add gitlab CI --- .gitlab-ci.yml | 43 +++++++++++++++++++++++++++++++++++++++++++ .travis.yml | 28 ---------------------------- README.md | 2 -- 3 files changed, 43 insertions(+), 30 deletions(-) create mode 100644 .gitlab-ci.yml delete mode 100644 .travis.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..e55b711 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,43 @@ +image: swift:5.0.1 + +stages: + - lint + - build + - document + - deploy + +cache: + key: ${CI_COMMIT_REF_SLUG}-${CI_COMMIT_SHA} + paths: + - .build/ + +before_script: + - gem install jazzy + - "./Scripts/install_sourcekitten.sh" + - "./Scripts/install_swiftlint.sh" + +lint: + stage: lint + script: + - make lint + +build: + stage: build + script: + - make build + +document: + stage: document + script: + - make document + artifacts: + paths: + - docs + +pages: + stage: deploy + script: + - mv docs public + artifacts: + paths: + - public diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 46250e5..0000000 --- a/.travis.yml +++ /dev/null @@ -1,28 +0,0 @@ -language: - - swift - -osx_image: xcode8.3 - -install: - - gem install jazzy - - "./Scripts/install_sourcekitten.sh" - - "./Scripts/install_swiftlint.sh" - -script: - - make lint - - make build - -before_deploy: - - make document - -deploy: - provider: pages - skip_cleanup: true - github_token: "$GITHUB_TOKEN" - local_dir: docs - on: - branch: master - -env: - global: - secure: EyOzJFSGY2ifBVqnQz7Xc0sDcg9maLb7VDKWIC2+1n2RsMHGptsxDfJf9r/bOc2kJN9mCzw19eA3XTkypeHKgIgPZ+boLPTDqiiNcD+0iVkYxqw/Q0v5et1+pJaOUo93cKfl2WLWXvISU1MYuzbjGwmnjPDUmujTwGZH1SFvhOKynqx9V/PiL4ZF+CurU2far+diLDhJXUPT4mDV6lDfiALUBvfj50AplM928Vwc6xr71SFii4fE+1GGGGI23ZyXmhnYIJBfQ/9d2wzW6szSRz+q0Gq8jQFJ2cZmBQPnfPY6/xARkDIf5H55HIxLg8pqA7Yn+WDT6/a8uoFLY6OzI8B/TTZ/pX4LXhkK0gbmXeeigRjxN3Dcsb++n9e5+3/Bq0y/Vm+Ufy+TtEvExvU6vdzDu8YZQaE0T2Loyqaw3BQBMoCunv4i7z0crXTLyNYNuc3zDGDmjkR3laxX8lcEZ85zTRTuYqxmvQxkxWUHKYQOvGy7SfkD1xc73f1XvCqpx45utZX0U/OzIxRflWFNy4mlgLvo23h5T0b44LGBBBWEVkjt5YduOuSo9L1wtOrADcDYyxSciIby2SHd4B2fGOb059KyCIUcX/qgOS6FJlmPeC963NCAuZB6DyscaoT6DrJto9nuZW2wNYdo7dvCC2E4ZqHnRPl2zux/RTmeuCU= diff --git a/README.md b/README.md index 0ee2657..57dff9a 100644 --- a/README.md +++ b/README.md @@ -78,8 +78,6 @@ tests. make test ``` -[![Build Status](https://travis-ci.org/lyricli-app/lyricli.svg?branch=master)](https://travis-ci.org/lyricli-app/lyricli) - [swiftlint]: https://github.com/realm/SwiftLint [jazzy]: https://github.com/realm/jazzy [sourcekitten]: https://github.com/jpsim/SourceKitten -- cgit From 3f7a07b8b9c62994fce87e37fd2f67b683cb6c58 Mon Sep 17 00:00:00 2001 From: Ben Beltran Date: Mon, 13 May 2019 22:15:14 +0200 Subject: Install Jazzy dependencies --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e55b711..2fa5994 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,6 +12,7 @@ cache: - .build/ before_script: + - apt install -y ruby ruby-dev libsqlite3-dev - gem install jazzy - "./Scripts/install_sourcekitten.sh" - "./Scripts/install_swiftlint.sh" -- cgit From 19e7bffcd3401026517e1f02d55f6050d3baf80d Mon Sep 17 00:00:00 2001 From: Ben Beltran Date: Mon, 13 May 2019 22:21:46 +0200 Subject: Add wget to apt packages --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2fa5994..4d984cb 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,7 +12,7 @@ cache: - .build/ before_script: - - apt install -y ruby ruby-dev libsqlite3-dev + - apt install -y ruby ruby-dev libsqlite3-dev wget - gem install jazzy - "./Scripts/install_sourcekitten.sh" - "./Scripts/install_swiftlint.sh" -- cgit From 2cbb0a97eeb4eea8ef18d59346759b20cc8fa180 Mon Sep 17 00:00:00 2001 From: Ben Beltran Date: Mon, 13 May 2019 22:31:50 +0200 Subject: Adapt CI scripts to work under swift docker image --- CHANGELOG.md | 1 + Scripts/install_sourcekitten.sh | 25 +++++-------------------- Scripts/install_swiftlint.sh | 26 ++++++-------------------- 3 files changed, 12 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2021ed1..7fbae3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - `lyricli_command` specifies the flags ### Changed +- CI scripts updated for gitlab CI instead of Travis - Flags are now single words - Update to Swift 5 tools - Replace CommandLineKit with Bariloche diff --git a/Scripts/install_sourcekitten.sh b/Scripts/install_sourcekitten.sh index 9420a26..f94fb53 100755 --- a/Scripts/install_sourcekitten.sh +++ b/Scripts/install_sourcekitten.sh @@ -1,25 +1,10 @@ #!/bin/bash -# Taken from: https://alexplescan.com/posts/2016/03/03/setting-up-swiftlint-on-travis-ci/ -# And adapted for sourcekitten - -# Installs the SourceKitten package. -# Tries to get the precompiled .pkg file from Github, but if that -# fails just recompiles from source. +# Installs SourceKitten from source (Intended to be used with +# swift docker image) set -e -SOURCEKITTEN_PKG_PATH="/tmp/SourceKitten.pkg" -SOURCEKITTEN_PKG_URL="https://github.com/jpsim/SourceKitten/releases/download/0.17.3/SourceKitten.pkg" - -wget --output-document=$SOURCEKITTEN_PKG_PATH $SOURCEKITTEN_PKG_URL - -if [ -f $SOURCEKITTEN_PKG_PATH ]; then - echo "SourceKitten package exists! Installing it..." - sudo installer -pkg $SOURCEKITTEN_PKG_PATH -target / -else - echo "SourceKitten package doesn't exist. Compiling from source..." && - git clone https://github.com/jspim/SourceKitten.git /tmp/SourceKitten && - cd /tmp/SourceKitten && - sudo make install -fi +git clone https://github.com/jpsim/SourceKitten.git /tmp/SourceKitten && +cd /tmp/SourceKitten && +make install diff --git a/Scripts/install_swiftlint.sh b/Scripts/install_swiftlint.sh index 6a2f250..4b8299d 100755 --- a/Scripts/install_swiftlint.sh +++ b/Scripts/install_swiftlint.sh @@ -1,25 +1,11 @@ #!/bin/bash -# Taken from: https://alexplescan.com/posts/2016/03/03/setting-up-swiftlint-on-travis-ci/ - -# Installs the SwiftLint package. -# Tries to get the precompiled .pkg file from Github, but if that -# fails just recompiles from source. +# Installs SwiftLint from source (Intended to be used with +# swift docker image) set -e -SWIFTLINT_PKG_PATH="/tmp/SwiftLint.pkg" -SWIFTLINT_PKG_URL="https://github.com/realm/SwiftLint/releases/download/0.18.1/SwiftLint.pkg" - -wget --output-document=$SWIFTLINT_PKG_PATH $SWIFTLINT_PKG_URL - -if [ -f $SWIFTLINT_PKG_PATH ]; then - echo "SwiftLint package exists! Installing it..." - sudo installer -pkg $SWIFTLINT_PKG_PATH -target / -else - echo "SwiftLint package doesn't exist. Compiling from source..." && - git clone https://github.com/realm/SwiftLint.git /tmp/SwiftLint && - cd /tmp/SwiftLint && - git submodule update --init --recursive && - sudo make install -fi +git clone https://github.com/realm/SwiftLint.git /tmp/SwiftLint && +cd /tmp/SwiftLint && +git submodule update --init --recursive && +make install -- cgit From 6a628388c496987819ef26bda1a99595bce2b1d5 Mon Sep 17 00:00:00 2001 From: Ben Beltran Date: Mon, 13 May 2019 23:22:58 +0200 Subject: Makes test environment docker-based Provides Dockerfile to build test environment that should be used by CI --- .gitlab-ci.yml | 8 +------- Dockerfile | 26 ++++++++++++++++++++++++++ Makefile | 9 ++++++++- Scripts/install_sourcekitten.sh | 10 ---------- Scripts/install_swiftlint.sh | 11 ----------- 5 files changed, 35 insertions(+), 29 deletions(-) create mode 100644 Dockerfile delete mode 100755 Scripts/install_sourcekitten.sh delete mode 100755 Scripts/install_swiftlint.sh diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4d984cb..ebe400d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,4 @@ -image: swift:5.0.1 +image: lyriclitest/swift:5.0.1 stages: - lint @@ -11,12 +11,6 @@ cache: paths: - .build/ -before_script: - - apt install -y ruby ruby-dev libsqlite3-dev wget - - gem install jazzy - - "./Scripts/install_sourcekitten.sh" - - "./Scripts/install_swiftlint.sh" - lint: stage: lint script: diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..db35f5c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,26 @@ +ARG swift_version=latest +FROM swift:${swift_version} + +RUN apt-get update && apt-get install -y \ + libsqlite3-dev \ + ruby \ + ruby-dev \ + wget \ + && rm -rf /var/lib/apt/lists/* + +RUN gem install --no-ri --no-rdoc jazzy + +# SourceKitten + +RUN git clone https://github.com/jpsim/SourceKitten.git /tmp/SourceKitten \ + && cd /tmp/SourceKitten \ + && make install \ + && rm -rf /tmp/SourceKitten + +# Swiftlint + +RUN git clone https://github.com/realm/SwiftLint.git /tmp/SwiftLint \ + && cd /tmp/SwiftLint \ + && git submodule update --init --recursive \ + && make install \ + && rm -rf /tmp/SwiftLint diff --git a/Makefile b/Makefile index 3066e11..d993480 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,7 @@ target_binary_name = lrc install_path = /usr/local/bin source_binary_path = $(build_path)/$(configuration)/$(source_binary_name) install_binary_path = $(install_path)/$(target_binary_name) +swift_version = 5.0.1 # Default to release configuration on install install: configuration = release @@ -40,4 +41,10 @@ document: build clean: swift package clean -.PHONY: build install test clean lint +docker-build: + docker build --force-rm --build-arg swift_version=$(swift_version) -t lyriclitest/swift:$(swift_version) . + +docker-push: docker-build + docker push lyriclitest/swift:$(swift_version) + +.PHONY: build install test clean lint docker-build docker-push diff --git a/Scripts/install_sourcekitten.sh b/Scripts/install_sourcekitten.sh deleted file mode 100755 index f94fb53..0000000 --- a/Scripts/install_sourcekitten.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -# Installs SourceKitten from source (Intended to be used with -# swift docker image) - -set -e - -git clone https://github.com/jpsim/SourceKitten.git /tmp/SourceKitten && -cd /tmp/SourceKitten && -make install diff --git a/Scripts/install_swiftlint.sh b/Scripts/install_swiftlint.sh deleted file mode 100755 index 4b8299d..0000000 --- a/Scripts/install_swiftlint.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -# Installs SwiftLint from source (Intended to be used with -# swift docker image) - -set -e - -git clone https://github.com/realm/SwiftLint.git /tmp/SwiftLint && -cd /tmp/SwiftLint && -git submodule update --init --recursive && -make install -- cgit From 9cf995f0faa99868b3a6204332571511e9155f9d Mon Sep 17 00:00:00 2001 From: Ben Beltran Date: Mon, 9 Mar 2020 21:28:13 -0500 Subject: Add Catalina support, don't auto-open apps --- Sources/lyricli/sources/itunes_source.swift | 18 +++++++++++++++++- Sources/lyricli/sources/spotify_source.swift | 6 ++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Sources/lyricli/sources/itunes_source.swift b/Sources/lyricli/sources/itunes_source.swift index 4e175c1..92b9969 100644 --- a/Sources/lyricli/sources/itunes_source.swift +++ b/Sources/lyricli/sources/itunes_source.swift @@ -1,4 +1,5 @@ import ScriptingBridge +import Foundation // Protocol to obtain the track from iTunes @objc protocol iTunesTrack { @@ -20,7 +21,12 @@ class ItunesSource: Source { // Calls the spotify API and returns the current track var currentTrack: Track? { - if let iTunes: iTunesApplication = SBApplication(bundleIdentifier: "com.apple.iTunes") { + if let iTunes: iTunesApplication = SBApplication(bundleIdentifier: bundleIdentifier) { + if let application = iTunes as? SBApplication { + if !application.isRunning { + return nil + } + } // Attempt to fetch the title from a stream if let currentStreamTitle = iTunes.currentStreamTitle { @@ -58,4 +64,14 @@ class ItunesSource: Source { return nil } + private var bundleIdentifier: String { + if ProcessInfo().isOperatingSystemAtLeast( + OperatingSystemVersion(majorVersion: 10, minorVersion: 15, patchVersion: 0) + ) { + return "com.apple.Music" + } + + return "com.apple.iTunes" + } + } diff --git a/Sources/lyricli/sources/spotify_source.swift b/Sources/lyricli/sources/spotify_source.swift index 2cd66f5..9c516c4 100644 --- a/Sources/lyricli/sources/spotify_source.swift +++ b/Sources/lyricli/sources/spotify_source.swift @@ -20,8 +20,14 @@ class SpotifySource: Source { var currentTrack: Track? { if let spotify: SpotifyApplication = SBApplication(bundleIdentifier: "com.spotify.client") { + if let application = spotify as? SBApplication { + if !application.isRunning { + return nil + } + } // Attempt to fetch the title from a song + if let currentTrack = spotify.currentTrack { if let track = currentTrack { if let name = track.name { -- cgit From c71a08f54d2846ca1d2139120d53aa36485e6752 Mon Sep 17 00:00:00 2001 From: Ben Beltran Date: Mon, 9 Mar 2020 21:35:15 -0500 Subject: Bumping to 1.0.0 to use semver --- Sources/lyricli/lyricli.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/lyricli/lyricli.swift b/Sources/lyricli/lyricli.swift index c4136fb..043c004 100644 --- a/Sources/lyricli/lyricli.swift +++ b/Sources/lyricli/lyricli.swift @@ -2,7 +2,7 @@ class Lyricli { // Version of the application - static var version = "0.4.0" + static var version = "1.0.0" // Flag that controls whether we should show the track artist and name before // the lyrics -- cgit From ebc27030ab873e6f65e67277bd543951a2e4d54b Mon Sep 17 00:00:00 2001 From: Ben Beltran Date: Mon, 9 Mar 2020 21:36:21 -0500 Subject: Update CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fbae3f..333c601 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - `printLyrics(_ currentTrack: Track)` allows directly specifying track in library - `lyricli_command` specifies the flags +- Support for catalina Music app ### Changed - CI scripts updated for gitlab CI instead of Travis @@ -16,6 +17,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Update to Swift 5 tools - Replace CommandLineKit with Bariloche - Reorganize sources folder +- Does not open apps when running ### Removed - Arguments Source (functionality moved to main) -- cgit From 60e75b5599d849faf98fb0692df69fb655a614d0 Mon Sep 17 00:00:00 2001 From: Ben Beltran Date: Mon, 9 Mar 2020 21:36:59 -0500 Subject: Update version --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 333c601..07ab746 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] + +## [1.0.0] ### Added - `printLyrics(_ currentTrack: Track)` allows directly specifying track in library @@ -50,6 +52,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Parsing of options to match legacy lyricli - Placeholder for the library with expected endpoints +[1.0.0]: https://github.com/lyricli-app/lyricli/compare/0.3.0...1.0.0 [0.3.0]: https://github.com/lyricli-app/lyricli/compare/0.2.0...0.3.0 [0.2.0]: https://github.com/lyricli-app/lyricli/compare/0.1.0...0.2.0 [Unreleased]: https://github.com/lyricli-app/lyricli/compare/master...develop -- cgit From 101a6eccd794add1a4b1fcb1c9b0d6ece24d2939 Mon Sep 17 00:00:00 2001 From: Ben Beltran Date: Mon, 9 Mar 2020 21:39:27 -0500 Subject: Update version in makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d993480..8428b44 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ document: build --author Lyricli \ --author_url https://gitlab.com/lyricli \ --github_url https://gitlab.com/lyricli/lyricli \ - --module-version 0.4.0 \ + --module-version 1.0.0 \ --module Lyricli \ clean: -- cgit From a12f29158ced867c200ce8ea596fa46b17c8c18a Mon Sep 17 00:00:00 2001 From: Ben Beltran Date: Mon, 9 Mar 2020 21:43:39 -0500 Subject: Removing build because no Scripting bridge :() --- .gitlab-ci.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ebe400d..225ceac 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,7 +2,6 @@ image: lyriclitest/swift:5.0.1 stages: - lint - - build - document - deploy @@ -16,11 +15,6 @@ lint: script: - make lint -build: - stage: build - script: - - make build - document: stage: document script: -- cgit From 97f47198a0dd96c571ec1086e7f8c68963d263d0 Mon Sep 17 00:00:00 2001 From: Ben Beltran Date: Mon, 9 Mar 2020 21:48:25 -0500 Subject: Create build folder before documenting --- Makefile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 8428b44..d244996 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,10 @@ install: configuration = release default: build -build: +prebuild: + mkdir -p $(build_path) + +build: prebuild swift build --build-path $(build_path) --configuration $(configuration) install: build @@ -26,7 +29,7 @@ test: build lint: cd Sources && swiftlint -document: build +document: prebuild sourcekitten doc --spm-module $(source_binary_name) > $(build_path)/$(source_binary_name).json jazzy \ -s $(build_path)/$(source_binary_name).json \ -- cgit From 2a7cc52436ab4a7b6530881513679ac7ede997a8 Mon Sep 17 00:00:00 2001 From: Ben Beltran Date: Mon, 9 Mar 2020 21:52:28 -0500 Subject: Removing gitlab CI config I can't build / document currently --- .gitlab-ci.yml | 2 -- Makefile | 7 ++----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 225ceac..56fa677 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,8 +2,6 @@ image: lyriclitest/swift:5.0.1 stages: - lint - - document - - deploy cache: key: ${CI_COMMIT_REF_SLUG}-${CI_COMMIT_SHA} diff --git a/Makefile b/Makefile index d244996..8428b44 100644 --- a/Makefile +++ b/Makefile @@ -14,10 +14,7 @@ install: configuration = release default: build -prebuild: - mkdir -p $(build_path) - -build: prebuild +build: swift build --build-path $(build_path) --configuration $(configuration) install: build @@ -29,7 +26,7 @@ test: build lint: cd Sources && swiftlint -document: prebuild +document: build sourcekitten doc --spm-module $(source_binary_name) > $(build_path)/$(source_binary_name).json jazzy \ -s $(build_path)/$(source_binary_name).json \ -- cgit From 9931580d9185e9123b6d45a45f20dbf929bb25b7 Mon Sep 17 00:00:00 2001 From: Ben Beltran Date: Mon, 9 Mar 2020 21:55:36 -0500 Subject: Remove unused configs --- .gitlab-ci.yml | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 56fa677..04ec6ba 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,19 +12,3 @@ lint: stage: lint script: - make lint - -document: - stage: document - script: - - make document - artifacts: - paths: - - docs - -pages: - stage: deploy - script: - - mv docs public - artifacts: - paths: - - public -- cgit