Compare commits

...

19 Commits

Author SHA1 Message Date
Andy
dd272c6f6d 2022.6.6.0
Minor fixes
Fixed Twitter gifs
2022-06-06 21:32:43 +03:00
Andy
fbcda1ae75 2022.6.4.0
Added pause automation
Extended automation information
Updated automation checker
2022-06-04 02:43:46 +03:00
Andy
9e87369c9b Update ReadMe 2022-06-04 02:14:18 +03:00
Andy
cc3618a50e Update CONTRIBUTING.md 2022-06-04 02:10:44 +03:00
Andy
33b9e9cfc6 2022.6.3.0
Updated plugin environments and dependencies
Added automation
Fixed Insta hash issue
Updated groups
Added toast notifications
Updated tagged posts notifications
Updated M3U8; fixed audio issue
Extended some of log exceptions
Fixed minor bugs
Other minor improvements
2022-06-03 20:42:28 +03:00
Andy
26dca2246e Update README.md 2022-05-27 21:40:30 +03:00
Andy
60b459e217 3.0.0.10
Added downloading groups
Added downloading Twitter saved posts
Added scripts when closing and completing the download
Opening Info and Progress forms when downloads start
Disabling the opening of forms Info and Progress at the start of downloads if it was once closed
Added focusing the main window when opening Info or Progress forms
Fixed downloading Instagram tagged data
Fixed forbidden characters Instagram stories
Updated form field checkers
Fixed downloading Imgur and Gfycat if they were posted on Reddit
Fixed separate Instagram posts were not downloading via the Video Downloader form.
Date time filenames
Twitter 4K images
2022-05-23 15:51:08 +03:00
Andy
f491e03812 Merge pull request #37 from unknown81311/main
Update MainFrame.vb
2022-05-02 08:11:35 +03:00
unknown81311
418f44edfd Update MainFrame.vb 2022-04-27 19:24:37 -06:00
Andy
075a2b9b80 3.0.0.9
Updated labels class
Moved some settings from SettingsCLS to LabelsKeeper
Excluded labels
Disable user grouping
Show groups of user sites when filtering by labels
Removed adding 'No Parsed' internal label
Fixed redownloading Instagram Stories
Changed global settings form
Updated Labels form
Fixed text separator in UserCreatorForm
Add target user if hidden
2022-04-24 20:35:30 +03:00
Andy
20c74ec8f1 Update ProgramsComparison.md 2022-04-20 18:48:06 +03:00
Andy
0594e77e0b 3.0.0.8
Script mode command
Disabled Instagram error 403
Fixed script does not run
2022-04-19 14:58:56 +03:00
Andy
a5fa935e76 3.0.0.7
Added script usage
Fixed  downloading of LPSG images
Fixed Instagram Stories
Fixed date/time file pattern
2022-04-14 18:12:01 +03:00
Andy
c90dd5637e Update Plugins.md 2022-04-12 05:41:03 +03:00
Andy
9a301ebc5e 3.0.0.6
Added GoTo Start/End channels buttons
Fixed saved Reddit posts downloading
Fixed Reddit accessibility check
Disabled main progress bar progress when downloading saved posts
Added Date and Time for Stories and Tagged Photos
2022-04-04 03:00:22 +03:00
Andy
11a590f14e 3.0.0.5
Added options for Reddit channel and user
Fixed minor bugs and typos
2022-04-02 04:36:38 +03:00
Andy
975d46715c 3.0.0.4
Changed XVIDEOS.M3U8 errors
Added TryCatch to XVIDEOS.UserData.Download
Removed old declarations in UserDataBase
Changed description replacement in UserDataHost
2022-03-26 20:00:55 +03:00
Andy
726fc486ce 3.0.0.3
Added additional 'download all' options
Fixed ListImagesLoader (User.FitToAddParams)
Fixed Instagram default value of SleepTimerOnPostsLimit
Fixed XVIDEOS typo
2022-03-24 19:14:58 +03:00
Andy
ede81f9d05 Update HowToSupport.md 2022-03-23 00:41:18 +03:00
114 changed files with 6752 additions and 900 deletions

View File

@@ -12,7 +12,7 @@ A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Profile URL:
1. **Profile URL**:
2. Do something
3. See error
@@ -26,8 +26,10 @@ A clear and concise description of what you expected to happen.
If applicable, add screenshots to help explain your problem.
**Release information (please complete the following information):**
- OS [e.g. Windows 10, Windows 11]
- Architecture [e.g. x86, x64]
- Version [e.g. 2.0.0.0]
- NET.Framework version
**Additional context**
Add any other context about the problem here.

View File

@@ -1,6 +1,6 @@
---
name: Add plugin
about: Add plugin to plugin list
name: I developed a plugin for SCrawler
about: I developed a plugin for SCrawler. Add plugin to plugin list.
title: "[NEW PLUGIN]"
labels: 'New Plugin'
assignees: ''

View File

@@ -3,30 +3,36 @@
I welcome requests! Follow these steps to contribute:
1. Find an [issue](https://github.com/AAndyProgram/SCrawler/issues) that needs assistance.
2. Let me know you are working on it by posting a comment on the issue.
3. If you find an error in the code, please provide a link to the file and the line number.
4. If you have a suggestion to change the code, you can post a block of code to replace. I don't currently have time to learn pull requests, so it might work this way.
1. Let me know you are working on it by posting a comment on the issue.
1. If you find an error in the code, please provide a link to the file and the line number.
1. If you have a code change suggestion, you can post a replacement code block. I also accept pull requests.
# How to build from source
1. Delete the "PersonalUtilities" project from the solution.
2. Add the latest version of the "PersonalUtilities.dll" library (from the [latest release](https://github.com/AAndyProgram/SCrawler/releases/latest)).
3. Import PersonalUtilities.Functions for the whole project.
1. Delete the "PersonalUtilities.Notifications" project from the solution.
1. Add the latest versions of the ```PersonalUtilities.dll``` and ```PersonalUtilities.Notifications.dll``` libraries (from the [latest release](https://github.com/AAndyProgram/SCrawler/releases/latest)).
1. Import PersonalUtilities.Functions for the whole project.
**Always use the correct "PersonalUtilities.dll" library. You must download this library from the release of the code you downloaded.**
# How to request a new site
1. Check [issues](https://github.com/AAndyProgram/SCrawler/issues) (open and [closed](https://github.com/AAndyProgram/SCrawler/issues?q=is%3Aissue+is%3Aclosed)) and [discussions](https://github.com/AAndyProgram/SCrawler/discussions) to find your issue. Perhaps I have already answered your request.
2. If you don't find anything, create a new issue with your request. I usually reply as soon as possible (within the next few hours).
- If I'm interested in a site you want to add, it may be added in future releases.
- If the site has an API that does not require authorization, it may be added in the coming releases.
- You can make it faster by posting a link to the API. **I don't use OAuth authentication** in my application, so if it's not too hard to make a new parsing algorithm **without OAuth** authorization, I can start developing it in the coming days. Otherwise, I need time to figure out how to do it.
- If the site does not have an API that does not require authorization, this may take some time.
- If you will be posting request urls **without OAuth** authentication, I might consider adding your site if I have time.
- If I'm **not** interested in the site you want to add, you can pay to have it added by making a donation of approximately $10. **But before that, you still need to create an issue. If I'm not interested, you can offer me a deal to develop it for money. I'll check the site you want to add, check the availability of the API and tell you how much time I need to develop it and the price. If you agree, I will do it.** [![ko-fi](https://www.ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/andyprogram)
1. If you don't find anything, create a new issue with your request. I usually reply as soon as possible (within the next few hours).
# Requirements for new site requests
**Attention! I'll add a new site only if I'm interested. I also have a life, and any development takes time.**
- Post a link to the site's API
- Post request URLs **without OAuth** authentication
- Post a **complete cURL** request which provides the required information (JSON is better)
**I don't use OAuth authentication** in my application, so if it's not too hard to make a new parsing algorithm **without OAuth** authorization, I can start developing it in the coming days. Otherwise, I need time to figure out how to do it.
If I'm interested in a site you want to add, it may be added in future releases.
# Sites I will never develop
- Facebook

View File

@@ -1,3 +1,106 @@
# 2022.6.6.0
- Added
- Ability to pause automation
- Fixed
- GIFs from Twitter not downloading
- Not quite correct algorithm for stopping automation
# 2022.6.3.0
Changed version numbering method. From now on, new versions will be numbered by release date (YYYY.M.D)
**Attention! Starting with this release, SCrawler may not work on windows 7 and 8 or may not work correctly. All future releases will only be guaranteed to work on windows 10 and 11.**
- Added
- **Automation** (downloading data automatically every ```X``` minutes)
- Expanded settings for Instagram tagged posts that are downloaded for the first time.
- Fixed
- Videos hosted on Reddit that are downloaded via m3u8 playlists are missing an audio track.
- Instagram hash not able to be auto-filled from cookies
# 3.0.0.10
- Added
- **Downloading groups**
- **Download saved Twitter posts** (bookmarks)
- Ability to enable/disable progress form opening at the start of downloading
- Ability to enable/disable Info form opening at the start of downloading
- The ability to disable the opening of forms Info and Progress at the start of downloads if it was once closed
- Focusing the main window when opening Info or Progress forms
- Ability to execute a script/command when closing SCrawler
- Ability to execute a script/command after all downloads are completed
- Minor improvements
- Fixed
- Instagram tagged data not downloading (now requires one more parameter **x-csrftoken** to download tagged data)
- In some cases, Instagram Stories cannot be downloaded due to forbidden Windows characters
- Separate Instagram posts were not downloading via the Video Downloader form.
- In some cases, an Imgur video hosted on Reddit won't download
- Gfycat data not downloading from saved Reddit posts
- In some cases, the date and time are not added to the filename
- Unable to download photos from Twitter in full resolution (4K)
# 3.0.0.9
- Added
- Excluded labels
- Ability to disable user grouping
- Ability to show groups of user sites when filtering by labels
- Fixed
- Removed adding "No Parsed" internal label when not needed
- Redownloading Instagram Stories
# 3.0.0.8
- Added
- Script mode ```command```
- Disabled Instagram error 403 (Forbidden) logging for downloading tagged data
- Fixed
- The script does not run after the user download is complete
# 3.0.0.7
- Added
- Ability to run a script after the user download is complete
- Hotkey ```F2``` for additional options in the user creation form
- Fixed
- (Issue #32) In some cases, Date and Time are still not added for Stories and Tagged Photos
- (Issue #33) Instagram Stories downloading error
- LPSG downloader does not download all content
# 3.0.0.6
- Added
- ```GoTo Start``` channels button
- ```GoTo End``` channels button
- Fixed
- In some cases, saved Reddit posts didn't fully download
- Incorrect Reddit accessibility check algorithm
- Incorrect behavior of the main progress bar when downloading saved posts
- (Issue #25) Date and Time not added for Stories and Tagged Photos
# 3.0.0.5
- Added
- ```New```, ```Hot```, ```Top``` Reddit channel and user download modes
# 3.0.0.4
- Fixed
- External plugins do not save information about downloaded files
- The user cannot be added to the collection if a special path has been specified.
# 3.0.0.3
- Added
- Download all by specific sites
- Download all, ignoring the ```Ready for download``` option
- Download all by specific sites, ignoring the ```Ready for download``` option
- Fixed
- (Issue #19) Typo in default Instagram settings (Post limit timer)
- Typo when applying "Download UHD" in XVIDEOS plugin
- The sites filter does not work unless the "Fast profiles loading" option is enabled.
# 3.0.0.2
- Added

34
FAQ.md
View File

@@ -2,6 +2,8 @@
**Please read the [GUIDE](https://github.com/AAndyProgram/SCrawler/wiki/) Before asking a question!**
**Also read [here](README.md) for basic information.**
Most of your questions are already answered. All settings, functions, buttons and everything else described in the guide.
Any other questions I will keep in this file.
@@ -44,6 +46,30 @@ A: Check your credentials. Both of these sites require cookies. Check your [Twit
----
#### Q: **I have set credentials but still nothing is downloading**
A: Click the ```Start downloading``` button
----
#### Q: **Where can I find the release?**
A: https://github.com/AAndyProgram/SCrawler/releases/latest
----
#### Q: **How to run the program?**
A: Double-click ```SCrawler.exe```
----
#### Q: **Where to find binaries?**
A: https://github.com/AAndyProgram/SCrawler/releases/latest
----
#### Q: **Does the program remember the last download and check for new posts, downloading only new posts? Or does the program download the entire profile every time?**
A: The program stored posts IDs in users' folders. For the first time, the program downloads the entire profile. All subsequent times the program will check for new posts and download **only new posts**!
@@ -64,4 +90,10 @@ A: There is no functionality to remove an individual label. You can open the ```
#### Q: **How to remove a user from the blacklist**
A: Just add that user back to the program. In the dialog box that opens, click on the ```Add and remove from blacklist```` button.
A: Just add that user back to the program. In the dialog box that opens, click on the ```Add and remove from blacklist``` button.
----
#### Q: **Can you add a step-by-step guide or video on how to use the program?**
A: **NO**! I will not do it. If you want, you can create a video tutorial and send it to me. Then I add it. All options and what each option does described on the wiki. The wiki also contains a description of all settings and how-to configure them. For complex settings, there is a steep-by-steep guide. Read the [main](README.md) information and [GUIDE](https://github.com/AAndyProgram/SCrawler/wiki/) and you won't have any problems. I have developed a program with an intuitive interface. There is a Settings button, download buttons, a context menu that drops down when a user is clicked, and other controls. Anyone can use it.

View File

@@ -2,10 +2,10 @@ Your support is very valuable to me. Any support is greatly appreciated. Your su
You can support the program by:
- **Bitcoin**: bitcoin:BC1Q0NH839FT5TA44DD7L7RLR97XDQAG9V8D6N7XET
- :heavy_dollar_sign: making donaion making donations on this site: https://ko-fi.com/andyprogram
- :heavy_dollar_sign: make a donation on this site: https://ko-fi.com/andyprogram
- :repeat: make a post about my program on your profile (Reddit, Twitter, Instagram and any other social networks)
- :speech_balloon: tell your friends about the program
- :heart: like the program on this site: https://alternativeto.net/software/scrawler/about/
- suggest my program as an alternative ([on this site](https://alternativeto.net/software/scrawler/about/)) to any program you have used before
I would be very grateful for any support! :blush:
I would be very grateful for any support! :blush:

View File

@@ -1,3 +1,6 @@
List of available plugins:
- LPSG
- XVIDEOS
- XVIDEOS
Tools:
- [image2post](https://github.com/unknown81311/SCrawler-image2post) by @unknown81311: **get reddit post URL from file.**

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 377 KiB

After

Width:  |  Height:  |  Size: 379 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -5,6 +5,8 @@ https://www.4kdownload.com/products/product-stogram
| Option | SCrawler | 4K Stogram |
| ---- | ---- | ---- |
| User managament | **Advanced** | Primitive |
| Automatic downloads | **Yes** | No |
| Downloading groups | **Yes** | No |
| Labeling users | **Yes** | No |
| Filtering | **Yes** | No |
| Collections | **Yes** | No |
@@ -19,7 +21,7 @@ https://www.4kdownload.com/products/product-stogram
| See Others Instagram Feed As Your Own | No | **Yes** |
| Download Instagram Video Posts | Yes | Yes |
| Backup Your Instagram Account | Yes | Yes |
| Save Instagram Posts by Date | No (only limited download) | **Yes** |
| Save Instagram Posts by Date | Yes | Yes |
| Download Instagram Saved Posts | Yes | Yes |
| Download Instagram Tagged Posts | Yes | Yes |
| Export and import subscriptions | No | **Yes** |
@@ -44,6 +46,8 @@ https://github.com/RipMeApp/ripme
| Option | SCrawler | RipMeApp |
| ---- | ---- | ---- |
| User managament | **Advanced** | No |
| Automatic downloads | **Yes** | No |
| Downloading groups | **Yes** | No |
| Labeling users | **Yes** | No |
| Filtering | **Yes** | No |
| Collections | **Yes** | No |
@@ -75,4 +79,4 @@ https://github.com/mikf/gallery-dl
**CLI tool**! Configured with JSON files only. Users need to learn complex configuration options, JSON, commands to use that tool. Very difficult to configure.
SCrawler has advanced user management, collections, labels, groups, a beautiful view, GUI, the ability to add plugins for other sites and much more. Just try it and compare.
SCrawler has advanced user management, collections, labels, groups, automatic downloads, a beautiful view, GUI, the ability to add plugins for other sites and much more. Just try it and compare.

View File

@@ -1,7 +1,7 @@
# Social networks crawler
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/AAndyProgram/SCrawler)](https://github.com/AAndyProgram/SCrawler/releases/latest)
[![GitHub](https://img.shields.io/github/license/AAndyProgram/SCrawler)](https://github.com/AAndyProgram/SCrawler/)
[![GitHub license](https://img.shields.io/github/license/AAndyProgram/SCrawler)](https://github.com/AAndyProgram/SCrawler/blob/main/LICENSE)
[![FAQ](https://img.shields.io/badge/FAQ-green)](FAQ.md)
[![GUIDE](https://img.shields.io/badge/GUIDE-green)](https://github.com/AAndyProgram/SCrawler/wiki)
[![How to support](https://img.shields.io/badge/HowToSupport-green)](HowToSupport.md)
@@ -21,20 +21,24 @@ Do you like this program? Consider adding to my coffee fund by making a donation
- Download pictures and videos from users' profiles and subreddits:
- Reddit images;
- Reddit galleries of images;
- Redgifs hosted videos (https://www.redgifs.com/);
- Reddit hosted videos (downloading Reddit hosted video is going through ffmpeg (**ffmpeg only works with the x64 program**));
- Reddit videos (downloading Reddit hosted video is going through ffmpeg (**ffmpeg only works with the x64 program**));
- Redgifs videos (https://www.redgifs.com/);
- Twitter images and videos;
- Instagram images and videos.
- Imgur images, galleries and videos
- Gfycat videos
- Instagram images and videos;
- Instagram tagged posts;
- Instagram stories;
- Imgur images, galleries and videos;
- Gfycat videos;
- [Other](#supported-sites) supported sites
- Parse [channel and view data](https://github.com/AAndyProgram/SCrawler/wiki/Channels).
- Download [saved Reddit and Instagram posts](https://github.com/AAndyProgram/SCrawler/wiki/Home#saved-posts).
- Add users from parsed channel.
- **Advanced user management.**
- Labeling users.
- Adding users to favorites and temporary.
- Filter exists users by label or group.
- Parse [channel and view data](https://github.com/AAndyProgram/SCrawler/wiki/Channels)
- Download [saved Reddit, Twitter and Instagram posts](https://github.com/AAndyProgram/SCrawler/wiki/Home#saved-posts)
- Add users from parsed channel
- **Advanced user management**
- **Automation** (downloading data automatically every ```X``` minutes)
- Labeling users
- Create download groups
- Adding users to favorites and temporary
- Filter exists users by label or group
- Selection of media types you want to download (images only, videos only, both)
- Download a special video, image or gallery
- Making collections (grouping users into collections)
@@ -75,7 +79,7 @@ Read [here](CONTRIBUTING.md#how-to-request-a-new-site) about
# Requirements
- Windows 7, 8, 9, 10, 11 with NET Framework 4.6.1 or higher
- Windows 10, 11 with NET Framework 4.6.1 or higher (v4.6.1 must be installed). You can check version compatibility with this [tool](Tools/NET.FrameworkVersion.ps1).
- Authorization [cookies](https://github.com/AAndyProgram/SCrawler/wiki/Settings#how-to-set-up-cookies) and [tokens](https://github.com/AAndyProgram/SCrawler/wiki/Settings#how-to-find-twitter-tokens) for Twitter (if you want to download data from Twitter)
- Authorization [cookies](https://github.com/AAndyProgram/SCrawler/wiki/Settings#how-to-set-up-cookies) and [Hash](https://github.com/AAndyProgram/SCrawler/wiki/Settings#instagram) for Instagram (if you want to download data from Instagram), [Hash 2](https://github.com/AAndyProgram/SCrawler/wiki/Settings#how-to-find-instagram-hash-2) for saved Instagram posts, Instagram [stories authorization headers](https://github.com/AAndyProgram/SCrawler/wiki/Settings#how-to-find-instagram-stories-authorization-headers) for Stories and Tagged data
- ffmpeg library for downloading videos hosted on Reddit (you can download it from the [official repo](https://github.com/GyanD/codexffmpeg/releases/tag/2021-01-12-git-ca21cb1e36) or [from my first release](https://github.com/AAndyProgram/SCrawler/releases/download/1.0.0.0/ffmpeg.zip)). **ffmpeg only works with the x64 version of the program.**
@@ -86,7 +90,7 @@ Read [here](CONTRIBUTING.md#how-to-request-a-new-site) about
# Installation
**Just unzip the program archive to any folder, copy the file ```ffmpeg.exe``` into it and enjoy.** :blush:
**Just download the [latest release](https://github.com/AAndyProgram/SCrawler/releases/latest), unzip the program archive to any folder, copy the file ```ffmpeg.exe``` into it and enjoy.** :blush:
**Don't put program in the ```Program Files``` system folder (this is portable program and program settings are stored in the program folder)**
@@ -97,7 +101,8 @@ Just download [latest](https://github.com/AAndyProgram/SCrawler/releases/latest)
# How to build from source
1. Delete the "PersonalUtilities" project from the solution.
1. Add the latest version of the "PersonalUtilities.dll" library (from the [latest release](https://github.com/AAndyProgram/SCrawler/releases/latest)).
1. Delete the "PersonalUtilities.Notifications" project from the solution.
1. Add the latest versions of the ```PersonalUtilities.dll``` and ```PersonalUtilities.Notifications.dll``` libraries (from the [latest release](https://github.com/AAndyProgram/SCrawler/releases/latest)).
1. Import PersonalUtilities.Functions for the whole project.
# How to make a plugin
@@ -116,7 +121,7 @@ You need to set up authorization for Twitter and Instagram:
- Authorization [cookies](https://github.com/AAndyProgram/SCrawler/wiki/Settings#how-to-set-up-cookies) and [tokens](https://github.com/AAndyProgram/SCrawler/wiki/Settings#how-to-find-twitter-tokens) for **Twitter** (if you want to download data from Twitter)
- Authorization [cookies](https://github.com/AAndyProgram/SCrawler/wiki/Settings#how-to-set-up-cookies) and [Hash](https://github.com/AAndyProgram/SCrawler/wiki/Settings#instagram) for **Instagram** (if you want to download data from Instagram), [Hash 2](https://github.com/AAndyProgram/SCrawler/wiki/Settings#how-to-find-instagram-hash-2) for **saved Instagram posts**, Instagram [stories authorization headers](https://github.com/AAndyProgram/SCrawler/wiki/Settings#how-to-find-instagram-stories-authorization-headers) for **Stories** and **Tagged data**
Just add a user profile and click the ```Start downloading``` button.
Just add a user profile and **click the ```Start downloading``` button**.
You can add users by patterns:
- https://www.instagram.com/SomeUserName

View File

@@ -9,10 +9,15 @@
Imports PersonalUtilities.Functions.RegularExpressions
Friend Module Declarations
Friend ReadOnly Property PhotoRegEx As RParams = RParams.DM("(https://www.lpsg.com/attachments)(.+?)(?="")", 0, RegexReturn.List)
Friend ReadOnly Property PhotoRegExExt As New RParams("img.data.src=""(/proxy[^""]+?)""", Nothing, 1, RegexReturn.List) With {
.Converter = Function(Input) $"https://www.lpsg.com/{SymbolsConverter.HTML.Decode(Input)}"}
Friend ReadOnly Property NextPageRegex As RParams = RParams.DMS("<link rel=""next"" href=""(.+?/page-(\d+))""", 2)
Private Const FileUrlRegexDefault As String = "(.+[^/]+?)(jpg|jpeg|gif|png)"
Private Const FileUrlRegexDefault As String = "([^/]+?)(jpg|jpeg|gif|png|webm)"
Private ReadOnly InputFReplacer As New ErrorsDescriber(EDP.ReturnValue)
Private ReadOnly InputForbidRemover As Func(Of String, String) = Function(Input) If(Input.IsEmptyString, Input, Input.StringRemoveWinForbiddenSymbols(, InputFReplacer))
Friend ReadOnly Property FileRegEx As New RParams(FileUrlRegexDefault, Nothing, 0) With {
.Converter = Function(ByVal Input As String) As String
Input = InputForbidRemover.Invoke(Input)
If Not Input.IsEmptyString Then
Dim lv$ = Input.Split("-").LastOrDefault
If Not lv.IsEmptyString Then
@@ -22,5 +27,22 @@ Friend Module Declarations
End If
Return Input
End Function}
Friend ReadOnly Property FileRegExExt As New RParams(FileUrlRegexDefault, 0, Nothing, InputForbidRemover)
Friend ReadOnly Property FileRegExExt2 As New RParams("([^/]+?)(?=(\Z|&))", 0, Nothing, InputForbidRemover)
Friend ReadOnly Property FileExistsRegEx As RParams = RParams.DMS(FileUrlRegexDefault, 2)
Private Class PUMComparer : Implements IEqualityComparer, IEqualityComparer(Of PluginUserMedia)
Private Overloads Function Equals(ByVal x As PluginUserMedia, ByVal y As PluginUserMedia) As Boolean Implements IEqualityComparer(Of PluginUserMedia).Equals
Return x.URL = y.URL
End Function
Private Function IEqualityComparer_Equals(ByVal x As Object, ByVal y As Object) As Boolean Implements IEqualityComparer.Equals
Return DirectCast(x, PluginUserMedia).URL = DirectCast(y, PluginUserMedia).URL
End Function
Private Overloads Function GetHashCode(ByVal Obj As Object) As Integer Implements IEqualityComparer.GetHashCode
Throw New NotImplementedException()
End Function
Private Overloads Function GetHashCode(ByVal Obj As PluginUserMedia) As Integer Implements IEqualityComparer(Of PluginUserMedia).GetHashCode
Throw New NotImplementedException()
End Function
End Class
Friend ReadOnly TempListAddParams As New ListAddParams(LAP.NotContainsOnly) With {.Comparer = New PUMComparer}
End Module

View File

@@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices
' by using the '*' as shown below:
' <Assembly: AssemblyVersion("1.0.*")>
<Assembly: AssemblyVersion("1.0.0.0")>
<Assembly: AssemblyFileVersion("1.0.0.0")>
<Assembly: AssemblyVersion("2022.6.3.0")>
<Assembly: AssemblyFileVersion("2022.6.3.0")>
<Assembly: NeutralResourcesLanguage("en")>

View File

@@ -91,7 +91,7 @@ Public Class SiteSettings : Implements ISiteSettings
Public Function GetSpecialData(ByVal URL As String, ByVal Path As String, ByVal AskForPath As Boolean) As IEnumerable(Of PluginUserMedia) Implements ISiteSettings.GetSpecialData
Return Nothing
End Function
Public Function Available(ByVal What As ISiteSettings.Download) As Boolean Implements ISiteSettings.Available
Public Function Available(ByVal What As ISiteSettings.Download, ByVal Silent As Boolean) As Boolean Implements ISiteSettings.Available
Return True
End Function
Public Function ReadyToDownload(ByVal What As ISiteSettings.Download) As Boolean Implements ISiteSettings.ReadyToDownload

View File

@@ -7,6 +7,9 @@
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY
Imports PersonalUtilities.Functions.RegularExpressions
Imports UStates = SCrawler.Plugin.PluginUserMedia.States
Imports UTypes = SCrawler.Plugin.PluginUserMedia.Types
Imports Converters = PersonalUtilities.Functions.SymbolsConverter.Converters
Public Class UserData : Implements IPluginContentProvider
#Region "XML names"
Private Const Name_LatestPage As String = "LatestPage"
@@ -58,14 +61,14 @@ Public Class UserData : Implements IPluginContentProvider
#End Region
Private Property LatestPage As String = String.Empty
Private Property Responser As Response = Nothing
Private Enum Mode : Internal : External : End Enum
Public Sub GetMedia() Implements IPluginContentProvider.GetMedia
Try
If Not Responser Is Nothing Then Responser.Dispose()
Responser = New Response
With Responser : .Copy(Settings.Responser) : .Error = EDP.ThrowException : End With
Dim l As List(Of String) = Nothing
Dim NextPage$ = String.Empty
Dim NextPage$
Dim r$
Dim _LPage As Func(Of String) = Function() If(LatestPage.IsEmptyString, String.Empty, $"page-{LatestPage}")
@@ -76,35 +79,60 @@ Public Class UserData : Implements IPluginContentProvider
Thrower.ThrowAny()
If Not r.IsEmptyString Then
NextPage = RegexReplace(r, NextPageRegex)
l.ListAddList(RegexReplace(r, PhotoRegEx), LAP.NotContainsOnly)
UpdateMediaList(RegexReplace(r, PhotoRegEx), Mode.Internal)
UpdateMediaList(RegexReplace(r, PhotoRegExExt), Mode.External)
If NextPage = LatestPage Or NextPage.IsEmptyString Then Exit Do Else LatestPage = NextPage
Else
Exit Do
End If
Loop
If l.ListExists Then
Dim f As SFile
For Each u$ In l
If Not IsEmptyString(RegexReplace(u, FileExistsRegEx)) Then
f = CStr(RegexReplace(u, FileRegEx))
f.Path = DataPath.CSFilePSN
f.Separator = "\"
TempMediaList.Add(New PluginUserMedia With {.ContentType = PluginUserMedia.Types.Picture, .URL = u, .File = f})
End If
Next
If TempMediaList.ListExists And ExistingContentList.ListExists Then _
TempMediaList.RemoveAll(Function(m) ExistingContentList.Exists(Function(mm) mm.URL = m.URL))
End If
If TempMediaList.ListExists And ExistingContentList.ListExists Then _
TempMediaList.RemoveAll(Function(m) ExistingContentList.Exists(Function(mm) mm.URL = m.URL))
Catch oex As OperationCanceledException
Catch dex As ObjectDisposedException
Catch ex As Exception
LogProvider.Add(ex, "[LPSG.UserData.GetMedia]")
If Responser.StatusCode = Net.HttpStatusCode.ServiceUnavailable Then
LogProvider.Add("LPSG not available")
Else
LogProvider.Add(ex, "[LPSG.UserData.GetMedia]")
End If
End Try
End Sub
Private Sub UpdateMediaList(ByVal l As List(Of String), ByVal m As Mode)
If l.ListExists Then
Dim f As SFile
Dim u$
Dim exists As Boolean
Dim r As RParams
Dim ude As New ErrorsDescriber(EDP.ReturnValue)
For Each url$ In l
If Not url.IsEmptyString Then u = SymbolsConverter.Decode(url, {Converters.HTML, Converters.ASCII}, ude) Else u = String.Empty
If Not u.IsEmptyString Then
exists = Not IsEmptyString(RegexReplace(u, FileExistsRegEx))
If m = Mode.Internal Then
r = FileRegEx
Else
r = FileRegExExt
If Not exists Then
r = FileRegExExt2
exists = Not IsEmptyString(RegexReplace(u, FileRegExExt2))
End If
End If
If exists Then
f = CStr(RegexReplace(u, r))
f.Path = DataPath.CSFilePSN
f.Separator = "\"
If f.Extension.IsEmptyString Then f.Extension = "jpg"
TempMediaList.ListAddValue(New PluginUserMedia With {.ContentType = UTypes.Picture, .URL = url, .File = f}, TempListAddParams)
End If
End If
Next
End If
End Sub
Public Sub Download() Implements IPluginContentProvider.Download
Try
With Responser : .UseWebClient = True : .UseWebClientCookies = True : End With
With Responser : .UseWebClient = True : .UseWebClientCookies = True : .ResetError() : End With
If TempMediaList.ListExists Then
Dim m As PluginUserMedia
Dim eweb As ErrorsDescriber = EDP.ThrowException
@@ -112,15 +140,20 @@ Public Class UserData : Implements IPluginContentProvider
For i% = 0 To TempMediaList.Count - 1
Thrower.ThrowAny()
m = TempMediaList(i)
m.DownloadState = PluginUserMedia.States.Tried
m.DownloadState = UStates.Tried
Try
If Not m.URL.IsEmptyString And Not m.File.IsEmptyString Then
Responser.DownloadFile(m.URL, m.File, eweb)
m.DownloadState = PluginUserMedia.States.Downloaded
m.DownloadState = UStates.Downloaded
Else
m.DownloadState = PluginUserMedia.States.Skipped
m.DownloadState = UStates.Skipped
End If
Catch wex As Exception
If Responser.Client.StatusCode = Net.HttpStatusCode.ServiceUnavailable Then
LogProvider.Add("LPSG not available")
Else
m.DownloadState = UStates.Skipped
End If
Catch ex As Exception
End Try
RaiseEvent ProgressChanged(1)
TempMediaList(i) = m

View File

@@ -41,7 +41,8 @@ Friend NotInheritable Class M3U8
Return Nothing
Catch ex As Exception
Logger.Add(ex, "[M3U8.Save]")
Return Nothing
ex.HelpLink = 1
Throw ex
Finally
CachePath.Delete(SFO.Path, SFODelete.None, EDP.None)
End Try
@@ -61,8 +62,8 @@ Friend NotInheritable Class M3U8
End If
Return Nothing
Catch ex As Exception
Logger.Add(ex, "[M3U8.Download]")
Return Nothing
If Not ex.HelpLink = 1 Then Logger.Add(ex, "[M3U8.Download]")
Throw ex
End Try
End Function
End Class

View File

@@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices
' by using the '*' as shown below:
' <Assembly: AssemblyVersion("1.0.*")>
<Assembly: AssemblyVersion("1.0.0.0")>
<Assembly: AssemblyFileVersion("1.0.0.0")>
<Assembly: AssemblyVersion("2022.6.6.0")>
<Assembly: AssemblyFileVersion("2022.6.6.0")>
<Assembly: NeutralResourcesLanguage("en")>

View File

@@ -29,7 +29,7 @@ Public Class SettingsForm : Implements IOkCancelToolbar
MyDefs.InvokeLoaderError(ex)
End Try
End Sub
Private Sub ToolbarBttOK() Implements IOkCancelToolbar.ToolbarBttOK
Private Sub OK() Implements IOkCancelToolbar.OK
Settings.Domains.Clear()
With LIST_DOMAINS
If .Items.Count > 0 Then
@@ -39,7 +39,7 @@ Public Class SettingsForm : Implements IOkCancelToolbar
Settings.UpdateDomains()
MyDefs.CloseForm()
End Sub
Private Sub ToolbarBttCancel() Implements IOkCancelToolbar.ToolbarBttCancel
Private Sub Cancel() Implements IOkCancelToolbar.Cancel
MyDefs.CloseForm(Windows.Forms.DialogResult.Cancel)
End Sub
Private Sub BTT_ADD_Click(sender As Object, e As EventArgs) Handles BTT_ADD.Click

View File

@@ -78,12 +78,12 @@ Public Class SiteSettings : Implements ISiteSettings
If Not ACheck(SiteDomains.Value) Then SiteDomains.Value = DomainsDefault
Domains.ListAddList(CStr(SiteDomains.Value).Split("|"), LAP.NotContainsOnly, LAP.ClearBeforeAdd)
Domains.ListAddList(DomainsDefault.Split("|"), LAP.NotContainsOnly)
SiteDomains.Value = Domains.ListToString(, "|")
SiteDomains.Value = Domains.ListToString("|")
_DomainsUpdateInProgress = False
End If
End Sub
#Region "Downloading"
Public Function Available(ByVal What As ISiteSettings.Download) As Boolean Implements ISiteSettings.Available
Public Function Available(ByVal What As ISiteSettings.Download, ByVal Silent As Boolean) As Boolean Implements ISiteSettings.Available
Return UseM3U8
End Function
Public Function ReadyToDownload(ByVal What As ISiteSettings.Download) As Boolean Implements ISiteSettings.ReadyToDownload

View File

@@ -10,6 +10,8 @@ Imports PersonalUtilities.Functions.RegularExpressions
Imports PersonalUtilities.Functions.XML
Imports PersonalUtilities.Tools.WEB
Imports PersonalUtilities.Tools.WebDocuments.JSON
Imports UStates = SCrawler.Plugin.PluginUserMedia.States
Imports UTypes = SCrawler.Plugin.PluginUserMedia.Types
Public Class UserData : Implements IPluginContentProvider
#Region "Interface declarations"
Public Event ProgressChanged(Count As Integer) Implements IPluginContentProvider.ProgressChanged
@@ -71,7 +73,7 @@ Public Class UserData : Implements IPluginContentProvider
Thrower.ThrowAny()
r = Responser.GetResponse($"https://www.xvideos.com/{user}/videos/new/{If(NextPage = 0, String.Empty, NextPage)}",, e)
If Not r.IsEmptyString Then
If Not EnvirSet Then UserExists = True : UserSuspended = False
If Not EnvirSet Then UserExists = True : UserSuspended = False : EnvirSet = True
j = JsonDocument.Parse(r).XmlIfNothing
With j
If .Contains("videos") Then
@@ -90,6 +92,7 @@ Public Class UserData : Implements IPluginContentProvider
End If
End With
Else
.Dispose()
Exit Do
End If
.Dispose()
@@ -147,7 +150,7 @@ Public Class UserData : Implements IPluginContentProvider
r = resp.GetResponse(m,, EDP.ThrowException)
If Not r.IsEmptyString Then
Dim ls As List(Of VSize) = FNF.RegexFields(Of VSize)(r, {M3U8Reparse}, {1, 2})
If ls.ListExists And DownloadUHD Then ls.RemoveAll(Function(v) v.Size > 1080)
If ls.ListExists And Not DownloadUHD Then ls.RemoveAll(Function(v) v.Size > 1080)
If ls.ListExists Then
ls.Sort()
m = $"{appender}/{ls(0).Value}"
@@ -164,7 +167,7 @@ Public Class UserData : Implements IPluginContentProvider
End If
If Not m.IsEmptyString Then
Return New PluginUserMedia With {
.ContentType = PluginUserMedia.Types.m3u8,
.ContentType = UTypes.m3u8,
.PostID = pID,
.URL = m,
.File = $"{t}.mp4",
@@ -194,9 +197,14 @@ Public Class UserData : Implements IPluginContentProvider
m = TempMediaList(i)
f = m.File
f.Path = DefPath
f = M3U8.Download(m.URL, m.SpecialFolder, Settings.FfmpegFile, f, LogProvider)
m.File = f
If Not f.IsEmptyString Then m.DownloadState = PluginUserMedia.States.Downloaded
m.DownloadState = UStates.Tried
Try
f = M3U8.Download(m.URL, m.SpecialFolder, Settings.FfmpegFile, f, LogProvider)
m.File = f
m.DownloadState = UStates.Downloaded
Catch ex As Exception
m.DownloadState = UStates.Skipped
End Try
TempMediaList(i) = m
RaiseEvent ProgressChanged(1)
Next

View File

@@ -33,7 +33,7 @@ Namespace Plugin
Sub EndUpdate()
#End Region
#Region "Site availability"
Function Available(ByVal What As Download) As Boolean
Function Available(ByVal What As Download, ByVal Silent As Boolean) As Boolean
Function ReadyToDownload(ByVal What As Download) As Boolean
#End Region
#Region "Downloading"

View File

@@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices
' by using the '*' as shown below:
' <Assembly: AssemblyVersion("1.0.*")>
<Assembly: AssemblyVersion("3.0.0.2")>
<Assembly: AssemblyFileVersion("3.0.0.2")>
<Assembly: AssemblyVersion("2022.6.3.0")>
<Assembly: AssemblyFileVersion("2022.6.3.0")>
<Assembly: NeutralResourcesLanguage("en")>

View File

@@ -21,6 +21,8 @@ Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "SCrawler.Plugin.LPSG", "SCr
EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "SCrawler.Plugin.XVIDEOS", "SCrawler.Plugin.XVIDEOS\SCrawler.Plugin.XVIDEOS.vbproj", "{CCCF47F4-C97C-4193-AC4B-C56DF2F9AA8A}"
EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "PersonalUtilities.Notifications", "..\..\MyUtilities\PersonalUtilities.Notifications\PersonalUtilities.Notifications.vbproj", "{FC532253-1AB3-4DEF-A28A-DFDD9A481EB2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -91,6 +93,18 @@ Global
{CCCF47F4-C97C-4193-AC4B-C56DF2F9AA8A}.Release|x64.Build.0 = Release|x64
{CCCF47F4-C97C-4193-AC4B-C56DF2F9AA8A}.Release|x86.ActiveCfg = Release|x86
{CCCF47F4-C97C-4193-AC4B-C56DF2F9AA8A}.Release|x86.Build.0 = Release|x86
{FC532253-1AB3-4DEF-A28A-DFDD9A481EB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FC532253-1AB3-4DEF-A28A-DFDD9A481EB2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC532253-1AB3-4DEF-A28A-DFDD9A481EB2}.Debug|x64.ActiveCfg = Debug|x64
{FC532253-1AB3-4DEF-A28A-DFDD9A481EB2}.Debug|x64.Build.0 = Debug|x64
{FC532253-1AB3-4DEF-A28A-DFDD9A481EB2}.Debug|x86.ActiveCfg = Debug|x86
{FC532253-1AB3-4DEF-A28A-DFDD9A481EB2}.Debug|x86.Build.0 = Debug|x86
{FC532253-1AB3-4DEF-A28A-DFDD9A481EB2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC532253-1AB3-4DEF-A28A-DFDD9A481EB2}.Release|Any CPU.Build.0 = Release|Any CPU
{FC532253-1AB3-4DEF-A28A-DFDD9A481EB2}.Release|x64.ActiveCfg = Release|x64
{FC532253-1AB3-4DEF-A28A-DFDD9A481EB2}.Release|x64.Build.0 = Release|x64
{FC532253-1AB3-4DEF-A28A-DFDD9A481EB2}.Release|x86.ActiveCfg = Release|x86
{FC532253-1AB3-4DEF-A28A-DFDD9A481EB2}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -33,25 +33,32 @@ Namespace API.Base
Friend Shared Function GetData(ByVal Site As String) As List(Of Data)
Try
Dim l As List(Of Data) = Nothing
Dim l2 As List(Of Data) = Nothing
Using w As New WebClient
Dim r$ = w.DownloadString($"https://downdetector.co.uk/status/{Site}/")
If Not r.IsEmptyString Then
l = FNF.RegexFields(Of Data)(r, {Params}, {1, 2})
If l.ListExists(2) Then
Dim lDate As Date = l(0).Date
Dim i%
Dim indx% = -1
For i = 1 To l.Count - 1
If l(i).Date < lDate Then indx = i : Exit For Else lDate = l(i).Date
Next
If indx >= 0 Then
For i = indx To 0 Step -1 : l.RemoveAt(i) : Next
End If
l.Sort()
l2 = New List(Of Data)
Dim d As Data
Dim eDates As New List(Of Date)
Dim MaxValue As Func(Of Date, Integer) = Function(dd) (From ddd In l Where ddd.Date = dd Select ddd.Value).DefaultIfEmpty(0).Max
For i% = 0 To l.Count - 1
If Not eDates.Contains(l(i).Date) Then
d = l(i)
d.Value = MaxValue(d.Date)
l2.Add(d)
eDates.Add(d.Date)
End If
Next
eDates.Clear()
l.Clear()
l2.Sort()
End If
End If
End Using
Return l
Return l2
Catch ex As Exception
Return ErrorsDescriber.Execute(EDP.SendInLog + EDP.ReturnValue, ex, $"[DownDetector.GetData({Site})]")
End Try

View File

@@ -21,7 +21,7 @@ Namespace API.Base
Friend Sub Download(ByVal Token As CancellationToken)
Try
If HOST.Source.ReadyToDownload(PDownload.SavedPosts) Then
If HOST.Available(PDownload.SavedPosts) Then
If HOST.Available(PDownload.SavedPosts, False) Then
HOST.DownloadStarted(PDownload.SavedPosts)
Dim u As New UserInfo With {.Plugin = HOST.Key, .Site = HOST.Name, .SpecialPath = HOST.SavedPostsPath}
Using user As IUserData = HOST.GetInstance(PDownload.SavedPosts, Nothing, False, False)

View File

@@ -91,7 +91,7 @@ Namespace API.Base
End Function
#End Region
#Region "Ready, Available"
Friend Overridable Function Available(ByVal What As Download) As Boolean Implements ISiteSettings.Available
Friend Overridable Function Available(ByVal What As Download, ByVal Silent As Boolean) As Boolean Implements ISiteSettings.Available
Return True
End Function
Friend Overridable Function ReadyToDownload(ByVal What As Download) As Boolean Implements ISiteSettings.ReadyToDownload

View File

@@ -10,6 +10,7 @@ Imports PersonalUtilities.Functions.XML
Imports PersonalUtilities.Functions.RegularExpressions
Imports PersonalUtilities.Forms.Toolbars
Imports PersonalUtilities.Tools.WEB
Imports PersonalUtilities.Tools
Imports System.IO
Imports System.Net
Imports System.Threading
@@ -115,6 +116,9 @@ Namespace API.Base
Private Const Name_PicturesCount As String = "PicturesCount"
Private Const Name_LastUpdated As String = "LastUpdated"
Private Const Name_ScriptUse As String = "ScriptUse"
Private Const Name_ScriptData As String = "ScriptData"
Private Const Name_DataMerging As String = "DataMerging"
#Region "Downloaded data"
Private Const Name_MediaType As String = "Type"
@@ -205,11 +209,14 @@ Namespace API.Base
#Region "Images"
Friend Overridable Function GetUserPicture() As Image Implements IUserData.GetPicture
If Settings.ViewModeIsPicture Then
Return GetPicture()
Return GetPicture(Of Image)()
Else
Return Nothing
End If
End Function
Friend Function GetUserPictureAddress() As SFile
Return GetPicture(Of SFile)(False)
End Function
Friend Overridable Sub SetPicture(ByVal f As SFile) Implements IUserData.SetPicture
Try
If Not f.IsEmptyString AndAlso f.Exists Then
@@ -221,7 +228,8 @@ Namespace API.Base
Protected Function GetNullPicture(ByVal MaxHeigh As XML.Base.XMLValue(Of Integer)) As Bitmap
Return New Bitmap(CInt(DivideWithZeroChecking(MaxHeigh.Value, 100) * 75), MaxHeigh.Value)
End Function
Protected Function GetPicture(Optional ByVal ReturnNullImageOnNothing As Boolean = True) As Image
Protected Function GetPicture(Of T)(Optional ByVal ReturnNullImageOnNothing As Boolean = True) As T
Dim rsfile As Boolean = GetType(T) Is GetType(SFile)
Dim f As SFile = Nothing
Dim p As UserImage = Nothing
Dim DelPath As Boolean = True
@@ -248,7 +256,7 @@ BlockPictureFolder:
End If
BlockPictureScan:
On Error GoTo BlockDeletePictureFolder
Dim NewPicFile As SFile = SFile.GetFiles(MyFile.CutPath, "*.jpg|*.png",,
Dim NewPicFile As SFile = SFile.GetFiles(MyFile.CutPath, "*.jpg|*.jpeg|*.png",,
New ErrorsDescriber(EDP.ReturnValue) With {
.ReturnValue = New List(Of SFile),
.ReturnValueExists = True}).FirstOrDefault
@@ -267,18 +275,21 @@ BlockReturn:
On Error GoTo BlockNullPicture
If Not p Is Nothing Then
Dim i As Image = Nothing
Select Case Settings.ViewMode.Value
Case View.LargeIcon : i = p.Large.OriginalImage.Clone
Case View.SmallIcon : i = p.Small.OriginalImage.Clone
End Select
Dim a As SFile = p.Address
If Not rsfile Then
Select Case Settings.ViewMode.Value
Case View.LargeIcon : i = p.Large.OriginalImage.Clone
Case View.SmallIcon : i = p.Small.OriginalImage.Clone
End Select
End If
p.Dispose()
Return i
If rsfile Then Return CObj(a) Else Return CObj(i)
End If
BlockNullPicture:
If ReturnNullImageOnNothing Then
Select Case Settings.ViewMode.Value
Case View.LargeIcon : Return GetNullPicture(Settings.MaxLargeImageHeigh)
Case View.SmallIcon : Return GetNullPicture(Settings.MaxSmallImageHeigh)
Case View.LargeIcon : Return CObj(GetNullPicture(Settings.MaxLargeImageHeigh))
Case View.SmallIcon : Return CObj(GetNullPicture(Settings.MaxSmallImageHeigh))
End Select
End If
Return Nothing
@@ -333,6 +344,13 @@ BlockNullPicture:
Protected ReadOnly _ContentNew As List(Of UserMedia)
Protected ReadOnly _TempMediaList As List(Of UserMedia)
Protected ReadOnly _TempPostsList As List(Of String)
Friend Function GetLastImageAddress() As SFile
If _ContentList.Count > 0 Then
Return _ContentList.LastOrDefault(Function(c) c.Type = UTypes.Picture And Not c.File.IsEmptyString And Not c.File.Extension = "gif").File
Else
Return Nothing
End If
End Function
#End Region
#Region "Files"
Friend Overridable Property MyFile As SFile Implements IUserData.File
@@ -405,6 +423,10 @@ BlockNullPicture:
End Get
End Property
#End Region
#Region "Script"
Friend Overridable Property ScriptUse As Boolean = False Implements IUserData.ScriptUse
Friend Overridable Property ScriptData As String Implements IUserData.ScriptData
#End Region
#End Region
#Region "Plugins Support"
Protected Event ProgressChanged As IPluginContentProvider.ProgressChangedEventHandler Implements IPluginContentProvider.ProgressChanged
@@ -469,6 +491,7 @@ BlockNullPicture:
Get
If Settings.LastUpdatedDate.HasValue AndAlso LastUpdated.HasValue AndAlso
LastUpdated.Value.Date > Settings.LastUpdatedDate.Value.Date Then Return False
If Not Settings.Labels.ExcludedIgnore AndAlso Settings.Labels.Excluded.ValuesList.ListContains(Labels) Then Return False
If Settings.SelectedSites.Count = 0 OrElse Settings.SelectedSites.Contains(Site) Then
Select Case Settings.ShowingMode.Value
Case ShowingModes.Regular : Return Not Temporary And Not Favorite
@@ -476,7 +499,7 @@ BlockNullPicture:
Case ShowingModes.Favorite : Return Favorite
Case ShowingModes.Deleted : Return Not UserExists
Case ShowingModes.Suspended : Return UserSuspended
Case ShowingModes.Labels : Return Settings.Labels.CurrentSelection.ListContains(Labels)
Case ShowingModes.Labels : Return Settings.Labels.Current.ValuesList.ListContains(Labels)
Case ShowingModes.NoLabels : Return Labels.Count = 0
Case Else : Return True
End Select
@@ -487,16 +510,16 @@ BlockNullPicture:
End Property
Friend Function GetLVIGroup(ByVal Destination As ListView) As ListViewGroup Implements IUserData.GetLVIGroup
Try
If Settings.ShowingMode.Value = ShowingModes.Labels Then
If Labels.Count > 0 And Settings.Labels.CurrentSelection.Count > 0 Then
If Settings.ShowingMode.Value = ShowingModes.Labels And Not Settings.ShowGroupsInsteadLabels Then
If Labels.Count > 0 And Settings.Labels.Current.Count > 0 Then
For i% = 0 To Labels.Count - 1
If Settings.Labels.CurrentSelection.Contains(Labels(i)) Then Return Destination.Groups.Item(Labels(i))
If Settings.Labels.Current.Contains(Labels(i)) Then Return Destination.Groups.Item(Labels(i))
Next
End If
Return Destination.Groups.Item(LabelsKeeper.NoLabeledName)
Else
ElseIf Settings.ShowGroups Then
Return Destination.Groups.Item(GetLviGroupName(HOST, Temporary, Favorite, IsCollection, IsChannel))
End If
Return Destination.Groups.Item(LabelsKeeper.NoLabeledName)
Catch ex As Exception
Return Destination.Groups.Item(LabelsKeeper.NoLabeledName)
End Try
@@ -559,7 +582,7 @@ BlockNullPicture:
If MyFile.Exists Then
FileExists = True
Using x As New XmlFile(MyFile) With {.XmlReadOnly = True}
User.Name = x.Value(Name_UserName)
If User.Name.IsEmptyString Then User.Name = x.Value(Name_UserName)
UserExists = x.Value(Name_UserExists).FromXML(Of Boolean)(True)
UserSuspended = x.Value(Name_UserSuspended).FromXML(Of Boolean)(False)
ID = x.Value(Name_UserID)
@@ -576,6 +599,8 @@ BlockNullPicture:
DownloadedVideos(True) = x.Value(Name_VideoCount).FromXML(Of Integer)(0)
DownloadedPictures(True) = x.Value(Name_PicturesCount).FromXML(Of Integer)(0)
LastUpdated = AConvert(Of Date)(x.Value(Name_LastUpdated), ADateTime.Formats.BaseDateTime, Nothing)
ScriptUse = x.Value(Name_ScriptUse).FromXML(Of Boolean)(False)
ScriptData = x.Value(Name_ScriptData)
DataMerging = x.Value(Name_DataMerging).FromXML(Of Boolean)(False)
ChangeCollectionName(x.Value(Name_CollectionName), False)
Labels.ListAddList(x.Value(Name_LabelsName).StringToList(Of String, List(Of String))("|", EDP.ReturnValue), LAP.NotContainsOnly, LAP.ClearBeforeAdd)
@@ -615,8 +640,10 @@ BlockNullPicture:
x.Add(Name_VideoCount, DownloadedVideos(True))
x.Add(Name_PicturesCount, DownloadedPictures(True))
x.Add(Name_LastUpdated, AConvert(Of String)(LastUpdated, ADateTime.Formats.BaseDateTime, String.Empty))
x.Add(Name_ScriptUse, ScriptUse.BoolToInteger)
x.Add(Name_ScriptData, ScriptData)
x.Add(Name_CollectionName, CollectionName)
x.Add(Name_LabelsName, Labels.ListToString(, "|", EDP.ReturnValue))
x.Add(Name_LabelsName, Labels.ListToString("|", EDP.ReturnValue))
x.Add(Name_DataMerging, DataMerging.BoolToInteger)
LoadUserInformation_OptionalFields(x, False)
@@ -724,7 +751,7 @@ BlockNullPicture:
Responser = New Response
If Not HOST.Responser Is Nothing Then Responser.Copy(HOST.Responser)
Dim UpPic As Boolean = Settings.ViewModeIsPicture AndAlso GetPicture(False) Is Nothing
Dim UpPic As Boolean = Settings.ViewModeIsPicture AndAlso GetPicture(Of Image)(False) Is Nothing
Dim sEnvir() As Boolean = {UserExists, UserSuspended}
Dim EnvirChanged As Func(Of Boolean) = Function() Not sEnvir(0) = UserExists Or Not sEnvir(1) = UserSuspended
UserExists = True
@@ -752,7 +779,7 @@ BlockNullPicture:
ReparseVideo(Token)
ThrowAny(Token)
If _TempPostsList.Count > 0 And __SaveData Then TextSaver.SaveTextToFile(_TempPostsList.ListToString(, Environment.NewLine), MyFilePosts, True,, EDP.None)
If _TempPostsList.Count > 0 And __SaveData Then TextSaver.SaveTextToFile(_TempPostsList.ListToString(Environment.NewLine), MyFilePosts, True,, EDP.None)
_ContentNew.ListAddList(_TempMediaList, LAP.ClearBeforeAdd)
DownloadContent(Token)
ThrowIfDisposed()
@@ -760,6 +787,7 @@ BlockNullPicture:
If DownloadedTotal(False) > 0 Or EnvirChanged.Invoke Then
If __SaveData Then
LastUpdated = Now
RunScript()
DownloadedPictures(True) = SFile.GetFiles(User.File.CutPath, "*.jpg|*.jpeg|*.png|*.gif|*.webm",, EDP.ReturnValue).Count
DownloadedVideos(True) = SFile.GetFiles(User.File.CutPath, "*.mp4|*.mkv|*.mov", SearchOption.AllDirectories, EDP.ReturnValue).Count
If Labels.Contains(LabelsKeeper.NoParsedUser) Then Labels.Remove(LabelsKeeper.NoParsedUser)
@@ -899,6 +927,7 @@ BlockNullPicture:
End Using
End If
End If
Catch iex As IndexOutOfRangeException When Disposed
Catch oex As OperationCanceledException When Token.IsCancellationRequested
Catch dex As ObjectDisposedException When Disposed
Catch ex As Exception
@@ -919,16 +948,10 @@ BlockNullPicture:
Dim ff As SFile = Nothing
Try
If Not f.IsEmptyString AndAlso f.Exists Then
Dim d As Date? = m.Post.Date
If Settings.FileReplaceNameByDate Then
Dim dd$ = AConvert(Of String)(If(d, Now), FileDateAppenderProvider, String.Empty)
If Settings.FileReplaceNameByDate Or Settings.FileAddTimeToFileName Then
ff = f
ff.Name = dd
ff.Name = String.Format(FileDateAppenderPattern, f.Name, CStr(AConvert(Of String)(If(m.Post.Date, Now), FileDateAppenderProvider, String.Empty)))
ff = SFile.Indexed_IndexFile(ff,, New NumberedFile(ff))
ElseIf d.HasValue AndAlso (Settings.FileAddDateToFileName Or Settings.FileAddTimeToFileName) AndAlso
(Not FileDateAppenderProvider Is Nothing And Not FileDateAppenderPattern.IsEmptyString) Then
ff = f
ff.Name = String.Format(FileDateAppenderPattern, f.Name, CStr(AConvert(Of String)(d.Value, FileDateAppenderProvider, String.Empty)))
End If
If Not ff.Name.IsEmptyString Then My.Computer.FileSystem.RenameFile(f, ff.File) : Return ff
End If
@@ -938,19 +961,38 @@ BlockNullPicture:
Return f
End Try
End Function
Private Sub RunScript()
Try
Const spa$ = "{0}"
If ScriptUse Then
Dim ScriptPattern$
If Not ScriptData.IsEmptyString Then
ScriptPattern = ScriptData
Else
ScriptPattern = Settings.ScriptData.Value
End If
If Not ScriptPattern.IsEmptyString Then
If Not ScriptPattern.Contains(spa) Then ScriptPattern &= $" ""{spa}"""
Using b As New BatchExecutor With {.RedirectStandardError = True}
b.Execute({String.Format(ScriptPattern, MyFile.CutPath(1).PathNoSeparator)}, EDP.SendInLog + EDP.ThrowException)
If b.HasError Or Not b.ErrorOutput.IsEmptyString Then Throw New Exception(b.ErrorOutput, b.ErrorException)
End Using
End If
End If
Catch ex As Exception
LogError(ex, "script execution error")
End Try
End Sub
#End Region
#Region "Delete, Move, Merge"
Friend Overridable Function Delete() As Integer Implements IUserData.Delete
Return DeleteF(Me)
End Function
Friend Function DeleteF(ByVal Instance As IUserData) As Integer
Dim f As SFile = SFile.GetPath(MyFile.CutPath.Path)
If f.Exists(SFO.Path, False) AndAlso (User.Merged OrElse f.Delete(SFO.Path, Settings.DeleteMode)) Then
ImageHandler(Me, False)
Settings.UsersList.Remove(User)
Settings.UpdateUsersList()
Settings.Users.Remove(Instance)
Downloader.UserRemove(Instance)
Settings.Users.Remove(Me)
Downloader.UserRemove(Me)
Dispose(True)
Return 1
Else
@@ -958,24 +1000,22 @@ BlockNullPicture:
End If
End Function
Friend Overridable Function MoveFiles(ByVal __CollectionName As String) As Boolean Implements IUserData.MoveFiles
Return MoveFilesF(Me, __CollectionName)
End Function
Friend Function MoveFilesF(ByRef Instance As IUserData, ByVal __CollectionName As String) As Boolean
Dim UserBefore As UserInfo = User
Dim Removed As Boolean = True
Dim _TurnBack As Boolean = False
Try
Dim f As SFile
If IncludedInCollection Then
Settings.Users.Add(Instance)
Settings.Users.Add(Me)
Removed = False
User.CollectionName = String.Empty
User.IncludedInCollection = False
Else
Settings.Users.Remove(Instance)
Settings.Users.Remove(Me)
Removed = True
User.CollectionName = __CollectionName
User.IncludedInCollection = True
User.SpecialPath = Nothing
End If
_TurnBack = True
User.UpdateUserFile()
@@ -987,7 +1027,7 @@ BlockNullPicture:
"Destination directory is not empty!"}, MsgBoxStyle.Exclamation,,, {"Delete", "Cancel"}) = 1 Then
MsgBoxE("Operation canceled", MsgBoxStyle.Exclamation)
User = UserBefore
If Removed Then Settings.Users.Add(Instance) Else Settings.Users.Remove(Instance)
If Removed Then Settings.Users.Add(Me) Else Settings.Users.Remove(Me)
_TurnBack = False
Return False
End If
@@ -995,6 +1035,8 @@ BlockNullPicture:
End If
f.CutPath.Exists(SFO.Path)
Directory.Move(UserBefore.File.CutPath(, EDP.ThrowException).Path, f.Path)
If Not ScriptData.IsEmptyString AndAlso ScriptData.Contains(UserBefore.File.PathNoSeparator) Then _
ScriptData = ScriptData.Replace(UserBefore.File.PathNoSeparator, MyFile.PathNoSeparator)
Settings.UsersList.Remove(UserBefore)
Settings.UpdateUsersList(User)
UpdateUserInformation()
@@ -1003,7 +1045,7 @@ BlockNullPicture:
ErrorsDescriber.Execute(EDP.LogMessageValue, ex, "Files moving error")
User = UserBefore
If _TurnBack Then
If Removed Then Settings.Users.Add(Instance) Else Settings.Users.Remove(Instance)
If Removed Then Settings.Users.Add(Me) Else Settings.Users.Remove(Me)
End If
Return False
End Try
@@ -1048,6 +1090,8 @@ BlockNullPicture:
New ErrorsDescriber(False, False, False, New List(Of SFile))).Count = 0 Then
UserBefore.File.CutPath.Delete(SFO.Path, Settings.DeleteMode, EDP.SendInLog)
End If
If Not ScriptData.IsEmptyString AndAlso ScriptData.Contains(UserBefore.File.PathNoSeparator) Then _
ScriptData = ScriptData.Replace(UserBefore.File.PathNoSeparator, MyFile.PathNoSeparator)
UpdateUserInformation()
End If
Catch ioex As InvalidOperationException When ioex.HelpLink = 1
@@ -1093,25 +1137,6 @@ BlockNullPicture:
Else
Return IIf(FriendlyName.IsEmptyString, Name, FriendlyName)
End If
'If Settings.ViewModeIsPicture Then
' If IsCollection Then
' Return CollectionName
' Else
' Return IIf(FriendlyName.IsEmptyString, Name, FriendlyName)
' End If
'Else
' Dim t$ = String.Empty
' If Temporary Then
' t = " (T)"
' ElseIf Favorite Then
' t = " (F)"
' End If
' If IsCollection Then
' Return $"Collection [{CollectionName}]{t}"
' Else
' Return $"[{Site}]{t} {IIf(FriendlyName.IsEmptyString, Name, FriendlyName)}"
' End If
'End If
End Function
#Region "Buttons actions"
Private Sub BTT_CONTEXT_DOWN_Click(sender As Object, e As EventArgs) Handles BTT_CONTEXT_DOWN.Click
@@ -1231,6 +1256,8 @@ BlockNullPicture:
ReadOnly Property Key As String
Property DownloadImages As Boolean
Property DownloadVideos As Boolean
Property ScriptUse As Boolean
Property ScriptData As String
Function GetLVI(ByVal Destination As ListView) As ListViewItem
Function GetLVIGroup(ByVal Destination As ListView) As ListViewGroup
Sub LoadUserInformation()

View File

@@ -30,14 +30,14 @@ Namespace API.Instagram
.EndLoaderOperations()
End With
End Sub
Private Sub ToolbarBttOK() Implements IOkCancelToolbar.ToolbarBttOK
Private Sub OK() Implements IOkCancelToolbar.OK
With MyExchangeOptions
.GetStories = CH_GET_STORIES.Checked
.GetTagged = CH_GET_TAGGED.Checked
End With
MyDefs.CloseForm()
End Sub
Private Sub ToolbarBttCancel() Implements IOkCancelToolbar.ToolbarBttCancel
Private Sub Cancel() Implements IOkCancelToolbar.Cancel
MyDefs.CloseForm(DialogResult.Cancel)
End Sub
End Class

View File

@@ -9,6 +9,7 @@
Imports SCrawler.API.Base
Imports SCrawler.Plugin
Imports SCrawler.Plugin.Attributes
Imports PersonalUtilities.Forms
Imports PersonalUtilities.Tools
Imports PersonalUtilities.Functions.XML
Imports PersonalUtilities.Functions.XML.Base
@@ -30,16 +31,43 @@ Namespace API.Instagram
End Property
#End Region
#Region "Providers"
Private Class TimersChecker : Implements ICustomProvider
Private Class TimersChecker : Implements IFieldsCheckerProvider
Private Property ErrorMessage As String Implements IFieldsCheckerProvider.ErrorMessage
Private Property Name As String Implements IFieldsCheckerProvider.Name
Private Property TypeError As Boolean Implements IFieldsCheckerProvider.TypeError
Private ReadOnly LVProvider As New ANumbers With {.FormatOptions = ANumbers.Options.GroupIntegral}
Private ReadOnly _LowestValue As Integer
Friend Sub New(ByVal LowestValue As Integer)
_LowestValue = LowestValue
End Sub
Private Function Convert(ByVal Value As Object, ByVal DestinationType As Type, ByVal Provider As IFormatProvider,
Optional ByVal NothingArg As Object = Nothing, Optional ByVal e As ErrorsDescriber = Nothing) As Object Implements ICustomProvider.Convert
If ACheck(Of Integer)(Value) AndAlso CInt(Value) >= _LowestValue Then
TypeError = False
ErrorMessage = String.Empty
If Not ACheck(Of Integer)(Value) Then
TypeError = True
ElseIf CInt(Value) < _LowestValue Then
ErrorMessage = $"The value of [{Name}] field must be greater than or equal to {_LowestValue.NumToString(LVProvider)}"
Else
Return Value
End If
Return Nothing
End Function
Private Function GetFormat(ByVal FormatType As Type) As Object Implements IFormatProvider.GetFormat
Throw New NotImplementedException()
End Function
End Class
Private Class TaggedNotifyLimitChecker : Implements IFieldsCheckerProvider
Private Property ErrorMessage As String Implements IFieldsCheckerProvider.ErrorMessage
Private Property Name As String Implements IFieldsCheckerProvider.Name
Private Property TypeError As Boolean Implements IFieldsCheckerProvider.TypeError
Private Function Convert(ByVal Value As Object, ByVal DestinationType As Type, ByVal Provider As IFormatProvider,
Optional ByVal NothingArg As Object = Nothing, Optional ByVal e As ErrorsDescriber = Nothing) As Object Implements ICustomProvider.Convert
Dim v% = AConvert(Of Integer)(Value, -10)
If v > 0 Or v = -1 Then
Return Value
Else
ErrorMessage = $"The value of [{Name}] field must be greater than 0 or equal to -1"
Return Nothing
End If
End Function
@@ -53,36 +81,44 @@ Namespace API.Instagram
Friend ReadOnly Property Hash As PropertyValue
<PropertyOption(ControlText:="Hash 2", ControlToolTip:="Instagram session hash for saved posts", IsAuth:=True), PXML("InstaHashSavedPosts"), ControlNumber(1)>
Friend ReadOnly Property HashSavedPosts As PropertyValue
<PropertyOption(ControlText:="x-ig-app-id", IsAuth:=True), ControlNumber(2)>
<PropertyOption(ControlText:="x-csrftoken", ControlToolTip:="Instagram token for tagged data", IsAuth:=True), ControlNumber(2)>
Friend ReadOnly Property CSRF_TOKEN As PropertyValue
<PropertyOption(ControlText:="x-ig-app-id", IsAuth:=True), ControlNumber(3)>
Friend Property IG_APP_ID As PropertyValue
<PropertyOption(ControlText:="x-ig-www-claim", IsAuth:=True), ControlNumber(3)>
<PropertyOption(ControlText:="x-ig-www-claim", IsAuth:=True), ControlNumber(4)>
Friend Property IG_WWW_CLAIM As PropertyValue
<PropertyOption(ControlText:="Saved posts user", IsAuth:=True), PXML("SavedPostsUserName"), ControlNumber(4)>
<PropertyOption(ControlText:="Saved posts user", IsAuth:=True), PXML("SavedPostsUserName"), ControlNumber(5)>
Friend ReadOnly Property SavedPostsUserName As PropertyValue
Friend ReadOnly Property StoriesAndTaggedReady As Boolean
Get
Return ACheck(IG_APP_ID.Value) And ACheck(IG_WWW_CLAIM.Value)
Return ACheck(IG_APP_ID.Value) And ACheck(IG_WWW_CLAIM.Value) And ACheck(CSRF_TOKEN.Value)
End Get
End Property
#End Region
#Region "Download properties"
Friend ReadOnly Property HashUpdateRequired As XMLValue(Of Boolean)
<PropertyOption(ControlText:="Request timer", AllowNull:=False), PXML("RequestsWaitTimer"), ControlNumber(5)>
<PropertyOption(ControlText:="Request timer", AllowNull:=False), PXML("RequestsWaitTimer"), ControlNumber(6)>
Friend ReadOnly Property RequestsWaitTimer As PropertyValue
<Provider(NameOf(RequestsWaitTimer), FieldsChecker:=True)>
Private ReadOnly Property RequestsWaitTimerProvider As IFormatProvider
<PropertyOption(ControlText:="Request timer counter", AllowNull:=False, LeftOffset:=120), PXML("RequestsWaitTimerTaskCount"), ControlNumber(6)>
<PropertyOption(ControlText:="Request timer counter", AllowNull:=False, LeftOffset:=120), PXML("RequestsWaitTimerTaskCount"), ControlNumber(7)>
Friend ReadOnly Property RequestsWaitTimerTaskCount As PropertyValue
<Provider(NameOf(RequestsWaitTimerTaskCount), FieldsChecker:=True)>
Private ReadOnly Property RequestsWaitTimerTaskCountProvider As IFormatProvider
<PropertyOption(ControlText:="Posts limit timer", AllowNull:=False), PXML("SleepTimerOnPostsLimit"), ControlNumber(7)>
<PropertyOption(ControlText:="Posts limit timer", AllowNull:=False), PXML("SleepTimerOnPostsLimit"), ControlNumber(8)>
Friend ReadOnly Property SleepTimerOnPostsLimit As PropertyValue
<Provider(NameOf(SleepTimerOnPostsLimit), FieldsChecker:=True)>
Private ReadOnly Property SleepTimerOnPostsLimitProvider As IFormatProvider
<PropertyOption(ControlText:="Get stories"), PXML, ControlNumber(8)>
<PropertyOption(ControlText:="Get stories"), PXML, ControlNumber(9)>
Friend ReadOnly Property GetStories As PropertyValue
<PropertyOption(ControlText:="Get tagged photos"), PXML, ControlNumber(9)>
<PropertyOption(ControlText:="Get tagged photos"), PXML, ControlNumber(10)>
Friend ReadOnly Property GetTagged As PropertyValue
<PropertyOption(ControlText:="Tagged notify limit",
ControlToolTip:="If the number of tagged posts exceeds this number you will be notified." & vbCr &
"-1 to disable"), PXML, ControlNumber(11)>
Friend ReadOnly Property TaggedNotifyLimit As PropertyValue
<Provider(NameOf(TaggedNotifyLimit), FieldsChecker:=True)>
Private ReadOnly Property TaggedNotifyLimitProvider As IFormatProvider
#End Region
#Region "429 bypass"
Friend ReadOnly Property DownloadingErrorDate As XMLValue(Of Date)
@@ -119,7 +155,7 @@ Namespace API.Instagram
LastApplyingValue = If(LastApplyingValue, 0) + 10
TooManyRequestsReadyForCatch = False
MyMainLOG = $"Instagram downloading error: too many requests. Try again after {If(LastApplyingValue, 10)} minutes..."
End If
End If
End If
Else
.ValueF = Nothing
@@ -136,11 +172,13 @@ Namespace API.Instagram
Dim app_id$ = String.Empty
Dim www_claim$ = String.Empty
Dim token$ = String.Empty
With Responser
If .File.Exists Then
.LoadSettings()
With .Headers
If .ContainsKey(Header_CSRF_TOKEN) Then token = .Item(Header_CSRF_TOKEN)
If .ContainsKey(Header_IG_APP_ID) Then app_id = .Item(Header_IG_APP_ID)
If .ContainsKey(Header_IG_WWW_CLAIM) Then www_claim = .Item(Header_IG_WWW_CLAIM)
End With
@@ -157,6 +195,7 @@ Namespace API.Instagram
HashUpdateRequired = New XMLValue(Of Boolean)("InstaHashUpdateRequired", True, _XML, n)
Hash = New PropertyValue(String.Empty, GetType(String))
HashSavedPosts = New PropertyValue(String.Empty, GetType(String))
CSRF_TOKEN = New PropertyValue(token, GetType(String), Sub(v) ChangeResponserFields(NameOf(CSRF_TOKEN), v))
IG_APP_ID = New PropertyValue(app_id, GetType(String), Sub(v) ChangeResponserFields(NameOf(IG_APP_ID), v))
IG_WWW_CLAIM = New PropertyValue(www_claim, GetType(String), Sub(v) ChangeResponserFields(NameOf(IG_WWW_CLAIM), v))
@@ -164,11 +203,13 @@ Namespace API.Instagram
RequestsWaitTimerProvider = New TimersChecker(100)
RequestsWaitTimerTaskCount = New PropertyValue(1)
RequestsWaitTimerTaskCountProvider = New TimersChecker(1)
SleepTimerOnPostsLimit = New PropertyValue(6000)
SleepTimerOnPostsLimit = New PropertyValue(60000)
SleepTimerOnPostsLimitProvider = New TimersChecker(10000)
GetStories = New PropertyValue(False)
GetTagged = New PropertyValue(False)
TaggedNotifyLimit = New PropertyValue(200)
TaggedNotifyLimitProvider = New TaggedNotifyLimitChecker
DownloadingErrorDate = New XMLValue(Of Date) With {
.Provider = New XMLValueConversionProvider(Function(ss, vv) AConvert(Of String)(vv, AModes.Var, Nothing))}
@@ -192,12 +233,14 @@ Namespace API.Instagram
End Function
Private Const Header_IG_APP_ID As String = "x-ig-app-id"
Private Const Header_IG_WWW_CLAIM As String = "x-ig-www-claim"
Private Const Header_CSRF_TOKEN As String = "x-csrftoken"
Private Sub ChangeResponserFields(ByVal PropName As String, ByVal Value As Object)
If Not PropName.IsEmptyString Then
Dim f$ = String.Empty
Select Case PropName
Case NameOf(IG_APP_ID) : f = Header_IG_APP_ID
Case NameOf(IG_WWW_CLAIM) : f = Header_IG_WWW_CLAIM
Case NameOf(CSRF_TOKEN) : f = Header_CSRF_TOKEN
End Select
If Not f.IsEmptyString Then
If Responser.Headers.Count > 0 AndAlso Responser.Headers.ContainsKey(f) Then Responser.Headers.Remove(f)
@@ -231,6 +274,24 @@ Namespace API.Instagram
Return False
End If
End Function
<PropertiesDataChecker({NameOf(TaggedNotifyLimit)})>
Private Function CheckNotifyLimit(ByVal p As IEnumerable(Of PropertyData)) As Boolean
If p.ListExists Then
Dim pi% = p.ListIndexOf(Function(pp) pp.Name = NameOf(TaggedNotifyLimit))
If pi >= 0 Then
Dim v% = AConvert(Of Integer)(p(pi).Value, -10)
If v > 0 Then
Return True
ElseIf v = -1 Then
Return MsgBoxE({"You turn off notifications for tagged posts. This is highly undesirable. Do you still want to do it?",
"Disabling tagged notification limits "}, MsgBoxStyle.YesNo) = MsgBoxResult.Yes
Else
Return False
End If
End If
End If
Return False
End Function
Friend Overrides Sub BeginInit()
End Sub
Friend Overrides Sub EndInit()
@@ -242,13 +303,17 @@ Namespace API.Instagram
#Region "Downloading"
Private ActiveJobs As Integer = 0
Private _NextWNM As UserData.WNM = UserData.WNM.Notify
Private _NextTagged As Boolean = True
Friend Overrides Sub DownloadStarted(ByVal What As Download)
If CStr(Hash.Value).IsEmptyString Or HashUpdateRequired Then GatherInstaHash()
ActiveJobs += 1
End Sub
Friend Overrides Sub BeforeStartDownload(ByVal User As Object, ByVal What As Download)
With DirectCast(User, UserData)
If What = Download.Main Then .WaitNotificationMode = _NextWNM
If What = Download.Main Then
.WaitNotificationMode = _NextWNM
.TaggedCheckSession = _NextTagged
End If
If LastDownloadDate.Value.AddMinutes(60) > Now Then
.RequestsCount = LastRequestsCount
Else
@@ -261,12 +326,14 @@ Namespace API.Instagram
With DirectCast(User, UserData)
_NextWNM = .WaitNotificationMode
If _NextWNM = UserData.WNM.SkipTemp Or _NextWNM = UserData.WNM.SkipCurrent Then _NextWNM = UserData.WNM.Notify
_NextTagged = .TaggedCheckSession
LastDownloadDate.Value = Now
LastRequestsCount.Value = .RequestsCount
End With
End Sub
Friend Overrides Sub DownloadDone(ByVal What As Download)
_NextWNM = UserData.WNM.Notify
_NextTagged = True
LastDownloadDate.Value = Now
ActiveJobs -= 1
If HashUpdateRequired Then MyMainLOG = "Check your Instagram credentials"
@@ -276,23 +343,24 @@ Namespace API.Instagram
Friend Function GatherInstaHash() As Boolean
Try
If Not Responser.Cookies.ListExists Then Throw New Exception("Instagram cookies does not set")
Dim rs As New RParams("=""([^""]+?ConsumerLibCommons[^""]+?.js)""", Nothing, 1) With {.MatchTimeOut = 10}
Dim r$ = Responser.GetResponse("https://instagram.com",, EDP.ThrowException)
Dim rs As New RParams("preload"" href=""(https://static.cdninstagram.com/rsrc.php/[^""]+?.js[^""]*)""", Nothing, 1, RegexReturn.List) With {.MatchTimeOut = 10}
Dim h$
Dim r$ = Responser.GetResponse("https://www.instagram.com",, EDP.ThrowException)
If Not r.IsEmptyString Then
Dim hStr$ = RegexReplace(r, rs)
If Not hStr.IsEmptyString Then
Do While Left(hStr, 1) = "/" : hStr = Right(hStr, hStr.Length - 1) : Loop
hStr = $"https://instagram.com/{hStr}"
r = Responser.GetResponse(hStr,, EDP.ThrowException)
If Not r.IsEmptyString Then
rs = New RParams("generatePaginationActionCreators.+?.profilePosts.byUserId.get.+?queryId:.([\d\w\S]+?)""", Nothing, 1) With {.MatchTimeOut = 10}
Dim h$ = RegexReplace(r, rs)
If Not h.IsEmptyString Then
Hash.Value = h
HashUpdateRequired.Value = False
Return True
Dim JsUrls As List(Of String) = RegexReplace(r, rs)
If JsUrls.ListExists Then
rs = New RParams("\{.+?var h=""([\w\d\S]+?)"".+?\)\.generatePaginationActionCreators", Nothing, 1) With {.MatchTimeOut = 10}
For Each url$ In JsUrls
r = Responser.GetResponse(url,, EDP.ReturnValue)
If Not r.IsEmptyString Then
h = RegexReplace(r, rs)
If Not h.IsEmptyString AndAlso h.Length > 30 Then
Hash.Value = h
HashUpdateRequired.Value = False
Return True
End If
End If
End If
Next
End If
End If
Return False
@@ -303,7 +371,7 @@ Namespace API.Instagram
End Try
End Function
Friend Overrides Function GetSpecialDataF(ByVal URL As String) As IEnumerable(Of UserMedia)
Return UserData.GetVideoInfo(URL, Responser)
Return UserData.GetVideoInfo(URL, Responser, Me)
End Function
Friend Overrides Sub UserOptions(ByRef Options As Object, ByVal OpenForm As Boolean)
If Options Is Nothing OrElse Not TypeOf Options Is EditorExchangeOptions Then Options = New EditorExchangeOptions(Me)

View File

@@ -14,6 +14,7 @@ Imports PersonalUtilities.Tools.WebDocuments.JSON
Imports SCrawler.API.Base
Imports System.Threading
Imports System.Net
Imports System.Reflection
Imports UTypes = SCrawler.API.Base.UserMedia.Types
Namespace API.Instagram
Friend Class UserData : Inherits UserDataBase
@@ -80,6 +81,7 @@ Namespace API.Instagram
If IsSavedPosts Then
DownloadPosts(Token)
ElseIf MySiteSettings.StoriesAndTaggedReady Then
DownloadedTags = 0
If GetStories Then DownloadData(String.Empty, Sections.Stories, Token)
If GetTaggedData Then DownloadData(String.Empty, Sections.Tagged, Token)
End If
@@ -95,6 +97,8 @@ Namespace API.Instagram
Tagged
Stories
End Enum
Private Const StoriesFolder As String = "Stories"
Private Const TaggedFolder As String = "Tagged"
#Region "429 bypass"
Friend Property RequestsCount As Integer = 0
Friend Enum WNM As Integer
@@ -138,7 +142,7 @@ Namespace API.Instagram
End Function
Private Sub ReconfigureAwaiter()
If WaitNotificationMode = WNM.SkipTemp Then WaitNotificationMode = WNM.Notify
If Caught429 Then Caught429 = False ': RequestsCount = 0
If Caught429 Then Caught429 = False
ProgressTempSet = False
End Sub
Private Sub NextRequest(ByVal StartWait As Boolean)
@@ -148,9 +152,77 @@ Namespace API.Instagram
End With
End Sub
#End Region
Private Const StoriesFolder As String = "Stories"
Private Const TaggedFolder As String = "Tagged"
#Region "Tags"
Private TaggedChecked As Boolean = False
Friend TaggedCheckSession As Boolean = True
Private DownloadedTags As Integer = 0
Private DownloadTagsLimit As Integer? = Nothing
Private ReadOnly Property TaggedLimitsNotifications(Optional ByVal v As Integer? = Nothing) As Boolean
Get
Return Not TaggedChecked AndAlso TaggedCheckSession AndAlso
CInt(MySiteSettings.TaggedNotifyLimit.Value) > 0 AndAlso
(Not v.HasValue OrElse v.Value > CInt(MySiteSettings.TaggedNotifyLimit.Value))
End Get
End Property
Private Function SetTagsLimit(ByVal Max As Integer, ByVal p As ANumbers) As DialogResult
Dim v%?
Dim aStr$ = $"Enter the number of posts from user {ToString()} that you want to download{vbCr}" &
$"(Max: {Max.NumToString(p)}; Requests: {(Max / 12).RoundUp.NumToString(p)})"
Dim tryBtt As New MsgBoxButton("Try again") With {.ToolTip = "You will be asked again about the limit"}
Dim cancelBtt As New MsgBoxButton("Cancel") With {.ToolTip = "Cancel tagged posts download operation"}
Dim selectBtt As New MsgBoxButton("Other options") With {.ToolTip = "The main message with options will be displayed again"}
Dim m As New MMessage("You have not entered a valid posts limit", "Tagged posts download limit", {tryBtt, selectBtt, cancelBtt})
Dim mh As New MMessage("", "Tagged posts download limit", {"Confirm", tryBtt, selectBtt, cancelBtt}) With {.ButtonsPerRow = 2}
Do
v = AConvert(Of Integer)(InputBoxE(aStr, "Tagged posts download limit", CInt(MySiteSettings.TaggedNotifyLimit.Value)), Nothing)
If v.HasValue Then
mh.Text = $"You have entered a limit of {v.Value.NumToString(p)} posts"
Select Case MsgBoxE(mh).Index
Case 0 : DownloadTagsLimit = v : Return DialogResult.OK
Case 1 : v = Nothing
Case 2 : Return DialogResult.Retry
Case 3 : Return DialogResult.Cancel
End Select
Else
Select Case MsgBoxE(m).Index
Case 1 : Return DialogResult.Retry
Case 2 : Return DialogResult.Cancel
End Select
End If
Loop While Not v.HasValue
Return DialogResult.Retry
End Function
Private Function TaggedContinue(ByVal TaggedCount As Integer) As DialogResult
Dim agi As New ANumbers With {.FormatOptions = ANumbers.Options.GroupIntegral}
Dim msg As New MMessage($"The number of tagged posts by user [{ToString()}] is {TaggedCount.NumToString(agi)}" & vbCr &
$"This is about {(TaggedCount / 12).RoundUp.NumToString(agi)} requests." & vbCr &
"The tagged data download operation can take a long time.",
"Too much tagged data",
{
"Continue",
New MsgBoxButton("Continue unnotified") With {
.ToolTip = "Continue downloading and cancel further notifications in the current downloading session."},
New MsgBoxButton("Limit") With {
.ToolTip = "Enter the limit of posts you want to download."},
New MsgBoxButton("Disable and cancel") With {
.ToolTip = "Disable downloading tagged data and cancel downloading tagged data."},
"Cancel"
}, MsgBoxStyle.Exclamation) With {.DefaultButton = 0, .CancelButton = 4, .ButtonsPerRow = 2}
Do
Select Case MsgBoxE(msg).Index
Case 0 : Return DialogResult.OK
Case 1 : TaggedCheckSession = False : Return DialogResult.OK
Case 2
Select Case SetTagsLimit(TaggedCount, agi)
Case DialogResult.OK : Return DialogResult.OK
Case DialogResult.Cancel : Return DialogResult.Cancel
End Select
Case 3 : GetTaggedData = False : Return DialogResult.Cancel
Case 4 : Return DialogResult.Cancel
End Select
Loop
End Function
#End Region
Private Overloads Sub DownloadData(ByVal Cursor As String, ByVal Section As Sections, ByVal Token As CancellationToken)
Dim URL$ = String.Empty
Dim StoriesList As List(Of String) = Nothing
@@ -193,6 +265,7 @@ Namespace API.Instagram
Case Sections.Stories
If Not StoriesRequested Then
StoriesList = GetStoriesList()
StoriesRequested = True
MySiteSettings.TooManyRequests(False)
RequestsCount += 1
ThrowAny(Token)
@@ -256,31 +329,21 @@ Namespace API.Instagram
If Not PostID.IsEmptyString And _TempPostsList.Contains(PostID) Then Throw New ExitException(_DownloadComplete)
_TempPostsList.Add(PostID)
ObtainMedia2(nn, PostID, SpecFolder)
DownloadedTags += 1
If DownloadTagsLimit.HasValue AndAlso DownloadedTags >= DownloadTagsLimit.Value Then _
Throw New ExitException(_DownloadComplete)
Next
If Not TaggedChecked Then
If TaggedLimitsNotifications Then
TaggedCount = j.Value("total_count").FromXML(Of Integer)(0)
TaggedChecked = True
If TaggedCount > 200 Then
Dim a% = MsgBoxE({$"The number of tagged posts is {TaggedCount.NumToString(New ANumbers With {
.FormatOptions = ANumbers.Options.GroupIntegral})}" & vbCr &
"The tagged data download operation can take a long time.", "Too much tagged data"}, vbExclamation,,,
{"Continue",
New MsgBoxButton("Disable and cancel") With {
.ToolTip = "Disable downloading tagged data and cancel downloading tagged data."},
"Cancel"})
If a > 0 Then
If a = 1 Then GetTaggedData = False
Throw New ExitException(_DownloadComplete)
End If
End If
If TaggedLimitsNotifications(TaggedCount) AndAlso
TaggedContinue(TaggedCount) = DialogResult.Cancel Then Throw New ExitException(_DownloadComplete)
End If
End Select
Else
If j.Value("status") = "ok" AndAlso j({"data", "user"}).XmlIfNothing.Count = 0 AndAlso _TempMediaList.Count = 0 Then
MySiteSettings.HashUpdateRequired.Value = True
UserExists = False
Throw New ExitException(_DownloadComplete)
End If
If j.Value("status") = "ok" AndAlso j({"data", "user"}).XmlIfNothing.Count = 0 AndAlso
_TempMediaList.Count = 0 AndAlso Section = Sections.Timeline Then _
UserExists = False : Throw New ExitException(_DownloadComplete)
End If
End Using
Else
@@ -298,7 +361,7 @@ Namespace API.Instagram
Catch dex As ObjectDisposedException When Disposed
Exit Do
Catch ex As Exception
If DownloadingException(ex, $"data downloading error [{URL}]") = 1 Then Continue Do Else Exit Do
If DownloadingException(ex, $"data downloading error [{URL}]", Section, False) = 1 Then Continue Do Else Exit Do
End Try
Loop
Catch eex2 As ExitException
@@ -390,11 +453,30 @@ Namespace API.Instagram
CreateMedia(node)
End If
End Sub
Private Sub ObtainMedia2(ByVal n As EContainer, ByVal PostID As String, Optional ByVal SpecialFolder As String = Nothing)
Private Sub ObtainMedia2(ByVal n As EContainer, ByVal PostID As String, Optional ByVal SpecialFolder As String = Nothing,
Optional ByVal DateObj As String = Nothing)
Try
Dim img As Predicate(Of EContainer) = Function(_img) Not _img.Name.IsEmptyString AndAlso _img.Name.StartsWith("image_versions") AndAlso _img.Count > 0
Dim vid As Predicate(Of EContainer) = Function(_vid) Not _vid.Name.IsEmptyString AndAlso _vid.Name.StartsWith("video_versions") AndAlso _vid.Count > 0
Dim ss As Func(Of EContainer, Sizes) = Function(_ss) New Sizes(_ss.Value("width"), _ss.Value("url"))
Dim mDate As Func(Of EContainer, String) = Function(ByVal elem As EContainer) As String
If elem.Contains("taken_at") Then
Return elem.Value("taken_at")
ElseIf elem.Contains("imported_taken_at") Then
Return elem.Value("imported_taken_at")
Else
Dim ev$ = elem.Value("device_timestamp")
If Not ev.IsEmptyString Then
If ev.Length > 10 Then
Return elem.Value("device_timestamp").Substring(0, 10)
Else
Return ev
End If
Else
Return String.Empty
End If
End If
End Function
If n.Count > 0 Then
Dim l As New List(Of Sizes)
Dim d As EContainer
@@ -408,6 +490,7 @@ Namespace API.Instagram
Case 1
If n.Contains(img) Then
t = n.Value("media_type").FromXML(Of Integer)(-1)
DateObj = mDate(n)
If t >= 0 Then
With n.ItemF({img, "candidates"}).XmlIfNothing
If .Count > 0 Then
@@ -415,7 +498,7 @@ Namespace API.Instagram
l.ListAddList(.Select(ss), LNC)
If l.Count > 0 Then
l.Sort()
_TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, l.First.Data, PostID, Nothing, SpecialFolder), LNC)
_TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, l.First.Data, PostID, DateObj, SpecialFolder), LNC)
l.Clear()
End If
End If
@@ -424,22 +507,24 @@ Namespace API.Instagram
End If
Case 2
If n.Contains(vid) Then
DateObj = mDate(n)
With n.ItemF({vid}).XmlIfNothing
If .Count > 0 Then
l.Clear()
l.ListAddList(.Select(ss), LNC)
If l.Count > 0 Then
l.Sort()
_TempMediaList.ListAddValue(MediaFromData(UTypes.Video, l.First.Data, PostID, Nothing, SpecialFolder), LNC)
_TempMediaList.ListAddValue(MediaFromData(UTypes.Video, l.First.Data, PostID, DateObj, SpecialFolder), LNC)
l.Clear()
End If
End If
End With
End If
Case 8
DateObj = mDate(n)
With n("carousel_media").XmlIfNothing
If .Count > 0 Then
For Each d In .Self : ObtainMedia2(d, PostID, SpecialFolder) : Next
For Each d In .Self : ObtainMedia2(d, PostID, SpecialFolder, DateObj) : Next
End If
End With
End Select
@@ -471,14 +556,14 @@ Namespace API.Instagram
Private Sub GetStoriesData(ByRef StoriesList As List(Of String), ByVal Token As CancellationToken)
Const ReqUrl$ = "https://i.instagram.com/api/v1/feed/reels_media/?{0}"
Dim tmpList As IEnumerable(Of String)
Dim qStr$, r$, sFolder$, storyID$
Dim qStr$, r$, sFolder$, storyID$, pid$
Dim i% = -1
Dim jj As EContainer, s As EContainer
ThrowAny(Token)
If StoriesList.ListExists Then
tmpList = StoriesList.Take(5)
If tmpList.ListExists Then
qStr = String.Format(ReqUrl, tmpList.Select(Function(q) $"reel_ids=highlight:{q}").ListToString(, "&"))
qStr = String.Format(ReqUrl, tmpList.Select(Function(q) $"reel_ids=highlight:{q}").ListToString("&"))
r = Responser.GetResponse(qStr,, EDP.ThrowException)
ThrowAny(Token)
If Not r.IsEmptyString Then
@@ -486,7 +571,7 @@ Namespace API.Instagram
If j.Contains("reels") Then
For Each jj In j("reels")
i += 1
sFolder = jj.Value("title")
sFolder = jj.Value("title").StringRemoveWinForbiddenSymbols
storyID = jj.Value("id").Replace("highlight:", String.Empty)
If sFolder.IsEmptyString Then sFolder = $"Story_{storyID}"
If sFolder.IsEmptyString Then sFolder = $"Story_{i}"
@@ -494,7 +579,14 @@ Namespace API.Instagram
If Not storyID.IsEmptyString Then storyID &= ":"
With jj("items").XmlIfNothing
If .Count > 0 Then
For Each s In .Self : ThrowAny(Token) : ObtainMedia2(s, storyID & s.Value("id"), sFolder) : Next
For Each s In .Self
pid = storyID & s.Value("id")
If Not _TempPostsList.Contains(pid) Then
ThrowAny(Token)
ObtainMedia2(s, pid, sFolder)
_TempPostsList.Add(pid)
End If
Next
End If
End With
Next
@@ -515,7 +607,7 @@ Namespace API.Instagram
End If
Return Nothing
Catch ex As Exception
DownloadingException(ex, "API.Instagram.GetStoriesList")
DownloadingException(ex, "API.Instagram.GetStoriesList", Sections.Stories, False)
Return Nothing
End Try
End Function
@@ -529,13 +621,18 @@ Namespace API.Instagram
''' <inheritdoc cref="UserDataBase.DownloadingException(Exception, String)"/><br/>
''' 1 - continue
''' </summary>
Protected Overrides Function DownloadingException(ByVal ex As Exception, ByVal Message As String, Optional ByVal FromPE As Boolean = False) As Integer
Protected Overloads Overrides Function DownloadingException(ByVal ex As Exception, ByVal Message As String, Optional ByVal FromPE As Boolean = False) As Integer
Return DownloadingException(ex, Message, Sections.Timeline, FromPE)
End Function
Private Overloads Function DownloadingException(ByVal ex As Exception, ByVal Message As String, ByVal s As Sections, ByVal FromPE As Boolean) As Integer
If Responser.StatusCode = HttpStatusCode.NotFound Then
UserExists = False
ElseIf Responser.StatusCode = HttpStatusCode.BadRequest Then
HasError = True
MyMainLOG = "Instagram credentials have expired"
MyMainLOG = $"Instagram credentials have expired: {ToString()} [{s}]"
MySiteSettings.HashUpdateRequired.Value = True
ElseIf Responser.StatusCode = HttpStatusCode.Forbidden And s = Sections.Tagged Then
Return 3
ElseIf Responser.StatusCode = 429 Then
With MySiteSettings
Dim WaiterExists As Boolean = .LastApplyingValue.HasValue
@@ -547,6 +644,7 @@ Namespace API.Instagram
Return 1
Else
MySiteSettings.HashUpdateRequired.Value = True
MyMainLOG = $"Instagram hash requested: {ToString()} [{s}]"
If Not FromPE Then LogError(ex, Message) : HasError = True
Return 0
End If
@@ -561,12 +659,13 @@ Namespace API.Instagram
m.SpecialFolder = SpecialFolder
Return m
End Function
Friend Shared Function GetVideoInfo(ByVal URL As String, ByVal r As Response) As IEnumerable(Of UserMedia)
Friend Shared Function GetVideoInfo(ByVal URL As String, ByVal r As Response, ByVal _Settings As SiteSettings) As IEnumerable(Of UserMedia)
Try
If Not URL.IsEmptyString AndAlso URL.Contains("instagram.com") Then
Dim PID$ = RegexReplace(URL, RParams.DMS(".*?instagram.com/p/([_\w\d]+)", 1))
If Not PID.IsEmptyString Then
Using t As New UserData
t.SetEnvironment(Settings(_Settings.GetType.GetCustomAttribute(Of Plugin.Attributes.Manifest)().GUID), Nothing, False, False)
t.Responser = New Response
t.Responser.Copy(r)
t._SavedPostsIDs.Add(PID)

View File

@@ -12,9 +12,12 @@ Imports PersonalUtilities.Functions.XML
Imports SCrawler.API.Base
Imports SCrawler.Plugin.Hosts
Imports System.Threading
Imports SCrawler.API.Reddit.RedditViewExchange
Imports View = SCrawler.API.Reddit.IRedditView.View
Imports Period = SCrawler.API.Reddit.IRedditView.Period
Namespace API.Reddit
Friend Class Channel : Implements ICollection(Of UserPost), IEquatable(Of Channel), IComparable(Of Channel),
IRangeSwitcherContainer(Of UserPost), ILoaderSaver, IMyEnumerator(Of UserPost), IChannelLimits, IDisposable
IRangeSwitcherContainer(Of UserPost), ILoaderSaver, IMyEnumerator(Of UserPost), IChannelLimits, IRedditView, IDisposable
#Region "XML Nodes' Names"
Private Const Name_Name As String = "Name"
Private Const Name_ID As String = "ID"
@@ -35,6 +38,7 @@ Namespace API.Reddit
End Property
Friend ReadOnly Property PostsLatest As List(Of UserPost)
Friend ReadOnly Property Posts As List(Of UserPost)
Friend ReadOnly Property PostsNames As List(Of String)
Friend ReadOnly Property PostsAll As List(Of UserPost)
Get
Return ListAddList(Nothing, Posts).ListAddList(PostsLatest).ListSort
@@ -57,6 +61,14 @@ Namespace API.Reddit
Return $"{ChannelsCollection.ChannelsPath.PathWithSeparator}{ID}.xml"
End Get
End Property
Private ReadOnly Property FilePosts As SFile
Get
Dim f As SFile = File
f.Name &= "_Posts"
f.Extension = "txt"
Return f
End Get
End Property
Friend ReadOnly Property CachePath As SFile
Get
Return $"{ChannelsCollection.ChannelsPathCache.PathWithSeparator}{ID}\"
@@ -72,7 +84,14 @@ Namespace API.Reddit
Return Posts(Index)
End Get
End Property
Private ReadOnly Property Range As RangeSwitcher(Of UserPost)
Friend Property ViewMode As View = View.New Implements IRedditView.ViewMode
Friend Property ViewPeriod As Period = Period.All Implements IRedditView.ViewPeriod
Friend Sub SetView(ByVal Options As IRedditView) Implements IRedditView.SetView
If Not Options Is Nothing Then
ViewMode = Options.ViewMode
ViewPeriod = Options.ViewPeriod
End If
End Sub
#Region "Statistics support"
Private ReadOnly CountOfAddedUsers As List(Of Integer)
Private ReadOnly CountOfLoadedPostsPerSession As List(Of Integer)
@@ -118,16 +137,20 @@ Namespace API.Reddit
Private _DownloadLimitCount As Integer? = Nothing
Friend Property DownloadLimitCount As Integer? Implements IChannelLimits.DownloadLimitCount
Get
If AutoGetLimits Then
If LatestParsedDate.HasValue OrElse Not DownloadLimitPost.IsEmptyString Then
Return Nothing
ElseIf _DownloadLimitCount.HasValue Then
Return _DownloadLimitCount
Else
Return DefaultDownloadLimitCount
End If
Else
If Not ViewMode = View.New And AutoGetLimits Then
Return _DownloadLimitCount
Else
If AutoGetLimits Then
If LatestParsedDate.HasValue OrElse Not DownloadLimitPost.IsEmptyString Then
Return Nothing
ElseIf _DownloadLimitCount.HasValue Then
Return _DownloadLimitCount
Else
Return DefaultDownloadLimitCount
End If
Else
Return _DownloadLimitCount
End If
End If
End Get
Set(ByVal NewLimit As Integer?)
@@ -137,11 +160,15 @@ Namespace API.Reddit
Private _DownloadLimitPost As String = String.Empty
Friend Property DownloadLimitPost As String Implements IChannelLimits.DownloadLimitPost
Get
Dim PID$ = ListAddList(Nothing, Posts, LAP.NotContainsOnly).ListAddList(PostsLatest, LAP.NotContainsOnly).ListSort.FirstOrDefault.ID
If AutoGetLimits And Not PID.IsEmptyString Then
Return PID
Else
If Not ViewMode = View.New And AutoGetLimits Then
Return _DownloadLimitPost
Else
Dim PID$ = ListAddList(Nothing, Posts, LAP.NotContainsOnly).ListAddList(PostsLatest, LAP.NotContainsOnly).ListSort.FirstOrDefault.ID
If AutoGetLimits And Not PID.IsEmptyString Then
Return PID
Else
Return _DownloadLimitPost
End If
End If
End Get
Set(ByVal NewLimit As String)
@@ -151,10 +178,14 @@ Namespace API.Reddit
Private _DownloadLimitDate As Date? = Nothing
Friend Property DownloadLimitDate As Date? Implements IChannelLimits.DownloadLimitDate
Get
If AutoGetLimits And LatestParsedDate.HasValue Then
Return LatestParsedDate
Else
If Not ViewMode = View.New And AutoGetLimits Then
Return _DownloadLimitDate
Else
If AutoGetLimits And LatestParsedDate.HasValue Then
Return LatestParsedDate
Else
Return _DownloadLimitDate
End If
End If
End Get
Set(ByVal NewLimit As Date?)
@@ -174,6 +205,11 @@ Namespace API.Reddit
DownloadLimitDate = .DownloadLimitDate
AutoGetLimits = .AutoGetLimits
End With
If Not ViewMode = View.New And AutoGetLimits Then
DownloadLimitDate = Nothing
DownloadLimitCount = Nothing
DownloadLimitPost = String.Empty
End If
End Sub
Friend Property AutoGetLimits As Boolean = True Implements IChannelLimits.AutoGetLimits
#End Region
@@ -181,7 +217,7 @@ Namespace API.Reddit
Friend Sub New()
Posts = New List(Of UserPost)
PostsLatest = New List(Of UserPost)
Range = New RangeSwitcher(Of UserPost)(Me)
PostsNames = New List(Of String)
CountOfAddedUsers = New List(Of Integer)
CountOfLoadedPostsPerSession = New List(Of Integer)
ChannelExistentUserNames = New List(Of String)
@@ -203,6 +239,7 @@ Namespace API.Reddit
End Function
Friend Sub Delete()
File.Delete(, SFODelete.DeleteToRecycleBin)
FilePosts.Delete(, SFODelete.DeleteToRecycleBin)
End Sub
Friend Sub DownloadData(ByVal Token As CancellationToken, Optional ByVal SkipExists As Boolean = True,
Optional ByVal p As MyProgress = Nothing)
@@ -214,10 +251,13 @@ Namespace API.Reddit
.SkipExistsUsers = SkipExists,
.ChannelInfo = Me
}
d.SetEnvironment(HOST, CUser, False)
d.RemoveUpdateHandlers()
d.SetLimit(Me)
d.DownloadData(Token)
With d
.SetEnvironment(HOST, CUser, False)
.RemoveUpdateHandlers()
.SetLimit(Me)
.SetView(Me)
.DownloadData(Token)
End With
Dim b% = Posts.Count
Posts.ListAddList(d.GetNewChannelPosts(), LAP.NotContainsOnly)
If Posts.Count - b > 0 Then CountOfLoadedPostsPerSession.Add(Posts.Count - b)
@@ -298,6 +338,9 @@ Namespace API.Reddit
Dim lc As New ListAddParams(LAP.ClearBeforeAdd)
Name = x.Value(Name_Name)
ID = x.Value(Name_ID)
ViewMode = x.Value(Name_ViewMode).FromXML(Of Integer)(CInt(View.[New]))
ViewPeriod = x.Value(Name_ViewPeriod).FromXML(Of Integer)(CInt(Period.All))
If FilePosts.Exists Then PostsNames.ListAddList(FilePosts.GetText.StringToList(Of String)("|"), LNC)
LatestParsedDate = AConvert(Of Date)(x.Value(Name_Date), XMLDateProvider, Nothing)
CountOfAddedUsers.ListAddList(x.Value(Name_UsersAdded).StringToList(Of Integer)("|"), lc)
CountOfLoadedPostsPerSession.ListAddList(x.Value(Name_PostsDownloaded).StringToList(Of Integer)("|"), lc)
@@ -317,9 +360,20 @@ Namespace API.Reddit
Friend Overloads Function Save(Optional ByVal f As SFile = Nothing, Optional ByVal e As ErrorsDescriber = Nothing) As Boolean Implements ILoaderSaver.Save
Dim XMLDateProvider As New ADateTime(ADateTime.Formats.BaseDateTime)
UpdateUsersStats()
If Not ViewMode = View.New Then
Dim l As New List(Of String)
If Posts.Count > 0 Or PostsLatest.Count > 0 Then l.ListAddList((From p In PostsAll Where Not p.ID.IsEmptyString Select p.ID), LAP.NotContainsOnly)
l.ListAddList(PostsNames, LAP.NotContainsOnly)
If l.Count > 0 Then TextSaver.SaveTextToFile(l.ListToString("|"), FilePosts, True,, EDP.SendInLog)
End If
Using x As New XmlFile With {.AllowSameNames = True, .Name = "Channel"}
x.Add(Name_Name, Name)
x.Add(Name_ID, ID)
x.Add(Name_ViewMode, CInt(ViewMode))
x.Add(Name_ViewPeriod, CInt(ViewPeriod))
x.Add(Name_UsersAdded, CountOfAddedUsers.ListToString("|"))
x.Add(Name_PostsDownloaded, CountOfLoadedPostsPerSession.ListToString("|"))
x.Add(Name_UsersExistent, ChannelExistentUserNames.ListToString("|"))
If Posts.Count > 0 Or PostsLatest.Count > 0 Then
Dim tmpPostList As List(Of UserPost) = Nothing
tmpPostList.ListAddList(Posts).ListAddList(PostsLatest)
@@ -327,9 +381,6 @@ Namespace API.Reddit
LatestParsedDate = tmpPostList.FirstOrDefault(Function(pd) pd.Date.HasValue).Date
x.Add(Name_Date, AConvert(Of String)(LatestParsedDate, XMLDateProvider, String.Empty))
x.Add(Name_PostsNode, String.Empty)
x.Add(Name_UsersAdded, CountOfAddedUsers.ListToString(, "|"))
x.Add(Name_PostsDownloaded, CountOfLoadedPostsPerSession.ListToString(, "|"))
x.Add(Name_UsersExistent, ChannelExistentUserNames.ListToString(, "|"))
With x(Name_PostsNode)
tmpPostList.Take(200).ToList.ForEach(Sub(p) .Add(New EContainer("Post",
String.Empty,
@@ -354,9 +405,9 @@ Namespace API.Reddit
If disposing Then
Posts.Clear()
PostsLatest.Clear()
PostsNames.Clear()
CountOfAddedUsers.Clear()
CountOfLoadedPostsPerSession.Clear()
Range.Dispose()
ChannelExistentUserNames.Clear()
CachePath.Delete(SFO.Path, SFODelete.None, EDP.SendInLog)
End If

View File

@@ -0,0 +1,40 @@
' Copyright (C) 2022 Andy
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY
Namespace API.Reddit
Friend Interface IRedditView
Enum View As Integer
[New] = 0
Hot = 1
Top = 2
End Enum
Enum Period As Integer
All = 0
Hour = 1
Day = 2
Week = 3
Month = 4
Year = 5
End Enum
Property ViewMode As View
Property ViewPeriod As Period
Sub SetView(ByVal Options As IRedditView)
End Interface
Friend Class RedditViewExchange : Implements IRedditView
Friend Const Name_ViewMode As String = "ViewMode"
Friend Const Name_ViewPeriod As String = "ViewPeriod"
Friend Property ViewMode As IRedditView.View Implements IRedditView.ViewMode
Friend Property ViewPeriod As IRedditView.Period Implements IRedditView.ViewPeriod
Friend Sub SetView(ByVal Options As IRedditView) Implements IRedditView.SetView
If Not Options Is Nothing Then
ViewMode = Options.ViewMode
ViewPeriod = Options.ViewPeriod
End If
End Sub
End Class
End Namespace

View File

@@ -14,23 +14,32 @@ Namespace API.Reddit
Namespace M3U8_Declarations
Friend Module M3U8_Declarations
Friend ReadOnly BaseUrlPattern As RParams = RParams.DM("([htps:/]{7,8}.+?/.+?)(?=/)", 0, EDP.ReturnValue)
''' <summary>Video</summary>
Friend ReadOnly PlayListRegEx_1 As RParams = RParams.DM("(#EXT-X-STREAM-INF)(.+)(RESOLUTION=)(\d+)(.+?[\r\n]{1,2})(.+?)([\r\n]{1,2})", 0,
RegexReturn.List, EDP.SendInLog, EDP.ReturnValue)
''' <summary>Audio, Video</summary>
Friend ReadOnly PlayListRegEx_2 As RParams = RParams.DM("(?<=#EXT-X-BYTERANGE.+?[\r\n]{1,2})(.+)(?=[\r\n]{0,2})", 0,
RegexReturn.List, EDP.SendInLog, EDP.ReturnValue)
Friend ReadOnly PlayListAudioRegEx As RParams = RParams.DM("(HLS_AUDIO_(\d+)[^""]+)", 0, RegexReturn.List, EDP.SendInLog, EDP.ReturnValue)
Friend ReadOnly DPED As New ErrorsDescriber(EDP.SendInLog + EDP.ReturnValue)
End Module
End Namespace
Friend NotInheritable Class M3U8
Private Sub New()
End Sub
Friend NotInheritable Class M3U8 : Implements IDisposable
#Region "Declarations"
Private Enum Types : Video : Audio : End Enum
Private Structure Resolution : Implements IRegExCreator, IComparable(Of Resolution)
Friend File As String
Friend Resolution As Integer
Friend HasError As Boolean
Friend Function CreateFromArray(ByVal ParamsArray() As String) As Object Implements IRegExCreator.CreateFromArray
If ParamsArray.ArrayExists Then
File = ParamsArray(0)
If ParamsArray.Length > 1 Then Resolution = AConvert(Of Integer)(ParamsArray(1), 0)
Try
If ParamsArray.Length > 1 Then Resolution = AConvert(Of Integer)(ParamsArray(1), EDP.ThrowException)
Catch ex As Exception
HasError = True
Resolution = 0
End Try
End If
Return Me
End Function
@@ -38,21 +47,60 @@ Namespace API.Reddit
Return Resolution.CompareTo(Other.Resolution) * -1
End Function
End Structure
Private Shared Function GetPlaylistUrls(ByVal PlayListURL As String, ByVal BaseUrl As String) As List(Of String)
Private ReadOnly PlayListURL As String
Private ReadOnly BaseURL As String
Private ReadOnly Video As List(Of String)
Private ReadOnly Audio As List(Of String)
Private OutFile As SFile
Private VideoFile As SFile
Private AudioFile As SFile
Private CachePath As SFile
#End Region
Private Sub New(ByVal URL As String, ByVal OutFile As SFile)
PlayListURL = URL
BaseURL = RegexReplace(URL, BaseUrlPattern)
Video = New List(Of String)
Audio = New List(Of String)
Me.OutFile = OutFile
Me.OutFile.Name = "PlayListFile"
Me.OutFile.Extension = "mp4"
CachePath = $"{OutFile.PathWithSeparator}_Cache\{SFile.GetDirectories($"{OutFile.PathWithSeparator}_Cache\",,, EDP.ReturnValue).ListIfNothing.Count + 1}\"
End Sub
#Region "Internal functions"
#Region "GetPlaylistUrls"
Private Overloads Sub GetPlaylistUrls()
Video.ListAddList(GetPlaylistUrls(PlayListURL, Types.Video))
Audio.ListAddList(GetPlaylistUrls(PlayListURL, Types.Audio))
End Sub
Private Overloads Function GetPlaylistUrls(ByVal PlayListURL As String, ByVal Type As Types) As List(Of String)
Try
If Not BaseUrl.IsEmptyString Then
If Not BaseURL.IsEmptyString Then
Using w As New WebClient
Dim r$ = w.DownloadString(PlayListURL)
If Not r.IsEmptyString Then
Dim l As List(Of Resolution) = FNF.RegexFields(Of Resolution)(r, {PlayListRegEx_1}, {6, 4})
Dim l As New List(Of Resolution)
If Type = Types.Video Then
l = FNF.RegexFields(Of Resolution)(r, {PlayListRegEx_1}, {6, 4})
Else
Try
l = FNF.RegexFields(Of Resolution)(r, {PlayListAudioRegEx}, {1, 2})
Catch anull As FNF.RegexFieldsTextBecameNullException
l.Clear()
End Try
End If
If l.ListExists Then
Dim plError As Predicate(Of Resolution) = Function(lr) lr.HasError
If l.Exists(plError) Then
l.RemoveAll(plError)
If l.Count = 0 Then Return New List(Of String)
End If
l.Sort()
Dim pls$ = $"{BaseUrl}/{l.First.File}"
Dim pls$ = $"{BaseURL}/{l.First.File}"
r = w.DownloadString(pls)
If Not r.IsEmptyString Then
Dim lp As New ListAddParams(LAP.NotContainsOnly) With {
.Converter = Function(input) $"{BaseUrl}/{input}",
.e = New ErrorsDescriber(False, False, True, New List(Of String))}
.Converter = Function(input) $"{BaseURL}/{input}",
.Error = New ErrorsDescriber(False, False, True, New List(Of String))}
Return ListAddList(Of String, List(Of String))(Nothing, DirectCast(RegexReplace(r, PlayListRegEx_2), List(Of String)), lp).ListIfNothing
End If
End If
@@ -61,47 +109,94 @@ Namespace API.Reddit
End If
Return New List(Of String)
Catch ex As Exception
Return ErrorsDescriber.Execute(DPED, ex, "[M3U8.GetPlaylistUrls]", New List(Of String))
Return ErrorsDescriber.Execute(DPED, ex, $"[M3U8.GetPlaylistUrls({Type}): {PlayListURL}]", New List(Of String))
End Try
End Function
Private Shared Function Save(ByVal URLs As List(Of String), ByVal f As SFile) As SFile
Dim CachePath As SFile = Nothing
#End Region
#Region "ConcatData"
Private Overloads Sub ConcatData()
ConcatData(Video, Types.Video, VideoFile)
ConcatData(Audio, Types.Audio, AudioFile)
MergeFiles()
End Sub
Private Overloads Sub ConcatData(ByVal Urls As List(Of String), ByVal Type As Types, ByRef TFile As SFile)
Try
If URLs.ListExists Then
Dim ConcatFile As SFile = f
ConcatFile.Name = "PlayListFile"
ConcatFile.Extension = "mp4"
CachePath = $"{f.PathWithSeparator}_Cache\{SFile.GetDirectories($"{f.PathWithSeparator}_Cache\",,, EDP.ReturnValue).ListIfNothing.Count + 1}\"
If Urls.ListExists Then
Dim ConcatFile As SFile = OutFile
If Type = Types.Audio Then
ConcatFile.Name &= "_AUDIO"
ConcatFile.Extension = "aac"
Else
If Audio.Count > 0 Then ConcatFile.Name &= "_VIDEO"
ConcatFile.Extension = "mp4"
End If
If CachePath.Exists(SFO.Path) Then
Dim p As New SFileNumbers(ConcatFile.Name,,, New ANumbers With {.Format = ANumbers.Formats.General})
ConcatFile = SFile.Indexed_IndexFile(ConcatFile,, p, EDP.ReturnValue)
ConcatFile = SFile.Indexed_IndexFile(ConcatFile,, p, EDP.ThrowException) 'EDP.ReturnValue
Dim i%
Dim eFiles As New List(Of SFile)
Dim dFile As SFile = CachePath
dFile.Extension = New SFile(URLs(0)).Extension
dFile.Extension = New SFile(Urls(0)).Extension
If dFile.Extension.IsEmptyString Then dFile.Extension = "ts"
Using w As New WebClient
For i = 0 To URLs.Count - 1
For i = 0 To Urls.Count - 1
dFile.Name = $"ConPart_{i}"
w.DownloadFile(URLs(i), dFile)
w.DownloadFile(Urls(i), dFile)
eFiles.Add(dFile)
Next
End Using
f = FFMPEG.ConcatenateFiles(eFiles, Settings.FfmpegFile, ConcatFile, p, DPED)
TFile = FFMPEG.ConcatenateFiles(eFiles, Settings.FfmpegFile, ConcatFile, p, DPED)
eFiles.Clear()
Return f
End If
End If
Return Nothing
Catch ex As Exception
Return ErrorsDescriber.Execute(DPED, ex, "[M3U8.Save]", New SFile)
Finally
CachePath.Delete(SFO.Path, SFODelete.None, DPED)
ErrorsDescriber.Execute(DPED, ex, $"[M3U8.Save({Type})]")
End Try
End Sub
#End Region
Private Sub MergeFiles()
Try
If Not VideoFile.IsEmptyString And Not AudioFile.IsEmptyString Then
Dim p As New SFileNumbers(OutFile.Name,, RParams.DMS("PlayListFile_(\d*)", 1), New ANumbers With {.Format = ANumbers.Formats.General})
OutFile = FFMPEG.MergeFiles({VideoFile, AudioFile}, Settings.FfmpegFile, OutFile, p, DPED)
Else
OutFile = VideoFile
End If
Catch ex As Exception
ErrorsDescriber.Execute(DPED, ex, $"[M3U8.MergeFiles]")
End Try
End Sub
Friend Function Download() As SFile
GetPlaylistUrls()
ConcatData()
Return OutFile
End Function
#End Region
#Region "Statics"
Friend Shared Function Download(ByVal URL As String, ByVal f As SFile) As SFile
Dim BaseUrl$ = RegexReplace(URL, BaseUrlPattern)
Return Save(GetPlaylistUrls(URL, BaseUrl), f)
Using m As New M3U8(URL, f) : Return m.Download() : End Using
End Function
#End Region
#Region "IDisposable Support"
Private disposedValue As Boolean = False
Private Overloads Sub Dispose(ByVal disposing As Boolean)
If Not disposedValue Then
If disposing Then
Video.Clear()
Audio.Clear()
CachePath.Delete(SFO.Path, SFODelete.None, DPED)
End If
disposedValue = True
End If
End Sub
Protected Overrides Sub Finalize()
Dispose(False)
MyBase.Finalize()
End Sub
Friend Overloads Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
End Class
End Namespace

View File

@@ -0,0 +1,301 @@
' Copyright (C) 2022 Andy
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY
Namespace API.Reddit
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()>
Partial Friend Class RedditViewSettingsForm : Inherits System.Windows.Forms.Form
<System.Diagnostics.DebuggerNonUserCode()>
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
Try
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
Finally
MyBase.Dispose(disposing)
End Try
End Sub
Private components As System.ComponentModel.IContainer
<System.Diagnostics.DebuggerStepThrough()>
Private Sub InitializeComponent()
Dim CONTAINER_MAIN As System.Windows.Forms.ToolStripContainer
Dim TP_MAIN As System.Windows.Forms.TableLayoutPanel
Dim TP_VIEW_MODE As System.Windows.Forms.TableLayoutPanel
Dim LBL_VIEW_MODE As System.Windows.Forms.Label
Dim LBL_PERIOD As System.Windows.Forms.Label
Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(RedditViewSettingsForm))
Me.OPT_VIEW_MODE_NEW = New System.Windows.Forms.RadioButton()
Me.OPT_VIEW_MODE_HOT = New System.Windows.Forms.RadioButton()
Me.OPT_VIEW_MODE_TOP = New System.Windows.Forms.RadioButton()
Me.TP_PERIOD = New System.Windows.Forms.TableLayoutPanel()
Me.OPT_PERIOD_ALL = New System.Windows.Forms.RadioButton()
Me.OPT_PERIOD_HOUR = New System.Windows.Forms.RadioButton()
Me.OPT_PERIOD_DAY = New System.Windows.Forms.RadioButton()
Me.OPT_PERIOD_WEEK = New System.Windows.Forms.RadioButton()
Me.OPT_PERIOD_MONTH = New System.Windows.Forms.RadioButton()
Me.OPT_PERIOD_YEAR = New System.Windows.Forms.RadioButton()
CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer()
TP_MAIN = New System.Windows.Forms.TableLayoutPanel()
TP_VIEW_MODE = New System.Windows.Forms.TableLayoutPanel()
LBL_VIEW_MODE = New System.Windows.Forms.Label()
LBL_PERIOD = New System.Windows.Forms.Label()
CONTAINER_MAIN.ContentPanel.SuspendLayout()
CONTAINER_MAIN.SuspendLayout()
TP_MAIN.SuspendLayout()
TP_VIEW_MODE.SuspendLayout()
Me.TP_PERIOD.SuspendLayout()
Me.SuspendLayout()
'
'CONTAINER_MAIN
'
'
'CONTAINER_MAIN.ContentPanel
'
CONTAINER_MAIN.ContentPanel.Controls.Add(TP_MAIN)
CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(477, 87)
CONTAINER_MAIN.Dock = System.Windows.Forms.DockStyle.Fill
CONTAINER_MAIN.LeftToolStripPanelVisible = False
CONTAINER_MAIN.Location = New System.Drawing.Point(0, 0)
CONTAINER_MAIN.Name = "CONTAINER_MAIN"
CONTAINER_MAIN.RightToolStripPanelVisible = False
CONTAINER_MAIN.Size = New System.Drawing.Size(477, 112)
CONTAINER_MAIN.TabIndex = 0
CONTAINER_MAIN.TopToolStripPanelVisible = False
'
'TP_MAIN
'
TP_MAIN.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single]
TP_MAIN.ColumnCount = 1
TP_MAIN.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_MAIN.Controls.Add(TP_VIEW_MODE, 0, 0)
TP_MAIN.Controls.Add(Me.TP_PERIOD, 0, 1)
TP_MAIN.Dock = System.Windows.Forms.DockStyle.Fill
TP_MAIN.Location = New System.Drawing.Point(0, 0)
TP_MAIN.Name = "TP_MAIN"
TP_MAIN.RowCount = 3
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 56.0!))
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20.0!))
TP_MAIN.Size = New System.Drawing.Size(477, 87)
TP_MAIN.TabIndex = 0
'
'TP_VIEW_MODE
'
TP_VIEW_MODE.ColumnCount = 4
TP_VIEW_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25.0!))
TP_VIEW_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25.0!))
TP_VIEW_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25.0!))
TP_VIEW_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25.0!))
TP_VIEW_MODE.Controls.Add(LBL_VIEW_MODE, 0, 0)
TP_VIEW_MODE.Controls.Add(Me.OPT_VIEW_MODE_NEW, 1, 0)
TP_VIEW_MODE.Controls.Add(Me.OPT_VIEW_MODE_HOT, 2, 0)
TP_VIEW_MODE.Controls.Add(Me.OPT_VIEW_MODE_TOP, 3, 0)
TP_VIEW_MODE.Dock = System.Windows.Forms.DockStyle.Fill
TP_VIEW_MODE.Location = New System.Drawing.Point(1, 1)
TP_VIEW_MODE.Margin = New System.Windows.Forms.Padding(0)
TP_VIEW_MODE.Name = "TP_VIEW_MODE"
TP_VIEW_MODE.RowCount = 1
TP_VIEW_MODE.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_VIEW_MODE.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
TP_VIEW_MODE.Size = New System.Drawing.Size(475, 28)
TP_VIEW_MODE.TabIndex = 0
'
'LBL_VIEW_MODE
'
LBL_VIEW_MODE.AutoSize = True
LBL_VIEW_MODE.Dock = System.Windows.Forms.DockStyle.Fill
LBL_VIEW_MODE.Location = New System.Drawing.Point(3, 0)
LBL_VIEW_MODE.Name = "LBL_VIEW_MODE"
LBL_VIEW_MODE.Size = New System.Drawing.Size(112, 28)
LBL_VIEW_MODE.TabIndex = 0
LBL_VIEW_MODE.Text = "View"
LBL_VIEW_MODE.TextAlign = System.Drawing.ContentAlignment.MiddleRight
'
'OPT_VIEW_MODE_NEW
'
Me.OPT_VIEW_MODE_NEW.AutoSize = True
Me.OPT_VIEW_MODE_NEW.Dock = System.Windows.Forms.DockStyle.Fill
Me.OPT_VIEW_MODE_NEW.Location = New System.Drawing.Point(121, 3)
Me.OPT_VIEW_MODE_NEW.Name = "OPT_VIEW_MODE_NEW"
Me.OPT_VIEW_MODE_NEW.Size = New System.Drawing.Size(112, 22)
Me.OPT_VIEW_MODE_NEW.TabIndex = 1
Me.OPT_VIEW_MODE_NEW.TabStop = True
Me.OPT_VIEW_MODE_NEW.Text = "New"
Me.OPT_VIEW_MODE_NEW.UseVisualStyleBackColor = True
'
'OPT_VIEW_MODE_HOT
'
Me.OPT_VIEW_MODE_HOT.AutoSize = True
Me.OPT_VIEW_MODE_HOT.Dock = System.Windows.Forms.DockStyle.Fill
Me.OPT_VIEW_MODE_HOT.Location = New System.Drawing.Point(239, 3)
Me.OPT_VIEW_MODE_HOT.Name = "OPT_VIEW_MODE_HOT"
Me.OPT_VIEW_MODE_HOT.Size = New System.Drawing.Size(112, 22)
Me.OPT_VIEW_MODE_HOT.TabIndex = 2
Me.OPT_VIEW_MODE_HOT.TabStop = True
Me.OPT_VIEW_MODE_HOT.Text = "Hot"
Me.OPT_VIEW_MODE_HOT.UseVisualStyleBackColor = True
'
'OPT_VIEW_MODE_TOP
'
Me.OPT_VIEW_MODE_TOP.AutoSize = True
Me.OPT_VIEW_MODE_TOP.Dock = System.Windows.Forms.DockStyle.Fill
Me.OPT_VIEW_MODE_TOP.Location = New System.Drawing.Point(357, 3)
Me.OPT_VIEW_MODE_TOP.Name = "OPT_VIEW_MODE_TOP"
Me.OPT_VIEW_MODE_TOP.Size = New System.Drawing.Size(115, 22)
Me.OPT_VIEW_MODE_TOP.TabIndex = 3
Me.OPT_VIEW_MODE_TOP.TabStop = True
Me.OPT_VIEW_MODE_TOP.Text = "Top"
Me.OPT_VIEW_MODE_TOP.UseVisualStyleBackColor = True
'
'TP_PERIOD
'
Me.TP_PERIOD.ColumnCount = 4
Me.TP_PERIOD.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25.0!))
Me.TP_PERIOD.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25.0!))
Me.TP_PERIOD.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25.0!))
Me.TP_PERIOD.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25.0!))
Me.TP_PERIOD.Controls.Add(LBL_PERIOD, 0, 0)
Me.TP_PERIOD.Controls.Add(Me.OPT_PERIOD_ALL, 1, 0)
Me.TP_PERIOD.Controls.Add(Me.OPT_PERIOD_HOUR, 2, 0)
Me.TP_PERIOD.Controls.Add(Me.OPT_PERIOD_DAY, 3, 0)
Me.TP_PERIOD.Controls.Add(Me.OPT_PERIOD_WEEK, 1, 1)
Me.TP_PERIOD.Controls.Add(Me.OPT_PERIOD_MONTH, 2, 1)
Me.TP_PERIOD.Controls.Add(Me.OPT_PERIOD_YEAR, 3, 1)
Me.TP_PERIOD.Dock = System.Windows.Forms.DockStyle.Fill
Me.TP_PERIOD.Location = New System.Drawing.Point(1, 30)
Me.TP_PERIOD.Margin = New System.Windows.Forms.Padding(0)
Me.TP_PERIOD.Name = "TP_PERIOD"
Me.TP_PERIOD.RowCount = 2
Me.TP_PERIOD.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
Me.TP_PERIOD.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
Me.TP_PERIOD.Size = New System.Drawing.Size(475, 56)
Me.TP_PERIOD.TabIndex = 2
'
'LBL_PERIOD
'
LBL_PERIOD.AutoSize = True
LBL_PERIOD.Dock = System.Windows.Forms.DockStyle.Fill
LBL_PERIOD.Location = New System.Drawing.Point(3, 0)
LBL_PERIOD.Name = "LBL_PERIOD"
LBL_PERIOD.Size = New System.Drawing.Size(112, 28)
LBL_PERIOD.TabIndex = 0
LBL_PERIOD.Text = "Period"
LBL_PERIOD.TextAlign = System.Drawing.ContentAlignment.MiddleRight
'
'OPT_PERIOD_ALL
'
Me.OPT_PERIOD_ALL.AutoSize = True
Me.OPT_PERIOD_ALL.Dock = System.Windows.Forms.DockStyle.Fill
Me.OPT_PERIOD_ALL.Location = New System.Drawing.Point(121, 3)
Me.OPT_PERIOD_ALL.Name = "OPT_PERIOD_ALL"
Me.OPT_PERIOD_ALL.Size = New System.Drawing.Size(112, 22)
Me.OPT_PERIOD_ALL.TabIndex = 1
Me.OPT_PERIOD_ALL.TabStop = True
Me.OPT_PERIOD_ALL.Text = "All"
Me.OPT_PERIOD_ALL.UseVisualStyleBackColor = True
'
'OPT_PERIOD_HOUR
'
Me.OPT_PERIOD_HOUR.AutoSize = True
Me.OPT_PERIOD_HOUR.Dock = System.Windows.Forms.DockStyle.Fill
Me.OPT_PERIOD_HOUR.Location = New System.Drawing.Point(239, 3)
Me.OPT_PERIOD_HOUR.Name = "OPT_PERIOD_HOUR"
Me.OPT_PERIOD_HOUR.Size = New System.Drawing.Size(112, 22)
Me.OPT_PERIOD_HOUR.TabIndex = 2
Me.OPT_PERIOD_HOUR.TabStop = True
Me.OPT_PERIOD_HOUR.Text = "Hour"
Me.OPT_PERIOD_HOUR.UseVisualStyleBackColor = True
'
'OPT_PERIOD_DAY
'
Me.OPT_PERIOD_DAY.AutoSize = True
Me.OPT_PERIOD_DAY.Dock = System.Windows.Forms.DockStyle.Fill
Me.OPT_PERIOD_DAY.Location = New System.Drawing.Point(357, 3)
Me.OPT_PERIOD_DAY.Name = "OPT_PERIOD_DAY"
Me.OPT_PERIOD_DAY.Size = New System.Drawing.Size(115, 22)
Me.OPT_PERIOD_DAY.TabIndex = 3
Me.OPT_PERIOD_DAY.TabStop = True
Me.OPT_PERIOD_DAY.Text = "Day"
Me.OPT_PERIOD_DAY.UseVisualStyleBackColor = True
'
'OPT_PERIOD_WEEK
'
Me.OPT_PERIOD_WEEK.AutoSize = True
Me.OPT_PERIOD_WEEK.Dock = System.Windows.Forms.DockStyle.Fill
Me.OPT_PERIOD_WEEK.Location = New System.Drawing.Point(121, 31)
Me.OPT_PERIOD_WEEK.Name = "OPT_PERIOD_WEEK"
Me.OPT_PERIOD_WEEK.Size = New System.Drawing.Size(112, 22)
Me.OPT_PERIOD_WEEK.TabIndex = 4
Me.OPT_PERIOD_WEEK.TabStop = True
Me.OPT_PERIOD_WEEK.Text = "Week"
Me.OPT_PERIOD_WEEK.UseVisualStyleBackColor = True
'
'OPT_PERIOD_MONTH
'
Me.OPT_PERIOD_MONTH.AutoSize = True
Me.OPT_PERIOD_MONTH.Dock = System.Windows.Forms.DockStyle.Fill
Me.OPT_PERIOD_MONTH.Location = New System.Drawing.Point(239, 31)
Me.OPT_PERIOD_MONTH.Name = "OPT_PERIOD_MONTH"
Me.OPT_PERIOD_MONTH.Size = New System.Drawing.Size(112, 22)
Me.OPT_PERIOD_MONTH.TabIndex = 5
Me.OPT_PERIOD_MONTH.TabStop = True
Me.OPT_PERIOD_MONTH.Text = "Month"
Me.OPT_PERIOD_MONTH.UseVisualStyleBackColor = True
'
'OPT_PERIOD_YEAR
'
Me.OPT_PERIOD_YEAR.AutoSize = True
Me.OPT_PERIOD_YEAR.Dock = System.Windows.Forms.DockStyle.Fill
Me.OPT_PERIOD_YEAR.Location = New System.Drawing.Point(357, 31)
Me.OPT_PERIOD_YEAR.Name = "OPT_PERIOD_YEAR"
Me.OPT_PERIOD_YEAR.Size = New System.Drawing.Size(115, 22)
Me.OPT_PERIOD_YEAR.TabIndex = 6
Me.OPT_PERIOD_YEAR.TabStop = True
Me.OPT_PERIOD_YEAR.Text = "Year"
Me.OPT_PERIOD_YEAR.UseVisualStyleBackColor = True
'
'RedditViewSettingsForm
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(477, 112)
Me.Controls.Add(CONTAINER_MAIN)
Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle
Me.Icon = CType(resources.GetObject("$this.Icon"), System.Drawing.Icon)
Me.KeyPreview = True
Me.MaximizeBox = False
Me.MaximumSize = New System.Drawing.Size(493, 151)
Me.MinimizeBox = False
Me.MinimumSize = New System.Drawing.Size(493, 151)
Me.Name = "RedditViewSettingsForm"
Me.ShowInTaskbar = False
Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide
Me.Text = "Options"
CONTAINER_MAIN.ContentPanel.ResumeLayout(False)
CONTAINER_MAIN.ResumeLayout(False)
CONTAINER_MAIN.PerformLayout()
TP_MAIN.ResumeLayout(False)
TP_VIEW_MODE.ResumeLayout(False)
TP_VIEW_MODE.PerformLayout()
Me.TP_PERIOD.ResumeLayout(False)
Me.TP_PERIOD.PerformLayout()
Me.ResumeLayout(False)
End Sub
Private WithEvents OPT_VIEW_MODE_NEW As RadioButton
Private WithEvents OPT_VIEW_MODE_HOT As RadioButton
Private WithEvents OPT_VIEW_MODE_TOP As RadioButton
Private WithEvents OPT_PERIOD_ALL As RadioButton
Private WithEvents OPT_PERIOD_HOUR As RadioButton
Private WithEvents OPT_PERIOD_DAY As RadioButton
Private WithEvents OPT_PERIOD_WEEK As RadioButton
Private WithEvents OPT_PERIOD_MONTH As RadioButton
Private WithEvents OPT_PERIOD_YEAR As RadioButton
Private WithEvents TP_PERIOD As TableLayoutPanel
End Class
End Namespace

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,90 @@
' Copyright (C) 2022 Andy
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY
Imports PersonalUtilities.Forms
Imports PersonalUtilities.Forms.Toolbars
Imports CView = SCrawler.API.Reddit.IRedditView.View
Imports CPeriod = SCrawler.API.Reddit.IRedditView.Period
Namespace API.Reddit
Friend Class RedditViewSettingsForm : Implements IOkCancelToolbar
Private ReadOnly MyDefs As DefaultFormProps
Private ReadOnly Property MyOptions As IRedditView
Friend Sub New(ByRef opt As IRedditView)
InitializeComponent()
MyOptions = opt
MyDefs = New DefaultFormProps
End Sub
Private Sub ChannelSettingsForm_Load(sender As Object, e As EventArgs) Handles Me.Load
Try
Dim n$ = String.Empty
If TypeOf MyOptions Is Channel Then
n = $"Channel [{DirectCast(MyOptions, Channel).Name}]"
ElseIf TypeOf MyOptions Is Base.IUserData Then
n = $"User [{DirectCast(MyOptions, Base.IUserData).Name}]"
End If
If Not n.IsEmptyString Then Text = n
With MyDefs
.MyViewInitialize(Me, Settings.Design, True)
.AddOkCancelToolbar()
.AppendDetectors()
.DelegateClosingChecker()
Select Case MyOptions.ViewMode
Case CView.Hot : OPT_VIEW_MODE_HOT.Checked = True
Case CView.Top : OPT_VIEW_MODE_TOP.Checked = True
Case Else : OPT_VIEW_MODE_NEW.Checked = True
End Select
Select Case MyOptions.ViewPeriod
Case CPeriod.Hour : OPT_PERIOD_HOUR.Checked = True
Case CPeriod.Day : OPT_PERIOD_DAY.Checked = True
Case CPeriod.Week : OPT_PERIOD_WEEK.Checked = True
Case CPeriod.Month : OPT_PERIOD_MONTH.Checked = True
Case CPeriod.Year : OPT_PERIOD_YEAR.Checked = True
Case Else : OPT_PERIOD_ALL.Checked = True
End Select
ChangePeriodEnabled()
.EndLoaderOperations()
End With
Catch ex As Exception
MyDefs.InvokeLoaderError(ex)
End Try
End Sub
Private Sub OK() Implements IOkCancelToolbar.OK
With MyOptions
Select Case True
Case OPT_VIEW_MODE_HOT.Checked : .ViewMode = CView.Hot
Case OPT_VIEW_MODE_TOP.Checked : .ViewMode = CView.Top
Case Else : .ViewMode = CView.New
End Select
Select Case True
Case OPT_PERIOD_HOUR.Checked : .ViewPeriod = CPeriod.Hour
Case OPT_PERIOD_DAY.Checked : .ViewPeriod = CPeriod.Day
Case OPT_PERIOD_WEEK.Checked : .ViewPeriod = CPeriod.Week
Case OPT_PERIOD_MONTH.Checked : .ViewPeriod = CPeriod.Month
Case OPT_PERIOD_YEAR.Checked : .ViewPeriod = CPeriod.Year
Case Else : .ViewPeriod = CPeriod.All
End Select
End With
MyDefs.CloseForm()
End Sub
Private Sub Cancel() Implements IOkCancelToolbar.Cancel
MyDefs.CloseForm(DialogResult.Cancel)
End Sub
Private Sub OPT_VIEW_MODE_NEW_CheckedChanged(sender As Object, e As EventArgs) Handles OPT_VIEW_MODE_NEW.CheckedChanged
ChangePeriodEnabled()
End Sub
Private Sub OPT_VIEW_MODE_HOT_CheckedChanged(sender As Object, e As EventArgs) Handles OPT_VIEW_MODE_HOT.CheckedChanged
ChangePeriodEnabled()
End Sub
Private Sub OPT_VIEW_MODE_TOP_CheckedChanged(sender As Object, e As EventArgs) Handles OPT_VIEW_MODE_TOP.CheckedChanged
ChangePeriodEnabled()
End Sub
Private Sub ChangePeriodEnabled()
TP_PERIOD.Enabled = OPT_VIEW_MODE_TOP.Checked
End Sub
End Class
End Namespace

View File

@@ -14,7 +14,7 @@ Imports PersonalUtilities.Functions.RegularExpressions
Imports DownDetector = SCrawler.API.Base.DownDetector
Imports Download = SCrawler.Plugin.ISiteSettings.Download
Namespace API.Reddit
<Manifest(RedditSiteKey), UseClassAsIs, SavedPosts>
<Manifest(RedditSiteKey), UseClassAsIs, SavedPosts, SpecialForm(False)>
Friend Class SiteSettings : Inherits SiteSettingsBase
Friend Overrides ReadOnly Property Icon As Icon
Get
@@ -28,6 +28,8 @@ Namespace API.Reddit
End Property
<PropertyOption(ControlText:="Saved posts user"), PXML("SavedPostsUserName")>
Friend ReadOnly Property SavedPostsUserName As PropertyValue
<PropertyOption(ControlText:="Use M3U8", ControlToolTip:="Use M3U8 or mp4 for Reddit videos"), PXML>
Friend ReadOnly Property UseM3U8 As PropertyValue
Friend Overrides ReadOnly Property Responser As WEB.Response
Friend Sub New()
MyBase.New(RedditSite)
@@ -43,6 +45,7 @@ Namespace API.Reddit
End If
End With
SavedPostsUserName = New PropertyValue(String.Empty, GetType(String))
UseM3U8 = New PropertyValue(True)
UrlPatternUser = "https://www.reddit.com/user/{0}/"
UrlPatternChannel = "https://www.reddit.com/r/{0}/"
ImageVideoContains = "redgifs"
@@ -53,7 +56,10 @@ Namespace API.Reddit
Case Download.Channel : Return New UserData With {.SaveToCache = False, .SkipExistsUsers = False, .AutoGetLimits = True}
Case Download.SavedPosts
Dim u As New UserData With {.IsSavedPosts = True}
DirectCast(u, UserDataBase).User = New UserInfo With {.Name = CStr(AConvert(Of String)(SavedPostsUserName.Value, String.Empty))}
DirectCast(u, UserDataBase).User = New UserInfo With {
.Name = CStr(AConvert(Of String)(SavedPostsUserName.Value, String.Empty)),
.IsChannel = True
}
Return u
End Select
Return Nothing
@@ -72,17 +78,21 @@ Namespace API.Reddit
Next
Return Nothing
End Function
Friend Overrides Function Available(ByVal What As Download) As Boolean
Friend Overrides Function Available(ByVal What As Download, ByVal Silent As Boolean) As Boolean
Try
Dim dl As List(Of DownDetector.Data) = DownDetector.GetData("reddit")
If dl.ListExists Then
dl = dl.Take(4).ToList
Dim avg% = dl.Average(Function(d) d.Value)
If avg > 100 Then
Return MsgBoxE({"Over the past hour, Reddit has received an average of " &
avg.NumToString(New ANumbers With {.FormatOptions = ANumbers.Options.GroupIntegral}) & " outage reports:" & vbCr &
dl.ListToString(, vbCr) & vbCr & vbCr &
"Do you want to continue parsing Reddit data?", "There are outage reports on Reddit"}, vbYesNo) = vbYes
If Silent Then
Return False
Else
Return MsgBoxE({"Over the past hour, Reddit has received an average of " &
avg.NumToString(New ANumbers With {.FormatOptions = ANumbers.Options.GroupIntegral}) & " outage reports:" & vbCr &
dl.ListToString(vbCr) & vbCr & vbCr &
"Do you want to continue parsing Reddit data?", "There are outage reports on Reddit"}, vbYesNo) = vbYes
End If
End If
End If
Return True
@@ -93,5 +103,11 @@ Namespace API.Reddit
Friend Overrides Function GetSpecialDataF(ByVal URL As String) As IEnumerable(Of UserMedia)
Return UserData.GetVideoInfo(URL, Responser)
End Function
Friend Overrides Sub UserOptions(ByRef Options As Object, ByVal OpenForm As Boolean)
If Options Is Nothing OrElse Not TypeOf Options Is RedditViewExchange Then Options = New RedditViewExchange
If OpenForm Then
Using f As New RedditViewSettingsForm(Options) : f.ShowDialog() : End Using
End If
End Sub
End Class
End Namespace

View File

@@ -14,10 +14,13 @@ Imports PersonalUtilities.Tools.WebDocuments.JSON
Imports System.Net
Imports System.Threading
Imports SCrawler.API.Base
Imports SCrawler.API.Reddit.RedditViewExchange
Imports UStates = SCrawler.API.Base.UserMedia.States
Imports UTypes = SCrawler.API.Base.UserMedia.Types
Imports CView = SCrawler.API.Reddit.IRedditView.View
Imports CPeriod = SCrawler.API.Reddit.IRedditView.Period
Namespace API.Reddit
Friend Class UserData : Inherits UserDataBase : Implements IChannelData
Friend Class UserData : Inherits UserDataBase : Implements IChannelData, IRedditView
Private ReadOnly Property MySiteSettings As SiteSettings
Get
Return DirectCast(HOST.Source, SiteSettings)
@@ -28,6 +31,11 @@ Namespace API.Reddit
Return If(IsChannel, DateProviderChannel, DateProvider)
End Get
End Property
Private ReadOnly Property UseM3U8 As Boolean
Get
Return Settings.UseM3U8 And CBool(DirectCast(HOST.Source, SiteSettings).UseM3U8.Value)
End Get
End Property
#Region "Channels Support"
#Region "IChannelLimits Support"
Friend Property DownloadLimitCount As Integer? Implements IChannelLimits.DownloadLimitCount
@@ -60,6 +68,41 @@ Namespace API.Reddit
Select c.Post) Else Return Nothing
End Function
#End Region
#Region "IRedditView Support"
Friend Property ViewMode As CView Implements IRedditView.ViewMode
Friend Property ViewPeriod As CPeriod Implements IRedditView.ViewPeriod
Friend Sub SetView(ByVal Options As IRedditView) Implements IRedditView.SetView
If Not Options Is Nothing Then
ViewMode = Options.ViewMode
ViewPeriod = Options.ViewPeriod
End If
End Sub
Private ReadOnly Property View As String
Get
Select Case ViewMode
Case CView.Hot : Return "hot"
Case CView.Top : Return "top"
Case Else : Return "new"
End Select
End Get
End Property
Private ReadOnly Property Period As String
Get
If ViewMode = CView.Top Then
Select Case ViewPeriod
Case CPeriod.Hour : Return "hour"
Case CPeriod.Day : Return "day"
Case CPeriod.Week : Return "week"
Case CPeriod.Month : Return "month"
Case CPeriod.Year : Return "year"
Case Else : Return "all"
End Select
Else
Return "all"
End If
End Get
End Property
#End Region
#Region "Initializer"
Friend Sub New()
ChannelPostsNames = New List(Of String)
@@ -69,6 +112,21 @@ Namespace API.Reddit
#End Region
#Region "Load and Update user info"
Protected Overrides Sub LoadUserInformation_OptionalFields(ByRef Container As XmlFile, ByVal Loading As Boolean)
With Container
If Loading Then
ViewMode = .Value(Name_ViewMode).FromXML(Of Integer)(CInt(CView.New))
ViewPeriod = .Value(Name_ViewPeriod).FromXML(Of Integer)(CInt(CPeriod.All))
Else
.Add(Name_ViewMode, CInt(ViewMode))
.Add(Name_ViewPeriod, CInt(ViewPeriod))
End If
End With
End Sub
Friend Overrides Function ExchangeOptionsGet() As Object
Return New RedditViewExchange With {.ViewMode = ViewMode, .ViewPeriod = ViewPeriod}
End Function
Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object)
If Not Obj Is Nothing AndAlso TypeOf Obj Is IRedditView Then SetView(DirectCast(Obj, IRedditView))
End Sub
#End Region
#Region "Download Overrides"
@@ -80,6 +138,7 @@ Namespace API.Reddit
Responser = New Response
Responser.Copy(MySiteSettings.Responser)
ChannelPostsNames.ListAddList(ChannelInfo.PostsAll.Select(Function(p) p.ID), LNC)
If Not ViewMode = CView.New Then ChannelPostsNames.ListAddList(ChannelInfo.PostsNames, LNC)
If SkipExistsUsers Then _ExistsUsersNames.ListAddList(Settings.UsersList.Select(Function(p) p.Name), LNC)
DownloadDataF(Token)
ReparseVideo(Token)
@@ -133,7 +192,7 @@ Namespace API.Reddit
Dim UPicType As Func(Of String, UTypes) = Function(input) IIf(input = "image", UTypes.Picture, UTypes.GIF)
Dim _PostID As Func(Of String) = Function() IIf(PostTmp.IsEmptyString, PostID, PostTmp)
URL = $"https://gateway.reddit.com/desktopapi/v1/user/{Name}/posts?rtj=only&allow_quarantined=true&allow_over18=1&include=identity&after={POST}&dist=25&sort=new&t=all&layout=classic"
URL = $"https://gateway.reddit.com/desktopapi/v1/user/{Name}/posts?rtj=only&allow_quarantined=true&allow_over18=1&include=identity&after={POST}&dist=25&sort={View}&t={Period}&layout=classic"
ThrowAny(Token)
Dim r$ = Responser.GetResponse(URL,, EDP.ThrowException)
If Not r.IsEmptyString Then
@@ -188,9 +247,12 @@ Namespace API.Reddit
added = False
End If
Case "video"
If Settings.UseM3U8 AndAlso s("hlsUrl").XmlIfNothingValue("/").ToLower.Contains("m3u8") Then
If UseM3U8 AndAlso s("hlsUrl").XmlIfNothingValue("/").ToLower.Contains("m3u8") Then
_TempMediaList.ListAddValue(MediaFromData(UTypes.m3u8, s.Value("hlsUrl"),
_PostID(), PostDate,, IsChannel), LNC)
ElseIf Not UseM3U8 AndAlso s("fallback_url").XmlIfNothingValue("/").ToLower.Contains("mp4") Then
_TempMediaList.ListAddValue(MediaFromData(UTypes.Video, s.Value("fallback_url"),
_PostID(), PostDate,, IsChannel), LNC)
Else
added = False
End If
@@ -241,7 +303,7 @@ Namespace API.Reddit
If IsSavedPosts Then
URL = $"https://www.reddit.com/user/{Name}/saved.json?after={POST}"
Else
URL = $"https://reddit.com/r/{Name}/new.json?allow_quarantined=true&allow_over18=1&include=identity&after={POST}&dist=25&sort=new&t=all&layout=classic"
URL = $"https://reddit.com/r/{Name}/{View}.json?allow_quarantined=true&allow_over18=1&include=identity&after={POST}&dist=25&sort={View}&t={Period}&layout=classic"
End If
ThrowAny(Token)
@@ -258,10 +320,13 @@ Namespace API.Reddit
PostID = s.Value("name")
If PostID.IsEmptyString AndAlso s.Contains("id") Then PostID = s("id").Value
If ChannelPostsNames.Contains(PostID) Then ExistsDetected = True : Continue For 'Exit Sub
If ChannelPostsNames.Contains(PostID) Then
If ViewMode = CView.New Then ExistsDetected = True Else NewPostDetected = True 'bypass
Continue For 'Exit Sub
End If
If DownloadLimitCount.HasValue AndAlso _TotalPostsDownloaded >= DownloadLimitCount.Value Then Exit Sub
If Not DownloadLimitPost.IsEmptyString AndAlso DownloadLimitPost = PostID Then Exit Sub
If DownloadLimitDate.HasValue AndAlso _TempMediaList.Count > 0 Then
If ViewMode = CView.New AndAlso DownloadLimitDate.HasValue AndAlso _TempMediaList.Count > 0 Then
With (From __u In _TempMediaList Where __u.Post.Date.HasValue Select __u.Post.Date.Value)
If .Count > 0 Then lDate = .Min Else lDate = Nothing
End With
@@ -283,7 +348,7 @@ Namespace API.Reddit
If s.Contains("created") Then PostDate = s("created").Value Else PostDate = String.Empty
_UserID = s.Value("author")
If SkipExistsUsers AndAlso _ExistsUsersNames.Count > 0 AndAlso
If Not IsSavedPosts AndAlso SkipExistsUsers AndAlso _ExistsUsersNames.Count > 0 AndAlso
Not _UserID.IsEmptyString AndAlso _ExistsUsersNames.Contains(_UserID) Then
If Not IsSavedPosts AndAlso Not ChannelInfo Is Nothing Then _
ChannelInfo.ChannelExistentUserNames.ListAddValue(_UserID, LNC)
@@ -291,7 +356,7 @@ Namespace API.Reddit
End If
tmpUrl = s.Value("url")
If Not tmpUrl.IsEmptyString AndAlso tmpUrl.Contains("redgifs.com") Then
If Not tmpUrl.IsEmptyString AndAlso tmpUrl.StringContains({"redgifs.com", "gfycat.com"}) Then
If SaveToCache Then
tmpUrl = s.Value({"media", "oembed"}, "thumbnail_url")
If Not tmpUrl.IsEmptyString Then
@@ -310,8 +375,12 @@ Namespace API.Reddit
_TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, tmpUrl, PostID, PostDate, _UserID, IsChannel), LNC)
_TotalPostsDownloaded += 1
End If
ElseIf UseM3U8 AndAlso Not s.Value({"media", "reddit_video"}, "hls_url").IsEmptyString Then
_TempMediaList.ListAddValue(MediaFromData(UTypes.m3u8, s.Value({"media", "reddit_video"}, "hls_url"),
PostID, PostDate, _UserID, IsChannel), LNC)
Else
_TempMediaList.ListAddValue(MediaFromData(UTypes.VideoPre + UTypes.m3u8, tmpUrl, PostID, PostDate, _UserID, IsChannel), LNC)
'_TempMediaList.ListAddValue(MediaFromData(UTypes.VideoPre + UTypes.m3u8, tmpUrl, PostID, PostDate, _UserID, IsChannel), LNC)
_TempMediaList.ListAddValue(MediaFromData(UTypes.Video, tmpUrl, PostID, PostDate, _UserID, IsChannel), LNC)
_TotalPostsDownloaded += 1
End If
ElseIf CreateImgurMedia(tmpUrl, PostID, PostDate, _UserID, IsChannel) Then
@@ -366,6 +435,8 @@ Namespace API.Reddit
_TempMediaList.ListAddValue(MediaFromData(UTypes.Video, _URL.Replace(".gifv", ".mp4"),
PostID, PostDate, _UserID, IsChannel), LNC)
End If
ElseIf _URL.Contains(".mp4") Then
_TempMediaList.ListAddValue(MediaFromData(UTypes.Video, _URL, PostID, PostDate, _UserID, IsChannel), LNC)
ElseIf _URL.Contains(".gif") Then
_TempMediaList.ListAddValue(MediaFromData(UTypes.GIF, _URL, PostID, PostDate, _UserID, IsChannel), LNC)
Else
@@ -643,6 +714,7 @@ Namespace API.Reddit
End Using
End If
End If
Catch iex As IndexOutOfRangeException When Disposed
Catch oex As OperationCanceledException When Token.IsCancellationRequested
Catch dex As ObjectDisposedException When Disposed
Catch ex As Exception
@@ -658,7 +730,7 @@ Namespace API.Reddit
ElseIf Responser.StatusCode = HttpStatusCode.BadGateway Or
Responser.StatusCode = HttpStatusCode.ServiceUnavailable Or
Responser.StatusCode = HttpStatusCode.GatewayTimeout Then
MyMainLOG = "Reddit is currently unavailable"
MyMainLOG = $"Reddit is currently unavailable ({ToString()})"
Else
If Not FromPE Then LogError(ex, Message) : HasError = True
Return 0

View File

@@ -12,7 +12,7 @@ Imports PersonalUtilities.Tools
Imports PersonalUtilities.Functions.RegularExpressions
Imports SCrawler.API.Base
Namespace API.Twitter
<Manifest("AndyProgram_Twitter"), UseClassAsIs>
<Manifest("AndyProgram_Twitter"), SavedPosts, UseClassAsIs>
Friend Class SiteSettings : Inherits SiteSettingsBase
Friend Const Header_Authorization As String = "authorization"
Friend Const Header_Token As String = "x-csrf-token"
@@ -31,6 +31,8 @@ Namespace API.Twitter
Private ReadOnly Property Auth As PropertyValue
<PropertyOption(AllowNull:=False, ControlText:="Token", ControlToolTip:="Set token from [x-csrf-token] response header")>
Private ReadOnly Property Token As PropertyValue
<PropertyOption(ControlText:="Saved posts user name", ControlToolTip:="Personal profile username", LeftOffset:=120), PXML>
Friend ReadOnly Property SavedPostsUserName As PropertyValue
Friend Overrides ReadOnly Property Responser As WEB.Response
Friend Sub New()
MyBase.New(TwitterSite)
@@ -70,6 +72,7 @@ Namespace API.Twitter
Auth = New PropertyValue(a, GetType(String), Sub(v) ChangeResponserFields(NameOf(Auth), v))
Token = New PropertyValue(t, GetType(String), Sub(v) ChangeResponserFields(NameOf(Token), v))
SavedPostsUserName = New PropertyValue(String.Empty, GetType(String))
UserRegex = RParams.DMS("[htps:/]{7,8}.*?twitter.com/([^/]+)", 1)
UrlPatternUser = "https://twitter.com/{0}"
@@ -90,7 +93,11 @@ Namespace API.Twitter
End If
End Sub
Friend Overrides Function GetInstance(ByVal What As ISiteSettings.Download) As IPluginContentProvider
Return New UserData
If What = ISiteSettings.Download.SavedPosts Then
Return New UserData With {.IsSavedPosts = True, .User = New UserInfo With {.Name = CStr(AConvert(Of String)(SavedPostsUserName.Value, String.Empty))}}
Else
Return New UserData
End If
End Function
Friend Overrides Function GetSpecialDataF(ByVal URL As String) As IEnumerable(Of UserMedia)
Return UserData.GetVideoInfo(URL, Responser)

View File

@@ -27,12 +27,19 @@ Namespace API.Twitter
End Sub
#Region "Download functions"
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
If _ContentList.Count > 0 Then _DataNames.ListAddList(_ContentList.Select(Function(c) c.File.File), LAP.ClearBeforeAdd, LAP.NotContainsOnly)
DownloadData(String.Empty, Token)
If IsSavedPosts Then
If _ContentList.Count > 0 Then _DataNames.ListAddList(_ContentList.Select(Function(c) c.Post.ID), LAP.ClearBeforeAdd, LAP.NotContainsOnly)
DownloadData(String.Empty, Token)
Else
If _ContentList.Count > 0 Then _DataNames.ListAddList(_ContentList.Select(Function(c) c.File.File), LAP.ClearBeforeAdd, LAP.NotContainsOnly)
DownloadData(String.Empty, Token)
End If
End Sub
Private Overloads Sub DownloadData(ByVal POST As String, ByVal Token As CancellationToken)
Dim URL$ = String.Empty
Try
Dim NextCursor$ = String.Empty
Dim __NextCursor As Predicate(Of EContainer) = Function(e) e.Value({"content", "operation", "cursor"}, "cursorType") = "Bottom"
Dim PostID$ = String.Empty
Dim PostDate$, dName$
Dim m As EContainer, nn As EContainer, s As EContainer
@@ -42,24 +49,37 @@ Namespace API.Twitter
Dim PicNode As Predicate(Of EContainer) = Function(e) e.Count > 0 AndAlso e.Contains("media_url")
Dim UID As Func(Of EContainer, String) = Function(e) e.XmlIfNothing.Item({"user", "id"}).XmlIfNothingValue
URL = $"https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name={Name}&count=200&exclude_replies=false&include_rts=1&tweet_mode=extended"
If Not POST.IsEmptyString Then URL &= $"&max_id={POST}"
If IsSavedPosts Then
If Name.IsEmptyString Then Throw New ArgumentNullException With {.HelpLink = 1}
URL = $"https://api.twitter.com/2/timeline/bookmark.json?screen_name={Name}&count=200" &
"&tweet_mode=extended&include_entities=true&include_user_entities=true&include_ext_media_availability=true"
If Not POST.IsEmptyString Then URL &= $"&cursor={SymbolsConverter.ASCII.EncodeSymbolsOnly(POST)}"
Else
URL = $"https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name={Name}&count=200&exclude_replies=false&include_rts=1&tweet_mode=extended"
If Not POST.IsEmptyString Then URL &= $"&max_id={POST}"
End If
ThrowAny(Token)
Dim r$ = Responser.GetResponse(URL,, EDP.ThrowException)
If Not r.IsEmptyString Then
Using w As EContainer = JsonDocument.Parse(r)
If Not w Is Nothing AndAlso w.Count > 0 Then
For Each nn In w
For Each nn In If(IsSavedPosts, w({"globalObjects", "tweets"}).XmlIfNothing, w)
ThrowAny(Token)
If nn.Count > 0 Then
PostID = nn.Value("id")
If ID.IsEmptyString Then
ID = UID(nn)
If Not ID.IsEmptyString Then UpdateUserInformation()
If IsSavedPosts Then
PostID = nn.Value
If PostID.IsEmptyString Then PostID = nn.Value("id_str")
Else
PostID = nn.Value("id")
If ID.IsEmptyString Then
ID = UID(nn)
If Not ID.IsEmptyString Then UpdateUserInformation()
End If
End If
If UserDescriptionNeedToUpdate() AndAlso nn.Value({"user"}, "screen_name") = Name Then UserDescriptionUpdate(nn.Value({"user"}, "description"))
If Not IsSavedPosts AndAlso UserDescriptionNeedToUpdate() AndAlso nn.Value({"user"}, "screen_name") = Name Then _
UserDescriptionUpdate(nn.Value({"user"}, "description"))
'Date Pattern:
'Sat Jan 01 01:10:15 +0000 2000
@@ -74,8 +94,8 @@ Namespace API.Twitter
Continue For
End If
If Not ParseUserMediaOnly OrElse (Not nn.Contains("retweeted_status") OrElse
(Not ID.IsEmptyString AndAlso UID(nn("retweeted_status")) = ID)) Then
If IsSavedPosts OrElse Not ParseUserMediaOnly OrElse (Not nn.Contains("retweeted_status") OrElse
(Not ID.IsEmptyString AndAlso UID(nn("retweeted_status")) = ID)) Then
If Not CheckVideoNode(nn, PostID, PostDate) Then
s = nn.ItemF({"extended_entities", "media"})
If s Is Nothing OrElse s.Count = 0 Then s = nn.ItemF({"retweeted_status", "extended_entities", "media"})
@@ -95,13 +115,25 @@ Namespace API.Twitter
End If
End If
Next
If IsSavedPosts Then
s = w.ItemF({"timeline", "instructions", 0, "addEntries", "entries"}).XmlIfNothing
If s.Count > 0 Then NextCursor = If(s.ItemF({__NextCursor})?.Value({"content", "operation", "cursor"}, "value"), String.Empty)
End If
End If
End Using
If POST.IsEmptyString And ExistsDetected Then Exit Sub
If Not PostID.IsEmptyString And NewPostDetected Then DownloadData(PostID, Token)
If IsSavedPosts Then
If Not NextCursor.IsEmptyString And Not NextCursor = POST Then DownloadData(NextCursor, Token)
Else
If POST.IsEmptyString And ExistsDetected Then Exit Sub
If Not PostID.IsEmptyString And NewPostDetected Then DownloadData(PostID, Token)
End If
End If
Catch ane As ArgumentNullException When ane.HelpLink = 1
MyMainLOG = "Username not set for saved Twitter posts"
Catch ex As Exception
ProcessException(ex, Token, $"data downloading error [{URL}]")
ProcessException(ex, Token, $"data downloading error{IIf(IsSavedPosts, " (Saved Posts)", String.Empty)} [{URL}]")
End Try
End Sub
Friend Shared Function GetVideoInfo(ByVal URL As String, ByVal resp As Response) As IEnumerable(Of UserMedia)
@@ -128,20 +160,34 @@ Namespace API.Twitter
End Function
#Region "Picture options"
Private Function GetPictureOption(ByVal w As EContainer) As String
Const P4K As String = "4096x4096"
Try
Dim ww As EContainer = w("sizes")
If Not ww Is Nothing AndAlso ww.Count > 0 Then
Dim l As New List(Of Sizes)
Dim Orig As Sizes? = New Sizes(w.Value({"original_info"}, "height").FromXML(Of Integer)(-1), P4K)
If Orig.Value.Value = -1 Then Orig = Nothing
Dim LargeContained As Boolean = ww.Contains("large")
For Each v As EContainer In ww
If v.Count > 0 AndAlso v.Contains("h") Then l.Add(New Sizes(v.Value("h"), v.Name))
Next
If l.Count > 0 Then
l.Sort()
If l(0).Data.IsEmptyString And LargeContained Then Return "large" Else Return l(0).Data
If Orig.HasValue AndAlso l(0).Value < Orig.Value.Value Then
Return P4K
ElseIf l(0).Data.IsEmptyString Then
If LargeContained Then Return "large" Else Return P4K
Else
Return l(0).Data
End If
Else
Return P4K
End If
ElseIf Not w.Value({"original_info"}, "height").IsEmptyString Then
Return P4K
Else
Return String.Empty
End If
Return String.Empty
Catch ex As Exception
LogError(ex, "[API.Twitter.UserData.GetPictureOption]")
Return String.Empty
@@ -151,6 +197,7 @@ Namespace API.Twitter
#Region "Video options"
Private Function CheckVideoNode(ByVal w As EContainer, ByVal PostID As String, ByVal PostDate As String) As Boolean
Try
If CheckForGif(w, PostID, PostDate) Then Return True
Dim URL$ = GetVideoNodeURL(w)
If Not URL.IsEmptyString Then
Dim f$ = UrlFile(URL)
@@ -166,6 +213,41 @@ Namespace API.Twitter
Return False
End Try
End Function
Private Function CheckForGif(ByVal w As EContainer, ByVal PostID As String, ByVal PostDate As String) As Boolean
Try
Dim gifUrl As Predicate(Of EContainer) = Function(e) Not e.Value("content_type").IsEmptyString AndAlso
e.Value("content_type").Contains("mp4") AndAlso
Not e.Value("url").IsEmptyString
Dim url$, ff$
Dim f As SFile
Dim m As UserMedia
With w({"extended_entities", "media"}).XmlIfNothing
If .Count > 0 Then
For Each n As EContainer In .Self
If n.Value("type") = "animated_gif" Then
With n({"video_info", "variants"}).XmlIfNothing.ItemF({gifUrl}).XmlIfNothing
url = .Value("url")
ff = UrlFile(url)
If Not ff.IsEmptyString Then
If Not _DataNames.Contains(ff) Then
m = MediaFromData(url, PostID, PostDate)
f = m.File
If Not f.IsEmptyString Then f.Name = $"GIF_{f.Name}" : m.File = f
_TempMediaList.ListAddValue(m, LNC)
End If
Return True
End If
End With
End If
Next
End If
End With
Return False
Catch ex As Exception
LogError(ex, "[API.Twitter.UserData.CheckForGif]")
Return False
End Try
End Function
Private Shared Function GetVideoNodeURL(ByVal w As EContainer) As String
Dim v As EContainer = w.GetNode(VideoNode)
If Not v Is Nothing AndAlso v.Count > 0 Then
@@ -220,6 +302,8 @@ Namespace API.Twitter
UserSuspended = True
ElseIf Responser.StatusCode = HttpStatusCode.BadRequest Then
MyMainLOG = "Twitter has invalid credentials"
ElseIf Responser.StatusCode = HttpStatusCode.ServiceUnavailable Then
MyMainLOG = $"Twitter is currently unavailable ({ToString()})"
Else
If Not FromPE Then LogError(ex, Message) : HasError = True
Return 0

View File

@@ -207,6 +207,18 @@ Namespace API
Return Count > 0 AndAlso Collections.Exists(Function(c) c.FitToAddParams)
End Get
End Property
Friend Overrides Property ScriptUse As Boolean
Get
Return Count > 0 AndAlso Collections.Exists(Function(c) c.ScriptUse)
End Get
Set(ByVal u As Boolean)
If Count > 0 Then Collections.ForEach(Sub(ByVal c As IUserData)
Dim b As Boolean = c.ScriptUse = u
c.ScriptUse = u
If Not b Then c.UpdateUserInformation()
End Sub)
End Set
End Property
#Region "Context buttons"
Friend ReadOnly Property ContextDown As ToolStripMenuItem()
Get
@@ -336,6 +348,7 @@ Namespace API
.Favorite = Favorite
.ReadyForDownload = ReadyForDownload
ConsolidateLabels()
ConsolidateScripts()
.UpdateUserInformation()
End If
ImageHandler(_Item, False)
@@ -381,6 +394,9 @@ Namespace API
Collections.ForEach(Sub(c) c.Labels.ListAddList(l, lp))
End If
End Sub
Private Sub ConsolidateScripts()
If Count > 1 AndAlso ScriptUse Then Collections.ForEach(Sub(c) c.ScriptUse = True)
End Sub
Friend Sub AddRange(ByVal _Items As IEnumerable(Of IUserData))
If Not _Items Is Nothing AndAlso _Items.Count > 0 Then
For i% = 0 To _Items.Count - 1 : Add(_Items(i)) : Next

View File

@@ -20,7 +20,7 @@ Imports CmbDefaultButtons = PersonalUtilities.Forms.Controls.Base.ActionButton.D
Imports RButton = PersonalUtilities.Tools.RangeSwitcherButton.Types
Friend Class ChannelViewForm : Implements IChannelLimits
Friend Event OnUsersAdded(ByVal StartIndex As Integer)
Friend Event OnDownloadDone(ByVal Message As String)
Friend Event OnDownloadDone As NotificationEventHandler
#Region "Appended user structure"
Private Structure PendingUser
Friend ID As String
@@ -160,7 +160,7 @@ Friend Class ChannelViewForm : Implements IChannelLimits
CMB_CHANNELS.Buttons.AddRange({CmbDefaultButtons.Refresh, CmbDefaultButtons.Add, CmbDefaultButtons.Delete,
New ActionButton(CmbDefaultButtons.Up) With {.ToolTipText = "Previous item (F1)"},
New ActionButton(CmbDefaultButtons.Down) With {.ToolTipText = "Next item (F4)"},
CmbDefaultButtons.Info})
CmbDefaultButtons.Edit, CmbDefaultButtons.Info})
TXT_LIMIT = New TextBoxExtended With {
.CaptionText = "Limit",
.Margin = New Padding(2),
@@ -201,11 +201,12 @@ Friend Class ChannelViewForm : Implements IChannelLimits
MyRange = New RangeSwitcher(Of UserPost) With {.Selector = SelectorExpression}
With MyRange
.Limit = ImagesInRow * ImagesRows
.InsertButtons(ToolbarTOP, {RButton.Previous, RButton.Next}, 5)
.InsertButtons(ToolbarTOP,, 5)
.SetButtonKey(RButton.Previous, Keys.F2)
.SetButtonKey(RButton.Next, Keys.F3)
.BindForm(Me)
.LabelNumbersProvider = CProvider
.LabelShowAbsolutIndexes = False
.UpdateControls()
End With
AddHandler Settings.ChannelsImagesColumns.OnValueChanged, AddressOf ImagesCountChanged
@@ -215,6 +216,7 @@ Friend Class ChannelViewForm : Implements IChannelLimits
MyDefs.MyViewInitialize(Me, Settings.Design)
RefillChannels(Settings.LatestSelectedChannel.Value)
ChangeComboIndex(0)
MyRange.LabelText = String.Empty
CMB_CHANNELS_ActionOnCheckedChange(CMB_CHANNELS.Checked)
With LIST_POSTS
Dim s As Size = GetImageSize()
@@ -279,11 +281,10 @@ Friend Class ChannelViewForm : Implements IChannelLimits
End With
CMB_CHANNELS.EndUpdate()
End Sub
#Region "Images refill methods"
Private Sub AppendPendingUsers()
If LIST_POSTS.CheckedIndices.Count > 0 Then
Dim c As Channel = GetCurrentChannel(False)
Dim lp As New ListAddParams(LAP.NotContainsOnly) With {.OnAddAction = Sub(ByVal u As PendingUser) u.ChannelUserAdded()}
Dim lp As New ListAddParams(LAP.NotContainsOnly) With {.OnProcessAction = Sub(ByVal u As PendingUser) u.ChannelUserAdded()}
PendingUsers.ListAddList((From p As ListViewItem In LIST_POSTS.Items
Where p.Checked
Select New PendingUser(p.Text, c, GetPostBySelected(CStr(p.Tag)).CachedFile)), lp)
@@ -311,7 +312,6 @@ Friend Class ChannelViewForm : Implements IChannelLimits
End With
Return s
End Function
#End Region
#Region "Toolbar controls"
#Region "Downloader"
Private TokenSource As CancellationTokenSource
@@ -326,7 +326,7 @@ Friend Class ChannelViewForm : Implements IChannelLimits
Private Async Sub BTT_DOWNLOAD_Click(sender As Object, e As EventArgs) Handles BTT_DOWNLOAD.Click
Try
AppendPendingUsers()
If Not TokenSource Is Nothing OrElse Not HOST.Source.Available(Plugin.ISiteSettings.Download.Channel) Then Exit Sub
If Not TokenSource Is Nothing OrElse Not HOST.Source.Available(Plugin.ISiteSettings.Download.Channel, False) Then Exit Sub
Dim InvokeToken As Action = Sub()
If TokenSource Is Nothing Then
CProgress.TotalCount = 0
@@ -543,21 +543,30 @@ Friend Class ChannelViewForm : Implements IChannelLimits
LBL_LIMIT_TEXT.Text = String.Empty
If Not c Is Nothing Then
Settings.LatestSelectedChannel.Value = c.ID
With c.PostsAll
If .Count > 0 Then
OPT_LIMITS_DEFAULT.Checked = True
Dim d As Date? = .FirstOrDefault(Function(p) p.Date.HasValue).Date
If d.HasValue Then
LBL_LIMIT_TEXT.Text = $"to date {AConvert(Of String)(d, ADateTime.Formats.BaseDateTime, String.Empty)}"
Dim d As Date?
If c.ViewMode = IRedditView.View.New Then
With c.PostsAll
If .Count > 0 Then
OPT_LIMITS_DEFAULT.Checked = True
d = .FirstOrDefault(Function(p) p.Date.HasValue).Date
If d.HasValue Then
LBL_LIMIT_TEXT.Text = $"to date {AConvert(Of String)(d, ADateTime.Formats.BaseDateTime, String.Empty)}"
Else
LBL_LIMIT_TEXT.Text = $"to post [{c.First(Function(p) Not p.ID.IsEmptyString).ID}]"
End If
Else
LBL_LIMIT_TEXT.Text = $"to post [{c.First(Function(p) Not p.ID.IsEmptyString).ID}]"
OPT_LIMITS_COUNT.Checked = True
If TXT_LIMIT.Text.IsEmptyString Then TXT_LIMIT.Value = Channel.DefaultDownloadLimitCount
LBL_LIMIT_TEXT.Text = $"first {TXT_LIMIT.Text} posts"
End If
Else
OPT_LIMITS_COUNT.Checked = True
If TXT_LIMIT.Text.IsEmptyString Then TXT_LIMIT.Value = Channel.DefaultDownloadLimitCount
LBL_LIMIT_TEXT.Text = $"first {TXT_LIMIT.Text} posts"
End If
End With
End With
Else
OPT_LIMITS_DEFAULT.Checked = True
d = c.LatestParsedDate
Dim per$ = IIf(c.ViewMode = IRedditView.View.Top, c.ViewPeriod.ToString, String.Empty)
If Not per.IsEmptyString Then per = $" ({per})"
LBL_LIMIT_TEXT.Text = $"[{c.ViewMode}{per}] to date {AConvert(Of String)(d, ADateTime.Formats.BaseDateTime, String.Empty)}"
End If
End If
End Sub
Private Sub CMB_CHANNELS_ActionSelectedItemChanged(ByVal _Item As ListViewItem) Handles CMB_CHANNELS.ActionSelectedItemChanged
@@ -582,6 +591,18 @@ Friend Class ChannelViewForm : Implements IChannelLimits
End Try
Case CmbDefaultButtons.Up : ChangeComboIndex(-1)
Case CmbDefaultButtons.Down : ChangeComboIndex(1)
Case CmbDefaultButtons.Edit
Try
c = GetCurrentChannel()
If Not c Is Nothing Then
Using f As New RedditViewSettingsForm(c)
f.ShowDialog()
If f.DialogResult = DialogResult.OK Then c.Save()
End Using
End If
Catch ex As Exception
ErrorsDescriber.Execute(EDP.LogMessageValue, ex, "Error on trying to edit channel")
End Try
Case CmbDefaultButtons.Info
Try
c = GetCurrentChannel()

View File

@@ -47,19 +47,19 @@ Friend Class ChannelsStatsForm : Implements IOkCancelDeleteToolbar
CMB_CHANNELS.EndUpdate()
End If
End Sub
Private Sub ToolbarBttOK() Implements IOkCancelToolbar.ToolbarBttOK
Private Sub OK() Implements IOkCancelToolbar.OK
MyDefs.CloseForm()
End Sub
Private Sub ToolbarBttCancel() Implements IOkCancelToolbar.ToolbarBttCancel
Private Sub Cancel() Implements IOkCancelToolbar.Cancel
MyDefs.CloseForm(DialogResult.Cancel)
End Sub
Private Sub ToolbarBttDelete() Implements IOkCancelDeleteToolbar.ToolbarBttDelete
Private Sub Delete() Implements IOkCancelDeleteToolbar.Delete
Try
Dim c As List(Of String) = CMB_CHANNELS.Items.CheckedItems.Select(Function(cc) CStr(cc.Value(1))).ListIfNothing
If c.ListExists Then
If MsgBoxE({$"The following channels will be deleted:{vbCr}{c.ListToString(, vbCr)}", "Deleting channels"}, vbExclamation,,, {"Confirm", "Cancel"}) = 0 Then
If MsgBoxE({$"The following channels will be deleted:{vbCr}{c.ListToString(vbCr)}", "Deleting channels"}, vbExclamation,,, {"Confirm", "Cancel"}) = 0 Then
For Each CID$ In c : Settings.Channels.Remove(Settings.Channels.Find(CID)) : Next
MyMainLOG = $"Deleted channels:{vbNewLine}{c.ListToString(, vbNewLine)}"
MyMainLOG = $"Deleted channels:{vbNewLine}{c.ListToString(vbNewLine)}"
MsgBoxE("Channels deleted")
DeletedChannels += c.Count
c.Clear()

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 B

View File

@@ -12,7 +12,12 @@ Namespace DownloadObjects
Friend Class ActiveDownloadingProgress
Private Const MinWidth As Integer = 450
Private MyView As FormsView
Friend Property Opened As Boolean = False
Private Opened As Boolean = False
Friend ReadOnly Property ReadyToOpen As Boolean
Get
Return Settings.DownloadOpenProgress And (Not Opened Or Settings.DownloadOpenProgress.Attribute) And Not Visible
End Get
End Property
Private ReadOnly JobsList As List(Of DownloadProgress)
Friend Property DisableProgressChange As Boolean = False
Friend Sub New()
@@ -34,37 +39,41 @@ Namespace DownloadObjects
End Sub
Private Sub Downloader_OnReconfigured()
Const RowHeight% = 30
With TP_MAIN
If .Controls.Count > 0 Then
For Each c As Control In .Controls
If Not c Is Nothing Then c.Dispose()
Next
.Controls.Clear()
End If
.RowStyles.Clear()
.RowCount = 0
End With
JobsList.ListClearDispose
With Downloader
If .Pool.Count > 0 Then
For Each j As TDownloader.Job In .Pool
With TP_MAIN
.RowStyles.Add(New RowStyle(SizeType.Absolute, RowHeight))
.RowCount += 1
JobsList.Add(New DownloadProgress(j))
AddHandler JobsList.Last.OnTotalCountChange, AddressOf Jobs_OnTotalCountChange
.Controls.Add(JobsList.Last.Get, 0, .RowStyles.Count - 1)
End With
Next
TP_MAIN.RowStyles.Add(New RowStyle(SizeType.Percent, 100))
TP_MAIN.RowCount += 1
End If
Dim s As Size = Size
s.Height = TP_MAIN.RowStyles.Count * RowHeight + PaddingE.GetOf({TP_MAIN}).Vertical(TP_MAIN.RowStyles.Count) - TP_MAIN.RowStyles.Count * 2
MinimumSize = New Size(MinWidth, s.Height)
Size = s
End With
TP_MAIN.Refresh()
Dim a As Action = Sub()
With TP_MAIN
If .Controls.Count > 0 Then
For Each c As Control In .Controls
If Not c Is Nothing Then c.Dispose()
Next
.Controls.Clear()
End If
.RowStyles.Clear()
.RowCount = 0
End With
JobsList.ListClearDispose
With Downloader
If .Pool.Count > 0 Then
For Each j As TDownloader.Job In .Pool
With TP_MAIN
.RowStyles.Add(New RowStyle(SizeType.Absolute, RowHeight))
.RowCount += 1
JobsList.Add(New DownloadProgress(j))
AddHandler JobsList.Last.OnTotalCountChange, AddressOf Jobs_OnTotalCountChange
.Controls.Add(JobsList.Last.Get, 0, .RowStyles.Count - 1)
End With
Next
TP_MAIN.RowStyles.Add(New RowStyle(SizeType.Percent, 100))
TP_MAIN.RowCount += 1
End If
Dim s As Size = Size
s.Height = TP_MAIN.RowStyles.Count * RowHeight + PaddingE.GetOf({TP_MAIN}).Vertical(TP_MAIN.RowStyles.Count) - TP_MAIN.RowStyles.Count * 2
MinimumSize = New Size(MinWidth, s.Height)
Size = s
End With
TP_MAIN.Refresh()
End Sub
If TP_MAIN.InvokeRequired Then TP_MAIN.Invoke(a) Else a.Invoke
End Sub
Private Sub Jobs_OnTotalCountChange()
If JobsList.Count > 0 And Not DisableProgressChange Then

View File

@@ -0,0 +1,346 @@
' Copyright (C) 2022 Andy
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY
Imports System.Threading
Imports PersonalUtilities.Functions.XML
Imports PersonalUtilities.Tools.Notifications
Imports SCrawler.DownloadObjects.Groups
Imports SCrawler.API
Imports SCrawler.API.Base
Namespace DownloadObjects
Friend Class AutoDownloader : Inherits GroupParameters
Friend Event UserFind(ByVal Key As String, ByVal Activate As Boolean)
Friend Enum Modes As Integer
None = 0
[Default] = 1
All = 2
Specified = 3
Groups = 4
End Enum
Friend Const DefaultTimer As Integer = 60
#Region "Notifications"
Private Const KeyOpenFolder As String = "_____OPEN_FOLDER_SCRAWLER_AUTOMATION"
Private Const KeyOpenSite As String = "_____OPEN_SITE_SCRAWLER_AUTOMATION"
Private Const KeyBttDismiss As String = "_____DISMISS_SCRAWLER_AUTOMATION"
Private Const KeyBttPhoto As String = "_____PHOTO_SCRAWLER_AUTOMATION"
Private ReadOnly UserKeys As List(Of NotifiedUser)
Private Class NotifiedUser : Implements IDisposable
Private ReadOnly Property User As IUserData
Private ReadOnly Property Key As String
Private ReadOnly Property KeyFolder As String
Private ReadOnly Property KeySite As String
Private ReadOnly Property KeyDismiss As String
Private ReadOnly Property Images As Dictionary(Of String, SFile)
Private Sub New()
Images = New Dictionary(Of String, SFile)
End Sub
Friend Sub New(ByVal _Key As String)
Me.New
Key = _Key
KeyFolder = $"{Key}{KeyOpenFolder}"
KeySite = $"{Key}{KeyOpenSite}"
KeyDismiss = $"{Key}{KeyBttDismiss}"
End Sub
Friend Sub New(ByVal _Key As String, ByRef _User As IUserData)
Me.New(_Key)
User = _User
End Sub
Public Shared Widening Operator CType(ByVal Key As String) As NotifiedUser
Return New NotifiedUser(Key)
End Operator
Friend Sub ShowNotification()
Try
If Not User Is Nothing Then
Dim Text$ = $"{User.Site} - {User.Name}{vbNewLine}" &
$"Downloaded: {User.DownloadedPictures(False)} images, {User.DownloadedVideos(False)} videos"
Dim Title$
If Not User.CollectionName.IsEmptyString Then
Title = User.CollectionName
Else
Title = User.ToString
End If
Using Notify As New Notification(Text, Title) With {.Key = Key}
Dim uPic As SFile = DirectCast(User, UserDataBase).GetUserPictureAddress
Dim uif As SFile = Nothing
Dim uifKey$ = String.Empty
If uPic.Exists Then Notify.Images = {New ToastImage(uPic)}
If User.DownloadedPictures(False) > 0 Then
uif = DirectCast(User, UserDataBase).GetLastImageAddress
If uif.Exists Then
Notify.Images = {New ToastImage(uif, IImage.Modes.Inline)}
uifKey = $"{Key}_{Images.Keys.Count + 1}_{KeyBttPhoto}"
If Not Images.ContainsKey(uifKey) Then Images.Add(uifKey, uif)
End If
End If
Notify.Buttons = {
New ToastButton(KeyFolder, "Folder"),
New ToastButton(KeySite, "Site")
}
If Not uifKey.IsEmptyString Then Notify.Buttons = {New ToastButton(uifKey, "Photo")}
Notify.Buttons = {New ToastButton(KeyDismiss, "Dismiss")}
Notify.Show()
End Using
End If
Catch ex As Exception
ErrorsDescriber.Execute(EDP.SendInLog, ex, "[AutoDownloader.NotifiedUser.ShowNotification]")
If Not User Is Nothing Then
MainFrameObj.ShowNotification($"Downloaded: {User.DownloadedPictures(False)} images, {User.DownloadedVideos(False)} videos",
User.ToString, IIf(User.HasError, ToolTipIcon.Warning, ToolTipIcon.Info))
End If
End Try
End Sub
''' <returns>True to activate</returns>
Friend Function Open(ByVal _Key As String) As Boolean
If Not User Is Nothing Then
If Key = _Key Then
Return True
ElseIf KeyFolder = _Key Then
User.OpenFolder()
ElseIf KeySite = _Key Then
User.OpenSite()
ElseIf Images.ContainsKey(_Key) Then
Images(_Key).Open(, EDP.None)
End If
End If
Return False
End Function
Public Overrides Function Equals(ByVal Obj As Object) As Boolean
With CType(Obj, NotifiedUser)
Return .Key = Key Or .Key = KeyFolder Or .Key = KeySite Or .Key = KeyDismiss Or Images.ContainsKey(.Key)
End With
End Function
#Region "IDisposable Support"
Private disposedValue As Boolean = False
Protected Overridable Overloads Sub Dispose(ByVal disposing As Boolean)
If Not disposedValue Then
If disposing Then Images.Clear()
disposedValue = True
End If
End Sub
Protected Overrides Sub Finalize()
Dispose(False)
MyBase.Finalize()
End Sub
Friend Overloads Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
End Class
#End Region
#Region "XML Names"
Private Const Name_Mode As String = "Mode"
Private Const Name_Groups As String = "Groups"
Private Const Name_Labels As String = "Labels"
Private Const Name_Timer As String = "Timer"
Private Const Name_LastDownloadDate As String = "LastDownloadDate"
Private Const Name_ShowNotifications As String = "Notify"
#End Region
#Region "Declarations"
Private _Mode As Modes = Modes.None
Friend Property Mode As Modes
Get
Return _Mode
End Get
Set(ByVal m As Modes)
_Mode = m
If _Mode = Modes.None Then [Stop]()
End Set
End Property
Friend ReadOnly Property Groups As List(Of String)
Friend Property Timer As Integer = DefaultTimer
Friend Property ShowNotifications As Boolean = True
Friend Property LastDownloadDate As Date = Now.AddYears(-1)
Private ReadOnly DateProvider As New ADateTime(ADateTime.Formats.BaseDateTime)
Friend ReadOnly Property Information As String
Get
Return $"Last download date: {LastDownloadDate.ToStringDate(ADateTime.Formats.BaseDateTime)} " &
$"({IIf(Working, "working", "stopped")}{IIf(Working And Pause, ", paused", String.Empty)})"
End Get
End Property
Private File As SFile = $"Settings\AutoDownload.xml"
Private AThread As Thread
#End Region
#Region "Initializer"
Friend Sub New()
Groups = New List(Of String)
UserKeys = New List(Of NotifiedUser)
If File.Exists Then
Using x As New XmlFile(File)
Mode = x.Value(Name_Mode).FromXML(Of Integer)(Modes.None)
Groups.ListAddList(x.Value(Name_Groups).StringToList(Of String)("|"), LAP.NotContainsOnly)
Labels.ListAddList(x.Value(Name_Labels).StringToList(Of String)("|"), LAP.NotContainsOnly)
Temporary = x.Value(Name_Temporary).FromXML(Of Integer)(CheckState.Indeterminate)
Favorite = x.Value(Name_Favorite).FromXML(Of Integer)(CheckState.Indeterminate)
ReadyForDownload = x.Value(Name_ReadyForDownload).FromXML(Of Boolean)(True)
ReadyForDownloadIgnore = x.Value(Name_ReadyForDownloadIgnore).FromXML(Of Boolean)(False)
Timer = x.Value(Name_Timer).FromXML(Of Integer)(DefaultTimer)
ShowNotifications = x.Value(Name_ShowNotifications).FromXML(Of Boolean)(True)
LastDownloadDate = AConvert(Of Date)(x.Value(Name_LastDownloadDate), DateProvider, Now.AddYears(-1))
End Using
End If
End Sub
#End Region
#Region "Groups Support"
Friend Sub GROUPS_Updated(ByVal Sender As DownloadGroup)
If Groups.Count > 0 Then
Dim i% = Groups.IndexOf(Sender.NameBefore)
If i >= 0 Then Groups(i) = Sender.Name : Update()
End If
End Sub
Friend Sub GROUPS_Deleted(ByVal Sender As DownloadGroup)
If Groups.Count > 0 Then
Dim i% = Groups.IndexOf(Sender.Name)
If i >= 0 Then Groups.RemoveAt(i) : Update()
End If
End Sub
#End Region
#Region "Update"
Friend Sub Update()
Try
Using x As New XmlFile With {.Name = "Settings"}
x.Add(Name_Mode, CInt(Mode))
x.Add(Name_Groups, Groups.ListToString("|"))
x.Add(Name_Labels, Labels.ListToString("|"))
x.Add(Name_Temporary, CInt(Temporary))
x.Add(Name_Favorite, CInt(Favorite))
x.Add(Name_ReadyForDownload, ReadyForDownload.BoolToInteger)
x.Add(Name_ReadyForDownloadIgnore, ReadyForDownloadIgnore.BoolToInteger)
x.Add(Name_Timer, Timer)
x.Add(Name_ShowNotifications, ShowNotifications.BoolToInteger)
x.Add(Name_LastDownloadDate, CStr(AConvert(Of String)(LastDownloadDate, DateProvider, String.Empty)))
x.Save(File)
End Using
Catch ex As Exception
ErrorsDescriber.Execute(EDP.SendInLog, ex, "[AutoDownloader.Update]")
End Try
End Sub
#End Region
#Region "Execution"
Private ReadOnly Property Working As Boolean
Get
Return If(AThread?.IsAlive, False)
End Get
End Property
Friend Sub Start()
If Not If(AThread?.IsAlive, False) And Not Mode = Modes.None Then
AThread = New Thread(New ThreadStart(AddressOf Checker))
AThread.SetApartmentState(ApartmentState.MTA)
AThread.Start()
End If
End Sub
Private _StopRequested As Boolean = False
Friend Property Pause As Boolean = False
Friend Sub [Stop]()
If Working Then _StopRequested = True
End Sub
Private Sub Checker()
Try
While Not _StopRequested Or Downloader.Working
If LastDownloadDate.AddMinutes(Timer) < Now And Not Downloader.Working And Not Pause And Not _StopRequested Then Download()
Thread.Sleep(500)
End While
Catch ex As Exception
ErrorsDescriber.Execute(EDP.SendInLog, ex, "[AutoDownloader.Checker]")
Finally
_StopRequested = False
End Try
End Sub
Private Sub Download()
Dim Keys As New List(Of String)
Try
Dim users As New List(Of IUserData)
Dim GName$
Dim i%
Dim l As New ListAddParams(LAP.IgnoreICopier + LAP.NotContainsOnly)
Dim notify As Action = Sub()
With Downloader.Downloaded
If ShowNotifications And .Count > 0 Then .ForEach(Sub(ByVal u As IUserData)
If Keys.Contains(u.Key) Then
ShowNotification(u)
Keys.Remove(u.Key)
End If
End Sub)
End With
End Sub
Select Case Mode
Case Modes.All : users.ListAddList(Settings.Users)
Case Modes.Default
Using g As New GroupParameters : users.ListAddList(DownloadGroup.GetUsers(g, True)) : End Using
Case Modes.Specified : users.ListAddList(DownloadGroup.GetUsers(Me, True))
Case Modes.Groups
If Groups.Count > 0 And Settings.Groups.Count > 0 Then
For Each GName In Groups
i = Settings.Groups.IndexOf(GName)
If i >= 0 Then users.ListAddList(Settings.Groups(i).GetUsers, l)
Next
End If
End Select
If users.Count > 0 Then
Keys.ListAddList(users.SelectMany(Of String)(Function(ByVal user As IUserData) As IEnumerable(Of String)
If user.IsCollection Then
With DirectCast(user, UserDataBind)
If .Count > 0 Then
Return .Collections.Select(Function(u) u.Key)
Else
Return New String() {}
End If
End With
Else
Return {user.Key}
End If
End Function))
With Downloader
.AutoDownloaderWorking = True
If .Downloaded.Count > 0 Then .Downloaded.RemoveAll(Function(u) Keys.Contains(u.Key)) : .InvokeDownloadsChangeEvent()
.AddRange(users)
.DisableOpenForms = False
While .Working Or .Count > 0 : notify.Invoke() : Thread.Sleep(200) : End While
.AutoDownloaderWorking = False
notify.Invoke
End With
End If
Catch ex As Exception
ErrorsDescriber.Execute(EDP.SendInLog, ex, "[AutoDownloader.Download]")
Finally
Keys.Clear()
LastDownloadDate = Now
Update()
End Try
End Sub
Private Sub ShowNotification(ByVal u As IUserData)
Dim i% = UserKeys.IndexOf(u.Key)
If i >= 0 Then
UserKeys(i).ShowNotification()
Else
UserKeys.Add(New NotifiedUser(u.Key, TDownloader.GetUserFromMainCollection(u)))
UserKeys.Last.ShowNotification()
End If
End Sub
Friend Function NotificationClicked(ByVal Key As String) As Boolean
Dim i% = UserKeys.IndexOf(Key)
If i >= 0 Then
RaiseEvent UserFind(Key, UserKeys(i).Open(Key))
Return True
Else
Return False
End If
End Function
#End Region
#Region "IDisposable Support"
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If Not disposedValue And disposing Then
[Stop]()
UserKeys.ListClearDispose()
Groups.Clear()
End If
MyBase.Dispose(disposing)
End Sub
#End Region
End Class
End Namespace

View File

@@ -0,0 +1,278 @@
' Copyright (C) 2022 Andy
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY
Namespace DownloadObjects
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()>
Partial Friend Class AutoDownloaderEditorForm : Inherits System.Windows.Forms.Form
<System.Diagnostics.DebuggerNonUserCode()>
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
Try
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
Finally
MyBase.Dispose(disposing)
End Try
End Sub
Private components As System.ComponentModel.IContainer
<System.Diagnostics.DebuggerStepThrough()>
Private Sub InitializeComponent()
Me.components = New System.ComponentModel.Container()
Dim CONTAINER_MAIN As System.Windows.Forms.ToolStripContainer
Dim ActionButton1 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(AutoDownloaderEditorForm))
Dim ActionButton2 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim TP_MODE As System.Windows.Forms.TableLayoutPanel
Dim ActionButton3 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim TT_MAIN As System.Windows.Forms.ToolTip
Me.DEF_GROUP = New SCrawler.DownloadObjects.Groups.GroupDefaults()
Me.TXT_GROUPS = New PersonalUtilities.Forms.Controls.TextBoxExtended()
Me.OPT_ALL = New System.Windows.Forms.RadioButton()
Me.OPT_DEFAULT = New System.Windows.Forms.RadioButton()
Me.OPT_SPEC = New System.Windows.Forms.RadioButton()
Me.OPT_DISABLED = New System.Windows.Forms.RadioButton()
Me.OPT_GROUP = New System.Windows.Forms.RadioButton()
Me.CH_NOTIFY = New System.Windows.Forms.CheckBox()
Me.TXT_TIMER = New PersonalUtilities.Forms.Controls.TextBoxExtended()
Me.LBL_LAST_TIME_UP = New System.Windows.Forms.Label()
CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer()
TP_MODE = New System.Windows.Forms.TableLayoutPanel()
TT_MAIN = New System.Windows.Forms.ToolTip(Me.components)
CONTAINER_MAIN.ContentPanel.SuspendLayout()
CONTAINER_MAIN.SuspendLayout()
Me.DEF_GROUP.SuspendLayout()
CType(Me.TXT_GROUPS, System.ComponentModel.ISupportInitialize).BeginInit()
TP_MODE.SuspendLayout()
CType(Me.TXT_TIMER, System.ComponentModel.ISupportInitialize).BeginInit()
Me.SuspendLayout()
'
'CONTAINER_MAIN
'
'
'CONTAINER_MAIN.ContentPanel
'
CONTAINER_MAIN.ContentPanel.Controls.Add(Me.DEF_GROUP)
CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(476, 242)
CONTAINER_MAIN.Dock = System.Windows.Forms.DockStyle.Fill
CONTAINER_MAIN.LeftToolStripPanelVisible = False
CONTAINER_MAIN.Location = New System.Drawing.Point(0, 0)
CONTAINER_MAIN.Name = "CONTAINER_MAIN"
CONTAINER_MAIN.RightToolStripPanelVisible = False
CONTAINER_MAIN.Size = New System.Drawing.Size(476, 242)
CONTAINER_MAIN.TabIndex = 0
CONTAINER_MAIN.TopToolStripPanelVisible = False
'
'DEF_GROUP
'
Me.DEF_GROUP.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single]
Me.DEF_GROUP.ColumnCount = 1
Me.DEF_GROUP.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
Me.DEF_GROUP.Controls.Add(Me.TXT_GROUPS, 0, 4)
Me.DEF_GROUP.Controls.Add(TP_MODE, 0, 0)
Me.DEF_GROUP.Controls.Add(Me.CH_NOTIFY, 0, 5)
Me.DEF_GROUP.Controls.Add(Me.TXT_TIMER, 0, 6)
Me.DEF_GROUP.Controls.Add(Me.LBL_LAST_TIME_UP, 0, 7)
Me.DEF_GROUP.Dock = System.Windows.Forms.DockStyle.Fill
Me.DEF_GROUP.Location = New System.Drawing.Point(0, 0)
Me.DEF_GROUP.Name = "DEF_GROUP"
Me.DEF_GROUP.RowCount = 9
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
Me.DEF_GROUP.Size = New System.Drawing.Size(476, 242)
Me.DEF_GROUP.TabIndex = 0
'
'TXT_GROUPS
'
ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image)
ActionButton1.Index = 0
ActionButton1.Name = "BTT_EDIT"
ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image)
ActionButton2.Index = 1
ActionButton2.Name = "BTT_CLEAR"
Me.TXT_GROUPS.Buttons.Add(ActionButton1)
Me.TXT_GROUPS.Buttons.Add(ActionButton2)
Me.TXT_GROUPS.CaptionText = "Groups"
Me.TXT_GROUPS.CaptionWidth = 50.0R
Me.TXT_GROUPS.Dock = System.Windows.Forms.DockStyle.Fill
Me.TXT_GROUPS.Location = New System.Drawing.Point(4, 111)
Me.TXT_GROUPS.Name = "TXT_GROUPS"
Me.TXT_GROUPS.Size = New System.Drawing.Size(468, 22)
Me.TXT_GROUPS.TabIndex = 4
'
'TP_MODE
'
TP_MODE.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single]
TP_MODE.ColumnCount = 5
TP_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 20.0!))
TP_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 20.0!))
TP_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 20.0!))
TP_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 20.0!))
TP_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 20.0!))
TP_MODE.Controls.Add(Me.OPT_ALL, 1, 0)
TP_MODE.Controls.Add(Me.OPT_DEFAULT, 2, 0)
TP_MODE.Controls.Add(Me.OPT_SPEC, 3, 0)
TP_MODE.Controls.Add(Me.OPT_DISABLED, 0, 0)
TP_MODE.Controls.Add(Me.OPT_GROUP, 4, 0)
TP_MODE.Dock = System.Windows.Forms.DockStyle.Fill
TP_MODE.Location = New System.Drawing.Point(1, 1)
TP_MODE.Margin = New System.Windows.Forms.Padding(0)
TP_MODE.Name = "TP_MODE"
TP_MODE.RowCount = 1
TP_MODE.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_MODE.Size = New System.Drawing.Size(474, 25)
TP_MODE.TabIndex = 8
'
'OPT_ALL
'
Me.OPT_ALL.AutoSize = True
Me.OPT_ALL.Dock = System.Windows.Forms.DockStyle.Fill
Me.OPT_ALL.Location = New System.Drawing.Point(98, 4)
Me.OPT_ALL.Name = "OPT_ALL"
Me.OPT_ALL.Size = New System.Drawing.Size(87, 17)
Me.OPT_ALL.TabIndex = 1
Me.OPT_ALL.TabStop = True
Me.OPT_ALL.Text = "ALL"
TT_MAIN.SetToolTip(Me.OPT_ALL, "Download all users")
Me.OPT_ALL.UseVisualStyleBackColor = True
'
'OPT_DEFAULT
'
Me.OPT_DEFAULT.AutoSize = True
Me.OPT_DEFAULT.Dock = System.Windows.Forms.DockStyle.Fill
Me.OPT_DEFAULT.Location = New System.Drawing.Point(192, 4)
Me.OPT_DEFAULT.Name = "OPT_DEFAULT"
Me.OPT_DEFAULT.Size = New System.Drawing.Size(87, 17)
Me.OPT_DEFAULT.TabIndex = 2
Me.OPT_DEFAULT.TabStop = True
Me.OPT_DEFAULT.Text = "Default"
TT_MAIN.SetToolTip(Me.OPT_DEFAULT, "All users marked ""Ready for download""")
Me.OPT_DEFAULT.UseVisualStyleBackColor = True
'
'OPT_SPEC
'
Me.OPT_SPEC.AutoSize = True
Me.OPT_SPEC.Dock = System.Windows.Forms.DockStyle.Fill
Me.OPT_SPEC.Location = New System.Drawing.Point(286, 4)
Me.OPT_SPEC.Name = "OPT_SPEC"
Me.OPT_SPEC.Size = New System.Drawing.Size(87, 17)
Me.OPT_SPEC.TabIndex = 3
Me.OPT_SPEC.TabStop = True
Me.OPT_SPEC.Text = "Specified"
TT_MAIN.SetToolTip(Me.OPT_SPEC, "Select parameters")
Me.OPT_SPEC.UseVisualStyleBackColor = True
'
'OPT_DISABLED
'
Me.OPT_DISABLED.AutoSize = True
Me.OPT_DISABLED.Dock = System.Windows.Forms.DockStyle.Fill
Me.OPT_DISABLED.Location = New System.Drawing.Point(4, 4)
Me.OPT_DISABLED.Name = "OPT_DISABLED"
Me.OPT_DISABLED.Size = New System.Drawing.Size(87, 17)
Me.OPT_DISABLED.TabIndex = 0
Me.OPT_DISABLED.TabStop = True
Me.OPT_DISABLED.Text = "Disabled"
TT_MAIN.SetToolTip(Me.OPT_DISABLED, "Automation disabled")
Me.OPT_DISABLED.UseVisualStyleBackColor = True
'
'OPT_GROUP
'
Me.OPT_GROUP.AutoSize = True
Me.OPT_GROUP.Dock = System.Windows.Forms.DockStyle.Fill
Me.OPT_GROUP.Location = New System.Drawing.Point(380, 4)
Me.OPT_GROUP.Name = "OPT_GROUP"
Me.OPT_GROUP.Size = New System.Drawing.Size(90, 17)
Me.OPT_GROUP.TabIndex = 4
Me.OPT_GROUP.TabStop = True
Me.OPT_GROUP.Text = "Groups"
TT_MAIN.SetToolTip(Me.OPT_GROUP, "Download groups")
Me.OPT_GROUP.UseVisualStyleBackColor = True
'
'CH_NOTIFY
'
Me.CH_NOTIFY.AutoSize = True
Me.CH_NOTIFY.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_NOTIFY.Location = New System.Drawing.Point(4, 140)
Me.CH_NOTIFY.Name = "CH_NOTIFY"
Me.CH_NOTIFY.Size = New System.Drawing.Size(468, 19)
Me.CH_NOTIFY.TabIndex = 12
Me.CH_NOTIFY.Text = "Show notifications"
Me.CH_NOTIFY.UseVisualStyleBackColor = True
'
'TXT_TIMER
'
ActionButton3.BackgroundImage = CType(resources.GetObject("ActionButton3.BackgroundImage"), System.Drawing.Image)
ActionButton3.Index = 0
ActionButton3.Name = "BTT_REFRESH"
Me.TXT_TIMER.Buttons.Add(ActionButton3)
Me.TXT_TIMER.CaptionText = "Timer"
Me.TXT_TIMER.CaptionWidth = 50.0R
Me.TXT_TIMER.Dock = System.Windows.Forms.DockStyle.Fill
Me.TXT_TIMER.Location = New System.Drawing.Point(4, 166)
Me.TXT_TIMER.Name = "TXT_TIMER"
Me.TXT_TIMER.Size = New System.Drawing.Size(468, 22)
Me.TXT_TIMER.TabIndex = 16
'
'LBL_LAST_TIME_UP
'
Me.LBL_LAST_TIME_UP.AutoSize = True
Me.LBL_LAST_TIME_UP.Dock = System.Windows.Forms.DockStyle.Fill
Me.LBL_LAST_TIME_UP.Font = New System.Drawing.Font("Microsoft Sans Serif", 8.25!, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Point, CType(204, Byte))
Me.LBL_LAST_TIME_UP.Location = New System.Drawing.Point(4, 192)
Me.LBL_LAST_TIME_UP.Name = "LBL_LAST_TIME_UP"
Me.LBL_LAST_TIME_UP.Size = New System.Drawing.Size(468, 25)
Me.LBL_LAST_TIME_UP.TabIndex = 20
Me.LBL_LAST_TIME_UP.Text = "Last download date: "
Me.LBL_LAST_TIME_UP.TextAlign = System.Drawing.ContentAlignment.TopCenter
'
'AutoDownloaderEditorForm
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(476, 242)
Me.Controls.Add(CONTAINER_MAIN)
Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle
Me.Icon = CType(resources.GetObject("$this.Icon"), System.Drawing.Icon)
Me.KeyPreview = True
Me.MaximizeBox = False
Me.MaximumSize = New System.Drawing.Size(492, 281)
Me.MinimizeBox = False
Me.MinimumSize = New System.Drawing.Size(492, 281)
Me.Name = "AutoDownloaderEditorForm"
Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide
Me.Text = "AutoDownloader settings"
CONTAINER_MAIN.ContentPanel.ResumeLayout(False)
CONTAINER_MAIN.ResumeLayout(False)
CONTAINER_MAIN.PerformLayout()
Me.DEF_GROUP.ResumeLayout(False)
Me.DEF_GROUP.PerformLayout()
CType(Me.TXT_GROUPS, System.ComponentModel.ISupportInitialize).EndInit()
TP_MODE.ResumeLayout(False)
TP_MODE.PerformLayout()
CType(Me.TXT_TIMER, System.ComponentModel.ISupportInitialize).EndInit()
Me.ResumeLayout(False)
End Sub
Private WithEvents DEF_GROUP As DownloadObjects.Groups.GroupDefaults
Private WithEvents TXT_GROUPS As PersonalUtilities.Forms.Controls.TextBoxExtended
Private WithEvents OPT_ALL As RadioButton
Private WithEvents OPT_DEFAULT As RadioButton
Private WithEvents OPT_SPEC As RadioButton
Private WithEvents OPT_DISABLED As RadioButton
Private WithEvents CH_NOTIFY As CheckBox
Friend WithEvents TXT_TIMER As PersonalUtilities.Forms.Controls.TextBoxExtended
Private WithEvents OPT_GROUP As RadioButton
Private WithEvents LBL_LAST_TIME_UP As Label
End Class
End Namespace

View File

@@ -0,0 +1,718 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="CONTAINER_MAIN.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="ActionButton1.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
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
AAAASUVORK5CYII=
</value>
</data>
<data name="ActionButton2.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
</value>
</data>
<metadata name="TP_MODE.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="TT_MAIN.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="TT_MAIN.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<data name="ActionButton3.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6
JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsTAAALEwEAmpwYAAACOElE
QVQ4T2P4//8/QczOJyyqHpzfiE0OQwAZC8iqszAzs7CJ69o4BR768V/W2jcGXQ0KB4aFNS3dDQtnrbCb
ePCK48wTN1wXXXzge/jXf/clV55zC4hIIatF0cjIyMikElzc57z0wX+XHd/+2+//99/ywP//xlu//tdb
+eK/4Zp3/1WTOhYzARViNUAluKjTdf37/0ZTTn9TbdhwXblhwwW1/qOP1Ja9+K8w+95/6cm3/6v2Xvkv
qKjniGGAoIqRpW3/4e8S9uGdzFz82gwMDFxAzCxm4ZegtuLDf+VJ1/8rZM25IqLvnM/CximCYYCic1QN
v7x2JIwPwyrJ3XNUylddE9G2TWNmZOBDl4czmJiZMSRBmFdSyYyJgUEQmxwIYxWEYXZBCUls4sgYq6CA
prWNbtG8nXKeaVPR5XiVjSxEzf0yYXy4BBMLO6eQjoOXZvrkbbazrv53Xf/2v4CSbjBMXkhBl1/CMyNZ
qWnvGy5pNQ+YONwAfjXzAOupl/47LLr333L50/96q9/8l23YdES6cO5KuYqVW+R7Tj6SnfP0v4hryjyY
HhQDmFjYeHVKFp7WX/Xuv9Kq9/+Vd/z7r7rv/3+l7f//y676DEwDN/9L+BVvYkKLCTgDhNkkVUyVlr74
qbbz73/VOTc/qsy89kWx+9h7qbQpJwS1bbOAscGGrB6EUTggLOqf16C55ft/HlnNAFZOXgVWdi4FRgYG
VnR1MIwhwMTCyqEQ37qEmZVDFF0OE/9nAACtFF4Ey6OP+wAAAABJRU5ErkJggg==
</value>
</data>
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAwAMDAQAAEABABoBgAAxgAAACAgEAABAAQA6AIAAC4HAAAYGBAAAQAEAOgBAAAWCgAAEBAQAAEA
BAAoAQAA/gsAADAwAAABAAgAqA4AACYNAAAgIAAAAQAIAKgIAADOGwAAGBgAAAEACADIBgAAdiQAABAQ
AAABAAgAaAUAAD4rAAAwMAAAAQAgAKglAACmMAAAICAAAAEAIACoEAAATlYAABgYAAABACAAiAkAAPZm
AAAQEAAAAQAgAGgEAAB+cAAAKAAAADAAAABgAAAAAQAEAAAAAACABAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAIAAAIAAAACAgACAAAAAgACAAICAAACAgIAAwMDAAAAA/wAA/wAAAP//AP8AAAD/AP8A//8AAP//
/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4YAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjsjgAAAAAAAAAAAA
AAAAAAAAAAAAAAAIbOh4AAAAAAAAAAAAAAAAAAAAAAAAAAAH5mfsgAAAAAAAAAAAAAAAAAAAAAAAAAB+
xs54YAAAAAAAAAAAAAAAAAAAAAAAAAfsbmxo5wAAAAAAAAAAAAAAAAAAAAAAAIbObObOeMAAAAAAAAAA
AAAAAAAAAAAACG5+zmzsaOgAAAAAAAAAAAAAAAAAAAAABn7ObOZmbneAAAAAAAAAAAAAAAAAAAAAfs5s
5+zs7I7AAAAAAAAAAAAAAAAAAAAH7Ofm7G7GbGiOAAAAAAAAAAAAAAAAAAB+fs7Ofs5+zmzngAAAAAAA
AAAAAAAAAAhn7Ojs5uzm7OZ4yAAAAAAAAAAAAAAAAAaOfm7Obsfsbs7OjnAAAAAAAAAAAAAAAH7Ojs7n
7O7ObOZs54AAAAAAAAAAAAAABn6Ozuduzn5uznzmyOcAAAAAAAAAAAAAfn7I6M7s5+zn7Obs5oyAAAAA
AAAAAAAIZ+jujuzo7Obs5uxubOjnAAAAAAAAAAAG586M5+js7n7OfOfs5s54cAAAAAAAAABnzo7o5+zu
fs5+5uzmzmzowAAAAAAAAAdujn5+fu7Ozuzs7Ofs5+bI6AAAAAAAAHzn7OjOjI5+5+jufs5uzs5ueOAA
AAAAAG6M6O6O7n7Ofs7Ozo7Ofmzs53gAAAAAB+zo7IznyOzuzufufs6Ofo6Ofn4AAAAACEdsZ2Z87o5+
js7O7O5cjHx8jIgAAAAAAAAAAAAAfOfs7Ojs6OfgAAAAAAAAAAAAAAAAAAAAbo7O6O7O7OfAAAAAAAAA
AAAAAAAAAAAAfsjm7Obo7s6AAAAAAAAAAAAAAAAAAAAAaO5+zo7OyO5wAAAAAAAAAAAAAAAAAAAAzn7O
js7n7sjAAAAAAAAAAAAAAAAAAAAAaM6Ozuzuzu5wAAAAAAAAAAAAAAAAAAAAbn7Obn5+jshgAAAAAAAA
AAAAAAAAAAAAbOjn7Ozs7O5wAAAAAAAAAAAAAAAAAAAAfnzn5+bn7n7AAAAAAAAAAAAAAAAAAAAAbOjs
7OzuzshgAAAAAAAAAAAAAAAAAAAAaOyOfn7I5+5wAAAAAAAAAAAAAAAAAAAAbOfs7Ozm7OfAAAAAAAAA
AAAAAAAAAAAAbnzn5+bs5u5wAAAAAAAAAAAAAAAAAAAAfOfsjOx+zn7AAAAAAAAAAAAAAAAAAAAAbnzn
5o7OfshgAAAAAAAAAAAAAAAAAAAAx+Z+zs5uzm5gAAAAAAAAAAAAAAAAAAAAbs7H5+fObsjAAAAAAAAA
AAAAAAAAAAAAZ2js585s7O5wAAAAAAAAAAAAAAAAAAAAjOyH5+jn53aAAAAAAAAAAAAAAAAAAAAACGZs
bHxsfGgAAAAAAAAAAAD///////8AAP///////wAA////////AAD///j///8AAP//8H///wAA///gP///
AAD//+Af//8AAP//wB///wAA//+AD///AAD//wAH//8AAP/+AAP//wAA//4AAf//AAD//AAB//8AAP/4
AAD//wAA//AAAH//AAD/4AAAP/8AAP/gAAAf/wAA/8AAAB//AAD/gAAAD/8AAP8AAAAH/wAA/gAAAAP/
AAD+AAAAAf8AAPwAAAAB/wAA+AAAAAD/AADwAAAAAH8AAPAAAAAAPwAA4AAAAAA/AADgAAAAAD8AAP/8
AAH//wAA//wAAf//AAD//AAB//8AAP/8AAH//wAA//wAAf//AAD//AAB//8AAP/8AAH//wAA//wAAf//
AAD//AAB//8AAP/8AAH//wAA//wAAf//AAD//AAB//8AAP/8AAH//wAA//wAAf//AAD//AAB//8AAP/8
AAH//wAA//wAAf//AAD//AAB//8AAP/8AAH//wAA//4AA///AAAoAAAAIAAAAEAAAAABAAQAAAAAAAAC
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAgAAAAICAAIAAAACAAIAAgIAAAICAgADAwMAAAAD/AAD/
AAAA//8A/wAAAP8A/wD//wAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5+AAAAAAAAAAAAAAAAAA
BoyHAAAAAAAAAAAAAAAAAOfn7AAAAAAAAAAAAAAAAAjIzn6AAAAAAAAAAAAAAAAO5uxo7AAAAAAAAAAA
AAAAaM7ObI6AAAAAAAAAAAAADn5ubOboyAAAAAAAAAAAAH7Ozs5sbo4AAAAAAAAAAAjI5+fn7saM4AAA
AAAAAAAO7n7Ozsbs6OcAAAAAAAAAaH7O5+bn5s6MgAAAAAAABo7o5+zs7Ozm6OAAAAAAAH7I7Ozufn5u
zsfsAAAAAAjOjn6Ofs7s5+bsjnAAAAAG6Ozo7O7n5+zs5ujnAAAAaOyOjo587Ozo6I7IjIAAAGxmxsZ+
7o7uzsbG7O4AAAAAAAAM587OyOhgAAAAAAAAAAAABo7n5+7OYAAAAAAAAAAAAAzozuzujsAAAAAAAAAA
AAAGjufuzs5wAAAAAAAAAAAADOfOyOfowAAAAAAAAAAAAAaOfm7O7mAAAAAAAAAAAAAM7Ofs5sjAAAAA
AAAAAAAABn585+7oYAAAAAAAAAAAAAyM6Oxs58AAAAAAAAAAAAAG5+zm5+5gAAAAAAAAAAAABOx+fs7I
wAAAAAAAAAAAAAZ+Z8hs7kAAAAAAAAAAAAAMjOjm52fAAAAAAAAAAAAAAGbExsbOAAAAAAAA///////8
f///+D////A////gH///4A///8AH//+AA///AAP//gAB//4AAP/8AAB/+AAAf/AAAD/gAAAf4AAAD8AA
AAfAAAAP/4AH//+AB///gAf//4AH//+AB///gAf//4AH//+AB///gAf//4AH//+AB///gAf//4AH///A
D/8oAAAAGAAAADAAAAABAAQAAAAAACABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAgAAAAICAAIAA
AACAAIAAgIAAAICAgADAwMAAAAD/AAD/AAAA//8A/wAAAP8A/wD//wAA////AAAAAAAAAAAAAAAAAAAA
AAAABgAAAAAAAAAAAAAAeOAAAAAAAAAAAAAG7IcAAAAAAAAAAAB+fujgAAAAAAAAAAbs7OyHAAAAAAAA
AGjufm7oYAAAAAAABo7OzsfOhwAAAAAAaO5+5+7s6GAAAAAG5+zs7Ozn7PYAAABo6Ojo7n6IjojgAAAM
bGzs7OyOx+wAAAAAAAfo7o7nAAAAAAAAAAaM7OyGAAAAAAAAAAbufu6MAAAAAAAAAAd+zn6GAAAAAAAA
AAzn7OznAAAAAAAAAAaOzuiGAAAAAAAAAAbn587sAAAAAAAAAAZ87m6GAAAAAAAAAAzozs6MAAAAAAAA
AAaOh+eGAAAAAAAAAABsbGxgAAAAAAAAAAAAAAAAAAAAAP///wD/7/8A/8f/AP+D/wD/Af8A/gD/APwA
fwD4AD8A8AAfAOAADwDAAAcA4AAPAP4A/wD+AP8A/gD/AP4A/wD+AP8A/gD/AP4A/wD+AP8A/gD/AP4A
/wD/Af8A////ACgAAAAQAAAAIAAAAAEABAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAACA
AAAAgIAAgAAAAIAAgACAgAAAgICAAMDAwAAAAP8AAP8AAAD//wD/AAAA/wD/AP//AAD///8AAAAABgAA
AAAAAABoYAAAAAAABo6MAAAAAABozshgAAAABo5uboYAAABo7OfOeGAABo5+fn6OhgB2xs7O6MfHgAAA
aOfIYAAAAABuzujgAAAAAGjn6MAAAAAAzs5+cAAAAABo5+jAAAAAAG7OyOAAAAAAaI6OcAAAAAAMbGYA
AAD+/wAA/H8AAPg/AADwHwAA4A8AAMAHAACAAwAAAAEAAPAfAADwHwAA8B8AAPAfAADwHwAA8B8AAPAf
AAD4PwAAKAAAADAAAABgAAAAAQAIAAAAAAAACQAAAAAAAAAAAAAAAQAAAAEAAAAAAACjaB0ApmsgAKlt
IwCrcCYArXMqALF1LACzeC4ArHYwALR6MQC4fTQAt385AMh1AADJdwQAy3gAAM17AADOfQEAy3oHAM5/
CQDMfA0A0H4BAMt/GQC7gDcAvoI6ALmBPADRgAIA0oIEANSDBADVhQUA1ogGANaMBwDZiQYA3I0GANKE
CgDWhwkA0YIMANaMCwDZiggA2o0JANyOCQDbkgsA3pAKAN6UCwDekg0A3ZQNAM+EGgDRhhUA1YkSANiN
EgDajhcA2pISANqSHgDalh4A3ZgaAOGUCgDgkg0A4ZUOAOSWDgDhmA4A5ZgPAOicDgDklxAA45cVAOGY
EADlmRAA5ZwRAOSdFwDonRIA550YAOmfGwDpoBIA6qEUAO2iFADrpBQA7qUWAO6mGADvqBgA8KUXAPCm
GADxqRgA9KsZAPKsGgD0rBoA9a0cAPiuGgD1sBsA+bEbAPixHADOhycAzo0lAMqKKwDRjCIA0Y8lANSP
JgDTji0A05ImANiRIwDdnScA1JQpANmVKwDXmCoA25stAMGJNQDAhj0A0I84AM2VPwDTmTYA3JwyANKR
OQDSlDgA2Js6AOGeIADknS8A3qAxANyiPwDopCAA7qogAOKiLQDtqykA8asjAPOxJwD6syAA+LMkAPq1
JwD2tSoA+rYsAPq4LgDiozEA6qUzAOepNQDpqTEA66wyAOmrNwDtqjUA6qw2AO2vNQDjpjoA6aw4AOir
PwDwrDgA67A3AO2xOQDssT8A8rIwAPazMwD2tzEA8bE2APq7NgDytDoA+Lc6APW5PAD5uToA+bw7APi7
PQD5vD0A/L49APzAPgCxgEMAv4VAALaFSAC5h0sAvJZmALyacgC5mnYAxYlBAMOLRgDHi0QAyY1GAMaO
SgDJj0oAyZBEAMyQSgDPlEkAypFNAM6TTADNlE4A0pVHANebQwDUnUUA0JRNANaaSgDDkVUAzpZWAM2X
WwDOmVsAzZpdANGZVgDUmlcA0ppaANOcWwDQnF4A16BHANqiSADapUkA3adLAN2lTQDbo1QA1KFeANql
WwDgpkMA4KtOAO6sSwDxrUYA8rdAAPGxRQD1uUAA+r1AAPSySADirl0Ax5ljAMOYZgDFmWUAz51gAM+f
ZADBnG4AxJ1uANGeYgDQnmUA0aBjANalYwDVoWQA2KRgAN+sYwDbqWYA3aplAN2sZwDRo2sA1KdrANWl
bADZqmoA3q5qAMWhcgDNpHMAzKV1AMmmeQDUqXAA1Kp5ANuwcADhrWAA569jAOCvaQDismgA5LRoAOGy
bADitGwA+8BDALGchQCxnokAxa2OAMqwkQDPs5MA1LiXAN3AngDjwJYAAAAAAP///wAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
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
AAC/YQAAvGgNALllFwC5Zx8AtWUpAMJkAADFaAAAyGsAAMxuAgDOcQYA0nYJANR5DQDFdREAz34aANd8
EADafxMA0IAGANSDBQDThAYA1YUFANiJBwDThg8A2YoIANqNCQDcjQoA25AKAN2QCgDekQ0A35UNAN2A
FgDXjxAA2Y4UAN6DGQDWjBsA3ZEQAN6UFgDdmBgA4JMKAOCSDQDhlQ4A5ZcPAOSZDgDghhsA44geAOSW
EADjmxEA5ZoQAOScEQDnnxQA6Z0SAOWcGgDpoBIA6aEUAO2iFADtpBYA5qAZAO+oGgDwphcA8acYAPGp
GAD0qxkA86waAPSsGgD1rhwA9rAbAPawHAD4sBoA+LEcAMyAIADXhSMA0IUnAN+NKgDRkScA2pYhAN2b
IwDcmyUA05MoANWWKQDali8A2ZksANucLQDcnS4A3Z0xAN2TOwDblT8A1po7ANKYPADVmj0A154+AOaO
JADjkCoA5ZIuAOqTKgDtkysA7ZQrAOiTLQDulSwA4pIxAOmWMQDrlzUA6J02AOOaOQDgnTwA6pw5APCa
NADynj0A36AvAN6hMADdoDgA2aE/AOSgIQDioSYA7KchAO2oJgDgoCkA6agrAPewIAD5tCIA+bQnAPOx
KAD5tigA+bcvAOOmMgDjpjQA5KU0AOepNQDnrD8A6Ko4AOyvOADprj8A86A/AO+zOgDysjAA8LE3APe4
NgD7ujEA8rY7APCzPQDytj4A9Lg6APW6PQD7vDoA+b0+AMWARADPkEUA3ZlEANmbTQDPnF8A0phUAOqe
QgDdoEEA2aJGAN2kRADep0kA3aVOANuiUADdplQA4ahGAO2qRwDooEgA4alKAOOtTQDzoUAA869EAPap
TgDsskAA77JGAOewTgDusUoA6rBMAPC1QwD0ukUA9rxGAPm9QQDwskkA8rVNAPe+SAD1uk8A+L5IAPWp
UADyqlQA6rRRAO22UgDuuFQA47BbAPCyUQD0vFAA8r5WAPC2XAD4sV0AyZ5nAMSlfwDfr3MA2K19AOWt
YgDltmcA67NgAOm5YQDsu2oA77ptAPW+awDwvm0A+bhpAOizcQDiu34A7Lt9APS9cAD7wEIA+8FGAPnA
SAD4wk4A+MNZAPnEWgD6w2AA/ctkAMOnhQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAABta58AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbc2/a8oAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAKpvpabIawAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADWcqgdHaa/awAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAG2JLR8dIM6tXgAAAAAAAAAAAAAAAAAAAAAAAAAAAABlsT0xIx8dLNJzngAAAAAA
AAAAAAAAAAAAAAAAAAAAUq58PDMxIyMdWdVr4gAAAAAAAAAAAAAAAAAAAAAAAJypj0REMzMxJSMdochr
AAAAAAAAAAAAAAAAAAAAAADLcN9KRURERDMxJSMjw69lAAAAAAAAAAAAAAAAAAAAAFDhuH9KSkQzRDMx
JSMq0o1fAAAAAAAAAAAAAAAAAAAY4Nu4gUdHQ0VEM0QlJSNU2XPJAAAAAAAAAAAAAAAAT8TcuNuSTUpK
R0REMzsxJSNd1WsAAAAAAAAAAAAAAJtw3bi425hNTUpKSkRERDMzMSOryGsAAAAAAAAAAADMUd2Vl7i4
mIFNTU1KSkRERDMzMSXQr2wAAAAAAAAAABfBsJOXmLi4g01NTU1KSkRERDk5MS3ZdJ0AAAAAAAAMz7S0
urrFxbiETYFNTU1KSo+xlbq6tMfTa9gAAAAAAJoGBgYGCQkL35FLTU2BTU1KthkZKys1NmSgAAAAAAAA
AAAAAAAAAAnfl0pLTU1NgU29FgAAAAAAAAAAAAAAAAAAAAAAAAAABt2VgkpNgU1NTdwVAAAAAAAAAAAA
AAAAAAAAAAAAAAAGxrGPSkpKTU2B2xQAAAAAAAAAAAAAAAAAAAAAAAAAAAbCi5BDREpLTU3cEwAAAAAA
AAAAAAAAAAAAAAAAAAAABMGIi3xAR0pLTdwTAAAAAAAAAAAAAAAAAAAAAAAAAAADsoWKjzlEQ0pL3BEA
AAAAAAAAAAAAAAAAAAAAAAAAAAOrhYWFOztEREq7EQAAAAAAAAAAAAAAAAAAAAAAAAAAA6tdXIV5OTtE
Q7YLAAAAAAAAAAAAAAAAAAAAAAAAAAABpVxcdn0nMztEtgkAAAAAAAAAAAAAAAAAAAAAAAAAAAGhWFpd
di8nMzu1CQAAAAAAAAAAAAAAAAAAAAAAAAAAAaVTWFxdViUnJ7EGAAAAAAAAAAAAAAAAAAAAAAAAAAAB
YFNYWFhcKSQnsAYAAAAAAAAAAAAAAAAAAAAAAAAAAA/XYWBjoaF3VFZWDQAAAAAAAAAAAAAAAAAAAAAA
AAAAAA8BAQEBAQEEBA4AAAAAAAAAAAAAAAD///////x////4P///8D///+Af///gD///wAf//4AD//8A
A//+AAH//gAA//wAAH/4AAB/8AAAP+AAAB/gAAAPwAAAB8AAAA//gAf//4AH//+AB///gAf//4AH//+A
B///gAf//4AH//+AB///gAf//4AH//+AB///gAf//8AP/ygAAAAYAAAAMAAAAAEACAAAAAAAQAIAAAAA
AAAAAAAAAAEAAAABAAAAAAAApWYWAKhpGQCqbBsAqm0dAKxuHgCucCEAsHMjALJ2JgC2eioAuH4uALyC
MgC9gzQAvoU1AN+YEwDklw8A5ZkQAOmdEgDooBIA6aEUAO2hFQDtpRYA8KYXAPGqFwDxpxgA8qoZAPSr
GgD0rRoA86wcAPauHAD3sBoA97AcAPmwGgD4sRwAwIY3AMGJOQDDizwAxIs8AMWNPgDjnSUA5J4nAN6g
MADnoyAA5aAnAOSjKQDgoi8A7awpAPCsIwD6syIA+rcrAOKlMwDqqzIA6Kk3AOSpOgDpqz0A+rozAPq6
NADytjsA97s+APe8PAD5uzgA36VCAN+sVADgqUQA5axHAOmuQADkrUoA6bNKAO63TgDws0EA9btDAPS6
RQD6vkEA9LxMAPm+SADhrlUA5LJZAPK7UAD7wEMA+8NOAPbBUAD6xFIA+8VUAPDDaQD0xmwA9shtAPjK
bgD6zW8A8cmCAPPMhAD0zoYA99CHAPDPmQDw0JkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmAAAAAAAA
AAAAAAAAAAAAAAAAAAAAACZcJgAAAAAAAAAAAAAAAAAAAAAAAAAAJjYnXSYAAAAAAAAAAAAAAAAAAAAA
AAAiRREPJ10mAAAAAAAAAAAAAAAAAAAAAAtHFhYQECddJgAAAAAAAAAAAAAAAAAACkobGxYRERAnXSYA
AAAAAAAAAAAAAAAJUjAbGxgbFhEQKF0mAAAAAAAAAAAAAAhSTjEgGxsbFhYRECtdJgAAAAAAAAAABjpI
SDggICAbGBgWERAnXSYAAAAAAAAFOVBSUk84IDAgGxtUW1paWlwmAAAAAAAABQUGBgg8IDAgMBtWCwsL
IiIAAAAAAAAAAAAAAAY6HiAgMCBXCgAAAAAAAAAAAAAAAAAAAAVHGx4wICBXCgAAAAAAAAAAAAAAAAAA
AAVJGxseMCBXCQAAAAAAAAAAAAAAAAAAAAVJLxsbHjBXCAAAAAAAAAAAAAAAAAAAAAFELhYcGx5XCAAA
AAAAAAAAAAAAAAAAAAFDMxMVGxtXBgAAAAAAAAAAAAAAAAAAAAFANCsWFhxVBgAAAAAAAAAAAAAAAAAA
AAE/MisOEBZVBQAAAAAAAAAAAAAAAAAAAAE9KS0OEBNUAwAAAAAAAAAAAAAAAAAAAAE+S0xAND9TAwAA
AAAAAAAAAAAAAAAAAAABAQEBAwEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP/v
/wD/x/8A/4P/AP8B/wD+AP8A/AB/APgAPwDwAB8A4AAPAMAABwDgAA8A/gD/AP4A/wD+AP8A/gD/AP4A
/wD+AP8A/gD/AP4A/wD+AP8A/gD/AP8B/wD///8AKAAAABAAAAAgAAAAAQAIAAAAAAAAAQAAAAAAAAAA
AAAAAQAAAAEAAAAAAAClZhYAsnYmALN4KQC4fi8A1Y0XANWOGADXkBkA2pUbANuVHADclhwA3poeAOCc
HwDgmyAA46EiAOaiIwDmpiMA56cnAOilIwDppiUA66omAO2rJwDuricA46YsAOyrKADurikA7q4sAPCv
KQDvsS4A8LAqAO2vMQDkpjgA5q8+AOqwOADwszIA4qtBAOi0TwDyvEoA7LlSAOSyXADnt18Aw5ljAMui
bQDqumEA5LhoAOa7cADpv3MA78FlAPDFdgDyyXkA88x6APXNegD20IAA6MeQAOnIkQDpyZcAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAP///wAAAAAAAAAAAwAAAAAAAAAAAAAAAAAAAzcCAAAAAAAAAAAAAAAAAycFNQIAAAAA
AAAAAAAAAysLCAY1BAAAAAAAAAAAAy8SDg0IBjUEAAAAAAAAAzMaFBIODQgINQQAAAAAAzQlIhQaEg4f
Li01BAAAKQEBAQEbGhQUMAQEBAQqAAAAAAABGxsbFDMEAAAAAAAAAAAAARwbGxszBAAAAAAAAAAAAAEe
FBsbMwQAAAAAAAAAAAABIRQcHDMEAAAAAAAAAAAAASARFBQzBAAAAAAAAAAAAAEjFw4WMwQAAAAAAAAA
AAABLCgkJjMDAAAAAAAAAAAAAAEBAQEBAAAAAAAA/v8AAPx/AAD4PwAA8B8AAOAPAADABwAAgAMAAAAB
AADwHwAA8B8AAPAfAADwHwAA8B8AAPAfAADwHwAA+D8AACgAAAAwAAAAYAAAAAEAIAAAAAAAgCUAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAADAAAABgAAAAgAAAAGAAAAAwAA
AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAMAAAAFgAA
ABsAAAAWAAAACwAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAA
AAwAAAAfAAAAMwAAADwAAAAyAAAAHQAAAAsAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAACAAAACSccDyHPllLiypFQ4M2UUesdFQtZAAAANQAAABoAAAAJAAAAAgAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAEAAAAHAAAAF8aOTb/RlU3z0pVH/82UU/K/iUvcAAAAUAAAADAAAAAWAAAABgAA
AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
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
Q//6tiz/+K4a//auG//1rRr/9Ksa//KpGf/wpxj/76MX/+2hFP/pnxP/6JwS/+WYD//hlQ//35IN/92O
Cv/aiwn/14gH/9SEBf/ViRP/4rJo/8+cXfS4hEjVAAAATQAAAC0AAAAUAAAABgAAAAEAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAUAAAASjl8jgq91LPfjpjr/+Ls///q+
Qf/7v0H/+79B//vAQ//7vDb/+bEc//iwHP/2rhz/9a0b//SrGv/yqhn/8agY/++kF//toRT/6p8T/+ic
Ev/lmRD/45YO/9+TDf/djwv/2owI/9eJB//UhQT/2JEj/+Gya/zRmVf5mm48sQAAAEYAAAAnAAAAEAAA
AAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAA5zTBtTrXIp+NOY
NPzytz3/+bw+//q9QP/6vkH/+79B//u/Qf/7vj7/+rMg//mxHP/4sBz/9q4c//WsG//0rBr/86oZ//Go
GP/vpBf/7aEV/+qfE//onRH/5ZkQ/+OWD//gkw7/3Y8J/9uMCP/XiQf/1YQG/9uaNv/armz30phU+nJR
LI0AAABAAAAAIgAAAAwAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAACzom
DSyobyXxv4Ut9e2wOv/1ujz/+Ls9//m8QP/6vUD/+r5B//u/Qf/7v0L/+rUn//mxG//5sR3/+LAc//au
HP/1rRv/9Kwa//OqGf/xqBj/76QX/+6iFf/roBP/6JwS/+aZEP/klg//4JMN/96OC//bjQn/2YkI/9WF
Bv/fpkz/06Zp8s2TUPY/LRhtAAAAOQAAABwAAAAJAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAEGRAFFKRqI9mwdibx56o3//G0Ov/ztjv/9bo8//a7Pv/5vED/+r1A//q+Qf/7wEP/+rgu//mx
G//5sh3/+bId//ixHP/2sBz/9a0b//SrGv/yqhn/8agY//CmF//uoxX/6qAT/+mdEf/mmRD/5JYP/+CT
Dv/ejwr/3IwK/9mJB//Whwn/4q5d/9GiZ+7Hj0znEg0HSAAAACcAAAAPAAAAAwAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAGoGcgpaluIvLdoDP/6q03/++yOf/xtDr/87Y7//S4PP/2uz3/+bw+//m9
QP/6vkL/+rs3//myHP/5sh3/+bId//myHf/5sR3/+LAc//WtHP/0rRv/9KsZ//KpGP/wphf/7qMV/+ug
E//onhL/55oR/+SXD//hlA3/3pAL/9yNCf/Zigf/2I0S/+S0aP/ToGPwvolJxAAAACcAAAARAAAABQAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACiaB9ppmsg9dKVL//nqjX/67A3/+6yOP/wtDr/87Y7//W4
PP/4uz3/+b0+//m9QP/5vUD/+rw7//myHv/5sh3/+bId//myHf/5sh3/+LEd//iwHP/2rhv/9awb//Or
Gv/xqBn/8KYY/+6jFf/roBP/6p4Q/+icDv/llw3/4ZQK/9+QCf/cjQb/2okF/9mRHf/ismj40ZVQ9MGK
SogAAAALAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACmaR7PyYgn+uSdL//loDD/56Iy/+qk
M//rpjT/7qk3//CrOP/xrTn/8a05//CxOP/4vD7/+bxA//izJP/4sRz/+bId//myHf/5sh3/+bId//mx
Hf/4sBz/9q4c//WsG//zqxr/8qkY//GrI//xsDr/8bFF//W0Sf/2s0n/9LJI//OwSP/yr0f/8a1G//Cs
R//urEv/5ahV6dGVT+AAAAAEAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACkaR2XpGoe/6Vq
H/+mayD/pmwh/6hsIv+pbSP/qW4k/6twJf+scCf/rXIn/65zKf/6vDz/+LxA//a1Kv/2sBr/+bEd//my
Hf/5sh3/+bId//myHf/5sR3/+LAc//auHP/1rRv/9Ksa//a3Ov/EiED/xYlB/8aKQ//Hi0T/yY1G/8qO
R//Lj0n/zJBK/82RS//Ok0z/0JRN/9GVTpcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK1yJ//5uzv/9rs+//a3
Mf/1rhr/9rAc//iyHf/5sh3/+bId//myHf/5sh3/+bEd//iwHP/2rhz/9a0b//m5Ov/Chj//AAAAKwAA
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
</value>
</data>
</root>

View File

@@ -0,0 +1,136 @@
' Copyright (C) 2022 Andy
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY
Imports PersonalUtilities.Forms
Imports PersonalUtilities.Forms.Controls.Base
Imports PersonalUtilities.Forms.Toolbars
Imports DModes = SCrawler.DownloadObjects.AutoDownloader.Modes
Namespace DownloadObjects
Friend Class AutoDownloaderEditorForm : Implements IOkCancelToolbar
Private ReadOnly MyDefs As DefaultFormProps
Private ReadOnly MyGroups As List(Of String)
Friend Property IsControlForm As Boolean = False
Friend Sub New()
InitializeComponent()
MyDefs = New DefaultFormProps
MyGroups.ListAddList(Settings.Automation.Groups, LAP.NotContainsOnly)
End Sub
Friend Class AutomationTimerChecker : Implements IFieldsCheckerProvider
Private Property ErrorMessage As String = "The timer value must be greater than 0" Implements IFieldsCheckerProvider.ErrorMessage
Private Property Name As String Implements IFieldsCheckerProvider.Name
Private Property TypeError As Boolean Implements IFieldsCheckerProvider.TypeError
Private Function Convert(ByVal Value As Object, ByVal DestinationType As Type, ByVal Provider As IFormatProvider,
Optional ByVal NothingArg As Object = Nothing, Optional ByVal e As ErrorsDescriber = Nothing) As Object Implements ICustomProvider.Convert
If CInt(AConvert(Of Integer)(Value, -10)) > 0 Then
Return Value
Else
Return Nothing
End If
End Function
Private Function GetFormat(ByVal FormatType As Type) As Object Implements IFormatProvider.GetFormat
Throw New NotImplementedException()
End Function
End Class
Private _Loaded As Boolean = False
Friend Shadows Sub Show()
MyBase.Show()
If Not _Loaded And IsControlForm Then AutoDownloaderEditorForm_Load(Nothing, EventArgs.Empty)
End Sub
Private Sub AutoDownloaderEditorForm_Load(sender As Object, e As EventArgs) Handles Me.Load
With MyDefs
If Not IsControlForm Then
.MyViewInitialize(Me, Settings.Design, True)
.AddOkCancelToolbar()
End If
With Settings.Automation
Select Case .Mode
Case DModes.None : OPT_DISABLED.Checked = True
Case DModes.All : OPT_ALL.Checked = True
Case DModes.Default : OPT_DEFAULT.Checked = True
Case DModes.Specified : OPT_SPEC.Checked = True
Case DModes.Groups : OPT_GROUP.Checked = True
End Select
ChangeEnabled()
DEF_GROUP.Set(Settings.Automation)
If MyGroups.Count > 0 Then TXT_GROUPS.Text = MyGroups.ListToString
If Settings.Groups.Count = 0 Then TXT_GROUPS.Clear() : TXT_GROUPS.Enabled = False
CH_NOTIFY.Checked = .ShowNotifications
TXT_TIMER.Text = .Timer
LBL_LAST_TIME_UP.Text = .Information
End With
If Not IsControlForm Then
.MyFieldsChecker = New FieldsChecker
With DirectCast(.MyFieldsChecker, FieldsChecker)
.AddControl(Of Integer)(TXT_TIMER, TXT_TIMER.CaptionText,, New AutomationTimerChecker)
.EndLoaderOperations()
End With
.DelegateClosingChecker()
.AppendDetectors()
.EndLoaderOperations()
End If
End With
_Loaded = True
End Sub
Private Sub AutoDownloaderEditorForm_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed
MyGroups.Clear()
End Sub
Friend Sub SaveSettings() Implements IOkCancelToolbar.OK
If If(MyDefs.MyFieldsChecker?.AllParamsOK, True) Then
With Settings.Automation
Select Case True
Case OPT_DISABLED.Checked : .Mode = DModes.None
Case OPT_ALL.Checked : .Mode = DModes.All
Case OPT_DEFAULT.Checked : .Mode = DModes.Default
Case OPT_SPEC.Checked : .Mode = DModes.Specified
Case OPT_GROUP.Checked : .Mode = DModes.Groups
End Select
DEF_GROUP.Get(Settings.Automation)
.Groups.Clear()
.Groups.ListAddList(MyGroups)
.Timer = AConvert(Of Integer)(TXT_TIMER.Text, AutoDownloader.DefaultTimer)
.Update()
End With
If Not IsControlForm Then MyDefs.CloseForm()
End If
End Sub
Private Sub Cancel() Implements IOkCancelToolbar.Cancel
MyDefs.CloseForm(DialogResult.Cancel)
End Sub
Private Sub TXT_GROUPS_ActionOnButtonClick(ByVal Sender As ActionButton) Handles TXT_GROUPS.ActionOnButtonClick
Select Case Sender.DefaultButton
Case ActionButton.DefaultButtons.Edit
Using f As New LabelsForm(MyGroups, Settings.Groups.Select(Function(g) g.Name)) With {.Text = "Groups"}
f.ShowDialog()
If f.DialogResult = DialogResult.OK Then MyGroups.ListAddList(f.LabelsList, LAP.ClearBeforeAdd) : TXT_GROUPS.Text = MyGroups.ListToString
End Using
Case ActionButton.DefaultButtons.Clear : MyGroups.Clear()
End Select
End Sub
Private Sub OPT_DISABLED_CheckedChanged(sender As Object, e As EventArgs) Handles OPT_DISABLED.CheckedChanged
ChangeEnabled()
End Sub
Private Sub OPT_ALL_CheckedChanged(sender As Object, e As EventArgs) Handles OPT_ALL.CheckedChanged
ChangeEnabled()
End Sub
Private Sub OPT_DEFAULT_CheckedChanged(sender As Object, e As EventArgs) Handles OPT_DEFAULT.CheckedChanged
ChangeEnabled()
End Sub
Private Sub OPT_SPEC_CheckedChanged(sender As Object, e As EventArgs) Handles OPT_SPEC.CheckedChanged
ChangeEnabled()
End Sub
Private Sub OPT_GROUP_CheckedChanged(sender As Object, e As EventArgs) Handles OPT_GROUP.CheckedChanged
ChangeEnabled()
End Sub
Private Sub ChangeEnabled()
DEF_GROUP.Enabled = OPT_SPEC.Checked
TXT_GROUPS.Enabled = OPT_GROUP.Checked
TXT_TIMER.Enabled = Not OPT_DISABLED.Checked
CH_NOTIFY.Enabled = Not OPT_DISABLED.Checked
End Sub
End Class
End Namespace

View File

@@ -156,7 +156,7 @@ Namespace DownloadObjects
RaiseEvent OnTotalCountChange()
End Sub
Private Sub JobProgress_OnProgressChange(ByVal Source As IMyProgress, ByVal Index As Integer)
MainProgress.Perform()
If Not Job.Type = Download.SavedPosts Then MainProgress.Perform()
End Sub
#End Region
#Region "IDisposable Support"

View File

@@ -11,7 +11,7 @@ Imports PersonalUtilities.Forms
Imports SCrawler.DownloadObjects
Imports SCrawler.Plugin.Hosts
Friend Class DownloadSavedPostsForm
Friend Event OnDownloadDone(ByVal Message As String)
Friend Event OnDownloadDone As NotificationEventHandler
Private MyView As FormsView
Private ReadOnly JobsList As List(Of DownloadProgress)
Friend ReadOnly Property Working As Boolean

View File

@@ -11,9 +11,15 @@ Imports PersonalUtilities.Forms
Imports SCrawler.API.Base
Namespace DownloadObjects
Friend Class DownloadedInfoForm
Friend Event OnUserLooking(ByVal Key As String)
Friend Event UserFind(ByVal Key As String)
Private MyView As FormsView
Private ReadOnly LParams As New ListAddParams(LAP.IgnoreICopier) With {.e = EDP.None}
Private ReadOnly LParams As New ListAddParams(LAP.IgnoreICopier) With {.Error = EDP.None}
Private Opened As Boolean = False
Friend ReadOnly Property ReadyToOpen As Boolean
Get
Return Settings.DownloadOpenInfo And (Not Opened Or Settings.DownloadOpenInfo.Attribute) And Not Visible
End Get
End Property
Friend Enum ViewModes As Integer
Session = 0
All = 1
@@ -50,6 +56,8 @@ Namespace DownloadObjects
BTT_CLEAR.Visible = ViewMode = ViewModes.Session
RefillList()
Catch ex As Exception
Finally
Opened = True
End Try
End Sub
Private Sub DownloadedInfoForm_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
@@ -135,7 +143,7 @@ Namespace DownloadObjects
Try
If _LatestSelected.ValueBetween(0, LIST_DOWN.Items.Count - 1) AndAlso _LatestSelected.ValueBetween(0, Downloader.Downloaded.Count - 1) Then
Dim i% = Settings.Users.IndexOf(_TempUsersList(_LatestSelected))
If i >= 0 Then RaiseEvent OnUserLooking(Settings.Users(i).Key)
If i >= 0 Then RaiseEvent UserFind(Settings.Users(i).Key)
End If
Catch ex As Exception
End Try

View File

@@ -0,0 +1,201 @@
' Copyright (C) 2022 Andy
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY
Imports PersonalUtilities.Functions.XML
Imports PersonalUtilities.Functions.XML.Base
Imports SCrawler.API
Imports SCrawler.API.Base
Namespace DownloadObjects.Groups
Friend Class DownloadGroup : Inherits GroupParameters : Implements IIndexable, IEContainerProvider
Friend Delegate Sub GroupEventHandler(ByVal Sender As DownloadGroup)
Friend Event Deleted As GroupEventHandler
Friend Event Updated As GroupEventHandler
#Region "XML Names"
Private Const Name_Name As String = "Name"
#End Region
Private WithEvents BTT_EDIT As ToolStripMenuItem
Private WithEvents BTT_DELETE As ToolStripMenuItem
Private WithEvents BTT_DOWNLOAD As ToolStripMenuItem
Private WithEvents BTT_DOWNLOAD_FULL As ToolStripMenuItem
Private ReadOnly SEP_1 As ToolStripSeparator
Private WithEvents BTT_MENU As ToolStripMenuItem
Friend Property NameBefore As String = String.Empty
Friend Property Name As String
Private _Key As String = String.Empty
Friend ReadOnly Property Key As String
Get
If _Key.IsEmptyString Then _Key = $"{Name}{Index}"
Return _Key
End Get
End Property
Private _Index As Integer = 0
Friend Property Index As Integer Implements IIndexable.Index
Get
Return _Index
End Get
Set(ByVal NewIndex As Integer)
Dim b As Boolean = Not _Index = NewIndex
_Index = NewIndex
If b Then RaiseEvent Updated(Me)
End Set
End Property
Friend Sub New()
BTT_MENU = New ToolStripMenuItem With {
.ToolTipText = "Download users of this group",
.AutoToolTip = True,
.Image = My.Resources.GroupBy_284.ToBitmap
}
BTT_DELETE = New ToolStripMenuItem With {
.Image = PersonalUtilities.My.Resources.DeletePic_02_Red_24,
.BackColor = ColorBttDeleteBack,
.ForeColor = ColorBttDeleteFore,
.Text = "Delete",
.ToolTipText = String.Empty,
.AutoToolTip = False
}
BTT_EDIT = New ToolStripMenuItem With {
.Image = PersonalUtilities.My.Resources.PencilPic_01_48,
.BackColor = ColorBttEditBack,
.ForeColor = ColorBttEditFore,
.Text = "Edit",
.ToolTipText = String.Empty,
.AutoToolTip = False
}
SEP_1 = New ToolStripSeparator
BTT_DOWNLOAD = New ToolStripMenuItem With {
.Image = My.Resources.StartPic_01_Green_16,
.Text = "Download",
.ToolTipText = "Download users of this group (respect the 'Ready for download' parameter)",
.AutoToolTip = True
}
BTT_DOWNLOAD_FULL = New ToolStripMenuItem With {
.Image = My.Resources.StartPic_01_Green_16,
.Text = "Download FULL",
.ToolTipText = "Download users of this group (ignore the 'Ready for download' parameter)",
.AutoToolTip = True
}
BTT_MENU.DropDownItems.AddRange({BTT_EDIT, BTT_DELETE, SEP_1, BTT_DOWNLOAD, BTT_DOWNLOAD_FULL})
End Sub
Friend Sub New(ByVal e As EContainer)
Me.New
Name = e.Attribute(Name_Name)
Temporary = e.Attribute(Name_Temporary).Value.FromXML(Of Integer)(CInt(CheckState.Indeterminate))
Favorite = e.Attribute(Name_Favorite).Value.FromXML(Of Integer)(CInt(CheckState.Indeterminate))
ReadyForDownload = e.Attribute(Name_ReadyForDownload).Value.FromXML(Of Boolean)(True)
ReadyForDownloadIgnore = e.Attribute(Name_ReadyForDownloadIgnore).Value.FromXML(Of Boolean)(False)
If Not e.Value.IsEmptyString Then Labels.ListAddList(e.Value.Split("|"), LAP.NotContainsOnly)
End Sub
Public Overrides Function ToString() As String
Return $"{IIf(Index >= 0 And Index <= 8, $"#{Index + 1}: ", String.Empty)}{Name}"
End Function
Private _ControlSent As Boolean = False
Friend Function GetControl() As ToolStripMenuItem
If Not _ControlSent Then
BTT_MENU.Text = ToString()
BTT_MENU.Tag = Key
_ControlSent = True
End If
Return BTT_MENU
End Function
Private Function SetIndex(ByVal Obj As Object, ByVal _Index As Integer) As Object Implements IIndexable.SetIndex
DirectCast(Obj, DownloadGroup).Index = _Index
Return Obj
End Function
#Region "Buttons"
Private Sub BTT_MENU_Click(sender As Object, e As EventArgs) Handles BTT_MENU.Click
DownloadUsers(True)
End Sub
Private Sub BTT_EDIT_Click(sender As Object, e As EventArgs) Handles BTT_EDIT.Click
Using f As New GroupEditorForm(Me)
f.ShowDialog()
If f.DialogResult = DialogResult.OK Then RaiseEvent Updated(Me)
End Using
End Sub
Private Sub BTT_DELETE_Click(sender As Object, e As EventArgs) Handles BTT_DELETE.Click
If MsgBoxE({$"Are you sure you want to delete the [{Name}] group?", "Deleting a group"}, vbExclamation + vbYesNo) = vbYes Then
RaiseEvent Deleted(Me)
MsgBoxE({$"Group [{Name}] deleted", "Deleting a group"})
End If
End Sub
Private Sub BTT_DOWNLOAD_Click(sender As Object, e As EventArgs) Handles BTT_DOWNLOAD.Click
DownloadUsers(True)
End Sub
Private Sub BTT_DOWNLOAD_FULL_Click(sender As Object, e As EventArgs) Handles BTT_DOWNLOAD_FULL.Click
DownloadUsers(False)
End Sub
Friend Overloads Function GetUsers() As IEnumerable(Of IUserData)
Return GetUsers(Me, True)
End Function
Friend Overloads Shared Function GetUsers(ByVal Instance As IGroup, ByVal UseReadyOption As Boolean) As IEnumerable(Of IUserData)
Try
If Settings.Users.Count > 0 Then
With Instance
Dim CheckParams As Predicate(Of IUserData) = Function(user) _
(.Temporary = CheckState.Indeterminate Or user.Temporary = CBool(.Temporary)) And
(.Favorite = CheckState.Indeterminate Or (user.Favorite = CBool(.Favorite))) And
(Not UseReadyOption Or .ReadyForDownloadIgnore Or user.ReadyForDownload = .ReadyForDownload)
Dim f As Func(Of IUserData, IEnumerable(Of IUserData)) = Function(ByVal user As IUserData) As IEnumerable(Of IUserData)
If user.IsCollection Then
With DirectCast(user, UserDataBind)
If .Count > 0 Then Return .Collections.SelectMany(f)
End With
Else
If .Labels.Count = 0 OrElse user.Labels.ListContains(.Labels) Then
If CheckParams.Invoke(user) Then Return {user}
End If
End If
Return New IUserData() {}
End Function
Return Settings.Users.SelectMany(f)
End With
Else
Return Nothing
End If
Catch ex As Exception
Return ErrorsDescriber.Execute(EDP.SendInLog, ex, "[DownloadGroup.GetUsers]")
End Try
End Function
Friend Sub DownloadUsers(ByVal UseReadyOption As Boolean)
Try
If Settings.Users.Count > 0 Then
Dim u As IEnumerable(Of IUserData) = GetUsers(Me, UseReadyOption)
If u.ListExists Then
Downloader.AddRange(u)
Else
MsgBoxE({$"No users found for group [{Name}].", "No users found"}, vbExclamation)
End If
End If
Catch ex As Exception
ErrorsDescriber.Execute(EDP.SendInLog, ex, "[DownloadGroup.DownloadUsers]")
End Try
End Sub
#End Region
#Region "IEContainerProvider Support"
Private Function ToEContainer(Optional ByVal e As ErrorsDescriber = Nothing) As EContainer Implements IEContainerProvider.ToEContainer
Return New EContainer("Group", Labels.ListToString("|"), {New EAttribute(Name_Name, Name),
New EAttribute(Name_Temporary, CInt(Temporary)),
New EAttribute(Name_Favorite, CInt(Favorite)),
New EAttribute(Name_ReadyForDownload, ReadyForDownload.BoolToInteger),
New EAttribute(Name_ReadyForDownloadIgnore, ReadyForDownloadIgnore.BoolToInteger)})
End Function
#End Region
#Region "IDisposable Support"
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If Not disposedValue And disposing Then
BTT_DELETE.Dispose()
BTT_EDIT.Dispose()
BTT_MENU.Dispose()
SEP_1.Dispose()
BTT_DOWNLOAD.Dispose()
BTT_DOWNLOAD_FULL.Dispose()
End If
MyBase.Dispose(disposing)
End Sub
#End Region
End Class
End Namespace

View File

@@ -0,0 +1,97 @@
' Copyright (C) 2022 Andy
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY
Imports PersonalUtilities.Functions.XML
Imports PersonalUtilities.Tools
Namespace DownloadObjects.Groups
Friend Class DownloadGroupCollection : Implements IEnumerable(Of DownloadGroup), IMyEnumerator(Of DownloadGroup)
Friend Event Deleted As DownloadGroup.GroupEventHandler
Friend Event Added As DownloadGroup.GroupEventHandler
Friend Event Updated As DownloadGroup.GroupEventHandler
Private ReadOnly GroupsList As List(Of DownloadGroup)
Private ReadOnly GroupFile As SFile = "Settings\Groups.xml"
Friend Sub New()
GroupsList = New List(Of DownloadGroup)
If GroupFile.Exists Then
Using x As New XmlFile(GroupFile,, False) With {.XmlReadOnly = True, .AllowSameNames = True}
x.LoadData()
If x.Count > 0 Then GroupsList.ListAddList(x, LAP.IgnoreICopier)
End Using
If GroupsList.Count > 0 Then GroupsList.ForEach(Sub(ByVal g As DownloadGroup)
AddHandler g.Deleted, AddressOf OnGroupDeleted
AddHandler g.Updated, AddressOf OnGroupUpdated
End Sub)
End If
GroupsList.ListReindex
End Sub
Friend Function GetLabels() As List(Of String)
Return ListAddList(Nothing, GroupsList.SelectMany(Function(g) g.Labels), LAP.NotContainsOnly)
End Function
Default Friend ReadOnly Property Item(ByVal Index As Integer) As DownloadGroup Implements IMyEnumerator(Of DownloadGroup).MyEnumeratorObject
Get
Return GroupsList(Index)
End Get
End Property
Friend ReadOnly Property Count As Integer Implements IMyEnumerator(Of DownloadGroup).MyEnumeratorCount
Get
Return GroupsList.Count
End Get
End Property
Friend Sub Update()
If Count > 0 Then
Using x As New XmlFile With {.Name = "Groups", .AllowSameNames = True}
x.AddRange(GroupsList)
x.Save(GroupFile)
End Using
Else
GroupFile.Delete()
End If
End Sub
Private Sub OnGroupUpdated(ByVal Sender As DownloadGroup)
Update()
RaiseEvent Updated(Sender)
End Sub
Private Sub OnGroupDeleted(ByVal Sender As DownloadGroup)
RaiseEvent Deleted(Sender)
Dim i% = GroupsList.FindIndex(Function(g) g.Key = Sender.Key)
If i >= 0 Then
GroupsList(i).Dispose()
GroupsList.RemoveAt(i)
GroupsList.ListReindex
Update()
End If
End Sub
Friend Sub Add()
Using f As New GroupEditorForm(Nothing)
f.ShowDialog()
If f.DialogResult = DialogResult.OK Then
GroupsList.Add(f.MyGroup)
GroupsList.ListReindex
RaiseEvent Added(GroupsList.Last)
Update()
End If
End Using
End Sub
Friend Function DownloadGroupIfExists(ByVal Index As Integer) As Boolean
If Index.ValueBetween(0, Count - 1) Then Item(Index).DownloadUsers(True) : Return True Else Return False
End Function
Friend Function IndexOf(ByVal Name As String) As Integer
If Count > 0 Then
Return GroupsList.FindIndex(Function(g) g.Name = Name)
Else
Return -1
End If
End Function
Private Function GetEnumerator() As IEnumerator(Of DownloadGroup) Implements IEnumerable(Of DownloadGroup).GetEnumerator
Return New MyEnumerator(Of DownloadGroup)(Me)
End Function
Private Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
Return GetEnumerator()
End Function
End Class
End Namespace

View File

@@ -0,0 +1,142 @@
' Copyright (C) 2022 Andy
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY
Imports PersonalUtilities.Forms.Controls
Imports PersonalUtilities.Forms.Controls.Base
Imports ADB = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons
Namespace DownloadObjects.Groups
Public Class GroupDefaults : Inherits TableLayoutPanel
Private ReadOnly TP_1 As TableLayoutPanel
Private ReadOnly TP_2 As TableLayoutPanel
Private ReadOnly CH_TEMPORARY As CheckBox
Private ReadOnly CH_FAV As CheckBox
Private ReadOnly CH_READY_FOR_DOWN As CheckBox
Private ReadOnly CH_READY_FOR_DOWN_IGNORE As CheckBox
Private WithEvents TXT_LABELS As TextBoxExtended
Private ReadOnly Labels As List(Of String)
Public Sub New()
Labels = New List(Of String)
TXT_LABELS = New TextBoxExtended
With TXT_LABELS
.BeginInit()
.Buttons.AddRange({ADB.Edit, ADB.Clear})
.CaptionText = "Labels"
.CaptionWidth = 50
.Dock = DockStyle.Fill
.EndInit()
End With
CH_TEMPORARY = New CheckBox With {.Text = "Temporary", .Name = "CH_TEMPORARY", .ThreeState = True, .CheckState = CheckState.Indeterminate, .Dock = DockStyle.Fill}
CH_FAV = New CheckBox With {.Text = "Favorite", .Name = "CH_FAV", .ThreeState = True, .CheckState = CheckState.Indeterminate, .Dock = DockStyle.Fill}
CH_READY_FOR_DOWN = New CheckBox With {.Text = "Ready for download", .Name = "CH_READY_FOR_DOWN", .Checked = True, .Dock = DockStyle.Fill}
CH_READY_FOR_DOWN_IGNORE = New CheckBox With {.Text = "Ignore ready for download", .Name = "CH_READY_FOR_DOWN_IGNORE", .Checked = False, .Dock = DockStyle.Fill}
TP_1 = New TableLayoutPanel With {.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single, .Margin = New Padding(0), .Dock = DockStyle.Fill}
FillTP(TP_1, CH_TEMPORARY, CH_FAV)
TP_2 = New TableLayoutPanel With {.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single, .Margin = New Padding(0), .Dock = DockStyle.Fill}
FillTP(TP_2, CH_READY_FOR_DOWN, CH_READY_FOR_DOWN_IGNORE)
End Sub
Private Sub FillTP(ByRef TP As TableLayoutPanel, ByVal CNT1 As Control, ByVal CNT2 As Control)
With TP
.ColumnCount = 2
.ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 50))
.ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 50))
.RowCount = 1
.RowStyles.Add(New RowStyle(SizeType.Percent, 100))
With .Controls : .Add(CNT1, 0, 0) : .Add(CNT2, 1, 0) : End With
End With
End Sub
Private Sub GroupDefaults_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed
Labels.Clear()
CH_TEMPORARY.Dispose()
CH_FAV.Dispose()
CH_READY_FOR_DOWN.Dispose()
CH_READY_FOR_DOWN_IGNORE.Dispose()
TXT_LABELS.Dispose()
With TP_1
.Controls.Clear()
.RowStyles.Clear()
.ColumnStyles.Clear()
.Dispose()
End With
With TP_2
.Controls.Clear()
.RowStyles.Clear()
.ColumnStyles.Clear()
.Dispose()
End With
End Sub
Protected Overrides Sub InitLayout()
MyBase.InitLayout()
If ColumnStyles.Count = 2 Or RowStyles.Count = 2 Then
ColumnStyles.Clear()
RowStyles.Clear()
CellBorderStyle = TableLayoutPanelCellBorderStyle.Single
ColumnCount = 1
ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 100))
RowCount = 5
RowStyles.Add(New RowStyle(SizeType.Absolute, 25))
RowStyles.Add(New RowStyle(SizeType.Absolute, 25))
RowStyles.Add(New RowStyle(SizeType.Absolute, 25))
RowStyles.Add(New RowStyle(SizeType.Absolute, 28))
RowStyles.Add(New RowStyle(SizeType.Percent, 100))
End If
Controls.Add(TP_1, 0, 1)
Controls.Add(TP_2, 0, 2)
Controls.Add(TXT_LABELS, 0, 3)
End Sub
Private Sub TXT_LABELS_ActionOnButtonClick(ByVal Sender As ActionButton) Handles TXT_LABELS.ActionOnButtonClick
Select Case Sender.DefaultButton
Case ADB.Edit
Using f As New LabelsForm(Labels)
f.ShowDialog()
If f.DialogResult = DialogResult.OK Then
Labels.ListAddList(f.LabelsList, LAP.NotContainsOnly, LAP.ClearBeforeAdd)
TXT_LABELS.Clear()
TXT_LABELS.Text = Labels.ListToString
End If
End Using
Case ADB.Clear : Labels.Clear()
End Select
End Sub
Friend Sub [Get](ByRef Instance As IGroup)
If Not Instance Is Nothing Then
With Instance
.Temporary = CH_TEMPORARY.CheckState
.Favorite = CH_FAV.CheckState
.ReadyForDownload = CH_READY_FOR_DOWN.Checked
.ReadyForDownloadIgnore = CH_READY_FOR_DOWN_IGNORE.Checked
.Labels.Clear()
.Labels.ListAddList(Labels)
End With
End If
End Sub
Friend Sub [Set](ByVal Instance As IGroup)
If Not Instance Is Nothing Then
With Instance
CH_TEMPORARY.CheckState = .Temporary
CH_FAV.CheckState = .Favorite
CH_READY_FOR_DOWN.Checked = .ReadyForDownload
CH_READY_FOR_DOWN_IGNORE.Checked = .ReadyForDownloadIgnore
Labels.ListAddList(.Labels)
TXT_LABELS.Text = Labels.ListToString
End With
End If
End Sub
Private _Enabled As Boolean = True
Friend Shadows Property Enabled As Boolean
Get
Return _Enabled
End Get
Set(ByVal e As Boolean)
_Enabled = e
TP_1.Enabled = e
TP_2.Enabled = e
TXT_LABELS.Enabled = e
End Set
End Property
End Class
End Namespace

View File

@@ -0,0 +1,115 @@
' Copyright (C) 2022 Andy
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY
Namespace DownloadObjects.Groups
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()>
Partial Friend Class GroupEditorForm : Inherits System.Windows.Forms.Form
<System.Diagnostics.DebuggerNonUserCode()>
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
Try
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
Finally
MyBase.Dispose(disposing)
End Try
End Sub
Private components As System.ComponentModel.IContainer
<System.Diagnostics.DebuggerStepThrough()>
Private Sub InitializeComponent()
Dim CONTAINER_MAIN As System.Windows.Forms.ToolStripContainer
Dim ActionButton1 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(GroupEditorForm))
Me.DEFS_GROUP = New SCrawler.DownloadObjects.Groups.GroupDefaults()
Me.TXT_NAME = New PersonalUtilities.Forms.Controls.TextBoxExtended()
CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer()
CONTAINER_MAIN.ContentPanel.SuspendLayout()
CONTAINER_MAIN.SuspendLayout()
Me.DEFS_GROUP.SuspendLayout()
CType(Me.TXT_NAME, System.ComponentModel.ISupportInitialize).BeginInit()
Me.SuspendLayout()
'
'CONTAINER_MAIN
'
'
'CONTAINER_MAIN.ContentPanel
'
CONTAINER_MAIN.ContentPanel.Controls.Add(Me.DEFS_GROUP)
CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(476, 134)
CONTAINER_MAIN.Dock = System.Windows.Forms.DockStyle.Fill
CONTAINER_MAIN.LeftToolStripPanelVisible = False
CONTAINER_MAIN.Location = New System.Drawing.Point(0, 0)
CONTAINER_MAIN.Name = "CONTAINER_MAIN"
CONTAINER_MAIN.RightToolStripPanelVisible = False
CONTAINER_MAIN.Size = New System.Drawing.Size(476, 134)
CONTAINER_MAIN.TabIndex = 0
CONTAINER_MAIN.TopToolStripPanelVisible = False
'
'DEFS_GROUP
'
Me.DEFS_GROUP.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single]
Me.DEFS_GROUP.ColumnCount = 1
Me.DEFS_GROUP.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
Me.DEFS_GROUP.Controls.Add(Me.TXT_NAME, 0, 0)
Me.DEFS_GROUP.Dock = System.Windows.Forms.DockStyle.Fill
Me.DEFS_GROUP.Location = New System.Drawing.Point(0, 0)
Me.DEFS_GROUP.Name = "DEFS_GROUP"
Me.DEFS_GROUP.RowCount = 5
Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
Me.DEFS_GROUP.Size = New System.Drawing.Size(476, 134)
Me.DEFS_GROUP.TabIndex = 1
'
'TXT_NAME
'
ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image)
ActionButton1.Index = 0
ActionButton1.Name = "BTT_CLEAR"
Me.TXT_NAME.Buttons.Add(ActionButton1)
Me.TXT_NAME.CaptionText = "Name"
Me.TXT_NAME.CaptionToolTipEnabled = True
Me.TXT_NAME.CaptionToolTipText = "Group name"
Me.TXT_NAME.CaptionWidth = 50.0R
Me.TXT_NAME.Dock = System.Windows.Forms.DockStyle.Fill
Me.TXT_NAME.Location = New System.Drawing.Point(4, 4)
Me.TXT_NAME.Name = "TXT_NAME"
Me.TXT_NAME.Size = New System.Drawing.Size(468, 22)
Me.TXT_NAME.TabIndex = 0
'
'GroupEditorForm
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(476, 134)
Me.Controls.Add(CONTAINER_MAIN)
Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle
Me.KeyPreview = True
Me.MaximizeBox = False
Me.MaximumSize = New System.Drawing.Size(492, 173)
Me.MinimizeBox = False
Me.MinimumSize = New System.Drawing.Size(492, 173)
Me.Name = "GroupEditorForm"
Me.ShowIcon = False
Me.ShowInTaskbar = False
Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide
Me.Text = "Group"
CONTAINER_MAIN.ContentPanel.ResumeLayout(False)
CONTAINER_MAIN.ResumeLayout(False)
CONTAINER_MAIN.PerformLayout()
Me.DEFS_GROUP.ResumeLayout(False)
CType(Me.TXT_NAME, System.ComponentModel.ISupportInitialize).EndInit()
Me.ResumeLayout(False)
End Sub
Private WithEvents TXT_NAME As PersonalUtilities.Forms.Controls.TextBoxExtended
Private WithEvents DEFS_GROUP As GroupDefaults
End Class
End Namespace

View File

@@ -0,0 +1,132 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="CONTAINER_MAIN.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="ActionButton1.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
</value>
</data>
</root>

View File

@@ -0,0 +1,81 @@
' Copyright (C) 2022 Andy
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY
Imports PersonalUtilities.Forms
Imports PersonalUtilities.Forms.Toolbars
Namespace DownloadObjects.Groups
Friend Class GroupEditorForm : Implements IOkCancelToolbar
Private ReadOnly MyDefs As DefaultFormProps
Friend Property MyGroup As DownloadGroup
Friend Sub New(ByRef g As DownloadGroup)
InitializeComponent()
MyGroup = g
MyDefs = New DefaultFormProps
End Sub
Private Class NameChecker : Implements IFieldsCheckerProvider
Private Property ErrorMessage As String Implements IFieldsCheckerProvider.ErrorMessage
Private Property Name As String Implements IFieldsCheckerProvider.Name
Private Property TypeError As Boolean Implements IFieldsCheckerProvider.TypeError
Private ReadOnly ExistingGroupName As String
Friend Sub New(ByVal _ExistingGroupName As String)
ExistingGroupName = _ExistingGroupName
End Sub
Private Function Convert(ByVal Value As Object, ByVal DestinationType As Type, ByVal Provider As IFormatProvider,
Optional ByVal NothingArg As Object = Nothing, Optional ByVal e As ErrorsDescriber = Nothing) As Object Implements ICustomProvider.Convert
If Not ACheck(Value) Then
ErrorMessage = "Group name cannot be empty"
ElseIf Not ExistingGroupName.IsEmptyString AndAlso CStr(Value) = ExistingGroupName Then
Return Value
ElseIf Settings.Groups.Count > 0 AndAlso Settings.Groups.LongCount(Function(g) g.Name = CStr(Value)) > 0 Then
ErrorMessage = "A group with the same name already exists"
Else
Return Value
End If
Return Nothing
End Function
Private Function GetFormat(ByVal FormatType As Type) As Object Implements IFormatProvider.GetFormat
Throw New NotImplementedException("GetFormat is not available in this context")
End Function
End Class
Private Sub GroupEditorForm_Load(sender As Object, e As EventArgs) Handles Me.Load
With MyDefs
.MyViewInitialize(Me, Settings.Design, True)
.AddOkCancelToolbar()
.DelegateClosingChecker()
If Not MyGroup Is Nothing Then
With MyGroup
TXT_NAME.Text = .Name
DEFS_GROUP.Set(MyGroup)
Text &= $" { .Name}"
End With
Else
Text = "New Group"
End If
.MyFieldsChecker = New FieldsChecker
DirectCast(.MyFieldsChecker, FieldsChecker).AddControl(Of String)(TXT_NAME, TXT_NAME.CaptionText,, New NameChecker(If(MyGroup?.Name, String.Empty)))
.MyFieldsChecker.EndLoaderOperations()
.AppendDetectors()
.EndLoaderOperations()
End With
End Sub
Private Sub OK() Implements IOkCancelToolbar.OK
If MyDefs.MyFieldsChecker.AllParamsOK Then
If MyGroup Is Nothing Then MyGroup = New DownloadGroup
With MyGroup
.NameBefore = .Name
.Name = TXT_NAME.Text
DEFS_GROUP.Get(MyGroup)
End With
MyDefs.CloseForm()
End If
End Sub
Private Sub Cancel() Implements IOkCancelToolbar.Cancel
MyDefs.CloseForm(DialogResult.Cancel)
End Sub
End Class
End Namespace

View File

@@ -0,0 +1,48 @@
' Copyright (C) 2022 Andy
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY
Namespace DownloadObjects.Groups
Friend Interface IGroup
ReadOnly Property Labels As List(Of String)
Property Temporary As CheckState
Property Favorite As CheckState
Property ReadyForDownload As Boolean
Property ReadyForDownloadIgnore As Boolean
End Interface
Friend Class GroupParameters : Implements IGroup, IDisposable
Protected Const Name_Temporary As String = "Temporary"
Protected Const Name_Favorite As String = "Favorite"
Protected Const Name_ReadyForDownload As String = "RFD"
Protected Const Name_ReadyForDownloadIgnore As String = "RFDI"
Friend ReadOnly Property Labels As List(Of String) Implements IGroup.Labels
Friend Property Temporary As CheckState = CheckState.Indeterminate Implements IGroup.Temporary
Friend Property Favorite As CheckState = CheckState.Indeterminate Implements IGroup.Favorite
Friend Property ReadyForDownload As Boolean = True Implements IGroup.ReadyForDownload
Friend Property ReadyForDownloadIgnore As Boolean = False Implements IGroup.ReadyForDownloadIgnore
Friend Sub New()
Labels = New List(Of String)
End Sub
#Region "IDisposable Support"
Protected disposedValue As Boolean = False
Protected Overridable Overloads Sub Dispose(ByVal disposing As Boolean)
If Not disposedValue Then
If disposing Then Labels.Clear()
disposedValue = True
End If
End Sub
Protected Overrides Sub Finalize()
Dispose(False)
MyBase.Finalize()
End Sub
Friend Overloads Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
End Class
End Namespace

View File

@@ -15,18 +15,44 @@ Imports SCrawler.Plugin.Hosts
Imports Download = SCrawler.Plugin.ISiteSettings.Download
Namespace DownloadObjects
Friend Class TDownloader : Implements IDisposable
#Region "Events"
Friend Event OnJobsChange(ByVal JobsCount As Integer)
Friend Event OnDownloadCountChange()
Friend Event OnDownloading(ByVal Value As Boolean)
Friend Event SendNotification(ByVal Message As String)
Friend Event SendNotification As NotificationEventHandler
Friend Event OnReconfigured()
#End Region
#Region "Declarations"
Friend ReadOnly Property Downloaded As List(Of IUserData)
Private ReadOnly NProv As IFormatProvider
#End Region
#Region "Working, Count"
Friend ReadOnly Property Working As Boolean
Get
Return Pool.Count > 0 AndAlso Pool.Exists(Function(j) j.Working)
End Get
End Property
Friend ReadOnly Property Count As Integer
Get
If Pool.Count = 0 Then Return 0 Else Return Pool.Sum(Function(j) j.Count)
End Get
End Property
#End Region
#Region "Automation Support"
Friend Property DisableOpenForms As Boolean = False
Private _DisableCompleteNotification As Boolean = False
Private _AutoDownloaderWorking As Boolean = False
Friend WriteOnly Property AutoDownloaderWorking As Boolean
Set(ByVal adw As Boolean)
_AutoDownloaderWorking = adw
DisableOpenForms = adw
_DisableCompleteNotification = adw
End Set
End Property
Friend Sub InvokeDownloadsChangeEvent()
RaiseEvent OnDownloadCountChange()
End Sub
#End Region
#Region "Jobs"
Friend Class Job : Implements IDisposable
Friend Event OnItemsCountChange(ByVal Sender As Job, ByVal Count As Integer)
@@ -105,11 +131,11 @@ Namespace DownloadObjects
Dim i% = Keys.IndexOf(DirectCast(User, UserDataBase).User.Plugin)
If i >= 0 Then Return Hosts(i) Else Throw New KeyNotFoundException($"Plugin key [{DirectCast(User, UserDataBase).User.Plugin}] not found")
End Function
Friend Function Available() As Boolean
Friend Function Available(ByVal Silent As Boolean) As Boolean
If Hosts.Count > 0 Then
Dim k$
For i% = Hosts.Count - 1 To 0 Step -1
If Not Hosts(i).Available(Type) Then
If Not Hosts(i).Available(Type, Silent) Then
k = Hosts(i).Key
If Not RemovingKeys.Contains(k) Then RemovingKeys.Add(k)
Hosts(i).DownloadDone(Type)
@@ -182,11 +208,14 @@ Namespace DownloadObjects
End Class
Friend ReadOnly Pool As List(Of Job)
#End Region
#Region "Initializer"
Friend Sub New()
Downloaded = New List(Of IUserData)
NProv = New ANumbers With {.FormatOptions = ANumbers.Options.GroupIntegral}
Pool = New List(Of Job)
End Sub
#End Region
#Region "Pool"
Friend Sub ReconfPool()
If Pool.Count = 0 OrElse Not Pool.Exists(Function(j) j.Working Or j.Count > 0) Then
Pool.ListClearDispose
@@ -204,16 +233,19 @@ Namespace DownloadObjects
RaiseEvent OnReconfigured()
End If
End Sub
#End Region
#Region "Thread"
Private CheckerThread As Thread
Private Sub [Start]()
If Not MyProgressForm.Opened AndAlso Pool.LongCount(Function(p) p.Count > 0) > 1 Then MyProgressForm.Show()
If Not DisableOpenForms AndAlso MyProgressForm.ReadyToOpen AndAlso Pool.LongCount(Function(p) p.Count > 0) > 1 Then MyProgressForm.Show() : MainFrameObj.Focus()
If Not If(CheckerThread?.IsAlive, False) Then
MainProgress.Enabled = True
If Not DisableOpenForms AndAlso InfoForm.ReadyToOpen Then InfoForm.Show() : MainFrameObj.Focus()
CheckerThread = New Thread(New ThreadStart(AddressOf JobsChecker))
CheckerThread.SetApartmentState(ApartmentState.MTA)
CheckerThread.Start()
End If
End Sub
End Sub
Private Sub JobsChecker()
Try
MainProgress.TotalCount = 0
@@ -235,6 +267,7 @@ Namespace DownloadObjects
End With
MyProgressForm.DisableProgressChange = True
If Pool.Count > 0 Then Pool.ForEach(Sub(p) If Not p.Progress Is Nothing Then p.Progress.TotalCount = 0)
ExecuteCommand(Settings.DownloadsCompleteCommand)
End Try
End Sub
Private Sub StartDownloading(ByRef _Job As Job)
@@ -243,7 +276,7 @@ Namespace DownloadObjects
Dim n$ = _Job.Name
Dim pt As Func(Of String, String) = Function(ByVal t As String) As String
Dim _t$ = If(isSeparated, $"{n} {Left(t, 1).ToLower}{Right(t, t.Length - 1)}", t)
RaiseEvent SendNotification(_t)
If Not _DisableCompleteNotification Then RaiseEvent SendNotification(_t)
Return _t
End Function
Try
@@ -254,9 +287,7 @@ Namespace DownloadObjects
Dim SiteChecked As Boolean = False
Do While _Job.Count > 0
_Job.ThrowIfCancellationRequested()
If Not SiteChecked Then
If Not _Job.Available Then Exit Sub Else SiteChecked = True : Continue Do
End If
If Not SiteChecked Then _Job.Available(_AutoDownloaderWorking) : SiteChecked = True : Continue Do
UpdateJobsLabel()
DownloadData(_Job, _Job.Token)
_Job.ThrowIfCancellationRequested()
@@ -282,7 +313,7 @@ Namespace DownloadObjects
End If
End Sub
Private Sub UpdateJobsLabel()
RaiseEvent OnJobsChange(Pool.Sum(Function(j) j.Count))
RaiseEvent OnJobsChange(Count)
End Sub
Private Sub DownloadData(ByRef _Job As Job, ByVal Token As CancellationToken)
Try
@@ -351,7 +382,7 @@ Namespace DownloadObjects
End Sub))
End Try
End Sub
Private Function GetUserFromMainCollection(ByVal User As IUserData) As IUserData
Friend Shared Function GetUserFromMainCollection(ByVal User As IUserData) As IUserData
Dim uSimple As Predicate(Of IUserData) = Function(u) u.Equals(DirectCast(User, UserDataBase))
Dim uCol As Predicate(Of IUserData) = Function(ByVal u As IUserData) As Boolean
If u.IsCollection Then
@@ -375,6 +406,8 @@ Namespace DownloadObjects
End If
Return Nothing
End Function
#End Region
#Region "Add"
Private Sub AddItem(ByVal Item As IUserData, ByVal _UpdateJobsLabel As Boolean)
ReconfPool()
If Item.IsCollection Then
@@ -401,6 +434,8 @@ Namespace DownloadObjects
End If
Start()
End Sub
#End Region
#Region "Contains, Remove"
Private Function Contains(ByVal _Item As IUserData)
If Pool.Count > 0 Then
For Each j As Job In Pool
@@ -412,6 +447,7 @@ Namespace DownloadObjects
Friend Sub UserRemove(ByVal _Item As IUserData)
If Downloaded.Count > 0 AndAlso Downloaded.Contains(_Item) Then Downloaded.Remove(_Item) : RaiseEvent OnDownloadCountChange()
End Sub
#End Region
#Region "IDisposable Support"
Private disposedValue As Boolean = False
Protected Overridable Overloads Sub Dispose(ByVal disposing As Boolean)

View File

@@ -63,7 +63,7 @@ Namespace DownloadObjects
End Sub
Private Sub UpdateUrlsFile()
If UrlList.Count > 0 Then
TextSaver.SaveTextToFile(UrlList.ListToString(, Environment.NewLine), DownloadingUrlsFile, True,, EDP.SendInLog)
TextSaver.SaveTextToFile(UrlList.ListToString(Environment.NewLine), DownloadingUrlsFile, True,, EDP.SendInLog)
Else
DownloadingUrlsFile.Delete(, Settings.DeleteMode, EDP.SendInLog)
End If
@@ -129,7 +129,7 @@ Namespace DownloadObjects
With Settings.LatestSavingPath
If Not .Value.IsEmptyString Then
If .Value.Exists(SFO.Path, False) Then
.Value.Open(SFO.Path, EDP.ShowMainMsg)
GlobalOpenPath(.Value, EDP.ShowMainMsg)
Else
MsgBoxE($"Path [{ .Value}] does not exists!", MsgBoxStyle.Exclamation)
End If

View File

@@ -43,7 +43,7 @@ Namespace Editors
Private Sub CollectionEditorForm_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
If e.KeyCode = Keys.Insert Then AddNewCollection() : e.Handled = True Else e.Handled = False
End Sub
Private Sub ToolbarBttOK() Implements IOkCancelToolbar.ToolbarBttOK
Private Sub OK() Implements IOkCancelToolbar.OK
If CMB_COLLECTIONS.SelectedIndex >= 0 Then
Collection = CMB_COLLECTIONS.Value.ToString
MyDefs.CloseForm()
@@ -51,7 +51,7 @@ Namespace Editors
MsgBoxE("Collection not selected", MsgBoxStyle.Exclamation)
End If
End Sub
Private Sub ToolbarBttCancel() Implements IOkCancelToolbar.ToolbarBttCancel
Private Sub Cancel() Implements IOkCancelToolbar.Cancel
MyDefs.CloseForm(DialogResult.Cancel)
End Sub
Private Sub CMB_COLLECTIONS_ActionOnButtonClick(ByVal Sender As ActionButton) Handles CMB_COLLECTIONS.ActionOnButtonClick
@@ -59,7 +59,7 @@ Namespace Editors
End Sub
Private Sub CMB_COLLECTIONS_ActionOnListDoubleClick(ByVal _Item As ListViewItem) Handles CMB_COLLECTIONS.ActionOnListDoubleClick
_Item.Selected = True
ToolbarBttOK()
OK()
End Sub
Private Sub AddNewCollection()
Dim c$ = InputBoxE("Enter new collection name:", "Collection name")

View File

@@ -27,7 +27,6 @@
Dim TP_FILE_NAME As System.Windows.Forms.TableLayoutPanel
Dim TP_FILE_PATTERNS As System.Windows.Forms.TableLayoutPanel
Dim LBL_DATE_POS As System.Windows.Forms.Label
Dim ActionButton7 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim TT_MAIN As System.Windows.Forms.ToolTip
Dim TP_CHANNELS_IMGS As System.Windows.Forms.TableLayoutPanel
Dim TAB_BASIS As System.Windows.Forms.TabPage
@@ -35,6 +34,15 @@
Dim TP_DEFS As System.Windows.Forms.TableLayoutPanel
Dim TAB_DEFS_CHANNELS As System.Windows.Forms.TabPage
Dim TP_CHANNELS As System.Windows.Forms.TableLayoutPanel
Dim TAB_BEHAVIOR As System.Windows.Forms.TabPage
Dim TP_BEHAVIOR As System.Windows.Forms.TableLayoutPanel
Dim ActionButton7 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim TP_OPEN_INFO As System.Windows.Forms.TableLayoutPanel
Dim TP_OPEN_PROGRESS As System.Windows.Forms.TableLayoutPanel
Dim TAB_DOWN As System.Windows.Forms.TabPage
Dim TP_DOWNLOADING As System.Windows.Forms.TableLayoutPanel
Dim ActionButton8 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim ActionButton9 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Me.TXT_GLOBAL_PATH = New PersonalUtilities.Forms.Controls.TextBoxExtended()
Me.TXT_IMAGE_LARGE = New PersonalUtilities.Forms.Controls.TextBoxExtended()
Me.TXT_IMAGE_SMALL = New PersonalUtilities.Forms.Controls.TextBoxExtended()
@@ -43,6 +51,8 @@
Me.TXT_MAX_JOBS_CHANNELS = New PersonalUtilities.Forms.Controls.TextBoxExtended()
Me.CH_CHECK_VER_START = New System.Windows.Forms.CheckBox()
Me.TXT_IMGUR_CLIENT_ID = New PersonalUtilities.Forms.Controls.TextBoxExtended()
Me.CH_SHOW_GROUPS = New System.Windows.Forms.CheckBox()
Me.CH_USERS_GROUPING = New System.Windows.Forms.CheckBox()
Me.OPT_FILE_NAME_REPLACE = New System.Windows.Forms.RadioButton()
Me.OPT_FILE_NAME_ADD_DATE = New System.Windows.Forms.RadioButton()
Me.CH_FILE_NAME_CHANGE = New System.Windows.Forms.CheckBox()
@@ -50,12 +60,7 @@
Me.CH_FILE_TIME = New System.Windows.Forms.CheckBox()
Me.OPT_FILE_DATE_START = New System.Windows.Forms.RadioButton()
Me.OPT_FILE_DATE_END = New System.Windows.Forms.RadioButton()
Me.CH_EXIT_CONFIRM = New System.Windows.Forms.CheckBox()
Me.CH_CLOSE_TO_TRAY = New System.Windows.Forms.CheckBox()
Me.CH_SHOW_NOTIFY = New System.Windows.Forms.CheckBox()
Me.CH_FAST_LOAD = New System.Windows.Forms.CheckBox()
Me.TXT_FOLDER_CMD = New PersonalUtilities.Forms.Controls.TextBoxExtended()
Me.CH_RECYCLE_DEL = New System.Windows.Forms.CheckBox()
Me.CH_COPY_CHANNEL_USER_IMAGE = New System.Windows.Forms.CheckBox()
Me.CH_DEF_TEMP = New System.Windows.Forms.CheckBox()
Me.CH_DOWN_IMAGES = New System.Windows.Forms.CheckBox()
@@ -64,10 +69,24 @@
Me.CH_CHANNELS_USERS_TEMP = New System.Windows.Forms.CheckBox()
Me.CH_COPY_CHANNEL_USER_IMAGE_ALL = New System.Windows.Forms.CheckBox()
Me.CH_UDESCR_UP = New System.Windows.Forms.CheckBox()
Me.CH_DOWN_OPEN_INFO_SUSPEND = New System.Windows.Forms.CheckBox()
Me.CH_DOWN_OPEN_PROGRESS_SUSPEND = New System.Windows.Forms.CheckBox()
Me.TXT_CHANNELS_ROWS = New PersonalUtilities.Forms.Controls.TextBoxExtended()
Me.TXT_CHANNELS_COLUMNS = New PersonalUtilities.Forms.Controls.TextBoxExtended()
Me.TXT_CHANNEL_USER_POST_LIMIT = New PersonalUtilities.Forms.Controls.TextBoxExtended()
Me.TXT_FOLDER_CMD = New PersonalUtilities.Forms.Controls.TextBoxExtended()
Me.CH_EXIT_CONFIRM = New System.Windows.Forms.CheckBox()
Me.CH_CLOSE_TO_TRAY = New System.Windows.Forms.CheckBox()
Me.CH_SHOW_NOTIFY = New System.Windows.Forms.CheckBox()
Me.TXT_CLOSE_SCRIPT = New PersonalUtilities.Forms.Controls.TextBoxExtended()
Me.CH_DOWN_OPEN_INFO = New System.Windows.Forms.CheckBox()
Me.CH_RECYCLE_DEL = New System.Windows.Forms.CheckBox()
Me.CH_DOWN_OPEN_PROGRESS = New System.Windows.Forms.CheckBox()
Me.TXT_SCRIPT = New PersonalUtilities.Forms.Controls.TextBoxExtended()
Me.TXT_DOWN_COMPLETE_SCRIPT = New PersonalUtilities.Forms.Controls.TextBoxExtended()
Me.TAB_MAIN = New System.Windows.Forms.TabControl()
Me.TAB_AUTO = New System.Windows.Forms.TabPage()
Me.PANEL_AUTO = New System.Windows.Forms.Panel()
Me.CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer()
TP_BASIS = New System.Windows.Forms.TableLayoutPanel()
TP_IMAGES = New System.Windows.Forms.TableLayoutPanel()
@@ -81,6 +100,12 @@
TP_DEFS = New System.Windows.Forms.TableLayoutPanel()
TAB_DEFS_CHANNELS = New System.Windows.Forms.TabPage()
TP_CHANNELS = New System.Windows.Forms.TableLayoutPanel()
TAB_BEHAVIOR = New System.Windows.Forms.TabPage()
TP_BEHAVIOR = New System.Windows.Forms.TableLayoutPanel()
TP_OPEN_INFO = New System.Windows.Forms.TableLayoutPanel()
TP_OPEN_PROGRESS = New System.Windows.Forms.TableLayoutPanel()
TAB_DOWN = New System.Windows.Forms.TabPage()
TP_DOWNLOADING = New System.Windows.Forms.TableLayoutPanel()
TP_BASIS.SuspendLayout()
CType(Me.TXT_GLOBAL_PATH, System.ComponentModel.ISupportInitialize).BeginInit()
TP_IMAGES.SuspendLayout()
@@ -92,7 +117,6 @@
CType(Me.TXT_IMGUR_CLIENT_ID, System.ComponentModel.ISupportInitialize).BeginInit()
TP_FILE_NAME.SuspendLayout()
TP_FILE_PATTERNS.SuspendLayout()
CType(Me.TXT_FOLDER_CMD, System.ComponentModel.ISupportInitialize).BeginInit()
TP_CHANNELS_IMGS.SuspendLayout()
CType(Me.TXT_CHANNELS_ROWS, System.ComponentModel.ISupportInitialize).BeginInit()
CType(Me.TXT_CHANNELS_COLUMNS, System.ComponentModel.ISupportInitialize).BeginInit()
@@ -102,7 +126,18 @@
TAB_DEFS_CHANNELS.SuspendLayout()
TP_CHANNELS.SuspendLayout()
CType(Me.TXT_CHANNEL_USER_POST_LIMIT, System.ComponentModel.ISupportInitialize).BeginInit()
TAB_BEHAVIOR.SuspendLayout()
TP_BEHAVIOR.SuspendLayout()
CType(Me.TXT_FOLDER_CMD, System.ComponentModel.ISupportInitialize).BeginInit()
CType(Me.TXT_CLOSE_SCRIPT, System.ComponentModel.ISupportInitialize).BeginInit()
TP_OPEN_INFO.SuspendLayout()
TP_OPEN_PROGRESS.SuspendLayout()
TAB_DOWN.SuspendLayout()
TP_DOWNLOADING.SuspendLayout()
CType(Me.TXT_SCRIPT, System.ComponentModel.ISupportInitialize).BeginInit()
CType(Me.TXT_DOWN_COMPLETE_SCRIPT, System.ComponentModel.ISupportInitialize).BeginInit()
Me.TAB_MAIN.SuspendLayout()
Me.TAB_AUTO.SuspendLayout()
Me.CONTAINER_MAIN.ContentPanel.SuspendLayout()
Me.CONTAINER_MAIN.SuspendLayout()
Me.SuspendLayout()
@@ -119,18 +154,12 @@
TP_BASIS.Controls.Add(Me.TXT_MAX_JOBS_CHANNELS, 0, 4)
TP_BASIS.Controls.Add(Me.CH_CHECK_VER_START, 0, 5)
TP_BASIS.Controls.Add(Me.TXT_IMGUR_CLIENT_ID, 0, 6)
TP_BASIS.Controls.Add(TP_FILE_NAME, 0, 7)
TP_BASIS.Controls.Add(TP_FILE_PATTERNS, 0, 8)
TP_BASIS.Controls.Add(Me.CH_EXIT_CONFIRM, 0, 9)
TP_BASIS.Controls.Add(Me.CH_CLOSE_TO_TRAY, 0, 10)
TP_BASIS.Controls.Add(Me.CH_SHOW_NOTIFY, 0, 11)
TP_BASIS.Controls.Add(Me.CH_FAST_LOAD, 0, 12)
TP_BASIS.Controls.Add(Me.TXT_FOLDER_CMD, 0, 13)
TP_BASIS.Controls.Add(Me.CH_RECYCLE_DEL, 0, 14)
TP_BASIS.Controls.Add(Me.CH_SHOW_GROUPS, 0, 7)
TP_BASIS.Controls.Add(Me.CH_USERS_GROUPING, 0, 8)
TP_BASIS.Dock = System.Windows.Forms.DockStyle.Fill
TP_BASIS.Location = New System.Drawing.Point(3, 3)
TP_BASIS.Name = "TP_BASIS"
TP_BASIS.RowCount = 16
TP_BASIS.RowCount = 10
TP_BASIS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
TP_BASIS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
TP_BASIS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
@@ -138,16 +167,10 @@
TP_BASIS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
TP_BASIS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
TP_BASIS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
TP_BASIS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30.0!))
TP_BASIS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30.0!))
TP_BASIS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
TP_BASIS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
TP_BASIS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
TP_BASIS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
TP_BASIS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
TP_BASIS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
TP_BASIS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_BASIS.Size = New System.Drawing.Size(570, 447)
TP_BASIS.Size = New System.Drawing.Size(570, 278)
TP_BASIS.TabIndex = 0
'
'TXT_GLOBAL_PATH
@@ -297,6 +320,30 @@
Me.TXT_IMGUR_CLIENT_ID.Size = New System.Drawing.Size(562, 22)
Me.TXT_IMGUR_CLIENT_ID.TabIndex = 6
'
'CH_SHOW_GROUPS
'
Me.CH_SHOW_GROUPS.AutoSize = True
Me.CH_SHOW_GROUPS.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_SHOW_GROUPS.Location = New System.Drawing.Point(4, 204)
Me.CH_SHOW_GROUPS.Name = "CH_SHOW_GROUPS"
Me.CH_SHOW_GROUPS.Size = New System.Drawing.Size(562, 19)
Me.CH_SHOW_GROUPS.TabIndex = 7
Me.CH_SHOW_GROUPS.Text = "Show groups"
TT_MAIN.SetToolTip(Me.CH_SHOW_GROUPS, "Grouping users by site")
Me.CH_SHOW_GROUPS.UseVisualStyleBackColor = True
'
'CH_USERS_GROUPING
'
Me.CH_USERS_GROUPING.AutoSize = True
Me.CH_USERS_GROUPING.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_USERS_GROUPING.Location = New System.Drawing.Point(4, 230)
Me.CH_USERS_GROUPING.Name = "CH_USERS_GROUPING"
Me.CH_USERS_GROUPING.Size = New System.Drawing.Size(562, 19)
Me.CH_USERS_GROUPING.TabIndex = 8
Me.CH_USERS_GROUPING.Text = "Use user grouping"
TT_MAIN.SetToolTip(Me.CH_USERS_GROUPING, "Group users by groups and/or labels")
Me.CH_USERS_GROUPING.UseVisualStyleBackColor = True
'
'TP_FILE_NAME
'
TP_FILE_NAME.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single]
@@ -308,21 +355,21 @@
TP_FILE_NAME.Controls.Add(Me.OPT_FILE_NAME_ADD_DATE, 2, 0)
TP_FILE_NAME.Controls.Add(Me.CH_FILE_NAME_CHANGE, 0, 0)
TP_FILE_NAME.Dock = System.Windows.Forms.DockStyle.Fill
TP_FILE_NAME.Location = New System.Drawing.Point(1, 201)
TP_FILE_NAME.Location = New System.Drawing.Point(1, 27)
TP_FILE_NAME.Margin = New System.Windows.Forms.Padding(0)
TP_FILE_NAME.Name = "TP_FILE_NAME"
TP_FILE_NAME.RowCount = 1
TP_FILE_NAME.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_FILE_NAME.Size = New System.Drawing.Size(568, 30)
TP_FILE_NAME.TabIndex = 7
TP_FILE_NAME.Size = New System.Drawing.Size(574, 30)
TP_FILE_NAME.TabIndex = 1
'
'OPT_FILE_NAME_REPLACE
'
Me.OPT_FILE_NAME_REPLACE.AutoSize = True
Me.OPT_FILE_NAME_REPLACE.Dock = System.Windows.Forms.DockStyle.Fill
Me.OPT_FILE_NAME_REPLACE.Location = New System.Drawing.Point(193, 4)
Me.OPT_FILE_NAME_REPLACE.Location = New System.Drawing.Point(195, 4)
Me.OPT_FILE_NAME_REPLACE.Name = "OPT_FILE_NAME_REPLACE"
Me.OPT_FILE_NAME_REPLACE.Size = New System.Drawing.Size(182, 22)
Me.OPT_FILE_NAME_REPLACE.Size = New System.Drawing.Size(184, 22)
Me.OPT_FILE_NAME_REPLACE.TabIndex = 1
Me.OPT_FILE_NAME_REPLACE.TabStop = True
Me.OPT_FILE_NAME_REPLACE.Text = "Replace file name by date"
@@ -332,9 +379,9 @@
'
Me.OPT_FILE_NAME_ADD_DATE.AutoSize = True
Me.OPT_FILE_NAME_ADD_DATE.Dock = System.Windows.Forms.DockStyle.Fill
Me.OPT_FILE_NAME_ADD_DATE.Location = New System.Drawing.Point(382, 4)
Me.OPT_FILE_NAME_ADD_DATE.Location = New System.Drawing.Point(386, 4)
Me.OPT_FILE_NAME_ADD_DATE.Name = "OPT_FILE_NAME_ADD_DATE"
Me.OPT_FILE_NAME_ADD_DATE.Size = New System.Drawing.Size(182, 22)
Me.OPT_FILE_NAME_ADD_DATE.Size = New System.Drawing.Size(184, 22)
Me.OPT_FILE_NAME_ADD_DATE.TabIndex = 2
Me.OPT_FILE_NAME_ADD_DATE.TabStop = True
Me.OPT_FILE_NAME_ADD_DATE.Text = "Add date/time to file name"
@@ -346,7 +393,7 @@
Me.CH_FILE_NAME_CHANGE.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_FILE_NAME_CHANGE.Location = New System.Drawing.Point(4, 4)
Me.CH_FILE_NAME_CHANGE.Name = "CH_FILE_NAME_CHANGE"
Me.CH_FILE_NAME_CHANGE.Size = New System.Drawing.Size(182, 22)
Me.CH_FILE_NAME_CHANGE.Size = New System.Drawing.Size(184, 22)
Me.CH_FILE_NAME_CHANGE.TabIndex = 0
Me.CH_FILE_NAME_CHANGE.Text = "Change file names"
Me.CH_FILE_NAME_CHANGE.UseVisualStyleBackColor = True
@@ -366,14 +413,14 @@
TP_FILE_PATTERNS.Controls.Add(Me.OPT_FILE_DATE_START, 3, 0)
TP_FILE_PATTERNS.Controls.Add(Me.OPT_FILE_DATE_END, 4, 0)
TP_FILE_PATTERNS.Dock = System.Windows.Forms.DockStyle.Fill
TP_FILE_PATTERNS.Location = New System.Drawing.Point(1, 232)
TP_FILE_PATTERNS.Location = New System.Drawing.Point(1, 58)
TP_FILE_PATTERNS.Margin = New System.Windows.Forms.Padding(0)
TP_FILE_PATTERNS.Name = "TP_FILE_PATTERNS"
TP_FILE_PATTERNS.RowCount = 1
TP_FILE_PATTERNS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_FILE_PATTERNS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 29.0!))
TP_FILE_PATTERNS.Size = New System.Drawing.Size(568, 30)
TP_FILE_PATTERNS.TabIndex = 8
TP_FILE_PATTERNS.Size = New System.Drawing.Size(574, 30)
TP_FILE_PATTERNS.TabIndex = 2
'
'CH_FILE_DATE
'
@@ -381,7 +428,7 @@
Me.CH_FILE_DATE.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_FILE_DATE.Location = New System.Drawing.Point(4, 4)
Me.CH_FILE_DATE.Name = "CH_FILE_DATE"
Me.CH_FILE_DATE.Size = New System.Drawing.Size(106, 22)
Me.CH_FILE_DATE.Size = New System.Drawing.Size(107, 22)
Me.CH_FILE_DATE.TabIndex = 0
Me.CH_FILE_DATE.Text = "Date"
Me.CH_FILE_DATE.UseVisualStyleBackColor = True
@@ -390,9 +437,9 @@
'
Me.CH_FILE_TIME.AutoSize = True
Me.CH_FILE_TIME.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_FILE_TIME.Location = New System.Drawing.Point(117, 4)
Me.CH_FILE_TIME.Location = New System.Drawing.Point(118, 4)
Me.CH_FILE_TIME.Name = "CH_FILE_TIME"
Me.CH_FILE_TIME.Size = New System.Drawing.Size(106, 22)
Me.CH_FILE_TIME.Size = New System.Drawing.Size(107, 22)
Me.CH_FILE_TIME.TabIndex = 1
Me.CH_FILE_TIME.Text = "Time"
Me.CH_FILE_TIME.UseVisualStyleBackColor = True
@@ -401,9 +448,9 @@
'
LBL_DATE_POS.AutoSize = True
LBL_DATE_POS.Dock = System.Windows.Forms.DockStyle.Fill
LBL_DATE_POS.Location = New System.Drawing.Point(230, 1)
LBL_DATE_POS.Location = New System.Drawing.Point(232, 1)
LBL_DATE_POS.Name = "LBL_DATE_POS"
LBL_DATE_POS.Size = New System.Drawing.Size(106, 28)
LBL_DATE_POS.Size = New System.Drawing.Size(107, 28)
LBL_DATE_POS.TabIndex = 2
LBL_DATE_POS.Text = "Date position:"
LBL_DATE_POS.TextAlign = System.Drawing.ContentAlignment.MiddleRight
@@ -412,9 +459,9 @@
'
Me.OPT_FILE_DATE_START.AutoSize = True
Me.OPT_FILE_DATE_START.Dock = System.Windows.Forms.DockStyle.Fill
Me.OPT_FILE_DATE_START.Location = New System.Drawing.Point(343, 4)
Me.OPT_FILE_DATE_START.Location = New System.Drawing.Point(346, 4)
Me.OPT_FILE_DATE_START.Name = "OPT_FILE_DATE_START"
Me.OPT_FILE_DATE_START.Size = New System.Drawing.Size(106, 22)
Me.OPT_FILE_DATE_START.Size = New System.Drawing.Size(107, 22)
Me.OPT_FILE_DATE_START.TabIndex = 3
Me.OPT_FILE_DATE_START.TabStop = True
Me.OPT_FILE_DATE_START.Text = "Start"
@@ -424,92 +471,26 @@
'
Me.OPT_FILE_DATE_END.AutoSize = True
Me.OPT_FILE_DATE_END.Dock = System.Windows.Forms.DockStyle.Fill
Me.OPT_FILE_DATE_END.Location = New System.Drawing.Point(456, 4)
Me.OPT_FILE_DATE_END.Location = New System.Drawing.Point(460, 4)
Me.OPT_FILE_DATE_END.Name = "OPT_FILE_DATE_END"
Me.OPT_FILE_DATE_END.Size = New System.Drawing.Size(108, 22)
Me.OPT_FILE_DATE_END.Size = New System.Drawing.Size(110, 22)
Me.OPT_FILE_DATE_END.TabIndex = 4
Me.OPT_FILE_DATE_END.TabStop = True
Me.OPT_FILE_DATE_END.Text = "End"
Me.OPT_FILE_DATE_END.UseVisualStyleBackColor = True
'
'CH_EXIT_CONFIRM
'
Me.CH_EXIT_CONFIRM.AutoSize = True
Me.CH_EXIT_CONFIRM.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_EXIT_CONFIRM.Location = New System.Drawing.Point(4, 266)
Me.CH_EXIT_CONFIRM.Name = "CH_EXIT_CONFIRM"
Me.CH_EXIT_CONFIRM.Size = New System.Drawing.Size(562, 19)
Me.CH_EXIT_CONFIRM.TabIndex = 9
Me.CH_EXIT_CONFIRM.Text = "Exit confirm"
Me.CH_EXIT_CONFIRM.UseVisualStyleBackColor = True
'
'CH_CLOSE_TO_TRAY
'
Me.CH_CLOSE_TO_TRAY.AutoSize = True
Me.CH_CLOSE_TO_TRAY.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_CLOSE_TO_TRAY.Location = New System.Drawing.Point(4, 292)
Me.CH_CLOSE_TO_TRAY.Name = "CH_CLOSE_TO_TRAY"
Me.CH_CLOSE_TO_TRAY.Size = New System.Drawing.Size(562, 19)
Me.CH_CLOSE_TO_TRAY.TabIndex = 10
Me.CH_CLOSE_TO_TRAY.Text = "Close to tray"
Me.CH_CLOSE_TO_TRAY.UseVisualStyleBackColor = True
'
'CH_SHOW_NOTIFY
'
Me.CH_SHOW_NOTIFY.AutoSize = True
Me.CH_SHOW_NOTIFY.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_SHOW_NOTIFY.Location = New System.Drawing.Point(4, 318)
Me.CH_SHOW_NOTIFY.Name = "CH_SHOW_NOTIFY"
Me.CH_SHOW_NOTIFY.Size = New System.Drawing.Size(562, 19)
Me.CH_SHOW_NOTIFY.TabIndex = 11
Me.CH_SHOW_NOTIFY.Text = "Show notifications"
Me.CH_SHOW_NOTIFY.UseVisualStyleBackColor = True
'
'CH_FAST_LOAD
'
Me.CH_FAST_LOAD.AutoSize = True
Me.CH_FAST_LOAD.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_FAST_LOAD.Location = New System.Drawing.Point(4, 344)
Me.CH_FAST_LOAD.Location = New System.Drawing.Point(4, 82)
Me.CH_FAST_LOAD.Name = "CH_FAST_LOAD"
Me.CH_FAST_LOAD.Size = New System.Drawing.Size(562, 19)
Me.CH_FAST_LOAD.TabIndex = 12
Me.CH_FAST_LOAD.Size = New System.Drawing.Size(568, 19)
Me.CH_FAST_LOAD.TabIndex = 3
Me.CH_FAST_LOAD.Text = "Fast profiles loading"
TT_MAIN.SetToolTip(Me.CH_FAST_LOAD, "Fast loading of profiles in the main window")
Me.CH_FAST_LOAD.UseVisualStyleBackColor = True
'
'TXT_FOLDER_CMD
'
Me.TXT_FOLDER_CMD.AutoShowClearButton = True
ActionButton7.BackgroundImage = CType(resources.GetObject("ActionButton7.BackgroundImage"), System.Drawing.Image)
ActionButton7.Enabled = False
ActionButton7.Index = 0
ActionButton7.Name = "BTT_CLEAR"
ActionButton7.Visible = False
Me.TXT_FOLDER_CMD.Buttons.Add(ActionButton7)
Me.TXT_FOLDER_CMD.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.CheckBox
Me.TXT_FOLDER_CMD.CaptionText = "Folder cmd"
Me.TXT_FOLDER_CMD.CaptionToolTipEnabled = True
Me.TXT_FOLDER_CMD.CaptionToolTipText = "The command to open a folder."
Me.TXT_FOLDER_CMD.Dock = System.Windows.Forms.DockStyle.Fill
Me.TXT_FOLDER_CMD.LeaveDefaultButtons = True
Me.TXT_FOLDER_CMD.Location = New System.Drawing.Point(4, 370)
Me.TXT_FOLDER_CMD.Name = "TXT_FOLDER_CMD"
Me.TXT_FOLDER_CMD.PlaceholderEnabled = True
Me.TXT_FOLDER_CMD.PlaceholderText = "MyCommand /arg {0}"
Me.TXT_FOLDER_CMD.Size = New System.Drawing.Size(562, 22)
Me.TXT_FOLDER_CMD.TabIndex = 13
'
'CH_RECYCLE_DEL
'
Me.CH_RECYCLE_DEL.AutoSize = True
Me.CH_RECYCLE_DEL.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_RECYCLE_DEL.Location = New System.Drawing.Point(4, 399)
Me.CH_RECYCLE_DEL.Name = "CH_RECYCLE_DEL"
Me.CH_RECYCLE_DEL.Size = New System.Drawing.Size(562, 19)
Me.CH_RECYCLE_DEL.TabIndex = 14
Me.CH_RECYCLE_DEL.Text = "Delete data to recycle bin"
Me.CH_RECYCLE_DEL.UseVisualStyleBackColor = True
'
'CH_COPY_CHANNEL_USER_IMAGE
'
Me.CH_COPY_CHANNEL_USER_IMAGE.AutoSize = True
@@ -599,15 +580,39 @@
'
Me.CH_UDESCR_UP.AutoSize = True
Me.CH_UDESCR_UP.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_UDESCR_UP.Location = New System.Drawing.Point(4, 108)
Me.CH_UDESCR_UP.Location = New System.Drawing.Point(4, 4)
Me.CH_UDESCR_UP.Name = "CH_UDESCR_UP"
Me.CH_UDESCR_UP.Size = New System.Drawing.Size(562, 19)
Me.CH_UDESCR_UP.TabIndex = 4
Me.CH_UDESCR_UP.Size = New System.Drawing.Size(568, 19)
Me.CH_UDESCR_UP.TabIndex = 0
Me.CH_UDESCR_UP.Text = "Update user description every time"
TT_MAIN.SetToolTip(Me.CH_UDESCR_UP, "If the user description does not contain a new user description, then the new one" &
" will be added via a new line")
Me.CH_UDESCR_UP.UseVisualStyleBackColor = True
'
'CH_DOWN_OPEN_INFO_SUSPEND
'
Me.CH_DOWN_OPEN_INFO_SUSPEND.AutoSize = True
Me.CH_DOWN_OPEN_INFO_SUSPEND.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_DOWN_OPEN_INFO_SUSPEND.Location = New System.Drawing.Point(290, 4)
Me.CH_DOWN_OPEN_INFO_SUSPEND.Name = "CH_DOWN_OPEN_INFO_SUSPEND"
Me.CH_DOWN_OPEN_INFO_SUSPEND.Size = New System.Drawing.Size(280, 17)
Me.CH_DOWN_OPEN_INFO_SUSPEND.TabIndex = 1
Me.CH_DOWN_OPEN_INFO_SUSPEND.Text = "Don't open again"
TT_MAIN.SetToolTip(Me.CH_DOWN_OPEN_INFO_SUSPEND, "Do not open the form automatically if it was once closed")
Me.CH_DOWN_OPEN_INFO_SUSPEND.UseVisualStyleBackColor = True
'
'CH_DOWN_OPEN_PROGRESS_SUSPEND
'
Me.CH_DOWN_OPEN_PROGRESS_SUSPEND.AutoSize = True
Me.CH_DOWN_OPEN_PROGRESS_SUSPEND.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_DOWN_OPEN_PROGRESS_SUSPEND.Location = New System.Drawing.Point(290, 4)
Me.CH_DOWN_OPEN_PROGRESS_SUSPEND.Name = "CH_DOWN_OPEN_PROGRESS_SUSPEND"
Me.CH_DOWN_OPEN_PROGRESS_SUSPEND.Size = New System.Drawing.Size(280, 17)
Me.CH_DOWN_OPEN_PROGRESS_SUSPEND.TabIndex = 1
Me.CH_DOWN_OPEN_PROGRESS_SUSPEND.Text = "Don't open again"
TT_MAIN.SetToolTip(Me.CH_DOWN_OPEN_PROGRESS_SUSPEND, "Do not open the form automatically if it was once closed")
Me.CH_DOWN_OPEN_PROGRESS_SUSPEND.UseVisualStyleBackColor = True
'
'TP_CHANNELS_IMGS
'
TP_CHANNELS_IMGS.ColumnCount = 2
@@ -659,7 +664,7 @@
TAB_BASIS.Location = New System.Drawing.Point(4, 22)
TAB_BASIS.Name = "TAB_BASIS"
TAB_BASIS.Padding = New System.Windows.Forms.Padding(3)
TAB_BASIS.Size = New System.Drawing.Size(576, 453)
TAB_BASIS.Size = New System.Drawing.Size(576, 284)
TAB_BASIS.TabIndex = 0
TAB_BASIS.Text = "Basis"
'
@@ -669,7 +674,7 @@
TAB_DEFAULTS.Location = New System.Drawing.Point(4, 22)
TAB_DEFAULTS.Name = "TAB_DEFAULTS"
TAB_DEFAULTS.Padding = New System.Windows.Forms.Padding(3)
TAB_DEFAULTS.Size = New System.Drawing.Size(576, 453)
TAB_DEFAULTS.Size = New System.Drawing.Size(576, 284)
TAB_DEFAULTS.TabIndex = 1
TAB_DEFAULTS.Text = "Defaults"
'
@@ -682,18 +687,17 @@
TP_DEFS.Controls.Add(Me.CH_DOWN_VIDEOS, 0, 3)
TP_DEFS.Controls.Add(Me.CH_DOWN_IMAGES, 0, 2)
TP_DEFS.Controls.Add(Me.CH_DEF_TEMP, 0, 1)
TP_DEFS.Controls.Add(Me.CH_UDESCR_UP, 0, 4)
TP_DEFS.Dock = System.Windows.Forms.DockStyle.Fill
TP_DEFS.Location = New System.Drawing.Point(3, 3)
TP_DEFS.Name = "TP_DEFS"
TP_DEFS.RowCount = 6
TP_DEFS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
TP_DEFS.RowCount = 5
TP_DEFS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
TP_DEFS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
TP_DEFS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
TP_DEFS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
TP_DEFS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_DEFS.Size = New System.Drawing.Size(570, 447)
TP_DEFS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20.0!))
TP_DEFS.Size = New System.Drawing.Size(570, 278)
TP_DEFS.TabIndex = 0
'
'TAB_DEFS_CHANNELS
@@ -702,7 +706,7 @@
TAB_DEFS_CHANNELS.Location = New System.Drawing.Point(4, 22)
TAB_DEFS_CHANNELS.Name = "TAB_DEFS_CHANNELS"
TAB_DEFS_CHANNELS.Padding = New System.Windows.Forms.Padding(3)
TAB_DEFS_CHANNELS.Size = New System.Drawing.Size(576, 453)
TAB_DEFS_CHANNELS.Size = New System.Drawing.Size(576, 284)
TAB_DEFS_CHANNELS.TabIndex = 4
TAB_DEFS_CHANNELS.Text = "Channels"
'
@@ -726,7 +730,7 @@
TP_CHANNELS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
TP_CHANNELS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
TP_CHANNELS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_CHANNELS.Size = New System.Drawing.Size(570, 447)
TP_CHANNELS.Size = New System.Drawing.Size(570, 278)
TP_CHANNELS.TabIndex = 0
'
'TXT_CHANNEL_USER_POST_LIMIT
@@ -749,31 +753,302 @@
Me.TXT_CHANNEL_USER_POST_LIMIT.Text = "1"
Me.TXT_CHANNEL_USER_POST_LIMIT.TextBoxTextAlign = System.Windows.Forms.HorizontalAlignment.Center
'
'TAB_BEHAVIOR
'
TAB_BEHAVIOR.Controls.Add(TP_BEHAVIOR)
TAB_BEHAVIOR.Location = New System.Drawing.Point(4, 22)
TAB_BEHAVIOR.Name = "TAB_BEHAVIOR"
TAB_BEHAVIOR.Size = New System.Drawing.Size(576, 284)
TAB_BEHAVIOR.TabIndex = 5
TAB_BEHAVIOR.Text = "Behavior"
'
'TP_BEHAVIOR
'
TP_BEHAVIOR.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single]
TP_BEHAVIOR.ColumnCount = 1
TP_BEHAVIOR.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_BEHAVIOR.Controls.Add(Me.TXT_FOLDER_CMD, 0, 7)
TP_BEHAVIOR.Controls.Add(Me.CH_EXIT_CONFIRM, 0, 0)
TP_BEHAVIOR.Controls.Add(Me.CH_CLOSE_TO_TRAY, 0, 1)
TP_BEHAVIOR.Controls.Add(Me.CH_SHOW_NOTIFY, 0, 2)
TP_BEHAVIOR.Controls.Add(Me.CH_FAST_LOAD, 0, 3)
TP_BEHAVIOR.Controls.Add(Me.TXT_CLOSE_SCRIPT, 0, 8)
TP_BEHAVIOR.Controls.Add(TP_OPEN_INFO, 0, 5)
TP_BEHAVIOR.Controls.Add(Me.CH_RECYCLE_DEL, 0, 4)
TP_BEHAVIOR.Controls.Add(TP_OPEN_PROGRESS, 0, 6)
TP_BEHAVIOR.Dock = System.Windows.Forms.DockStyle.Fill
TP_BEHAVIOR.Location = New System.Drawing.Point(0, 0)
TP_BEHAVIOR.Name = "TP_BEHAVIOR"
TP_BEHAVIOR.RowCount = 11
TP_BEHAVIOR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
TP_BEHAVIOR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
TP_BEHAVIOR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
TP_BEHAVIOR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
TP_BEHAVIOR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
TP_BEHAVIOR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
TP_BEHAVIOR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
TP_BEHAVIOR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
TP_BEHAVIOR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
TP_BEHAVIOR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
TP_BEHAVIOR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_BEHAVIOR.Size = New System.Drawing.Size(576, 284)
TP_BEHAVIOR.TabIndex = 0
'
'TXT_FOLDER_CMD
'
Me.TXT_FOLDER_CMD.AutoShowClearButton = True
ActionButton7.BackgroundImage = CType(resources.GetObject("ActionButton7.BackgroundImage"), System.Drawing.Image)
ActionButton7.Enabled = False
ActionButton7.Index = 0
ActionButton7.Name = "BTT_CLEAR"
ActionButton7.Visible = False
Me.TXT_FOLDER_CMD.Buttons.Add(ActionButton7)
Me.TXT_FOLDER_CMD.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.CheckBox
Me.TXT_FOLDER_CMD.CaptionText = "Folder cmd"
Me.TXT_FOLDER_CMD.CaptionToolTipEnabled = True
Me.TXT_FOLDER_CMD.CaptionToolTipText = "The command to open a folder."
Me.TXT_FOLDER_CMD.Dock = System.Windows.Forms.DockStyle.Fill
Me.TXT_FOLDER_CMD.LeaveDefaultButtons = True
Me.TXT_FOLDER_CMD.Location = New System.Drawing.Point(4, 186)
Me.TXT_FOLDER_CMD.Name = "TXT_FOLDER_CMD"
Me.TXT_FOLDER_CMD.PlaceholderEnabled = True
Me.TXT_FOLDER_CMD.PlaceholderText = "MyCommand /arg {0}"
Me.TXT_FOLDER_CMD.Size = New System.Drawing.Size(568, 22)
Me.TXT_FOLDER_CMD.TabIndex = 7
'
'CH_EXIT_CONFIRM
'
Me.CH_EXIT_CONFIRM.AutoSize = True
Me.CH_EXIT_CONFIRM.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_EXIT_CONFIRM.Location = New System.Drawing.Point(4, 4)
Me.CH_EXIT_CONFIRM.Name = "CH_EXIT_CONFIRM"
Me.CH_EXIT_CONFIRM.Size = New System.Drawing.Size(568, 19)
Me.CH_EXIT_CONFIRM.TabIndex = 0
Me.CH_EXIT_CONFIRM.Text = "Exit confirm"
Me.CH_EXIT_CONFIRM.UseVisualStyleBackColor = True
'
'CH_CLOSE_TO_TRAY
'
Me.CH_CLOSE_TO_TRAY.AutoSize = True
Me.CH_CLOSE_TO_TRAY.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_CLOSE_TO_TRAY.Location = New System.Drawing.Point(4, 30)
Me.CH_CLOSE_TO_TRAY.Name = "CH_CLOSE_TO_TRAY"
Me.CH_CLOSE_TO_TRAY.Size = New System.Drawing.Size(568, 19)
Me.CH_CLOSE_TO_TRAY.TabIndex = 1
Me.CH_CLOSE_TO_TRAY.Text = "Close to tray"
Me.CH_CLOSE_TO_TRAY.UseVisualStyleBackColor = True
'
'CH_SHOW_NOTIFY
'
Me.CH_SHOW_NOTIFY.AutoSize = True
Me.CH_SHOW_NOTIFY.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_SHOW_NOTIFY.Location = New System.Drawing.Point(4, 56)
Me.CH_SHOW_NOTIFY.Name = "CH_SHOW_NOTIFY"
Me.CH_SHOW_NOTIFY.Size = New System.Drawing.Size(568, 19)
Me.CH_SHOW_NOTIFY.TabIndex = 2
Me.CH_SHOW_NOTIFY.Text = "Show notifications"
Me.CH_SHOW_NOTIFY.UseVisualStyleBackColor = True
'
'TXT_CLOSE_SCRIPT
'
Me.TXT_CLOSE_SCRIPT.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.CheckBox
Me.TXT_CLOSE_SCRIPT.CaptionText = "Close cmd"
Me.TXT_CLOSE_SCRIPT.CaptionToolTipEnabled = True
Me.TXT_CLOSE_SCRIPT.CaptionToolTipText = "This command will be executed when SCrawler is closed"
Me.TXT_CLOSE_SCRIPT.Dock = System.Windows.Forms.DockStyle.Fill
Me.TXT_CLOSE_SCRIPT.Location = New System.Drawing.Point(4, 215)
Me.TXT_CLOSE_SCRIPT.Name = "TXT_CLOSE_SCRIPT"
Me.TXT_CLOSE_SCRIPT.PlaceholderEnabled = True
Me.TXT_CLOSE_SCRIPT.PlaceholderText = "Enter command here..."
Me.TXT_CLOSE_SCRIPT.Size = New System.Drawing.Size(568, 22)
Me.TXT_CLOSE_SCRIPT.TabIndex = 8
'
'TP_OPEN_INFO
'
TP_OPEN_INFO.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single]
TP_OPEN_INFO.ColumnCount = 2
TP_OPEN_INFO.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
TP_OPEN_INFO.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
TP_OPEN_INFO.Controls.Add(Me.CH_DOWN_OPEN_INFO, 0, 0)
TP_OPEN_INFO.Controls.Add(Me.CH_DOWN_OPEN_INFO_SUSPEND, 1, 0)
TP_OPEN_INFO.Dock = System.Windows.Forms.DockStyle.Fill
TP_OPEN_INFO.Location = New System.Drawing.Point(1, 131)
TP_OPEN_INFO.Margin = New System.Windows.Forms.Padding(0)
TP_OPEN_INFO.Name = "TP_OPEN_INFO"
TP_OPEN_INFO.RowCount = 1
TP_OPEN_INFO.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_OPEN_INFO.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 24.0!))
TP_OPEN_INFO.Size = New System.Drawing.Size(574, 25)
TP_OPEN_INFO.TabIndex = 5
'
'CH_DOWN_OPEN_INFO
'
Me.CH_DOWN_OPEN_INFO.AutoSize = True
Me.CH_DOWN_OPEN_INFO.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_DOWN_OPEN_INFO.Location = New System.Drawing.Point(4, 4)
Me.CH_DOWN_OPEN_INFO.Name = "CH_DOWN_OPEN_INFO"
Me.CH_DOWN_OPEN_INFO.Size = New System.Drawing.Size(279, 17)
Me.CH_DOWN_OPEN_INFO.TabIndex = 0
Me.CH_DOWN_OPEN_INFO.Text = "Open the 'Info' form when the download starts"
Me.CH_DOWN_OPEN_INFO.UseVisualStyleBackColor = True
'
'CH_RECYCLE_DEL
'
Me.CH_RECYCLE_DEL.AutoSize = True
Me.CH_RECYCLE_DEL.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_RECYCLE_DEL.Location = New System.Drawing.Point(4, 108)
Me.CH_RECYCLE_DEL.Name = "CH_RECYCLE_DEL"
Me.CH_RECYCLE_DEL.Size = New System.Drawing.Size(568, 19)
Me.CH_RECYCLE_DEL.TabIndex = 4
Me.CH_RECYCLE_DEL.Text = "Delete data to recycle bin"
Me.CH_RECYCLE_DEL.UseVisualStyleBackColor = True
'
'TP_OPEN_PROGRESS
'
TP_OPEN_PROGRESS.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single]
TP_OPEN_PROGRESS.ColumnCount = 2
TP_OPEN_PROGRESS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
TP_OPEN_PROGRESS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
TP_OPEN_PROGRESS.Controls.Add(Me.CH_DOWN_OPEN_PROGRESS, 0, 0)
TP_OPEN_PROGRESS.Controls.Add(Me.CH_DOWN_OPEN_PROGRESS_SUSPEND, 1, 0)
TP_OPEN_PROGRESS.Dock = System.Windows.Forms.DockStyle.Fill
TP_OPEN_PROGRESS.Location = New System.Drawing.Point(1, 157)
TP_OPEN_PROGRESS.Margin = New System.Windows.Forms.Padding(0)
TP_OPEN_PROGRESS.Name = "TP_OPEN_PROGRESS"
TP_OPEN_PROGRESS.RowCount = 1
TP_OPEN_PROGRESS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_OPEN_PROGRESS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 24.0!))
TP_OPEN_PROGRESS.Size = New System.Drawing.Size(574, 25)
TP_OPEN_PROGRESS.TabIndex = 6
'
'CH_DOWN_OPEN_PROGRESS
'
Me.CH_DOWN_OPEN_PROGRESS.AutoSize = True
Me.CH_DOWN_OPEN_PROGRESS.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_DOWN_OPEN_PROGRESS.Location = New System.Drawing.Point(4, 4)
Me.CH_DOWN_OPEN_PROGRESS.Name = "CH_DOWN_OPEN_PROGRESS"
Me.CH_DOWN_OPEN_PROGRESS.Size = New System.Drawing.Size(279, 17)
Me.CH_DOWN_OPEN_PROGRESS.TabIndex = 0
Me.CH_DOWN_OPEN_PROGRESS.Text = "Open the 'Progress' form when the download starts"
Me.CH_DOWN_OPEN_PROGRESS.UseVisualStyleBackColor = True
'
'TAB_DOWN
'
TAB_DOWN.Controls.Add(TP_DOWNLOADING)
TAB_DOWN.Location = New System.Drawing.Point(4, 22)
TAB_DOWN.Name = "TAB_DOWN"
TAB_DOWN.Size = New System.Drawing.Size(576, 284)
TAB_DOWN.TabIndex = 6
TAB_DOWN.Text = "Downloading"
'
'TP_DOWNLOADING
'
TP_DOWNLOADING.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single]
TP_DOWNLOADING.ColumnCount = 1
TP_DOWNLOADING.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_DOWNLOADING.Controls.Add(TP_FILE_NAME, 0, 1)
TP_DOWNLOADING.Controls.Add(TP_FILE_PATTERNS, 0, 2)
TP_DOWNLOADING.Controls.Add(Me.TXT_SCRIPT, 0, 3)
TP_DOWNLOADING.Controls.Add(Me.CH_UDESCR_UP, 0, 0)
TP_DOWNLOADING.Controls.Add(Me.TXT_DOWN_COMPLETE_SCRIPT, 0, 4)
TP_DOWNLOADING.Dock = System.Windows.Forms.DockStyle.Fill
TP_DOWNLOADING.Location = New System.Drawing.Point(0, 0)
TP_DOWNLOADING.Name = "TP_DOWNLOADING"
TP_DOWNLOADING.RowCount = 6
TP_DOWNLOADING.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
TP_DOWNLOADING.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30.0!))
TP_DOWNLOADING.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30.0!))
TP_DOWNLOADING.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
TP_DOWNLOADING.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
TP_DOWNLOADING.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_DOWNLOADING.Size = New System.Drawing.Size(576, 284)
TP_DOWNLOADING.TabIndex = 0
'
'TXT_SCRIPT
'
ActionButton8.BackgroundImage = CType(resources.GetObject("ActionButton8.BackgroundImage"), System.Drawing.Image)
ActionButton8.Index = 0
ActionButton8.Name = "BTT_OPEN"
ActionButton9.BackgroundImage = CType(resources.GetObject("ActionButton9.BackgroundImage"), System.Drawing.Image)
ActionButton9.Index = 1
ActionButton9.Name = "BTT_CLEAR"
Me.TXT_SCRIPT.Buttons.Add(ActionButton8)
Me.TXT_SCRIPT.Buttons.Add(ActionButton9)
Me.TXT_SCRIPT.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.CheckBox
Me.TXT_SCRIPT.CaptionText = "Script"
Me.TXT_SCRIPT.CaptionToolTipEnabled = True
Me.TXT_SCRIPT.CaptionToolTipText = "Default script. If the checkbox is checked, newly created users will be created u" &
"sing the script option."
Me.TXT_SCRIPT.ChangeControlsEnableOnCheckedChange = False
Me.TXT_SCRIPT.Dock = System.Windows.Forms.DockStyle.Fill
Me.TXT_SCRIPT.Location = New System.Drawing.Point(4, 92)
Me.TXT_SCRIPT.Name = "TXT_SCRIPT"
Me.TXT_SCRIPT.PlaceholderEnabled = True
Me.TXT_SCRIPT.PlaceholderText = "Enter script path here..."
Me.TXT_SCRIPT.Size = New System.Drawing.Size(568, 22)
Me.TXT_SCRIPT.TabIndex = 3
'
'TXT_DOWN_COMPLETE_SCRIPT
'
Me.TXT_DOWN_COMPLETE_SCRIPT.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.CheckBox
Me.TXT_DOWN_COMPLETE_SCRIPT.CaptionText = "After download cmd"
Me.TXT_DOWN_COMPLETE_SCRIPT.CaptionToolTipEnabled = True
Me.TXT_DOWN_COMPLETE_SCRIPT.CaptionToolTipText = "This command will be executed after all downloads are completed"
Me.TXT_DOWN_COMPLETE_SCRIPT.CaptionWidth = 120.0R
Me.TXT_DOWN_COMPLETE_SCRIPT.Dock = System.Windows.Forms.DockStyle.Fill
Me.TXT_DOWN_COMPLETE_SCRIPT.Location = New System.Drawing.Point(4, 121)
Me.TXT_DOWN_COMPLETE_SCRIPT.Name = "TXT_DOWN_COMPLETE_SCRIPT"
Me.TXT_DOWN_COMPLETE_SCRIPT.PlaceholderEnabled = True
Me.TXT_DOWN_COMPLETE_SCRIPT.PlaceholderText = "Enter command here..."
Me.TXT_DOWN_COMPLETE_SCRIPT.Size = New System.Drawing.Size(568, 22)
Me.TXT_DOWN_COMPLETE_SCRIPT.TabIndex = 4
'
'TAB_MAIN
'
Me.TAB_MAIN.Controls.Add(TAB_BASIS)
Me.TAB_MAIN.Controls.Add(TAB_BEHAVIOR)
Me.TAB_MAIN.Controls.Add(TAB_DEFAULTS)
Me.TAB_MAIN.Controls.Add(TAB_DOWN)
Me.TAB_MAIN.Controls.Add(Me.TAB_AUTO)
Me.TAB_MAIN.Controls.Add(TAB_DEFS_CHANNELS)
Me.TAB_MAIN.Dock = System.Windows.Forms.DockStyle.Fill
Me.TAB_MAIN.Location = New System.Drawing.Point(0, 0)
Me.TAB_MAIN.Name = "TAB_MAIN"
Me.TAB_MAIN.SelectedIndex = 0
Me.TAB_MAIN.Size = New System.Drawing.Size(584, 479)
Me.TAB_MAIN.Size = New System.Drawing.Size(584, 310)
Me.TAB_MAIN.TabIndex = 1
'
'TAB_AUTO
'
Me.TAB_AUTO.Controls.Add(Me.PANEL_AUTO)
Me.TAB_AUTO.Location = New System.Drawing.Point(4, 22)
Me.TAB_AUTO.Name = "TAB_AUTO"
Me.TAB_AUTO.Size = New System.Drawing.Size(576, 284)
Me.TAB_AUTO.TabIndex = 7
Me.TAB_AUTO.Text = "Automation"
'
'PANEL_AUTO
'
Me.PANEL_AUTO.AutoSize = True
Me.PANEL_AUTO.Dock = System.Windows.Forms.DockStyle.Fill
Me.PANEL_AUTO.Location = New System.Drawing.Point(0, 0)
Me.PANEL_AUTO.Name = "PANEL_AUTO"
Me.PANEL_AUTO.Size = New System.Drawing.Size(576, 284)
Me.PANEL_AUTO.TabIndex = 0
'
'CONTAINER_MAIN
'
'
'CONTAINER_MAIN.ContentPanel
'
Me.CONTAINER_MAIN.ContentPanel.Controls.Add(Me.TAB_MAIN)
Me.CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(584, 479)
Me.CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(584, 310)
Me.CONTAINER_MAIN.Dock = System.Windows.Forms.DockStyle.Fill
Me.CONTAINER_MAIN.LeftToolStripPanelVisible = False
Me.CONTAINER_MAIN.Location = New System.Drawing.Point(0, 0)
Me.CONTAINER_MAIN.Name = "CONTAINER_MAIN"
Me.CONTAINER_MAIN.RightToolStripPanelVisible = False
Me.CONTAINER_MAIN.Size = New System.Drawing.Size(584, 479)
Me.CONTAINER_MAIN.Size = New System.Drawing.Size(584, 310)
Me.CONTAINER_MAIN.TabIndex = 0
Me.CONTAINER_MAIN.TopToolStripPanelVisible = False
'
@@ -781,15 +1056,15 @@
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(584, 479)
Me.ClientSize = New System.Drawing.Size(584, 310)
Me.Controls.Add(Me.CONTAINER_MAIN)
Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle
Me.Icon = CType(resources.GetObject("$this.Icon"), System.Drawing.Icon)
Me.KeyPreview = True
Me.MaximizeBox = False
Me.MaximumSize = New System.Drawing.Size(600, 518)
Me.MaximumSize = New System.Drawing.Size(600, 349)
Me.MinimizeBox = False
Me.MinimumSize = New System.Drawing.Size(600, 518)
Me.MinimumSize = New System.Drawing.Size(600, 349)
Me.Name = "GlobalSettingsForm"
Me.ShowInTaskbar = False
Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide
@@ -808,7 +1083,6 @@
TP_FILE_NAME.PerformLayout()
TP_FILE_PATTERNS.ResumeLayout(False)
TP_FILE_PATTERNS.PerformLayout()
CType(Me.TXT_FOLDER_CMD, System.ComponentModel.ISupportInitialize).EndInit()
TP_CHANNELS_IMGS.ResumeLayout(False)
CType(Me.TXT_CHANNELS_ROWS, System.ComponentModel.ISupportInitialize).EndInit()
CType(Me.TXT_CHANNELS_COLUMNS, System.ComponentModel.ISupportInitialize).EndInit()
@@ -820,7 +1094,23 @@
TP_CHANNELS.ResumeLayout(False)
TP_CHANNELS.PerformLayout()
CType(Me.TXT_CHANNEL_USER_POST_LIMIT, System.ComponentModel.ISupportInitialize).EndInit()
TAB_BEHAVIOR.ResumeLayout(False)
TP_BEHAVIOR.ResumeLayout(False)
TP_BEHAVIOR.PerformLayout()
CType(Me.TXT_FOLDER_CMD, System.ComponentModel.ISupportInitialize).EndInit()
CType(Me.TXT_CLOSE_SCRIPT, System.ComponentModel.ISupportInitialize).EndInit()
TP_OPEN_INFO.ResumeLayout(False)
TP_OPEN_INFO.PerformLayout()
TP_OPEN_PROGRESS.ResumeLayout(False)
TP_OPEN_PROGRESS.PerformLayout()
TAB_DOWN.ResumeLayout(False)
TP_DOWNLOADING.ResumeLayout(False)
TP_DOWNLOADING.PerformLayout()
CType(Me.TXT_SCRIPT, System.ComponentModel.ISupportInitialize).EndInit()
CType(Me.TXT_DOWN_COMPLETE_SCRIPT, System.ComponentModel.ISupportInitialize).EndInit()
Me.TAB_MAIN.ResumeLayout(False)
Me.TAB_AUTO.ResumeLayout(False)
Me.TAB_AUTO.PerformLayout()
Me.CONTAINER_MAIN.ContentPanel.ResumeLayout(False)
Me.CONTAINER_MAIN.ResumeLayout(False)
Me.CONTAINER_MAIN.PerformLayout()
@@ -862,5 +1152,16 @@
Private WithEvents CH_FAST_LOAD As CheckBox
Private WithEvents TXT_FOLDER_CMD As PersonalUtilities.Forms.Controls.TextBoxExtended
Private WithEvents CH_RECYCLE_DEL As CheckBox
Private WithEvents TXT_SCRIPT As PersonalUtilities.Forms.Controls.TextBoxExtended
Private WithEvents CH_SHOW_GROUPS As CheckBox
Private WithEvents CH_USERS_GROUPING As CheckBox
Private WithEvents CH_DOWN_OPEN_INFO As CheckBox
Private WithEvents CH_DOWN_OPEN_PROGRESS As CheckBox
Private WithEvents TXT_CLOSE_SCRIPT As PersonalUtilities.Forms.Controls.TextBoxExtended
Private WithEvents TXT_DOWN_COMPLETE_SCRIPT As PersonalUtilities.Forms.Controls.TextBoxExtended
Private WithEvents CH_DOWN_OPEN_INFO_SUSPEND As CheckBox
Private WithEvents CH_DOWN_OPEN_PROGRESS_SUSPEND As CheckBox
Private WithEvents TAB_AUTO As TabPage
Private WithEvents PANEL_AUTO As Panel
End Class
End Namespace

View File

@@ -191,6 +191,12 @@
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
</value>
</data>
<metadata name="TT_MAIN.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="TT_MAIN.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="TP_FILE_NAME.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
@@ -200,20 +206,6 @@
<metadata name="LBL_DATE_POS.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="TT_MAIN.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="TT_MAIN.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<data name="ActionButton7.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
</value>
</data>
<data name="CH_SEPARATE_VIDEO_FOLDER.ToolTip" xml:space="preserve">
<value>This is a global setting for newly added users only.
This parameter specifies how the video will be stored in the users' download path.
@@ -237,6 +229,51 @@ If checked, videos will be stored in separate folder; otherwise, videos will be
<metadata name="TP_CHANNELS.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="TAB_BEHAVIOR.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="TP_BEHAVIOR.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<data name="ActionButton7.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
</value>
</data>
<metadata name="TP_OPEN_INFO.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="TP_OPEN_PROGRESS.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="TAB_DOWN.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="TP_DOWNLOADING.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<data name="ActionButton8.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
wwAADsMBx2+oZAAAAR5JREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbGujg3ZATZPKYdC6FQhPwlAMkg3dP
WQwhyWIyJIUW5NqyPb7oCVtIlhVTwYf8nv7/t2zJagel9KmqKsIACYL9RjI8UHz5zshougZr/AEvbxEP
aZCDBY3VslixaJvX3wzkkDiOwbZtDRGA5vdNAg+TL27qgmt5XkBG/gTdAG7Gt+3PP9oOaEGFCVEC6rp+
5g9MfM/c5e4OsEZMZkQEtGL5H2DdZ5JRArDwPA+iKII0TfkC9vroC9j5vq8JTWw3WzWgLMtZGIaa0MR8
vlAD8PYlSaIJTTiOowY0p0Bc19XEJo6HE59FAPuMzyAINKGJ1XLFZxHALtMrnkBXOIQIIIQ8YvF/KrgB
cMaRN0UdBBkAAAAASUVORK5CYII=
</value>
</data>
<data name="ActionButton9.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
</value>
</data>
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAA8AAAAQAAEABAAwOgAA9gAAADAwEAABAAQAaAYAACg7AAAgIBAAAQAEAOgCAACQQQAAGBgQAAEA

View File

@@ -11,10 +11,19 @@ Imports PersonalUtilities.Forms.Controls.Base
Imports PersonalUtilities.Forms.Toolbars
Namespace Editors
Friend Class GlobalSettingsForm : Implements IOkCancelToolbar
Private ReadOnly MyDefs As DefaultFormProps(Of FieldsChecker)
Private ReadOnly MyDefs As DefaultFormProps
Private ReadOnly Automation As DownloadObjects.AutoDownloaderEditorForm
Friend Sub New()
InitializeComponent()
MyDefs = New DefaultFormProps(Of FieldsChecker)
MyDefs = New DefaultFormProps
Automation = New DownloadObjects.AutoDownloaderEditorForm With {
.MaximumSize = New Size(0, 0),
.MinimumSize = New Size(0, 0),
.Dock = DockStyle.Fill,
.FormBorderStyle = FormBorderStyle.None,
.TopLevel = False,
.IsControlForm = True
}
End Sub
Private Sub GlobalSettingsForm_Load(sender As Object, e As EventArgs) Handles Me.Load
Try
@@ -32,16 +41,41 @@ Namespace Editors
TXT_MAX_JOBS_CHANNELS.Value = .ChannelsMaxJobsCount.Value
CH_CHECK_VER_START.Checked = .CheckUpdatesAtStart
TXT_IMGUR_CLIENT_ID.Text = .ImgurClientID
CH_SHOW_GROUPS.Checked = .ShowGroups
CH_USERS_GROUPING.Checked = .UseGrouping
'Behavior
CH_EXIT_CONFIRM.Checked = .ExitConfirm
CH_CLOSE_TO_TRAY.Checked = .CloseToTray
CH_SHOW_NOTIFY.Checked = .ShowNotifications
CH_FAST_LOAD.Checked = .FastProfilesLoading
CH_RECYCLE_DEL.Checked = .DeleteToRecycleBin
CH_DOWN_OPEN_INFO.Checked = .DownloadOpenInfo
CH_DOWN_OPEN_INFO_SUSPEND.Checked = Not .DownloadOpenInfo.Attribute
CH_DOWN_OPEN_PROGRESS.Checked = .DownloadOpenProgress
CH_DOWN_OPEN_PROGRESS_SUSPEND.Checked = Not .DownloadOpenProgress.Attribute
TXT_FOLDER_CMD.Text = .OpenFolderInOtherProgram
TXT_FOLDER_CMD.Checked = .OpenFolderInOtherProgram.Attribute
CH_RECYCLE_DEL.Checked = .DeleteToRecycleBin
TXT_CLOSE_SCRIPT.Text = .ClosingCommand
TXT_CLOSE_SCRIPT.Checked = .ClosingCommand.Attribute
'Defaults
CH_SEPARATE_VIDEO_FOLDER.Checked = .SeparateVideoFolder.Value
CH_DEF_TEMP.Checked = .DefaultTemporary
CH_DOWN_IMAGES.Checked = .DefaultDownloadImages
CH_DOWN_VIDEOS.Checked = .DefaultDownloadVideos
'Downloading
CH_UDESCR_UP.Checked = .UpdateUserDescriptionEveryTime
TXT_SCRIPT.Checked = .ScriptData.Attribute
TXT_SCRIPT.Text = .ScriptData.Value
TXT_DOWN_COMPLETE_SCRIPT.Text = .DownloadsCompleteCommand
TXT_DOWN_COMPLETE_SCRIPT.Checked = .DownloadsCompleteCommand.Attribute
'Downloading: file names
CH_FILE_NAME_CHANGE.Checked = .FileReplaceNameByDate Or .FileAddDateToFileName Or .FileAddTimeToFileName
OPT_FILE_NAME_REPLACE.Checked = .FileReplaceNameByDate
OPT_FILE_NAME_ADD_DATE.Checked = Not .FileReplaceNameByDate
CH_FILE_DATE.Checked = .FileAddDateToFileName
CH_FILE_TIME.Checked = .FileAddTimeToFileName
OPT_FILE_DATE_START.Checked = Not .FileDateTimePositionEnd
OPT_FILE_DATE_END.Checked = .FileDateTimePositionEnd
'Channels
TXT_CHANNELS_ROWS.Value = .ChannelsImagesRows.Value
TXT_CHANNELS_COLUMNS.Value = .ChannelsImagesColumns.Value
@@ -51,23 +85,15 @@ Namespace Editors
CH_COPY_CHANNEL_USER_IMAGE_ALL.Checked = .ChannelsAddUserImagesFromAllChannels
CH_COPY_CHANNEL_USER_IMAGE_ALL.Enabled = CH_COPY_CHANNEL_USER_IMAGE.Checked
CH_CHANNELS_USERS_TEMP.Checked = .ChannelsDefaultTemporary
'Channels filenames
CH_FILE_NAME_CHANGE.Checked = .FileReplaceNameByDate Or .FileAddDateToFileName Or .FileAddTimeToFileName
OPT_FILE_NAME_REPLACE.Checked = .FileReplaceNameByDate
OPT_FILE_NAME_ADD_DATE.Checked = Not .FileReplaceNameByDate
CH_FILE_DATE.Checked = .FileAddDateToFileName
CH_FILE_TIME.Checked = .FileAddTimeToFileName
OPT_FILE_DATE_START.Checked = Not .FileDateTimePositionEnd
OPT_FILE_DATE_END.Checked = .FileDateTimePositionEnd
'Other program settings
CH_EXIT_CONFIRM.Checked = .ExitConfirm
CH_CLOSE_TO_TRAY.Checked = .CloseToTray
CH_SHOW_NOTIFY.Checked = .ShowNotifications
End With
PANEL_AUTO.Controls.Add(Automation)
Automation.Show()
.MyFieldsChecker = New FieldsChecker
With .MyFieldsChecker
With DirectCast(.MyFieldsChecker, FieldsChecker)
.AddControl(Of String)(TXT_GLOBAL_PATH, TXT_GLOBAL_PATH.CaptionText)
.AddControl(Of String)(TXT_COLLECTIONS_PATH, TXT_COLLECTIONS_PATH.CaptionText)
.AddControl(Of Integer)(Automation.TXT_TIMER, Automation.TXT_TIMER.CaptionText,,
New DownloadObjects.AutoDownloaderEditorForm.AutomationTimerChecker)
.EndLoaderOperations()
End With
.AppendDetectors()
@@ -78,7 +104,10 @@ Namespace Editors
MyDefs.InvokeLoaderError(ex)
End Try
End Sub
Private Sub ToolbarBttOK() Implements IOkCancelToolbar.ToolbarBttOK
Private Sub GlobalSettingsForm_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed
Automation.Dispose()
End Sub
Private Sub OK() Implements IOkCancelToolbar.OK
If MyDefs.MyFieldsChecker.AllParamsOK Then
With Settings
Dim a As Func(Of String, Object, Integer) =
@@ -119,29 +148,34 @@ Namespace Editors
.ChannelsMaxJobsCount.Value = TXT_MAX_JOBS_CHANNELS.Value
.CheckUpdatesAtStart.Value = CH_CHECK_VER_START.Checked
.ImgurClientID.Value = TXT_IMGUR_CLIENT_ID.Text
.ShowGroups.Value = CH_SHOW_GROUPS.Checked
.UseGrouping.Value = CH_USERS_GROUPING.Checked
'Behavior
.ExitConfirm.Value = CH_EXIT_CONFIRM.Checked
.CloseToTray.Value = CH_CLOSE_TO_TRAY.Checked
.ShowNotifications.Value = CH_SHOW_NOTIFY.Checked
.FastProfilesLoading.Value = CH_FAST_LOAD.Checked
.DeleteToRecycleBin.Value = CH_RECYCLE_DEL.Checked
.DownloadOpenInfo.Value = CH_DOWN_OPEN_INFO.Checked
.DownloadOpenInfo.Attribute.Value = Not CH_DOWN_OPEN_INFO_SUSPEND.Checked
.DownloadOpenProgress.Value = CH_DOWN_OPEN_PROGRESS.Checked
.DownloadOpenProgress.Attribute.Value = Not CH_DOWN_OPEN_PROGRESS_SUSPEND.Checked
.OpenFolderInOtherProgram.Value = TXT_FOLDER_CMD.Text
.OpenFolderInOtherProgram.Attribute.Value = TXT_FOLDER_CMD.Checked
.DeleteToRecycleBin.Value = CH_RECYCLE_DEL.Checked
.ClosingCommand.Value = TXT_CLOSE_SCRIPT.Text
.ClosingCommand.Attribute.Value = TXT_CLOSE_SCRIPT.Checked
'Defaults
.SeparateVideoFolder.Value = CH_SEPARATE_VIDEO_FOLDER.Checked
.DefaultTemporary.Value = CH_DEF_TEMP.Checked
.DefaultDownloadImages.Value = CH_DOWN_IMAGES.Checked
.DefaultDownloadVideos.Value = CH_DOWN_VIDEOS.Checked
'Downloading
.UpdateUserDescriptionEveryTime.Value = CH_UDESCR_UP.Checked
'Channels
.ChannelsImagesRows.Value = CInt(TXT_CHANNELS_ROWS.Value)
.ChannelsImagesColumns.Value = CInt(TXT_CHANNELS_COLUMNS.Value)
.FromChannelDownloadTop.Value = CInt(TXT_CHANNEL_USER_POST_LIMIT.Value)
.FromChannelDownloadTopUse.Value = TXT_CHANNEL_USER_POST_LIMIT.Checked
.FromChannelCopyImageToUser.Value = CH_COPY_CHANNEL_USER_IMAGE.Checked
.ChannelsAddUserImagesFromAllChannels.Value = CH_COPY_CHANNEL_USER_IMAGE_ALL.Checked
.ChannelsDefaultTemporary.Value = CH_CHANNELS_USERS_TEMP.Checked
'Other program settings
.ExitConfirm.Value = CH_EXIT_CONFIRM.Checked
.CloseToTray.Value = CH_CLOSE_TO_TRAY.Checked
.ShowNotifications.Value = CH_SHOW_NOTIFY.Checked
.ScriptData.Value = TXT_SCRIPT.Text
.ScriptData.Attribute.Value = TXT_SCRIPT.Checked
.DownloadsCompleteCommand.Value = TXT_DOWN_COMPLETE_SCRIPT.Text
.DownloadsCompleteCommand.Attribute.Value = TXT_DOWN_COMPLETE_SCRIPT.Checked
'Downloading: file names
If CH_FILE_NAME_CHANGE.Checked Then
.FileReplaceNameByDate.Value = OPT_FILE_NAME_REPLACE.Checked
.FileAddDateToFileName.Value = CH_FILE_DATE.Checked
@@ -152,13 +186,23 @@ Namespace Editors
.FileAddTimeToFileName.Value = False
.FileReplaceNameByDate.Value = False
End If
'Channels
.ChannelsImagesRows.Value = CInt(TXT_CHANNELS_ROWS.Value)
.ChannelsImagesColumns.Value = CInt(TXT_CHANNELS_COLUMNS.Value)
.FromChannelDownloadTop.Value = CInt(TXT_CHANNEL_USER_POST_LIMIT.Value)
.FromChannelDownloadTopUse.Value = TXT_CHANNEL_USER_POST_LIMIT.Checked
.FromChannelCopyImageToUser.Value = CH_COPY_CHANNEL_USER_IMAGE.Checked
.ChannelsAddUserImagesFromAllChannels.Value = CH_COPY_CHANNEL_USER_IMAGE_ALL.Checked
.ChannelsDefaultTemporary.Value = CH_CHANNELS_USERS_TEMP.Checked
Automation.SaveSettings()
.EndUpdate()
End With
MyDefs.CloseForm()
End If
End Sub
Private Sub ToolbarBttCancel() Implements IOkCancelToolbar.ToolbarBttCancel
Private Sub Cancel() Implements IOkCancelToolbar.Cancel
MyDefs.CloseForm(DialogResult.Cancel)
End Sub
Private Sub TXT_GLOBAL_PATH_ActionOnButtonClick(ByVal Sender As ActionButton) Handles TXT_GLOBAL_PATH.ActionOnButtonClick
@@ -195,6 +239,9 @@ Namespace Editors
CH_FILE_TIME.Enabled = b
ChangePositionControlsEnabling()
End Sub
Private Sub TXT_SCRIPT_ActionOnButtonClick(ByVal Sender As ActionButton) Handles TXT_SCRIPT.ActionOnButtonClick
SettingsCLS.ScriptTextBoxButtonClick(TXT_SCRIPT, Sender)
End Sub
Private Sub CH_COPY_CHANNEL_USER_IMAGE_CheckedChanged(sender As Object, e As EventArgs) Handles CH_COPY_CHANNEL_USER_IMAGE.CheckedChanged
CH_COPY_CHANNEL_USER_IMAGE_ALL.Enabled = CH_COPY_CHANNEL_USER_IMAGE.Checked
End Sub

View File

@@ -11,31 +11,47 @@ Imports PersonalUtilities.Forms.Toolbars
Imports PersonalUtilities.Forms.Controls
Imports PersonalUtilities.Forms.Controls.Base
Imports PersonalUtilities.Functions.Messaging
Friend Class LabelsForm : Implements IOkCancelToolbar
Friend Class LabelsForm : Implements IOkCancelDeleteToolbar
Private ReadOnly MyDefs As DefaultFormProps
Friend ReadOnly Property LabelsList As List(Of String)
Private ReadOnly _Source As IEnumerable(Of String) = Nothing
Private ReadOnly Property Source As IEnumerable(Of String)
Get
If Not _Source Is Nothing Then
Return _Source
Else
Return Settings.Labels
End If
End Get
End Property
Private _AnyLabelAdd As Boolean = False
Friend Property MultiUser As Boolean = False
Public Property MultiUserClearExists As Boolean = False
Friend Property MultiUserClearExists As Boolean = False
Friend Property WithDeleteButton As Boolean = False
Friend Sub New(ByVal LabelsArr As IEnumerable(Of String))
InitializeComponent()
LabelsList = New List(Of String)
LabelsList.ListAddList(LabelsArr)
MyDefs = New DefaultFormProps
End Sub
Friend Sub New(ByVal Current As IEnumerable(Of String), ByVal Source As IEnumerable(Of String))
Me.New(Current)
_Source = Source
End Sub
Private Sub LabelsForm_Load(sender As Object, e As EventArgs) Handles Me.Load
Try
With MyDefs
.MyViewInitialize(Me, Settings.Design)
.AddOkCancelToolbar()
.AddOkCancelToolbar(, WithDeleteButton)
.DelegateClosingChecker()
If Settings.Labels.Count > 0 Then
If Source.Count > 0 Then
Dim items As New List(Of Integer)
CMB_LABELS.BeginUpdate()
For i% = 0 To Settings.Labels.Count - 1
If LabelsList.Contains(Settings.Labels(i)) Then items.Add(i)
CMB_LABELS.Items.Add(Settings.Labels(i))
For i% = 0 To Source.Count - 1
If LabelsList.Contains(Source(i)) Then items.Add(i)
CMB_LABELS.Items.Add(Source(i))
Next
If Not _Source Is Nothing Then CMB_LABELS.Buttons.Clear()
CMB_LABELS.EndUpdate()
CMB_LABELS.ListCheckedIndexes = items
End If
@@ -47,12 +63,12 @@ Friend Class LabelsForm : Implements IOkCancelToolbar
End Try
End Sub
Private Sub LabelsForm_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
If e.KeyCode = Keys.Insert Then AddNewLabel() : e.Handled = True
If e.KeyCode = Keys.Insert And _Source Is Nothing Then AddNewLabel() : e.Handled = True
End Sub
Private Sub LabelsForm_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed
LabelsList.Clear()
End Sub
Private Sub ToolbarBttOK() Implements IOkCancelToolbar.ToolbarBttOK
Private Sub OK() Implements IOkCancelToolbar.OK
Try
If MultiUser Then
Dim m As New MMessage("You are changing labels for more one user" & vbNewLine & "What do you want to do?",
@@ -68,15 +84,19 @@ Friend Class LabelsForm : Implements IOkCancelToolbar
End Select
End If
LabelsList.ListAddList(CMB_LABELS.Items.CheckedItems.Select(Function(l) CStr(l.Value(0))), LAP.ClearBeforeAdd, LAP.NotContainsOnly)
If _AnyLabelAdd Then Settings.Labels.Update()
If _AnyLabelAdd And _Source Is Nothing Then Settings.Labels.Update()
MyDefs.CloseForm()
Catch ex As Exception
ErrorsDescriber.Execute(EDP.LogMessageValue, ex, "Choosing labels")
End Try
End Sub
Private Sub ToolbarBttCancel() Implements IOkCancelToolbar.ToolbarBttCancel
Private Sub Cancel() Implements IOkCancelToolbar.Cancel
MyDefs.CloseForm(DialogResult.Cancel)
End Sub
Private Sub Delete() Implements IOkCancelDeleteToolbar.Delete
LabelsList.Clear()
MyDefs.CloseForm()
End Sub
Private Sub CMB_LABELS_ActionOnButtonClick(ByVal Sender As ActionButton) Handles CMB_LABELS.ActionOnButtonClick
If Sender.DefaultButton = ActionButton.DefaultButtons.Add Then AddNewLabel()
End Sub

View File

@@ -14,13 +14,14 @@
Private components As System.ComponentModel.IContainer
<System.Diagnostics.DebuggerStepThrough()>
Private Sub InitializeComponent()
Dim ActionButton7 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Me.components = New System.ComponentModel.Container()
Dim ActionButton1 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(SiteEditorForm))
Dim ActionButton8 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim ActionButton9 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim ActionButton10 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim ActionButton11 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim ActionButton12 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim ActionButton2 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim ActionButton3 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim ActionButton4 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim ActionButton5 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim ActionButton6 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Me.TP_MAIN = New System.Windows.Forms.TableLayoutPanel()
Me.TXT_PATH = New PersonalUtilities.Forms.Controls.TextBoxExtended()
Me.TXT_COOKIES = New PersonalUtilities.Forms.Controls.TextBoxExtended()
@@ -28,6 +29,7 @@
Me.TXT_PATH_SAVED_POSTS = New PersonalUtilities.Forms.Controls.TextBoxExtended()
Me.CH_GET_USER_MEDIA_ONLY = New System.Windows.Forms.CheckBox()
Me.CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer()
Me.TT_MAIN = New System.Windows.Forms.ToolTip(Me.components)
Me.TP_MAIN.SuspendLayout()
CType(Me.TXT_PATH, System.ComponentModel.ISupportInitialize).BeginInit()
CType(Me.TXT_COOKIES, System.ComponentModel.ISupportInitialize).BeginInit()
@@ -59,14 +61,14 @@
'
'TXT_PATH
'
ActionButton7.BackgroundImage = CType(resources.GetObject("ActionButton7.BackgroundImage"), System.Drawing.Image)
ActionButton7.Index = 0
ActionButton7.Name = "BTT_OPEN"
ActionButton8.BackgroundImage = CType(resources.GetObject("ActionButton8.BackgroundImage"), System.Drawing.Image)
ActionButton8.Index = 1
ActionButton8.Name = "BTT_CLEAR"
Me.TXT_PATH.Buttons.Add(ActionButton7)
Me.TXT_PATH.Buttons.Add(ActionButton8)
ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image)
ActionButton1.Index = 0
ActionButton1.Name = "BTT_OPEN"
ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image)
ActionButton2.Index = 1
ActionButton2.Name = "BTT_CLEAR"
Me.TXT_PATH.Buttons.Add(ActionButton1)
Me.TXT_PATH.Buttons.Add(ActionButton2)
Me.TXT_PATH.CaptionText = "Path"
Me.TXT_PATH.CaptionToolTipEnabled = True
Me.TXT_PATH.CaptionToolTipText = "Specific path to store Twitter files"
@@ -78,14 +80,14 @@
'
'TXT_COOKIES
'
ActionButton9.BackgroundImage = CType(resources.GetObject("ActionButton9.BackgroundImage"), System.Drawing.Image)
ActionButton9.Index = 0
ActionButton9.Name = "BTT_EDIT"
ActionButton10.BackgroundImage = CType(resources.GetObject("ActionButton10.BackgroundImage"), System.Drawing.Image)
ActionButton10.Index = 1
ActionButton10.Name = "BTT_CLEAR"
Me.TXT_COOKIES.Buttons.Add(ActionButton9)
Me.TXT_COOKIES.Buttons.Add(ActionButton10)
ActionButton3.BackgroundImage = CType(resources.GetObject("ActionButton3.BackgroundImage"), System.Drawing.Image)
ActionButton3.Index = 0
ActionButton3.Name = "BTT_EDIT"
ActionButton4.BackgroundImage = CType(resources.GetObject("ActionButton4.BackgroundImage"), System.Drawing.Image)
ActionButton4.Index = 1
ActionButton4.Name = "BTT_CLEAR"
Me.TXT_COOKIES.Buttons.Add(ActionButton3)
Me.TXT_COOKIES.Buttons.Add(ActionButton4)
Me.TXT_COOKIES.CaptionText = "Cookies"
Me.TXT_COOKIES.ClearTextByButtonClear = False
Me.TXT_COOKIES.Dock = System.Windows.Forms.DockStyle.Fill
@@ -114,14 +116,14 @@
'
'TXT_PATH_SAVED_POSTS
'
ActionButton11.BackgroundImage = CType(resources.GetObject("ActionButton11.BackgroundImage"), System.Drawing.Image)
ActionButton11.Index = 0
ActionButton11.Name = "BTT_OPEN"
ActionButton12.BackgroundImage = CType(resources.GetObject("ActionButton12.BackgroundImage"), System.Drawing.Image)
ActionButton12.Index = 1
ActionButton12.Name = "BTT_CLEAR"
Me.TXT_PATH_SAVED_POSTS.Buttons.Add(ActionButton11)
Me.TXT_PATH_SAVED_POSTS.Buttons.Add(ActionButton12)
ActionButton5.BackgroundImage = CType(resources.GetObject("ActionButton5.BackgroundImage"), System.Drawing.Image)
ActionButton5.Index = 0
ActionButton5.Name = "BTT_OPEN"
ActionButton6.BackgroundImage = CType(resources.GetObject("ActionButton6.BackgroundImage"), System.Drawing.Image)
ActionButton6.Index = 1
ActionButton6.Name = "BTT_CLEAR"
Me.TXT_PATH_SAVED_POSTS.Buttons.Add(ActionButton5)
Me.TXT_PATH_SAVED_POSTS.Buttons.Add(ActionButton6)
Me.TXT_PATH_SAVED_POSTS.CaptionText = "Saved posts path"
Me.TXT_PATH_SAVED_POSTS.Dock = System.Windows.Forms.DockStyle.Fill
Me.TXT_PATH_SAVED_POSTS.Location = New System.Drawing.Point(3, 31)
@@ -192,5 +194,6 @@
Private WithEvents TXT_PATH_SAVED_POSTS As PersonalUtilities.Forms.Controls.TextBoxExtended
Private WithEvents TP_SITE_PROPS As SiteDefaults
Private WithEvents CH_GET_USER_MEDIA_ONLY As CheckBox
Private WithEvents TT_MAIN As ToolTip
End Class
End Namespace

View File

@@ -118,7 +118,7 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="ActionButton7.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<data name="ActionButton1.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
wwAADsMBx2+oZAAAAR5JREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbGujg3ZATZPKYdC6FQhPwlAMkg3dP
@@ -129,7 +129,7 @@
cMaRN0UdBBkAAAAASUVORK5CYII=
</value>
</data>
<data name="ActionButton8.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<data name="ActionButton2.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
@@ -137,7 +137,7 @@
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
</value>
</data>
<data name="ActionButton9.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<data name="ActionButton3.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAACH
DwAAjA8AAP1SAACBQAAAfXkAAOmLAAA85QAAGcxzPIV3AAAKOWlDQ1BQaG90b3Nob3AgSUNDIHByb2Zp
@@ -195,7 +195,7 @@
AAAASUVORK5CYII=
</value>
</data>
<data name="ActionButton10.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<data name="ActionButton4.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
@@ -203,7 +203,7 @@
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
</value>
</data>
<data name="ActionButton11.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<data name="ActionButton5.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
wwAADsMBx2+oZAAAAR5JREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbGujg3ZATZPKYdC6FQhPwlAMkg3dP
@@ -214,7 +214,7 @@
cMaRN0UdBBkAAAAASUVORK5CYII=
</value>
</data>
<data name="ActionButton12.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<data name="ActionButton6.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
@@ -222,4 +222,7 @@
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
</value>
</data>
<metadata name="TT_MAIN.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>

View File

@@ -18,13 +18,17 @@ Namespace Editors
Friend Class SiteEditorForm : Implements IOkCancelToolbar
Private ReadOnly LBL_AUTH As Label
Private ReadOnly LBL_OTHER As Label
Private ReadOnly MyDefs As DefaultFormProps(Of FieldsChecker)
Private ReadOnly MyDefs As DefaultFormProps
Private WithEvents SpecialButton As Button
#Region "Providers"
Private Class SavedPostsChecker : Implements ICustomProvider
Private Class SavedPostsChecker : Implements IFieldsCheckerProvider
Private Property ErrorMessage As String Implements IFieldsCheckerProvider.ErrorMessage
Private Property Name As String Implements IFieldsCheckerProvider.Name
Private Property TypeError As Boolean Implements IFieldsCheckerProvider.TypeError
Private Function Convert(ByVal Value As Object, ByVal DestinationType As Type, ByVal Provider As IFormatProvider,
Optional ByVal NothingArg As Object = Nothing, Optional ByVal e As ErrorsDescriber = Nothing) As Object Implements ICustomProvider.Convert
If Not ACheck(Value) OrElse CStr(Value).Contains("/") Then
If ACheck(Value) AndAlso CStr(Value).Contains("/") Then
ErrorMessage = $"Path [{Name}] contains forbidden character ""/"""
Return Nothing
Else
Return Value
@@ -38,7 +42,7 @@ Namespace Editors
Private ReadOnly Property Host As SettingsHost
Friend Sub New(ByVal h As SettingsHost)
InitializeComponent()
MyDefs = New DefaultFormProps(Of FieldsChecker)
MyDefs = New DefaultFormProps
Host = h
LBL_AUTH = New Label With {.Text = "Authorization", .TextAlign = ContentAlignment.MiddleCenter, .Dock = DockStyle.Fill}
LBL_OTHER = New Label With {.Text = "Other Parameters", .TextAlign = ContentAlignment.MiddleCenter, .Dock = DockStyle.Fill}
@@ -65,7 +69,7 @@ Namespace Editors
SiteDefaultsFunctions.SetChecker(TP_SITE_PROPS, Host)
With MyDefs.MyFieldsChecker
With DirectCast(MyDefs.MyFieldsChecker, FieldsChecker)
.AddControl(Of String)(TXT_PATH, TXT_PATH.CaptionText, True, New SavedPostsChecker)
.AddControl(Of String)(TXT_PATH_SAVED_POSTS, TXT_PATH_SAVED_POSTS.CaptionText, True, New SavedPostsChecker)
End With
@@ -109,11 +113,12 @@ Namespace Editors
End Select
End If
.CreateControl()
.CreateControl(TT_MAIN)
AddTpControl(.Control, .ControlHeight)
If .LeftOffset > offset Then offset = .LeftOffset
If Not .Options.AllowNull Or Not .ProviderFieldsChecker Is Nothing Then
MyDefs.MyFieldsChecker.AddControl(.Control, .Options.ControlText, .Type, .Options.AllowNull, .ProviderFieldsChecker)
DirectCast(MyDefs.MyFieldsChecker, FieldsChecker).
AddControl(.Control, .Options.ControlText, .Type, .Options.AllowNull, .ProviderFieldsChecker)
End If
End If
End With
@@ -152,7 +157,7 @@ Namespace Editors
LBL_AUTH.Dispose()
LBL_OTHER.Dispose()
End Sub
Private Sub ToolbarBttOK() Implements IOkCancelToolbar.ToolbarBttOK
Private Sub OK() Implements IOkCancelToolbar.OK
If MyDefs.MyFieldsChecker.AllParamsOK Then
Dim i%, ii%
With Host
@@ -195,7 +200,7 @@ Namespace Editors
MyDefs.CloseForm()
End If
End Sub
Private Sub ToolbarBttCancel() Implements IOkCancelToolbar.ToolbarBttCancel
Private Sub Cancel() Implements IOkCancelToolbar.Cancel
MyDefs.CloseForm(DialogResult.Cancel)
End Sub
Private Sub TXT_PATH_ActionOnButtonClick(ByVal Sender As ActionButton) Handles TXT_PATH.ActionOnButtonClick

View File

@@ -39,7 +39,7 @@ Namespace Editors
Private Sub SiteSelectionForm_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed
SelectedSites.Clear()
End Sub
Public Sub ToolbarBttOK() Implements IOkCancelToolbar.ToolbarBttOK
Public Sub OK() Implements IOkCancelToolbar.OK
Try
SelectedSites.ListAddList(CMB_SITES.Items.CheckedItems.Select(Function(i) CStr(i.Value(0))), LAP.ClearBeforeAdd)
MyDefs.CloseForm()
@@ -47,7 +47,7 @@ Namespace Editors
ErrorsDescriber.Execute(EDP.LogMessageValue, ex)
End Try
End Sub
Public Sub ToolbarBttCancel() Implements IOkCancelToolbar.ToolbarBttCancel
Public Sub Cancel() Implements IOkCancelToolbar.Cancel
MyDefs.CloseForm(DialogResult.Cancel)
End Sub
End Class

View File

@@ -29,6 +29,8 @@
Dim TP_DOWN_OPTIONS As System.Windows.Forms.TableLayoutPanel
Dim ActionButton5 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim ActionButton6 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim ActionButton7 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim ActionButton8 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim TT_MAIN As System.Windows.Forms.ToolTip
Me.TXT_USER = New PersonalUtilities.Forms.Controls.TextBoxExtended()
Me.CH_IS_CHANNEL = New System.Windows.Forms.CheckBox()
@@ -47,6 +49,7 @@
Me.CH_DOWN_IMAGES = New System.Windows.Forms.CheckBox()
Me.CH_DOWN_VIDEOS = New System.Windows.Forms.CheckBox()
Me.TXT_SPEC_FOLDER = New PersonalUtilities.Forms.Controls.TextBoxExtended()
Me.TXT_SCRIPT = New PersonalUtilities.Forms.Controls.TextBoxExtended()
Me.CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer()
TP_MAIN = New System.Windows.Forms.TableLayoutPanel()
TP_SITE = New System.Windows.Forms.TableLayoutPanel()
@@ -66,6 +69,7 @@
CType(Me.TXT_LABELS, System.ComponentModel.ISupportInitialize).BeginInit()
TP_DOWN_OPTIONS.SuspendLayout()
CType(Me.TXT_SPEC_FOLDER, System.ComponentModel.ISupportInitialize).BeginInit()
CType(Me.TXT_SCRIPT, System.ComponentModel.ISupportInitialize).BeginInit()
Me.CONTAINER_MAIN.ContentPanel.SuspendLayout()
Me.CONTAINER_MAIN.SuspendLayout()
Me.SuspendLayout()
@@ -79,27 +83,29 @@
TP_MAIN.Controls.Add(TP_SITE, 0, 3)
TP_MAIN.Controls.Add(TP_PARAMS, 0, 4)
TP_MAIN.Controls.Add(TP_OTHER, 0, 6)
TP_MAIN.Controls.Add(Me.TXT_DESCR, 0, 9)
TP_MAIN.Controls.Add(Me.TXT_DESCR, 0, 10)
TP_MAIN.Controls.Add(Me.TXT_USER_FRIENDLY, 0, 1)
TP_MAIN.Controls.Add(Me.TP_ADD_BY_LIST, 0, 7)
TP_MAIN.Controls.Add(Me.TXT_LABELS, 0, 8)
TP_MAIN.Controls.Add(TP_DOWN_OPTIONS, 0, 5)
TP_MAIN.Controls.Add(Me.TXT_SPEC_FOLDER, 0, 2)
TP_MAIN.Controls.Add(Me.TXT_SCRIPT, 0, 9)
TP_MAIN.Dock = System.Windows.Forms.DockStyle.Fill
TP_MAIN.Location = New System.Drawing.Point(0, 0)
TP_MAIN.Name = "TP_MAIN"
TP_MAIN.RowCount = 10
TP_MAIN.RowCount = 11
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66708!))
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66708!))
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667!))
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66708!))
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66542!))
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667!))
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 150.0!))
TP_MAIN.Size = New System.Drawing.Size(454, 431)
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 26.0!))
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 26.0!))
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_MAIN.Size = New System.Drawing.Size(454, 461)
TP_MAIN.TabIndex = 0
'
'TXT_USER
@@ -119,7 +125,7 @@
TP_SITE.ColumnCount = 3
TP_SITE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 79.0!))
TP_SITE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_SITE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 88.0!))
TP_SITE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 96.0!))
TP_SITE.Controls.Add(Me.CH_IS_CHANNEL, 0, 0)
TP_SITE.Controls.Add(Me.CMB_SITE, 1, 0)
TP_SITE.Controls.Add(Me.BTT_OTHER_SETTINGS, 2, 0)
@@ -129,7 +135,7 @@
TP_SITE.Name = "TP_SITE"
TP_SITE.RowCount = 1
TP_SITE.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_SITE.Size = New System.Drawing.Size(452, 31)
TP_SITE.Size = New System.Drawing.Size(452, 28)
TP_SITE.TabIndex = 3
'
'CH_IS_CHANNEL
@@ -138,7 +144,7 @@
Me.CH_IS_CHANNEL.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_IS_CHANNEL.Location = New System.Drawing.Point(4, 4)
Me.CH_IS_CHANNEL.Name = "CH_IS_CHANNEL"
Me.CH_IS_CHANNEL.Size = New System.Drawing.Size(73, 23)
Me.CH_IS_CHANNEL.Size = New System.Drawing.Size(73, 20)
Me.CH_IS_CHANNEL.TabIndex = 0
Me.CH_IS_CHANNEL.Text = "Channel"
Me.CH_IS_CHANNEL.UseVisualStyleBackColor = True
@@ -160,22 +166,22 @@
Me.CMB_SITE.Columns.Add(ListColumn1)
Me.CMB_SITE.Columns.Add(ListColumn2)
Me.CMB_SITE.Dock = System.Windows.Forms.DockStyle.Fill
Me.CMB_SITE.Location = New System.Drawing.Point(84, 2)
Me.CMB_SITE.Margin = New System.Windows.Forms.Padding(3, 1, 3, 3)
Me.CMB_SITE.Location = New System.Drawing.Point(84, 3)
Me.CMB_SITE.Margin = New System.Windows.Forms.Padding(3, 2, 3, 3)
Me.CMB_SITE.Name = "CMB_SITE"
Me.CMB_SITE.Size = New System.Drawing.Size(275, 22)
Me.CMB_SITE.Size = New System.Drawing.Size(267, 22)
Me.CMB_SITE.TabIndex = 1
Me.CMB_SITE.TextBoxBorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
'
'BTT_OTHER_SETTINGS
'
Me.BTT_OTHER_SETTINGS.Dock = System.Windows.Forms.DockStyle.Fill
Me.BTT_OTHER_SETTINGS.Location = New System.Drawing.Point(364, 2)
Me.BTT_OTHER_SETTINGS.Location = New System.Drawing.Point(356, 2)
Me.BTT_OTHER_SETTINGS.Margin = New System.Windows.Forms.Padding(1)
Me.BTT_OTHER_SETTINGS.Name = "BTT_OTHER_SETTINGS"
Me.BTT_OTHER_SETTINGS.Size = New System.Drawing.Size(86, 27)
Me.BTT_OTHER_SETTINGS.Size = New System.Drawing.Size(94, 24)
Me.BTT_OTHER_SETTINGS.TabIndex = 2
Me.BTT_OTHER_SETTINGS.Text = "Options"
Me.BTT_OTHER_SETTINGS.Text = "Options (F2)"
TT_MAIN.SetToolTip(Me.BTT_OTHER_SETTINGS, "Other settings")
Me.BTT_OTHER_SETTINGS.UseVisualStyleBackColor = True
'
@@ -188,13 +194,13 @@
TP_PARAMS.Controls.Add(Me.CH_TEMP, 0, 0)
TP_PARAMS.Controls.Add(Me.CH_FAV, 1, 0)
TP_PARAMS.Dock = System.Windows.Forms.DockStyle.Fill
TP_PARAMS.Location = New System.Drawing.Point(1, 120)
TP_PARAMS.Location = New System.Drawing.Point(1, 117)
TP_PARAMS.Margin = New System.Windows.Forms.Padding(0)
TP_PARAMS.Name = "TP_PARAMS"
TP_PARAMS.RowCount = 1
TP_PARAMS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_PARAMS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30.0!))
TP_PARAMS.Size = New System.Drawing.Size(452, 31)
TP_PARAMS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 27.0!))
TP_PARAMS.Size = New System.Drawing.Size(452, 28)
TP_PARAMS.TabIndex = 4
'
'CH_TEMP
@@ -203,7 +209,7 @@
Me.CH_TEMP.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_TEMP.Location = New System.Drawing.Point(4, 4)
Me.CH_TEMP.Name = "CH_TEMP"
Me.CH_TEMP.Size = New System.Drawing.Size(218, 23)
Me.CH_TEMP.Size = New System.Drawing.Size(218, 20)
Me.CH_TEMP.TabIndex = 0
Me.CH_TEMP.Text = "Temporary"
Me.CH_TEMP.UseVisualStyleBackColor = True
@@ -214,7 +220,7 @@
Me.CH_FAV.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_FAV.Location = New System.Drawing.Point(229, 4)
Me.CH_FAV.Name = "CH_FAV"
Me.CH_FAV.Size = New System.Drawing.Size(219, 23)
Me.CH_FAV.Size = New System.Drawing.Size(219, 20)
Me.CH_FAV.TabIndex = 1
Me.CH_FAV.Text = "Favorite"
Me.CH_FAV.UseVisualStyleBackColor = True
@@ -228,13 +234,13 @@
TP_OTHER.Controls.Add(Me.CH_PARSE_USER_MEDIA, 1, 0)
TP_OTHER.Controls.Add(Me.CH_READY_FOR_DOWN, 0, 0)
TP_OTHER.Dock = System.Windows.Forms.DockStyle.Fill
TP_OTHER.Location = New System.Drawing.Point(1, 184)
TP_OTHER.Location = New System.Drawing.Point(1, 175)
TP_OTHER.Margin = New System.Windows.Forms.Padding(0)
TP_OTHER.Name = "TP_OTHER"
TP_OTHER.RowCount = 1
TP_OTHER.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_OTHER.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30.0!))
TP_OTHER.Size = New System.Drawing.Size(452, 31)
TP_OTHER.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 27.0!))
TP_OTHER.Size = New System.Drawing.Size(452, 28)
TP_OTHER.TabIndex = 6
'
'CH_PARSE_USER_MEDIA
@@ -243,7 +249,7 @@
Me.CH_PARSE_USER_MEDIA.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_PARSE_USER_MEDIA.Location = New System.Drawing.Point(229, 4)
Me.CH_PARSE_USER_MEDIA.Name = "CH_PARSE_USER_MEDIA"
Me.CH_PARSE_USER_MEDIA.Size = New System.Drawing.Size(219, 23)
Me.CH_PARSE_USER_MEDIA.Size = New System.Drawing.Size(219, 20)
Me.CH_PARSE_USER_MEDIA.TabIndex = 0
Me.CH_PARSE_USER_MEDIA.Text = "Get user media only"
TT_MAIN.SetToolTip(Me.CH_PARSE_USER_MEDIA, "For twitter only!" & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "If checked then user media only will be downloaded." & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Otherwise" &
@@ -256,7 +262,7 @@
Me.CH_READY_FOR_DOWN.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_READY_FOR_DOWN.Location = New System.Drawing.Point(4, 4)
Me.CH_READY_FOR_DOWN.Name = "CH_READY_FOR_DOWN"
Me.CH_READY_FOR_DOWN.Size = New System.Drawing.Size(218, 23)
Me.CH_READY_FOR_DOWN.Size = New System.Drawing.Size(218, 20)
Me.CH_READY_FOR_DOWN.TabIndex = 1
Me.CH_READY_FOR_DOWN.Text = "Ready for download"
TT_MAIN.SetToolTip(Me.CH_READY_FOR_DOWN, "Can be downloaded by [Download All]")
@@ -275,11 +281,11 @@
Me.TXT_DESCR.Dock = System.Windows.Forms.DockStyle.Fill
Me.TXT_DESCR.GroupBoxed = True
Me.TXT_DESCR.GroupBoxText = "Description"
Me.TXT_DESCR.Location = New System.Drawing.Point(4, 282)
Me.TXT_DESCR.Location = New System.Drawing.Point(4, 290)
Me.TXT_DESCR.Multiline = True
Me.TXT_DESCR.Name = "TXT_DESCR"
Me.TXT_DESCR.Size = New System.Drawing.Size(446, 145)
Me.TXT_DESCR.TabIndex = 9
Me.TXT_DESCR.Size = New System.Drawing.Size(446, 167)
Me.TXT_DESCR.TabIndex = 10
'
'TXT_USER_FRIENDLY
'
@@ -300,12 +306,12 @@
Me.TP_ADD_BY_LIST.Controls.Add(Me.CH_ADD_BY_LIST, 0, 0)
Me.TP_ADD_BY_LIST.Controls.Add(Me.CH_AUTO_DETECT_SITE, 1, 0)
Me.TP_ADD_BY_LIST.Dock = System.Windows.Forms.DockStyle.Fill
Me.TP_ADD_BY_LIST.Location = New System.Drawing.Point(1, 216)
Me.TP_ADD_BY_LIST.Location = New System.Drawing.Point(1, 204)
Me.TP_ADD_BY_LIST.Margin = New System.Windows.Forms.Padding(0)
Me.TP_ADD_BY_LIST.Name = "TP_ADD_BY_LIST"
Me.TP_ADD_BY_LIST.RowCount = 1
Me.TP_ADD_BY_LIST.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
Me.TP_ADD_BY_LIST.Size = New System.Drawing.Size(452, 30)
Me.TP_ADD_BY_LIST.Size = New System.Drawing.Size(452, 28)
Me.TP_ADD_BY_LIST.TabIndex = 7
'
'CH_ADD_BY_LIST
@@ -314,7 +320,7 @@
Me.CH_ADD_BY_LIST.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_ADD_BY_LIST.Location = New System.Drawing.Point(4, 4)
Me.CH_ADD_BY_LIST.Name = "CH_ADD_BY_LIST"
Me.CH_ADD_BY_LIST.Size = New System.Drawing.Size(218, 22)
Me.CH_ADD_BY_LIST.Size = New System.Drawing.Size(218, 20)
Me.CH_ADD_BY_LIST.TabIndex = 0
Me.CH_ADD_BY_LIST.Text = "Add by list"
Me.CH_ADD_BY_LIST.UseVisualStyleBackColor = True
@@ -325,7 +331,7 @@
Me.CH_AUTO_DETECT_SITE.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_AUTO_DETECT_SITE.Location = New System.Drawing.Point(229, 4)
Me.CH_AUTO_DETECT_SITE.Name = "CH_AUTO_DETECT_SITE"
Me.CH_AUTO_DETECT_SITE.Size = New System.Drawing.Size(219, 22)
Me.CH_AUTO_DETECT_SITE.Size = New System.Drawing.Size(219, 20)
Me.CH_AUTO_DETECT_SITE.TabIndex = 1
Me.CH_AUTO_DETECT_SITE.Text = "Auto detect site"
Me.CH_AUTO_DETECT_SITE.UseVisualStyleBackColor = True
@@ -343,7 +349,8 @@
Me.TXT_LABELS.CaptionText = "Labels"
Me.TXT_LABELS.CaptionWidth = 50.0R
Me.TXT_LABELS.Dock = System.Windows.Forms.DockStyle.Fill
Me.TXT_LABELS.Location = New System.Drawing.Point(4, 250)
Me.TXT_LABELS.Location = New System.Drawing.Point(4, 235)
Me.TXT_LABELS.Margin = New System.Windows.Forms.Padding(3, 2, 3, 3)
Me.TXT_LABELS.Name = "TXT_LABELS"
Me.TXT_LABELS.Size = New System.Drawing.Size(446, 22)
Me.TXT_LABELS.TabIndex = 8
@@ -358,13 +365,13 @@
TP_DOWN_OPTIONS.Controls.Add(Me.CH_DOWN_IMAGES, 0, 0)
TP_DOWN_OPTIONS.Controls.Add(Me.CH_DOWN_VIDEOS, 1, 0)
TP_DOWN_OPTIONS.Dock = System.Windows.Forms.DockStyle.Fill
TP_DOWN_OPTIONS.Location = New System.Drawing.Point(1, 152)
TP_DOWN_OPTIONS.Location = New System.Drawing.Point(1, 146)
TP_DOWN_OPTIONS.Margin = New System.Windows.Forms.Padding(0)
TP_DOWN_OPTIONS.Name = "TP_DOWN_OPTIONS"
TP_DOWN_OPTIONS.RowCount = 1
TP_DOWN_OPTIONS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_DOWN_OPTIONS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30.0!))
TP_DOWN_OPTIONS.Size = New System.Drawing.Size(452, 31)
TP_DOWN_OPTIONS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 27.0!))
TP_DOWN_OPTIONS.Size = New System.Drawing.Size(452, 28)
TP_DOWN_OPTIONS.TabIndex = 5
'
'CH_DOWN_IMAGES
@@ -373,7 +380,7 @@
Me.CH_DOWN_IMAGES.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_DOWN_IMAGES.Location = New System.Drawing.Point(4, 4)
Me.CH_DOWN_IMAGES.Name = "CH_DOWN_IMAGES"
Me.CH_DOWN_IMAGES.Size = New System.Drawing.Size(218, 23)
Me.CH_DOWN_IMAGES.Size = New System.Drawing.Size(218, 20)
Me.CH_DOWN_IMAGES.TabIndex = 0
Me.CH_DOWN_IMAGES.Text = "Download Images"
Me.CH_DOWN_IMAGES.UseVisualStyleBackColor = True
@@ -384,7 +391,7 @@
Me.CH_DOWN_VIDEOS.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_DOWN_VIDEOS.Location = New System.Drawing.Point(229, 4)
Me.CH_DOWN_VIDEOS.Name = "CH_DOWN_VIDEOS"
Me.CH_DOWN_VIDEOS.Size = New System.Drawing.Size(219, 23)
Me.CH_DOWN_VIDEOS.Size = New System.Drawing.Size(219, 20)
Me.CH_DOWN_VIDEOS.TabIndex = 1
Me.CH_DOWN_VIDEOS.Text = "Download videos"
Me.CH_DOWN_VIDEOS.UseVisualStyleBackColor = True
@@ -408,19 +415,45 @@
Me.TXT_SPEC_FOLDER.Size = New System.Drawing.Size(446, 22)
Me.TXT_SPEC_FOLDER.TabIndex = 2
'
'TXT_SCRIPT
'
ActionButton7.BackgroundImage = CType(resources.GetObject("ActionButton7.BackgroundImage"), System.Drawing.Image)
ActionButton7.Enabled = False
ActionButton7.Index = 0
ActionButton7.Name = "BTT_OPEN"
ActionButton8.BackgroundImage = CType(resources.GetObject("ActionButton8.BackgroundImage"), System.Drawing.Image)
ActionButton8.Enabled = False
ActionButton8.Index = 1
ActionButton8.Name = "BTT_CLEAR"
Me.TXT_SCRIPT.Buttons.Add(ActionButton7)
Me.TXT_SCRIPT.Buttons.Add(ActionButton8)
Me.TXT_SCRIPT.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.CheckBox
Me.TXT_SCRIPT.CaptionText = "Script"
Me.TXT_SCRIPT.CaptionToolTipEnabled = True
Me.TXT_SCRIPT.CaptionToolTipText = "Execute script after downloading this user"
Me.TXT_SCRIPT.CaptionWidth = 65.0R
Me.TXT_SCRIPT.Dock = System.Windows.Forms.DockStyle.Fill
Me.TXT_SCRIPT.Location = New System.Drawing.Point(4, 262)
Me.TXT_SCRIPT.Margin = New System.Windows.Forms.Padding(3, 2, 3, 3)
Me.TXT_SCRIPT.Name = "TXT_SCRIPT"
Me.TXT_SCRIPT.PlaceholderEnabled = True
Me.TXT_SCRIPT.PlaceholderText = "Leave blank to use the default script..."
Me.TXT_SCRIPT.Size = New System.Drawing.Size(446, 22)
Me.TXT_SCRIPT.TabIndex = 9
'
'CONTAINER_MAIN
'
'
'CONTAINER_MAIN.ContentPanel
'
Me.CONTAINER_MAIN.ContentPanel.Controls.Add(TP_MAIN)
Me.CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(454, 431)
Me.CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(454, 461)
Me.CONTAINER_MAIN.Dock = System.Windows.Forms.DockStyle.Fill
Me.CONTAINER_MAIN.LeftToolStripPanelVisible = False
Me.CONTAINER_MAIN.Location = New System.Drawing.Point(0, 0)
Me.CONTAINER_MAIN.Name = "CONTAINER_MAIN"
Me.CONTAINER_MAIN.RightToolStripPanelVisible = False
Me.CONTAINER_MAIN.Size = New System.Drawing.Size(454, 431)
Me.CONTAINER_MAIN.Size = New System.Drawing.Size(454, 461)
Me.CONTAINER_MAIN.TabIndex = 0
Me.CONTAINER_MAIN.TopToolStripPanelVisible = False
'
@@ -428,15 +461,15 @@
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(454, 431)
Me.ClientSize = New System.Drawing.Size(454, 461)
Me.Controls.Add(Me.CONTAINER_MAIN)
Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle
Me.Icon = CType(resources.GetObject("$this.Icon"), System.Drawing.Icon)
Me.KeyPreview = True
Me.MaximizeBox = False
Me.MaximumSize = New System.Drawing.Size(470, 470)
Me.MaximumSize = New System.Drawing.Size(470, 500)
Me.MinimizeBox = False
Me.MinimumSize = New System.Drawing.Size(470, 470)
Me.MinimumSize = New System.Drawing.Size(470, 500)
Me.Name = "UserCreatorForm"
Me.ShowInTaskbar = False
Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide
@@ -458,6 +491,7 @@
TP_DOWN_OPTIONS.ResumeLayout(False)
TP_DOWN_OPTIONS.PerformLayout()
CType(Me.TXT_SPEC_FOLDER, System.ComponentModel.ISupportInitialize).EndInit()
CType(Me.TXT_SCRIPT, System.ComponentModel.ISupportInitialize).EndInit()
Me.CONTAINER_MAIN.ContentPanel.ResumeLayout(False)
Me.CONTAINER_MAIN.ResumeLayout(False)
Me.CONTAINER_MAIN.PerformLayout()
@@ -483,5 +517,6 @@
Private WithEvents TXT_SPEC_FOLDER As PersonalUtilities.Forms.Controls.TextBoxExtended
Private WithEvents CMB_SITE As PersonalUtilities.Forms.Controls.ComboBoxExtended
Private WithEvents BTT_OTHER_SETTINGS As Button
Private WithEvents TXT_SCRIPT As PersonalUtilities.Forms.Controls.TextBoxExtended
End Class
End Namespace

View File

@@ -273,6 +273,25 @@
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
</value>
</data>
<data name="ActionButton7.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
wwAADsMBx2+oZAAAAR5JREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbGujg3ZATZPKYdC6FQhPwlAMkg3dP
WQwhyWIyJIUW5NqyPb7oCVtIlhVTwYf8nv7/t2zJagel9KmqKsIACYL9RjI8UHz5zshougZr/AEvbxEP
aZCDBY3VslixaJvX3wzkkDiOwbZtDRGA5vdNAg+TL27qgmt5XkBG/gTdAG7Gt+3PP9oOaEGFCVEC6rp+
5g9MfM/c5e4OsEZMZkQEtGL5H2DdZ5JRArDwPA+iKII0TfkC9vroC9j5vq8JTWw3WzWgLMtZGIaa0MR8
vlAD8PYlSaIJTTiOowY0p0Bc19XEJo6HE59FAPuMzyAINKGJ1XLFZxHALtMrnkBXOIQIIIQ8YvF/KrgB
cMaRN0UdBBkAAAAASUVORK5CYII=
</value>
</data>
<data name="ActionButton8.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
</value>
</data>
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">

View File

@@ -15,9 +15,11 @@ Imports PersonalUtilities.Functions.RegularExpressions
Imports SCrawler.API.Base
Imports SCrawler.Plugin
Imports SCrawler.Plugin.Hosts
Imports ADB = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons
Namespace Editors
Friend Class UserCreatorForm : Implements IOkCancelToolbar
Private ReadOnly MyDef As DefaultFormProps(Of FieldsChecker)
Private ReadOnly MyDef As DefaultFormProps
Friend Property User As UserInfo
Friend Property UserInstance As IUserData
Friend Property StartIndex As Integer = -1
@@ -65,6 +67,16 @@ Namespace Editors
Return TXT_USER_FRIENDLY.Text
End Get
End Property
Friend ReadOnly Property ScriptUse As Boolean
Get
Return TXT_SCRIPT.Checked
End Get
End Property
Friend ReadOnly Property ScriptData As String
Get
Return TXT_SCRIPT.Text
End Get
End Property
Friend Property MyExchangeOptions As Object = Nothing
Private ReadOnly _SpecPathPattern As RParams = RParams.DM("\w:\\.*", 0, EDP.ReturnValue)
Private ReadOnly Property SpecialPath(ByVal s As SettingsHost) As SFile
@@ -85,7 +97,7 @@ Namespace Editors
Friend Sub New()
InitializeComponent()
UserLabels = New List(Of String)
MyDef = New DefaultFormProps(Of FieldsChecker)
MyDef = New DefaultFormProps
End Sub
''' <summary>Edit exist user</summary>
Friend Sub New(ByVal _Instance As IUserData)
@@ -111,6 +123,7 @@ Namespace Editors
CH_TEMP.Checked = Settings.DefaultTemporary
CH_DOWN_IMAGES.Checked = Settings.DefaultDownloadImages
CH_DOWN_VIDEOS.Checked = Settings.DefaultDownloadVideos
TXT_SCRIPT.Checked = Settings.ScriptData.Attribute
SetParamsBySite()
Else
TP_ADD_BY_LIST.Enabled = False
@@ -135,7 +148,9 @@ Namespace Editors
CH_READY_FOR_DOWN.Checked = .ReadyForDownload
CH_DOWN_IMAGES.Checked = .DownloadImages
CH_DOWN_VIDEOS.Checked = .DownloadVideos
TXT_DESCR.Text = .Description
TXT_SCRIPT.Checked = .ScriptUse
TXT_SCRIPT.Text = .ScriptData
TXT_DESCR.Text = .Description.StringFormatLines
UserLabels.ListAddList(.Labels)
If UserLabels.ListExists Then TXT_LABELS.Text = UserLabels.ListToString
End With
@@ -148,7 +163,7 @@ Namespace Editors
End If
End If
.MyFieldsChecker = New FieldsChecker
.MyFieldsChecker.AddControl(Of String)(TXT_USER, TXT_USER.CaptionText)
DirectCast(.MyFieldsChecker, FieldsChecker).AddControl(Of String)(TXT_USER, TXT_USER.CaptionText)
.MyFieldsChecker.EndLoaderOperations()
.AppendDetectors()
.EndLoaderOperations()
@@ -158,7 +173,13 @@ Namespace Editors
End Try
End Sub
Private Sub UserCreatorForm_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
If e.KeyCode = Keys.F4 Then ChangeLabels() : e.Handled = True
Dim b As Boolean = True
Select Case e.KeyCode
Case Keys.F4 : ChangeLabels()
Case Keys.F2 : If BTT_OTHER_SETTINGS.Enabled Then BTT_OTHER_SETTINGS.PerformClick()
Case Else : b = False
End Select
If b Then e.Handled = True
End Sub
Private Sub UserCreatorForm_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
If Not BeforeCloseChecker(MyDef.ChangesDetected) Then
@@ -173,7 +194,7 @@ Namespace Editors
Private Function GetSiteByCheckers() As SettingsHost
Return If(CMB_SITE.SelectedIndex >= 0, Settings(CStr(CMB_SITE.Items(CMB_SITE.SelectedIndex).Value(0))), Nothing)
End Function
Private Sub ToolbarBttOK() Implements IOkCancelToolbar.ToolbarBttOK
Private Sub OK() Implements IOkCancelToolbar.OK
If Not CH_ADD_BY_LIST.Checked Then
If MyDef.MyFieldsChecker.AllParamsOK Then
Dim s As SettingsHost = GetSiteByCheckers()
@@ -188,6 +209,14 @@ Namespace Editors
.UpdateUserFile()
End With
User = tmpUser
Dim ScriptText$ = TXT_SCRIPT.Text
If Not ScriptText.IsEmptyString Then
Dim f As SFile = ScriptText
If Not SFile.IsDirectory(ScriptText) And Not UserInstance Is Nothing Then
With DirectCast(UserInstance, UserDataBase) : f.Path = .MyFile.Path : End With
End If
TXT_SCRIPT.Text = f
End If
If Not UserInstance Is Nothing Then
With DirectCast(UserInstance, UserDataBase)
.User = User
@@ -208,12 +237,14 @@ Namespace Editors
.Labels.ListAddList(UserLabels, LAP.NotContainsOnly, LAP.ClearBeforeAdd)
End If
.ParseUserMediaOnly = CH_PARSE_USER_MEDIA.Checked
.ScriptUse = TXT_SCRIPT.Checked
.ScriptData = TXT_SCRIPT.Text
.UpdateUserInformation()
End With
End If
GoTo CloseForm
Else
MsgBoxE("User site does not selected", MsgBoxStyle.Exclamation)
MsgBoxE("User site not selected", MsgBoxStyle.Exclamation)
End If
End If
Else
@@ -223,7 +254,7 @@ Namespace Editors
CloseForm:
MyDef.CloseForm()
End Sub
Private Sub ToolbarBttCancel() Implements IOkCancelToolbar.ToolbarBttCancel
Private Sub Cancel() Implements IOkCancelToolbar.Cancel
MyDef.CloseForm(IIf(StartIndex >= 0, DialogResult.OK, DialogResult.Cancel))
End Sub
Private _TextChangeInvoked As Boolean = False
@@ -346,6 +377,7 @@ CloseForm:
Dim UsersForCreate As New List(Of UserInfo)
Dim BannedUsers() As String = Nothing
Dim uu$
Dim ulabels As List(Of String) = ListAddList(Nothing, UserLabels).ListAddValue(LabelsKeeper.NoParsedUser, LAP.NotContainsOnly)
Dim tmpUser As UserInfo
Dim s As SettingsHost = GetSiteByCheckers()
Dim sObj As ExchangeOptions
@@ -356,6 +388,8 @@ CloseForm:
Dim sf As Func(Of SettingsHost, String) = Function(__s) SpecialPath(__s).PathWithSeparator
Dim __sf As Func(Of String, SettingsHost, SFile) = Function(Input, __s) IIf(sf(__s).IsEmptyString, Nothing, New SFile($"{sf(__s)}{Input}\"))
Settings.Labels.Add(LabelsKeeper.NoParsedUser)
For i% = 0 To u.Count - 1
uu = u(i)
If CH_AUTO_DETECT_SITE.Checked Then
@@ -397,7 +431,8 @@ CloseForm:
.ReadyForDownload = CH_READY_FOR_DOWN.Checked
.DownloadImages = CH_DOWN_IMAGES.Checked
.DownloadVideos = CH_DOWN_VIDEOS.Checked
.Labels.ListAddList(UserLabels)
.ScriptUse = TXT_SCRIPT.Checked
.Labels.ListAddList(ulabels)
.ParseUserMediaOnly = CH_PARSE_USER_MEDIA.Checked
If Not CH_AUTO_DETECT_SITE.Checked Then _
DirectCast(.Self, UserDataBase).HOST.Source.UserOptions(MyExchangeOptions, False)
@@ -412,8 +447,8 @@ CloseForm:
Dim m As New MMessage($"Added {Added} users (skipped (already exists and/or duplicated) {Skipped})")
If BannedUsers.ListExists Or NonIdentified.Count > 0 Then
Dim t$ = String.Empty
If BannedUsers.ListExists Then t.StringAppendLine($"Banned users:{vbNewLine}{BannedUsers.ListToString(, vbNewLine)}")
If NonIdentified.Count > 0 Then t.StringAppendLine($"Non-Identified users:{vbNewLine}{NonIdentified.ListToString(, vbNewLine)}", vbNewLine.StringDup(2))
If BannedUsers.ListExists Then t.StringAppendLine($"Banned users:{vbNewLine}{BannedUsers.ListToString(vbNewLine)}")
If NonIdentified.Count > 0 Then t.StringAppendLine($"Non-Identified users:{vbNewLine}{NonIdentified.ListToString(vbNewLine)}", vbNewLine.StringDup(2))
m.Style = MsgBoxStyle.Exclamation
m.Text.StringAppendLine("Some of users does not recognized and/or banned")
m.Text.StringAppendLine(t, vbNewLine.StringDup(2))
@@ -439,8 +474,8 @@ CloseForm:
End Function
Private Sub TXT_LABELS_ActionOnButtonClick(ByVal Sender As ActionButton) Handles TXT_LABELS.ActionOnButtonClick
Select Case Sender.DefaultButton
Case ActionButton.DefaultButtons.Open : ChangeLabels()
Case ActionButton.DefaultButtons.Clear : UserLabels.Clear()
Case ADB.Open : ChangeLabels()
Case ADB.Clear : UserLabels.Clear()
End Select
End Sub
Private Sub ChangeLabels()
@@ -456,5 +491,8 @@ CloseForm:
End If
End Using
End Sub
Private Sub TXT_SCRIPT_ActionOnButtonClick(ByVal Sender As ActionButton) Handles TXT_SCRIPT.ActionOnButtonClick
SettingsCLS.ScriptTextBoxButtonClick(TXT_SCRIPT, Sender)
End Sub
End Class
End Namespace

View File

@@ -40,13 +40,13 @@ Friend Class FDatePickerForm : Implements IOkCancelDeleteToolbar
MyDefs.InvokeLoaderError(ex)
End Try
End Sub
Private Sub ToolbarBttOK() Implements IOkCancelToolbar.ToolbarBttOK
Private Sub OK() Implements IOkCancelToolbar.OK
MyDefs.CloseForm()
End Sub
Private Sub ToolbarBttCancel() Implements IOkCancelToolbar.ToolbarBttCancel
Private Sub Cancel() Implements IOkCancelToolbar.Cancel
MyDefs.CloseForm(DialogResult.Cancel)
End Sub
Private Sub ToolbarBttDelete() Implements IOkCancelDeleteToolbar.ToolbarBttDelete
Private Sub Delete() Implements IOkCancelDeleteToolbar.Delete
MyDefs.CloseForm(DialogResult.Abort)
End Sub
End Class

View File

@@ -6,6 +6,8 @@
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY
Imports PersonalUtilities.Functions.XML
Imports PersonalUtilities.Functions.XML.Base
Imports PersonalUtilities.Tools
Friend Class LabelsKeeper : Implements ICollection(Of String), IMyEnumerator(Of String), IDisposable
Friend Event NewLabelAdded()
@@ -20,13 +22,33 @@ Friend Class LabelsKeeper : Implements ICollection(Of String), IMyEnumerator(Of
Return NewLabels.Count > 0
End Get
End Property
Friend ReadOnly Property CurrentSelection As List(Of String)
Friend Sub New()
Friend ReadOnly Property Current As XMLValuesCollection(Of String)
Friend ReadOnly Property Excluded As XMLValuesCollection(Of String)
Friend ReadOnly Property ExcludedIgnore As XMLValue(Of Boolean)
Private ReadOnly Property SourceXML As XmlFile
Friend Sub New(ByRef x As XmlFile)
SourceXML = x
LabelsList = New List(Of String)
NewLabels = New List(Of String)
CurrentSelection = New List(Of String)
If LabelsFile.Exists Then LabelsList.ListAddList(IO.File.ReadAllLines(LabelsFile), LAP.NotContainsOnly)
LabelsList.ListAddList({NoLabeledName, NoParsedUser}, LAP.NotContainsOnly)
Current = New XMLValuesCollection(Of String)(XMLValueBase.ListModes.String, "LatestSelectedLabels", x) With {.ListAddParameters = LAP.NotContainsOnly}
Excluded = New XMLValuesCollection(Of String)(XMLValueBase.ListModes.String, "LatestExcludedLabels", x) With {.ListAddParameters = LAP.NotContainsOnly}
ExcludedIgnore = New XMLValue(Of Boolean)("LatestExcludedLabelsIgnore", False, x)
End Sub
Friend Sub Verify()
SourceXML.BeginUpdate()
Dim r As Predicate(Of String) = Function(l) Not LabelsList.Contains(l)
Dim c% = Current.Count
If c > 0 Then
Current.ValuesList.RemoveAll(r)
If Not Current.Count = c Then Current.Update()
End If
c = Excluded.Count
If c > 0 Then
Excluded.ValuesList.RemoveAll(r)
If Not c = Excluded.Count Then Excluded.Update()
End If
SourceXML.EndUpdate()
End Sub
Friend ReadOnly Property ToList As List(Of String)
Get
@@ -50,7 +72,7 @@ Friend Class LabelsKeeper : Implements ICollection(Of String), IMyEnumerator(Of
Friend Sub Update()
If LabelsList.Count > 0 Then
LabelsList.Sort()
TextSaver.SaveTextToFile(LabelsList.ListToString(, vbNewLine), LabelsFile, True, False, EDP.SendInLog)
TextSaver.SaveTextToFile(LabelsList.ListToString(vbNewLine), LabelsFile, True, False, EDP.SendInLog)
Else
LabelsFile.Delete(, Settings.DeleteMode, EDP.SendInLog)
End If
@@ -93,7 +115,7 @@ Friend Class LabelsKeeper : Implements ICollection(Of String), IMyEnumerator(Of
Private disposedValue As Boolean = False
Protected Overridable Overloads Sub Dispose(ByVal disposing As Boolean)
If Not disposedValue Then
If disposing Then Clear() : CurrentSelection.Clear()
If disposing Then Clear() : Current.Dispose() : Excluded.Dispose()
disposedValue = True
End If
End Sub

Some files were not shown because too many files have changed in this diff Show More