Compare commits
25 Commits
3.0.0.1
...
2022.6.10.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab020d9b5f | ||
|
|
4ba1624edf | ||
|
|
f3d956f33f | ||
|
|
4a5e050201 | ||
|
|
dd272c6f6d | ||
|
|
fbcda1ae75 | ||
|
|
9e87369c9b | ||
|
|
cc3618a50e | ||
|
|
33b9e9cfc6 | ||
|
|
26dca2246e | ||
|
|
60b459e217 | ||
|
|
f491e03812 | ||
|
|
418f44edfd | ||
|
|
075a2b9b80 | ||
|
|
20c74ec8f1 | ||
|
|
0594e77e0b | ||
|
|
a5fa935e76 | ||
|
|
c90dd5637e | ||
|
|
9a301ebc5e | ||
|
|
11a590f14e | ||
|
|
975d46715c | ||
|
|
726fc486ce | ||
|
|
ede81f9d05 | ||
|
|
fccb786e55 | ||
|
|
2be52c7c56 |
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -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.
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/plugin_add.md
vendored
@@ -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: ''
|
||||
|
||||
@@ -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.** [](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
|
||||
|
||||
120
Changelog.md
@@ -1,3 +1,123 @@
|
||||
# 2022.6.10.0
|
||||
|
||||
**Attention! From now on, Instagram requires Cookies, Hash and authorization headers!**
|
||||
|
||||
- Fixed
|
||||
- Can't get Instagram user ID
|
||||
|
||||
# 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
|
||||
- **LPSG** site plugin
|
||||
- **XVIDEOS** site plugin
|
||||
- Updated
|
||||
- Plugin provider
|
||||
- Fixed
|
||||
- Minor bugs
|
||||
|
||||
# 3.0.0.1
|
||||
|
||||
- Added
|
||||
|
||||
34
FAQ.md
@@ -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.
|
||||
@@ -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:
|
||||
|
||||
@@ -1 +1,6 @@
|
||||
List of available plugins
|
||||
List of available plugins:
|
||||
- LPSG
|
||||
- XVIDEOS
|
||||
|
||||
Tools:
|
||||
- [image2post](https://github.com/unknown81311/SCrawler-image2post) by @unknown81311: **get reddit post URL from file.**
|
||||
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 17 KiB |
BIN
ProgramScreenshots/GroupCreating.png
Normal file
|
After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 377 KiB After Width: | Height: | Size: 379 KiB |
BIN
ProgramScreenshots/MainWindowGroups.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 10 KiB |
BIN
ProgramScreenshots/SettingsAutoDownloader.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 12 KiB |
BIN
ProgramScreenshots/SettingsGlobalBasis.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
ProgramScreenshots/SettingsGlobalBehavior.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
ProgramScreenshots/SettingsGlobalChannels.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
ProgramScreenshots/SettingsGlobalDefaults.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
ProgramScreenshots/SettingsGlobalDownloading.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 13 KiB |
BIN
ProgramScreenshots/SettingsRedditView.png
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
BIN
ProgramScreenshots/SettingsSiteInstagram.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
ProgramScreenshots/SettingsSiteReddit.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
ProgramScreenshots/SettingsSiteTwitter.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 14 KiB |
@@ -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.
|
||||
51
README.md
@@ -1,7 +1,9 @@
|
||||
# :rainbow_flag: Happy LGBT Pride Month :tada:
|
||||
|
||||
# Social networks crawler
|
||||
|
||||
[](https://github.com/AAndyProgram/SCrawler/releases/latest)
|
||||
[](https://github.com/AAndyProgram/SCrawler/)
|
||||
[](https://github.com/AAndyProgram/SCrawler/blob/main/LICENSE)
|
||||
[](FAQ.md)
|
||||
[](https://github.com/AAndyProgram/SCrawler/wiki)
|
||||
[](HowToSupport.md)
|
||||
@@ -21,20 +23,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)
|
||||
@@ -51,6 +57,8 @@ Do you like this program? Consider adding to my coffee fund by making a donation
|
||||
- RedGifs
|
||||
- Imgur
|
||||
- Gfycat
|
||||
- LPSG
|
||||
- XVIDEOS
|
||||
- [Other sites](Plugins.md)
|
||||
|
||||
# How does it works:
|
||||
@@ -73,9 +81,9 @@ 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
|
||||
- Authorization cookies and tokens for Twitter (if you want to download data from Twitter)
|
||||
- Authorization cookies Instagram (if you want to download data from Instagram)
|
||||
- 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.**
|
||||
|
||||
# Guide
|
||||
@@ -84,7 +92,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)**
|
||||
|
||||
@@ -95,7 +103,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
|
||||
@@ -110,7 +119,11 @@ Read more about how to support the program [here](HowToSupport.md).
|
||||
|
||||
The program has an intuitive interface.
|
||||
|
||||
Just add a user profile and click the ```Start downloading``` button.
|
||||
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), [Hash](https://github.com/AAndyProgram/SCrawler/wiki/Settings#instagram) and [authorization headers](https://github.com/AAndyProgram/SCrawler/wiki/Settings#how-to-find-instagram-authorization-headers) 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**
|
||||
|
||||
Just add a user profile and **click the ```Start downloading``` button**.
|
||||
|
||||
You can add users by patterns:
|
||||
- https://www.instagram.com/SomeUserName
|
||||
|
||||
3
SCrawler.Plugin.LPSG/.editorconfig
Normal file
@@ -0,0 +1,3 @@
|
||||
[*.vb]
|
||||
# Modifier preferences
|
||||
file_header_template = Copyright (C) 2022 Andy\nThis program is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
BIN
SCrawler.Plugin.LPSG/Content/Icons/Icon32.ico
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
SCrawler.Plugin.LPSG/Content/Pictures/IconPic_32.png
Normal file
|
After Width: | Height: | Size: 656 B |
48
SCrawler.Plugin.LPSG/Declarations.vb
Normal 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
|
||||
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|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
|
||||
Input = Input.Replace($"-{lv}", String.Empty)
|
||||
Input &= $".{lv}"
|
||||
End If
|
||||
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
|
||||
13
SCrawler.Plugin.LPSG/My Project/Application.Designer.vb
generated
Normal file
@@ -0,0 +1,13 @@
|
||||
'------------------------------------------------------------------------------
|
||||
' <auto-generated>
|
||||
' This code was generated by a tool.
|
||||
' Runtime Version:4.0.30319.42000
|
||||
'
|
||||
' Changes to this file may cause incorrect behavior and will be lost if
|
||||
' the code is regenerated.
|
||||
' </auto-generated>
|
||||
'------------------------------------------------------------------------------
|
||||
|
||||
Option Strict On
|
||||
Option Explicit On
|
||||
|
||||
10
SCrawler.Plugin.LPSG/My Project/Application.myapp
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<MyApplicationData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<MySubMain>false</MySubMain>
|
||||
<SingleInstance>false</SingleInstance>
|
||||
<ShutdownMode>0</ShutdownMode>
|
||||
<EnableVisualStyles>true</EnableVisualStyles>
|
||||
<AuthenticationMode>0</AuthenticationMode>
|
||||
<ApplicationType>1</ApplicationType>
|
||||
<SaveMySettingsOnExit>true</SaveMySettingsOnExit>
|
||||
</MyApplicationData>
|
||||
37
SCrawler.Plugin.LPSG/My Project/AssemblyInfo.vb
Normal file
@@ -0,0 +1,37 @@
|
||||
Imports System.Resources
|
||||
Imports System
|
||||
Imports System.Reflection
|
||||
Imports System.Runtime.InteropServices
|
||||
|
||||
' General Information about an assembly is controlled through the following
|
||||
' set of attributes. Change these attribute values to modify the information
|
||||
' associated with an assembly.
|
||||
|
||||
' Review the values of the assembly attributes
|
||||
|
||||
<Assembly: AssemblyTitle("LPSG")>
|
||||
<Assembly: AssemblyDescription("LPSG plugin for SCrawler")>
|
||||
<Assembly: AssemblyCompany("AndyProgram")>
|
||||
<Assembly: AssemblyProduct("LPSG")>
|
||||
<Assembly: AssemblyCopyright("Copyright © 2022")>
|
||||
<Assembly: AssemblyTrademark("AndyProgram")>
|
||||
|
||||
<Assembly: ComVisible(False)>
|
||||
|
||||
'The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
<Assembly: Guid("4beaf92d-0566-4331-ad29-034d09a7326f")>
|
||||
|
||||
' Version information for an assembly consists of the following four values:
|
||||
'
|
||||
' Major Version
|
||||
' Minor Version
|
||||
' Build Number
|
||||
' Revision
|
||||
'
|
||||
' You can specify all the values or you can default the Build and Revision Numbers
|
||||
' by using the '*' as shown below:
|
||||
' <Assembly: AssemblyVersion("1.0.*")>
|
||||
|
||||
<Assembly: AssemblyVersion("2022.6.3.0")>
|
||||
<Assembly: AssemblyFileVersion("2022.6.3.0")>
|
||||
<Assembly: NeutralResourcesLanguage("en")>
|
||||
83
SCrawler.Plugin.LPSG/My Project/Resources.Designer.vb
generated
Normal file
@@ -0,0 +1,83 @@
|
||||
'------------------------------------------------------------------------------
|
||||
' <auto-generated>
|
||||
' This code was generated by a tool.
|
||||
' Runtime Version:4.0.30319.42000
|
||||
'
|
||||
' Changes to this file may cause incorrect behavior and will be lost if
|
||||
' the code is regenerated.
|
||||
' </auto-generated>
|
||||
'------------------------------------------------------------------------------
|
||||
|
||||
Option Strict On
|
||||
Option Explicit On
|
||||
|
||||
Imports System
|
||||
|
||||
Namespace My.Resources
|
||||
|
||||
'This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
'class via a tool like ResGen or Visual Studio.
|
||||
'To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
'with the /str option, or rebuild your VS project.
|
||||
'''<summary>
|
||||
''' A strongly-typed resource class, for looking up localized strings, etc.
|
||||
'''</summary>
|
||||
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0"), _
|
||||
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
|
||||
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
|
||||
Global.Microsoft.VisualBasic.HideModuleNameAttribute()> _
|
||||
Friend Module Resources
|
||||
|
||||
Private resourceMan As Global.System.Resources.ResourceManager
|
||||
|
||||
Private resourceCulture As Global.System.Globalization.CultureInfo
|
||||
|
||||
'''<summary>
|
||||
''' Returns the cached ResourceManager instance used by this class.
|
||||
'''</summary>
|
||||
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||
Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager
|
||||
Get
|
||||
If Object.ReferenceEquals(resourceMan, Nothing) Then
|
||||
Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("LPSG.Resources", GetType(Resources).Assembly)
|
||||
resourceMan = temp
|
||||
End If
|
||||
Return resourceMan
|
||||
End Get
|
||||
End Property
|
||||
|
||||
'''<summary>
|
||||
''' Overrides the current thread's CurrentUICulture property for all
|
||||
''' resource lookups using this strongly typed resource class.
|
||||
'''</summary>
|
||||
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||
Friend Property Culture() As Global.System.Globalization.CultureInfo
|
||||
Get
|
||||
Return resourceCulture
|
||||
End Get
|
||||
Set
|
||||
resourceCulture = value
|
||||
End Set
|
||||
End Property
|
||||
|
||||
'''<summary>
|
||||
''' Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
|
||||
'''</summary>
|
||||
Friend ReadOnly Property Icon32() As System.Drawing.Icon
|
||||
Get
|
||||
Dim obj As Object = ResourceManager.GetObject("Icon32", resourceCulture)
|
||||
Return CType(obj,System.Drawing.Icon)
|
||||
End Get
|
||||
End Property
|
||||
|
||||
'''<summary>
|
||||
''' Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
'''</summary>
|
||||
Friend ReadOnly Property IconPic_32() As System.Drawing.Bitmap
|
||||
Get
|
||||
Dim obj As Object = ResourceManager.GetObject("IconPic_32", resourceCulture)
|
||||
Return CType(obj,System.Drawing.Bitmap)
|
||||
End Get
|
||||
End Property
|
||||
End Module
|
||||
End Namespace
|
||||
127
SCrawler.Plugin.LPSG/My Project/Resources.resx
Normal file
@@ -0,0 +1,127 @@
|
||||
<?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>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="Icon32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Content\Icons\Icon32.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="IconPic_32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Content\Pictures\IconPic_32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
</root>
|
||||
73
SCrawler.Plugin.LPSG/My Project/Settings.Designer.vb
generated
Normal file
@@ -0,0 +1,73 @@
|
||||
'------------------------------------------------------------------------------
|
||||
' <auto-generated>
|
||||
' This code was generated by a tool.
|
||||
' Runtime Version:4.0.30319.42000
|
||||
'
|
||||
' Changes to this file may cause incorrect behavior and will be lost if
|
||||
' the code is regenerated.
|
||||
' </auto-generated>
|
||||
'------------------------------------------------------------------------------
|
||||
|
||||
Option Strict On
|
||||
Option Explicit On
|
||||
|
||||
|
||||
Namespace My
|
||||
|
||||
<Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
|
||||
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.10.0.0"), _
|
||||
Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||
Partial Friend NotInheritable Class MySettings
|
||||
Inherits Global.System.Configuration.ApplicationSettingsBase
|
||||
|
||||
Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings()),MySettings)
|
||||
|
||||
#Region "My.Settings Auto-Save Functionality"
|
||||
#If _MyType = "WindowsForms" Then
|
||||
Private Shared addedHandler As Boolean
|
||||
|
||||
Private Shared addedHandlerLockObject As New Object
|
||||
|
||||
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||
Private Shared Sub AutoSaveSettings(sender As Global.System.Object, e As Global.System.EventArgs)
|
||||
If My.Application.SaveMySettingsOnExit Then
|
||||
My.Settings.Save()
|
||||
End If
|
||||
End Sub
|
||||
#End If
|
||||
#End Region
|
||||
|
||||
Public Shared ReadOnly Property [Default]() As MySettings
|
||||
Get
|
||||
|
||||
#If _MyType = "WindowsForms" Then
|
||||
If Not addedHandler Then
|
||||
SyncLock addedHandlerLockObject
|
||||
If Not addedHandler Then
|
||||
AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings
|
||||
addedHandler = True
|
||||
End If
|
||||
End SyncLock
|
||||
End If
|
||||
#End If
|
||||
Return defaultInstance
|
||||
End Get
|
||||
End Property
|
||||
End Class
|
||||
End Namespace
|
||||
|
||||
Namespace My
|
||||
|
||||
<Global.Microsoft.VisualBasic.HideModuleNameAttribute(), _
|
||||
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
|
||||
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute()> _
|
||||
Friend Module MySettingsProperty
|
||||
|
||||
<Global.System.ComponentModel.Design.HelpKeywordAttribute("My.Settings")> _
|
||||
Friend ReadOnly Property Settings() As Global.LPSG.My.MySettings
|
||||
Get
|
||||
Return Global.LPSG.My.MySettings.Default
|
||||
End Get
|
||||
End Property
|
||||
End Module
|
||||
End Namespace
|
||||
7
SCrawler.Plugin.LPSG/My Project/Settings.settings
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" UseMySettingsClassName="true">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Settings />
|
||||
</SettingsFile>
|
||||
166
SCrawler.Plugin.LPSG/SCrawler.Plugin.LPSG.vbproj
Normal file
@@ -0,0 +1,166 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{22A130B2-DDF4-4FB5-BA38-E5DB4CF1B8A2}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>LPSG</RootNamespace>
|
||||
<AssemblyName>SCrawler.Plugin.LPSG</AssemblyName>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<MyType>Windows</MyType>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<DefineDebug>true</DefineDebug>
|
||||
<DefineTrace>true</DefineTrace>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DocumentationFile>
|
||||
</DocumentationFile>
|
||||
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<DefineDebug>false</DefineDebug>
|
||||
<DefineTrace>true</DefineTrace>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DocumentationFile>
|
||||
</DocumentationFile>
|
||||
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OptionExplicit>On</OptionExplicit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OptionCompare>Binary</OptionCompare>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OptionStrict>Off</OptionStrict>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OptionInfer>On</OptionInfer>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DefineDebug>true</DefineDebug>
|
||||
<DefineTrace>true</DefineTrace>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<DefineTrace>true</DefineTrace>
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DefineDebug>true</DefineDebug>
|
||||
<DefineTrace>true</DefineTrace>
|
||||
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<DefineTrace>true</DefineTrace>
|
||||
<OutputPath>bin\x86\Release\</OutputPath>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Import Include="Microsoft.VisualBasic" />
|
||||
<Import Include="PersonalUtilities.Functions" />
|
||||
<Import Include="PersonalUtilities.Tools.WEB" />
|
||||
<Import Include="SCrawler.Plugin" />
|
||||
<Import Include="SCrawler.Plugin.Attributes" />
|
||||
<Import Include="System" />
|
||||
<Import Include="System.Collections" />
|
||||
<Import Include="System.Collections.Generic" />
|
||||
<Import Include="System.Data" />
|
||||
<Import Include="System.Diagnostics" />
|
||||
<Import Include="System.Linq" />
|
||||
<Import Include="System.Xml.Linq" />
|
||||
<Import Include="System.Threading.Tasks" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Declarations.vb" />
|
||||
<Compile Include="My Project\AssemblyInfo.vb" />
|
||||
<Compile Include="My Project\Application.Designer.vb">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Application.myapp</DependentUpon>
|
||||
<DesignTime>True</DesignTime>
|
||||
</Compile>
|
||||
<Compile Include="My Project\Resources.Designer.vb">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="My Project\Settings.Designer.vb">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
<Compile Include="SiteSettings.vb" />
|
||||
<Compile Include="UserData.vb" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="My Project\Resources.resx">
|
||||
<Generator>VbMyResourcesResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.vb</LastGenOutput>
|
||||
<CustomToolNamespace>My.Resources</CustomToolNamespace>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include=".editorconfig" />
|
||||
<None Include="My Project\Application.myapp">
|
||||
<Generator>MyApplicationCodeGenerator</Generator>
|
||||
<LastGenOutput>Application.Designer.vb</LastGenOutput>
|
||||
</None>
|
||||
<None Include="My Project\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<CustomToolNamespace>My</CustomToolNamespace>
|
||||
<LastGenOutput>Settings.Designer.vb</LastGenOutput>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\MyUtilities\PersonalUtilities\PersonalUtilities.vbproj">
|
||||
<Project>{8405896b-2685-4916-bc93-1fb514c323a9}</Project>
|
||||
<Name>PersonalUtilities</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SCrawler.PluginProvider\SCrawler.PluginProvider.vbproj">
|
||||
<Project>{d4650f6b-5a54-44b6-999b-6c675b7116b1}</Project>
|
||||
<Name>SCrawler.PluginProvider</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Content\Icons\Icon32.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Content\Pictures\IconPic_32.png" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
|
||||
</Project>
|
||||
100
SCrawler.Plugin.LPSG/SiteSettings.vb
Normal file
@@ -0,0 +1,100 @@
|
||||
' 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.Drawing
|
||||
Imports PersonalUtilities.Functions.RegularExpressions
|
||||
<Manifest("AndyProgram_LPSG")>
|
||||
Public Class SiteSettings : Implements ISiteSettings
|
||||
Public ReadOnly Property Icon As Icon Implements ISiteSettings.Icon
|
||||
Get
|
||||
Return My.Resources.Icon32
|
||||
End Get
|
||||
End Property
|
||||
Public ReadOnly Property Image As Image Implements ISiteSettings.Image
|
||||
Get
|
||||
Return My.Resources.IconPic_32
|
||||
End Get
|
||||
End Property
|
||||
Public ReadOnly Property Site As String = "LPSG" Implements ISiteSettings.Site
|
||||
Public Property Logger As ILogProvider Implements ISiteSettings.Logger
|
||||
Friend ReadOnly Property Responser As Response
|
||||
Public Sub New()
|
||||
Responser = New Response($"Settings\Responser_LPSG.xml")
|
||||
With Responser
|
||||
If .File.Exists Then
|
||||
.LoadSettings()
|
||||
Else
|
||||
.CookiesDomain = "www.lpsg.com"
|
||||
.Cookies = New CookieKeeper("www.lpsg.com")
|
||||
End If
|
||||
End With
|
||||
End Sub
|
||||
Public Sub BeginInit() Implements ISiteSettings.BeginInit
|
||||
End Sub
|
||||
Public Sub EndInit() Implements ISiteSettings.EndInit
|
||||
End Sub
|
||||
Public Function GetInstance(ByVal What As ISiteSettings.Download) As IPluginContentProvider Implements ISiteSettings.GetInstance
|
||||
Return New UserData
|
||||
End Function
|
||||
Public Sub Load(ByVal XMLValues As IEnumerable(Of KeyValuePair(Of String, String))) Implements ISiteSettings.Load
|
||||
End Sub
|
||||
#Region "Download functions"
|
||||
Public Sub DownloadStarted(ByVal What As ISiteSettings.Download) Implements ISiteSettings.DownloadStarted
|
||||
End Sub
|
||||
Public Sub BeforeStartDownload(ByVal User As Object, ByVal What As ISiteSettings.Download) Implements ISiteSettings.BeforeStartDownload
|
||||
End Sub
|
||||
Public Sub AfterDownload(ByVal User As Object, ByVal What As ISiteSettings.Download) Implements ISiteSettings.AfterDownload
|
||||
End Sub
|
||||
Public Sub DownloadDone(ByVal What As ISiteSettings.Download) Implements ISiteSettings.DownloadDone
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Update"
|
||||
Public Sub BeginUpdate() Implements ISiteSettings.BeginUpdate
|
||||
End Sub
|
||||
Public Sub EndUpdate() Implements ISiteSettings.EndUpdate
|
||||
End Sub
|
||||
Public Sub Update() Implements ISiteSettings.Update
|
||||
Responser.SaveSettings()
|
||||
End Sub
|
||||
#End Region
|
||||
Public Sub Reset() Implements ISiteSettings.Reset
|
||||
End Sub
|
||||
Public Sub OpenSettingsForm() Implements ISiteSettings.OpenSettingsForm
|
||||
End Sub
|
||||
Public Sub UserOptions(ByRef Options As Object, ByVal OpenForm As Boolean) Implements ISiteSettings.UserOptions
|
||||
Options = Nothing
|
||||
End Sub
|
||||
Public Function GetUserUrl(ByVal UserName As String, ByVal Channel As Boolean) As String Implements ISiteSettings.GetUserUrl
|
||||
Return $"https://www.lpsg.com/threads/{UserName}/"
|
||||
End Function
|
||||
Private ReadOnly UserRegEx As RParams = RParams.DMS(".+?lpsg.com/threads/([^/]+)", 1)
|
||||
Public Function IsMyUser(ByVal UserURL As String) As ExchangeOptions Implements ISiteSettings.IsMyUser
|
||||
Try
|
||||
Dim r$ = RegexReplace(UserURL, UserRegEx)
|
||||
If Not r.IsEmptyString Then
|
||||
Return New ExchangeOptions(Site, r)
|
||||
Else
|
||||
Return Nothing
|
||||
End If
|
||||
Catch ex As Exception
|
||||
Return Nothing
|
||||
End Try
|
||||
End Function
|
||||
Public Function IsMyImageVideo(ByVal URL As String) As ExchangeOptions Implements ISiteSettings.IsMyImageVideo
|
||||
Return Nothing
|
||||
End Function
|
||||
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, 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
|
||||
Return True
|
||||
End Function
|
||||
End Class
|
||||
190
SCrawler.Plugin.LPSG/UserData.vb
Normal file
@@ -0,0 +1,190 @@
|
||||
' 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.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"
|
||||
#End Region
|
||||
#Region "Interface declarations"
|
||||
Public Event ProgressChanged(ByVal Count As Integer) Implements IPluginContentProvider.ProgressChanged
|
||||
Public Event TotalCountChanged(ByVal Count As Integer) Implements IPluginContentProvider.TotalCountChanged
|
||||
Public Property Thrower As IThrower Implements IPluginContentProvider.Thrower
|
||||
Public Property LogProvider As ILogProvider Implements IPluginContentProvider.LogProvider
|
||||
Public Property ESettings As ISiteSettings Implements IPluginContentProvider.Settings
|
||||
Private ReadOnly Property Settings As SiteSettings
|
||||
Get
|
||||
Return DirectCast(ESettings, SiteSettings)
|
||||
End Get
|
||||
End Property
|
||||
Public Property Name As String Implements IPluginContentProvider.Name
|
||||
Public Property ID As String Implements IPluginContentProvider.ID
|
||||
Public Property ParseUserMediaOnly As Boolean Implements IPluginContentProvider.ParseUserMediaOnly
|
||||
Public Property UserDescription As String Implements IPluginContentProvider.UserDescription
|
||||
Public Property ExistingContentList As List(Of PluginUserMedia) Implements IPluginContentProvider.ExistingContentList
|
||||
Public Property TempPostsList As List(Of String) Implements IPluginContentProvider.TempPostsList
|
||||
Public Property TempMediaList As List(Of PluginUserMedia) Implements IPluginContentProvider.TempMediaList
|
||||
Public Property UserExists As Boolean Implements IPluginContentProvider.UserExists
|
||||
Public Property UserSuspended As Boolean Implements IPluginContentProvider.UserSuspended
|
||||
Public Property IsSavedPosts As Boolean Implements IPluginContentProvider.IsSavedPosts
|
||||
Public Property SeparateVideoFolder As Boolean Implements IPluginContentProvider.SeparateVideoFolder
|
||||
Public Property DataPath As String Implements IPluginContentProvider.DataPath
|
||||
Public Property PostsNumberLimit As Integer? Implements IPluginContentProvider.PostsNumberLimit
|
||||
Public Property PostsDateLimit As Date? Implements IPluginContentProvider.PostsDateLimit
|
||||
#End Region
|
||||
#Region "Interface exchange options"
|
||||
Public Sub ExchangeOptionsSet(ByVal Obj As Object) Implements IPluginContentProvider.ExchangeOptionsSet
|
||||
End Sub
|
||||
Public Function ExchangeOptionsGet() As Object Implements IPluginContentProvider.ExchangeOptionsGet
|
||||
Return Nothing
|
||||
End Function
|
||||
#End Region
|
||||
#Region "Interface XML"
|
||||
Public Sub XmlFieldsSet(ByVal Fields As List(Of KeyValuePair(Of String, String))) Implements IPluginContentProvider.XmlFieldsSet
|
||||
If Fields.ListExists Then
|
||||
For Each f As KeyValuePair(Of String, String) In Fields
|
||||
If f.Key = Name_LatestPage Then LatestPage = f.Value
|
||||
Next
|
||||
End If
|
||||
End Sub
|
||||
Public Function XmlFieldsGet() As List(Of KeyValuePair(Of String, String)) Implements IPluginContentProvider.XmlFieldsGet
|
||||
Return New List(Of KeyValuePair(Of String, String)) From {New KeyValuePair(Of String, String)(Name_LatestPage, LatestPage)}
|
||||
End Function
|
||||
#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 NextPage$
|
||||
Dim r$
|
||||
Dim _LPage As Func(Of String) = Function() If(LatestPage.IsEmptyString, String.Empty, $"page-{LatestPage}")
|
||||
|
||||
Do
|
||||
r = Responser.GetResponse($"https://www.lpsg.com/threads/{Name}/{_LPage.Invoke}")
|
||||
UserExists = True
|
||||
UserSuspended = False
|
||||
Thrower.ThrowAny()
|
||||
If Not r.IsEmptyString Then
|
||||
NextPage = RegexReplace(r, NextPageRegex)
|
||||
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 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
|
||||
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 : .ResetError() : End With
|
||||
If TempMediaList.ListExists Then
|
||||
Dim m As PluginUserMedia
|
||||
Dim eweb As ErrorsDescriber = EDP.ThrowException
|
||||
RaiseEvent TotalCountChanged(TempMediaList.Count)
|
||||
For i% = 0 To TempMediaList.Count - 1
|
||||
Thrower.ThrowAny()
|
||||
m = TempMediaList(i)
|
||||
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 = UStates.Downloaded
|
||||
Else
|
||||
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
|
||||
End Try
|
||||
RaiseEvent ProgressChanged(1)
|
||||
TempMediaList(i) = m
|
||||
Next
|
||||
End If
|
||||
Catch oex As OperationCanceledException
|
||||
Catch dex As ObjectDisposedException
|
||||
Catch ex As Exception
|
||||
LogProvider.Add(ex, "[LPSG.UserData.Download]")
|
||||
End Try
|
||||
End Sub
|
||||
#Region "IDisposable Support"
|
||||
Private disposedValue As Boolean = False
|
||||
Protected Overridable Overloads Sub Dispose(ByVal disposing As Boolean)
|
||||
If Not disposedValue Then
|
||||
If disposing Then
|
||||
If Not Responser Is Nothing Then Responser.Dispose()
|
||||
If ExistingContentList.ListExists Then ExistingContentList.Clear()
|
||||
If TempPostsList.ListExists Then TempPostsList.Clear()
|
||||
If TempMediaList.ListExists Then TempMediaList.Clear()
|
||||
End If
|
||||
disposedValue = True
|
||||
End If
|
||||
End Sub
|
||||
Protected Overrides Sub Finalize()
|
||||
Dispose(False)
|
||||
MyBase.Finalize()
|
||||
End Sub
|
||||
Public Overloads Sub Dispose() Implements IDisposable.Dispose
|
||||
Dispose(True)
|
||||
GC.SuppressFinalize(Me)
|
||||
End Sub
|
||||
#End Region
|
||||
End Class
|
||||
3
SCrawler.Plugin.XVIDEOS/.editorconfig
Normal file
@@ -0,0 +1,3 @@
|
||||
[*.vb]
|
||||
# Modifier preferences
|
||||
file_header_template = Copyright (C) 2022 Andy\nThis program is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
BIN
SCrawler.Plugin.XVIDEOS/Content/Icons/Icon32.ico
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
SCrawler.Plugin.XVIDEOS/Content/Pictures/IconPic32.png
Normal file
|
After Width: | Height: | Size: 1016 B |
16
SCrawler.Plugin.XVIDEOS/Declarations.vb
Normal file
@@ -0,0 +1,16 @@
|
||||
' 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.RegularExpressions
|
||||
Friend Module Declarations
|
||||
Friend ReadOnly Property M3U8Regex As RParams = RParams.DM("http.+?.m3u8.*?(?=')", 0)
|
||||
Friend ReadOnly Property VideoTitleRegex As RParams = RParams.DMS("html5player.setVideoTitle\('(.+)(?='\);)", 1)
|
||||
Friend ReadOnly Property VideoID As RParams = RParams.DMS(".*?www.xvideos.com/(video\d+).*", 1)
|
||||
Friend ReadOnly Property M3U8Reparse As RParams = RParams.DM("NAME=""(\d+).*?""[\r\n]*?(.+)(?=(|[\r\n]+?))", 0, RegexReturn.List)
|
||||
Friend ReadOnly Property M3U8Appender As RParams = RParams.DM("(.+)(?=/.+?\.m3u8.*?)", 0)
|
||||
End Module
|
||||
69
SCrawler.Plugin.XVIDEOS/M3U8.vb
Normal file
@@ -0,0 +1,69 @@
|
||||
' 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.Net
|
||||
Imports PersonalUtilities.Tools.WEB
|
||||
Friend NotInheritable Class M3U8
|
||||
Private Sub New()
|
||||
End Sub
|
||||
Private Shared Function Save(ByVal URLs As List(Of String), ByVal ffmpegFile As SFile, ByVal f As SFile, ByRef Logger As ILogProvider) As SFile
|
||||
Dim CachePath As SFile = Nothing
|
||||
Try
|
||||
If URLs.ListExists Then
|
||||
Dim ConcatFile As SFile = f
|
||||
If ConcatFile.Name.IsEmptyString Then ConcatFile.Name = "PlayListFile"
|
||||
ConcatFile.Extension = "mp4"
|
||||
CachePath = $"{f.PathWithSeparator}_Cache\{SFile.GetDirectories($"{f.PathWithSeparator}_Cache\",,, EDP.ReturnValue).ListIfNothing.Count + 1}\"
|
||||
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)
|
||||
Dim i%
|
||||
Dim eFiles As New List(Of SFile)
|
||||
Dim dFile As SFile = CachePath
|
||||
dFile.Extension = "ts"
|
||||
Using w As New WebClient
|
||||
For i = 0 To URLs.Count - 1
|
||||
dFile.Name = $"ConPart_{i}"
|
||||
w.DownloadFile(URLs(i), dFile)
|
||||
eFiles.Add(dFile)
|
||||
Next
|
||||
End Using
|
||||
f = FFMPEG.ConcatenateFiles(eFiles, ffmpegFile, ConcatFile, p, EDP.ThrowException)
|
||||
eFiles.Clear()
|
||||
Return f
|
||||
End If
|
||||
End If
|
||||
Return Nothing
|
||||
Catch ex As Exception
|
||||
Logger.Add(ex, "[M3U8.Save]")
|
||||
ex.HelpLink = 1
|
||||
Throw ex
|
||||
Finally
|
||||
CachePath.Delete(SFO.Path, SFODelete.None, EDP.None)
|
||||
End Try
|
||||
End Function
|
||||
Friend Shared Function Download(ByVal URL As String, ByVal Appender As String, ByVal ffmpegFile As SFile, ByVal f As SFile,
|
||||
ByRef Logger As ILogProvider) As SFile
|
||||
Try
|
||||
If Not URL.IsEmptyString Then
|
||||
Using w As New WebClient
|
||||
Dim r$ = w.DownloadString(URL)
|
||||
If Not r.IsEmptyString Then
|
||||
Dim l As List(Of String) = ListAddList(Nothing, r.StringFormatLines.StringToList(Of String)(vbNewLine).ListWithRemove(Function(v) v.Trim.StartsWith("#")),
|
||||
New ListAddParams With {.Converter = Function(Input) $"{Appender}/{Input.ToString.Trim}"})
|
||||
If l.ListExists Then Return Save(l, ffmpegFile, f, Logger)
|
||||
End If
|
||||
End Using
|
||||
End If
|
||||
Return Nothing
|
||||
Catch ex As Exception
|
||||
If Not ex.HelpLink = 1 Then Logger.Add(ex, "[M3U8.Download]")
|
||||
Throw ex
|
||||
End Try
|
||||
End Function
|
||||
End Class
|
||||
13
SCrawler.Plugin.XVIDEOS/My Project/Application.Designer.vb
generated
Normal file
@@ -0,0 +1,13 @@
|
||||
'------------------------------------------------------------------------------
|
||||
' <auto-generated>
|
||||
' This code was generated by a tool.
|
||||
' Runtime Version:4.0.30319.42000
|
||||
'
|
||||
' Changes to this file may cause incorrect behavior and will be lost if
|
||||
' the code is regenerated.
|
||||
' </auto-generated>
|
||||
'------------------------------------------------------------------------------
|
||||
|
||||
Option Strict On
|
||||
Option Explicit On
|
||||
|
||||
10
SCrawler.Plugin.XVIDEOS/My Project/Application.myapp
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<MyApplicationData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<MySubMain>false</MySubMain>
|
||||
<SingleInstance>false</SingleInstance>
|
||||
<ShutdownMode>0</ShutdownMode>
|
||||
<EnableVisualStyles>true</EnableVisualStyles>
|
||||
<AuthenticationMode>0</AuthenticationMode>
|
||||
<ApplicationType>1</ApplicationType>
|
||||
<SaveMySettingsOnExit>true</SaveMySettingsOnExit>
|
||||
</MyApplicationData>
|
||||
37
SCrawler.Plugin.XVIDEOS/My Project/AssemblyInfo.vb
Normal file
@@ -0,0 +1,37 @@
|
||||
Imports System.Resources
|
||||
Imports System
|
||||
Imports System.Reflection
|
||||
Imports System.Runtime.InteropServices
|
||||
|
||||
' General Information about an assembly is controlled through the following
|
||||
' set of attributes. Change these attribute values to modify the information
|
||||
' associated with an assembly.
|
||||
|
||||
' Review the values of the assembly attributes
|
||||
|
||||
<Assembly: AssemblyTitle("XVIDEOS")>
|
||||
<Assembly: AssemblyDescription("XVIDEOS plugin for SCrawler")>
|
||||
<Assembly: AssemblyCompany("AndyProgram")>
|
||||
<Assembly: AssemblyProduct("XVIDEOS")>
|
||||
<Assembly: AssemblyCopyright("Copyright © 2022")>
|
||||
<Assembly: AssemblyTrademark("AndyProgram")>
|
||||
|
||||
<Assembly: ComVisible(False)>
|
||||
|
||||
'The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
<Assembly: Guid("d31a0e3b-081d-4155-9a41-4c0a641c87b6")>
|
||||
|
||||
' Version information for an assembly consists of the following four values:
|
||||
'
|
||||
' Major Version
|
||||
' Minor Version
|
||||
' Build Number
|
||||
' Revision
|
||||
'
|
||||
' You can specify all the values or you can default the Build and Revision Numbers
|
||||
' by using the '*' as shown below:
|
||||
' <Assembly: AssemblyVersion("1.0.*")>
|
||||
|
||||
<Assembly: AssemblyVersion("2022.6.7.0")>
|
||||
<Assembly: AssemblyFileVersion("2022.6.7.0")>
|
||||
<Assembly: NeutralResourcesLanguage("en")>
|
||||
83
SCrawler.Plugin.XVIDEOS/My Project/Resources.Designer.vb
generated
Normal file
@@ -0,0 +1,83 @@
|
||||
'------------------------------------------------------------------------------
|
||||
' <auto-generated>
|
||||
' This code was generated by a tool.
|
||||
' Runtime Version:4.0.30319.42000
|
||||
'
|
||||
' Changes to this file may cause incorrect behavior and will be lost if
|
||||
' the code is regenerated.
|
||||
' </auto-generated>
|
||||
'------------------------------------------------------------------------------
|
||||
|
||||
Option Strict On
|
||||
Option Explicit On
|
||||
|
||||
Imports System
|
||||
|
||||
Namespace My.Resources
|
||||
|
||||
'This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
'class via a tool like ResGen or Visual Studio.
|
||||
'To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
'with the /str option, or rebuild your VS project.
|
||||
'''<summary>
|
||||
''' A strongly-typed resource class, for looking up localized strings, etc.
|
||||
'''</summary>
|
||||
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0"), _
|
||||
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
|
||||
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
|
||||
Global.Microsoft.VisualBasic.HideModuleNameAttribute()> _
|
||||
Friend Module Resources
|
||||
|
||||
Private resourceMan As Global.System.Resources.ResourceManager
|
||||
|
||||
Private resourceCulture As Global.System.Globalization.CultureInfo
|
||||
|
||||
'''<summary>
|
||||
''' Returns the cached ResourceManager instance used by this class.
|
||||
'''</summary>
|
||||
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||
Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager
|
||||
Get
|
||||
If Object.ReferenceEquals(resourceMan, Nothing) Then
|
||||
Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("XVIDEOS.Resources", GetType(Resources).Assembly)
|
||||
resourceMan = temp
|
||||
End If
|
||||
Return resourceMan
|
||||
End Get
|
||||
End Property
|
||||
|
||||
'''<summary>
|
||||
''' Overrides the current thread's CurrentUICulture property for all
|
||||
''' resource lookups using this strongly typed resource class.
|
||||
'''</summary>
|
||||
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||
Friend Property Culture() As Global.System.Globalization.CultureInfo
|
||||
Get
|
||||
Return resourceCulture
|
||||
End Get
|
||||
Set
|
||||
resourceCulture = value
|
||||
End Set
|
||||
End Property
|
||||
|
||||
'''<summary>
|
||||
''' Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
|
||||
'''</summary>
|
||||
Friend ReadOnly Property Icon32() As System.Drawing.Icon
|
||||
Get
|
||||
Dim obj As Object = ResourceManager.GetObject("Icon32", resourceCulture)
|
||||
Return CType(obj,System.Drawing.Icon)
|
||||
End Get
|
||||
End Property
|
||||
|
||||
'''<summary>
|
||||
''' Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
'''</summary>
|
||||
Friend ReadOnly Property IconPic32() As System.Drawing.Bitmap
|
||||
Get
|
||||
Dim obj As Object = ResourceManager.GetObject("IconPic32", resourceCulture)
|
||||
Return CType(obj,System.Drawing.Bitmap)
|
||||
End Get
|
||||
End Property
|
||||
End Module
|
||||
End Namespace
|
||||
127
SCrawler.Plugin.XVIDEOS/My Project/Resources.resx
Normal file
@@ -0,0 +1,127 @@
|
||||
<?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>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="Icon32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Content\Icons\Icon32.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="IconPic32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Content\Pictures\IconPic32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
</root>
|
||||
73
SCrawler.Plugin.XVIDEOS/My Project/Settings.Designer.vb
generated
Normal file
@@ -0,0 +1,73 @@
|
||||
'------------------------------------------------------------------------------
|
||||
' <auto-generated>
|
||||
' This code was generated by a tool.
|
||||
' Runtime Version:4.0.30319.42000
|
||||
'
|
||||
' Changes to this file may cause incorrect behavior and will be lost if
|
||||
' the code is regenerated.
|
||||
' </auto-generated>
|
||||
'------------------------------------------------------------------------------
|
||||
|
||||
Option Strict On
|
||||
Option Explicit On
|
||||
|
||||
|
||||
Namespace My
|
||||
|
||||
<Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
|
||||
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.10.0.0"), _
|
||||
Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||
Partial Friend NotInheritable Class MySettings
|
||||
Inherits Global.System.Configuration.ApplicationSettingsBase
|
||||
|
||||
Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings()),MySettings)
|
||||
|
||||
#Region "My.Settings Auto-Save Functionality"
|
||||
#If _MyType = "WindowsForms" Then
|
||||
Private Shared addedHandler As Boolean
|
||||
|
||||
Private Shared addedHandlerLockObject As New Object
|
||||
|
||||
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||
Private Shared Sub AutoSaveSettings(sender As Global.System.Object, e As Global.System.EventArgs)
|
||||
If My.Application.SaveMySettingsOnExit Then
|
||||
My.Settings.Save()
|
||||
End If
|
||||
End Sub
|
||||
#End If
|
||||
#End Region
|
||||
|
||||
Public Shared ReadOnly Property [Default]() As MySettings
|
||||
Get
|
||||
|
||||
#If _MyType = "WindowsForms" Then
|
||||
If Not addedHandler Then
|
||||
SyncLock addedHandlerLockObject
|
||||
If Not addedHandler Then
|
||||
AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings
|
||||
addedHandler = True
|
||||
End If
|
||||
End SyncLock
|
||||
End If
|
||||
#End If
|
||||
Return defaultInstance
|
||||
End Get
|
||||
End Property
|
||||
End Class
|
||||
End Namespace
|
||||
|
||||
Namespace My
|
||||
|
||||
<Global.Microsoft.VisualBasic.HideModuleNameAttribute(), _
|
||||
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
|
||||
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute()> _
|
||||
Friend Module MySettingsProperty
|
||||
|
||||
<Global.System.ComponentModel.Design.HelpKeywordAttribute("My.Settings")> _
|
||||
Friend ReadOnly Property Settings() As Global.XVIDEOS.My.MySettings
|
||||
Get
|
||||
Return Global.XVIDEOS.My.MySettings.Default
|
||||
End Get
|
||||
End Property
|
||||
End Module
|
||||
End Namespace
|
||||
7
SCrawler.Plugin.XVIDEOS/My Project/Settings.settings
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" UseMySettingsClassName="true">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Settings />
|
||||
</SettingsFile>
|
||||
175
SCrawler.Plugin.XVIDEOS/SCrawler.Plugin.XVIDEOS.vbproj
Normal file
@@ -0,0 +1,175 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{CCCF47F4-C97C-4193-AC4B-C56DF2F9AA8A}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>XVIDEOS</RootNamespace>
|
||||
<AssemblyName>SCrawler.Plugin.XVIDEOS</AssemblyName>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<MyType>Windows</MyType>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<DefineDebug>true</DefineDebug>
|
||||
<DefineTrace>true</DefineTrace>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DocumentationFile>
|
||||
</DocumentationFile>
|
||||
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<DefineDebug>false</DefineDebug>
|
||||
<DefineTrace>true</DefineTrace>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DocumentationFile>
|
||||
</DocumentationFile>
|
||||
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OptionExplicit>On</OptionExplicit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OptionCompare>Binary</OptionCompare>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OptionStrict>Off</OptionStrict>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OptionInfer>On</OptionInfer>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DefineDebug>true</DefineDebug>
|
||||
<DefineTrace>true</DefineTrace>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<DefineTrace>true</DefineTrace>
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DefineDebug>true</DefineDebug>
|
||||
<DefineTrace>true</DefineTrace>
|
||||
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<DefineTrace>true</DefineTrace>
|
||||
<OutputPath>bin\x86\Release\</OutputPath>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Import Include="Microsoft.VisualBasic" />
|
||||
<Import Include="PersonalUtilities.Functions" />
|
||||
<Import Include="SCrawler.Plugin" />
|
||||
<Import Include="SCrawler.Plugin.Attributes" />
|
||||
<Import Include="System" />
|
||||
<Import Include="System.Collections" />
|
||||
<Import Include="System.Collections.Generic" />
|
||||
<Import Include="System.Data" />
|
||||
<Import Include="System.Diagnostics" />
|
||||
<Import Include="System.Linq" />
|
||||
<Import Include="System.Xml.Linq" />
|
||||
<Import Include="System.Threading.Tasks" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Declarations.vb" />
|
||||
<Compile Include="M3U8.vb" />
|
||||
<Compile Include="My Project\AssemblyInfo.vb" />
|
||||
<Compile Include="My Project\Application.Designer.vb">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Application.myapp</DependentUpon>
|
||||
<DesignTime>True</DesignTime>
|
||||
</Compile>
|
||||
<Compile Include="My Project\Resources.Designer.vb">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="My Project\Settings.Designer.vb">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
<Compile Include="SettingsForm.Designer.vb">
|
||||
<DependentUpon>SettingsForm.vb</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="SettingsForm.vb">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="SiteSettings.vb" />
|
||||
<Compile Include="UserData.vb" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="My Project\Resources.resx">
|
||||
<Generator>VbMyResourcesResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.vb</LastGenOutput>
|
||||
<CustomToolNamespace>My.Resources</CustomToolNamespace>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="SettingsForm.resx">
|
||||
<DependentUpon>SettingsForm.vb</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include=".editorconfig" />
|
||||
<None Include="My Project\Application.myapp">
|
||||
<Generator>MyApplicationCodeGenerator</Generator>
|
||||
<LastGenOutput>Application.Designer.vb</LastGenOutput>
|
||||
</None>
|
||||
<None Include="My Project\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<CustomToolNamespace>My</CustomToolNamespace>
|
||||
<LastGenOutput>Settings.Designer.vb</LastGenOutput>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\MyUtilities\PersonalUtilities\PersonalUtilities.vbproj">
|
||||
<Project>{8405896b-2685-4916-bc93-1fb514c323a9}</Project>
|
||||
<Name>PersonalUtilities</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SCrawler.PluginProvider\SCrawler.PluginProvider.vbproj">
|
||||
<Project>{d4650f6b-5a54-44b6-999b-6c675b7116b1}</Project>
|
||||
<Name>SCrawler.PluginProvider</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Content\Pictures\IconPic32.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Content\Icons\Icon32.ico" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
|
||||
</Project>
|
||||
129
SCrawler.Plugin.XVIDEOS/SettingsForm.Designer.vb
generated
Normal file
@@ -0,0 +1,129 @@
|
||||
' 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
|
||||
|
||||
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()>
|
||||
Partial Public Class SettingsForm : 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 resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(SettingsForm))
|
||||
Me.LIST_DOMAINS = New System.Windows.Forms.ListBox()
|
||||
Me.ToolbarTOP = New System.Windows.Forms.ToolStrip()
|
||||
Me.BTT_ADD = New System.Windows.Forms.ToolStripButton()
|
||||
Me.BTT_DELETE = New System.Windows.Forms.ToolStripButton()
|
||||
CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer()
|
||||
CONTAINER_MAIN.ContentPanel.SuspendLayout()
|
||||
CONTAINER_MAIN.TopToolStripPanel.SuspendLayout()
|
||||
CONTAINER_MAIN.SuspendLayout()
|
||||
Me.ToolbarTOP.SuspendLayout()
|
||||
Me.SuspendLayout()
|
||||
'
|
||||
'CONTAINER_MAIN
|
||||
'
|
||||
'
|
||||
'CONTAINER_MAIN.ContentPanel
|
||||
'
|
||||
CONTAINER_MAIN.ContentPanel.Controls.Add(Me.LIST_DOMAINS)
|
||||
CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(384, 266)
|
||||
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(384, 291)
|
||||
CONTAINER_MAIN.TabIndex = 0
|
||||
'
|
||||
'CONTAINER_MAIN.TopToolStripPanel
|
||||
'
|
||||
CONTAINER_MAIN.TopToolStripPanel.Controls.Add(Me.ToolbarTOP)
|
||||
'
|
||||
'LIST_DOMAINS
|
||||
'
|
||||
Me.LIST_DOMAINS.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.LIST_DOMAINS.FormattingEnabled = True
|
||||
Me.LIST_DOMAINS.Location = New System.Drawing.Point(0, 0)
|
||||
Me.LIST_DOMAINS.Name = "LIST_DOMAINS"
|
||||
Me.LIST_DOMAINS.Size = New System.Drawing.Size(384, 266)
|
||||
Me.LIST_DOMAINS.TabIndex = 0
|
||||
'
|
||||
'ToolbarTOP
|
||||
'
|
||||
Me.ToolbarTOP.Dock = System.Windows.Forms.DockStyle.None
|
||||
Me.ToolbarTOP.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden
|
||||
Me.ToolbarTOP.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_ADD, Me.BTT_DELETE})
|
||||
Me.ToolbarTOP.Location = New System.Drawing.Point(0, 0)
|
||||
Me.ToolbarTOP.Name = "ToolbarTOP"
|
||||
Me.ToolbarTOP.Size = New System.Drawing.Size(384, 25)
|
||||
Me.ToolbarTOP.Stretch = True
|
||||
Me.ToolbarTOP.TabIndex = 0
|
||||
'
|
||||
'BTT_ADD
|
||||
'
|
||||
Me.BTT_ADD.AutoToolTip = False
|
||||
Me.BTT_ADD.BackColor = System.Drawing.Color.FromArgb(CType(CType(192, Byte), Integer), CType(CType(255, Byte), Integer), CType(CType(192, Byte), Integer))
|
||||
Me.BTT_ADD.ForeColor = System.Drawing.Color.DarkGreen
|
||||
Me.BTT_ADD.Image = CType(resources.GetObject("BTT_ADD.Image"), System.Drawing.Image)
|
||||
Me.BTT_ADD.ImageTransparentColor = System.Drawing.Color.Magenta
|
||||
Me.BTT_ADD.Name = "BTT_ADD"
|
||||
Me.BTT_ADD.Size = New System.Drawing.Size(49, 22)
|
||||
Me.BTT_ADD.Text = "Add"
|
||||
'
|
||||
'BTT_DELETE
|
||||
'
|
||||
Me.BTT_DELETE.AutoToolTip = False
|
||||
Me.BTT_DELETE.BackColor = System.Drawing.Color.FromArgb(CType(CType(255, Byte), Integer), CType(CType(192, Byte), Integer), CType(CType(192, Byte), Integer))
|
||||
Me.BTT_DELETE.ForeColor = System.Drawing.Color.Maroon
|
||||
Me.BTT_DELETE.Image = CType(resources.GetObject("BTT_DELETE.Image"), System.Drawing.Image)
|
||||
Me.BTT_DELETE.ImageTransparentColor = System.Drawing.Color.Magenta
|
||||
Me.BTT_DELETE.Name = "BTT_DELETE"
|
||||
Me.BTT_DELETE.Size = New System.Drawing.Size(60, 22)
|
||||
Me.BTT_DELETE.Text = "Delete"
|
||||
'
|
||||
'SettingsForm
|
||||
'
|
||||
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
|
||||
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
|
||||
Me.ClientSize = New System.Drawing.Size(384, 291)
|
||||
Me.Controls.Add(CONTAINER_MAIN)
|
||||
Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle
|
||||
Me.Icon = CType(resources.GetObject("$this.Icon"), System.Drawing.Icon)
|
||||
Me.MaximizeBox = False
|
||||
Me.MaximumSize = New System.Drawing.Size(400, 330)
|
||||
Me.MinimizeBox = False
|
||||
Me.MinimumSize = New System.Drawing.Size(400, 330)
|
||||
Me.Name = "SettingsForm"
|
||||
Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide
|
||||
Me.Text = "Settings"
|
||||
CONTAINER_MAIN.ContentPanel.ResumeLayout(False)
|
||||
CONTAINER_MAIN.TopToolStripPanel.ResumeLayout(False)
|
||||
CONTAINER_MAIN.TopToolStripPanel.PerformLayout()
|
||||
CONTAINER_MAIN.ResumeLayout(False)
|
||||
CONTAINER_MAIN.PerformLayout()
|
||||
Me.ToolbarTOP.ResumeLayout(False)
|
||||
Me.ToolbarTOP.PerformLayout()
|
||||
Me.ResumeLayout(False)
|
||||
|
||||
End Sub
|
||||
|
||||
Private WithEvents LIST_DOMAINS As Windows.Forms.ListBox
|
||||
Private WithEvents ToolbarTOP As Windows.Forms.ToolStrip
|
||||
Private WithEvents BTT_ADD As Windows.Forms.ToolStripButton
|
||||
Private WithEvents BTT_DELETE As Windows.Forms.ToolStripButton
|
||||
End Class
|
||||
477
SCrawler.Plugin.XVIDEOS/SettingsForm.resx
Normal file
@@ -0,0 +1,477 @@
|
||||
<?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>
|
||||
<metadata name="ToolbarTOP.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="BTT_ADD.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAN+SURBVEhLrZVZSFRRGMdvKa6oE5Y1bpTtRY2pJYk3ayyd
|
||||
xgrvaDXlQotLKVqSo7QR2QIREUX0EgUSET1V9NTyYBHt6ZTOqNPY7DomWNbriX/fuYzkg2jY/eAPM5zD
|
||||
//+d7/7OvcJkFXIlqDX0ahDGE18LbJt6cSOtWWTaDhGbPonQdZEsIrY7cuWQwLapFzfZ9FlkES8ERL8W
|
||||
EPteQMLHYFR69coFUNcs5o2AWe+nYW5HKFK7otHkL1IuoKBbZLzzFHMo0qwxWN8zG2eHSpULkGxalmIO
|
||||
w2qrCvm2eJr/AlwZrlIuYN9XHcuwqKC3JWC3czGqXKm4OVKvXMARTyHTfUlEmWspatxp9D8Ld0ZM/xYw
|
||||
EeejMnkMv0tdS1DnzkBzv4jT/jy0fm/EzLvhE0p9P7JV7jB3lHHiu6BHhMGmRbkjH3WebTjq245z/nL6
|
||||
nYFjvnVo8efjzKAOrcONuD1skoNuDNfj8lAFWgZL0OQrphEWoMa1E+oHkZADuHn0K2L8rYDEjhBoCENO
|
||||
itSXgr2u5TjkycTx/g1koMP5Qb0ccHogj8xEVLlTsaNvIXJ750BjiUZSewhU5LPTIv0N4J1zc76osUTR
|
||||
ZjWKAuaHvZk44dPijF9HAXk4OaCFyZdNzyIde5zLUGifh5yeOKzoikJ8RzBU7wSE06Us+jQmoMAqIpnM
|
||||
U6mDXJtaxrDSrUGDdw2O9a/HCTI96suByZuNw57VqKa1MtcybLXPxTo6qWzeHgx+Gbn5tCcCpHdjAnbZ
|
||||
NmKtNZYwTESJYwnq6WE2EinNZMhNj3izZDXQqKppJJymLfZkZHfHYWlnJNQfghBFIw5rEyA8Jj2ggJdj
|
||||
Ag769cw0ZGAtP8rYhZH97NLPanbpVxW7/PMAu/atlnSQzNeg0qWB0bkIensSmj3lqHUaf1d4ilipU2LG
|
||||
LxIzWCUmfSZ9JL2VmBzAMR0PsVHxTbeGmlmleyWMjoXYTKfMpNPWuI3y2oTimE5WfOP1bw1sBz2X/N4E
|
||||
pNONnm8Oxx6HQTYJbJt6cZOLAzUsrzdeftHxt2kskbLbFpjx/xY3OeWtYKssMUgkUmYQzvzbUDzK+f8W
|
||||
N6l3lbCk9lCoCMOI5wKCnhIlZgUD9tkNjJuHUefTOYaPKOCNggEl3RILp84FukDCQ9I9CnihYEBxpySP
|
||||
hNiWL5DURnqmVACxzI3G1aScC8If1IGynvf45pQAAAAASUVORK5CYII=
|
||||
</value>
|
||||
</data>
|
||||
<data name="BTT_DELETE.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAVFSURBVEhLjZVrTJNXGMcLQmdHO6Sdt6ygAyYgN+1bS+uE
|
||||
4ASlxVfSUkFkRMyouILinShGYzTRKCZL9mH7sH3YMj+YzUSXZXNeQOcEFkFhysbVQWlL6dsLvMwtWaBn
|
||||
/1OKl1A2nuSX8p7znP/z5znnPa+ARntubkRjXNxnd5Ys6b2xbNmn+XL5WxgO80/+T/SoVOo/YmLu9S9d
|
||||
+uhqfLwRQxEgxD9J44nZLH6Qm/tNT20tGbh4kTw9dMh3Q6NpyJBI3sF0+FRW8OhimHX2kpJB/vx5Ml5f
|
||||
TwaKitwfJyZWxURGRmF6qkhDXNwn3QcOkKenTpGBkyeJFcmWI0fIdbX6XppEsgIpQYv0aTTvQdzCX7hA
|
||||
eKzl6+rI+IkTpJdlPd/K5R8hRQrCBHdkMisVh3MyeOwYsSJp+OxZYq2t9d1QqX5OlUgSkPhKEbRlo724
|
||||
2EqdU/FxiPOHD5NxGPOWlZHGxYs7kaYGEsGt6OhLvRUVZAAFLMB69CixY8HImTPEjnbdVqubU8TiRCT7
|
||||
i/QoFBuHi4qsY+fOER5mxmGKx7rx/fvJ6O7dpEGl4splsq+RqgNSgWH58mXXlcp7/Tt3+oaQZAPDcDOC
|
||||
PXGhZc6DB8kdFFktFic9ZJhcm9FoHzt92t8SHo55tJevqSFjEL+rUrkTRKIvIWwCaYBuuCCckckSUaTZ
|
||||
smMHse/ZQxzV1WRk3z7CoZiH/jfV1b4WjaZjsKDAyh8/7nfMY45HLl9VNSWuVLqTRKJL0KsAyQHxUOAP
|
||||
4WqpNOlHhaJpqLTU56isJE7gMpuJGwJeFPPu3UvG4HaMCuOZx7NfHO1t0mg86WIxFafOV4L54MVRDYRQ
|
||||
JZWuvJWe3mzfupU4y8uJC3hMJuKFw1EUHMUGjhYUEO/69cSr0RA3aMrI8K6WSC5j/S5AnYvADPHpEK6J
|
||||
ikpuSEtrtrHshHvbNuLSaomLYQgnlxNOIiFceDjh5s0jI2Kx73ZsrEcdFUU3tBKkgNfBrOLT4W/Xg/T0
|
||||
9mEIOqgYcAIq7CcsjPzOMH8bExO/R/6HIBXMSdwf9rIys33dOotDJJopDuiYNT5+opFl+5OiowuwJBLM
|
||||
TdxrMh3kNmzgHHA/m7gNDAJLcjJ5VFjYuX3t2lVY+p/Xij9cJlMdt2mTyxERMUPcid7TdlHxAdAbGkqe
|
||||
gO5Vq3zthYW/GdVq2qbZi3h27TrG5eW5gzl3ymRkKC/vH3tCgo+K9wTE20ATeMwwk+1GY+f22YrgKNZx
|
||||
Wq3HIRb7hV9py6JFpEun+/N0VlZL2+bNw5akJPIYoq3gPvgJNIL2NWsmW43Gjg1pafSCfHHVuysqajmd
|
||||
zoNjN1N84ULSk5//rIphbiG1Oi8l5f1Ovb6/C72fFm8AN8F10KpSTbYUFrZ9wbJ044UgROA2GKwjCxYE
|
||||
dU7FKxWKm0g0A7qR0n3Z2e92GAx9Hampz8V/AN+Ba6A9K2ui1WDoRu5yIBQ4jcYud0xMUOdmhrmNpKqA
|
||||
+PSXSrg/J0eNje1rS031vSx+JSSEtGZmTtxlWRvyckGUoKW0tGSYZV0uiL7k/K89wcWnQ1iTnZ2Bje3F
|
||||
C0muBsRxbUxe1mqHdCtWfI6cqQKI+TeLio5bt2zxONVqX49O96xGqWzA+Gzi0yE0ZWYqaDtase4XjWby
|
||||
ilZre0MkqsecHky1CBHCxMZGPjQYvnqq1zsv5+Tg9IXWYJwBYjpPk2YJ4bXi4g9+1ett91mW0yYk0G+B
|
||||
AcgBPa7P19I/FgAlyA/8zvX1fw3Qo0lPzmbwNgj6ws0D1DH9WNNf+jyXoCbo/f9mAFowYEwg+Bc5Ntw7
|
||||
FHW1qQAAAABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
AAABAAUAEBAAAAEAIABoBAAAVgAAABgYAAABACAAiAkAAL4EAAAgIAAAAQAIAKgIAABGDgAAMDAAAAEA
|
||||
IACoJQAA7hYAACAgAAABAAgAqAgAAJY8AAAoAAAAEAAAACAAAAABACAAAAAAAAAEAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAIO/wADF/8AAxb/AAEJ/wAAAP8AAAD/AAAA/wAAAP8AAQb/AAMV/wAD
|
||||
F/8AAhL/AAAC/wAAAP8AAAD/AAAA/wAHMv8AFoz/ABiW/wAQaf8AAQz/AAAA/wAAAP8AAAT/AAxU/wAY
|
||||
lP8AGJP/AAtJ/wAAAv8AAAD/AAAA/wAAAP8AAQ3/ABOQ/wAh3v8AH9T/AAtb/wAAAf8AAAD/AAc7/wAc
|
||||
x/8AIeD/ABis/wADHv8AAAD/AAAA/wAAAP8AAAD/AAAA/wAFK/8AG73/ACLk/wAbvf8ABSr/AAIV/wAW
|
||||
o/8AIuP/AB7P/wAIRv8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAH/AAtZ/wAf1v8AIeH/ABSU/wAQ
|
||||
e/8AINz/ACDe/wAPdv8AAAX/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wABC/8AE4z/ACHg/wAg
|
||||
2/8AINn/ACHi/wAXpf8AAhn/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAQm/wAa
|
||||
t/8AIeH/ACHh/wAdyP8ABzr/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAB
|
||||
C/8AFZj/ACHi/wAh4f8AG7r/AAQh/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AClH/AB7S/wAh4P8AIeD/ACHe/wAQfP8AAAb/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8ABCX/ABq2/wAi4/8AGrn/ABag/wAh4P8AHtD/AAlH/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAQr/ABKI/wAh4f8AH9X/AApQ/wAEKP8AG7v/ACLk/wAYrv8AAx7/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/Ag1W/wIi1/8CJOP/ABOL/wABCv8AAAD/AAxc/wIi2f8CJOL/AhN//wABB/8AAAD/AAAA/wAA
|
||||
AP8AAAD/CQ0h/ylBsv8vTt7/Iz67/wMJKv8AAAD/AAAA/wACEP8aMJr/L07e/y1Iyv8RGD//AAAA/wAA
|
||||
AP8AAAD/AAAA/wUHEP8RFzL/Ehg0/wwQI/8BAQL/AAAA/wAAAP8AAAD/CAsY/xIYM/8SGDT/CAsZ/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAoAAAAGAAAADAAAAABACAAAAAAAAAJAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAEM/wADG/8AAxr/AAMa/wADFv8AAQT/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAB/wACEf8AAxv/AAMa/wADG/8AAhT/AAAC/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAQk/wAT
|
||||
dv8AF4b/ABeF/wAVgP8ACT7/AAAC/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAQl/wATdP8AF4X/ABeF/wAW
|
||||
gf8ACUD/AAAD/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAI/wAOav8AHcX/AB/K/wAfyv8AGaz/AAQv/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AART/ABKL/wAeyf8AH8r/AB/L/wAVkv8AAhr/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wADJP8AF6v/ACHi/wAh4P8AIeD/ABKR/wABE/8AAAD/AAAA/wAAA/8ADGH/AB/W/wAh
|
||||
4f8AIuL/ABzJ/wAISf8AAAH/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AB0b/AB3K/wAh
|
||||
4P8AIeD/AB7U/wALYP8AAAT/AAAA/wAFN/8AGr3/ACHi/wAh4P8AINr/AA5y/wAAB/8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAf/AA53/wAg2v8AIeD/ACHh/wAauv8ABTL/AAIT/wAT
|
||||
k/8AId//ACHf/wAh4P8AFaD/AAIb/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAIg/wAVpP8AIeH/ACHg/wAh3v8AE5X/AA1z/wAf1P8AIeD/ACHh/wAbwf8ABjz/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAHQf8AHMX/ACHh/wAh
|
||||
3/8AINr/AB/W/wAh4P8AIeD/AB/W/wAMZ/8AAAb/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAACP8ADXD/ACDZ/wAh4P8AId//ACHg/wAh3/8AId//ABSU/wAB
|
||||
Fv8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAhj/ABWe/wAh3/8AId//ACHf/wAh4P8AGrz/AAUx/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAT/AAxr/wAg3P8AId//ACHf/wAh
|
||||
4f8AFqP/AAIT/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAyX/ABiv/wAh4P8AId//ACHf/wAh4P8AH9L/AApb/wAAAv8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wABDf8AEYL/ACDd/wAh
|
||||
3/8AIeD/ACHg/wAh3/8AIeH/ABm3/wAFL/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAC/wAKU/8AHs7/ACHh/wAh4P8AHMX/ABeo/wAg3P8AIeD/ACHf/wAS
|
||||
jv8AARL/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAQq/wAY
|
||||
sP8AIeH/ACHg/wAf1/8ADGj/AAQy/wAYtP8AIeH/ACHg/wAe0v8AC1v/AAAD/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAQv/ABGG/wAg3f8AIeD/ACHh/wAVnf8AAhr/AAAB/wAL
|
||||
XP8AH9P/ACHg/wAh4P8AGrn/AAQu/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
Av8ACVX/AB3R/wAg4P8AIOH/ABvE/wAHPv8AAAD/AAAA/wABE/8AE5L/ACDf/wAg3/8AIN//ABGO/wAB
|
||||
Ef8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wULLv8NKbj/DjHn/w4x5f8MLt//ARFz/wAA
|
||||
CP8AAAD/AAAA/wAAAP8ABTT/ByXD/w4x5v8OMeb/Di7Y/wgWYf8BAQT/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/BAYN/yg5hf9BXuH/QF7i/0Ff4/8tRa7/Awgd/wAAAP8AAAD/AAAA/wAAAP8AAQX/GChx/z9b
|
||||
3f9BX+L/QV/k/zZOt/8MECj/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AgMJ/w8VMf8VHT//FRw9/xUc
|
||||
Pv8KDiH/AAEB/wAAAP8AAAD/AAAA/wAAAP8AAAD/BQcP/xMZOP8VHD7/FRw+/xMbPP8FBxL/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAACAA
|
||||
AABAAAAAAQAIAAAAAAAABAAAAAAAAAAAAAAAAQAAAAEAAAAAAAAIDigAFBxBABMbPwADBhQADRMxABQb
|
||||
QAASGj0AAQEGABsnWgBSbewAVXHyAFRx8QBVcvQANUqlAAABAwANFz8ATmjiAFVy8gA+U7UAAQIKAAAA
|
||||
AgAULJcAG0LsABtB6gAZP+QAAQ1bAAAACAALKawAHELtABtB6wAbPtgABg46AAABHgAAGb0AACDhAAAg
|
||||
3wAAIeEAABq/AAABIAAACGcAACDeAAAKcAAABlEAACDYAAAh4AAAId8AACHiAAARjQAAAAEAAAIpAAAc
|
||||
xwAAIuIAABWoAAAACgAAEIsAAAZPAAAAAwAAE5cAAB7OAAADNgAAARsAABq7AAAZugAAARkAAAZXAAAg
|
||||
2wAAC3AAAAVNAAAg1wAADoMAAAEiAAAavQAAEIcAAB/TAAAYtAAAARgAABm4AAAFSQAAH9YAAA6CAAAe
|
||||
zAAAAzUAAAIzAAAQiAAAEIkAAAZSAAAg2gAAEpIAACDcAAAbwgAAASUAAAZbAAATmwAAB2EAABOZAAAA
|
||||
BQAAAScAABvEAAACKgAAEY4AACHdAAAIZAAAAAQAAAhjAAABHwAAGr4AABzKAAACMQAACGIAACHcAAAT
|
||||
nAAABlMAACDZAAAVpgAAAi0AABzIAAALcgAAAAYAABSgAAAe0AAAAzwAAAdOAAAcsQAAHLMAAB61AAAR
|
||||
gQAABUcAABuvAAActAAAE4cAAAEVAAAUdQAAGIEAABeAAAAXgQAAE3MAAAtTAAAHQwAAAAcAAAIaAAAC
|
||||
GQAAAQ4AAAEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAi4yNjY2MjgAAAAAAAAAAAAA5jY2NjYyPAAAAAAAAAACDhIWGhoeIgwAA
|
||||
AAAAAAAAMYmFhoaGhYoAAAAAAAAAAAB6e3x8fH1+ZwAAAAAAAAB/gIF8fH2CGwAAAAAAAAAAAHZ3Ly4u
|
||||
LlleAAAAAAAAaUglLi4teHkAAAAAAAAAAAAAAHN0JS4uJTNjAAAAABVkLy4uLi51AAAAAAAAAAAAAAAA
|
||||
AG1uLi4uL29gAAAAcHEtLi40cjYAAAAAAAAAAAAAAAAAZ18vLi4uZWgAAGlqJS4uJWtsAAAAAAAAAAAA
|
||||
AAAAAAAAYWIlLi4lM2MxZC8uLi5lZgAAAAAAAAAAAAAAAAAAAAAAXEItLi40XV4sLS4uL19gAAAAAAAA
|
||||
AAAAAAAAAAAAAAAVWC8uLi5ZTy0uLiVaWwAAAAAAAAAAAAAAAAAAAAAAAAAnJiUuLi4tLi4tV0EAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAABWLC0uLi4uLiUwFQAAAAAAAAAAAAAAAAAAAAAAAAAAADFVLS4uLi4lTT0A
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAFNKLS4uLjRUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxUC4uLi4u
|
||||
LVFSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE5PLS4uLi4uNDU2AAAAAAAAAAAAAAAAAAAAAAAAAABMTS8u
|
||||
Li0lLi4uLkMAAAAAAAAAAAAAAAAAAAAAAAAAMUklLi4tSksuLi4tOzwAAAAAAAAAAAAAAAAAAAAAAABE
|
||||
RS0uLiVGR0glLi40NTYAAAAAAAAAAAAAAAAAAAAAPT4lLi4lP0AAQUIuLi4uQwAAAAAAAAAAAAAAAAAA
|
||||
ADE3JS4uLSw4AAA5OjQuLi07PAAAAAAAAAAAAAAAAAAAKywtLi4vMDEAAAAyMyUuLjQ1NgAAAAAAAAAA
|
||||
AAAAACEiIyQkJSYnAAAAAAAoKSQkJCQqAAAAAAAAAAAAAAAVFhcYGBgZGgAAAAAAABscHRgYHh8gAAAA
|
||||
AAAAAAAAAAkKCwwMDQ4PAAAAAAAAABAREgwMDRMUAAAAAAAAAAAAAQIDAwMDBAAAAAAAAAAAAAUGAwMD
|
||||
BwgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAMAAAAGAA
|
||||
AAABACAAAAAAAAAkAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAC/wAAB/8AAAr/AAAJ/wAA
|
||||
Cf8AAAn/AAAJ/wAACf8AAAj/AAAF/wAAAv8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAH/AAAH/wAACf8AAAn/AAAJ/wAACf8AAAn/AAAJ/wAA
|
||||
Cf8AAAf/AAAB/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAH/AAAI/wAD
|
||||
Gv8ABSr/AAYq/wAGKv8ABSr/AAUq/wAGK/8ABSn/AAQh/wACEP8AAAL/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wABB/8AAhT/AAUm/wAGK/8ABSr/AAUq/wAF
|
||||
Kv8ABir/AAYr/wAEJf8AAhj/AAAF/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAP/AAEP/wAJPf8AEmj/ABRv/wAUb/8AE2//ABNv/wAUcP8AE27/ABFl/wAIOf8AAQ3/AAAC/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAEIf8AC03/ABJp/wAU
|
||||
cP8AE2//ABNv/wATb/8AFG//ABRw/wANWP8ABTH/AAEK/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAH/AAAJ/wAHOP8AEXH/ABmV/wAbnv8AGpv/ABqc/wAanP8AGpz/ABmY/wAR
|
||||
cv8ABzz/AAEM/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAX/AAEa/wAK
|
||||
Uf8AFYf/ABmZ/wAbnf8AGpz/ABqc/wAbnf8AG5v/ABiO/wANWv8AAyD/AAAG/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wACHf8ACVT/ABed/wAduf8AHbv/AB27/wAd
|
||||
u/8AHbv/AB68/wAaq/8AEHz/AAQo/wAABf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AARL/AAdM/wATjP8AHLn/AB28/wAdu/8AHbv/AB27/wAevf8AHLH/ABOG/wAIP/8AAAT/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAABP8ABCr/ABKL/wAc
|
||||
xP8AINv/ACDZ/wAg2P8AINj/ACHY/wAg1/8AGrn/AApm/wACJP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAACP8ABDH/ABOR/wAcxv8AINn/ACDZ/wAg2P8AINj/ACDZ/wAg1/8AGrf/AApf/wAC
|
||||
IP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAhH/AAlV/wAVpP8AINz/ACHh/wAh4f8AIeH/ACHg/wAi5P8AH9b/ABSk/wAIUv8AAA3/AAAC/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAEJv8ADGv/ABu//wAg3/8AIeL/ACHh/wAh4P8AIeH/ACLj/wAc
|
||||
yf8AEY7/AAQy/wAACf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAX/AAEe/wANbv8AGr//ACDb/wAh4f8AId//ACHf/wAh4f8AId7/AB7R/wAR
|
||||
hv8ABDL/AAEJ/wAAAP8AAAD/AAAA/wAAAP8AAAH/AAEL/wAKU/8AFqj/AB/X/wAh4/8AId//ACHf/wAh
|
||||
4P8AId//ACDZ/wAUnv8AB0//AAEP/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAF/wAFOv8AD4b/AB7M/wAi4v8AId//ACHf/wAh
|
||||
3/8AIeD/ACHf/wAZuP8ADXL/AAMZ/wAAAP8AAAD/AAAA/wAAAP8AAQv/AAQ4/wARi/8AHtH/ACHe/wAh
|
||||
4P8AId//ACHf/wAi4v8AINv/ABm6/wAMZf8AARX/AAAD/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wABE/8AB0j/ABem/wAf
|
||||
1f8AIeH/ACHg/wAh3/8AIeD/ACHh/wAf1v8AF6j/AAdJ/wABE/8AAAD/AAAA/wAAAf8AAyD/AA10/wAZ
|
||||
uf8AIeD/ACHg/wAh3/8AId//ACHg/wAh4f8AHMj/AA9+/wAFM/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAxj/AA1v/wAZtv8AIN//ACHg/wAh3/8AId//ACHf/wAi4v8AHs3/AA+H/wAFOv8AAAT/AAAA/wAB
|
||||
E/8ACEr/ABes/wAf2P8AIeH/ACHf/wAh3/8AIeD/ACHh/wAe0v8AFaH/AAVA/wAAD/8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAn/AAMv/wAQg/8AHc//ACDe/wAh4f8AId//ACHf/wAh4f8AINv/ABq//wAN
|
||||
bP8AARv/AAAE/wAGOf8AEYz/AB3N/wAh4f8AId//ACHf/wAh3/8AIeD/ACHf/wAXrv8ACWL/AAIZ/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAL/AAAM/wAITv8AE6D/AB7U/wAi4/8AId//ACHf/wAh
|
||||
4P8AIeD/ACDa/wAVnv8ACVf/AAQ0/wANbv8AG7//ACDc/wAh4v8AId//ACHf/wAh4f8AIN3/ABzG/wAP
|
||||
ef8AAyj/AAAH/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wACIf8ACWL/ABq6/wAg
|
||||
3f8AIeD/ACHf/wAh3/8AIeD/ACLi/wAcxv8AE53/AA18/wAVpv8AIdv/ACHg/wAh4P8AId//ACHf/wAh
|
||||
4f8AHtD/ABOV/wAHQv8AAAL/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
A/8ABCj/ABGH/wAbxf8AIeL/ACHg/wAh3/8AId//ACHg/wAg2f8AHc//ABvF/wAe0f8AId//ACHf/wAh
|
||||
3/8AId//ACHh/wAf2f8AGLD/AAhQ/wABF/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAQ7/AAdI/wAUmf8AH9f/ACHf/wAh4P8AId//ACHf/wAh3/8AIeD/ACHf/wAh
|
||||
3/8AIeD/ACHf/wAh3/8AIeD/ACHh/wAZvP8ADnj/AAMj/wAAA/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAP/AAAV/wALY/8AGbf/AB/Z/wAh4f8AId//ACHf/wAh
|
||||
3/8AId//ACHg/wAh3/8AId//ACHf/wAh4P8AId7/AB7S/wARjf8ABDv/AAEL/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAD/wAEMf8ADXn/ABzH/wAh
|
||||
4f8AIeD/ACHf/wAh3/8AId//ACHf/wAh3/8AId//ACHf/wAh4v8AH9b/ABan/wAKU/8AAQz/AAAC/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
Dv8ABj3/ABWb/wAez/8AIeH/ACHg/wAh3/8AId//ACHf/wAh3/8AId//ACHg/wAg2/8AGrr/AAxn/wAE
|
||||
Jf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAhT/AAtl/wAYsP8AId//ACHg/wAh3/8AId//ACHf/wAh3/8AIeD/ACHh/wAd
|
||||
zv8AE5X/AAQv/wAABf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAr/AAM1/wASjf8AINj/ACHf/wAh4P8AId//ACHf/wAh
|
||||
3/8AIeD/ACLi/wAavv8ADnf/AAMa/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAQ3/AAZG/wAUmf8AINv/ACHf/wAh
|
||||
4P8AId//ACHf/wAh3/8AIeD/ACLh/wAdyf8AE4//AAQu/wAABv8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAv8AAyL/AA56/wAa
|
||||
vP8AIeD/ACHg/wAh3/8AId//ACHf/wAh3/8AId//ACHg/wAh3f8AG7r/AApf/wACIP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAB
|
||||
Gf8ACFT/ABix/wAf2f8AIeD/ACHf/wAh3/8AId//ACHf/wAh3/8AId//ACHf/wAi4v8AH9P/ABWi/wAI
|
||||
TP8AAAX/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAG/wAHQv8AEpL/AB7Q/wAh4/8AId//ACHf/wAh3/8AIeD/ACHh/wAh4P8AId//ACHf/wAi
|
||||
4f8AId7/AB3N/wAQgv8ABC//AAEJ/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAb/AAMi/wAPdf8AHMb/ACDd/wAh4f8AId//ACHf/wAh3/8AId7/ACDb/wAg
|
||||
3f8AId//ACHf/wAh3/8AIeD/ACHg/wAYtP8ADGz/AAMc/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAhP/AAtg/wAXq/8AINz/ACHg/wAh3/8AId//ACHg/wAg
|
||||
3P8AHtH/ABvA/wAdzf8AId//ACHf/wAh3/8AId//ACHg/wAf1f8AF6b/AAZF/wAAEf8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAADf8ABjv/ABWa/wAez/8AIeL/ACHg/wAh
|
||||
3/8AIeD/ACHi/wAcy/8AFaL/AA51/wAVm/8AH9X/ACHf/wAh4P8AId//ACHf/wAi4f8AHcr/AA+C/wAF
|
||||
NP8AAAH/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAC/wADLv8ADXX/ABzF/wAh
|
||||
4f8AIeD/ACHf/wAh3/8AIeD/ACDd/wAWqf8ACmH/AAIo/wALX/8AGbb/AB/Z/wAh4v8AId//ACHf/wAi
|
||||
4v8AINv/ABm7/wAMZf8AARX/AAAD/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAP/AAAR/wAL
|
||||
Xv8AGLP/AB/Y/wAh4f8AId//ACHf/wAh4f8AIN3/ABzI/wAPdv8AAiL/AAAJ/wAEMf8ADXz/ABzK/wAh
|
||||
4v8AId//ACHf/wAh4P8AId//ACDZ/wAUnf8AB07/AAEP/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAQ3/AAZD/wATlP8AH9X/ACHf/wAh4P8AId//ACHf/wAi4v8AHtH/ABKW/wAHRf8AAAb/AAAA/wAA
|
||||
D/8ABkL/ABak/wAf1P8AIuH/ACHg/wAh3/8AIeD/ACHh/wAcx/8AEYr/AAQu/wAAB/8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAv8ABCT/ABCB/wAbwv8AIeH/ACHg/wAh3/8AId//ACHg/wAg2/8AGbX/AAlZ/wAC
|
||||
HP8AAAD/AAAA/wAAAP8AAxf/AA1u/wAZtv8AId//ACHg/wAh3/8AId//ACHg/wAh3v8AG7v/AApg/wAC
|
||||
IP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wACHf8ACVr/ABm1/wAg2/8AIeD/ACHf/wAh3/8AIeD/ACHi/wAb
|
||||
w/8AEIL/AAQk/wAAAv8AAAD/AAAA/wAAAP8AAQn/AAQw/wARhf8AHtH/ACHe/wAh4f8AId//ACHf/wAi
|
||||
4v8AH9T/ABWi/wAITP8AAAX/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAH/AAAI/wAHR/8AEZf/AB3R/wAg4v8AH9//AB/f/wAg
|
||||
4P8AIN//AB7X/wATl/8AB0b/AAEN/wAAAP8AAAD/AAAA/wAAAP8AAAL/AAAN/wAJU/8AFab/AB7W/wAg
|
||||
4v8AH97/AB/f/wAg4f8AH97/ABvM/wAOgf8AAy//AAAJ/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAQf/AgYp/wQUfP8EIcv/BCTf/wQl
|
||||
4/8EJeH/BCXh/wQm4/8DJNr/ARq4/wAMY/8AABX/AAAD/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAC
|
||||
J/8AC2z/Ah3C/wMk4P8EJeH/BCXh/wQl4f8EJeL/BCXi/wQctv8EEG3/AQQc/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8DBhb/DR5s/xQx
|
||||
uP8WO+b/Fjvp/xY76P8WO+j/Fjvo/xY86v8RM9H/BBaB/wAGNP8AAAP/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAABv8BBzH/CCGa/xAz1f8XPOv/Fjvp/xY76P8WO+n/Fjvp/xc63v8TLq7/CBJJ/wIE
|
||||
Ev8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wYI
|
||||
Ev8VH0r/L0ey/zpZ5/87Xvf/O131/ztd9P87XfX/O172/zRV5f8jPa//BxFG/wABEP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8CBRP/Chti/yM+tv85WvD/O130/zte9f87XfT/O131/zxe
|
||||
9v84Vt7/KDqS/xEZPv8AAQT/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/woPJf8gLmj/QFa8/0tk1/9KY9T/SmPU/0pj1P9KZNX/SmTW/z1Ttv8lNHX/BwsZ/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8BAwj/CQ8q/yc3ff9FXMj/SmPT/0pk
|
||||
1f9KY9T/SmPU/0tk1/9IYM//O0+s/xslVP8AAQf/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wUIF/8PFzn/HCZX/x8rYP8fKl3/Hipd/x4qXf8fKl7/Hype/xYe
|
||||
Rv8KDiT/AgMH/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAH/AgMI/w0T
|
||||
LP8aI1L/Hilc/x8qXv8eKl3/Hipd/x8qXv8eKV3/GyVV/w0TLP8BAQX/AAAB/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wIDCf8EBxT/BwoZ/wgLGv8HCxn/BwsZ/wcL
|
||||
Gf8HCxn/BwsZ/wQGD/8AAAT/AAAB/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wIDCf8FBxT/BwoZ/wgLGv8HCxn/BwsZ/wcKGf8HCxr/Bwsa/wQGD/8AAAL/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAACAAAABAAAAAAQAIAAAAAAAABAAAAAAAAAAA
|
||||
AAAAAQAAAAEAAAAAAAAIDigAFBxBABMbPwADBhQADRMxABQbQAASGj0AAQEGABsnWgBSbewAVXHyAFRx
|
||||
8QBVcvQANUqlAAABAwANFz8ATmjiAFVy8gA+U7UAAQIKAAAAAgAULJcAG0LsABtB6gAZP+QAAQ1bAAAA
|
||||
CAALKawAHELtABtB6wAbPtgABg46AAABHgAAGb0AACDhAAAg3wAAIeEAABq/AAABIAAACGcAACDeAAAK
|
||||
cAAABlEAACDYAAAh4AAAId8AACHiAAARjQAAAAEAAAIpAAAcxwAAIuIAABWoAAAACgAAEIsAAAZPAAAA
|
||||
AwAAE5cAAB7OAAADNgAAARsAABq7AAAZugAAARkAAAZXAAAg2wAAC3AAAAVNAAAg1wAADoMAAAEiAAAa
|
||||
vQAAEIcAAB/TAAAYtAAAARgAABm4AAAFSQAAH9YAAA6CAAAezAAAAzUAAAIzAAAQiAAAEIkAAAZSAAAg
|
||||
2gAAEpIAACDcAAAbwgAAASUAAAZbAAATmwAAB2EAABOZAAAABQAAAScAABvEAAACKgAAEY4AACHdAAAI
|
||||
ZAAAAAQAAAhjAAABHwAAGr4AABzKAAACMQAACGIAACHcAAATnAAABlMAACDZAAAVpgAAAi0AABzIAAAL
|
||||
cgAAAAYAABSgAAAe0AAAAzwAAAdOAAAcsQAAHLMAAB61AAARgQAABUcAABuvAAActAAAE4cAAAEVAAAU
|
||||
dQAAGIEAABeAAAAXgQAAE3MAAAtTAAAHQwAAAAcAAAIaAAACGQAAAQ4AAAEUAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAi4yNjY2M
|
||||
jgAAAAAAAAAAAAA5jY2NjYyPAAAAAAAAAACDhIWGhoeIgwAAAAAAAAAAMYmFhoaGhYoAAAAAAAAAAAB6
|
||||
e3x8fH1+ZwAAAAAAAAB/gIF8fH2CGwAAAAAAAAAAAHZ3Ly4uLlleAAAAAAAAaUglLi4teHkAAAAAAAAA
|
||||
AAAAAHN0JS4uJTNjAAAAABVkLy4uLi51AAAAAAAAAAAAAAAAAG1uLi4uL29gAAAAcHEtLi40cjYAAAAA
|
||||
AAAAAAAAAAAAZ18vLi4uZWgAAGlqJS4uJWtsAAAAAAAAAAAAAAAAAAAAYWIlLi4lM2MxZC8uLi5lZgAA
|
||||
AAAAAAAAAAAAAAAAAAAAXEItLi40XV4sLS4uL19gAAAAAAAAAAAAAAAAAAAAAAAVWC8uLi5ZTy0uLiVa
|
||||
WwAAAAAAAAAAAAAAAAAAAAAAAAAnJiUuLi4tLi4tV0EAAAAAAAAAAAAAAAAAAAAAAAAAAABWLC0uLi4u
|
||||
LiUwFQAAAAAAAAAAAAAAAAAAAAAAAAAAADFVLS4uLi4lTT0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFNK
|
||||
LS4uLjRUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxUC4uLi4uLVFSAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AE5PLS4uLi4uNDU2AAAAAAAAAAAAAAAAAAAAAAAAAABMTS8uLi0lLi4uLkMAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAMUklLi4tSksuLi4tOzwAAAAAAAAAAAAAAAAAAAAAAABERS0uLiVGR0glLi40NTYAAAAAAAAAAAAA
|
||||
AAAAAAAAPT4lLi4lP0AAQUIuLi4uQwAAAAAAAAAAAAAAAAAAADE3JS4uLSw4AAA5OjQuLi07PAAAAAAA
|
||||
AAAAAAAAAAAAKywtLi4vMDEAAAAyMyUuLjQ1NgAAAAAAAAAAAAAAACEiIyQkJSYnAAAAAAAoKSQkJCQq
|
||||
AAAAAAAAAAAAAAAVFhcYGBgZGgAAAAAAABscHRgYHh8gAAAAAAAAAAAAAAkKCwwMDQ4PAAAAAAAAABAR
|
||||
EgwMDRMUAAAAAAAAAAAAAQIDAwMDBAAAAAAAAAAAAAUGAwMDBwgAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
||||
72
SCrawler.Plugin.XVIDEOS/SettingsForm.vb
Normal file
@@ -0,0 +1,72 @@
|
||||
' 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.Toolbars
|
||||
Imports PersonalUtilities.Forms
|
||||
Public Class SettingsForm : Implements IOkCancelToolbar
|
||||
Private ReadOnly MyDefs As DefaultFormProps
|
||||
Private ReadOnly Property Settings As SiteSettings
|
||||
Friend Sub New(ByRef s As SiteSettings)
|
||||
InitializeComponent()
|
||||
MyDefs = New DefaultFormProps
|
||||
Settings = s
|
||||
End Sub
|
||||
Private Sub SettingsForm_Load(sender As Object, e As EventArgs) Handles Me.Load
|
||||
Try
|
||||
With MyDefs
|
||||
.MyViewInitialize(Me, Settings.Design, True)
|
||||
.AddOkCancelToolbar()
|
||||
If Settings.Domains.Count > 0 Then Settings.Domains.ForEach(Sub(d) LIST_DOMAINS.Items.Add(d))
|
||||
.EndLoaderOperations()
|
||||
End With
|
||||
Catch ex As Exception
|
||||
MyDefs.InvokeLoaderError(ex)
|
||||
End Try
|
||||
End Sub
|
||||
Private Sub OK() Implements IOkCancelToolbar.OK
|
||||
Settings.Domains.Clear()
|
||||
With LIST_DOMAINS
|
||||
If .Items.Count > 0 Then
|
||||
For Each i In .Items : Settings.Domains.Add(i.ToString) : Next
|
||||
End If
|
||||
End With
|
||||
Settings.UpdateDomains()
|
||||
MyDefs.CloseForm()
|
||||
End Sub
|
||||
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
|
||||
Dim nd$ = InputBoxE("Enter a new domain using the pattern [xvideos.com]:", "New domain")
|
||||
If Not nd.IsEmptyString Then
|
||||
If Not LIST_DOMAINS.Items.Contains(nd) Then
|
||||
LIST_DOMAINS.Items.Add(nd)
|
||||
Else
|
||||
MsgBoxE($"The domain [{nd}] already added")
|
||||
End If
|
||||
End If
|
||||
End Sub
|
||||
Private Sub BTT_DELETE_Click(sender As Object, e As EventArgs) Handles BTT_DELETE.Click
|
||||
If _LatestSelected.ValueBetween(0, LIST_DOMAINS.Items.Count - 1) Then
|
||||
Dim n$ = LIST_DOMAINS.Items(_LatestSelected)
|
||||
If MsgBoxE({$"Are you sure you want to delete the [{n}] domain?",
|
||||
"Removing domains"}, MsgBoxStyle.YesNo) = MsgBoxResult.Yes Then
|
||||
LIST_DOMAINS.Items.RemoveAt(_LatestSelected)
|
||||
MsgBoxE($"Domain [{n}] removed")
|
||||
Else
|
||||
MsgBoxE("Operation canceled")
|
||||
End If
|
||||
Else
|
||||
MsgBoxE("No domain selected", vbExclamation)
|
||||
End If
|
||||
End Sub
|
||||
Private _LatestSelected As Integer = -1
|
||||
Private Sub LIST_DOMENS_SelectedIndexChanged(sender As Object, e As EventArgs) Handles LIST_DOMAINS.SelectedIndexChanged
|
||||
_LatestSelected = LIST_DOMAINS.SelectedIndex
|
||||
End Sub
|
||||
End Class
|
||||
185
SCrawler.Plugin.XVIDEOS/SiteSettings.vb
Normal file
@@ -0,0 +1,185 @@
|
||||
' 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.Drawing
|
||||
Imports PersonalUtilities.Functions.XML
|
||||
Imports PersonalUtilities.Functions.RegularExpressions
|
||||
Imports PersonalUtilities.Tools.WEB
|
||||
<Manifest("AndyProgram_XVIDEOS"), SpecialForm(True)>
|
||||
Public Class SiteSettings : Implements ISiteSettings
|
||||
Public ReadOnly Property Icon As Icon Implements ISiteSettings.Icon
|
||||
Get
|
||||
Return My.Resources.Icon32
|
||||
End Get
|
||||
End Property
|
||||
Public ReadOnly Property Image As Image Implements ISiteSettings.Image
|
||||
Get
|
||||
Return My.Resources.IconPic32
|
||||
End Get
|
||||
End Property
|
||||
Public ReadOnly Property Site As String = "XVIDEOS" Implements ISiteSettings.Site
|
||||
Public Property Logger As ILogProvider Implements ISiteSettings.Logger
|
||||
#Region "M3U8"
|
||||
Private ReadOnly OS64 As Boolean
|
||||
Private ReadOnly FfmpegExists As Boolean
|
||||
Friend ReadOnly FfmpegFile As SFile
|
||||
Friend ReadOnly Property UseM3U8 As Boolean
|
||||
Get
|
||||
Return OS64 And FfmpegExists
|
||||
End Get
|
||||
End Property
|
||||
#End Region
|
||||
<PXML("Domains")> Private Property SiteDomains As PropertyValue
|
||||
<PropertyOption(ControlText:="Download UHD", ControlToolTip:="Download UHD (4K) content"), PXML>
|
||||
Public Property DownloadUHD As PropertyValue
|
||||
Friend ReadOnly Property Domains As List(Of String)
|
||||
Public ReadOnly Property Responser As Response
|
||||
Private Const DomainsDefault As String = "xvideos.com|xnxx.com"
|
||||
Private _Initialized As Boolean = False
|
||||
Friend Design As XmlFile
|
||||
Public Sub New()
|
||||
Responser = New Response($"Settings\Responser_{Site}.xml")
|
||||
With Responser
|
||||
If .File.Exists Then
|
||||
.LoadSettings()
|
||||
Else
|
||||
.CookiesDomain = "www.xvideos.com"
|
||||
.SaveSettings()
|
||||
End If
|
||||
End With
|
||||
OS64 = Environment.Is64BitOperatingSystem
|
||||
FfmpegFile = "ffmpeg.exe"
|
||||
FfmpegExists = FfmpegFile.Exists
|
||||
Domains = New List(Of String)
|
||||
SiteDomains = New PropertyValue(DomainsDefault, GetType(String), Sub(s) UpdateDomains())
|
||||
DownloadUHD = New PropertyValue(False)
|
||||
End Sub
|
||||
Public Function GetInstance(ByVal What As ISiteSettings.Download) As IPluginContentProvider Implements ISiteSettings.GetInstance
|
||||
Return New UserData
|
||||
End Function
|
||||
Public Sub BeginInit() Implements ISiteSettings.BeginInit
|
||||
End Sub
|
||||
Public Sub EndInit() Implements ISiteSettings.EndInit
|
||||
_Initialized = True
|
||||
UpdateDomains()
|
||||
End Sub
|
||||
Public Sub Load(ByVal XMLValues As IEnumerable(Of KeyValuePair(Of String, String))) Implements ISiteSettings.Load
|
||||
End Sub
|
||||
Private _DomainsUpdateInProgress As Boolean = False
|
||||
Friend Sub UpdateDomains()
|
||||
If Not _Initialized Then Exit Sub
|
||||
If Not _DomainsUpdateInProgress Then
|
||||
_DomainsUpdateInProgress = True
|
||||
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("|")
|
||||
_DomainsUpdateInProgress = False
|
||||
End If
|
||||
End Sub
|
||||
#Region "Downloading"
|
||||
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
|
||||
Return UseM3U8
|
||||
End Function
|
||||
Public Sub DownloadStarted(ByVal What As ISiteSettings.Download) Implements ISiteSettings.DownloadStarted
|
||||
End Sub
|
||||
Public Sub BeforeStartDownload(ByVal User As Object, ByVal What As ISiteSettings.Download) Implements ISiteSettings.BeforeStartDownload
|
||||
End Sub
|
||||
Public Sub AfterDownload(ByVal User As Object, ByVal What As ISiteSettings.Download) Implements ISiteSettings.AfterDownload
|
||||
End Sub
|
||||
Public Sub DownloadDone(ByVal What As ISiteSettings.Download) Implements ISiteSettings.DownloadDone
|
||||
End Sub
|
||||
#End Region
|
||||
Public Sub BeginUpdate() Implements ISiteSettings.BeginUpdate
|
||||
End Sub
|
||||
Public Sub EndUpdate() Implements ISiteSettings.EndUpdate
|
||||
End Sub
|
||||
Public Sub Update() Implements ISiteSettings.Update
|
||||
UpdateDomains()
|
||||
Responser.SaveSettings()
|
||||
End Sub
|
||||
Public Sub Reset() Implements ISiteSettings.Reset
|
||||
End Sub
|
||||
Public Sub OpenSettingsForm() Implements ISiteSettings.OpenSettingsForm
|
||||
Using f As New SettingsForm(Me)
|
||||
Design = New XmlFile("Settings\Design_XVIDEOS.xml")
|
||||
f.ShowDialog()
|
||||
Design.Dispose()
|
||||
End Using
|
||||
End Sub
|
||||
Public Sub UserOptions(ByRef Options As Object, ByVal OpenForm As Boolean) Implements ISiteSettings.UserOptions
|
||||
Options = Nothing
|
||||
End Sub
|
||||
Public Function GetUserUrl(ByVal UserName As String, ByVal Channel As Boolean) As String Implements ISiteSettings.GetUserUrl
|
||||
Dim user$ = UserName.Split("_").FirstOrDefault
|
||||
user &= $"/{UserName.Replace($"{user}_", String.Empty)}"
|
||||
Return user
|
||||
End Function
|
||||
Private Const UserRegexDefault As String = "/(profiles|[\w]*?[-]{0,1}channels)/([^/]+)(\Z|.*?)"
|
||||
Private Const URD As String = ".*?{0}{1}"
|
||||
Public Function IsMyUser(ByVal UserURL As String) As ExchangeOptions Implements ISiteSettings.IsMyUser
|
||||
If Not UserURL.IsEmptyString Then
|
||||
If Domains.Count > 0 Then
|
||||
Dim uName$, uOpt$, fStr$
|
||||
For i% = 0 To Domains.Count - 1
|
||||
fStr = String.Format(URD, Domains(i), UserRegexDefault)
|
||||
uName = RegexReplace(UserURL, RParams.DMS(fStr, 2))
|
||||
If Not uName.IsEmptyString Then
|
||||
uOpt = RegexReplace(UserURL, RParams.DMS(fStr, 1))
|
||||
If Not uOpt.IsEmptyString Then Return New ExchangeOptions(Site, $"{uOpt}_{uName}")
|
||||
End If
|
||||
Next
|
||||
End If
|
||||
End If
|
||||
Return Nothing
|
||||
End Function
|
||||
Public Function IsMyImageVideo(ByVal URL As String) As ExchangeOptions Implements ISiteSettings.IsMyImageVideo
|
||||
If Not URL.IsEmptyString And Domains.Count > 0 Then
|
||||
If Domains.Exists(Function(d) URL.Contains(d)) Then Return New ExchangeOptions With {.UserName = URL, .Exists = True}
|
||||
End If
|
||||
Return Nothing
|
||||
End Function
|
||||
Private Class TempThrower : Implements IThrower
|
||||
Private Sub ThrowAny() Implements IThrower.ThrowAny
|
||||
End Sub
|
||||
End Class
|
||||
Public Function GetSpecialData(ByVal URL As String, ByVal Path As String, ByVal AskForPath As Boolean) As IEnumerable(Of PluginUserMedia) Implements ISiteSettings.GetSpecialData
|
||||
If Not URL.IsEmptyString And UseM3U8 Then
|
||||
Dim f As SFile = Path.CSFileP
|
||||
f.Name = "video"
|
||||
f.Extension = "mp4"
|
||||
#Disable Warning BC40000
|
||||
If AskForPath Then f = SFile.SaveAs(f,, True, "mp4")
|
||||
#Enable Warning
|
||||
If Not f.IsEmptyString Then
|
||||
Using user As New UserData With {
|
||||
.LogProvider = Logger,
|
||||
.Thrower = New TempThrower,
|
||||
.ESettings = Me,
|
||||
.DataPath = f.Path
|
||||
}
|
||||
With user
|
||||
.TempMediaList = New List(Of PluginUserMedia) From {UserData.GetVideoData(URL, Responser.Copy, DownloadUHD.Value, String.Empty, Logger)}
|
||||
If Not .TempMediaList(0).URL.IsEmptyString Then
|
||||
.Download()
|
||||
If .TempMediaList(0).DownloadState = PluginUserMedia.States.Downloaded Then
|
||||
Dim p As PluginUserMedia = .TempMediaList(0)
|
||||
p.SpecialFolder = p.File
|
||||
Return {p}
|
||||
End If
|
||||
End If
|
||||
End With
|
||||
End Using
|
||||
End If
|
||||
End If
|
||||
Return Nothing
|
||||
End Function
|
||||
End Class
|
||||
240
SCrawler.Plugin.XVIDEOS/UserData.vb
Normal file
@@ -0,0 +1,240 @@
|
||||
' 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.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
|
||||
Public Event TotalCountChanged(Count As Integer) Implements IPluginContentProvider.TotalCountChanged
|
||||
Public Property Thrower As IThrower Implements IPluginContentProvider.Thrower
|
||||
Public Property LogProvider As ILogProvider Implements IPluginContentProvider.LogProvider
|
||||
Public Property ESettings As ISiteSettings Implements IPluginContentProvider.Settings
|
||||
Private ReadOnly Property Settings As SiteSettings
|
||||
Get
|
||||
Return DirectCast(ESettings, SiteSettings)
|
||||
End Get
|
||||
End Property
|
||||
Public Property Name As String Implements IPluginContentProvider.Name
|
||||
Public Property ID As String Implements IPluginContentProvider.ID
|
||||
Public Property ParseUserMediaOnly As Boolean Implements IPluginContentProvider.ParseUserMediaOnly
|
||||
Public Property UserDescription As String Implements IPluginContentProvider.UserDescription
|
||||
Public Property ExistingContentList As List(Of PluginUserMedia) Implements IPluginContentProvider.ExistingContentList
|
||||
Public Property TempPostsList As List(Of String) Implements IPluginContentProvider.TempPostsList
|
||||
Public Property TempMediaList As List(Of PluginUserMedia) Implements IPluginContentProvider.TempMediaList
|
||||
Public Property UserExists As Boolean Implements IPluginContentProvider.UserExists
|
||||
Public Property UserSuspended As Boolean Implements IPluginContentProvider.UserSuspended
|
||||
Public Property IsSavedPosts As Boolean Implements IPluginContentProvider.IsSavedPosts
|
||||
Public Property SeparateVideoFolder As Boolean Implements IPluginContentProvider.SeparateVideoFolder
|
||||
Public Property DataPath As String Implements IPluginContentProvider.DataPath
|
||||
Public Property PostsNumberLimit As Integer? Implements IPluginContentProvider.PostsNumberLimit
|
||||
Public Property PostsDateLimit As Date? Implements IPluginContentProvider.PostsDateLimit
|
||||
#End Region
|
||||
#Region "Interface exchange options"
|
||||
Public Sub ExchangeOptionsSet(ByVal Obj As Object) Implements IPluginContentProvider.ExchangeOptionsSet
|
||||
End Sub
|
||||
Public Function ExchangeOptionsGet() As Object Implements IPluginContentProvider.ExchangeOptionsGet
|
||||
Return Nothing
|
||||
End Function
|
||||
#End Region
|
||||
#Region "Interface XML"
|
||||
Public Sub XmlFieldsSet(ByVal Fields As List(Of KeyValuePair(Of String, String))) Implements IPluginContentProvider.XmlFieldsSet
|
||||
End Sub
|
||||
Public Function XmlFieldsGet() As List(Of KeyValuePair(Of String, String)) Implements IPluginContentProvider.XmlFieldsGet
|
||||
Return Nothing
|
||||
End Function
|
||||
#End Region
|
||||
Private Property Responser As Response
|
||||
Public Sub GetMedia() Implements IPluginContentProvider.GetMedia
|
||||
Try
|
||||
If Not Settings.UseM3U8 Then LogProvider.Add("File [ffmpeg.exe] not found") : Exit Sub
|
||||
If Not Responser Is Nothing Then Responser.Dispose()
|
||||
Responser = New Response
|
||||
Responser.Copy(Settings.Responser)
|
||||
|
||||
Dim NextPage% = 0
|
||||
Dim r$
|
||||
Dim j As EContainer, jj As EContainer
|
||||
Dim e As ErrorsDescriber = EDP.ThrowException
|
||||
Dim user$ = Settings.GetUserUrl(Name, False)
|
||||
Dim p As PluginUserMedia
|
||||
Dim EnvirSet As Boolean = False
|
||||
|
||||
Do
|
||||
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 : EnvirSet = True
|
||||
j = JsonDocument.Parse(r).XmlIfNothing
|
||||
With j
|
||||
If .Contains("videos") Then
|
||||
With .Item("videos")
|
||||
If .Count > 0 Then
|
||||
NextPage += 1
|
||||
For Each jj In .Self
|
||||
p = New PluginUserMedia With {
|
||||
.PostID = jj.Value("id"),
|
||||
.URL = $"https://www.xvideos.com{jj.Value("u")}"
|
||||
}
|
||||
If Not p.PostID.IsEmptyString And Not jj.Value("u").IsEmptyString Then
|
||||
If Not TempPostsList.Contains(p.PostID) Then TempPostsList.Add(p.PostID) : TempMediaList.Add(p) Else Exit Do
|
||||
End If
|
||||
Next
|
||||
End If
|
||||
End With
|
||||
Else
|
||||
.Dispose()
|
||||
Exit Do
|
||||
End If
|
||||
.Dispose()
|
||||
End With
|
||||
Else
|
||||
Exit Do
|
||||
End If
|
||||
Loop
|
||||
|
||||
If TempMediaList.Count > 0 Then
|
||||
For i% = 0 To TempMediaList.Count - 1
|
||||
Thrower.ThrowAny()
|
||||
With TempMediaList(i)
|
||||
TempMediaList(i) = GetVideoData(.URL, Responser, Settings.DownloadUHD.Value, .PostID, LogProvider)
|
||||
End With
|
||||
Next
|
||||
TempMediaList.RemoveAll(Function(m) m.URL.IsEmptyString)
|
||||
End If
|
||||
Catch oex As OperationCanceledException
|
||||
Catch dex As ObjectDisposedException
|
||||
Catch ex As Exception
|
||||
If Responser.StatusCode = Net.HttpStatusCode.NotFound Then
|
||||
UserExists = False
|
||||
Else
|
||||
LogProvider.Add(ex, "[XVIDEOS.UserData.GetMedia]")
|
||||
End If
|
||||
Finally
|
||||
If TempMediaList.ListExists Then TempMediaList.RemoveAll(Function(m) m.URL.IsEmptyString)
|
||||
End Try
|
||||
End Sub
|
||||
Private Structure VSize : Implements IRegExCreator, IComparable(Of VSize)
|
||||
Friend Size As Integer
|
||||
Friend Value As String
|
||||
Private Function CreateFromArray(ByVal ParamsArray() As String) As Object Implements IRegExCreator.CreateFromArray
|
||||
If ParamsArray.ListExists(2) Then
|
||||
Size = AConvert(Of Integer)(ParamsArray(0), 0)
|
||||
Value = ParamsArray(1)
|
||||
End If
|
||||
Return Me
|
||||
End Function
|
||||
Private Function CompareTo(ByVal Other As VSize) As Integer Implements IComparable(Of VSize).CompareTo
|
||||
Return Size.CompareTo(Other.Size) * -1
|
||||
End Function
|
||||
End Structure
|
||||
Friend Shared Function GetVideoData(ByVal URL As String, ByVal resp As Response, ByVal DownloadUHD As Boolean,
|
||||
ByVal ID As String, ByRef Logger As ILogProvider) As PluginUserMedia
|
||||
Try
|
||||
If Not URL.IsEmptyString Then
|
||||
Dim r$ = resp.GetResponse(URL,, EDP.ThrowException)
|
||||
If Not r.IsEmptyString Then
|
||||
Dim m$ = RegexReplace(r, M3U8Regex)
|
||||
If Not m.IsEmptyString Then
|
||||
Dim appender$ = RegexReplace(m, M3U8Appender)
|
||||
Dim t$ = RegexReplace(r, VideoTitleRegex)
|
||||
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 Not DownloadUHD Then ls.RemoveAll(Function(v) v.Size > 1080)
|
||||
If ls.ListExists Then
|
||||
ls.Sort()
|
||||
m = $"{appender}/{ls(0).Value}"
|
||||
ls.Clear()
|
||||
Dim pID$ = ID
|
||||
If pID.IsEmptyString Then pID = RegexReplace(r, VideoID)
|
||||
If pID.IsEmptyString Then pID = "0"
|
||||
|
||||
If Not t.IsEmptyString Then t = t.StringRemoveWinForbiddenSymbols(" ")
|
||||
If t.IsEmptyString Then
|
||||
t = pID
|
||||
Else
|
||||
If t.Length > 100 Then t = Left(t, 100)
|
||||
End If
|
||||
If Not m.IsEmptyString Then
|
||||
Return New PluginUserMedia With {
|
||||
.ContentType = UTypes.m3u8,
|
||||
.PostID = pID,
|
||||
.URL = m,
|
||||
.File = $"{t}.mp4",
|
||||
.SpecialFolder = appender
|
||||
}
|
||||
End If
|
||||
End If
|
||||
End If
|
||||
End If
|
||||
End If
|
||||
End If
|
||||
Return Nothing
|
||||
Catch ex As Exception
|
||||
Logger.Add(ex, $"[XVIDEOS.UserData.GetVideoData({URL})]")
|
||||
Return Nothing
|
||||
End Try
|
||||
End Function
|
||||
Public Sub Download() Implements IPluginContentProvider.Download
|
||||
Try
|
||||
If TempMediaList.Count > 0 Then
|
||||
RaiseEvent TotalCountChanged(TempMediaList.Count - 1)
|
||||
Dim m As PluginUserMedia
|
||||
Dim f As SFile
|
||||
Dim DefPath As String = DataPath.CSFilePSN
|
||||
For i% = 0 To TempMediaList.Count - 1
|
||||
Thrower.ThrowAny()
|
||||
m = TempMediaList(i)
|
||||
f = m.File
|
||||
f.Path = DefPath
|
||||
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
|
||||
End If
|
||||
Catch oex As OperationCanceledException
|
||||
Catch dex As ObjectDisposedException
|
||||
Catch ex As Exception
|
||||
LogProvider.Add(ex, $"[XVIDEOS.UserData.Download]")
|
||||
End Try
|
||||
End Sub
|
||||
#Region "IDisposable Support"
|
||||
Private disposedValue As Boolean = False
|
||||
Protected Overridable Overloads Sub Dispose(ByVal disposing As Boolean)
|
||||
If Not disposedValue Then
|
||||
If disposing Then
|
||||
If Not Responser Is Nothing Then Responser.Dispose()
|
||||
If TempMediaList.ListExists Then TempMediaList.Clear()
|
||||
If TempPostsList.ListExists Then TempPostsList.Clear()
|
||||
If ExistingContentList.ListExists Then ExistingContentList.Clear()
|
||||
End If
|
||||
disposedValue = True
|
||||
End If
|
||||
End Sub
|
||||
Protected Overrides Sub Finalize()
|
||||
Dispose(False)
|
||||
MyBase.Finalize()
|
||||
End Sub
|
||||
Public Overloads Sub Dispose() Implements IDisposable.Dispose
|
||||
Dispose(True)
|
||||
GC.SuppressFinalize(Me)
|
||||
End Sub
|
||||
#End Region
|
||||
End Class
|
||||
@@ -7,7 +7,7 @@
|
||||
' This program is distributed in the hope that it will be useful,
|
||||
' but WITHOUT ANY WARRANTY
|
||||
Namespace Plugin
|
||||
Public Interface IPluginContentProvider
|
||||
Public Interface IPluginContentProvider : Inherits IDisposable
|
||||
Event ProgressChanged(ByVal Count As Integer)
|
||||
Event TotalCountChanged(ByVal Count As Integer)
|
||||
Property Thrower As IThrower
|
||||
@@ -19,7 +19,7 @@ Namespace Plugin
|
||||
Property UserDescription As String
|
||||
Property ExistingContentList As List(Of PluginUserMedia)
|
||||
Property TempPostsList As List(Of String)
|
||||
Property TempMediaList As List(Of IPluginUserMedia)
|
||||
Property TempMediaList As List(Of PluginUserMedia)
|
||||
Property UserExists As Boolean
|
||||
Property UserSuspended As Boolean
|
||||
Property IsSavedPosts As Boolean
|
||||
|
||||
@@ -17,10 +17,11 @@ Namespace Plugin
|
||||
ReadOnly Property Icon As Icon
|
||||
ReadOnly Property Image As Image
|
||||
ReadOnly Property Site As String
|
||||
Property Logger As ILogProvider
|
||||
Function GetUserUrl(ByVal UserName As String, ByVal Channel As Boolean) As String
|
||||
Function IsMyUser(ByVal UserURL As String) As ExchangeOptions
|
||||
Function IsMyImageVideo(ByVal URL As String) As ExchangeOptions
|
||||
Function GetSpecialData(ByVal URL As String) As IEnumerable(Of IPluginUserMedia)
|
||||
Function GetSpecialData(ByVal URL As String, ByVal Path As String, ByVal AskForPath As Boolean) As IEnumerable(Of PluginUserMedia)
|
||||
Function GetInstance(ByVal What As Download) As IPluginContentProvider
|
||||
#Region "XML Support"
|
||||
Sub Load(ByVal XMLValues As IEnumerable(Of KeyValuePair(Of String, String)))
|
||||
@@ -32,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"
|
||||
|
||||
@@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices
|
||||
' by using the '*' as shown below:
|
||||
' <Assembly: AssemblyVersion("1.0.*")>
|
||||
|
||||
<Assembly: AssemblyVersion("3.0.0.1")>
|
||||
<Assembly: AssemblyFileVersion("3.0.0.1")>
|
||||
<Assembly: AssemblyVersion("2022.6.3.0")>
|
||||
<Assembly: AssemblyFileVersion("2022.6.3.0")>
|
||||
<Assembly: NeutralResourcesLanguage("en")>
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
' 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 Plugin
|
||||
Public Structure PluginUserMedia : Implements IPluginUserMedia
|
||||
Public Property ContentType As Integer Implements IPluginUserMedia.ContentType
|
||||
Public Property URL As String Implements IPluginUserMedia.URL
|
||||
Public Property MD5 As String Implements IPluginUserMedia.MD5
|
||||
Public Property File As String Implements IPluginUserMedia.File
|
||||
Public Property DownloadState As Integer Implements IPluginUserMedia.DownloadState
|
||||
Public Property PostID As String Implements IPluginUserMedia.PostID
|
||||
Public Property PostDate As Date? Implements IPluginUserMedia.PostDate
|
||||
Public Property SpecialFolder As String Implements IPluginUserMedia.SpecialFolder
|
||||
End Structure
|
||||
Public Interface IPluginUserMedia
|
||||
Enum Types As Integer
|
||||
Undefined = 0
|
||||
[Picture] = 1
|
||||
[Video] = 2
|
||||
[Text] = 3
|
||||
VideoPre = 10
|
||||
GIF = 50
|
||||
m3u8 = 100
|
||||
End Enum
|
||||
Enum States As Integer : Unknown = 0 : Tried = 1 : Downloaded = 2 : Skipped = 3 : End Enum
|
||||
Property ContentType As Integer
|
||||
Property URL As String
|
||||
Property MD5 As String
|
||||
Property File As String
|
||||
Property DownloadState As Integer
|
||||
Property PostID As String
|
||||
Property PostDate As Date?
|
||||
Property SpecialFolder As String
|
||||
End Interface
|
||||
End Namespace
|
||||
30
SCrawler.PluginProvider/Objects/PluginUserMedia.vb
Normal file
@@ -0,0 +1,30 @@
|
||||
' 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 Plugin
|
||||
Public Structure PluginUserMedia
|
||||
Enum Types As Integer
|
||||
Undefined = 0
|
||||
[Picture] = 1
|
||||
[Video] = 2
|
||||
[Text] = 3
|
||||
VideoPre = 10
|
||||
GIF = 50
|
||||
m3u8 = 100
|
||||
End Enum
|
||||
Enum States As Integer : Unknown = 0 : Tried = 1 : Downloaded = 2 : Skipped = 3 : End Enum
|
||||
Public ContentType As Integer
|
||||
Public URL As String
|
||||
Public MD5 As String
|
||||
Public File As String
|
||||
Public DownloadState As Integer
|
||||
Public PostID As String
|
||||
Public PostDate As Date?
|
||||
Public SpecialFolder As String
|
||||
End Structure
|
||||
End Namespace
|
||||
@@ -105,7 +105,7 @@
|
||||
<Compile Include="Objects\ExchangeOptions.vb" />
|
||||
<Compile Include="ObjectInterfaces\ILogProvider.vb" />
|
||||
<Compile Include="Interfaces\IPluginContentProvider.vb" />
|
||||
<Compile Include="ObjectInterfaces\IPluginUserMedia.vb" />
|
||||
<Compile Include="Objects\PluginUserMedia.vb" />
|
||||
<Compile Include="Interfaces\ISiteSettings.vb" />
|
||||
<Compile Include="ObjectInterfaces\IThrower.vb" />
|
||||
<Compile Include="My Project\AssemblyInfo.vb" />
|
||||
|
||||
42
SCrawler.sln
@@ -17,6 +17,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
||||
EndProject
|
||||
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "SCrawler.PluginProvider", "SCrawler.PluginProvider\SCrawler.PluginProvider.vbproj", "{D4650F6B-5A54-44B6-999B-6C675B7116B1}"
|
||||
EndProject
|
||||
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "SCrawler.Plugin.LPSG", "SCrawler.Plugin.LPSG\SCrawler.Plugin.LPSG.vbproj", "{22A130B2-DDF4-4FB5-BA38-E5DB4CF1B8A2}"
|
||||
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
|
||||
@@ -63,6 +69,42 @@ Global
|
||||
{D4650F6B-5A54-44B6-999B-6C675B7116B1}.Release|x64.Build.0 = Release|x64
|
||||
{D4650F6B-5A54-44B6-999B-6C675B7116B1}.Release|x86.ActiveCfg = Release|x86
|
||||
{D4650F6B-5A54-44B6-999B-6C675B7116B1}.Release|x86.Build.0 = Release|x86
|
||||
{22A130B2-DDF4-4FB5-BA38-E5DB4CF1B8A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{22A130B2-DDF4-4FB5-BA38-E5DB4CF1B8A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{22A130B2-DDF4-4FB5-BA38-E5DB4CF1B8A2}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{22A130B2-DDF4-4FB5-BA38-E5DB4CF1B8A2}.Debug|x64.Build.0 = Debug|x64
|
||||
{22A130B2-DDF4-4FB5-BA38-E5DB4CF1B8A2}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{22A130B2-DDF4-4FB5-BA38-E5DB4CF1B8A2}.Debug|x86.Build.0 = Debug|x86
|
||||
{22A130B2-DDF4-4FB5-BA38-E5DB4CF1B8A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{22A130B2-DDF4-4FB5-BA38-E5DB4CF1B8A2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{22A130B2-DDF4-4FB5-BA38-E5DB4CF1B8A2}.Release|x64.ActiveCfg = Release|x64
|
||||
{22A130B2-DDF4-4FB5-BA38-E5DB4CF1B8A2}.Release|x64.Build.0 = Release|x64
|
||||
{22A130B2-DDF4-4FB5-BA38-E5DB4CF1B8A2}.Release|x86.ActiveCfg = Release|x86
|
||||
{22A130B2-DDF4-4FB5-BA38-E5DB4CF1B8A2}.Release|x86.Build.0 = Release|x86
|
||||
{CCCF47F4-C97C-4193-AC4B-C56DF2F9AA8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CCCF47F4-C97C-4193-AC4B-C56DF2F9AA8A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CCCF47F4-C97C-4193-AC4B-C56DF2F9AA8A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{CCCF47F4-C97C-4193-AC4B-C56DF2F9AA8A}.Debug|x64.Build.0 = Debug|x64
|
||||
{CCCF47F4-C97C-4193-AC4B-C56DF2F9AA8A}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{CCCF47F4-C97C-4193-AC4B-C56DF2F9AA8A}.Debug|x86.Build.0 = Debug|x86
|
||||
{CCCF47F4-C97C-4193-AC4B-C56DF2F9AA8A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CCCF47F4-C97C-4193-AC4B-C56DF2F9AA8A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CCCF47F4-C97C-4193-AC4B-C56DF2F9AA8A}.Release|x64.ActiveCfg = Release|x64
|
||||
{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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -11,11 +11,12 @@ Imports PersonalUtilities.Functions.RegularExpressions
|
||||
Imports PersonalUtilities.Tools.WEB
|
||||
Imports Download = SCrawler.Plugin.ISiteSettings.Download
|
||||
Namespace API.Base
|
||||
Friend MustInherit Class SiteSettingsBase : Implements ISiteSettings, IResponserContainer
|
||||
Friend MustInherit Class SiteSettingsBase : Implements ISiteSettings
|
||||
Friend ReadOnly Property Site As String Implements ISiteSettings.Site
|
||||
Friend Overridable ReadOnly Property Icon As Icon = Nothing Implements ISiteSettings.Icon
|
||||
Friend Overridable ReadOnly Property Image As Image = Nothing Implements ISiteSettings.Image
|
||||
Friend Overridable ReadOnly Property Responser As Response Implements IResponserContainer.Responser
|
||||
Private Property Logger As ILogProvider = LogConnector Implements ISiteSettings.Logger
|
||||
Friend Overridable ReadOnly Property Responser As Response
|
||||
Friend MustOverride Function GetInstance(ByVal What As Download) As IPluginContentProvider Implements ISiteSettings.GetInstance
|
||||
Friend Sub New(ByVal SiteName As String)
|
||||
Site = SiteName
|
||||
@@ -82,7 +83,7 @@ Namespace API.Base
|
||||
Return Nothing
|
||||
End If
|
||||
End Function
|
||||
Friend Overridable Function GetSpecialData(ByVal URL As String) As IEnumerable(Of IPluginUserMedia) Implements ISiteSettings.GetSpecialData
|
||||
Friend Overridable 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
|
||||
Friend Overridable Function GetSpecialDataF(ByVal URL As String) As IEnumerable(Of UserMedia)
|
||||
@@ -90,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
|
||||
|
||||
@@ -42,7 +42,7 @@ Namespace API.Base
|
||||
Me.New(_URL)
|
||||
[Type] = _Type
|
||||
End Sub
|
||||
Friend Sub New(ByVal m As Plugin.IPluginUserMedia)
|
||||
Friend Sub New(ByVal m As Plugin.PluginUserMedia)
|
||||
If Not IsNothing(m) Then
|
||||
[Type] = m.ContentType
|
||||
URL = m.URL
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
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
|
||||
@@ -114,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"
|
||||
@@ -204,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
|
||||
@@ -220,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
|
||||
@@ -247,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
|
||||
@@ -266,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
|
||||
@@ -332,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
|
||||
@@ -404,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
|
||||
@@ -421,7 +444,7 @@ BlockNullPicture:
|
||||
Friend Property ExternalPlugin As IPluginContentProvider
|
||||
Private Property IPluginContentProvider_ExistingContentList As List(Of PluginUserMedia) Implements IPluginContentProvider.ExistingContentList
|
||||
Private Property IPluginContentProvider_TempPostsList As List(Of String) Implements IPluginContentProvider.TempPostsList
|
||||
Private Property IPluginContentProvider_TempMediaList As List(Of IPluginUserMedia) Implements IPluginContentProvider.TempMediaList
|
||||
Private Property IPluginContentProvider_TempMediaList As List(Of PluginUserMedia) Implements IPluginContentProvider.TempMediaList
|
||||
Private Property IPluginContentProvider_SeparateVideoFolder As Boolean Implements IPluginContentProvider.SeparateVideoFolder
|
||||
Private Property IPluginContentProvider_DataPath As String Implements IPluginContentProvider.DataPath
|
||||
Private Sub IPluginContentProvider_XmlFieldsSet(ByVal Fields As List(Of KeyValuePair(Of String, String))) Implements IPluginContentProvider.XmlFieldsSet
|
||||
@@ -468,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
|
||||
@@ -475,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
|
||||
@@ -486,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
|
||||
@@ -558,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)
|
||||
@@ -575,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)
|
||||
@@ -614,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)
|
||||
@@ -712,7 +740,7 @@ BlockNullPicture:
|
||||
#Region "Download functions and options"
|
||||
Friend Overridable Property DownloadTopCount As Integer? = Nothing Implements IUserData.DownloadTopCount, IPluginContentProvider.PostsNumberLimit
|
||||
Friend Overridable Property DownloadToDate As Date? = Nothing Implements IUserData.DownloadToDate, IPluginContentProvider.PostsDateLimit
|
||||
Protected Responser As PersonalUtilities.Tools.WEB.Response
|
||||
Protected Responser As Response
|
||||
Friend Overridable Sub DownloadData(ByVal Token As CancellationToken) Implements IContentProvider.DownloadData
|
||||
Dim Canceled As Boolean = False
|
||||
_ExternalCompatibilityToken = Token
|
||||
@@ -720,14 +748,10 @@ BlockNullPicture:
|
||||
UpdateDataFiles()
|
||||
UserDescriptionReset()
|
||||
If Not Responser Is Nothing Then Responser.Dispose()
|
||||
Responser = New PersonalUtilities.Tools.WEB.Response
|
||||
If TypeOf HOST.Source Is IResponserContainer Then
|
||||
With DirectCast(HOST.Source, IResponserContainer)
|
||||
If Not .Responser Is Nothing Then Responser.Copy(.Responser)
|
||||
End With
|
||||
End If
|
||||
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
|
||||
@@ -755,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()
|
||||
@@ -763,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)
|
||||
@@ -902,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
|
||||
@@ -922,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
|
||||
@@ -941,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
|
||||
@@ -961,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()
|
||||
@@ -990,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
|
||||
@@ -998,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()
|
||||
@@ -1006,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
|
||||
@@ -1051,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
|
||||
@@ -1096,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
|
||||
@@ -1234,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()
|
||||
|
||||
@@ -21,8 +21,6 @@ Namespace API.Instagram
|
||||
With MyDefs
|
||||
.MyViewInitialize(Me, Settings.Design, True)
|
||||
.AddOkCancelToolbar()
|
||||
.DelegateClosingChecker()
|
||||
.AppendDetectors()
|
||||
With MyExchangeOptions
|
||||
CH_GET_STORIES.Checked = .GetStories
|
||||
CH_GET_TAGGED.Checked = .GetTagged
|
||||
@@ -30,14 +28,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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 TaggedChecked > 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
|
||||
@@ -451,7 +536,8 @@ Namespace API.Instagram
|
||||
End Try
|
||||
End Sub
|
||||
#End Region
|
||||
Private Sub GetUserId()
|
||||
#Region "GetUserId"
|
||||
<Obsolete> Private Sub GetUserId_Old()
|
||||
Try
|
||||
Dim r$ = Responser.GetResponse($"https://www.instagram.com/{Name}/?__a=1",, EDP.ThrowException)
|
||||
If Not r.IsEmptyString Then
|
||||
@@ -467,18 +553,35 @@ Namespace API.Instagram
|
||||
End If
|
||||
End Try
|
||||
End Sub
|
||||
Private Sub GetUserId()
|
||||
Try
|
||||
Dim r$ = Responser.GetResponse($"https://i.instagram.com/api/v1/users/web_profile_info/?username={Name}",, EDP.ThrowException)
|
||||
If Not r.IsEmptyString Then
|
||||
Using j As EContainer = JsonDocument.Parse(r).XmlIfNothing
|
||||
ID = j({"data", "user"}, "id").XmlIfNothingValue
|
||||
End Using
|
||||
End If
|
||||
Catch ex As Exception
|
||||
If Responser.StatusCode = HttpStatusCode.NotFound Or Responser.StatusCode = HttpStatusCode.BadRequest Then
|
||||
Throw ex
|
||||
Else
|
||||
LogError(ex, "get Instagram user id")
|
||||
End If
|
||||
End Try
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Pinned stories"
|
||||
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 +589,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 +597,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 +625,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 +639,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 +662,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 +677,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)
|
||||
|
||||
@@ -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
|
||||
|
||||
40
SCrawler/API/Reddit/IRedditView.vb
Normal 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
|
||||
@@ -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
|
||||
301
SCrawler/API/Reddit/RedditViewSettingsForm.Designer.vb
generated
Normal 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
|
||||
1268
SCrawler/API/Reddit/RedditViewSettingsForm.resx
Normal file
88
SCrawler/API/Reddit/RedditViewSettingsForm.vb
Normal file
@@ -0,0 +1,88 @@
|
||||
' 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()
|
||||
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
|
||||
@@ -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
|
||||
@@ -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 = $"[{CInt(Responser.StatusCode)}] Reddit is currently unavailable ({ToString()})"
|
||||
Else
|
||||
If Not FromPE Then LogError(ex, Message) : HasError = True
|
||||
Return 0
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
@@ -222,7 +224,8 @@ Friend Class ChannelViewForm : Implements IChannelLimits
|
||||
.SmallImageList = New ImageList With {.ColorDepth = ColorDepth.Depth32Bit, .ImageSize = s}
|
||||
End With
|
||||
CMB_CHANNELS.Enabled(False) = Not CMB_CHANNELS.Checked
|
||||
MyDefs.EndLoaderOperations()
|
||||
MyDefs.DelegateClosingChecker = False
|
||||
MyDefs.EndLoaderOperations(False)
|
||||
SetLimitsByChannel(, False)
|
||||
End Sub
|
||||
Private Sub ChannelViewForm_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
|
||||
@@ -279,11 +282,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 +313,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 +327,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 +544,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 +592,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()
|
||||
|
||||
@@ -22,14 +22,12 @@ Friend Class ChannelsStatsForm : Implements IOkCancelDeleteToolbar
|
||||
With MyDefs
|
||||
.MyViewInitialize(Me, Settings.Design)
|
||||
.AddOkCancelToolbar()
|
||||
.DelegateClosingChecker()
|
||||
.MyOkCancel.EnableDelete = False
|
||||
If Settings.Channels.Count > 0 Then
|
||||
RefillList()
|
||||
Else
|
||||
MsgBoxE("Channels not found", vbExclamation)
|
||||
End If
|
||||
.AppendDetectors()
|
||||
.EndLoaderOperations()
|
||||
End With
|
||||
Catch ex As Exception
|
||||
@@ -47,19 +45,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()
|
||||
|
||||
BIN
SCrawler/Content/Icons/GroupBy_284.ico
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
SCrawler/Content/Pictures/Pause_Blue_16.png
Normal file
|
After Width: | Height: | Size: 345 B |
BIN
SCrawler/Content/Pictures/ScriptPic32.png
Normal file
|
After Width: | Height: | Size: 490 B |
@@ -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
|
||||
|
||||
346
SCrawler/Download/AutoDownloader.vb
Normal 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
|
||||
278
SCrawler/Download/AutoDownloaderEditorForm.Designer.vb
generated
Normal 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
|
||||