mirror of
https://github.com/fiso64/slsk-batchdl.git
synced 2024-12-22 22:42:41 +00:00
commit
This commit is contained in:
parent
93fb18f221
commit
b0fc22364d
3 changed files with 71 additions and 36 deletions
|
@ -197,6 +197,7 @@ Options:
|
||||||
'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
|
||||||
|
'm3u': Skip all tracks that don't have a fail entry in m3u
|
||||||
--music-dir <path> Specify to also skip downloading tracks found in a music
|
--music-dir <path> Specify to also skip downloading tracks found in a music
|
||||||
library. Use with --skip-existing
|
library. 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
|
||||||
|
|
|
@ -96,7 +96,6 @@ static class Program
|
||||||
static string timeUnit = "s";
|
static string timeUnit = "s";
|
||||||
static string displayStyle = "single";
|
static string displayStyle = "single";
|
||||||
static string input = "";
|
static string input = "";
|
||||||
static bool preciseSkip = true;
|
|
||||||
static string nameFormat = "";
|
static string nameFormat = "";
|
||||||
static string invalidReplaceStr = " ";
|
static string invalidReplaceStr = " ";
|
||||||
static bool skipNotFound = false;
|
static bool skipNotFound = false;
|
||||||
|
@ -114,7 +113,6 @@ static class Program
|
||||||
static string ytdlpArgument = "";
|
static string ytdlpArgument = "";
|
||||||
static bool skipExisting = false;
|
static bool skipExisting = false;
|
||||||
static string m3uOption = "fails";
|
static string m3uOption = "fails";
|
||||||
static bool useTagsCheckExisting = false;
|
|
||||||
static bool removeTracksFromSource = false;
|
static bool removeTracksFromSource = false;
|
||||||
static bool getDeleted = false;
|
static bool getDeleted = false;
|
||||||
static bool deletedOnly = false;
|
static bool deletedOnly = false;
|
||||||
|
@ -168,6 +166,17 @@ static class Program
|
||||||
CSV
|
CSV
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static SkipMode skipMode = SkipMode.NamePrecise;
|
||||||
|
|
||||||
|
public enum SkipMode
|
||||||
|
{
|
||||||
|
Name,
|
||||||
|
NamePrecise,
|
||||||
|
Tag,
|
||||||
|
TagPrecise,
|
||||||
|
M3u,
|
||||||
|
};
|
||||||
|
|
||||||
static void PrintHelp()
|
static void PrintHelp()
|
||||||
{
|
{
|
||||||
Console.WriteLine("Usage: sldl <input> [OPTIONS]" +
|
Console.WriteLine("Usage: sldl <input> [OPTIONS]" +
|
||||||
|
@ -280,6 +289,7 @@ static class Program
|
||||||
"\n 'name-precise' (default): Use filenames and check conditions" +
|
"\n 'name-precise' (default): Use filenames and check conditions" +
|
||||||
"\n 'tag': Use file tags (slower)" +
|
"\n 'tag': Use file tags (slower)" +
|
||||||
"\n 'tag-precise': Use file tags and check file conditions" +
|
"\n 'tag-precise': Use file tags and check file conditions" +
|
||||||
|
"\n 'm3u': Skip all tracks that don't have a fail entry in m3u" +
|
||||||
"\n --music-dir <path> Specify to also skip downloading tracks found in a music" +
|
"\n --music-dir <path> Specify to also skip downloading tracks found in a music" +
|
||||||
"\n library. Use with --skip-existing" +
|
"\n library. Use with --skip-existing" +
|
||||||
"\n --skip-not-found Skip searching for tracks that weren't found on Soulseek" +
|
"\n --skip-not-found Skip searching for tracks that weren't found on Soulseek" +
|
||||||
|
@ -706,7 +716,7 @@ static class Program
|
||||||
albumArtOption = "";
|
albumArtOption = "";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentException($"Invalid album art download mode \'{args[i]}\'");
|
throw new ArgumentException($"Invalid album art download mode '{args[i]}'");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "--aao":
|
case "--aao":
|
||||||
|
@ -852,11 +862,6 @@ static class Program
|
||||||
case "--no-modify-share-count":
|
case "--no-modify-share-count":
|
||||||
noModifyShareCount = true;
|
noModifyShareCount = true;
|
||||||
break;
|
break;
|
||||||
case "--seut":
|
|
||||||
case "--skip-existing-use-tags":
|
|
||||||
skipExisting = true;
|
|
||||||
useTagsCheckExisting = true;
|
|
||||||
break;
|
|
||||||
case "-d":
|
case "-d":
|
||||||
case "--desperate":
|
case "--desperate":
|
||||||
desperateSearch = true;
|
desperateSearch = true;
|
||||||
|
@ -872,23 +877,20 @@ static class Program
|
||||||
displayStyle = args[i];
|
displayStyle = args[i];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentException($"Invalid display style \"{args[i]}\"");
|
throw new ArgumentException($"Invalid display style '{args[i]}'");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "--sm":
|
case "--sm":
|
||||||
case "--skip-mode":
|
case "--skip-mode":
|
||||||
switch (args[++i])
|
skipMode = args[++i].ToLower().Trim() switch
|
||||||
{
|
{
|
||||||
case "name":
|
"name" => SkipMode.Name,
|
||||||
case "name-precise":
|
"name-precise" => SkipMode.NamePrecise,
|
||||||
case "tag":
|
"tag" => SkipMode.Tag,
|
||||||
case "tag-precise":
|
"tag-precise" => SkipMode.TagPrecise,
|
||||||
useTagsCheckExisting = args[i].Contains("tag");
|
"m3u" => SkipMode.M3u,
|
||||||
preciseSkip = args[i].Contains("-precise");
|
_ => throw new ArgumentException($"Invalid skip mode '{args[i]}'"),
|
||||||
break;
|
};
|
||||||
default:
|
|
||||||
throw new ArgumentException($"Invalid skip mode \'{args[i]}\'");
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case "--nrsc":
|
case "--nrsc":
|
||||||
case "--no-remove-special-chars":
|
case "--no-remove-special-chars":
|
||||||
|
@ -1497,19 +1499,27 @@ static class Program
|
||||||
static List<Track> DoSkipExisting(List<Track> tracks, bool print, bool useCache)
|
static List<Track> DoSkipExisting(List<Track> tracks, bool print, bool useCache)
|
||||||
{
|
{
|
||||||
var existing = new Dictionary<Track, string>();
|
var existing = new Dictionary<Track, string>();
|
||||||
|
|
||||||
|
if (skipMode == SkipMode.M3u)
|
||||||
|
{
|
||||||
|
existing = SkipExistingM3u(tracks);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (!(musicDir != "" && outputFolder.StartsWith(musicDir, StringComparison.OrdinalIgnoreCase)) && System.IO.Directory.Exists(outputFolder))
|
if (!(musicDir != "" && outputFolder.StartsWith(musicDir, StringComparison.OrdinalIgnoreCase)) && System.IO.Directory.Exists(outputFolder))
|
||||||
{
|
{
|
||||||
var d = SkipExisting(tracks, outputFolder, necessaryCond, useTagsCheckExisting, preciseSkip, useCache);
|
var d = SkipExisting(tracks, outputFolder, necessaryCond, skipMode, useCache);
|
||||||
d.ToList().ForEach(x => existing.TryAdd(x.Key, x.Value));
|
d.ToList().ForEach(x => existing.TryAdd(x.Key, x.Value));
|
||||||
}
|
}
|
||||||
if (musicDir != "" && System.IO.Directory.Exists(musicDir))
|
if (musicDir != "" && System.IO.Directory.Exists(musicDir))
|
||||||
{
|
{
|
||||||
if (print) Console.WriteLine($"Checking if tracks exist in library..");
|
if (print) Console.WriteLine($"Checking if tracks exist in library..");
|
||||||
var d = SkipExisting(tracks, musicDir, necessaryCond, useTagsCheckExisting, preciseSkip, useCache);
|
var d = SkipExisting(tracks, musicDir, necessaryCond, skipMode, useCache);
|
||||||
d.ToList().ForEach(x => existing.TryAdd(x.Key, x.Value));
|
d.ToList().ForEach(x => existing.TryAdd(x.Key, x.Value));
|
||||||
}
|
}
|
||||||
else if (musicDir != "" && !System.IO.Directory.Exists(musicDir))
|
else if (musicDir != "" && !System.IO.Directory.Exists(musicDir))
|
||||||
if (print) Console.WriteLine($"Musid dir does not exist: {musicDir}");
|
if (print) Console.WriteLine($"Music dir does not exist: {musicDir}");
|
||||||
|
}
|
||||||
|
|
||||||
return existing.Select(x => x.Key).ToList();
|
return existing.Select(x => x.Key).ToList();
|
||||||
}
|
}
|
||||||
|
@ -3950,11 +3960,13 @@ static class Program
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Dictionary<Track, string> SkipExisting(List<Track> tracks, string dir, FileConditions necessaryCond, bool useTags, bool precise, bool useCache)
|
static Dictionary<Track, string> SkipExisting(List<Track> tracks, string dir, FileConditions necessaryCond, SkipMode mode, bool useCache)
|
||||||
{
|
{
|
||||||
var existing = new Dictionary<Track, string>();
|
var existing = new Dictionary<Track, string>();
|
||||||
List<string> musicFiles;
|
List<string> musicFiles;
|
||||||
List<TagLib.File> musicIndex;
|
List<TagLib.File> musicIndex;
|
||||||
|
bool useTags = mode == SkipMode.Tag || mode == SkipMode.TagPrecise;
|
||||||
|
bool precise = mode == SkipMode.NamePrecise || mode == SkipMode.TagPrecise;
|
||||||
|
|
||||||
if (useCache && MusicCache.TryGetValue(dir, out var cached))
|
if (useCache && MusicCache.TryGetValue(dir, out var cached))
|
||||||
{
|
{
|
||||||
|
@ -3991,6 +4003,22 @@ static class Program
|
||||||
return existing;
|
return existing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Dictionary<Track, string> SkipExistingM3u(List<Track> tracks)
|
||||||
|
{
|
||||||
|
var existing = new Dictionary<Track, string>();
|
||||||
|
|
||||||
|
for (int i = 0; i < tracks.Count; i++)
|
||||||
|
{
|
||||||
|
if (!m3uEditor.HasFail(tracks[i], out _))
|
||||||
|
{
|
||||||
|
existing.TryAdd(tracks[i], "");
|
||||||
|
tracks[i] = new Track(tracks[i]) { TrackState = Track.State.Exists, DownloadPath = "" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
static List<TagLib.File> BuildMusicIndex(List<string> musicFiles)
|
static List<TagLib.File> BuildMusicIndex(List<string> musicFiles)
|
||||||
{
|
{
|
||||||
var musicIndex = new List<TagLib.File>();
|
var musicIndex = new List<TagLib.File>();
|
||||||
|
@ -4761,18 +4789,18 @@ public class M3UEditor
|
||||||
this.offset = offset;
|
this.offset = offset;
|
||||||
this.option = option;
|
this.option = option;
|
||||||
path = Path.GetFullPath(m3uPath);
|
path = Path.GetFullPath(m3uPath);
|
||||||
m3uListLabels = false;/*trackLists.lists.Any(x => x.type != TrackLists.ListType.Normal);*/
|
|
||||||
fails = ReadAllLines()
|
var lines = ReadAllLines();
|
||||||
.Where(x => x.StartsWith("# Failed: "))
|
fails = lines.Where(x => x.StartsWith("# Failed: "))
|
||||||
.Select(line =>
|
.Select(line =>
|
||||||
{
|
{
|
||||||
var lastBracketIndex = line.LastIndexOf('[');
|
var lastBracketIndex = line.LastIndexOf('[');
|
||||||
lastBracketIndex = lastBracketIndex == -1 ? line.Length : lastBracketIndex;
|
lastBracketIndex = lastBracketIndex == -1 ? line.Length : lastBracketIndex;
|
||||||
var key = line.Substring("# Failed: ".Length, lastBracketIndex - "# Failed: ".Length).Trim();
|
var key = line.Substring("# Failed: ".Length, lastBracketIndex - "# Failed: ".Length).Trim();
|
||||||
var value = lastBracketIndex != line.Length ? line.Substring(lastBracketIndex + 1).Trim().TrimEnd(']') : "";
|
var value = lastBracketIndex != line.Length ? line.Substring(lastBracketIndex + 1).Trim().TrimEnd(']') : "";
|
||||||
return new { Key = key, Value = value };
|
return new { Key = key, Reason = value };
|
||||||
})
|
})
|
||||||
.ToSafeDictionary(pair => pair.Key, pair => pair.Value);
|
.ToSafeDictionary(pair => pair.Key, pair => pair.Reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update()
|
public void Update()
|
||||||
|
@ -4829,6 +4857,12 @@ public class M3UEditor
|
||||||
if (type != TrackLists.ListType.Normal)
|
if (type != TrackLists.ListType.Normal)
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
else if (option == "fails" && track.TrackState == Track.State.Downloaded && index < lines.Count && lines[index].StartsWith($"# Failed: {track}"))
|
||||||
|
{
|
||||||
|
lines[index] = "";
|
||||||
|
needUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (type == TrackLists.ListType.Normal)
|
if (type == TrackLists.ListType.Normal)
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
<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="SmallestCSVParser" Version="1.1.1" />
|
<PackageReference Include="SmallestCSVParser" Version="1.1.1" />
|
||||||
<PackageReference Include="Soulseek" Version="6.4.1" />
|
<PackageReference Include="Soulseek" Version="6.5.0" />
|
||||||
<PackageReference Include="SpotifyAPI.Web" Version="7.1.1" />
|
<PackageReference Include="SpotifyAPI.Web" Version="7.1.1" />
|
||||||
<PackageReference Include="SpotifyAPI.Web.Auth" Version="7.1.1" />
|
<PackageReference Include="SpotifyAPI.Web.Auth" Version="7.1.1" />
|
||||||
<PackageReference Include="TagLibSharp" Version="2.3.0" />
|
<PackageReference Include="TagLibSharp" Version="2.3.0" />
|
||||||
|
|
Loading…
Reference in a new issue