Changed a bunch of stuff. Almost ready for release.

- updated cli for config viewing and changes
- updated config method. an environment variable `IRS_CONFIG_LOCATION` will be set pointing to a yaml file with a config
- moved album metadata changing from a janky homebrew json modifier to the core json lib
- mapper.cr is the collection of classes for messing around with json metadata
- playlists are almost done, they still need the ability to (optionally) change the metadata of the songs downloaded in
the playlist, but they (optionally) will place all downloaded playlist songs in a single folder
- added a getter to the filename in song.cr
This commit is contained in:
Cooper Hammond 2020-05-12 22:28:03 -07:00
parent 4c20735abd
commit d1657ba86d
6 changed files with 122 additions and 19 deletions

View file

@ -17,6 +17,7 @@ class CLI
[["-h", "--help"], "help", "bool"], [["-h", "--help"], "help", "bool"],
[["-v", "--version"], "version", "bool"], [["-v", "--version"], "version", "bool"],
[["-i", "--install"], "install", "bool"], [["-i", "--install"], "install", "bool"],
[["-c", "--config"], "config", "bool"],
[["-a", "--artist"], "artist", "string"], [["-a", "--artist"], "artist", "string"],
[["-s", "--song"], "song", "string"], [["-s", "--song"], "song", "string"],
[["-A", "--album"], "album", "string"], [["-A", "--album"], "album", "string"],
@ -44,7 +45,8 @@ class CLI
#{Style.bold "Arguments:"} #{Style.bold "Arguments:"}
#{Style.blue "-h, --help"} Show this help message and exit #{Style.blue "-h, --help"} Show this help message and exit
#{Style.blue "-v, --version"} Show the program version and exit #{Style.blue "-v, --version"} Show the program version and exit
#{Style.blue "-i, --install"} Download necessary binaries to #{Style.green "~/.irs/bin"} #{Style.blue "-i, --install"} Download binaries to config location
#{Style.blue "-c, --config"} Show config file location
#{Style.blue "-a, --artist <artist>"} Specify artist name for downloading #{Style.blue "-a, --artist <artist>"} Specify artist name for downloading
#{Style.blue "-s, --song <song>"} Specify song name to download #{Style.blue "-s, --song <song>"} Specify song name to download
#{Style.blue "-A, --album <album>"} Specify the album name to download #{Style.blue "-A, --album <album>"} Specify the album name to download
@ -59,13 +61,16 @@ class CLI
#{Style.dim %(# => downloads the playlist "a different drummer" by the user prakkillian)} #{Style.dim %(# => downloads the playlist "a different drummer" by the user prakkillian)}
#{Style.bold "This project is licensed under the MIT license."} #{Style.bold "This project is licensed under the MIT license."}
#{Style.bold "Project page: <github.com/cooperhammond/irs>"} #{Style.bold "Project page: <https://github.com/cooperhammond/irs>"}
EOP EOP
puts msg puts msg
end end
def act_on_args def act_on_args
Config.check_necessities()
if @args["help"]? || @args.keys.size == 0 if @args["help"]? || @args.keys.size == 0
help help
exit exit
@ -75,6 +80,9 @@ class CLI
elsif @args["install"]? elsif @args["install"]?
YdlBinaries.get_both(Config.binary_location) YdlBinaries.get_both(Config.binary_location)
exit exit
elsif @args["config"]?
puts ENV["IRS_CONFIG_LOCATION"]?
exit
elsif @args["song"]? && @args["artist"]? elsif @args["song"]? && @args["artist"]?
s = Song.new(@args["song"], @args["artist"]) s = Song.new(@args["song"], @args["artist"])
s.provide_client_keys(Config.client_key, Config.client_secret) s.provide_client_keys(Config.client_key, Config.client_secret)
@ -89,6 +97,10 @@ class CLI
p = Playlist.new(@args["playlist"], @args["artist"]) p = Playlist.new(@args["playlist"], @args["artist"])
p.provide_client_keys(Config.client_key, Config.client_secret) p.provide_client_keys(Config.client_key, Config.client_secret)
p.grab_it() p.grab_it()
else
puts Style.red("Those arguments don't do anything when used that way.")
puts "Type `irs -h` to see usage."
exit 1
end end
end end
@ -124,7 +136,7 @@ class CLI
end end
# ensure there's an argument if the program needs one # ensure there's an argument if the program needs one
if flag[2] == "string" && i + 1 > argv.size if flag[2] == "string" && i + 1 >= argv.size
arg_error argv, i, %("#{arg}" needs an argument.) arg_error argv, i, %("#{arg}" needs an argument.)
end end

View file

@ -1,22 +1,105 @@
require "yaml"
require "./styles"
EXAMPLE_CONFIG = <<-EOP
#{Style.dim "exampleconfig.yml"}
#{Style.dim "===="}
binary_directory: ~/.irs/bin
music_directory: ~/Music
client_key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
client_secret: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
single_folder_playlist:
enabled: true
retain_playlist_order: true
overwrite_album: false
#{Style.dim "===="}
EOP
module Config module Config
extend self extend self
@@arguments = [
"binary_directory",
"music_directory",
"client_key",
"client_secret",
"single_folder_playlist: enabled",
"single_folder_playlist: retain_playlist_order",
"single_folder_playlist: overwrite_album"
]
@@conf = YAML.parse("")
begin
@@conf = YAML.parse(File.read(ENV["IRS_CONFIG_LOCATION"]))
rescue
puts Style.red "Before anything else, define the environment variable IRS_CONFIG_LOCATION pointing to a .yml file like this one."
puts EXAMPLE_CONFIG
puts Style.bold "See https://github.com/cooperhammond/irs for more information on the config file"
exit 1
end
def binary_location : String def binary_location : String
path = "~/.irs/bin" path = @@conf["binary_directory"].to_s
return Path[path].expand(home: true).to_s return Path[path].expand(home: true).to_s
end end
def music_directory : String def music_directory : String
path = "./Music/" path = @@conf["music_directory"].to_s
return Path[path].expand(home: true).to_s return Path[path].expand(home: true).to_s
end end
def client_key : String def client_key : String
return "362f75b91aeb471bb392945f93eba842" return @@conf["client_key"].to_s
end end
def client_secret : String def client_secret : String
return "013556dd71e14e1da9443dee73e23a91" return @@conf["client_secret"].to_s
end
def single_folder_playlist? : Bool
return @@conf["single_folder_playlist"]["enabled"].as_bool
end
def retain_playlist_order? : Bool
return @@conf["single_folder_playlist"]["retain_playlist_order"].as_bool
end
def overwrite_album? : Bool
return @@conf["single_folder_playlist"]["overwrite_album"].as_bool
end
def check_necessities
missing_configs = [] of String
@@arguments.each do |argument|
if !check_conf(argument)
missing_configs.push(argument)
end
end
if missing_configs.size > 0
puts Style.red("You are missing the following key(s) in your YAML config file:")
missing_configs.each do |config|
puts " " + config
end
puts "\nHere's an example of what your config should look like:"
puts EXAMPLE_CONFIG
puts Style.bold "See https://github.com/cooperhammond/irs for more information on the config file"
exit 1
end
end
private def check_conf(key : String) : YAML::Any?
if key.includes?(": ")
args = key.split(": ")
if @@conf[args[0]]?
return @@conf[args[0]][args[1]]?
else
return @@conf[args[0]]?
end
else
return @@conf[key]?
end
end end
end end

View file

@ -5,8 +5,6 @@ require "./song"
require "./list" require "./list"
class Album < SpotifyList class Album < SpotifyList
@home_music_directory = Config.music_directory @home_music_directory = Config.music_directory
@ -37,7 +35,7 @@ class Album < SpotifyList
} }
)) ))
prepped_data = AlbumTrackMetadataMapper.from_json(datum.to_json) prepped_data = AlbumTracksMapper.from_json(datum.to_json)
prepped_data.album = album_metadata prepped_data.album = album_metadata
data = parse_to_json(prepped_data.to_json) data = parse_to_json(prepped_data.to_json)

View file

@ -24,7 +24,7 @@ class PlaylistTracksMapper
) )
end end
class AlbumTrackMetadataMapper class AlbumTracksMapper
JSON.mapping( JSON.mapping(
album: { album: {
type: JSON::Any, type: JSON::Any,

View file

@ -3,9 +3,11 @@ require "../bottle/config"
require "./song" require "./song"
require "./list" require "./list"
class Playlist < SpotifyList class Playlist < SpotifyList
@home_music_directory = Config.music_directory @home_music_directory = Config.music_directory
@playlist : JSON::Any?
# Uses the `spotify_searcher` defined in parent `SpotifyList` to find the # Uses the `spotify_searcher` defined in parent `SpotifyList` to find the
# correct metadata of the list # correct metadata of the list
@ -14,8 +16,8 @@ class Playlist < SpotifyList
"name" => @list_name.as(String), "name" => @list_name.as(String),
"username" => @list_author.as(String) "username" => @list_author.as(String)
}) })
if playlist if @playlist
return playlist.as(JSON::Any) return @playlist.as(JSON::Any)
else else
puts "No playlists were found by that name and user." puts "No playlists were found by that name and user."
exit 1 exit 1
@ -26,16 +28,24 @@ class Playlist < SpotifyList
# of spotify's album json. Moves the title of the album and the album art # of spotify's album json. Moves the title of the album and the album art
# to the json of the single song # to the json of the single song
def organize_song_metadata(list : JSON::Any, datum : JSON::Any) : JSON::Any def organize_song_metadata(list : JSON::Any, datum : JSON::Any) : JSON::Any
puts datum
puts "THIS"
exit 0
data = datum data = datum
return data return data
end end
private def organize(song : Song) private def organize(song : Song)
song.organize_it(@home_music_directory) if Config.single_folder_playlist?
path = Path[@home_music_directory].expand(home: true)
path = path / @playlist.as(JSON::Any)["name"].to_s
.gsub(/[\/]/, "").gsub(" ", " ")
strpath = path.to_s
if !File.directory?(strpath)
FileUtils.mkdir_p(strpath)
end
safe_filename = song.filename.gsub(/[\/]/, "").gsub(" ", " ")
File.rename("./" + song.filename, (path / safe_filename).to_s)
else
song.organize_it(@home_music_directory)
end
end end
end end

View file

@ -11,7 +11,7 @@ class Song
@client_secret = "" @client_secret = ""
@metadata : JSON::Any? @metadata : JSON::Any?
@filename = "" getter filename = ""
@artist = "" @artist = ""
@album = "" @album = ""