From fa5f3bb3b7c2345987744dc715908d4b1880c8be Mon Sep 17 00:00:00 2001 From: Cooper Hammond Date: Thu, 15 Apr 2021 11:22:01 -0600 Subject: [PATCH] added search terms config option and cli menu -S or --select will allow you to choose your song, for playlists or for albums --- shard.yml | 2 +- src/bottle/cli.cr | 29 ++++++++++++------------ src/bottle/config.cr | 6 +++++ src/glue/list.cr | 6 +++-- src/glue/song.cr | 9 +++++--- src/search/youtube.cr | 51 ++++++++++++++++++++++++++++++++++++++----- 6 files changed, 77 insertions(+), 26 deletions(-) diff --git a/shard.yml b/shard.yml index 45052e8..adf4c41 100755 --- a/shard.yml +++ b/shard.yml @@ -1,5 +1,5 @@ name: irs -version: 1.3.1 +version: 1.4.0 authors: - Cooper Hammond diff --git a/src/bottle/cli.cr b/src/bottle/cli.cr index 6ff7351..7b2b7d3 100755 --- a/src/bottle/cli.cr +++ b/src/bottle/cli.cr @@ -21,7 +21,7 @@ class CLI [["-A", "--album"], "album", "string"], [["-p", "--playlist"], "playlist", "string"], [["-u", "--url"], "url", "string"], - [["-g", "--give-url"], "give-url", "bool"], + [["-S", "--select"], "select", "bool"] ] @args : Hash(String, String) @@ -50,8 +50,10 @@ class CLI #{Style.blue "-s, --song "} Specify song name to download #{Style.blue "-A, --album "} Specify the album name to download #{Style.blue "-p, --playlist "} Specify the playlist name to download - #{Style.blue "-u, --url "} Specify the youtube url to download from (for single songs only) - #{Style.blue "-g, --give-url"} Specify the youtube url sources while downloading (for albums or playlists only) + #{Style.blue "-u, --url []"} Specify the youtube url to download from + #{Style.blue " "} (for single songs, include as an command-line + #{Style.blue " "} argument, for albums or playlists do not) + #{Style.blue "-S, --select"} Use a menu to choose each song's video source #{Style.bold "Examples:"} $ #{Style.green %(irs --song "Bohemian Rhapsody" --artist "Queen")} @@ -73,33 +75,32 @@ class CLI if @args["help"]? || @args.keys.size == 0 help + elsif @args["version"]? version + elsif @args["install"]? YdlBinaries.get_both(Config.binary_location) + elsif @args["config"]? puts ENV["IRS_CONFIG_LOCATION"]? + elsif @args["song"]? && @args["artist"]? s = Song.new(@args["song"], @args["artist"]) s.provide_client_keys(Config.client_key, Config.client_secret) - s.grab_it(@args["url"]?) + s.grab_it(flags: @args) s.organize_it() + elsif @args["album"]? && @args["artist"]? a = Album.new(@args["album"], @args["artist"]) a.provide_client_keys(Config.client_key, Config.client_secret) - if @args["give-url"]? - a.grab_it(true) - else - a.grab_it(false) - end + a.grab_it(flags: @args) + elsif @args["playlist"]? && @args["artist"]? p = Playlist.new(@args["playlist"], @args["artist"]) p.provide_client_keys(Config.client_key, Config.client_secret) - if @args["give-url"]? - p.grab_it(true) - else - p.grab_it(false) - end + p.grab_it(flags: @args) + else puts Style.red("Those arguments don't do anything when used that way.") puts "Type `irs -h` to see usage." diff --git a/src/bottle/config.cr b/src/bottle/config.cr index 3dde482..cf9d388 100755 --- a/src/bottle/config.cr +++ b/src/bottle/config.cr @@ -7,6 +7,7 @@ require "../search/spotify" EXAMPLE_CONFIG = <<-EOP #{Style.dim "exampleconfig.yml"} #{Style.dim "===="} +#{Style.blue "search_terms"}: #{Style.green "\"lyrics\""} #{Style.blue "binary_directory"}: #{Style.green "~/.irs/bin"} #{Style.blue "music_directory"}: #{Style.green "~/Music"} #{Style.blue "filename_pattern"}: #{Style.green "\"{track_number} - {title}\""} @@ -24,6 +25,7 @@ module Config extend self @@arguments = [ + "search_terms", "binary_directory", "music_directory", "filename_pattern", @@ -45,6 +47,10 @@ module Config exit 1 end + def search_terms : String + return @@conf["search_terms"].to_s + end + def binary_location : String path = @@conf["binary_directory"].to_s return Path[path].expand(home: true).to_s diff --git a/src/glue/list.cr b/src/glue/list.cr index 99c7134..717b0ed 100755 --- a/src/glue/list.cr +++ b/src/glue/list.cr @@ -27,7 +27,9 @@ abstract class SpotifyList end # Finds the list, and downloads all of the songs using the `Song` class - def grab_it(ask_url : Bool = false) + def grab_it(flags = {} of String => String) + ask_url = flags["url"]? + if !@spotify_searcher.authorized? raise("Need to call provide_client_keys on Album or Playlist class.") end @@ -54,7 +56,7 @@ abstract class SpotifyList song.provide_metadata(data) puts Style.bold("[#{data["track_number"]}/#{contents.size}]") - song.grab_it ask_url: ask_url + song.grab_it(flags: flags) organize(song) diff --git a/src/glue/song.cr b/src/glue/song.cr index 07c5697..c7acdad 100755 --- a/src/glue/song.cr +++ b/src/glue/song.cr @@ -29,7 +29,7 @@ class Song Style.green(" + ") + Style.dim("URL found \n"), " Validating URL ...\r", Style.green(" + ") + Style.dim("URL validated \n"), - "URL?: " + " URL?: " ], "download" => [ " Downloading video:\n", @@ -57,7 +57,10 @@ class Song # ``` # Song.new("Bohemian Rhapsody", "Queen").grab_it # ``` - def grab_it(url : (String | Nil) = nil, ask_url : Bool = false) + def grab_it(url : (String | Nil) = nil, flags = {} of String => String) + ask_url = flags["url"]? + select_link = flags["select"]? + outputter("intro", 0) if !@spotify_searcher.authorized? && !@metadata @@ -99,7 +102,7 @@ class Song if !url outputter("url", 0) - url = Youtube.find_url(data, search_terms: "lyrics") + url = Youtube.find_url(data, flags: flags) if !url raise("There was no url found on youtube for " + %("#{@song_name}" by "#{@artist_name}. ) + diff --git a/src/search/youtube.cr b/src/search/youtube.cr index 054af55..5dd58c5 100755 --- a/src/search/youtube.cr +++ b/src/search/youtube.cr @@ -5,6 +5,9 @@ require "uri" require "./ranking" +require "../bottle/config" +require "../bottle/styles" + module Youtube extend self @@ -26,8 +29,13 @@ module Youtube # Youtube.find_url("Bohemian Rhapsody", "Queen") # => "https://www.youtube.com/watch?v=dQw4w9WgXcQ" # ``` - def find_url(spotify_metadata : JSON::Any, search_terms = "", - download_first = false, select_link = false) : String? + def find_url(spotify_metadata : JSON::Any, + flags = {} of String => String) : String? + + search_terms = Config.search_terms + + download_first = flags["dl_first"]? + select_link = flags["select"]? song_name = spotify_metadata["name"].as_s artist_name = spotify_metadata["artists"][0]["name"].as_s @@ -52,11 +60,12 @@ module Youtube return root + yt_metadata[0]["href"] end + ranked = Ranker.rank_videos(spotify_metadata, yt_metadata, human_query) + if select_link - # return select_link_menu() + return root + select_link_menu(spotify_metadata, yt_metadata) end - ranked = Ranker.rank_videos(spotify_metadata, yt_metadata, human_query) begin return root + yt_metadata[ranked[0]["index"]]["href"] @@ -67,8 +76,38 @@ module Youtube exit 1 end - # - private def select_link_menu() : String + # Presents a menu with song info for the user to choose which url they want to download + private def select_link_menu(spotify_metadata : JSON::Any, + yt_metadata : YT_METADATA_CLASS) : String + puts Style.dim(" Spotify info: ") + + Style.bold("\"" + spotify_metadata["name"].to_s) + "\" by \"" + + Style.bold(spotify_metadata["artists"][0]["name"].to_s + "\"") + + " @ " + Style.blue((spotify_metadata["duration_ms"].as_i / 1000).to_i.to_s) + "s" + puts " Choose video to download:" + index = 1 + yt_metadata.each do |vid| + print " " + Style.bold(index.to_s + " ") + puts "\"" + vid["title"] + "\" @ " + Style.blue((vid["duration_ms"].to_i / 1000).to_i.to_s) + "s" + index += 1 + if index > 5 + break + end + end + + input = 0 + while true # not between 1 and 5 + begin + print Style.bold(" > ") + input = gets.not_nil!.chomp.to_i + if input < 6 && input > 0 + break + end + rescue + puts Style.red(" Invalid input, try again.") + end + end + + return yt_metadata[input]["href"] end