mirror of
https://github.com/fiso64/slsk-batchdl.git
synced 2024-12-31 18:52:41 +00:00
big commit
This commit is contained in:
parent
027d460d7a
commit
8850478aaa
4 changed files with 1358 additions and 613 deletions
130
README.md
130
README.md
|
@ -25,18 +25,23 @@ Playlists are retrieved using the YoutubeExplode library which unfortunately doe
|
||||||
slsk-batchdl "title=MC MENTAL @ HIS BEST,length=242" --pref-format "flac,wav"
|
slsk-batchdl "title=MC MENTAL @ HIS BEST,length=242" --pref-format "flac,wav"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Interactive album download:
|
||||||
|
```
|
||||||
|
slsk-batchdl "album=Some Album" --interactive
|
||||||
|
```
|
||||||
|
|
||||||
#### See which songs by an artist are missing in your library:
|
#### See which songs by an artist are missing in your library:
|
||||||
```
|
```
|
||||||
slsk-batchdl "artist=MC MENTAL" --aggregate --print tracks-full --skip-existing --music-dir "path\to\music"
|
slsk-batchdl "artist=MC MENTAL" --aggregate --print tracks-full --skip-existing --music-dir "path\to\music"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Options:
|
### Options
|
||||||
```
|
```
|
||||||
Usage: slsk-batchdl <input> [OPTIONS]
|
Usage: slsk-batchdl <input> [OPTIONS]
|
||||||
|
|
||||||
<input> <input> is one of the following:
|
<input> <input> is one of the following:
|
||||||
|
|
||||||
Spotify playlist url or "spotify-likes": Download a spotify
|
Spotify playlist url or 'spotify-likes': Download a spotify
|
||||||
playlist or your liked songs. --spotify-id and
|
playlist or your liked songs. --spotify-id and
|
||||||
--spotify-secret may be required in addition.
|
--spotify-secret may be required in addition.
|
||||||
|
|
||||||
|
@ -50,13 +55,29 @@ Usage: slsk-batchdl <input> [OPTIONS]
|
||||||
|
|
||||||
Name of the track, album, or artist to search for:
|
Name of the track, album, or artist to search for:
|
||||||
Can either be any typical search string or a comma-separated
|
Can either be any typical search string or a comma-separated
|
||||||
list like "title=Song Name,artist=Artist Name,length=215"
|
list like 'title=Song Name,artist=Artist Name,length=215'
|
||||||
Allowed properties are: title, artist, album, length (sec)
|
Allowed properties are: title, artist, album, length (sec)
|
||||||
|
Specify artist and album only to download an album.
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
--user <username> Soulseek username
|
--user <username> Soulseek username
|
||||||
--pass <password> Soulseek password
|
--pass <password> Soulseek password
|
||||||
|
|
||||||
|
-p --path <path> Download folder
|
||||||
|
-f --folder <name> Subfolder name. Set to '.' to output directly to the
|
||||||
|
download folder (default: playlist/csv name)
|
||||||
|
-n --number <maxtracks> Download the first n tracks of a playlist
|
||||||
|
-o --offset <offset> Skip a specified number of tracks
|
||||||
|
-r --reverse Download tracks in reverse order
|
||||||
|
--remove-from-playlist Remove downloaded tracks from playlist (spotify only)
|
||||||
|
--name-format <format> Name format for downloaded tracks, e.g "{artist} - {title}"
|
||||||
|
--fast-search Begin downloading as soon as a file satisfying the preferred
|
||||||
|
conditions is found. Increases chance to download bad files.
|
||||||
|
--m3u <option> Create an m3u8 playlist file
|
||||||
|
'none': Do not create a playlist file
|
||||||
|
'fails' (default): Write only failed downloads to the m3u
|
||||||
|
'all': Write successes + fails as comments
|
||||||
|
|
||||||
--spotify-id <id> spotify client ID
|
--spotify-id <id> spotify client ID
|
||||||
--spotify-secret <secret> spotify client secret
|
--spotify-secret <secret> spotify client secret
|
||||||
|
|
||||||
|
@ -70,26 +91,6 @@ Options:
|
||||||
channel names; attempt to parse them into title and artist
|
channel names; attempt to parse them into title and artist
|
||||||
names.
|
names.
|
||||||
|
|
||||||
-a --aggregate When input is a string: Instead of downloading a single
|
|
||||||
track matching the search string, find and download all
|
|
||||||
distinct songs associated with the provided artist, album,
|
|
||||||
or track title. Input string must be a list of properties.
|
|
||||||
--min-users-aggregate <num> Minimum number of users sharing a track before it is
|
|
||||||
downloaded in aggregate mode. Setting it to higher values
|
|
||||||
will significantly reduce false positives, but may introduce
|
|
||||||
false negatives. Default: 2
|
|
||||||
--relax Slightly relax file filtering in aggregate mode to include
|
|
||||||
more results
|
|
||||||
|
|
||||||
-p --path <path> Download folder
|
|
||||||
-f --folder <name> Subfolder name (default: playlist/csv name)
|
|
||||||
-n --number <maxtracks> Download the first n tracks of a playlist
|
|
||||||
-o --offset <offset> Skip a specified number of tracks
|
|
||||||
-r --reverse Download tracks in reverse order
|
|
||||||
--remove-from-playlist Remove downloaded tracks from playlist (spotify only)
|
|
||||||
--name-format <format> Name format for downloaded tracks, e.g "{artist} - {title}"
|
|
||||||
--m3u Create an m3u8 playlist file
|
|
||||||
|
|
||||||
--format <format> Accepted file format(s), comma-separated
|
--format <format> Accepted file format(s), comma-separated
|
||||||
--length-tol <sec> Length tolerance in seconds (default: 3)
|
--length-tol <sec> Length tolerance in seconds (default: 3)
|
||||||
--min-bitrate <rate> Minimum file bitrate
|
--min-bitrate <rate> Minimum file bitrate
|
||||||
|
@ -107,35 +108,63 @@ Options:
|
||||||
--pref-strict-artist Prefer download if filepath contains track artist
|
--pref-strict-artist Prefer download if filepath contains track artist
|
||||||
--pref-banned-users <list> Comma-separated list of users to deprioritize
|
--pref-banned-users <list> Comma-separated list of users to deprioritize
|
||||||
|
|
||||||
|
-a --aggregate When input is a string: Instead of downloading a single
|
||||||
|
track matching the search string, find and download all
|
||||||
|
distinct songs associated with the provided artist or track
|
||||||
|
title. The input string must be a list of properties.
|
||||||
|
--min-users-aggregate <num> Minimum number of users sharing a track before it is
|
||||||
|
downloaded in aggregate mode. Setting it to higher values
|
||||||
|
will significantly reduce false positives, but may introduce
|
||||||
|
false negatives. Default: 2
|
||||||
|
--relax Slightly relax file filtering in aggregate mode to include
|
||||||
|
more results
|
||||||
|
|
||||||
|
--interactive When downloading albums: Allows to select the wanted album
|
||||||
|
--album-track-count <num> Specify the exact number of tracks in the album. Folders
|
||||||
|
with a different number of tracks will be ignored. Append
|
||||||
|
a '+' or '-' to the number for the inequalities >= and <=.
|
||||||
|
--album-ignore-fails When downloading an album and one of the files fails, do not
|
||||||
|
skip to the next source and do not delete all successfully
|
||||||
|
downloaded files
|
||||||
|
--album-art <option> When downloading albums, optionally retrieve album images
|
||||||
|
from another location:
|
||||||
|
'default': Download from the same folder as the music
|
||||||
|
'largest': Download from the folder with the largest image
|
||||||
|
'most': Download from the folder containing the most images
|
||||||
|
|
||||||
-s --skip-existing Skip if a track matching file conditions is found in the
|
-s --skip-existing Skip if a track matching file conditions is found in the
|
||||||
output folder or your music library (if provided)
|
output folder or your music library (if provided)
|
||||||
--skip-mode <mode> name: Use only filenames to check if a track exists
|
--skip-mode <mode> 'name': Use only filenames to check if a track exists
|
||||||
name-precise (default): Use filenames and check conditions
|
'name-precise' (default): Use filenames and check conditions
|
||||||
tag: Use file tags (slower)
|
'tag': Use file tags (slower)
|
||||||
tag-precise: Use file tags and check file conditions
|
'tag-precise': Use file tags and check file conditions
|
||||||
--music-dir <path> Specify to skip downloading tracks found in a music library
|
--music-dir <path> Specify to skip downloading tracks found in a music library
|
||||||
Use with --skip-existing
|
Use with --skip-existing
|
||||||
--skip-not-found Skip searching for tracks that weren't found on Soulseek
|
--skip-not-found Skip searching for tracks that weren't found on Soulseek
|
||||||
during the last run.
|
during the last run. Fails are read from the m3u file.
|
||||||
--remove-ft Remove "ft." or "feat." and everything after from the
|
|
||||||
track names before searching
|
--no-remove-special-chars Do not remove special characters before searching
|
||||||
--remove-regex <regex> Remove a regex from all track titles and artist names
|
--remove-ft Remove 'feat.' and everything after before searching
|
||||||
--no-artist-search Perform an additional search without artist name if nothing
|
--remove-brackets Remove square brackets and their contents before searching
|
||||||
was found. Useful for sources such as youtube or soundcloud
|
--regex <regex> Remove a regexp from all track titles and artist names.
|
||||||
where the "artist" could just be an uploader.
|
Optionally specify the replacement regex after a semicolon
|
||||||
--artist-search Also try to find track by searching for the artist only
|
--artist-maybe-wrong Performs an additional search without the artist name.
|
||||||
--no-diacr-search Also perform a search without diacritics
|
Useful for sources like SoundCloud where the "artist"
|
||||||
--no-regex-search <regex> Also perform a search without a regex pattern
|
could just be an uploader. Note that when downloading a
|
||||||
|
YouTube playlist via url, this option is set automatically
|
||||||
|
on a per track basis, so it is best kept off in that case.
|
||||||
|
-d --desperate Tries harder to find the desired track by searching for the
|
||||||
|
artist/album/title only, then filtering the results.
|
||||||
--yt-dlp Use yt-dlp to download tracks that weren't found on
|
--yt-dlp Use yt-dlp to download tracks that weren't found on
|
||||||
Soulseek. yt-dlp must be available from the command line.
|
Soulseek. yt-dlp must be available from the command line.
|
||||||
|
|
||||||
--config <path> Manually specify config file location
|
--config <path> Manually specify config file location
|
||||||
--search-timeout <ms> Max search time in ms (default: 6000)
|
--search-timeout <ms> Max search time in ms (default: 5000)
|
||||||
--max-stale-time <ms> Max download time without progress in ms (default: 50000)
|
--max-stale-time <ms> Max download time without progress in ms (default: 50000)
|
||||||
--concurrent-downloads <num> Max concurrent downloads (default: 2)
|
--concurrent-downloads <num> Max concurrent downloads (default: 2)
|
||||||
--searches-per-time <num> Max searches per time interval. Higher values may cause
|
--searches-per-time <num> Max searches per time interval. Higher values may cause
|
||||||
30-minute bans. (default: 34)
|
30-minute bans. (default: 34)
|
||||||
--searches-time <sec> Controls how often available searches are replenished.
|
--searches-renew-time <sec> Controls how often available searches are replenished.
|
||||||
Lower values may cause 30-minute bans. (default: 220)
|
Lower values may cause 30-minute bans. (default: 220)
|
||||||
--display <option> Changes how searches and downloads are displayed:
|
--display <option> Changes how searches and downloads are displayed:
|
||||||
single (default): Show transfer state and percentage
|
single (default): Show transfer state and percentage
|
||||||
|
@ -144,23 +173,32 @@ Options:
|
||||||
--listen-port <port> Port for incoming connections (default: 50000)
|
--listen-port <port> Port for incoming connections (default: 50000)
|
||||||
|
|
||||||
--print <option> Print tracks or search results instead of downloading:
|
--print <option> Print tracks or search results instead of downloading:
|
||||||
tracks: Print all tracks to be downloaded
|
'tracks': Print all tracks to be downloaded
|
||||||
tracks-full: Print extended information about all tracks
|
'tracks-full': Print extended information about all tracks
|
||||||
results: Print search results satisfying file conditions
|
'results': Print search results satisfying file conditions
|
||||||
results-full: Print search results including full paths
|
'results-full': Print search results including full paths
|
||||||
```
|
```
|
||||||
Files not satisfying the conditions will not be downloaded. For example, `--length-tol` is set to 3 by default, meaning that files whose duration differs from the supplied duration by more than 3 seconds will not be downloaded (disable it by setting it to 99999).
|
Files not satisfying the conditions will not be downloaded. For example, `--length-tol` is set to 3 by default, meaning that files whose duration differs from the supplied duration by more than 3 seconds will not be downloaded (disable it by setting it to 99999).
|
||||||
Files satisfying `pref-` conditions will be preferred. For example, setting `--pref-format "flac,wav"` will make it download high quality files if they exist and only download low quality files if there's nothing else.
|
Files satisfying `pref-` conditions will be preferred. For example, setting `--pref-format "flac,wav"` will make it download high quality files if they exist and only download low quality files if there's nothing else.
|
||||||
|
|
||||||
Configuration files: Create a file named `slsk-batchdl.conf` in the same directory as the executable and write your arguments there, e.g:
|
#### Name format:
|
||||||
|
Available tags are: artist, artists, album_artist, album_artists, title, album, year, track, disc, filename, default_foldername. Name format supports subdirectories as well as conditional expressions: `{str1|str2}` – If any tags in str1 are null, choose str2. String literals enclosed in parentheses are ignored in the null check.
|
||||||
|
```
|
||||||
|
{artist( - )title|album_artist( - )title|filename}
|
||||||
|
{album(/)}{track(. )}{artist|(unknown artist)} - {title|(unknown title)}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration files
|
||||||
|
Create a file named `slsk-batchdl.conf` in the same directory as the executable and write your arguments there, e.g:
|
||||||
```
|
```
|
||||||
--username "fakename"
|
--username "fakename"
|
||||||
--password "fakepass"
|
--password "fakepass"
|
||||||
--pref-format "flac"
|
--pref-format "flac"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Notes:
|
### Notes
|
||||||
- For Mac you can use publish.sh to build the app.
|
- For Mac you can use publish.sh to build the app.
|
||||||
- The CSV file must use `"` as string delimiter and be encoded with UTF8.
|
- The CSV file must use `"` as string delimiter and be encoded with UTF8.
|
||||||
- `--display single` and especially `double` can cause the printed lines to be duplicated or overwritten on some configurations. Use `simple` if that's an issue.
|
- `--display single` and especially `double` can cause the printed lines to be duplicated or overwritten on some configurations. Use `simple` if that's an issue.
|
||||||
- The server will ban you for 30 minutes if too many searches are performed within a short timespan. Adjust `--searches-per-time` and `--searches-time` in case it happens. By default it's configured to allow up to 34 searches every 220 seconds. These values were determined through experimentation as unfortunately I couldn't find any information regarding soulseek's rate limits, so they may be incorrect. You can also use `--random-login` to re-login with a random username and password automatically.
|
- The server will ban you for 30 minutes if too many searches are performed within a short timespan. Adjust `--searches-per-time` and `--searches-renew-time` in case it happens. By default it's configured to allow up to 34 searches every 220 seconds. These values were determined through experimentation as unfortunately I couldn't find any information regarding soulseek's rate limits, so they may be incorrect. You can also use `--random-login` to re-login with a random username and password automatically.
|
||||||
|
- An issue I've not been able to resolve is audio files not appearing in the search results, even though they exist in the shown folders. This happens in soulseek clients as well; search for "AD PIANO IV Monochrome". You will find a few users whose folders only contain non-audio files. However, when you browse their shares, you can see that they do have audio in those exact folders. If you know why this is happening, please open an issue.
|
File diff suppressed because it is too large
Load diff
|
@ -433,4 +433,70 @@ public static class YouTube
|
||||||
return (getItem(titlePatterns), getItem(usernamePatterns), duration);
|
return (getItem(titlePatterns), getItem(usernamePatterns), duration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task<List<(int length, string id, string title)>> YtdlpSearch(Track track)
|
||||||
|
{
|
||||||
|
Process process = new Process();
|
||||||
|
ProcessStartInfo startInfo = new ProcessStartInfo();
|
||||||
|
|
||||||
|
startInfo.FileName = "yt-dlp";
|
||||||
|
string search = track.ArtistName != "" ? $"{track.ArtistName} - {track.TrackTitle}" : track.TrackTitle;
|
||||||
|
startInfo.Arguments = $"\"ytsearch3:{search}\" --print \"%(duration>%s)s === %(id)s === %(title)s\"";
|
||||||
|
|
||||||
|
startInfo.RedirectStandardOutput = true;
|
||||||
|
startInfo.RedirectStandardError = true;
|
||||||
|
startInfo.UseShellExecute = false;
|
||||||
|
process.StartInfo = startInfo;
|
||||||
|
process.OutputDataReceived += (sender, e) => { Console.WriteLine(e.Data); };
|
||||||
|
process.ErrorDataReceived += (sender, e) => { Console.WriteLine(e.Data); };
|
||||||
|
|
||||||
|
process.Start();
|
||||||
|
|
||||||
|
List<(int, string, string)> results = new List<(int, string, string)>();
|
||||||
|
string output;
|
||||||
|
Regex regex = new Regex(@"^(\d+) === ([\w-]+) === (.+)$");
|
||||||
|
while ((output = process.StandardOutput.ReadLine()) != null)
|
||||||
|
{
|
||||||
|
Match match = regex.Match(output);
|
||||||
|
if (match.Success)
|
||||||
|
{
|
||||||
|
int seconds = int.Parse(match.Groups[1].Value);
|
||||||
|
string id = match.Groups[2].Value;
|
||||||
|
string title = match.Groups[3].Value;
|
||||||
|
results.Add((seconds, id, title));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
process.WaitForExit();
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<string> YtdlpDownload(string id, string savePathNoExt)
|
||||||
|
{
|
||||||
|
Process process = new Process();
|
||||||
|
ProcessStartInfo startInfo = new ProcessStartInfo();
|
||||||
|
|
||||||
|
startInfo.FileName = "yt-dlp";
|
||||||
|
startInfo.Arguments = $"\"{id}\" -f bestaudio/best -ci -o \"{savePathNoExt}.%(ext)s\" -x";
|
||||||
|
|
||||||
|
startInfo.RedirectStandardOutput = true;
|
||||||
|
startInfo.RedirectStandardError = true;
|
||||||
|
startInfo.UseShellExecute = false;
|
||||||
|
process.StartInfo = startInfo;
|
||||||
|
process.OutputDataReceived += (sender, e) => { Console.WriteLine(e.Data); };
|
||||||
|
process.ErrorDataReceived += (sender, e) => { Console.WriteLine(e.Data); };
|
||||||
|
|
||||||
|
process.Start();
|
||||||
|
process.WaitForExit();
|
||||||
|
|
||||||
|
string[] files = Directory.GetFiles(Path.GetDirectoryName(savePathNoExt), Path.GetFileName(savePathNoExt + ".ext") + ".*");
|
||||||
|
|
||||||
|
foreach (string file in files)
|
||||||
|
{
|
||||||
|
if (Utils.IsMusicFile(file))
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,11 +21,11 @@
|
||||||
<PackageReference Include="Goblinfactory.ProgressBar" Version="1.0.0" />
|
<PackageReference Include="Goblinfactory.ProgressBar" Version="1.0.0" />
|
||||||
<PackageReference Include="Google.Apis.YouTube.v3" Version="1.63.0.3205" />
|
<PackageReference Include="Google.Apis.YouTube.v3" Version="1.63.0.3205" />
|
||||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.54" />
|
<PackageReference Include="HtmlAgilityPack" Version="1.11.54" />
|
||||||
<PackageReference Include="Soulseek" Version="6.2.0" />
|
<PackageReference Include="Soulseek" Version="6.4.1" />
|
||||||
<PackageReference Include="SpotifyAPI.Web" Version="7.0.2" />
|
<PackageReference Include="SpotifyAPI.Web" Version="7.0.2" />
|
||||||
<PackageReference Include="SpotifyAPI.Web.Auth" Version="7.0.2" />
|
<PackageReference Include="SpotifyAPI.Web.Auth" Version="7.0.2" />
|
||||||
<PackageReference Include="TagLibSharp" Version="2.3.0" />
|
<PackageReference Include="TagLibSharp" Version="2.3.0" />
|
||||||
<PackageReference Include="YoutubeExplode" Version="6.3.10" />
|
<PackageReference Include="YoutubeExplode" Version="6.3.13" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
Loading…
Reference in a new issue