Skip to content

Commit e4eb80c

Browse files
committed
Updated UDP to implement #155, fixed #135 and possibly #138, added directory name length limit parameter (#156), updated copyright year, removed jetbrains from readme since they no longer provide their software license, changed version scheme, updated CommandLineParser, code refactoring, id is now appended to media and attachment file names (can be disabled)
1 parent 09b7e62 commit e4eb80c

File tree

19 files changed

+132
-161
lines changed

19 files changed

+132
-161
lines changed

PatreonDownloader.App/Models/CommandLineOptions.cs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,22 @@ class CommandLineOptions
2727
[Option("log-save", Required = false, HelpText = "Create log files in the \"logs\" directory.", Default = false)]
2828
public bool SaveLogs { get; set; }
2929

30-
[Option("overwrite-files", Required = false, HelpText = "Overwrite already existing files (recommended if creator might have files multiple files with the same filename or makes changes to already existing posts)", Default = false)]
31-
public bool OverwriteFiles { get; set; }
30+
[Option("file-exists-action", Required = false, HelpText =
31+
"What to do with files already existing on the disk.\r\nPossible options:\r\n" +
32+
"BackupIfDifferent: Check remote file size if enabled and available. If it's different, disabled or not available then download remote file and compare it with existing file, create a backup copy of old file if they are different.\r\n" +
33+
"ReplaceIfDifferent: Same as BackupIfDifferent, but the backup copy of the file will not be created.\r\n" +
34+
"AlwaysReplace: Always replace existing file. Warning: will result in increased bandwidth usage.\r\n" +
35+
"KeepExisting: Always keep existing file. The most bandwidth-friendly option.",
36+
Default = FileExistsAction.BackupIfDifferent)]
37+
public FileExistsAction FileExistsAction { get; set; }
3238

33-
[Option("no-remote-size-action", Required = false, HelpText = "What to do with existing files when it is not possible to retrieve file size from the server. Possible options: ReplaceExisting, KeepExisting. --overwrite-files has priority over KeepExisting.", Default = RemoteFileSizeNotAvailableAction.KeepExisting)]
34-
public RemoteFileSizeNotAvailableAction NoRemoteSizeAction { get; set; }
39+
[Option("use-legacy-file-naming", Required = false, HelpText = "Use legacy filenaming pattern (used before version 21). Not compatible with --file-exists-action BackupIfDifferent, ReplaceIfDifferent. Warning: this is compatibility option and might be removed in the future, you should not use it unless you absolutely need it.", Default = false)]
40+
public bool IsUseLegacyFilenaming { get; set; }
41+
42+
[Option("disable-remote-file-size-check", Required = false,
43+
HelpText = "Do not ask the server for the file size (if it's available) and do not use it in various pre-download checks if the file already exists on the disk. Warning: will result in increased bandwidth usage if used with --file-exists-action BackupIfDifferent, ReplaceIfDifferent, AlwaysReplace.",
44+
Default = false)]
45+
public bool IsDisableRemoteFileSizeCheck { get; set; }
3546

3647
[Option("remote-browser-address", Required = false, HelpText = "Advanced users only. Address of the browser with remote debugging enabled. Refer to documentation for more details.")]
3748
public string RemoteBrowserAddress { get; set; }
@@ -41,10 +52,16 @@ class CommandLineOptions
4152

4253
[Option("sub-directory-pattern", Required = false, HelpText = "Pattern which will be used to create a name for the sub directories if --use-sub-directories is used. Supported parameters: %PostId%, %PublishedAt%, %PostTitle%.", Default = "[%PostId%] %PublishedAt% %PostTitle%")]
4354
public string SubDirectoryPattern { get; set; }
55+
56+
[Option("max-sub-directory-name-length", Required = false, HelpText = "Limits the length of the name for the subdirectories created when --use-sub-directories is used.", Default = 100)]
57+
public int MaxSubdirectoryNameLength { get; set; }
58+
4459
[Option("max-filename-length", Required = false, HelpText = "All names of downloaded files will be truncated so their length won't be more than specified value (excluding file extension)", Default = 100)]
4560
public int MaxFilenameLength { get; set; }
61+
4662
[Option("filenames-fallback-to-content-type", Required = false, HelpText = "Fallback to using filename generated from url hash if the server returns file content type (extension) and all other methods have failed. Use with caution, this might result in unwanted files being created or the same files being downloaded on every run under different names.", Default = false)]
4763
public bool FilenamesFallbackToContentType { get; set; }
64+
4865
[Option("proxy-server-address", Required = false, HelpText = "The address of proxy server to use in the following format: [<proxy-scheme>://]<proxy-host>[:<proxy-port>]. Supported protocols: http(s), socks4, socks4a, socks5.")]
4966
public string ProxyServerAddress { get; set; }
5067
}

PatreonDownloader.App/PatreonDownloader.App.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
</PropertyGroup>
99

1010
<ItemGroup>
11-
<PackageReference Include="CommandLineParser" Version="2.8.0" />
11+
<PackageReference Include="CommandLineParser" Version="2.9.1" />
1212
<PackageReference Include="NLog" Version="5.0.0" />
1313
</ItemGroup>
1414

PatreonDownloader.App/Program.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ private static async Task RunPatreonDownloader(CommandLineOptions commandLineOpt
140140
_universalDownloader.FileDownloaded += UniversalDownloaderOnFileDownloaded;
141141

142142
PatreonDownloaderSettings settings = await InitializeSettings(commandLineOptions);
143-
await _universalDownloader.Download(commandLineOptions.Url, commandLineOptions.DownloadDirectory, settings);
143+
await _universalDownloader.Download(commandLineOptions.Url, settings);
144144

145145
_universalDownloader.StatusChanged -= UniversalDownloaderOnStatusChanged;
146146
_universalDownloader.PostCrawlStart -= UniversalDownloaderOnPostCrawlStart;
@@ -185,7 +185,6 @@ private static async Task<PatreonDownloaderSettings> InitializeSettings(CommandL
185185

186186
PatreonDownloaderSettings settings = new PatreonDownloaderSettings
187187
{
188-
OverwriteFiles = commandLineOptions.OverwriteFiles,
189188
UrlBlackList = (_configuration["UrlBlackList"] ?? "").ToLowerInvariant().Split("|").ToList(),
190189
UserAgent = userAgent,
191190
CookieContainer = cookieContainer,
@@ -194,14 +193,20 @@ private static async Task<PatreonDownloaderSettings> InitializeSettings(CommandL
194193
SaveEmbeds = commandLineOptions.SaveEmbeds,
195194
SaveJson = commandLineOptions.SaveJson,
196195
DownloadDirectory = commandLineOptions.DownloadDirectory,
197-
RemoteFileSizeNotAvailableAction = commandLineOptions.NoRemoteSizeAction,
198-
UseSubDirectories = commandLineOptions.UseSubDirectories,
196+
FileExistsAction = commandLineOptions.FileExistsAction,
197+
IsCheckRemoteFileSize = !commandLineOptions.IsDisableRemoteFileSizeCheck,
198+
IsUseSubDirectories = commandLineOptions.UseSubDirectories,
199199
SubDirectoryPattern = commandLineOptions.SubDirectoryPattern,
200+
MaxSubdirectoryNameLength = commandLineOptions.MaxSubdirectoryNameLength,
200201
MaxFilenameLength = commandLineOptions.MaxFilenameLength,
201202
FallbackToContentTypeFilenames = commandLineOptions.FilenamesFallbackToContentType,
202-
ProxyServerAddress = commandLineOptions.ProxyServerAddress
203+
ProxyServerAddress = commandLineOptions.ProxyServerAddress,
204+
IsUseLegacyFilenaming = commandLineOptions.IsUseLegacyFilenaming
203205
};
204206

207+
if (settings.IsUseLegacyFilenaming && (settings.FileExistsAction == FileExistsAction.BackupIfDifferent || settings.FileExistsAction == FileExistsAction.ReplaceIfDifferent))
208+
throw new Exception("Legacy file naming cannot be used with BackupIfDifferent or ReplaceIfDifferent file exists action");
209+
205210
return settings;
206211
}
207212

PatreonDownloader.App/Properties/AssemblyInfo.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
[assembly: AssemblyConfiguration("")]
1111
[assembly: AssemblyCompany("")]
1212
[assembly: AssemblyProduct("Patreon Downloader")]
13-
[assembly: AssemblyCopyright("Copyright 2019-2022 Aleksey Tsutsey & Contributors")]
13+
[assembly: AssemblyCopyright("Copyright 2019-2023 Aleksey Tsutsey & Contributors")]
1414
[assembly: AssemblyTrademark("")]
1515
[assembly: AssemblyCulture("")]
1616

@@ -29,5 +29,5 @@
2929
// Build Number
3030
// Revision
3131
//
32-
[assembly: AssemblyVersion("0.10.6.0")]
33-
[assembly: AssemblyFileVersion("0.10.6.0")]
32+
[assembly: AssemblyVersion("21.0.0.0")]
33+
[assembly: AssemblyFileVersion("21.0.0.0")]

PatreonDownloader.App/UpdateChecker.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,8 @@ public UpdateChecker()
2323
string remoteVersion = remoteVersionData[0];
2424
string message = remoteVersionData.Length > 1 ? remoteVersionData[1] : null;
2525
Version currentVersion = Assembly.GetEntryAssembly().GetName().Version;
26-
string currentVersionString = $"{currentVersion.Major}.{currentVersion.Minor}.{currentVersion.Build}.{currentVersion.Revision}";
2726

28-
return (remoteVersion != currentVersionString, !string.IsNullOrWhiteSpace(message) ? message : null);
27+
return (remoteVersion != currentVersion.Major.ToString(), !string.IsNullOrWhiteSpace(message) ? message : null);
2928
}
3029
}
3130
}

PatreonDownloader.Common/Properties/AssemblyInfo.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
[assembly: AssemblyConfiguration("")]
1111
[assembly: AssemblyCompany("")]
1212
[assembly: AssemblyProduct("Patreon Downloader")]
13-
[assembly: AssemblyCopyright("Copyright 2019-2022 Aleksey Tsutsey & Contributors")]
13+
[assembly: AssemblyCopyright("Copyright 2019-2023 Aleksey Tsutsey & Contributors")]
1414
[assembly: AssemblyTrademark("")]
1515
[assembly: AssemblyCulture("")]
1616

PatreonDownloader.Implementation/Helpers/PostSubdirectoryHelper.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ internal class PostSubdirectoryHelper
1717
/// </summary>
1818
/// <param name="crawledUrl">Crawled url with published date, post title and post id</param>
1919
/// <param name="pattern">Pattern for directory name</param>
20+
/// <param name="lengthLimit">Limit the directory name length to this amount of characters</param>
2021
/// <returns></returns>
21-
public static string CreateNameFromPattern(PatreonCrawledUrl crawledUrl, string pattern)
22+
public static string CreateNameFromPattern(PatreonCrawledUrl crawledUrl, string pattern, int lengthLimit)
2223
{
2324
string postTitle = crawledUrl.Title?.Trim() ?? "No Title";
2425
while (postTitle.Length > 1 && postTitle[^1] == '.')
@@ -29,6 +30,9 @@ public static string CreateNameFromPattern(PatreonCrawledUrl crawledUrl, string
2930
.Replace("%posttitle%", postTitle)
3031
.Replace("%postid%", crawledUrl.PostId);
3132

33+
if (retString.Length > lengthLimit)
34+
retString = retString.Substring(0, lengthLimit);
35+
3236
return PathSanitizer.SanitizePath(retString);
3337
}
3438
}

PatreonDownloader.Implementation/Models/PatreonDownloaderSettings.cs

Lines changed: 28 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -8,103 +8,58 @@
88

99
namespace PatreonDownloader.Implementation.Models
1010
{
11-
public class PatreonDownloaderSettings : UniversalDownloaderPlatformSettings
11+
public record PatreonDownloaderSettings : UniversalDownloaderPlatformSettings
1212
{
13-
private bool _saveDescriptions;
14-
private bool _saveEmbeds;
15-
private bool _saveJson;
16-
private bool _saveAvatarAndCover;
17-
private string _downloadDirectory;
18-
private bool _useSubDirectories;
19-
private string _subDirectoryPattern;
20-
private int _maxFilenameLength;
21-
private bool _fallbackToContentTypeFilenames;
13+
public bool SaveDescriptions { get; init; }
2214

23-
public bool SaveDescriptions
24-
{
25-
get => _saveDescriptions;
26-
set => ConsumableSetter.Set(Consumed, ref _saveDescriptions, value);
27-
}
15+
public bool SaveEmbeds { get; init; }
2816

29-
public bool SaveEmbeds
30-
{
31-
get => _saveEmbeds;
32-
set => ConsumableSetter.Set(Consumed, ref _saveEmbeds, value);
33-
}
17+
public bool SaveJson { get; init; }
3418

35-
public bool SaveJson
36-
{
37-
get => _saveJson;
38-
set => ConsumableSetter.Set(Consumed, ref _saveJson, value);
39-
}
40-
41-
public bool SaveAvatarAndCover
42-
{
43-
get => _saveAvatarAndCover;
44-
set => ConsumableSetter.Set(Consumed, ref _saveAvatarAndCover, value);
45-
}
19+
public bool SaveAvatarAndCover { get; init; }
4620

4721
/// <summary>
48-
/// Target directory for downloaded files. If set to null files will be downloaded into #AppDirectory#/downloads/#CreatorName#.
22+
/// Create a new directory for every post and store files of said post in that directory
4923
/// </summary>
50-
public string DownloadDirectory
51-
{
52-
get => _downloadDirectory;
53-
set => ConsumableSetter.Set(Consumed, ref _downloadDirectory, value);
54-
}
24+
public bool IsUseSubDirectories { get; init; }
5525

5626
/// <summary>
57-
/// Create a new directory for every post and store files of said post in that directory
27+
/// Pattern used to generate directory name if UseSubDirectories is enabled
5828
/// </summary>
59-
public bool UseSubDirectories
60-
{
61-
get => _useSubDirectories;
62-
set => ConsumableSetter.Set(Consumed, ref _useSubDirectories, value);
63-
}
29+
public string SubDirectoryPattern { get; init; }
6430

6531
/// <summary>
66-
/// Pattern used to generate directory name if UseSubDirectories is enabled
32+
/// Subdirectory names will be truncated to this length
6733
/// </summary>
68-
public string SubDirectoryPattern
69-
{
70-
get => _subDirectoryPattern;
71-
set => ConsumableSetter.Set(Consumed, ref _subDirectoryPattern, value);
72-
}
34+
public int MaxSubdirectoryNameLength { get; init; }
7335

7436
/// <summary>
7537
/// Filenames will be truncated to this length
7638
/// </summary>
77-
public int MaxFilenameLength
78-
{
79-
get => _maxFilenameLength;
80-
set => ConsumableSetter.Set(Consumed, ref _maxFilenameLength, value);
81-
}
39+
public int MaxFilenameLength { get; init; }
8240

8341
/// <summary>
8442
/// Fallback to using sha256 hash and Content-Type for filenames if Content-Disposition fails
8543
/// </summary>
86-
public bool FallbackToContentTypeFilenames
87-
{
88-
get => _fallbackToContentTypeFilenames;
89-
set => ConsumableSetter.Set(Consumed, ref _fallbackToContentTypeFilenames, value);
90-
}
44+
public bool FallbackToContentTypeFilenames { get; init; }
9145

92-
public PatreonDownloaderSettings()
93-
{
94-
_saveDescriptions = true;
95-
_saveEmbeds = true;
96-
_saveJson = true;
97-
_saveAvatarAndCover = true;
98-
_downloadDirectory = null;
99-
_useSubDirectories = false;
100-
_subDirectoryPattern = "[%PostId%] %PublishedAt% %PostTitle%";
101-
_fallbackToContentTypeFilenames = false;
102-
_maxFilenameLength = 100;
103-
}
46+
/// <summary>
47+
/// Use legacy file naming pattern (without addition of media/attachment ids to filenames). NOT COMPATIBLE WITH FileExistsAction BackupIfDifferent/ReplaceIfDifferent
48+
/// </summary>
49+
public bool IsUseLegacyFilenaming { get; init; }
10450

105-
public override string ToString()
51+
public PatreonDownloaderSettings()
10652
{
107-
return $"SaveDescriptions={_saveDescriptions},SaveEmbeds={_saveEmbeds},SaveJson={_saveJson},SaveAvatarAndCover={_saveAvatarAndCover},DownloadDirectory={_downloadDirectory},OverwriteFiles={base.OverwriteFiles},UseSubDirectories={_useSubDirectories},MaxFilenameLength={_maxFilenameLength},FallbackToContentTypeFilenames={_fallbackToContentTypeFilenames}";
53+
SaveDescriptions = true;
54+
SaveEmbeds = true;
55+
SaveJson = true;
56+
SaveAvatarAndCover = true;
57+
IsUseSubDirectories = false;
58+
SubDirectoryPattern = "[%PostId%] %PublishedAt% %PostTitle%";
59+
FallbackToContentTypeFilenames = false;
60+
MaxFilenameLength = 100;
61+
MaxSubdirectoryNameLength = 100;
62+
IsUseLegacyFilenaming = false;
10863
}
10964
}
11065
}

PatreonDownloader.Implementation/PatreonCrawledUrl.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ namespace PatreonDownloader.Implementation
77
public class PatreonCrawledUrl : CrawledUrl
88
{
99
public string PostId { get; set; }
10+
/// <summary>
11+
/// Internal patreon file id, only filled for media and attachments
12+
/// </summary>
13+
public string FileId { get; set; }
1014
public string Title { get; set; }
1115
public DateTime PublishedAt { get; set; }
1216
public PatreonCrawledUrlType UrlType { get; set; }
@@ -41,7 +45,8 @@ public object Clone()
4145
{
4246
return new PatreonCrawledUrl
4347
{
44-
PostId = PostId,
48+
PostId = PostId,
49+
FileId = FileId,
4550
Url = Url,
4651
Filename = Filename,
4752
UrlType = UrlType,

0 commit comments

Comments
 (0)