Compare commits
8 Commits
2022.9.16.
...
2022.11.16
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bdc7321331 | ||
|
|
7d169acebc | ||
|
|
f5c156b8e5 | ||
|
|
d91ee72eaa | ||
|
|
4e9de23b60 | ||
|
|
129558c262 | ||
|
|
a3e79eb4bc | ||
|
|
eb28255de3 |
2
.gitignore
vendored
@@ -34,7 +34,9 @@ bld/
|
|||||||
[Ll]og/
|
[Ll]og/
|
||||||
[Ll]ogs/
|
[Ll]ogs/
|
||||||
ffmpeg/
|
ffmpeg/
|
||||||
|
cURL/
|
||||||
Info/
|
Info/
|
||||||
|
Hidden/
|
||||||
|
|
||||||
# Visual Studio 2015/2017 cache/options directory
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
.vs/
|
.vs/
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ I welcome requests! Follow these steps to contribute:
|
|||||||
1. If you have a code change suggestion, you can post a replacement code block. I also accept pull requests.
|
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
|
# How to build from source
|
||||||
|
|
||||||
1. Delete the "PersonalUtilities" project from the solution.
|
1. Delete the "PersonalUtilities" project from the solution.
|
||||||
1. Delete the "PersonalUtilities.Notifications" project from the solution.
|
1. Delete the "PersonalUtilities.Notifications" project from the solution.
|
||||||
1. The following libraries must be added to project references with the '**Copy to output folder**' option:
|
1. The following libraries must be added to project references with the '**Copy to output folder**' option:
|
||||||
@@ -21,7 +20,6 @@ I welcome requests! Follow these steps to contribute:
|
|||||||
**Always use the correct libraries. You must download libraries from the same release date as the code commit date.**
|
**Always use the correct libraries. You must download libraries from the same release date as the code commit date.**
|
||||||
|
|
||||||
# How to request a new site
|
# 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.
|
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.
|
||||||
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).
|
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).
|
||||||
|
|
||||||
@@ -38,16 +36,5 @@ I welcome requests! Follow these steps to contribute:
|
|||||||
If I'm interested in a site you want to add, it may be added in future releases.
|
If I'm interested in a site you want to add, it may be added in future releases.
|
||||||
|
|
||||||
# Sites I will never develop
|
# Sites I will never develop
|
||||||
|
|
||||||
- Facebook
|
- Facebook
|
||||||
|
- Tumblr
|
||||||
# Sites requested by users
|
|
||||||
|
|
||||||
- TikTok
|
|
||||||
- API for receiving data without authorization was not found. Therefore, I don't have time to start developing this site parsing algorithm. If anyone knows of requests that may collect data without OAuth authentication, please let me know.
|
|
||||||
|
|
||||||
# Contact me
|
|
||||||
|
|
||||||
[](https://matrix.to/#/@andyprogram:matrix.org)
|
|
||||||
|
|
||||||
[](https://discordapp.com/users/1012768226679206009) AndyProgram#3804
|
|
||||||
122
Changelog.md
@@ -1,3 +1,125 @@
|
|||||||
|
# 2022.11.16.0
|
||||||
|
|
||||||
|
*2022-11-16*
|
||||||
|
|
||||||
|
**ATTENTION! This version makes changes to the base SCrawler user configuration file. Since you started using this version, you still can downgrade. BUT! Once you add a virtual collection or a virtual user to a collection, you won't be able to downgrade without losing data.**
|
||||||
|
|
||||||
|
- Added
|
||||||
|
- **PornHub**
|
||||||
|
- **XHamster**
|
||||||
|
- An ability to download saved XVIDEOS posts
|
||||||
|
- Download indicator. While downloading, the rainbow tray icon changed to a blue arrow.
|
||||||
|
- Collections: the ability to edit a collection using a form
|
||||||
|
- Collections: the ability to create a **`virtual collection`** and add a **`virtual user`** to a real collection
|
||||||
|
- Collections: an easier way to added users to a collection
|
||||||
|
- Collections: an easier way to create collections
|
||||||
|
- Added icons for channels form context menu buttons
|
||||||
|
- More convenient change of user labels from the context menu of the user list
|
||||||
|
- Notifications: complete transition from default notifications to ToastNotifications
|
||||||
|
- Notifications: when you click on the notification that some of the channels are downloaded, the channels form opens
|
||||||
|
- Notifications: when you click on the notification that all users are downloaded, the main window form opens
|
||||||
|
- Notifications: when you click on the notification that the saved posts are downloaded, the saved posts form opens
|
||||||
|
- Import users
|
||||||
|
- Minor improvements
|
||||||
|
- Plugins
|
||||||
|
- Added
|
||||||
|
- `TaskGroup` attribute
|
||||||
|
- `IUserMedia` interface
|
||||||
|
- Changed
|
||||||
|
- `GetUserUrl` and `GetUserPostUrl` functions: `String UserName` and `String UserID` changed to ` IPluginContentProvider User`
|
||||||
|
- Fixed
|
||||||
|
- Collections editor: new added collections are still not added to the top of the collections list
|
||||||
|
- Users search form doesn't remember last size
|
||||||
|
- Minor bugs
|
||||||
|
|
||||||
|
# 2022.10.23.0
|
||||||
|
|
||||||
|
*2022-10-23*
|
||||||
|
|
||||||
|
- Added
|
||||||
|
- RedGifs token Auto-Renewal
|
||||||
|
- Download groups: ability to select sites
|
||||||
|
- Download groups: ability to exclude labels and sites
|
||||||
|
- AutoDownloader: ability to exclude labels and sites in ```All```, ```Default``` and ```Specified``` modes
|
||||||
|
- The ```Download All``` button turns blue when pause is enabled
|
||||||
|
- Updated Twitter status codes
|
||||||
|
- Minor improvements
|
||||||
|
- Fixed
|
||||||
|
- Updated Twitter status codes
|
||||||
|
- AutoDownloader: incorrect next run date in scheduler task information
|
||||||
|
- AutoDownloader: minor bugs
|
||||||
|
- (Issue #69) **RedGifs data is not downloading**. Requires token.
|
||||||
|
- Minor bugs
|
||||||
|
|
||||||
|
# 2022.10.18.0
|
||||||
|
|
||||||
|
*2022-10-18*
|
||||||
|
|
||||||
|
- Added
|
||||||
|
- **TikTok** ([limited](https://github.com/AAndyProgram/SCrawler/wiki/Settings#tiktok-limits))
|
||||||
|
- **Search form** (```Ctrl+F```)
|
||||||
|
- Feed improvements
|
||||||
|
- Ability to save the download session for viewing later
|
||||||
|
- Ability to download user, excluding from the feed (use the ```Ctrl``` key with a button click of with a hot key press)
|
||||||
|
- Ability to disable the notification about the absence of the ffmpeg.exe file
|
||||||
|
- Extended user information with labels
|
||||||
|
- Advanced AutoDownloader pause options
|
||||||
|
- Added pause buttons to tray icon and AutoDownloader form
|
||||||
|
- Additional Instagram protection
|
||||||
|
- Advanced notification management
|
||||||
|
- Silent mode (temporarily disable notification)
|
||||||
|
- Excluding users whose profiles do not exist from downloading with groups and AutoDownloader
|
||||||
|
- Minor improvements
|
||||||
|
- Updated
|
||||||
|
- Grouped all download buttons into one menu
|
||||||
|
- **Finished missing posts**. You can now download missing posts if they exist.
|
||||||
|
- PluginProvider: added ```BeginEdit``` and ```EndEdit``` methods
|
||||||
|
- PluginProvider: ```GetSpecialData``` return type changed from ```IEnumerable(Of PluginUserMedia)``` to ```IEnumerable```
|
||||||
|
- XVIDEOS and LPSG plugins are moved from libraries to SCrawler
|
||||||
|
- Fixed
|
||||||
|
- (Issue #69) **RedGifs data is not downloading**. Requires cookies and token.
|
||||||
|
- Some minor bugs when deleting a collection
|
||||||
|
- Feed: start video playing may cause the program to freeze (strange behavior of the vlc library)
|
||||||
|
- Feed: videos hosted on Reddit not showing up in feed
|
||||||
|
- Feed: minor bugs
|
||||||
|
- Collection users were not banned when deleted with the ban option
|
||||||
|
- When trying to delete multiple collections, each collection asked for confirmation to delete
|
||||||
|
- Minor bugs
|
||||||
|
|
||||||
|
# 2022.9.24.0
|
||||||
|
|
||||||
|
*2022-09-24*
|
||||||
|
|
||||||
|
- Added
|
||||||
|
- Ability to copy user data to another destination
|
||||||
|
- Ability to add 'Session' and 'Date' values to the post title in the feed
|
||||||
|
- Minor feed improvements
|
||||||
|
- The newly created collection will now appear at the top of the list (after reopening the form)
|
||||||
|
- Ability to add multiple users at a time to the collection.
|
||||||
|
- Fixed
|
||||||
|
- Autodownloader opens a compressed image instead of a full one
|
||||||
|
- Incorrect resizing of the feed grid after deleting a media file
|
||||||
|
- Incorrect behavior when deleting/removing a user from a collection.
|
||||||
|
- An incorrect function that displayed the number of spent Instagram requests.
|
||||||
|
- Bug in the XVIDEOS downloader
|
||||||
|
- Minor bugs
|
||||||
|
|
||||||
|
# 2022.9.17.0
|
||||||
|
|
||||||
|
*2022-09-17*
|
||||||
|
|
||||||
|
- Added
|
||||||
|
- Added two date filters to filter users (in range, not in range)
|
||||||
|
- (Request #71) Download data for a specific date range
|
||||||
|
- The ability to disable site downloading (in the site settings form)
|
||||||
|
- Updated
|
||||||
|
- Plugins
|
||||||
|
- Fixed
|
||||||
|
- (Issue #71) ```Download data to the date``` doesn't work for Twitter
|
||||||
|
- Download data for a specific date range doesn't work for multiple users
|
||||||
|
- Incorrect feed sorting algorithm
|
||||||
|
- Minor bugs
|
||||||
|
|
||||||
# 2022.9.16.0
|
# 2022.9.16.0
|
||||||
|
|
||||||
*2022-09-16*
|
*2022-09-16*
|
||||||
|
|||||||
22
FAQ.md
@@ -18,7 +18,7 @@ A: https://github.com/AAndyProgram/SCrawler/wiki/Settings#how-to-set-up-cookies
|
|||||||
|
|
||||||
#### Q: **I can't copy cookies.**
|
#### Q: **I can't copy cookies.**
|
||||||
|
|
||||||
A: Use the mouse. Don't use ```Ctrl``` + ```A```!
|
A: Use the mouse. Don't use ```Ctrl+A```!
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
@@ -44,6 +44,8 @@ A: How to request a new site you can read [here](CONTRIBUTING.md#how-to-request-
|
|||||||
|
|
||||||
A: Check your credentials. Both of these sites require cookies. Check your [Twitter tokens](https://github.com/AAndyProgram/SCrawler/wiki/Settings#how-to-find-twitter-tokens) and [Instagram settings](https://github.com/AAndyProgram/SCrawler/wiki/Settings#instagram-settings). If all settings are set, but nothing works, go to [create a new issue](https://github.com/AAndyProgram/SCrawler/issues). Don't forget to attach the LOG.
|
A: Check your credentials. Both of these sites require cookies. Check your [Twitter tokens](https://github.com/AAndyProgram/SCrawler/wiki/Settings#how-to-find-twitter-tokens) and [Instagram settings](https://github.com/AAndyProgram/SCrawler/wiki/Settings#instagram-settings). If all settings are set, but nothing works, go to [create a new issue](https://github.com/AAndyProgram/SCrawler/issues). Don't forget to attach the LOG.
|
||||||
|
|
||||||
|
**[SITES REQUIREMENTS](https://github.com/AAndyProgram/SCrawler/wiki/Settings#sites-requirements)**
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
#### Q: **I have set credentials but still nothing is downloading**
|
#### Q: **I have set credentials but still nothing is downloading**
|
||||||
@@ -94,6 +96,24 @@ A: Just add that user back to the program. In the dialog box that opens, click o
|
|||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
|
#### Q: **Why don't you answer how it works**
|
||||||
|
|
||||||
|
A: Because **I don't want to**. I don't want to waste my time explaining things that are already covered in the **[GUIDE](https://github.com/AAndyProgram/SCrawler/wiki)**! If you didn't bother to read the guide, why would I waste my time?! ALL FUNCTIONALITY IS DESCRIBED IN THE GUIDE. Before publishing a new release, I update the guide. If you don't respect my work, I don't waste my time.
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
#### Q: **You lost me. Your program is too complicated.**
|
||||||
|
|
||||||
|
A: **I'm fine with that**. If the program is difficult for you or you can't configure it, I can only suggest you find another (easier) program. I really don't mind! The program is free. I am develop SCrawler for myself and publish on GitHub because people found my program useful. If someone can't use it or doesn't like it, I'm fine.
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
#### Q: **I can't configure something**
|
||||||
|
|
||||||
|
A: I can only [suggest](#q-you-lost-me-your-program-is-too-complicated) you find another (easier) program.
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
#### Q: **Can you add a step-by-step guide or video on how to use the program?**
|
#### 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.
|
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.
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
Your support is very valuable to me. Any support is greatly appreciated. Your support encourages me to make new features, update the program, add new sites, etc.
|
Your support is very valuable to me. Any support is greatly appreciated. Your support encourages me to make new features, update the program, add new sites, etc.
|
||||||
|
|
||||||
You can support the program by:
|
You can support the program by:
|
||||||
- **Bitcoin**: bitcoin:BC1Q0NH839FT5TA44DD7L7RLR97XDQAG9V8D6N7XET
|
- **Bitcoin**: BC1Q0NH839FT5TA44DD7L7RLR97XDQAG9V8D6N7XET
|
||||||
- :heavy_dollar_sign: make a donation 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)
|
- :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
|
- :speech_balloon: tell your friends about the program
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
List of available plugins:
|
List of available plugins:
|
||||||
- LPSG
|
|
||||||
- XVIDEOS
|
|
||||||
|
|
||||||
Tools:
|
Tools:
|
||||||
- [image2post](https://github.com/unknown81311/SCrawler-image2post) by @unknown81311: **get reddit post URL from file.**
|
- [image2post](https://github.com/unknown81311/SCrawler-image2post) by @unknown81311: **get reddit post URL from file.**
|
||||||
|
Before Width: | Height: | Size: 574 KiB After Width: | Height: | Size: 483 KiB |
BIN
ProgramScreenshots/FeedWindowItemContext.png
Normal file
|
After Width: | Height: | Size: 9.7 KiB |
BIN
ProgramScreenshots/FeedWindowSessionContext.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 370 KiB After Width: | Height: | Size: 363 KiB |
|
Before Width: | Height: | Size: 379 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 15 KiB |
BIN
ProgramScreenshots/MainWindowPause.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
ProgramScreenshots/MainWindowView.png
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 14 KiB |
BIN
ProgramScreenshots/SearchUsers.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 11 KiB |
BIN
ProgramScreenshots/SettingsGlobalNotifications.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 28 KiB |
BIN
ProgramScreenshots/SettingsSiteInstagramAdditional.png
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
BIN
ProgramScreenshots/SettingsSiteLPSG.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
ProgramScreenshots/SettingsSitePornHub.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
ProgramScreenshots/SettingsSiteRedGifs.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
BIN
ProgramScreenshots/SettingsSiteTikTok.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 16 KiB |
BIN
ProgramScreenshots/SettingsSiteXHamster.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
ProgramScreenshots/SettingsSiteXvideos.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
ProgramScreenshots/SettingsSiteXvideosAdditional.png
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
ProgramScreenshots/TrayContextMenu.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
@@ -68,7 +68,7 @@ https://github.com/RipMeApp/ripme
|
|||||||
| **Free options** | The program is completely free | The program is completely free, but site limits are not declared |
|
| **Free options** | The program is completely free | The program is completely free, but site limits are not declared |
|
||||||
| Operating Systems | Windows 10+ | Windows, MacOS, Linux |
|
| Operating Systems | Windows 10+ | Windows, MacOS, Linux |
|
||||||
| Select want content type to download | Yes | Yes |
|
| Select want content type to download | Yes | Yes |
|
||||||
| Suported sites | 6 internal and any site using plugins | 86+ sites (declared) |
|
| Suported sites | 9 internal and any site using plugins | 86+ sites (declared) |
|
||||||
| Other sites support | **Yes** | No |
|
| Other sites support | **Yes** | No |
|
||||||
| Still supported | **Yes** | **No (last release date May 4, 2021)** |
|
| Still supported | **Yes** | **No (last release date May 4, 2021)** |
|
||||||
|
|
||||||
|
|||||||
83
README.md
@@ -6,29 +6,31 @@
|
|||||||
[](https://github.com/AAndyProgram/SCrawler/wiki)
|
[](https://github.com/AAndyProgram/SCrawler/wiki)
|
||||||
[](HowToSupport.md)
|
[](HowToSupport.md)
|
||||||
|
|
||||||
A program to download photo and video from [any site](#supported-sites) (e.g. Reddit, Twitter, Instagram).
|
A program to download photo and video from [any site](#supported-sites) (e.g. Reddit, Twitter, Instagram, TikTok, RedGifs, PornHub, XHamster, XVIDEOS, LPSG).
|
||||||
|
|
||||||
|
**If you like SCrawler, please like the program on [this site]( https://alternativeto.net/software/scrawler/about/)**
|
||||||
|
|
||||||
Do you like this program? Consider adding to my coffee fund by making a donation to show your support. :blush:
|
Do you like this program? Consider adding to my coffee fund by making a donation to show your support. :blush:
|
||||||
|
|
||||||
[](https://ko-fi.com/andyprogram)
|
[](https://ko-fi.com/andyprogram)
|
||||||
|
|
||||||
**Bitcoin**: bitcoin:BC1Q0NH839FT5TA44DD7L7RLR97XDQAG9V8D6N7XET
|
**Bitcoin**: BC1Q0NH839FT5TA44DD7L7RLR97XDQAG9V8D6N7XET
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
# What can program do:
|
# What can program do:
|
||||||
- Download pictures and videos from users' profiles and subreddits:
|
- Download pictures and videos from users' profiles and subreddits:
|
||||||
- Reddit images;
|
- Reddit images, galleries of images, videos (downloading Reddit hosted video is going through ffmpeg (**ffmpeg only works with the x64 program**)), saved posts;
|
||||||
- Reddit galleries of images;
|
|
||||||
- Reddit videos (downloading Reddit hosted video is going through ffmpeg (**ffmpeg only works with the x64 program**));
|
|
||||||
- Redgifs videos (https://www.redgifs.com/);
|
- Redgifs videos (https://www.redgifs.com/);
|
||||||
- Twitter images and videos;
|
- Twitter images and videos, saved (bookmarked) posts;
|
||||||
- Instagram images and videos;
|
- Instagram images and videos, tagged posts, stories, saved posts;
|
||||||
- Instagram tagged posts;
|
- TikTok videos ([limited](https://github.com/AAndyProgram/SCrawler/wiki/Settings#tiktok-limits));
|
||||||
- Instagram stories;
|
|
||||||
- Imgur images, galleries and videos;
|
- Imgur images, galleries and videos;
|
||||||
- Gfycat videos;
|
- Gfycat videos;
|
||||||
|
- PornHub images, videos, save (liked) posts;
|
||||||
|
- XHamster images, videos, saved posts;
|
||||||
|
- XVIDEOS videos;
|
||||||
- [Other](#supported-sites) supported sites
|
- [Other](#supported-sites) supported sites
|
||||||
- Parse [channel and view data](https://github.com/AAndyProgram/SCrawler/wiki/Channels)
|
- 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)
|
- Download [saved Reddit, Twitter and Instagram posts](https://github.com/AAndyProgram/SCrawler/wiki/Home#saved-posts)
|
||||||
@@ -53,14 +55,19 @@ Do you like this program? Consider adding to my coffee fund by making a donation
|
|||||||
- **Reddit**
|
- **Reddit**
|
||||||
- **Twitter**
|
- **Twitter**
|
||||||
- **Instagram**
|
- **Instagram**
|
||||||
|
- **TikTok** ([limited](https://github.com/AAndyProgram/SCrawler/wiki/Settings#tiktok-limits))
|
||||||
- RedGifs
|
- RedGifs
|
||||||
- Imgur
|
- Imgur
|
||||||
- Gfycat
|
- Gfycat
|
||||||
- LPSG
|
- LPSG
|
||||||
- XVIDEOS
|
- **PornHub**
|
||||||
|
- **XHamster**
|
||||||
|
- **XVIDEOS**
|
||||||
- [Other sites](Plugins.md)
|
- [Other sites](Plugins.md)
|
||||||
|
|
||||||
# How does it works:
|
**[SITES REQUIREMENTS](https://github.com/AAndyProgram/SCrawler/wiki/Settings#sites-requirements)**
|
||||||
|
|
||||||
|
# How it works
|
||||||
|
|
||||||
First, the program downloads the full profile. After the program downloads only new posts. The program remembers downloaded posts.
|
First, the program downloads the full profile. After the program downloads only new posts. The program remembers downloaded posts.
|
||||||
|
|
||||||
@@ -72,8 +79,6 @@ The program parses all user posts, obtain MD5 images hash and compares them wit
|
|||||||
|
|
||||||
The program parses all user posts and compares file names with existing ones to remove duplicates. Then the media will be downloaded.
|
The program parses all user posts and compares file names with existing ones to remove duplicates. Then the media will be downloaded.
|
||||||
|
|
||||||
You can read about Instagram restrictions [here](https://github.com/AAndyProgram/SCrawler/wiki/Settings#instagram-limits)
|
|
||||||
|
|
||||||
## How to request a new site
|
## How to request a new site
|
||||||
|
|
||||||
Read [here](CONTRIBUTING.md#how-to-request-a-new-site) about
|
Read [here](CONTRIBUTING.md#how-to-request-a-new-site) about
|
||||||
@@ -81,12 +86,35 @@ Read [here](CONTRIBUTING.md#how-to-request-a-new-site) about
|
|||||||
# Requirements
|
# Requirements
|
||||||
|
|
||||||
- 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).
|
- 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)
|
- **[SITES REQUIREMENTS](https://github.com/AAndyProgram/SCrawler/wiki/Settings#sites-requirements)**
|
||||||
- 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
|
# Guide
|
||||||
|
|
||||||
|
- [Main window](https://github.com/AAndyProgram/SCrawler/wiki)
|
||||||
|
- [Users](https://github.com/AAndyProgram/SCrawler/wiki/Users)
|
||||||
|
- [Add/Edit/Delete users](https://github.com/AAndyProgram/SCrawler/wiki/Users)
|
||||||
|
- [Collections](https://github.com/AAndyProgram/SCrawler/wiki#collections)
|
||||||
|
- [User operations](https://github.com/AAndyProgram/SCrawler/wiki#context-menu)
|
||||||
|
- [User labels](https://github.com/AAndyProgram/SCrawler/wiki/Users#labels)
|
||||||
|
- **[DOWNLOAD](https://github.com/AAndyProgram/SCrawler/wiki#download)**
|
||||||
|
- [Automation](https://github.com/AAndyProgram/SCrawler/wiki/Settings#automation)
|
||||||
|
- [Download groups](https://github.com/AAndyProgram/SCrawler/wiki/Settings#download-groups)
|
||||||
|
- [Downloading information](https://github.com/AAndyProgram/SCrawler/wiki#info)
|
||||||
|
- [Reddit channels](https://github.com/AAndyProgram/SCrawler/wiki/Channels)
|
||||||
|
- [Saved posts](https://github.com/AAndyProgram/SCrawler/wiki#saved-posts)
|
||||||
|
- [View modes, filters](https://github.com/AAndyProgram/SCrawler/wiki#view)
|
||||||
|
- **[SETTINGS](https://github.com/AAndyProgram/SCrawler/wiki/Settings)**
|
||||||
|
- **[SITES REQUIREMENTS](https://github.com/AAndyProgram/SCrawler/wiki/Settings#sites-requirements)**
|
||||||
|
- [Reddit](https://github.com/AAndyProgram/SCrawler/wiki/Settings#reddit)
|
||||||
|
- [Twitter](https://github.com/AAndyProgram/SCrawler/wiki/Settings#twitter)
|
||||||
|
- [Instagram](https://github.com/AAndyProgram/SCrawler/wiki/Settings#instagram)
|
||||||
|
- [TikTok](https://github.com/AAndyProgram/SCrawler/wiki/Settings#tiktok)
|
||||||
|
- [RedGifs](https://github.com/AAndyProgram/SCrawler/wiki/Settings#redgifs)
|
||||||
|
- [PornHub](https://github.com/AAndyProgram/SCrawler/wiki/Settings#pornhub)
|
||||||
|
- [XHamster](https://github.com/AAndyProgram/SCrawler/wiki/Settings#xhamster)
|
||||||
|
- [XVIDEOS](https://github.com/AAndyProgram/SCrawler/wiki/Settings#xvideos)
|
||||||
|
- [LPSG](https://github.com/AAndyProgram/SCrawler/wiki/Settings#lpsg)
|
||||||
|
|
||||||
**Full guide you can find [here](https://github.com/AAndyProgram/SCrawler/wiki)**
|
**Full guide you can find [here](https://github.com/AAndyProgram/SCrawler/wiki)**
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
@@ -115,22 +143,9 @@ Read more about how to support the program [here](HowToSupport.md).
|
|||||||
|
|
||||||
The program has an intuitive interface.
|
The program has an intuitive interface.
|
||||||
|
|
||||||
You need to set up authorization for Twitter and Instagram:
|
**[SITES REQUIREMENTS](https://github.com/AAndyProgram/SCrawler/wiki/Settings#sites-requirements)**
|
||||||
- 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**.
|
Just add a user profile and **click the ```Download``` button**.
|
||||||
|
|
||||||
You can add users by patterns:
|
|
||||||
- https://www.instagram.com/SomeUserName
|
|
||||||
- https://twitter.com/SomeUserName
|
|
||||||
- https://reddit.com/user/SomeUserName
|
|
||||||
- https://reddit.com/r/SomeSubredditName
|
|
||||||
- https://www.redgifs.com/users/SomeUserName
|
|
||||||
- u/SomeUserName
|
|
||||||
- r/SomeSubredditName
|
|
||||||
- SomeUserName (in this case, you need to select the user's site)
|
|
||||||
- SomeSubredditName
|
|
||||||
|
|
||||||
Read more about adding users and subreddits [here](https://github.com/AAndyProgram/SCrawler/wiki/Users)
|
Read more about adding users and subreddits [here](https://github.com/AAndyProgram/SCrawler/wiki/Users)
|
||||||
|
|
||||||
@@ -143,9 +158,3 @@ Create a shortcut for the program. Open shortcut properties. In the ```Shortcut`
|
|||||||
Example: ```D:\Programs\SCrawler\SCrawler.exe v```
|
Example: ```D:\Programs\SCrawler\SCrawler.exe v```
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
# Contact me
|
|
||||||
|
|
||||||
[](https://matrix.to/#/@andyprogram:matrix.org)
|
|
||||||
|
|
||||||
[](https://discordapp.com/users/1012768226679206009) AndyProgram#3804
|
|
||||||
|
|||||||
@@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices
|
|||||||
' by using the '*' as shown below:
|
' by using the '*' as shown below:
|
||||||
' <Assembly: AssemblyVersion("1.0.*")>
|
' <Assembly: AssemblyVersion("1.0.*")>
|
||||||
|
|
||||||
<Assembly: AssemblyVersion("2022.9.10.0")>
|
<Assembly: AssemblyVersion("2022.10.12.0")>
|
||||||
<Assembly: AssemblyFileVersion("2022.9.10.0")>
|
<Assembly: AssemblyFileVersion("2022.10.12.0")>
|
||||||
<Assembly: NeutralResourcesLanguage("en")>
|
<Assembly: NeutralResourcesLanguage("en")>
|
||||||
|
|||||||
@@ -54,6 +54,10 @@ Public Class SiteSettings : Implements ISiteSettings
|
|||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Update"
|
#Region "Update"
|
||||||
|
Public Sub BeginEdit() Implements ISiteSettings.BeginEdit
|
||||||
|
End Sub
|
||||||
|
Public Sub EndEdit() Implements ISiteSettings.EndEdit
|
||||||
|
End Sub
|
||||||
Public Sub BeginUpdate() Implements ISiteSettings.BeginUpdate
|
Public Sub BeginUpdate() Implements ISiteSettings.BeginUpdate
|
||||||
End Sub
|
End Sub
|
||||||
Public Sub EndUpdate() Implements ISiteSettings.EndUpdate
|
Public Sub EndUpdate() Implements ISiteSettings.EndUpdate
|
||||||
@@ -92,7 +96,7 @@ Public Class SiteSettings : Implements ISiteSettings
|
|||||||
Return Nothing
|
Return Nothing
|
||||||
End Function
|
End Function
|
||||||
Public Function Available(ByVal What As ISiteSettings.Download, ByVal Silent As Boolean) As Boolean Implements ISiteSettings.Available
|
Public Function Available(ByVal What As ISiteSettings.Download, ByVal Silent As Boolean) As Boolean Implements ISiteSettings.Available
|
||||||
Return True
|
Return If(Responser.Cookies?.Count, 0) > 0
|
||||||
End Function
|
End Function
|
||||||
Public Function ReadyToDownload(ByVal What As ISiteSettings.Download) As Boolean Implements ISiteSettings.ReadyToDownload
|
Public Function ReadyToDownload(ByVal What As ISiteSettings.Download) As Boolean Implements ISiteSettings.ReadyToDownload
|
||||||
Return True
|
Return True
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ Public Class UserData : Implements IPluginContentProvider
|
|||||||
Public Property SeparateVideoFolder As Boolean Implements IPluginContentProvider.SeparateVideoFolder
|
Public Property SeparateVideoFolder As Boolean Implements IPluginContentProvider.SeparateVideoFolder
|
||||||
Public Property DataPath As String Implements IPluginContentProvider.DataPath
|
Public Property DataPath As String Implements IPluginContentProvider.DataPath
|
||||||
Public Property PostsNumberLimit As Integer? Implements IPluginContentProvider.PostsNumberLimit
|
Public Property PostsNumberLimit As Integer? Implements IPluginContentProvider.PostsNumberLimit
|
||||||
Public Property PostsDateLimit As Date? Implements IPluginContentProvider.PostsDateLimit
|
Public Property DownloadDateFrom As Date? Implements IPluginContentProvider.DownloadDateFrom
|
||||||
|
Public Property DownloadDateTo As Date? Implements IPluginContentProvider.DownloadDateTo
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Interface exchange options"
|
#Region "Interface exchange options"
|
||||||
Public Sub ExchangeOptionsSet(ByVal Obj As Object) Implements IPluginContentProvider.ExchangeOptionsSet
|
Public Sub ExchangeOptionsSet(ByVal Obj As Object) Implements IPluginContentProvider.ExchangeOptionsSet
|
||||||
|
|||||||
@@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices
|
|||||||
' by using the '*' as shown below:
|
' by using the '*' as shown below:
|
||||||
' <Assembly: AssemblyVersion("1.0.*")>
|
' <Assembly: AssemblyVersion("1.0.*")>
|
||||||
|
|
||||||
<Assembly: AssemblyVersion("2022.9.10.0")>
|
<Assembly: AssemblyVersion("2022.10.12.0")>
|
||||||
<Assembly: AssemblyFileVersion("2022.9.10.0")>
|
<Assembly: AssemblyFileVersion("2022.10.12.0")>
|
||||||
<Assembly: NeutralResourcesLanguage("en")>
|
<Assembly: NeutralResourcesLanguage("en")>
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ Public Class SettingsForm
|
|||||||
Settings.UpdateDomains()
|
Settings.UpdateDomains()
|
||||||
MyDefs.CloseForm()
|
MyDefs.CloseForm()
|
||||||
End Sub
|
End Sub
|
||||||
Private Sub MyDefs_ButtonAddClick(ByVal Sender As Object, ByVal e As EditToolbar.EditToolbarEventArgs) Handles MyDefs.ButtonAddClick
|
Private Sub MyDefs_ButtonAddClick(ByVal Sender As Object, ByVal e As EditToolbarEventArgs) Handles MyDefs.ButtonAddClick
|
||||||
Dim nd$ = InputBoxE("Enter a new domain using the pattern [xvideos.com]:", "New domain")
|
Dim nd$ = InputBoxE("Enter a new domain using the pattern [xvideos.com]:", "New domain")
|
||||||
If Not nd.IsEmptyString Then
|
If Not nd.IsEmptyString Then
|
||||||
If Not LIST_DOMAINS.Items.Contains(nd) Then
|
If Not LIST_DOMAINS.Items.Contains(nd) Then
|
||||||
@@ -45,7 +45,7 @@ Public Class SettingsForm
|
|||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
Private Sub MyDefs_ButtonDeleteClickE(ByVal Sender As Object, ByVal e As EditToolbar.EditToolbarEventArgs) Handles MyDefs.ButtonDeleteClickE
|
Private Sub MyDefs_ButtonDeleteClickE(ByVal Sender As Object, ByVal e As EditToolbarEventArgs) Handles MyDefs.ButtonDeleteClickE
|
||||||
If _LatestSelected.ValueBetween(0, LIST_DOMAINS.Items.Count - 1) Then
|
If _LatestSelected.ValueBetween(0, LIST_DOMAINS.Items.Count - 1) Then
|
||||||
Dim n$ = LIST_DOMAINS.Items(_LatestSelected)
|
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
|
If MsgBoxE({$"Are you sure you want to delete the [{n}] domain?", "Removing domains"}, MsgBoxStyle.YesNo) = MsgBoxResult.Yes Then
|
||||||
|
|||||||
@@ -97,6 +97,10 @@ Public Class SiteSettings : Implements ISiteSettings
|
|||||||
Public Sub DownloadDone(ByVal What As ISiteSettings.Download) Implements ISiteSettings.DownloadDone
|
Public Sub DownloadDone(ByVal What As ISiteSettings.Download) Implements ISiteSettings.DownloadDone
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
|
Public Sub BeginEdit() Implements ISiteSettings.BeginEdit
|
||||||
|
End Sub
|
||||||
|
Public Sub EndEdit() Implements ISiteSettings.EndEdit
|
||||||
|
End Sub
|
||||||
Public Sub BeginUpdate() Implements ISiteSettings.BeginUpdate
|
Public Sub BeginUpdate() Implements ISiteSettings.BeginUpdate
|
||||||
End Sub
|
End Sub
|
||||||
Public Sub EndUpdate() Implements ISiteSettings.EndUpdate
|
Public Sub EndUpdate() Implements ISiteSettings.EndUpdate
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ Public Class UserData : Implements IPluginContentProvider
|
|||||||
Public Property SeparateVideoFolder As Boolean Implements IPluginContentProvider.SeparateVideoFolder
|
Public Property SeparateVideoFolder As Boolean Implements IPluginContentProvider.SeparateVideoFolder
|
||||||
Public Property DataPath As String Implements IPluginContentProvider.DataPath
|
Public Property DataPath As String Implements IPluginContentProvider.DataPath
|
||||||
Public Property PostsNumberLimit As Integer? Implements IPluginContentProvider.PostsNumberLimit
|
Public Property PostsNumberLimit As Integer? Implements IPluginContentProvider.PostsNumberLimit
|
||||||
Public Property PostsDateLimit As Date? Implements IPluginContentProvider.PostsDateLimit
|
Public Property DownloadDateFrom As Date? Implements IPluginContentProvider.DownloadDateFrom
|
||||||
|
Public Property DownloadDateTo As Date? Implements IPluginContentProvider.DownloadDateTo
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Interface exchange options"
|
#Region "Interface exchange options"
|
||||||
Public Sub ExchangeOptionsSet(ByVal Obj As Object) Implements IPluginContentProvider.ExchangeOptionsSet
|
Public Sub ExchangeOptionsSet(ByVal Obj As Object) Implements IPluginContentProvider.ExchangeOptionsSet
|
||||||
@@ -70,7 +71,7 @@ Public Class UserData : Implements IPluginContentProvider
|
|||||||
|
|
||||||
Dim NextPage% = 0
|
Dim NextPage% = 0
|
||||||
Dim r$
|
Dim r$
|
||||||
Dim j As EContainer, jj As EContainer
|
Dim jj As EContainer
|
||||||
Dim e As ErrorsDescriber = EDP.ThrowException
|
Dim e As ErrorsDescriber = EDP.ThrowException
|
||||||
Dim user$ = Settings.GetUserUrl(Name, False)
|
Dim user$ = Settings.GetUserUrl(Name, False)
|
||||||
Dim p As PluginUserMedia
|
Dim p As PluginUserMedia
|
||||||
@@ -81,8 +82,7 @@ Public Class UserData : Implements IPluginContentProvider
|
|||||||
r = Responser.GetResponse($"https://www.xvideos.com/{user}/videos/new/{If(NextPage = 0, String.Empty, NextPage)}",, e)
|
r = Responser.GetResponse($"https://www.xvideos.com/{user}/videos/new/{If(NextPage = 0, String.Empty, NextPage)}",, e)
|
||||||
If Not r.IsEmptyString Then
|
If Not r.IsEmptyString Then
|
||||||
If Not EnvirSet Then UserExists = True : UserSuspended = False : EnvirSet = True
|
If Not EnvirSet Then UserExists = True : UserSuspended = False : EnvirSet = True
|
||||||
j = JsonDocument.Parse(r).XmlIfNothing
|
With JsonDocument.Parse(r).XmlIfNothing
|
||||||
With j
|
|
||||||
If .Contains("videos") Then
|
If .Contains("videos") Then
|
||||||
With .Item("videos")
|
With .Item("videos")
|
||||||
If .Count > 0 Then
|
If .Count > 0 Then
|
||||||
@@ -93,9 +93,12 @@ Public Class UserData : Implements IPluginContentProvider
|
|||||||
.URL = $"https://www.xvideos.com{jj.Value("u")}"
|
.URL = $"https://www.xvideos.com{jj.Value("u")}"
|
||||||
}
|
}
|
||||||
If Not p.PostID.IsEmptyString And Not jj.Value("u").IsEmptyString Then
|
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
|
If Not TempPostsList.Contains(p.PostID) Then TempPostsList.Add(p.PostID) : TempMediaList.Add(p) Else .Dispose() : Exit Do
|
||||||
End If
|
End If
|
||||||
Next
|
Next
|
||||||
|
Else
|
||||||
|
.Dispose()
|
||||||
|
Exit Do
|
||||||
End If
|
End If
|
||||||
End With
|
End With
|
||||||
Else
|
Else
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
[*.vb]
|
[*.vb]
|
||||||
# Modifier preferences
|
# 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/>
|
file_header_template = Copyright (C) 2023 Andy https://github.com/AAndyProgram\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/>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
@@ -53,6 +53,9 @@ Namespace Plugin.Attributes
|
|||||||
ElementName = XMLElementName
|
ElementName = XMLElementName
|
||||||
End Sub
|
End Sub
|
||||||
End Class
|
End Class
|
||||||
|
''' <summary>Attribute to disable some properties for host use</summary>
|
||||||
|
<AttributeUsage(AttributeTargets.Property, AllowMultiple:=False, Inherited:=False)> Public NotInheritable Class DoNotUse : Inherits Attribute
|
||||||
|
End Class
|
||||||
''' <summary>Special property updater</summary>
|
''' <summary>Special property updater</summary>
|
||||||
<AttributeUsage(AttributeTargets.Method, AllowMultiple:=True, Inherited:=False)> Public NotInheritable Class PropertyUpdater : Inherits Attribute
|
<AttributeUsage(AttributeTargets.Method, AllowMultiple:=True, Inherited:=False)> Public NotInheritable Class PropertyUpdater : Inherits Attribute
|
||||||
Public ReadOnly Name As String
|
Public ReadOnly Name As String
|
||||||
@@ -129,13 +132,26 @@ Namespace Plugin.Attributes
|
|||||||
''' Predefined task counter.<br/>
|
''' Predefined task counter.<br/>
|
||||||
''' <see cref="TaskCounter"/> will take precedence if it is defined.
|
''' <see cref="TaskCounter"/> will take precedence if it is defined.
|
||||||
''' </param>
|
''' </param>
|
||||||
Public Sub New(Optional ByVal JobsCount As Integer = -1)
|
Public Sub New(Optional ByVal TasksCount As Integer = -1)
|
||||||
TasksCount = JobsCount
|
Me.TasksCount = TasksCount
|
||||||
End Sub
|
End Sub
|
||||||
End Class
|
End Class
|
||||||
''' <summary>A property attribute that specifies how many users should be downloaded at the same time in one thread</summary>
|
''' <summary>A property attribute that specifies how many users should be downloaded at the same time in one thread</summary>
|
||||||
<AttributeUsage(AttributeTargets.Property, AllowMultiple:=False, Inherited:=False)> Public NotInheritable Class TaskCounter : Inherits Attribute
|
<AttributeUsage(AttributeTargets.Property, AllowMultiple:=False, Inherited:=False)> Public NotInheritable Class TaskCounter : Inherits Attribute
|
||||||
End Class
|
End Class
|
||||||
|
''' <remarks>
|
||||||
|
''' This attribute cannot be combined with <see cref="SeparatedTasks"/>.
|
||||||
|
''' If set to <see cref="SeparatedTasks"/>, this attribute will be ignored
|
||||||
|
''' </remarks>
|
||||||
|
''' <inheritdoc cref="SeparatedTasks"/>
|
||||||
|
<AttributeUsage(AttributeTargets.Class, AllowMultiple:=False, Inherited:=False)> Public NotInheritable Class TaskGroup : Inherits Attribute
|
||||||
|
Public ReadOnly Name As String
|
||||||
|
''' <summary>Initialize a new TaskGroup attribute.</summary>
|
||||||
|
''' <param name="Name">Group name</param>
|
||||||
|
Public Sub New(ByVal Name As String)
|
||||||
|
Me.Name = Name
|
||||||
|
End Sub
|
||||||
|
End Class
|
||||||
''' <summary>This attribute indicates that the plugin has a SavedPosts environment</summary>
|
''' <summary>This attribute indicates that the plugin has a SavedPosts environment</summary>
|
||||||
<AttributeUsage(AttributeTargets.Class, AllowMultiple:=False, Inherited:=False)> Public NotInheritable Class SavedPosts : Inherits Attribute
|
<AttributeUsage(AttributeTargets.Class, AllowMultiple:=False, Inherited:=False)> Public NotInheritable Class SavedPosts : Inherits Attribute
|
||||||
End Class
|
End Class
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
@@ -17,16 +17,17 @@ Namespace Plugin
|
|||||||
Property ID As String
|
Property ID As String
|
||||||
Property ParseUserMediaOnly As Boolean
|
Property ParseUserMediaOnly As Boolean
|
||||||
Property UserDescription As String
|
Property UserDescription As String
|
||||||
Property ExistingContentList As List(Of PluginUserMedia)
|
Property ExistingContentList As List(Of IUserMedia)
|
||||||
Property TempPostsList As List(Of String)
|
Property TempPostsList As List(Of String)
|
||||||
Property TempMediaList As List(Of PluginUserMedia)
|
Property TempMediaList As List(Of IUserMedia)
|
||||||
Property UserExists As Boolean
|
Property UserExists As Boolean
|
||||||
Property UserSuspended As Boolean
|
Property UserSuspended As Boolean
|
||||||
Property IsSavedPosts As Boolean
|
Property IsSavedPosts As Boolean
|
||||||
Property SeparateVideoFolder As Boolean
|
Property SeparateVideoFolder As Boolean
|
||||||
Property DataPath As String
|
Property DataPath As String
|
||||||
Property PostsNumberLimit As Integer?
|
Property PostsNumberLimit As Integer?
|
||||||
Property PostsDateLimit As Date?
|
Property DownloadDateFrom As Date?
|
||||||
|
Property DownloadDateTo As Date?
|
||||||
Function ExchangeOptionsGet() As Object
|
Function ExchangeOptionsGet() As Object
|
||||||
Sub ExchangeOptionsSet(ByVal Obj As Object)
|
Sub ExchangeOptionsSet(ByVal Obj As Object)
|
||||||
Sub XmlFieldsSet(ByVal Fields As List(Of KeyValuePair(Of String, String)))
|
Sub XmlFieldsSet(ByVal Fields As List(Of KeyValuePair(Of String, String)))
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
@@ -18,12 +18,12 @@ Namespace Plugin
|
|||||||
ReadOnly Property Image As Image
|
ReadOnly Property Image As Image
|
||||||
ReadOnly Property Site As String
|
ReadOnly Property Site As String
|
||||||
Property Logger As ILogProvider
|
Property Logger As ILogProvider
|
||||||
Function GetUserUrl(ByVal UserName As String, ByVal Channel As Boolean) As String
|
Function GetUserUrl(ByVal User As IPluginContentProvider, ByVal Channel As Boolean) As String
|
||||||
Function IsMyUser(ByVal UserURL As String) As ExchangeOptions
|
Function IsMyUser(ByVal UserURL As String) As ExchangeOptions
|
||||||
Function IsMyImageVideo(ByVal URL As String) As ExchangeOptions
|
Function IsMyImageVideo(ByVal URL As String) As ExchangeOptions
|
||||||
Function GetSpecialData(ByVal URL As String, ByVal Path As String, ByVal AskForPath As Boolean) As IEnumerable(Of PluginUserMedia)
|
Function GetSpecialData(ByVal URL As String, ByVal Path As String, ByVal AskForPath As Boolean) As IEnumerable
|
||||||
Function GetInstance(ByVal What As Download) As IPluginContentProvider
|
Function GetInstance(ByVal What As Download) As IPluginContentProvider
|
||||||
Function GetUserPostUrl(ByVal UserID As String, ByVal PostID As String) As String
|
Function GetUserPostUrl(ByVal User As IPluginContentProvider, ByVal Media As IUserMedia) As String
|
||||||
#Region "XML Support"
|
#Region "XML Support"
|
||||||
Sub Load(ByVal XMLValues As IEnumerable(Of KeyValuePair(Of String, String)))
|
Sub Load(ByVal XMLValues As IEnumerable(Of KeyValuePair(Of String, String)))
|
||||||
#End Region
|
#End Region
|
||||||
@@ -32,6 +32,8 @@ Namespace Plugin
|
|||||||
Sub EndInit()
|
Sub EndInit()
|
||||||
Sub BeginUpdate()
|
Sub BeginUpdate()
|
||||||
Sub EndUpdate()
|
Sub EndUpdate()
|
||||||
|
Sub BeginEdit()
|
||||||
|
Sub EndEdit()
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Site availability"
|
#Region "Site availability"
|
||||||
Function Available(ByVal What As Download, ByVal Silent As Boolean) As Boolean
|
Function Available(ByVal What As Download, ByVal Silent As Boolean) As Boolean
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ Imports System.Runtime.InteropServices
|
|||||||
<Assembly: AssemblyDescription("Plugin provider for SCrawler")>
|
<Assembly: AssemblyDescription("Plugin provider for SCrawler")>
|
||||||
<Assembly: AssemblyCompany("AndyProgram")>
|
<Assembly: AssemblyCompany("AndyProgram")>
|
||||||
<Assembly: AssemblyProduct("SCrawler.PluginProvider")>
|
<Assembly: AssemblyProduct("SCrawler.PluginProvider")>
|
||||||
<Assembly: AssemblyCopyright("Copyright © 2022")>
|
<Assembly: AssemblyCopyright("Copyright © 2023")>
|
||||||
<Assembly: AssemblyTrademark("AndyProgram")>
|
<Assembly: AssemblyTrademark("AndyProgram")>
|
||||||
|
|
||||||
<Assembly: ComVisible(False)>
|
<Assembly: ComVisible(False)>
|
||||||
@@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices
|
|||||||
' by using the '*' as shown below:
|
' by using the '*' as shown below:
|
||||||
' <Assembly: AssemblyVersion("1.0.*")>
|
' <Assembly: AssemblyVersion("1.0.*")>
|
||||||
|
|
||||||
<Assembly: AssemblyVersion("2022.9.10.0")>
|
<Assembly: AssemblyVersion("2022.11.16.0")>
|
||||||
<Assembly: AssemblyFileVersion("2022.9.10.0")>
|
<Assembly: AssemblyFileVersion("2022.11.16.0")>
|
||||||
<Assembly: NeutralResourcesLanguage("en")>
|
<Assembly: NeutralResourcesLanguage("en")>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
@@ -7,8 +7,7 @@
|
|||||||
' This program is distributed in the hope that it will be useful,
|
' This program is distributed in the hope that it will be useful,
|
||||||
' but WITHOUT ANY WARRANTY
|
' but WITHOUT ANY WARRANTY
|
||||||
Namespace Plugin
|
Namespace Plugin
|
||||||
Public Structure PluginUserMedia
|
Public Enum UserMediaTypes As Integer
|
||||||
Enum Types As Integer
|
|
||||||
Undefined = 0
|
Undefined = 0
|
||||||
[Picture] = 1
|
[Picture] = 1
|
||||||
[Video] = 2
|
[Video] = 2
|
||||||
@@ -17,15 +16,35 @@ Namespace Plugin
|
|||||||
GIF = 50
|
GIF = 50
|
||||||
m3u8 = 100
|
m3u8 = 100
|
||||||
End Enum
|
End Enum
|
||||||
Enum States As Integer : Unknown = 0 : Tried = 1 : Downloaded = 2 : Skipped = 3 : Missing = 4 : End Enum
|
Public Enum UserMediaStates As Integer
|
||||||
Public ContentType As Integer
|
Unknown = 0
|
||||||
Public URL As String
|
Tried = 1
|
||||||
Public MD5 As String
|
Downloaded = 2
|
||||||
Public File As String
|
Skipped = 3
|
||||||
Public DownloadState As Integer
|
Missing = 4
|
||||||
Public PostID As String
|
End Enum
|
||||||
Public PostDate As Date?
|
Public Structure PluginUserMedia : Implements IUserMedia
|
||||||
Public SpecialFolder As String
|
Public Property ContentType As Integer Implements IUserMedia.ContentType
|
||||||
Public Attempts As Integer
|
Public Property URL As String Implements IUserMedia.URL
|
||||||
|
Public Property URL_BASE As String Implements IUserMedia.URL_BASE
|
||||||
|
Public Property MD5 As String Implements IUserMedia.MD5
|
||||||
|
Public Property File As String Implements IUserMedia.File
|
||||||
|
Public Property DownloadState As Integer Implements IUserMedia.DownloadState
|
||||||
|
Public Property PostID As String Implements IUserMedia.PostID
|
||||||
|
Public Property PostDate As Date? Implements IUserMedia.PostDate
|
||||||
|
Public Property SpecialFolder As String Implements IUserMedia.SpecialFolder
|
||||||
|
Public Property Attempts As Integer Implements IUserMedia.Attempts
|
||||||
End Structure
|
End Structure
|
||||||
|
Public Interface IUserMedia
|
||||||
|
Property ContentType As Integer
|
||||||
|
Property URL As String
|
||||||
|
Property URL_BASE 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
|
||||||
|
Property Attempts As Integer
|
||||||
|
End Interface
|
||||||
End Namespace
|
End Namespace
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
|
|||||||
28
SCrawler.sln
@@ -17,10 +17,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "SCrawler.PluginProvider", "SCrawler.PluginProvider\SCrawler.PluginProvider.vbproj", "{D4650F6B-5A54-44B6-999B-6C675B7116B1}"
|
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "SCrawler.PluginProvider", "SCrawler.PluginProvider\SCrawler.PluginProvider.vbproj", "{D4650F6B-5A54-44B6-999B-6C675B7116B1}"
|
||||||
EndProject
|
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}"
|
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "PersonalUtilities.Notifications", "..\..\MyUtilities\PersonalUtilities.Notifications\PersonalUtilities.Notifications.vbproj", "{FC532253-1AB3-4DEF-A28A-DFDD9A481EB2}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
@@ -69,30 +65,6 @@ Global
|
|||||||
{D4650F6B-5A54-44B6-999B-6C675B7116B1}.Release|x64.Build.0 = Release|x64
|
{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.ActiveCfg = Release|x86
|
||||||
{D4650F6B-5A54-44B6-999B-6C675B7116B1}.Release|x86.Build.0 = 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.ActiveCfg = Debug|Any CPU
|
||||||
{FC532253-1AB3-4DEF-A28A-DFDD9A481EB2}.Debug|Any CPU.Build.0 = 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.ActiveCfg = Debug|x64
|
||||||
|
|||||||
@@ -123,4 +123,4 @@ insert_final_newline=false
|
|||||||
[*.vb]
|
[*.vb]
|
||||||
# Modifier preferences
|
# Modifier preferences
|
||||||
visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion
|
visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion
|
||||||
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/>
|
file_header_template = Copyright (C) 2023 Andy https://github.com/AAndyProgram\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/>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
|
|||||||
64
SCrawler/API/Base/M3U8Base.vb
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
|
' 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.Tools.Web
|
||||||
|
Imports PersonalUtilities.Tools.Web.Clients
|
||||||
|
Namespace API.Base
|
||||||
|
Namespace M3U8Declarations
|
||||||
|
Friend Module M3U8Defaults
|
||||||
|
Friend ReadOnly TsFilesRegEx As RParams = RParams.DM(".+?\.ts[^\r\n]*", 0, RegexReturn.List)
|
||||||
|
End Module
|
||||||
|
End Namespace
|
||||||
|
Friend NotInheritable Class M3U8Base
|
||||||
|
Private Sub New()
|
||||||
|
End Sub
|
||||||
|
Friend Shared Function CreateUrl(ByVal Appender As String, ByVal File As String) As String
|
||||||
|
File = File.StringTrimStart("/")
|
||||||
|
If File.StartsWith("http") Then
|
||||||
|
Return File
|
||||||
|
Else
|
||||||
|
If File.StartsWith("hls/") And Appender.Contains("hls/") Then _
|
||||||
|
Appender = LinkFormatterSecure(Appender.Replace("https://", String.Empty).Split("/").First)
|
||||||
|
Return $"{Appender.StringTrimEnd("/")}/{File}"
|
||||||
|
End If
|
||||||
|
End Function
|
||||||
|
Friend Shared Function Download(ByVal URLs As List(Of String), ByVal DestinationFile As SFile, Optional ByVal Responser As Response = Nothing) As SFile
|
||||||
|
Dim CachePath As SFile = Nothing
|
||||||
|
Try
|
||||||
|
If URLs.ListExists Then
|
||||||
|
Dim ConcatFile As SFile = DestinationFile
|
||||||
|
If ConcatFile.Name.IsEmptyString Then ConcatFile.Name = "PlayListFile"
|
||||||
|
ConcatFile.Extension = "mp4"
|
||||||
|
CachePath = $"{DestinationFile.PathWithSeparator}_Cache\{SFile.GetDirectories($"{DestinationFile.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 DownloadObjects.WebClient2(Responser)
|
||||||
|
For i = 0 To URLs.Count - 1
|
||||||
|
dFile.Name = $"ConPart_{i}"
|
||||||
|
w.DownloadFile(URLs(i), dFile)
|
||||||
|
eFiles.Add(dFile)
|
||||||
|
Next
|
||||||
|
End Using
|
||||||
|
DestinationFile = FFMPEG.ConcatenateFiles(eFiles, Settings.FfmpegFile, ConcatFile, p, EDP.ThrowException)
|
||||||
|
eFiles.Clear()
|
||||||
|
Return DestinationFile
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Return Nothing
|
||||||
|
Finally
|
||||||
|
CachePath.Delete(SFO.Path, SFODelete.None, EDP.None)
|
||||||
|
End Try
|
||||||
|
End Function
|
||||||
|
End Class
|
||||||
|
End Namespace
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
@@ -7,8 +7,8 @@
|
|||||||
' This program is distributed in the hope that it will be useful,
|
' This program is distributed in the hope that it will be useful,
|
||||||
' but WITHOUT ANY WARRANTY
|
' but WITHOUT ANY WARRANTY
|
||||||
Imports System.Threading
|
Imports System.Threading
|
||||||
Imports PersonalUtilities.Forms.Toolbars
|
|
||||||
Imports SCrawler.Plugin.Hosts
|
Imports SCrawler.Plugin.Hosts
|
||||||
|
Imports PersonalUtilities.Forms.Toolbars
|
||||||
Imports PDownload = SCrawler.Plugin.ISiteSettings.Download
|
Imports PDownload = SCrawler.Plugin.ISiteSettings.Download
|
||||||
Namespace API.Base
|
Namespace API.Base
|
||||||
Friend NotInheritable Class ProfileSaved
|
Friend NotInheritable Class ProfileSaved
|
||||||
@@ -25,7 +25,7 @@ Namespace API.Base
|
|||||||
HOST.DownloadStarted(PDownload.SavedPosts)
|
HOST.DownloadStarted(PDownload.SavedPosts)
|
||||||
Dim u As New UserInfo With {.Plugin = HOST.Key, .Site = HOST.Name, .SpecialPath = HOST.SavedPostsPath}
|
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)
|
Using user As IUserData = HOST.GetInstance(PDownload.SavedPosts, Nothing, False, False)
|
||||||
If Not user Is Nothing AndAlso (Not user.Name.IsEmptyString Or Not HOST.IsMyClass) Then
|
If Not user Is Nothing AndAlso Not user.Name.IsEmptyString Then
|
||||||
u.Name = user.Name
|
u.Name = user.Name
|
||||||
With DirectCast(user, UserDataBase)
|
With DirectCast(user, UserDataBase)
|
||||||
With .User : u.IsChannel = .IsChannel : u.UpdateUserFile() : End With
|
With .User : u.IsChannel = .IsChannel : u.UpdateUserFile() : End With
|
||||||
@@ -45,13 +45,14 @@ Namespace API.Base
|
|||||||
Progress.InformationTemporary = $"Host [{HOST.Name}] is unavailable"
|
Progress.InformationTemporary = $"Host [{HOST.Name}] is unavailable"
|
||||||
End If
|
End If
|
||||||
Else
|
Else
|
||||||
Progress.InformationTemporary = $"Host [{HOST.Name}] is nor ready"
|
Progress.InformationTemporary = $"Host [{HOST.Name}] is not ready"
|
||||||
End If
|
End If
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
Progress.InformationTemporary = $"{HOST.Name} downloading error"
|
Progress.InformationTemporary = $"{HOST.Name} downloading error"
|
||||||
ErrorsDescriber.Execute(EDP.SendInLog, ex, $"[API.Base.ProfileSaved.Download({HOST.Key})]")
|
ErrorsDescriber.Execute(EDP.SendInLog, ex, $"[API.Base.ProfileSaved.Download({HOST.Key})]")
|
||||||
Finally
|
Finally
|
||||||
HOST.DownloadDone(PDownload.SavedPosts)
|
HOST.DownloadDone(PDownload.SavedPosts)
|
||||||
|
MainFrameObj.UpdateLogButton()
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
End Class
|
End Class
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
@@ -7,7 +7,8 @@
|
|||||||
' This program is distributed in the hope that it will be useful,
|
' This program is distributed in the hope that it will be useful,
|
||||||
' but WITHOUT ANY WARRANTY
|
' but WITHOUT ANY WARRANTY
|
||||||
Imports PersonalUtilities.Functions.RegularExpressions
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
Imports PersonalUtilities.Tools.WEB
|
Imports PersonalUtilities.Tools.Web.Clients
|
||||||
|
Imports PersonalUtilities.Tools.Web.Cookies
|
||||||
Imports SCrawler.Plugin
|
Imports SCrawler.Plugin
|
||||||
Imports Download = SCrawler.Plugin.ISiteSettings.Download
|
Imports Download = SCrawler.Plugin.ISiteSettings.Download
|
||||||
Namespace API.Base
|
Namespace API.Base
|
||||||
@@ -40,6 +41,7 @@ Namespace API.Base
|
|||||||
.CookiesEncryptKey = SettingsCLS.CookieEncryptKey
|
.CookiesEncryptKey = SettingsCLS.CookieEncryptKey
|
||||||
.SaveSettings()
|
.SaveSettings()
|
||||||
End If
|
End If
|
||||||
|
If .CookiesDomain.IsEmptyString Then .CookiesDomain = CookiesDomain
|
||||||
End With
|
End With
|
||||||
End Sub
|
End Sub
|
||||||
#Region "XML"
|
#Region "XML"
|
||||||
@@ -56,6 +58,10 @@ Namespace API.Base
|
|||||||
End Sub
|
End Sub
|
||||||
Friend Overridable Sub EndUpdate() Implements ISiteSettings.EndUpdate
|
Friend Overridable Sub EndUpdate() Implements ISiteSettings.EndUpdate
|
||||||
End Sub
|
End Sub
|
||||||
|
Friend Overridable Sub BeginEdit() Implements ISiteSettings.BeginEdit
|
||||||
|
End Sub
|
||||||
|
Friend Overridable Sub EndEdit() Implements ISiteSettings.EndEdit
|
||||||
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Before and After Download"
|
#Region "Before and After Download"
|
||||||
Friend Overridable Sub DownloadStarted(ByVal What As Download) Implements ISiteSettings.DownloadStarted
|
Friend Overridable Sub DownloadStarted(ByVal What As Download) Implements ISiteSettings.DownloadStarted
|
||||||
@@ -70,15 +76,18 @@ Namespace API.Base
|
|||||||
#Region "User info"
|
#Region "User info"
|
||||||
Protected UrlPatternUser As String = String.Empty
|
Protected UrlPatternUser As String = String.Empty
|
||||||
Protected UrlPatternChannel As String = String.Empty
|
Protected UrlPatternChannel As String = String.Empty
|
||||||
Friend Overridable Function GetUserUrl(ByVal UserName As String, ByVal Channel As Boolean) As String Implements ISiteSettings.GetUserUrl
|
Friend Overridable Function GetUserUrl(ByVal User As IPluginContentProvider, ByVal Channel As Boolean) As String Implements ISiteSettings.GetUserUrl
|
||||||
If Channel Then
|
If Channel Then
|
||||||
If Not UrlPatternChannel.IsEmptyString Then Return String.Format(UrlPatternChannel, UserName)
|
If Not UrlPatternChannel.IsEmptyString Then Return String.Format(UrlPatternChannel, User.Name)
|
||||||
Else
|
Else
|
||||||
If Not UrlPatternUser.IsEmptyString Then Return String.Format(UrlPatternUser, UserName)
|
If Not UrlPatternUser.IsEmptyString Then Return String.Format(UrlPatternUser, User.Name)
|
||||||
End If
|
End If
|
||||||
Return String.Empty
|
Return String.Empty
|
||||||
End Function
|
End Function
|
||||||
Friend Overridable Function GetUserPostUrl(ByVal UserID As String, ByVal PostID As String) As String Implements ISiteSettings.GetUserPostUrl
|
Private Function ISiteSettings_GetUserPostUrl(ByVal User As IPluginContentProvider, ByVal Media As IUserMedia) As String Implements ISiteSettings.GetUserPostUrl
|
||||||
|
Return GetUserPostUrl(User, Media)
|
||||||
|
End Function
|
||||||
|
Friend Overridable Function GetUserPostUrl(ByVal User As UserDataBase, ByVal Media As UserMedia) As String
|
||||||
Return String.Empty
|
Return String.Empty
|
||||||
End Function
|
End Function
|
||||||
Protected UserRegex As RParams = Nothing
|
Protected UserRegex As RParams = Nothing
|
||||||
@@ -90,7 +99,7 @@ Namespace API.Base
|
|||||||
End If
|
End If
|
||||||
Return Nothing
|
Return Nothing
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
Return ErrorsDescriber.Execute(EDP.SendInLog + EDP.ReturnValue, ex, "[API.Base.SiteSettingsBase.IsMyUser]")
|
Return ErrorsDescriber.Execute(EDP.SendInLog + EDP.ReturnValue, ex, $"[API.Base.SiteSettingsBase.IsMyUser({UserURL})]", New ExchangeOptions)
|
||||||
End Try
|
End Try
|
||||||
End Function
|
End Function
|
||||||
Protected ImageVideoContains As String = String.Empty
|
Protected ImageVideoContains As String = String.Empty
|
||||||
@@ -101,17 +110,25 @@ Namespace API.Base
|
|||||||
Return Nothing
|
Return Nothing
|
||||||
End If
|
End If
|
||||||
End Function
|
End Function
|
||||||
Friend Overridable Function GetSpecialData(ByVal URL As String, ByVal Path As String, ByVal AskForPath As Boolean) As IEnumerable(Of PluginUserMedia) Implements ISiteSettings.GetSpecialData
|
Friend Overridable Function GetSpecialData(ByVal URL As String, ByVal Path As String, ByVal AskForPath As Boolean) As IEnumerable Implements ISiteSettings.GetSpecialData
|
||||||
Return Nothing
|
Return Nothing
|
||||||
End Function
|
End Function
|
||||||
Friend Overridable Function GetSpecialDataF(ByVal URL As String) As IEnumerable(Of UserMedia)
|
Friend Shared Function GetSpecialDataFile(ByVal Path As String, ByVal AskForPath As Boolean, ByRef SpecFolderObj As String) As SFile
|
||||||
Return Nothing
|
Dim f As SFile = Path.CSFileP
|
||||||
|
If f.Name.IsEmptyString Then f.Name = "OutputFile"
|
||||||
|
#Disable Warning BC40000
|
||||||
|
If Path.CSFileP.IsEmptyString Or AskForPath Then f = SFile.SaveAs(f, "File destination",,,, EDP.ReturnValue) : SpecFolderObj = f.Path
|
||||||
|
#Enable Warning
|
||||||
|
Return f
|
||||||
End Function
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Ready, Available"
|
#Region "Ready, Available"
|
||||||
Friend Overridable Function Available(ByVal What As Download, ByVal Silent As Boolean) As Boolean Implements ISiteSettings.Available
|
Friend Overridable Function BaseAuthExists() As Boolean
|
||||||
Return True
|
Return True
|
||||||
End Function
|
End Function
|
||||||
|
Friend Overridable Function Available(ByVal What As Download, ByVal Silent As Boolean) As Boolean Implements ISiteSettings.Available
|
||||||
|
Return BaseAuthExists()
|
||||||
|
End Function
|
||||||
Friend Overridable Function ReadyToDownload(ByVal What As Download) As Boolean Implements ISiteSettings.ReadyToDownload
|
Friend Overridable Function ReadyToDownload(ByVal What As Download) As Boolean Implements ISiteSettings.ReadyToDownload
|
||||||
Return True
|
Return True
|
||||||
End Function
|
End Function
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
@@ -6,9 +6,25 @@
|
|||||||
'
|
'
|
||||||
' This program is distributed in the hope that it will be useful,
|
' This program is distributed in the hope that it will be useful,
|
||||||
' but WITHOUT ANY WARRANTY
|
' but WITHOUT ANY WARRANTY
|
||||||
|
Imports SCrawler.Plugin
|
||||||
|
Imports PersonalUtilities.Functions.XML
|
||||||
|
Imports PersonalUtilities.Functions.XML.Base
|
||||||
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
Namespace API.Base
|
Namespace API.Base
|
||||||
Friend Module Structures
|
Friend Module Structures
|
||||||
Friend Structure UserMedia : Implements IEquatable(Of UserMedia)
|
Friend Structure UserMedia : Implements IUserMedia, IEquatable(Of UserMedia), IEContainerProvider
|
||||||
|
#Region "XML Names"
|
||||||
|
Friend Const Name_MediaNode As String = "MediaData"
|
||||||
|
Private Const Name_MediaType As String = "Type"
|
||||||
|
Private Const Name_MediaState As String = "State"
|
||||||
|
Private Const Name_MediaAttempts As String = "Attempts"
|
||||||
|
Private Const Name_MediaURL As String = "URL"
|
||||||
|
Private Const Name_MediaHash As String = "Hash"
|
||||||
|
Private Const Name_MediaFile As String = "File"
|
||||||
|
Private Const Name_MediaPostID As String = "ID"
|
||||||
|
Private Const Name_MediaPostDate As String = "Date"
|
||||||
|
Private Const Name_SpecialFolder As String = "SpecialFolder"
|
||||||
|
#End Region
|
||||||
Friend Enum Types As Integer
|
Friend Enum Types As Integer
|
||||||
Undefined = 0
|
Undefined = 0
|
||||||
[Picture] = 1
|
[Picture] = 1
|
||||||
@@ -33,27 +49,137 @@ Namespace API.Base
|
|||||||
''' SomeFolder\SomeFolder2
|
''' SomeFolder\SomeFolder2
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Friend SpecialFolder As String
|
Friend SpecialFolder As String
|
||||||
Friend Sub New(ByVal _URL As String)
|
Friend [Object] As Object
|
||||||
URL = _URL
|
#Region "Interface Support"
|
||||||
URL_BASE = _URL
|
Private Property IUserMedia_Type As Integer Implements IUserMedia.ContentType
|
||||||
|
Get
|
||||||
|
Return Type
|
||||||
|
End Get
|
||||||
|
Set(ByVal Type As Integer)
|
||||||
|
Me.Type = Type
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
Private Property IUserMedia_URL_BASE As String Implements IUserMedia.URL_BASE
|
||||||
|
Get
|
||||||
|
Return URL_BASE
|
||||||
|
End Get
|
||||||
|
Set(ByVal URL_BASE As String)
|
||||||
|
Me.URL_BASE = URL_BASE
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
Private Property IUserMedia_URL As String Implements IUserMedia.URL
|
||||||
|
Get
|
||||||
|
Return URL
|
||||||
|
End Get
|
||||||
|
Set(ByVal URL As String)
|
||||||
|
Me.URL = URL
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
Private Property IUserMedia_MD5 As String Implements IUserMedia.MD5
|
||||||
|
Get
|
||||||
|
Return MD5
|
||||||
|
End Get
|
||||||
|
Set(ByVal MD5 As String)
|
||||||
|
Me.MD5 = MD5
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
Private Property IUserMedia_File As String Implements IUserMedia.File
|
||||||
|
Get
|
||||||
|
Return File
|
||||||
|
End Get
|
||||||
|
Set(ByVal File As String)
|
||||||
|
Me.File = File
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
Private Property IUserMedia_State As Integer Implements IUserMedia.DownloadState
|
||||||
|
Get
|
||||||
|
Return State
|
||||||
|
End Get
|
||||||
|
Set(ByVal State As Integer)
|
||||||
|
Me.State = State
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
Private Property IUserMedia_PostID As String Implements IUserMedia.PostID
|
||||||
|
Get
|
||||||
|
Return Post.ID
|
||||||
|
End Get
|
||||||
|
Set(ByVal PostID As String)
|
||||||
|
Post.ID = PostID
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
Private Property IUserMedia_PostDate As Date? Implements IUserMedia.PostDate
|
||||||
|
Get
|
||||||
|
Return Post.Date
|
||||||
|
End Get
|
||||||
|
Set(ByVal PostDate As Date?)
|
||||||
|
Post.Date = PostDate
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
Private Property IUserMedia_SpecialFolder As String Implements IUserMedia.SpecialFolder
|
||||||
|
Get
|
||||||
|
Return SpecialFolder
|
||||||
|
End Get
|
||||||
|
Set(ByVal SpecialFolder As String)
|
||||||
|
Me.SpecialFolder = SpecialFolder
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
Private Property IUserMedia_Attempts As Integer Implements IUserMedia.Attempts
|
||||||
|
Get
|
||||||
|
Return Attempts
|
||||||
|
End Get
|
||||||
|
Set(ByVal Attempts As Integer)
|
||||||
|
Me.Attempts = Attempts
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
#End Region
|
||||||
|
Friend Sub New(ByVal URL As String)
|
||||||
|
Me.URL = URL
|
||||||
|
URL_BASE = URL
|
||||||
File = URL
|
File = URL
|
||||||
Type = Types.Undefined
|
Type = Types.Undefined
|
||||||
End Sub
|
End Sub
|
||||||
Friend Sub New(ByVal _URL As String, ByVal _Type As Types)
|
Friend Sub New(ByVal URL As String, ByVal Type As Types)
|
||||||
Me.New(_URL)
|
Me.New(URL)
|
||||||
[Type] = _Type
|
Me.Type = Type
|
||||||
End Sub
|
End Sub
|
||||||
Friend Sub New(ByVal m As Plugin.PluginUserMedia)
|
Friend Sub New(ByVal m As Plugin.IUserMedia)
|
||||||
If Not IsNothing(m) Then
|
|
||||||
[Type] = m.ContentType
|
[Type] = m.ContentType
|
||||||
URL = m.URL
|
URL = m.URL
|
||||||
|
URL_BASE = m.URL_BASE
|
||||||
MD5 = m.MD5
|
MD5 = m.MD5
|
||||||
File = m.File
|
File = m.File
|
||||||
Post = New UserPost With {.ID = m.PostID, .[Date] = m.PostDate}
|
Post = New UserPost With {.ID = m.PostID, .[Date] = m.PostDate}
|
||||||
State = m.DownloadState
|
State = m.DownloadState
|
||||||
SpecialFolder = m.SpecialFolder
|
SpecialFolder = m.SpecialFolder
|
||||||
Attempts = m.Attempts
|
Attempts = m.Attempts
|
||||||
|
End Sub
|
||||||
|
Friend Sub New(ByVal e As EContainer, ByVal UserInstance As IUserData)
|
||||||
|
Type = e.Attribute(Name_MediaType).Value.FromXML(Of Integer)(CInt(Types.Undefined))
|
||||||
|
State = e.Attribute(Name_MediaState).Value.FromXML(Of Integer)(CInt(States.Downloaded))
|
||||||
|
Attempts = e.Attribute(Name_MediaAttempts).Value.FromXML(Of Integer)(0)
|
||||||
|
URL = e.Attribute(Name_MediaURL).Value
|
||||||
|
URL_BASE = e.Value
|
||||||
|
MD5 = e.Attribute(Name_MediaHash).Value
|
||||||
|
File = e.Attribute(Name_MediaFile).Value
|
||||||
|
|
||||||
|
Dim vp As Boolean? = Nothing
|
||||||
|
Dim upath$ = String.Empty
|
||||||
|
If Not UserInstance Is Nothing Then
|
||||||
|
With DirectCast(UserInstance, UserDataBase)
|
||||||
|
vp = .SeparateVideoFolder
|
||||||
|
upath = .MyFile.CutPath.PathWithSeparator
|
||||||
|
End With
|
||||||
End If
|
End If
|
||||||
|
|
||||||
|
SpecialFolder = e.Attribute(Name_SpecialFolder).Value
|
||||||
|
If Not SpecialFolder.IsEmptyString Then upath &= $"{SpecialFolder}\"
|
||||||
|
If vp.HasValue AndAlso vp.Value Then upath &= $"Video\"
|
||||||
|
If Not upath.IsEmptyString Then File = $"{upath.CSFilePS}{File.File}"
|
||||||
|
|
||||||
|
Post = New UserPost With {
|
||||||
|
.ID = e.Attribute(Name_MediaPostID).Value,
|
||||||
|
.[Date] = AConvert(Of Date)(e.Attribute(Name_MediaPostDate).Value, ParsersDataDateProvider, Nothing)
|
||||||
|
}
|
||||||
End Sub
|
End Sub
|
||||||
Public Shared Widening Operator CType(ByVal _URL As String) As UserMedia
|
Public Shared Widening Operator CType(ByVal _URL As String) As UserMedia
|
||||||
Return New UserMedia(_URL)
|
Return New UserMedia(_URL)
|
||||||
@@ -61,44 +187,69 @@ Namespace API.Base
|
|||||||
Public Shared Widening Operator CType(ByVal m As UserMedia) As String
|
Public Shared Widening Operator CType(ByVal m As UserMedia) As String
|
||||||
Return m.URL
|
Return m.URL
|
||||||
End Operator
|
End Operator
|
||||||
|
Public Overrides Function GetHashCode() As Integer
|
||||||
|
If Not File.IsEmptyString Then
|
||||||
|
Return File.GetHashCode
|
||||||
|
ElseIf Not URL_BASE.IsEmptyString Then
|
||||||
|
Return URL_BASE.GetHashCode
|
||||||
|
ElseIf Not URL.IsEmptyString Then
|
||||||
|
Return URL.GetHashCode
|
||||||
|
Else
|
||||||
|
Return 0
|
||||||
|
End If
|
||||||
|
End Function
|
||||||
Public Overrides Function ToString() As String
|
Public Overrides Function ToString() As String
|
||||||
Return URL
|
Return URL
|
||||||
End Function
|
End Function
|
||||||
Friend Function PluginUserMedia() As Plugin.PluginUserMedia
|
|
||||||
Return New Plugin.PluginUserMedia With {
|
|
||||||
.ContentType = Type,
|
|
||||||
.DownloadState = State,
|
|
||||||
.File = File,
|
|
||||||
.MD5 = MD5,
|
|
||||||
.URL = URL,
|
|
||||||
.SpecialFolder = SpecialFolder,
|
|
||||||
.PostID = Post.ID,
|
|
||||||
.PostDate = Post.Date,
|
|
||||||
.Attempts = Attempts
|
|
||||||
}
|
|
||||||
End Function
|
|
||||||
Friend Overloads Function Equals(ByVal Other As UserMedia) As Boolean Implements IEquatable(Of UserMedia).Equals
|
Friend Overloads Function Equals(ByVal Other As UserMedia) As Boolean Implements IEquatable(Of UserMedia).Equals
|
||||||
Return URL = Other.URL
|
Return URL = Other.URL
|
||||||
End Function
|
End Function
|
||||||
Public Overrides Function Equals(ByVal Obj As Object) As Boolean
|
Public Overrides Function Equals(ByVal Obj As Object) As Boolean
|
||||||
Return Equals(CType(Obj, UserMedia))
|
Return Equals(CType(Obj, UserMedia))
|
||||||
End Function
|
End Function
|
||||||
|
Friend Function ToEContainer(Optional ByVal e As ErrorsDescriber = Nothing) As EContainer Implements IEContainerProvider.ToEContainer
|
||||||
|
Return New EContainer(Name_MediaNode, URL_BASE, {New EAttribute(Name_MediaType, CInt(Type)),
|
||||||
|
New EAttribute(Name_MediaState, CInt(State)),
|
||||||
|
New EAttribute(Name_MediaAttempts, Attempts),
|
||||||
|
New EAttribute(Name_MediaURL, URL),
|
||||||
|
New EAttribute(Name_MediaHash, MD5),
|
||||||
|
New EAttribute(Name_MediaFile, File.File),
|
||||||
|
New EAttribute(Name_SpecialFolder, SpecialFolder),
|
||||||
|
New EAttribute(Name_MediaPostID, Post.ID),
|
||||||
|
New EAttribute(Name_MediaPostDate, AConvert(Of String)(Post.Date, ParsersDataDateProvider, String.Empty))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
End Function
|
||||||
End Structure
|
End Structure
|
||||||
Friend Structure UserPost : Implements IEquatable(Of UserPost), IComparable(Of UserPost)
|
Friend Structure UserPost : Implements IEquatable(Of UserPost), IComparable(Of UserPost)
|
||||||
''' <summary>Post ID</summary>
|
''' <summary>Post ID</summary>
|
||||||
Friend ID As String
|
Friend ID As String
|
||||||
Friend [Date] As Date?
|
Friend [Date] As Date?
|
||||||
#Region "Channel compatible fields"
|
|
||||||
Friend UserID As String
|
Friend UserID As String
|
||||||
Friend CachedFile As SFile
|
Friend CachedFile As SFile
|
||||||
|
#Region "Initializers"
|
||||||
|
Public Sub New(ByVal ID As String)
|
||||||
|
Me.ID = ID
|
||||||
|
End Sub
|
||||||
|
Public Sub New(ByVal [Date] As Date?)
|
||||||
|
Me.Date = [Date]
|
||||||
|
End Sub
|
||||||
|
Public Sub New(ByVal ID As String, ByVal [Date] As Date?)
|
||||||
|
Me.ID = ID
|
||||||
|
Me.Date = [Date]
|
||||||
|
End Sub
|
||||||
|
Public Shared Widening Operator CType(ByVal ID As String) As UserPost
|
||||||
|
Return New UserPost(ID)
|
||||||
|
End Operator
|
||||||
|
Public Shared Widening Operator CType(ByVal Post As UserPost) As String
|
||||||
|
Return Post.ID
|
||||||
|
End Operator
|
||||||
#End Region
|
#End Region
|
||||||
Friend Function GetImage(ByVal s As Size, ByVal e As ErrorsDescriber, ByVal NullArg As Image) As Image
|
#Region "ToString"
|
||||||
If Not CachedFile.IsEmptyString Then
|
Public Overrides Function ToString() As String
|
||||||
Return If(PersonalUtilities.Tools.ImageRenderer.GetImage(SFile.GetBytes(CachedFile), s, e), NullArg.Clone)
|
Return ID
|
||||||
Else
|
|
||||||
Return NullArg.Clone
|
|
||||||
End If
|
|
||||||
End Function
|
End Function
|
||||||
|
#End Region
|
||||||
#Region "IEquatable, IComparable Support"
|
#Region "IEquatable, IComparable Support"
|
||||||
Friend Overloads Function Equals(ByVal Other As UserPost) As Boolean Implements IEquatable(Of UserPost).Equals
|
Friend Overloads Function Equals(ByVal Other As UserPost) As Boolean Implements IEquatable(Of UserPost).Equals
|
||||||
Return ID = Other.ID
|
Return ID = Other.ID
|
||||||
@@ -116,7 +267,7 @@ Namespace API.Base
|
|||||||
End Function
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
End Structure
|
End Structure
|
||||||
Friend Structure Sizes : Implements IComparable(Of Sizes)
|
Friend Structure Sizes : Implements IRegExCreator, IComparable(Of Sizes)
|
||||||
Friend Value As Integer
|
Friend Value As Integer
|
||||||
Friend Data As String
|
Friend Data As String
|
||||||
Friend ReadOnly HasError As Boolean
|
Friend ReadOnly HasError As Boolean
|
||||||
@@ -128,6 +279,16 @@ Namespace API.Base
|
|||||||
HasError = True
|
HasError = True
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
|
Private Function CreateFromArray(ByVal ParamsArray() As String) As Object Implements IRegExCreator.CreateFromArray
|
||||||
|
If ParamsArray.ListExists(2) Then
|
||||||
|
Return New Sizes With {
|
||||||
|
.Value = AConvert(Of Integer)(ParamsArray(0), 0),
|
||||||
|
.Data = ParamsArray(1)
|
||||||
|
}
|
||||||
|
Else
|
||||||
|
Return New Sizes
|
||||||
|
End If
|
||||||
|
End Function
|
||||||
Friend Function CompareTo(ByVal Other As Sizes) As Integer Implements IComparable(Of Sizes).CompareTo
|
Friend Function CompareTo(ByVal Other As Sizes) As Integer Implements IComparable(Of Sizes).CompareTo
|
||||||
Return Value.CompareTo(Other.Value) * -1
|
Return Value.CompareTo(Other.Value) * -1
|
||||||
End Function
|
End Function
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
@@ -10,7 +10,7 @@ Imports PersonalUtilities.Functions.XML
|
|||||||
Imports PersonalUtilities.Functions.RegularExpressions
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
Imports PersonalUtilities.Forms.Toolbars
|
Imports PersonalUtilities.Forms.Toolbars
|
||||||
Imports PersonalUtilities.Tools
|
Imports PersonalUtilities.Tools
|
||||||
Imports PersonalUtilities.Tools.WEB
|
Imports PersonalUtilities.Tools.Web.Clients
|
||||||
Imports System.IO
|
Imports System.IO
|
||||||
Imports System.Net
|
Imports System.Net
|
||||||
Imports System.Threading
|
Imports System.Threading
|
||||||
@@ -51,14 +51,12 @@ Namespace API.Base
|
|||||||
#Region "Collection buttons"
|
#Region "Collection buttons"
|
||||||
Private _CollectionButtonsExists As Boolean = False
|
Private _CollectionButtonsExists As Boolean = False
|
||||||
Private _CollectionButtonsColorsSet As Boolean = False
|
Private _CollectionButtonsColorsSet As Boolean = False
|
||||||
Friend InternalCollectionIndex As Integer = -1
|
Friend WithEvents BTT_CONTEXT_DOWN As ToolStripKeyMenuItem
|
||||||
Friend WithEvents BTT_CONTEXT_DOWN As ToolStripMenuItem
|
|
||||||
Friend WithEvents BTT_CONTEXT_EDIT As ToolStripMenuItem
|
Friend WithEvents BTT_CONTEXT_EDIT As ToolStripMenuItem
|
||||||
Friend WithEvents BTT_CONTEXT_DELETE As ToolStripMenuItem
|
Friend WithEvents BTT_CONTEXT_DELETE As ToolStripMenuItem
|
||||||
Friend WithEvents BTT_CONTEXT_OPEN_PATH As ToolStripMenuItem
|
Friend WithEvents BTT_CONTEXT_OPEN_PATH As ToolStripMenuItem
|
||||||
Friend WithEvents BTT_CONTEXT_OPEN_SITE As ToolStripMenuItem
|
Friend WithEvents BTT_CONTEXT_OPEN_SITE As ToolStripMenuItem
|
||||||
Friend Sub CreateButtons(ByVal CollectionIndex As Integer)
|
Friend Sub CreateButtons()
|
||||||
InternalCollectionIndex = CollectionIndex
|
|
||||||
Dim tn$ = $"[{Site}] - {Name}"
|
Dim tn$ = $"[{Site}] - {Name}"
|
||||||
Dim _tn$ = $"{Site}{Name}"
|
Dim _tn$ = $"{Site}{Name}"
|
||||||
Dim tnn As Func(Of String, String) = Function(Input) $"{Input}{_tn}"
|
Dim tnn As Func(Of String, String) = Function(Input) $"{Input}{_tn}"
|
||||||
@@ -70,11 +68,11 @@ Namespace API.Base
|
|||||||
i = .Image
|
i = .Image
|
||||||
End If
|
End If
|
||||||
End With
|
End With
|
||||||
BTT_CONTEXT_DOWN = New ToolStripMenuItem(tn, i) With {.Name = tnn("DOWN"), .Tag = CollectionIndex}
|
BTT_CONTEXT_DOWN = New ToolStripKeyMenuItem(tn, i) With {.Name = tnn("DOWN"), .Tag = Me}
|
||||||
BTT_CONTEXT_EDIT = New ToolStripMenuItem(tn, i) With {.Name = tnn("EDIT"), .Tag = CollectionIndex}
|
BTT_CONTEXT_EDIT = New ToolStripMenuItem(tn, i) With {.Name = tnn("EDIT"), .Tag = Me}
|
||||||
BTT_CONTEXT_DELETE = New ToolStripMenuItem(tn, i) With {.Name = tnn("DELETE"), .Tag = CollectionIndex}
|
BTT_CONTEXT_DELETE = New ToolStripMenuItem(tn, i) With {.Name = tnn("DELETE"), .Tag = Me}
|
||||||
BTT_CONTEXT_OPEN_PATH = New ToolStripMenuItem(tn, i) With {.Name = tnn("PATH"), .Tag = CollectionIndex}
|
BTT_CONTEXT_OPEN_PATH = New ToolStripMenuItem(tn, i) With {.Name = tnn("PATH"), .Tag = Me}
|
||||||
BTT_CONTEXT_OPEN_SITE = New ToolStripMenuItem(tn, i) With {.Name = tnn("SITE"), .Tag = CollectionIndex}
|
BTT_CONTEXT_OPEN_SITE = New ToolStripMenuItem(tn, i) With {.Name = tnn("SITE"), .Tag = Me}
|
||||||
UpdateButtonsColor()
|
UpdateButtonsColor()
|
||||||
_CollectionButtonsExists = True
|
_CollectionButtonsExists = True
|
||||||
If _UserInformationLoaded Then _CollectionButtonsColorsSet = True
|
If _UserInformationLoaded Then _CollectionButtonsColorsSet = True
|
||||||
@@ -96,9 +94,16 @@ Namespace API.Base
|
|||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "XML Declarations"
|
#Region "XML Declarations"
|
||||||
Private Const Name_Site As String = "Site"
|
Private Const Name_Site As String = UserInfo.Name_Site
|
||||||
Private Const Name_IsChannel As String = "IsChannel"
|
Private Const Name_Plugin As String = UserInfo.Name_Plugin
|
||||||
Private Const Name_UserName As String = "UserName"
|
Private Const Name_IsChannel As String = UserInfo.Name_IsChannel
|
||||||
|
Friend Const Name_UserName As String = "UserName"
|
||||||
|
Private Const Name_Model_User As String = UserInfo.Name_Model_User
|
||||||
|
Private Const Name_Model_Collection As String = UserInfo.Name_Model_Collection
|
||||||
|
Private Const Name_Merged As String = UserInfo.Name_Merged
|
||||||
|
Private Const Name_SpecialPath As String = UserInfo.Name_SpecialPath
|
||||||
|
Private Const Name_SpecialCollectionPath As String = UserInfo.Name_SpecialCollectionPath
|
||||||
|
|
||||||
Private Const Name_UserExists As String = "UserExists"
|
Private Const Name_UserExists As String = "UserExists"
|
||||||
Private Const Name_UserSuspended As String = "UserSuspended"
|
Private Const Name_UserSuspended As String = "UserSuspended"
|
||||||
Private Const Name_FriendlyName As String = "FriendlyName"
|
Private Const Name_FriendlyName As String = "FriendlyName"
|
||||||
@@ -110,8 +115,8 @@ Namespace API.Base
|
|||||||
Private Const Name_CreatedByChannel As String = "CreatedByChannel"
|
Private Const Name_CreatedByChannel As String = "CreatedByChannel"
|
||||||
|
|
||||||
Private Const Name_SeparateVideoFolder As String = "SeparateVideoFolder"
|
Private Const Name_SeparateVideoFolder As String = "SeparateVideoFolder"
|
||||||
Private Const Name_CollectionName As String = "Collection"
|
Private Const Name_CollectionName As String = UserInfo.Name_Collection
|
||||||
Private Const Name_LabelsName As String = "Labels"
|
Friend Const Name_LabelsName As String = "Labels"
|
||||||
|
|
||||||
Private Const Name_ReadyForDownload As String = "ReadyForDownload"
|
Private Const Name_ReadyForDownload As String = "ReadyForDownload"
|
||||||
Private Const Name_DownloadImages As String = "DownloadImages"
|
Private Const Name_DownloadImages As String = "DownloadImages"
|
||||||
@@ -124,17 +129,7 @@ Namespace API.Base
|
|||||||
Private Const Name_ScriptUse As String = "ScriptUse"
|
Private Const Name_ScriptUse As String = "ScriptUse"
|
||||||
Private Const Name_ScriptData As String = "ScriptData"
|
Private Const Name_ScriptData As String = "ScriptData"
|
||||||
|
|
||||||
Private Const Name_DataMerging As String = "DataMerging"
|
<Obsolete("Use 'Name_Merged'", False)> Friend Const Name_DataMerging As String = "DataMerging"
|
||||||
#Region "Downloaded data"
|
|
||||||
Private Const Name_MediaType As String = "Type"
|
|
||||||
Private Const Name_MediaState As String = "State"
|
|
||||||
Private Const Name_MediaAttempts As String = "Attempts"
|
|
||||||
Private Const Name_MediaURL As String = "URL"
|
|
||||||
Private Const Name_MediaHash As String = "Hash"
|
|
||||||
Private Const Name_MediaFile As String = "File"
|
|
||||||
Private Const Name_MediaPostID As String = "ID"
|
|
||||||
Private Const Name_MediaPostDate As String = "Date"
|
|
||||||
#End Region
|
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Declarations"
|
#Region "Declarations"
|
||||||
#Region "Host, Site, Progress, Self"
|
#Region "Host, Site, Progress, Self"
|
||||||
@@ -168,6 +163,21 @@ Namespace API.Base
|
|||||||
End Property
|
End Property
|
||||||
Friend Overridable Property ID As String = String.Empty Implements IContentProvider.ID, IPluginContentProvider.ID
|
Friend Overridable Property ID As String = String.Empty Implements IContentProvider.ID, IPluginContentProvider.ID
|
||||||
Friend Overridable Property FriendlyName As String = String.Empty Implements IContentProvider.FriendlyName
|
Friend Overridable Property FriendlyName As String = String.Empty Implements IContentProvider.FriendlyName
|
||||||
|
Friend ReadOnly Property UserModel As UsageModel Implements IUserData.UserModel
|
||||||
|
Get
|
||||||
|
Return User.UserModel
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
Friend Overridable ReadOnly Property CollectionModel As UsageModel Implements IUserData.CollectionModel
|
||||||
|
Get
|
||||||
|
Return User.CollectionModel
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
Friend Overridable ReadOnly Property IsVirtual As Boolean Implements IUserData.IsVirtual
|
||||||
|
Get
|
||||||
|
Return UserModel = UsageModel.Virtual
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Description"
|
#Region "Description"
|
||||||
Friend Property UserDescription As String = String.Empty Implements IContentProvider.Description, IPluginContentProvider.UserDescription
|
Friend Property UserDescription As String = String.Empty Implements IContentProvider.Description, IPluginContentProvider.UserDescription
|
||||||
@@ -243,7 +253,7 @@ Namespace API.Base
|
|||||||
Protected Function GetNullPicture(ByVal MaxHeigh As XML.Base.XMLValue(Of Integer)) As Bitmap
|
Protected Function GetNullPicture(ByVal MaxHeigh As XML.Base.XMLValue(Of Integer)) As Bitmap
|
||||||
Return New Bitmap(CInt(DivideWithZeroChecking(MaxHeigh.Value, 100) * 75), MaxHeigh.Value)
|
Return New Bitmap(CInt(DivideWithZeroChecking(MaxHeigh.Value, 100) * 75), MaxHeigh.Value)
|
||||||
End Function
|
End Function
|
||||||
Protected Function GetPicture(Of T)(Optional ByVal ReturnNullImageOnNothing As Boolean = True, Optional ByVal GetToast As Boolean = False) As T
|
Friend Function GetPicture(Of T)(Optional ByVal ReturnNullImageOnNothing As Boolean = True, Optional ByVal GetToast As Boolean = False) As T
|
||||||
Dim rsfile As Boolean = GetType(T) Is GetType(SFile)
|
Dim rsfile As Boolean = GetType(T) Is GetType(SFile)
|
||||||
Dim f As SFile = Nothing
|
Dim f As SFile = Nothing
|
||||||
Dim p As UserImage = Nothing
|
Dim p As UserImage = Nothing
|
||||||
@@ -320,7 +330,7 @@ BlockNullPicture:
|
|||||||
Friend Property SeparateVideoFolder As Boolean?
|
Friend Property SeparateVideoFolder As Boolean?
|
||||||
Protected ReadOnly Property SeparateVideoFolderF As Boolean
|
Protected ReadOnly Property SeparateVideoFolderF As Boolean
|
||||||
Get
|
Get
|
||||||
Return (SeparateVideoFolder.HasValue AndAlso SeparateVideoFolder.Value) OrElse Settings.SeparateVideoFolder.Value
|
Return If(SeparateVideoFolder, Settings.SeparateVideoFolder.Value)
|
||||||
End Get
|
End Get
|
||||||
End Property
|
End Property
|
||||||
#End Region
|
#End Region
|
||||||
@@ -347,7 +357,7 @@ BlockNullPicture:
|
|||||||
Friend Overridable Sub ChangeCollectionName(ByVal NewName As String, ByVal UpdateSettings As Boolean)
|
Friend Overridable Sub ChangeCollectionName(ByVal NewName As String, ByVal UpdateSettings As Boolean)
|
||||||
Dim u As UserInfo = User
|
Dim u As UserInfo = User
|
||||||
u.CollectionName = NewName
|
u.CollectionName = NewName
|
||||||
u.IncludedInCollection = Not NewName.IsEmptyString
|
u.UpdateUserFile()
|
||||||
User = u
|
User = u
|
||||||
If UpdateSettings Then Settings.UpdateUsersList(User)
|
If UpdateSettings Then Settings.UpdateUsersList(User)
|
||||||
End Sub
|
End Sub
|
||||||
@@ -466,7 +476,13 @@ BlockNullPicture:
|
|||||||
End Get
|
End Get
|
||||||
End Property
|
End Property
|
||||||
Friend Overridable Function GetUserInformation() As String
|
Friend Overridable Function GetUserInformation() As String
|
||||||
Dim OutStr$ = $"User: {Name}"
|
Dim OutStr$ = $"User: {Name} (site: {Site}"
|
||||||
|
If IncludedInCollection Then
|
||||||
|
OutStr &= $"; collection: {CollectionName}"
|
||||||
|
If CollectionModel = UsageModel.Default And UserModel = UsageModel.Virtual Then OutStr &= "; virtual"
|
||||||
|
End If
|
||||||
|
OutStr &= ")"
|
||||||
|
OutStr.StringAppendLine($"Labels: {Labels.ListToString}")
|
||||||
OutStr.StringAppendLine($"Path: {MyFile.CutPath.Path}")
|
OutStr.StringAppendLine($"Path: {MyFile.CutPath.Path}")
|
||||||
OutStr.StringAppendLine($"Total downloaded ({DownloadedTotal(True).NumToString(ANumbers.Formats.Number, 3)}):")
|
OutStr.StringAppendLine($"Total downloaded ({DownloadedTotal(True).NumToString(ANumbers.Formats.Number, 3)}):")
|
||||||
OutStr.StringAppendLine($"Pictures: {DownloadedPictures(True).NumToString(ANumbers.Formats.Number, 3)}")
|
OutStr.StringAppendLine($"Pictures: {DownloadedPictures(True).NumToString(ANumbers.Formats.Number, 3)}")
|
||||||
@@ -503,9 +519,9 @@ BlockNullPicture:
|
|||||||
Private Property IPluginContentProvider_Thrower As IThrower Implements IPluginContentProvider.Thrower
|
Private Property IPluginContentProvider_Thrower As IThrower Implements IPluginContentProvider.Thrower
|
||||||
Private Property IPluginContentProvider_LogProvider As ILogProvider Implements IPluginContentProvider.LogProvider
|
Private Property IPluginContentProvider_LogProvider As ILogProvider Implements IPluginContentProvider.LogProvider
|
||||||
Friend Property ExternalPlugin As IPluginContentProvider
|
Friend Property ExternalPlugin As IPluginContentProvider
|
||||||
Private Property IPluginContentProvider_ExistingContentList As List(Of PluginUserMedia) Implements IPluginContentProvider.ExistingContentList
|
Private Property IPluginContentProvider_ExistingContentList As List(Of IUserMedia) Implements IPluginContentProvider.ExistingContentList
|
||||||
Private Property IPluginContentProvider_TempPostsList As List(Of String) Implements IPluginContentProvider.TempPostsList
|
Private Property IPluginContentProvider_TempPostsList As List(Of String) Implements IPluginContentProvider.TempPostsList
|
||||||
Private Property IPluginContentProvider_TempMediaList As List(Of PluginUserMedia) Implements IPluginContentProvider.TempMediaList
|
Private Property IPluginContentProvider_TempMediaList As List(Of IUserMedia) Implements IPluginContentProvider.TempMediaList
|
||||||
Private Property IPluginContentProvider_SeparateVideoFolder As Boolean Implements IPluginContentProvider.SeparateVideoFolder
|
Private Property IPluginContentProvider_SeparateVideoFolder As Boolean Implements IPluginContentProvider.SeparateVideoFolder
|
||||||
Private Property IPluginContentProvider_DataPath As String Implements IPluginContentProvider.DataPath
|
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
|
Private Sub IPluginContentProvider_XmlFieldsSet(ByVal Fields As List(Of KeyValuePair(Of String, String))) Implements IPluginContentProvider.XmlFieldsSet
|
||||||
@@ -550,11 +566,18 @@ BlockNullPicture:
|
|||||||
End Function
|
End Function
|
||||||
Friend Overridable ReadOnly Property FitToAddParams As Boolean Implements IUserData.FitToAddParams
|
Friend Overridable ReadOnly Property FitToAddParams As Boolean Implements IUserData.FitToAddParams
|
||||||
Get
|
Get
|
||||||
If Settings.LastUpdatedDate.HasValue AndAlso LastUpdated.HasValue AndAlso
|
With Settings
|
||||||
LastUpdated.Value.Date > Settings.LastUpdatedDate.Value.Date Then Return False
|
If LastUpdated.HasValue And Not .ViewDateMode.Value = ShowingDates.Off Then
|
||||||
If Not Settings.Labels.ExcludedIgnore AndAlso Settings.Labels.Excluded.ValuesList.ListContains(Labels) Then Return False
|
Dim f As Date = If(.ViewDateFrom.HasValue, .ViewDateFrom.Value.Date, Date.MinValue.Date)
|
||||||
If Settings.SelectedSites.Count = 0 OrElse Settings.SelectedSites.Contains(Site) Then
|
Dim t As Date = If(.ViewDateTo.HasValue, .ViewDateTo.Value.Date, Date.MaxValue.Date)
|
||||||
Select Case Settings.ShowingMode.Value
|
Select Case DirectCast(.ViewDateMode.Value, ShowingDates)
|
||||||
|
Case ShowingDates.In : If Not LastUpdated.Value.ValueBetween(f, t) Then Return False
|
||||||
|
Case ShowingDates.Not : If LastUpdated.Value.ValueBetween(f, t) Then Return False
|
||||||
|
End Select
|
||||||
|
End If
|
||||||
|
If Not .Labels.ExcludedIgnore AndAlso .Labels.Excluded.ValuesList.ListContains(Labels) Then Return False
|
||||||
|
If .SelectedSites.Count = 0 OrElse .SelectedSites.Contains(Site) Then
|
||||||
|
Select Case .ShowingMode.Value
|
||||||
Case ShowingModes.Regular : Return Not Temporary And Not Favorite
|
Case ShowingModes.Regular : Return Not Temporary And Not Favorite
|
||||||
Case ShowingModes.Temporary : Return Temporary
|
Case ShowingModes.Temporary : Return Temporary
|
||||||
Case ShowingModes.Favorite : Return Favorite
|
Case ShowingModes.Favorite : Return Favorite
|
||||||
@@ -567,6 +590,7 @@ BlockNullPicture:
|
|||||||
Else
|
Else
|
||||||
Return False
|
Return False
|
||||||
End If
|
End If
|
||||||
|
End With
|
||||||
End Get
|
End Get
|
||||||
End Property
|
End Property
|
||||||
Friend Function GetLVIGroup(ByVal Destination As ListView) As ListViewGroup Implements IUserData.GetLVIGroup
|
Friend Function GetLVIGroup(ByVal Destination As ListView) As ListViewGroup Implements IUserData.GetLVIGroup
|
||||||
@@ -621,7 +645,7 @@ BlockNullPicture:
|
|||||||
With DirectCast(u, UserDataBase)
|
With DirectCast(u, UserDataBase)
|
||||||
If Not .User.Plugin.IsEmptyString Then
|
If Not .User.Plugin.IsEmptyString Then
|
||||||
uName = .User.Name
|
uName = .User.Name
|
||||||
Return Settings(.User.Plugin).GetUserPostUrl(.ID, PostData.Post.ID)
|
Return Settings(.User.Plugin).GetUserPostUrl(.Self, PostData)
|
||||||
End If
|
End If
|
||||||
End With
|
End With
|
||||||
End If
|
End If
|
||||||
@@ -658,7 +682,13 @@ BlockNullPicture:
|
|||||||
LastUpdated = AConvert(Of Date)(x.Value(Name_LastUpdated), ADateTime.Formats.BaseDateTime, Nothing)
|
LastUpdated = AConvert(Of Date)(x.Value(Name_LastUpdated), ADateTime.Formats.BaseDateTime, Nothing)
|
||||||
ScriptUse = x.Value(Name_ScriptUse).FromXML(Of Boolean)(False)
|
ScriptUse = x.Value(Name_ScriptUse).FromXML(Of Boolean)(False)
|
||||||
ScriptData = x.Value(Name_ScriptData)
|
ScriptData = x.Value(Name_ScriptData)
|
||||||
|
#Disable Warning BC40000
|
||||||
|
If x.Contains(Name_DataMerging) Then
|
||||||
DataMerging = x.Value(Name_DataMerging).FromXML(Of Boolean)(False)
|
DataMerging = x.Value(Name_DataMerging).FromXML(Of Boolean)(False)
|
||||||
|
Else
|
||||||
|
DataMerging = x.Value(Name_Merged).FromXML(Of Boolean)(False)
|
||||||
|
End If
|
||||||
|
#Enable Warning
|
||||||
ChangeCollectionName(x.Value(Name_CollectionName), 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)
|
Labels.ListAddList(x.Value(Name_LabelsName).StringToList(Of String, List(Of String))("|", EDP.ReturnValue), LAP.NotContainsOnly, LAP.ClearBeforeAdd)
|
||||||
LoadUserInformation_OptionalFields(x, True)
|
LoadUserInformation_OptionalFields(x, True)
|
||||||
@@ -676,7 +706,13 @@ BlockNullPicture:
|
|||||||
MyFile.Exists(SFO.Path)
|
MyFile.Exists(SFO.Path)
|
||||||
Using x As New XmlFile With {.Name = "User"}
|
Using x As New XmlFile With {.Name = "User"}
|
||||||
x.Add(Name_Site, Site)
|
x.Add(Name_Site, Site)
|
||||||
|
x.Add(Name_Plugin, HOST.Key)
|
||||||
x.Add(Name_UserName, User.Name)
|
x.Add(Name_UserName, User.Name)
|
||||||
|
x.Add(Name_IsChannel, IsChannel.BoolToInteger)
|
||||||
|
x.Add(Name_Model_User, CInt(UserModel))
|
||||||
|
x.Add(Name_Model_Collection, CInt(CollectionModel))
|
||||||
|
x.Add(Name_SpecialPath, User.SpecialPath)
|
||||||
|
x.Add(Name_SpecialCollectionPath, User.SpecialCollectionPath)
|
||||||
x.Add(Name_UserExists, UserExists.BoolToInteger)
|
x.Add(Name_UserExists, UserExists.BoolToInteger)
|
||||||
x.Add(Name_UserSuspended, UserSuspended.BoolToInteger)
|
x.Add(Name_UserSuspended, UserSuspended.BoolToInteger)
|
||||||
x.Add(Name_UserID, ID)
|
x.Add(Name_UserID, ID)
|
||||||
@@ -701,7 +737,7 @@ BlockNullPicture:
|
|||||||
x.Add(Name_ScriptData, ScriptData)
|
x.Add(Name_ScriptData, ScriptData)
|
||||||
x.Add(Name_CollectionName, CollectionName)
|
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)
|
x.Add(Name_Merged, DataMerging.BoolToInteger)
|
||||||
|
|
||||||
LoadUserInformation_OptionalFields(x, False)
|
LoadUserInformation_OptionalFields(x, False)
|
||||||
|
|
||||||
@@ -723,25 +759,7 @@ BlockNullPicture:
|
|||||||
Using x As New XmlFile(MyFileData, Protector.Modes.All, False) With {.XmlReadOnly = True, .AllowSameNames = True}
|
Using x As New XmlFile(MyFileData, Protector.Modes.All, False) With {.XmlReadOnly = True, .AllowSameNames = True}
|
||||||
x.LoadData()
|
x.LoadData()
|
||||||
If x.Count > 0 Then
|
If x.Count > 0 Then
|
||||||
|
For Each v As EContainer In x : _ContentList.Add(New UserMedia(v, Me)) : Next
|
||||||
Dim fs$ = MyFile.CutPath.PathWithSeparator
|
|
||||||
Dim gfn As Func(Of String, String) = Function(Input) If(Input.IsEmptyString, String.Empty,
|
|
||||||
If(Input.Contains("\"), Input.CSFile.File, Input))
|
|
||||||
For Each v As EContainer In x
|
|
||||||
_ContentList.Add(New UserMedia With {
|
|
||||||
.Type = v.Attribute(Name_MediaType).Value.FromXML(Of Integer)(CInt(UTypes.Undefined)),
|
|
||||||
.State = v.Attribute(Name_MediaState).Value.FromXML(Of Integer)(CInt(UStates.Downloaded)),
|
|
||||||
.Attempts = v.Attribute(Name_MediaAttempts).Value.FromXML(Of Integer)(0),
|
|
||||||
.URL = v.Attribute(Name_MediaURL).Value,
|
|
||||||
.URL_BASE = v.Value,
|
|
||||||
.MD5 = v.Attribute(Name_MediaHash).Value,
|
|
||||||
.File = fs & gfn.Invoke(v.Attribute(Name_MediaFile).Value),
|
|
||||||
.Post = New UserPost With {
|
|
||||||
.ID = v.Attribute(Name_MediaPostID).Value,
|
|
||||||
.[Date] = AConvert(Of Date)(v.Attribute(Name_MediaPostDate).Value, ParsersDataDateProvider, Nothing)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
Next
|
|
||||||
End If
|
End If
|
||||||
_DataLoaded = True
|
_DataLoaded = True
|
||||||
End Using
|
End Using
|
||||||
@@ -755,21 +773,7 @@ BlockNullPicture:
|
|||||||
If MyFileData.IsEmptyString Then Exit Sub
|
If MyFileData.IsEmptyString Then Exit Sub
|
||||||
MyFileData.Exists(SFO.Path)
|
MyFileData.Exists(SFO.Path)
|
||||||
Using x As New XmlFile With {.AllowSameNames = True, .Name = "Data"}
|
Using x As New XmlFile With {.AllowSameNames = True, .Name = "Data"}
|
||||||
If _ContentList.Count > 0 Then
|
If _ContentList.Count > 0 Then x.AddRange(_ContentList)
|
||||||
For Each i As UserMedia In _ContentList
|
|
||||||
x.Add(New EContainer("MediaData", i.URL_BASE, {New EAttribute(Name_MediaType, CInt(i.Type)),
|
|
||||||
New EAttribute(Name_MediaState, CInt(i.State)),
|
|
||||||
New EAttribute(Name_MediaAttempts, i.Attempts),
|
|
||||||
New EAttribute(Name_MediaURL, i.URL),
|
|
||||||
New EAttribute(Name_MediaHash, i.MD5),
|
|
||||||
New EAttribute(Name_MediaFile, i.File.File),
|
|
||||||
New EAttribute(Name_MediaPostID, i.Post.ID),
|
|
||||||
New EAttribute(Name_MediaPostDate, AConvert(Of String)(i.Post.Date, ParsersDataDateProvider, String.Empty))
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
Next
|
|
||||||
End If
|
|
||||||
x.Save(MyFileData)
|
x.Save(MyFileData)
|
||||||
End Using
|
End Using
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
@@ -781,7 +785,7 @@ BlockNullPicture:
|
|||||||
#Region "Open site, folder"
|
#Region "Open site, folder"
|
||||||
Friend Overridable Sub OpenSite(Optional ByVal e As ErrorsDescriber = Nothing) Implements IContentProvider.OpenSite
|
Friend Overridable Sub OpenSite(Optional ByVal e As ErrorsDescriber = Nothing) Implements IContentProvider.OpenSite
|
||||||
Try
|
Try
|
||||||
Dim URL$ = HOST.Source.GetUserUrl(Name, IsChannel)
|
Dim URL$ = HOST.Source.GetUserUrl(Me, IsChannel)
|
||||||
If Not URL.IsEmptyString Then Process.Start(URL)
|
If Not URL.IsEmptyString Then Process.Start(URL)
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
If Not e.Exists Then e = New ErrorsDescriber(EDP.ShowAllMsg)
|
If Not e.Exists Then e = New ErrorsDescriber(EDP.ShowAllMsg)
|
||||||
@@ -792,10 +796,55 @@ BlockNullPicture:
|
|||||||
GlobalOpenPath(MyFile.CutPath)
|
GlobalOpenPath(MyFile.CutPath)
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Download functions and options"
|
#Region "Download limits"
|
||||||
|
Protected Enum DateResult : [Continue] : [Skip] : [Exit] : End Enum
|
||||||
Friend Overridable Property DownloadTopCount As Integer? = Nothing Implements IUserData.DownloadTopCount, IPluginContentProvider.PostsNumberLimit
|
Friend Overridable Property DownloadTopCount As Integer? = Nothing Implements IUserData.DownloadTopCount, IPluginContentProvider.PostsNumberLimit
|
||||||
Friend Overridable Property DownloadToDate As Date? = Nothing Implements IUserData.DownloadToDate, IPluginContentProvider.PostsDateLimit
|
Friend Overridable Property IncludeInTheFeed As Boolean = True
|
||||||
|
Private _DownloadDateFrom As Date? = Nothing
|
||||||
|
Private _DownloadDateFromF As Date
|
||||||
|
Friend Overridable Property DownloadDateFrom As Date? Implements IUserData.DownloadDateFrom, IPluginContentProvider.DownloadDateFrom
|
||||||
|
Get
|
||||||
|
Return _DownloadDateFrom
|
||||||
|
End Get
|
||||||
|
Set(ByVal d As Date?)
|
||||||
|
_DownloadDateFrom = d
|
||||||
|
If _DownloadDateFrom.HasValue Then _DownloadDateFromF = _DownloadDateFrom.Value.Date Else _DownloadDateFromF = Date.MinValue.Date
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
Private _DownloadDateTo As Date? = Nothing
|
||||||
|
Private _DownloadDateToF As Date
|
||||||
|
Friend Overridable Property DownloadDateTo As Date? Implements IUserData.DownloadDateTo, IPluginContentProvider.DownloadDateTo
|
||||||
|
Get
|
||||||
|
Return _DownloadDateTo
|
||||||
|
End Get
|
||||||
|
Set(ByVal d As Date?)
|
||||||
|
_DownloadDateTo = d
|
||||||
|
If _DownloadDateTo.HasValue Then _DownloadDateToF = _DownloadDateTo.Value Else _DownloadDateToF = Date.MaxValue.Date
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
Protected Function CheckDatesLimit(ByVal DateObj As Object, ByVal DateProvider As IFormatProvider) As DateResult
|
||||||
|
Try
|
||||||
|
If (DownloadDateFrom.HasValue Or DownloadDateTo.HasValue) AndAlso ACheck(DateObj) Then
|
||||||
|
Dim td As Date? = AConvert(Of Date)(DateObj, DateProvider, Nothing)
|
||||||
|
If td.HasValue Then
|
||||||
|
If td.Value.ValueBetween(_DownloadDateFromF, _DownloadDateToF) Then
|
||||||
|
Return DateResult.Continue
|
||||||
|
ElseIf td.Value > _DownloadDateToF Then
|
||||||
|
Return DateResult.Skip
|
||||||
|
Else
|
||||||
|
Return DateResult.Exit
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Return DateResult.Continue
|
||||||
|
Catch ex As Exception
|
||||||
|
Return ErrorsDescriber.Execute(EDP.SendInLog, ex, $"[UserDataBase.CheckDatesLimit({If(TypeOf DateObj Is String, CStr(DateObj), "?")})]", DateResult.Continue)
|
||||||
|
End Try
|
||||||
|
End Function
|
||||||
|
#End Region
|
||||||
|
#Region "Download functions and options"
|
||||||
Protected Responser As Response
|
Protected Responser As Response
|
||||||
|
Protected UseResponserClient As Boolean = False
|
||||||
Friend Overridable Sub DownloadData(ByVal Token As CancellationToken) Implements IContentProvider.DownloadData
|
Friend Overridable Sub DownloadData(ByVal Token As CancellationToken) Implements IContentProvider.DownloadData
|
||||||
Dim Canceled As Boolean = False
|
Dim Canceled As Boolean = False
|
||||||
_ExternalCompatibilityToken = Token
|
_ExternalCompatibilityToken = Token
|
||||||
@@ -805,6 +854,9 @@ BlockNullPicture:
|
|||||||
If Not Responser Is Nothing Then Responser.Dispose()
|
If Not Responser Is Nothing Then Responser.Dispose()
|
||||||
Responser = New Response
|
Responser = New Response
|
||||||
If Not HOST.Responser Is Nothing Then Responser.Copy(HOST.Responser)
|
If Not HOST.Responser Is Nothing Then Responser.Copy(HOST.Responser)
|
||||||
|
'TODO: UserDataBase remove [Responser.DecodersError]
|
||||||
|
Responser.DecodersError = New ErrorsDescriber(EDP.SendInLog + EDP.ReturnValue) With {
|
||||||
|
.DeclaredMessage = New MMessage($"SymbolsConverter error: [{ToStringForLog()}]", ToStringForLog())}
|
||||||
|
|
||||||
Dim UpPic As Boolean = Settings.ViewModeIsPicture AndAlso GetPicture(Of Image)(False) Is Nothing
|
Dim UpPic As Boolean = Settings.ViewModeIsPicture AndAlso GetPicture(Of Image)(False) Is Nothing
|
||||||
Dim sEnvir() As Boolean = {UserExists, UserSuspended}
|
Dim sEnvir() As Boolean = {UserExists, UserSuspended}
|
||||||
@@ -816,6 +868,7 @@ BlockNullPicture:
|
|||||||
DownloadedVideos(False) = 0
|
DownloadedVideos(False) = 0
|
||||||
_TempMediaList.Clear()
|
_TempMediaList.Clear()
|
||||||
_TempPostsList.Clear()
|
_TempPostsList.Clear()
|
||||||
|
LatestData.Clear()
|
||||||
Dim __SaveData As Boolean = Not CreatedByChannel Or Not Settings.FromChannelDownloadTopUse
|
Dim __SaveData As Boolean = Not CreatedByChannel Or Not Settings.FromChannelDownloadTopUse
|
||||||
|
|
||||||
LoadContentInformation()
|
LoadContentInformation()
|
||||||
@@ -827,10 +880,10 @@ BlockNullPicture:
|
|||||||
ThrowAny(Token)
|
ThrowAny(Token)
|
||||||
DownloadDataF(Token)
|
DownloadDataF(Token)
|
||||||
ThrowAny(Token)
|
ThrowAny(Token)
|
||||||
|
If Settings.ReparseMissingInTheRoutine Then ReparseMissing(Token) : ThrowAny(Token)
|
||||||
Else
|
Else
|
||||||
'ReparseMissing(Token)
|
ReparseMissing(Token)
|
||||||
End If
|
End If
|
||||||
'_TempMediaList.ListAddList(ContentMissing, LNC)
|
|
||||||
|
|
||||||
If _TempMediaList.Count > 0 Then
|
If _TempMediaList.Count > 0 Then
|
||||||
If Not DownloadImages Then _TempMediaList.RemoveAll(Function(m) m.Type = UTypes.GIF Or m.Type = UTypes.Picture)
|
If Not DownloadImages Then _TempMediaList.RemoveAll(Function(m) m.Type = UTypes.GIF Or m.Type = UTypes.Picture)
|
||||||
@@ -841,12 +894,13 @@ BlockNullPicture:
|
|||||||
|
|
||||||
ReparseVideo(Token)
|
ReparseVideo(Token)
|
||||||
ThrowAny(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 Not DownloadMissingOnly And __SaveData Then _
|
||||||
|
TextSaver.SaveTextToFile(_TempPostsList.ListToString(Environment.NewLine), MyFilePosts, True,, EDP.None)
|
||||||
_ContentNew.ListAddList(_TempMediaList, LAP.ClearBeforeAdd)
|
_ContentNew.ListAddList(_TempMediaList, LAP.ClearBeforeAdd)
|
||||||
DownloadContent(Token)
|
DownloadContent(Token)
|
||||||
ThrowIfDisposed()
|
ThrowIfDisposed()
|
||||||
|
|
||||||
LatestData.ListAddList(_ContentNew.Where(_downContent), LNC)
|
If IncludeInTheFeed Then LatestData.ListAddList(_ContentNew.Where(_downContent), LNC)
|
||||||
Dim mcb& = If(ContentMissingExists, _ContentList.LongCount(Function(c) MissingFinder(c)), 0)
|
Dim mcb& = If(ContentMissingExists, _ContentList.LongCount(Function(c) MissingFinder(c)), 0)
|
||||||
_ContentList.ListAddList(_ContentNew.Where(Function(c) _downContent(c) Or MissingFinder(c)), LNC)
|
_ContentList.ListAddList(_ContentNew.Where(Function(c) _downContent(c) Or MissingFinder(c)), LNC)
|
||||||
Dim mca& = If(ContentMissingExists, _ContentList.LongCount(Function(c) MissingFinder(c)), 0)
|
Dim mca& = If(ContentMissingExists, _ContentList.LongCount(Function(c) MissingFinder(c)), 0)
|
||||||
@@ -871,7 +925,7 @@ BlockNullPicture:
|
|||||||
ThrowIfDisposed()
|
ThrowIfDisposed()
|
||||||
If UpPic Or EnvirChanged.Invoke Then OnUserUpdated()
|
If UpPic Or EnvirChanged.Invoke Then OnUserUpdated()
|
||||||
Catch oex As OperationCanceledException When Token.IsCancellationRequested
|
Catch oex As OperationCanceledException When Token.IsCancellationRequested
|
||||||
MyMainLOG = $"{Site} - {Name}: downloading canceled"
|
MyMainLOG = $"{ToStringForLog()}: downloading canceled"
|
||||||
Canceled = True
|
Canceled = True
|
||||||
Catch dex As ObjectDisposedException When Disposed
|
Catch dex As ObjectDisposedException When Disposed
|
||||||
Canceled = True
|
Canceled = True
|
||||||
@@ -883,21 +937,11 @@ BlockNullPicture:
|
|||||||
If Not Canceled Then _DataParsed = True
|
If Not Canceled Then _DataParsed = True
|
||||||
_ContentNew.Clear()
|
_ContentNew.Clear()
|
||||||
DownloadTopCount = Nothing
|
DownloadTopCount = Nothing
|
||||||
DownloadToDate = Nothing
|
DownloadDateFrom = Nothing
|
||||||
|
DownloadDateTo = Nothing
|
||||||
DownloadMissingOnly = False
|
DownloadMissingOnly = False
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
Protected Function CheckDatesLimit(ByVal DateString As String, ByVal DateProvider As IFormatProvider) As Boolean
|
|
||||||
Try
|
|
||||||
If DownloadToDate.HasValue And Not DateString.IsEmptyString Then
|
|
||||||
Dim td As Date? = AConvert(Of Date)(DateString, DateProvider, Nothing)
|
|
||||||
If td.HasValue Then Return td.Value < DownloadToDate.Value
|
|
||||||
End If
|
|
||||||
Return True
|
|
||||||
Catch ex As Exception
|
|
||||||
Return ErrorsDescriber.Execute(EDP.SendInLog, ex, $"[UserDataBase.CheckDatesLimit({DateString})]", True)
|
|
||||||
End Try
|
|
||||||
End Function
|
|
||||||
Protected Sub UpdateDataFiles()
|
Protected Sub UpdateDataFiles()
|
||||||
If Not User.File.IsEmptyString Then
|
If Not User.File.IsEmptyString Then
|
||||||
MyFileData = User.File
|
MyFileData = User.File
|
||||||
@@ -912,9 +956,24 @@ BlockNullPicture:
|
|||||||
Protected MustOverride Sub DownloadDataF(ByVal Token As CancellationToken)
|
Protected MustOverride Sub DownloadDataF(ByVal Token As CancellationToken)
|
||||||
Protected Overridable Sub ReparseVideo(ByVal Token As CancellationToken)
|
Protected Overridable Sub ReparseVideo(ByVal Token As CancellationToken)
|
||||||
End Sub
|
End Sub
|
||||||
|
''' <summary>
|
||||||
|
''' Missing posts must be collected from [<see cref="_ContentList"/>].<br/>
|
||||||
|
''' Reparsed post must be added to [<see cref="_TempMediaList"/>].<br/>
|
||||||
|
''' At the end of the function, reparsed posts must be removed from [<see cref="_ContentList"/>].
|
||||||
|
''' </summary>
|
||||||
Protected Overridable Sub ReparseMissing(ByVal Token As CancellationToken)
|
Protected Overridable Sub ReparseMissing(ByVal Token As CancellationToken)
|
||||||
End Sub
|
End Sub
|
||||||
Protected MustOverride Sub DownloadContent(ByVal Token As CancellationToken)
|
Protected MustOverride Sub DownloadContent(ByVal Token As CancellationToken)
|
||||||
|
Private NotInheritable Class OptionalWebClient : Inherits DownloadObjects.WebClient2
|
||||||
|
Friend Sub New(ByRef Source As UserDataBase)
|
||||||
|
UseResponserClient = Source.UseResponserClient
|
||||||
|
If UseResponserClient Then
|
||||||
|
RC = Source.Responser
|
||||||
|
Else
|
||||||
|
WC = New WebClient
|
||||||
|
End If
|
||||||
|
End Sub
|
||||||
|
End Class
|
||||||
Protected Sub DownloadContentDefault(ByVal Token As CancellationToken)
|
Protected Sub DownloadContentDefault(ByVal Token As CancellationToken)
|
||||||
Try
|
Try
|
||||||
Dim i%
|
Dim i%
|
||||||
@@ -930,8 +989,9 @@ BlockNullPicture:
|
|||||||
Dim __isVideo As Boolean
|
Dim __isVideo As Boolean
|
||||||
Dim f As SFile
|
Dim f As SFile
|
||||||
Dim v As UserMedia
|
Dim v As UserMedia
|
||||||
Using w As New WebClient
|
|
||||||
If vsf Then SFileShares.SFileExists($"{MyDir}\Video\", SFO.Path)
|
Using w As New OptionalWebClient(Me)
|
||||||
|
If vsf Then CSFileP($"{MyDir}\Video\").Exists(SFO.Path)
|
||||||
Progress.Maximum += _ContentNew.Count
|
Progress.Maximum += _ContentNew.Count
|
||||||
For i = 0 To _ContentNew.Count - 1
|
For i = 0 To _ContentNew.Count - 1
|
||||||
ThrowAny(Token)
|
ThrowAny(Token)
|
||||||
@@ -947,7 +1007,7 @@ BlockNullPicture:
|
|||||||
|
|
||||||
If v.URL_BASE.IsEmptyString Then v.URL_BASE = v.URL
|
If v.URL_BASE.IsEmptyString Then v.URL_BASE = v.URL
|
||||||
|
|
||||||
If Not v.File.IsEmptyString And Not v.URL_BASE.IsEmptyString Then
|
If Not v.File.IsEmptyString And Not v.URL.IsEmptyString Then
|
||||||
Try
|
Try
|
||||||
__isVideo = v.Type = UTypes.Video Or f.Extension = "mp4"
|
__isVideo = v.Type = UTypes.Video Or f.Extension = "mp4"
|
||||||
|
|
||||||
@@ -969,7 +1029,13 @@ BlockNullPicture:
|
|||||||
f.Path = $"{f.PathWithSeparator}Video"
|
f.Path = $"{f.PathWithSeparator}Video"
|
||||||
If Not v.SpecialFolder.IsEmptyString Then f.Exists(SFO.Path)
|
If Not v.SpecialFolder.IsEmptyString Then f.Exists(SFO.Path)
|
||||||
End If
|
End If
|
||||||
w.DownloadFile(v.URL_BASE, f.ToString)
|
|
||||||
|
If v.Type = UTypes.m3u8 And UseInternalM3U8Function Then
|
||||||
|
f = DownloadM3U8(v.URL, v, f)
|
||||||
|
If f.IsEmptyString Then Throw New Exception("M3U8 download failed")
|
||||||
|
Else
|
||||||
|
w.DownloadFile(v.URL, f.ToString)
|
||||||
|
End If
|
||||||
|
|
||||||
If __isVideo Then
|
If __isVideo Then
|
||||||
v.Type = UTypes.Video
|
v.Type = UTypes.Video
|
||||||
@@ -985,7 +1051,7 @@ BlockNullPicture:
|
|||||||
Catch wex As Exception
|
Catch wex As Exception
|
||||||
v.Attempts += 1
|
v.Attempts += 1
|
||||||
v.State = UStates.Missing
|
v.State = UStates.Missing
|
||||||
If MissingErrorsAdd Then ErrorDownloading(f, v.URL_BASE)
|
If MissingErrorsAdd Then ErrorDownloading(f, v.URL)
|
||||||
End Try
|
End Try
|
||||||
Else
|
Else
|
||||||
v.State = UStates.Skipped
|
v.State = UStates.Skipped
|
||||||
@@ -1010,15 +1076,31 @@ BlockNullPicture:
|
|||||||
HasError = True
|
HasError = True
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
|
Protected UseInternalM3U8Function As Boolean = False
|
||||||
|
Protected Overridable Function DownloadM3U8(ByVal URL As String, ByVal Media As UserMedia, ByVal DestinationFile As SFile) As SFile
|
||||||
|
Return Nothing
|
||||||
|
End Function
|
||||||
|
Protected Const EXCEPTION_OPERATION_CANCELED As Integer = -1
|
||||||
''' <param name="RDE">Request DownloadingException</param>
|
''' <param name="RDE">Request DownloadingException</param>
|
||||||
Protected Sub ProcessException(ByVal ex As Exception, ByVal Token As CancellationToken, ByVal Message As String, Optional ByVal RDE As Boolean = True)
|
''' <returns>0 - exit</returns>
|
||||||
|
Protected Function ProcessException(ByVal ex As Exception, ByVal Token As CancellationToken, ByVal Message As String,
|
||||||
|
Optional ByVal RDE As Boolean = True, Optional ByVal EObj As Object = Nothing,
|
||||||
|
Optional ByVal ThrowEx As Boolean = True) As Integer
|
||||||
If Not ((TypeOf ex Is OperationCanceledException And Token.IsCancellationRequested) Or
|
If Not ((TypeOf ex Is OperationCanceledException And Token.IsCancellationRequested) Or
|
||||||
(TypeOf ex Is ObjectDisposedException And Disposed)) Then
|
(TypeOf ex Is ObjectDisposedException And Disposed)) Then
|
||||||
If RDE AndAlso DownloadingException(ex, Message, True) = 0 Then LogError(ex, Message) : HasError = True
|
If RDE Then
|
||||||
|
Dim v% = DownloadingException(ex, Message, True, EObj)
|
||||||
|
If v = 0 Then LogError(ex, Message) : HasError = True
|
||||||
|
Return v
|
||||||
End If
|
End If
|
||||||
End Sub
|
Else
|
||||||
|
'URGENT: UserDataBase.ProcessException [Throw ex]
|
||||||
|
If ThrowEx Then Throw ex Else Return EXCEPTION_OPERATION_CANCELED
|
||||||
|
End If
|
||||||
|
Return 0
|
||||||
|
End Function
|
||||||
''' <summary>0 - Execute LogError and set HasError</summary>
|
''' <summary>0 - Execute LogError and set HasError</summary>
|
||||||
Protected MustOverride Function DownloadingException(ByVal ex As Exception, ByVal Message As String, Optional ByVal FromPE As Boolean = False) As Integer
|
Protected MustOverride Function DownloadingException(ByVal ex As Exception, ByVal Message As String, Optional ByVal FromPE As Boolean = False, Optional ByVal EObj As Object = Nothing) As Integer
|
||||||
Protected Function ChangeFileNameByProvider(ByVal f As SFile, ByVal m As UserMedia) As SFile
|
Protected Function ChangeFileNameByProvider(ByVal f As SFile, ByVal m As UserMedia) As SFile
|
||||||
Dim ff As SFile = Nothing
|
Dim ff As SFile = Nothing
|
||||||
Try
|
Try
|
||||||
@@ -1059,14 +1141,14 @@ BlockNullPicture:
|
|||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Delete, Move, Merge"
|
#Region "Delete, Move, Merge, Copy"
|
||||||
Friend Overridable Function Delete() As Integer Implements IUserData.Delete
|
Friend Overridable Function Delete(Optional ByVal Multiple As Boolean = False, Optional ByVal CollectionValue As Integer = -1) As Integer Implements IUserData.Delete
|
||||||
Dim f As SFile = SFile.GetPath(MyFile.CutPath.Path)
|
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
|
If f.Exists(SFO.Path, False) AndAlso (User.Merged OrElse f.Delete(SFO.Path, Settings.DeleteMode)) Then
|
||||||
MainFrameObj.ImageHandler(Me, False)
|
If Not IncludedInCollection Then MainFrameObj.ImageHandler(Me, False)
|
||||||
Settings.UsersList.Remove(User)
|
Settings.UsersList.Remove(User)
|
||||||
Settings.UpdateUsersList()
|
Settings.UpdateUsersList()
|
||||||
Settings.Users.Remove(Me)
|
If Not IncludedInCollection Then Settings.Users.Remove(Me)
|
||||||
Downloader.UserRemove(Me)
|
Downloader.UserRemove(Me)
|
||||||
Dispose(True)
|
Dispose(True)
|
||||||
Return 1
|
Return 1
|
||||||
@@ -1074,26 +1156,31 @@ BlockNullPicture:
|
|||||||
Return 0
|
Return 0
|
||||||
End If
|
End If
|
||||||
End Function
|
End Function
|
||||||
Friend Overridable Function MoveFiles(ByVal __CollectionName As String) As Boolean Implements IUserData.MoveFiles
|
Friend Overridable Function MoveFiles(ByVal __CollectionName As String, ByVal __SpecialCollectionPath As SFile) As Boolean Implements IUserData.MoveFiles
|
||||||
Dim UserBefore As UserInfo = User
|
Dim UserBefore As UserInfo = User
|
||||||
Dim Removed As Boolean = True
|
Dim Removed As Boolean = True
|
||||||
Dim _TurnBack As Boolean = False
|
Dim _TurnBack As Boolean = False
|
||||||
Try
|
Try
|
||||||
Dim f As SFile
|
Dim f As SFile
|
||||||
|
Dim v As Boolean = IsVirtual
|
||||||
If IncludedInCollection Then
|
If IncludedInCollection Then
|
||||||
Settings.Users.Add(Me)
|
Settings.Users.Add(Me)
|
||||||
Removed = False
|
Removed = False
|
||||||
User.CollectionName = String.Empty
|
User.CollectionName = String.Empty
|
||||||
User.IncludedInCollection = False
|
User.SpecialCollectionPath = String.Empty
|
||||||
|
User.UserModel = UsageModel.Default
|
||||||
|
User.CollectionModel = UsageModel.Default
|
||||||
Else
|
Else
|
||||||
Settings.Users.Remove(Me)
|
Settings.Users.Remove(Me)
|
||||||
Removed = True
|
Removed = True
|
||||||
User.CollectionName = __CollectionName
|
User.CollectionName = __CollectionName
|
||||||
User.IncludedInCollection = True
|
User.SpecialCollectionPath = __SpecialCollectionPath
|
||||||
User.SpecialPath = Nothing
|
If Not IsVirtual Then User.SpecialPath = Nothing
|
||||||
End If
|
End If
|
||||||
_TurnBack = True
|
_TurnBack = True
|
||||||
User.UpdateUserFile()
|
User.UpdateUserFile()
|
||||||
|
|
||||||
|
If Not v Then
|
||||||
f = User.File.CutPath(, EDP.ThrowException)
|
f = User.File.CutPath(, EDP.ThrowException)
|
||||||
If f.Exists(SFO.Path, False) Then
|
If f.Exists(SFO.Path, False) Then
|
||||||
If If(SFile.GetFiles(f,, SearchOption.AllDirectories), New List(Of SFile)).Count > 0 AndAlso
|
If If(SFile.GetFiles(f,, SearchOption.AllDirectories), New List(Of SFile)).Count > 0 AndAlso
|
||||||
@@ -1112,6 +1199,8 @@ BlockNullPicture:
|
|||||||
Directory.Move(UserBefore.File.CutPath(, EDP.ThrowException).Path, f.Path)
|
Directory.Move(UserBefore.File.CutPath(, EDP.ThrowException).Path, f.Path)
|
||||||
If Not ScriptData.IsEmptyString AndAlso ScriptData.Contains(UserBefore.File.PathNoSeparator) Then _
|
If Not ScriptData.IsEmptyString AndAlso ScriptData.Contains(UserBefore.File.PathNoSeparator) Then _
|
||||||
ScriptData = ScriptData.Replace(UserBefore.File.PathNoSeparator, MyFile.PathNoSeparator)
|
ScriptData = ScriptData.Replace(UserBefore.File.PathNoSeparator, MyFile.PathNoSeparator)
|
||||||
|
End If
|
||||||
|
|
||||||
Settings.UsersList.Remove(UserBefore)
|
Settings.UsersList.Remove(UserBefore)
|
||||||
Settings.UpdateUsersList(User)
|
Settings.UpdateUsersList(User)
|
||||||
UpdateUserInformation()
|
UpdateUserInformation()
|
||||||
@@ -1183,10 +1272,52 @@ BlockNullPicture:
|
|||||||
End If
|
End If
|
||||||
Return f
|
Return f
|
||||||
End Function
|
End Function
|
||||||
|
Private Class FilesCopyingException : Inherits ErrorsDescriberException
|
||||||
|
Friend Sub New(ByVal User As IUserData, ByVal Msg As String, ByVal Path As SFile)
|
||||||
|
SendInLogOnlyMessage = True
|
||||||
|
If User.IncludedInCollection Then _MainMessage = $"[{User.CollectionName}] - "
|
||||||
|
_MainMessage &= $"[{User.Site}] - [{User.Name}]. {Msg}: {Path.Path}."
|
||||||
|
End Sub
|
||||||
|
End Class
|
||||||
|
Friend Overridable Function CopyFiles(ByVal DestinationPath As SFile, Optional ByVal e As ErrorsDescriber = Nothing) As Boolean Implements IUserData.CopyFiles
|
||||||
|
Dim fSource As SFile = Nothing
|
||||||
|
Dim fDest As SFile = Nothing
|
||||||
|
Try
|
||||||
|
Dim pOffset%
|
||||||
|
If IncludedInCollection Then
|
||||||
|
If DataMerging Then pOffset = 1 Else pOffset = 2
|
||||||
|
Else
|
||||||
|
pOffset = 1
|
||||||
|
End If
|
||||||
|
fSource = User.File.CutPath(pOffset).Path.CSFileP
|
||||||
|
|
||||||
|
Dim OptPath$ = String.Empty
|
||||||
|
If IncludedInCollection Then
|
||||||
|
OptPath = $"Collections\{CollectionName}" 'Copying a collection based on the first file
|
||||||
|
Else
|
||||||
|
OptPath = $"{Site}\{Name}"
|
||||||
|
End If
|
||||||
|
fDest = $"{DestinationPath.PathWithSeparator}{OptPath}".CSFileP
|
||||||
|
If fDest.Exists(SFO.Path, False) AndAlso MsgBoxE({$"The following path already exists:{vbCr}{fDest.Path}" & vbCr &
|
||||||
|
"Do you want to copy files here?", "Copying files"}, vbExclamation + vbYesNo) = vbNo Then _
|
||||||
|
Throw New FilesCopyingException(Me, "The following path already exists", fDest)
|
||||||
|
|
||||||
|
If DestinationPath.Exists(SFO.Path, True) Then
|
||||||
|
My.Computer.FileSystem.CopyDirectory(fSource, fDest, FileIO.UIOption.OnlyErrorDialogs, FileIO.UICancelOption.ThrowException)
|
||||||
|
Else
|
||||||
|
Throw New FilesCopyingException(Me, "Cannot create the following path", fDest)
|
||||||
|
End If
|
||||||
|
Return True
|
||||||
|
Catch cex As OperationCanceledException
|
||||||
|
Return ErrorsDescriber.Execute(e, New FilesCopyingException(Me, "Copy canceled", fDest),, False)
|
||||||
|
Catch ex As Exception
|
||||||
|
Return ErrorsDescriber.Execute(e, ex,, False)
|
||||||
|
End Try
|
||||||
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Errors functions"
|
#Region "Errors functions"
|
||||||
Protected Sub LogError(ByVal ex As Exception, ByVal Message As String)
|
Protected Sub LogError(ByVal ex As Exception, ByVal Message As String)
|
||||||
ErrorsDescriber.Execute(EDP.SendInLog, ex, $"{IIf(IncludedInCollection, $"{CollectionName}-", String.Empty)}{Site} - {Name}: {Message}")
|
ErrorsDescriber.Execute(EDP.SendInLog, ex, $"{ToStringForLog()}: {Message}")
|
||||||
End Sub
|
End Sub
|
||||||
Protected Sub ErrorDownloading(ByVal f As SFile, ByVal URL As String)
|
Protected Sub ErrorDownloading(ByVal f As SFile, ByVal URL As String)
|
||||||
If Not f.Exists Then MyMainLOG = $"Error downloading from [{URL}] to [{f}]"
|
If Not f.Exists Then MyMainLOG = $"Error downloading from [{URL}] to [{f}]"
|
||||||
@@ -1201,11 +1332,14 @@ BlockNullPicture:
|
|||||||
End Sub
|
End Sub
|
||||||
''' <exception cref="OperationCanceledException"></exception>
|
''' <exception cref="OperationCanceledException"></exception>
|
||||||
''' <exception cref="ObjectDisposedException"></exception>
|
''' <exception cref="ObjectDisposedException"></exception>
|
||||||
Friend Overloads Sub ThrowAny(ByVal Token As CancellationToken)
|
Friend Overridable Overloads Sub ThrowAny(ByVal Token As CancellationToken)
|
||||||
Token.ThrowIfCancellationRequested()
|
Token.ThrowIfCancellationRequested()
|
||||||
ThrowIfDisposed()
|
ThrowIfDisposed()
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
|
Protected Function ToStringForLog() As String
|
||||||
|
Return $"{IIf(IncludedInCollection, $"[{CollectionName}] - ", String.Empty)}[{Site}] - {Name}"
|
||||||
|
End Function
|
||||||
Public Overrides Function ToString() As String
|
Public Overrides Function ToString() As String
|
||||||
If IsCollection Then
|
If IsCollection Then
|
||||||
Return CollectionName
|
Return CollectionName
|
||||||
@@ -1224,8 +1358,8 @@ BlockNullPicture:
|
|||||||
Return hcStr.GetHashCode
|
Return hcStr.GetHashCode
|
||||||
End Function
|
End Function
|
||||||
#Region "Buttons actions"
|
#Region "Buttons actions"
|
||||||
Private Sub BTT_CONTEXT_DOWN_Click(sender As Object, e As EventArgs) Handles BTT_CONTEXT_DOWN.Click
|
Private Sub BTT_CONTEXT_DOWN_KeyClick(sender As Object, e As MyKeyEventArgs) Handles BTT_CONTEXT_DOWN.KeyClick
|
||||||
Downloader.Add(Me)
|
Downloader.Add(Me, e.IncludeInTheFeed)
|
||||||
End Sub
|
End Sub
|
||||||
Private Sub BTT_CONTEXT_EDIT_Click(sender As Object, e As EventArgs) Handles BTT_CONTEXT_EDIT.Click
|
Private Sub BTT_CONTEXT_EDIT_Click(sender As Object, e As EventArgs) Handles BTT_CONTEXT_EDIT.Click
|
||||||
Using f As New Editors.UserCreatorForm(Me)
|
Using f As New Editors.UserCreatorForm(Me)
|
||||||
@@ -1302,6 +1436,7 @@ BlockNullPicture:
|
|||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
End Class
|
End Class
|
||||||
|
#Region "Base interfaces"
|
||||||
Friend Interface IContentProvider
|
Friend Interface IContentProvider
|
||||||
ReadOnly Property Site As String
|
ReadOnly Property Site As String
|
||||||
Property Name As String
|
Property Name As String
|
||||||
@@ -1324,6 +1459,9 @@ BlockNullPicture:
|
|||||||
ReadOnly Property IsCollection As Boolean
|
ReadOnly Property IsCollection As Boolean
|
||||||
Property CollectionName As String
|
Property CollectionName As String
|
||||||
ReadOnly Property IncludedInCollection As Boolean
|
ReadOnly Property IncludedInCollection As Boolean
|
||||||
|
ReadOnly Property UserModel As UsageModel
|
||||||
|
ReadOnly Property CollectionModel As UsageModel
|
||||||
|
ReadOnly Property IsVirtual As Boolean
|
||||||
ReadOnly Property Labels As List(Of String)
|
ReadOnly Property Labels As List(Of String)
|
||||||
#End Region
|
#End Region
|
||||||
ReadOnly Property IsChannel As Boolean
|
ReadOnly Property IsChannel As Boolean
|
||||||
@@ -1355,12 +1493,14 @@ BlockNullPicture:
|
|||||||
''' 2 - Collection removed<br/>
|
''' 2 - Collection removed<br/>
|
||||||
''' 3 - Collection split
|
''' 3 - Collection split
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Function Delete() As Integer
|
Function Delete(Optional ByVal Multiple As Boolean = False, Optional ByVal CollectionValue As Integer = -1) As Integer
|
||||||
Function MoveFiles(ByVal CollectionName As String) As Boolean
|
Function MoveFiles(ByVal CollectionName As String, ByVal SpecialCollectionPath As SFile) As Boolean
|
||||||
|
Function CopyFiles(ByVal DestinationPath As SFile, Optional ByVal e As ErrorsDescriber = Nothing) As Boolean
|
||||||
Sub OpenFolder()
|
Sub OpenFolder()
|
||||||
ReadOnly Property Self As IUserData
|
ReadOnly Property Self As IUserData
|
||||||
Property DownloadTopCount As Integer?
|
Property DownloadTopCount As Integer?
|
||||||
Property DownloadToDate As Date?
|
Property DownloadDateFrom As Date?
|
||||||
|
Property DownloadDateTo As Date?
|
||||||
Sub SetEnvironment(ByRef h As SettingsHost, ByVal u As UserInfo, ByVal _LoadUserInformation As Boolean,
|
Sub SetEnvironment(ByRef h As SettingsHost, ByVal u As UserInfo, ByVal _LoadUserInformation As Boolean,
|
||||||
Optional ByVal AttachUserInfo As Boolean = True)
|
Optional ByVal AttachUserInfo As Boolean = True)
|
||||||
ReadOnly Property Disposed As Boolean
|
ReadOnly Property Disposed As Boolean
|
||||||
@@ -1377,4 +1517,5 @@ BlockNullPicture:
|
|||||||
Property SkipExistsUsers As Boolean
|
Property SkipExistsUsers As Boolean
|
||||||
Property SaveToCache As Boolean
|
Property SaveToCache As Boolean
|
||||||
End Interface
|
End Interface
|
||||||
|
#End Region
|
||||||
End Namespace
|
End Namespace
|
||||||
86
SCrawler/API/BaseObjects/DomainEnvir.vb
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
|
' 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 ADB = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons
|
||||||
|
Namespace API.BaseObjects
|
||||||
|
Friend Interface IDomainContainer
|
||||||
|
ReadOnly Property Icon As Icon
|
||||||
|
ReadOnly Property Site As String
|
||||||
|
ReadOnly Property Domains As List(Of String)
|
||||||
|
ReadOnly Property DomainsTemp As List(Of String)
|
||||||
|
ReadOnly Property DomainsDefault As String
|
||||||
|
ReadOnly Property DomainsSettingProp As Plugin.PropertyValue
|
||||||
|
Property DomainsChanged As Boolean
|
||||||
|
Property Initialized As Boolean
|
||||||
|
Property DomainsUpdateInProgress As Boolean
|
||||||
|
Property DomainsUpdatedBySite As Boolean
|
||||||
|
Sub UpdateDomains()
|
||||||
|
End Interface
|
||||||
|
Friend NotInheritable Class DomainContainer
|
||||||
|
Private Sub New()
|
||||||
|
End Sub
|
||||||
|
Friend Shared Sub EndInit(ByVal s As IDomainContainer)
|
||||||
|
If ACheck(s.DomainsSettingProp.Value) Then s.Domains.ListAddList(CStr(s.DomainsSettingProp.Value).Split("|"), LAP.NotContainsOnly)
|
||||||
|
End Sub
|
||||||
|
Friend Overloads Shared Sub UpdateDomains(ByVal s As IDomainContainer)
|
||||||
|
UpdateDomains(s, Nothing, True)
|
||||||
|
End Sub
|
||||||
|
Friend Overloads Shared Sub UpdateDomains(ByVal s As IDomainContainer, ByVal NewDomains As IEnumerable(Of String), ByVal Internal As Boolean)
|
||||||
|
With s
|
||||||
|
If Not .Initialized Or (.DomainsUpdatedBySite And Not Internal) Then Exit Sub
|
||||||
|
If Not .DomainsUpdateInProgress Then
|
||||||
|
.DomainsUpdateInProgress = True
|
||||||
|
.Domains.ListAddList(.DomainsDefault.Split("|"), LAP.NotContainsOnly)
|
||||||
|
.Domains.ListAddList(NewDomains, LAP.NotContainsOnly)
|
||||||
|
.DomainsSettingProp.Value = .Domains.ListToString("|")
|
||||||
|
If Not Internal Then .DomainsUpdatedBySite = True
|
||||||
|
.DomainsUpdateInProgress = False
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
End Sub
|
||||||
|
Friend Shared Sub Update(ByVal s As IDomainContainer)
|
||||||
|
With s
|
||||||
|
If .DomainsChanged Then
|
||||||
|
.Domains.Clear()
|
||||||
|
.Domains.ListAddList(.DomainsTemp, LAP.NotContainsOnly)
|
||||||
|
.UpdateDomains()
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
End Sub
|
||||||
|
Friend Shared Sub EndEdit(ByVal s As IDomainContainer)
|
||||||
|
s.DomainsTemp.ListAddList(s.Domains, LAP.ClearBeforeAdd, LAP.NotContainsOnly)
|
||||||
|
s.DomainsChanged = False
|
||||||
|
End Sub
|
||||||
|
Friend Shared Sub OpenSettingsForm(ByVal s As IDomainContainer)
|
||||||
|
Dim __add As EventHandler(Of SimpleListFormEventArgs) = Sub(sender, e) e.ValueNew = InputBoxE($"Enter a new domain using the pattern [{s.Site}.com]:", "New domain").IfNullOrEmptyE(Nothing)
|
||||||
|
Dim __delete As EventHandler(Of SimpleListFormEventArgs) = Sub(sender, e)
|
||||||
|
Dim n$ = AConvert(Of String)(e.ValueCurrent, AModes.Var, String.Empty)
|
||||||
|
e.Result = MsgBoxE({$"Are you sure you want to delete the [{n}] domain?",
|
||||||
|
"Removing domains"}, vbYesNo) = vbYes
|
||||||
|
End Sub
|
||||||
|
Using f As New SimpleListForm(Of String)(If(s.DomainsChanged, s.DomainsTemp, s.Domains), Settings.Design) With {
|
||||||
|
.Buttons = {ADB.Add, ADB.Delete},
|
||||||
|
.Mode = SimpleListFormModes.Remaining,
|
||||||
|
.FormText = s.Site,
|
||||||
|
.Icon = s.Icon,
|
||||||
|
.LocationOnly = True,
|
||||||
|
.Size = New Size(400, 330),
|
||||||
|
.DesignXMLNode = s.Site
|
||||||
|
}
|
||||||
|
AddHandler f.AddClick, __add
|
||||||
|
AddHandler f.DeleteClick, __delete
|
||||||
|
f.ShowDialog()
|
||||||
|
If f.DialogResult = DialogResult.OK Then
|
||||||
|
s.DomainsChanged = True
|
||||||
|
s.DomainsTemp.ListAddList(f.DataResult, LAP.ClearBeforeAdd, LAP.NotContainsOnly)
|
||||||
|
End If
|
||||||
|
End Using
|
||||||
|
End Sub
|
||||||
|
End Class
|
||||||
|
End Namespace
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
@@ -6,9 +6,9 @@
|
|||||||
'
|
'
|
||||||
' This program is distributed in the hope that it will be useful,
|
' This program is distributed in the hope that it will be useful,
|
||||||
' but WITHOUT ANY WARRANTY
|
' but WITHOUT ANY WARRANTY
|
||||||
Imports PersonalUtilities.Functions.RegularExpressions
|
|
||||||
Imports System.Net
|
Imports System.Net
|
||||||
Imports SCrawler.API.Base
|
Imports SCrawler.API.Base
|
||||||
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
Namespace API.Gfycat
|
Namespace API.Gfycat
|
||||||
Friend NotInheritable Class Envir
|
Friend NotInheritable Class Envir
|
||||||
Private Sub New()
|
Private Sub New()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
@@ -6,12 +6,12 @@
|
|||||||
'
|
'
|
||||||
' This program is distributed in the hope that it will be useful,
|
' This program is distributed in the hope that it will be useful,
|
||||||
' but WITHOUT ANY WARRANTY
|
' but WITHOUT ANY WARRANTY
|
||||||
Imports PersonalUtilities.Functions.XML
|
|
||||||
Imports PersonalUtilities.Functions.RegularExpressions
|
|
||||||
Imports PersonalUtilities.Tools.WebDocuments.JSON
|
|
||||||
Imports System.Net
|
Imports System.Net
|
||||||
Imports SCrawler.API.Base
|
Imports SCrawler.API.Base
|
||||||
Imports SCrawler.API.Imgur.Declarations
|
Imports SCrawler.API.Imgur.Declarations
|
||||||
|
Imports PersonalUtilities.Functions.XML
|
||||||
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
|
Imports PersonalUtilities.Tools.Web.Documents.JSON
|
||||||
Namespace API.Imgur
|
Namespace API.Imgur
|
||||||
Namespace Declarations
|
Namespace Declarations
|
||||||
Friend Module Imgur_Declarations
|
Friend Module Imgur_Declarations
|
||||||
@@ -67,7 +67,7 @@ Namespace API.Imgur
|
|||||||
Return DownloadingException(ex, $"[API.Imgur.Envir.GetImage({URL})]", String.Empty, e)
|
Return DownloadingException(ex, $"[API.Imgur.Envir.GetImage({URL})]", String.Empty, e)
|
||||||
End Try
|
End Try
|
||||||
End Function
|
End Function
|
||||||
Friend Shared Function GetVideoInfo(ByVal URL As String) As IEnumerable(Of UserMedia)
|
Friend Shared Function GetVideoInfo(ByVal URL As String, Optional ByVal e As ErrorsDescriber = Nothing) As IEnumerable(Of UserMedia)
|
||||||
Try
|
Try
|
||||||
If Not URL.IsEmptyString AndAlso URL.ToLower.Contains("imgur") AndAlso Not Settings.ImgurClientID.IsEmptyString Then
|
If Not URL.IsEmptyString AndAlso URL.ToLower.Contains("imgur") AndAlso Not Settings.ImgurClientID.IsEmptyString Then
|
||||||
Dim img$ = GetImage(URL, EDP.ReturnValue)
|
Dim img$ = GetImage(URL, EDP.ReturnValue)
|
||||||
@@ -79,7 +79,8 @@ Namespace API.Imgur
|
|||||||
End If
|
End If
|
||||||
Return Nothing
|
Return Nothing
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
Return ErrorsDescriber.Execute(EDP.ShowMainMsg + EDP.SendInLog + EDP.ReturnValue, ex, "Imgur standalone downloader: fetch media error")
|
If Not e.Exists Then e = EDP.LogMessageValue
|
||||||
|
Return ErrorsDescriber.Execute(e, ex, "Imgur standalone downloader: fetch media error")
|
||||||
End Try
|
End Try
|
||||||
End Function
|
End Function
|
||||||
Private Shared Function DownloadingException(ByVal ex As Exception, ByVal Message As String,
|
Private Shared Function DownloadingException(ByVal ex As Exception, ByVal Message As String,
|
||||||
|
|||||||
135
SCrawler/API/Instagram/AdditionalSettingsForm.Designer.vb
generated
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
|
' 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.Instagram
|
||||||
|
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()>
|
||||||
|
Partial Friend Class AdditionalSettingsForm : 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
|
||||||
|
Me.CH_DOWN_TIME = New System.Windows.Forms.CheckBox()
|
||||||
|
Me.CH_DOWN_TAG = New System.Windows.Forms.CheckBox()
|
||||||
|
Me.CH_DOWN_SAVED = New System.Windows.Forms.CheckBox()
|
||||||
|
CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer()
|
||||||
|
TP_MAIN = New System.Windows.Forms.TableLayoutPanel()
|
||||||
|
CONTAINER_MAIN.ContentPanel.SuspendLayout()
|
||||||
|
CONTAINER_MAIN.SuspendLayout()
|
||||||
|
TP_MAIN.SuspendLayout()
|
||||||
|
Me.SuspendLayout()
|
||||||
|
'
|
||||||
|
'CONTAINER_MAIN
|
||||||
|
'
|
||||||
|
'
|
||||||
|
'CONTAINER_MAIN.ContentPanel
|
||||||
|
'
|
||||||
|
CONTAINER_MAIN.ContentPanel.Controls.Add(TP_MAIN)
|
||||||
|
CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(234, 78)
|
||||||
|
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(234, 103)
|
||||||
|
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.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20.0!))
|
||||||
|
TP_MAIN.Controls.Add(Me.CH_DOWN_TIME, 0, 0)
|
||||||
|
TP_MAIN.Controls.Add(Me.CH_DOWN_TAG, 0, 1)
|
||||||
|
TP_MAIN.Controls.Add(Me.CH_DOWN_SAVED, 0, 2)
|
||||||
|
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 = 4
|
||||||
|
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||||
|
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||||
|
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||||
|
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||||
|
TP_MAIN.Size = New System.Drawing.Size(234, 78)
|
||||||
|
TP_MAIN.TabIndex = 0
|
||||||
|
'
|
||||||
|
'CH_DOWN_TIME
|
||||||
|
'
|
||||||
|
Me.CH_DOWN_TIME.AutoSize = True
|
||||||
|
Me.CH_DOWN_TIME.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.CH_DOWN_TIME.Location = New System.Drawing.Point(4, 4)
|
||||||
|
Me.CH_DOWN_TIME.Name = "CH_DOWN_TIME"
|
||||||
|
Me.CH_DOWN_TIME.Size = New System.Drawing.Size(226, 19)
|
||||||
|
Me.CH_DOWN_TIME.TabIndex = 0
|
||||||
|
Me.CH_DOWN_TIME.Text = "Download Timeline"
|
||||||
|
Me.CH_DOWN_TIME.UseVisualStyleBackColor = True
|
||||||
|
'
|
||||||
|
'CH_DOWN_TAG
|
||||||
|
'
|
||||||
|
Me.CH_DOWN_TAG.AutoSize = True
|
||||||
|
Me.CH_DOWN_TAG.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.CH_DOWN_TAG.Location = New System.Drawing.Point(4, 30)
|
||||||
|
Me.CH_DOWN_TAG.Name = "CH_DOWN_TAG"
|
||||||
|
Me.CH_DOWN_TAG.Size = New System.Drawing.Size(226, 19)
|
||||||
|
Me.CH_DOWN_TAG.TabIndex = 1
|
||||||
|
Me.CH_DOWN_TAG.Text = "Download Stories and Tagged data"
|
||||||
|
Me.CH_DOWN_TAG.UseVisualStyleBackColor = True
|
||||||
|
'
|
||||||
|
'CH_DOWN_SAVED
|
||||||
|
'
|
||||||
|
Me.CH_DOWN_SAVED.AutoSize = True
|
||||||
|
Me.CH_DOWN_SAVED.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.CH_DOWN_SAVED.Location = New System.Drawing.Point(4, 56)
|
||||||
|
Me.CH_DOWN_SAVED.Name = "CH_DOWN_SAVED"
|
||||||
|
Me.CH_DOWN_SAVED.Size = New System.Drawing.Size(226, 19)
|
||||||
|
Me.CH_DOWN_SAVED.TabIndex = 2
|
||||||
|
Me.CH_DOWN_SAVED.Text = "Download saved posts"
|
||||||
|
Me.CH_DOWN_SAVED.UseVisualStyleBackColor = True
|
||||||
|
'
|
||||||
|
'AdditionalSettingsForm
|
||||||
|
'
|
||||||
|
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
|
||||||
|
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
|
||||||
|
Me.ClientSize = New System.Drawing.Size(234, 103)
|
||||||
|
Me.Controls.Add(CONTAINER_MAIN)
|
||||||
|
Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle
|
||||||
|
Me.Icon = Global.SCrawler.My.Resources.SiteResources.InstagramIcon_32
|
||||||
|
Me.KeyPreview = True
|
||||||
|
Me.MaximizeBox = False
|
||||||
|
Me.MaximumSize = New System.Drawing.Size(250, 142)
|
||||||
|
Me.MinimizeBox = False
|
||||||
|
Me.MinimumSize = New System.Drawing.Size(250, 142)
|
||||||
|
Me.Name = "AdditionalSettingsForm"
|
||||||
|
Me.ShowInTaskbar = False
|
||||||
|
Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide
|
||||||
|
Me.Text = "Additional settings"
|
||||||
|
CONTAINER_MAIN.ContentPanel.ResumeLayout(False)
|
||||||
|
CONTAINER_MAIN.ResumeLayout(False)
|
||||||
|
CONTAINER_MAIN.PerformLayout()
|
||||||
|
TP_MAIN.ResumeLayout(False)
|
||||||
|
TP_MAIN.PerformLayout()
|
||||||
|
Me.ResumeLayout(False)
|
||||||
|
|
||||||
|
End Sub
|
||||||
|
Private WithEvents CH_DOWN_TIME As CheckBox
|
||||||
|
Private WithEvents CH_DOWN_TAG As CheckBox
|
||||||
|
Private WithEvents CH_DOWN_SAVED As CheckBox
|
||||||
|
End Class
|
||||||
|
End Namespace
|
||||||
@@ -120,4 +120,7 @@
|
|||||||
<metadata name="CONTAINER_MAIN.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
<metadata name="CONTAINER_MAIN.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
<value>False</value>
|
<value>False</value>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
<metadata name="TP_MAIN.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>False</value>
|
||||||
|
</metadata>
|
||||||
</root>
|
</root>
|
||||||
41
SCrawler/API/Instagram/AdditionalSettingsForm.vb
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
|
' 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
|
||||||
|
Namespace API.Instagram
|
||||||
|
Friend Class AdditionalSettingsForm
|
||||||
|
Private WithEvents MyDefs As DefaultFormOptions
|
||||||
|
Friend Property MyParameters As SettingsExchangeOptions
|
||||||
|
Friend Sub New(ByVal Parameters As SettingsExchangeOptions)
|
||||||
|
InitializeComponent()
|
||||||
|
MyParameters = Parameters
|
||||||
|
MyDefs = New DefaultFormOptions(Me, Settings.Design)
|
||||||
|
End Sub
|
||||||
|
Private Sub MyForm_Load(sender As Object, e As EventArgs) Handles Me.Load
|
||||||
|
With MyDefs
|
||||||
|
.MyViewInitialize(True)
|
||||||
|
.AddOkCancelToolbar()
|
||||||
|
With MyParameters
|
||||||
|
CH_DOWN_TIME.Checked = .DownloadTimeline
|
||||||
|
CH_DOWN_TAG.Checked = .DownloadStoriesTagged
|
||||||
|
CH_DOWN_SAVED.Checked = .DownloadSaved
|
||||||
|
End With
|
||||||
|
.EndLoaderOperations()
|
||||||
|
End With
|
||||||
|
End Sub
|
||||||
|
Private Sub MyDefs_ButtonOkClick(ByVal Sender As Object, ByVal e As KeyHandleEventArgs) Handles MyDefs.ButtonOkClick
|
||||||
|
MyParameters = New SettingsExchangeOptions With {
|
||||||
|
.DownloadTimeline = CH_DOWN_TIME.Checked,
|
||||||
|
.DownloadStoriesTagged = CH_DOWN_TAG.Checked,
|
||||||
|
.DownloadSaved = CH_DOWN_SAVED.Checked,
|
||||||
|
.Changed = True
|
||||||
|
}
|
||||||
|
MyDefs.CloseForm()
|
||||||
|
End Sub
|
||||||
|
End Class
|
||||||
|
End Namespace
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
@@ -10,6 +10,7 @@ Imports PersonalUtilities.Functions.RegularExpressions
|
|||||||
Namespace API.Instagram
|
Namespace API.Instagram
|
||||||
Friend Module Declarations
|
Friend Module Declarations
|
||||||
Friend Const InstagramSite As String = "Instagram"
|
Friend Const InstagramSite As String = "Instagram"
|
||||||
|
Friend Const InstagramSiteKey As String = "AndyProgram_Instagram"
|
||||||
Friend ReadOnly FilesPattern As RParams = RParams.DMS(".+?([^/\?]+?\.[\w\d]{3,4})(?=(\?|\Z))", 1, EDP.ReturnValue)
|
Friend ReadOnly FilesPattern As RParams = RParams.DMS(".+?([^/\?]+?\.[\w\d]{3,4})(?=(\?|\Z))", 1, EDP.ReturnValue)
|
||||||
Friend ReadOnly Property DateProvider As New CustomProvider(Function(v, d, p, n, e) ADateTime.ParseUnicode(v))
|
Friend ReadOnly Property DateProvider As New CustomProvider(Function(v, d, p, n, e) ADateTime.ParseUnicode(v))
|
||||||
End Module
|
End Module
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
|
|||||||
4
SCrawler/API/Instagram/OptionsForm.Designer.vb
generated
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
@@ -95,13 +95,13 @@ Namespace API.Instagram
|
|||||||
Me.ClientSize = New System.Drawing.Size(260, 78)
|
Me.ClientSize = New System.Drawing.Size(260, 78)
|
||||||
Me.Controls.Add(CONTAINER_MAIN)
|
Me.Controls.Add(CONTAINER_MAIN)
|
||||||
Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle
|
Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle
|
||||||
|
Me.Icon = Global.SCrawler.My.Resources.SiteResources.InstagramIcon_32
|
||||||
Me.KeyPreview = True
|
Me.KeyPreview = True
|
||||||
Me.MaximizeBox = False
|
Me.MaximizeBox = False
|
||||||
Me.MaximumSize = New System.Drawing.Size(276, 117)
|
Me.MaximumSize = New System.Drawing.Size(276, 117)
|
||||||
Me.MinimizeBox = False
|
Me.MinimizeBox = False
|
||||||
Me.MinimumSize = New System.Drawing.Size(276, 117)
|
Me.MinimumSize = New System.Drawing.Size(276, 117)
|
||||||
Me.Name = "OptionsForm"
|
Me.Name = "OptionsForm"
|
||||||
Me.ShowIcon = False
|
|
||||||
Me.ShowInTaskbar = False
|
Me.ShowInTaskbar = False
|
||||||
Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide
|
Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide
|
||||||
Me.Text = "Options"
|
Me.Text = "Options"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
|
|||||||
23
SCrawler/API/Instagram/SettingsExchangeOptions.vb
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
|
' 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.Instagram
|
||||||
|
Friend Structure SettingsExchangeOptions
|
||||||
|
Friend DownloadTimeline As Boolean
|
||||||
|
Friend DownloadStoriesTagged As Boolean
|
||||||
|
Friend DownloadSaved As Boolean
|
||||||
|
Friend Changed As Boolean
|
||||||
|
Friend Sub New(ByVal Source As SiteSettings)
|
||||||
|
With Source
|
||||||
|
DownloadTimeline = .DownloadTimeline
|
||||||
|
DownloadStoriesTagged = .DownloadStoriesTagged
|
||||||
|
DownloadSaved = .DownloadSaved
|
||||||
|
End With
|
||||||
|
End Sub
|
||||||
|
End Structure
|
||||||
|
End Namespace
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
@@ -10,24 +10,23 @@ Imports SCrawler.API.Base
|
|||||||
Imports SCrawler.Plugin
|
Imports SCrawler.Plugin
|
||||||
Imports SCrawler.Plugin.Attributes
|
Imports SCrawler.Plugin.Attributes
|
||||||
Imports PersonalUtilities.Forms
|
Imports PersonalUtilities.Forms
|
||||||
Imports PersonalUtilities.Tools.WEB
|
|
||||||
Imports PersonalUtilities.Functions.XML
|
Imports PersonalUtilities.Functions.XML
|
||||||
Imports PersonalUtilities.Functions.XML.Base
|
Imports PersonalUtilities.Functions.XML.Base
|
||||||
Imports PersonalUtilities.Functions.RegularExpressions
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
Imports Download = SCrawler.Plugin.ISiteSettings.Download
|
Imports Download = SCrawler.Plugin.ISiteSettings.Download
|
||||||
Namespace API.Instagram
|
Namespace API.Instagram
|
||||||
<Manifest("AndyProgram_Instagram"), UseClassAsIs, SeparatedTasks(1), SavedPosts, SpecialForm(False)>
|
<Manifest(InstagramSiteKey), SeparatedTasks(1), SavedPosts, SpecialForm(False), SpecialForm(True)>
|
||||||
Friend Class SiteSettings : Inherits SiteSettingsBase
|
Friend Class SiteSettings : Inherits SiteSettingsBase
|
||||||
#Region "Declarations"
|
#Region "Declarations"
|
||||||
#Region "Images"
|
#Region "Images"
|
||||||
Friend Overrides ReadOnly Property Icon As Icon
|
Friend Overrides ReadOnly Property Icon As Icon
|
||||||
Get
|
Get
|
||||||
Return My.Resources.InstagramIcon
|
Return My.Resources.SiteResources.InstagramIcon_32
|
||||||
End Get
|
End Get
|
||||||
End Property
|
End Property
|
||||||
Friend Overrides ReadOnly Property Image As Image
|
Friend Overrides ReadOnly Property Image As Image
|
||||||
Get
|
Get
|
||||||
Return My.Resources.InstagramPic76
|
Return My.Resources.SiteResources.InstagramPic_76
|
||||||
End Get
|
End Get
|
||||||
End Property
|
End Property
|
||||||
#End Region
|
#End Region
|
||||||
@@ -78,23 +77,23 @@ Namespace API.Instagram
|
|||||||
End Class
|
End Class
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Authorization properties"
|
#Region "Authorization properties"
|
||||||
<PropertyOption(ControlText:="Hash", ControlToolTip:="Instagram session hash", IsAuth:=True), PXML("InstaHash"), ControlNumber(0)>
|
<PropertyOption(ControlText:="Hash", ControlToolTip:="Instagram session hash", IsAuth:=True, AllowNull:=False), PXML("InstaHash"), ControlNumber(0)>
|
||||||
Friend ReadOnly Property Hash As PropertyValue
|
Friend ReadOnly Property Hash As PropertyValue
|
||||||
<PropertyOption(ControlText:="Hash 2", ControlToolTip:="Instagram session hash for saved posts", IsAuth:=True), PXML("InstaHashSavedPosts"), ControlNumber(1)>
|
Private Const HashSavedPosts_Text As String = "Hash 2"
|
||||||
|
<PropertyOption(ControlText:=HashSavedPosts_Text, ControlToolTip:="Instagram session hash for saved posts", IsAuth:=True), PXML("InstaHashSavedPosts"), ControlNumber(1)>
|
||||||
Friend ReadOnly Property HashSavedPosts As PropertyValue
|
Friend ReadOnly Property HashSavedPosts As PropertyValue
|
||||||
<PropertyOption(ControlText:="x-csrftoken", ControlToolTip:="Instagram token for tagged data", IsAuth:=True), ControlNumber(2)>
|
<PropertyOption(ControlText:="x-csrftoken", ControlToolTip:="Instagram token for tagged data", IsAuth:=True, AllowNull:=False), ControlNumber(2)>
|
||||||
Friend ReadOnly Property CSRF_TOKEN As PropertyValue
|
Friend ReadOnly Property CSRF_TOKEN As PropertyValue
|
||||||
<PropertyOption(ControlText:="x-ig-app-id", IsAuth:=True), ControlNumber(3)>
|
<PropertyOption(ControlText:="x-ig-app-id", IsAuth:=True, AllowNull:=False), ControlNumber(3)>
|
||||||
Friend Property IG_APP_ID As PropertyValue
|
Friend Property IG_APP_ID As PropertyValue
|
||||||
<PropertyOption(ControlText:="x-ig-www-claim", IsAuth:=True), ControlNumber(4)>
|
<PropertyOption(ControlText:="x-ig-www-claim", IsAuth:=True, AllowNull:=False), ControlNumber(4)>
|
||||||
Friend Property IG_WWW_CLAIM As PropertyValue
|
Friend Property IG_WWW_CLAIM As PropertyValue
|
||||||
<PropertyOption(ControlText:="Saved posts user", IsAuth:=True), PXML("SavedPostsUserName"), ControlNumber(5)>
|
Private Const SavedPostsUserName_Text As String = "Saved posts user"
|
||||||
|
<PropertyOption(ControlText:=SavedPostsUserName_Text, ControlToolTip:="Personal profile username", IsAuth:=True), PXML("SavedPostsUserName"), ControlNumber(5)>
|
||||||
Friend ReadOnly Property SavedPostsUserName As PropertyValue
|
Friend ReadOnly Property SavedPostsUserName As PropertyValue
|
||||||
Friend ReadOnly Property BaseAuthExists As Boolean
|
Friend Overrides Function BaseAuthExists() As Boolean
|
||||||
Get
|
Return If(Responser.Cookies?.Count, 0) > 0 And ACheck(IG_APP_ID.Value) And ACheck(IG_WWW_CLAIM.Value) And ACheck(CSRF_TOKEN.Value)
|
||||||
Return Responser.Cookies.Count > 0 And ACheck(IG_APP_ID.Value) And ACheck(IG_WWW_CLAIM.Value) And ACheck(CSRF_TOKEN.Value)
|
End Function
|
||||||
End Get
|
|
||||||
End Property
|
|
||||||
Private Const Header_IG_APP_ID As String = "x-ig-app-id"
|
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_IG_WWW_CLAIM As String = "x-ig-www-claim"
|
||||||
Private Const Header_CSRF_TOKEN As String = "x-csrftoken"
|
Private Const Header_CSRF_TOKEN As String = "x-csrftoken"
|
||||||
@@ -107,8 +106,8 @@ Namespace API.Instagram
|
|||||||
Case NameOf(CSRF_TOKEN) : f = Header_CSRF_TOKEN
|
Case NameOf(CSRF_TOKEN) : f = Header_CSRF_TOKEN
|
||||||
End Select
|
End Select
|
||||||
If Not f.IsEmptyString Then
|
If Not f.IsEmptyString Then
|
||||||
If Responser.Headers.Count > 0 AndAlso Responser.Headers.ContainsKey(f) Then Responser.Headers.Remove(f)
|
Responser.HeadersRemove(f)
|
||||||
If Not CStr(Value).IsEmptyString Then Responser.Headers.Add(f, CStr(Value))
|
If Not CStr(Value).IsEmptyString Then Responser.HeadersAdd(f, CStr(Value))
|
||||||
Responser.SaveSettings()
|
Responser.SaveSettings()
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
@@ -138,11 +137,17 @@ Namespace API.Instagram
|
|||||||
<Provider(NameOf(TaggedNotifyLimit), FieldsChecker:=True)>
|
<Provider(NameOf(TaggedNotifyLimit), FieldsChecker:=True)>
|
||||||
Private ReadOnly Property TaggedNotifyLimitProvider As IFormatProvider
|
Private ReadOnly Property TaggedNotifyLimitProvider As IFormatProvider
|
||||||
#End Region
|
#End Region
|
||||||
|
#Region "Download ready"
|
||||||
|
Friend ReadOnly Property DownloadTimeline As XMLValue(Of Boolean)
|
||||||
|
Friend ReadOnly Property DownloadStoriesTagged As XMLValue(Of Boolean)
|
||||||
|
Friend ReadOnly Property DownloadSaved As XMLValue(Of Boolean)
|
||||||
|
#End Region
|
||||||
#Region "429 bypass"
|
#Region "429 bypass"
|
||||||
Private ReadOnly Property DownloadingErrorDate As XMLValue(Of Date)
|
Private ReadOnly Property DownloadingErrorDate As XMLValue(Of Date)
|
||||||
Friend Property LastApplyingValue As Integer? = Nothing
|
Friend Property LastApplyingValue As Integer? = Nothing
|
||||||
Friend ReadOnly Property ReadyForDownload As Boolean
|
Friend ReadOnly Property ReadyForDownload As Boolean
|
||||||
Get
|
Get
|
||||||
|
If SkipUntilNextSession Then Return False
|
||||||
With DownloadingErrorDate
|
With DownloadingErrorDate
|
||||||
If .ValueF.Exists Then
|
If .ValueF.Exists Then
|
||||||
Return .ValueF.Value.AddMinutes(If(LastApplyingValue, 10)) < Now
|
Return .ValueF.Value.AddMinutes(If(LastApplyingValue, 10)) < Now
|
||||||
@@ -186,7 +191,6 @@ Namespace API.Instagram
|
|||||||
End With
|
End With
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
Private Initialized As Boolean = False
|
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Initializer"
|
#Region "Initializer"
|
||||||
Friend Sub New(ByRef _XML As XmlFile, ByVal GlobalPath As SFile)
|
Friend Sub New(ByRef _XML As XmlFile, ByVal GlobalPath As SFile)
|
||||||
@@ -198,11 +202,13 @@ Namespace API.Instagram
|
|||||||
|
|
||||||
With Responser
|
With Responser
|
||||||
If .Headers.Count > 0 Then
|
If .Headers.Count > 0 Then
|
||||||
With .Headers
|
token = .HeadersValue(Header_CSRF_TOKEN)
|
||||||
If .ContainsKey(Header_CSRF_TOKEN) Then token = .Item(Header_CSRF_TOKEN)
|
app_id = .HeadersValue(Header_IG_APP_ID)
|
||||||
If .ContainsKey(Header_IG_APP_ID) Then app_id = .Item(Header_IG_APP_ID)
|
www_claim = .HeadersValue(Header_IG_WWW_CLAIM)
|
||||||
If .ContainsKey(Header_IG_WWW_CLAIM) Then www_claim = .Item(Header_IG_WWW_CLAIM)
|
End If
|
||||||
End With
|
If Not .Cookies Is Nothing Then
|
||||||
|
.Cookies.ChangedAllowInternalDrop = False
|
||||||
|
.Cookies.Changed = False
|
||||||
End If
|
End If
|
||||||
End With
|
End With
|
||||||
|
|
||||||
@@ -216,6 +222,10 @@ Namespace API.Instagram
|
|||||||
IG_APP_ID = New PropertyValue(app_id, GetType(String), Sub(v) ChangeResponserFields(NameOf(IG_APP_ID), 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))
|
IG_WWW_CLAIM = New PropertyValue(www_claim, GetType(String), Sub(v) ChangeResponserFields(NameOf(IG_WWW_CLAIM), v))
|
||||||
|
|
||||||
|
DownloadTimeline = New XMLValue(Of Boolean)("DownloadTimeline", True, _XML, n)
|
||||||
|
DownloadStoriesTagged = New XMLValue(Of Boolean)("DownloadStoriesTagged", True, _XML, n)
|
||||||
|
DownloadSaved = New XMLValue(Of Boolean)("DownloadSaved", True, _XML, n)
|
||||||
|
|
||||||
RequestsWaitTimer = New PropertyValue(1000)
|
RequestsWaitTimer = New PropertyValue(1000)
|
||||||
RequestsWaitTimerProvider = New TimersChecker(100)
|
RequestsWaitTimerProvider = New TimersChecker(100)
|
||||||
RequestsWaitTimerTaskCount = New PropertyValue(1)
|
RequestsWaitTimerTaskCount = New PropertyValue(1)
|
||||||
@@ -233,17 +243,68 @@ Namespace API.Instagram
|
|||||||
LastDownloadDate = New XMLValue(Of Date)("LastDownloadDate", Now.AddDays(-1), _XML, n)
|
LastDownloadDate = New XMLValue(Of Date)("LastDownloadDate", Now.AddDays(-1), _XML, n)
|
||||||
LastRequestsCount = New XMLValue(Of Integer)("LastRequestsCount", 0, _XML, n)
|
LastRequestsCount = New XMLValue(Of Integer)("LastRequestsCount", 0, _XML, n)
|
||||||
LastRequestsCountLabel = New PropertyValue(LastRequestsCountLabelStr.Invoke(LastRequestsCount.Value))
|
LastRequestsCountLabel = New PropertyValue(LastRequestsCountLabelStr.Invoke(LastRequestsCount.Value))
|
||||||
AddHandler LastRequestsCount.OnValueChanged, Sub(sender, __name, __value) LastRequestsCountLabel.Value = LastRequestsCountLabelStr.Invoke(__value)
|
AddHandler LastRequestsCount.OnValueChanged, Sub(sender, __name, __value) LastRequestsCountLabel.Value = LastRequestsCountLabelStr.Invoke(DirectCast(__value, Existable(Of Integer)).Value)
|
||||||
|
|
||||||
UrlPatternUser = "https://www.instagram.com/{0}/"
|
UrlPatternUser = "https://www.instagram.com/{0}/"
|
||||||
UserRegex = RParams.DMS("[htps:/]{7,8}.*?instagram.com/([^/]+)", 1)
|
UserRegex = RParams.DMS("[htps:/]{7,8}.*?instagram.com/([^/]+)", 1)
|
||||||
ImageVideoContains = "instagram.com"
|
ImageVideoContains = "instagram.com"
|
||||||
End Sub
|
End Sub
|
||||||
Friend Overrides Sub BeginInit()
|
Private Structure LatestValues
|
||||||
|
Friend Hash As String
|
||||||
|
Friend Hash2 As String
|
||||||
|
Friend Token As String
|
||||||
|
Friend AppID As String
|
||||||
|
Friend WwwClaim As String
|
||||||
|
Friend Exists As Boolean
|
||||||
|
Friend Sub New(ByVal Source As SiteSettings)
|
||||||
|
Exists = True
|
||||||
|
With Source
|
||||||
|
Hash = AConvert(Of String)(.Hash.Value, String.Empty)
|
||||||
|
Hash2 = AConvert(Of String)(.HashSavedPosts.Value, String.Empty)
|
||||||
|
With .Responser
|
||||||
|
Token = .HeadersValue(Header_CSRF_TOKEN)
|
||||||
|
AppID = .HeadersValue(Header_IG_APP_ID)
|
||||||
|
WwwClaim = .HeadersValue(Header_IG_WWW_CLAIM)
|
||||||
|
End With
|
||||||
|
End With
|
||||||
End Sub
|
End Sub
|
||||||
Friend Overrides Sub EndInit()
|
End Structure
|
||||||
Initialized = True
|
Private LV As LatestValues = Nothing
|
||||||
MyBase.EndInit()
|
Private ASO As SettingsExchangeOptions = Nothing
|
||||||
|
Friend Overrides Sub BeginEdit()
|
||||||
|
LV = New LatestValues(Me)
|
||||||
|
ASO = Nothing
|
||||||
|
MyBase.BeginEdit()
|
||||||
|
End Sub
|
||||||
|
Friend Overrides Sub EndEdit()
|
||||||
|
LV = Nothing
|
||||||
|
ASO = Nothing
|
||||||
|
MyBase.EndEdit()
|
||||||
|
End Sub
|
||||||
|
Friend Overrides Sub Update()
|
||||||
|
If LV.Exists Then
|
||||||
|
Dim __lv As New LatestValues(Me)
|
||||||
|
If If(Responser.Cookies?.Count, 0) > 0 Then
|
||||||
|
Dim _cookiesChanged As Boolean = If(Responser.Cookies?.Changed, False)
|
||||||
|
If Not DownloadTimeline AndAlso (_cookiesChanged Or
|
||||||
|
(Not LV.Hash = __lv.Hash And Not __lv.Hash.IsEmptyString)) Then DownloadTimeline.Value = True
|
||||||
|
If Not DownloadSaved AndAlso (_cookiesChanged Or (Not LV.Hash2 = __lv.Hash2 And Not __lv.Hash2.IsEmptyString)) Then DownloadSaved.Value = True
|
||||||
|
If Not DownloadStoriesTagged AndAlso (
|
||||||
|
_cookiesChanged Or (
|
||||||
|
(Not LV.Hash = __lv.Hash Or Not LV.Token = __lv.Token Or Not LV.AppID = __lv.AppID Or Not LV.WwwClaim = __lv.WwwClaim) And
|
||||||
|
(Not __lv.Hash.IsEmptyString And Not __lv.Token.IsEmptyString And Not __lv.AppID.IsEmptyString And Not __lv.WwwClaim.IsEmptyString)
|
||||||
|
)) Then DownloadStoriesTagged.Value = True
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
If ASO.Changed Then
|
||||||
|
DownloadTimeline.Value = ASO.DownloadTimeline
|
||||||
|
DownloadStoriesTagged.Value = ASO.DownloadStoriesTagged
|
||||||
|
DownloadSaved.Value = ASO.DownloadSaved
|
||||||
|
End If
|
||||||
|
LV = Nothing
|
||||||
|
ASO = Nothing
|
||||||
|
If Not Responser.Cookies Is Nothing Then Responser.Cookies.Changed = False
|
||||||
|
MyBase.Update()
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "PropertiesDataChecker"
|
#Region "PropertiesDataChecker"
|
||||||
@@ -290,6 +351,37 @@ Namespace API.Instagram
|
|||||||
End If
|
End If
|
||||||
Return False
|
Return False
|
||||||
End Function
|
End Function
|
||||||
|
<PropertiesDataChecker({NameOf(HashSavedPosts), NameOf(SavedPostsUserName)})>
|
||||||
|
Private Function CheckSavedOptions(ByVal p As IEnumerable(Of PropertyData)) As Boolean
|
||||||
|
If p.ListExists Then
|
||||||
|
Const MsgTitle$ = "Saved posts credentials"
|
||||||
|
Dim __hash$ = String.Empty
|
||||||
|
Dim __name$ = String.Empty
|
||||||
|
Dim _OptionlErrorText$ = $"For download saved posts, you must to set both [{HashSavedPosts_Text}] and [{SavedPostsUserName_Text}]."
|
||||||
|
For i% = 0 To p.Count - 1
|
||||||
|
Select Case p(i).Name
|
||||||
|
Case NameOf(HashSavedPosts) : __hash = p(i).Value
|
||||||
|
Case NameOf(SavedPostsUserName) : __name = p(i).Value
|
||||||
|
End Select
|
||||||
|
Next
|
||||||
|
If __hash = __name Then
|
||||||
|
If __hash.IsEmptyString Then
|
||||||
|
Return True
|
||||||
|
Else
|
||||||
|
MsgBoxE({$"[{HashSavedPosts_Text}] and [{SavedPostsUserName_Text}] for saved posts cannot be equal!", MsgTitle}, vbCritical)
|
||||||
|
End If
|
||||||
|
Else
|
||||||
|
If __hash.IsEmptyString Then
|
||||||
|
MsgBoxE({$"[{HashSavedPosts_Text}] not set.{vbCr}{_OptionlErrorText}", MsgTitle}, vbCritical)
|
||||||
|
ElseIf __name.IsEmptyString Then
|
||||||
|
MsgBoxE({$"[{SavedPostsUserName_Text}] not set.{vbCr}{_OptionlErrorText}", MsgTitle}, vbCritical)
|
||||||
|
Else
|
||||||
|
Return True
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Return False
|
||||||
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Plugin functions"
|
#Region "Plugin functions"
|
||||||
Friend Overrides Function GetInstance(ByVal What As Download) As IPluginContentProvider
|
Friend Overrides Function GetInstance(ByVal What As Download) As IPluginContentProvider
|
||||||
@@ -303,11 +395,12 @@ Namespace API.Instagram
|
|||||||
Return Nothing
|
Return Nothing
|
||||||
End Function
|
End Function
|
||||||
#Region "Downloading"
|
#Region "Downloading"
|
||||||
|
Friend Property SkipUntilNextSession As Boolean = False
|
||||||
Friend Overrides Function ReadyToDownload(ByVal What As Download) As Boolean
|
Friend Overrides Function ReadyToDownload(ByVal What As Download) As Boolean
|
||||||
If ActiveJobs < 2 AndAlso ReadyForDownload AndAlso BaseAuthExists Then
|
If ActiveJobs < 2 AndAlso Not SkipUntilNextSession AndAlso ReadyForDownload AndAlso BaseAuthExists() Then
|
||||||
Select Case What
|
Select Case What
|
||||||
Case Download.Main : Return ACheck(Hash.Value)
|
Case Download.Main : Return ACheck(Hash.Value) And DownloadTimeline
|
||||||
Case Download.SavedPosts : Return ACheck(HashSavedPosts.Value)
|
Case Download.SavedPosts : Return ACheck(HashSavedPosts.Value) And DownloadSaved
|
||||||
End Select
|
End Select
|
||||||
End If
|
End If
|
||||||
Return False
|
Return False
|
||||||
@@ -346,10 +439,11 @@ Namespace API.Instagram
|
|||||||
_NextTagged = True
|
_NextTagged = True
|
||||||
LastDownloadDate.Value = Now
|
LastDownloadDate.Value = Now
|
||||||
ActiveJobs -= 1
|
ActiveJobs -= 1
|
||||||
|
SkipUntilNextSession = False
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
Friend Overrides Function GetSpecialDataF(ByVal URL As String) As IEnumerable(Of UserMedia)
|
Friend Overrides Function GetSpecialData(ByVal URL As String, ByVal Path As String, ByVal AskForPath As Boolean) As IEnumerable
|
||||||
Return UserData.GetVideoInfo(URL, Responser, Me)
|
Return UserData.GetVideoInfo(URL, Responser)
|
||||||
End Function
|
End Function
|
||||||
Friend Overrides Sub UserOptions(ByRef Options As Object, ByVal OpenForm As Boolean)
|
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)
|
If Options Is Nothing OrElse Not TypeOf Options Is EditorExchangeOptions Then Options = New EditorExchangeOptions(Me)
|
||||||
@@ -357,6 +451,12 @@ Namespace API.Instagram
|
|||||||
Using f As New OptionsForm(Options) : f.ShowDialog() : End Using
|
Using f As New OptionsForm(Options) : f.ShowDialog() : End Using
|
||||||
End If
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
|
Friend Overrides Sub OpenSettingsForm()
|
||||||
|
Using f As New AdditionalSettingsForm(If(ASO.Changed, ASO, New SettingsExchangeOptions(Me)))
|
||||||
|
f.ShowDialog()
|
||||||
|
If f.DialogResult = DialogResult.OK Then ASO = f.MyParameters
|
||||||
|
End Using
|
||||||
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
End Class
|
End Class
|
||||||
End Namespace
|
End Namespace
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
@@ -6,15 +6,14 @@
|
|||||||
'
|
'
|
||||||
' This program is distributed in the hope that it will be useful,
|
' This program is distributed in the hope that it will be useful,
|
||||||
' but WITHOUT ANY WARRANTY
|
' but WITHOUT ANY WARRANTY
|
||||||
|
Imports System.Net
|
||||||
|
Imports System.Threading
|
||||||
Imports PersonalUtilities.Functions.XML
|
Imports PersonalUtilities.Functions.XML
|
||||||
Imports PersonalUtilities.Functions.Messaging
|
Imports PersonalUtilities.Functions.Messaging
|
||||||
Imports PersonalUtilities.Functions.RegularExpressions
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
Imports PersonalUtilities.Tools.WEB
|
Imports PersonalUtilities.Tools.Web.Clients
|
||||||
Imports PersonalUtilities.Tools.WebDocuments.JSON
|
Imports PersonalUtilities.Tools.Web.Documents.JSON
|
||||||
Imports SCrawler.API.Base
|
Imports SCrawler.API.Base
|
||||||
Imports System.Net
|
|
||||||
Imports System.Threading
|
|
||||||
Imports System.Reflection
|
|
||||||
Imports UTypes = SCrawler.API.Base.UserMedia.Types
|
Imports UTypes = SCrawler.API.Base.UserMedia.Types
|
||||||
Namespace API.Instagram
|
Namespace API.Instagram
|
||||||
Friend Class UserData : Inherits UserDataBase
|
Friend Class UserData : Inherits UserDataBase
|
||||||
@@ -70,41 +69,58 @@ Namespace API.Instagram
|
|||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Download data"
|
#Region "Download data"
|
||||||
|
Private E560Thrown As Boolean = False
|
||||||
Private Class ExitException : Inherits Exception
|
Private Class ExitException : Inherits Exception
|
||||||
|
Friend Shared Sub Throw560(ByRef Source As UserData)
|
||||||
|
If Not Source.E560Thrown Then
|
||||||
|
MyMainLOG = $"{Source.ToStringForLog}: (560) Download skipped until next session"
|
||||||
|
Source.E560Thrown = True
|
||||||
|
End If
|
||||||
|
Throw New ExitException
|
||||||
|
End Sub
|
||||||
|
Friend Sub New()
|
||||||
|
End Sub
|
||||||
Friend Sub New(ByRef CompleteArg As Boolean)
|
Friend Sub New(ByRef CompleteArg As Boolean)
|
||||||
CompleteArg = True
|
CompleteArg = True
|
||||||
End Sub
|
End Sub
|
||||||
End Class
|
End Class
|
||||||
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
|
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
|
||||||
|
Dim s As Sections = Sections.Timeline
|
||||||
Try
|
Try
|
||||||
|
ThrowAny(Token)
|
||||||
_InstaHash = String.Empty
|
_InstaHash = String.Empty
|
||||||
HasError = False
|
HasError = False
|
||||||
If Not LastCursor.IsEmptyString Then
|
Dim fc As Boolean = IIf(IsSavedPosts, MySiteSettings.DownloadSaved.Value, MySiteSettings.DownloadTimeline.Value)
|
||||||
DownloadData(LastCursor, Sections.Timeline, Token)
|
If fc And Not LastCursor.IsEmptyString Then
|
||||||
|
s = IIf(IsSavedPosts, Sections.SavedPosts, Sections.Timeline)
|
||||||
|
DownloadData(LastCursor, s, Token)
|
||||||
ThrowAny(Token)
|
ThrowAny(Token)
|
||||||
If Not HasError Then FirstLoadingDone = True
|
If Not HasError Then FirstLoadingDone = True
|
||||||
End If
|
End If
|
||||||
If Not HasError Then
|
If fc And Not HasError Then
|
||||||
DownloadData(String.Empty, Sections.Timeline, Token)
|
s = IIf(IsSavedPosts, Sections.SavedPosts, Sections.Timeline)
|
||||||
|
DownloadData(String.Empty, s, Token)
|
||||||
ThrowAny(Token)
|
ThrowAny(Token)
|
||||||
If Not HasError Then FirstLoadingDone = True
|
If Not HasError Then FirstLoadingDone = True
|
||||||
End If
|
End If
|
||||||
If FirstLoadingDone Then LastCursor = String.Empty
|
If FirstLoadingDone Then LastCursor = String.Empty
|
||||||
If IsSavedPosts Then
|
If IsSavedPosts Then
|
||||||
DownloadPosts(Token)
|
If MySiteSettings.DownloadSaved Then s = Sections.SavedPosts : DownloadPosts(Token)
|
||||||
ElseIf MySiteSettings.BaseAuthExists Then
|
ElseIf MySiteSettings.BaseAuthExists() Then
|
||||||
DownloadedTags = 0
|
DownloadedTags = 0
|
||||||
If GetStories Then DownloadData(String.Empty, Sections.Stories, Token)
|
If MySiteSettings.DownloadStoriesTagged And GetStories Then s = Sections.Stories : DownloadData(String.Empty, s, Token)
|
||||||
If GetTaggedData Then DownloadData(String.Empty, Sections.Tagged, Token)
|
If MySiteSettings.DownloadStoriesTagged And GetTaggedData Then s = Sections.Tagged : DownloadData(String.Empty, s, Token)
|
||||||
End If
|
End If
|
||||||
If WaitNotificationMode = WNM.SkipTemp Or WaitNotificationMode = WNM.SkipCurrent Then WaitNotificationMode = WNM.Notify
|
If WaitNotificationMode = WNM.SkipTemp Or WaitNotificationMode = WNM.SkipCurrent Then WaitNotificationMode = WNM.Notify
|
||||||
Catch eex As ExitException
|
Catch eex As ExitException
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
ProcessException(ex, Token, "[API.Instagram.UserData.DownloadDataF", False)
|
ProcessException(ex, Token, "[API.Instagram.UserData.DownloadDataF]", False, s)
|
||||||
|
Finally
|
||||||
|
E560Thrown = False
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
Private _InstaHash As String = String.Empty
|
Private _InstaHash As String = String.Empty
|
||||||
Private Enum Sections : Timeline : Tagged : Stories : End Enum
|
Private Enum Sections : Timeline : Tagged : Stories : SavedPosts : End Enum
|
||||||
Private Const StoriesFolder As String = "Stories"
|
Private Const StoriesFolder As String = "Stories"
|
||||||
Private Const TaggedFolder As String = "Tagged"
|
Private Const TaggedFolder As String = "Tagged"
|
||||||
#Region "429 bypass"
|
#Region "429 bypass"
|
||||||
@@ -262,7 +278,7 @@ Namespace API.Instagram
|
|||||||
|
|
||||||
'Create query
|
'Create query
|
||||||
Select Case Section
|
Select Case Section
|
||||||
Case Sections.Timeline
|
Case Sections.Timeline, Sections.SavedPosts
|
||||||
Dim vars$ = "{""id"":" & ID & ",""first"":50,""after"":""" & Cursor & """}"
|
Dim vars$ = "{""id"":" & ID & ",""first"":50,""after"":""" & Cursor & """}"
|
||||||
vars = SymbolsConverter.ASCII.EncodeSymbolsOnly(vars)
|
vars = SymbolsConverter.ASCII.EncodeSymbolsOnly(vars)
|
||||||
URL = $"https://www.instagram.com/graphql/query/?query_hash={_InstaHash}&variables={vars}"
|
URL = $"https://www.instagram.com/graphql/query/?query_hash={_InstaHash}&variables={vars}"
|
||||||
@@ -303,7 +319,7 @@ Namespace API.Instagram
|
|||||||
n = j.ItemF(ENode).XmlIfNothing
|
n = j.ItemF(ENode).XmlIfNothing
|
||||||
If n.Count > 0 Then
|
If n.Count > 0 Then
|
||||||
Select Case Section
|
Select Case Section
|
||||||
Case Sections.Timeline
|
Case Sections.Timeline, Sections.SavedPosts
|
||||||
If n.Contains("page_info") Then
|
If n.Contains("page_info") Then
|
||||||
With n("page_info")
|
With n("page_info")
|
||||||
HasNextPage = .Value("has_next_page").FromXML(Of Boolean)(False)
|
HasNextPage = .Value("has_next_page").FromXML(Of Boolean)(False)
|
||||||
@@ -317,9 +333,7 @@ Namespace API.Instagram
|
|||||||
node = nn(0).XmlIfNothing
|
node = nn(0).XmlIfNothing
|
||||||
If IsSavedPosts Then
|
If IsSavedPosts Then
|
||||||
PostID = node.Value("shortcode")
|
PostID = node.Value("shortcode")
|
||||||
If Not PostID.IsEmptyString Then
|
If Not PostID.IsEmptyString AndAlso _TempPostsList.Contains(PostID) Then Throw New ExitException(_DownloadComplete)
|
||||||
If _TempPostsList.Contains(PostID) Then Throw New ExitException(_DownloadComplete) 'Else _SavedPostsIDs.Add(PostID)
|
|
||||||
End If
|
|
||||||
End If
|
End If
|
||||||
PostID = node.Value("id")
|
PostID = node.Value("id")
|
||||||
Pinned = CBool(If(node("pinned_for_users")?.Count, 0))
|
Pinned = CBool(If(node("pinned_for_users")?.Count, 0))
|
||||||
@@ -329,7 +343,10 @@ Namespace API.Instagram
|
|||||||
If IsSavedPosts Then
|
If IsSavedPosts Then
|
||||||
_SavedPostsIDs.Add(PostID)
|
_SavedPostsIDs.Add(PostID)
|
||||||
Else
|
Else
|
||||||
If Not CheckDatesLimit(PostDate, DateProvider) And Not Pinned Then Throw New ExitException(_DownloadComplete)
|
Select Case CheckDatesLimit(PostDate, DateProvider)
|
||||||
|
Case DateResult.Skip : Continue For
|
||||||
|
Case DateResult.Exit : If Not Pinned Then Throw New ExitException(_DownloadComplete)
|
||||||
|
End Select
|
||||||
ObtainMedia(node, PostID, PostDate, SpecFolder)
|
ObtainMedia(node, PostID, PostDate, SpecFolder)
|
||||||
End If
|
End If
|
||||||
Next
|
Next
|
||||||
@@ -370,7 +387,7 @@ Namespace API.Instagram
|
|||||||
Catch dex As ObjectDisposedException When Disposed
|
Catch dex As ObjectDisposedException When Disposed
|
||||||
Exit Do
|
Exit Do
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
If DownloadingException(ex, $"data downloading error [{URL}]", Section, False) = 1 Then Continue Do Else Exit Do
|
If DownloadingException(ex, $"data downloading error [{URL}]", False, Section) = 1 Then Continue Do Else Exit Do
|
||||||
End Try
|
End Try
|
||||||
Loop
|
Loop
|
||||||
Catch eex2 As ExitException
|
Catch eex2 As ExitException
|
||||||
@@ -378,7 +395,7 @@ Namespace API.Instagram
|
|||||||
Catch oex2 As OperationCanceledException When Token.IsCancellationRequested Or oex2.HelpLink = InstAborted
|
Catch oex2 As OperationCanceledException When Token.IsCancellationRequested Or oex2.HelpLink = InstAborted
|
||||||
If oex2.HelpLink = InstAborted Then HasError = True
|
If oex2.HelpLink = InstAborted Then HasError = True
|
||||||
Catch DoEx As Exception
|
Catch DoEx As Exception
|
||||||
ProcessException(DoEx, Token, $"data downloading error [{URL}]")
|
ProcessException(DoEx, Token, $"data downloading error [{URL}]",, Section)
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
Private Sub DownloadPosts(ByVal Token As CancellationToken)
|
Private Sub DownloadPosts(ByVal Token As CancellationToken)
|
||||||
@@ -429,23 +446,26 @@ Namespace API.Instagram
|
|||||||
Next
|
Next
|
||||||
End If
|
End If
|
||||||
_DownloadComplete = True
|
_DownloadComplete = True
|
||||||
|
Catch eex As ExitException
|
||||||
|
Throw eex
|
||||||
Catch oex As OperationCanceledException When Token.IsCancellationRequested
|
Catch oex As OperationCanceledException When Token.IsCancellationRequested
|
||||||
Exit Do
|
Exit Do
|
||||||
Catch dex As ObjectDisposedException When Disposed
|
Catch dex As ObjectDisposedException When Disposed
|
||||||
Exit Do
|
Exit Do
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
If DownloadingException(ex, $"downloading saved posts error [{URL}]") = 1 Then Continue Do Else Exit Do
|
If DownloadingException(ex, $"downloading saved posts error [{URL}]", False, Sections.SavedPosts) = 1 Then Continue Do Else Exit Do
|
||||||
End Try
|
End Try
|
||||||
Loop
|
Loop
|
||||||
|
Catch eex2 As ExitException
|
||||||
Catch oex2 As OperationCanceledException When Token.IsCancellationRequested Or oex2.HelpLink = InstAborted
|
Catch oex2 As OperationCanceledException When Token.IsCancellationRequested Or oex2.HelpLink = InstAborted
|
||||||
If oex2.HelpLink = InstAborted Then HasError = True
|
If oex2.HelpLink = InstAborted Then HasError = True
|
||||||
Catch DoEx As Exception
|
Catch DoEx As Exception
|
||||||
ProcessException(DoEx, Token, $"downloading saved posts error [{URL}]")
|
ProcessException(DoEx, Token, $"downloading saved posts error [{URL}]",, Sections.SavedPosts)
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Code ID converters"
|
#Region "Code ID converters"
|
||||||
Friend Shared Function CodeToID(ByVal Code As String) As String
|
Private Shared Function CodeToID(ByVal Code As String) As String
|
||||||
Const CodeSymbols$ = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
|
Const CodeSymbols$ = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||||
Try
|
Try
|
||||||
If Not Code.IsEmptyString Then
|
If Not Code.IsEmptyString Then
|
||||||
@@ -490,6 +510,7 @@ Namespace API.Instagram
|
|||||||
Dim vid As Predicate(Of EContainer) = Function(_vid) Not _vid.Name.IsEmptyString AndAlso _vid.Name.StartsWith("video_versions") AndAlso _vid.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 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
|
Dim mDate As Func(Of EContainer, String) = Function(ByVal elem As EContainer) As String
|
||||||
|
If Not DateObj.IsEmptyString Then Return DateObj
|
||||||
If elem.Contains("taken_at") Then
|
If elem.Contains("taken_at") Then
|
||||||
Return elem.Value("taken_at")
|
Return elem.Value("taken_at")
|
||||||
ElseIf elem.Contains("imported_taken_at") Then
|
ElseIf elem.Contains("imported_taken_at") Then
|
||||||
@@ -498,7 +519,7 @@ Namespace API.Instagram
|
|||||||
Dim ev$ = elem.Value("device_timestamp")
|
Dim ev$ = elem.Value("device_timestamp")
|
||||||
If Not ev.IsEmptyString Then
|
If Not ev.IsEmptyString Then
|
||||||
If ev.Length > 10 Then
|
If ev.Length > 10 Then
|
||||||
Return elem.Value("device_timestamp").Substring(0, 10)
|
Return ev.Substring(0, 10)
|
||||||
Else
|
Else
|
||||||
Return ev
|
Return ev
|
||||||
End If
|
End If
|
||||||
@@ -655,7 +676,7 @@ Namespace API.Instagram
|
|||||||
End If
|
End If
|
||||||
Return Nothing
|
Return Nothing
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
DownloadingException(ex, "API.Instagram.GetStoriesList", Sections.Stories, False)
|
DownloadingException(ex, "API.Instagram.GetStoriesList", False, Sections.Stories)
|
||||||
Return Nothing
|
Return Nothing
|
||||||
End Try
|
End Try
|
||||||
End Function
|
End Function
|
||||||
@@ -666,19 +687,24 @@ Namespace API.Instagram
|
|||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Exceptions"
|
#Region "Exceptions"
|
||||||
|
''' <exception cref="ExitException"></exception>
|
||||||
|
''' <inheritdoc cref="UserDataBase.ThrowAny(CancellationToken)"/>
|
||||||
|
Friend Overrides Sub ThrowAny(ByVal Token As CancellationToken)
|
||||||
|
If MySiteSettings.SkipUntilNextSession Then ExitException.Throw560(Me)
|
||||||
|
MyBase.ThrowAny(Token)
|
||||||
|
End Sub
|
||||||
''' <summary>
|
''' <summary>
|
||||||
''' <inheritdoc cref="UserDataBase.DownloadingException(Exception, String)"/><br/>
|
''' <inheritdoc cref="UserDataBase.DownloadingException(Exception, String, Boolean, Object)"/><br/>
|
||||||
''' 1 - continue
|
''' 1 - continue
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Protected Overloads Overrides Function DownloadingException(ByVal ex As Exception, ByVal Message As String, Optional ByVal FromPE As Boolean = False) As Integer
|
Protected Overrides Function DownloadingException(ByVal ex As Exception, ByVal Message As String, Optional ByVal FromPE As Boolean = False,
|
||||||
Return DownloadingException(ex, Message, Sections.Timeline, FromPE)
|
Optional ByVal s As Object = Nothing) As Integer
|
||||||
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
|
If Responser.StatusCode = HttpStatusCode.NotFound Then
|
||||||
UserExists = False
|
UserExists = False
|
||||||
ElseIf Responser.StatusCode = HttpStatusCode.BadRequest Then
|
ElseIf Responser.StatusCode = HttpStatusCode.BadRequest Then
|
||||||
HasError = True
|
HasError = True
|
||||||
MyMainLOG = $"Instagram credentials have expired [{CInt(Responser.StatusCode)}]: {ToString()} [{s}]"
|
MyMainLOG = $"Instagram credentials have expired [{CInt(Responser.StatusCode)}]: {ToStringForLog()} [{s}]"
|
||||||
|
DisableSection(s)
|
||||||
ElseIf Responser.StatusCode = HttpStatusCode.Forbidden And s = Sections.Tagged Then
|
ElseIf Responser.StatusCode = HttpStatusCode.Forbidden And s = Sections.Tagged Then
|
||||||
Return 3
|
Return 3
|
||||||
ElseIf Responser.StatusCode = 429 Then
|
ElseIf Responser.StatusCode = 429 Then
|
||||||
@@ -690,13 +716,27 @@ Namespace API.Instagram
|
|||||||
Caught429 = True
|
Caught429 = True
|
||||||
MyMainLOG = $"Number of requests before error 429: {RequestsCount}"
|
MyMainLOG = $"Number of requests before error 429: {RequestsCount}"
|
||||||
Return 1
|
Return 1
|
||||||
|
ElseIf Responser.StatusCode = 560 Then
|
||||||
|
MySiteSettings.SkipUntilNextSession = True
|
||||||
Else
|
Else
|
||||||
MyMainLOG = $"Instagram hash requested [{CInt(Responser.StatusCode)}]: {ToString()} [{s}]"
|
MyMainLOG = $"Instagram hash requested [{CInt(Responser.StatusCode)}]: {ToString()} [{s}]"
|
||||||
|
DisableSection(s)
|
||||||
If Not FromPE Then LogError(ex, Message) : HasError = True
|
If Not FromPE Then LogError(ex, Message) : HasError = True
|
||||||
Return 0
|
Return 0
|
||||||
End If
|
End If
|
||||||
Return 2
|
Return 2
|
||||||
End Function
|
End Function
|
||||||
|
Private Sub DisableSection(ByVal Section As Object)
|
||||||
|
If Not IsNothing(Section) AndAlso TypeOf Section Is Sections Then
|
||||||
|
Dim s As Sections = DirectCast(Section, Sections)
|
||||||
|
Select Case s
|
||||||
|
Case Sections.Timeline : MySiteSettings.DownloadTimeline.Value = False
|
||||||
|
Case Sections.SavedPosts : MySiteSettings.DownloadSaved.Value = False
|
||||||
|
Case Else : MySiteSettings.DownloadStoriesTagged.Value = False
|
||||||
|
End Select
|
||||||
|
MyMainLOG = $"[{s}] downloading is disabled until you update your credentials".ToUpper
|
||||||
|
End If
|
||||||
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Create media"
|
#Region "Create media"
|
||||||
Private Shared Function MediaFromData(ByVal t As UTypes, ByVal _URL As String, ByVal PostID As String, ByVal PostDate As String,
|
Private Shared Function MediaFromData(ByVal t As UTypes, ByVal _URL As String, ByVal PostID As String, ByVal PostDate As String,
|
||||||
@@ -710,14 +750,14 @@ Namespace API.Instagram
|
|||||||
End Function
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Standalone downloader"
|
#Region "Standalone downloader"
|
||||||
Friend Shared Function GetVideoInfo(ByVal URL As String, ByVal r As Response, ByVal _Settings As SiteSettings) As IEnumerable(Of UserMedia)
|
Friend Shared Function GetVideoInfo(ByVal URL As String, ByVal r As Response) As IEnumerable(Of UserMedia)
|
||||||
Try
|
Try
|
||||||
If Not URL.IsEmptyString AndAlso URL.Contains("instagram.com") Then
|
If Not URL.IsEmptyString AndAlso URL.Contains("instagram.com") Then
|
||||||
Dim PID$ = RegexReplace(URL, RParams.DMS(".*?instagram.com/p/([_\w\d]+)", 1))
|
Dim PID$ = RegexReplace(URL, RParams.DMS(".*?instagram.com/p/([_\w\d]+)", 1))
|
||||||
If Not PID.IsEmptyString AndAlso Not ACheck(Of Long)(PID) Then PID = CodeToID(PID)
|
If Not PID.IsEmptyString AndAlso Not ACheck(Of Long)(PID) Then PID = CodeToID(PID)
|
||||||
If Not PID.IsEmptyString Then
|
If Not PID.IsEmptyString Then
|
||||||
Using t As New UserData
|
Using t As New UserData
|
||||||
t.SetEnvironment(Settings(_Settings.GetType.GetCustomAttribute(Of Plugin.Attributes.Manifest)().GUID), Nothing, False, False)
|
t.SetEnvironment(Settings(InstagramSiteKey), Nothing, False, False)
|
||||||
t.Responser = New Response
|
t.Responser = New Response
|
||||||
t.Responser.Copy(r)
|
t.Responser.Copy(r)
|
||||||
t._SavedPostsIDs.Add(PID)
|
t._SavedPostsIDs.Add(PID)
|
||||||
@@ -728,7 +768,7 @@ Namespace API.Instagram
|
|||||||
End If
|
End If
|
||||||
Return Nothing
|
Return Nothing
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
Return ErrorsDescriber.Execute(EDP.ShowMainMsg + EDP.SendInLog, ex, "Instagram standalone downloader: fetch media error")
|
Return ErrorsDescriber.Execute(EDP.ShowMainMsg + EDP.SendInLog, ex, $"Instagram standalone downloader: fetch media error ({URL})")
|
||||||
End Try
|
End Try
|
||||||
End Function
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
|
|||||||
37
SCrawler/API/LPSG/Declarations.vb
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
|
' 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 SCrawler.API.Base
|
||||||
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
|
Namespace API.LPSG
|
||||||
|
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)
|
||||||
|
Friend ReadOnly Property TempListAddParams As New ListAddParams(LAP.NotContainsOnly) With {.Comparer = New FComparer(Of UserMedia)(Function(x, y) x.URL = y.URL)}
|
||||||
|
End Module
|
||||||
|
End Namespace
|
||||||
37
SCrawler/API/LPSG/SiteSettings.vb
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
|
' 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 SCrawler.Plugin
|
||||||
|
Imports SCrawler.Plugin.Attributes
|
||||||
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
|
Namespace API.LPSG
|
||||||
|
<Manifest("AndyProgram_LPSG")>
|
||||||
|
Friend Class SiteSettings : Inherits Base.SiteSettingsBase
|
||||||
|
Friend Overrides ReadOnly Property Icon As Icon
|
||||||
|
Get
|
||||||
|
Return My.Resources.SiteResources.LPSGIcon_48
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
Friend Overrides ReadOnly Property Image As Image
|
||||||
|
Get
|
||||||
|
Return My.Resources.SiteResources.LPSGPic_32
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
Friend Sub New()
|
||||||
|
MyBase.New("LPSG", "www.lpsg.com")
|
||||||
|
UrlPatternUser = "https://www.lpsg.com/threads/{0}/"
|
||||||
|
UserRegex = RParams.DMS(".+?lpsg.com/threads/([^/]+)", 1)
|
||||||
|
End Sub
|
||||||
|
Friend Overrides Function GetInstance(ByVal What As ISiteSettings.Download) As IPluginContentProvider
|
||||||
|
Return New UserData
|
||||||
|
End Function
|
||||||
|
Friend Overrides Function Available(ByVal What As ISiteSettings.Download, ByVal Silent As Boolean) As Boolean
|
||||||
|
Return If(Responser.Cookies?.Count, 0) > 0
|
||||||
|
End Function
|
||||||
|
End Class
|
||||||
|
End Namespace
|
||||||
105
SCrawler/API/LPSG/UserData.vb
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
|
' 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 SCrawler.API.Base
|
||||||
|
Imports PersonalUtilities.Functions.XML
|
||||||
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
|
Imports PersonalUtilities.Tools.Web.Clients
|
||||||
|
Imports UTypes = SCrawler.API.Base.UserMedia.Types
|
||||||
|
Imports Converters = PersonalUtilities.Functions.SymbolsConverter.Converters
|
||||||
|
Namespace API.LPSG
|
||||||
|
Friend Class UserData : Inherits UserDataBase
|
||||||
|
Private Const Name_LatestPage As String = "LatestPage"
|
||||||
|
Protected Overrides Sub LoadUserInformation_OptionalFields(ByRef Container As XmlFile, ByVal Loading As Boolean)
|
||||||
|
If Loading Then
|
||||||
|
LatestPage = Container.Value(Name_LatestPage)
|
||||||
|
Else
|
||||||
|
Container.Add(Name_LatestPage, LatestPage)
|
||||||
|
End If
|
||||||
|
End Sub
|
||||||
|
Private Property LatestPage As String = String.Empty
|
||||||
|
Private Enum Mode : Internal : External : End Enum
|
||||||
|
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
|
||||||
|
Dim URL$ = String.Empty
|
||||||
|
Try
|
||||||
|
Responser.DeclaredError = EDP.ThrowException
|
||||||
|
|
||||||
|
Dim NextPage$
|
||||||
|
Dim r$
|
||||||
|
Dim _LPage As Func(Of String) = Function() If(LatestPage.IsEmptyString, String.Empty, $"page-{LatestPage}")
|
||||||
|
|
||||||
|
Do
|
||||||
|
URL = $"https://www.lpsg.com/threads/{Name}/{_LPage.Invoke}"
|
||||||
|
r = Responser.GetResponse(URL)
|
||||||
|
UserExists = True
|
||||||
|
UserSuspended = False
|
||||||
|
ThrowAny(Token)
|
||||||
|
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 _ContentList.ListExists Then _
|
||||||
|
_TempMediaList.RemoveAll(Function(m) _ContentList.Exists(Function(mm) mm.URL = m.URL))
|
||||||
|
Catch ex As Exception
|
||||||
|
ProcessException(ex, Token, $"data downloading error [{URL}]")
|
||||||
|
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 = MyFile.CutPath.PathNoSeparator
|
||||||
|
f.Separator = "\"
|
||||||
|
If f.Extension.IsEmptyString Then f.Extension = "jpg"
|
||||||
|
_TempMediaList.ListAddValue(New UserMedia With {.Type = UTypes.Picture, .URL = url, .File = f}, TempListAddParams)
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Next
|
||||||
|
End If
|
||||||
|
End Sub
|
||||||
|
Protected Overrides Sub DownloadContent(ByVal Token As CancellationToken)
|
||||||
|
With Responser : .Mode = Response.Modes.WebClient : .ResetStatus() : End With
|
||||||
|
UseResponserClient = True
|
||||||
|
DownloadContentDefault(Token)
|
||||||
|
End Sub
|
||||||
|
Protected Overrides Function DownloadingException(ByVal ex As Exception, ByVal Message As String, Optional ByVal FromPE As Boolean = False,
|
||||||
|
Optional ByVal EObj As Object = Nothing) As Integer
|
||||||
|
If Responser.StatusCode = Net.HttpStatusCode.ServiceUnavailable Then
|
||||||
|
MyMainLOG = $"{ToStringForLog()}: LPSG not available"
|
||||||
|
Return 1
|
||||||
|
Else
|
||||||
|
Return 0
|
||||||
|
End If
|
||||||
|
End Function
|
||||||
|
End Class
|
||||||
|
End Namespace
|
||||||
44
SCrawler/API/PornHub/Declarations.vb
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
|
' 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
|
||||||
|
Namespace API.PornHub
|
||||||
|
Friend Module Declarations
|
||||||
|
#Region "Converters"
|
||||||
|
Private ReadOnly UnicodeHexConverter As Func(Of String, String) = Function(Input) SymbolsConverter.UnicodeHex.Decode(Input, EDP.ReturnValue)
|
||||||
|
Friend ReadOnly HtmlConverter As Func(Of String, String) = Function(Input) SymbolsConverter.HTML.Decode(Input, EDP.ReturnValue)
|
||||||
|
#End Region
|
||||||
|
#Region "Declarations video"
|
||||||
|
Friend ReadOnly RegexVideo_FlashVarsBlock As RParams = RParams.DM("(?<=flashvars_\['[nN]ext[vV]ideo'\];[\r\n]*?)(.+?)(?=;flashvars_\d+?)", 0, EDP.ReturnValue)
|
||||||
|
Friend ReadOnly RegexVideo_FlashVars_Vars As RParams = RParams.DM("var ([\w\d]{10,})=("".+?)(?=(;|\Z))", 0, RegexReturn.List)
|
||||||
|
Friend ReadOnly RegexVideo_FlashVars_Compiler As RParams = RParams.DM("(?<=\*/)([\w\d\S]{10,})", 0, RegexReturn.List)
|
||||||
|
Friend ReadOnly RegexVideo_Video_All As RParams = RParams.DM("div class=""thumbnail-info-wrapper clearfix.+?[\r\n\s]*?\<span class=""title.+?[\r\n\s]*?\<a href=""([^""]+?)""[\s]+?title=""([^""]*?)""",
|
||||||
|
0, RegexReturn.List, EDP.ReturnValue, UnicodeHexConverter)
|
||||||
|
Friend ReadOnly RegexVideo_Video_Wrong As RParams = RParams.DM("div class=""thumbnail-info-wrapper clearfix.+?[\r\n\s]*?\<span class=""title.+?[\r\n\s]*?\<a href=""([^""]+?)""[\s]+?title=""([^""]*?)""[\w\W\s\r\n]+?(?=\<div class=""videoUploaderBlock)",
|
||||||
|
0, RegexReturn.List, EDP.ReturnValue, UnicodeHexConverter)
|
||||||
|
Private ReadOnly RegexVideo_Video_Wrong_Option As RParams = RParams.DM("div class=""thumbnail-info-wrapper clearfix.+?[\r\n\s]*?\<span class=""title.+?[\r\n\s]*?\<a href=""([^""]+?)""[\s]+?title=""([^""]*?)""[\w\W\s\r\n]+?", 0, RegexReturn.ListByMatch)
|
||||||
|
Friend ReadOnly RegexVideo_Video_Wrong_Fields As RField() = {New RField(New RFieldOption(1, RegexVideo_Video_Wrong_Option)), New RField(New RFieldOption(2, RegexVideo_Video_Wrong_Option))}
|
||||||
|
Friend ReadOnly RegexVideo_Video_VideoKey As RParams = RParams.DMS("viewkey=([\w\d]+)", 1, EDP.ReturnValue)
|
||||||
|
#End Region
|
||||||
|
#Region "Declarations M3U8"
|
||||||
|
Friend ReadOnly Regex_M3U8_FirstFileRegEx As RParams = RParams.DM(".+?m3u8.*", 0)
|
||||||
|
Friend ReadOnly Regex_M3U8_FileUrl As RParams = RParams.DMS("((https://([^/]+)/.+?)([^/]+?m3u8))(.*)", 2, EDP.ReturnValue)
|
||||||
|
#End Region
|
||||||
|
#Region "Declarations GIF"
|
||||||
|
Friend ReadOnly Regex_Gif_Array As RParams = RParams.DM("\<li id=""(gif\d+)"" class=""gifLi.gifVideoBlock""\>", 0, RegexReturn.List, EDP.ReturnValue)
|
||||||
|
Friend ReadOnly Regex_Gif_UrlName As RParams = RParams.DMS("""name"":.*?""([^""]*)""[^\}]+?""contentUrl"":.*?""([^""]+)""", 0, RegexReturn.ListByMatch, EDP.ReturnValue)
|
||||||
|
#End Region
|
||||||
|
#Region "Declarations photo"
|
||||||
|
Friend ReadOnly Regex_Photo_ModelHub_PhotoBlocks As RParams = RParams.DM("var PHOTOS_ARRAY_(\d+) = \{[\r\n\s]*?(urls:.*?\[[^]]*\])", 0, RegexReturn.List, EDP.ReturnValue)
|
||||||
|
Friend ReadOnly Regex_Photo_PornHub_PhotoBlocks As RParams = RParams.DM("photoAlbumListContainer[\r\n\s\S]+?title=""([^""]+)""[\r\n\s\S]+?a href=""(/album/\d+)""", 0, RegexReturn.List)
|
||||||
|
Friend ReadOnly Regex_Photo_PornHub_AlbumPhotoArr As RParams = RParams.DMS("\<a href=""(/photo/\d+)""", 1, RegexReturn.List, EDP.ReturnValue,
|
||||||
|
CType(Function(Input$) If(Input.IsEmptyString, String.Empty, $"https://www.pornhub.com{Input.Trim}"), Func(Of String, String)))
|
||||||
|
Friend ReadOnly Regex_Photo_PornHub_SinglePhoto As RParams = RParams.DMS("(?<!thumbImage.+?)<img src=""(https://[^""]+\d+[^""]+)""", 1, EDP.ReturnValue)
|
||||||
|
#End Region
|
||||||
|
End Module
|
||||||
|
End Namespace
|
||||||
42
SCrawler/API/PornHub/M3U8.vb
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
|
' 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 SCrawler.API.Base
|
||||||
|
Imports SCrawler.API.Base.M3U8Declarations
|
||||||
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
|
Imports PersonalUtilities.Tools.Web.Clients
|
||||||
|
Namespace API.PornHub
|
||||||
|
Friend NotInheritable Class M3U8
|
||||||
|
Private Sub New()
|
||||||
|
End Sub
|
||||||
|
Private Shared Function GetUrlsList(ByVal URL As String, ByVal Responser As Response) As List(Of String)
|
||||||
|
Dim appender$ = RegexReplace(URL, Regex_M3U8_FileUrl)
|
||||||
|
Dim r$ = Responser.GetResponse(URL)
|
||||||
|
If Not r.IsEmptyString Then
|
||||||
|
Dim file$ = RegexReplace(r, Regex_M3U8_FirstFileRegEx)
|
||||||
|
If Not file.IsEmptyString Then
|
||||||
|
Dim NewUrl$ = M3U8Base.CreateUrl(appender, file)
|
||||||
|
If Not NewUrl.IsEmptyString Then
|
||||||
|
r = Responser.GetResponse(NewUrl)
|
||||||
|
If Not r.IsEmptyString Then
|
||||||
|
Dim l As List(Of String) = RegexReplace(r, TsFilesRegEx)
|
||||||
|
If l.ListExists Then
|
||||||
|
For i% = 0 To l.Count - 1 : l(i) = M3U8Base.CreateUrl(appender, l(i)) : Next
|
||||||
|
Return l
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Return Nothing
|
||||||
|
End Function
|
||||||
|
Friend Shared Function Download(ByVal URL As String, ByVal Responser As Response, ByVal Destination As SFile) As SFile
|
||||||
|
Return M3U8Base.Download(GetUrlsList(URL, Responser), Destination, Responser)
|
||||||
|
End Function
|
||||||
|
End Class
|
||||||
|
End Namespace
|
||||||
118
SCrawler/API/PornHub/OptionsForm.Designer.vb
generated
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
|
' 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.PornHub
|
||||||
|
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()>
|
||||||
|
Partial Friend Class OptionsForm : 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
|
||||||
|
Me.CH_DOWN_GIFS = New System.Windows.Forms.CheckBox()
|
||||||
|
Me.CH_DOWN_PHOTO_MODELHUB = New System.Windows.Forms.CheckBox()
|
||||||
|
CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer()
|
||||||
|
TP_MAIN = New System.Windows.Forms.TableLayoutPanel()
|
||||||
|
CONTAINER_MAIN.ContentPanel.SuspendLayout()
|
||||||
|
CONTAINER_MAIN.SuspendLayout()
|
||||||
|
TP_MAIN.SuspendLayout()
|
||||||
|
Me.SuspendLayout()
|
||||||
|
'
|
||||||
|
'CONTAINER_MAIN
|
||||||
|
'
|
||||||
|
'
|
||||||
|
'CONTAINER_MAIN.ContentPanel
|
||||||
|
'
|
||||||
|
CONTAINER_MAIN.ContentPanel.Controls.Add(TP_MAIN)
|
||||||
|
CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(278, 52)
|
||||||
|
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(278, 77)
|
||||||
|
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(Me.CH_DOWN_GIFS, 0, 0)
|
||||||
|
TP_MAIN.Controls.Add(Me.CH_DOWN_PHOTO_MODELHUB, 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, 25.0!))
|
||||||
|
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||||
|
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||||
|
TP_MAIN.Size = New System.Drawing.Size(278, 52)
|
||||||
|
TP_MAIN.TabIndex = 0
|
||||||
|
'
|
||||||
|
'CH_DOWN_GIFS
|
||||||
|
'
|
||||||
|
Me.CH_DOWN_GIFS.AutoSize = True
|
||||||
|
Me.CH_DOWN_GIFS.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.CH_DOWN_GIFS.Location = New System.Drawing.Point(4, 4)
|
||||||
|
Me.CH_DOWN_GIFS.Name = "CH_DOWN_GIFS"
|
||||||
|
Me.CH_DOWN_GIFS.Size = New System.Drawing.Size(270, 19)
|
||||||
|
Me.CH_DOWN_GIFS.TabIndex = 0
|
||||||
|
Me.CH_DOWN_GIFS.Text = "Download gifs"
|
||||||
|
Me.CH_DOWN_GIFS.UseVisualStyleBackColor = True
|
||||||
|
'
|
||||||
|
'CH_DOWN_PHOTO_MODELHUB
|
||||||
|
'
|
||||||
|
Me.CH_DOWN_PHOTO_MODELHUB.AutoSize = True
|
||||||
|
Me.CH_DOWN_PHOTO_MODELHUB.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.CH_DOWN_PHOTO_MODELHUB.Location = New System.Drawing.Point(4, 30)
|
||||||
|
Me.CH_DOWN_PHOTO_MODELHUB.Name = "CH_DOWN_PHOTO_MODELHUB"
|
||||||
|
Me.CH_DOWN_PHOTO_MODELHUB.Size = New System.Drawing.Size(270, 19)
|
||||||
|
Me.CH_DOWN_PHOTO_MODELHUB.TabIndex = 1
|
||||||
|
Me.CH_DOWN_PHOTO_MODELHUB.Text = "Download photo only from ModelHub"
|
||||||
|
Me.CH_DOWN_PHOTO_MODELHUB.UseVisualStyleBackColor = True
|
||||||
|
'
|
||||||
|
'OptionsForm
|
||||||
|
'
|
||||||
|
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
|
||||||
|
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
|
||||||
|
Me.ClientSize = New System.Drawing.Size(278, 77)
|
||||||
|
Me.Controls.Add(CONTAINER_MAIN)
|
||||||
|
Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle
|
||||||
|
Me.Icon = Global.SCrawler.My.Resources.SiteResources.InstagramIcon_32
|
||||||
|
Me.KeyPreview = True
|
||||||
|
Me.MaximizeBox = False
|
||||||
|
Me.MaximumSize = New System.Drawing.Size(294, 116)
|
||||||
|
Me.MinimizeBox = False
|
||||||
|
Me.MinimumSize = New System.Drawing.Size(294, 116)
|
||||||
|
Me.Name = "OptionsForm"
|
||||||
|
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_MAIN.PerformLayout()
|
||||||
|
Me.ResumeLayout(False)
|
||||||
|
|
||||||
|
End Sub
|
||||||
|
Private WithEvents CH_DOWN_GIFS As CheckBox
|
||||||
|
Private WithEvents CH_DOWN_PHOTO_MODELHUB As CheckBox
|
||||||
|
End Class
|
||||||
|
End Namespace
|
||||||
126
SCrawler/API/PornHub/OptionsForm.resx
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
<?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="TP_MAIN.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>False</value>
|
||||||
|
</metadata>
|
||||||
|
</root>
|
||||||
34
SCrawler/API/PornHub/OptionsForm.vb
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
|
' 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
|
||||||
|
Namespace API.PornHub
|
||||||
|
Friend Class OptionsForm
|
||||||
|
Private WithEvents MyDefs As DefaultFormOptions
|
||||||
|
Private ReadOnly MyExchangeOptions As UserExchangeOptions
|
||||||
|
Friend Sub New(ByRef ExchangeOptions As UserExchangeOptions)
|
||||||
|
InitializeComponent()
|
||||||
|
MyExchangeOptions = ExchangeOptions
|
||||||
|
MyDefs = New DefaultFormOptions(Me, Settings.Design)
|
||||||
|
End Sub
|
||||||
|
Private Sub MyForm_Load(sender As Object, e As EventArgs) Handles Me.Load
|
||||||
|
With MyDefs
|
||||||
|
.MyViewInitialize(True)
|
||||||
|
.AddOkCancelToolbar()
|
||||||
|
CH_DOWN_GIFS.Checked = MyExchangeOptions.DownloadGifs
|
||||||
|
CH_DOWN_PHOTO_MODELHUB.Checked = MyExchangeOptions.DownloadPhotoOnlyFromModelHub
|
||||||
|
.EndLoaderOperations()
|
||||||
|
End With
|
||||||
|
End Sub
|
||||||
|
Private Sub MyDefs_ButtonOkClick(ByVal Sender As Object, ByVal e As KeyHandleEventArgs) Handles MyDefs.ButtonOkClick
|
||||||
|
MyExchangeOptions.DownloadGifs = CH_DOWN_GIFS.Checked
|
||||||
|
MyExchangeOptions.DownloadPhotoOnlyFromModelHub = CH_DOWN_PHOTO_MODELHUB.Checked
|
||||||
|
MyDefs.CloseForm()
|
||||||
|
End Sub
|
||||||
|
End Class
|
||||||
|
End Namespace
|
||||||
123
SCrawler/API/PornHub/SiteSettings.vb
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
|
' 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 SCrawler.API.Base
|
||||||
|
Imports SCrawler.Plugin
|
||||||
|
Imports SCrawler.Plugin.Attributes
|
||||||
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
|
Imports PersonalUtilities.Tools.Web.Clients
|
||||||
|
Namespace API.PornHub
|
||||||
|
<Manifest("AndyProgram_PornHub"), SavedPosts, SpecialForm(False), SeparatedTasks(1)>
|
||||||
|
Friend Class SiteSettings : Inherits SiteSettingsBase
|
||||||
|
#Region "Declarations"
|
||||||
|
Friend Overrides ReadOnly Property Icon As Icon
|
||||||
|
Get
|
||||||
|
Return My.Resources.SiteResources.PornHubIcon_16
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
Friend Overrides ReadOnly Property Image As Image
|
||||||
|
Get
|
||||||
|
Return My.Resources.SiteResources.PornHubPic_16
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
Private ReadOnly Property CurlPathExists As Boolean
|
||||||
|
<PropertyOption(ControlText:="Download GIF", ControlToolTip:="Default for new users", ThreeStates:=True), PXML>
|
||||||
|
Friend ReadOnly Property DownloadGifs As PropertyValue
|
||||||
|
<PropertyOption(ControlText:="Download GIFs as mp4", ControlToolTip:="Download gifs in 'mp4' format instead of native 'webm'"), PXML>
|
||||||
|
Friend ReadOnly Property DownloadGifsAsMp4 As PropertyValue
|
||||||
|
<PropertyOption(ControlText:="Photo ModelHub only",
|
||||||
|
ControlToolTip:="Download photo only from ModelHub. Prornstar photos hosted on PornHub itself will not be downloaded." & vbCr &
|
||||||
|
"Attention! Downloading photos hosted on PornHub is a very heavy job."), PXML>
|
||||||
|
Friend ReadOnly Property DownloadPhotoOnlyFromModelHub As PropertyValue
|
||||||
|
<PropertyOption(ControlText:="Saved posts user", ControlToolTip:="Personal profile username"), PXML>
|
||||||
|
Friend ReadOnly Property SavedPostsUserName As PropertyValue
|
||||||
|
#End Region
|
||||||
|
#Region "Initializer"
|
||||||
|
Friend Sub New()
|
||||||
|
MyBase.New("PornHub", "pornhub.com")
|
||||||
|
Responser.CurlPath = $"cURL\curl.exe"
|
||||||
|
CurlPathExists = Responser.CurlPath.Exists
|
||||||
|
Responser.DeclaredError = EDP.ThrowException
|
||||||
|
|
||||||
|
DownloadGifsAsMp4 = New PropertyValue(True)
|
||||||
|
DownloadGifs = New PropertyValue(CInt(CheckState.Indeterminate), GetType(Integer))
|
||||||
|
DownloadPhotoOnlyFromModelHub = New PropertyValue(True)
|
||||||
|
SavedPostsUserName = New PropertyValue(String.Empty, GetType(String))
|
||||||
|
|
||||||
|
UrlPatternUser = "https://www.pornhub.com/{0}/{1}"
|
||||||
|
UserRegex = RParams.DMS("pornhub.com/([^/]+)/([^/]+).*?", 0, RegexReturn.ListByMatch)
|
||||||
|
ImageVideoContains = "pornhub"
|
||||||
|
End Sub
|
||||||
|
#End Region
|
||||||
|
#Region "GetInstance, GetSpecialData"
|
||||||
|
Friend Overrides Function GetInstance(ByVal What As ISiteSettings.Download) As IPluginContentProvider
|
||||||
|
If What = ISiteSettings.Download.SavedPosts Then
|
||||||
|
Return New UserData With {
|
||||||
|
.IsSavedPosts = True,
|
||||||
|
.VideoPageModel = UserData.VideoPageModels.Favorite,
|
||||||
|
.PersonType = UserData.PersonTypeUser,
|
||||||
|
.User = New UserInfo With {.Name = $"{UserData.PersonTypeUser}_{CStr(AConvert(Of String)(SavedPostsUserName.Value, String.Empty))}"}
|
||||||
|
}
|
||||||
|
Else
|
||||||
|
Return New UserData
|
||||||
|
End If
|
||||||
|
End Function
|
||||||
|
Friend Overrides Function GetSpecialData(ByVal URL As String, ByVal Path As String, ByVal AskForPath As Boolean) As IEnumerable
|
||||||
|
If Available(ISiteSettings.Download.Main, True) Then
|
||||||
|
Using resp As Response = Responser.Copy
|
||||||
|
Dim spf$ = String.Empty
|
||||||
|
Dim f As SFile = GetSpecialDataFile(Path, AskForPath, spf)
|
||||||
|
Dim m As UserMedia = UserData.GetVideoInfo(URL, resp, f)
|
||||||
|
If m.State = UserMedia.States.Downloaded Then
|
||||||
|
m.SpecialFolder = f
|
||||||
|
Return {m}
|
||||||
|
End If
|
||||||
|
End Using
|
||||||
|
End If
|
||||||
|
Return Nothing
|
||||||
|
End Function
|
||||||
|
#End Region
|
||||||
|
#Region "Downloading"
|
||||||
|
Friend Overrides Function Available(ByVal What As ISiteSettings.Download, ByVal Silent As Boolean) As Boolean
|
||||||
|
Return Settings.UseM3U8 And CurlPathExists And (Not What = ISiteSettings.Download.SavedPosts OrElse ACheck(SavedPostsUserName.Value))
|
||||||
|
End Function
|
||||||
|
#End Region
|
||||||
|
#Region "IsMyUser"
|
||||||
|
Friend Overrides Function IsMyUser(ByVal UserURL As String) As ExchangeOptions
|
||||||
|
Try
|
||||||
|
If Not UserURL.IsEmptyString Then
|
||||||
|
Dim alist As List(Of String) = RegexReplace(UserURL.ToLower, UserRegex)
|
||||||
|
If alist.ListExists(3) Then Return New ExchangeOptions(Site, $"{alist(1)}_{alist(2)}")
|
||||||
|
End If
|
||||||
|
Return Nothing
|
||||||
|
Catch ex As Exception
|
||||||
|
Return ErrorsDescriber.Execute(EDP.SendInLog + EDP.ReturnValue, ex, $"[API.PornHub.SiteSettings.IsMyUser({UserURL})]", New ExchangeOptions)
|
||||||
|
End Try
|
||||||
|
End Function
|
||||||
|
#End Region
|
||||||
|
#Region "GetUserUrl, GetUserPostUrl"
|
||||||
|
Friend Overrides Function GetUserUrl(ByVal User As IPluginContentProvider, ByVal Channel As Boolean) As String
|
||||||
|
With DirectCast(User, UserData) : Return String.Format(UrlPatternUser, .PersonType, .NameTrue) : End With
|
||||||
|
End Function
|
||||||
|
Friend Overrides Function GetUserPostUrl(ByVal User As UserDataBase, ByVal Media As UserMedia) As String
|
||||||
|
'TODELETE: remove comment
|
||||||
|
Return Media.URL_BASE '$"https://www.pornhub.com/view_video.php?viewkey={Media.Post.ID}"
|
||||||
|
End Function
|
||||||
|
#End Region
|
||||||
|
#Region "User options"
|
||||||
|
Friend Overrides Sub UserOptions(ByRef Options As Object, ByVal OpenForm As Boolean)
|
||||||
|
Dim e As UserExchangeOptions = Nothing
|
||||||
|
If Not Options Is Nothing AndAlso TypeOf Options Is UserExchangeOptions Then e = Options
|
||||||
|
If e Is Nothing Then e = New UserExchangeOptions(Me)
|
||||||
|
If OpenForm Then
|
||||||
|
Using f As New OptionsForm(e) : f.ShowDialog() : End Using
|
||||||
|
End If
|
||||||
|
End Sub
|
||||||
|
#End Region
|
||||||
|
End Class
|
||||||
|
End Namespace
|
||||||
656
SCrawler/API/PornHub/UserData.vb
Normal file
@@ -0,0 +1,656 @@
|
|||||||
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
|
' 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 SCrawler.API.Base
|
||||||
|
Imports PersonalUtilities.Functions.XML
|
||||||
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
|
Imports PersonalUtilities.Tools.Web.Clients
|
||||||
|
Imports PersonalUtilities.Tools.Web.Documents.JSON
|
||||||
|
Imports UTypes = SCrawler.API.Base.UserMedia.Types
|
||||||
|
Namespace API.PornHub
|
||||||
|
Friend Class UserData : Inherits UserDataBase
|
||||||
|
Private Const UrlPattern As String = "https://www.pornhub.com/{0}"
|
||||||
|
#Region "Declarations"
|
||||||
|
#Region "XML names"
|
||||||
|
Private Const Name_PersonType As String = "PersonType"
|
||||||
|
Private Const Name_NameTrue As String = "NameTrue"
|
||||||
|
Private Const Name_VideoPageModel As String = "VideoPageModel"
|
||||||
|
Private Const Name_PhotoPageModel As String = "PhotoPageModel"
|
||||||
|
Private Const Name_DownloadGifs As String = "DownloadGifs"
|
||||||
|
Private Const Name_DownloadPhotoOnlyFromModelHub As String = "DownloadPhotoOnlyFromModelHub"
|
||||||
|
#End Region
|
||||||
|
#Region "Structures"
|
||||||
|
Private Structure FlashVar : Implements IRegExCreator
|
||||||
|
Friend Name As String
|
||||||
|
Friend Value As String
|
||||||
|
Public Shared Widening Operator CType(ByVal Name As String) As FlashVar
|
||||||
|
Return New FlashVar With {.Name = Name}
|
||||||
|
End Operator
|
||||||
|
Private Function CreateFromArray(ByVal ParamsArray() As String) As Object Implements IRegExCreator.CreateFromArray
|
||||||
|
If ParamsArray.ListExists(2) Then
|
||||||
|
Name = ParamsArray(0)
|
||||||
|
Value = ParamsArray(1)
|
||||||
|
If Not Value.IsEmptyString Then Value = Value.Replace(""" + """, String.Empty).Replace("""", String.Empty).StringTrim
|
||||||
|
End If
|
||||||
|
Return Me
|
||||||
|
End Function
|
||||||
|
Public Overrides Function Equals(ByVal Obj As Object) As Boolean
|
||||||
|
Return CType(Obj, FlashVar).Name = Name
|
||||||
|
End Function
|
||||||
|
End Structure
|
||||||
|
Private Structure UserVideo : Implements IRegExCreator
|
||||||
|
Friend URL As String
|
||||||
|
Friend ID As String
|
||||||
|
Friend Title As String
|
||||||
|
Friend Function ToUserMedia() As UserMedia
|
||||||
|
Return New UserMedia(URL, UTypes.VideoPre) With {
|
||||||
|
.File = If(Title.IsEmptyString, .File, New SFile($"{Title}.mp4")),
|
||||||
|
.Post = ID
|
||||||
|
}
|
||||||
|
End Function
|
||||||
|
Private Function CreateFromArray(ByVal ParamsArray() As String) As Object Implements IRegExCreator.CreateFromArray
|
||||||
|
If ParamsArray.ListExists Then
|
||||||
|
URL = ParamsArray(0)
|
||||||
|
ID = RegexReplace(URL, RegexVideo_Video_VideoKey)
|
||||||
|
URL = String.Format(UrlPattern, URL.TrimStart("/"))
|
||||||
|
Title = HtmlConverter(ParamsArray(1)).StringRemoveWinForbiddenSymbols.StringTrim
|
||||||
|
End If
|
||||||
|
Return Me
|
||||||
|
End Function
|
||||||
|
Public Overrides Function Equals(ByVal Obj As Object) As Boolean
|
||||||
|
Return DirectCast(Obj, UserVideo).URL = URL
|
||||||
|
End Function
|
||||||
|
End Structure
|
||||||
|
Private Structure PhotoBlock : Implements IRegExCreator
|
||||||
|
Friend AlbumID As String
|
||||||
|
Friend Data As String
|
||||||
|
Private Function CreateFromArray(ByVal ParamsArray() As String) As Object Implements IRegExCreator.CreateFromArray
|
||||||
|
If ParamsArray.ListExists(2) Then
|
||||||
|
AlbumID = ParamsArray(0)
|
||||||
|
Data = ParamsArray(1).StringTrim
|
||||||
|
End If
|
||||||
|
Return Me
|
||||||
|
End Function
|
||||||
|
End Structure
|
||||||
|
#End Region
|
||||||
|
#Region "Enums"
|
||||||
|
Friend Enum VideoPageModels As Integer
|
||||||
|
[Default] = 0
|
||||||
|
ConcatPage = 1
|
||||||
|
Favorite = 2
|
||||||
|
Undefined = -1
|
||||||
|
End Enum
|
||||||
|
Private Enum PhotoPageModels As Integer
|
||||||
|
Undefined = 0
|
||||||
|
PornHubPage = 1
|
||||||
|
ModelHubPage = 2
|
||||||
|
End Enum
|
||||||
|
#End Region
|
||||||
|
#Region "Constants"
|
||||||
|
Private Const PersonTypeModel As String = "model"
|
||||||
|
Friend Const PersonTypeUser As String = "users"
|
||||||
|
#End Region
|
||||||
|
#Region "Person"
|
||||||
|
Friend Property PersonType As String
|
||||||
|
Friend Property NameTrue As String
|
||||||
|
Private _FriendlyName As String = String.Empty
|
||||||
|
Friend Overrides Property FriendlyName As String
|
||||||
|
Get
|
||||||
|
If _FriendlyName.IsEmptyString Then Return NameTrue Else Return _FriendlyName
|
||||||
|
End Get
|
||||||
|
Set(ByVal n As String)
|
||||||
|
_FriendlyName = n
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
#End Region
|
||||||
|
#Region "Advanced fields"
|
||||||
|
Friend Property VideoPageModel As VideoPageModels = VideoPageModels.Undefined
|
||||||
|
Private Property PhotoPageModel As PhotoPageModels = PhotoPageModels.Undefined
|
||||||
|
Friend Property DownloadGifs As Boolean
|
||||||
|
Friend Property DownloadPhotoOnlyFromModelHub As Boolean = True
|
||||||
|
#End Region
|
||||||
|
#Region "ExchangeOptions"
|
||||||
|
Friend Overrides Function ExchangeOptionsGet() As Object
|
||||||
|
Return New UserExchangeOptions(Me)
|
||||||
|
End Function
|
||||||
|
Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object)
|
||||||
|
If Not Obj Is Nothing AndAlso TypeOf Obj Is UserExchangeOptions Then
|
||||||
|
With DirectCast(Obj, UserExchangeOptions)
|
||||||
|
DownloadGifs = .DownloadGifs
|
||||||
|
DownloadPhotoOnlyFromModelHub = .DownloadPhotoOnlyFromModelHub
|
||||||
|
End With
|
||||||
|
End If
|
||||||
|
End Sub
|
||||||
|
#End Region
|
||||||
|
Private ReadOnly Property MySettings As SiteSettings
|
||||||
|
Get
|
||||||
|
Return DirectCast(HOST.Source, SiteSettings)
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
#End Region
|
||||||
|
#Region "Initializer, loader"
|
||||||
|
Friend Sub New()
|
||||||
|
UseInternalM3U8Function = True
|
||||||
|
End Sub
|
||||||
|
Protected Overrides Sub LoadUserInformation_OptionalFields(ByRef Container As XmlFile, ByVal Loading As Boolean)
|
||||||
|
With Container
|
||||||
|
Dim SetNames As Action = Sub()
|
||||||
|
If Not Name.IsEmptyString And NameTrue.IsEmptyString Then
|
||||||
|
Dim n$() = Name.Split("_")
|
||||||
|
If n.ListExists(2) Then
|
||||||
|
NameTrue = Name.Replace($"{n(0)}_", String.Empty)
|
||||||
|
PersonType = n(0)
|
||||||
|
If (PersonType = PersonTypeModel Or PersonType = PersonTypeUser) And
|
||||||
|
VideoPageModel = VideoPageModels.Undefined Then VideoPageModel = VideoPageModels.Default
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
End Sub
|
||||||
|
If Loading Then
|
||||||
|
PersonType = .Value(Name_PersonType)
|
||||||
|
NameTrue = .Value(Name_NameTrue)
|
||||||
|
VideoPageModel = .Value(Name_VideoPageModel).FromXML(Of Integer)(VideoPageModels.Undefined)
|
||||||
|
PhotoPageModel = .Value(Name_PhotoPageModel).FromXML(Of Integer)(PhotoPageModels.Undefined)
|
||||||
|
DownloadGifs = .Value(Name_DownloadGifs).FromXML(Of Integer)(False)
|
||||||
|
DownloadPhotoOnlyFromModelHub = .Value(Name_DownloadPhotoOnlyFromModelHub).FromXML(Of Boolean)(True)
|
||||||
|
SetNames.Invoke()
|
||||||
|
Else
|
||||||
|
SetNames.Invoke()
|
||||||
|
.Add(Name_PersonType, PersonType)
|
||||||
|
.Add(Name_NameTrue, NameTrue)
|
||||||
|
.Add(Name_VideoPageModel, CInt(VideoPageModel))
|
||||||
|
.Add(Name_PhotoPageModel, CInt(PhotoPageModel))
|
||||||
|
.Add(Name_DownloadGifs, DownloadGifs.BoolToInteger)
|
||||||
|
.Add(Name_DownloadPhotoOnlyFromModelHub, DownloadPhotoOnlyFromModelHub.BoolToInteger)
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
End Sub
|
||||||
|
#End Region
|
||||||
|
#Region "Downloading"
|
||||||
|
#Region "Download override"
|
||||||
|
Private Const DataDownloaded As Integer = -10
|
||||||
|
Private Const DataDownloaded_NotFound As Integer = -20
|
||||||
|
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
|
||||||
|
Try
|
||||||
|
Responser.ResetStatus()
|
||||||
|
If PersonType = PersonTypeUser Then Responser.Mode = Response.Modes.Curl
|
||||||
|
|
||||||
|
If IsSavedPosts Then VideoPageModel = VideoPageModels.Favorite
|
||||||
|
|
||||||
|
Dim page% = 1
|
||||||
|
Dim __continue As Boolean = True
|
||||||
|
Dim __videoDone As Boolean = False
|
||||||
|
Dim d%
|
||||||
|
If DownloadVideos Then
|
||||||
|
If PersonType = PersonTypeUser Then Responser.Mode = Response.Modes.Curl : Responser.Method = "POST"
|
||||||
|
If VideoPageModel = VideoPageModels.Undefined Then
|
||||||
|
__continue = False
|
||||||
|
d = DownloadUserVideos(page, Token)
|
||||||
|
Select Case d
|
||||||
|
Case DataDownloaded : __continue = True : page += 1
|
||||||
|
Case 1 : VideoPageModel = VideoPageModels.ConcatPage
|
||||||
|
Case EXCEPTION_OPERATION_CANCELED : ThrowAny(Token)
|
||||||
|
Case DataDownloaded_NotFound : __videoDone = True
|
||||||
|
End Select
|
||||||
|
If Not __continue And Not __videoDone Then
|
||||||
|
d = DownloadUserVideos(page, Token)
|
||||||
|
Select Case d
|
||||||
|
Case DataDownloaded : __continue = True : page += 1
|
||||||
|
Case 1 : VideoPageModel = VideoPageModels.Undefined
|
||||||
|
Case EXCEPTION_OPERATION_CANCELED : ThrowAny(Token)
|
||||||
|
Case DataDownloaded_NotFound : __videoDone = True
|
||||||
|
End Select
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
If __continue And Not __videoDone Then
|
||||||
|
Do While DownloadUserVideos(page, Token) = DataDownloaded And page < 100 : page += 1 : Loop
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
|
||||||
|
Responser.Method = "GET"
|
||||||
|
If DownloadGifs And Not IsSavedPosts Then DownloadUserGifs(Token)
|
||||||
|
If DownloadImages Then DownloadUserPhotos(Token)
|
||||||
|
Finally
|
||||||
|
Responser.Mode = Response.Modes.Default
|
||||||
|
Responser.Method = "GET"
|
||||||
|
End Try
|
||||||
|
End Sub
|
||||||
|
#End Region
|
||||||
|
#Region "Download video"
|
||||||
|
Private ReadOnly Property VideoPageType As String
|
||||||
|
Get
|
||||||
|
Select Case VideoPageModel
|
||||||
|
Case VideoPageModels.Default : Return "/videos/upload"
|
||||||
|
Case VideoPageModels.Favorite : Return "/videos/favorites/"
|
||||||
|
Case Else : Return String.Empty
|
||||||
|
End Select
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
Private ReadOnly Property VideoPageAppender As String
|
||||||
|
Get
|
||||||
|
Return If(PersonType = PersonTypeUser, "ajax?o=newest&page=", String.Empty)
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
Private Overloads Function DownloadUserVideos(ByVal Page As Integer, ByVal Token As CancellationToken) As Integer
|
||||||
|
Const VideoUrlPattern$ = "https://www.pornhub.com/{0}/{1}{2}{3}"
|
||||||
|
Const HtmlPageNotFoundVideo$ = "<span>Error Page Not Found</span>"
|
||||||
|
Dim URL$ = String.Empty
|
||||||
|
Try
|
||||||
|
Dim p$
|
||||||
|
If PersonType = PersonTypeUser Then
|
||||||
|
p = Page
|
||||||
|
Else
|
||||||
|
p = IIf(Page = 1, String.Empty, $"?page={Page}")
|
||||||
|
End If
|
||||||
|
|
||||||
|
URL = $"{String.Format(VideoUrlPattern, PersonType, NameTrue, VideoPageType, VideoPageAppender)}{p}"
|
||||||
|
ThrowAny(Token)
|
||||||
|
|
||||||
|
Dim r$ = Responser.GetResponse(URL)
|
||||||
|
If Not r.IsEmptyString Then
|
||||||
|
If PersonType = PersonTypeUser And r.Contains(HtmlPageNotFoundVideo) Then Return DataDownloaded_NotFound
|
||||||
|
Dim l As List(Of UserVideo) = RegexFields(Of UserVideo)(r, {RegexVideo_Video_All}, {1, 2})
|
||||||
|
Dim lw As List(Of UserVideo) = Nothing
|
||||||
|
If Not PersonType = PersonTypeUser Then RegexFields(Of UserVideo)(r, {RegexVideo_Video_Wrong}, RegexVideo_Video_Wrong_Fields)
|
||||||
|
If l.ListExists Then
|
||||||
|
If lw.ListExists Then l.ListWithRemove(lw)
|
||||||
|
If l.Count > 0 Then
|
||||||
|
Dim lBefore% = l.Count
|
||||||
|
l.RemoveAll(Function(ByVal uv As UserVideo) As Boolean
|
||||||
|
If Not _TempPostsList.Contains(uv.ID) Then
|
||||||
|
_TempPostsList.Add(uv.ID)
|
||||||
|
Return False
|
||||||
|
Else
|
||||||
|
Return True
|
||||||
|
End If
|
||||||
|
End Function)
|
||||||
|
If l.Count > 0 Then _TempMediaList.ListAddList(l.Select(Function(uv) uv.ToUserMedia))
|
||||||
|
If l.Count = lBefore And l.Count > 0 Then Return DataDownloaded
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Return DataDownloaded_NotFound
|
||||||
|
Catch regex_ex As RegexFieldsTextBecameNullException
|
||||||
|
If PersonType = PersonTypeUser Or IsSavedPosts Then
|
||||||
|
Return DataDownloaded_NotFound
|
||||||
|
Else
|
||||||
|
Return ProcessException(regex_ex, Token, $"videos downloading error [{URL}]")
|
||||||
|
End If
|
||||||
|
Catch ex As Exception
|
||||||
|
Return ProcessException(ex, Token, $"videos downloading error [{URL}]")
|
||||||
|
End Try
|
||||||
|
End Function
|
||||||
|
#End Region
|
||||||
|
#Region "Download GIF"
|
||||||
|
Private Sub DownloadUserGifs(ByVal Token As CancellationToken)
|
||||||
|
Dim URL$ = $"https://www.pornhub.com/{PersonType}/{NameTrue}/gifs"
|
||||||
|
Try
|
||||||
|
ThrowAny(Token)
|
||||||
|
Dim r$ = Responser.GetResponse(URL)
|
||||||
|
If Not r.IsEmptyString Then
|
||||||
|
Dim n$
|
||||||
|
Dim m As UserMedia = Nothing
|
||||||
|
Dim l As List(Of RegexMatchStruct) = RegexFields(Of RegexMatchStruct)(r, {Regex_Gif_Array}, {1})
|
||||||
|
Dim l2 As List(Of String) = Nothing
|
||||||
|
Dim l3 As List(Of String) = Nothing
|
||||||
|
If l.ListExists Then l2 = l.Select(Function(ll) $"gif/{ll.Arr(0).Replace("gif", String.Empty)}").ToList
|
||||||
|
If l2.ListExists Then
|
||||||
|
For Each gif$ In l2
|
||||||
|
If Not _TempPostsList.Contains(gif) Then
|
||||||
|
_TempPostsList.Add(gif)
|
||||||
|
URL = $"https://www.pornhub.com/{gif}"
|
||||||
|
m = New UserMedia(URL, UTypes.Video) With {.Post = gif, .SpecialFolder = "GIFs\"}
|
||||||
|
ThrowAny(Token)
|
||||||
|
Try
|
||||||
|
r = Responser.GetResponse(URL)
|
||||||
|
If Not r.IsEmptyString Then
|
||||||
|
If l3.ListExists Then l3.Clear() : l3 = Nothing
|
||||||
|
l3 = RegexReplace(r, Regex_Gif_UrlName)
|
||||||
|
If l3.ListExists(3) Then
|
||||||
|
m.URL = l3(2)
|
||||||
|
m.File = m.URL
|
||||||
|
n = HtmlConverter(l3(1)).StringRemoveWinForbiddenSymbols.StringTrim
|
||||||
|
If MySettings.DownloadGifsAsMp4.Value Then m.File.Extension = "mp4"
|
||||||
|
If Not n.IsEmptyString Then m.File.Name = n
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Catch gif_down_ex As Exception
|
||||||
|
m.State = UserMedia.States.Missing
|
||||||
|
End Try
|
||||||
|
_TempMediaList.ListAddValue(m)
|
||||||
|
End If
|
||||||
|
Next
|
||||||
|
End If
|
||||||
|
If l.ListExists Then l.Clear()
|
||||||
|
If l2.ListExists Then l2.Clear()
|
||||||
|
If l3.ListExists Then l3.Clear()
|
||||||
|
End If
|
||||||
|
Catch ex As Exception
|
||||||
|
ProcessException(ex, Token, $"gifs downloading error [{URL}]")
|
||||||
|
End Try
|
||||||
|
End Sub
|
||||||
|
#End Region
|
||||||
|
#Region "Download photo"
|
||||||
|
Private Const PhotoUrlPattern_ModelHub As String = "https://www.modelhub.com/{0}/photos"
|
||||||
|
Private Const PhotoUrlPattern_PornHub As String = "https://www.pornhub.com/{0}/{1}/photos"
|
||||||
|
Private Sub DownloadUserPhotos(ByVal Token As CancellationToken)
|
||||||
|
Try
|
||||||
|
If IsSavedPosts Then
|
||||||
|
DownloadUserPhotos_SavedPosts(Token)
|
||||||
|
ElseIf PersonType = PersonTypeModel Then
|
||||||
|
If PhotoPageModel = PhotoPageModels.Undefined Then
|
||||||
|
If DownloadUserPhotos_ModelHub(Token) Then PhotoPageModel = PhotoPageModels.ModelHubPage
|
||||||
|
ThrowAny(Token)
|
||||||
|
If PhotoPageModel = PhotoPageModels.Undefined AndAlso DownloadPhotoOnlyFromModelHub AndAlso
|
||||||
|
DownloadUserPhotos_PornHub(Token) Then PhotoPageModel = PhotoPageModels.PornHubPage
|
||||||
|
Else
|
||||||
|
Select Case PhotoPageModel
|
||||||
|
Case PhotoPageModels.ModelHubPage : DownloadUserPhotos_ModelHub(Token)
|
||||||
|
Case PhotoPageModels.PornHubPage : If DownloadPhotoOnlyFromModelHub Then DownloadUserPhotos_PornHub(Token)
|
||||||
|
End Select
|
||||||
|
End If
|
||||||
|
ElseIf Not DownloadPhotoOnlyFromModelHub Then
|
||||||
|
DownloadUserPhotos_PornHub(Token)
|
||||||
|
End If
|
||||||
|
ThrowAny(Token)
|
||||||
|
Catch ex As Exception
|
||||||
|
ProcessException(ex, Token, $"photos downloading error")
|
||||||
|
End Try
|
||||||
|
End Sub
|
||||||
|
Private Function DownloadUserPhotos_ModelHub(ByVal Token As CancellationToken) As Boolean
|
||||||
|
Dim URL$ = String.Empty
|
||||||
|
Try
|
||||||
|
Dim jErr As New ErrorsDescriber(EDP.SendInLog + EDP.ReturnValue)
|
||||||
|
Dim albumName$
|
||||||
|
If PersonType = PersonTypeModel Then
|
||||||
|
URL = String.Format(PhotoUrlPattern_ModelHub, NameTrue)
|
||||||
|
Dim r$ = Responser.GetResponse(URL)
|
||||||
|
If Not r.IsEmptyString Then
|
||||||
|
Dim l As List(Of PhotoBlock) = RegexFields(Of PhotoBlock)(r, {Regex_Photo_ModelHub_PhotoBlocks}, {1, 2})
|
||||||
|
If l.ListExists Then l.RemoveAll(Function(ll) ll.Data.IsEmptyString)
|
||||||
|
If l.ListExists Then
|
||||||
|
Dim albumRegex As RParams = RParams.DMS("", 1, EDP.ReturnValue)
|
||||||
|
For Each block As PhotoBlock In l
|
||||||
|
If Not _TempPostsList.Contains(block.AlbumID) Then _TempPostsList.Add(block.AlbumID) Else Continue For
|
||||||
|
albumRegex.Pattern = "<li id=""" & block.AlbumID & """ class=""modelBox"">[\r\n\s]*?<div class=""modelPhoto"">[\r\n\s]*?\<[^\>]*?alt=""([^""]*)"""
|
||||||
|
albumName = StringTrim(RegexReplace(r, albumRegex))
|
||||||
|
If albumName.IsEmptyString Then albumName = block.AlbumID
|
||||||
|
Using j As EContainer = JsonDocument.Parse("{" & block.Data & "}", jErr)
|
||||||
|
If Not j Is Nothing Then
|
||||||
|
If If(j("urls")?.Count, 0) > 0 Then
|
||||||
|
_TempMediaList.ListAddList(j("urls").Select(Function(jj) _
|
||||||
|
New UserMedia(jj.ItemF({0}).XmlIfNothingValue, UTypes.Picture) With {
|
||||||
|
.SpecialFolder = $"Albums\{albumName}\"}), LNC)
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
End Using
|
||||||
|
Next
|
||||||
|
l.Clear()
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Return True
|
||||||
|
Catch ex As Exception
|
||||||
|
ThrowAny(Token)
|
||||||
|
Return False
|
||||||
|
End Try
|
||||||
|
End Function
|
||||||
|
Private Overloads Function DownloadUserPhotos_PornHub(ByVal Token As CancellationToken) As Boolean
|
||||||
|
Try
|
||||||
|
Dim albumName$
|
||||||
|
Dim page%
|
||||||
|
Dim r$ = Responser.GetResponse(String.Format(PhotoUrlPattern_PornHub, PersonType, NameTrue))
|
||||||
|
If Not r.IsEmptyString Then
|
||||||
|
Dim l As List(Of PhotoBlock) = RegexFields(Of PhotoBlock)(r, {Regex_Photo_PornHub_PhotoBlocks}, {2, 1})
|
||||||
|
If l.ListExists Then l.RemoveAll(Function(ll) ll.AlbumID.IsEmptyString)
|
||||||
|
If l.ListExists Then
|
||||||
|
For Each block As PhotoBlock In l
|
||||||
|
If Not _TempPostsList.Contains(block.AlbumID) Then _TempPostsList.Add(block.AlbumID) Else Continue For
|
||||||
|
albumName = block.Data
|
||||||
|
If albumName.IsEmptyString Then
|
||||||
|
albumName = block.AlbumID.Split("/").LastOrDefault.StringTrim
|
||||||
|
Else
|
||||||
|
albumName = HtmlConverter(albumName).StringRemoveWinForbiddenSymbols.StringTrim
|
||||||
|
End If
|
||||||
|
page = 1
|
||||||
|
Do While DownloadUserPhotos_PornHub(page, block.AlbumID, albumName, Token) : page += 1 : Loop
|
||||||
|
Next
|
||||||
|
l.Clear()
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Return True
|
||||||
|
Catch ex As Exception
|
||||||
|
ThrowAny(Token)
|
||||||
|
Return False
|
||||||
|
End Try
|
||||||
|
End Function
|
||||||
|
Private Overloads Function DownloadUserPhotos_PornHub(ByVal Page As Integer, ByVal AlbumID As String, ByVal AlbumName As String,
|
||||||
|
ByVal Token As CancellationToken) As Boolean
|
||||||
|
Try
|
||||||
|
Dim r$ = Responser.GetResponse($"https://www.pornhub.com{AlbumID}{IIf(Page = 1, String.Empty, $"?page={Page}")}")
|
||||||
|
If Not r.IsEmptyString Then
|
||||||
|
Dim l As List(Of String) = RegexReplace(r, Regex_Photo_PornHub_AlbumPhotoArr)
|
||||||
|
If l.ListExists Then l.RemoveAll(Function(_url) _url.IsEmptyString)
|
||||||
|
If l.ListExists Then
|
||||||
|
For Each url$ In l
|
||||||
|
ThrowAny(Token)
|
||||||
|
Try
|
||||||
|
r = Responser.GetResponse(url)
|
||||||
|
If Not r.IsEmptyString Then
|
||||||
|
url = RegexReplace(r, Regex_Photo_PornHub_SinglePhoto)
|
||||||
|
If Not url.IsEmptyString Then _
|
||||||
|
_TempMediaList.ListAddValue(New UserMedia(url, UTypes.Picture) With {.SpecialFolder = $"Albums\{AlbumName}\"}, LNC)
|
||||||
|
End If
|
||||||
|
Catch
|
||||||
|
End Try
|
||||||
|
Next
|
||||||
|
l.Clear()
|
||||||
|
Return True
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Return False
|
||||||
|
Catch ex As Exception
|
||||||
|
ThrowAny(Token)
|
||||||
|
Return False
|
||||||
|
End Try
|
||||||
|
End Function
|
||||||
|
Private Function DownloadUserPhotos_SavedPosts(ByVal Token As CancellationToken) As Boolean
|
||||||
|
Const HtmlPageNotFoundPhoto$ = "Page Not Found"
|
||||||
|
Dim URL$ = $"https://www.pornhub.com/{PersonType}/{NameTrue}/photos/favorites"
|
||||||
|
Try
|
||||||
|
Dim r$ = Responser.GetResponse(URL)
|
||||||
|
If Not r.IsEmptyString Then
|
||||||
|
If r.Contains(HtmlPageNotFoundPhoto) Then Return False
|
||||||
|
Dim urls As List(Of String) = RegexReplace(r, Regex_Photo_PornHub_AlbumPhotoArr)
|
||||||
|
If urls.ListExists Then
|
||||||
|
Dim NewUrl$
|
||||||
|
Dim m As UserMedia
|
||||||
|
Dim l2 As List(Of UserMedia) = urls.Select(Function(__url) New UserMedia(__url, UTypes.Picture) With {
|
||||||
|
.Post = __url.Split("/").LastOrDefault}).ToList
|
||||||
|
urls.Clear()
|
||||||
|
If l2.ListExists Then l2.RemoveAll(Function(media) media.URL.IsEmptyString)
|
||||||
|
If l2.ListExists Then
|
||||||
|
Dim lBefore% = l2.Count
|
||||||
|
If _TempPostsList.Count > 0 Then l2.RemoveAll(Function(media) _TempPostsList.Contains(media.Post.ID))
|
||||||
|
If l2.Count > 0 Then
|
||||||
|
For i% = 0 To l2.Count - 1
|
||||||
|
m = l2(i)
|
||||||
|
ThrowAny(Token)
|
||||||
|
Try
|
||||||
|
r = Responser.GetResponse(m.URL)
|
||||||
|
If Not r.IsEmptyString Then
|
||||||
|
NewUrl = RegexReplace(r, Regex_Photo_PornHub_SinglePhoto)
|
||||||
|
If Not NewUrl.IsEmptyString Then
|
||||||
|
m.URL = NewUrl
|
||||||
|
m.File = NewUrl
|
||||||
|
_TempPostsList.ListAddValue(m.Post.ID, LNC)
|
||||||
|
Else
|
||||||
|
Throw New Exception
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Catch
|
||||||
|
m.State = UserMedia.States.Missing
|
||||||
|
End Try
|
||||||
|
_TempMediaList.ListAddValue(m, LNC)
|
||||||
|
Next
|
||||||
|
End If
|
||||||
|
Return l2.Count = lBefore
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Return False
|
||||||
|
Catch ex As Exception
|
||||||
|
Return ProcessException(ex, Token, $"photos downloading error [{URL}]")
|
||||||
|
End Try
|
||||||
|
End Function
|
||||||
|
#End Region
|
||||||
|
#End Region
|
||||||
|
#Region "ReparseVideo"
|
||||||
|
Protected Overrides Sub ReparseVideo(ByVal Token As CancellationToken)
|
||||||
|
Const ERR_NEW_URL$ = "ERR_NEW_URL"
|
||||||
|
Dim URL$ = String.Empty
|
||||||
|
Try
|
||||||
|
If _TempMediaList.Count > 0 AndAlso _TempMediaList.Exists(Function(tm) tm.Type = UTypes.VideoPre) Then
|
||||||
|
Dim m As UserMedia
|
||||||
|
Dim r$, NewUrl$
|
||||||
|
For i% = _TempMediaList.Count - 1 To 0 Step -1
|
||||||
|
If _TempMediaList(i).Type = UTypes.VideoPre Then
|
||||||
|
m = _TempMediaList(i)
|
||||||
|
ThrowAny(Token)
|
||||||
|
Try
|
||||||
|
URL = m.URL
|
||||||
|
r = Responser.Curl(URL)
|
||||||
|
If Not r.IsEmptyString Then
|
||||||
|
NewUrl = CreateVideoURL(r)
|
||||||
|
If NewUrl.IsEmptyString Then
|
||||||
|
Throw New Exception With {.HelpLink = ERR_NEW_URL}
|
||||||
|
Else
|
||||||
|
m.URL = NewUrl
|
||||||
|
m.Type = UTypes.m3u8
|
||||||
|
_TempMediaList(i) = m
|
||||||
|
End If
|
||||||
|
Else
|
||||||
|
_TempMediaList.RemoveAt(i)
|
||||||
|
End If
|
||||||
|
Catch mid_ex As Exception
|
||||||
|
If mid_ex.HelpLink = ERR_NEW_URL OrElse DownloadingException(mid_ex, "") = 1 Then
|
||||||
|
m.State = UserMedia.States.Missing
|
||||||
|
_TempMediaList(i) = m
|
||||||
|
Else
|
||||||
|
_TempMediaList.RemoveAt(i)
|
||||||
|
End If
|
||||||
|
End Try
|
||||||
|
End If
|
||||||
|
Next
|
||||||
|
End If
|
||||||
|
Catch ex As Exception
|
||||||
|
ProcessException(ex, Token, "video reparsing error", False)
|
||||||
|
End Try
|
||||||
|
End Sub
|
||||||
|
#End Region
|
||||||
|
#Region "ReparseMissing"
|
||||||
|
Protected Overrides Sub ReparseMissing(ByVal Token As CancellationToken)
|
||||||
|
Dim rList As New List(Of Integer)
|
||||||
|
Try
|
||||||
|
If ContentMissingExists Then
|
||||||
|
Dim m As UserMedia
|
||||||
|
Dim r$
|
||||||
|
Dim eCurl As New ErrorsDescriber(EDP.ReturnValue)
|
||||||
|
For i% = 0 To _ContentList.Count - 1
|
||||||
|
m = _ContentList(i)
|
||||||
|
If m.State = UserMedia.States.Missing AndAlso Not m.URL_BASE.IsEmptyString Then
|
||||||
|
ThrowAny(Token)
|
||||||
|
r = Responser.Curl(m.URL_BASE, eCurl)
|
||||||
|
If Not r.IsEmptyString Then
|
||||||
|
Dim NewUrl$ = CreateVideoURL(r)
|
||||||
|
If Not NewUrl.IsEmptyString Then
|
||||||
|
m.URL = NewUrl
|
||||||
|
_TempMediaList.ListAddValue(m, LNC)
|
||||||
|
rList.Add(i)
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Next
|
||||||
|
End If
|
||||||
|
Catch ex As Exception
|
||||||
|
ProcessException(ex, Token, "missing data downloading error")
|
||||||
|
Finally
|
||||||
|
If rList.Count > 0 Then
|
||||||
|
For i% = rList.Count - 1 To 0 Step -1 : _ContentList.RemoveAt(rList(i)) : Next
|
||||||
|
rList.Clear()
|
||||||
|
End If
|
||||||
|
End Try
|
||||||
|
End Sub
|
||||||
|
#End Region
|
||||||
|
#Region "Download content"
|
||||||
|
Protected Overrides Sub DownloadContent(ByVal Token As CancellationToken)
|
||||||
|
DownloadContentDefault(Token)
|
||||||
|
End Sub
|
||||||
|
Protected Overrides Function DownloadM3U8(ByVal URL As String, ByVal Media As UserMedia, ByVal DestinationFile As SFile) As SFile
|
||||||
|
Return M3U8.Download(URL, Responser, DestinationFile)
|
||||||
|
End Function
|
||||||
|
#End Region
|
||||||
|
#Region "CreateVideoURL"
|
||||||
|
Private Shared Function CreateVideoURL(ByVal r As String) As String
|
||||||
|
Try
|
||||||
|
Dim OutStr$ = String.Empty
|
||||||
|
If Not r.IsEmptyString Then
|
||||||
|
Dim _VarBlock$ = RegexReplace(r, RegexVideo_FlashVarsBlock)
|
||||||
|
If Not _VarBlock.IsEmptyString Then
|
||||||
|
Dim vars As List(Of FlashVar) = RegexFields(Of FlashVar)(_VarBlock, {RegexVideo_FlashVars_Vars}, {1, 2})
|
||||||
|
Dim compiler As List(Of String) = RegexReplace(_VarBlock, RegexVideo_FlashVars_Compiler)
|
||||||
|
If vars.ListExists And compiler.ListExists Then
|
||||||
|
Dim v$
|
||||||
|
Dim i%
|
||||||
|
For Each var$ In compiler
|
||||||
|
i = vars.IndexOf(var)
|
||||||
|
If i >= 0 Then
|
||||||
|
v = vars(i).Value
|
||||||
|
If Not v.IsEmptyString Then OutStr &= v
|
||||||
|
End If
|
||||||
|
Next
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Return OutStr
|
||||||
|
Catch ex As Exception
|
||||||
|
Return ErrorsDescriber.Execute(EDP.SendInLog, ex, "[API.PornHub.UserData.CreateVideoURL]", String.Empty)
|
||||||
|
End Try
|
||||||
|
End Function
|
||||||
|
#End Region
|
||||||
|
#Region "Standalone downloader"
|
||||||
|
Friend Shared Function GetVideoInfo(ByVal URL As String, ByVal Responser As Response, ByVal Destination As SFile) As UserMedia
|
||||||
|
Try
|
||||||
|
Dim r$ = Responser.Curl(URL)
|
||||||
|
If Not r.IsEmptyString Then
|
||||||
|
Dim NewUrl$ = CreateVideoURL(r)
|
||||||
|
If Not NewUrl.IsEmptyString Then
|
||||||
|
Dim f As SFile = M3U8.Download(NewUrl, Responser, Destination)
|
||||||
|
If Not f.IsEmptyString Then Return New UserMedia With {.State = UserMedia.States.Downloaded}
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Return Nothing
|
||||||
|
Catch ex As Exception
|
||||||
|
Return ErrorsDescriber.Execute(EDP.SendInLog + EDP.ReturnValue, ex, $"PornHub standalone download error: [{URL}]", New UserMedia)
|
||||||
|
End Try
|
||||||
|
End Function
|
||||||
|
#End Region
|
||||||
|
#Region "Exceptions"
|
||||||
|
Protected Overrides Function DownloadingException(ByVal ex As Exception, ByVal Message As String,
|
||||||
|
Optional ByVal FromPE As Boolean = False, Optional ByVal EObj As Object = Nothing) As Integer
|
||||||
|
If Responser.Status = Net.WebExceptionStatus.ConnectionClosed Then
|
||||||
|
Return 1
|
||||||
|
ElseIf Responser.StatusCode = Net.HttpStatusCode.ServiceUnavailable Then
|
||||||
|
Return 2
|
||||||
|
Else
|
||||||
|
Return 0
|
||||||
|
End If
|
||||||
|
End Function
|
||||||
|
#End Region
|
||||||
|
End Class
|
||||||
|
End Namespace
|
||||||
23
SCrawler/API/PornHub/UserExchangeOptions.vb
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
|
' 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.PornHub
|
||||||
|
Friend Class UserExchangeOptions
|
||||||
|
Friend Property DownloadGifs As Boolean
|
||||||
|
Friend Property DownloadPhotoOnlyFromModelHub As Boolean
|
||||||
|
Friend Sub New(ByVal u As UserData)
|
||||||
|
DownloadGifs = u.DownloadGifs
|
||||||
|
DownloadPhotoOnlyFromModelHub = u.DownloadPhotoOnlyFromModelHub
|
||||||
|
End Sub
|
||||||
|
Friend Sub New(ByVal s As SiteSettings)
|
||||||
|
Dim v As CheckState = CInt(s.DownloadGifs.Value)
|
||||||
|
DownloadGifs = Not v = CheckState.Unchecked
|
||||||
|
DownloadPhotoOnlyFromModelHub = s.DownloadPhotoOnlyFromModelHub.Value
|
||||||
|
End Sub
|
||||||
|
End Class
|
||||||
|
End Namespace
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
@@ -236,8 +236,19 @@ Namespace API.Reddit
|
|||||||
Return If(Name.IsEmptyString, ID, Name)
|
Return If(Name.IsEmptyString, ID, Name)
|
||||||
End Function
|
End Function
|
||||||
Friend Sub Delete()
|
Friend Sub Delete()
|
||||||
File.Delete(, SFODelete.DeleteToRecycleBin)
|
Dim f As SFile = ChannelsCollection.ChannelsDeletedPath
|
||||||
FilePosts.Delete(, SFODelete.DeleteToRecycleBin)
|
With File
|
||||||
|
f.Name = .Name
|
||||||
|
f.Extension = .Extension
|
||||||
|
.Copy(f,, True, SFODelete.DeleteToRecycleBin)
|
||||||
|
.Delete(, SFODelete.DeleteToRecycleBin)
|
||||||
|
End With
|
||||||
|
With FilePosts
|
||||||
|
f.Name = .Name
|
||||||
|
f.Extension = .Extension
|
||||||
|
.Copy(f,, True, SFODelete.DeleteToRecycleBin)
|
||||||
|
.Delete(, SFODelete.DeleteToRecycleBin)
|
||||||
|
End With
|
||||||
End Sub
|
End Sub
|
||||||
Friend Sub DownloadData(ByVal Token As CancellationToken, Optional ByVal SkipExists As Boolean = True,
|
Friend Sub DownloadData(ByVal Token As CancellationToken, Optional ByVal SkipExists As Boolean = True,
|
||||||
Optional ByVal p As MyProgress = Nothing)
|
Optional ByVal p As MyProgress = Nothing)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
@@ -6,10 +6,10 @@
|
|||||||
'
|
'
|
||||||
' This program is distributed in the hope that it will be useful,
|
' This program is distributed in the hope that it will be useful,
|
||||||
' but WITHOUT ANY WARRANTY
|
' but WITHOUT ANY WARRANTY
|
||||||
|
Imports System.Threading
|
||||||
|
Imports SCrawler.API.Base
|
||||||
Imports PersonalUtilities.Tools
|
Imports PersonalUtilities.Tools
|
||||||
Imports PersonalUtilities.Forms.Toolbars
|
Imports PersonalUtilities.Forms.Toolbars
|
||||||
Imports SCrawler.API.Base
|
|
||||||
Imports System.Threading
|
|
||||||
Namespace API.Reddit
|
Namespace API.Reddit
|
||||||
Friend Class ChannelsCollection : Implements ICollection(Of Channel), IMyEnumerator(Of Channel), IChannelLimits, IDisposable
|
Friend Class ChannelsCollection : Implements ICollection(Of Channel), IMyEnumerator(Of Channel), IChannelLimits, IDisposable
|
||||||
Friend Shared ReadOnly Property ChannelsPath As SFile
|
Friend Shared ReadOnly Property ChannelsPath As SFile
|
||||||
@@ -17,6 +17,11 @@ Namespace API.Reddit
|
|||||||
Return $"{SettingsFolderName}\Channels\"
|
Return $"{SettingsFolderName}\Channels\"
|
||||||
End Get
|
End Get
|
||||||
End Property
|
End Property
|
||||||
|
Friend Shared ReadOnly Property ChannelsDeletedPath As SFile
|
||||||
|
Get
|
||||||
|
Return $"{SettingsFolderName}\ChannelsDeleted\"
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
Friend Shared ReadOnly Property ChannelsPathCache As SFile
|
Friend Shared ReadOnly Property ChannelsPathCache As SFile
|
||||||
Get
|
Get
|
||||||
Return $"{Settings.GlobalPath.Value.PathWithSeparator}_CachedData\"
|
Return $"{Settings.GlobalPath.Value.PathWithSeparator}_CachedData\"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
' but WITHOUT ANY WARRANTY
|
' but WITHOUT ANY WARRANTY
|
||||||
Imports System.Net
|
Imports System.Net
|
||||||
Imports SCrawler.API.Reddit.M3U8_Declarations
|
Imports SCrawler.API.Reddit.M3U8_Declarations
|
||||||
Imports PersonalUtilities.Tools.WEB
|
Imports PersonalUtilities.Tools.Web
|
||||||
Imports PersonalUtilities.Functions.RegularExpressions
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
Namespace API.Reddit
|
Namespace API.Reddit
|
||||||
Namespace M3U8_Declarations
|
Namespace M3U8_Declarations
|
||||||
@@ -130,7 +130,7 @@ Namespace API.Reddit
|
|||||||
End If
|
End If
|
||||||
If CachePath.Exists(SFO.Path) Then
|
If CachePath.Exists(SFO.Path) Then
|
||||||
Dim p As New SFileNumbers(ConcatFile.Name,,, New ANumbers With {.Format = ANumbers.Formats.General})
|
Dim p As New SFileNumbers(ConcatFile.Name,,, New ANumbers With {.Format = ANumbers.Formats.General})
|
||||||
ConcatFile = SFile.Indexed_IndexFile(ConcatFile,, p, EDP.ThrowException) 'EDP.ReturnValue
|
ConcatFile = SFile.Indexed_IndexFile(ConcatFile,, p, EDP.ThrowException)
|
||||||
Dim i%
|
Dim i%
|
||||||
Dim eFiles As New List(Of SFile)
|
Dim eFiles As New List(Of SFile)
|
||||||
Dim dFile As SFile = CachePath
|
Dim dFile As SFile = CachePath
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
@@ -27,7 +27,6 @@ Namespace API.Reddit
|
|||||||
Dim TP_VIEW_MODE 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_VIEW_MODE As System.Windows.Forms.Label
|
||||||
Dim LBL_PERIOD 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_NEW = New System.Windows.Forms.RadioButton()
|
||||||
Me.OPT_VIEW_MODE_HOT = 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.OPT_VIEW_MODE_TOP = New System.Windows.Forms.RadioButton()
|
||||||
@@ -266,7 +265,7 @@ Namespace API.Reddit
|
|||||||
Me.ClientSize = New System.Drawing.Size(477, 112)
|
Me.ClientSize = New System.Drawing.Size(477, 112)
|
||||||
Me.Controls.Add(CONTAINER_MAIN)
|
Me.Controls.Add(CONTAINER_MAIN)
|
||||||
Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle
|
Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle
|
||||||
Me.Icon = CType(resources.GetObject("$this.Icon"), System.Drawing.Icon)
|
Me.Icon = Global.SCrawler.My.Resources.SiteResources.RedditIcon_128
|
||||||
Me.KeyPreview = True
|
Me.KeyPreview = True
|
||||||
Me.MaximizeBox = False
|
Me.MaximizeBox = False
|
||||||
Me.MaximumSize = New System.Drawing.Size(493, 151)
|
Me.MaximumSize = New System.Drawing.Size(493, 151)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2022 Andy
|
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
||||||
' This program is free software: you can redistribute it and/or modify
|
' 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
|
' it under the terms of the GNU General Public License as published by
|
||||||
' the Free Software Foundation, either version 3 of the License, or
|
' the Free Software Foundation, either version 3 of the License, or
|
||||||
@@ -68,16 +68,7 @@ Namespace API.Reddit
|
|||||||
End With
|
End With
|
||||||
MyDefs.CloseForm()
|
MyDefs.CloseForm()
|
||||||
End Sub
|
End Sub
|
||||||
Private Sub OPT_VIEW_MODE_NEW_CheckedChanged(sender As Object, e As EventArgs) Handles OPT_VIEW_MODE_NEW.CheckedChanged
|
Private Sub ChangePeriodEnabled() Handles OPT_VIEW_MODE_NEW.CheckedChanged, OPT_VIEW_MODE_HOT.CheckedChanged, OPT_VIEW_MODE_TOP.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
|
TP_PERIOD.Enabled = OPT_VIEW_MODE_TOP.Checked
|
||||||
End Sub
|
End Sub
|
||||||
End Class
|
End Class
|
||||||
|
|||||||