mirror of
https://github.com/cooperhammond/irs.git
synced 2024-12-22 17:35:28 +00:00
make the way mp3s are saved configurable
Signed-off-by: Luca Schlecker <luca.schlecker@hotmail.com>
This commit is contained in:
parent
2c364c38c2
commit
2e8bc6c8c5
57
README.md
57
README.md
|
@ -96,6 +96,8 @@ If you're one of those cool people who compiles from source
|
||||||
```yaml
|
```yaml
|
||||||
binary_directory: ~/.irs/bin
|
binary_directory: ~/.irs/bin
|
||||||
music_directory: ~/Music
|
music_directory: ~/Music
|
||||||
|
filename_pattern: "{track_number} - {title}"
|
||||||
|
directory_pattern: "{artist}/{album}"
|
||||||
client_key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
client_key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||||
client_secret: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
client_secret: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||||
single_folder_playlist:
|
single_folder_playlist:
|
||||||
|
@ -122,6 +124,8 @@ Here's what they do:
|
||||||
```yaml
|
```yaml
|
||||||
binary_directory: ~/.irs/bin
|
binary_directory: ~/.irs/bin
|
||||||
music_directory: ~/Music
|
music_directory: ~/Music
|
||||||
|
filename_pattern: "{track_number} - {title}"
|
||||||
|
directory_pattern: "{artist}/{album}"
|
||||||
client_key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
client_key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||||
client_secret: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
client_secret: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||||
single_folder_playlist:
|
single_folder_playlist:
|
||||||
|
@ -132,8 +136,8 @@ single_folder_playlist:
|
||||||
- `binary_directory`: a path specifying where the downloaded binaries should
|
- `binary_directory`: a path specifying where the downloaded binaries should
|
||||||
be placed
|
be placed
|
||||||
- `music_directory`: a path specifying where downloaded mp3s should be placed.
|
- `music_directory`: a path specifying where downloaded mp3s should be placed.
|
||||||
Note that there will be more structure created inside that folder, usually
|
- `filename_pattern`: a pattern for the output filename of the mp3
|
||||||
in the format of `music-dir>artist-name>album-name>track`
|
- `directory_pattern`: a pattern for the folder structure your mp3s are saved in
|
||||||
- `client_key`: a client key from your spotify API application
|
- `client_key`: a client key from your spotify API application
|
||||||
- `client_secret`: a client secret key from your spotify API application
|
- `client_secret`: a client secret key from your spotify API application
|
||||||
- `single_folder_playlist/enabled`: if set to true, all mp3s from a downloaded
|
- `single_folder_playlist/enabled`: if set to true, all mp3s from a downloaded
|
||||||
|
@ -145,6 +149,55 @@ single_folder_playlist:
|
||||||
the album name and album image of the mp3 with the title of your playlist
|
the album name and album image of the mp3 with the title of your playlist
|
||||||
and the image for your playlist respectively
|
and the image for your playlist respectively
|
||||||
|
|
||||||
|
|
||||||
|
In a pattern following keywords will be replaced:
|
||||||
|
|
||||||
|
| Keyword | Replacement | Example |
|
||||||
|
| :----: | :----: | :----: |
|
||||||
|
| `{artist}` | Artist Name | Queen |
|
||||||
|
| `{title}` | Track Title | Bohemian Rhapsody |
|
||||||
|
| `{album}` | Album Name | Stone Cold Classics |
|
||||||
|
| `{track_number}` | Track Number | 9 |
|
||||||
|
| `{total_tracks}` | Total Tracks in Album | 14 |
|
||||||
|
| `{disc_number}` | Disc Number | 1 |
|
||||||
|
| `{day}` | Release Day | 01 |
|
||||||
|
| `{month}` | Release Month | 01 |
|
||||||
|
| `{year}` | Release Year | 2006 |
|
||||||
|
| `{id}` | Spotify ID | 6l8GvAyoUZwWDgF1e4822w |
|
||||||
|
|
||||||
|
Beware OS-restrictions when naming your mp3s.
|
||||||
|
|
||||||
|
Pattern Examples:
|
||||||
|
```yaml
|
||||||
|
music_directory: ~/Music
|
||||||
|
filename_pattern: "{track_number} - {title}"
|
||||||
|
directory_pattern: "{artist}/{album}"
|
||||||
|
```
|
||||||
|
Outputs: `~/Music/Queen/Stone Cold Classics/9 - Bohemian Rhapsody.mp3`
|
||||||
|
<br><br>
|
||||||
|
```yaml
|
||||||
|
music_directory: ~/Music
|
||||||
|
filename_pattern: "{artist} - {title}"
|
||||||
|
directory_pattern: ""
|
||||||
|
```
|
||||||
|
Outputs: `~/Music/Queen - Bohemian Rhapsody.mp3`
|
||||||
|
<br><br>
|
||||||
|
```yaml
|
||||||
|
music_directory: ~/Music
|
||||||
|
filename_pattern: "{track_number} of {total_tracks} - {title}"
|
||||||
|
directory_pattern: "{year}/{artist}/{album}"
|
||||||
|
```
|
||||||
|
Outputs: `~/Music/2006/Queen/Stone Cold Classics/9 of 14 - Bohemian Rhapsody.mp3`
|
||||||
|
<br><br>
|
||||||
|
```yaml
|
||||||
|
music_directory: ~/Music
|
||||||
|
filename_pattern: "{track_number}. {title}"
|
||||||
|
directory_pattern: "irs/{artist} - {album}"
|
||||||
|
```
|
||||||
|
Outputs: `~/Music/irs/Queen - Stone Cold Classics/9. Bohemian Rhapsody.mp3`
|
||||||
|
<br>
|
||||||
|
|
||||||
|
|
||||||
## How it works
|
## How it works
|
||||||
|
|
||||||
**At it's core** `irs` downloads individual songs. It does this by interfacing
|
**At it's core** `irs` downloads individual songs. It does this by interfacing
|
||||||
|
|
|
@ -83,7 +83,7 @@ class CLI
|
||||||
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(@args["url"]?)
|
s.grab_it(@args["url"]?)
|
||||||
s.organize_it(Config.music_directory)
|
s.organize_it()
|
||||||
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)
|
||||||
|
|
|
@ -9,6 +9,8 @@ EXAMPLE_CONFIG = <<-EOP
|
||||||
#{Style.dim "===="}
|
#{Style.dim "===="}
|
||||||
#{Style.blue "binary_directory"}: #{Style.green "~/.irs/bin"}
|
#{Style.blue "binary_directory"}: #{Style.green "~/.irs/bin"}
|
||||||
#{Style.blue "music_directory"}: #{Style.green "~/Music"}
|
#{Style.blue "music_directory"}: #{Style.green "~/Music"}
|
||||||
|
#{Style.blue "filename_pattern"}: #{Style.green "\"{track_number} - {title}\""}
|
||||||
|
#{Style.blue "directory_pattern"}: #{Style.green "\"{artist}/{album}\""}
|
||||||
#{Style.blue "client_key"}: #{Style.green "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"}
|
#{Style.blue "client_key"}: #{Style.green "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"}
|
||||||
#{Style.blue "client_secret"}: #{Style.green "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"}
|
#{Style.blue "client_secret"}: #{Style.green "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"}
|
||||||
#{Style.blue "single_folder_playlist"}:
|
#{Style.blue "single_folder_playlist"}:
|
||||||
|
@ -24,6 +26,8 @@ module Config
|
||||||
@@arguments = [
|
@@arguments = [
|
||||||
"binary_directory",
|
"binary_directory",
|
||||||
"music_directory",
|
"music_directory",
|
||||||
|
"filename_pattern",
|
||||||
|
"directory_pattern",
|
||||||
"client_key",
|
"client_key",
|
||||||
"client_secret",
|
"client_secret",
|
||||||
"single_folder_playlist: enabled",
|
"single_folder_playlist: enabled",
|
||||||
|
@ -50,6 +54,14 @@ module Config
|
||||||
path = @@conf["music_directory"].to_s
|
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 filename_pattern : String
|
||||||
|
return @@conf["filename_pattern"].to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def directory_pattern : String
|
||||||
|
return @@conf["directory_pattern"].to_s
|
||||||
|
end
|
||||||
|
|
||||||
def client_key : String
|
def client_key : String
|
||||||
return @@conf["client_key"].to_s
|
return @@conf["client_key"].to_s
|
||||||
|
|
28
src/bottle/pattern.cr
Normal file
28
src/bottle/pattern.cr
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
module Pattern
|
||||||
|
extend self
|
||||||
|
|
||||||
|
def parse(formatString : String, metadata : JSON::Any)
|
||||||
|
formatted : String = formatString
|
||||||
|
|
||||||
|
date : Array(String) = (metadata["album"]? || JSON.parse("{}"))["release_date"]?.to_s.split('-')
|
||||||
|
|
||||||
|
keys : Hash(String, String) = {
|
||||||
|
"artist" => ((metadata.dig?("artists") || JSON.parse("{}"))[0]? || JSON.parse("{}"))["name"]?.to_s,
|
||||||
|
"title" => metadata["name"]?.to_s,
|
||||||
|
"album" => (metadata["album"]? || JSON.parse("{}"))["name"]?.to_s,
|
||||||
|
"track_number" => metadata["track_number"]?.to_s,
|
||||||
|
"disc_number" => metadata["disc_number"]?.to_s,
|
||||||
|
"total_tracks" => (metadata["album"]? || JSON.parse("{}"))["total_tracks"]?.to_s,
|
||||||
|
"year" => date[0]?.to_s,
|
||||||
|
"month" => date[1]?.to_s,
|
||||||
|
"day" => date[2]?.to_s,
|
||||||
|
"id" => metadata["id"]?.to_s
|
||||||
|
}
|
||||||
|
|
||||||
|
keys.each do |pair|
|
||||||
|
formatted = formatted.gsub("{#{pair[0]}}", pair[1] || "")
|
||||||
|
end
|
||||||
|
|
||||||
|
return formatted
|
||||||
|
end
|
||||||
|
end
|
|
@ -42,6 +42,6 @@ class Album < SpotifyList
|
||||||
end
|
end
|
||||||
|
|
||||||
private def organize(song : Song)
|
private def organize(song : Song)
|
||||||
song.organize_it(@home_music_directory)
|
song.organize_it()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -69,7 +69,7 @@ class Playlist < SpotifyList
|
||||||
safe_filename = song.filename.gsub(/[\/]/, "").gsub(" ", " ")
|
safe_filename = song.filename.gsub(/[\/]/, "").gsub(" ", " ")
|
||||||
File.rename("./" + song.filename, (path / safe_filename).to_s)
|
File.rename("./" + song.filename, (path / safe_filename).to_s)
|
||||||
else
|
else
|
||||||
song.organize_it(@home_music_directory)
|
song.organize_it()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,6 +4,8 @@ require "../search/youtube"
|
||||||
require "../interact/ripper"
|
require "../interact/ripper"
|
||||||
require "../interact/tagger"
|
require "../interact/tagger"
|
||||||
|
|
||||||
|
require "../bottle/config"
|
||||||
|
require "../bottle/pattern"
|
||||||
require "../bottle/styles"
|
require "../bottle/styles"
|
||||||
|
|
||||||
class Song
|
class Song
|
||||||
|
@ -83,7 +85,7 @@ class Song
|
||||||
end
|
end
|
||||||
|
|
||||||
data = @metadata.as(JSON::Any)
|
data = @metadata.as(JSON::Any)
|
||||||
@filename = data["track_number"].to_s + " - #{data["name"].to_s}.mp3"
|
@filename = "#{Pattern.parse(Config.filename_pattern, data)}.mp3"
|
||||||
|
|
||||||
if ask_url
|
if ask_url
|
||||||
outputter("url", 4)
|
outputter("url", 4)
|
||||||
|
@ -154,20 +156,24 @@ class Song
|
||||||
outputter("finished", 0)
|
outputter("finished", 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Will organize the song into the user's provided music directory as
|
# Will organize the song into the user's provided music directory
|
||||||
# music_directory > artist_name > album_name > song
|
# in the user's provided structure
|
||||||
# Must be called AFTER the song has been downloaded.
|
# 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")
|
# s.organize_it()
|
||||||
# # Will move the mp3 file to
|
# # With
|
||||||
|
# # directory_pattern = "{artist}/{album}"
|
||||||
|
# # filename_pattern = "{track_number} - {title}"
|
||||||
|
# # Mp3 will be moved to
|
||||||
# # /home/cooper/Music/Queen/A Night At The Opera/1 - Bohemian Rhapsody.mp3
|
# # /home/cooper/Music/Queen/A Night At The Opera/1 - Bohemian Rhapsody.mp3
|
||||||
# ```
|
# ```
|
||||||
def organize_it(music_directory : String)
|
def organize_it()
|
||||||
path = Path[music_directory].expand(home: true)
|
path = Path[Config.music_directory].expand(home: true)
|
||||||
path = path / @artist_name.gsub(/[\/]/, "").gsub(" ", " ")
|
Pattern.parse(Config.directory_pattern, @metadata.as(JSON::Any)).split('/').each do |dir|
|
||||||
path = path / @album.gsub(/[\/]/, "").gsub(" ", " ")
|
path = path / dir.gsub(/[\/]/, "").gsub(" ", " ")
|
||||||
|
end
|
||||||
strpath = path.to_s
|
strpath = path.to_s
|
||||||
if !File.directory?(strpath)
|
if !File.directory?(strpath)
|
||||||
FileUtils.mkdir_p(strpath)
|
FileUtils.mkdir_p(strpath)
|
||||||
|
|
Loading…
Reference in a new issue