mirror of
https://github.com/cooperhammond/irs.git
synced 2024-12-22 17:35:28 +00:00
Merge pull request #66 from Who23/youtube-sources
Add ability to specifiy youtube URLs manually Looks like wonderful stuff, I appreciate the contribution and time investment to my small homebrew project, I hope you've been getting good stuff out of it.
This commit is contained in:
commit
58895e2e87
|
@ -54,6 +54,8 @@ Arguments:
|
||||||
-s, --song <song> Specify song name to download
|
-s, --song <song> Specify song name to download
|
||||||
-A, --album <album> Specify the album name to download
|
-A, --album <album> Specify the album name to download
|
||||||
-p, --playlist <playlist> Specify the playlist name to download
|
-p, --playlist <playlist> Specify the playlist name to download
|
||||||
|
-u, --url <url> Specify the youtube url to download from (for single songs only)
|
||||||
|
-g, --give-url Specify the youtube url sources while downloading (for albums or playlists only only)
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
$ irs --song "Bohemian Rhapsody" --artist "Queen"
|
$ irs --song "Bohemian Rhapsody" --artist "Queen"
|
||||||
|
|
|
@ -20,6 +20,8 @@ class CLI
|
||||||
[["-s", "--song"], "song", "string"],
|
[["-s", "--song"], "song", "string"],
|
||||||
[["-A", "--album"], "album", "string"],
|
[["-A", "--album"], "album", "string"],
|
||||||
[["-p", "--playlist"], "playlist", "string"],
|
[["-p", "--playlist"], "playlist", "string"],
|
||||||
|
[["-u", "--url"], "url", "string"],
|
||||||
|
[["-g", "--give-url"], "give-url", "bool"],
|
||||||
]
|
]
|
||||||
|
|
||||||
@args : Hash(String, String)
|
@args : Hash(String, String)
|
||||||
|
@ -48,6 +50,8 @@ class CLI
|
||||||
#{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
|
||||||
#{Style.blue "-p, --playlist <playlist>"} Specify the playlist name to download
|
#{Style.blue "-p, --playlist <playlist>"} Specify the playlist name to download
|
||||||
|
#{Style.blue "-u, --url <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.bold "Examples:"}
|
#{Style.bold "Examples:"}
|
||||||
$ #{Style.green %(irs --song "Bohemian Rhapsody" --artist "Queen")}
|
$ #{Style.green %(irs --song "Bohemian Rhapsody" --artist "Queen")}
|
||||||
|
@ -82,17 +86,17 @@ class CLI
|
||||||
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)
|
||||||
s.grab_it
|
s.grab_it(@args["url"]?)
|
||||||
s.organize_it(Config.music_directory)
|
s.organize_it(Config.music_directory)
|
||||||
exit
|
exit
|
||||||
elsif @args["album"]? && @args["artist"]?
|
elsif @args["album"]? && @args["artist"]?
|
||||||
a = Album.new(@args["album"], @args["artist"])
|
a = Album.new(@args["album"], @args["artist"])
|
||||||
a.provide_client_keys(Config.client_key, Config.client_secret)
|
a.provide_client_keys(Config.client_key, Config.client_secret)
|
||||||
a.grab_it
|
a.grab_it(!!@args["give-url"])
|
||||||
elsif @args["playlist"]? && @args["artist"]?
|
elsif @args["playlist"]? && @args["artist"]?
|
||||||
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(!!@args["give-url"])
|
||||||
else
|
else
|
||||||
puts Style.red("Those arguments don't do anything when used that way.")
|
puts Style.red("Those arguments don't do anything when used that way.")
|
||||||
puts "Type `irs -h` to see usage."
|
puts "Type `irs -h` to see usage."
|
||||||
|
|
|
@ -17,6 +17,9 @@ abstract class SpotifyList
|
||||||
"searching" => [
|
"searching" => [
|
||||||
Style.bold("Searching for %l by %a ... \r"),
|
Style.bold("Searching for %l by %a ... \r"),
|
||||||
Style.green("+ ") + Style.bold("%l by %a \n")
|
Style.green("+ ") + Style.bold("%l by %a \n")
|
||||||
|
],
|
||||||
|
"url" => [
|
||||||
|
Style.bold("When prompted for a URL, provide a youtube URL or press enter to scrape for one\n")
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,11 +27,15 @@ abstract class SpotifyList
|
||||||
end
|
end
|
||||||
|
|
||||||
# Finds the list, and downloads all of the songs using the `Song` class
|
# Finds the list, and downloads all of the songs using the `Song` class
|
||||||
def grab_it
|
def grab_it(ask_url : Bool = false)
|
||||||
if !@spotify_searcher.authorized?
|
if !@spotify_searcher.authorized?
|
||||||
raise("Need to call provide_client_keys on Album or Playlist class.")
|
raise("Need to call provide_client_keys on Album or Playlist class.")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if ask_url
|
||||||
|
outputter("url", 0)
|
||||||
|
end
|
||||||
|
|
||||||
outputter("searching", 0)
|
outputter("searching", 0)
|
||||||
list = find_it()
|
list = find_it()
|
||||||
outputter("searching", 1)
|
outputter("searching", 1)
|
||||||
|
@ -47,7 +54,7 @@ abstract class SpotifyList
|
||||||
song.provide_metadata(data)
|
song.provide_metadata(data)
|
||||||
|
|
||||||
puts Style.bold("[#{data["track_number"]}/#{contents.size}]")
|
puts Style.bold("[#{data["track_number"]}/#{contents.size}]")
|
||||||
song.grab_it
|
song.grab_it ask_url: ask_url
|
||||||
|
|
||||||
organize(song)
|
organize(song)
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,10 @@ class Song
|
||||||
],
|
],
|
||||||
"url" => [
|
"url" => [
|
||||||
" Searching for URL ...\r",
|
" Searching for URL ...\r",
|
||||||
Style.green(" + ") + Style.dim("URL found \n")
|
Style.green(" + ") + Style.dim("URL found \n"),
|
||||||
|
" Validating URL ...\r",
|
||||||
|
Style.green(" + ") + Style.dim("URL validated \n"),
|
||||||
|
"URL?: "
|
||||||
],
|
],
|
||||||
"download" => [
|
"download" => [
|
||||||
" Downloading video:\n",
|
" Downloading video:\n",
|
||||||
|
@ -47,11 +50,12 @@ class Song
|
||||||
end
|
end
|
||||||
|
|
||||||
# Find, downloads, and tags the mp3 song that this class represents.
|
# Find, downloads, and tags the mp3 song that this class represents.
|
||||||
#
|
# Optionally takes a youtube URL to download from
|
||||||
|
#
|
||||||
# ```
|
# ```
|
||||||
# Song.new("Bohemian Rhapsody", "Queen").grab_it
|
# Song.new("Bohemian Rhapsody", "Queen").grab_it
|
||||||
# ```
|
# ```
|
||||||
def grab_it
|
def grab_it(url : (String | Nil) = nil, ask_url : Bool = false)
|
||||||
outputter("intro", 0)
|
outputter("intro", 0)
|
||||||
|
|
||||||
if !@spotify_searcher.authorized? && !@metadata
|
if !@spotify_searcher.authorized? && !@metadata
|
||||||
|
@ -81,14 +85,31 @@ class Song
|
||||||
data = @metadata.as(JSON::Any)
|
data = @metadata.as(JSON::Any)
|
||||||
@filename = data["track_number"].to_s + " - #{data["name"].to_s}.mp3"
|
@filename = data["track_number"].to_s + " - #{data["name"].to_s}.mp3"
|
||||||
|
|
||||||
outputter("url", 0)
|
if ask_url
|
||||||
url = Youtube.find_url(@song_name, @artist_name, search_terms: "lyrics")
|
outputter("url", 4)
|
||||||
if !url
|
url = gets
|
||||||
raise("There was no url found on youtube for " +
|
if !url.nil? && url.strip == ""
|
||||||
%("#{@song_name}" by "#{@artist_name}. ) +
|
url = nil
|
||||||
"Check your input and try again.")
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if !url
|
||||||
|
outputter("url", 0)
|
||||||
|
url = Youtube.find_url(@song_name, @artist_name, search_terms: "lyrics")
|
||||||
|
if !url
|
||||||
|
raise("There was no url found on youtube for " +
|
||||||
|
%("#{@song_name}" by "#{@artist_name}. ) +
|
||||||
|
"Check your input and try again.")
|
||||||
|
end
|
||||||
|
outputter("url", 1)
|
||||||
|
else
|
||||||
|
outputter("url", 2)
|
||||||
|
if !Youtube.is_valid_url(url)
|
||||||
|
raise("The url '#{url}' is an invalid youtube URL " +
|
||||||
|
"Check the URL and try again")
|
||||||
|
end
|
||||||
|
outputter("url", 3)
|
||||||
end
|
end
|
||||||
outputter("url", 1)
|
|
||||||
|
|
||||||
outputter("download", 0)
|
outputter("download", 0)
|
||||||
Ripper.download_mp3(url.as(String), @filename)
|
Ripper.download_mp3(url.as(String), @filename)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
require "http"
|
require "http"
|
||||||
require "xml"
|
require "xml"
|
||||||
require "json"
|
require "json"
|
||||||
|
require "uri"
|
||||||
|
|
||||||
|
|
||||||
module Youtube
|
module Youtube
|
||||||
|
@ -23,6 +24,45 @@ module Youtube
|
||||||
|
|
||||||
alias NODES_CLASS = Array(Hash(String, String))
|
alias NODES_CLASS = Array(Hash(String, String))
|
||||||
|
|
||||||
|
# Checks if the given URL is a valid youtube URL
|
||||||
|
#
|
||||||
|
# ```
|
||||||
|
# Youtube.is_valid_url("https://www.youtube.com/watch?v=NOTANACTUALVIDEOID")
|
||||||
|
# => false
|
||||||
|
# ```
|
||||||
|
def is_valid_url(url : String) : Bool
|
||||||
|
uri = URI.parse url
|
||||||
|
|
||||||
|
# is it a video on youtube, with a query
|
||||||
|
query = uri.query
|
||||||
|
if uri.host != "www.youtube.com" || uri.path != "/watch" || !query
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
queries = query.split('&')
|
||||||
|
|
||||||
|
# find the video ID
|
||||||
|
i = 0
|
||||||
|
while i < queries.size
|
||||||
|
if queries[i].starts_with?("v=")
|
||||||
|
vID = queries[i][2..-1]
|
||||||
|
break
|
||||||
|
end
|
||||||
|
i += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if !vID
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# this is an internal endpoint to validate the video ID
|
||||||
|
response = HTTP::Client.get "https://www.youtube.com/get_video_info?video_id=#{vID}"
|
||||||
|
|
||||||
|
return response.body.includes?("status=ok")
|
||||||
|
end
|
||||||
|
|
||||||
# Finds a youtube url based off of the given information.
|
# Finds a youtube url based off of the given information.
|
||||||
# The query to youtube is constructed like this:
|
# The query to youtube is constructed like this:
|
||||||
# "<song_name> <artist_name> <search terms>"
|
# "<song_name> <artist_name> <search terms>"
|
||||||
|
|
Loading…
Reference in a new issue