mirror of
https://github.com/cooperhammond/irs.git
synced 2024-12-22 17:35:28 +00:00
crystal tool format respec
This commit is contained in:
parent
d1657ba86d
commit
de219cbe66
|
@ -8,9 +8,7 @@ require "../glue/song"
|
|||
require "../glue/album"
|
||||
require "../glue/playlist"
|
||||
|
||||
|
||||
class CLI
|
||||
|
||||
# layout:
|
||||
# [[shortflag, longflag], key, type]
|
||||
@options = [
|
||||
|
@ -21,10 +19,9 @@ class CLI
|
|||
[["-a", "--artist"], "artist", "string"],
|
||||
[["-s", "--song"], "song", "string"],
|
||||
[["-A", "--album"], "album", "string"],
|
||||
[["-p", "--playlist"], "playlist", "string"]
|
||||
[["-p", "--playlist"], "playlist", "string"],
|
||||
]
|
||||
|
||||
|
||||
@args : Hash(String, String)
|
||||
|
||||
def initialize(argv : Array(String))
|
||||
|
@ -68,8 +65,7 @@ class CLI
|
|||
end
|
||||
|
||||
def act_on_args
|
||||
|
||||
Config.check_necessities()
|
||||
Config.check_necessities
|
||||
|
||||
if @args["help"]? || @args.keys.size == 0
|
||||
help
|
||||
|
@ -86,17 +82,17 @@ class CLI
|
|||
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()
|
||||
s.grab_it
|
||||
s.organize_it(Config.music_directory)
|
||||
exit
|
||||
elsif @args["album"]? && @args["artist"]?
|
||||
a = Album.new(@args["album"], @args["artist"])
|
||||
a.provide_client_keys(Config.client_key, Config.client_secret)
|
||||
a.grab_it()
|
||||
a.grab_it
|
||||
elsif @args["playlist"]? && @args["artist"]?
|
||||
p = Playlist.new(@args["playlist"], @args["artist"])
|
||||
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."
|
||||
|
@ -111,7 +107,6 @@ class CLI
|
|||
current_key = ""
|
||||
pass_next_arg = false
|
||||
argv.each do |arg|
|
||||
|
||||
# If the previous arg was an arg flag, this is an arg, so pass it
|
||||
if pass_next_arg
|
||||
pass_next_arg = false
|
||||
|
@ -140,7 +135,6 @@ class CLI
|
|||
arg_error argv, i, %("#{arg}" needs an argument.)
|
||||
end
|
||||
|
||||
|
||||
key = flag[1].as(String)
|
||||
if flag[2] == "string"
|
||||
arguments[key] = argv[i + 1]
|
||||
|
|
|
@ -2,7 +2,6 @@ require "yaml"
|
|||
|
||||
require "./styles"
|
||||
|
||||
|
||||
EXAMPLE_CONFIG = <<-EOP
|
||||
#{Style.dim "exampleconfig.yml"}
|
||||
#{Style.dim "===="}
|
||||
|
@ -18,7 +17,6 @@ single_folder_playlist:
|
|||
EOP
|
||||
|
||||
module Config
|
||||
|
||||
extend self
|
||||
|
||||
@@arguments = [
|
||||
|
@ -28,7 +26,7 @@ module Config
|
|||
"client_secret",
|
||||
"single_folder_playlist: enabled",
|
||||
"single_folder_playlist: retain_playlist_order",
|
||||
"single_folder_playlist: overwrite_album"
|
||||
"single_folder_playlist: overwrite_album",
|
||||
]
|
||||
|
||||
@@conf = YAML.parse("")
|
||||
|
|
|
@ -4,9 +4,7 @@ require "./mapper"
|
|||
require "./song"
|
||||
require "./list"
|
||||
|
||||
|
||||
class Album < SpotifyList
|
||||
|
||||
@home_music_directory = Config.music_directory
|
||||
|
||||
# Uses the `spotify_searcher` defined in parent `SpotifyList` to find the
|
||||
|
@ -14,7 +12,7 @@ class Album < SpotifyList
|
|||
def find_it
|
||||
album = @spotify_searcher.find_item("album", {
|
||||
"name" => @list_name.as(String),
|
||||
"artist" => @list_author.as(String)
|
||||
"artist" => @list_author.as(String),
|
||||
})
|
||||
if album
|
||||
return album.as(JSON::Any)
|
||||
|
|
|
@ -8,10 +8,9 @@ require "../interact/tagger"
|
|||
|
||||
require "./song"
|
||||
|
||||
|
||||
# A parent class for downloading albums and playlists from spotify
|
||||
abstract class SpotifyList
|
||||
@spotify_searcher = SpotifySearcher.new()
|
||||
@spotify_searcher = SpotifySearcher.new
|
||||
@file_names = [] of String
|
||||
|
||||
def initialize(@list_name : String, @list_author : String?)
|
||||
|
@ -19,7 +18,6 @@ abstract class SpotifyList
|
|||
|
||||
# Finds the list, and downloads all of the songs using the `Song` class
|
||||
def grab_it
|
||||
|
||||
if !@spotify_searcher.authorized?
|
||||
raise("Need to call provide_client_keys on Album or Playlist class.")
|
||||
end
|
||||
|
@ -38,7 +36,7 @@ abstract class SpotifyList
|
|||
song = Song.new(data["name"].to_s, data["artists"][0]["name"].to_s)
|
||||
song.provide_spotify(@spotify_searcher)
|
||||
song.provide_metadata(data)
|
||||
song.grab_it()
|
||||
song.grab_it
|
||||
|
||||
organize(song)
|
||||
|
||||
|
@ -64,5 +62,4 @@ abstract class SpotifyList
|
|||
# Needed because most people want albums sorted by artist, but playlists all
|
||||
# in one folder
|
||||
private abstract def organize(song : Song)
|
||||
|
||||
end
|
|
@ -4,7 +4,7 @@ class PlaylistExtensionMapper
|
|||
JSON.mapping(
|
||||
tracks: {
|
||||
type: PlaylistTracksMapper,
|
||||
setter: true
|
||||
setter: true,
|
||||
},
|
||||
id: String,
|
||||
images: JSON::Any,
|
||||
|
@ -18,7 +18,7 @@ class PlaylistTracksMapper
|
|||
JSON.mapping(
|
||||
items: {
|
||||
type: Array(JSON::Any),
|
||||
setter: true
|
||||
setter: true,
|
||||
},
|
||||
total: Int32
|
||||
)
|
||||
|
@ -29,7 +29,7 @@ class AlbumTracksMapper
|
|||
album: {
|
||||
type: JSON::Any,
|
||||
nilable: true,
|
||||
setter: true
|
||||
setter: true,
|
||||
},
|
||||
artists: JSON::Any,
|
||||
disc_number: Int32,
|
||||
|
@ -41,7 +41,6 @@ class AlbumTracksMapper
|
|||
)
|
||||
end
|
||||
|
||||
|
||||
def parse_to_json(string_json : String) : JSON::Any
|
||||
return JSON.parse(string_json)
|
||||
end
|
|
@ -3,9 +3,7 @@ require "../bottle/config"
|
|||
require "./song"
|
||||
require "./list"
|
||||
|
||||
|
||||
class Playlist < SpotifyList
|
||||
|
||||
@home_music_directory = Config.music_directory
|
||||
@playlist : JSON::Any?
|
||||
|
||||
|
@ -14,7 +12,7 @@ class Playlist < SpotifyList
|
|||
def find_it
|
||||
@playlist = @spotify_searcher.find_item("playlist", {
|
||||
"name" => @list_name.as(String),
|
||||
"username" => @list_author.as(String)
|
||||
"username" => @list_author.as(String),
|
||||
})
|
||||
if @playlist
|
||||
return @playlist.as(JSON::Any)
|
||||
|
|
|
@ -4,9 +4,8 @@ require "../search/youtube"
|
|||
require "../interact/ripper"
|
||||
require "../interact/tagger"
|
||||
|
||||
|
||||
class Song
|
||||
@spotify_searcher = SpotifySearcher.new()
|
||||
@spotify_searcher = SpotifySearcher.new
|
||||
@client_id = ""
|
||||
@client_secret = ""
|
||||
|
||||
|
@ -21,7 +20,7 @@ class Song
|
|||
# Find, downloads, and tags the mp3 song that this class represents.
|
||||
#
|
||||
# ```
|
||||
# Song.new("Bohemian Rhapsody", "Queen").grab_it()
|
||||
# Song.new("Bohemian Rhapsody", "Queen").grab_it
|
||||
# ```
|
||||
def grab_it
|
||||
if !@spotify_searcher.authorized? && !@metadata
|
||||
|
@ -37,7 +36,7 @@ class Song
|
|||
puts "Searching for metadata ..."
|
||||
@metadata = @spotify_searcher.find_item("track", {
|
||||
"name" => @song_name,
|
||||
"artist" => @artist_name
|
||||
"artist" => @artist_name,
|
||||
})
|
||||
|
||||
if !@metadata
|
||||
|
@ -82,11 +81,10 @@ class Song
|
|||
tagger.add_text_tag("disc", data["disc_number"].to_s)
|
||||
|
||||
puts "Tagging metadata ..."
|
||||
tagger.save()
|
||||
tagger.save
|
||||
File.delete(temp_albumart_filename)
|
||||
|
||||
puts %("#{data["name"].to_s}" by "#{data["artists"][0]["name"].to_s}" downloaded.)
|
||||
|
||||
end
|
||||
|
||||
# Will organize the song into the user's provided music directory as
|
||||
|
@ -94,7 +92,7 @@ class Song
|
|||
# Must be called AFTER the song has been downloaded.
|
||||
#
|
||||
# ```
|
||||
# s = Song.new("Bohemian Rhapsody", "Queen").grab_it()
|
||||
# s = Song.new("Bohemian Rhapsody", "Queen").grab_it
|
||||
# s.organize_it("/home/cooper/Music")
|
||||
# # Will move the mp3 file to
|
||||
# # /home/cooper/Music/Queen/A Night At The Opera/1 - Bohemian Rhapsody.mp3
|
||||
|
@ -116,7 +114,7 @@ class Song
|
|||
# called.
|
||||
#
|
||||
# ```
|
||||
# Song.new(...).provide_metadata(...).grab_it()
|
||||
# Song.new(...).provide_metadata(...).grab_it
|
||||
# ```
|
||||
def provide_metadata(metadata : JSON::Any) : self
|
||||
@metadata = metadata
|
||||
|
@ -128,8 +126,8 @@ class Song
|
|||
# provide_client_keys are not called.
|
||||
#
|
||||
# ```
|
||||
# Song.new(...).provide_spotify(SpotifySearcher.new()
|
||||
# .authenticate("XXXXXXXXXX", "XXXXXXXXXXX")).grab_it()
|
||||
# Song.new(...).provide_spotify(SpotifySearcher.new
|
||||
# .authenticate("XXXXXXXXXX", "XXXXXXXXXXX")).grab_it
|
||||
# ```
|
||||
def provide_spotify(spotify : SpotifySearcher) : self
|
||||
@spotify_searcher = spotify
|
||||
|
@ -140,7 +138,7 @@ class Song
|
|||
# provide_spotify are not called.
|
||||
#
|
||||
# ```
|
||||
# Song.new(...).provide_client_keys("XXXXXXXXXX", "XXXXXXXXX").grab_it()
|
||||
# Song.new(...).provide_client_keys("XXXXXXXXXX", "XXXXXXXXX").grab_it
|
||||
# ```
|
||||
def provide_client_keys(client_id : String, client_secret : String) : self
|
||||
@client_id = client_id
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
class Logger
|
||||
|
||||
@done_signal = "---DONE---"
|
||||
|
||||
@command : String
|
||||
|
@ -68,12 +67,12 @@ class Logger
|
|||
end
|
||||
end
|
||||
|
||||
status = called.get()
|
||||
status = called.get
|
||||
if status == true && delete_file == true
|
||||
log.delete()
|
||||
log.delete
|
||||
end
|
||||
|
||||
return called.get()
|
||||
return called.get
|
||||
end
|
||||
|
||||
# Reads each line of the file into an Array of Strings
|
||||
|
|
|
@ -2,7 +2,6 @@ require "./logger"
|
|||
require "../bottle/config"
|
||||
|
||||
module Ripper
|
||||
|
||||
extend self
|
||||
|
||||
BIN_LOC = Path[Config.binary_location]
|
||||
|
@ -35,7 +34,6 @@ module Ripper
|
|||
command += " #{option} #{options[option]}"
|
||||
end
|
||||
|
||||
|
||||
l = Logger.new(command, ".ripper.log")
|
||||
o = RipperOutputCensor.new
|
||||
|
||||
|
@ -64,6 +62,5 @@ module Ripper
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -5,10 +5,9 @@ require "../bottle/config"
|
|||
# t = Tags.new("bohem rap.mp3")
|
||||
# t.add_album_art("a night at the opera album cover.jpg")
|
||||
# t.add_text_tag("title", "Bohemian Rhapsody")
|
||||
# t.save()
|
||||
# t.save
|
||||
# ```
|
||||
class Tags
|
||||
|
||||
# TODO: export this path to a config file
|
||||
@BIN_LOC = Config.binary_location
|
||||
@query_args = [] of String
|
||||
|
@ -20,7 +19,6 @@ class Tags
|
|||
end
|
||||
|
||||
@query_args.push(%(-i "#{@filename}"))
|
||||
|
||||
end
|
||||
|
||||
# Add album art to the mp3. Album art must be added BEFORE text tags are.
|
||||
|
|
|
@ -2,7 +2,7 @@ require "./bottle/cli"
|
|||
|
||||
def main
|
||||
cli = CLI.new(ARGV)
|
||||
cli.act_on_args()
|
||||
cli.act_on_args
|
||||
end
|
||||
|
||||
main()
|
|
@ -15,14 +15,14 @@ class SpotifySearcher
|
|||
# https://developer.spotify.com/documentation/general/guides/authorization-guide/#client-credentials-flow
|
||||
#
|
||||
# ```
|
||||
# SpotifySearcher.new().authorize("XXXXXXXXXX", "XXXXXXXXXX")
|
||||
# SpotifySearcher.new.authorize("XXXXXXXXXX", "XXXXXXXXXX")
|
||||
# ```
|
||||
def authorize(client_id : String, client_secret : String) : self
|
||||
auth_url = "https://accounts.spotify.com/api/token"
|
||||
|
||||
headers = HTTP::Headers{
|
||||
"Authorization" => "Basic " +
|
||||
Base64.strict_encode "#{client_id}:#{client_secret}"
|
||||
Base64.strict_encode "#{client_id}:#{client_secret}",
|
||||
}
|
||||
|
||||
payload = "grant_type=client_credentials"
|
||||
|
@ -33,7 +33,7 @@ class SpotifySearcher
|
|||
access_token = JSON.parse(response.body)["access_token"]
|
||||
|
||||
@access_header = HTTP::Headers{
|
||||
"Authorization" => "Bearer #{access_token}"
|
||||
"Authorization" => "Bearer #{access_token}",
|
||||
}
|
||||
|
||||
@authorized = true
|
||||
|
@ -57,10 +57,9 @@ class SpotifySearcher
|
|||
# ```
|
||||
def find_item(item_type : String, item_parameters : Hash, offset = 0,
|
||||
limit = 20) : JSON::Any?
|
||||
|
||||
query = generate_query(item_type, item_parameters, offset, limit)
|
||||
|
||||
url = @root_url.join("search?q=#{query}").to_s()
|
||||
url = @root_url.join("search?q=#{query}").to_s
|
||||
|
||||
response = HTTP::Client.get(url, headers: @access_header)
|
||||
error_check(response)
|
||||
|
@ -102,7 +101,6 @@ class SpotifySearcher
|
|||
# ```
|
||||
def find_user_playlist(username : String, name : String, offset = 0,
|
||||
limit = 20) : JSON::Any?
|
||||
|
||||
url = "users/#{username}/playlists?limit=#{limit}&offset=#{offset}"
|
||||
url = @root_url.join(url).to_s
|
||||
|
||||
|
@ -132,17 +130,16 @@ class SpotifySearcher
|
|||
# Get the complete metadata of an item based off of its id
|
||||
#
|
||||
# ```
|
||||
# SpotifySearcher.new().authorize(...).get_item("artist", "1dfeR4HaWDbWqFHLkxsg1d")
|
||||
# SpotifySearcher.new.authorize(...).get_item("artist", "1dfeR4HaWDbWqFHLkxsg1d")
|
||||
# ```
|
||||
def get_item(item_type : String, id : String, offset = 0,
|
||||
limit = 100) : JSON::Any
|
||||
|
||||
if item_type == "playlist"
|
||||
return get_playlist(id, offset, limit)
|
||||
end
|
||||
|
||||
url = "#{item_type}s/#{id}?limit=#{limit}&offset=#{offset}"
|
||||
url = @root_url.join(url).to_s()
|
||||
url = @root_url.join(url).to_s
|
||||
|
||||
response = HTTP::Client.get(url, headers: @access_header)
|
||||
error_check(response)
|
||||
|
@ -156,11 +153,11 @@ class SpotifySearcher
|
|||
# insert ALL tracks from the playlist into the `JSON::Any`
|
||||
#
|
||||
# ```
|
||||
# SpotifySearcher.new().authorize(...).get_playlist("122Fc9gVuSZoksEjKEx7L0")
|
||||
# SpotifySearcher.new.authorize(...).get_playlist("122Fc9gVuSZoksEjKEx7L0")
|
||||
# ```
|
||||
def get_playlist(id, offset = 0, limit = 100) : JSON::Any
|
||||
url = "playlists/#{id}?limit=#{limit}&offset=#{offset}"
|
||||
url = @root_url.join(url).to_s()
|
||||
url = @root_url.join(url).to_s
|
||||
|
||||
response = HTTP::Client.get(url, headers: @access_header)
|
||||
error_check(response)
|
||||
|
@ -180,7 +177,7 @@ class SpotifySearcher
|
|||
private def playlist_extension(parent : PlaylistExtensionMapper,
|
||||
id : String, offset = 0, limit = 100) : JSON::Any
|
||||
url = "playlists/#{id}/tracks?limit=#{limit}&offset=#{offset}"
|
||||
url = @root_url.join(url).to_s()
|
||||
url = @root_url.join(url).to_s
|
||||
|
||||
response = HTTP::Client.get(url, headers: @access_header)
|
||||
error_check(response)
|
||||
|
@ -202,10 +199,9 @@ class SpotifySearcher
|
|||
# Find the genre of an artist based off of their id
|
||||
#
|
||||
# ```
|
||||
# SpotifySearcher.new().authorize(...).find_genre("1dfeR4HaWDbWqFHLkxsg1d")
|
||||
# SpotifySearcher.new.authorize(...).find_genre("1dfeR4HaWDbWqFHLkxsg1d")
|
||||
# ```
|
||||
def find_genre(id : String) : String
|
||||
|
||||
genre = get_item("artist", id)["genres"][0].to_s
|
||||
genre = genre.split(" ").map { |x| x.capitalize }.join(" ")
|
||||
|
||||
|
@ -234,7 +230,6 @@ class SpotifySearcher
|
|||
item_parameters.keys.each do |k|
|
||||
# This will map album and track names from the name key to the query
|
||||
if k == "name"
|
||||
|
||||
# will remove the "name:<title>" param from the query
|
||||
if item_type == "playlist"
|
||||
query += item_parameters[k].gsub(" ", "+") + "+"
|
||||
|
@ -332,10 +327,8 @@ class SpotifySearcher
|
|||
private def param_encode(key : String, value : String) : String
|
||||
return key.gsub(" ", "+") + ":" + value.gsub(" ", "+") + "+"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
# puts SpotifySearcher.new()
|
||||
# .authorize("XXXXXXXXXXXXXXX",
|
||||
# "XXXXXXXXXXXXXXX")
|
||||
|
|
|
@ -1,24 +1,22 @@
|
|||
require "http"
|
||||
require "xml"
|
||||
|
||||
|
||||
module Youtube
|
||||
|
||||
extend self
|
||||
|
||||
VALID_LINK_CLASSES = [
|
||||
"yt-simple-endpoint style-scope ytd-video-renderer",
|
||||
"yt-uix-tile-link yt-ui-ellipsis yt-ui-ellipsis-2 yt-uix-sessionlink spf-link "
|
||||
"yt-uix-tile-link yt-ui-ellipsis yt-ui-ellipsis-2 yt-uix-sessionlink spf-link ",
|
||||
]
|
||||
|
||||
GARBAGE_PHRASES = [
|
||||
"cover", "album", "live", "clean", "version", "full", "full album", "row",
|
||||
"at", "@", "session", "how to", "npr music", "reimagined", "hr version",
|
||||
"trailer"
|
||||
"trailer",
|
||||
]
|
||||
|
||||
GOLDEN_PHRASES = [
|
||||
"official video", "official music video"
|
||||
"official video", "official music video",
|
||||
]
|
||||
|
||||
# Finds a youtube url based off of the given information.
|
||||
|
@ -78,10 +76,9 @@ module Youtube
|
|||
|
||||
points.push({
|
||||
"points" => pts,
|
||||
"index" => index
|
||||
"index" => index,
|
||||
})
|
||||
index += 1
|
||||
|
||||
end
|
||||
|
||||
# Sort first by points and then by original index of the song
|
||||
|
|
Loading…
Reference in a new issue