\\s*
[\\S\\s]*
");
147 | int pageIndex = 1;
148 | argLink.Args = $"?page={pageIndex}";
149 | Console.WriteLine(string.Format(Properties.Resources.Msg_Album_Download, argLink.FullUrl));
150 | string albumHtmlText = GetHtmlText(argLink.FullUrl);
151 |
152 | while (!corruptRegex.IsMatch(albumHtmlText) || loadingRegex.IsMatch(albumHtmlText))
153 | {
154 | if (loadingRegex.IsMatch(albumHtmlText))
155 | {
156 | if (IsDebug)
157 | {
158 | Console.ForegroundColor = ConsoleColor.Yellow;
159 | Console.WriteLine($"Regex '{loadingRegex}' is matched. Retrying in 5 seconds.");
160 | Console.ResetColor();
161 | }
162 |
163 | Thread.Sleep(5000);
164 | albumHtmlText = GetHtmlText(argLink.FullUrl);
165 | continue;
166 | }
167 |
168 | DownloadAlbum(albumHtmlText, argLink, GetDownloadDir(argLink, albumHtmlText, pageIndex.ToString()));
169 | pageIndex++;
170 | argLink.Args = $"?page={pageIndex}";
171 | Console.WriteLine(string.Format(Properties.Resources.Msg_Album_Download, argLink.FullUrl));
172 | albumHtmlText = GetHtmlText(argLink.FullUrl);
173 | }
174 | ConsoleBackLine(); //Empty page.
175 | }
176 | else
177 | {
178 | Console.WriteLine(string.Format(Properties.Resources.Msg_Album_Download, argLink.FullUrl));
179 | string albumHtmlText = GetHtmlText(argLink.FullUrl);
180 |
181 | while (loadingRegex.IsMatch(albumHtmlText))
182 | {
183 | if (IsDebug)
184 | {
185 | Console.ForegroundColor = ConsoleColor.Yellow;
186 | Console.WriteLine($"Regex '{loadingRegex}' is matched. Retrying in 5 seconds.");
187 | Console.ResetColor();
188 | }
189 |
190 | Thread.Sleep(5000);
191 | albumHtmlText = GetHtmlText(argLink.FullUrl);
192 | }
193 |
194 | DownloadAlbum(albumHtmlText, argLink,
195 | GetDownloadDir(argLink, albumHtmlText, "1"),
196 | Args.ContainsKey(ARG_STARTINDEX) ? Convert.ToInt32(Args[ARG_STARTINDEX]) : 0,
197 | Args.ContainsKey(ARG_LENGTH) ? Convert.ToInt32(Args[ARG_LENGTH]) : 0);
198 | }
199 | }
200 | else if (argLink.Type.ToLower() == "photo")
201 | {
202 | DownloadPhoto(argLink, GetDownloadDir(argLink, string.Empty));
203 | }
204 | }
205 | catch (Exception e)
206 | {
207 | ThrowException(e);
208 | }
209 |
210 | Console.ForegroundColor = ConsoleColor.Yellow;
211 | Console.WriteLine(Properties.Resources.Msg_AllDone);
212 | Console.ResetColor();
213 | Console.WriteLine();
214 | }
215 |
216 | static string GetDownloadDir(LinkInfo link, string htmlText, string pageIndex = "0")
217 | {
218 | string albumName = $"{link.Type}-{link.ID}";
219 | Regex albumNameRegex = new Regex("
\\s*(?[\\S\\s].*?)\\s*\\s*
");
220 | if (albumNameRegex.IsMatch(htmlText))
221 | {
222 | albumName = albumNameRegex.Match(htmlText).Groups["album"].Value;
223 | }
224 |
225 | string result = Args[ARG_DOWNLOADDIR]
226 | .Replace(REPLACE_DOWNLOADDIR_ALBUM, albumName)
227 | .Replace(REPLACE_DOWNLOADDIR_ID, link.ID)
228 | .Replace(REPLACE_DOWNLOADDIR_PAGE, pageIndex);
229 | foreach (char ch in Path.GetInvalidPathChars())
230 | {
231 | result = result.Replace(ch.ToString(), string.Empty);
232 | }
233 |
234 | return result;
235 | }
236 |
237 | static void DownloadAlbum(string albumHtmlText, LinkInfo albumLink, string downloadDir, int startIndex = 0, int length = 0)
238 | {
239 | List
photoLinks = new List();
240 | Regex regex = new Regex("/photo/[0-9]+)\">");
241 | foreach (Match match in regex.Matches(albumHtmlText))
242 | {
243 | LinkInfo photoLink = LinkInfo.Parse($"{albumLink.Host}{match.Groups["photoLink"].Value}");
244 |
245 | if (photoLink != null)
246 | {
247 | photoLinks.Add(photoLink);
248 | }
249 | }
250 |
251 | DownloadPhotos(photoLinks.ToArray(), downloadDir, startIndex, length);
252 | }
253 |
254 | static void DownloadPhoto(LinkInfo photoLink, string downloadDir)
255 | {
256 | DownloadPhotos(new LinkInfo[] { photoLink }, downloadDir);
257 | }
258 |
259 | static void DownloadPhotos(LinkInfo[] photoLinks, string downloadDir, int startIndex = 0, int length = 0)
260 | {
261 | int retryCount = 0;
262 | int _startIndex = (startIndex < 0 || startIndex >= photoLinks.Length) ? 0 : startIndex;
263 | int _length = (length + _startIndex < 1 || length + _startIndex > photoLinks.Length) ? photoLinks.Length : length + _startIndex;
264 |
265 | if (IsDebug)
266 | {
267 | Console.ForegroundColor = ConsoleColor.Yellow;
268 | Console.WriteLine($"StartIndex: {_startIndex}({startIndex}) Length: {_length}({length}) Count: {photoLinks.Length}");
269 | Console.WriteLine($"Dir: {Path.GetFullPath(downloadDir)}");
270 | Console.ResetColor();
271 | }
272 |
273 | if (!Directory.Exists(downloadDir))
274 | {
275 | Directory.CreateDirectory(downloadDir);
276 | if (IsDebug)
277 | {
278 | Console.ForegroundColor = ConsoleColor.Red;
279 | Console.WriteLine($"Dir created!");
280 | Console.ResetColor();
281 | }
282 | }
283 |
284 | for (int i = _startIndex; i < _length; i++)
285 | {
286 | LinkInfo photoLink = photoLinks[i];
287 | Console.ForegroundColor = ConsoleColor.Blue;
288 | Console.WriteLine(string.Format(
289 | $"{(retryCount == 0 ? $"{Properties.Resources.Msg_Photo_Download}" : $"{Properties.Resources.Msg_Photo_Download_Retrying}")}",
290 | photoLink.FullUrl, i + 1, photoLinks.Length, retryCount));
291 | Console.ResetColor();
292 | try
293 | {
294 | string photoHtmlText = GetHtmlText(photoLink.FullUrl);
295 | string photoSourceUrl = GetPhotoSourceUrl(photoHtmlText);
296 | //TODO: Loading page match.
297 | ConsoleBackLine();
298 | Console.ForegroundColor = ConsoleColor.Blue;
299 | Console.WriteLine(string.Format(Properties.Resources.Msg_Photo_Downloading, Path.GetFileName(photoSourceUrl), i + 1, photoLinks.Length));
300 | Console.ResetColor();
301 |
302 | string fileName = Path.GetFileName(photoSourceUrl);
303 | if (Args.ContainsKey(ARG_RENAME) && !string.IsNullOrWhiteSpace(Args[ARG_RENAME]))
304 | {
305 | Regex fromAlbumRegex = new Regex("[0-9]+)\">(?.*?)");
306 | Match fromAlbumMatch = fromAlbumRegex.Match(photoHtmlText);
307 | string r_index = i.ToString();
308 | string r_id = photoLink.ID;
309 | string r_albumid = fromAlbumMatch.Groups["album_id"].Value;
310 | string r_album = fromAlbumMatch.Groups["album"].Value;
311 | string r_ext = Path.GetExtension(photoSourceUrl);
312 |
313 | fileName = Args[ARG_RENAME]
314 | .Replace(REPLACE_PHOTO_INDEX, r_index)
315 | .Replace(REPLACE_PHOTO_ID, r_id)
316 | .Replace(REPLACE_PHOTO_ALBUM_ID, r_albumid)
317 | .Replace(REPLACE_PHOTO_ALBUM, r_album)
318 | .Replace(REPLACE_PHOTO_EXT, r_ext);
319 |
320 | foreach (char ch in Path.GetInvalidFileNameChars())
321 | {
322 | fileName = fileName.Replace(ch.ToString(), string.Empty);
323 | }
324 | }
325 |
326 | WebClient.DownloadFile(photoSourceUrl, Path.Combine(downloadDir, fileName));
327 | ConsoleBackLine();
328 | Console.ForegroundColor = ConsoleColor.Green;
329 | Console.WriteLine(string.Format(Properties.Resources.Msg_Photo_DownloadCompleted, photoLink.FullUrl /*Path.GetFileName(photoSourceUrl)*/, i + 1, photoLinks.Length, fileName));
330 | Console.ResetColor();
331 | retryCount = 0;
332 | }
333 | catch (Exception e)
334 | {
335 | if (IsDebug)
336 | {
337 | ConsoleBackLine();
338 | }
339 | ThrowException(e);
340 | if (retryCount < SETTING_RETRYCOUNT)
341 | {
342 | retryCount++;
343 | if (IsDebug)
344 | {
345 | Console.ForegroundColor = ConsoleColor.Yellow;
346 | Console.WriteLine($"Download failed. Retrying in 5 seconds. ({retryCount})");
347 | Console.ResetColor();
348 | }
349 | Thread.Sleep(5000);
350 | /*if (IsDebug)*/
351 | ConsoleBackLine();
352 | i--;
353 | continue;
354 | }
355 | else
356 | {
357 | Console.ForegroundColor = ConsoleColor.Red;
358 | Console.WriteLine(string.Format(Properties.Resources.Msg_Photo_DownloadFailed, photoLink.FullUrl, i + 1, photoLinks.Length));
359 | Console.ResetColor();
360 | retryCount = 0;
361 | }
362 | }
363 | }
364 | }
365 |
366 | static string GetHtmlText(string url)
367 | {
368 | HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
369 | request.Timeout = 30 * 1000;
370 | request.AllowAutoRedirect = true;
371 | request.UserAgent = "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)";
372 | request.Method = "GET";
373 | request.KeepAlive = true;
374 | HttpWebResponse response = (HttpWebResponse)request.GetResponse();
375 | using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
376 | {
377 | return reader.ReadToEnd();
378 | }
379 | }
380 |
381 | static string GetPhotoSourceUrl(string htmlText)
382 | {
383 | Regex regex = new Regex("\\s*
\\S+/\\S+original_[0-9]+\\.jpg)\"[\\S\\s]*?>\\s*");
384 | if (regex.IsMatch(htmlText))
385 | {
386 | Match match = regex.Match(htmlText);
387 | return match.Groups["src"].Value;
388 | }
389 | return null;
390 | }
391 |
392 | static void ConsoleBackLine()
393 | {
394 | Console.SetCursorPosition(0, Console.CursorTop - 1);
395 | Console.Write(string.Empty.PadRight(Console.WindowWidth));
396 | Console.SetCursorPosition(0, Console.CursorTop - 1);
397 | }
398 |
399 | static void ThrowException(Exception e)
400 | {
401 | if (IsDebug)
402 | {
403 | Console.BackgroundColor = ConsoleColor.Black;
404 | Console.ForegroundColor = ConsoleColor.Red;
405 | Console.WriteLine(e.Message);
406 | if (IsDebugInfo)
407 | {
408 | if (e.InnerException != null)
409 | {
410 | Console.WriteLine($"InnerException: {e.InnerException.Message}");
411 | }
412 | Console.WriteLine($"StackTrace:\r\n{e.StackTrace}");
413 | Console.WriteLine();
414 | }
415 | Console.ResetColor();
416 | }
417 | }
418 |
419 | ///
420 | /// Pornhub album or photo format link.
421 | ///
422 | class LinkInfo
423 | {
424 | #region Properties
425 | public string Protocol { get; set; }
426 | //public string Region { get; set; }
427 | public string Type { get; set; }
428 | public string ID { get; set; }
429 | public string Host { get; set; }
430 | public string Args { get; set; }
431 | public string UrlWithoutArgs
432 | {
433 | get
434 | {
435 | return $"{Host}/{Type}/{ID}";
436 | }
437 | }
438 | public string FullUrl
439 | {
440 | get
441 | {
442 | return $"{Host}/{Type}/{ID}{Args}";
443 | }
444 | }
445 |
446 | private static Regex regex = new Regex("(?(?(?:(?[http|https]+)://)?(?:(?\\w{2,})\\.)?pornhub\\.com)/(?\\w+)/(?[0-9]+))(?\\?\\S+)?");
447 | #endregion
448 |
449 | #region Methods
450 | public static LinkInfo Parse(string url)
451 | {
452 | if (regex.IsMatch(url))
453 | {
454 | Match match = regex.Match(url);
455 | return new LinkInfo()
456 | {
457 | Protocol = match.Groups["protocol"].Value,
458 | //Region = match.Groups["region"].Value,
459 | Type = match.Groups["type"].Value,
460 | ID = match.Groups["id"].Value,
461 | Host = match.Groups["host"].Value,
462 | Args = match.Groups["args"].Value,
463 | //UrlWithoutArgs = match.Groups["url_without_args"].Value,
464 | //FullUrl = url,
465 | };
466 | }
467 | return null;
468 | }
469 |
470 | public static bool TryParse(string url, out LinkInfo result)
471 | {
472 | return (result = Parse(url)) != null;
473 | }
474 | #endregion
475 | }
476 | }
477 | }
478 |
--------------------------------------------------------------------------------
/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 有关程序集的一般信息由以下
6 | // 控制。更改这些特性值可修改
7 | // 与程序集关联的信息。
8 | [assembly: AssemblyTitle("Pornhub Photo Downloader")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Pornhub Photo Downloader")]
13 | [assembly: AssemblyCopyright("")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // 将 ComVisible 设置为 false 会使此程序集中的类型
18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
19 | //请将此类型的 ComVisible 特性设置为 true。
20 | [assembly: ComVisible(false)]
21 |
22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
23 | [assembly: Guid("b9484bdc-149c-4580-8667-108eff103cff")]
24 |
25 | // 程序集的版本信息由下列四个值组成:
26 | //
27 | // 主版本
28 | // 次版本
29 | // 生成号
30 | // 修订号
31 | //
32 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
33 | //通过使用 "*",如下所示:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.1.0.20519")]
37 |
--------------------------------------------------------------------------------
/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // 此代码由工具生成。
4 | // 运行时版本:4.0.30319.42000
5 | //
6 | // 对此文件的更改可能会导致不正确的行为,并且如果
7 | // 重新生成代码,这些更改将会丢失。
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace PornhubPhotoDownloader.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// 一个强类型的资源类,用于查找本地化的字符串等。
17 | ///
18 | // 此类是由 StronglyTypedResourceBuilder
19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
20 | // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
21 | // (以 /str 作为命令选项),或重新生成 VS 项目。
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// 返回此类使用的缓存的 ResourceManager 实例。
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PornhubPhotoDownloader.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// 重写当前线程的 CurrentUICulture 属性
51 | /// 重写当前线程的 CurrentUICulture 属性。
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 |
63 | ///
64 | /// 查找类似 开始下载“{0}”。 的本地化字符串。
65 | ///
66 | internal static string Msg_Album_Download {
67 | get {
68 | return ResourceManager.GetString("Msg.Album.Download", resourceCulture);
69 | }
70 | }
71 |
72 | ///
73 | /// 查找类似 全部完成。 的本地化字符串。
74 | ///
75 | internal static string Msg_AllDone {
76 | get {
77 | return ResourceManager.GetString("Msg.AllDone", resourceCulture);
78 | }
79 | }
80 |
81 | ///
82 | /// 查找类似 下载相册的所有照片。 的本地化字符串。
83 | ///
84 | internal static string Msg_Help_All {
85 | get {
86 | return ResourceManager.GetString("Msg.Help.All", resourceCulture);
87 | }
88 | }
89 |
90 | ///
91 | /// 查找类似 显示调试信息。 的本地化字符串。
92 | ///
93 | internal static string Msg_Help_Debug {
94 | get {
95 | return ResourceManager.GetString("Msg.Help.Debug", resourceCulture);
96 | }
97 | }
98 |
99 | ///
100 | /// 查找类似 显示更多的调试信息。这是“-Debug”的附加选项。 的本地化字符串。
101 | ///
102 | internal static string Msg_Help_DebugInfo {
103 | get {
104 | return ResourceManager.GetString("Msg.Help.DebugInfo", resourceCulture);
105 | }
106 | }
107 |
108 | ///
109 | /// 查找类似 指定下载目录。 的本地化字符串。
110 | ///
111 | internal static string Msg_Help_DownloadDir {
112 | get {
113 | return ResourceManager.GetString("Msg.Help.DownloadDir", resourceCulture);
114 | }
115 | }
116 |
117 | ///
118 | /// 查找类似 指定“-Dir”选项时可用使用“{id}”、“{album}”、“{page}”关键字。
119 | ///下载照片时“{album}”关键字将被格式化为“photo-{id}”。 的本地化字符串。
120 | ///
121 | internal static string Msg_Help_DownloadDir_Keywords {
122 | get {
123 | return ResourceManager.GetString("Msg.Help.DownloadDir.Keywords", resourceCulture);
124 | }
125 | }
126 |
127 | ///
128 | /// 查找类似 指定将下载的照片数量。指定“-All”时选项将被忽略。 的本地化字符串。
129 | ///
130 | internal static string Msg_Help_Length {
131 | get {
132 | return ResourceManager.GetString("Msg.Help.Length", resourceCulture);
133 | }
134 | }
135 |
136 | ///
137 | /// 查找类似 使用指定的格式重命名文件。 的本地化字符串。
138 | ///
139 | internal static string Msg_Help_Rename {
140 | get {
141 | return ResourceManager.GetString("Msg.Help.Rename", resourceCulture);
142 | }
143 | }
144 |
145 | ///
146 | /// 查找类似 指定“-Rename”选项时可用使用“{index}”、“{id}”、“{albumid}”、“{album}”、“{ext}”关键字。 的本地化字符串。
147 | ///
148 | internal static string Msg_Help_Rename_Keywords {
149 | get {
150 | return ResourceManager.GetString("Msg.Help.Rename.Keywords", resourceCulture);
151 | }
152 | }
153 |
154 | ///
155 | /// 查找类似 指定起始的下载位置(从零开始)。指定“-All”时选项将被忽略。 的本地化字符串。
156 | ///
157 | internal static string Msg_Help_StartIndex {
158 | get {
159 | return ResourceManager.GetString("Msg.Help.StartIndex", resourceCulture);
160 | }
161 | }
162 |
163 | ///
164 | /// 查找类似 PPD <url> [-All] [-Dir:<path>] [-Index:0] [Length:5] 的本地化字符串。
165 | ///
166 | internal static string Msg_Help_Use {
167 | get {
168 | return ResourceManager.GetString("Msg.Help.Use", resourceCulture);
169 | }
170 | }
171 |
172 | ///
173 | /// 查找类似 无效的链接“{0}”。 的本地化字符串。
174 | ///
175 | internal static string Msg_InvalidLink {
176 | get {
177 | return ResourceManager.GetString("Msg.InvalidLink", resourceCulture);
178 | }
179 | }
180 |
181 | ///
182 | /// 查找类似 开始下载“{0}”,第 {1} 个,共 {2} 个。 的本地化字符串。
183 | ///
184 | internal static string Msg_Photo_Download {
185 | get {
186 | return ResourceManager.GetString("Msg.Photo.Download", resourceCulture);
187 | }
188 | }
189 |
190 | ///
191 | /// 查找类似 正在重试“{0}”,第 {1} 个,共 {2} 个。第 {3} 次。 的本地化字符串。
192 | ///
193 | internal static string Msg_Photo_Download_Retrying {
194 | get {
195 | return ResourceManager.GetString("Msg.Photo.Download.Retrying", resourceCulture);
196 | }
197 | }
198 |
199 | ///
200 | /// 查找类似 下载完成“{0}”,第 {1} 个,共 {2} 个。 的本地化字符串。
201 | ///
202 | internal static string Msg_Photo_DownloadCompleted {
203 | get {
204 | return ResourceManager.GetString("Msg.Photo.DownloadCompleted", resourceCulture);
205 | }
206 | }
207 |
208 | ///
209 | /// 查找类似 下载失败“{0}”,第 {1} 个,共 {2} 个。 的本地化字符串。
210 | ///
211 | internal static string Msg_Photo_DownloadFailed {
212 | get {
213 | return ResourceManager.GetString("Msg.Photo.DownloadFailed", resourceCulture);
214 | }
215 | }
216 |
217 | ///
218 | /// 查找类似 正在下载“{0}”,第 {1} 个,共 {2} 个。 的本地化字符串。
219 | ///
220 | internal static string Msg_Photo_Downloading {
221 | get {
222 | return ResourceManager.GetString("Msg.Photo.Downloading", resourceCulture);
223 | }
224 | }
225 |
226 | ///
227 | /// 查找类似 Pornhub 照片下载 的本地化字符串。
228 | ///
229 | internal static string Title {
230 | get {
231 | return ResourceManager.GetString("Title", resourceCulture);
232 | }
233 | }
234 | }
235 | }
236 |
--------------------------------------------------------------------------------
/Properties/Resources.en.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | Download "{0}"
122 |
123 |
124 | All done!
125 |
126 |
127 | Download all photo of the album.
128 |
129 |
130 | Show debugging information.
131 |
132 |
133 | Show more debugging information. Option for "-Debug".
134 |
135 |
136 | Download directory.
137 |
138 |
139 | Download length.
140 |
141 |
142 | Download starting position (zero-based).
143 |
144 |
145 | Invalid link "{0}".
146 |
147 |
148 | Download "{0}". ({1} of {2})
149 |
150 |
151 | Retrying "{0}". ({1} of {2}) ({3})
152 |
153 |
154 | Completed "{0}". ({1} of {2})
155 |
156 |
157 | Failed "{0}". ({1} of {2})
158 |
159 |
160 | Downloading "{0}". ({1} of {2})
161 |
162 |
163 | Pornhub Photo Downloader
164 |
165 |
--------------------------------------------------------------------------------
/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | 开始下载“{0}”。
122 |
123 |
124 | 全部完成。
125 |
126 |
127 | 下载相册的所有照片。
128 |
129 |
130 | 显示调试信息。
131 |
132 |
133 | 显示更多的调试信息。这是“-Debug”的附加选项。
134 |
135 |
136 | 指定下载目录。
137 |
138 |
139 | 指定“-Dir”选项时可用使用“{id}”、“{album}”、“{page}”关键字。
140 | 下载照片时“{album}”关键字将被格式化为“photo-{id}”。
141 |
142 |
143 | 指定将下载的照片数量。指定“-All”时选项将被忽略。
144 |
145 |
146 | 使用指定的格式重命名文件。
147 |
148 |
149 | 指定“-Rename”选项时可用使用“{index}”、“{id}”、“{albumid}”、“{album}”、“{ext}”关键字。
150 |
151 |
152 | 指定起始的下载位置(从零开始)。指定“-All”时选项将被忽略。
153 |
154 |
155 | PPD <url> [-All] [-Dir:<path>] [-Index:0] [Length:5]
156 |
157 |
158 | 无效的链接“{0}”。
159 |
160 |
161 | 开始下载“{0}”,第 {1} 个,共 {2} 个。
162 |
163 |
164 | 正在重试“{0}”,第 {1} 个,共 {2} 个。第 {3} 次。
165 |
166 |
167 | 下载完成“{0}”,第 {1} 个,共 {2} 个。
168 |
169 |
170 | 下载失败“{0}”,第 {1} 个,共 {2} 个。
171 |
172 |
173 | 正在下载“{0}”,第 {1} 个,共 {2} 个。
174 |
175 |
176 | Pornhub 照片下载
177 |
178 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Pornhub Photo Downloader
2 |
3 |
4 |
5 |
6 |
7 |
8 | 批量下载 Pornhub 上的相册或照片。
9 |
10 | ```powershell
11 | 示例 .\ppd "https://cn.pornhub.com/album/48071401" -all
12 | ```
13 |
14 | #### 重命名
15 |
16 | 使用[关键字](#参数)以重命名下载目录和文件名。
17 |
18 | ```powershell
19 | 示例 .\ppd "https://cn.pornhub.com/album/48071401" -all -dir:"Downloads\{album}"
20 | ```
21 |
22 | ## 参数
23 |
24 | | 名称 | 描述 | 附加 |
25 | | ----------------- | -------------------------------- | ---------------------------------------------------------- |
26 | | {url} | 相册或照片链接。 | 必须在参数列表的首位。 |
27 | | -All | 下载相册的所有照片。 | 仅相册。 |
28 | | -Dir:{path} | 指定下载目录。 | 关键字“{id}”、“{album}”、“{page}”。 |
29 | | -Index:{value} | 指定起始的下载位置(从零开始)。 | 指定“-All”时选项将被忽略。 |
30 | | -Length:{value} | 指定将下载的照片数量。 | 指定“-All”时选项将被忽略。 |
31 | | -Debug | 显示调试信息。 | |
32 | | -Info | 显示更多的调试信息。 | 这是“-Debug”的附加选项。 |
33 | | -Lang:{value} | 指定区域。 | -Lang:en |
34 | | -Rename:{pattern} | 使用指定的格式重命名文件。 | 关键字“{index}”、“{id}”、“{albumid}”、“{album}”、“{ext}”。 |
35 |
36 | ## 截图
37 |
38 | 
--------------------------------------------------------------------------------
/docs/Images/00.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nicengi/PornhubPhotoDownloader/99ef325a8df2df65deb6f0f6ef1d492abab473f9/docs/Images/00.png
--------------------------------------------------------------------------------
/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------