make the way mp3s are saved configurable

Signed-off-by: Luca Schlecker <luca.schlecker@hotmail.com>
This commit is contained in:
Luca Schlecker 2020-12-29 23:27:16 +01:00
parent 2c364c38c2
commit 2e8bc6c8c5
7 changed files with 113 additions and 14 deletions

View file

@ -96,6 +96,8 @@ If you're one of those cool people who compiles from source
```yaml
binary_directory: ~/.irs/bin
music_directory: ~/Music
filename_pattern: "{track_number} - {title}"
directory_pattern: "{artist}/{album}"
client_key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
client_secret: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
single_folder_playlist:
@ -122,6 +124,8 @@ Here's what they do:
```yaml
binary_directory: ~/.irs/bin
music_directory: ~/Music
filename_pattern: "{track_number} - {title}"
directory_pattern: "{artist}/{album}"
client_key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
client_secret: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
single_folder_playlist:
@ -132,8 +136,8 @@ single_folder_playlist:
- `binary_directory`: a path specifying where the downloaded binaries 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
in the format of `music-dir>artist-name>album-name>track`
- `filename_pattern`: a pattern for the output filename of the mp3
- `directory_pattern`: a pattern for the folder structure your mp3s are saved in
- `client_key`: a client 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
@ -145,6 +149,55 @@ single_folder_playlist:
the album name and album image of the mp3 with the title of your playlist
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
**At it's core** `irs` downloads individual songs. It does this by interfacing

View file

@ -83,7 +83,7 @@ class CLI
s = Song.new(@args["song"], @args["artist"])
s.provide_client_keys(Config.client_key, Config.client_secret)
s.grab_it(@args["url"]?)
s.organize_it(Config.music_directory)
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)

View file

@ -9,6 +9,8 @@ EXAMPLE_CONFIG = <<-EOP
#{Style.dim "===="}
#{Style.blue "binary_directory"}: #{Style.green "~/.irs/bin"}
#{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_secret"}: #{Style.green "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"}
#{Style.blue "single_folder_playlist"}:
@ -24,6 +26,8 @@ module Config
@@arguments = [
"binary_directory",
"music_directory",
"filename_pattern",
"directory_pattern",
"client_key",
"client_secret",
"single_folder_playlist: enabled",
@ -50,6 +54,14 @@ module Config
path = @@conf["music_directory"].to_s
return Path[path].expand(home: true).to_s
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
return @@conf["client_key"].to_s

28
src/bottle/pattern.cr Normal file
View 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

View file

@ -42,6 +42,6 @@ class Album < SpotifyList
end
private def organize(song : Song)
song.organize_it(@home_music_directory)
song.organize_it()
end
end

View file

@ -69,7 +69,7 @@ class Playlist < SpotifyList
safe_filename = song.filename.gsub(/[\/]/, "").gsub(" ", " ")
File.rename("./" + song.filename, (path / safe_filename).to_s)
else
song.organize_it(@home_music_directory)
song.organize_it()
end
end
end

View file

@ -4,6 +4,8 @@ require "../search/youtube"
require "../interact/ripper"
require "../interact/tagger"
require "../bottle/config"
require "../bottle/pattern"
require "../bottle/styles"
class Song
@ -83,7 +85,7 @@ class Song
end
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
outputter("url", 4)
@ -154,20 +156,24 @@ class Song
outputter("finished", 0)
end
# Will organize the song into the user's provided music directory as
# music_directory > artist_name > album_name > song
# Will organize the song into the user's provided music directory
# in the user's provided structure
# Must be called AFTER the song has been downloaded.
#
# ```
# s = Song.new("Bohemian Rhapsody", "Queen").grab_it
# s.organize_it("/home/cooper/Music")
# # Will move the mp3 file to
# s.organize_it()
# # 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
# ```
def organize_it(music_directory : String)
path = Path[music_directory].expand(home: true)
path = path / @artist_name.gsub(/[\/]/, "").gsub(" ", " ")
path = path / @album.gsub(/[\/]/, "").gsub(" ", " ")
def organize_it()
path = Path[Config.music_directory].expand(home: true)
Pattern.parse(Config.directory_pattern, @metadata.as(JSON::Any)).split('/').each do |dir|
path = path / dir.gsub(/[\/]/, "").gsub(" ", " ")
end
strpath = path.to_s
if !File.directory?(strpath)
FileUtils.mkdir_p(strpath)