Skip to content

Commit

Permalink
Overhaul File naming System (#21)
Browse files Browse the repository at this point in the history
* Overhaul File naming System to support more tokens and be more easily extended in the future

* Fix  bug when downloading tracks with a large name causing multiple lines to print. 

* Fix Misc issues

* Update Readme
  • Loading branch information
MinisculeGirraffe authored Aug 22, 2022
1 parent 668d4c8 commit a3b4088
Show file tree
Hide file tree
Showing 13 changed files with 429 additions and 133 deletions.
58 changes: 57 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "tdl"
description = "A command line tool for downloading files from the TIDAL API"
version = "0.2.5"
version = "0.3.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down Expand Up @@ -35,12 +35,12 @@ log = "0.4.17"
env_logger = "0.9.0"
shellexpand = "2.1.0"
futures = "0.3.21"
indicatif = "0.17.0"
indicatif = {version = "0.17.0", features = ["improved_unicode"]}
console = "0.15.0"
tabled = "0.8.0"
sanitize-filename = "0.4.0"
http-cache-reqwest = "0.5.0"

phf = { version = "0.11", features = ["macros"] }

[dependencies.serde_with]
version = "2.0.0"
Expand Down
106 changes: 73 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,39 +51,79 @@ tdl autocomplete -s zsh > $FPATH/tdl.zsh

Configs are stored in `~/.config/tdl/config.toml`, and will auto-generate with the default settings when the executable is ran.

### download_path

`download_path` will expand env variables along with shell accelerators such as `~`.

In addition to specify the format to save tracks in, you can use the following tokens:

- Artist:
- `{artist}`
- Artist Name
- `{artist_id}`
- Unique ID from the Tidal API
- Album:
- `{album}`
- Album Title
- `{album_id}`
- Unique ID from the Tidal API:
- `{album_release}`
- Full YYYY-MM-DD of relase
- `{album_release_year}`
- YYYY date of album release

- Track:
- `{track_num}`
- `{track_name}`
- `{track_id}`
- `{quality}`
- String literal of audio_quality

Example Values:

- `$HOME/Music/{artist}/{album} [{album_id}] [{album_release_year}]/{track_num} - {track_name}`

- `$MUSIC_DIR/{artist} - [{artist_id}]/{album}/{track_name}`
### download_paths

The `download_paths` section in config is used to decide where files will be placed in the file system.



`base_path` will expand env variables along with shell accelerators such as `~`. This is the parent folder all files will be placed under.

Each of the following keys will create a nested folder structure in the following template:
`{base_path}/{artist}/{album}/{track}`


Examples:

``` toml
[download_paths]
base_path = '$HOME/Music'
artist = '{artist_name}'
album = '{album_name} [{album_id}] [{album_release_year}]'
track = '{track_num} - {track_name} - {track_volume}'
```
Resulting Naming path:
`/Users/username/Music/100 gecs/1000 gecs [129835816] [2019]/1 - 745 sticky - 1.flac`

You can also specify any token under any key so long as it's not a child. A track will be able to use any key from the album or artist. However an album won't be able to use a track key.

Keys can also be left blank to skip folder creation.

``` toml
[download_paths]
base_path = '$HOME/Music'
artist = ''
album = '{artist_name} - {album_name} [{album_id}] [{album_release_year}]'
track = '[{track_num}] - {artist_name} - {track_name} - {track_volume}'
```

Resulting Naming path:
`/Users/username/Music/100 gecs - 1000 gecs [129835816] [2019]/[1] - 100 gecs - 745 sticky - 1.flac`

Available Keys:

Artist:

|Token | Description | Example |
| ----|-----|--|
| `{artist_name}`| Artist Name| 100 Gecs
| `{artist_id}` | Unique ID from Tidal | 10828611

Album:
|Token | Description | Example |
| ----|-----|--|
| `{album_name}`| Album Title | 1000 Gecs |
| `{album_id}` | Unique ID from Tidal | 192059802 |
| `{album_duration}` | Duration in seconds of Album |3000 |
| `{album_tracks}` | Number of tracks in Album | 17
| `{album_explicit}`| Shortcode if album is explicit, empty if false | E |
| `{album_quality}` | String literal of `audio_quality` | HI_RES
| `{album_release}`| YYYY-MM-DD string of album release date | 2020-07-05 |
|`{album_release_year}` | YYYY string of album release | 2020

Track:

|Token | Description | Example |
| ----|-----|--|
| `{track_id}` | Unique ID from Tidal | 129835817
| `{track_name}` | Name of Track | 745 Sticky
| `{track_duration}` | Track Duration in Seconds | 120
| `{track_num}` | Number track appears on album | 7
| `{track_volume}` | Volume number of track, if album includes multiple discs | 1
| `{track_isrc}` | International Standard Recording Code of track | DEZ750500205
| `{track_explicit}` | Shortcode if album is explicit, empty if false | E
| `{track_quality}` | String literal of `audio_quality` | HI_RES


### audio_quality

Expand Down
2 changes: 1 addition & 1 deletion src/api/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ impl AuthClient {
.await?;
if !req.status().is_success() {
if req.status().is_client_error() {
return Err(Error::msg(req.status().canonical_reason().unwrap()));
return Err(Error::msg(req.status().canonical_reason().unwrap_or("")));
} else {
return Err(Error::msg("Failed to check auth status"));
}
Expand Down
8 changes: 6 additions & 2 deletions src/api/media.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ impl MediaClient {
self.get::<Album>(&url, None).await
}

pub async fn get_artist(&self, id: &str) -> Result<Artist, Error> {
let url = format!("https://api.tidal.com/v1/artists/{id}");
self.get::<Artist>(&url, None).await
}
pub async fn get_stream_url(&self, id: usize) -> Result<PlaybackManifest, Error> {
let url = format!("{}/tracks/{}/playbackinfopostpaywall", &self.api_base, id);
let query = &[
Expand All @@ -54,8 +58,8 @@ impl MediaClient {
}
}

pub async fn get_album_items(&self, id: &str) -> Result<Vec<Album>, Error> {
let url = format!("https://api.tidal.com/v1/artists/{}/albums", id);
pub async fn get_artist_albums(&self, id: &str) -> Result<Vec<Album>, Error> {
let url = format!("https://api.tidal.com/v1/artists/{id}/albums");
let mut albums: Vec<Album> = Vec::new();
let album_req = self.get_items::<Album>(&url, None, None);
if self.include_singles {
Expand Down
10 changes: 8 additions & 2 deletions src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,15 @@ impl ApiClient {
Arc::new(Self {
country_code: (
String::from("countryCode"),
config.login_key.country_code.unwrap(),
config
.login_key
.country_code
.expect("Country code is not set in config"),
),
access_token: config.login_key.access_token.unwrap(),
access_token: config
.login_key
.access_token
.expect("Access Token is not present in config"),
http_client: build_middleware_client(config.cache_dir),
include_singles: config.include_singles,
api_base: String::from("https://api.tidalhifi.com/v1"),
Expand Down
4 changes: 2 additions & 2 deletions src/api/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,8 @@ pub struct PlaybackManifest {
impl PlaybackManifest {
pub fn get_file_extension(&self) -> Option<&str> {
match self.mime_type.as_str() {
"audio/mp4" => Some(".m4a"),
"audio/flac" => Some(".flac"),
"audio/mp4" => Some("m4a"),
"audio/flac" => Some("flac"),
_ => None,
}
}
Expand Down
Loading

0 comments on commit a3b4088

Please sign in to comment.