Skip to content

Commit

Permalink
Adjust username visibility opaque threshold & cache parsed default us…
Browse files Browse the repository at this point in the history
…ernames

Fix typo (lay295#1082)

Update Simplified Chinese Translation (lay295#1080)

Fix TsMerger M3U8 support (lay295#1084)

Cleanup (lay295#1086)

* Simplify notifying properties

* Fix ReadOnlySpanExtensions.UnEscapedIndexOf ArgumentOutOfRangeException args

* Fix system emoji vendor missing from exception message

* Simplify CacheHandler user prompt code

Remove chatupdate compression arg shorthand (-c) (lay295#1087)

Fix README

Prompt user before overwriting files (lay295#1085)

* Create destination file immediately

* Fix potential NRE

* Implement FileOverwriteHandler for CLI

* Add GetNonCollidingName tests

* TwitchDownloaderArgs -> ITwitchDownloaderArgs & rearrange arg interfaces due to help text ordering

* Update help text

* Create WPF task file overwrite handler

* Throw when no output file is returned, refresh FileInfos before checking Exists property

* Genericize opening explorer for a given file

* Update ___Options output file property to reflect possibly new filename

* Add icon

* Add translations

* Annotate as windows only

* Update README

* Forgot to add it to the whole CLI

* Overwrite -> Collision

* Missed a few spots

* Update wording

* Use warning icon to match file explorer overwrite prompt

* Make "remember my choice" wording more clear

* Fix missing zh-cn translations

Add `DEBUG` to WPF title when compiled in debug mode (lay295#1088)

Bump nuget packages (lay295#1089)

Bump version
  • Loading branch information
ScrubN committed Jun 8, 2024
1 parent edf646b commit f113e0d
Show file tree
Hide file tree
Showing 69 changed files with 1,091 additions and 339 deletions.
14 changes: 10 additions & 4 deletions TwitchDownloaderCLI.Tests/TwitchDownloaderCLI.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,16 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>
<PackageReference Include="xunit" Version="2.5.3"/>
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3"/>
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="xunit" Version="2.8.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,12 @@ internal enum LogLevel
Error = 1 << 5,
Ffmpeg = 1 << 6,
}

public enum OverwriteBehavior
{
Overwrite,
Exit,
Rename,
Prompt,
}
}
7 changes: 6 additions & 1 deletion TwitchDownloaderCLI/Modes/Arguments/CacheArgs.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
using CommandLine;
using TwitchDownloaderCLI.Models;

namespace TwitchDownloaderCLI.Modes.Arguments
{
[Verb("cache", HelpText = "Manage the working cache")]
internal sealed class CacheArgs : TwitchDownloaderArgs
internal sealed class CacheArgs : ITwitchDownloaderArgs
{
[Option('c', "clear", Default = false, Required = false, HelpText = "Clears the default cache folder.")]
public bool ClearCache { get; set; }

[Option("force-clear", Default = false, Required = false, HelpText = "Clears the default cache folder, bypassing the confirmation prompt")]
public bool ForceClearCache { get; set; }

// Interface args
public bool? ShowBanner { get; set; }
public LogLevel LogLevel { get; set; }
}
}
7 changes: 6 additions & 1 deletion TwitchDownloaderCLI/Modes/Arguments/ChatDownloadArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace TwitchDownloaderCLI.Modes.Arguments
{
[Verb("chatdownload", HelpText = "Downloads the chat from a VOD or clip")]
internal sealed class ChatDownloadArgs : TwitchDownloaderArgs
internal sealed class ChatDownloadArgs : IFileCollisionArgs, ITwitchDownloaderArgs
{
[Option('u', "id", Required = true, HelpText = "The ID or URL of the VOD or clip to download that chat of.")]
public string Id { get; set; }
Expand Down Expand Up @@ -45,5 +45,10 @@ internal sealed class ChatDownloadArgs : TwitchDownloaderArgs

[Option("temp-path", Default = "", HelpText = "Path to temporary folder to use for cache.")]
public string TempFolder { get; set; }

// Interface args
public OverwriteBehavior OverwriteBehavior { get; set; }
public bool? ShowBanner { get; set; }
public LogLevel LogLevel { get; set; }
}
}
7 changes: 6 additions & 1 deletion TwitchDownloaderCLI/Modes/Arguments/ChatRenderArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
namespace TwitchDownloaderCLI.Modes.Arguments
{
[Verb("chatrender", HelpText = "Renders a chat JSON as a video")]
internal sealed class ChatRenderArgs : TwitchDownloaderArgs
internal sealed class ChatRenderArgs : IFileCollisionArgs, ITwitchDownloaderArgs
{
[Option('i', "input", Required = true, HelpText = "Path to JSON chat file input.")]
public string InputFile { get; set; }
Expand Down Expand Up @@ -152,5 +152,10 @@ internal sealed class ChatRenderArgs : TwitchDownloaderArgs

[Option("scale-highlight-indent", Default = 1.0, HelpText = "Number to scale highlight indent size (sub messages).")]
public double ScaleAccentIndent { get; set; }

// Interface args
public OverwriteBehavior OverwriteBehavior { get; set; }
public bool? ShowBanner { get; set; }
public LogLevel LogLevel { get; set; }
}
}
9 changes: 7 additions & 2 deletions TwitchDownloaderCLI/Modes/Arguments/ChatUpdateArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
namespace TwitchDownloaderCLI.Modes.Arguments
{
[Verb("chatupdate", HelpText = "Updates the embedded emotes, badges, bits, and trims a chat JSON and/or converts a JSON chat to another format.")]
internal sealed class ChatUpdateArgs : TwitchDownloaderArgs
internal sealed class ChatUpdateArgs : IFileCollisionArgs, ITwitchDownloaderArgs
{
[Option('i', "input", Required = true, HelpText = "Path to input file. Valid extensions are: .json, .json.gz.")]
public string InputFile { get; set; }

[Option('o', "output", Required = true, HelpText = "Path to output file. File extension will be used to determine new chat type. Valid extensions are: .json, .html, and .txt.")]
public string OutputFile { get; set; }

[Option('c', "compression", Default = ChatCompression.None, HelpText = "Compresses an output json chat file using a specified compression, usually resulting in 40-90% size reductions. Valid values are: None, Gzip.")]
[Option("compression", Default = ChatCompression.None, HelpText = "Compresses an output json chat file using a specified compression, usually resulting in 40-90% size reductions. Valid values are: None, Gzip.")]
public ChatCompression Compression { get; set; }

[Option('E', "embed-missing", Default = false, HelpText = "Embeds missing emotes, badges, and cheermotes. Already embedded images will be untouched.")]
Expand Down Expand Up @@ -42,5 +42,10 @@ internal sealed class ChatUpdateArgs : TwitchDownloaderArgs

[Option("temp-path", Default = "", HelpText = "Path to temporary folder to use for cache.")]
public string TempFolder { get; set; }

// Interface args
public OverwriteBehavior OverwriteBehavior { get; set; }
public bool? ShowBanner { get; set; }
public LogLevel LogLevel { get; set; }
}
}
8 changes: 7 additions & 1 deletion TwitchDownloaderCLI/Modes/Arguments/ClipDownloadArgs.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
using CommandLine;
using TwitchDownloaderCLI.Models;

namespace TwitchDownloaderCLI.Modes.Arguments
{
[Verb("clipdownload", HelpText = "Downloads a clip from Twitch")]
internal sealed class ClipDownloadArgs : TwitchDownloaderArgs
internal sealed class ClipDownloadArgs : IFileCollisionArgs, ITwitchDownloaderArgs
{
[Option('u', "id", Required = true, HelpText = "The ID or URL of the clip to download.")]
public string Id { get; set; }
Expand All @@ -25,5 +26,10 @@ internal sealed class ClipDownloadArgs : TwitchDownloaderArgs

[Option("temp-path", Default = "", HelpText = "Path to temporary caching folder.")]
public string TempFolder { get; set; }

// Interface args
public OverwriteBehavior OverwriteBehavior { get; set; }
public bool? ShowBanner { get; set; }
public LogLevel LogLevel { get; set; }
}
}
7 changes: 6 additions & 1 deletion TwitchDownloaderCLI/Modes/Arguments/FfmpegArgs.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
using CommandLine;
using TwitchDownloaderCLI.Models;

namespace TwitchDownloaderCLI.Modes.Arguments
{
[Verb("ffmpeg", HelpText = "Manage standalone ffmpeg")]
internal sealed class FfmpegArgs : TwitchDownloaderArgs
internal sealed class FfmpegArgs : ITwitchDownloaderArgs
{
[Option('d', "download", Default = false, Required = false, HelpText = "Downloads FFmpeg as a standalone file.")]
public bool DownloadFfmpeg { get; set; }

// Interface args
public bool? ShowBanner { get; set; }
public LogLevel LogLevel { get; set; }
}
}
11 changes: 11 additions & 0 deletions TwitchDownloaderCLI/Modes/Arguments/IFileCollisionArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using CommandLine;
using TwitchDownloaderCLI.Models;

namespace TwitchDownloaderCLI.Modes.Arguments
{
internal interface IFileCollisionArgs
{
[Option("collision", Default = OverwriteBehavior.Prompt, HelpText = "Sets the handling of output file name collisions. Valid values are: Overwrite, Exit, Rename, Prompt.")]
public OverwriteBehavior OverwriteBehavior { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace TwitchDownloaderCLI.Modes.Arguments
{
internal abstract class TwitchDownloaderArgs
internal interface ITwitchDownloaderArgs
{
[Option("banner", Default = true, HelpText = "Displays a banner containing version and copyright information.")]
public bool? ShowBanner { get; set; }
Expand Down
8 changes: 7 additions & 1 deletion TwitchDownloaderCLI/Modes/Arguments/TsMergeArgs.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
using CommandLine;
using TwitchDownloaderCLI.Models;

namespace TwitchDownloaderCLI.Modes.Arguments
{
[Verb("tsmerge", HelpText = "Concatenates multiple .ts/.tsv/.tsa/.m2t/.m2ts (MPEG Transport Stream) files into a single file")]
internal sealed class TsMergeArgs : TwitchDownloaderArgs
internal sealed class TsMergeArgs : IFileCollisionArgs, ITwitchDownloaderArgs
{
[Option('i', "input", Required = true, HelpText = "Path a text file containing the absolute paths of the files to concatenate, separated by newlines. M3U/M3U8 is also supported.")]
public string InputList { get; set; }

[Option('o', "output", Required = true, HelpText = "Path to output file.")]
public string OutputFile { get; set; }

// Interface args
public OverwriteBehavior OverwriteBehavior { get; set; }
public bool? ShowBanner { get; set; }
public LogLevel LogLevel { get; set; }
}
}
7 changes: 6 additions & 1 deletion TwitchDownloaderCLI/Modes/Arguments/VideoDownloadArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
namespace TwitchDownloaderCLI.Modes.Arguments
{
[Verb("videodownload", HelpText = "Downloads a stream VOD from Twitch")]
internal sealed class VideoDownloadArgs : TwitchDownloaderArgs
internal sealed class VideoDownloadArgs : IFileCollisionArgs, ITwitchDownloaderArgs
{
[Option('u', "id", Required = true, HelpText = "The ID or URL of the VOD to download.")]
public string Id { get; set; }
Expand Down Expand Up @@ -35,5 +35,10 @@ internal sealed class VideoDownloadArgs : TwitchDownloaderArgs

[Option("temp-path", Default = "", HelpText = "Path to temporary caching folder.")]
public string TempFolder { get; set; }

// Interface args
public OverwriteBehavior OverwriteBehavior { get; set; }
public bool? ShowBanner { get; set; }
public LogLevel LogLevel { get; set; }
}
}
12 changes: 3 additions & 9 deletions TwitchDownloaderCLI/Modes/CacheHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,15 @@ private static void PromptClearCache()
Console.WriteLine("Are you sure you want to clear the cache? This should really only be done if the program isn't working correctly.");
while (true)
{
Console.Write("[Y]es / [N]o: ");
Console.Write("[Y] Yes / [N] No: ");
var userInput = Console.ReadLine()!.Trim().ToLower();
switch (userInput)
{
case "y":
case "ye":
case "yes":
case "y" or "yes":
ClearTempCache();
return;
case "n":
case "no":
case "n" or "no":
return;
default:
Console.Write("Invalid input. ");
continue;
}
}
}
Expand Down
8 changes: 5 additions & 3 deletions TwitchDownloaderCLI/Modes/DownloadChat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ internal static void Download(ChatDownloadArgs inputOptions)
{
var progress = new CliTaskProgress(inputOptions.LogLevel);

var downloadOptions = GetDownloadOptions(inputOptions, progress);
var collisionHandler = new FileCollisionHandler(inputOptions);
var downloadOptions = GetDownloadOptions(inputOptions, collisionHandler, progress);

var chatDownloader = new ChatDownloader(downloadOptions, progress);
chatDownloader.DownloadAsync(CancellationToken.None).Wait();
}

private static ChatDownloadOptions GetDownloadOptions(ChatDownloadArgs inputOptions, ITaskLogger logger)
private static ChatDownloadOptions GetDownloadOptions(ChatDownloadArgs inputOptions, FileCollisionHandler collisionHandler, ITaskLogger logger)
{
if (inputOptions.Id is null)
{
Expand Down Expand Up @@ -64,7 +65,8 @@ private static ChatDownloadOptions GetDownloadOptions(ChatDownloadArgs inputOpti
BttvEmotes = (bool)inputOptions.BttvEmotes!,
FfzEmotes = (bool)inputOptions.FfzEmotes!,
StvEmotes = (bool)inputOptions.StvEmotes!,
TempFolder = inputOptions.TempFolder
TempFolder = inputOptions.TempFolder,
FileCollisionCallback = collisionHandler.HandleCollisionCallback,
};

return downloadOptions;
Expand Down
8 changes: 5 additions & 3 deletions TwitchDownloaderCLI/Modes/DownloadClip.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@ internal static void Download(ClipDownloadArgs inputOptions)
FfmpegHandler.DetectFfmpeg(inputOptions.FfmpegPath, progress);
}

var downloadOptions = GetDownloadOptions(inputOptions, progress);
var collisionHandler = new FileCollisionHandler(inputOptions);
var downloadOptions = GetDownloadOptions(inputOptions, collisionHandler, progress);

var clipDownloader = new ClipDownloader(downloadOptions, progress);
clipDownloader.DownloadAsync(new CancellationToken()).Wait();
}

private static ClipDownloadOptions GetDownloadOptions(ClipDownloadArgs inputOptions, ITaskLogger logger)
private static ClipDownloadOptions GetDownloadOptions(ClipDownloadArgs inputOptions, FileCollisionHandler collisionHandler, ITaskLogger logger)
{
if (inputOptions.Id is null)
{
Expand All @@ -50,7 +51,8 @@ private static ClipDownloadOptions GetDownloadOptions(ClipDownloadArgs inputOpti
ThrottleKib = inputOptions.ThrottleKib,
FfmpegPath = string.IsNullOrWhiteSpace(inputOptions.FfmpegPath) ? FfmpegHandler.FfmpegExecutableName : Path.GetFullPath(inputOptions.FfmpegPath),
EncodeMetadata = inputOptions.EncodeMetadata!.Value,
TempFolder = inputOptions.TempFolder
TempFolder = inputOptions.TempFolder,
FileCollisionCallback = collisionHandler.HandleCollisionCallback,
};

return downloadOptions;
Expand Down
8 changes: 5 additions & 3 deletions TwitchDownloaderCLI/Modes/DownloadVideo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@ internal static void Download(VideoDownloadArgs inputOptions)

FfmpegHandler.DetectFfmpeg(inputOptions.FfmpegPath, progress);

var downloadOptions = GetDownloadOptions(inputOptions, progress);
var collisionHandler = new FileCollisionHandler(inputOptions);
var downloadOptions = GetDownloadOptions(inputOptions, collisionHandler, progress);

var videoDownloader = new VideoDownloader(downloadOptions, progress);
videoDownloader.DownloadAsync(new CancellationToken()).Wait();
}

private static VideoDownloadOptions GetDownloadOptions(VideoDownloadArgs inputOptions, ITaskLogger logger)
private static VideoDownloadOptions GetDownloadOptions(VideoDownloadArgs inputOptions, FileCollisionHandler collisionHandler, ITaskLogger logger)
{
if (inputOptions.Id is null)
{
Expand Down Expand Up @@ -76,7 +77,8 @@ private static VideoDownloadOptions GetDownloadOptions(VideoDownloadArgs inputOp
"Run 'TwitchDownloaderCLI cache help' for more information.");

return Array.Empty<DirectoryInfo>();
}
},
FileCollisionCallback = collisionHandler.HandleCollisionCallback,
};

return downloadOptions;
Expand Down
8 changes: 5 additions & 3 deletions TwitchDownloaderCLI/Modes/MergeTs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,20 @@ internal static void Merge(TsMergeArgs inputOptions)

progress.LogInfo("The TS merger is experimental and is subject to change without notice in future releases.");

var mergeOptions = GetMergeOptions(inputOptions);
var collisionHandler = new FileCollisionHandler(inputOptions);
var mergeOptions = GetMergeOptions(inputOptions, collisionHandler);

var tsMerger = new TsMerger(mergeOptions, progress);
tsMerger.MergeAsync(new CancellationToken()).Wait();
}

private static TsMergeOptions GetMergeOptions(TsMergeArgs inputOptions)
private static TsMergeOptions GetMergeOptions(TsMergeArgs inputOptions, FileCollisionHandler collisionHandler)
{
TsMergeOptions mergeOptions = new()
{
OutputFile = inputOptions.OutputFile,
InputFile = inputOptions.InputList
InputFile = inputOptions.InputList,
FileCollisionCallback = collisionHandler.HandleCollisionCallback,
};

return mergeOptions;
Expand Down
9 changes: 6 additions & 3 deletions TwitchDownloaderCLI/Modes/RenderChat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@ internal static void Render(ChatRenderArgs inputOptions)

FfmpegHandler.DetectFfmpeg(inputOptions.FfmpegPath, progress);

var renderOptions = GetRenderOptions(inputOptions, progress);
var collisionHandler = new FileCollisionHandler(inputOptions);
var renderOptions = GetRenderOptions(inputOptions, collisionHandler, progress);

using var chatRenderer = new ChatRenderer(renderOptions, progress);
chatRenderer.ParseJsonAsync().Wait();
chatRenderer.RenderVideoAsync(new CancellationToken()).Wait();
}

private static ChatRenderOptions GetRenderOptions(ChatRenderArgs inputOptions, ITaskLogger logger)
private static ChatRenderOptions GetRenderOptions(ChatRenderArgs inputOptions, FileCollisionHandler collisionHandler, ITaskLogger logger)
{
ChatRenderOptions renderOptions = new()
{
Expand Down Expand Up @@ -77,7 +79,7 @@ private static ChatRenderOptions GetRenderOptions(ChatRenderArgs inputOptions, I
"twitter" or "twemoji" => EmojiVendor.TwitterTwemoji,
"google" or "notocolor" => EmojiVendor.GoogleNotoColor,
"system" or "none" => EmojiVendor.None,
_ => throw new NotSupportedException("Invalid emoji vendor. Valid values are: 'twitter' / 'twemoji', and 'google' / 'notocolor'")
_ => throw new NotSupportedException("Invalid emoji vendor. Valid values are: 'twitter' / 'twemoji', 'google' / 'notocolor', and 'system' / 'none'")
},
SkipDriveWaiting = inputOptions.SkipDriveWaiting,
EmoteScale = inputOptions.ScaleEmote,
Expand All @@ -93,6 +95,7 @@ private static ChatRenderOptions GetRenderOptions(ChatRenderArgs inputOptions, I
DisperseCommentOffsets = inputOptions.DisperseCommentOffsets,
AlternateMessageBackgrounds = inputOptions.AlternateMessageBackgrounds,
AdjustUsernameVisibility = inputOptions.AdjustUsernameVisibility,
FileCollisionCallback = collisionHandler.HandleCollisionCallback,
};

if (renderOptions.GenerateMask && renderOptions.BackgroundColor.Alpha == 255 && !(renderOptions.AlternateMessageBackgrounds! && renderOptions.AlternateBackgroundColor.Alpha != 255))
Expand Down
Loading

0 comments on commit f113e0d

Please sign in to comment.