Compare commits
9 Commits
2024.9.2.0
...
2025.8.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e09752a2d5 | ||
|
|
05772a9fc4 | ||
|
|
24ad338c60 | ||
|
|
ff0c4587eb | ||
|
|
fff63d0a9f | ||
|
|
2f838929cc | ||
|
|
4d74f5204b | ||
|
|
b42832719f | ||
|
|
aedcebc781 |
208
Changelog.md
@@ -1,3 +1,211 @@
|
|||||||
|
# 2025.8.1.0
|
||||||
|
|
||||||
|
*2025-08-01*
|
||||||
|
|
||||||
|
- Added
|
||||||
|
- Sites:
|
||||||
|
- Reddit: **bypass error `429`**
|
||||||
|
- Twitter: **[large profile option](https://github.com/AAndyProgram/SCrawler/wiki/Settings#twitter-user-settings) in user settings**
|
||||||
|
- Minor improvements
|
||||||
|
- Updated
|
||||||
|
- yt-dlp up to version **2025.27.21**
|
||||||
|
- gallery-dl up to version **1.30.2**
|
||||||
|
- Fixed
|
||||||
|
- Reddit: in some cases crossposts don't download
|
||||||
|
- Minor bugs
|
||||||
|
|
||||||
|
# 2025.7.18.0
|
||||||
|
|
||||||
|
*2025-07-18*
|
||||||
|
|
||||||
|
- Added
|
||||||
|
- Sites:
|
||||||
|
- OnlyFans: support for GIF files
|
||||||
|
- Reddit: extended `429` error handling
|
||||||
|
- Xhamster: support for downloading 'moments'
|
||||||
|
- Minor improvements
|
||||||
|
- Updated
|
||||||
|
- yt-dlp up to version **2025.06.30**
|
||||||
|
- gallery-dl up to version **1.30.0**
|
||||||
|
- Fixed
|
||||||
|
- OnlyFans: **hanging on purchased content**
|
||||||
|
- Minor bugs
|
||||||
|
|
||||||
|
# 2025.6.12.0
|
||||||
|
|
||||||
|
*2025-06-12*
|
||||||
|
|
||||||
|
- Updated
|
||||||
|
- yt-dlp up to version **2025.06.09**
|
||||||
|
- Fixed
|
||||||
|
- Sites:
|
||||||
|
- YouTube: audio formats of protocol `m3u8` are not handled correctly
|
||||||
|
- BlueSky: data is not downloaded in some cases
|
||||||
|
- Reddit: new users do not inherit default text settings
|
||||||
|
- Saved posts: text downloading with saved posts
|
||||||
|
- Environment incorrect output
|
||||||
|
|
||||||
|
# 2025.6.1.0
|
||||||
|
|
||||||
|
*2025-06-01*
|
||||||
|
|
||||||
|
- Added
|
||||||
|
- Sites:
|
||||||
|
- YouTube (standalone app):
|
||||||
|
- support for **youtu.be** domain
|
||||||
|
- **filters**
|
||||||
|
- hotkey `Ctrl+F5` for refresh
|
||||||
|
- **Bluesky, Instagram, OnlyFans, Reddit, Threads, Twitter: the ability to download text posts**
|
||||||
|
- OnlyFans:
|
||||||
|
- updated `DynamicRules`
|
||||||
|
- `backend` option *(`aio` & `httpx`)*
|
||||||
|
- Reddit: add `Best` and `Rising` view modes
|
||||||
|
- TikTok: downloading of avatar, site name and description
|
||||||
|
- Feed:
|
||||||
|
- **filters**
|
||||||
|
- add the ability to show test posts
|
||||||
|
- Minor improvements
|
||||||
|
- Updated
|
||||||
|
- yt-dlp up to version **2025.05.22**
|
||||||
|
- gallery-dl up to version **1.29.7**
|
||||||
|
- PluginProvider
|
||||||
|
- IUserMedia: properties `PostText`, `PostTextFile`, `PostTextFileSpecialFolder`
|
||||||
|
- Fixed
|
||||||
|
- Sites:
|
||||||
|
- OnlyFans:
|
||||||
|
- DRM videos are not downloading in some cases *(only if you can't download video try changing `backend` option to `httpx`)*
|
||||||
|
- incorrect open posts
|
||||||
|
- while limited downloading, the first time, the profile still loads completely
|
||||||
|
- Reddit:
|
||||||
|
- **data is not downloading**
|
||||||
|
- post date is incorrect
|
||||||
|
- Threads
|
||||||
|
- change domain from `net` to `com`
|
||||||
|
- data is not downloading
|
||||||
|
- Twitter
|
||||||
|
- fix JSON error
|
||||||
|
- data is not downloaded in some cases
|
||||||
|
- Minor bugs
|
||||||
|
|
||||||
|
# 2025.3.17.0
|
||||||
|
|
||||||
|
*2025-03-17*
|
||||||
|
|
||||||
|
- Added
|
||||||
|
- **TikTok: downloading photos**
|
||||||
|
- Updated
|
||||||
|
- gallery-dl up to version **1.29.2**
|
||||||
|
- Fixed
|
||||||
|
- Sites
|
||||||
|
- Facebook: reels aren't downloaded from noname profiles
|
||||||
|
- PornHub: newly added users aren't downloading
|
||||||
|
- Threads: users aren't updated if there is a pinned post
|
||||||
|
|
||||||
|
# 2025.2.25.0
|
||||||
|
|
||||||
|
*2025-02-25*
|
||||||
|
|
||||||
|
- Added
|
||||||
|
- Sites:
|
||||||
|
- **Bluesky**
|
||||||
|
- Facebook: **`Reels` downloads**
|
||||||
|
- OnlyFans: default value for `App-Token`
|
||||||
|
- Pinterest: **sub-boards downloading**
|
||||||
|
- Threads: ability to manually change `UserName`
|
||||||
|
- Twitter:
|
||||||
|
- new icon support
|
||||||
|
- **sleep timers to fully download large profiles**
|
||||||
|
- Feed:
|
||||||
|
- ability to invert selection
|
||||||
|
- open post URL when double-clicking on subscription image
|
||||||
|
- Minor improvements
|
||||||
|
- Updated
|
||||||
|
- yt-dlp up to version **2025.02.19**
|
||||||
|
- gallery-dl up to version **1.28.5**
|
||||||
|
- PluginProvider
|
||||||
|
- `IPluginContentProvider`: added property `NameTrue`
|
||||||
|
- Fixed
|
||||||
|
- Sites:
|
||||||
|
- Facebook: videos are not downloading
|
||||||
|
- LPSG: simplified 403 error
|
||||||
|
- PornHub: photos & videos are not downloading
|
||||||
|
- Reddit: **token does not update automatically**
|
||||||
|
- Threads: **data is not downloading**
|
||||||
|
- Minor bugs
|
||||||
|
|
||||||
|
# 2025.1.12.0
|
||||||
|
|
||||||
|
*2025-01-12*
|
||||||
|
|
||||||
|
- Added
|
||||||
|
- Sites:
|
||||||
|
- YouTube (standalone app):
|
||||||
|
- ability to add channel name to file name (`Add channel to file name`)
|
||||||
|
- adding channel name and video URL to info file
|
||||||
|
- OnlyFans: **built-in usage of DRM keys**
|
||||||
|
- Threads: automatically change `heic` extension to `jpg`
|
||||||
|
- Twitter: download broadcasts *(user option)*
|
||||||
|
- Minor improvements
|
||||||
|
- Updated
|
||||||
|
- yt-dlp up to version **2024.12.23**
|
||||||
|
- gallery-dl up to version **1.28.3**
|
||||||
|
- **OF-Scraper** up to version **3.12.9** *(you must update it personally)*
|
||||||
|
- Fixed
|
||||||
|
- Sites:
|
||||||
|
- DownDetector: fixed 403 error
|
||||||
|
- OnlyFans: **DRM videos not downloading**
|
||||||
|
- xHamster: some videos are not downloading
|
||||||
|
- YouTube: **communities are not downloading** *(see settings in wiki)*
|
||||||
|
- Minor bugs
|
||||||
|
|
||||||
|
# 2024.11.21.0
|
||||||
|
|
||||||
|
*2024-11-21*
|
||||||
|
|
||||||
|
- Added
|
||||||
|
- Sites:
|
||||||
|
- Instagram:
|
||||||
|
- setting to skip errors without disabling download *(site settings)*
|
||||||
|
- settings to force update of username and/or user information *(user settings)*
|
||||||
|
- setting to continue downloading profile if error 560 occurs while downloading user stories *(site settings)*
|
||||||
|
- improve username update algorithm
|
||||||
|
- YouTube: 404 error handling (community)
|
||||||
|
- Main window: add extra buttons for special download (limited and dated) in collection
|
||||||
|
- Global settings: ability to change the feed opening shortcut (`Ctrl+F`/`Alt+F` *(Settings - Behavior)*)
|
||||||
|
- Minor improvements
|
||||||
|
- Updated
|
||||||
|
- yt-dlp up to version **2024.11.18**
|
||||||
|
- gallery-dl up to version **1.27.7**
|
||||||
|
- Fixed
|
||||||
|
- Users: network paths aren't working
|
||||||
|
- Main window: in some cases users are not updated in the list
|
||||||
|
- Minor bugs
|
||||||
|
|
||||||
|
# 2024.10.24.0
|
||||||
|
|
||||||
|
*2024-10-24*
|
||||||
|
|
||||||
|
- Added
|
||||||
|
- YouTube (standalone app):
|
||||||
|
- settings `Embed thumbnail (cover)` and `Allow webm formats`
|
||||||
|
- changed cover selection for music downloads
|
||||||
|
- allow `webm` formats if there are no `mp4` formats via http protocol (issue #211)
|
||||||
|
- Sites:
|
||||||
|
- Instagram:
|
||||||
|
- **ability to manually change username**
|
||||||
|
- **mark user as non-existent if user `ID` cannot be obtained**
|
||||||
|
- Twitter: **ability to manually change username**
|
||||||
|
- Main window: add users search button to 'Info' menu
|
||||||
|
- Minor improvements
|
||||||
|
- Updated
|
||||||
|
- yt-dlp up to version **2024.10.22**
|
||||||
|
- gallery-dl up to version **1.27.6**
|
||||||
|
- Fixed
|
||||||
|
- YouTube (standalone app): adding incorrect playlist lines
|
||||||
|
- Reddit: incorrect UNIX date parsing
|
||||||
|
- Can't change data path (issue #206)
|
||||||
|
- Minor bugs
|
||||||
|
|
||||||
# 2024.9.2.0
|
# 2024.9.2.0
|
||||||
|
|
||||||
*2024-09-02*
|
*2024-09-02*
|
||||||
|
|||||||
15
FAQ.md
@@ -26,22 +26,22 @@ I strongly recommend you to **regularly** create backup copies of the settings f
|
|||||||
|
|
||||||
# Most frequently questions about SCrawler
|
# Most frequently questions about SCrawler
|
||||||
|
|
||||||
**Is something doesn't download, always check the [SITE'S REQUIREMENTS](https://github.com/AAndyProgram/SCrawler/wiki/Settings#sites-requirements) before asking questions!**
|
**If something doesn't download, always check the [SITE'S REQUIREMENTS](https://github.com/AAndyProgram/SCrawler/wiki/Settings#sites-requirements) before asking questions!**
|
||||||
|
|
||||||
*How to use: find your problem in the list and read the answer.*
|
*How to use: find your problem in the list and read the answer.*
|
||||||
|
|
||||||
## General questions
|
## General questions
|
||||||
- **PROFILES**
|
- **PROFILES**
|
||||||
- I added a profile but **nothing downloaded** :arrow_forward: check your cookies and [site requirements](https://github.com/AAndyProgram/SCrawler/wiki/Settings#sites-requirements). If there are any optional fields that you don't fill in, do so. Still nothing works - [report it](#how-to-report-a-problem)!
|
- I added a profile but **nothing downloaded** :arrow_forward: check your cookies and [site requirements](https://github.com/AAndyProgram/SCrawler/wiki/Settings#sites-requirements). If there are any optional fields that you don't fill in, do so. Still nothing works - [report it](#how-to-report-a-problem)!
|
||||||
- User downloading failed :arrow_forward: check your credentials and **[SITES REQUIREMENTS](https://github.com/AAndyProgram/SCrawler/wiki/Settings#sites-requirements)**. If all settings are set and nothing works, [report it](#how-to-report-a-problem). <u>Don't forget to attach the LOG.</u>
|
- User downloading failed :arrow_forward: check your credentials and **[SITES REQUIREMENTS](https://github.com/AAndyProgram/SCrawler/wiki/Settings#sites-requirements)**. If all settings are set and nothing works, [report it](#how-to-report-a-problem). **Don't forget to attach the LOG.**
|
||||||
- [How to redownload user](https://github.com/AAndyProgram/SCrawler/wiki#redownload-user)
|
- [How to redownload user](https://github.com/AAndyProgram/SCrawler/wiki#redownload-user)
|
||||||
- How to **add profile** to download :arrow_forward: copy the **[profile URL](https://github.com/AAndyProgram/SCrawler/wiki#add-user)** and press `Insert` or `Ctrl+Insert`. **ALWAYS PASTE THE USER PROFILE URL**. After that select this user and press `F5` or click the `Download selected` button.
|
- How to **add profile** to download :arrow_forward: copy the **[profile URL](https://github.com/AAndyProgram/SCrawler/wiki#add-user)** and press `Insert` or `Ctrl+Insert`. **ALWAYS PASTE THE USER PROFILE URL**. After that select this user and press `F5` or click the `Download selected` button.
|
||||||
- How to download **[saved posts](https://github.com/AAndyProgram/SCrawler/wiki#saved-posts)**
|
- How to download **[saved posts](https://github.com/AAndyProgram/SCrawler/wiki#saved-posts)**
|
||||||
- **[HOW TO ADD COOKIES](https://github.com/AAndyProgram/SCrawler/wiki/Settings#how-to-set-up-cookies)**
|
- **[HOW TO ADD COOKIES](https://github.com/AAndyProgram/SCrawler/wiki/Settings#how-to-set-up-cookies)**
|
||||||
- [How to report a problem](#how-to-report-a-problem)
|
- [How to report a problem](#how-to-report-a-problem)
|
||||||
- I want you to **add the site** to SCrawler :arrow_forward: **I'm not currently accepting requests to add new sites**, but you can [create a plugin](https://github.com/AAndyProgram/SCrawler/wiki/Plugins) (for your site) for SCrawler.
|
- I want you to **add the site** to SCrawler :arrow_forward: **I'm not currently accepting requests to add new sites**, but you can [create a plugin](https://github.com/AAndyProgram/SCrawler/wiki/Plugins) (for your site) for SCrawler.
|
||||||
- What language is SCrawler written in :arrow_forward: vb.net
|
- What language is SCrawler written in :arrow_forward: `vb.net`
|
||||||
- I don't know vb.net and I can't write a plugin :arrow_forward: you can write a plugin in `C#`
|
- I don't know `vb.net` and I can't write a plugin :arrow_forward: you can write a plugin in `C#`
|
||||||
- I have a suggestion, will it be added :arrow_forward: maybe if it interested me.
|
- I have a suggestion, will it be added :arrow_forward: maybe if it interested me.
|
||||||
- How to name files using a pattern (e.g. `Site_PostID_Name.jpg`) :arrow_forward: **there is no such functionality and there are no such plans**.
|
- How to name files using a pattern (e.g. `Site_PostID_Name.jpg`) :arrow_forward: **there is no such functionality and there are no such plans**.
|
||||||
- **DON'T CHANGE THE DEFAULT SITE SETTINGS UNLESS YOU KNOW EXACTLY WHAT YOU'RE DOING!** SCrawler already has all the default settings to work. You only need to add credentials (where [required](https://github.com/AAndyProgram/SCrawler/wiki/Settings#sites-requirements)).
|
- **DON'T CHANGE THE DEFAULT SITE SETTINGS UNLESS YOU KNOW EXACTLY WHAT YOU'RE DOING!** SCrawler already has all the default settings to work. You only need to add credentials (where [required](https://github.com/AAndyProgram/SCrawler/wiki/Settings#sites-requirements)).
|
||||||
@@ -55,19 +55,20 @@ I strongly recommend you to **regularly** create backup copies of the settings f
|
|||||||
- [Video how to configure](#video-how-to-configure)
|
- [Video how to configure](#video-how-to-configure)
|
||||||
- **Antivirus**
|
- **Antivirus**
|
||||||
- **Antivirus detects SCrawler as a virus** :arrow_forward: SCrawler doesn't contain any viruses at all. All code is posted on GitHub. You can review it. I have nothing to hide. SCrawler just downloads pictures and videos. That's all. If you trust SCrawler, you should just add it to the antivirus exceptions, as I did. Sometimes antiviruses identify SCawler as a virus. This is usually related to the number of files being edited (users' settings files) and the number of files being downloaded. In this case, the antivirus can also remove these files, which will damage users' settings. **If you don't trust SCrawler, just delete it.**
|
- **Antivirus detects SCrawler as a virus** :arrow_forward: SCrawler doesn't contain any viruses at all. All code is posted on GitHub. You can review it. I have nothing to hide. SCrawler just downloads pictures and videos. That's all. If you trust SCrawler, you should just add it to the antivirus exceptions, as I did. Sometimes antiviruses identify SCawler as a virus. This is usually related to the number of files being edited (users' settings files) and the number of files being downloaded. In this case, the antivirus can also remove these files, which will damage users' settings. **If you don't trust SCrawler, just delete it.**
|
||||||
- **Antivirus detects gallery-dl as a virus** :arrow_forward: it's a trustworthy program that is trusted by thousands of people around the world. Antiviruses identify some builds as containing viruses, but this is not true. **If you don't trust gallery-dl, you can simply delete it**. **But if you delete it, you won't be able to download [Twitter & Pinterest](https://github.com/AAndyProgram/SCrawler/wiki/Settings#gallery-dl).** You should decide for yourself.
|
- **Antivirus detects gallery-dl as a virus** :arrow_forward: it's a trustworthy program that is trusted by thousands of people around the world. Antiviruses identify some builds as containing viruses, but this is not true. **If you don't trust gallery-dl, you can simply delete it. But if you delete it, you won't be able to download [Twitter & Pinterest](https://github.com/AAndyProgram/SCrawler/wiki/Settings#gallery-dl).** You should decide for yourself.
|
||||||
|
|
||||||
## Sites questions
|
## Sites questions
|
||||||
|
|
||||||
*How to use: find the site you need in the list and read the answer.*
|
*How to use: find the site you need in the list and read the answer.*
|
||||||
|
|
||||||
- Reddit: don't use credentials at all or configure [OAuth](https://github.com/AAndyProgram/SCrawler/wiki/Settings#how-to-get-reddit-credentials). **Reddit profiles can be downloaded without any credentials at all. Subreddits require OAuth! If nothing downloads, use OAuth!**
|
- Reddit: don't use credentials at all or configure [OAuth](https://github.com/AAndyProgram/SCrawler/wiki/Settings#how-to-get-reddit-credentials). **Reddit profiles can be downloaded without any credentials at all. Subreddits require OAuth! If nothing downloads, use OAuth!** Don't use OAuth token to download saved posts (use cookies only).
|
||||||
- **META** (**Instagram**, Threads, Facebook): you need **cookies** and fill in **all fields**
|
- **META** (**Instagram**, Threads, Facebook): you need **cookies** and fill in **all fields**
|
||||||
|
- **Instagram [TIPS](https://github.com/AAndyProgram/SCrawler/wiki/Settings#instagram-tips)**
|
||||||
- **Instagram saved posts**: I don't consider questions like "I have 10k saved posts and only 1000 were downloaded". Download posts, remove them from saved posts, delete the `Saved posts` **settings folder**, repeat.
|
- **Instagram saved posts**: I don't consider questions like "I have 10k saved posts and only 1000 were downloaded". Download posts, remove them from saved posts, delete the `Saved posts` **settings folder**, repeat.
|
||||||
- TikTok: works via yt-dlp. If something doesn't download, we need to wait until yt-dlp fixes it. TikTok doesn't require cookies to download.
|
- TikTok: works via yt-dlp. If something doesn't download, we need to wait until yt-dlp fixes it. TikTok doesn't require cookies to download.
|
||||||
- Porn sites: **COOKIES**!
|
- Porn sites: **COOKIES**!
|
||||||
- ThisVid: https://github.com/AAndyProgram/SCrawler/wiki/Settings#thisvid-faq
|
- ThisVid: https://github.com/AAndyProgram/SCrawler/wiki/Settings#thisvid-faq
|
||||||
- **OnlyFans**: cookies + **all fields** + [OF-Scraper (download the correct version that I pointed)](https://github.com/AAndyProgram/SCrawler/wiki/Settings#of-scraper) & [mp4decrypt](https://www.bento4.com/downloads/) to download DRM protected videos. [OF-Scraper support](https://github.com/AAndyProgram/SCrawler/wiki/Settings#of-scraper-support). Also read [this](https://github.com/AAndyProgram/SCrawler/wiki/Settings#onlyfans-faq)
|
- **OnlyFans**: cookies + **all fields** + [OF-Scraper (download the correct version that I pointed)](https://github.com/AAndyProgram/SCrawler/wiki/Settings#of-scraper) & [mp4decrypt](https://www.bento4.com/downloads/) & **DRM keys** to download DRM protected videos. [OF-Scraper support](https://github.com/AAndyProgram/SCrawler/wiki/Settings#of-scraper-support). Also read [this](https://github.com/AAndyProgram/SCrawler/wiki/Settings#onlyfans-faq)
|
||||||
- **JustForFans**: **THE VIDEO ISN'T DOWNLOADING AT THE MOMENT** ([Issue](https://discord.com/channels/1124032649682493462/1205547615199039551/1231349555132366870))
|
- **JustForFans**: **THE VIDEO ISN'T DOWNLOADING AT THE MOMENT** ([Issue](https://discord.com/channels/1124032649682493462/1205547615199039551/1231349555132366870))
|
||||||
|
|
||||||
## Other questions
|
## Other questions
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
BIN
ProgramScreenshots/SettingsSiteBluesky.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 14 KiB |
27
README.md
@@ -35,16 +35,17 @@ A program to download photo and video from [any site](#supported-sites) (e.g. Yo
|
|||||||
# What can program do:
|
# What can program do:
|
||||||
- Download pictures and videos from user profiles:
|
- Download pictures and videos from user profiles:
|
||||||
- YouTube videos, shorts, community feeds, users, artists, playlists, music, tracks;
|
- YouTube videos, shorts, community feeds, users, artists, playlists, music, tracks;
|
||||||
- Reddit images, galleries of images, videos, saved posts;
|
- Reddit images, galleries of images, videos, text, saved posts;
|
||||||
- Redgifs images and videos (https://www.redgifs.com/);
|
- Redgifs images and videos (https://www.redgifs.com/);
|
||||||
- Twitter images and videos, saved (bookmarked) posts, likes, communities;
|
- Twitter images and videos, text, saved (bookmarked) posts, likes, communities;
|
||||||
- OnlyFans images and videos, saved (bookmarked) posts, stories;
|
- Bluesky images and videos, text;
|
||||||
|
- OnlyFans images and videos, text, saved (bookmarked) posts, stories;
|
||||||
- JustForFans images and videos, saved (bookmarked) posts;
|
- JustForFans images and videos, saved (bookmarked) posts;
|
||||||
- Mastodon images and videos, saved (bookmarked) posts;
|
- Mastodon images and videos, saved (bookmarked) posts;
|
||||||
- Instagram images and videos, tagged posts, stories, saved posts;
|
- Instagram images and videos, text, tagged posts, stories, saved posts;
|
||||||
- Threads images and videos, saved posts;
|
- Threads images and videos, text, saved posts;
|
||||||
- Facebook images and videos, stories, saved posts;
|
- Facebook images and videos, stories, saved posts;
|
||||||
- TikTok videos;
|
- TikTok images and videos;
|
||||||
- Pinterest boards, users, saved posts;
|
- Pinterest boards, users, saved posts;
|
||||||
- Imgur images, galleries and videos;
|
- Imgur images, galleries and videos;
|
||||||
- Gfycat videos;
|
- Gfycat videos;
|
||||||
@@ -78,6 +79,7 @@ A program to download photo and video from [any site](#supported-sites) (e.g. Yo
|
|||||||
- **YouTube Music**
|
- **YouTube Music**
|
||||||
- **Reddit**
|
- **Reddit**
|
||||||
- **Twitter**
|
- **Twitter**
|
||||||
|
- **Bluesky**
|
||||||
- **OnlyFans** *(partial support)*[^1]
|
- **OnlyFans** *(partial support)*[^1]
|
||||||
- **Instagram**
|
- **Instagram**
|
||||||
- **Threads**
|
- **Threads**
|
||||||
@@ -131,6 +133,7 @@ First, the program downloads the full profile. After the program downloads only
|
|||||||
- **[SITES REQUIREMENTS](https://github.com/AAndyProgram/SCrawler/wiki/Settings#sites-requirements)**
|
- **[SITES REQUIREMENTS](https://github.com/AAndyProgram/SCrawler/wiki/Settings#sites-requirements)**
|
||||||
- [Reddit](https://github.com/AAndyProgram/SCrawler/wiki/Settings#reddit)
|
- [Reddit](https://github.com/AAndyProgram/SCrawler/wiki/Settings#reddit)
|
||||||
- [Twitter](https://github.com/AAndyProgram/SCrawler/wiki/Settings#twitter)
|
- [Twitter](https://github.com/AAndyProgram/SCrawler/wiki/Settings#twitter)
|
||||||
|
- [Bluesky](https://github.com/AAndyProgram/SCrawler/wiki/Settings#bluesky)
|
||||||
- [OnlyFans](https://github.com/AAndyProgram/SCrawler/wiki/Settings#onlyfans)
|
- [OnlyFans](https://github.com/AAndyProgram/SCrawler/wiki/Settings#onlyfans)
|
||||||
- [Mastodon](https://github.com/AAndyProgram/SCrawler/wiki/Settings#mastodon)
|
- [Mastodon](https://github.com/AAndyProgram/SCrawler/wiki/Settings#mastodon)
|
||||||
- [Instagram](https://github.com/AAndyProgram/SCrawler/wiki/Settings#instagram)
|
- [Instagram](https://github.com/AAndyProgram/SCrawler/wiki/Settings#instagram)
|
||||||
@@ -215,16 +218,4 @@ F5-->[*]
|
|||||||
|
|
||||||
Discord server: https://discord.gg/uFNUXvFFmg
|
Discord server: https://discord.gg/uFNUXvFFmg
|
||||||
|
|
||||||
<!--
|
|
||||||
[e-mail](mailto:andyprogram@proton.me): andyprogram@proton.me
|
|
||||||
|
|
||||||
Matrix (Element): https://matrix.to/#/@andyprogram:matrix.org
|
|
||||||
|
|
||||||
Discord (contact the developer): andyprogram
|
|
||||||
|
|
||||||
Discord server: https://discord.gg/uFNUXvFFmg
|
|
||||||
|
|
||||||
[Wire](https://account.wire.com/user-profile/?id=93985052-cf2c-4b72-ac75-bbe3231cf544): @andyprogram
|
|
||||||
-->
|
|
||||||
|
|
||||||
[^1]: Partial support means that I don't have personal accounts on paid porn sites because I don't pay for porn. If this site has stopped downloading and you want me to fix it, please be ready to give me access to an account with at least one active subscription. Otherwise, the download from this site will not be fixed.
|
[^1]: Partial support means that I don't have personal accounts on paid porn sites because I don't pay for porn. If this site has stopped downloading and you want me to fix it, please be ready to give me access to an account with at least one active subscription. Otherwise, the download from this site will not be fixed.
|
||||||
@@ -17,6 +17,7 @@ Namespace Plugin
|
|||||||
Property Settings As ISiteSettings
|
Property Settings As ISiteSettings
|
||||||
Property AccountName As String
|
Property AccountName As String
|
||||||
Property Name As String
|
Property Name As String
|
||||||
|
Property NameTrue As String
|
||||||
Property ID As String
|
Property ID As String
|
||||||
Property Options As String
|
Property Options As String
|
||||||
Property ParseUserMediaOnly As Boolean
|
Property ParseUserMediaOnly 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 © 2024")>
|
<Assembly: AssemblyCopyright("Copyright © 2025")>
|
||||||
<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("2024.5.18.0")>
|
<Assembly: AssemblyVersion("2025.6.1.0")>
|
||||||
<Assembly: AssemblyFileVersion("2024.5.18.0")>
|
<Assembly: AssemblyFileVersion("2025.6.1.0")>
|
||||||
<Assembly: NeutralResourcesLanguage("en")>
|
<Assembly: NeutralResourcesLanguage("en")>
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ Namespace Plugin
|
|||||||
Public Property DownloadState As UserMediaStates Implements IUserMedia.DownloadState
|
Public Property DownloadState As UserMediaStates Implements IUserMedia.DownloadState
|
||||||
Public Property PostID As String Implements IUserMedia.PostID
|
Public Property PostID As String Implements IUserMedia.PostID
|
||||||
Public Property PostDate As Date? Implements IUserMedia.PostDate
|
Public Property PostDate As Date? Implements IUserMedia.PostDate
|
||||||
|
Public Property PostText As String Implements IUserMedia.PostText
|
||||||
|
Public Property PostTextFile As String Implements IUserMedia.PostTextFile
|
||||||
|
Public Property PostTextFileSpecialFolder As Boolean Implements IUserMedia.PostTextFileSpecialFolder
|
||||||
Public Property SpecialFolder As String Implements IUserMedia.SpecialFolder
|
Public Property SpecialFolder As String Implements IUserMedia.SpecialFolder
|
||||||
Public Property Attempts As Integer Implements IUserMedia.Attempts
|
Public Property Attempts As Integer Implements IUserMedia.Attempts
|
||||||
Public Property [Object] As Object Implements IUserMedia.Object
|
Public Property [Object] As Object Implements IUserMedia.Object
|
||||||
@@ -48,6 +51,9 @@ Namespace Plugin
|
|||||||
Property DownloadState As UserMediaStates
|
Property DownloadState As UserMediaStates
|
||||||
Property PostID As String
|
Property PostID As String
|
||||||
Property PostDate As Date?
|
Property PostDate As Date?
|
||||||
|
Property PostText As String
|
||||||
|
Property PostTextFile As String
|
||||||
|
Property PostTextFileSpecialFolder As Boolean
|
||||||
Property SpecialFolder As String
|
Property SpecialFolder As String
|
||||||
Property Attempts As Integer
|
Property Attempts As Integer
|
||||||
Property [Object] As Object
|
Property [Object] As Object
|
||||||
|
|||||||
BIN
SCrawler.Shared/Content/Icons/FilterIcon.ico
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
SCrawler.Shared/Content/Images/FilterPic.png
Normal file
|
After Width: | Height: | Size: 320 B |
@@ -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("2023.12.15.0")>
|
<Assembly: AssemblyVersion("2025.6.1.0")>
|
||||||
<Assembly: AssemblyFileVersion("2023.12.15.0")>
|
<Assembly: AssemblyFileVersion("2025.6.1.0")>
|
||||||
<Assembly: NeutralResourcesLanguage("en")>
|
<Assembly: NeutralResourcesLanguage("en")>
|
||||||
|
|||||||
26
SCrawler.Shared/My Project/Resources.Designer.vb
generated
@@ -26,7 +26,7 @@ Namespace My.Resources
|
|||||||
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
|
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
|
||||||
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
|
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
|
||||||
Global.Microsoft.VisualBasic.HideModuleNameAttribute()> _
|
Global.Microsoft.VisualBasic.HideModuleNameAttribute()> _
|
||||||
Friend Module Resources
|
Public Module Resources
|
||||||
|
|
||||||
Private resourceMan As Global.System.Resources.ResourceManager
|
Private resourceMan As Global.System.Resources.ResourceManager
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ Namespace My.Resources
|
|||||||
''' Returns the cached ResourceManager instance used by this class.
|
''' Returns the cached ResourceManager instance used by this class.
|
||||||
'''</summary>
|
'''</summary>
|
||||||
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||||
Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager
|
Public ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager
|
||||||
Get
|
Get
|
||||||
If Object.ReferenceEquals(resourceMan, Nothing) Then
|
If Object.ReferenceEquals(resourceMan, Nothing) Then
|
||||||
Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("SCrawler.Resources", GetType(Resources).Assembly)
|
Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("SCrawler.Resources", GetType(Resources).Assembly)
|
||||||
@@ -51,7 +51,7 @@ Namespace My.Resources
|
|||||||
''' resource lookups using this strongly typed resource class.
|
''' resource lookups using this strongly typed resource class.
|
||||||
'''</summary>
|
'''</summary>
|
||||||
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||||
Friend Property Culture() As Global.System.Globalization.CultureInfo
|
Public Property Culture() As Global.System.Globalization.CultureInfo
|
||||||
Get
|
Get
|
||||||
Return resourceCulture
|
Return resourceCulture
|
||||||
End Get
|
End Get
|
||||||
@@ -59,5 +59,25 @@ Namespace My.Resources
|
|||||||
resourceCulture = value
|
resourceCulture = value
|
||||||
End Set
|
End Set
|
||||||
End Property
|
End Property
|
||||||
|
|
||||||
|
'''<summary>
|
||||||
|
''' Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
|
||||||
|
'''</summary>
|
||||||
|
Public ReadOnly Property FilterIcon() As System.Drawing.Icon
|
||||||
|
Get
|
||||||
|
Dim obj As Object = ResourceManager.GetObject("FilterIcon", resourceCulture)
|
||||||
|
Return CType(obj,System.Drawing.Icon)
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
|
||||||
|
'''<summary>
|
||||||
|
''' Looks up a localized resource of type System.Drawing.Bitmap.
|
||||||
|
'''</summary>
|
||||||
|
Public ReadOnly Property FilterPic() As System.Drawing.Bitmap
|
||||||
|
Get
|
||||||
|
Dim obj As Object = ResourceManager.GetObject("FilterPic", resourceCulture)
|
||||||
|
Return CType(obj,System.Drawing.Bitmap)
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
End Module
|
End Module
|
||||||
End Namespace
|
End Namespace
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.binary.base64
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
value : The object must be serialized with
|
value : The object must be serialized with
|
||||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
: and then encoded with base64 encoding.
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.soap.base64
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
@@ -60,6 +60,7 @@
|
|||||||
: and then encoded with base64 encoding.
|
: 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: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:element name="root" msdata:IsDataSet="true">
|
||||||
<xsd:complexType>
|
<xsd:complexType>
|
||||||
<xsd:choice maxOccurs="unbounded">
|
<xsd:choice maxOccurs="unbounded">
|
||||||
@@ -68,9 +69,10 @@
|
|||||||
<xsd:sequence>
|
<xsd:sequence>
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
</xsd:sequence>
|
</xsd:sequence>
|
||||||
<xsd:attribute name="name" type="xsd:string" />
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
<xsd:attribute name="type" type="xsd:string" />
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
</xsd:complexType>
|
</xsd:complexType>
|
||||||
</xsd:element>
|
</xsd:element>
|
||||||
<xsd:element name="assembly">
|
<xsd:element name="assembly">
|
||||||
@@ -85,9 +87,10 @@
|
|||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
<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:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
</xsd:sequence>
|
</xsd:sequence>
|
||||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
<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="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
</xsd:complexType>
|
</xsd:complexType>
|
||||||
</xsd:element>
|
</xsd:element>
|
||||||
<xsd:element name="resheader">
|
<xsd:element name="resheader">
|
||||||
@@ -109,9 +112,16 @@
|
|||||||
<value>2.0</value>
|
<value>2.0</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
<resheader name="reader">
|
<resheader name="reader">
|
||||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
|
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||||
|
<data name="FilterIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
|
<value>..\Content\Icons\FilterIcon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
|
</data>
|
||||||
|
<data name="FilterPic" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
|
<value>..\Content\Images\FilterPic.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -82,6 +82,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Data" />
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
<Reference Include="System.Windows.Forms" />
|
<Reference Include="System.Windows.Forms" />
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
@@ -123,7 +124,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="My Project\Resources.resx">
|
<EmbeddedResource Include="My Project\Resources.resx">
|
||||||
<Generator>VbMyResourcesResXFileCodeGenerator</Generator>
|
<Generator>PublicVbMyResourcesResXFileCodeGenerator</Generator>
|
||||||
<LastGenOutput>Resources.Designer.vb</LastGenOutput>
|
<LastGenOutput>Resources.Designer.vb</LastGenOutput>
|
||||||
<CustomToolNamespace>My.Resources</CustomToolNamespace>
|
<CustomToolNamespace>My.Resources</CustomToolNamespace>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
@@ -147,5 +148,9 @@
|
|||||||
<Name>PersonalUtilities</Name>
|
<Name>PersonalUtilities</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="Content\Icons\FilterIcon.ico" />
|
||||||
|
<Content Include="Content\Images\FilterPic.png" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
|
||||||
</Project>
|
</Project>
|
||||||
@@ -18,6 +18,7 @@ Namespace API.YouTube.Base
|
|||||||
Public Const TrueUrlPattern As String = "https?://[^/]*?youtube.com/[^\?/&]+((\??[^\?/&]+|/[^\?/&]+))"
|
Public Const TrueUrlPattern As String = "https?://[^/]*?youtube.com/[^\?/&]+((\??[^\?/&]+|/[^\?/&]+))"
|
||||||
'2 - type; 5 - id
|
'2 - type; 5 - id
|
||||||
Public Const UrlTypePattern As String = "(?<=https?://[^/]*?youtube.com/)((@|[^\?/&]+))([/\?]{0,1}(list=|v=|)([^\?/&]*))(?=(\S+|\Z|))"
|
Public Const UrlTypePattern As String = "(?<=https?://[^/]*?youtube.com/)((@|[^\?/&]+))([/\?]{0,1}(list=|v=|)([^\?/&]*))(?=(\S+|\Z|))"
|
||||||
|
Public Const UrlTypePattern_BE As String = "(?<=https?://[^/]*?youtu.be/)([^\?/&]+)"
|
||||||
Private Sub New()
|
Private Sub New()
|
||||||
End Sub
|
End Sub
|
||||||
Public Shared Function StandardizeURL(ByVal URL As String) As String
|
Public Shared Function StandardizeURL(ByVal URL As String) As String
|
||||||
@@ -36,6 +37,7 @@ Namespace API.YouTube.Base
|
|||||||
Next
|
Next
|
||||||
data.Clear()
|
data.Clear()
|
||||||
End If
|
End If
|
||||||
|
If val.IsEmptyString Then val = RegexReplace(URL, RParams.DMS(UrlTypePattern_BE, 0, EDP.ReturnValue))
|
||||||
If Not val.IsEmptyString Then Return $"https://www.youtube.com/watch?v={val}"
|
If Not val.IsEmptyString Then Return $"https://www.youtube.com/watch?v={val}"
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
@@ -100,6 +102,9 @@ Namespace API.YouTube.Base
|
|||||||
Return YouTubeMediaType.Channel
|
Return YouTubeMediaType.Channel
|
||||||
End Select
|
End Select
|
||||||
End If
|
End If
|
||||||
|
Else
|
||||||
|
Dim v$ = RegexReplace(URL, RParams.DMS(UrlTypePattern_BE, 0, EDP.ReturnValue))
|
||||||
|
If Not v.IsEmptyString Then Return YouTubeMediaType.Single
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
Return YouTubeMediaType.Undefined
|
Return YouTubeMediaType.Undefined
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ Namespace API.YouTube.Base
|
|||||||
#Region "Declarations"
|
#Region "Declarations"
|
||||||
<Browsable(False)> Private ReadOnly Property XML As XmlFile Implements IXMLValuesContainer.XML
|
<Browsable(False)> Private ReadOnly Property XML As XmlFile Implements IXMLValuesContainer.XML
|
||||||
<Browsable(False)> Friend ReadOnly Property DesignXml As XmlFile
|
<Browsable(False)> Friend ReadOnly Property DesignXml As XmlFile
|
||||||
|
<Browsable(False)> Friend ReadOnly Property FILTER As Controls.YTDataFilter
|
||||||
<Browsable(False)> Private Property Mode As GridUpdateModes = GridUpdateModes.OnConfirm Implements IGridValuesContainer.Mode
|
<Browsable(False)> Private Property Mode As GridUpdateModes = GridUpdateModes.OnConfirm Implements IGridValuesContainer.Mode
|
||||||
<Browsable(False), XMLVV(-1)> Friend ReadOnly Property PlaylistFormSplitterDistance As XMLValue(Of Integer)
|
<Browsable(False), XMLVV(-1)> Friend ReadOnly Property PlaylistFormSplitterDistance As XMLValue(Of Integer)
|
||||||
<Browsable(False)> Friend ReadOnly Property DownloadLocations As DownloadLocationsCollection
|
<Browsable(False)> Friend ReadOnly Property DownloadLocations As DownloadLocationsCollection
|
||||||
@@ -168,9 +169,6 @@ Namespace API.YouTube.Base
|
|||||||
<Browsable(True), GridVisible, XMLVN({"Info"}), Category("Info"), DisplayName("Create description files"),
|
<Browsable(True), GridVisible, XMLVN({"Info"}), Category("Info"), DisplayName("Create description files"),
|
||||||
Description("Create video description files. Default: false.")>
|
Description("Create video description files. Default: false.")>
|
||||||
Public ReadOnly Property CreateDescriptionFiles As XMLValue(Of Boolean)
|
Public ReadOnly Property CreateDescriptionFiles As XMLValue(Of Boolean)
|
||||||
<Browsable(True), GridVisible, XMLVN({"Info"}, True), Category("Info"), DisplayName("Create description files: add upload date"),
|
|
||||||
Description("Add the upload date to the top of the description file. Default: true.")>
|
|
||||||
Public ReadOnly Property CreateDescriptionFiles_AddUploadDate As XMLValue(Of Boolean)
|
|
||||||
<Browsable(True), GridVisible, XMLVN({"Info"}, True), Category("Info"), DisplayName("Create description files: create without description"),
|
<Browsable(True), GridVisible, XMLVN({"Info"}, True), Category("Info"), DisplayName("Create description files: create without description"),
|
||||||
Description("Create a description file with the upload date, even if the description does not exist. Default: true.")>
|
Description("Create a description file with the upload date, even if the description does not exist. Default: true.")>
|
||||||
Public ReadOnly Property CreateDescriptionFiles_CreateWithNoDescription As XMLValue(Of Boolean)
|
Public ReadOnly Property CreateDescriptionFiles_CreateWithNoDescription As XMLValue(Of Boolean)
|
||||||
@@ -191,7 +189,7 @@ Namespace API.YouTube.Base
|
|||||||
<Browsable(True), GridVisible, XMLVN({"Defaults"}), Category("Defaults"), DisplayName("Use cookies"),
|
<Browsable(True), GridVisible, XMLVN({"Defaults"}), Category("Defaults"), DisplayName("Use cookies"),
|
||||||
Description("By default, use cookies when downloading from YouTube.")>
|
Description("By default, use cookies when downloading from YouTube.")>
|
||||||
Public ReadOnly Property DefaultUseCookies As XMLValue(Of Boolean)
|
Public ReadOnly Property DefaultUseCookies As XMLValue(Of Boolean)
|
||||||
<Browsable(True), GridVisible, XMLVN({"Defaults"}, Protocols.Any), Category("Defaults"), DisplayName("Protocol"),
|
<Browsable(True), GridVisible, XMLVN({"Defaults"}, Protocols.https), Category("Defaults"), DisplayName("Protocol"),
|
||||||
Description("Priority download protocol. Default: 'Any'")>
|
Description("Priority download protocol. Default: 'Any'")>
|
||||||
Public ReadOnly Property DefaultProtocol As XMLValue(Of Protocols)
|
Public ReadOnly Property DefaultProtocol As XMLValue(Of Protocols)
|
||||||
<Browsable(True), GridVisible(False), XMLVN({"Defaults"}), Category("Defaults"),
|
<Browsable(True), GridVisible(False), XMLVN({"Defaults"}), Category("Defaults"),
|
||||||
@@ -267,6 +265,9 @@ Namespace API.YouTube.Base
|
|||||||
<Browsable(True), GridVisible, XMLVN({"Defaults"}), Category("Defaults"), DisplayName("Add date to title: video list"),
|
<Browsable(True), GridVisible, XMLVN({"Defaults"}), Category("Defaults"), DisplayName("Add date to title: video list"),
|
||||||
Description("Add video upload date before video title (visual only) in the video list")>
|
Description("Add video upload date before video title (visual only) in the video list")>
|
||||||
Public ReadOnly Property FileAddDateToFileName_VideoList As XMLValue(Of Boolean)
|
Public ReadOnly Property FileAddDateToFileName_VideoList As XMLValue(Of Boolean)
|
||||||
|
<Browsable(True), GridVisible, XMLVN({"Defaults"}, FileDateMode.None), Category("Defaults"), DisplayName("Add channel to file name"),
|
||||||
|
Description("Add channel name before/after the file name")>
|
||||||
|
Public ReadOnly Property FileAddChannelToFileName As XMLValue(Of FileDateMode)
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Defaults ChannelsDownload"
|
#Region "Defaults ChannelsDownload"
|
||||||
<Browsable(True), GridVisible, XMLVN({"Defaults", "Channels"}), Category("Defaults"), DisplayName("Default download tabs for channels"),
|
<Browsable(True), GridVisible, XMLVN({"Defaults", "Channels"}), Category("Defaults"), DisplayName("Default download tabs for channels"),
|
||||||
@@ -311,6 +312,9 @@ Namespace API.YouTube.Base
|
|||||||
<Browsable(True), GridVisible, XMLVN({"DefaultsVideo"}, 1080), Category("Defaults Video"), DisplayName("Default definition"),
|
<Browsable(True), GridVisible, XMLVN({"DefaultsVideo"}, 1080), Category("Defaults Video"), DisplayName("Default definition"),
|
||||||
Description("The default maximum video resolution. -1 for max definition")>
|
Description("The default maximum video resolution. -1 for max definition")>
|
||||||
Public ReadOnly Property DefaultVideoDefinition As XMLValue(Of Integer)
|
Public ReadOnly Property DefaultVideoDefinition As XMLValue(Of Integer)
|
||||||
|
<Browsable(True), GridVisible, XMLVN({"DefaultsVideo"}, True), Category("Defaults Video"), DisplayName("Allow webm formats"),
|
||||||
|
Description("Allow webm formats over http if mp4 formats are not available. Default: true.")>
|
||||||
|
Public ReadOnly Property DefaultVideoAllowWebm As XMLValue(Of Boolean)
|
||||||
<Browsable(True), GridVisible, XMLVN({"DefaultsVideo"}), Category("Defaults Video"), DisplayName("Convert non-AVC codecs to AVC"),
|
<Browsable(True), GridVisible, XMLVN({"DefaultsVideo"}), Category("Defaults Video"), DisplayName("Convert non-AVC codecs to AVC"),
|
||||||
Description("Convert non-AVC codecs (eg 'VP9') to AVC. Not recommended due to high CPU usage!")>
|
Description("Convert non-AVC codecs (eg 'VP9') to AVC. Not recommended due to high CPU usage!")>
|
||||||
Public ReadOnly Property DefaultVideoConvertNonAVC As XMLValue(Of Boolean)
|
Public ReadOnly Property DefaultVideoConvertNonAVC As XMLValue(Of Boolean)
|
||||||
@@ -416,6 +420,9 @@ Namespace API.YouTube.Base
|
|||||||
<Browsable(True), GridVisible, XMLVN({"DefaultsAudio"}, True), Category("Defaults Audio"), DisplayName("Embed thumbnail"),
|
<Browsable(True), GridVisible, XMLVN({"DefaultsAudio"}, True), Category("Defaults Audio"), DisplayName("Embed thumbnail"),
|
||||||
Description("Embed thumbnail in the audio as cover art. Default: true.")>
|
Description("Embed thumbnail in the audio as cover art. Default: true.")>
|
||||||
Public ReadOnly Property DefaultAudioEmbedThumbnail As XMLValue(Of Boolean)
|
Public ReadOnly Property DefaultAudioEmbedThumbnail As XMLValue(Of Boolean)
|
||||||
|
<Browsable(True), GridVisible, XMLVN({"DefaultsAudio"}, True), Category("Defaults Audio"), DisplayName("Embed thumbnail (cover)"),
|
||||||
|
Description("Try embedding the playlist cover (if it exists) as cover art. Default: true.")>
|
||||||
|
Public ReadOnly Property DefaultAudioEmbedThumbnail_Cover As XMLValue(Of Boolean)
|
||||||
<Browsable(True), GridVisible, XMLVN({"DefaultsAudio"}, True), Category("Defaults Audio"), DisplayName("Embed thumbnail (extracted files)"),
|
<Browsable(True), GridVisible, XMLVN({"DefaultsAudio"}, True), Category("Defaults Audio"), DisplayName("Embed thumbnail (extracted files)"),
|
||||||
Description("Embed thumbnail in the extracted (additional file ('mp3' only)) audio as cover art. Default: true.")>
|
Description("Embed thumbnail in the extracted (additional file ('mp3' only)) audio as cover art. Default: true.")>
|
||||||
Public ReadOnly Property DefaultAudioEmbedThumbnail_ExtractedFiles As XMLValue(Of Boolean)
|
Public ReadOnly Property DefaultAudioEmbedThumbnail_ExtractedFiles As XMLValue(Of Boolean)
|
||||||
@@ -508,6 +515,7 @@ Namespace API.YouTube.Base
|
|||||||
XML.LoadData(EDP.None)
|
XML.LoadData(EDP.None)
|
||||||
DesignXml = New XmlFile("Settings\DesignDownloader.xml", Protector.Modes.All, False)
|
DesignXml = New XmlFile("Settings\DesignDownloader.xml", Protector.Modes.All, False)
|
||||||
DesignXml.LoadData(EDP.None)
|
DesignXml.LoadData(EDP.None)
|
||||||
|
FILTER = New Controls.YTDataFilter
|
||||||
InitializeXMLValueProperties(Me)
|
InitializeXMLValueProperties(Me)
|
||||||
AddHandler ShowNotificationsEveryDownload.TempValueChanged, AddressOf ShowNotificationsEveryDownload_TempValueChanged
|
AddHandler ShowNotificationsEveryDownload.TempValueChanged, AddressOf ShowNotificationsEveryDownload_TempValueChanged
|
||||||
Cookies = New CookieKeeper
|
Cookies = New CookieKeeper
|
||||||
|
|||||||
324
SCrawler.YouTube/Controls/FilterForm.Designer.vb
generated
Normal file
@@ -0,0 +1,324 @@
|
|||||||
|
' Copyright (C) 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.YouTube.Controls
|
||||||
|
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()>
|
||||||
|
Partial Friend Class FilterForm : Inherits System.Windows.Forms.Form
|
||||||
|
<System.Diagnostics.DebuggerNonUserCode()>
|
||||||
|
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
|
||||||
|
Try
|
||||||
|
If disposing AndAlso components IsNot Nothing Then
|
||||||
|
components.Dispose()
|
||||||
|
End If
|
||||||
|
Finally
|
||||||
|
MyBase.Dispose(disposing)
|
||||||
|
End Try
|
||||||
|
End Sub
|
||||||
|
Private components As System.ComponentModel.IContainer
|
||||||
|
<System.Diagnostics.DebuggerStepThrough()>
|
||||||
|
Private Sub InitializeComponent()
|
||||||
|
Dim CONTAINER_MAIN As System.Windows.Forms.ToolStripContainer
|
||||||
|
Dim TP_MAIN As System.Windows.Forms.TableLayoutPanel
|
||||||
|
Dim TP_TYPES As System.Windows.Forms.TableLayoutPanel
|
||||||
|
Dim TP_USERS As System.Windows.Forms.TableLayoutPanel
|
||||||
|
Dim TP_USERS_2 As System.Windows.Forms.TableLayoutPanel
|
||||||
|
Me.CH_FILTER_ALL = New System.Windows.Forms.CheckBox()
|
||||||
|
Me.CH_FILTER_SINGLE = New System.Windows.Forms.CheckBox()
|
||||||
|
Me.CH_FILTER_CHANNEL = New System.Windows.Forms.CheckBox()
|
||||||
|
Me.CH_FILTER_PLS = New System.Windows.Forms.CheckBox()
|
||||||
|
Me.TP_MUSIC = New System.Windows.Forms.TableLayoutPanel()
|
||||||
|
Me.CH_M_ALL = New System.Windows.Forms.CheckBox()
|
||||||
|
Me.CH_M_VIDEO = New System.Windows.Forms.CheckBox()
|
||||||
|
Me.CH_M_MUSIC = New System.Windows.Forms.CheckBox()
|
||||||
|
Me.LIST_USERS = New System.Windows.Forms.CheckedListBox()
|
||||||
|
Me.CH_USERS_USE = New System.Windows.Forms.CheckBox()
|
||||||
|
Me.BTT_SELECT_ALL = New System.Windows.Forms.Button()
|
||||||
|
Me.BTT_SELECT_NONE = New System.Windows.Forms.Button()
|
||||||
|
CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer()
|
||||||
|
TP_MAIN = New System.Windows.Forms.TableLayoutPanel()
|
||||||
|
TP_TYPES = New System.Windows.Forms.TableLayoutPanel()
|
||||||
|
TP_USERS = New System.Windows.Forms.TableLayoutPanel()
|
||||||
|
TP_USERS_2 = New System.Windows.Forms.TableLayoutPanel()
|
||||||
|
CONTAINER_MAIN.ContentPanel.SuspendLayout()
|
||||||
|
CONTAINER_MAIN.SuspendLayout()
|
||||||
|
TP_MAIN.SuspendLayout()
|
||||||
|
TP_TYPES.SuspendLayout()
|
||||||
|
Me.TP_MUSIC.SuspendLayout()
|
||||||
|
TP_USERS.SuspendLayout()
|
||||||
|
TP_USERS_2.SuspendLayout()
|
||||||
|
Me.SuspendLayout()
|
||||||
|
'
|
||||||
|
'CONTAINER_MAIN
|
||||||
|
'
|
||||||
|
'
|
||||||
|
'CONTAINER_MAIN.ContentPanel
|
||||||
|
'
|
||||||
|
CONTAINER_MAIN.ContentPanel.Controls.Add(TP_MAIN)
|
||||||
|
CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(384, 361)
|
||||||
|
CONTAINER_MAIN.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
CONTAINER_MAIN.LeftToolStripPanelVisible = False
|
||||||
|
CONTAINER_MAIN.Location = New System.Drawing.Point(0, 0)
|
||||||
|
CONTAINER_MAIN.Name = "CONTAINER_MAIN"
|
||||||
|
CONTAINER_MAIN.RightToolStripPanelVisible = False
|
||||||
|
CONTAINER_MAIN.Size = New System.Drawing.Size(384, 361)
|
||||||
|
CONTAINER_MAIN.TabIndex = 0
|
||||||
|
CONTAINER_MAIN.TopToolStripPanelVisible = False
|
||||||
|
'
|
||||||
|
'TP_MAIN
|
||||||
|
'
|
||||||
|
TP_MAIN.ColumnCount = 1
|
||||||
|
TP_MAIN.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||||
|
TP_MAIN.Controls.Add(TP_TYPES, 0, 0)
|
||||||
|
TP_MAIN.Controls.Add(Me.TP_MUSIC, 0, 1)
|
||||||
|
TP_MAIN.Controls.Add(TP_USERS, 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 = 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.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20.0!))
|
||||||
|
TP_MAIN.Size = New System.Drawing.Size(384, 361)
|
||||||
|
TP_MAIN.TabIndex = 0
|
||||||
|
'
|
||||||
|
'TP_TYPES
|
||||||
|
'
|
||||||
|
TP_TYPES.ColumnCount = 4
|
||||||
|
TP_TYPES.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25.0!))
|
||||||
|
TP_TYPES.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25.0!))
|
||||||
|
TP_TYPES.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25.0!))
|
||||||
|
TP_TYPES.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25.0!))
|
||||||
|
TP_TYPES.Controls.Add(Me.CH_FILTER_ALL, 0, 0)
|
||||||
|
TP_TYPES.Controls.Add(Me.CH_FILTER_SINGLE, 1, 0)
|
||||||
|
TP_TYPES.Controls.Add(Me.CH_FILTER_CHANNEL, 2, 0)
|
||||||
|
TP_TYPES.Controls.Add(Me.CH_FILTER_PLS, 3, 0)
|
||||||
|
TP_TYPES.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
TP_TYPES.Location = New System.Drawing.Point(0, 0)
|
||||||
|
TP_TYPES.Margin = New System.Windows.Forms.Padding(0)
|
||||||
|
TP_TYPES.Name = "TP_TYPES"
|
||||||
|
TP_TYPES.RowCount = 1
|
||||||
|
TP_TYPES.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||||
|
TP_TYPES.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||||
|
TP_TYPES.Size = New System.Drawing.Size(384, 25)
|
||||||
|
TP_TYPES.TabIndex = 0
|
||||||
|
'
|
||||||
|
'CH_FILTER_ALL
|
||||||
|
'
|
||||||
|
Me.CH_FILTER_ALL.AutoSize = True
|
||||||
|
Me.CH_FILTER_ALL.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.CH_FILTER_ALL.Location = New System.Drawing.Point(3, 3)
|
||||||
|
Me.CH_FILTER_ALL.Name = "CH_FILTER_ALL"
|
||||||
|
Me.CH_FILTER_ALL.Size = New System.Drawing.Size(90, 19)
|
||||||
|
Me.CH_FILTER_ALL.TabIndex = 0
|
||||||
|
Me.CH_FILTER_ALL.Text = "ALL"
|
||||||
|
Me.CH_FILTER_ALL.UseVisualStyleBackColor = True
|
||||||
|
'
|
||||||
|
'CH_FILTER_SINGLE
|
||||||
|
'
|
||||||
|
Me.CH_FILTER_SINGLE.AutoSize = True
|
||||||
|
Me.CH_FILTER_SINGLE.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.CH_FILTER_SINGLE.Location = New System.Drawing.Point(99, 3)
|
||||||
|
Me.CH_FILTER_SINGLE.Name = "CH_FILTER_SINGLE"
|
||||||
|
Me.CH_FILTER_SINGLE.Size = New System.Drawing.Size(90, 19)
|
||||||
|
Me.CH_FILTER_SINGLE.TabIndex = 1
|
||||||
|
Me.CH_FILTER_SINGLE.Text = "Single"
|
||||||
|
Me.CH_FILTER_SINGLE.UseVisualStyleBackColor = True
|
||||||
|
'
|
||||||
|
'CH_FILTER_CHANNEL
|
||||||
|
'
|
||||||
|
Me.CH_FILTER_CHANNEL.AutoSize = True
|
||||||
|
Me.CH_FILTER_CHANNEL.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.CH_FILTER_CHANNEL.Location = New System.Drawing.Point(195, 3)
|
||||||
|
Me.CH_FILTER_CHANNEL.Name = "CH_FILTER_CHANNEL"
|
||||||
|
Me.CH_FILTER_CHANNEL.Size = New System.Drawing.Size(90, 19)
|
||||||
|
Me.CH_FILTER_CHANNEL.TabIndex = 2
|
||||||
|
Me.CH_FILTER_CHANNEL.Text = "Channel"
|
||||||
|
Me.CH_FILTER_CHANNEL.UseVisualStyleBackColor = True
|
||||||
|
'
|
||||||
|
'CH_FILTER_PLS
|
||||||
|
'
|
||||||
|
Me.CH_FILTER_PLS.AutoSize = True
|
||||||
|
Me.CH_FILTER_PLS.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.CH_FILTER_PLS.Location = New System.Drawing.Point(291, 3)
|
||||||
|
Me.CH_FILTER_PLS.Name = "CH_FILTER_PLS"
|
||||||
|
Me.CH_FILTER_PLS.Size = New System.Drawing.Size(90, 19)
|
||||||
|
Me.CH_FILTER_PLS.TabIndex = 3
|
||||||
|
Me.CH_FILTER_PLS.Text = "Playlist"
|
||||||
|
Me.CH_FILTER_PLS.UseVisualStyleBackColor = True
|
||||||
|
'
|
||||||
|
'TP_MUSIC
|
||||||
|
'
|
||||||
|
Me.TP_MUSIC.ColumnCount = 3
|
||||||
|
Me.TP_MUSIC.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333!))
|
||||||
|
Me.TP_MUSIC.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333!))
|
||||||
|
Me.TP_MUSIC.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333!))
|
||||||
|
Me.TP_MUSIC.Controls.Add(Me.CH_M_ALL, 0, 0)
|
||||||
|
Me.TP_MUSIC.Controls.Add(Me.CH_M_VIDEO, 1, 0)
|
||||||
|
Me.TP_MUSIC.Controls.Add(Me.CH_M_MUSIC, 2, 0)
|
||||||
|
Me.TP_MUSIC.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.TP_MUSIC.Location = New System.Drawing.Point(0, 25)
|
||||||
|
Me.TP_MUSIC.Margin = New System.Windows.Forms.Padding(0)
|
||||||
|
Me.TP_MUSIC.Name = "TP_MUSIC"
|
||||||
|
Me.TP_MUSIC.RowCount = 1
|
||||||
|
Me.TP_MUSIC.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||||
|
Me.TP_MUSIC.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||||
|
Me.TP_MUSIC.Size = New System.Drawing.Size(384, 25)
|
||||||
|
Me.TP_MUSIC.TabIndex = 1
|
||||||
|
'
|
||||||
|
'CH_M_ALL
|
||||||
|
'
|
||||||
|
Me.CH_M_ALL.AutoSize = True
|
||||||
|
Me.CH_M_ALL.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.CH_M_ALL.Location = New System.Drawing.Point(3, 3)
|
||||||
|
Me.CH_M_ALL.Name = "CH_M_ALL"
|
||||||
|
Me.CH_M_ALL.Size = New System.Drawing.Size(122, 19)
|
||||||
|
Me.CH_M_ALL.TabIndex = 0
|
||||||
|
Me.CH_M_ALL.Text = "ALL"
|
||||||
|
Me.CH_M_ALL.UseVisualStyleBackColor = True
|
||||||
|
'
|
||||||
|
'CH_M_VIDEO
|
||||||
|
'
|
||||||
|
Me.CH_M_VIDEO.AutoSize = True
|
||||||
|
Me.CH_M_VIDEO.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.CH_M_VIDEO.Location = New System.Drawing.Point(131, 3)
|
||||||
|
Me.CH_M_VIDEO.Name = "CH_M_VIDEO"
|
||||||
|
Me.CH_M_VIDEO.Size = New System.Drawing.Size(122, 19)
|
||||||
|
Me.CH_M_VIDEO.TabIndex = 1
|
||||||
|
Me.CH_M_VIDEO.Text = "Video"
|
||||||
|
Me.CH_M_VIDEO.UseVisualStyleBackColor = True
|
||||||
|
'
|
||||||
|
'CH_M_MUSIC
|
||||||
|
'
|
||||||
|
Me.CH_M_MUSIC.AutoSize = True
|
||||||
|
Me.CH_M_MUSIC.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.CH_M_MUSIC.Location = New System.Drawing.Point(259, 3)
|
||||||
|
Me.CH_M_MUSIC.Name = "CH_M_MUSIC"
|
||||||
|
Me.CH_M_MUSIC.Size = New System.Drawing.Size(122, 19)
|
||||||
|
Me.CH_M_MUSIC.TabIndex = 2
|
||||||
|
Me.CH_M_MUSIC.Text = "Music"
|
||||||
|
Me.CH_M_MUSIC.UseVisualStyleBackColor = True
|
||||||
|
'
|
||||||
|
'TP_USERS
|
||||||
|
'
|
||||||
|
TP_USERS.ColumnCount = 1
|
||||||
|
TP_USERS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||||
|
TP_USERS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20.0!))
|
||||||
|
TP_USERS.Controls.Add(Me.LIST_USERS, 0, 1)
|
||||||
|
TP_USERS.Controls.Add(TP_USERS_2, 0, 0)
|
||||||
|
TP_USERS.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
TP_USERS.Location = New System.Drawing.Point(0, 50)
|
||||||
|
TP_USERS.Margin = New System.Windows.Forms.Padding(0)
|
||||||
|
TP_USERS.Name = "TP_USERS"
|
||||||
|
TP_USERS.RowCount = 2
|
||||||
|
TP_USERS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||||
|
TP_USERS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||||
|
TP_USERS.Size = New System.Drawing.Size(384, 311)
|
||||||
|
TP_USERS.TabIndex = 3
|
||||||
|
'
|
||||||
|
'LIST_USERS
|
||||||
|
'
|
||||||
|
Me.LIST_USERS.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.LIST_USERS.FormattingEnabled = True
|
||||||
|
Me.LIST_USERS.Location = New System.Drawing.Point(3, 28)
|
||||||
|
Me.LIST_USERS.Name = "LIST_USERS"
|
||||||
|
Me.LIST_USERS.Size = New System.Drawing.Size(378, 280)
|
||||||
|
Me.LIST_USERS.TabIndex = 1
|
||||||
|
'
|
||||||
|
'TP_USERS_2
|
||||||
|
'
|
||||||
|
TP_USERS_2.ColumnCount = 3
|
||||||
|
TP_USERS_2.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333!))
|
||||||
|
TP_USERS_2.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333!))
|
||||||
|
TP_USERS_2.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333!))
|
||||||
|
TP_USERS_2.Controls.Add(Me.CH_USERS_USE, 0, 0)
|
||||||
|
TP_USERS_2.Controls.Add(Me.BTT_SELECT_ALL, 1, 0)
|
||||||
|
TP_USERS_2.Controls.Add(Me.BTT_SELECT_NONE, 2, 0)
|
||||||
|
TP_USERS_2.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
TP_USERS_2.Location = New System.Drawing.Point(0, 0)
|
||||||
|
TP_USERS_2.Margin = New System.Windows.Forms.Padding(0)
|
||||||
|
TP_USERS_2.Name = "TP_USERS_2"
|
||||||
|
TP_USERS_2.RowCount = 1
|
||||||
|
TP_USERS_2.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||||
|
TP_USERS_2.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||||
|
TP_USERS_2.Size = New System.Drawing.Size(384, 25)
|
||||||
|
TP_USERS_2.TabIndex = 0
|
||||||
|
'
|
||||||
|
'CH_USERS_USE
|
||||||
|
'
|
||||||
|
Me.CH_USERS_USE.AutoSize = True
|
||||||
|
Me.CH_USERS_USE.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.CH_USERS_USE.Location = New System.Drawing.Point(3, 3)
|
||||||
|
Me.CH_USERS_USE.Name = "CH_USERS_USE"
|
||||||
|
Me.CH_USERS_USE.Size = New System.Drawing.Size(122, 19)
|
||||||
|
Me.CH_USERS_USE.TabIndex = 0
|
||||||
|
Me.CH_USERS_USE.Text = "Filter users"
|
||||||
|
Me.CH_USERS_USE.UseVisualStyleBackColor = True
|
||||||
|
'
|
||||||
|
'BTT_SELECT_ALL
|
||||||
|
'
|
||||||
|
Me.BTT_SELECT_ALL.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.BTT_SELECT_ALL.Location = New System.Drawing.Point(129, 1)
|
||||||
|
Me.BTT_SELECT_ALL.Margin = New System.Windows.Forms.Padding(1)
|
||||||
|
Me.BTT_SELECT_ALL.Name = "BTT_SELECT_ALL"
|
||||||
|
Me.BTT_SELECT_ALL.Size = New System.Drawing.Size(126, 23)
|
||||||
|
Me.BTT_SELECT_ALL.TabIndex = 1
|
||||||
|
Me.BTT_SELECT_ALL.Text = "All"
|
||||||
|
Me.BTT_SELECT_ALL.UseVisualStyleBackColor = True
|
||||||
|
'
|
||||||
|
'BTT_SELECT_NONE
|
||||||
|
'
|
||||||
|
Me.BTT_SELECT_NONE.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.BTT_SELECT_NONE.Location = New System.Drawing.Point(257, 1)
|
||||||
|
Me.BTT_SELECT_NONE.Margin = New System.Windows.Forms.Padding(1)
|
||||||
|
Me.BTT_SELECT_NONE.Name = "BTT_SELECT_NONE"
|
||||||
|
Me.BTT_SELECT_NONE.Size = New System.Drawing.Size(126, 23)
|
||||||
|
Me.BTT_SELECT_NONE.TabIndex = 2
|
||||||
|
Me.BTT_SELECT_NONE.Text = "None"
|
||||||
|
Me.BTT_SELECT_NONE.UseVisualStyleBackColor = True
|
||||||
|
'
|
||||||
|
'FilterForm
|
||||||
|
'
|
||||||
|
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
|
||||||
|
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
|
||||||
|
Me.ClientSize = New System.Drawing.Size(384, 361)
|
||||||
|
Me.Controls.Add(CONTAINER_MAIN)
|
||||||
|
Me.MinimizeBox = False
|
||||||
|
Me.MinimumSize = New System.Drawing.Size(400, 400)
|
||||||
|
Me.Name = "FilterForm"
|
||||||
|
Me.ShowInTaskbar = False
|
||||||
|
Me.Text = "Filter"
|
||||||
|
CONTAINER_MAIN.ContentPanel.ResumeLayout(False)
|
||||||
|
CONTAINER_MAIN.ResumeLayout(False)
|
||||||
|
CONTAINER_MAIN.PerformLayout()
|
||||||
|
TP_MAIN.ResumeLayout(False)
|
||||||
|
TP_TYPES.ResumeLayout(False)
|
||||||
|
TP_TYPES.PerformLayout()
|
||||||
|
Me.TP_MUSIC.ResumeLayout(False)
|
||||||
|
Me.TP_MUSIC.PerformLayout()
|
||||||
|
TP_USERS.ResumeLayout(False)
|
||||||
|
TP_USERS_2.ResumeLayout(False)
|
||||||
|
TP_USERS_2.PerformLayout()
|
||||||
|
Me.ResumeLayout(False)
|
||||||
|
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
Private WithEvents CH_FILTER_ALL As CheckBox
|
||||||
|
Private WithEvents CH_FILTER_SINGLE As CheckBox
|
||||||
|
Private WithEvents CH_FILTER_CHANNEL As CheckBox
|
||||||
|
Private WithEvents CH_FILTER_PLS As CheckBox
|
||||||
|
Private WithEvents TP_MUSIC As TableLayoutPanel
|
||||||
|
Private WithEvents CH_M_ALL As CheckBox
|
||||||
|
Private WithEvents CH_M_VIDEO As CheckBox
|
||||||
|
Private WithEvents CH_M_MUSIC As CheckBox
|
||||||
|
Private WithEvents LIST_USERS As CheckedListBox
|
||||||
|
Private WithEvents CH_USERS_USE As CheckBox
|
||||||
|
Private WithEvents BTT_SELECT_ALL As Button
|
||||||
|
Private WithEvents BTT_SELECT_NONE As Button
|
||||||
|
End Class
|
||||||
|
End Namespace
|
||||||
135
SCrawler.YouTube/Controls/FilterForm.resx
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
<?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>
|
||||||
|
<metadata name="TP_TYPES.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>False</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="TP_USERS.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>False</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="TP_USERS_2.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>False</value>
|
||||||
|
</metadata>
|
||||||
|
</root>
|
||||||
181
SCrawler.YouTube/Controls/FilterForm.vb
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
' Copyright (C) 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.YouTube.Base
|
||||||
|
Imports SCrawler.API.YouTube.Objects
|
||||||
|
Imports PersonalUtilities.Forms
|
||||||
|
Imports SimpleUser = SCrawler.API.YouTube.Controls.YTDataFilter.SimpleUser
|
||||||
|
Namespace API.YouTube.Controls
|
||||||
|
Friend Class FilterForm
|
||||||
|
Private WithEvents MyDefs As DefaultFormOptions
|
||||||
|
Friend ReadOnly Property DATA As List(Of IYouTubeMediaContainer)
|
||||||
|
Private ReadOnly Property DataTMP As List(Of IYouTubeMediaContainer)
|
||||||
|
Private ReadOnly Property MyFilterTmp As YTDataFilter
|
||||||
|
Private ReadOnly Property MyTmpUsers As List(Of SimpleUser)
|
||||||
|
Friend Sub New(ByVal d As IEnumerable(Of IYouTubeMediaContainer))
|
||||||
|
InitializeComponent()
|
||||||
|
MyDefs = New DefaultFormOptions(Me, MyYouTubeSettings.DesignXml)
|
||||||
|
DATA = New List(Of IYouTubeMediaContainer)
|
||||||
|
DATA.ListAddList(d)
|
||||||
|
DataTMP = New List(Of IYouTubeMediaContainer)
|
||||||
|
DataTMP.ListAddList(d)
|
||||||
|
MyFilterTmp = New YTDataFilter(MyYouTubeSettings.FILTER)
|
||||||
|
MyTmpUsers = New List(Of SimpleUser)
|
||||||
|
Icon = My.Resources.FilterIcon
|
||||||
|
End Sub
|
||||||
|
Private Sub FilterForm_Load(sender As Object, e As EventArgs) Handles Me.Load
|
||||||
|
Try
|
||||||
|
With MyDefs
|
||||||
|
.MyViewInitialize()
|
||||||
|
.AddOkCancelToolbar(True)
|
||||||
|
|
||||||
|
With MyYouTubeSettings.FILTER
|
||||||
|
With .Types
|
||||||
|
If .Count = 0 Or (.Count = 1 AndAlso .Item(0) = YouTubeMediaType.Undefined) Then
|
||||||
|
CH_FILTER_ALL.Checked = True
|
||||||
|
Else
|
||||||
|
If .Contains(YouTubeMediaType.Single) Then CH_FILTER_SINGLE.Checked = True
|
||||||
|
If .Contains(YouTubeMediaType.Channel) Then CH_FILTER_CHANNEL.Checked = True
|
||||||
|
If .Contains(YouTubeMediaType.PlayList) Then CH_FILTER_PLS.Checked = True
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
If .IsMusic And .IsVideo Then
|
||||||
|
CH_M_ALL.Checked = True
|
||||||
|
Else
|
||||||
|
CH_M_MUSIC.Checked = .IsMusic
|
||||||
|
CH_M_VIDEO.Checked = .IsVideo
|
||||||
|
End If
|
||||||
|
|
||||||
|
CH_USERS_USE.Checked = .UserList.Count > 0
|
||||||
|
End With
|
||||||
|
|
||||||
|
.EndLoaderOperations()
|
||||||
|
_RefillEnabled = True
|
||||||
|
RefillList(True)
|
||||||
|
CH_USERS_USE_CheckedChanged()
|
||||||
|
End With
|
||||||
|
Catch ex As Exception
|
||||||
|
MyDefs.InvokeLoaderError(ex)
|
||||||
|
End Try
|
||||||
|
End Sub
|
||||||
|
Private Sub FilterForm_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed
|
||||||
|
DATA.ListClearDispose
|
||||||
|
DataTMP.ListClearDispose
|
||||||
|
MyTmpUsers.ListClearDispose
|
||||||
|
End Sub
|
||||||
|
Private _RefillEnabled As Boolean = False
|
||||||
|
Private Sub RefillList(Optional ByVal Init As Boolean = False)
|
||||||
|
If Not MyDefs.Initializing And _RefillEnabled Then
|
||||||
|
ApplyFilter(MyFilterTmp, Init)
|
||||||
|
MyFilterTmp.Populate(DATA, DataTMP, CH_USERS_USE.Checked)
|
||||||
|
With DataTMP
|
||||||
|
If .Count > 0 Then
|
||||||
|
Dim tmpUsers As New List(Of SimpleUser)
|
||||||
|
tmpUsers.ListAddList(DataTMP, LAP.NotContainsOnly, CType(Function(obj As YouTubeMediaContainerBase) CType(obj, SimpleUser), Func(Of Object, Object)))
|
||||||
|
If tmpUsers.Count > 0 Then
|
||||||
|
tmpUsers.Sort()
|
||||||
|
LIST_USERS.BeginUpdate()
|
||||||
|
LIST_USERS.Items.Clear()
|
||||||
|
tmpUsers.ForEach(Sub(u) LIST_USERS.Items.Add(u, True))
|
||||||
|
|
||||||
|
If CH_USERS_USE.Checked And MyFilterTmp.UserList.Count > 0 Then
|
||||||
|
For i% = 0 To LIST_USERS.Items.Count - 1
|
||||||
|
LIST_USERS.SetItemChecked(i, MyFilterTmp.UserList.Contains(LIST_USERS.Items(i)))
|
||||||
|
Next
|
||||||
|
End If
|
||||||
|
|
||||||
|
LIST_USERS.EndUpdate()
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
End If
|
||||||
|
End Sub
|
||||||
|
Private Sub ApplyFilter(ByRef Filter As YTDataFilter, ByVal Init As Boolean)
|
||||||
|
With Filter
|
||||||
|
.Reset(False, Not Init)
|
||||||
|
With .Types
|
||||||
|
If CH_FILTER_ALL.Checked Then
|
||||||
|
.Add(YouTubeMediaType.Undefined)
|
||||||
|
Else
|
||||||
|
If CH_FILTER_SINGLE.Checked Then .Add(YouTubeMediaType.Single)
|
||||||
|
If CH_FILTER_CHANNEL.Checked Then .Add(YouTubeMediaType.Channel)
|
||||||
|
If CH_FILTER_PLS.Checked Then .Add(YouTubeMediaType.PlayList)
|
||||||
|
End If
|
||||||
|
If .Count = 0 Then .Add(YouTubeMediaType.Undefined)
|
||||||
|
End With
|
||||||
|
If CH_M_ALL.Checked Then
|
||||||
|
.IsMusic = True
|
||||||
|
.IsVideo = True
|
||||||
|
Else
|
||||||
|
If CH_M_MUSIC.Checked Then .IsMusic = True
|
||||||
|
If CH_M_VIDEO.Checked Then .IsVideo = True
|
||||||
|
End If
|
||||||
|
If Not .IsVideo And Not .IsMusic Then .IsMusic = True : .IsVideo = True
|
||||||
|
|
||||||
|
If CH_USERS_USE.Checked And Not Init Then
|
||||||
|
.UserList.Clear()
|
||||||
|
If LIST_USERS.CheckedItems.Count > 0 Then
|
||||||
|
For Each item In LIST_USERS.CheckedItems : .UserList.Add(item) : Next
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
End Sub
|
||||||
|
Private Sub MyDefs_ButtonOkClick(ByVal Sender As Object, ByVal e As KeyHandleEventArgs) Handles MyDefs.ButtonOkClick
|
||||||
|
ApplyFilter(MyYouTubeSettings.FILTER, False)
|
||||||
|
MyYouTubeSettings.FILTER.RemoveAll(DATA)
|
||||||
|
MyYouTubeSettings.FILTER.Update()
|
||||||
|
MyDefs.CloseForm()
|
||||||
|
End Sub
|
||||||
|
Private Sub MyDefs_ButtonDeleteClickOC(ByVal Sender As Object, ByVal e As KeyHandleEventArgs) Handles MyDefs.ButtonDeleteClickOC
|
||||||
|
With MyYouTubeSettings.FILTER : .Reset() : .Update() : End With
|
||||||
|
MyDefs.CloseForm()
|
||||||
|
End Sub
|
||||||
|
Private Sub UpdateControlOptions(ByRef CNT As CheckBox, ByVal v As Boolean)
|
||||||
|
If v Then CNT.Checked = True
|
||||||
|
CNT.Enabled = Not v
|
||||||
|
End Sub
|
||||||
|
Private Sub CH_FILTER_ALL_CheckedChanged(sender As Object, e As EventArgs) Handles CH_FILTER_ALL.CheckedChanged
|
||||||
|
_RefillEnabled = False
|
||||||
|
Dim v As Boolean = CH_FILTER_ALL.Checked
|
||||||
|
UpdateControlOptions(CH_FILTER_SINGLE, v)
|
||||||
|
UpdateControlOptions(CH_FILTER_CHANNEL, v)
|
||||||
|
UpdateControlOptions(CH_FILTER_PLS, v)
|
||||||
|
_RefillEnabled = True
|
||||||
|
RefillList()
|
||||||
|
End Sub
|
||||||
|
Private Sub CH_FILTER_SINGLE_CHANNEL_PLS_CheckedChanged(sender As Object, e As EventArgs) Handles CH_FILTER_SINGLE.CheckedChanged,
|
||||||
|
CH_FILTER_CHANNEL.CheckedChanged,
|
||||||
|
CH_FILTER_PLS.CheckedChanged
|
||||||
|
RefillList()
|
||||||
|
End Sub
|
||||||
|
Private Sub CH_M_ALL_CheckedChanged(sender As Object, e As EventArgs) Handles CH_M_ALL.CheckedChanged
|
||||||
|
_RefillEnabled = False
|
||||||
|
Dim v As Boolean = CH_M_ALL.Checked
|
||||||
|
UpdateControlOptions(CH_M_VIDEO, v)
|
||||||
|
UpdateControlOptions(CH_M_MUSIC, v)
|
||||||
|
_RefillEnabled = True
|
||||||
|
RefillList()
|
||||||
|
End Sub
|
||||||
|
Private Sub CH_M_VIDEO_MUSIC_CheckedChanged(sender As Object, e As EventArgs) Handles CH_M_VIDEO.CheckedChanged, CH_M_MUSIC.CheckedChanged
|
||||||
|
RefillList()
|
||||||
|
End Sub
|
||||||
|
Private Sub CH_USERS_USE_CheckedChanged() Handles CH_USERS_USE.CheckedChanged
|
||||||
|
LIST_USERS.Enabled = CH_USERS_USE.Checked
|
||||||
|
BTT_SELECT_ALL.Enabled = CH_USERS_USE.Checked
|
||||||
|
BTT_SELECT_NONE.Enabled = CH_USERS_USE.Checked
|
||||||
|
End Sub
|
||||||
|
Private Sub BTT_SELECT_ALL_NONE_Click(sender As Object, e As EventArgs) Handles BTT_SELECT_ALL.Click, BTT_SELECT_NONE.Click
|
||||||
|
Dim checked As Boolean = sender Is BTT_SELECT_ALL
|
||||||
|
With LIST_USERS
|
||||||
|
If .Items.Count > 0 Then
|
||||||
|
For i% = 0 To .Items.Count - 1 : .SetItemChecked(i, checked) : Next
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
End Sub
|
||||||
|
End Class
|
||||||
|
End Namespace
|
||||||
@@ -155,7 +155,7 @@ Namespace API.YouTube.Controls
|
|||||||
With DirectCast(MyContainer, YouTubeMediaContainerBase)
|
With DirectCast(MyContainer, YouTubeMediaContainerBase)
|
||||||
Select Case Sender.DefaultButton
|
Select Case Sender.DefaultButton
|
||||||
Case ADB.Open
|
Case ADB.Open
|
||||||
Using f As New SimpleListForm(Of String)(IIf(isLyrics, AvailableSubtitlesFormats, AvailableAudioFormats)) With {
|
Using f As New SimpleListForm(Of String)(If(isLyrics, AvailableSubtitlesFormats, AvailableAudioFormats)) With {
|
||||||
.DesignXML = DesignXML,
|
.DesignXML = DesignXML,
|
||||||
.DesignXMLNodeName = SimpleArraysFormNode,
|
.DesignXMLNodeName = SimpleArraysFormNode,
|
||||||
.FormText = DirectCast(e.AssociatedControl, TextBoxExtended).CaptionText,
|
.FormText = DirectCast(e.AssociatedControl, TextBoxExtended).CaptionText,
|
||||||
|
|||||||
@@ -121,9 +121,10 @@ Namespace API.YouTube.Controls
|
|||||||
Me.TXT_LIMIT.Location = New System.Drawing.Point(3, 3)
|
Me.TXT_LIMIT.Location = New System.Drawing.Point(3, 3)
|
||||||
Me.TXT_LIMIT.Name = "TXT_LIMIT"
|
Me.TXT_LIMIT.Name = "TXT_LIMIT"
|
||||||
Me.TXT_LIMIT.PlaceholderEnabled = True
|
Me.TXT_LIMIT.PlaceholderEnabled = True
|
||||||
Me.TXT_LIMIT.PlaceholderText = "e.g. ABCDE"
|
Me.TXT_LIMIT.PlaceholderText = "e.g. RDAMP"
|
||||||
Me.TXT_LIMIT.Size = New System.Drawing.Size(378, 22)
|
Me.TXT_LIMIT.Size = New System.Drawing.Size(378, 22)
|
||||||
Me.TXT_LIMIT.TabIndex = 2
|
Me.TXT_LIMIT.TabIndex = 2
|
||||||
|
Me.TXT_LIMIT.Text = "RDAMP"
|
||||||
'
|
'
|
||||||
'CONTAINER_MAIN
|
'CONTAINER_MAIN
|
||||||
'
|
'
|
||||||
|
|||||||
122
SCrawler.YouTube/Controls/YTDataFilter.vb
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
' Copyright (C) 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.YouTube.Base
|
||||||
|
Imports SCrawler.API.YouTube.Objects
|
||||||
|
Imports PersonalUtilities.Functions.XML
|
||||||
|
Imports PersonalUtilities.Functions.XML.Base
|
||||||
|
Namespace API.YouTube.Controls
|
||||||
|
Friend Class YTDataFilter
|
||||||
|
Private Const Name_Types As String = "Types"
|
||||||
|
Private Const Name_IsMusic As String = "IsMusic"
|
||||||
|
Private Const Name_IsVideo As String = "IsVideo"
|
||||||
|
Private Const Name_UserList As String = "UserList"
|
||||||
|
Friend Structure SimpleUser : Implements IEContainerProvider, IComparable(Of SimpleUser)
|
||||||
|
Private Const Name_UID As String = "UID"
|
||||||
|
Friend Title As String
|
||||||
|
Friend ID As String
|
||||||
|
Friend Sub New(ByVal _Title As String, ByVal _ID As String)
|
||||||
|
Title = _Title
|
||||||
|
ID = _ID
|
||||||
|
End Sub
|
||||||
|
Private Sub New(ByVal u As YouTubeMediaContainerBase)
|
||||||
|
Title = u.Title
|
||||||
|
ID = u.ID
|
||||||
|
End Sub
|
||||||
|
Public Shared Widening Operator CType(ByVal u As YouTubeMediaContainerBase) As SimpleUser
|
||||||
|
Return New SimpleUser(u.UserTitle, u.UserID)
|
||||||
|
End Operator
|
||||||
|
Public Shared Widening Operator CType(ByVal e As EContainer) As SimpleUser
|
||||||
|
Return New SimpleUser(e.Value, e.Attribute(Name_UID).Value)
|
||||||
|
End Operator
|
||||||
|
Public Overrides Function ToString() As String
|
||||||
|
Return String.Format(CStr(Interaction.Switch(Title.IsEmptyString, "{1}", ID.IsEmptyString, "{0}", True, "{0} ({1})")), Title, ID)
|
||||||
|
End Function
|
||||||
|
Public Overrides Function Equals(ByVal Obj As Object) As Boolean
|
||||||
|
Return Not IsDBNull(Obj) AndAlso ToString() = DirectCast(Obj, SimpleUser).ToString
|
||||||
|
End Function
|
||||||
|
Private Function CompareTo(ByVal Other As SimpleUser) As Integer Implements IComparable(Of SimpleUser).CompareTo
|
||||||
|
Return ToString.CompareTo(Other.ToString)
|
||||||
|
End Function
|
||||||
|
Private Function ToEContainer(Optional ByVal e As ErrorsDescriber = Nothing) As EContainer Implements IEContainerProvider.ToEContainer
|
||||||
|
Return New EContainer("User", Title, {New EAttribute(Name_UID, ID)})
|
||||||
|
End Function
|
||||||
|
End Structure
|
||||||
|
Friend ReadOnly Property Types As List(Of YouTubeMediaType)
|
||||||
|
Friend Property IsMusic As Boolean = True
|
||||||
|
Friend Property IsVideo As Boolean = True
|
||||||
|
Friend ReadOnly Property UserList As List(Of SimpleUser)
|
||||||
|
Private ReadOnly File As New SFile("Settings\YouTubeFilter.xml")
|
||||||
|
Friend Sub New(Optional ByVal LoadFromFile As Boolean = True)
|
||||||
|
Types = New List(Of YouTubeMediaType) From {YouTubeMediaType.Undefined}
|
||||||
|
UserList = New List(Of SimpleUser)
|
||||||
|
If LoadFromFile AndAlso File.Exists Then
|
||||||
|
Using e As New XmlFile(File, Protector.Modes.All, False) With {.AllowSameNames = True}
|
||||||
|
e.LoadData()
|
||||||
|
If e.Count > 0 Then
|
||||||
|
Types.Clear()
|
||||||
|
Types.ListAddList(e.Value(Name_Types).StringToList(Of Integer)(","), LAP.NotContainsOnly)
|
||||||
|
IsMusic = e.Value(Name_IsMusic).FromXML(Of Boolean)(True)
|
||||||
|
IsVideo = e.Value(Name_IsVideo).FromXML(Of Boolean)(True)
|
||||||
|
UserList.ListAddList(e(Name_UserList), LAP.IgnoreICopier)
|
||||||
|
End If
|
||||||
|
End Using
|
||||||
|
End If
|
||||||
|
End Sub
|
||||||
|
Friend Sub New(ByVal f As YTDataFilter)
|
||||||
|
Me.New(False)
|
||||||
|
With f
|
||||||
|
Types.ListAddList(.Types, LAP.NotContainsOnly)
|
||||||
|
IsMusic = .IsMusic
|
||||||
|
IsVideo = .IsVideo
|
||||||
|
UserList.ListAddList(.UserList)
|
||||||
|
End With
|
||||||
|
End Sub
|
||||||
|
Friend Sub Reset(Optional ByVal AddDefType As Boolean = True, Optional ByVal ClearUserList As Boolean = True)
|
||||||
|
Types.Clear()
|
||||||
|
If AddDefType Then Types.Add(YouTubeMediaType.Undefined)
|
||||||
|
IsMusic = True
|
||||||
|
IsVideo = True
|
||||||
|
If ClearUserList Then UserList.Clear()
|
||||||
|
End Sub
|
||||||
|
Friend Sub Update()
|
||||||
|
Using x As New XmlFile With {.AllowSameNames = True}
|
||||||
|
With x
|
||||||
|
.Add(Name_Types, Types.ListToStringE(","))
|
||||||
|
.Add(Name_IsMusic, IsMusic.BoolToInteger)
|
||||||
|
.Add(Name_IsVideo, IsVideo.BoolToInteger)
|
||||||
|
.Add(Name_UserList, String.Empty)
|
||||||
|
.Self()(Name_UserList).AddRange(UserList)
|
||||||
|
.Name = "FILTER"
|
||||||
|
.Save(File)
|
||||||
|
End With
|
||||||
|
End Using
|
||||||
|
End Sub
|
||||||
|
Friend Function Ready(ByVal Item As YouTubeMediaContainerBase, Optional ByVal IgnoreUserList As Boolean = False) As Boolean
|
||||||
|
With Item
|
||||||
|
If Not IsMusic Or Not IsVideo Then
|
||||||
|
If .IsMusic And Not IsMusic Then Return False
|
||||||
|
If Not .IsMusic And Not IsVideo Then Return False
|
||||||
|
End If
|
||||||
|
If Not Types.Contains(YouTubeMediaType.Undefined) AndAlso Not Types.Contains(.ObjectType) Then Return False
|
||||||
|
If Not IgnoreUserList AndAlso UserList.Count > 0 AndAlso Not UserList.Contains(Item) Then Return False
|
||||||
|
End With
|
||||||
|
Return True
|
||||||
|
End Function
|
||||||
|
Friend Overloads Sub RemoveAll(ByRef Data As List(Of IYouTubeMediaContainer))
|
||||||
|
Data.RemoveAll(Function(item) Not Ready(item))
|
||||||
|
End Sub
|
||||||
|
Friend Overloads Sub RemoveAll(ByRef Data As List(Of YouTubeMediaContainerBase))
|
||||||
|
Data.RemoveAll(Function(item) Not Ready(item))
|
||||||
|
End Sub
|
||||||
|
Friend Sub Populate(ByVal InitList As List(Of IYouTubeMediaContainer), ByVal DestList As List(Of IYouTubeMediaContainer), ByVal IgnoreUserList As Boolean)
|
||||||
|
DestList.Clear()
|
||||||
|
If InitList.Count > 0 Then InitList.ForEach(Sub(item) If Ready(item, IgnoreUserList) Then DestList.ListAddValue(item))
|
||||||
|
End Sub
|
||||||
|
End Class
|
||||||
|
End Namespace
|
||||||
@@ -59,6 +59,7 @@ Namespace API.YouTube
|
|||||||
Public ReadOnly TrueUrlRegEx As RParams = RParams.DM(Base.YouTubeFunctions.TrueUrlPattern, 0, EDP.ReturnValue)
|
Public ReadOnly TrueUrlRegEx As RParams = RParams.DM(Base.YouTubeFunctions.TrueUrlPattern, 0, EDP.ReturnValue)
|
||||||
Friend ReadOnly MusicUrlApply As RParams = RParams.DMS("https://([w\.]*)youtube.com.+", 1, RegexReturn.Replace, EDP.ReturnValue,
|
Friend ReadOnly MusicUrlApply As RParams = RParams.DMS("https://([w\.]*)youtube.com.+", 1, RegexReturn.Replace, EDP.ReturnValue,
|
||||||
CType(Function(input$) "music.", Func(Of String, String)), String.Empty)
|
CType(Function(input$) "music.", Func(Of String, String)), String.Empty)
|
||||||
|
Friend ReadOnly M3U8ExcludedSymbols As String() = {".", ",", ":", "/", "\", "(", ")", "[", "]"}
|
||||||
<Extension> Friend Function ToMusicUrl(ByVal URL As String, ByVal IsMusic As Boolean) As String
|
<Extension> Friend Function ToMusicUrl(ByVal URL As String, ByVal IsMusic As Boolean) As String
|
||||||
Try : Return If(IsMusic And Not URL.IsEmptyString, CStr(RegexReplace(URL, MusicUrlApply)).IfNullOrEmpty(URL), URL) : Catch : Return URL : End Try
|
Try : Return If(IsMusic And Not URL.IsEmptyString, CStr(RegexReplace(URL, MusicUrlApply)).IfNullOrEmpty(URL), URL) : Catch : Return URL : End Try
|
||||||
End Function
|
End Function
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ Namespace DownloadObjects.STDownloader
|
|||||||
Me.BTT_CLEAR_DONE = New System.Windows.Forms.ToolStripMenuItem()
|
Me.BTT_CLEAR_DONE = New System.Windows.Forms.ToolStripMenuItem()
|
||||||
Me.BTT_CLEAR_ALL = New System.Windows.Forms.ToolStripMenuItem()
|
Me.BTT_CLEAR_ALL = New System.Windows.Forms.ToolStripMenuItem()
|
||||||
Me.BTT_SELECT_ALL = New System.Windows.Forms.ToolStripMenuItem()
|
Me.BTT_SELECT_ALL = New System.Windows.Forms.ToolStripMenuItem()
|
||||||
|
Me.BTT_SELECT_NONE = New System.Windows.Forms.ToolStripMenuItem()
|
||||||
Me.TOOLBAR_BOTTOM = New System.Windows.Forms.StatusStrip()
|
Me.TOOLBAR_BOTTOM = New System.Windows.Forms.StatusStrip()
|
||||||
Me.PR_MAIN = New System.Windows.Forms.ToolStripProgressBar()
|
Me.PR_MAIN = New System.Windows.Forms.ToolStripProgressBar()
|
||||||
Me.LBL_INFO = New System.Windows.Forms.ToolStripStatusLabel()
|
Me.LBL_INFO = New System.Windows.Forms.ToolStripStatusLabel()
|
||||||
@@ -43,6 +44,7 @@ Namespace DownloadObjects.STDownloader
|
|||||||
Me.MENU_ADD = New System.Windows.Forms.ToolStripDropDownButton()
|
Me.MENU_ADD = New System.Windows.Forms.ToolStripDropDownButton()
|
||||||
Me.BTT_ADD = New PersonalUtilities.Forms.Controls.KeyClick.ToolStripMenuItemKeyClick()
|
Me.BTT_ADD = New PersonalUtilities.Forms.Controls.KeyClick.ToolStripMenuItemKeyClick()
|
||||||
Me.BTT_ADD_PLS_ARR = New PersonalUtilities.Forms.Controls.KeyClick.ToolStripMenuItemKeyClick()
|
Me.BTT_ADD_PLS_ARR = New PersonalUtilities.Forms.Controls.KeyClick.ToolStripMenuItemKeyClick()
|
||||||
|
Me.BTT_FILTER = New System.Windows.Forms.ToolStripButton()
|
||||||
Me.BTT_DOWN = New System.Windows.Forms.ToolStripButton()
|
Me.BTT_DOWN = New System.Windows.Forms.ToolStripButton()
|
||||||
Me.BTT_STOP = New System.Windows.Forms.ToolStripButton()
|
Me.BTT_STOP = New System.Windows.Forms.ToolStripButton()
|
||||||
Me.SEP_LOG = New System.Windows.Forms.ToolStripSeparator()
|
Me.SEP_LOG = New System.Windows.Forms.ToolStripSeparator()
|
||||||
@@ -50,7 +52,7 @@ Namespace DownloadObjects.STDownloader
|
|||||||
Me.BTT_INFO = New System.Windows.Forms.ToolStripButton()
|
Me.BTT_INFO = New System.Windows.Forms.ToolStripButton()
|
||||||
Me.BTT_DONATE = New System.Windows.Forms.ToolStripButton()
|
Me.BTT_DONATE = New System.Windows.Forms.ToolStripButton()
|
||||||
Me.BTT_BUG_REPORT = New System.Windows.Forms.ToolStripButton()
|
Me.BTT_BUG_REPORT = New System.Windows.Forms.ToolStripButton()
|
||||||
Me.BTT_SELECT_NONE = New System.Windows.Forms.ToolStripMenuItem()
|
Me.SEP_FILTER = New System.Windows.Forms.ToolStripSeparator()
|
||||||
SEP_2 = New System.Windows.Forms.ToolStripSeparator()
|
SEP_2 = New System.Windows.Forms.ToolStripSeparator()
|
||||||
SEP_3 = New System.Windows.Forms.ToolStripSeparator()
|
SEP_3 = New System.Windows.Forms.ToolStripSeparator()
|
||||||
MENU_DEL_CLEAR = New System.Windows.Forms.ToolStripDropDownButton()
|
MENU_DEL_CLEAR = New System.Windows.Forms.ToolStripDropDownButton()
|
||||||
@@ -134,6 +136,12 @@ Namespace DownloadObjects.STDownloader
|
|||||||
Me.BTT_SELECT_ALL.Size = New System.Drawing.Size(185, 22)
|
Me.BTT_SELECT_ALL.Size = New System.Drawing.Size(185, 22)
|
||||||
Me.BTT_SELECT_ALL.Text = "Select all"
|
Me.BTT_SELECT_ALL.Text = "Select all"
|
||||||
'
|
'
|
||||||
|
'BTT_SELECT_NONE
|
||||||
|
'
|
||||||
|
Me.BTT_SELECT_NONE.Name = "BTT_SELECT_NONE"
|
||||||
|
Me.BTT_SELECT_NONE.Size = New System.Drawing.Size(185, 22)
|
||||||
|
Me.BTT_SELECT_NONE.Text = "Select none"
|
||||||
|
'
|
||||||
'TOOLBAR_BOTTOM
|
'TOOLBAR_BOTTOM
|
||||||
'
|
'
|
||||||
Me.TOOLBAR_BOTTOM.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.PR_MAIN, Me.LBL_INFO})
|
Me.TOOLBAR_BOTTOM.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.PR_MAIN, Me.LBL_INFO})
|
||||||
@@ -169,7 +177,7 @@ Namespace DownloadObjects.STDownloader
|
|||||||
'TOOLBAR_TOP
|
'TOOLBAR_TOP
|
||||||
'
|
'
|
||||||
Me.TOOLBAR_TOP.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden
|
Me.TOOLBAR_TOP.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden
|
||||||
Me.TOOLBAR_TOP.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_SETTINGS, Me.SEP_1, Me.MENU_ADD, SEP_2, Me.BTT_DOWN, Me.BTT_STOP, SEP_3, MENU_DEL_CLEAR, Me.SEP_LOG, Me.BTT_LOG, Me.BTT_INFO, Me.BTT_DONATE, Me.BTT_BUG_REPORT})
|
Me.TOOLBAR_TOP.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_SETTINGS, Me.SEP_1, Me.MENU_ADD, Me.SEP_FILTER, Me.BTT_FILTER, SEP_2, Me.BTT_DOWN, Me.BTT_STOP, SEP_3, MENU_DEL_CLEAR, Me.SEP_LOG, Me.BTT_LOG, Me.BTT_INFO, Me.BTT_DONATE, Me.BTT_BUG_REPORT})
|
||||||
Me.TOOLBAR_TOP.Location = New System.Drawing.Point(0, 0)
|
Me.TOOLBAR_TOP.Location = New System.Drawing.Point(0, 0)
|
||||||
Me.TOOLBAR_TOP.Name = "TOOLBAR_TOP"
|
Me.TOOLBAR_TOP.Name = "TOOLBAR_TOP"
|
||||||
Me.TOOLBAR_TOP.Size = New System.Drawing.Size(584, 25)
|
Me.TOOLBAR_TOP.Size = New System.Drawing.Size(584, 25)
|
||||||
@@ -222,6 +230,15 @@ Namespace DownloadObjects.STDownloader
|
|||||||
Me.BTT_ADD_PLS_ARR.Text = "Add URL array"
|
Me.BTT_ADD_PLS_ARR.Text = "Add URL array"
|
||||||
Me.BTT_ADD_PLS_ARR.ToolTipText = "Click to add." & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Ctrl+click to use cookies for download (if supported)." & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Shift to a" &
|
Me.BTT_ADD_PLS_ARR.ToolTipText = "Click to add." & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Ctrl+click to use cookies for download (if supported)." & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Shift to a" &
|
||||||
"dd without downloading."
|
"dd without downloading."
|
||||||
|
'
|
||||||
|
'BTT_FILTER
|
||||||
|
'
|
||||||
|
Me.BTT_FILTER.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image
|
||||||
|
Me.BTT_FILTER.Image = CType(resources.GetObject("BTT_FILTER.Image"), System.Drawing.Image)
|
||||||
|
Me.BTT_FILTER.ImageTransparentColor = System.Drawing.Color.Magenta
|
||||||
|
Me.BTT_FILTER.Name = "BTT_FILTER"
|
||||||
|
Me.BTT_FILTER.Size = New System.Drawing.Size(23, 22)
|
||||||
|
Me.BTT_FILTER.Text = "Filter"
|
||||||
'
|
'
|
||||||
'BTT_DOWN
|
'BTT_DOWN
|
||||||
'
|
'
|
||||||
@@ -286,11 +303,10 @@ Namespace DownloadObjects.STDownloader
|
|||||||
Me.BTT_BUG_REPORT.Size = New System.Drawing.Size(23, 22)
|
Me.BTT_BUG_REPORT.Size = New System.Drawing.Size(23, 22)
|
||||||
Me.BTT_BUG_REPORT.Text = "Bug report"
|
Me.BTT_BUG_REPORT.Text = "Bug report"
|
||||||
'
|
'
|
||||||
'BTT_SELECT_NONE
|
'SEP_FILTER
|
||||||
'
|
'
|
||||||
Me.BTT_SELECT_NONE.Name = "BTT_SELECT_NONE"
|
Me.SEP_FILTER.Name = "SEP_FILTER"
|
||||||
Me.BTT_SELECT_NONE.Size = New System.Drawing.Size(185, 22)
|
Me.SEP_FILTER.Size = New System.Drawing.Size(6, 25)
|
||||||
Me.BTT_SELECT_NONE.Text = "Select none"
|
|
||||||
'
|
'
|
||||||
'VideoListForm
|
'VideoListForm
|
||||||
'
|
'
|
||||||
@@ -337,5 +353,7 @@ Namespace DownloadObjects.STDownloader
|
|||||||
Private WithEvents BTT_CLEAR_SELECTED As ToolStripMenuItem
|
Private WithEvents BTT_CLEAR_SELECTED As ToolStripMenuItem
|
||||||
Private WithEvents BTT_SELECT_ALL As ToolStripMenuItem
|
Private WithEvents BTT_SELECT_ALL As ToolStripMenuItem
|
||||||
Private WithEvents BTT_SELECT_NONE As ToolStripMenuItem
|
Private WithEvents BTT_SELECT_NONE As ToolStripMenuItem
|
||||||
|
Public WithEvents BTT_FILTER As ToolStripButton
|
||||||
|
Public WithEvents SEP_FILTER As ToolStripSeparator
|
||||||
End Class
|
End Class
|
||||||
End Namespace
|
End Namespace
|
||||||
@@ -130,30 +130,31 @@
|
|||||||
<data name="BTT_DELETE.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="BTT_DELETE.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
<value>
|
<value>
|
||||||
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
|
||||||
HR8AAAAASUVORK5CYII=
|
RxAASABgv+e63uX/HACQqUlmzgEAeHXVtQAAPE9icliTK/m/HpEQZP9/yTOIoS/Y32gy2FQGa9GfAAAA
|
||||||
|
AElFTkSuQmCC
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<metadata name="MENU_DEL_SEP_1.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
<metadata name="MENU_DEL_SEP_1.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
@@ -162,88 +163,91 @@
|
|||||||
<data name="BTT_CLEAR_SELECTED.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="BTT_CLEAR_SELECTED.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
<value>
|
<value>
|
||||||
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
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="BTT_CLEAR_DONE.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="BTT_CLEAR_DONE.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
<value>
|
<value>
|
||||||
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
|
||||||
HR8AAAAASUVORK5CYII=
|
RxAASABgv+e63uX/HACQqUlmzgEAeHXVtQAAPE9icliTK/m/HpEQZP9/yTOIoS/Y32gy2FQGa9GfAAAA
|
||||||
|
AElFTkSuQmCC
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="BTT_CLEAR_ALL.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="BTT_CLEAR_ALL.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
<value>
|
<value>
|
||||||
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAVDSURBVEhLjZVtTFNXGMcLQmdHO6AdarLSOcTxXqC3lls3
|
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAV6SURBVEhLjZVrTFNnGMcfT4Wto2dcOtRkyBzigALlcmo5
|
||||||
FeVFihZsqaBjRM2ouILiC0oUozGaaBSTJfuwfdg+bJnJnFuiyzKZMOp8ATJl4IYLAjqspfS9cNlLskjP
|
dVNwXKRowRYEGSNiRi3jXiwQqYEQTVxQkyX7sH3YPmyZicYt0WUXBEaJjkumDNxwQUCHWErpFQ5zSxbo
|
||||||
/qe0OmPZeJJfbu85z/k//z7n3Ht5NPqLimLMSUkfXV20aPiKTPbhOqn0FQxHBSb/J4ZUKvY3mez6yMKF
|
s7xd200Fxz95c9qcc37//3me9wIAAKOZmQGGiIiP+7ZsmewKD/9of1jYywCwkdz7P01Ipexv4eE3pjZv
|
||||||
fReTkw0YigERgUkaAyaT8FZR0ZdDzc1k9OxZ0tHU5L/Csp15ItFSTEfPZIWPQYZ507Z580Pu9Gky1dpK
|
HrkSGVkAAAEAsMH3wFhlpeBmZuYXE83NOH3+PHbpdK4ulu1NoekdAOD3GO0JjTPMG6bi4gdcRwcunTuH
|
||||||
hisrPe+nptbLYmPjMT1TpHPJkg/u7d1LHhw7RkaPHiVWJFsOHCBtLHtdLhK9jpSwRUbU6jUQt3BnzhAO
|
k4WF9g+io6vCAwODfSa927d/eLehAe+3t+N0WxsaOzpwpqkJO1n2hpimX1vLZEome9NUXDzDnT2LXHs7
|
||||||
a7mWFjJ15Ai5p9V6v5ZK30OKGETxrkokVir+oKmJPDx0iFiRNH7yJLnW3Oy/olLdyBKJUpD4TBG0pdhW
|
cno9LrW24l2FwvFVWNj7ABDirkKfUGgk8Ps6HT5oaUFjayvOnTmDfc3Nri6p9Id4mo560mRCKs0yFRUZ
|
||||||
VWWlzqn4FMS5/fvJFIz5amqIOSHhLtJYIOJ1JCaeG66tJaMoYAHWgweJDQscJ06QG2hXB8t2ZwqFqUgO
|
SXICX9LrkWtsxKWmJnSWlqIhNPQOALAAQEPP1q0XJsvLcVqnwxmdDo0nTqBJr8f506fxuk7n6mHZwTiB
|
||||||
FBlSKIrHKyutk6dOEQ5mpmCKw7qpPXvIxI4dpE2lcm2RSC4gtRSIefrFi19tUyqvt2/b5n+EpDEwDjcO
|
INprMpGcnDVXWGhcfO895FpbcamlBTmdDpe0WlyoqMBOqdR6RCi8DAA57q9Qbdv2SqdEcuPa0aOuh1ot
|
||||||
7IkbLXPu20euokiuUJj2E8MUjRkMtsnjxwMt4eCYQ3u5xkYyCXFzbq4nRSD4FMJGIAd0w3nRjESSiiLd
|
zmq1ONfYiPPNzWhra0PL8ePYx7KDSQJBzE8MkzlbUGBaPHXKXRKuqQm5hgbk6upwsaICDUlJ9ig+/zMA
|
||||||
li1biG3nTmJvaCCO3buJC8W8EOpuaPD3qNV37peXW7nDhwOOOcxxyOXq65+IpwkE56BXCzKC4pEgEPxc
|
UAOA2NNw8GOEwuhOiWRw5sgRNNXUoLm6Gufr69Gq1aJDr8f+6mrXkEx2+15enpE7edKdmNNqkaupQa6q
|
||||||
sTjtO4Wi64fqar+9ro44gdtkIh4I+FDMt2sXmYTbSSqMew73AXG0t0up9MqFQipOnaeD+eDpUQ0GXyUW
|
ygeP4fMvAEA5AMR64JS3rP5JISEx15KTBwwlJS6zRoMWjQZtlZVor6pCZ309OmtrcbGhARcJuL4eudra
|
||||||
p3dkZ3fbNm4kzq1biRt4jUbig8MJFJzABk6UlxPf6tXEp1YTD+jKy/PliETnsX47oM4F4DnxUPCXxcdn
|
f+Dl5TggkTjEAgGBk+QiAHj+sanqNZGGhIh6EhIGTYcOoaWsDG1lZehQq9FZUYELGg0ulJbiQl4eOvfu
|
||||||
dMjl3QMZGY89mzYRt0ZD3AxDXFIpcYlExBUdTVzz5pFuodDfnpTkZePi6IbWgUzwIphVPBSBdt2Sy/vH
|
RadMhnaZDAdSUpyJNH0JAI55kvNXg3vlvzM4OLZHLB4cE4mW7YcPo00uRxvDoDUsDK00jVY/P7TyeNgv
|
||||||
IWiHmAM4ARUOEBVF+rKz/zKkpn6L/HdBFpiTeCBsNTUmm1ptsQsEz4sDOjaQnPzYrNXeT0tMLMeSWDA3
|
ELi6IyIcbFAQaagGAOIA4IVnwb1yl+umWDw6R9No5vFwnsdDC4/nBrvHxo04kpDwZ0F09LcA8C4AxK8X
|
||||||
cZ/RuM9VUOCyw/1s4mPgIbBkZJA+ne7uW8uX52Dpf75WAuE2Gluca9e67TExz4k70XvaLio+CoYjI8kA
|
7paptLTSJJPNmPn8p+Eew7HIyGWDQnEvZuvWPAAIXDfcqVYft6anW800vSZ8lsfDBzwezsTG4ohSeeet
|
||||||
uJyT4++vqPjVwLK0TbMX8W7ffshRUuIJ59wpkZBHJSV/30hJ8VPxoaB4L+gCZoaZ7qf/ZLYiOIot9oIC
|
XbsSn1yMq8qmVust+/bZzAEBT8Etfn7uchH4NI+HkxSFYxSF3yQmukbz838tYFlSprVNHMeOtcxnZ9tX
|
||||||
r10oDAg/05YFC8hgaenvx1eu7Oldv37ckpZGfoHobXATXKMFKMuWTf9oMNwpkMvpC/Lpq95TW9tMxR3h
|
S24RCvFhdvZf16OiXAQ+4YEPUxQOUBQaGGZllHzJWiYOtVpvTk93mAUCN/ixsmzahOM5Ob+f2rNnaPjA
|
||||||
xBMSyOCqVX/UM0wHUhtKMjPfvltWdn8QvQ+Jd4J20EaLqFTTPRUVvZ9otXTj+SCC59mwweqIiwvvHOJ1
|
gbmZmBj8haLwFkVhP0XhdWJAxs6dKz8WFNxOF4vJBvnvVm8vL28m8PnV4KGhOJ6a+qiKYXoAoDo7Lu7t
|
||||||
CkU7Ek2AbqR4d37+G316/cidrKwn4pfBN+AS6E9Pf3xbr7+H3MWAz7PrdIMemSyscxPDfI+k+qB46EvF
|
O7m598ZjY33wXorCborCTmIila4M5ecPf6pQkMb7uxtvP3jQOB8U9DScJE9NfaRJTu4GgEoAII0MqU9L
|
||||||
31NYyPZVVIxcyMry/1v8q4gIchsFzBrNGPKKQDyvp7p687hG43ZDNOR8oLj4z53hxUPBb8zPz8PGDt/K
|
e31EpZq6HR/vg39HUfg1ReFVisJRkWj5lkp1FwC2uU3MSuW4PTx81eSVDPM9AFR54N6Tyl+bkcGO5OdP
|
||||||
ziYXg+LmvLzpzzWaR6VLl36MnJkCiPntlZWHrWVl3h6W9VPnjUplJ8ZnEw8F37hihYK24wusM6vV0xfg
|
XYqPd/0X/uWGDXhLJFo2yOWzAJAJAMEwVFJSPCeX22yhob7kY1lZf9SsDvfKvy4tLWVUqZy8mZCAVzxw
|
||||||
/CWBoBVzOjDTIkQEk5QU26vXf/agrMx5vrAQpy+yEeMMENJ5mjRL8C9VVb3zs043dlOrdZWkpNBvgR5I
|
Q0rKykW5/GHOjh2f+AzIxtRdWHjSmJvrGGBZF0leJ5H0PgPulb969+5kUo6LLOsyyGQrl+Xy2Rf5/HMA
|
||||||
AT2uT9bSH3FACdYFr3N9/F8A9GjSk7MevAbCPnDzAHVMP9b0Su/nEtQEff+/HIQWDBrj8f4B7zPYbtFn
|
oPSViLzMREQEDqtUn9/PzbVcysgYpiiqDgAYABCsAffK/2pR0Ts/K5Wz/QqFNTsqipwFKgAI80xX37vk
|
||||||
HR8AAAAASUVORK5CYII=
|
RxAASABgv+e63uX/HACQqUlmzgEAeHXVtQAAPE9icliTK/m/HpEQZP9/yTOIoS/Y32gy2FQGa9GfAAAA
|
||||||
|
AElFTkSuQmCC
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<metadata name="MENU_DEL_SEP_2.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
<metadata name="MENU_DEL_SEP_2.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
@@ -252,30 +256,31 @@
|
|||||||
<data name="MENU_DEL_CLEAR.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="MENU_DEL_CLEAR.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
<value>
|
<value>
|
||||||
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
|
||||||
dCWdzmEAAAAASUVORK5CYII=
|
W/rDDwBEAHDYdd/q8n8BAOjUpDPnCAC8vuFaAACOKzE9rOmd/t+KaAi6/7/iuqihJ9jfOenaM1O34/0A
|
||||||
|
AAAASUVORK5CYII=
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<metadata name="TOOLBAR_BOTTOM.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
<metadata name="TOOLBAR_BOTTOM.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
@@ -287,105 +292,123 @@
|
|||||||
<data name="BTT_ADD.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="BTT_ADD.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
<value>
|
<value>
|
||||||
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
|
||||||
hKygM1JCJAAAAABJRU5ErkJggg==
|
rwTiqI6ApvuidiViSNQekHhdhHhVL8AlQ/Cp10vnFTz/HxZurHotmkteAAAAAElFTkSuQmCC
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="BTT_ADD_PLS_ARR.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="BTT_ADD_PLS_ARR.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
<value>
|
<value>
|
||||||
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
|
||||||
H0WkrMjY2947AAAAAElFTkSuQmCC
|
II0aCGh8IOlXIoUk/QFJNyRIvxkFuGoK/uP10nkJz58BqISsoFjBRioAAAAASUVORK5CYII=
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MENU_ADD.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="MENU_ADD.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
<value>
|
<value>
|
||||||
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
|
||||||
|
QmCC
|
||||||
|
</value>
|
||||||
|
</data>
|
||||||
|
<data name="BTT_FILTER.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>
|
||||||
|
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||||
|
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIFSURBVDhPpZLtS1NhGMbPPxJmmlYSgqHiKzGU1EDxg4iK
|
||||||
|
YKyG2WBogqMYJQOtCEVRFBGdTBCJfRnkS4VaaWNT5sqx1BUxRXxDHYxAJLvkusEeBaPAB+5z4Jzn+t3X
|
||||||
|
/aLhnEfjo8m+dCoa+7/C3O2Hqe0zDC+8KG+cRZHZhdzaaWTVTCLDMIY0vfM04Nfh77/G/sEhwpEDbO3t
|
||||||
|
I7TxE8urEVy99fT/AL5gWDLrTB/hnF4XsW0khCu5ln8DmJliT2AXrcNBsU1gj/MH4nMeKwBrPktM28xM
|
||||||
|
cX79DFKrHHD5d9D26hvicx4pABt2lpg10zYzU0zr7+e3xXGcrkEB2O2TNec9nJFwB3alZn5jZorfeDZh
|
||||||
|
6Q3g8s06BeCoKF4MRURoH1+BY2oNCbeb0TIclIYxOhzf8frTOuo7FxCbbVIAzpni0iceEc8vhzEwGkJD
|
||||||
|
lx83ymxifejdKjRNk/8PWnyIyTQqAJek0jqHwfEVscu31baIu8+90sTE4nY025dQ2/5FIPpnXlzKuK8A
|
||||||
|
HBUzHot52djqQ6HZhfR7IwK4mKpHtvEDMqvfCiQ6zaAAXM8x94aIWTNrLLG4kVUzgaTSPlzLtyJOZxbb
|
||||||
|
1wtfyg4Q+AfA3aZlButjSfxGcUJBk4g5tuP3haQKRKXcUQDOmbvNTpPOJeFFjordZmbWTNvMTHFUcpUC
|
||||||
|
nOccAdABIDXXE1nzAAAAAElFTkSuQmCC
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="BTT_STOP.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="BTT_STOP.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
<value>
|
<value>
|
||||||
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
|
||||||
bAAAAABJRU5ErkJggg==
|
CAIACQDs9lxXu/xfAAAyNcnM2QMAry+7FgCA9iQmhzW5kv+rEQlB9v9XPIMY+oL9DaXP2MIw0VMVAAAA
|
||||||
|
AElFTkSuQmCC
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="BTT_LOG.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="BTT_LOG.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
<value>
|
<value>
|
||||||
iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFmSURBVFhH1dc/K4VhHMbxJ5EFEQbFiERKCotIrMJIiYEi
|
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGTSURBVFhH1ZfPK21RGIaf5GaCCAPF0JVISWEiElNhSIkB
|
||||||
pbwCZcOqJC9AikUWiqRkJYtSRDbESMT3V07dna7zHHru+9T51me+Ts//E+V7LRjFFAZRiZzUhDVc4/vX
|
RUr5C5QZpkryB0gxkQlFUjKlO1HKjcwQQyJatdXp7TtnH3t/Z+CpZ7be7z3tH2uvA7+cFmAUmAIGgSpd
|
||||||
B47Rh6D14Aqp4XQ36ECQ2nALNezaQjG8Vo5DqMF0bxiA1+bwCTWoLMFbNTiDGsrkABXw0jDsKldDmdyj
|
UCiagDXgCviMfAOOgT5d7E0P8C+jWL0GOjTkRRtwY5SqW0CJhtNSARwaZZYvwIAOSMsc8G6UZXNJB6Sh
|
||||||
HokrwCrUSBz7wXbRJs4eLkdQI9m0I3ENeIAaiGN3QjMSZ4fxv+ffnKIKibOnmhqI84V5eMleOHY41VAm
|
FjgzSnJ5AFTqoKQMR0+5luTyFmjQQUkoAlaNgjjDDw4PbWrC5nJkFORjuw5Lwl/gzhgeZ3gTmnVYEsJl
|
||||||
9k7wdgtW4wRqSHlCP7y2AjWmbMB7Y7DzqgZdz2iF9zrxCDXq2oU9uLz31+tgAcHahhp1DSFY9pGhRl29
|
/On9D54C1TosCWFX0+FxfgDzOigp4YMTLqeW5DJ8E9xewRrgxCjJ5gPQr0PSsmIUZXNDwx6MRfdVy9RH
|
||||||
CFYXxrMoQ7BmsZfFPkoRpHWow+56hX26BWkRatR1gRIEaQLvUMMpOyhCkBpxBzWcMoOgLUMNm0vUIWj2
|
oFXDHnQC90ahuhttXO7k+xwsaNCTbaNQHdKQJ+GQoYVqr4Y86QLGYyzXkCezwF6M+0CZBr1YNy65+hwd
|
||||||
ebaJF7jj5+hGTiqE/f+bxDRGUIt8LIp+AC/GHt3tQnwvAAAAAElFTkSuQmCC
|
3QrColGoXgClGvRiAng1SjPdAf5o0ItG4L9RmumMhrxZNkq/vQTqNeBNOJ5tAk9Sfg506+JCURz9/5sE
|
||||||
|
poERoE4X/Rq+AC/GHt09Rk0KAAAAAElFTkSuQmCC
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -39,6 +39,7 @@ Namespace DownloadObjects.STDownloader
|
|||||||
MyView = New FormView(Me)
|
MyView = New FormView(Me)
|
||||||
MyProgress = New MyProgress(TOOLBAR_BOTTOM, PR_MAIN, LBL_INFO)
|
MyProgress = New MyProgress(TOOLBAR_BOTTOM, PR_MAIN, LBL_INFO)
|
||||||
MyJob = New JobThread(Of MediaItem)
|
MyJob = New JobThread(Of MediaItem)
|
||||||
|
BTT_FILTER.Image = My.Resources.FilterPic
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Form handlers"
|
#Region "Form handlers"
|
||||||
@@ -95,15 +96,18 @@ Namespace DownloadObjects.STDownloader
|
|||||||
Dim b As Boolean = True
|
Dim b As Boolean = True
|
||||||
Select Case e.KeyCode
|
Select Case e.KeyCode
|
||||||
Case Keys.Insert : BTT_ADD.PerformClick()
|
Case Keys.Insert : BTT_ADD.PerformClick()
|
||||||
Case Keys.F5 : BTT_DOWN.PerformClick()
|
Case Keys.F5
|
||||||
|
If e.Control Then LoadData(True) Else BTT_DOWN.PerformClick()
|
||||||
Case Else : b = False
|
Case Else : b = False
|
||||||
End Select
|
End Select
|
||||||
If b Then e.Handled = True
|
If b Then e.Handled = True
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Refill, save list"
|
#Region "Refill, save list"
|
||||||
Protected Sub LoadData()
|
Protected Sub LoadData(Optional ByVal ClearTable As Boolean = False)
|
||||||
|
If ClearTable Then RemoveControls(,, False)
|
||||||
Dim c As List(Of IYouTubeMediaContainer) = LoadData_GetFiles()
|
Dim c As List(Of IYouTubeMediaContainer) = LoadData_GetFiles()
|
||||||
|
If c.ListExists Then MyYouTubeSettings.FILTER.RemoveAll(c)
|
||||||
If c.ListExists Then
|
If c.ListExists Then
|
||||||
c.Sort(New ContainerDateComparer)
|
c.Sort(New ContainerDateComparer)
|
||||||
SuspendLayout()
|
SuspendLayout()
|
||||||
@@ -415,6 +419,12 @@ Namespace DownloadObjects.STDownloader
|
|||||||
Return ErrorsDescriber.Execute(EDP.SendToLog + EDP.ReturnValue, ex, "[VideoListForm.ValidateContainerURL]", True)
|
Return ErrorsDescriber.Execute(EDP.SendToLog + EDP.ReturnValue, ex, "[VideoListForm.ValidateContainerURL]", True)
|
||||||
End Try
|
End Try
|
||||||
End Function
|
End Function
|
||||||
|
Private Sub BTT_FILTER_Click(sender As Object, e As EventArgs) Handles BTT_FILTER.Click
|
||||||
|
Using f As New FilterForm(LoadData_GetFiles)
|
||||||
|
f.ShowDialog()
|
||||||
|
If f.DialogResult = DialogResult.OK Or f.DialogResult = DialogResult.Abort Then LoadData(True)
|
||||||
|
End Using
|
||||||
|
End Sub
|
||||||
Private Sub BTT_DOWN_Click(sender As Object, e As EventArgs) Handles BTT_DOWN.Click
|
Private Sub BTT_DOWN_Click(sender As Object, e As EventArgs) Handles BTT_DOWN.Click
|
||||||
With TP_CONTROLS
|
With TP_CONTROLS
|
||||||
If .Controls.Count > 0 Then
|
If .Controls.Count > 0 Then
|
||||||
@@ -494,7 +504,8 @@ Namespace DownloadObjects.STDownloader
|
|||||||
Protected Sub CheckVersionImpl(ByVal Force As Boolean)
|
Protected Sub CheckVersionImpl(ByVal Force As Boolean)
|
||||||
CheckVersion(Force)
|
CheckVersion(Force)
|
||||||
End Sub
|
End Sub
|
||||||
Protected Overloads Sub RemoveControls(Optional ByVal Predicate As Predicate(Of MediaItem) = Nothing, Optional ByVal RemoveFiles As Boolean = False)
|
Protected Overloads Sub RemoveControls(Optional ByVal Predicate As Predicate(Of MediaItem) = Nothing, Optional ByVal RemoveFiles As Boolean = False,
|
||||||
|
Optional ByVal ProcessDelete As Boolean = True)
|
||||||
ControlInvokeFast(TP_CONTROLS, Sub()
|
ControlInvokeFast(TP_CONTROLS, Sub()
|
||||||
With TP_CONTROLS
|
With TP_CONTROLS
|
||||||
If .Controls.Count > 0 Then
|
If .Controls.Count > 0 Then
|
||||||
@@ -509,7 +520,10 @@ Namespace DownloadObjects.STDownloader
|
|||||||
For i = rCnt.Count - 1 To 0 Step -1
|
For i = rCnt.Count - 1 To 0 Step -1
|
||||||
cnt = .Controls(rCnt(i))
|
cnt = .Controls(rCnt(i))
|
||||||
.Controls.RemoveAt(rCnt(i))
|
.Controls.RemoveAt(rCnt(i))
|
||||||
If Not cnt.MyContainer Is Nothing Then cnt.MyContainer.Delete(RemoveFiles) : cnt.MyContainer.Dispose()
|
If Not cnt.MyContainer Is Nothing Then
|
||||||
|
If ProcessDelete Then cnt.MyContainer.Delete(RemoveFiles)
|
||||||
|
cnt.MyContainer.Dispose()
|
||||||
|
End If
|
||||||
cnt.Dispose()
|
cnt.Dispose()
|
||||||
Next
|
Next
|
||||||
End If
|
End If
|
||||||
|
|||||||
261
SCrawler.YouTube/Editors/BugReporterForm.Designer.vb
generated
@@ -24,7 +24,6 @@ Namespace Editors
|
|||||||
Private Sub InitializeComponent()
|
Private Sub InitializeComponent()
|
||||||
Me.components = New System.ComponentModel.Container()
|
Me.components = New System.ComponentModel.Container()
|
||||||
Dim TP_MAIN As System.Windows.Forms.TableLayoutPanel
|
Dim TP_MAIN As System.Windows.Forms.TableLayoutPanel
|
||||||
Dim TP_BUTTONS As System.Windows.Forms.TableLayoutPanel
|
|
||||||
Dim ActionButton1 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
Dim ActionButton1 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||||
Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(BugReporterForm))
|
Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(BugReporterForm))
|
||||||
Dim ActionButton2 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
Dim ActionButton2 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||||
@@ -33,31 +32,32 @@ Namespace Editors
|
|||||||
Dim ActionButton5 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
Dim ActionButton5 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||||
Dim ActionButton6 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
Dim ActionButton6 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||||
Dim ActionButton7 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
Dim ActionButton7 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||||
|
Dim TP_BUTTONS As System.Windows.Forms.TableLayoutPanel
|
||||||
Dim ActionButton8 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
Dim ActionButton8 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||||
Dim ActionButton9 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
Dim ActionButton9 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||||
Me.BTT_EMAIL = New System.Windows.Forms.Button()
|
|
||||||
Me.BTT_GITHUB = New System.Windows.Forms.Button()
|
|
||||||
Me.BTT_COPY = New System.Windows.Forms.Button()
|
|
||||||
Me.BTT_CANCEL = New System.Windows.Forms.Button()
|
|
||||||
Me.BTT_ANON = New System.Windows.Forms.Button()
|
|
||||||
Me.TT_MAIN = New System.Windows.Forms.ToolTip(Me.components)
|
|
||||||
Me.TXT_DESCR = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
Me.TXT_DESCR = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
||||||
Me.TXT_URL_PROFILE = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
Me.TXT_URL_PROFILE = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
||||||
Me.TXT_URL_POST = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
Me.TXT_URL_POST = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
||||||
Me.TXT_REPRODUCE = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
Me.TXT_REPRODUCE = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
||||||
Me.TXT_EXPECT = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
Me.TXT_EXPECT = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
||||||
Me.TXT_LOG = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
Me.TXT_LOG = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
||||||
|
Me.BTT_EMAIL = New System.Windows.Forms.Button()
|
||||||
|
Me.BTT_GITHUB = New System.Windows.Forms.Button()
|
||||||
|
Me.BTT_COPY = New System.Windows.Forms.Button()
|
||||||
|
Me.BTT_CANCEL = New System.Windows.Forms.Button()
|
||||||
|
Me.BTT_ANON = New System.Windows.Forms.Button()
|
||||||
Me.TXT_FILES = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
Me.TXT_FILES = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
||||||
|
Me.TT_MAIN = New System.Windows.Forms.ToolTip(Me.components)
|
||||||
TP_MAIN = New System.Windows.Forms.TableLayoutPanel()
|
TP_MAIN = New System.Windows.Forms.TableLayoutPanel()
|
||||||
TP_BUTTONS = New System.Windows.Forms.TableLayoutPanel()
|
TP_BUTTONS = New System.Windows.Forms.TableLayoutPanel()
|
||||||
TP_MAIN.SuspendLayout()
|
TP_MAIN.SuspendLayout()
|
||||||
TP_BUTTONS.SuspendLayout()
|
|
||||||
CType(Me.TXT_DESCR, System.ComponentModel.ISupportInitialize).BeginInit()
|
CType(Me.TXT_DESCR, System.ComponentModel.ISupportInitialize).BeginInit()
|
||||||
CType(Me.TXT_URL_PROFILE, System.ComponentModel.ISupportInitialize).BeginInit()
|
CType(Me.TXT_URL_PROFILE, System.ComponentModel.ISupportInitialize).BeginInit()
|
||||||
CType(Me.TXT_URL_POST, System.ComponentModel.ISupportInitialize).BeginInit()
|
CType(Me.TXT_URL_POST, System.ComponentModel.ISupportInitialize).BeginInit()
|
||||||
CType(Me.TXT_REPRODUCE, System.ComponentModel.ISupportInitialize).BeginInit()
|
CType(Me.TXT_REPRODUCE, System.ComponentModel.ISupportInitialize).BeginInit()
|
||||||
CType(Me.TXT_EXPECT, System.ComponentModel.ISupportInitialize).BeginInit()
|
CType(Me.TXT_EXPECT, System.ComponentModel.ISupportInitialize).BeginInit()
|
||||||
CType(Me.TXT_LOG, System.ComponentModel.ISupportInitialize).BeginInit()
|
CType(Me.TXT_LOG, System.ComponentModel.ISupportInitialize).BeginInit()
|
||||||
|
TP_BUTTONS.SuspendLayout()
|
||||||
CType(Me.TXT_FILES, System.ComponentModel.ISupportInitialize).BeginInit()
|
CType(Me.TXT_FILES, System.ComponentModel.ISupportInitialize).BeginInit()
|
||||||
Me.SuspendLayout()
|
Me.SuspendLayout()
|
||||||
'
|
'
|
||||||
@@ -88,6 +88,123 @@ Namespace Editors
|
|||||||
TP_MAIN.Size = New System.Drawing.Size(584, 461)
|
TP_MAIN.Size = New System.Drawing.Size(584, 461)
|
||||||
TP_MAIN.TabIndex = 0
|
TP_MAIN.TabIndex = 0
|
||||||
'
|
'
|
||||||
|
'TXT_DESCR
|
||||||
|
'
|
||||||
|
ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image)
|
||||||
|
ActionButton1.Dock = System.Windows.Forms.DockStyle.Top
|
||||||
|
ActionButton1.Name = "Clear"
|
||||||
|
ActionButton1.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
||||||
|
Me.TXT_DESCR.Buttons.Add(ActionButton1)
|
||||||
|
Me.TXT_DESCR.CaptionDock = System.Windows.Forms.DockStyle.Top
|
||||||
|
Me.TXT_DESCR.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.None
|
||||||
|
Me.TXT_DESCR.CaptionVisible = False
|
||||||
|
Me.TXT_DESCR.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.TXT_DESCR.GroupBoxed = True
|
||||||
|
Me.TXT_DESCR.GroupBoxText = "Describe the bug or write your message"
|
||||||
|
Me.TXT_DESCR.Location = New System.Drawing.Point(3, 3)
|
||||||
|
Me.TXT_DESCR.Multiline = True
|
||||||
|
Me.TXT_DESCR.Name = "TXT_DESCR"
|
||||||
|
Me.TXT_DESCR.Size = New System.Drawing.Size(578, 69)
|
||||||
|
Me.TXT_DESCR.TabIndex = 0
|
||||||
|
Me.TXT_DESCR.TextToolTip = "A clear and concise description of what the bug is"
|
||||||
|
Me.TXT_DESCR.TextToolTipEnabled = True
|
||||||
|
'
|
||||||
|
'TXT_URL_PROFILE
|
||||||
|
'
|
||||||
|
ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image)
|
||||||
|
ActionButton2.Name = "Clear"
|
||||||
|
ActionButton2.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
||||||
|
Me.TXT_URL_PROFILE.Buttons.Add(ActionButton2)
|
||||||
|
Me.TXT_URL_PROFILE.CaptionText = "Profile URL"
|
||||||
|
Me.TXT_URL_PROFILE.CaptionWidth = 75.0R
|
||||||
|
Me.TXT_URL_PROFILE.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.TXT_URL_PROFILE.Location = New System.Drawing.Point(3, 78)
|
||||||
|
Me.TXT_URL_PROFILE.Name = "TXT_URL_PROFILE"
|
||||||
|
Me.TXT_URL_PROFILE.Size = New System.Drawing.Size(578, 22)
|
||||||
|
Me.TXT_URL_PROFILE.TabIndex = 1
|
||||||
|
'
|
||||||
|
'TXT_URL_POST
|
||||||
|
'
|
||||||
|
ActionButton3.BackgroundImage = CType(resources.GetObject("ActionButton3.BackgroundImage"), System.Drawing.Image)
|
||||||
|
ActionButton3.Name = "Clear"
|
||||||
|
ActionButton3.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
||||||
|
Me.TXT_URL_POST.Buttons.Add(ActionButton3)
|
||||||
|
Me.TXT_URL_POST.CaptionText = "Post URL"
|
||||||
|
Me.TXT_URL_POST.CaptionWidth = 75.0R
|
||||||
|
Me.TXT_URL_POST.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.TXT_URL_POST.Location = New System.Drawing.Point(3, 106)
|
||||||
|
Me.TXT_URL_POST.Name = "TXT_URL_POST"
|
||||||
|
Me.TXT_URL_POST.Size = New System.Drawing.Size(578, 22)
|
||||||
|
Me.TXT_URL_POST.TabIndex = 2
|
||||||
|
'
|
||||||
|
'TXT_REPRODUCE
|
||||||
|
'
|
||||||
|
ActionButton4.BackgroundImage = CType(resources.GetObject("ActionButton4.BackgroundImage"), System.Drawing.Image)
|
||||||
|
ActionButton4.Dock = System.Windows.Forms.DockStyle.Top
|
||||||
|
ActionButton4.Name = "Clear"
|
||||||
|
ActionButton4.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
||||||
|
Me.TXT_REPRODUCE.Buttons.Add(ActionButton4)
|
||||||
|
Me.TXT_REPRODUCE.CaptionDock = System.Windows.Forms.DockStyle.Top
|
||||||
|
Me.TXT_REPRODUCE.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.None
|
||||||
|
Me.TXT_REPRODUCE.CaptionVisible = False
|
||||||
|
Me.TXT_REPRODUCE.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.TXT_REPRODUCE.GroupBoxed = True
|
||||||
|
Me.TXT_REPRODUCE.GroupBoxText = "Steps to reproduce"
|
||||||
|
Me.TXT_REPRODUCE.Location = New System.Drawing.Point(3, 134)
|
||||||
|
Me.TXT_REPRODUCE.Multiline = True
|
||||||
|
Me.TXT_REPRODUCE.Name = "TXT_REPRODUCE"
|
||||||
|
Me.TXT_REPRODUCE.Size = New System.Drawing.Size(578, 69)
|
||||||
|
Me.TXT_REPRODUCE.TabIndex = 3
|
||||||
|
Me.TXT_REPRODUCE.TextToolTip = "Steps to reproduce the behavior:" & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "1. Do something" & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "2. See error"
|
||||||
|
Me.TXT_REPRODUCE.TextToolTipEnabled = True
|
||||||
|
'
|
||||||
|
'TXT_EXPECT
|
||||||
|
'
|
||||||
|
ActionButton5.BackgroundImage = CType(resources.GetObject("ActionButton5.BackgroundImage"), System.Drawing.Image)
|
||||||
|
ActionButton5.Dock = System.Windows.Forms.DockStyle.Top
|
||||||
|
ActionButton5.Name = "Clear"
|
||||||
|
ActionButton5.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
||||||
|
Me.TXT_EXPECT.Buttons.Add(ActionButton5)
|
||||||
|
Me.TXT_EXPECT.CaptionDock = System.Windows.Forms.DockStyle.Top
|
||||||
|
Me.TXT_EXPECT.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.None
|
||||||
|
Me.TXT_EXPECT.CaptionVisible = False
|
||||||
|
Me.TXT_EXPECT.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.TXT_EXPECT.GroupBoxed = True
|
||||||
|
Me.TXT_EXPECT.GroupBoxText = "Expected behavior"
|
||||||
|
Me.TXT_EXPECT.Location = New System.Drawing.Point(3, 209)
|
||||||
|
Me.TXT_EXPECT.Multiline = True
|
||||||
|
Me.TXT_EXPECT.Name = "TXT_EXPECT"
|
||||||
|
Me.TXT_EXPECT.Size = New System.Drawing.Size(578, 69)
|
||||||
|
Me.TXT_EXPECT.TabIndex = 4
|
||||||
|
Me.TXT_EXPECT.TextToolTip = "A clear and concise description of what you expected to happen."
|
||||||
|
Me.TXT_EXPECT.TextToolTipEnabled = True
|
||||||
|
'
|
||||||
|
'TXT_LOG
|
||||||
|
'
|
||||||
|
ActionButton6.BackgroundImage = CType(resources.GetObject("ActionButton6.BackgroundImage"), System.Drawing.Image)
|
||||||
|
ActionButton6.Dock = System.Windows.Forms.DockStyle.Top
|
||||||
|
ActionButton6.Name = "Open"
|
||||||
|
ActionButton6.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Open
|
||||||
|
ActionButton6.ToolTipText = "Select log files to add their text to the message"
|
||||||
|
ActionButton7.BackgroundImage = CType(resources.GetObject("ActionButton7.BackgroundImage"), System.Drawing.Image)
|
||||||
|
ActionButton7.Dock = System.Windows.Forms.DockStyle.Top
|
||||||
|
ActionButton7.Name = "Clear"
|
||||||
|
ActionButton7.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
||||||
|
ActionButton7.ToolTipText = "Empty"
|
||||||
|
Me.TXT_LOG.Buttons.Add(ActionButton6)
|
||||||
|
Me.TXT_LOG.Buttons.Add(ActionButton7)
|
||||||
|
Me.TXT_LOG.CaptionDock = System.Windows.Forms.DockStyle.Top
|
||||||
|
Me.TXT_LOG.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.None
|
||||||
|
Me.TXT_LOG.CaptionVisible = False
|
||||||
|
Me.TXT_LOG.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.TXT_LOG.GroupBoxed = True
|
||||||
|
Me.TXT_LOG.GroupBoxText = "Log data"
|
||||||
|
Me.TXT_LOG.Location = New System.Drawing.Point(3, 284)
|
||||||
|
Me.TXT_LOG.Multiline = True
|
||||||
|
Me.TXT_LOG.Name = "TXT_LOG"
|
||||||
|
Me.TXT_LOG.Size = New System.Drawing.Size(578, 69)
|
||||||
|
Me.TXT_LOG.TabIndex = 5
|
||||||
|
'
|
||||||
'TP_BUTTONS
|
'TP_BUTTONS
|
||||||
'
|
'
|
||||||
TP_BUTTONS.ColumnCount = 6
|
TP_BUTTONS.ColumnCount = 6
|
||||||
@@ -119,7 +236,7 @@ Namespace Editors
|
|||||||
Me.BTT_EMAIL.Name = "BTT_EMAIL"
|
Me.BTT_EMAIL.Name = "BTT_EMAIL"
|
||||||
Me.BTT_EMAIL.Size = New System.Drawing.Size(94, 24)
|
Me.BTT_EMAIL.Size = New System.Drawing.Size(94, 24)
|
||||||
Me.BTT_EMAIL.TabIndex = 1
|
Me.BTT_EMAIL.TabIndex = 1
|
||||||
Me.BTT_EMAIL.Text = "email"
|
Me.BTT_EMAIL.Text = "Email"
|
||||||
Me.TT_MAIN.SetToolTip(Me.BTT_EMAIL, "Create a message to send via email.")
|
Me.TT_MAIN.SetToolTip(Me.BTT_EMAIL, "Create a message to send via email.")
|
||||||
Me.BTT_EMAIL.UseVisualStyleBackColor = True
|
Me.BTT_EMAIL.UseVisualStyleBackColor = True
|
||||||
'
|
'
|
||||||
@@ -167,129 +284,6 @@ Namespace Editors
|
|||||||
Me.TT_MAIN.SetToolTip(Me.BTT_ANON, resources.GetString("BTT_ANON.ToolTip"))
|
Me.TT_MAIN.SetToolTip(Me.BTT_ANON, resources.GetString("BTT_ANON.ToolTip"))
|
||||||
Me.BTT_ANON.UseVisualStyleBackColor = True
|
Me.BTT_ANON.UseVisualStyleBackColor = True
|
||||||
'
|
'
|
||||||
'TXT_DESCR
|
|
||||||
'
|
|
||||||
ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image)
|
|
||||||
ActionButton1.Dock = System.Windows.Forms.DockStyle.Top
|
|
||||||
ActionButton1.Name = "Clear"
|
|
||||||
ActionButton1.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
|
||||||
Me.TXT_DESCR.Buttons.Add(ActionButton1)
|
|
||||||
Me.TXT_DESCR.CaptionDock = System.Windows.Forms.DockStyle.Top
|
|
||||||
Me.TXT_DESCR.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.None
|
|
||||||
Me.TXT_DESCR.CaptionVisible = False
|
|
||||||
Me.TXT_DESCR.Dock = System.Windows.Forms.DockStyle.Fill
|
|
||||||
Me.TXT_DESCR.GroupBoxed = True
|
|
||||||
Me.TXT_DESCR.GroupBoxText = "Describe the bug or write your message"
|
|
||||||
Me.TXT_DESCR.Lines = New String(-1) {}
|
|
||||||
Me.TXT_DESCR.Location = New System.Drawing.Point(3, 3)
|
|
||||||
Me.TXT_DESCR.Multiline = True
|
|
||||||
Me.TXT_DESCR.Name = "TXT_DESCR"
|
|
||||||
Me.TXT_DESCR.Size = New System.Drawing.Size(578, 69)
|
|
||||||
Me.TXT_DESCR.TabIndex = 0
|
|
||||||
Me.TXT_DESCR.TextToolTip = "A clear and concise description of what the bug is"
|
|
||||||
Me.TXT_DESCR.TextToolTipEnabled = True
|
|
||||||
'
|
|
||||||
'TXT_URL_PROFILE
|
|
||||||
'
|
|
||||||
ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image)
|
|
||||||
ActionButton2.Name = "Clear"
|
|
||||||
ActionButton2.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
|
||||||
Me.TXT_URL_PROFILE.Buttons.Add(ActionButton2)
|
|
||||||
Me.TXT_URL_PROFILE.CaptionText = "Profile URL"
|
|
||||||
Me.TXT_URL_PROFILE.CaptionWidth = 75.0R
|
|
||||||
Me.TXT_URL_PROFILE.Dock = System.Windows.Forms.DockStyle.Fill
|
|
||||||
Me.TXT_URL_PROFILE.Lines = New String(-1) {}
|
|
||||||
Me.TXT_URL_PROFILE.Location = New System.Drawing.Point(3, 78)
|
|
||||||
Me.TXT_URL_PROFILE.Name = "TXT_URL_PROFILE"
|
|
||||||
Me.TXT_URL_PROFILE.Size = New System.Drawing.Size(578, 22)
|
|
||||||
Me.TXT_URL_PROFILE.TabIndex = 1
|
|
||||||
'
|
|
||||||
'TXT_URL_POST
|
|
||||||
'
|
|
||||||
ActionButton3.BackgroundImage = CType(resources.GetObject("ActionButton3.BackgroundImage"), System.Drawing.Image)
|
|
||||||
ActionButton3.Name = "Clear"
|
|
||||||
ActionButton3.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
|
||||||
Me.TXT_URL_POST.Buttons.Add(ActionButton3)
|
|
||||||
Me.TXT_URL_POST.CaptionText = "Post URL"
|
|
||||||
Me.TXT_URL_POST.CaptionWidth = 75.0R
|
|
||||||
Me.TXT_URL_POST.Dock = System.Windows.Forms.DockStyle.Fill
|
|
||||||
Me.TXT_URL_POST.Lines = New String(-1) {}
|
|
||||||
Me.TXT_URL_POST.Location = New System.Drawing.Point(3, 106)
|
|
||||||
Me.TXT_URL_POST.Name = "TXT_URL_POST"
|
|
||||||
Me.TXT_URL_POST.Size = New System.Drawing.Size(578, 22)
|
|
||||||
Me.TXT_URL_POST.TabIndex = 2
|
|
||||||
'
|
|
||||||
'TXT_REPRODUCE
|
|
||||||
'
|
|
||||||
ActionButton4.BackgroundImage = CType(resources.GetObject("ActionButton4.BackgroundImage"), System.Drawing.Image)
|
|
||||||
ActionButton4.Dock = System.Windows.Forms.DockStyle.Top
|
|
||||||
ActionButton4.Name = "Clear"
|
|
||||||
ActionButton4.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
|
||||||
Me.TXT_REPRODUCE.Buttons.Add(ActionButton4)
|
|
||||||
Me.TXT_REPRODUCE.CaptionDock = System.Windows.Forms.DockStyle.Top
|
|
||||||
Me.TXT_REPRODUCE.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.None
|
|
||||||
Me.TXT_REPRODUCE.CaptionVisible = False
|
|
||||||
Me.TXT_REPRODUCE.Dock = System.Windows.Forms.DockStyle.Fill
|
|
||||||
Me.TXT_REPRODUCE.GroupBoxed = True
|
|
||||||
Me.TXT_REPRODUCE.GroupBoxText = "To Reproduce"
|
|
||||||
Me.TXT_REPRODUCE.Lines = New String(-1) {}
|
|
||||||
Me.TXT_REPRODUCE.Location = New System.Drawing.Point(3, 134)
|
|
||||||
Me.TXT_REPRODUCE.Multiline = True
|
|
||||||
Me.TXT_REPRODUCE.Name = "TXT_REPRODUCE"
|
|
||||||
Me.TXT_REPRODUCE.Size = New System.Drawing.Size(578, 69)
|
|
||||||
Me.TXT_REPRODUCE.TabIndex = 3
|
|
||||||
Me.TXT_REPRODUCE.TextToolTip = "Steps to reproduce the behavior:" & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "1. Do something" & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "2. See error"
|
|
||||||
Me.TXT_REPRODUCE.TextToolTipEnabled = True
|
|
||||||
'
|
|
||||||
'TXT_EXPECT
|
|
||||||
'
|
|
||||||
ActionButton5.BackgroundImage = CType(resources.GetObject("ActionButton5.BackgroundImage"), System.Drawing.Image)
|
|
||||||
ActionButton5.Dock = System.Windows.Forms.DockStyle.Top
|
|
||||||
ActionButton5.Name = "Clear"
|
|
||||||
ActionButton5.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
|
||||||
Me.TXT_EXPECT.Buttons.Add(ActionButton5)
|
|
||||||
Me.TXT_EXPECT.CaptionDock = System.Windows.Forms.DockStyle.Top
|
|
||||||
Me.TXT_EXPECT.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.None
|
|
||||||
Me.TXT_EXPECT.CaptionVisible = False
|
|
||||||
Me.TXT_EXPECT.Dock = System.Windows.Forms.DockStyle.Fill
|
|
||||||
Me.TXT_EXPECT.GroupBoxed = True
|
|
||||||
Me.TXT_EXPECT.GroupBoxText = "Expected behavior"
|
|
||||||
Me.TXT_EXPECT.Lines = New String(-1) {}
|
|
||||||
Me.TXT_EXPECT.Location = New System.Drawing.Point(3, 209)
|
|
||||||
Me.TXT_EXPECT.Multiline = True
|
|
||||||
Me.TXT_EXPECT.Name = "TXT_EXPECT"
|
|
||||||
Me.TXT_EXPECT.Size = New System.Drawing.Size(578, 69)
|
|
||||||
Me.TXT_EXPECT.TabIndex = 4
|
|
||||||
Me.TXT_EXPECT.TextToolTip = "A clear and concise description of what you expected to happen."
|
|
||||||
Me.TXT_EXPECT.TextToolTipEnabled = True
|
|
||||||
'
|
|
||||||
'TXT_LOG
|
|
||||||
'
|
|
||||||
ActionButton6.BackgroundImage = CType(resources.GetObject("ActionButton6.BackgroundImage"), System.Drawing.Image)
|
|
||||||
ActionButton6.Dock = System.Windows.Forms.DockStyle.Top
|
|
||||||
ActionButton6.Name = "Open"
|
|
||||||
ActionButton6.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Open
|
|
||||||
ActionButton6.ToolTipText = "Select log files to add their text to the message"
|
|
||||||
ActionButton7.BackgroundImage = CType(resources.GetObject("ActionButton7.BackgroundImage"), System.Drawing.Image)
|
|
||||||
ActionButton7.Dock = System.Windows.Forms.DockStyle.Top
|
|
||||||
ActionButton7.Name = "Clear"
|
|
||||||
ActionButton7.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
|
||||||
ActionButton7.ToolTipText = "Empty"
|
|
||||||
Me.TXT_LOG.Buttons.Add(ActionButton6)
|
|
||||||
Me.TXT_LOG.Buttons.Add(ActionButton7)
|
|
||||||
Me.TXT_LOG.CaptionDock = System.Windows.Forms.DockStyle.Top
|
|
||||||
Me.TXT_LOG.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.None
|
|
||||||
Me.TXT_LOG.CaptionVisible = False
|
|
||||||
Me.TXT_LOG.Dock = System.Windows.Forms.DockStyle.Fill
|
|
||||||
Me.TXT_LOG.GroupBoxed = True
|
|
||||||
Me.TXT_LOG.GroupBoxText = "Log data"
|
|
||||||
Me.TXT_LOG.Lines = New String(-1) {}
|
|
||||||
Me.TXT_LOG.Location = New System.Drawing.Point(3, 284)
|
|
||||||
Me.TXT_LOG.Multiline = True
|
|
||||||
Me.TXT_LOG.Name = "TXT_LOG"
|
|
||||||
Me.TXT_LOG.Size = New System.Drawing.Size(578, 69)
|
|
||||||
Me.TXT_LOG.TabIndex = 5
|
|
||||||
'
|
|
||||||
'TXT_FILES
|
'TXT_FILES
|
||||||
'
|
'
|
||||||
ActionButton8.BackgroundImage = CType(resources.GetObject("ActionButton8.BackgroundImage"), System.Drawing.Image)
|
ActionButton8.BackgroundImage = CType(resources.GetObject("ActionButton8.BackgroundImage"), System.Drawing.Image)
|
||||||
@@ -310,7 +304,6 @@ Namespace Editors
|
|||||||
Me.TXT_FILES.Dock = System.Windows.Forms.DockStyle.Fill
|
Me.TXT_FILES.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
Me.TXT_FILES.GroupBoxed = True
|
Me.TXT_FILES.GroupBoxed = True
|
||||||
Me.TXT_FILES.GroupBoxText = "Files"
|
Me.TXT_FILES.GroupBoxText = "Files"
|
||||||
Me.TXT_FILES.Lines = New String(-1) {}
|
|
||||||
Me.TXT_FILES.Location = New System.Drawing.Point(3, 359)
|
Me.TXT_FILES.Location = New System.Drawing.Point(3, 359)
|
||||||
Me.TXT_FILES.Multiline = True
|
Me.TXT_FILES.Multiline = True
|
||||||
Me.TXT_FILES.Name = "TXT_FILES"
|
Me.TXT_FILES.Name = "TXT_FILES"
|
||||||
@@ -332,13 +325,13 @@ Namespace Editors
|
|||||||
Me.Name = "BugReporterForm"
|
Me.Name = "BugReporterForm"
|
||||||
Me.Text = "New message"
|
Me.Text = "New message"
|
||||||
TP_MAIN.ResumeLayout(False)
|
TP_MAIN.ResumeLayout(False)
|
||||||
TP_BUTTONS.ResumeLayout(False)
|
|
||||||
CType(Me.TXT_DESCR, System.ComponentModel.ISupportInitialize).EndInit()
|
CType(Me.TXT_DESCR, System.ComponentModel.ISupportInitialize).EndInit()
|
||||||
CType(Me.TXT_URL_PROFILE, System.ComponentModel.ISupportInitialize).EndInit()
|
CType(Me.TXT_URL_PROFILE, System.ComponentModel.ISupportInitialize).EndInit()
|
||||||
CType(Me.TXT_URL_POST, System.ComponentModel.ISupportInitialize).EndInit()
|
CType(Me.TXT_URL_POST, System.ComponentModel.ISupportInitialize).EndInit()
|
||||||
CType(Me.TXT_REPRODUCE, System.ComponentModel.ISupportInitialize).EndInit()
|
CType(Me.TXT_REPRODUCE, System.ComponentModel.ISupportInitialize).EndInit()
|
||||||
CType(Me.TXT_EXPECT, System.ComponentModel.ISupportInitialize).EndInit()
|
CType(Me.TXT_EXPECT, System.ComponentModel.ISupportInitialize).EndInit()
|
||||||
CType(Me.TXT_LOG, System.ComponentModel.ISupportInitialize).EndInit()
|
CType(Me.TXT_LOG, System.ComponentModel.ISupportInitialize).EndInit()
|
||||||
|
TP_BUTTONS.ResumeLayout(False)
|
||||||
CType(Me.TXT_FILES, System.ComponentModel.ISupportInitialize).EndInit()
|
CType(Me.TXT_FILES, System.ComponentModel.ISupportInitialize).EndInit()
|
||||||
Me.ResumeLayout(False)
|
Me.ResumeLayout(False)
|
||||||
|
|
||||||
|
|||||||
@@ -124,60 +124,60 @@
|
|||||||
<data name="ActionButton1.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="ActionButton1.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
<value>
|
<value>
|
||||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||||
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
|
xAAADsQBlSsOGwAAAHpJREFUOE+1kVEKgDAMQ3e2/e+MXqpn6W/HxM7SpkIVB4HxSMKiTUTaFwVQ1X25
|
||||||
tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX
|
DjMfSxskHBYsAxHJkjUjHgrUNMY4peaMPxb03rcZMVhgn2oDKAwn+L0aROH/Cny4NAGFSx8x+10ZDwV2
|
||||||
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
|
gt+LOCxQsw1nPBS8VQBVTTzyhrdZSUm7AAAAAElFTkSuQmCC
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ActionButton2.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="ActionButton2.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
<value>
|
<value>
|
||||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||||
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
|
xAAADsQBlSsOGwAAAHpJREFUOE+1kVEKgDAMQ3e2/e+MXqpn6W/HxM7SpkIVB4HxSMKiTUTaFwVQ1X25
|
||||||
tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX
|
DjMfSxskHBYsAxHJkjUjHgrUNMY4peaMPxb03rcZMVhgn2oDKAwn+L0aROH/Cny4NAGFSx8x+10ZDwV2
|
||||||
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
|
gt+LOCxQsw1nPBS8VQBVTTzyhrdZSUm7AAAAAElFTkSuQmCC
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ActionButton3.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="ActionButton3.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
<value>
|
<value>
|
||||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||||
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
|
xAAADsQBlSsOGwAAAHpJREFUOE+1kVEKgDAMQ3e2/e+MXqpn6W/HxM7SpkIVB4HxSMKiTUTaFwVQ1X25
|
||||||
tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX
|
DjMfSxskHBYsAxHJkjUjHgrUNMY4peaMPxb03rcZMVhgn2oDKAwn+L0aROH/Cny4NAGFSx8x+10ZDwV2
|
||||||
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
|
gt+LOCxQsw1nPBS8VQBVTTzyhrdZSUm7AAAAAElFTkSuQmCC
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ActionButton4.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="ActionButton4.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
<value>
|
<value>
|
||||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||||
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
|
xAAADsQBlSsOGwAAAHpJREFUOE+1kVEKgDAMQ3e2/e+MXqpn6W/HxM7SpkIVB4HxSMKiTUTaFwVQ1X25
|
||||||
tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX
|
DjMfSxskHBYsAxHJkjUjHgrUNMY4peaMPxb03rcZMVhgn2oDKAwn+L0aROH/Cny4NAGFSx8x+10ZDwV2
|
||||||
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
|
gt+LOCxQsw1nPBS8VQBVTTzyhrdZSUm7AAAAAElFTkSuQmCC
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ActionButton5.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="ActionButton5.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
<value>
|
<value>
|
||||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||||
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
|
xAAADsQBlSsOGwAAAHpJREFUOE+1kVEKgDAMQ3e2/e+MXqpn6W/HxM7SpkIVB4HxSMKiTUTaFwVQ1X25
|
||||||
tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX
|
DjMfSxskHBYsAxHJkjUjHgrUNMY4peaMPxb03rcZMVhgn2oDKAwn+L0aROH/Cny4NAGFSx8x+10ZDwV2
|
||||||
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
|
gt+LOCxQsw1nPBS8VQBVTTzyhrdZSUm7AAAAAElFTkSuQmCC
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ActionButton6.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="ActionButton6.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
<value>
|
<value>
|
||||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||||
wwAADsMBx2+oZAAAAR5JREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbGujg3ZATZPKYdC6FQhPwlAMkg3dP
|
wwAADsMBx2+oZAAAARlJREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbWujg3dATZPKYZC6BQhvw1AMkg3dP
|
||||||
WQwhyWIyJIUW5NqyPb7oCVtIlhVTwYf8nv7/t2zJagel9KmqKsIACYL9RjI8UHz5zshougZr/AEvbxEP
|
XQyl7WIyJIEW5CbS0/jKE5GwpCghgg9s6/8/y5Kj6DA45zcAwAAAezB6rjNnB4XX244NHt8wGs7wblop
|
||||||
aZCDBY3VslixaJvX3wzkkDiOwbZtDRGA5vdNAg+TL27qgmt5XkBG/gTdAG7Gt+3PP9oOaEGFCVEC6rp+
|
yRGxwZQBYKIfbn477EvqusY4jj2MgMpPiwav7l9UyYXmdrs9duzP4ApUmd72sfrxVsD33JQISyClvFUX
|
||||||
5g9MfM/c5e4OsEZMZkQEtGL5H2DdZ5JRArDwPA+iKII0TfkC9vroC9j5vq8JTWw3WzWgLMtZGIaa0MR8
|
w9nJssvJFei9CJUtgQ7394Du3YKLJaCbLMuwqips21ZNuDve/35X8J7nuRcMsVwsbYEQYlSWpRcMMR5P
|
||||||
vlAD8PYlSaIJTTiOowY0p0Bc19XEJo6HE59FAPuMzyAINKGJ1XLFZxHALtMrnkBXOIQIIIQ8YvF/KrgB
|
bAH9fU3TeMEQSZLYgsMpsDRNvXCIr89vWyCEeC6KwguGmL/ObYGU8oFOwA2ewwgYY9f6f7iUf3DGkTcu
|
||||||
cMaRN0UdBBkAAAAASUVORK5CYII=
|
khP7AAAAAElFTkSuQmCC
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ActionButton7.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="ActionButton7.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
<value>
|
<value>
|
||||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||||
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
|
xAAADsQBlSsOGwAAAHpJREFUOE+1kVEKgDAMQ3e2/e+MXqpn6W/HxM7SpkIVB4HxSMKiTUTaFwVQ1X25
|
||||||
tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX
|
DjMfSxskHBYsAxHJkjUjHgrUNMY4peaMPxb03rcZMVhgn2oDKAwn+L0aROH/Cny4NAGFSx8x+10ZDwV2
|
||||||
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
|
gt+LOCxQsw1nPBS8VQBVTTzyhrdZSUm7AAAAAElFTkSuQmCC
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<metadata name="TP_BUTTONS.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
<metadata name="TP_BUTTONS.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
@@ -195,31 +195,31 @@ If you would like a response from the developer, response, please add your conta
|
|||||||
<data name="ActionButton8.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="ActionButton8.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
<value>
|
<value>
|
||||||
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
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ActionButton9.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="ActionButton9.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
<value>
|
<value>
|
||||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||||
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
|
xAAADsQBlSsOGwAAAHpJREFUOE+1kVEKgDAMQ3e2/e+MXqpn6W/HxM7SpkIVB4HxSMKiTUTaFwVQ1X25
|
||||||
tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX
|
DjMfSxskHBYsAxHJkjUjHgrUNMY4peaMPxb03rcZMVhgn2oDKAwn+L0aROH/Cny4NAGFSx8x+10ZDwV2
|
||||||
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
|
gt+LOCxQsw1nPBS8VQBVTTzyhrdZSUm7AAAAAElFTkSuQmCC
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -10,6 +10,7 @@ Imports System.Threading
|
|||||||
Imports PersonalUtilities.Tools
|
Imports PersonalUtilities.Tools
|
||||||
Imports PersonalUtilities.Tools.Web
|
Imports PersonalUtilities.Tools.Web
|
||||||
Imports PersonalUtilities.Functions.Messaging
|
Imports PersonalUtilities.Functions.Messaging
|
||||||
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
Imports SCrawler.DownloadObjects.STDownloader
|
Imports SCrawler.DownloadObjects.STDownloader
|
||||||
Public Module MainModShared
|
Public Module MainModShared
|
||||||
Public Property BATCH As BatchExecutor
|
Public Property BATCH As BatchExecutor
|
||||||
@@ -135,9 +136,11 @@ Namespace Editors
|
|||||||
Public Shared Function GetProgramEnvirText(ByVal EnvirData As IDownloaderSettings, ByVal IsYouTube As Boolean) As String
|
Public Shared Function GetProgramEnvirText(ByVal EnvirData As IDownloaderSettings, ByVal IsYouTube As Boolean) As String
|
||||||
Try
|
Try
|
||||||
Dim output$ = String.Empty
|
Dim output$ = String.Empty
|
||||||
|
Dim verAfter As RParams = RParams.DM("\A\w\:\\.*", 0, EDP.ReturnValue)
|
||||||
Using b As New BatchExecutor(True)
|
Using b As New BatchExecutor(True)
|
||||||
Dim f As SFile
|
Dim f As SFile
|
||||||
Dim cmd$, ff$, vText$
|
Dim cmd$, ff$, vText$
|
||||||
|
Dim ii%
|
||||||
|
|
||||||
For i% = 0 To IIf(IsYouTube, 1, 3)
|
For i% = 0 To IIf(IsYouTube, 1, 3)
|
||||||
cmd = "--version"
|
cmd = "--version"
|
||||||
@@ -154,7 +157,17 @@ Namespace Editors
|
|||||||
Else
|
Else
|
||||||
b.Reset()
|
b.Reset()
|
||||||
b.Execute($"""{f}"" {cmd}", EDP.None)
|
b.Execute($"""{f}"" {cmd}", EDP.None)
|
||||||
If b.OutputData.Count > 3 Then vText = b.OutputData(3) Else vText = "undefined"
|
'If b.OutputData.Count > 3 Then vText = b.OutputData(3) Else vText = "undefined"
|
||||||
|
|
||||||
|
vText = String.Empty
|
||||||
|
With b.OutputData
|
||||||
|
If .Count > 0 Then
|
||||||
|
ii = .FindIndex(Function(bb) Not CStr(RegexReplace(bb, verAfter)).IsEmptyString)
|
||||||
|
If ii >= 0 And ii + 1 <= .Count - 1 Then vText = .Item(ii + 1)
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
If vText.IsEmptyString Then vText = "undefined"
|
||||||
|
|
||||||
output.StringAppendLine($"{ff} version: {vText}")
|
output.StringAppendLine($"{ff} version: {vText}")
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ Imports System.Runtime.InteropServices
|
|||||||
<Assembly: AssemblyDescription("YouTube plugin environment")>
|
<Assembly: AssemblyDescription("YouTube plugin environment")>
|
||||||
<Assembly: AssemblyCompany("AndyProgram")>
|
<Assembly: AssemblyCompany("AndyProgram")>
|
||||||
<Assembly: AssemblyProduct("SCrawler.YouTube")>
|
<Assembly: AssemblyProduct("SCrawler.YouTube")>
|
||||||
<Assembly: AssemblyCopyright("Copyright © 2024")>
|
<Assembly: AssemblyCopyright("Copyright © 2025")>
|
||||||
<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("2024.8.10.0")>
|
<Assembly: AssemblyVersion("2025.8.1.0")>
|
||||||
<Assembly: AssemblyFileVersion("2024.8.10.0")>
|
<Assembly: AssemblyFileVersion("2025.8.1.0")>
|
||||||
<Assembly: NeutralResourcesLanguage("en")>
|
<Assembly: NeutralResourcesLanguage("en")>
|
||||||
|
|||||||
@@ -116,7 +116,9 @@ Namespace API.YouTube.Objects
|
|||||||
<XMLEC> Public Property IsShorts As Boolean = False Implements IYouTubeMediaContainer.IsShorts
|
<XMLEC> Public Property IsShorts As Boolean = False Implements IYouTubeMediaContainer.IsShorts
|
||||||
<XMLEC> Public Property ID As String Implements IYouTubeMediaContainer.ID, IUserMedia.PostID
|
<XMLEC> Public Property ID As String Implements IYouTubeMediaContainer.ID, IUserMedia.PostID
|
||||||
<XMLEC> Public Property Title As String Implements IDownloadableMedia.Title
|
<XMLEC> Public Property Title As String Implements IDownloadableMedia.Title
|
||||||
<XMLEC> Public Property Description As String Implements IYouTubeMediaContainer.Description
|
<XMLEC> Public Property Description As String Implements IYouTubeMediaContainer.Description, IUserMedia.PostText
|
||||||
|
Private Property IUserMedia_PostTextFile As String Implements IUserMedia.PostTextFile
|
||||||
|
Private Property IUserMedia_PostTextFileSpecialFolder As Boolean Implements IUserMedia.PostTextFileSpecialFolder
|
||||||
<XMLEC> Public Property PlaylistID As String Implements IYouTubeMediaContainer.PlaylistID
|
<XMLEC> Public Property PlaylistID As String Implements IYouTubeMediaContainer.PlaylistID
|
||||||
<XMLEC> Public Property PlaylistTitle As String Implements IYouTubeMediaContainer.PlaylistTitle
|
<XMLEC> Public Property PlaylistTitle As String Implements IYouTubeMediaContainer.PlaylistTitle
|
||||||
<XMLEC> Public Property UserID As String Implements IYouTubeMediaContainer.UserID
|
<XMLEC> Public Property UserID As String Implements IYouTubeMediaContainer.UserID
|
||||||
@@ -175,7 +177,9 @@ Namespace API.YouTube.Objects
|
|||||||
Protected _ThumbnailUrl As String = String.Empty
|
Protected _ThumbnailUrl As String = String.Empty
|
||||||
<XMLEC> Public Overridable Property ThumbnailUrl As String Implements IDownloadableMedia.ThumbnailUrl
|
<XMLEC> Public Overridable Property ThumbnailUrl As String Implements IDownloadableMedia.ThumbnailUrl
|
||||||
Get
|
Get
|
||||||
If _ThumbnailUrl.IsEmptyString And Thumbnails.Count > 0 Then
|
If Not CoverURL.IsEmptyString Then
|
||||||
|
Return CoverURL
|
||||||
|
ElseIf _ThumbnailUrl.IsEmptyString And Thumbnails.Count > 0 Then
|
||||||
Return Thumbnails.FirstOrDefault.URL
|
Return Thumbnails.FirstOrDefault.URL
|
||||||
Else
|
Else
|
||||||
Return _ThumbnailUrl
|
Return _ThumbnailUrl
|
||||||
@@ -683,10 +687,17 @@ Namespace API.YouTube.Objects
|
|||||||
Friend Sub FileDateUpdate()
|
Friend Sub FileDateUpdate()
|
||||||
Dim n$ = _File.Name.StringTrim
|
Dim n$ = _File.Name.StringTrim
|
||||||
Dim s$ = IIf(n.IsEmptyString, String.Empty, " ")
|
Dim s$ = IIf(n.IsEmptyString, String.Empty, " ")
|
||||||
|
Dim c$ = AccountName.IfNullOrEmpty(UserID)
|
||||||
Select Case MyYouTubeSettings.FileAddDateToFileName.Value
|
Select Case MyYouTubeSettings.FileAddDateToFileName.Value
|
||||||
Case FileDateMode.Before : n = $"[{DateAdded:yyyy-MM-dd}]{s}{n}"
|
Case FileDateMode.Before : n = $"[{DateAdded:yyyy-MM-dd}]{s}{n}"
|
||||||
Case FileDateMode.After : n = $"{n}{s}[{DateAdded:yyyy-MM-dd}]"
|
Case FileDateMode.After : n = $"{n}{s}[{DateAdded:yyyy-MM-dd}]"
|
||||||
End Select
|
End Select
|
||||||
|
If Not c.IsEmptyString Then
|
||||||
|
Select Case MyYouTubeSettings.FileAddChannelToFileName.Value
|
||||||
|
Case FileDateMode.Before : n = $"[{c}] {n}"
|
||||||
|
Case FileDateMode.After : n = $"{n} [{c}]"
|
||||||
|
End Select
|
||||||
|
End If
|
||||||
_File.Name = n
|
_File.Name = n
|
||||||
End Sub
|
End Sub
|
||||||
Public Property FileSettings As SFile
|
Public Property FileSettings As SFile
|
||||||
@@ -727,6 +738,7 @@ Namespace API.YouTube.Objects
|
|||||||
#Region "Command"
|
#Region "Command"
|
||||||
<XMLEC> Public Property UseCookies As Boolean = MyYouTubeSettings.DefaultUseCookies Implements IYouTubeMediaContainer.UseCookies
|
<XMLEC> Public Property UseCookies As Boolean = MyYouTubeSettings.DefaultUseCookies Implements IYouTubeMediaContainer.UseCookies
|
||||||
Protected Const mp3 As String = "mp3"
|
Protected Const mp3 As String = "mp3"
|
||||||
|
Private Const mp4 As String = "mp4"
|
||||||
Private Const aac As String = "aac"
|
Private Const aac As String = "aac"
|
||||||
Private Const ac3 As String = "ac3"
|
Private Const ac3 As String = "ac3"
|
||||||
Protected PostProcessing_AudioAC3 As Boolean = False
|
Protected PostProcessing_AudioAC3 As Boolean = False
|
||||||
@@ -762,7 +774,12 @@ Namespace API.YouTube.Objects
|
|||||||
'2023.3.4 -> 2023.7.6
|
'2023.3.4 -> 2023.7.6
|
||||||
'cmd.StringAppend($"ba*[format_id={SelectedAudio.ID}]", "+")
|
'cmd.StringAppend($"ba*[format_id={SelectedAudio.ID}]", "+")
|
||||||
cmd.StringAppend(SelectedAudio.ID, "+")
|
cmd.StringAppend(SelectedAudio.ID, "+")
|
||||||
If OutputAudioCodec.StringToLower = ac3 Then
|
If SelectedVideoIndex >= 0 And SelectedAudio.ProtocolType = Protocols.m3u8 And
|
||||||
|
(SelectedAudio.Codec.StringToLower = mp4 Or OutputAudioCodec.StringToLower = mp4) Then
|
||||||
|
PostProcessing_AudioAC3 = True
|
||||||
|
formats.StringAppend($"--merge-output-format ""{mp4}{IIf(OutputVideoExtension.IsEmptyString, String.Empty, $"/{OutputVideoExtension.StringToLower}")}""", " ")
|
||||||
|
atCodec = aac
|
||||||
|
ElseIf OutputAudioCodec.StringToLower = ac3 Then
|
||||||
PostProcessing_AudioAC3 = True
|
PostProcessing_AudioAC3 = True
|
||||||
formats.StringAppend($"--audio-format {aac}", " ")
|
formats.StringAppend($"--audio-format {aac}", " ")
|
||||||
atCodec = aac
|
atCodec = aac
|
||||||
@@ -806,7 +823,9 @@ Namespace API.YouTube.Objects
|
|||||||
'cmd = $"yt-dlp -f ""{cmd}"""
|
'cmd = $"yt-dlp -f ""{cmd}"""
|
||||||
'cmd = $"yt-dlp -f {cmd}"
|
'cmd = $"yt-dlp -f {cmd}"
|
||||||
cmd = $"{YTDLP_NAME} -f {cmd}"
|
cmd = $"{YTDLP_NAME} -f {cmd}"
|
||||||
If Not MyYouTubeSettings.ReplaceModificationDate Then cmd &= " --no-mtime"
|
'yt-dlp 2025.07.21
|
||||||
|
'If Not MyYouTubeSettings.ReplaceModificationDate Then cmd &= " --no-mtime"
|
||||||
|
cmd &= $" --{IIf(MyYouTubeSettings.ReplaceModificationDate.Value, String.Empty, "no-")}mtime"
|
||||||
cmd.StringAppend(formats, " ")
|
cmd.StringAppend(formats, " ")
|
||||||
cmd.StringAppend(subs, " ")
|
cmd.StringAppend(subs, " ")
|
||||||
cmd.StringAppend(YouTubeFunctions.GetCookiesCommand(WithCookies, YouTubeCookieNetscapeFile), " ")
|
cmd.StringAppend(YouTubeFunctions.GetCookiesCommand(WithCookies, YouTubeCookieNetscapeFile), " ")
|
||||||
@@ -904,7 +923,8 @@ Namespace API.YouTube.Objects
|
|||||||
Const m3u8DataRow$ = "#EXTINF:{0},{1}" & vbCrLf & "{2}"
|
Const m3u8DataRow$ = "#EXTINF:{0},{1}" & vbCrLf & "{2}"
|
||||||
With Element
|
With Element
|
||||||
Dim f As SFile = __file.IfNullOrEmpty(.File)
|
Dim f As SFile = __file.IfNullOrEmpty(.File)
|
||||||
Dim __f$ = SymbolsConverter.ASCII.EncodeSymbolsOnly(If(Mode = M3U8CreationMode.Absolute, f.ToString, f.File))
|
Dim fStr$ = f.ToString.StringReplaceSymbols({"\"}, "/", EDP.ReturnValue)
|
||||||
|
Dim __f$ = SymbolsConverter.ASCII.Extended.EncodeSymbolsOnly(If(Mode = M3U8CreationMode.Absolute, fStr, f.File), M3U8ExcludedSymbols)
|
||||||
If Mode = M3U8CreationMode.Absolute Then __f = $"file:///{__f}"
|
If Mode = M3U8CreationMode.Absolute Then __f = $"file:///{__f}"
|
||||||
Dim fName$ = .Title.IfNullOrEmpty(f.Name)
|
Dim fName$ = .Title.IfNullOrEmpty(f.Name)
|
||||||
If MyYouTubeSettings.MusicPlaylistCreate_M3U8_AppendNumber And .PlaylistIndex > 0 Then fName = $"{ .PlaylistIndex}. {fName}"
|
If MyYouTubeSettings.MusicPlaylistCreate_M3U8_AppendNumber And .PlaylistIndex > 0 Then fName = $"{ .PlaylistIndex}. {fName}"
|
||||||
@@ -1022,12 +1042,19 @@ Namespace API.YouTube.Objects
|
|||||||
End If
|
End If
|
||||||
|
|
||||||
Dim cDown As Boolean = False
|
Dim cDown As Boolean = False
|
||||||
|
Dim fCover As SFile = Nothing
|
||||||
|
Dim cUrl$ = String.Empty
|
||||||
For Each elem In Elements
|
For Each elem In Elements
|
||||||
With DirectCast(elem, YouTubeMediaContainerBase)
|
With DirectCast(elem, YouTubeMediaContainerBase)
|
||||||
If Not .CoverDownloaded Then .CoverDownloaded = cDown
|
'If Not .CoverDownloaded Then .CoverDownloaded = cDown
|
||||||
|
.CoverDownloaded = cDown
|
||||||
|
.CoverFile = fCover
|
||||||
|
.CoverURL = cUrl
|
||||||
AddHandler .FileDownloadStarted, fDown
|
AddHandler .FileDownloadStarted, fDown
|
||||||
.Download(UseCookies, Token)
|
.Download(UseCookies, Token)
|
||||||
cDown = .CoverDownloaded
|
cDown = .CoverDownloaded
|
||||||
|
fCover = .CoverFile
|
||||||
|
cUrl = .CoverURL
|
||||||
RemoveHandler .FileDownloadStarted, fDown
|
RemoveHandler .FileDownloadStarted, fDown
|
||||||
End With
|
End With
|
||||||
If Token.IsCancellationRequested Or disposedValue Then Exit For
|
If Token.IsCancellationRequested Or disposedValue Then Exit For
|
||||||
@@ -1054,6 +1081,8 @@ Namespace API.YouTube.Objects
|
|||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
Protected CoverDownloaded As Boolean = False
|
Protected CoverDownloaded As Boolean = False
|
||||||
|
Protected CoverFile As SFile = Nothing
|
||||||
|
Protected CoverURL As String = String.Empty
|
||||||
Private Sub DownloadPlaylistCover(ByVal PlsId As String, ByVal f As SFile, ByVal UseCookies As Boolean)
|
Private Sub DownloadPlaylistCover(ByVal PlsId As String, ByVal f As SFile, ByVal UseCookies As Boolean)
|
||||||
Try
|
Try
|
||||||
Dim url$ = $"https://{IIf(IsMusic, "music", "www")}.youtube.com/playlist?list={PlsId}"
|
Dim url$ = $"https://{IIf(IsMusic, "music", "www")}.youtube.com/playlist?list={PlsId}"
|
||||||
@@ -1089,7 +1118,8 @@ Namespace API.YouTube.Objects
|
|||||||
url = LinkFormatterSecure(u)
|
url = LinkFormatterSecure(u)
|
||||||
f.Name = "cover"
|
f.Name = "cover"
|
||||||
f.Extension = "jpg"
|
f.Extension = "jpg"
|
||||||
If resp.DownloadFile(url, f, EDP.ReturnValue) And f.Exists Then CoverDownloaded = True : AddFile(f)
|
If resp.DownloadFile(url, f, EDP.ReturnValue) And f.Exists Then _
|
||||||
|
CoverFile = f : CoverURL = url : CoverDownloaded = True : AddFile(f)
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
End Using
|
End Using
|
||||||
@@ -1195,12 +1225,15 @@ Namespace API.YouTube.Objects
|
|||||||
End If
|
End If
|
||||||
|
|
||||||
With MyYouTubeSettings
|
With MyYouTubeSettings
|
||||||
If .CreateDescriptionFiles And (Not Description.IsEmptyString Or
|
If .CreateDescriptionFiles And (Not Description.IsEmptyString Or .CreateDescriptionFiles_CreateWithNoDescription) Then
|
||||||
(.CreateDescriptionFiles_CreateWithNoDescription And .CreateDescriptionFiles_AddUploadDate)) Then
|
|
||||||
Dim fileDesr As SFile = File
|
Dim fileDesr As SFile = File
|
||||||
fileDesr.Extension = "txt"
|
fileDesr.Extension = "txt"
|
||||||
Using fileDesrText As New TextSaver(fileDesr)
|
Using fileDesrText As New TextSaver(fileDesr)
|
||||||
If .CreateDescriptionFiles_AddUploadDate Then fileDesrText.Append($"Uploaded: {DateAdded:yyyy-MM-dd HH:mm:ss}")
|
fileDesrText.Append($"Uploaded: {DateAdded:yyyy-MM-dd HH:mm:ss}")
|
||||||
|
fileDesrText.AppendLine()
|
||||||
|
fileDesrText.AppendLine($"URL: {URL}")
|
||||||
|
fileDesrText.AppendLine($"Channel name: {AccountName}")
|
||||||
|
fileDesrText.AppendLine($"Channel ID: {UserID}")
|
||||||
If Not Description.IsEmptyString Then
|
If Not Description.IsEmptyString Then
|
||||||
If Not fileDesrText.IsEmptyString Then fileDesrText.AppendLine.AppendLine()
|
If Not fileDesrText.IsEmptyString Then fileDesrText.AppendLine.AppendLine()
|
||||||
fileDesrText.Append(Description)
|
fileDesrText.Append(Description)
|
||||||
@@ -1270,10 +1303,10 @@ Namespace API.YouTube.Objects
|
|||||||
End Sub
|
End Sub
|
||||||
Dim embedThumbTo As Action(Of SFile) =
|
Dim embedThumbTo As Action(Of SFile) =
|
||||||
Sub(ByVal dFile As SFile)
|
Sub(ByVal dFile As SFile)
|
||||||
If dFile.Exists And ThumbnailFile.Exists Then
|
If dFile.Exists And CoverFile.IfNullOrEmpty(ThumbnailFile).Exists Then
|
||||||
Dim dFileNew As SFile = dFile
|
Dim dFileNew As SFile = dFile
|
||||||
dFileNew.Name &= "_NEW"
|
dFileNew.Name &= "_NEW"
|
||||||
.Execute($"ffmpeg -i ""{dFile}"" -i ""{ThumbnailFile}"" -map 0:0 -map 1:0 -c copy -id3v2_version 3 -metadata:s:v title=""Cover"" -metadata:s:v comment=""Cover"" ""{dFileNew}""")
|
.Execute($"ffmpeg -i ""{dFile}"" -i ""{CoverFile.IfNullOrEmpty(ThumbnailFile)}"" -map 0:0 -map 1:0 -c copy -id3v2_version 3 -metadata:s:v title=""Cover"" -metadata:s:v comment=""Cover"" ""{dFileNew}""")
|
||||||
If dFileNew.Exists AndAlso dFile.Delete(,, EDP.ReturnValue) Then SFile.Rename(dFileNew, dFile)
|
If dFileNew.Exists AndAlso dFile.Delete(,, EDP.ReturnValue) Then SFile.Rename(dFileNew, dFile)
|
||||||
End If
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
@@ -1353,6 +1386,10 @@ Namespace API.YouTube.Objects
|
|||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
|
|
||||||
|
'mp3
|
||||||
|
If IsMusic And ObjectType = YouTubeMediaType.Single And File.Extension = mp3 And
|
||||||
|
Not mp3ThumbEmbedded And CoverFile.Exists And MyYouTubeSettings.DefaultAudioEmbedThumbnail_Cover Then embedThumbTo.Invoke(File)
|
||||||
|
|
||||||
'Update video
|
'Update video
|
||||||
ThrowAny(Token)
|
ThrowAny(Token)
|
||||||
If SelectedVideoIndex >= 0 AndAlso tempFilesList.Count > 0 AndAlso tempFilesList.Exists(Function(tf) tf.ToReplace) Then
|
If SelectedVideoIndex >= 0 AndAlso tempFilesList.Count > 0 AndAlso tempFilesList.Exists(Function(tf) tf.ToReplace) Then
|
||||||
@@ -1724,8 +1761,12 @@ Namespace API.YouTube.Objects
|
|||||||
If If(e({"formats"})?.Count, 0) > 0 Then
|
If If(e({"formats"})?.Count, 0) > 0 Then
|
||||||
Dim obj As MediaObject
|
Dim obj As MediaObject
|
||||||
Dim nValue#
|
Dim nValue#
|
||||||
Dim sValue$
|
Dim sValue$ = String.Empty
|
||||||
Dim validCodecValue As Func(Of String, Boolean) = Function(codec) Not codec.IsEmptyString AndAlso Not codec = "none"
|
Dim allowWebm As Boolean = MyYouTubeSettings.DefaultVideoAllowWebm
|
||||||
|
Dim validCodecValue As Func(Of String, Boolean) = Function(ByVal codec As String) As Boolean
|
||||||
|
sValue = codec
|
||||||
|
Return Not codec.IsEmptyString AndAlso Not codec = "none"
|
||||||
|
End Function
|
||||||
|
|
||||||
For Each ee In e({"formats"})
|
For Each ee In e({"formats"})
|
||||||
obj = New MediaObject With {
|
obj = New MediaObject With {
|
||||||
@@ -1749,19 +1790,30 @@ Namespace API.YouTube.Objects
|
|||||||
If obj.Size <= 0 And obj.Bitrate > 0 And Duration.TotalSeconds > 0 Then _
|
If obj.Size <= 0 And obj.Bitrate > 0 And Duration.TotalSeconds > 0 Then _
|
||||||
obj.Size = (obj.Bitrate / 8 * Duration.TotalSeconds).RoundVal(2)
|
obj.Size = (obj.Bitrate / 8 * Duration.TotalSeconds).RoundVal(2)
|
||||||
|
|
||||||
sValue = ee.Value("vcodec")
|
'sValue = ee.Value("vcodec")
|
||||||
If validCodecValue(sValue) Then
|
If validCodecValue(ee.Value("vcodec")) Then
|
||||||
obj.Type = UMTypes.Video
|
obj.Type = UMTypes.Video
|
||||||
obj.Codec = sValue.Split(".").First
|
obj.Codec = sValue.Split(".").First
|
||||||
If validCodecValue(ee.Value("acodec")) Then obj.Type = av
|
If validCodecValue(ee.Value("acodec")) Then obj.Type = av
|
||||||
Else
|
ElseIf validCodecValue(ee.Value("acodec")) Then
|
||||||
sValue = ee.Value("acodec")
|
|
||||||
If validCodecValue(sValue) Then
|
|
||||||
obj.Type = UMTypes.Audio
|
obj.Type = UMTypes.Audio
|
||||||
obj.Codec = sValue.Split(".").First
|
obj.Codec = sValue.Split(".").First
|
||||||
Else
|
Else
|
||||||
Continue For
|
Dim fd As Boolean = False
|
||||||
|
sValue = ee.Value("format_note")
|
||||||
|
If Not sValue.IsEmptyString Then
|
||||||
|
With ListAddList(Nothing, sValue.Split(","), CType(Function(v) CStr(v).StringToLower.StringTrim, Func(Of Object, Object)), EDP.ReturnValue)
|
||||||
|
If .ListContains({"high", "low"}) Then
|
||||||
|
obj.Type = UMTypes.Audio
|
||||||
|
obj.Codec = ee.Value("ext")
|
||||||
|
If obj.Protocol.StringToLower.StartsWith("m3u8") Then obj.Protocol = "m3u8"
|
||||||
|
If obj.Bitrate <= 0 Then obj.Bitrate = IIf(.Contains("high"), 129, 53)
|
||||||
|
If obj.Size <= 0 Then obj.Size = 1
|
||||||
|
fd = True
|
||||||
End If
|
End If
|
||||||
|
End With
|
||||||
|
End If
|
||||||
|
If Not fd Then Continue For
|
||||||
End If
|
End If
|
||||||
MediaObjects.Add(obj)
|
MediaObjects.Add(obj)
|
||||||
Next
|
Next
|
||||||
@@ -1773,14 +1825,18 @@ Namespace API.YouTube.Objects
|
|||||||
Dim data As New List(Of MediaObject)(MediaObjects.Where(Function(mo) mo.Type = t And mo.Extension = webm))
|
Dim data As New List(Of MediaObject)(MediaObjects.Where(Function(mo) mo.Type = t And mo.Extension = webm))
|
||||||
If data.Count > 0 Then
|
If data.Count > 0 Then
|
||||||
Dim d As MediaObject = Nothing
|
Dim d As MediaObject = Nothing
|
||||||
Dim expWebm As Predicate(Of MediaObject) = Function(mo) mo.Extension = webm
|
Dim allWebm As Boolean = False, allAVC As Boolean = False
|
||||||
Dim expAVC As Predicate(Of MediaObject) = Function(mo) mo.Codec.IfNullOrEmpty("/").ToLower.StartsWith(avc)
|
Dim expWebm As Predicate(Of MediaObject) = Function(mo) Not allWebm And mo.Extension = webm
|
||||||
Dim comp As Func(Of MediaObject, Predicate(Of MediaObject), Boolean, Boolean) =
|
Dim expAVC As Predicate(Of MediaObject) = Function(mo) Not allAVC And mo.Codec.IfNullOrEmpty("/").ToLower.StartsWith(avc)
|
||||||
Function(mo, exp, isTrue) mo.Type = t And exp.Invoke(mo) = isTrue And mo.Width = d.Width
|
Dim comp As Func(Of MediaObject, Predicate(Of MediaObject), Boolean, Boolean, Boolean) =
|
||||||
Dim CountWebm As Func(Of MediaObject, Boolean) = Function(mo) comp.Invoke(mo, expWebm, False)
|
Function(mo, exp, isTrue, checkHttp) mo.Type = t And exp.Invoke(mo) = isTrue And mo.Width = d.Width And
|
||||||
Dim RemoveWebm As Predicate(Of MediaObject) = Function(mo) comp.Invoke(mo, expWebm, True)
|
(Not checkHttp OrElse mo.ProtocolType = Protocols.https)
|
||||||
Dim CountAVC As Func(Of MediaObject, Boolean) = Function(mo) comp.Invoke(mo, expAVC, True)
|
Dim CountWebm As Func(Of MediaObject, Boolean) = Function(mo) comp.Invoke(mo, expWebm, False, allowWebm)
|
||||||
Dim RemoveAVC As Predicate(Of MediaObject) = Function(mo) comp.Invoke(mo, expAVC, False)
|
Dim RemoveWebm As Predicate(Of MediaObject) = Function(mo) comp.Invoke(mo, expWebm, True, allowWebm)
|
||||||
|
Dim CountAVC As Func(Of MediaObject, Boolean) = Function(mo) comp.Invoke(mo, expAVC, True, False)
|
||||||
|
Dim RemoveAVC As Predicate(Of MediaObject) = Function(mo) comp.Invoke(mo, expAVC, False, False)
|
||||||
|
allWebm = data.All(FPredicate(Of MediaObject).ToFunc(expWebm))
|
||||||
|
allAVC = data.All(FPredicate(Of MediaObject).ToFunc(expAVC))
|
||||||
For Each d In data
|
For Each d In data
|
||||||
If MediaObjects.Count = 0 Then Exit For
|
If MediaObjects.Count = 0 Then Exit For
|
||||||
If MediaObjects.LongCount(CountWebm) > 0 Then MediaObjects.RemoveAll(RemoveWebm)
|
If MediaObjects.LongCount(CountWebm) > 0 Then MediaObjects.RemoveAll(RemoveWebm)
|
||||||
|
|||||||
@@ -124,12 +124,19 @@
|
|||||||
<Compile Include="Controls\ChannelTabsChooserForm.vb">
|
<Compile Include="Controls\ChannelTabsChooserForm.vb">
|
||||||
<SubType>Form</SubType>
|
<SubType>Form</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Controls\FilterForm.Designer.vb">
|
||||||
|
<DependentUpon>FilterForm.vb</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Controls\FilterForm.vb">
|
||||||
|
<SubType>Form</SubType>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Controls\PlayListParserForm.Designer.vb">
|
<Compile Include="Controls\PlayListParserForm.Designer.vb">
|
||||||
<DependentUpon>PlayListParserForm.vb</DependentUpon>
|
<DependentUpon>PlayListParserForm.vb</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Controls\PlayListParserForm.vb">
|
<Compile Include="Controls\PlayListParserForm.vb">
|
||||||
<SubType>Form</SubType>
|
<SubType>Form</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Controls\YTDataFilter.vb" />
|
||||||
<Compile Include="Downloader\DownloadLocationsCollection.vb" />
|
<Compile Include="Downloader\DownloadLocationsCollection.vb" />
|
||||||
<Compile Include="Downloader\IDownloaderSettings.vb" />
|
<Compile Include="Downloader\IDownloaderSettings.vb" />
|
||||||
<Compile Include="Downloader\Notificator.vb" />
|
<Compile Include="Downloader\Notificator.vb" />
|
||||||
@@ -220,6 +227,9 @@
|
|||||||
<EmbeddedResource Include="Controls\ChannelTabsChooserForm.resx">
|
<EmbeddedResource Include="Controls\ChannelTabsChooserForm.resx">
|
||||||
<DependentUpon>ChannelTabsChooserForm.vb</DependentUpon>
|
<DependentUpon>ChannelTabsChooserForm.vb</DependentUpon>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Include="Controls\FilterForm.resx">
|
||||||
|
<DependentUpon>FilterForm.vb</DependentUpon>
|
||||||
|
</EmbeddedResource>
|
||||||
<EmbeddedResource Include="Controls\PlayListParserForm.resx">
|
<EmbeddedResource Include="Controls\PlayListParserForm.resx">
|
||||||
<DependentUpon>PlayListParserForm.vb</DependentUpon>
|
<DependentUpon>PlayListParserForm.vb</DependentUpon>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ Imports System.Runtime.InteropServices
|
|||||||
<Assembly: AssemblyDescription("SCrawler YouTube downloader")>
|
<Assembly: AssemblyDescription("SCrawler YouTube downloader")>
|
||||||
<Assembly: AssemblyCompany("AndyProgram")>
|
<Assembly: AssemblyCompany("AndyProgram")>
|
||||||
<Assembly: AssemblyProduct("SCrawler.YouTubeDownloader")>
|
<Assembly: AssemblyProduct("SCrawler.YouTubeDownloader")>
|
||||||
<Assembly: AssemblyCopyright("Copyright © 2024")>
|
<Assembly: AssemblyCopyright("Copyright © 2025")>
|
||||||
<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("2024.8.10.0")>
|
<Assembly: AssemblyVersion("2025.8.1.0")>
|
||||||
<Assembly: AssemblyFileVersion("2024.8.10.0")>
|
<Assembly: AssemblyFileVersion("2025.8.1.0")>
|
||||||
<Assembly: NeutralResourcesLanguage("en")>
|
<Assembly: NeutralResourcesLanguage("en")>
|
||||||
|
|||||||
@@ -28,6 +28,15 @@ Namespace API.Base
|
|||||||
Friend Const GifsDownloadCaption As String = "Download GIFs"
|
Friend Const GifsDownloadCaption As String = "Download GIFs"
|
||||||
Friend Const UseMD5ComparisonCaption As String = "Use MD5 comparison"
|
Friend Const UseMD5ComparisonCaption As String = "Use MD5 comparison"
|
||||||
Friend Const UseMD5ComparisonToolTip As String = "Each image will be checked for existence using MD5"
|
Friend Const UseMD5ComparisonToolTip As String = "Each image will be checked for existence using MD5"
|
||||||
|
Friend Const UserNameChangeCaption As String = "UserName"
|
||||||
|
Friend Const UserNameChangeToolTip As String = "If the user has changed their UserName, you can set a new name here. Not required for new users."
|
||||||
|
|
||||||
|
Friend Const DownloadTextCaption As String = "Download text"
|
||||||
|
Friend Const DownloadTextTip As String = "Download text (if available) for posts with image and video" & vbCr & "If this checkbox is checked, the post text will be downloaded along with the file and saved under the same name but with the 'txt' extension."
|
||||||
|
Friend Const DownloadTextPostsCaption As String = "Download text posts"
|
||||||
|
Friend Const DownloadTextPostsTip As String = "Download text (if available) for text posts (no image and video)"
|
||||||
|
Friend Const DownloadTextSpecialFolderCaption As String = "Text special folder"
|
||||||
|
Friend Const DownloadTextSpecialFolderTip As String = "If checked, text files will be saved to a separate folder"
|
||||||
Private Sub New()
|
Private Sub New()
|
||||||
End Sub
|
End Sub
|
||||||
End Class
|
End Class
|
||||||
|
|||||||
@@ -6,8 +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 System.Net
|
Imports SCrawler.Plugin
|
||||||
Imports PersonalUtilities.Functions.RegularExpressions
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
|
Imports Download = SCrawler.Plugin.ISiteSettings.Download
|
||||||
Namespace API.Base
|
Namespace API.Base
|
||||||
Friend NotInheritable Class DownDetector
|
Friend NotInheritable Class DownDetector
|
||||||
Private Shared ReadOnly Property Params As New RParams("x:.'([\S]+?)',.y:.(\d+)", -1, Nothing, RegexReturn.List)
|
Private Shared ReadOnly Property Params As New RParams("x:.'([\S]+?)',.y:.(\d+)", -1, Nothing, RegexReturn.List)
|
||||||
@@ -34,8 +35,7 @@ Namespace API.Base
|
|||||||
Try
|
Try
|
||||||
Dim l As List(Of Data) = Nothing
|
Dim l As List(Of Data) = Nothing
|
||||||
Dim l2 As List(Of Data) = Nothing
|
Dim l2 As List(Of Data) = Nothing
|
||||||
Using w As New WebClient
|
Dim r$ = GetWebString($"https://downdetector.co.uk/status/{Site}/",, EDP.ThrowException)
|
||||||
Dim r$ = w.DownloadString($"https://downdetector.co.uk/status/{Site}/")
|
|
||||||
If Not r.IsEmptyString Then
|
If Not r.IsEmptyString Then
|
||||||
l = RegexFields(Of Data)(r, {Params}, {1, 2})
|
l = RegexFields(Of Data)(r, {Params}, {1, 2})
|
||||||
If l.ListExists(2) Then
|
If l.ListExists(2) Then
|
||||||
@@ -43,7 +43,7 @@ Namespace API.Base
|
|||||||
l2 = New List(Of Data)
|
l2 = New List(Of Data)
|
||||||
Dim d As Data
|
Dim d As Data
|
||||||
Dim eDates As New List(Of Date)
|
Dim eDates As New List(Of Date)
|
||||||
Dim MaxValue As Func(Of Date, Integer) = Function(dd) (From ddd In l Where ddd.Date = dd Select ddd.Value).DefaultIfEmpty(0).Max
|
Dim MaxValue As Func(Of Date, Integer) = Function(dd) (From ddd As Data In l Where ddd.Date = dd Select ddd.Value).DefaultIfEmpty(0).Max
|
||||||
For i% = 0 To l.Count - 1
|
For i% = 0 To l.Count - 1
|
||||||
If Not eDates.Contains(l(i).Date) Then
|
If Not eDates.Contains(l(i).Date) Then
|
||||||
d = l(i)
|
d = l(i)
|
||||||
@@ -57,11 +57,84 @@ Namespace API.Base
|
|||||||
l2.Sort()
|
l2.Sort()
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
End Using
|
|
||||||
Return l2
|
Return l2
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
Return ErrorsDescriber.Execute(EDP.SendToLog + EDP.ReturnValue, ex, $"[DownDetector.GetData({Site})]")
|
Return ErrorsDescriber.Execute(EDP.SendToLog + EDP.ReturnValue, ex, $"[DownDetector.GetData({Site})]")
|
||||||
End Try
|
End Try
|
||||||
End Function
|
End Function
|
||||||
|
Friend Interface IDownDetector
|
||||||
|
ReadOnly Property Value As Integer
|
||||||
|
ReadOnly Property AddToLog As Boolean
|
||||||
|
ReadOnly Property CheckSite As String
|
||||||
|
Function Available(ByVal What As Download, ByVal Silent As Boolean) As Boolean
|
||||||
|
End Interface
|
||||||
|
Friend Class Checker(Of T As {ISiteSettings, IDownDetector})
|
||||||
|
Protected ReadOnly Property Source As T
|
||||||
|
Private ReadOnly NP As New ANumbers With {.FormatOptions = ANumbers.Options.GroupIntegral}
|
||||||
|
Friend Sub New(ByRef _Source As T)
|
||||||
|
Source = _Source
|
||||||
|
End Sub
|
||||||
|
Private ____AvailableChecked As Boolean = False
|
||||||
|
Private ____AvailableResult As Boolean = False
|
||||||
|
Friend Overridable Function Available(ByVal What As Download, ByVal Silent As Boolean) As Boolean
|
||||||
|
If Settings.DownDetectorEnabled And Source.Value >= 0 Then
|
||||||
|
If Not ____AvailableChecked Then
|
||||||
|
____AvailableResult = AvailableImpl(What, Silent)
|
||||||
|
____AvailableChecked = True
|
||||||
|
End If
|
||||||
|
Return ____AvailableResult
|
||||||
|
Else
|
||||||
|
Return True
|
||||||
|
End If
|
||||||
|
End Function
|
||||||
|
Protected Overridable Function AvailableImpl(ByVal What As Download, ByVal Silent As Boolean) As Boolean
|
||||||
|
Try
|
||||||
|
Source.AvailableText = String.Empty
|
||||||
|
If Source.Value < 0 Then
|
||||||
|
Return True
|
||||||
|
Else
|
||||||
|
Dim dl As List(Of Data) = GetData(Source.CheckSite)
|
||||||
|
If dl.ListExists Then
|
||||||
|
dl = dl.Take(4).ToList
|
||||||
|
Dim avg% = dl.Average(Function(d) d.Value)
|
||||||
|
If avg > Source.Value Then
|
||||||
|
Source.AvailableText = $"Over the past hour, {Source.Site} has received an average of {avg.NumToString(NP)} outage reports:{vbCr}{dl.ListToString(vbCr)}"
|
||||||
|
If Source.AddToLog Then MyMainLOG = Source.AvailableText
|
||||||
|
If Silent Then
|
||||||
|
Return AvailableImpl_FALSE_SILENT()
|
||||||
|
Else
|
||||||
|
If MsgBoxE({$"{Source.AvailableText}{vbCr}{vbCr}Do you want to continue parsing {Source.Site} data?",
|
||||||
|
$"There are outage reports on {Source.Site}"}, vbYesNo) = vbYes Then
|
||||||
|
Return AvailableImpl_FALSE_SILENT_NOT_MSG_YES()
|
||||||
|
Else
|
||||||
|
Return AvailableImpl_FALSE_SILENT_NOT_MSG_NO()
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Return AvailableImpl_TRUE()
|
||||||
|
End If
|
||||||
|
Catch ex As Exception
|
||||||
|
Return ErrorsDescriber.Execute(EDP.SendToLog + EDP.ReturnValue, ex, $"[API.{Source.Site}.SiteSettings.Available([DownDetector])]", True)
|
||||||
|
End Try
|
||||||
|
End Function
|
||||||
|
Protected Overridable Function AvailableImpl_TRUE() As Boolean
|
||||||
|
Return True
|
||||||
|
End Function
|
||||||
|
Protected Overridable Function AvailableImpl_FALSE_SILENT() As Boolean
|
||||||
|
Return False
|
||||||
|
End Function
|
||||||
|
Protected Overridable Function AvailableImpl_FALSE_SILENT_NOT_MSG_YES() As Boolean
|
||||||
|
Return True
|
||||||
|
End Function
|
||||||
|
Protected Overridable Function AvailableImpl_FALSE_SILENT_NOT_MSG_NO() As Boolean
|
||||||
|
Return False
|
||||||
|
End Function
|
||||||
|
Friend Overridable Sub Reset()
|
||||||
|
____AvailableChecked = False
|
||||||
|
____AvailableResult = False
|
||||||
|
Source.AvailableText = String.Empty
|
||||||
|
End Sub
|
||||||
|
End Class
|
||||||
End Class
|
End Class
|
||||||
End Namespace
|
End Namespace
|
||||||
46
SCrawler/API/Base/EditorExchangeOptionsBase.vb
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
' Copyright (C) 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.Attributes
|
||||||
|
Imports DN = SCrawler.API.Base.DeclaredNames
|
||||||
|
Namespace API.Base
|
||||||
|
Friend Class EditorExchangeOptionsBase
|
||||||
|
Friend Overridable Property SiteKey As String
|
||||||
|
<PSetting(Address:=SettingAddress.User, Caption:=DN.UserNameChangeCaption, ToolTip:=DN.UserNameChangeToolTip)>
|
||||||
|
Friend Overridable Property UserName As String = String.Empty
|
||||||
|
<PSetting(Address:=SettingAddress.User, Caption:=DN.DownloadTextCaption, ToolTip:=DN.DownloadTextTip)>
|
||||||
|
Friend Overridable Property DownloadText As Boolean = False
|
||||||
|
<PSetting(Address:=SettingAddress.User, Caption:=DN.DownloadTextPostsCaption, ToolTip:=DN.DownloadTextPostsTip)>
|
||||||
|
Friend Overridable Property DownloadTextPosts As Boolean = False
|
||||||
|
<PSetting(Address:=SettingAddress.User, Caption:=DN.DownloadTextSpecialFolderCaption, ToolTip:=DN.DownloadTextSpecialFolderTip)>
|
||||||
|
Friend Overridable Property DownloadTextSpecialFolder As Boolean = False
|
||||||
|
Friend Sub New(ByVal u As UserDataBase)
|
||||||
|
UserName = u.NameTrue(True)
|
||||||
|
DownloadText = u.DownloadText
|
||||||
|
DownloadTextPosts = u.DownloadTextPosts
|
||||||
|
DownloadTextSpecialFolder = u.DownloadTextSpecialFolder
|
||||||
|
End Sub
|
||||||
|
Friend Sub New(ByVal s As SiteSettingsBase)
|
||||||
|
DownloadText = s.DownloadText.Value
|
||||||
|
DownloadTextPosts = s.DownloadTextPosts.Value
|
||||||
|
DownloadTextSpecialFolder = s.DownloadTextSpecialFolder.Value
|
||||||
|
End Sub
|
||||||
|
Friend Sub New()
|
||||||
|
End Sub
|
||||||
|
Protected _ApplyBase_Name As Boolean = True
|
||||||
|
Protected _ApplyBase_Text As Boolean = True
|
||||||
|
Friend Sub ApplyBase(ByRef u As UserDataBase)
|
||||||
|
If _ApplyBase_Name Then u.NameTrue = UserName
|
||||||
|
If _ApplyBase_Text Then
|
||||||
|
u.DownloadText = DownloadText
|
||||||
|
u.DownloadTextPosts = DownloadTextPosts
|
||||||
|
u.DownloadTextSpecialFolder = DownloadTextSpecialFolder
|
||||||
|
End If
|
||||||
|
End Sub
|
||||||
|
End Class
|
||||||
|
End Namespace
|
||||||
43
SCrawler/API/Base/EditorExchangeOptionsBase_P.vb
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
' Copyright (C) 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.Attributes
|
||||||
|
Namespace API.Base
|
||||||
|
Friend Interface IPSite
|
||||||
|
Property QueryString As String
|
||||||
|
End Interface
|
||||||
|
Friend Class EditorExchangeOptionsBase_P : Inherits EditorExchangeOptionsBase : Implements IPSite
|
||||||
|
<PSetting(Address:=SettingAddress.None)> Friend Overrides Property UserName As String
|
||||||
|
<PSetting(Address:=SettingAddress.None)> Friend Overrides Property DownloadText As Boolean
|
||||||
|
<PSetting(Address:=SettingAddress.None)> Friend Overrides Property DownloadTextPosts As Boolean
|
||||||
|
<PSetting(Address:=SettingAddress.None)> Friend Overrides Property DownloadTextSpecialFolder As Boolean
|
||||||
|
<PSetting(Address:=SettingAddress.User, Caption:="Query",
|
||||||
|
ToolTip:="Query string. Don't change this field when creating a user! Change it only for the same request.")>
|
||||||
|
Friend Property QueryString As String Implements IPSite.QueryString
|
||||||
|
Friend Sub New()
|
||||||
|
DisableBase()
|
||||||
|
End Sub
|
||||||
|
Friend Sub New(ByVal u As UserDataBase)
|
||||||
|
MyBase.New(u)
|
||||||
|
DisableBase()
|
||||||
|
If TypeOf u Is IPSite Then QueryString = DirectCast(u, IPSite).QueryString
|
||||||
|
End Sub
|
||||||
|
Friend Sub New(ByVal s As SiteSettingsBase)
|
||||||
|
MyBase.New(s)
|
||||||
|
DisableBase()
|
||||||
|
End Sub
|
||||||
|
Friend Overridable Sub Apply(ByRef u As IPSite)
|
||||||
|
ApplyBase(u)
|
||||||
|
u.QueryString = QueryString
|
||||||
|
End Sub
|
||||||
|
Protected Overridable Sub DisableBase()
|
||||||
|
_ApplyBase_Name = False
|
||||||
|
_ApplyBase_Text = False
|
||||||
|
End Sub
|
||||||
|
End Class
|
||||||
|
End Namespace
|
||||||
@@ -6,66 +6,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
|
||||||
Imports PersonalUtilities.Tools
|
|
||||||
Imports PersonalUtilities.Functions.RegularExpressions
|
|
||||||
Namespace API.Base.GDL
|
Namespace API.Base.GDL
|
||||||
Friend Module Declarations
|
|
||||||
Private Structure GDLURL : Implements IRegExCreator
|
|
||||||
Private _URL As String
|
|
||||||
Friend ReadOnly Property URL As String
|
|
||||||
Get
|
|
||||||
Return _URL
|
|
||||||
End Get
|
|
||||||
End Property
|
|
||||||
Public Shared Widening Operator CType(ByVal u As String) As GDLURL
|
|
||||||
Return New GDLURL With {._URL = u}
|
|
||||||
End Operator
|
|
||||||
Public Shared Widening Operator CType(ByVal u As GDLURL) As String
|
|
||||||
Return u.URL
|
|
||||||
End Operator
|
|
||||||
Private Function CreateFromArray(ByVal ParamsArray() As String) As Object Implements IRegExCreator.CreateFromArray
|
|
||||||
If ParamsArray.ListExists(2) Then
|
|
||||||
Dim u$ = ParamsArray(0).StringTrim.StringTrimEnd("/"), u2$
|
|
||||||
If Not u.IsEmptyString Then
|
|
||||||
u2 = ParamsArray(1).StringTrim
|
|
||||||
If Not u2.IsEmptyString AndAlso u2.StartsWith("GET", StringComparison.OrdinalIgnoreCase) Then
|
|
||||||
u2 = u2.Remove(0, 3).StringTrim.StringTrimStart("/")
|
|
||||||
If Not u2.IsEmptyString Then _URL = $"{u}/{u2}"
|
|
||||||
End If
|
|
||||||
End If
|
|
||||||
End If
|
|
||||||
Return Me
|
|
||||||
End Function
|
|
||||||
Public Shared Operator =(ByVal x As GDLURL, ByVal y As GDLURL) As Boolean
|
|
||||||
Return x.URL = y.URL
|
|
||||||
End Operator
|
|
||||||
Public Shared Operator <>(ByVal x As GDLURL, ByVal y As GDLURL) As Boolean
|
|
||||||
Return Not x.URL = y.URL
|
|
||||||
End Operator
|
|
||||||
Public Overrides Function ToString() As String
|
|
||||||
Return URL
|
|
||||||
End Function
|
|
||||||
Public Overrides Function Equals(ByVal Obj As Object) As Boolean
|
|
||||||
Return URL = CType(Obj, String)
|
|
||||||
End Function
|
|
||||||
End Structure
|
|
||||||
Private ReadOnly Property GdlUrlPattern As RParams = RParams.DM(GDLBatch.UrlLibStart.Replace("[", "\[").Replace("]", "\]") &
|
|
||||||
"([^""]+?)""(GET [^""]+)""", 0, EDP.ReturnValue)
|
|
||||||
Friend Function GetUrlsFromGalleryDl(ByVal Batch As BatchExecutor, ByVal Command As String) As List(Of String)
|
|
||||||
Dim urls As New List(Of String)
|
|
||||||
Dim u As GDLURL
|
|
||||||
With Batch
|
|
||||||
.Execute(Command)
|
|
||||||
If .ErrorOutputData.Count > 0 Then
|
|
||||||
For Each eValue$ In .ErrorOutputData
|
|
||||||
u = RegexFields(Of GDLURL)(eValue, {GdlUrlPattern}, {1, 2}, EDP.ReturnValue).ListIfNothing.FirstOrDefault
|
|
||||||
If Not u.URL.IsEmptyString Then urls.ListAddValue(u, LNC)
|
|
||||||
Next
|
|
||||||
End If
|
|
||||||
End With
|
|
||||||
Return urls
|
|
||||||
End Function
|
|
||||||
End Module
|
|
||||||
Friend Class GDLBatch : Inherits TokenBatch
|
Friend Class GDLBatch : Inherits TokenBatch
|
||||||
Friend Const UrlLibStart As String = "[urllib3.connectionpool][debug]"
|
Friend Const UrlLibStart As String = "[urllib3.connectionpool][debug]"
|
||||||
Friend Const UrlTextStart As String = UrlLibStart & " https"
|
Friend Const UrlTextStart As String = UrlLibStart & " https"
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ Namespace API.Base
|
|||||||
End Enum
|
End Enum
|
||||||
ReadOnly Property Site As String
|
ReadOnly Property Site As String
|
||||||
ReadOnly Property Name As String
|
ReadOnly Property Name As String
|
||||||
|
Property NameTrue As String
|
||||||
Property ID As String
|
Property ID As String
|
||||||
Property Options As String
|
Property Options As String
|
||||||
Property FriendlyName As String
|
Property FriendlyName As String
|
||||||
@@ -56,6 +57,7 @@ Namespace API.Base
|
|||||||
Property FileExists As Boolean
|
Property FileExists As Boolean
|
||||||
Property DownloadedPictures(ByVal Total As Boolean) As Integer
|
Property DownloadedPictures(ByVal Total As Boolean) As Integer
|
||||||
Property DownloadedVideos(ByVal Total As Boolean) As Integer
|
Property DownloadedVideos(ByVal Total As Boolean) As Integer
|
||||||
|
Property DownloadedTexts(ByVal Total As Boolean) As Integer
|
||||||
ReadOnly Property DownloadedTotal(Optional ByVal Total As Boolean = True) As Integer
|
ReadOnly Property DownloadedTotal(Optional ByVal Total As Boolean = True) As Integer
|
||||||
ReadOnly Property DownloadedInformation As String
|
ReadOnly Property DownloadedInformation As String
|
||||||
Property HasError As Boolean
|
Property HasError As Boolean
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ Imports PersonalUtilities.Tools.Web.Cookies
|
|||||||
Imports PersonalUtilities.Tools.Web.Clients
|
Imports PersonalUtilities.Tools.Web.Clients
|
||||||
Imports PersonalUtilities.Functions.RegularExpressions
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
Imports Download = SCrawler.Plugin.ISiteSettings.Download
|
Imports Download = SCrawler.Plugin.ISiteSettings.Download
|
||||||
|
Imports DN = SCrawler.API.Base.DeclaredNames
|
||||||
Namespace API.Base
|
Namespace API.Base
|
||||||
Friend MustInherit Class SiteSettingsBase : Implements ISiteSettings, IResponserContainer
|
Friend MustInherit Class SiteSettingsBase : Implements ISiteSettings, IResponserContainer
|
||||||
#Region "Declarations"
|
#Region "Declarations"
|
||||||
@@ -33,7 +34,7 @@ Namespace API.Base
|
|||||||
End Property
|
End Property
|
||||||
Friend Property AccountName As String Implements ISiteSettings.AccountName
|
Friend Property AccountName As String Implements ISiteSettings.AccountName
|
||||||
Friend Property Temporary As Boolean = False Implements ISiteSettings.Temporary
|
Friend Property Temporary As Boolean = False Implements ISiteSettings.Temporary
|
||||||
Friend Property DefaultInstance As ISiteSettings = Nothing Implements ISiteSettings.DefaultInstance
|
Friend Overridable Property DefaultInstance As ISiteSettings = Nothing Implements ISiteSettings.DefaultInstance
|
||||||
Protected _UserAgentDefault As String = String.Empty
|
Protected _UserAgentDefault As String = String.Empty
|
||||||
Friend Overridable Property UserAgentDefault As String Implements ISiteSettings.UserAgentDefault
|
Friend Overridable Property UserAgentDefault As String Implements ISiteSettings.UserAgentDefault
|
||||||
Get
|
Get
|
||||||
@@ -55,6 +56,11 @@ Namespace API.Base
|
|||||||
Friend Overridable ReadOnly Property Responser As Responser
|
Friend Overridable ReadOnly Property Responser As Responser
|
||||||
Private _UserOptionsExists As Boolean = False
|
Private _UserOptionsExists As Boolean = False
|
||||||
Private _UserOptionsType As Type = Nothing
|
Private _UserOptionsType As Type = Nothing
|
||||||
|
Protected Overridable Function UserOptionsValid(ByVal Options As Object) As Boolean
|
||||||
|
Return True
|
||||||
|
End Function
|
||||||
|
Protected Overridable Sub UserOptionsSetParameters(ByRef Options As Object)
|
||||||
|
End Sub
|
||||||
Protected Property UserOptionsType As Type
|
Protected Property UserOptionsType As Type
|
||||||
Get
|
Get
|
||||||
Return _UserOptionsType
|
Return _UserOptionsType
|
||||||
@@ -64,6 +70,14 @@ Namespace API.Base
|
|||||||
_UserOptionsExists = Not t Is Nothing
|
_UserOptionsExists = Not t Is Nothing
|
||||||
End Set
|
End Set
|
||||||
End Property
|
End Property
|
||||||
|
#Region "New user defaults"
|
||||||
|
<PropertyOption(ControlText:=DN.DownloadTextCaption, ControlToolTip:=DN.DownloadTextTip, Category:=DN.CAT_UserDefs), PXML, PClonable>
|
||||||
|
Friend Overridable Property DownloadText As PropertyValue
|
||||||
|
<PropertyOption(ControlText:=DN.DownloadTextPostsCaption, ControlToolTip:=DN.DownloadTextPostsTip, Category:=DN.CAT_UserDefs), PXML, PClonable>
|
||||||
|
Friend Overridable Property DownloadTextPosts As PropertyValue
|
||||||
|
<PropertyOption(ControlText:=DN.DownloadTextSpecialFolderCaption, ControlToolTip:=DN.DownloadTextSpecialFolderTip, Category:=DN.CAT_UserDefs), PXML, PClonable>
|
||||||
|
Friend Overridable Property DownloadTextSpecialFolder As PropertyValue
|
||||||
|
#End Region
|
||||||
#End Region
|
#End Region
|
||||||
#Region "EnvironmentPrograms"
|
#Region "EnvironmentPrograms"
|
||||||
Private Property CMDEncoding As String Implements ISiteSettings.CMDEncoding
|
Private Property CMDEncoding As String Implements ISiteSettings.CMDEncoding
|
||||||
@@ -119,6 +133,9 @@ Namespace API.Base
|
|||||||
_Image = __Image
|
_Image = __Image
|
||||||
Responser = New Responser With {.DeclaredError = EDP.ThrowException}
|
Responser = New Responser With {.DeclaredError = EDP.ThrowException}
|
||||||
SettingsVersion = New PropertyValue(0)
|
SettingsVersion = New PropertyValue(0)
|
||||||
|
DownloadText = New PropertyValue(False)
|
||||||
|
DownloadTextPosts = New PropertyValue(False)
|
||||||
|
DownloadTextSpecialFolder = New PropertyValue(True)
|
||||||
UpdateResponserFile()
|
UpdateResponserFile()
|
||||||
End Sub
|
End Sub
|
||||||
Friend Sub New(ByVal SiteName As String, ByVal CookiesDomain As String, ByVal AccName As String, ByVal Temp As Boolean,
|
Friend Sub New(ByVal SiteName As String, ByVal CookiesDomain As String, ByVal AccName As String, ByVal Temp As Boolean,
|
||||||
@@ -243,7 +260,7 @@ Namespace API.Base
|
|||||||
#Region "User info"
|
#Region "User info"
|
||||||
Protected UrlPatternUser As String = String.Empty
|
Protected UrlPatternUser As String = String.Empty
|
||||||
Friend Overridable Function GetUserUrl(ByVal User As IPluginContentProvider) As String Implements ISiteSettings.GetUserUrl
|
Friend Overridable Function GetUserUrl(ByVal User As IPluginContentProvider) As String Implements ISiteSettings.GetUserUrl
|
||||||
If Not UrlPatternUser.IsEmptyString Then Return String.Format(UrlPatternUser, User.Name)
|
If Not UrlPatternUser.IsEmptyString Then Return String.Format(UrlPatternUser, User.NameTrue.IfNullOrEmpty(User.Name))
|
||||||
Return String.Empty
|
Return String.Empty
|
||||||
End Function
|
End Function
|
||||||
Private Function ISiteSettings_GetUserPostUrl(ByVal User As IPluginContentProvider, ByVal Media As IUserMedia) As String Implements ISiteSettings.GetUserPostUrl
|
Private Function ISiteSettings_GetUserPostUrl(ByVal User As IPluginContentProvider, ByVal Media As IUserMedia) As String Implements ISiteSettings.GetUserPostUrl
|
||||||
@@ -380,11 +397,41 @@ Namespace API.Base
|
|||||||
End Sub
|
End Sub
|
||||||
Friend Overridable Sub UserOptions(ByRef Options As Object, ByVal OpenForm As Boolean) Implements ISiteSettings.UserOptions
|
Friend Overridable Sub UserOptions(ByRef Options As Object, ByVal OpenForm As Boolean) Implements ISiteSettings.UserOptions
|
||||||
If _UserOptionsExists Then
|
If _UserOptionsExists Then
|
||||||
If Options Is Nothing OrElse Not Options.GetType Is _UserOptionsType Then
|
If Options Is Nothing OrElse (Not Options.GetType Is _UserOptionsType OrElse Not UserOptionsValid(Options)) Then
|
||||||
Options = AConvert(Me, AModes.Var, _UserOptionsType,, True, Nothing)
|
Dim args% = 0
|
||||||
If Options Is Nothing Then Options = Activator.CreateInstance(_UserOptionsType)
|
Dim constructor As ConstructorInfo = Nothing
|
||||||
|
With _UserOptionsType.GetTypeInfo.DeclaredConstructors
|
||||||
|
If .ListExists Then
|
||||||
|
With .Where(Function(ByVal c As ConstructorInfo) As Boolean
|
||||||
|
With c.GetParameters
|
||||||
|
If .ListExists Then
|
||||||
|
If .Count = 1 Then
|
||||||
|
Return .Self()(0).ParameterType Is Me.GetType
|
||||||
|
Else
|
||||||
|
Return False
|
||||||
End If
|
End If
|
||||||
If OpenForm Then
|
Else
|
||||||
|
Return True
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
Return If(c.GetParameters?.Count, 0).ValueBetween(0, 1)
|
||||||
|
End Function)
|
||||||
|
If .ListExists Then
|
||||||
|
args = .Max(Of Integer)(Function(c) If(c.GetParameters?.Count, 0))
|
||||||
|
constructor = .First(Function(c) If(c.GetParameters?.Count, 0) = args)
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
If Not constructor Is Nothing Then
|
||||||
|
If args > 0 AndAlso constructor.GetParameters()(0).ParameterType.GetInterface(GetType(ISiteSettings).Name) Is Nothing Then _
|
||||||
|
Throw New Exception("Class Interface type is incompatible")
|
||||||
|
If args = 0 Then Options = constructor.Invoke(Nothing) Else Options = constructor.Invoke({Me})
|
||||||
|
End If
|
||||||
|
If Options Is Nothing Then Options = Activator.CreateInstance(_UserOptionsType)
|
||||||
|
If Not Options Is Nothing Then UserOptionsSetParameters(Options)
|
||||||
|
End If
|
||||||
|
If Not Options Is Nothing And OpenForm Then
|
||||||
Using f As New InternalSettingsForm(Options, Me, False) : f.ShowDialog() : End Using
|
Using f As New InternalSettingsForm(Options, Me, False) : f.ShowDialog() : End Using
|
||||||
End If
|
End If
|
||||||
Else
|
Else
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ Namespace API.Base
|
|||||||
Private Const Name_MediaPostID As String = "ID"
|
Private Const Name_MediaPostID As String = "ID"
|
||||||
Private Const Name_MediaPostDate As String = "Date"
|
Private Const Name_MediaPostDate As String = "Date"
|
||||||
Private Const Name_SpecialFolder As String = "SpecialFolder"
|
Private Const Name_SpecialFolder As String = "SpecialFolder"
|
||||||
|
Private Const Name_PostTextFile As String = "PostTextFile"
|
||||||
|
Private Const Name_PostTextFileSpecialFolder As String = "PostTextFileSpecialFolder"
|
||||||
#End Region
|
#End Region
|
||||||
Friend Enum Types As Integer
|
Friend Enum Types As Integer
|
||||||
Undefined = 0
|
Undefined = 0
|
||||||
@@ -46,12 +48,25 @@ Namespace API.Base
|
|||||||
End Enum
|
End Enum
|
||||||
Friend Enum States As Integer : Unknown = 0 : Tried = 1 : Downloaded = 2 : Skipped = 3 : Missing = 4 : End Enum
|
Friend Enum States As Integer : Unknown = 0 : Tried = 1 : Downloaded = 2 : Skipped = 3 : Missing = 4 : End Enum
|
||||||
Friend [Type] As Types
|
Friend [Type] As Types
|
||||||
|
Friend ReadOnly Property IsVideoType As Boolean
|
||||||
|
Get
|
||||||
|
Return Type = Types.m3u8 Or Type = Types.Video Or Type = Types.VideoPre
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
Friend ReadOnly Property IsAudioType As Boolean
|
||||||
|
Get
|
||||||
|
Return Type = Types.Audio Or Type = Types.AudioPre
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
Friend URL_BASE As String
|
Friend URL_BASE As String
|
||||||
Friend URL As String
|
Friend URL As String
|
||||||
Friend MD5 As String
|
Friend MD5 As String
|
||||||
Friend [File] As SFile
|
Friend [File] As SFile
|
||||||
Friend Post As UserPost
|
Friend Post As UserPost
|
||||||
Friend PictureOption As String
|
Friend PictureOption As String
|
||||||
|
Friend PostText As String
|
||||||
|
Friend PostTextFile As SFile
|
||||||
|
Friend PostTextFileSpecialFolder As Boolean
|
||||||
Friend State As States
|
Friend State As States
|
||||||
Friend Attempts As Integer
|
Friend Attempts As Integer
|
||||||
''' <summary>
|
''' <summary>
|
||||||
@@ -125,6 +140,30 @@ Namespace API.Base
|
|||||||
Post = New UserPost(Post.ID, PostDate)
|
Post = New UserPost(Post.ID, PostDate)
|
||||||
End Set
|
End Set
|
||||||
End Property
|
End Property
|
||||||
|
Private Property IUserMedia_PostText As String Implements IUserMedia.PostText
|
||||||
|
Get
|
||||||
|
Return PostText
|
||||||
|
End Get
|
||||||
|
Set(ByVal NewText As String)
|
||||||
|
PostText = NewText
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
Private Property IUserMedia_PostTextFile As String Implements IUserMedia.PostTextFile
|
||||||
|
Get
|
||||||
|
Return PostTextFile.ToString
|
||||||
|
End Get
|
||||||
|
Set(ByVal NewPostFile As String)
|
||||||
|
If Not NewPostFile.IsEmptyString Then PostTextFile = New SFile(NewPostFile) Else PostTextFile = Nothing
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
Private Property IUserMedia_PostTextFileSpecialFolder As Boolean Implements IUserMedia.PostTextFileSpecialFolder
|
||||||
|
Get
|
||||||
|
Return PostTextFileSpecialFolder
|
||||||
|
End Get
|
||||||
|
Set(ByVal IsSpecialFolder As Boolean)
|
||||||
|
PostTextFileSpecialFolder = IsSpecialFolder
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
Private Property IUserMedia_SpecialFolder As String Implements IUserMedia.SpecialFolder
|
Private Property IUserMedia_SpecialFolder As String Implements IUserMedia.SpecialFolder
|
||||||
Get
|
Get
|
||||||
Return SpecialFolder
|
Return SpecialFolder
|
||||||
@@ -171,6 +210,9 @@ Namespace API.Base
|
|||||||
SpecialFolder = m.SpecialFolder
|
SpecialFolder = m.SpecialFolder
|
||||||
Attempts = m.Attempts
|
Attempts = m.Attempts
|
||||||
Me.Object = m.Object
|
Me.Object = m.Object
|
||||||
|
PostText = m.PostText
|
||||||
|
PostTextFile = m.PostTextFile
|
||||||
|
PostTextFileSpecialFolder = m.PostTextFileSpecialFolder
|
||||||
End Sub
|
End Sub
|
||||||
Friend Sub New(ByVal e As EContainer, ByVal UserInstance As IUserData)
|
Friend Sub New(ByVal e As EContainer, ByVal UserInstance As IUserData)
|
||||||
Type = e.Attribute(Name_MediaType).Value.FromXML(Of Integer)(CInt(Types.Undefined))
|
Type = e.Attribute(Name_MediaType).Value.FromXML(Of Integer)(CInt(Types.Undefined))
|
||||||
@@ -180,6 +222,8 @@ Namespace API.Base
|
|||||||
URL_BASE = e.Value
|
URL_BASE = e.Value
|
||||||
MD5 = e.Attribute(Name_MediaHash).Value
|
MD5 = e.Attribute(Name_MediaHash).Value
|
||||||
File = e.Attribute(Name_MediaFile).Value
|
File = e.Attribute(Name_MediaFile).Value
|
||||||
|
PostTextFile = e.Attribute(Name_PostTextFile).Value
|
||||||
|
PostTextFileSpecialFolder = e.Attribute(Name_PostTextFileSpecialFolder).Value.FromXML(Of Boolean)(False)
|
||||||
|
|
||||||
Dim vp As Boolean? = Nothing
|
Dim vp As Boolean? = Nothing
|
||||||
Dim upath$ = String.Empty
|
Dim upath$ = String.Empty
|
||||||
@@ -194,7 +238,13 @@ Namespace API.Base
|
|||||||
SpecialFolder = e.Attribute(Name_SpecialFolder).Value
|
SpecialFolder = e.Attribute(Name_SpecialFolder).Value
|
||||||
If Not SpecialFolder.IsEmptyString Then upath &= $"{SpecialFolder}\"
|
If Not SpecialFolder.IsEmptyString Then upath &= $"{SpecialFolder}\"
|
||||||
If vp.HasValue AndAlso vp.Value Then upath &= $"Video\"
|
If vp.HasValue AndAlso vp.Value Then upath &= $"Video\"
|
||||||
If Not upath.IsEmptyString Then File = $"{upath.CSFilePS}{File.File}"
|
If Not upath.IsEmptyString Then
|
||||||
|
File = $"{upath.CSFilePS}{File.File}"
|
||||||
|
If Not PostTextFile.IsEmptyString Then
|
||||||
|
PostTextFile = $"{upath.CSFilePS}{IIf(PostTextFileSpecialFolder, $"{UserDataBase.PostTextSpecialFolderDefault}\", String.Empty)}{PostTextFile.File}"
|
||||||
|
If Type = Types.Text Then File = PostTextFile
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
|
||||||
Post = New UserPost With {
|
Post = New UserPost With {
|
||||||
.ID = e.Attribute(Name_MediaPostID).Value,
|
.ID = e.Attribute(Name_MediaPostID).Value,
|
||||||
@@ -234,7 +284,9 @@ Namespace API.Base
|
|||||||
New EAttribute(Name_MediaURL, URL),
|
New EAttribute(Name_MediaURL, URL),
|
||||||
New EAttribute(Name_MediaHash, MD5),
|
New EAttribute(Name_MediaHash, MD5),
|
||||||
New EAttribute(Name_MediaFile, File.File),
|
New EAttribute(Name_MediaFile, File.File),
|
||||||
|
New EAttribute(Name_PostTextFile, PostTextFile.File),
|
||||||
New EAttribute(Name_SpecialFolder, SpecialFolder),
|
New EAttribute(Name_SpecialFolder, SpecialFolder),
|
||||||
|
New EAttribute(Name_PostTextFileSpecialFolder, PostTextFileSpecialFolder.BoolToInteger),
|
||||||
New EAttribute(Name_MediaPostID, Post.ID),
|
New EAttribute(Name_MediaPostID, Post.ID),
|
||||||
New EAttribute(Name_MediaPostDate, AConvert(Of String)(Post.Date, DateTimeDefaultProvider, String.Empty))
|
New EAttribute(Name_MediaPostDate, AConvert(Of String)(Post.Date, DateTimeDefaultProvider, String.Empty))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ Imports CookieUpdateModes = PersonalUtilities.Tools.Web.Cookies.CookieKeeper.Upd
|
|||||||
Namespace API.Base
|
Namespace API.Base
|
||||||
Friend MustInherit Class UserDataBase : Implements IUserData, IPluginContentProvider, IThrower
|
Friend MustInherit Class UserDataBase : Implements IUserData, IPluginContentProvider, IThrower
|
||||||
Friend Const UserFileAppender As String = "User"
|
Friend Const UserFileAppender As String = "User"
|
||||||
|
Friend Const PostTextSpecialFolderDefault As String = "txt"
|
||||||
#Region "Events"
|
#Region "Events"
|
||||||
Private ReadOnly UserUpdatedEventHandlers As List(Of IUserData.UserUpdatedEventHandler)
|
Private ReadOnly UserUpdatedEventHandlers As List(Of IUserData.UserUpdatedEventHandler)
|
||||||
Friend Custom Event UserUpdated As IUserData.UserUpdatedEventHandler Implements IUserData.UserUpdated
|
Friend Custom Event UserUpdated As IUserData.UserUpdatedEventHandler Implements IUserData.UserUpdated
|
||||||
@@ -80,6 +81,8 @@ Namespace API.Base
|
|||||||
Private _CollectionButtonsExists As Boolean = False
|
Private _CollectionButtonsExists As Boolean = False
|
||||||
Private _CollectionButtonsColorsSet As Boolean = False
|
Private _CollectionButtonsColorsSet As Boolean = False
|
||||||
Friend WithEvents BTT_CONTEXT_DOWN As ToolStripKeyMenuItem
|
Friend WithEvents BTT_CONTEXT_DOWN As ToolStripKeyMenuItem
|
||||||
|
Friend WithEvents BTT_CONTEXT_DOWN_LIMIT As ToolStripKeyMenuItem
|
||||||
|
Friend WithEvents BTT_CONTEXT_DOWN_DATE As ToolStripKeyMenuItem
|
||||||
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_ERASE As ToolStripMenuItem
|
Friend WithEvents BTT_CONTEXT_ERASE As ToolStripMenuItem
|
||||||
@@ -98,6 +101,8 @@ Namespace API.Base
|
|||||||
End If
|
End If
|
||||||
End With
|
End With
|
||||||
BTT_CONTEXT_DOWN = New ToolStripKeyMenuItem(tn, i) With {.Name = tnn("DOWN"), .Tag = Me}
|
BTT_CONTEXT_DOWN = New ToolStripKeyMenuItem(tn, i) With {.Name = tnn("DOWN"), .Tag = Me}
|
||||||
|
BTT_CONTEXT_DOWN_LIMIT = New ToolStripKeyMenuItem(tn, i) With {.Name = tnn("DOWN_LIMIT"), .Tag = Me}
|
||||||
|
BTT_CONTEXT_DOWN_DATE = New ToolStripKeyMenuItem(tn, i) With {.Name = tnn("DOWN_DATE"), .Tag = Me}
|
||||||
BTT_CONTEXT_EDIT = New ToolStripMenuItem(tn, i) With {.Name = tnn("EDIT"), .Tag = Me}
|
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 = Me}
|
BTT_CONTEXT_DELETE = New ToolStripMenuItem(tn, i) With {.Name = tnn("DELETE"), .Tag = Me}
|
||||||
BTT_CONTEXT_ERASE = New ToolStripMenuItem(tn, i) With {.Name = tnn("ERASE"), .Tag = Me}
|
BTT_CONTEXT_ERASE = New ToolStripMenuItem(tn, i) With {.Name = tnn("ERASE"), .Tag = Me}
|
||||||
@@ -117,7 +122,8 @@ Namespace API.Base
|
|||||||
cb = MyColor.EditBack
|
cb = MyColor.EditBack
|
||||||
cf = MyColor.EditFore
|
cf = MyColor.EditFore
|
||||||
End If
|
End If
|
||||||
For Each b As ToolStripMenuItem In {BTT_CONTEXT_DOWN, BTT_CONTEXT_EDIT, BTT_CONTEXT_DELETE, BTT_CONTEXT_ERASE,
|
For Each b As ToolStripMenuItem In {BTT_CONTEXT_DOWN, BTT_CONTEXT_DOWN_LIMIT, BTT_CONTEXT_DOWN_DATE,
|
||||||
|
BTT_CONTEXT_EDIT, BTT_CONTEXT_DELETE, BTT_CONTEXT_ERASE,
|
||||||
BTT_CONTEXT_OPEN_PATH, BTT_CONTEXT_OPEN_SITE}
|
BTT_CONTEXT_OPEN_PATH, BTT_CONTEXT_OPEN_SITE}
|
||||||
If Not b Is Nothing Then b.BackColor = cb : b.ForeColor = cf
|
If Not b Is Nothing Then b.BackColor = cb : b.ForeColor = cf
|
||||||
Next
|
Next
|
||||||
@@ -147,6 +153,9 @@ Namespace API.Base
|
|||||||
Private Const Name_IsSubscription As String = UserInfo.Name_IsSubscription
|
Private Const Name_IsSubscription As String = UserInfo.Name_IsSubscription
|
||||||
Private Const Name_Temporary As String = "Temporary"
|
Private Const Name_Temporary As String = "Temporary"
|
||||||
Private Const Name_Favorite As String = "Favorite"
|
Private Const Name_Favorite As String = "Favorite"
|
||||||
|
Private Const Name_DownloadText As String = "DownloadText"
|
||||||
|
Private Const Name_DownloadTextPosts As String = "DownloadTextPosts"
|
||||||
|
Private Const Name_DownloadTextSpecialFolder As String = "DownloadTextSpecialFolder"
|
||||||
Private Const Name_BackColor As String = "BackColor"
|
Private Const Name_BackColor As String = "BackColor"
|
||||||
Private Const Name_ForeColor As String = "ForeColor"
|
Private Const Name_ForeColor As String = "ForeColor"
|
||||||
Private Const Name_CreatedByChannel As String = "CreatedByChannel"
|
Private Const Name_CreatedByChannel As String = "CreatedByChannel"
|
||||||
@@ -162,6 +171,7 @@ Namespace API.Base
|
|||||||
|
|
||||||
Private Const Name_VideoCount As String = "VideoCount"
|
Private Const Name_VideoCount As String = "VideoCount"
|
||||||
Private Const Name_PicturesCount As String = "PicturesCount"
|
Private Const Name_PicturesCount As String = "PicturesCount"
|
||||||
|
Private Const Name_TextCount As String = "TextCount"
|
||||||
Private Const Name_LastUpdated As String = "LastUpdated"
|
Private Const Name_LastUpdated As String = "LastUpdated"
|
||||||
|
|
||||||
Private Const Name_ScriptUse As String = "ScriptUse"
|
Private Const Name_ScriptUse As String = "ScriptUse"
|
||||||
@@ -173,6 +183,8 @@ Namespace API.Base
|
|||||||
#Region "Additional names"
|
#Region "Additional names"
|
||||||
Protected Const Name_SiteMode As String = "SiteMode"
|
Protected Const Name_SiteMode As String = "SiteMode"
|
||||||
Protected Const Name_TrueName As String = "TrueName"
|
Protected Const Name_TrueName As String = "TrueName"
|
||||||
|
'TODELETE Name_TrueName2
|
||||||
|
<Obsolete> Protected Const Name_TrueName2 As String = "NameTrue"
|
||||||
Protected Const Name_Arguments As String = "Arguments"
|
Protected Const Name_Arguments As String = "Arguments"
|
||||||
#End Region
|
#End Region
|
||||||
#End Region
|
#End Region
|
||||||
@@ -240,7 +252,20 @@ Namespace API.Base
|
|||||||
#End Region
|
#End Region
|
||||||
#Region "User name, ID, exist, suspend, options"
|
#Region "User name, ID, exist, suspend, options"
|
||||||
Friend User As UserInfo
|
Friend User As UserInfo
|
||||||
|
Private _IsSavedPosts As Boolean = False
|
||||||
Friend Property IsSavedPosts As Boolean Implements IPluginContentProvider.IsSavedPosts
|
Friend Property IsSavedPosts As Boolean Implements IPluginContentProvider.IsSavedPosts
|
||||||
|
Get
|
||||||
|
Return _IsSavedPosts
|
||||||
|
End Get
|
||||||
|
Set(ByVal __IsSavedPosts As Boolean)
|
||||||
|
_IsSavedPosts = __IsSavedPosts
|
||||||
|
If _IsSavedPosts Then
|
||||||
|
DownloadText = True
|
||||||
|
DownloadTextPosts = True
|
||||||
|
DownloadTextSpecialFolder = True
|
||||||
|
End If
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
Private _UserExists As Boolean = True
|
Private _UserExists As Boolean = True
|
||||||
Friend Overridable Property UserExists As Boolean Implements IUserData.Exists, IPluginContentProvider.UserExists
|
Friend Overridable Property UserExists As Boolean Implements IUserData.Exists, IPluginContentProvider.UserExists
|
||||||
Get
|
Get
|
||||||
@@ -273,7 +298,31 @@ Namespace API.Base
|
|||||||
Return User.Name
|
Return User.Name
|
||||||
End Get
|
End Get
|
||||||
End Property
|
End Property
|
||||||
Friend Overridable Property ID As String = String.Empty Implements IUserData.ID, IPluginContentProvider.ID
|
Private _NameTrue As String = String.Empty
|
||||||
|
Friend Overridable Overloads Property NameTrue As String Implements IUserData.NameTrue, IPluginContentProvider.NameTrue
|
||||||
|
Get
|
||||||
|
Return NameTrue(False)
|
||||||
|
End Get
|
||||||
|
Set(ByVal NewName As String)
|
||||||
|
If Not _NameTrue = NewName Then EnvirChanged(NewName)
|
||||||
|
_NameTrue = NewName
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
Friend Overloads ReadOnly Property NameTrue(ByVal Exact As Boolean) As String
|
||||||
|
Get
|
||||||
|
Return If(Exact, _NameTrue, _NameTrue.IfNullOrEmpty(Name))
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
Private _ID As String = String.Empty
|
||||||
|
Friend Property ID As String Implements IUserData.ID, IPluginContentProvider.ID
|
||||||
|
Get
|
||||||
|
Return _ID
|
||||||
|
End Get
|
||||||
|
Set(ByVal NewId As String)
|
||||||
|
If Not _ID = NewId Then EnvirChanged(NewId)
|
||||||
|
_ID = NewId
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
Protected _FriendlyName As String = String.Empty
|
Protected _FriendlyName As String = String.Empty
|
||||||
Friend Overridable Property FriendlyName As String Implements IUserData.FriendlyName
|
Friend Overridable Property FriendlyName As String Implements IUserData.FriendlyName
|
||||||
Get
|
Get
|
||||||
@@ -343,13 +392,21 @@ Namespace API.Base
|
|||||||
Protected Function UserDescriptionNeedToUpdate() As Boolean
|
Protected Function UserDescriptionNeedToUpdate() As Boolean
|
||||||
Return (UserDescription.IsEmptyString Or _DescriptionEveryTime) And Not _DescriptionChecked
|
Return (UserDescription.IsEmptyString Or _DescriptionEveryTime) And Not _DescriptionChecked
|
||||||
End Function
|
End Function
|
||||||
Protected Sub UserDescriptionUpdate(ByVal Descr As String)
|
Protected Sub UserDescriptionUpdate(ByVal Descr As String, Optional ByVal Force As Boolean = False,
|
||||||
If UserDescriptionNeedToUpdate() Then
|
Optional ByVal InsertFirst As Boolean = False, Optional ByVal AppendDate As Boolean = False)
|
||||||
|
If UserDescriptionNeedToUpdate() Or Force Then
|
||||||
|
If AppendDate Then Descr = $"{Now.ToStringDateDef}: {Descr}"
|
||||||
If UserDescription.IsEmptyString Then
|
If UserDescription.IsEmptyString Then
|
||||||
UserDescription = Descr
|
UserDescription = Descr
|
||||||
|
_ForceSaveUserInfo = True
|
||||||
ElseIf Not UserDescription.Contains(Descr) Then
|
ElseIf Not UserDescription.Contains(Descr) Then
|
||||||
|
If InsertFirst Then
|
||||||
|
UserDescription = $"{Descr}{vbNewLine}{UserDescription}"
|
||||||
|
Else
|
||||||
UserDescription &= $"{vbNewLine}----{vbNewLine}{Descr}"
|
UserDescription &= $"{vbNewLine}----{vbNewLine}{Descr}"
|
||||||
End If
|
End If
|
||||||
|
_ForceSaveUserInfo = True
|
||||||
|
End If
|
||||||
_DescriptionChecked = True
|
_DescriptionChecked = True
|
||||||
End If
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
@@ -609,6 +666,9 @@ BlockNullPicture:
|
|||||||
Friend Overridable Property ReadyForDownload As Boolean = True Implements IUserData.ReadyForDownload
|
Friend Overridable Property ReadyForDownload As Boolean = True Implements IUserData.ReadyForDownload
|
||||||
Friend Property DownloadImages As Boolean = True Implements IUserData.DownloadImages
|
Friend Property DownloadImages As Boolean = True Implements IUserData.DownloadImages
|
||||||
Friend Property DownloadVideos As Boolean = True Implements IUserData.DownloadVideos
|
Friend Property DownloadVideos As Boolean = True Implements IUserData.DownloadVideos
|
||||||
|
Friend Overridable Property DownloadText As Boolean = False
|
||||||
|
Friend Overridable Property DownloadTextPosts As Boolean = False
|
||||||
|
Friend Overridable Property DownloadTextSpecialFolder As Boolean = True
|
||||||
Friend Property DownloadMissingOnly As Boolean = False Implements IUserData.DownloadMissingOnly
|
Friend Property DownloadMissingOnly As Boolean = False Implements IUserData.DownloadMissingOnly
|
||||||
Private _IconBannerDownloaded As Boolean = False
|
Private _IconBannerDownloaded As Boolean = False
|
||||||
Friend WriteOnly Property IconBannerDownloaded As Boolean
|
Friend WriteOnly Property IconBannerDownloaded As Boolean
|
||||||
@@ -720,9 +780,23 @@ BlockNullPicture:
|
|||||||
End If
|
End If
|
||||||
End Set
|
End Set
|
||||||
End Property
|
End Property
|
||||||
|
Private _DownloadedTextsTotal As Integer = 0
|
||||||
|
Private _DownloadedTextsSession As Integer = 0
|
||||||
|
Friend Property DownloadedTexts(ByVal Total As Boolean) As Integer Implements IUserData.DownloadedTexts
|
||||||
|
Get
|
||||||
|
Return IIf(Total, _DownloadedTextsTotal, _DownloadedTextsSession)
|
||||||
|
End Get
|
||||||
|
Set(ByVal NewValue As Integer)
|
||||||
|
If Total Then
|
||||||
|
_DownloadedTextsTotal = NewValue
|
||||||
|
Else
|
||||||
|
_DownloadedTextsSession = NewValue
|
||||||
|
End If
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
Friend Overridable ReadOnly Property DownloadedTotal(Optional ByVal Total As Boolean = True) As Integer Implements IUserData.DownloadedTotal
|
Friend Overridable ReadOnly Property DownloadedTotal(Optional ByVal Total As Boolean = True) As Integer Implements IUserData.DownloadedTotal
|
||||||
Get
|
Get
|
||||||
Return DownloadedPictures(Total) + DownloadedVideos(Total)
|
Return DownloadedPictures(Total) + DownloadedVideos(Total) + DownloadedTexts(Total)
|
||||||
End Get
|
End Get
|
||||||
End Property
|
End Property
|
||||||
Friend ReadOnly Property DownloadedInformation As String Implements IUserData.DownloadedInformation
|
Friend ReadOnly Property DownloadedInformation As String Implements IUserData.DownloadedInformation
|
||||||
@@ -902,6 +976,10 @@ BlockNullPicture:
|
|||||||
FileExists = True
|
FileExists = True
|
||||||
Using x As New XmlFile(MyFileSettings) With {.XmlReadOnly = True}
|
Using x As New XmlFile(MyFileSettings) With {.XmlReadOnly = True}
|
||||||
If User.Name.IsEmptyString Then User.Name = x.Value(Name_UserName)
|
If User.Name.IsEmptyString Then User.Name = x.Value(Name_UserName)
|
||||||
|
_NameTrue = x.Value(Name_TrueName)
|
||||||
|
#Disable Warning BC40008
|
||||||
|
If _NameTrue.IsEmptyString AndAlso x.Contains(Name_TrueName2) Then _NameTrue = x.Value(Name_TrueName2)
|
||||||
|
#Enable Warning
|
||||||
UserExists = x.Value(Name_UserExists).FromXML(Of Boolean)(True)
|
UserExists = x.Value(Name_UserExists).FromXML(Of Boolean)(True)
|
||||||
UserSuspended = x.Value(Name_UserSuspended).FromXML(Of Boolean)(False)
|
UserSuspended = x.Value(Name_UserSuspended).FromXML(Of Boolean)(False)
|
||||||
ID = x.Value(Name_UserID)
|
ID = x.Value(Name_UserID)
|
||||||
@@ -929,9 +1007,13 @@ BlockNullPicture:
|
|||||||
ReadyForDownload = x.Value(Name_ReadyForDownload).FromXML(Of Boolean)(True)
|
ReadyForDownload = x.Value(Name_ReadyForDownload).FromXML(Of Boolean)(True)
|
||||||
DownloadImages = x.Value(Name_DownloadImages).FromXML(Of Boolean)(True)
|
DownloadImages = x.Value(Name_DownloadImages).FromXML(Of Boolean)(True)
|
||||||
DownloadVideos = x.Value(Name_DownloadVideos).FromXML(Of Boolean)(True)
|
DownloadVideos = x.Value(Name_DownloadVideos).FromXML(Of Boolean)(True)
|
||||||
|
DownloadText = x.Value(Name_DownloadText).FromXML(Of Boolean)(IsSavedPosts)
|
||||||
|
DownloadTextPosts = x.Value(Name_DownloadTextPosts).FromXML(Of Boolean)(IsSavedPosts)
|
||||||
|
DownloadTextSpecialFolder = x.Value(Name_DownloadTextSpecialFolder).FromXML(Of Boolean)(True)
|
||||||
_IconBannerDownloaded = x.Value(Name_IconBannerDownloaded).FromXML(Of Boolean)(False)
|
_IconBannerDownloaded = x.Value(Name_IconBannerDownloaded).FromXML(Of Boolean)(False)
|
||||||
DownloadedVideos(True) = x.Value(Name_VideoCount).FromXML(Of Integer)(0)
|
DownloadedVideos(True) = x.Value(Name_VideoCount).FromXML(Of Integer)(0)
|
||||||
DownloadedPictures(True) = x.Value(Name_PicturesCount).FromXML(Of Integer)(0)
|
DownloadedPictures(True) = x.Value(Name_PicturesCount).FromXML(Of Integer)(0)
|
||||||
|
DownloadedTexts(True) = x.Value(Name_TextCount).FromXML(Of Integer)(0)
|
||||||
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)
|
||||||
@@ -947,6 +1029,9 @@ BlockNullPicture:
|
|||||||
LogError(ex, "user information loading error")
|
LogError(ex, "user information loading error")
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
|
Private Sub UpdateUserInformation_Ex()
|
||||||
|
If _ForceSaveUserInfoOnException Then UpdateUserInformation()
|
||||||
|
End Sub
|
||||||
Friend Overridable Overloads Sub UpdateUserInformation() Implements IUserData.UpdateUserInformation
|
Friend Overridable Overloads Sub UpdateUserInformation() Implements IUserData.UpdateUserInformation
|
||||||
UpdateUserInformation(False)
|
UpdateUserInformation(False)
|
||||||
End Sub
|
End Sub
|
||||||
@@ -959,6 +1044,7 @@ BlockNullPicture:
|
|||||||
x.Add(Name_Plugin, HOST.Key)
|
x.Add(Name_Plugin, HOST.Key)
|
||||||
x.Add(Name_AccountName, AccountName)
|
x.Add(Name_AccountName, AccountName)
|
||||||
x.Add(Name_UserName, User.Name)
|
x.Add(Name_UserName, User.Name)
|
||||||
|
x.Add(Name_TrueName, _NameTrue)
|
||||||
x.Add(Name_Model_User, CInt(UserModel))
|
x.Add(Name_Model_User, CInt(UserModel))
|
||||||
x.Add(Name_Model_Collection, CInt(CollectionModel))
|
x.Add(Name_Model_Collection, CInt(CollectionModel))
|
||||||
x.Add(Name_SpecialPath, User.SpecialPath)
|
x.Add(Name_SpecialPath, User.SpecialPath)
|
||||||
@@ -987,9 +1073,13 @@ BlockNullPicture:
|
|||||||
x.Add(Name_ReadyForDownload, ReadyForDownload.BoolToInteger)
|
x.Add(Name_ReadyForDownload, ReadyForDownload.BoolToInteger)
|
||||||
x.Add(Name_DownloadImages, DownloadImages.BoolToInteger)
|
x.Add(Name_DownloadImages, DownloadImages.BoolToInteger)
|
||||||
x.Add(Name_DownloadVideos, DownloadVideos.BoolToInteger)
|
x.Add(Name_DownloadVideos, DownloadVideos.BoolToInteger)
|
||||||
|
x.Add(Name_DownloadText, DownloadText.BoolToInteger)
|
||||||
|
x.Add(Name_DownloadTextPosts, DownloadTextPosts.BoolToInteger)
|
||||||
|
x.Add(Name_DownloadTextSpecialFolder, DownloadTextSpecialFolder.BoolToInteger)
|
||||||
x.Add(Name_IconBannerDownloaded, _IconBannerDownloaded.BoolToInteger)
|
x.Add(Name_IconBannerDownloaded, _IconBannerDownloaded.BoolToInteger)
|
||||||
x.Add(Name_VideoCount, DownloadedVideos(True))
|
x.Add(Name_VideoCount, DownloadedVideos(True))
|
||||||
x.Add(Name_PicturesCount, DownloadedPictures(True))
|
x.Add(Name_PicturesCount, DownloadedPictures(True))
|
||||||
|
x.Add(Name_TextCount, DownloadedTexts(True))
|
||||||
x.Add(Name_LastUpdated, AConvert(Of String)(LastUpdated, ADateTime.Formats.BaseDateTime, String.Empty))
|
x.Add(Name_LastUpdated, AConvert(Of String)(LastUpdated, ADateTime.Formats.BaseDateTime, String.Empty))
|
||||||
x.Add(Name_ScriptUse, ScriptUse.BoolToInteger)
|
x.Add(Name_ScriptUse, ScriptUse.BoolToInteger)
|
||||||
x.Add(Name_ScriptData, ScriptData)
|
x.Add(Name_ScriptData, ScriptData)
|
||||||
@@ -1117,6 +1207,7 @@ BlockNullPicture:
|
|||||||
Protected UseClientTokens As Boolean = False
|
Protected UseClientTokens As Boolean = False
|
||||||
Protected _ForceSaveUserData As Boolean = False
|
Protected _ForceSaveUserData As Boolean = False
|
||||||
Protected _ForceSaveUserInfo As Boolean = False
|
Protected _ForceSaveUserInfo As Boolean = False
|
||||||
|
Protected _ForceSaveUserInfoOnException As Boolean = False
|
||||||
Private _DownloadInProgress As Boolean = False
|
Private _DownloadInProgress As Boolean = False
|
||||||
Private _EnvirUserExists As Boolean
|
Private _EnvirUserExists As Boolean
|
||||||
Private _EnvirUserSuspended As Boolean
|
Private _EnvirUserSuspended As Boolean
|
||||||
@@ -1136,6 +1227,7 @@ BlockNullPicture:
|
|||||||
_DescriptionEveryTime = Settings.UpdateUserDescriptionEveryTime
|
_DescriptionEveryTime = Settings.UpdateUserDescriptionEveryTime
|
||||||
_ForceSaveUserData = False
|
_ForceSaveUserData = False
|
||||||
_ForceSaveUserInfo = False
|
_ForceSaveUserInfo = False
|
||||||
|
_ForceSaveUserInfoOnException = False
|
||||||
_EnvirUserExists = UserExists
|
_EnvirUserExists = UserExists
|
||||||
_EnvirUserSuspended = UserSuspended
|
_EnvirUserSuspended = UserSuspended
|
||||||
_EnvirCreatedByChannel = CreatedByChannel
|
_EnvirCreatedByChannel = CreatedByChannel
|
||||||
@@ -1152,6 +1244,8 @@ BlockNullPicture:
|
|||||||
Select Case Caller
|
Select Case Caller
|
||||||
Case NameOf(UserExists) : If Not _EnvirUserExists = CBool(NewValue) Then _EnvirChanged = True : _EnvirInvokeUserUpdated = True
|
Case NameOf(UserExists) : If Not _EnvirUserExists = CBool(NewValue) Then _EnvirChanged = True : _EnvirInvokeUserUpdated = True
|
||||||
Case NameOf(UserSuspended) : If Not _EnvirUserSuspended = CBool(NewValue) Then _EnvirChanged = True : _EnvirInvokeUserUpdated = True
|
Case NameOf(UserSuspended) : If Not _EnvirUserSuspended = CBool(NewValue) Then _EnvirChanged = True : _EnvirInvokeUserUpdated = True
|
||||||
|
Case NameOf(NameTrue) : _EnvirChanged = True : _ForceSaveUserInfo = True : _ForceSaveUserInfoOnException = True
|
||||||
|
Case NameOf(ID) : _EnvirChanged = True : _ForceSaveUserInfo = True : _ForceSaveUserInfoOnException = True
|
||||||
Case Else : _EnvirChanged = True
|
Case Else : _EnvirChanged = True
|
||||||
End Select
|
End Select
|
||||||
End If
|
End If
|
||||||
@@ -1205,6 +1299,7 @@ BlockNullPicture:
|
|||||||
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)
|
||||||
If Not DownloadVideos Then _TempMediaList.RemoveAll(Function(m) m.Type = UTypes.Video Or
|
If Not DownloadVideos Then _TempMediaList.RemoveAll(Function(m) m.Type = UTypes.Video Or
|
||||||
m.Type = UTypes.VideoPre Or m.Type = UTypes.m3u8)
|
m.Type = UTypes.VideoPre Or m.Type = UTypes.m3u8)
|
||||||
|
If Not DownloadTextPosts Then _TempMediaList.RemoveAll(Function(m) m.Type = UTypes.Text)
|
||||||
If DownloadMissingOnly Then _TempMediaList.RemoveAll(Function(m) Not m.State = UStates.Missing)
|
If DownloadMissingOnly Then _TempMediaList.RemoveAll(Function(m) Not m.State = UStates.Missing)
|
||||||
End If
|
End If
|
||||||
|
|
||||||
@@ -1265,21 +1360,26 @@ BlockNullPicture:
|
|||||||
ThrowIfDisposed()
|
ThrowIfDisposed()
|
||||||
If Not _PictureExists Or _EnvirInvokeUserUpdated Then OnUserUpdated()
|
If Not _PictureExists Or _EnvirInvokeUserUpdated Then OnUserUpdated()
|
||||||
Catch oex As OperationCanceledException When Token.IsCancellationRequested Or TokenPersonal.IsCancellationRequested Or TokenQueue.IsCancellationRequested
|
Catch oex As OperationCanceledException When Token.IsCancellationRequested Or TokenPersonal.IsCancellationRequested Or TokenQueue.IsCancellationRequested
|
||||||
|
UpdateUserInformation_Ex()
|
||||||
MyMainLOG = $"{ToStringForLog()}: downloading canceled"
|
MyMainLOG = $"{ToStringForLog()}: downloading canceled"
|
||||||
Canceled = True
|
Canceled = True
|
||||||
Catch exit_ex As ExitException
|
Catch exit_ex As ExitException
|
||||||
|
UpdateUserInformation_Ex()
|
||||||
If Not exit_ex.Silent Then
|
If Not exit_ex.Silent Then
|
||||||
If exit_ex.SimpleLogLine Then
|
If exit_ex.SimpleLogLine Then
|
||||||
MyMainLOG = $"{ToStringForLog()}: downloading interrupted (exit) ({exit_ex.Message})"
|
LogError(Nothing, $"downloading interrupted (exit) ({exit_ex.Message})")
|
||||||
Else
|
Else
|
||||||
ErrorsDescriber.Execute(EDP.SendToLog, exit_ex, $"{ToStringForLog()}: downloading interrupted (exit)")
|
LogError(exit_ex, "downloading interrupted (exit)")
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
|
If _EnvirInvokeUserUpdated Then OnUserUpdated()
|
||||||
Canceled = True
|
Canceled = True
|
||||||
Catch dex As ObjectDisposedException When Disposed
|
Catch dex As ObjectDisposedException When Disposed
|
||||||
Canceled = True
|
Canceled = True
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
|
UpdateUserInformation_Ex()
|
||||||
LogError(ex, "downloading data error")
|
LogError(ex, "downloading data error")
|
||||||
|
If _EnvirInvokeUserUpdated Then OnUserUpdated()
|
||||||
HasError = True
|
HasError = True
|
||||||
Finally
|
Finally
|
||||||
If Not UserExists Then AddNonExistingUserToLog($"User '{ToStringForLog()}' not found on the site")
|
If Not UserExists Then AddNonExistingUserToLog($"User '{ToStringForLog()}' not found on the site")
|
||||||
@@ -1415,6 +1515,7 @@ BlockNullPicture:
|
|||||||
Data.DownloadState = UserMediaStates.Missing
|
Data.DownloadState = UserMediaStates.Missing
|
||||||
End If
|
End If
|
||||||
YouTube.Objects.YouTubeMediaContainerBase.Update(_ContentNew(0), Data)
|
YouTube.Objects.YouTubeMediaContainerBase.Update(_ContentNew(0), Data)
|
||||||
|
If _ContentNew.Count > 1 Then Data.Files.ListAddList(_ContentNew.Select(Function(cc) cc.File), LNC)
|
||||||
If ResetTitle And Not _ContentNew(0).File.Name.IsEmptyString Then Data.Title = _ContentNew(0).File.Name
|
If ResetTitle And Not _ContentNew(0).File.Name.IsEmptyString Then Data.Title = _ContentNew(0).File.Name
|
||||||
Else
|
Else
|
||||||
Data.DownloadState = UserMediaStates.Missing
|
Data.DownloadState = UserMediaStates.Missing
|
||||||
@@ -1612,7 +1713,8 @@ BlockNullPicture:
|
|||||||
Dim dCount% = 0, dTotal% = 0
|
Dim dCount% = 0, dTotal% = 0
|
||||||
ThrowAny(Token)
|
ThrowAny(Token)
|
||||||
If _ContentNew.Count > 0 Then
|
If _ContentNew.Count > 0 Then
|
||||||
_ContentNew.RemoveAll(Function(c) c.URL.IsEmptyString)
|
_ContentNew.RemoveAll(Function(c) Not c.Type = UTypes.Text And c.URL.IsEmptyString)
|
||||||
|
If Not DownloadText Or Not DownloadTextPosts Then _ContentNew.RemoveAll(Function(c) c.Type = UTypes.Text)
|
||||||
If _ContentNew.Count > 0 Then
|
If _ContentNew.Count > 0 Then
|
||||||
If UseMD5Comparison Then LoadMD5()
|
If UseMD5Comparison Then LoadMD5()
|
||||||
MyFile.Exists(SFO.Path)
|
MyFile.Exists(SFO.Path)
|
||||||
@@ -1621,7 +1723,7 @@ BlockNullPicture:
|
|||||||
Dim vsf As Boolean = SeparateVideoFolderF
|
Dim vsf As Boolean = SeparateVideoFolderF
|
||||||
Dim __isVideo As Boolean
|
Dim __isVideo As Boolean
|
||||||
Dim __interrupt As Boolean
|
Dim __interrupt As Boolean
|
||||||
Dim f As SFile
|
Dim f As SFile, fTxt As SFile
|
||||||
Dim v As UserMedia
|
Dim v As UserMedia
|
||||||
Dim __fileDeleted As Boolean
|
Dim __fileDeleted As Boolean
|
||||||
Dim fileNumProvider As SFileNumbers = SFileNumbers.Default
|
Dim fileNumProvider As SFileNumbers = SFileNumbers.Default
|
||||||
@@ -1635,9 +1737,11 @@ BlockNullPicture:
|
|||||||
ErrorsDescriber.Execute(EDP.SendToLog, file_del_ex)
|
ErrorsDescriber.Execute(EDP.SendToLog, file_del_ex)
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
Dim updateDownCount As Action = Sub()
|
Dim updateDownCount As Action(Of Boolean) = Sub(ByVal forceText As Boolean)
|
||||||
Dim __n% = IIf(__fileDeleted, -1, 1)
|
Dim __n% = IIf(__fileDeleted And Not forceText, -1, 1)
|
||||||
If __isVideo Then
|
If v.Type = UTypes.Text Or forceText Then
|
||||||
|
DownloadedTexts(False) += __n
|
||||||
|
ElseIf __isVideo Then
|
||||||
v.Type = UTypes.Video
|
v.Type = UTypes.Video
|
||||||
DownloadedVideos(False) += __n
|
DownloadedVideos(False) += __n
|
||||||
ElseIf v.Type = UTypes.GIF Then
|
ElseIf v.Type = UTypes.GIF Then
|
||||||
@@ -1679,8 +1783,9 @@ BlockNullPicture:
|
|||||||
|
|
||||||
__fileDeleted = False
|
__fileDeleted = False
|
||||||
|
|
||||||
If Not f.IsEmptyString And Not v.URL.IsEmptyString Then
|
If (v.Type = UTypes.Text And DownloadText) Or (Not f.IsEmptyString And Not v.URL.IsEmptyString) Then
|
||||||
Try
|
Try
|
||||||
|
If v.Type = UTypes.Text Then GoTo stxt
|
||||||
__isVideo = v.Type = UTypes.Video Or f.Extension = "mp4" Or v.Type = UTypes.m3u8
|
__isVideo = v.Type = UTypes.Video Or f.Extension = "mp4" Or v.Type = UTypes.m3u8
|
||||||
|
|
||||||
If f.Extension.IsEmptyString Then
|
If f.Extension.IsEmptyString Then
|
||||||
@@ -1723,7 +1828,7 @@ BlockNullPicture:
|
|||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
|
|
||||||
updateDownCount()
|
updateDownCount(False)
|
||||||
|
|
||||||
v.File = ChangeFileNameByProvider(f, v)
|
v.File = ChangeFileNameByProvider(f, v)
|
||||||
v.State = UStates.Downloaded
|
v.State = UStates.Downloaded
|
||||||
@@ -1734,7 +1839,7 @@ BlockNullPicture:
|
|||||||
If Not v.MD5.IsEmptyString Then
|
If Not v.MD5.IsEmptyString Then
|
||||||
If _MD5List.Contains(v.MD5) Then
|
If _MD5List.Contains(v.MD5) Then
|
||||||
__fileDeleted = v.File.Delete(SFO.File, SFODelete.DeletePermanently, EDP.ReturnValue)
|
__fileDeleted = v.File.Delete(SFO.File, SFODelete.DeletePermanently, EDP.ReturnValue)
|
||||||
If __fileDeleted Then dCount -= 1 : updateDownCount()
|
If __fileDeleted Then dCount -= 1 : updateDownCount(False)
|
||||||
Else
|
Else
|
||||||
_MD5List.Add(v.MD5)
|
_MD5List.Add(v.MD5)
|
||||||
End If
|
End If
|
||||||
@@ -1743,7 +1848,33 @@ BlockNullPicture:
|
|||||||
dCount -= 1
|
dCount -= 1
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
|
stxt:
|
||||||
|
If DownloadText And Not v.PostText.IsEmptyString And (v.Type = UTypes.Text Or v.File.Exists) Then
|
||||||
|
fTxt = v.File
|
||||||
|
If fTxt.IsEmptyString Then
|
||||||
|
If DownloadTextPosts And Not f.IsEmptyString Then
|
||||||
|
fTxt = f
|
||||||
|
If v.Type = UTypes.Text Then fTxt.Name &= IIf(fTxt.Name.IsEmptyString, String.Empty, "_") &
|
||||||
|
v.Post.ID.StringRemoveWinForbiddenSymbols
|
||||||
|
If fTxt.IsEmptyString Then Throw New ArgumentNullException("Text", "Error downloading text") With {.HelpLink = 10}
|
||||||
|
Else
|
||||||
|
Continue For
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
v.PostTextFileSpecialFolder = DownloadTextSpecialFolder
|
||||||
|
If DownloadTextSpecialFolder Then fTxt.Path = $"{fTxt.Path.StringTrimEnd("\")}\{PostTextSpecialFolderDefault}"
|
||||||
|
fTxt.Extension = "txt"
|
||||||
|
v.PostTextFile = TextSaver.SaveTextToFile(v.PostText, fTxt,,, Settings.FeedShowTextPosts_LogErrors_E)
|
||||||
|
If Not v.PostTextFile.Exists Then Throw New ArgumentNullException("Text", "Error downloading text") With {.HelpLink = 10}
|
||||||
|
If v.Type = UTypes.Text Then v.File = v.PostTextFile
|
||||||
|
v.State = UStates.Downloaded
|
||||||
|
updateDownCount(Not v.Type = UTypes.Text)
|
||||||
|
If v.URL.IsEmptyString Then v.URL = v.PostTextFile.File
|
||||||
|
If v.URL_BASE.IsEmptyString Then v.URL_BASE = v.URL
|
||||||
|
End If
|
||||||
dCount += 1
|
dCount += 1
|
||||||
|
Catch anex As ArgumentNullException When anex.HelpLink = 10
|
||||||
|
LogError(anex, anex.Message, Settings.FeedShowTextPosts_LogErrors_E)
|
||||||
Catch woex As OperationCanceledException When Token.IsCancellationRequested
|
Catch woex As OperationCanceledException When Token.IsCancellationRequested
|
||||||
__deleteFile.Invoke(f, v.URL_BASE)
|
__deleteFile.Invoke(f, v.URL_BASE)
|
||||||
v.State = UStates.Missing
|
v.State = UStates.Missing
|
||||||
@@ -1751,7 +1882,7 @@ BlockNullPicture:
|
|||||||
_ContentNew(i) = v
|
_ContentNew(i) = v
|
||||||
Throw woex
|
Throw woex
|
||||||
Catch wex As Exception
|
Catch wex As Exception
|
||||||
If DownloadContentDefault_ProcessDownloadException() Then
|
If Not v.Type = UTypes.Text AndAlso DownloadContentDefault_ProcessDownloadException() Then
|
||||||
v.Attempts += 1
|
v.Attempts += 1
|
||||||
v.State = UStates.Missing
|
v.State = UStates.Missing
|
||||||
If MissingErrorsAdd Then ErrorDownloading(f, v.URL)
|
If MissingErrorsAdd Then ErrorDownloading(f, v.URL)
|
||||||
@@ -1831,6 +1962,31 @@ BlockNullPicture:
|
|||||||
Protected Overridable Function CreateFileFromUrl(ByVal URL As String) As SFile
|
Protected Overridable Function CreateFileFromUrl(ByVal URL As String) As SFile
|
||||||
Return New SFile(URL)
|
Return New SFile(URL)
|
||||||
End Function
|
End Function
|
||||||
|
Protected Overridable Function SimpleDownloadAvatar(ByVal ImageAddress As String, Optional ByVal FileCreateFunc As Func(Of String, SFile) = Nothing,
|
||||||
|
Optional ByVal e As ErrorsDescriber = Nothing) As SFile
|
||||||
|
Try
|
||||||
|
If Not ImageAddress.IsEmptyString Then
|
||||||
|
Dim f As SFile
|
||||||
|
If FileCreateFunc Is Nothing Then
|
||||||
|
f = CreateFileFromUrl(ImageAddress)
|
||||||
|
Else
|
||||||
|
f = FileCreateFunc.Invoke(ImageAddress)
|
||||||
|
End If
|
||||||
|
If Not f.Name.IsEmptyString Then f.Name = f.Name.StringRemoveWinForbiddenSymbols.StringTrim
|
||||||
|
If Not f.Name.IsEmptyString Then
|
||||||
|
f.Path = DownloadContentDefault_GetRootDir()
|
||||||
|
f.Separator = "\"
|
||||||
|
If f.Extension.IsEmptyString Then f.Extension = "jpg"
|
||||||
|
If Not f.Exists Then GetWebFile(ImageAddress, f, EDP.ReturnValue)
|
||||||
|
If f.Exists Then IconBannerDownloaded = True : Return f
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Return Nothing
|
||||||
|
Catch ex As Exception
|
||||||
|
If Not e.Exists Then e = New ErrorsDescriber(EDP.ReturnValue)
|
||||||
|
Return ErrorsDescriber.Execute(e, ex, $"SimpleDownloadAvatar({ImageAddress})", New SFile)
|
||||||
|
End Try
|
||||||
|
End Function
|
||||||
Protected Overridable Function ChangeFileNameByProvider(ByVal f As SFile, ByVal m As UserMedia) As SFile
|
Protected Overridable Function ChangeFileNameByProvider(ByVal f As SFile, ByVal m As UserMedia) As SFile
|
||||||
Dim ff As SFile = Nothing
|
Dim ff As SFile = Nothing
|
||||||
Try
|
Try
|
||||||
@@ -1912,13 +2068,14 @@ BlockNullPicture:
|
|||||||
If m.Contains(IUserData.EraseMode.History) Then
|
If m.Contains(IUserData.EraseMode.History) Then
|
||||||
If MyFilePosts.Delete(SFO.File, SFODelete.DeleteToRecycleBin, e) Then result = True
|
If MyFilePosts.Delete(SFO.File, SFODelete.DeleteToRecycleBin, e) Then result = True
|
||||||
If MyFileData.Delete(SFO.File, SFODelete.DeleteToRecycleBin, e) Then result = True
|
If MyFileData.Delete(SFO.File, SFODelete.DeleteToRecycleBin, e) Then result = True
|
||||||
|
If MyMD5File.Delete(SFO.File, SFODelete.DeleteToRecycleBin, e) Then result = True
|
||||||
LastUpdated = Nothing
|
LastUpdated = Nothing
|
||||||
EraseData_AdditionalDataFiles()
|
EraseData_AdditionalDataFiles()
|
||||||
UpdateUserInformation()
|
UpdateUserInformation()
|
||||||
End If
|
End If
|
||||||
If m.Contains(IUserData.EraseMode.Data) Then
|
If m.Contains(IUserData.EraseMode.Data) Then
|
||||||
Dim files As List(Of SFile) = SFile.GetFiles(DownloadContentDefault_GetRootDir.CSFileP,, SearchOption.AllDirectories, e)
|
Dim files As List(Of SFile) = SFile.GetFiles(DownloadContentDefault_GetRootDir.CSFileP,, SearchOption.AllDirectories, e)
|
||||||
If files.ListExists Then files.RemoveAll(Function(f) Not f.Extension.IsEmptyString AndAlso (f.Extension = "txt" Or f.Extension = "xml"))
|
If files.ListExists Then files.RemoveAll(Function(f) Not f.Extension.IsEmptyString AndAlso ((f.Path.EndsWith(SettingsFolderName) And f.Extension = "txt") Or f.Extension = "xml"))
|
||||||
If files.ListExists Then files.ForEach(Sub(f) f.Delete(SFO.File, Settings.DeleteMode, e))
|
If files.ListExists Then files.ForEach(Sub(f) f.Delete(SFO.File, Settings.DeleteMode, e))
|
||||||
LatestData.Clear()
|
LatestData.Clear()
|
||||||
result = True
|
result = True
|
||||||
@@ -1928,6 +2085,8 @@ BlockNullPicture:
|
|||||||
_TempMediaList.Clear()
|
_TempMediaList.Clear()
|
||||||
_ContentNew.Clear()
|
_ContentNew.Clear()
|
||||||
_ContentList.Clear()
|
_ContentList.Clear()
|
||||||
|
_MD5List.Clear()
|
||||||
|
_MD5Loaded = False
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
@@ -2129,6 +2288,7 @@ BlockNullPicture:
|
|||||||
End Function
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Errors functions"
|
#Region "Errors functions"
|
||||||
|
''' <summary>ToStringForLog(): Message</summary>
|
||||||
Protected Sub LogError(ByVal ex As Exception, ByVal Message As String, Optional ByVal e As ErrorsDescriber = Nothing)
|
Protected Sub LogError(ByVal ex As Exception, ByVal Message As String, Optional ByVal e As ErrorsDescriber = Nothing)
|
||||||
ErrorsDescriber.Execute(If(e.Exists, e, New ErrorsDescriber(EDP.SendToLog)), ex, $"{ToStringForLog()}: {Message}")
|
ErrorsDescriber.Execute(If(e.Exists, e, New ErrorsDescriber(EDP.SendToLog)), ex, $"{ToStringForLog()}: {Message}")
|
||||||
End Sub
|
End Sub
|
||||||
@@ -2159,6 +2319,17 @@ BlockNullPicture:
|
|||||||
Friend Function ToStringForLog() As String
|
Friend Function ToStringForLog() As String
|
||||||
Return $"{IIf(IncludedInCollection, $"[{CollectionName}] - ", String.Empty)}[{Site}] - {Name}"
|
Return $"{IIf(IncludedInCollection, $"[{CollectionName}] - ", String.Empty)}[{Site}] - {Name}"
|
||||||
End Function
|
End Function
|
||||||
|
Friend Overloads Function ToStringExt(ByVal UseFriendlyName As Boolean) As String
|
||||||
|
Return $"{IIf(IncludedInCollection, $"[{CollectionName}] - ", String.Empty)}[{Site}] - {String.Format(CStr(IIf(Not FriendlyName.IsEmptyString And
|
||||||
|
UseFriendlyName, "{1} ({0})", "{0}")), Name, FriendlyName)}"
|
||||||
|
End Function
|
||||||
|
Friend Overloads Shared Function ToStringExt(ByVal User As UserInfo) As String
|
||||||
|
If Not IsDBNull(User) Then
|
||||||
|
With User : Return $"{IIf(.IncludedInCollection, $"[{ .CollectionName}] - ", String.Empty)}[{ .Site}] - { .Name}" : End With
|
||||||
|
Else
|
||||||
|
Return String.Empty
|
||||||
|
End If
|
||||||
|
End Function
|
||||||
Public Overrides Function ToString() As String
|
Public Overrides Function ToString() As String
|
||||||
If IsCollection Then
|
If IsCollection Then
|
||||||
Return CollectionName
|
Return CollectionName
|
||||||
@@ -2180,6 +2351,12 @@ BlockNullPicture:
|
|||||||
Private Sub BTT_CONTEXT_DOWN_KeyClick(sender As Object, e As MyKeyEventArgs) Handles BTT_CONTEXT_DOWN.KeyClick
|
Private Sub BTT_CONTEXT_DOWN_KeyClick(sender As Object, e As MyKeyEventArgs) Handles BTT_CONTEXT_DOWN.KeyClick
|
||||||
Downloader.Add(Me, e.IncludeInTheFeed)
|
Downloader.Add(Me, e.IncludeInTheFeed)
|
||||||
End Sub
|
End Sub
|
||||||
|
Private Sub BTT_CONTEXT_DOWN_LIMIT_KeyClick(sender As Object, e As MyKeyEventArgs) Handles BTT_CONTEXT_DOWN_LIMIT.KeyClick
|
||||||
|
ControlInvokeFast(MainFrameObj.MF, Sub() MainFrameObj.MF.DownloadSelectedUser(MainFrame.DownUserLimits.Number, e.IncludeInTheFeed, Me), EDP.SendToLog)
|
||||||
|
End Sub
|
||||||
|
Private Sub BTT_CONTEXT_DOWN_DATE_KeyClick(sender As Object, e As MyKeyEventArgs) Handles BTT_CONTEXT_DOWN_DATE.KeyClick
|
||||||
|
ControlInvokeFast(MainFrameObj.MF, Sub() MainFrameObj.MF.DownloadSelectedUser(MainFrame.DownUserLimits.Date, e.IncludeInTheFeed, Me), EDP.SendToLog)
|
||||||
|
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)
|
||||||
f.ShowDialog()
|
f.ShowDialog()
|
||||||
@@ -2260,6 +2437,8 @@ BlockNullPicture:
|
|||||||
If Not ProgressPre Is Nothing Then ProgressPre.Reset() : ProgressPre.Dispose()
|
If Not ProgressPre Is Nothing Then ProgressPre.Reset() : ProgressPre.Dispose()
|
||||||
If Not Responser Is Nothing Then Responser.Dispose()
|
If Not Responser Is Nothing Then Responser.Dispose()
|
||||||
If Not BTT_CONTEXT_DOWN Is Nothing Then BTT_CONTEXT_DOWN.Dispose()
|
If Not BTT_CONTEXT_DOWN Is Nothing Then BTT_CONTEXT_DOWN.Dispose()
|
||||||
|
If Not BTT_CONTEXT_DOWN_LIMIT Is Nothing Then BTT_CONTEXT_DOWN_LIMIT.Dispose()
|
||||||
|
If Not BTT_CONTEXT_DOWN_DATE Is Nothing Then BTT_CONTEXT_DOWN_DATE.Dispose()
|
||||||
If Not BTT_CONTEXT_EDIT Is Nothing Then BTT_CONTEXT_EDIT.Dispose()
|
If Not BTT_CONTEXT_EDIT Is Nothing Then BTT_CONTEXT_EDIT.Dispose()
|
||||||
If Not BTT_CONTEXT_DELETE Is Nothing Then BTT_CONTEXT_DELETE.Dispose()
|
If Not BTT_CONTEXT_DELETE Is Nothing Then BTT_CONTEXT_DELETE.Dispose()
|
||||||
If Not BTT_CONTEXT_ERASE Is Nothing Then BTT_CONTEXT_ERASE.Dispose()
|
If Not BTT_CONTEXT_ERASE Is Nothing Then BTT_CONTEXT_ERASE.Dispose()
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ Namespace API.Base
|
|||||||
m.GetMemberCustomAttributes(Of Provider).ListExists
|
m.GetMemberCustomAttributes(Of Provider).ListExists
|
||||||
Dim m1 As MemberInfo, m2 As MemberInfo
|
Dim m1 As MemberInfo, m2 As MemberInfo
|
||||||
Dim tmpObj As Object
|
Dim tmpObj As Object
|
||||||
|
Dim maxOffset%
|
||||||
|
|
||||||
members = GetObjectMembers(MyObject, Function(m) (m.MemberType = MemberTypes.Field Or m.MemberType = MemberTypes.Property) AndAlso
|
members = GetObjectMembers(MyObject, Function(m) (m.MemberType = MemberTypes.Field Or m.MemberType = MemberTypes.Property) AndAlso
|
||||||
Not m.GetCustomAttribute(Of PSettingAttribute) Is Nothing,, True,
|
Not m.GetCustomAttribute(Of PSettingAttribute) Is Nothing,, True,
|
||||||
@@ -175,6 +176,9 @@ Namespace API.Base
|
|||||||
|
|
||||||
If MyMembers.Count > 0 Then
|
If MyMembers.Count > 0 Then
|
||||||
|
|
||||||
|
maxOffset = MyMembers.Max(Function(mm) mm.LeftOffset)
|
||||||
|
If maxOffset > 0 Then MyMembers.ForEach(Sub(mm) mm.LeftOffset = maxOffset)
|
||||||
|
|
||||||
Dim prov As IEnumerable(Of Provider)
|
Dim prov As IEnumerable(Of Provider)
|
||||||
Dim _prov As Provider
|
Dim _prov As Provider
|
||||||
Dim si% = -1
|
Dim si% = -1
|
||||||
|
|||||||
18
SCrawler/API/Bluesky/Declarations.vb
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
' Copyright (C) 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.Bluesky
|
||||||
|
Friend Module Declarations
|
||||||
|
Friend Const BlueskySiteKey As String = "AndyProgram_Bluesky"
|
||||||
|
Friend ReadOnly DateProvider As New ADateTime("yyyy-MM-ddTHH:mm:ss.FFF%K")
|
||||||
|
Friend ReadOnly RegEx_PlayLists As RParams = RParams.DM("RESOLUTION=\d+x(\d+)\s*(\S+)", 0, RegexReturn.List, EDP.ReturnValue)
|
||||||
|
Friend ReadOnly RegEx_FilePattern As RParams = RParams.DM("(.+?)(\.|@)(gif|m3u8|[^/\?\&]+)", 0, RegexReturn.ListByMatch, EDP.ReturnValue)
|
||||||
|
Friend ReadOnly RegEx_SinglePostPattern As RParams = RParams.DM("profile/([^/]+)/post/([^/\?\&]+)", 0, RegexReturn.ListByMatch, EDP.ReturnValue)
|
||||||
|
End Module
|
||||||
|
End Namespace
|
||||||
51
SCrawler/API/Bluesky/M3U8.vb
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
' Copyright (C) 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.Forms.Toolbars
|
||||||
|
Imports PersonalUtilities.Tools.Web.Clients
|
||||||
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
|
Namespace API.Bluesky
|
||||||
|
Friend NotInheritable Class M3U8
|
||||||
|
Private Sub New()
|
||||||
|
End Sub
|
||||||
|
Private Shared Function GetUrlsList(ByVal URL As String) As List(Of String)
|
||||||
|
Using resp As New Responser With {.AllowAutoRedirect = False}
|
||||||
|
Dim r$ = resp.GetResponse(URL)
|
||||||
|
If Not r.IsEmptyString Then
|
||||||
|
Dim file$ = String.Empty, appender$
|
||||||
|
Dim files As List(Of Sizes) = RegexFields(Of Sizes)(r, {RegEx_PlayLists}, {1, 2})
|
||||||
|
If files.ListExists Then files.RemoveAll(Function(ff) ff.Value = 0 Or ff.Data.IsEmptyString)
|
||||||
|
If files.ListExists Then
|
||||||
|
files.Sort()
|
||||||
|
file = files(0).Data
|
||||||
|
appender = URL.Replace(URL.Split("/").Last, String.Empty)
|
||||||
|
file = M3U8Base.CreateUrl(appender, file)
|
||||||
|
If Not file.IsEmptyString Then
|
||||||
|
r = resp.GetResponse(file)
|
||||||
|
If Not r.IsEmptyString Then
|
||||||
|
Dim l As List(Of String) = RegexReplace(r, M3U8Declarations.TsFilesRegEx)
|
||||||
|
If l.ListExists Then
|
||||||
|
appender = file.Replace(file.Split("/").Last, String.Empty)
|
||||||
|
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
|
||||||
|
End Using
|
||||||
|
Return Nothing
|
||||||
|
End Function
|
||||||
|
Friend Shared Function Download(ByVal URL As String, ByVal Destination As SFile, ByVal Token As CancellationToken,
|
||||||
|
ByVal Progress As MyProgress, ByVal UsePreProgress As Boolean) As SFile
|
||||||
|
Return M3U8Base.Download(GetUrlsList(URL), Destination,, Token, Progress, UsePreProgress)
|
||||||
|
End Function
|
||||||
|
End Class
|
||||||
|
End Namespace
|
||||||
100
SCrawler/API/Bluesky/SiteSettings.vb
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
' Copyright (C) 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.XML
|
||||||
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
|
Imports PersonalUtilities.Tools.Web.Clients
|
||||||
|
Imports PersonalUtilities.Tools.Web.Documents.JSON
|
||||||
|
Namespace API.Bluesky
|
||||||
|
<Manifest(BlueskySiteKey), SpecialForm(False)>
|
||||||
|
Friend Class SiteSettings : Inherits SiteSettingsBase
|
||||||
|
<PropertyOption(ControlText:="Cookies enabled", ControlToolTip:="If checked, cookies will be used in requests", IsAuth:=True), PXML, PClonable, HiddenControl>
|
||||||
|
Friend ReadOnly Property CookiesEnabled As PropertyValue
|
||||||
|
<PropertyOption(ControlText:="User name", IsAuth:=True, AllowNull:=False), PXML>
|
||||||
|
Friend ReadOnly Property UserHandle As PropertyValue
|
||||||
|
<PropertyOption(ControlText:="Password", IsAuth:=True, AllowNull:=False), PXML>
|
||||||
|
Friend ReadOnly Property UserPassword As PropertyValue
|
||||||
|
<PXML> Friend ReadOnly Property Token As PropertyValue
|
||||||
|
<PXML> Friend ReadOnly Property TokenUpdateTime As PropertyValue
|
||||||
|
<PropertyOption(ControlText:="Token update", ControlToolTip:="Token refresh interval (in minutes)." & vbCr & "Default: 120.", IsAuth:=True), PXML, PClonable, HiddenControl>
|
||||||
|
Friend ReadOnly Property TokenRefreshInterval As PropertyValue
|
||||||
|
Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean)
|
||||||
|
MyBase.New("Bluesky", "bsky.app", AccName, Temp, My.Resources.SiteResources.BlueskyIcon_32, My.Resources.SiteResources.BlueskyPic_32)
|
||||||
|
|
||||||
|
Responser.ContentType = "application/json"
|
||||||
|
|
||||||
|
CookiesEnabled = New PropertyValue(False)
|
||||||
|
UserHandle = New PropertyValue(String.Empty, GetType(String))
|
||||||
|
UserPassword = New PropertyValue(String.Empty, GetType(String))
|
||||||
|
Token = New PropertyValue(String.Empty, GetType(String))
|
||||||
|
TokenUpdateTime = New PropertyValue(Now.AddYears(-1))
|
||||||
|
TokenRefreshInterval = New PropertyValue(120)
|
||||||
|
|
||||||
|
_AllowUserAgentUpdate = False
|
||||||
|
UrlPatternUser = "https://bsky.app/profile/{0}"
|
||||||
|
ImageVideoContains = "bsky.app"
|
||||||
|
UserRegex = RParams.DMS("bsky.app/profile/([^/\?]+)", 1, EDP.ReturnValue)
|
||||||
|
UserOptionsType = GetType(EditorExchangeOptionsBase)
|
||||||
|
End Sub
|
||||||
|
Protected Overrides Function UserOptionsValid(ByVal Options As Object) As Boolean
|
||||||
|
Return DirectCast(Options, EditorExchangeOptionsBase).SiteKey = BlueskySiteKey
|
||||||
|
End Function
|
||||||
|
Protected Overrides Sub UserOptionsSetParameters(ByRef Options As Object)
|
||||||
|
DirectCast(Options, EditorExchangeOptionsBase).SiteKey = BlueskySiteKey
|
||||||
|
End Sub
|
||||||
|
Friend Overrides Function GetInstance(ByVal What As ISiteSettings.Download) As IPluginContentProvider
|
||||||
|
Return New UserData
|
||||||
|
End Function
|
||||||
|
Friend Overrides Function BaseAuthExists() As Boolean
|
||||||
|
Return Not CStr(UserHandle.Value).IsEmptyString And Not CStr(UserPassword.Value).IsEmptyString
|
||||||
|
End Function
|
||||||
|
Friend Overrides Function Available(ByVal What As ISiteSettings.Download, ByVal Silent As Boolean) As Boolean
|
||||||
|
Return MyBase.Available(What, Silent) AndAlso UpdateToken()
|
||||||
|
End Function
|
||||||
|
Private _TokenUpdating As Boolean = False
|
||||||
|
Friend Function UpdateToken(Optional ByVal Force As Boolean = False) As Boolean
|
||||||
|
Try
|
||||||
|
While _TokenUpdating : Threading.Thread.Sleep(100) : End While
|
||||||
|
_TokenUpdating = True
|
||||||
|
If BaseAuthExists() Then
|
||||||
|
If CDate(TokenUpdateTime.Value).AddMinutes(TokenRefreshInterval.Value) < Now Or Force Then
|
||||||
|
Using resp As Responser = Responser.Copy
|
||||||
|
With resp
|
||||||
|
.Mode = Responser.Modes.Curl
|
||||||
|
.Method = "POST"
|
||||||
|
.CurlSslNoRevoke = True
|
||||||
|
.CurlInsecure = True
|
||||||
|
.CurlArgumentsLeft = "-d ""{\" & $"""identifier\"": \""{UserHandle.Value}\"", \""password\"": \""{UserPassword.Value}\""" & "}"""
|
||||||
|
|
||||||
|
Dim r$ = .GetResponse("https://bsky.social/xrpc/com.atproto.server.createSession")
|
||||||
|
If Not r.IsEmptyString Then
|
||||||
|
Using j As EContainer = JsonDocument.Parse(r, EDP.ReturnValue)
|
||||||
|
If j.ListExists Then
|
||||||
|
Dim t$ = j.Value("accessJwt")
|
||||||
|
If Not t.IsEmptyString Then Token.Value = $"Bearer {t}" : TokenUpdateTime.Value = Now : Return True
|
||||||
|
End If
|
||||||
|
End Using
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
End Using
|
||||||
|
Else
|
||||||
|
Return True
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Return False
|
||||||
|
Catch ex As Exception
|
||||||
|
Return ErrorsDescriber.Execute(EDP.SendToLog + EDP.ReturnValue, ex, "Bluesky.SiteSettings.UpdateToken", False)
|
||||||
|
Finally
|
||||||
|
_TokenUpdating = False
|
||||||
|
End Try
|
||||||
|
End Function
|
||||||
|
End Class
|
||||||
|
End Namespace
|
||||||
363
SCrawler/API/Bluesky/UserData.vb
Normal file
@@ -0,0 +1,363 @@
|
|||||||
|
' Copyright (C) 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 SCrawler.API.YouTube.Objects
|
||||||
|
Imports PersonalUtilities.Functions.XML
|
||||||
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
|
Imports PersonalUtilities.Tools.Web.Documents.JSON
|
||||||
|
Imports UTypes = SCrawler.API.Base.UserMedia.Types
|
||||||
|
Imports UStates = SCrawler.API.Base.UserMedia.States
|
||||||
|
Namespace API.Bluesky
|
||||||
|
Friend Class UserData : Inherits UserDataBase
|
||||||
|
#Region "Declarations"
|
||||||
|
Private ReadOnly Property MySettings As SiteSettings
|
||||||
|
Get
|
||||||
|
Return HOST.Source
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
Private ReadOnly Property ID_Encoded As String
|
||||||
|
Get
|
||||||
|
Return If(ID.IsEmptyString, String.Empty, SymbolsConverter.ASCII.EncodeSymbolsOnly(ID))
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
Private ReadOnly _TmpPosts2 As List(Of String)
|
||||||
|
#End Region
|
||||||
|
#Region "Loader"
|
||||||
|
Protected Overrides Sub LoadUserInformation_OptionalFields(ByRef Container As XmlFile, ByVal Loading As Boolean)
|
||||||
|
End Sub
|
||||||
|
Friend Overrides Function ExchangeOptionsGet() As Object
|
||||||
|
Return New EditorExchangeOptionsBase(Me) With {.SiteKey = BlueskySiteKey}
|
||||||
|
End Function
|
||||||
|
Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object)
|
||||||
|
If Not Obj Is Nothing AndAlso TypeOf Obj Is EditorExchangeOptionsBase AndAlso
|
||||||
|
DirectCast(Obj, EditorExchangeOptionsBase).SiteKey = BlueskySiteKey Then DirectCast(Obj, EditorExchangeOptionsBase).ApplyBase(Me)
|
||||||
|
End Sub
|
||||||
|
#End Region
|
||||||
|
#Region "Initializer"
|
||||||
|
Friend Sub New()
|
||||||
|
UseInternalM3U8Function = True
|
||||||
|
_TmpPosts2 = New List(Of String)
|
||||||
|
End Sub
|
||||||
|
#End Region
|
||||||
|
#Region "Token"
|
||||||
|
Private Function UpdateToken(Optional ByVal Force As Boolean = False, Optional ByVal OnlyAddHeader As Boolean = False) As Boolean
|
||||||
|
Dim process As Boolean = True
|
||||||
|
If CDate(MySettings.TokenUpdateTime.Value).AddHours(2) <= Now Or Force Then
|
||||||
|
process = MySettings.UpdateToken(Force)
|
||||||
|
If process Then _TokenUpdateCount += 1
|
||||||
|
End If
|
||||||
|
If process Or OnlyAddHeader Then Responser.Headers.Add("authorization", MySettings.Token.Value)
|
||||||
|
Return Not Responser.Headers.Value("authorization").IsEmptyString
|
||||||
|
End Function
|
||||||
|
Private _TokenUpdateCount As Integer = 0
|
||||||
|
Private Sub TokenUpdateCountReset()
|
||||||
|
_TokenUpdateCount = 0
|
||||||
|
End Sub
|
||||||
|
#End Region
|
||||||
|
#Region "Download"
|
||||||
|
Private _PostCount As Integer = 0
|
||||||
|
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
|
||||||
|
_TmpPosts2.Clear()
|
||||||
|
Try
|
||||||
|
If Not CBool(MySettings.CookiesEnabled.Value) Then Responser.Cookies.Clear()
|
||||||
|
UpdateToken(, True)
|
||||||
|
_TokenUpdateCount = 0
|
||||||
|
_PostCount = 0
|
||||||
|
DownloadData(String.Empty, Token)
|
||||||
|
Finally
|
||||||
|
_TempPostsList.ListAddList(_TmpPosts2, LNC)
|
||||||
|
_TmpPosts2.Clear()
|
||||||
|
End Try
|
||||||
|
End Sub
|
||||||
|
Private Overloads Sub DownloadData(ByVal Cursor As String, ByVal Token As CancellationToken)
|
||||||
|
Dim URL$ = String.Empty
|
||||||
|
Try
|
||||||
|
If ID.IsEmptyString Then GetProfileInfo(Token)
|
||||||
|
If ID.IsEmptyString Then Throw New ArgumentNullException("ID", "ID is null")
|
||||||
|
If UpdateToken() Then
|
||||||
|
Dim nextCursor$ = String.Empty
|
||||||
|
Dim c%
|
||||||
|
URL = $"https://bsky.social/xrpc/app.bsky.feed.getAuthorFeed?actor={ID_Encoded}&filter=posts_and_author_threads&includePins=false&limit=99"
|
||||||
|
If Not Cursor.IsEmptyString Then URL &= $"&cursor={SymbolsConverter.ASCII.EncodeSymbolsOnly(Cursor)}"
|
||||||
|
Dim r$ = Responser.GetResponse(URL)
|
||||||
|
TokenUpdateCountReset()
|
||||||
|
If Not r.IsEmptyString Then
|
||||||
|
Using j As EContainer = JsonDocument.Parse(r)
|
||||||
|
If j.ListExists Then
|
||||||
|
With j("feed")
|
||||||
|
If .ListExists Then
|
||||||
|
For Each post As EContainer In .Self
|
||||||
|
With post({"post"})
|
||||||
|
c = DefaultParser(.Self,, nextCursor)
|
||||||
|
Select Case c
|
||||||
|
Case CInt(DateResult.Skip) * -1 : Continue For
|
||||||
|
Case CInt(DateResult.Exit) * -1 : Exit Sub
|
||||||
|
Case Is > 0 : _PostCount += c
|
||||||
|
End Select
|
||||||
|
If DownloadTopCount.HasValue AndAlso DownloadTopCount.Value <= _PostCount Then Exit Sub
|
||||||
|
End With
|
||||||
|
Next
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
End If
|
||||||
|
End Using
|
||||||
|
|
||||||
|
If Not nextCursor.IsEmptyString Then DownloadData(nextCursor, Token)
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Catch ex As Exception
|
||||||
|
ProcessException(ex, Token, $"DownloadData({URL})")
|
||||||
|
End Try
|
||||||
|
End Sub
|
||||||
|
#End Region
|
||||||
|
#Region "DefaultParser"
|
||||||
|
Private Const Down_ImageAddress As String = "https://cdn.bsky.app/img/feed_fullsize/plain/{0}/{1}"
|
||||||
|
Private Function GetPostID(ByVal PostUri As String) As String
|
||||||
|
Return If(PostUri.IsEmptyString, String.Empty, PostUri.Split("/").LastOrDefault)
|
||||||
|
End Function
|
||||||
|
Private Function DefaultParser(ByVal e As EContainer, Optional ByVal CheckDateLimits As Boolean = True, Optional ByRef NextCursor As String = Nothing,
|
||||||
|
Optional ByVal CheckTempPosts As Boolean = True, Optional ByVal State As UStates = UStates.Unknown) As Integer
|
||||||
|
Const exitReturn% = CInt(DateResult.Exit) * -1
|
||||||
|
Const skipReturn% = CInt(DateResult.Skip) * -1
|
||||||
|
Dim postID$, postDate$, __url$, __urlBase$, __txt$, __userId$
|
||||||
|
Dim updateUrl As Boolean
|
||||||
|
Dim c% = 0
|
||||||
|
Dim m As UserMedia
|
||||||
|
Dim d As EContainer
|
||||||
|
With e
|
||||||
|
If .ListExists Then
|
||||||
|
postID = GetPostID(.Value("uri"))
|
||||||
|
postDate = String.Empty
|
||||||
|
__urlBase = String.Empty
|
||||||
|
__txt = String.Empty
|
||||||
|
__userId = .Value({"author"}, "did")
|
||||||
|
With .Item({"record"})
|
||||||
|
If .ListExists Then
|
||||||
|
'2025-01-28T02:42:12.415Z
|
||||||
|
postDate = .Value("createdAt")
|
||||||
|
NextCursor = postDate
|
||||||
|
If CheckDateLimits Then
|
||||||
|
Select Case CheckDatesLimit(postDate, DateProvider)
|
||||||
|
Case DateResult.Skip : Return skipReturn 'Continue For
|
||||||
|
Case DateResult.Exit : Return exitReturn 'Exit Sub
|
||||||
|
End Select
|
||||||
|
End If
|
||||||
|
|
||||||
|
If CheckTempPosts Then
|
||||||
|
'If _TempPostsList.Contains(postID) Then Return exitReturn Else _TempPostsList.Add(postID)
|
||||||
|
If _TempPostsList.Contains(postID) Then Return exitReturn Else _TmpPosts2.Add(postID)
|
||||||
|
End If
|
||||||
|
|
||||||
|
If ParseUserMediaOnly And Not ID.IsEmptyString And Not __userId.IsEmptyString And Not ID = __userId Then Return skipReturn
|
||||||
|
|
||||||
|
__urlBase = $"https://bsky.app/profile/{NameTrue}/post/{postID}"
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
|
||||||
|
Dim createMedia As Func(Of String, UTypes, UserMedia) =
|
||||||
|
Function(ByVal url As String, ByVal type As UTypes) As UserMedia
|
||||||
|
m = New UserMedia(url, type) With {
|
||||||
|
.URL_BASE = __urlBase,
|
||||||
|
.File = CreateFileFromUrl(url, type),
|
||||||
|
.Post = New UserPost(postID, If(AConvert(Of Date)(postDate, DateProvider, Nothing, EDP.ReturnValue), Nothing)),
|
||||||
|
.State = State,
|
||||||
|
.PostText = __txt,
|
||||||
|
.PostTextFileSpecialFolder = DownloadTextSpecialFolder
|
||||||
|
}
|
||||||
|
If type = UTypes.Text Then m.PostTextFile = $"{postID}.txt"
|
||||||
|
_TempMediaList.ListAddValue(m, LNC)
|
||||||
|
c += 1
|
||||||
|
Return m
|
||||||
|
End Function
|
||||||
|
|
||||||
|
__txt = .Value({"record"}, "text").IfNullOrEmpty(__txt)
|
||||||
|
|
||||||
|
For Each SecondExtraction As Boolean In {False, True}
|
||||||
|
With If(SecondExtraction, .Item({"record", "embed"}), .Item("embed"))
|
||||||
|
If .ListExists Then
|
||||||
|
|
||||||
|
If If(.Item("images")?.Count, 0) > 0 Then
|
||||||
|
With .Item("images")
|
||||||
|
For Each d In .Self
|
||||||
|
updateUrl = False
|
||||||
|
__url = d.Value("fullsize")
|
||||||
|
If __url.IsEmptyString Then __url = d.Value({"image", "ref"}, "$link") : updateUrl = True
|
||||||
|
If __url.IsEmptyString And SecondExtraction Then updateUrl = False : __url = e.Value({"embed"}, "thumb")
|
||||||
|
If Not __url.IsEmptyString Then createMedia(__url, UTypes.Picture)
|
||||||
|
Next
|
||||||
|
End With
|
||||||
|
End If
|
||||||
|
|
||||||
|
If Not .Value("playlist").IsEmptyString Then createMedia(.Value("playlist"), UTypes.m3u8)
|
||||||
|
|
||||||
|
If If(.Item("external")?.Count, 0) > 0 Then
|
||||||
|
__txt = .Value({"external"}, "title").IfNullOrEmpty(__txt)
|
||||||
|
createMedia(.Value({"external"}, "uri"), UTypes.GIF)
|
||||||
|
End If
|
||||||
|
|
||||||
|
If If(.Item({"media"}, "external")?.Count, 0) > 0 Then
|
||||||
|
__txt = .Value({"media", "external"}, "title").IfNullOrEmpty(__txt)
|
||||||
|
createMedia(.Value({"media", "external"}, "uri"), UTypes.GIF)
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
|
||||||
|
If c > 0 Then Exit For
|
||||||
|
Next
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
Return c
|
||||||
|
End Function
|
||||||
|
#End Region
|
||||||
|
#Region "GetProfileInfo"
|
||||||
|
Private Sub GetProfileInfo(ByVal Token As CancellationToken)
|
||||||
|
Try
|
||||||
|
If UpdateToken() Then
|
||||||
|
Dim r$ = Responser.GetResponse($"https://bsky.social/xrpc/app.bsky.actor.getProfile?actor={ID.IfNullOrEmpty(NameTrue)}")
|
||||||
|
TokenUpdateCountReset()
|
||||||
|
If Not r.IsEmptyString Then
|
||||||
|
Using j As EContainer = JsonDocument.Parse(r)
|
||||||
|
If j.ListExists Then
|
||||||
|
ID = j.Value("did")
|
||||||
|
UserSiteNameUpdate(j.Value("displayName"))
|
||||||
|
UserDescriptionUpdate(j.Value("description"))
|
||||||
|
NameTrue = j.Value("handle")
|
||||||
|
SimpleDownloadAvatar(j.Value("avatar"))
|
||||||
|
SimpleDownloadAvatar(j.Value("banner"))
|
||||||
|
End If
|
||||||
|
End Using
|
||||||
|
End If
|
||||||
|
Else
|
||||||
|
Throw New ArgumentException("Token is null", "Token")
|
||||||
|
End If
|
||||||
|
Catch ex As Exception
|
||||||
|
ProcessException(ex, Token, "GetProfileInfo")
|
||||||
|
End Try
|
||||||
|
End Sub
|
||||||
|
#End Region
|
||||||
|
#Region "ReparseMissing"
|
||||||
|
Protected Overrides Sub ReparseMissing(ByVal Token As CancellationToken)
|
||||||
|
Const uriPattern$ = "at://{0}/app.bsky.feed.post/{1}"
|
||||||
|
Dim rList As New List(Of Integer)
|
||||||
|
Try
|
||||||
|
If ContentMissingExists AndAlso UpdateToken() Then
|
||||||
|
Dim r$, url$, uri$
|
||||||
|
Dim tu As Byte
|
||||||
|
Dim m As UserMedia
|
||||||
|
Dim j As EContainer
|
||||||
|
For i% = 0 To _ContentList.Count - 1
|
||||||
|
m = _ContentList(i)
|
||||||
|
If m.State = UStates.Missing Then
|
||||||
|
uri = SymbolsConverter.ASCII.EncodeSymbolsOnly(String.Format(uriPattern, NameTrue, m.Post.ID))
|
||||||
|
url = $"https://bsky.social/xrpc/app.bsky.feed.getPostThread?uri={uri}&depth=10"
|
||||||
|
For tu = 0 To 1
|
||||||
|
Try
|
||||||
|
Responser.ResetStatus()
|
||||||
|
r = Responser.GetResponse(url)
|
||||||
|
TokenUpdateCountReset()
|
||||||
|
If Not r.IsEmptyString Then
|
||||||
|
j = JsonDocument.Parse(r)
|
||||||
|
If j.ListExists Then
|
||||||
|
If DefaultParser(j({"thread", "post"}), False,, False, UStates.Missing) > 0 Then rList.Add(i)
|
||||||
|
j.Dispose()
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Exit For
|
||||||
|
Catch eex As Exception
|
||||||
|
If ProcessException(eex, Token, $"ReparseMissing({url})",,, False) <> 1 Then Throw eex
|
||||||
|
End Try
|
||||||
|
Next
|
||||||
|
End If
|
||||||
|
Next
|
||||||
|
Else
|
||||||
|
Throw New ArgumentException("Token is null", "Token")
|
||||||
|
End If
|
||||||
|
Catch ex As Exception
|
||||||
|
ProcessException(ex, Token, "ReparseMissing 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 "CreateFileFromUrl"
|
||||||
|
Protected Overloads Overrides Function CreateFileFromUrl(ByVal URL As String) As SFile
|
||||||
|
Return CreateFileFromUrl(URL, UTypes.Undefined)
|
||||||
|
End Function
|
||||||
|
Protected Overloads Function CreateFileFromUrl(ByVal URL As String, ByVal Type As UTypes) As SFile
|
||||||
|
Dim f As SFile = MyBase.CreateFileFromUrl(URL)
|
||||||
|
Dim force As Boolean = False
|
||||||
|
f.Separator = "\"
|
||||||
|
With URL.Split("/")
|
||||||
|
If .ListExists Then
|
||||||
|
With DirectCast(RegexReplace(.Last, RegEx_FilePattern), List(Of String))
|
||||||
|
If .ListExists(4) Then
|
||||||
|
f.Name = .Item(1).IfNullOrEmpty(f.Name)
|
||||||
|
f.Extension = .Item(3)
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
If Not f.Extension.IsEmptyString AndAlso f.Extension.ToLower = "m3u8" Then force = True : Type = UTypes.m3u8
|
||||||
|
If f.Extension.IsEmptyString Or force Then
|
||||||
|
Select Case Type
|
||||||
|
Case UTypes.Picture : f.Extension = "jpg"
|
||||||
|
Case UTypes.GIF : f.Extension = "gif"
|
||||||
|
Case UTypes.m3u8 : f.Name = "Video" : f.Extension = "mp4"
|
||||||
|
End Select
|
||||||
|
End If
|
||||||
|
Return f
|
||||||
|
End Function
|
||||||
|
#End Region
|
||||||
|
#Region "DownloadContent"
|
||||||
|
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, ByVal Token As CancellationToken) As SFile
|
||||||
|
Return M3U8.Download(URL, DestinationFile, Token, Progress, Not IsSingleObjectDownload)
|
||||||
|
End Function
|
||||||
|
#End Region
|
||||||
|
#Region "DownloadSingleObject"
|
||||||
|
Protected Overrides Sub DownloadSingleObject_GetPosts(ByVal Data As IYouTubeMediaContainer, ByVal Token As CancellationToken)
|
||||||
|
_TokenUpdateCount = 0
|
||||||
|
UpdateToken()
|
||||||
|
Dim l As List(Of String) = RegexReplace(Data.URL, RegEx_SinglePostPattern)
|
||||||
|
If l.ListExists(3) Then
|
||||||
|
NameTrue = l(1)
|
||||||
|
_ContentList.Add(New UserMedia(Data.URL) With {.State = UStates.Missing, .Post = l(2)})
|
||||||
|
ReparseMissing(Token)
|
||||||
|
End If
|
||||||
|
MyBase.DownloadSingleObject_GetPosts(Data, Token)
|
||||||
|
End Sub
|
||||||
|
#End Region
|
||||||
|
#Region "Exception"
|
||||||
|
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.BadRequest Then '400
|
||||||
|
If _TokenUpdateCount = 0 AndAlso UpdateToken(True) Then
|
||||||
|
Return 1
|
||||||
|
Else
|
||||||
|
Return 0
|
||||||
|
End If
|
||||||
|
Else
|
||||||
|
Return 0
|
||||||
|
End If
|
||||||
|
End Function
|
||||||
|
#End Region
|
||||||
|
#Region "IDisposable Support"
|
||||||
|
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
|
||||||
|
If disposing Then _TmpPosts2.Clear()
|
||||||
|
MyBase.Dispose(disposing)
|
||||||
|
End Sub
|
||||||
|
#End Region
|
||||||
|
End Class
|
||||||
|
End Namespace
|
||||||
@@ -18,6 +18,8 @@ Namespace API.Facebook
|
|||||||
Friend ReadOnly Regex_FileName As RParams = RParams.DM("([^/\?]+\..{3,4})(?=(\?|\Z))", 0, EDP.ReturnValue)
|
Friend ReadOnly Regex_FileName As RParams = RParams.DM("([^/\?]+\..{3,4})(?=(\?|\Z))", 0, EDP.ReturnValue)
|
||||||
Friend ReadOnly Regex_ProfileUrlID As RParams = RParams.DMS("profile.php\?id=(\d+)", 1, EDP.ReturnValue)
|
Friend ReadOnly Regex_ProfileUrlID As RParams = RParams.DMS("profile.php\?id=(\d+)", 1, EDP.ReturnValue)
|
||||||
Friend ReadOnly Regex_VideoPageID As RParams = RParams.DMS("pageid.:.(\d+)", 1, RegexOptions.IgnoreCase, EDP.ReturnValue)
|
Friend ReadOnly Regex_VideoPageID As RParams = RParams.DMS("pageid.:.(\d+)", 1, RegexOptions.IgnoreCase, EDP.ReturnValue)
|
||||||
|
Friend ReadOnly Regex_ReelsPageID As RParams = RParams.DMS("\{[^\}]*""tab_key"":""owner_reels"",?[^\}]*""id"":""([^\}""]+)""", 1, RegexOptions.IgnoreCase, EDP.ReturnValue)
|
||||||
|
Friend ReadOnly Regex_ReelsFilePattern As RParams = RParams.DM("[^/]+\.mp4", 0, EDP.ReturnValue)
|
||||||
Friend ReadOnly Regex_StoryBucket As RParams = RParams.DMS("story_bucket[^\>]*?(\d+)", 1, EDP.ReturnValue)
|
Friend ReadOnly Regex_StoryBucket As RParams = RParams.DMS("story_bucket[^\>]*?(\d+)", 1, EDP.ReturnValue)
|
||||||
|
|
||||||
Friend ReadOnly Regex_VideoIDFromURL As RParams = RParams.DMS("facebook.com/([^/]+/videos/|watch/\D*[\?&]{1}v=)(\d+)", 2, EDP.ReturnValue)
|
Friend ReadOnly Regex_VideoIDFromURL As RParams = RParams.DMS("facebook.com/([^/]+/videos/|watch/\D*[\?&]{1}v=)(\d+)", 2, EDP.ReturnValue)
|
||||||
|
|||||||
@@ -36,8 +36,13 @@ Namespace API.Facebook
|
|||||||
Friend ReadOnly Property ParsePhotoBlock As PropertyValue
|
Friend ReadOnly Property ParsePhotoBlock As PropertyValue
|
||||||
<PropertyOption(ControlText:="Download videos", IsAuth:=False, Category:=DN.CAT_UserDefs), PXML, PClonable>
|
<PropertyOption(ControlText:="Download videos", IsAuth:=False, Category:=DN.CAT_UserDefs), PXML, PClonable>
|
||||||
Friend ReadOnly Property ParseVideoBlock As PropertyValue
|
Friend ReadOnly Property ParseVideoBlock As PropertyValue
|
||||||
|
<PropertyOption(ControlText:="Download reels", IsAuth:=False, Category:=DN.CAT_UserDefs), PXML, PClonable>
|
||||||
|
Friend ReadOnly Property ParseReelsBlock As PropertyValue
|
||||||
<PropertyOption(ControlText:="Download stories", IsAuth:=False, Category:=DN.CAT_UserDefs), PXML, PClonable>
|
<PropertyOption(ControlText:="Download stories", IsAuth:=False, Category:=DN.CAT_UserDefs), PXML, PClonable>
|
||||||
Friend ReadOnly Property ParseStoriesBlock As PropertyValue
|
Friend ReadOnly Property ParseStoriesBlock As PropertyValue
|
||||||
|
<DoNotUse> Friend Overrides Property DownloadText As PropertyValue
|
||||||
|
<DoNotUse> Friend Overrides Property DownloadTextPosts As PropertyValue
|
||||||
|
<DoNotUse> Friend Overrides Property DownloadTextSpecialFolder As PropertyValue
|
||||||
#End Region
|
#End Region
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Initializer"
|
#Region "Initializer"
|
||||||
@@ -52,6 +57,7 @@ Namespace API.Facebook
|
|||||||
Header_Accept = New PropertyValue(String.Empty, GetType(String))
|
Header_Accept = New PropertyValue(String.Empty, GetType(String))
|
||||||
ParsePhotoBlock = New PropertyValue(True)
|
ParsePhotoBlock = New PropertyValue(True)
|
||||||
ParseVideoBlock = New PropertyValue(True)
|
ParseVideoBlock = New PropertyValue(True)
|
||||||
|
ParseReelsBlock = New PropertyValue(False)
|
||||||
ParseStoriesBlock = New PropertyValue(True)
|
ParseStoriesBlock = New PropertyValue(True)
|
||||||
|
|
||||||
UrlPatternUser = "https://www.facebook.com/{0}"
|
UrlPatternUser = "https://www.facebook.com/{0}"
|
||||||
|
|||||||
@@ -23,9 +23,11 @@ Namespace API.Facebook
|
|||||||
Private Const Name_IsNoNameProfile As String = "IsNoNameProfile"
|
Private Const Name_IsNoNameProfile As String = "IsNoNameProfile"
|
||||||
Private Const Name_OptionsParsed As String = "OptionsParsed"
|
Private Const Name_OptionsParsed As String = "OptionsParsed"
|
||||||
Private Const Name_VideoPageID As String = "VideoPageID"
|
Private Const Name_VideoPageID As String = "VideoPageID"
|
||||||
|
Private Const Name_ReelsPageID As String = "ReelsPageID"
|
||||||
Private Const Name_StoryBucket As String = "StoryBucket"
|
Private Const Name_StoryBucket As String = "StoryBucket"
|
||||||
Private Const Name_ParsePhotoBlock As String = "ParsePhotoBlock"
|
Private Const Name_ParsePhotoBlock As String = "ParsePhotoBlock"
|
||||||
Private Const Name_ParseVideoBlock As String = "ParseVideoBlock"
|
Private Const Name_ParseVideoBlock As String = "ParseVideoBlock"
|
||||||
|
Private Const Name_ParseReelsBlock As String = "ParseReelsBlock"
|
||||||
Private Const Name_ParseStoriesBlock As String = "ParseStoriesBlock"
|
Private Const Name_ParseStoriesBlock As String = "ParseStoriesBlock"
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Declarations"
|
#Region "Declarations"
|
||||||
@@ -37,15 +39,18 @@ Namespace API.Facebook
|
|||||||
Private IsNoNameProfile As Boolean = False
|
Private IsNoNameProfile As Boolean = False
|
||||||
Private OptionsParsed As Boolean = False
|
Private OptionsParsed As Boolean = False
|
||||||
Private Property VideoPageID As String = String.Empty
|
Private Property VideoPageID As String = String.Empty
|
||||||
|
Private Property ReelsPageID As String = String.Empty
|
||||||
Private Property StoryBucket As String = String.Empty
|
Private Property StoryBucket As String = String.Empty
|
||||||
Friend Property ParsePhotoBlock As Boolean = True
|
Friend Property ParsePhotoBlock As Boolean = True
|
||||||
Friend Property ParseVideoBlock As Boolean = True
|
Friend Property ParseVideoBlock As Boolean = True
|
||||||
|
Friend Property ParseReelsBlock As Boolean = False
|
||||||
Friend Property ParseStoriesBlock As Boolean = True
|
Friend Property ParseStoriesBlock As Boolean = True
|
||||||
Private Enum PageBlock As Integer
|
Private Enum PageBlock As Integer
|
||||||
Timeline = Sections.Timeline
|
Timeline = Sections.Timeline
|
||||||
Stories = Sections.Stories
|
Stories = Sections.Stories
|
||||||
Photos = 100
|
Photos = 100
|
||||||
Videos = 101
|
Videos = 101
|
||||||
|
Reels = Sections.Reels
|
||||||
Undefined = -1
|
Undefined = -1
|
||||||
End Enum
|
End Enum
|
||||||
#End Region
|
#End Region
|
||||||
@@ -67,6 +72,7 @@ Namespace API.Facebook
|
|||||||
With DirectCast(Obj, UserExchangeOptions)
|
With DirectCast(Obj, UserExchangeOptions)
|
||||||
ParsePhotoBlock = .ParsePhotoBlock
|
ParsePhotoBlock = .ParsePhotoBlock
|
||||||
ParseVideoBlock = .ParseVideoBlock
|
ParseVideoBlock = .ParseVideoBlock
|
||||||
|
ParseReelsBlock = .ParseReelsBlock
|
||||||
ParseStoriesBlock = .ParseStoriesBlock
|
ParseStoriesBlock = .ParseStoriesBlock
|
||||||
End With
|
End With
|
||||||
End If
|
End If
|
||||||
@@ -90,18 +96,22 @@ Namespace API.Facebook
|
|||||||
End If
|
End If
|
||||||
OptionsParsed = .Value(Name_OptionsParsed).FromXML(Of Boolean)(False)
|
OptionsParsed = .Value(Name_OptionsParsed).FromXML(Of Boolean)(False)
|
||||||
VideoPageID = .Value(Name_VideoPageID)
|
VideoPageID = .Value(Name_VideoPageID)
|
||||||
|
ReelsPageID = .Value(Name_ReelsPageID)
|
||||||
StoryBucket = .Value(Name_StoryBucket)
|
StoryBucket = .Value(Name_StoryBucket)
|
||||||
ParsePhotoBlock = .Value(Name_ParsePhotoBlock).FromXML(Of Boolean)(True)
|
ParsePhotoBlock = .Value(Name_ParsePhotoBlock).FromXML(Of Boolean)(True)
|
||||||
ParseVideoBlock = .Value(Name_ParseVideoBlock).FromXML(Of Boolean)(True)
|
ParseVideoBlock = .Value(Name_ParseVideoBlock).FromXML(Of Boolean)(True)
|
||||||
|
ParseReelsBlock = .Value(Name_ParseReelsBlock).FromXML(Of Boolean)(False)
|
||||||
ParseStoriesBlock = .Value(Name_ParseStoriesBlock).FromXML(Of Boolean)(True)
|
ParseStoriesBlock = .Value(Name_ParseStoriesBlock).FromXML(Of Boolean)(True)
|
||||||
Else
|
Else
|
||||||
updateNames.Invoke
|
updateNames.Invoke
|
||||||
.Add(Name_IsNoNameProfile, IsNoNameProfile.BoolToInteger)
|
.Add(Name_IsNoNameProfile, IsNoNameProfile.BoolToInteger)
|
||||||
.Add(Name_OptionsParsed, OptionsParsed.BoolToInteger)
|
.Add(Name_OptionsParsed, OptionsParsed.BoolToInteger)
|
||||||
.Add(Name_VideoPageID, VideoPageID)
|
.Add(Name_VideoPageID, VideoPageID)
|
||||||
|
.Add(Name_ReelsPageID, ReelsPageID)
|
||||||
.Add(Name_StoryBucket, StoryBucket)
|
.Add(Name_StoryBucket, StoryBucket)
|
||||||
.Add(Name_ParsePhotoBlock, ParsePhotoBlock.BoolToInteger)
|
.Add(Name_ParsePhotoBlock, ParsePhotoBlock.BoolToInteger)
|
||||||
.Add(Name_ParseVideoBlock, ParseVideoBlock.BoolToInteger)
|
.Add(Name_ParseVideoBlock, ParseVideoBlock.BoolToInteger)
|
||||||
|
.Add(Name_ParseReelsBlock, ParseReelsBlock.BoolToInteger)
|
||||||
.Add(Name_ParseStoriesBlock, ParseStoriesBlock.BoolToInteger)
|
.Add(Name_ParseStoriesBlock, ParseStoriesBlock.BoolToInteger)
|
||||||
End If
|
End If
|
||||||
End With
|
End With
|
||||||
@@ -146,6 +156,7 @@ Namespace API.Facebook
|
|||||||
Else
|
Else
|
||||||
If DownloadImages And ParsePhotoBlock Then DownloadData_Photo(String.Empty, Token)
|
If DownloadImages And ParsePhotoBlock Then DownloadData_Photo(String.Empty, Token)
|
||||||
If DownloadVideos And ParseVideoBlock Then DownloadData_Video(String.Empty, Token)
|
If DownloadVideos And ParseVideoBlock Then DownloadData_Video(String.Empty, Token)
|
||||||
|
If DownloadVideos And ParseReelsBlock Then DownloadData_Reels(String.Empty, Token)
|
||||||
If (DownloadImages Or DownloadVideos) And ParseStoriesBlock Then DownloadData_Stories(Token)
|
If (DownloadImages Or DownloadVideos) And ParseStoriesBlock Then DownloadData_Stories(Token)
|
||||||
End If
|
End If
|
||||||
LoadSavePostsKV(False)
|
LoadSavePostsKV(False)
|
||||||
@@ -158,10 +169,12 @@ Namespace API.Facebook
|
|||||||
Private Const Header_fb_fr_name_Video As String = "PagesCometChannelTabAllVideosCardImplPaginationQuery"
|
Private Const Header_fb_fr_name_Video As String = "PagesCometChannelTabAllVideosCardImplPaginationQuery"
|
||||||
Private Const Header_fb_fr_name_Stories As String = "StoriesSuspenseContentPaneRootWithEntryPointQuery"
|
Private Const Header_fb_fr_name_Stories As String = "StoriesSuspenseContentPaneRootWithEntryPointQuery"
|
||||||
Private Const Header_fb_fr_name_SavedPosts As String = "CometSaveDashboardAllItemsPaginationQuery"
|
Private Const Header_fb_fr_name_SavedPosts As String = "CometSaveDashboardAllItemsPaginationQuery"
|
||||||
|
Private Const Header_fb_fr_name_Reels As String = "ProfileCometAppCollectionReelsRendererPaginationQuery"
|
||||||
Private Const DocID_Photo As String = "6684543058255697"
|
Private Const DocID_Photo As String = "6684543058255697"
|
||||||
Private Const DocID_Video As String = "24545934291687581"
|
Private Const DocID_Video As String = "24545934291687581"
|
||||||
Private Const DocID_Stories As String = "6771064226315961"
|
Private Const DocID_Stories As String = "6771064226315961"
|
||||||
Private Const DocID_SavedPosts As String = "7112228098805003"
|
Private Const DocID_SavedPosts As String = "7112228098805003"
|
||||||
|
Private Const DocID_Reels As String = "28517740954539304"
|
||||||
Private Const Graphql_UrlPattern As String = "https://www.facebook.com/api/graphql?lsd={0}&doc_id={1}&server_timestamps=true&fb_dtsg={3}&fb_api_req_friendly_name={2}&variables={4}"
|
Private Const Graphql_UrlPattern As String = "https://www.facebook.com/api/graphql?lsd={0}&doc_id={1}&server_timestamps=true&fb_dtsg={3}&fb_api_req_friendly_name={2}&variables={4}"
|
||||||
Private Const VideoHtmlUrlPattern As String = "https://www.facebook.com/watch/?v={0}"
|
Private Const VideoHtmlUrlPattern As String = "https://www.facebook.com/watch/?v={0}"
|
||||||
Private Sub DownloadData_Photo(ByVal Cursor As String, ByVal Token As CancellationToken)
|
Private Sub DownloadData_Photo(ByVal Cursor As String, ByVal Token As CancellationToken)
|
||||||
@@ -238,7 +251,7 @@ Namespace API.Facebook
|
|||||||
Dim newPostsDetected As Boolean = False
|
Dim newPostsDetected As Boolean = False
|
||||||
Dim pid As PostKV
|
Dim pid As PostKV
|
||||||
|
|
||||||
If VideoPageID.IsEmptyString Then GetVideoPageID(Token)
|
If VideoPageID.IsEmptyString Then GetVideoPageID(False, Token)
|
||||||
If VideoPageID.IsEmptyString Then Throw New TokensException("Unable to obtain 'VideoPageID'", False)
|
If VideoPageID.IsEmptyString Then Throw New TokensException("Unable to obtain 'VideoPageID'", False)
|
||||||
ValidateBaseTokens()
|
ValidateBaseTokens()
|
||||||
|
|
||||||
@@ -355,6 +368,123 @@ Namespace API.Facebook
|
|||||||
ProcessException(ex, Token, $"data (stories) downloading error [{URL}]",, Responser)
|
ProcessException(ex, Token, $"data (stories) downloading error [{URL}]",, Responser)
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
|
Private Sub DownloadData_Reels(ByVal Cursor As String, ByVal Token As CancellationToken)
|
||||||
|
Dim URL$ = String.Empty
|
||||||
|
Const VarPattern$ = """count"":10,""cursor"":{0},""feedLocation"":""COMET_MEDIA_VIEWER"",""feedbackSource"":65,""focusCommentID"":null,""renderLocation"":null,""scale"":1,""useDefaultActor"":true,""id"":""{1}"",""__relay_internal__pv__FBReelsMediaFooter_comet_enable_reels_ads_gkrelayprovider"":true,""__relay_internal__pv__IsWorkUserrelayprovider"":false"
|
||||||
|
Try
|
||||||
|
Dim nextCursor$ = String.Empty
|
||||||
|
Dim newPostsDetected As Boolean = False
|
||||||
|
Dim nodeFound As Boolean = False
|
||||||
|
Dim pid As PostKV = Nothing
|
||||||
|
Dim __urlBase$ = String.Empty
|
||||||
|
Dim lines As List(Of String)
|
||||||
|
Dim j As EContainer, rr As EContainer
|
||||||
|
Dim jDataRoot As EContainer = Nothing
|
||||||
|
Dim indx% = -1
|
||||||
|
Dim s As New List(Of Sizes)
|
||||||
|
Dim videoIdNode$() = {"profile_reel_node", "node", "video", "id"}
|
||||||
|
|
||||||
|
Dim obtainBasePostData As Action = Sub()
|
||||||
|
If indx.ValueBetween(0, jDataRoot.Count - 1) Then
|
||||||
|
With jDataRoot(indx)
|
||||||
|
pid = New PostKV(String.Empty, .Item(videoIdNode).XmlIfNothingValue.
|
||||||
|
IfNullOrEmpty(.Value({"node"}, "id")), PageBlock.Reels)
|
||||||
|
pid.Code = $"Reels:{pid.ID}"
|
||||||
|
nextCursor = .Value("cursor")
|
||||||
|
If Not .Item(videoIdNode).XmlIfNothing.IsEmptyString Then
|
||||||
|
__urlBase = $"https://www.facebook.com/reel/{pid.ID}"
|
||||||
|
Else
|
||||||
|
__urlBase = String.Empty
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
Else
|
||||||
|
pid = Nothing
|
||||||
|
nextCursor = String.Empty
|
||||||
|
__urlBase = String.Empty
|
||||||
|
End If
|
||||||
|
End Sub
|
||||||
|
Dim createFile As Func(Of String, SFile, SFile) = Function(ByVal __url As String, ByVal cFile As SFile) As SFile
|
||||||
|
Dim f As New SFile(RegexReplace(__url, Regex_ReelsFilePattern))
|
||||||
|
If Not f.IsEmptyString Then Return f Else Return cFile
|
||||||
|
End Function
|
||||||
|
|
||||||
|
If ReelsPageID.IsEmptyString Then GetVideoPageID(True, Token)
|
||||||
|
If ReelsPageID.IsEmptyString Then Throw New TokensException("Unable to obtain 'ReelsPageID'", False)
|
||||||
|
ValidateBaseTokens()
|
||||||
|
|
||||||
|
URL = String.Format(Graphql_UrlPattern, Token_lsd, DocID_Reels, Header_fb_fr_name_Reels, Token_dtsg_Var,
|
||||||
|
SymbolsConverter.ASCII.EncodeSymbolsOnly("{" & String.Format(VarPattern, If(Cursor.IsEmptyString, "null", $"""{Cursor}"""), ReelsPageID) & "}"))
|
||||||
|
|
||||||
|
ResponserApplyDefs(Header_fb_fr_name_Reels)
|
||||||
|
ThrowAny(Token)
|
||||||
|
|
||||||
|
WaitTimer()
|
||||||
|
Dim r$ = Responser.GetResponse(URL)
|
||||||
|
If Not r.IsEmptyString Then
|
||||||
|
lines = r.StringToList(Of String)(vbCrLf).ListIfNothing
|
||||||
|
If lines.ListExists Then
|
||||||
|
For Each line$ In lines
|
||||||
|
j = JsonDocument.Parse(line, EDP.ReturnValue)
|
||||||
|
If j.ListExists Then
|
||||||
|
jDataRoot = j({"data", "node", "aggregated_fb_shorts", "edges"})
|
||||||
|
If jDataRoot.ListExists Then
|
||||||
|
|
||||||
|
With j({"extensions", "all_video_dash_prefetch_representations"})
|
||||||
|
If .ListExists Then
|
||||||
|
ProgressPre.ChangeMax(.Count)
|
||||||
|
For indx = 0 To .Count - 1
|
||||||
|
ProgressPre.Perform()
|
||||||
|
|
||||||
|
obtainBasePostData()
|
||||||
|
If Not pid.ID.IsEmptyString AndAlso Not PostKvExists(pid) Then
|
||||||
|
newPostsDetected = True
|
||||||
|
PostsKVIDs.ListAddValue(pid, LNC)
|
||||||
|
_TempPostsList.Add(pid.Code)
|
||||||
|
|
||||||
|
With .ItemF({indx, "representations"})
|
||||||
|
If .ListExists Then
|
||||||
|
s.Clear()
|
||||||
|
For Each rr In .Self : s.Add(New Sizes(rr.Value("width"), rr.Value("base_url"))) : Next
|
||||||
|
If s.Count > 0 Then s.RemoveAll(Function(ss) ss.Value = 0 Or ss.Data.IsEmptyString)
|
||||||
|
If s.Count > 0 Then
|
||||||
|
s.Sort()
|
||||||
|
_TempMediaList.ListAddValue(New UserMedia(s(0).Data, UTypes.Video) With {
|
||||||
|
.URL_BASE = __urlBase.IfNullOrEmpty(.URL_BASE),
|
||||||
|
.Post = pid.ID,
|
||||||
|
.File = createFile(s(0).Data, .File),
|
||||||
|
.SpecialFolder = "Reels*"
|
||||||
|
}, LNC)
|
||||||
|
s.Clear()
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
|
||||||
|
|
||||||
|
If Limit > 0 And _TempMediaList.Count >= Limit Then j.Dispose() : Exit Sub
|
||||||
|
Else
|
||||||
|
j.Dispose()
|
||||||
|
Exit Sub
|
||||||
|
End If
|
||||||
|
|
||||||
|
Next
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
|
||||||
|
End If
|
||||||
|
|
||||||
|
j.Dispose()
|
||||||
|
End If
|
||||||
|
Next
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
|
||||||
|
If newPostsDetected And Not nextCursor.IsEmptyString Then DownloadData_Reels(nextCursor, Token)
|
||||||
|
Catch tex As TokensException When Not tex.BasicTokens
|
||||||
|
TokensException.SendToLog(Me, tex, "data (reels)")
|
||||||
|
Catch ex As Exception
|
||||||
|
ProcessException(ex, Token, $"data (reels) downloading error [{URL}]",, Responser)
|
||||||
|
End Try
|
||||||
|
End Sub
|
||||||
Private Sub DownloadData_SavedPosts(ByVal Cursor As String, ByVal Token As CancellationToken)
|
Private Sub DownloadData_SavedPosts(ByVal Cursor As String, ByVal Token As CancellationToken)
|
||||||
Dim URL$ = String.Empty
|
Dim URL$ = String.Empty
|
||||||
Const VarPattern$ = """content_filter"":[],""count"":10,""cursor"":{0},""scale"":1,""use_case"":""SAVE_DEFAULT"""
|
Const VarPattern$ = """content_filter"":[],""count"":10,""cursor"":{0},""scale"":1,""use_case"":""SAVE_DEFAULT"""
|
||||||
@@ -507,13 +637,19 @@ Namespace API.Facebook
|
|||||||
Return True
|
Return True
|
||||||
End If
|
End If
|
||||||
End Function
|
End Function
|
||||||
Private Sub GetVideoPageID(ByVal Token As CancellationToken)
|
Private Sub GetVideoPageID(ByVal GetReels As Boolean, ByVal Token As CancellationToken)
|
||||||
Dim URL$ = $"{GetProfileUrl()}\videos"
|
Dim URL$ = $"{GetProfileUrl()}{IIf(IsNoNameProfile, "&sk=", "/")}{IIf(GetReels, IIf(IsNoNameProfile, "reels_tab", "reels"), "videos")}"
|
||||||
Dim resp As Responser = HtmlResponserCreate()
|
Dim resp As Responser = HtmlResponserCreate()
|
||||||
Try
|
Try
|
||||||
WaitTimer()
|
WaitTimer()
|
||||||
Dim r$ = resp.GetResponse(URL)
|
Dim r$ = resp.GetResponse(URL)
|
||||||
If Not r.IsEmptyString Then VideoPageID = RegexReplace(r, Regex_VideoPageID)
|
If Not r.IsEmptyString Then
|
||||||
|
If GetReels Then
|
||||||
|
ReelsPageID = RegexReplace(r, Regex_ReelsPageID)
|
||||||
|
Else
|
||||||
|
VideoPageID = RegexReplace(r, Regex_VideoPageID)
|
||||||
|
End If
|
||||||
|
End If
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
ProcessException(ex, Token, "get video page ID",, resp)
|
ProcessException(ex, Token, "get video page ID",, resp)
|
||||||
Finally
|
Finally
|
||||||
@@ -540,10 +676,7 @@ Namespace API.Facebook
|
|||||||
End If
|
End If
|
||||||
Token_Photosby = RegexReplace(r, Regex_Photos_by)
|
Token_Photosby = RegexReplace(r, Regex_Photos_by)
|
||||||
If StoryBucket.IsEmptyString Then StoryBucket = RegexReplace(r, Regex_StoryBucket)
|
If StoryBucket.IsEmptyString Then StoryBucket = RegexReplace(r, Regex_StoryBucket)
|
||||||
If ID.IsEmptyString Then
|
If ID.IsEmptyString Then ID = RegexReplace(r, Regex_UserID)
|
||||||
ID = RegexReplace(r, Regex_UserID)
|
|
||||||
If Not ID.IsEmptyString Then _ForceSaveUserInfo = True
|
|
||||||
End If
|
|
||||||
End If
|
End If
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
ProcessException(ex, Token, "get user token",, resp)
|
ProcessException(ex, Token, "get user token",, resp)
|
||||||
@@ -658,17 +791,39 @@ Namespace API.Facebook
|
|||||||
HtmlResponserDispose(resp)
|
HtmlResponserDispose(resp)
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
|
Private Structure VideoResolution : Implements IComparable(Of VideoResolution)
|
||||||
|
Friend W As Integer
|
||||||
|
Friend H As Integer
|
||||||
|
Friend B As Integer
|
||||||
|
Friend U As String
|
||||||
|
Friend ReadOnly Property Wrong As Boolean
|
||||||
|
Get
|
||||||
|
Return W = 0 Or H = 0 Or B = 0 Or U.IsEmptyString
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
Private Function CompareTo(ByVal Other As VideoResolution) As Integer Implements IComparable(Of VideoResolution).CompareTo
|
||||||
|
Return CLng(Math.Max(W, H) * B).CompareTo(CLng(Math.Max(Other.W, Other.H) * Other.B)) * -1
|
||||||
|
End Function
|
||||||
|
End Structure
|
||||||
Protected Function ReparseSingleVideo(ByVal m As UserMedia, ByVal resp As Responser, ByRef result As Boolean) As UserMedia
|
Protected Function ReparseSingleVideo(ByVal m As UserMedia, ByVal resp As Responser, ByRef result As Boolean) As UserMedia
|
||||||
Const nameSD$ = "browser_native_sd_url"
|
Const nameSD$ = "browser_native_sd_url"
|
||||||
Const nameHD$ = "browser_native_hd_url"
|
Const nameHD$ = "browser_native_hd_url"
|
||||||
|
Const nameDPR$ = "all_video_dash_prefetch_representations"
|
||||||
Const pattern$ = "<script type=""application/json""[^\>]*data-sjs>([^<]+?{0}[^<]+)<"
|
Const pattern$ = "<script type=""application/json""[^\>]*data-sjs>([^<]+?{0}[^<]+)<"
|
||||||
Dim URL$ = String.Empty
|
Dim URL$ = String.Empty
|
||||||
Dim j As EContainer = Nothing
|
Dim j As EContainer = Nothing
|
||||||
Try
|
Try
|
||||||
Dim r$, script$, __url$
|
Dim r$ = String.Empty, script$ = String.Empty, __url$ = String.Empty
|
||||||
|
Dim isNewNodes As Boolean = False
|
||||||
|
Dim __date As Date? = Nothing
|
||||||
Dim jNode As EContainer
|
Dim jNode As EContainer
|
||||||
Dim jf As Predicate(Of EContainer) = Function(ee) Not ee.Name.IsEmptyString AndAlso (ee.Name.ToLower = nameSD Or ee.Name.ToLower = nameHD)
|
Dim jf As Predicate(Of EContainer) = Function(ee) Not ee.Name.IsEmptyString AndAlso (ee.Name.ToLower = nameSD Or ee.Name.ToLower = nameHD)
|
||||||
Dim re As RParams = RParams.DMS("", 1, RegexOptions.IgnoreCase, EDP.ReturnValue)
|
Dim re As RParams = RParams.DMS("", 1, RegexOptions.IgnoreCase, EDP.ReturnValue)
|
||||||
|
Dim nf As New XML.Base.NodeParams(nameDPR, True, True, True, True, 20)
|
||||||
|
Dim __extractScript As Action(Of String) = Sub(ByVal inputName As String)
|
||||||
|
re.Pattern = String.Format(pattern, inputName)
|
||||||
|
script = RegexReplace(r, re)
|
||||||
|
End Sub
|
||||||
If m.Post.ID.IsEmptyString Then
|
If m.Post.ID.IsEmptyString Then
|
||||||
URL = m.URL_BASE
|
URL = m.URL_BASE
|
||||||
Else
|
Else
|
||||||
@@ -677,31 +832,48 @@ Namespace API.Facebook
|
|||||||
WaitTimer()
|
WaitTimer()
|
||||||
r = resp.GetResponse(URL)
|
r = resp.GetResponse(URL)
|
||||||
If Not r.IsEmptyString Then
|
If Not r.IsEmptyString Then
|
||||||
re.Pattern = String.Format(pattern, nameHD)
|
__extractScript(nameHD)
|
||||||
script = RegexReplace(r, re)
|
If script.IsEmptyString Then __extractScript(nameSD)
|
||||||
If script.IsEmptyString Then
|
If script.IsEmptyString Then __extractScript(nameDPR) : isNewNodes = True
|
||||||
re.Pattern = String.Format(pattern, nameSD)
|
|
||||||
script = RegexReplace(r, re)
|
|
||||||
End If
|
|
||||||
If Not script.IsEmptyString Then
|
If Not script.IsEmptyString Then
|
||||||
j = JsonDocument.Parse(script)
|
j = JsonDocument.Parse(script)
|
||||||
If j.ListExists Then
|
If j.ListExists Then
|
||||||
j.SetSourceReferences()
|
j.SetSourceReferences()
|
||||||
|
If isNewNodes Then
|
||||||
|
jNode = j.GetNode({nf})
|
||||||
|
If Not jNode Is Nothing Then
|
||||||
|
With jNode.ItemF({0, "representations"})
|
||||||
|
If .ListExists Then
|
||||||
|
Dim intE As New ErrorsDescriber(False, False, False, 0)
|
||||||
|
Dim intC As Func(Of String, Integer) = Function(__input) AConvert(Of Integer)(__input, intE)
|
||||||
|
Dim dataV As List(Of VideoResolution) = .Select(Function(jj) New VideoResolution With {
|
||||||
|
.W = intC(jj.Value("width")),
|
||||||
|
.H = intC(jj.Value("height")),
|
||||||
|
.B = intC(jj.Value("bandwidth")),
|
||||||
|
.U = jj.Value("base_url")}).ListIfNothing
|
||||||
|
If dataV.ListExists Then dataV.RemoveAll(Function(dd) dd.Wrong)
|
||||||
|
If dataV.ListExists Then dataV.Sort() : __url = dataV(0).U : dataV.Clear() : __date = m.Post.Date
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
End If
|
||||||
|
Else
|
||||||
jNode = j.Find(jf, True)
|
jNode = j.Find(jf, True)
|
||||||
If Not jNode Is Nothing Then
|
If Not jNode Is Nothing Then
|
||||||
With DirectCast(jNode.Source, EContainer)
|
With DirectCast(jNode.Source, EContainer)
|
||||||
__url = .Value(nameHD).IfNullOrEmpty(.Value(nameSD))
|
__url = .Value(nameHD).IfNullOrEmpty(.Value(nameSD))
|
||||||
|
If Not __url.IsEmptyString Then __date = AConvert(Of Date)(.Value("publish_time"), UnixDate32Provider, Nothing)
|
||||||
|
End With
|
||||||
|
End If
|
||||||
|
End If
|
||||||
If Not __url.IsEmptyString Then
|
If Not __url.IsEmptyString Then
|
||||||
m.URL = __url
|
m.URL = __url
|
||||||
m.URL_BASE = URL
|
m.URL_BASE = URL
|
||||||
m.Type = UTypes.Video
|
m.Type = UTypes.Video
|
||||||
m.File = CreateFileFromUrl(__url)
|
m.File = CreateFileFromUrl(__url)
|
||||||
m.Post.Date = AConvert(Of Date)(.Value("publish_time"), UnixDate32Provider, Nothing)
|
m.Post.Date = __date
|
||||||
result = True
|
result = True
|
||||||
Return m
|
Return m
|
||||||
End If
|
End If
|
||||||
End With
|
|
||||||
End If
|
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
@@ -738,7 +910,10 @@ Namespace API.Facebook
|
|||||||
#End Region
|
#End Region
|
||||||
#Region "DownloadSingleObject"
|
#Region "DownloadSingleObject"
|
||||||
Protected Overrides Sub DownloadSingleObject_GetPosts(ByVal Data As IYouTubeMediaContainer, ByVal Token As CancellationToken)
|
Protected Overrides Sub DownloadSingleObject_GetPosts(ByVal Data As IYouTubeMediaContainer, ByVal Token As CancellationToken)
|
||||||
_ContentList.Add(New UserMedia(Data.URL, UTypes.VideoPre) With {.Post = CStr(AConvert(Of String)(Data.URL, Regex_VideoIDFromURL, String.Empty))})
|
_ContentList.Add(New UserMedia(Data.URL, UTypes.VideoPre) With {
|
||||||
|
.Post = CStr(AConvert(Of String)(Data.URL, Regex_VideoIDFromURL, String.Empty)),
|
||||||
|
.State = UStates.Missing
|
||||||
|
})
|
||||||
ReparseMissing(Token)
|
ReparseMissing(Token)
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ Namespace API.Facebook
|
|||||||
Friend Property ParsePhotoBlock As Boolean = True
|
Friend Property ParsePhotoBlock As Boolean = True
|
||||||
<PSetting(NameOf(SiteSettings.ParseVideoBlock), NameOf(MySettings))>
|
<PSetting(NameOf(SiteSettings.ParseVideoBlock), NameOf(MySettings))>
|
||||||
Friend Property ParseVideoBlock As Boolean = True
|
Friend Property ParseVideoBlock As Boolean = True
|
||||||
|
<PSetting(NameOf(SiteSettings.ParseReelsBlock), NameOf(MySettings))>
|
||||||
|
Friend Property ParseReelsBlock As Boolean = False
|
||||||
<PSetting(NameOf(SiteSettings.ParseStoriesBlock), NameOf(MySettings))>
|
<PSetting(NameOf(SiteSettings.ParseStoriesBlock), NameOf(MySettings))>
|
||||||
Friend Property ParseStoriesBlock As Boolean = True
|
Friend Property ParseStoriesBlock As Boolean = True
|
||||||
Private ReadOnly Property MySettings As SiteSettings
|
Private ReadOnly Property MySettings As SiteSettings
|
||||||
@@ -20,12 +22,14 @@ Namespace API.Facebook
|
|||||||
MySettings = u.HostCollection.Default.Source
|
MySettings = u.HostCollection.Default.Source
|
||||||
ParsePhotoBlock = u.ParsePhotoBlock
|
ParsePhotoBlock = u.ParsePhotoBlock
|
||||||
ParseVideoBlock = u.ParseVideoBlock
|
ParseVideoBlock = u.ParseVideoBlock
|
||||||
|
ParseReelsBlock = u.ParseReelsBlock
|
||||||
ParseStoriesBlock = u.ParseStoriesBlock
|
ParseStoriesBlock = u.ParseStoriesBlock
|
||||||
End Sub
|
End Sub
|
||||||
Friend Sub New(ByVal s As SiteSettings)
|
Friend Sub New(ByVal s As SiteSettings)
|
||||||
MySettings = s
|
MySettings = s
|
||||||
ParsePhotoBlock = s.ParsePhotoBlock.Value
|
ParsePhotoBlock = s.ParsePhotoBlock.Value
|
||||||
ParseVideoBlock = s.ParseVideoBlock.Value
|
ParseVideoBlock = s.ParseVideoBlock.Value
|
||||||
|
ParseReelsBlock = s.ParseReelsBlock.Value
|
||||||
ParseStoriesBlock = s.ParseStoriesBlock.Value
|
ParseStoriesBlock = s.ParseStoriesBlock.Value
|
||||||
End Sub
|
End Sub
|
||||||
End Class
|
End Class
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
' but WITHOUT ANY WARRANTY
|
' but WITHOUT ANY WARRANTY
|
||||||
Imports SCrawler.Plugin.Attributes
|
Imports SCrawler.Plugin.Attributes
|
||||||
Namespace API.Instagram
|
Namespace API.Instagram
|
||||||
Friend Class EditorExchangeOptions
|
Friend NotInheritable Class EditorExchangeOptions : Inherits Base.EditorExchangeOptionsBase
|
||||||
#Region "Download"
|
#Region "Download"
|
||||||
<PSetting(Caption:="Get timeline", ToolTip:="Download user timeline")>
|
<PSetting(Caption:="Get timeline", ToolTip:="Download user timeline")>
|
||||||
Friend Property GetTimeline As Boolean
|
Friend Property GetTimeline As Boolean
|
||||||
@@ -35,7 +35,13 @@ Namespace API.Instagram
|
|||||||
#End Region
|
#End Region
|
||||||
<PSetting(Caption:="Place the extracted image into the video folder")>
|
<PSetting(Caption:="Place the extracted image into the video folder")>
|
||||||
Friend Property PutImageVideoFolder As Boolean
|
Friend Property PutImageVideoFolder As Boolean
|
||||||
|
Friend Overrides Property UserName As String
|
||||||
|
<PSetting(Address:=SettingAddress.User, Caption:="Force update UserName", ToolTip:="Try to force update UserName if it is not found on the site")>
|
||||||
|
Friend Property ForceUpdateUserName As Boolean = False
|
||||||
|
<PSetting(Address:=SettingAddress.User, Caption:="Force update user information")>
|
||||||
|
Friend Property ForceUpdateUserInfo As Boolean = False
|
||||||
Friend Sub New(ByVal u As UserData)
|
Friend Sub New(ByVal u As UserData)
|
||||||
|
MyBase.New(u)
|
||||||
With u
|
With u
|
||||||
GetTimeline = .GetTimeline
|
GetTimeline = .GetTimeline
|
||||||
GetReels = .GetReels
|
GetReels = .GetReels
|
||||||
@@ -50,9 +56,13 @@ Namespace API.Instagram
|
|||||||
GetTagged_VideoPic = .GetTaggedData_VideoPic
|
GetTagged_VideoPic = .GetTaggedData_VideoPic
|
||||||
|
|
||||||
PutImageVideoFolder = .PutImageVideoFolder
|
PutImageVideoFolder = .PutImageVideoFolder
|
||||||
|
|
||||||
|
ForceUpdateUserName = .ForceUpdateUserName
|
||||||
|
ForceUpdateUserInfo = .ForceUpdateUserInfo
|
||||||
End With
|
End With
|
||||||
End Sub
|
End Sub
|
||||||
Friend Sub New(ByVal s As SiteSettings)
|
Friend Sub New(ByVal s As SiteSettings)
|
||||||
|
MyBase.New(s)
|
||||||
With s
|
With s
|
||||||
GetTimeline = CBool(.GetTimeline.Value)
|
GetTimeline = CBool(.GetTimeline.Value)
|
||||||
GetReels = CBool(.GetReels.Value)
|
GetReels = CBool(.GetReels.Value)
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ Imports PersonalUtilities.Tools.Web.Cookies
|
|||||||
Imports Download = SCrawler.Plugin.ISiteSettings.Download
|
Imports Download = SCrawler.Plugin.ISiteSettings.Download
|
||||||
Imports DN = SCrawler.API.Base.DeclaredNames
|
Imports DN = SCrawler.API.Base.DeclaredNames
|
||||||
Namespace API.Instagram
|
Namespace API.Instagram
|
||||||
<Manifest(InstagramSiteKey), SeparatedTasks(1), SavedPosts, SpecialForm(False)>
|
<Manifest(InstagramSiteKey), SeparatedTasks(1), SavedPosts, SpecialForm(False), UseDownDetector>
|
||||||
Friend Class SiteSettings : Inherits SiteSettingsBase
|
Friend Class SiteSettings : Inherits SiteSettingsBase : Implements DownDetector.IDownDetector
|
||||||
#Region "Declarations"
|
#Region "Declarations"
|
||||||
#Region "Providers"
|
#Region "Providers"
|
||||||
Friend Class TimersChecker : Inherits FieldsCheckerProviderBase
|
Friend Class TimersChecker : Inherits FieldsCheckerProviderBase
|
||||||
@@ -58,8 +58,10 @@ Namespace API.Instagram
|
|||||||
#Region "Categories"
|
#Region "Categories"
|
||||||
Private Const CAT_DOWN As String = "Download data"
|
Private Const CAT_DOWN As String = "Download data"
|
||||||
Private Const CAT_UserDefs_VIDEO As String = DN.CAT_UserDefs & ": extract image from video"
|
Private Const CAT_UserDefs_VIDEO As String = DN.CAT_UserDefs & ": extract image from video"
|
||||||
|
Private Const CAT_ERRORS As String = "Errors"
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Authorization properties"
|
#Region "Properties"
|
||||||
|
#Region "Authorization"
|
||||||
Friend Const Header_IG_APP_ID As String = "x-ig-app-id"
|
Friend Const Header_IG_APP_ID As String = "x-ig-app-id"
|
||||||
Friend Const Header_IG_WWW_CLAIM As String = "x-ig-www-claim"
|
Friend Const Header_IG_WWW_CLAIM As String = "x-ig-www-claim"
|
||||||
Friend Const Header_CSRF_TOKEN As String = "x-csrftoken"
|
Friend Const Header_CSRF_TOKEN As String = "x-csrftoken"
|
||||||
@@ -68,18 +70,18 @@ Namespace API.Instagram
|
|||||||
Friend Const Header_Browser As String = "Sec-Ch-Ua"
|
Friend Const Header_Browser As String = "Sec-Ch-Ua"
|
||||||
Friend Const Header_BrowserExt As String = "Sec-Ch-Ua-Full-Version-List"
|
Friend Const Header_BrowserExt As String = "Sec-Ch-Ua-Full-Version-List"
|
||||||
Friend Const Header_Platform_Verion As String = "Sec-Ch-Ua-Platform-Version"
|
Friend Const Header_Platform_Verion As String = "Sec-Ch-Ua-Platform-Version"
|
||||||
<PropertyOption(ControlText:="x-csrftoken", ControlToolTip:="Can be automatically extracted from cookies", IsAuth:=True, AllowNull:=True), ControlNumber(2), PClonable(Clone:=False)>
|
<PropertyOption(ControlText:="x-csrftoken", ControlToolTip:="Can be automatically extracted from cookies", IsAuth:=True, AllowNull:=True), PClonable(Clone:=False)>
|
||||||
Friend ReadOnly Property HH_CSRF_TOKEN As PropertyValue
|
Friend ReadOnly Property HH_CSRF_TOKEN As PropertyValue
|
||||||
<CookieValueExtractor(NameOf(HH_CSRF_TOKEN))>
|
<CookieValueExtractor(NameOf(HH_CSRF_TOKEN))>
|
||||||
Private Function GetValueFromCookies(ByVal PropName As String, ByVal c As CookieKeeper) As String
|
Private Function GetValueFromCookies(ByVal PropName As String, ByVal c As CookieKeeper) As String
|
||||||
Return c.GetCookieValue(Header_CSRF_TOKEN_COOKIE, PropName, NameOf(HH_CSRF_TOKEN))
|
Return c.GetCookieValue(Header_CSRF_TOKEN_COOKIE, PropName, NameOf(HH_CSRF_TOKEN))
|
||||||
End Function
|
End Function
|
||||||
<PropertyOption(ControlText:="x-ig-app-id", IsAuth:=True, AllowNull:=False), ControlNumber(3), PClonable(Clone:=False)>
|
<PropertyOption(ControlText:="x-ig-app-id", IsAuth:=True, AllowNull:=False), PClonable(Clone:=False)>
|
||||||
Friend ReadOnly Property HH_IG_APP_ID As PropertyValue
|
Friend ReadOnly Property HH_IG_APP_ID As PropertyValue
|
||||||
<PropertyOption(ControlText:="x-asbd-id", IsAuth:=True, AllowNull:=True), ControlNumber(4), PClonable(Clone:=False)>
|
<PropertyOption(ControlText:="x-asbd-id", IsAuth:=True, AllowNull:=True), PClonable(Clone:=False)>
|
||||||
Friend ReadOnly Property HH_ASBD_ID As PropertyValue
|
Friend ReadOnly Property HH_ASBD_ID As PropertyValue
|
||||||
'PropertyOption(ControlText:="x-ig-www-claim", IsAuth:=True, AllowNull:=True)
|
'PropertyOption(ControlText:="x-ig-www-claim", IsAuth:=True, AllowNull:=True)
|
||||||
<ControlNumber(5), PClonable(Clone:=False)>
|
<PClonable(Clone:=False)>
|
||||||
Friend ReadOnly Property HH_IG_WWW_CLAIM As PropertyValue
|
Friend ReadOnly Property HH_IG_WWW_CLAIM As PropertyValue
|
||||||
Private ReadOnly Property HH_IG_WWW_CLAIM_IS_ZERO As Boolean
|
Private ReadOnly Property HH_IG_WWW_CLAIM_IS_ZERO As Boolean
|
||||||
Get
|
Get
|
||||||
@@ -88,16 +90,16 @@ Namespace API.Instagram
|
|||||||
End Get
|
End Get
|
||||||
End Property
|
End Property
|
||||||
<PropertyOption(ControlText:="sec-ch-ua", IsAuth:=True, AllowNull:=True,
|
<PropertyOption(ControlText:="sec-ch-ua", IsAuth:=True, AllowNull:=True,
|
||||||
InheritanceName:=SettingsCLS.HEADER_DEF_sec_ch_ua), ControlNumber(6), PClonable, PXML(OnlyForChecked:=True)>
|
InheritanceName:=SettingsCLS.HEADER_DEF_sec_ch_ua), PClonable, PXML(OnlyForChecked:=True)>
|
||||||
Private ReadOnly Property HH_BROWSER As PropertyValue
|
Private ReadOnly Property HH_BROWSER As PropertyValue
|
||||||
<PropertyOption(ControlText:="sec-ch-ua-full", ControlToolTip:="sec-ch-ua-full-version-list", IsAuth:=True, AllowNull:=True,
|
<PropertyOption(ControlText:="sec-ch-ua-full", ControlToolTip:="sec-ch-ua-full-version-list", IsAuth:=True, AllowNull:=True,
|
||||||
InheritanceName:=SettingsCLS.HEADER_DEF_sec_ch_ua_full_version_list), ControlNumber(7), PClonable, PXML(OnlyForChecked:=True)>
|
InheritanceName:=SettingsCLS.HEADER_DEF_sec_ch_ua_full_version_list), PClonable, PXML(OnlyForChecked:=True)>
|
||||||
Private ReadOnly Property HH_BROWSER_EXT As PropertyValue
|
Private ReadOnly Property HH_BROWSER_EXT As PropertyValue
|
||||||
<PropertyOption(ControlText:="sec-ch-ua-platform-ver", ControlToolTip:="sec-ch-ua-platform-version", IsAuth:=True, AllowNull:=True, LeftOffset:=135,
|
<PropertyOption(ControlText:="sec-ch-ua-platform-ver", ControlToolTip:="sec-ch-ua-platform-version", IsAuth:=True, AllowNull:=True, LeftOffset:=135,
|
||||||
InheritanceName:=SettingsCLS.HEADER_DEF_sec_ch_ua_platform_version), ControlNumber(8), PClonable, PXML(OnlyForChecked:=True)>
|
InheritanceName:=SettingsCLS.HEADER_DEF_sec_ch_ua_platform_version), PClonable, PXML(OnlyForChecked:=True)>
|
||||||
Private ReadOnly Property HH_PLATFORM As PropertyValue
|
Private ReadOnly Property HH_PLATFORM As PropertyValue
|
||||||
<PropertyOption(ControlText:="UserAgent", IsAuth:=True, AllowNull:=True,
|
<PropertyOption(ControlText:="UserAgent", IsAuth:=True, AllowNull:=True,
|
||||||
InheritanceName:=SettingsCLS.HEADER_DEF_UserAgent), ControlNumber(9), PClonable, PXML(OnlyForChecked:=True)>
|
InheritanceName:=SettingsCLS.HEADER_DEF_UserAgent), PClonable, PXML(OnlyForChecked:=True)>
|
||||||
Private ReadOnly Property HH_USER_AGENT As PropertyValue
|
Private ReadOnly Property HH_USER_AGENT As PropertyValue
|
||||||
Friend Overrides Function BaseAuthExists() As Boolean
|
Friend Overrides Function BaseAuthExists() As Boolean
|
||||||
Return Responser.CookiesExists And ACheck(HH_IG_APP_ID.Value) And ACheck(HH_CSRF_TOKEN.Value)
|
Return Responser.CookiesExists And ACheck(HH_IG_APP_ID.Value) And ACheck(HH_CSRF_TOKEN.Value)
|
||||||
@@ -126,113 +128,179 @@ Namespace API.Instagram
|
|||||||
End If
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
#Region "HH_IG_WWW_CLAIM"
|
#Region "HH_IG_WWW_CLAIM"
|
||||||
<PropertyOption(ControlText:="ig-www-claim update interval", IsAuth:=True, LeftOffset:=150), PXML, ControlNumber(10), PClonable, HiddenControl>
|
<PropertyOption(ControlText:="ig-www-claim update interval", IsAuth:=True, LeftOffset:=150), PXML, PClonable, HiddenControl>
|
||||||
Private ReadOnly Property HH_IG_WWW_CLAIM_UPDATE_INTERVAL As PropertyValue
|
Private ReadOnly Property HH_IG_WWW_CLAIM_UPDATE_INTERVAL As PropertyValue
|
||||||
<PropertyOption(ControlText:="ig-www-claim: always 0", ControlToolTip:="Keep token value always = 0", IsAuth:=True),
|
<PropertyOption(ControlText:="ig-www-claim: always 0", ControlToolTip:="Keep token value always = 0", IsAuth:=True),
|
||||||
PXML, ControlNumber(11), PClonable, HiddenControl>
|
PXML, PClonable, HiddenControl>
|
||||||
Friend ReadOnly Property HH_IG_WWW_CLAIM_ALWAYS_ZERO As PropertyValue
|
Friend ReadOnly Property HH_IG_WWW_CLAIM_ALWAYS_ZERO As PropertyValue
|
||||||
<PropertyOption(ControlText:="ig-www-claim: reset each session", ControlToolTip:="Set 'x-ig-www-claim' to '0' before each session", IsAuth:=True),
|
<PropertyOption(ControlText:="ig-www-claim: reset each session", ControlToolTip:="Set 'x-ig-www-claim' to '0' before each session", IsAuth:=True),
|
||||||
PXML, ControlNumber(12), PClonable, HiddenControl>
|
PXML, PClonable, HiddenControl>
|
||||||
Friend ReadOnly Property HH_IG_WWW_CLAIM_RESET_EACH_SESSION As PropertyValue
|
Friend ReadOnly Property HH_IG_WWW_CLAIM_RESET_EACH_SESSION As PropertyValue
|
||||||
<PropertyOption(ControlText:="ig-www-claim: reset each target", ControlToolTip:="Set 'x-ig-www-claim' to '0' before each target", IsAuth:=True),
|
<PropertyOption(ControlText:="ig-www-claim: reset each target", ControlToolTip:="Set 'x-ig-www-claim' to '0' before each target", IsAuth:=True),
|
||||||
PXML, ControlNumber(13), PClonable, HiddenControl>
|
PXML, PClonable, HiddenControl>
|
||||||
Friend ReadOnly Property HH_IG_WWW_CLAIM_RESET_EACH_TARGET As PropertyValue
|
Friend ReadOnly Property HH_IG_WWW_CLAIM_RESET_EACH_TARGET As PropertyValue
|
||||||
<PropertyOption(ControlText:="ig-www-claim: use in requests", IsAuth:=True), PXML, ControlNumber(14), PClonable, HiddenControl>
|
<PropertyOption(ControlText:="ig-www-claim: use in requests", IsAuth:=True), PXML, PClonable, HiddenControl>
|
||||||
Friend ReadOnly Property HH_IG_WWW_CLAIM_USE As PropertyValue
|
Friend ReadOnly Property HH_IG_WWW_CLAIM_USE As PropertyValue
|
||||||
<PropertyOption(ControlText:="ig-www-claim: use default algorithm to update", IsAuth:=True), PXML, ControlNumber(15), PClonable, HiddenControl>
|
<PropertyOption(ControlText:="ig-www-claim: use default algorithm to update", IsAuth:=True), PXML, PClonable, HiddenControl>
|
||||||
Friend ReadOnly Property HH_IG_WWW_CLAIM_USE_DEFAULT_ALGO As PropertyValue
|
Friend ReadOnly Property HH_IG_WWW_CLAIM_USE_DEFAULT_ALGO As PropertyValue
|
||||||
<Provider(NameOf(HH_IG_WWW_CLAIM_UPDATE_INTERVAL), FieldsChecker:=True)>
|
<Provider(NameOf(HH_IG_WWW_CLAIM_UPDATE_INTERVAL), FieldsChecker:=True)>
|
||||||
Private ReadOnly Property TokenUpdateIntervalProvider As IFormatProvider
|
Private ReadOnly Property TokenUpdateIntervalProvider As IFormatProvider
|
||||||
#End Region
|
#End Region
|
||||||
<PropertyOption(ControlText:="Use GraphQL to download", IsAuth:=True), PXML, ControlNumber(16), PClonable>
|
<PropertyOption(ControlText:="Use GraphQL to download", IsAuth:=True), PXML, PClonable>
|
||||||
Friend ReadOnly Property USE_GQL As PropertyValue
|
Friend ReadOnly Property USE_GQL As PropertyValue
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Download properties"
|
#Region "Download data"
|
||||||
<PropertyOption(ControlText:="DownDetector",
|
<PropertyOption(ControlText:="Download timeline", Category:=CAT_DOWN), PXML, PClonable>
|
||||||
ControlToolTip:="Use 'DownDetector' to determine if the site is accessible. -1 to disable." & vbCr &
|
Friend ReadOnly Property DownloadTimeline As PropertyValue
|
||||||
"The value represents the average number of error reports over the last 4 hours"),
|
<PXML> Private ReadOnly Property DownloadTimeline_Def As PropertyValue
|
||||||
PClonable, PXML, ControlNumber(17)>
|
<PropertyOption(ControlText:="Download reels", Category:=CAT_DOWN), PXML, PClonable>
|
||||||
Private ReadOnly Property DownDetectorValue As PropertyValue
|
Friend ReadOnly Property DownloadReels As PropertyValue
|
||||||
<Provider(NameOf(DownDetectorValue), FieldsChecker:=True)>
|
<PXML> Private ReadOnly Property DownloadReels_Def As PropertyValue
|
||||||
Private ReadOnly Property DownDetectorValueProvider As IFormatProvider
|
<PropertyOption(ControlText:="Download stories", Category:=CAT_DOWN), PXML, PClonable>
|
||||||
<PropertyOption(ControlText:="Add 'DownDetector' information to the log."), PClonable, PXML, ControlNumber(18), HiddenControl>
|
Friend ReadOnly Property DownloadStories As PropertyValue
|
||||||
Private ReadOnly Property DownDetectorValueAddToLog As PropertyValue
|
<PXML> Private ReadOnly Property DownloadStories_Def As PropertyValue
|
||||||
|
<PropertyOption(ControlText:="Download stories: user", Category:=CAT_DOWN), PXML, PClonable>
|
||||||
|
Friend ReadOnly Property DownloadStoriesUser As PropertyValue
|
||||||
|
<PXML> Private ReadOnly Property DownloadStoriesUser_Def As PropertyValue
|
||||||
|
<PropertyOption(ControlText:="Download tagged posts", Category:=CAT_DOWN), PXML, PClonable>
|
||||||
|
Friend ReadOnly Property DownloadTagged As PropertyValue
|
||||||
|
<PXML> Private ReadOnly Property DownloadTagged_Def As PropertyValue
|
||||||
|
#End Region
|
||||||
|
#Region "Timers"
|
||||||
Friend Const TimersUrgentTip As String = vbCr & "It is highly recommended not to change the default value."
|
Friend Const TimersUrgentTip As String = vbCr & "It is highly recommended not to change the default value."
|
||||||
<PropertyOption(ControlText:="Request timer (any)",
|
<PropertyOption(ControlText:="Request timer (any)",
|
||||||
ControlToolTip:="The timer (in milliseconds) that SCrawler should wait before executing the next request." &
|
ControlToolTip:="The timer (in milliseconds) that SCrawler should wait before executing the next request." &
|
||||||
vbCr & "The default value is 1'000." & vbCr & "The minimum value is 0." & TimersUrgentTip, AllowNull:=False, Category:=DN.CAT_Timers),
|
vbCr & "The default value is 1'000." & vbCr & "The minimum value is 0." & TimersUrgentTip, AllowNull:=False, Category:=DN.CAT_Timers),
|
||||||
PXML, ControlNumber(19), PClonable>
|
PXML, PClonable>
|
||||||
Friend ReadOnly Property RequestsWaitTimer_Any As PropertyValue
|
Friend ReadOnly Property RequestsWaitTimer_Any As PropertyValue
|
||||||
<Provider(NameOf(RequestsWaitTimer_Any), FieldsChecker:=True)>
|
<Provider(NameOf(RequestsWaitTimer_Any), FieldsChecker:=True)>
|
||||||
Private ReadOnly Property RequestsWaitTimer_AnyProvider As IFormatProvider
|
Private ReadOnly Property RequestsWaitTimer_AnyProvider As IFormatProvider
|
||||||
<PropertyOption(ControlText:="Request timer",
|
<PropertyOption(ControlText:="Request timer",
|
||||||
ControlToolTip:="The time value (in milliseconds) that the program will wait before processing the next 'Request time counter' request." &
|
ControlToolTip:="The time value (in milliseconds) that the program will wait before processing the next 'Request time counter' request." &
|
||||||
vbCr & "The default value is 1'000." & vbCr & "The minimum value is 100." & TimersUrgentTip,
|
vbCr & "The default value is 1'000." & vbCr & "The minimum value is 100." & TimersUrgentTip,
|
||||||
AllowNull:=False, Category:=DN.CAT_Timers), PXML, ControlNumber(20), PClonable>
|
AllowNull:=False, Category:=DN.CAT_Timers), PXML, PClonable>
|
||||||
Friend ReadOnly Property RequestsWaitTimer As PropertyValue
|
Friend ReadOnly Property RequestsWaitTimer As PropertyValue
|
||||||
<Provider(NameOf(RequestsWaitTimer), FieldsChecker:=True)>
|
<Provider(NameOf(RequestsWaitTimer), FieldsChecker:=True)>
|
||||||
Private ReadOnly Property RequestsWaitTimerProvider As IFormatProvider
|
Private ReadOnly Property RequestsWaitTimerProvider As IFormatProvider
|
||||||
<PropertyOption(ControlText:="Request timer counter",
|
<PropertyOption(ControlText:="Request timer counter",
|
||||||
ControlToolTip:="How many requests will be sent to Instagram before the program waits 'Request timer'." &
|
ControlToolTip:="How many requests will be sent to Instagram before the program waits 'Request timer'." &
|
||||||
vbCr & "The default value is 1." & vbCr & "The minimum value is 1." & TimersUrgentTip,
|
vbCr & "The default value is 1." & vbCr & "The minimum value is 1." & TimersUrgentTip,
|
||||||
AllowNull:=False, LeftOffset:=120, Category:=DN.CAT_Timers), PXML, ControlNumber(21), PClonable>
|
AllowNull:=False, LeftOffset:=120, Category:=DN.CAT_Timers), PXML, PClonable>
|
||||||
Friend ReadOnly Property RequestsWaitTimerTaskCount As PropertyValue
|
Friend ReadOnly Property RequestsWaitTimerTaskCount As PropertyValue
|
||||||
<Provider(NameOf(RequestsWaitTimerTaskCount), FieldsChecker:=True)>
|
<Provider(NameOf(RequestsWaitTimerTaskCount), FieldsChecker:=True)>
|
||||||
Private ReadOnly Property RequestsWaitTimerTaskCountProvider As IFormatProvider
|
Private ReadOnly Property RequestsWaitTimerTaskCountProvider As IFormatProvider
|
||||||
<PropertyOption(ControlText:="Posts limit timer",
|
<PropertyOption(ControlText:="Posts limit timer",
|
||||||
ControlToolTip:="The time value (in milliseconds) the program will wait before processing the next request after 195 requests." &
|
ControlToolTip:="The time value (in milliseconds) the program will wait before processing the next request after 195 requests." &
|
||||||
vbCr & "The default value is 60'000." & vbCr & "The minimum value is 10'000." & TimersUrgentTip,
|
vbCr & "The default value is 60'000." & vbCr & "The minimum value is 10'000." & TimersUrgentTip,
|
||||||
AllowNull:=False, Category:=DN.CAT_Timers), PXML, ControlNumber(22), PClonable>
|
AllowNull:=False, Category:=DN.CAT_Timers), PXML, PClonable>
|
||||||
Friend ReadOnly Property SleepTimerOnPostsLimit As PropertyValue
|
Friend ReadOnly Property SleepTimerOnPostsLimit As PropertyValue
|
||||||
<Provider(NameOf(SleepTimerOnPostsLimit), FieldsChecker:=True)>
|
<Provider(NameOf(SleepTimerOnPostsLimit), FieldsChecker:=True)>
|
||||||
Private ReadOnly Property SleepTimerOnPostsLimitProvider As IFormatProvider
|
Private ReadOnly Property SleepTimerOnPostsLimitProvider As IFormatProvider
|
||||||
<PropertyOption(ControlText:="Get timeline", ControlToolTip:="Default value for new users", Category:=DN.CAT_UserDefs), PXML, ControlNumber(23), PClonable>
|
<PropertyOption(ControlText:="Next profile timer",
|
||||||
|
ControlToolTip:="The time value (in milliseconds) the program will wait before processing the next profile." &
|
||||||
|
vbCr & "-2 to use max timer." & vbCr & "-1 to disable." & vbCr & "The default value is -2" & TimersUrgentTip,
|
||||||
|
AllowNull:=False, Category:=DN.CAT_Timers), PXML, PClonable>
|
||||||
|
Friend ReadOnly Property SleepTimerRequestsNextProfile As PropertyValue
|
||||||
|
Friend ReadOnly Property SleepTimerRequestsNextProfileMax As Integer
|
||||||
|
Get
|
||||||
|
Return {RequestsWaitTimer_Any, RequestsWaitTimer, SleepTimerOnPostsLimit}.Max(Function(obj) CInt(obj.Value))
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
<Provider(NameOf(SleepTimerRequestsNextProfile), FieldsChecker:=True)>
|
||||||
|
Private ReadOnly Property SleepTimerRequestsNextProfileProvider As IFormatProvider
|
||||||
|
#End Region
|
||||||
|
#Region "New user defaults"
|
||||||
|
<PropertyOption(ControlText:="Get timeline", ControlToolTip:="Default value for new users", Category:=DN.CAT_UserDefs), PXML, PClonable>
|
||||||
Friend ReadOnly Property GetTimeline As PropertyValue
|
Friend ReadOnly Property GetTimeline As PropertyValue
|
||||||
<PropertyOption(ControlText:="From timeline", ControlToolTip:="Default value for new users", Category:=CAT_UserDefs_VIDEO), PXML, ControlNumber(23), PClonable>
|
<PropertyOption(ControlText:="From timeline", ControlToolTip:="Default value for new users", Category:=CAT_UserDefs_VIDEO), PXML, PClonable>
|
||||||
Friend ReadOnly Property GetTimeline_VideoPic As PropertyValue
|
Friend ReadOnly Property GetTimeline_VideoPic As PropertyValue
|
||||||
<PropertyOption(ControlText:="Get reels", ControlToolTip:="Default value for new users", Category:=DN.CAT_UserDefs), PXML, ControlNumber(24), PClonable>
|
<PropertyOption(ControlText:="Get reels", ControlToolTip:="Default value for new users", Category:=DN.CAT_UserDefs), PXML, PClonable>
|
||||||
Friend ReadOnly Property GetReels As PropertyValue
|
Friend ReadOnly Property GetReels As PropertyValue
|
||||||
<PropertyOption(ControlText:="From reels", ControlToolTip:="Default value for new users", Category:=CAT_UserDefs_VIDEO), PXML, ControlNumber(24), PClonable>
|
<PropertyOption(ControlText:="From reels", ControlToolTip:="Default value for new users", Category:=CAT_UserDefs_VIDEO), PXML, PClonable>
|
||||||
Friend ReadOnly Property GetReels_VideoPic As PropertyValue
|
Friend ReadOnly Property GetReels_VideoPic As PropertyValue
|
||||||
<PropertyOption(ControlText:="Get stories", ControlToolTip:="Default value for new users", Category:=DN.CAT_UserDefs), PXML, ControlNumber(25), PClonable>
|
<PropertyOption(ControlText:="Get stories", ControlToolTip:="Default value for new users", Category:=DN.CAT_UserDefs), PXML, PClonable>
|
||||||
Friend ReadOnly Property GetStories As PropertyValue
|
Friend ReadOnly Property GetStories As PropertyValue
|
||||||
<PropertyOption(ControlText:="From stories", ControlToolTip:="Default value for new users", Category:=CAT_UserDefs_VIDEO), PXML, ControlNumber(25), PClonable>
|
<PropertyOption(ControlText:="From stories", ControlToolTip:="Default value for new users", Category:=CAT_UserDefs_VIDEO), PXML, PClonable>
|
||||||
Friend ReadOnly Property GetStories_VideoPic As PropertyValue
|
Friend ReadOnly Property GetStories_VideoPic As PropertyValue
|
||||||
<PropertyOption(ControlText:="Get stories: user", ControlToolTip:="Default value for new users", Category:=DN.CAT_UserDefs), PXML, ControlNumber(26), PClonable>
|
<PropertyOption(ControlText:="Get stories: user", ControlToolTip:="Default value for new users", Category:=DN.CAT_UserDefs), PXML, PClonable>
|
||||||
Friend ReadOnly Property GetStoriesUser As PropertyValue
|
Friend ReadOnly Property GetStoriesUser As PropertyValue
|
||||||
<PropertyOption(ControlText:="From stories: user", ControlToolTip:="Default value for new users", Category:=CAT_UserDefs_VIDEO), PXML, ControlNumber(26), PClonable>
|
<PropertyOption(ControlText:="From stories: user", ControlToolTip:="Default value for new users", Category:=CAT_UserDefs_VIDEO), PXML, PClonable>
|
||||||
Friend ReadOnly Property GetStoriesUser_VideoPic As PropertyValue
|
Friend ReadOnly Property GetStoriesUser_VideoPic As PropertyValue
|
||||||
<PropertyOption(ControlText:="Get tagged posts", ControlToolTip:="Default value for new users", Category:=DN.CAT_UserDefs), PXML, ControlNumber(27), PClonable>
|
<PropertyOption(ControlText:="Get tagged posts", ControlToolTip:="Default value for new users", Category:=DN.CAT_UserDefs), PXML, PClonable>
|
||||||
Friend ReadOnly Property GetTagged As PropertyValue
|
Friend ReadOnly Property GetTagged As PropertyValue
|
||||||
<PropertyOption(ControlText:="From tagged posts", ControlToolTip:="Default value for new users", Category:=CAT_UserDefs_VIDEO), PXML, ControlNumber(27), PClonable>
|
<PropertyOption(ControlText:="From tagged posts", ControlToolTip:="Default value for new users", Category:=CAT_UserDefs_VIDEO), PXML, PClonable>
|
||||||
Friend ReadOnly Property GetTagged_VideoPic As PropertyValue
|
Friend ReadOnly Property GetTagged_VideoPic As PropertyValue
|
||||||
<PropertyOption(ControlText:="From saved posts", ControlToolTip:="Default value for new users", Category:=CAT_UserDefs_VIDEO), PXML, ControlNumber(28), PClonable>
|
<PropertyOption(ControlText:="From saved posts", ControlToolTip:="Default value for new users", Category:=CAT_UserDefs_VIDEO), PXML, PClonable>
|
||||||
Friend ReadOnly Property GetSavedPosts_VideoPic As PropertyValue
|
Friend ReadOnly Property GetSavedPosts_VideoPic As PropertyValue
|
||||||
<PropertyOption(ControlText:="Place the extracted image into the video folder", ControlToolTip:="Default value for new users", Category:=CAT_UserDefs_VIDEO), PXML, ControlNumber(29), PClonable>
|
<PropertyOption(ControlText:="Place the extracted image into the video folder", ControlToolTip:="Default value for new users", Category:=CAT_UserDefs_VIDEO), PXML, PClonable>
|
||||||
Friend ReadOnly Property PutImageVideoFolder As PropertyValue
|
Friend ReadOnly Property PutImageVideoFolder As PropertyValue
|
||||||
|
#End Region
|
||||||
|
#Region "Errors"
|
||||||
|
Private Const ErrorsDefault As String = "572"
|
||||||
|
<PropertyOption(ControlText:="Skip errors",
|
||||||
|
ControlToolTip:="Skip the following errors (comma separated)." & vbCr &
|
||||||
|
"Facing these errors will not disable the download, but will add a simple line to the log.", Category:=CAT_ERRORS),
|
||||||
|
PClonable, PXML>
|
||||||
|
Private ReadOnly Property SkipErrors As PropertyValue
|
||||||
|
<PropertyOption(ControlText:="Add skipped errors to the log", Category:=CAT_ERRORS), PClonable, PXML>
|
||||||
|
Private ReadOnly Property SkipErrors_AddToLog As PropertyValue
|
||||||
|
<PropertyOption(ControlText:="Skip errors (exclude)",
|
||||||
|
ControlToolTip:="Exclude the following errors from being added to the log (comma separated)", Category:=CAT_ERRORS), PClonable, PXML>
|
||||||
|
Private ReadOnly Property SkipErrors_AddToLog_Silent As PropertyValue
|
||||||
|
Friend ReadOnly Property ErrorSpecialHandling(ByVal ErrCode As Integer) As Boolean
|
||||||
|
Get
|
||||||
|
With CStr(SkipErrors.Value) : Return Not .IsEmptyString AndAlso .Contains(ErrCode) : End With
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
Friend ReadOnly Property ErrorSpecialHandling_AddToLog(ByVal ErrCode As Integer) As Boolean
|
||||||
|
Get
|
||||||
|
With CStr(SkipErrors_AddToLog_Silent.Value)
|
||||||
|
Return CBool(SkipErrors_AddToLog.Value) AndAlso (.IsEmptyString OrElse Not .Contains(ErrCode))
|
||||||
|
End With
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
<PropertyOption(ControlText:="Ignore stories downloading errors (560)",
|
||||||
|
ControlToolTip:="If checked, error 560 will be skipped and the download will continue. Otherwise, the download will be interrupted.",
|
||||||
|
Category:=CAT_ERRORS), PClonable, PXML>
|
||||||
|
Friend ReadOnly Property IgnoreStoriesDownloadingErrors As PropertyValue
|
||||||
|
#End Region
|
||||||
|
#Region "Other params"
|
||||||
|
<PropertyOption(ControlText:="DownDetector",
|
||||||
|
ControlToolTip:="Use 'DownDetector' to determine if the site is accessible. -1 to disable." & vbCr &
|
||||||
|
"The value represents the average number of error reports over the last 4 hours"),
|
||||||
|
PClonable, PXML>
|
||||||
|
Private ReadOnly Property DownDetectorValue As PropertyValue
|
||||||
|
<Provider(NameOf(DownDetectorValue), FieldsChecker:=True)>
|
||||||
|
Private ReadOnly Property DownDetectorValueProvider As IFormatProvider
|
||||||
|
<PropertyOption(ControlText:="Add 'DownDetector' information to the log."), PClonable, PXML, HiddenControl>
|
||||||
|
Private ReadOnly Property DownDetectorValueAddToLog As PropertyValue
|
||||||
<PropertyOption(ControlText:="Tagged notify limit",
|
<PropertyOption(ControlText:="Tagged notify limit",
|
||||||
ControlToolTip:="If the number of tagged posts exceeds this number you will be notified." & vbCr &
|
ControlToolTip:="If the number of tagged posts exceeds this number you will be notified." & vbCr &
|
||||||
"-1 to disable"), PXML, ControlNumber(27), PClonable>
|
"-1 to disable"), PXML, PClonable>
|
||||||
Friend ReadOnly Property TaggedNotifyLimit As PropertyValue
|
Friend ReadOnly Property TaggedNotifyLimit As PropertyValue
|
||||||
<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"
|
#End Region
|
||||||
<PropertyOption(ControlText:="Download timeline", Category:=CAT_DOWN), PXML, ControlNumber(10), PClonable>
|
#Region "IDownDetector Support"
|
||||||
Friend ReadOnly Property DownloadTimeline As PropertyValue
|
Private ReadOnly Property IDownDetector_Value As Integer Implements DownDetector.IDownDetector.Value
|
||||||
<PXML> Private ReadOnly Property DownloadTimeline_Def As PropertyValue
|
Get
|
||||||
<PropertyOption(ControlText:="Download reels", Category:=CAT_DOWN), PXML, ControlNumber(11), PClonable>
|
Return DownDetectorValue.Value
|
||||||
Friend ReadOnly Property DownloadReels As PropertyValue
|
End Get
|
||||||
<PXML> Private ReadOnly Property DownloadReels_Def As PropertyValue
|
End Property
|
||||||
<PropertyOption(ControlText:="Download stories", Category:=CAT_DOWN), PXML, ControlNumber(12), PClonable>
|
Private ReadOnly Property IDownDetector_AddToLog As Boolean Implements DownDetector.IDownDetector.AddToLog
|
||||||
Friend ReadOnly Property DownloadStories As PropertyValue
|
Get
|
||||||
<PXML> Private ReadOnly Property DownloadStories_Def As PropertyValue
|
Return DownDetectorValueAddToLog.Value
|
||||||
<PropertyOption(ControlText:="Download stories: user", Category:=CAT_DOWN), PXML, ControlNumber(13), PClonable>
|
End Get
|
||||||
Friend ReadOnly Property DownloadStoriesUser As PropertyValue
|
End Property
|
||||||
<PXML> Private ReadOnly Property DownloadStoriesUser_Def As PropertyValue
|
Private ReadOnly Property IDownDetector_CheckSite As String Implements DownDetector.IDownDetector.CheckSite
|
||||||
<PropertyOption(ControlText:="Download tagged posts", Category:=CAT_DOWN), PXML, ControlNumber(14), PClonable>
|
Get
|
||||||
Friend ReadOnly Property DownloadTagged As PropertyValue
|
Return "instagram"
|
||||||
<PXML> Private ReadOnly Property DownloadTagged_Def As PropertyValue
|
End Get
|
||||||
|
End Property
|
||||||
|
Private Function IDownDetector_Available(ByVal What As Download, ByVal Silent As Boolean) As Boolean Implements DownDetector.IDownDetector.Available
|
||||||
|
Return MDD.Available(What, Silent)
|
||||||
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
#Region "429 bypass"
|
#Region "429 bypass"
|
||||||
<PXML("InstagramDownloadingErrorDate")>
|
<PXML("InstagramDownloadingErrorDate")>
|
||||||
@@ -266,8 +334,40 @@ Namespace API.Instagram
|
|||||||
End Get
|
End Get
|
||||||
End Property
|
End Property
|
||||||
Private Const LastDownloadDateResetInterval As Integer = 60
|
Private Const LastDownloadDateResetInterval As Integer = 60
|
||||||
|
Private TooManyRequestsReadyForCatch As Boolean = True
|
||||||
|
Friend Function GetWaitDate() As Date
|
||||||
|
With DownloadingErrorDate
|
||||||
|
If ACheck(Of Date)(.Value) Then
|
||||||
|
Return CDate(.Value).AddMinutes(If(LastApplyingValue, 10))
|
||||||
|
Else
|
||||||
|
Return Now
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
End Function
|
||||||
|
Friend Sub TooManyRequests(ByVal Catched As Boolean)
|
||||||
|
With DownloadingErrorDate
|
||||||
|
If Catched Then
|
||||||
|
If Not ACheck(Of Date)(.Value) Then
|
||||||
|
.Value = Now
|
||||||
|
If TooManyRequestsReadyForCatch Then
|
||||||
|
LastApplyingValue = If(LastApplyingValue, 0) + 10
|
||||||
|
TooManyRequestsReadyForCatch = False
|
||||||
|
MyMainLOG = $"Instagram downloading error: too many requests. Try again after {If(LastApplyingValue, 10)} minutes..."
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Else
|
||||||
|
.Value = Nothing
|
||||||
|
LastApplyingValue = Nothing
|
||||||
|
TooManyRequestsReadyForCatch = True
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
End Sub
|
||||||
|
#End Region
|
||||||
|
#Region "LastRequestsCount, Label"
|
||||||
<PXML> Private ReadOnly Property LastDownloadDate As PropertyValue
|
<PXML> Private ReadOnly Property LastDownloadDate As PropertyValue
|
||||||
<PXML> Private ReadOnly Property LastRequestsCount As PropertyValue
|
<PXML> Private ReadOnly Property LastRequestsCount As PropertyValue
|
||||||
|
<PropertyOption(IsInformationLabel:=True)>
|
||||||
|
Private ReadOnly Property LastRequestsCountLabel As PropertyValue
|
||||||
Private ReadOnly MyLastRequests As Dictionary(Of Date, Integer)
|
Private ReadOnly MyLastRequests As Dictionary(Of Date, Integer)
|
||||||
Private ReadOnly Property MyLastRequestsDate As Date
|
Private ReadOnly Property MyLastRequestsDate As Date
|
||||||
Get
|
Get
|
||||||
@@ -321,36 +421,6 @@ Namespace API.Instagram
|
|||||||
ErrorsDescriber.Execute(EDP.SendToLog, ex, "[SiteSettings.Instagram.RefreshMyLastRequests]")
|
ErrorsDescriber.Execute(EDP.SendToLog, ex, "[SiteSettings.Instagram.RefreshMyLastRequests]")
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
<PropertyOption(IsInformationLabel:=True), ControlNumber(100)>
|
|
||||||
Private ReadOnly Property LastRequestsCountLabel As PropertyValue
|
|
||||||
Private TooManyRequestsReadyForCatch As Boolean = True
|
|
||||||
Friend Function GetWaitDate() As Date
|
|
||||||
With DownloadingErrorDate
|
|
||||||
If ACheck(Of Date)(.Value) Then
|
|
||||||
Return CDate(.Value).AddMinutes(If(LastApplyingValue, 10))
|
|
||||||
Else
|
|
||||||
Return Now
|
|
||||||
End If
|
|
||||||
End With
|
|
||||||
End Function
|
|
||||||
Friend Sub TooManyRequests(ByVal Catched As Boolean)
|
|
||||||
With DownloadingErrorDate
|
|
||||||
If Catched Then
|
|
||||||
If Not ACheck(Of Date)(.Value) Then
|
|
||||||
.Value = Now
|
|
||||||
If TooManyRequestsReadyForCatch Then
|
|
||||||
LastApplyingValue = If(LastApplyingValue, 0) + 10
|
|
||||||
TooManyRequestsReadyForCatch = False
|
|
||||||
MyMainLOG = $"Instagram downloading error: too many requests. Try again after {If(LastApplyingValue, 10)} minutes..."
|
|
||||||
End If
|
|
||||||
End If
|
|
||||||
Else
|
|
||||||
.Value = Nothing
|
|
||||||
LastApplyingValue = Nothing
|
|
||||||
TooManyRequestsReadyForCatch = True
|
|
||||||
End If
|
|
||||||
End With
|
|
||||||
End Sub
|
|
||||||
#End Region
|
#End Region
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Initializer"
|
#Region "Initializer"
|
||||||
@@ -427,9 +497,6 @@ Namespace API.Instagram
|
|||||||
DownloadTagged = New PropertyValue(False)
|
DownloadTagged = New PropertyValue(False)
|
||||||
DownloadTagged_Def = New PropertyValue(DownloadTagged.Value, GetType(Boolean))
|
DownloadTagged_Def = New PropertyValue(DownloadTagged.Value, GetType(Boolean))
|
||||||
|
|
||||||
DownDetectorValue = New PropertyValue(20)
|
|
||||||
DownDetectorValueProvider = New TimersChecker(-1)
|
|
||||||
DownDetectorValueAddToLog = New PropertyValue(False)
|
|
||||||
RequestsWaitTimer_Any = New PropertyValue(1000)
|
RequestsWaitTimer_Any = New PropertyValue(1000)
|
||||||
RequestsWaitTimer_AnyProvider = New TimersChecker(0)
|
RequestsWaitTimer_AnyProvider = New TimersChecker(0)
|
||||||
RequestsWaitTimer = New PropertyValue(1000)
|
RequestsWaitTimer = New PropertyValue(1000)
|
||||||
@@ -438,6 +505,8 @@ Namespace API.Instagram
|
|||||||
RequestsWaitTimerTaskCountProvider = New TimersChecker(1)
|
RequestsWaitTimerTaskCountProvider = New TimersChecker(1)
|
||||||
SleepTimerOnPostsLimit = New PropertyValue(60000)
|
SleepTimerOnPostsLimit = New PropertyValue(60000)
|
||||||
SleepTimerOnPostsLimitProvider = New TimersChecker(10000)
|
SleepTimerOnPostsLimitProvider = New TimersChecker(10000)
|
||||||
|
SleepTimerRequestsNextProfile = New PropertyValue(-2)
|
||||||
|
SleepTimerRequestsNextProfileProvider = New TimersChecker(-2)
|
||||||
|
|
||||||
GetTimeline = New PropertyValue(True)
|
GetTimeline = New PropertyValue(True)
|
||||||
GetTimeline_VideoPic = New PropertyValue(True)
|
GetTimeline_VideoPic = New PropertyValue(True)
|
||||||
@@ -451,6 +520,15 @@ Namespace API.Instagram
|
|||||||
GetTagged_VideoPic = New PropertyValue(True)
|
GetTagged_VideoPic = New PropertyValue(True)
|
||||||
GetSavedPosts_VideoPic = New PropertyValue(True)
|
GetSavedPosts_VideoPic = New PropertyValue(True)
|
||||||
PutImageVideoFolder = New PropertyValue(False)
|
PutImageVideoFolder = New PropertyValue(False)
|
||||||
|
|
||||||
|
SkipErrors = New PropertyValue(ErrorsDefault)
|
||||||
|
SkipErrors_AddToLog = New PropertyValue(True)
|
||||||
|
SkipErrors_AddToLog_Silent = New PropertyValue(String.Empty, GetType(String))
|
||||||
|
IgnoreStoriesDownloadingErrors = New PropertyValue(False)
|
||||||
|
|
||||||
|
DownDetectorValue = New PropertyValue(20)
|
||||||
|
DownDetectorValueProvider = New TimersChecker(-1)
|
||||||
|
DownDetectorValueAddToLog = New PropertyValue(False)
|
||||||
TaggedNotifyLimit = New PropertyValue(200)
|
TaggedNotifyLimit = New PropertyValue(200)
|
||||||
TaggedNotifyLimitProvider = New TaggedNotifyLimitChecker
|
TaggedNotifyLimitProvider = New TaggedNotifyLimitChecker
|
||||||
|
|
||||||
@@ -460,6 +538,8 @@ Namespace API.Instagram
|
|||||||
LastRequestsCountLabel = New PropertyValue(String.Empty, GetType(String))
|
LastRequestsCountLabel = New PropertyValue(String.Empty, GetType(String))
|
||||||
MyLastRequests = New Dictionary(Of Date, Integer)
|
MyLastRequests = New Dictionary(Of Date, Integer)
|
||||||
|
|
||||||
|
MDD = New DownDetector.Checker(Of SiteSettings)(Me)
|
||||||
|
|
||||||
_AllowUserAgentUpdate = False
|
_AllowUserAgentUpdate = False
|
||||||
UrlPatternUser = "https://www.instagram.com/{0}/"
|
UrlPatternUser = "https://www.instagram.com/{0}/"
|
||||||
UserRegex = RParams.DMS(String.Format(UserRegexDefaultPattern, "instagram.com/"), 1)
|
UserRegex = RParams.DMS(String.Format(UserRegexDefaultPattern, "instagram.com/"), 1)
|
||||||
@@ -507,20 +587,13 @@ Namespace API.Instagram
|
|||||||
End Function
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Downloading"
|
#Region "Downloading"
|
||||||
Private ____DownloadStarted As Boolean = False
|
Private ReadOnly MDD As DownDetector.Checker(Of SiteSettings)
|
||||||
Private ____AvailableRequested As Boolean = False
|
|
||||||
Private ____AvailableSilent As Boolean = True
|
|
||||||
Private ____AvailableChecked As Boolean = False
|
|
||||||
Private ____AvailableResult As Boolean = False
|
|
||||||
Private Sub ResetDownloadOptions()
|
Private Sub ResetDownloadOptions()
|
||||||
If ActiveJobs < 1 Then
|
If ActiveJobs < 1 Then
|
||||||
____DownloadStarted = False
|
MDD.Reset()
|
||||||
____AvailableRequested = False
|
|
||||||
____AvailableChecked = False
|
|
||||||
____AvailableSilent = True
|
|
||||||
____AvailableResult = False
|
|
||||||
If ActiveSessionRequestsExists Then RefreshMyLastRequests(Now)
|
If ActiveSessionRequestsExists Then RefreshMyLastRequests(Now)
|
||||||
ActiveSessionRequestsExists = False
|
ActiveSessionRequestsExists = False
|
||||||
|
ActiveSessionLastProfileRequests = False
|
||||||
_NextWNM = UserData.WNM.Notify
|
_NextWNM = UserData.WNM.Notify
|
||||||
_NextTagged = True
|
_NextTagged = True
|
||||||
SkipUntilNextSession = False
|
SkipUntilNextSession = False
|
||||||
@@ -529,79 +602,22 @@ Namespace API.Instagram
|
|||||||
End If
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
Friend Overrides Function Available(ByVal What As Download, ByVal Silent As Boolean) As Boolean
|
Friend Overrides Function Available(ByVal What As Download, ByVal Silent As Boolean) As Boolean
|
||||||
If MyBase.Available(What, Silent) And ActiveJobs < 2 Then
|
Return MyBase.Available(What, Silent) And ActiveJobs < 2
|
||||||
If CInt(DownDetectorValue.Value) >= 0 Then
|
|
||||||
If ____DownloadStarted Then
|
|
||||||
____AvailableRequested = True
|
|
||||||
____AvailableSilent = Silent
|
|
||||||
Return True
|
|
||||||
Else
|
|
||||||
Return AvailableImpl(What, Silent)
|
|
||||||
End If
|
|
||||||
Else
|
|
||||||
Return True
|
|
||||||
End If
|
|
||||||
Else
|
|
||||||
Return False
|
|
||||||
End If
|
|
||||||
End Function
|
|
||||||
#Disable Warning IDE0060
|
|
||||||
Private Function AvailableImpl(ByVal What As Download, ByVal Silent As Boolean) As Boolean
|
|
||||||
#Enable Warning
|
|
||||||
Try
|
|
||||||
AvailableText = String.Empty
|
|
||||||
If CInt(DownDetectorValue.Value) = -1 Then
|
|
||||||
Return True
|
|
||||||
Else
|
|
||||||
Dim dl As List(Of DownDetector.Data) = DownDetector.GetData("instagram")
|
|
||||||
If dl.ListExists Then
|
|
||||||
dl = dl.Take(4).ToList
|
|
||||||
Dim avg% = dl.Average(Function(d) d.Value)
|
|
||||||
If avg > CInt(DownDetectorValue.Value) Then
|
|
||||||
AvailableText = "Over the past hour, Instagram has received an average of " &
|
|
||||||
avg.NumToString(New ANumbers With {.FormatOptions = ANumbers.Options.GroupIntegral}) & " outage reports:" & vbCr &
|
|
||||||
dl.ListToString(vbCr)
|
|
||||||
If CBool(DownDetectorValueAddToLog.Value) Then MyMainLOG = AvailableText
|
|
||||||
If Silent Then
|
|
||||||
Return False
|
|
||||||
Else
|
|
||||||
Return MsgBoxE({$"{AvailableText}{vbCr}{vbCr}Do you want to continue parsing Instagram data?",
|
|
||||||
"There are outage reports on Instagram"}, vbYesNo) = vbYes
|
|
||||||
End If
|
|
||||||
End If
|
|
||||||
End If
|
|
||||||
Return True
|
|
||||||
End If
|
|
||||||
Catch ex As Exception
|
|
||||||
Return ErrorsDescriber.Execute(EDP.SendToLog + EDP.ReturnValue, ex, "[API.Instagram.SiteSettings.Available]", True)
|
|
||||||
End Try
|
|
||||||
End Function
|
End Function
|
||||||
Friend Property SkipUntilNextSession As Boolean = False
|
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 Not SkipUntilNextSession AndAlso ReadyForDownload AndAlso BaseAuthExists() AndAlso CBool(DownloadTimeline.Value) Then
|
Return ActiveJobs < 2 AndAlso Not SkipUntilNextSession AndAlso ReadyForDownload AndAlso BaseAuthExists() AndAlso CBool(DownloadTimeline.Value)
|
||||||
If ____DownloadStarted And ____AvailableRequested Then
|
|
||||||
____AvailableResult = AvailableImpl(What, ____AvailableSilent)
|
|
||||||
____AvailableChecked = True
|
|
||||||
____AvailableRequested = False
|
|
||||||
Return ____AvailableResult
|
|
||||||
ElseIf ____AvailableChecked Then
|
|
||||||
Return ____AvailableResult
|
|
||||||
Else
|
|
||||||
Return True
|
|
||||||
End If
|
|
||||||
Else
|
|
||||||
Return False
|
|
||||||
End If
|
|
||||||
End Function
|
End Function
|
||||||
Private ActiveJobs As Integer = 0
|
Private ActiveJobs As Integer = 0
|
||||||
Private ActiveSessionDate As Date
|
Private ActiveSessionDate As Date
|
||||||
Private ActiveSessionRequestsExists As Boolean = False
|
Private ActiveSessionRequestsExists As Boolean = False
|
||||||
|
Friend ActiveSessionLastProfileRequests As Boolean = False
|
||||||
Private _NextWNM As UserData.WNM = UserData.WNM.Notify
|
Private _NextWNM As UserData.WNM = UserData.WNM.Notify
|
||||||
Private _NextTagged As Boolean = True
|
Private _NextTagged As Boolean = True
|
||||||
Friend Overrides Sub DownloadStarted(ByVal What As Download)
|
Friend Overrides Sub DownloadStarted(ByVal What As Download)
|
||||||
ResetDownloadOptions()
|
ResetDownloadOptions()
|
||||||
ActiveJobs += 1
|
ActiveJobs += 1
|
||||||
If ActiveJobs = 1 Then ____DownloadStarted = True : ActiveSessionDate = Now
|
If ActiveJobs = 1 Then ActiveSessionDate = Now
|
||||||
If Not HH_IG_WWW_CLAIM_IS_ZERO AndAlso
|
If Not HH_IG_WWW_CLAIM_IS_ZERO AndAlso
|
||||||
(
|
(
|
||||||
(CBool(HH_IG_WWW_CLAIM_USE_DEFAULT_ALGO.Value) AndAlso MyLastRequestsDate.AddMinutes(HH_IG_WWW_CLAIM_UPDATE_INTERVAL.Value) < Now) Or
|
(CBool(HH_IG_WWW_CLAIM_USE_DEFAULT_ALGO.Value) AndAlso MyLastRequestsDate.AddMinutes(HH_IG_WWW_CLAIM_UPDATE_INTERVAL.Value) < Now) Or
|
||||||
@@ -632,6 +648,7 @@ Namespace API.Instagram
|
|||||||
_NextWNM = .WaitNotificationMode
|
_NextWNM = .WaitNotificationMode
|
||||||
If _NextWNM = UserData.WNM.SkipTemp Or _NextWNM = UserData.WNM.SkipCurrent Then _NextWNM = UserData.WNM.Notify
|
If _NextWNM = UserData.WNM.SkipTemp Or _NextWNM = UserData.WNM.SkipCurrent Then _NextWNM = UserData.WNM.Notify
|
||||||
_NextTagged = .TaggedCheckSession
|
_NextTagged = .TaggedCheckSession
|
||||||
|
If MyLastRequestsCount <> .RequestsCountSession Then ActiveSessionLastProfileRequests = True
|
||||||
MyLastRequestsCount = .RequestsCountSession
|
MyLastRequestsCount = .RequestsCountSession
|
||||||
If .RequestsCountSession > 0 Then ActiveSessionRequestsExists = True
|
If .RequestsCountSession > 0 Then ActiveSessionRequestsExists = True
|
||||||
_FieldsChangerSuspended = True
|
_FieldsChangerSuspended = True
|
||||||
@@ -732,9 +749,6 @@ Namespace API.Instagram
|
|||||||
Using f As New InternalSettingsForm(Options, Me, False) : f.ShowDialog() : End Using
|
Using f As New InternalSettingsForm(Options, Me, False) : f.ShowDialog() : End Using
|
||||||
End If
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
Friend Overrides Function GetUserUrl(ByVal User As IPluginContentProvider) As String
|
|
||||||
Return String.Format(UrlPatternUser, DirectCast(User, UserData).NameTrue)
|
|
||||||
End Function
|
|
||||||
Friend Overrides Function GetUserPostUrl(ByVal User As UserDataBase, ByVal Media As UserMedia) As String
|
Friend Overrides Function GetUserPostUrl(ByVal User As UserDataBase, ByVal Media As UserMedia) As String
|
||||||
Try
|
Try
|
||||||
Dim code$ = DirectCast(User, UserData).GetPostCodeById(Media.Post.ID)
|
Dim code$ = DirectCast(User, UserData).GetPostCodeById(Media.Post.ID)
|
||||||
|
|||||||
@@ -37,10 +37,11 @@ Namespace API.Instagram
|
|||||||
Private Const Name_GetTagged_VideoPic As String = "GetTaggedData_VideoPic"
|
Private Const Name_GetTagged_VideoPic As String = "GetTaggedData_VideoPic"
|
||||||
Private Const Name_PutImageVideoFolder As String = "PutImageVideoFolder"
|
Private Const Name_PutImageVideoFolder As String = "PutImageVideoFolder"
|
||||||
Private Const Name_TaggedChecked As String = "TaggedChecked"
|
Private Const Name_TaggedChecked As String = "TaggedChecked"
|
||||||
Private Const Name_NameTrue As String = "NameTrue"
|
Private Const Name_ForceUpdateUserName As String = "ForceUpdateUserName"
|
||||||
|
Private Const Name_ForceUpdateUserInfo As String = "ForceUpdateUserInfo"
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Declarations"
|
#Region "Declarations"
|
||||||
Protected Structure PostKV : Implements IEContainerProvider
|
Friend Structure PostKV : Implements IEContainerProvider
|
||||||
Private Const Name_Code As String = "Code"
|
Private Const Name_Code As String = "Code"
|
||||||
Private Const Name_Section As String = "Section"
|
Private Const Name_Section As String = "Section"
|
||||||
Friend Code As String
|
Friend Code As String
|
||||||
@@ -111,13 +112,9 @@ Namespace API.Instagram
|
|||||||
Case Else : Return True
|
Case Else : Return True
|
||||||
End Select
|
End Select
|
||||||
End Function
|
End Function
|
||||||
Protected _NameTrue As String = String.Empty
|
|
||||||
Friend ReadOnly Property NameTrue As String
|
|
||||||
Get
|
|
||||||
Return _NameTrue.IfNullOrEmpty(Name)
|
|
||||||
End Get
|
|
||||||
End Property
|
|
||||||
Private UserNameRequested As Boolean = False
|
Private UserNameRequested As Boolean = False
|
||||||
|
Friend Property ForceUpdateUserName As Boolean = False
|
||||||
|
Friend Property ForceUpdateUserInfo As Boolean = False
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Loader"
|
#Region "Loader"
|
||||||
Protected Overrides Sub LoadUserInformation_OptionalFields(ByRef Container As XmlFile, ByVal Loading As Boolean)
|
Protected Overrides Sub LoadUserInformation_OptionalFields(ByRef Container As XmlFile, ByVal Loading As Boolean)
|
||||||
@@ -137,7 +134,8 @@ Namespace API.Instagram
|
|||||||
GetTaggedData = .Value(Name_GetTagged).FromXML(Of Boolean)(CBool(MySiteSettings.GetTagged.Value))
|
GetTaggedData = .Value(Name_GetTagged).FromXML(Of Boolean)(CBool(MySiteSettings.GetTagged.Value))
|
||||||
GetTaggedData_VideoPic = .Value(Name_GetTagged_VideoPic).FromXML(Of Boolean)(CBool(MySiteSettings.GetTagged_VideoPic.Value))
|
GetTaggedData_VideoPic = .Value(Name_GetTagged_VideoPic).FromXML(Of Boolean)(CBool(MySiteSettings.GetTagged_VideoPic.Value))
|
||||||
TaggedChecked = .Value(Name_TaggedChecked).FromXML(Of Boolean)(False)
|
TaggedChecked = .Value(Name_TaggedChecked).FromXML(Of Boolean)(False)
|
||||||
_NameTrue = .Value(Name_NameTrue)
|
ForceUpdateUserName = .Value(Name_ForceUpdateUserName).FromXML(Of Boolean)(False)
|
||||||
|
ForceUpdateUserInfo = .Value(Name_ForceUpdateUserInfo).FromXML(Of Boolean)(False)
|
||||||
Else
|
Else
|
||||||
.Add(Name_LastCursor, LastCursor)
|
.Add(Name_LastCursor, LastCursor)
|
||||||
.Add(Name_FirstLoadingDone, FirstLoadingDone.BoolToInteger)
|
.Add(Name_FirstLoadingDone, FirstLoadingDone.BoolToInteger)
|
||||||
@@ -153,7 +151,8 @@ Namespace API.Instagram
|
|||||||
.Add(Name_GetTagged_VideoPic, GetTaggedData_VideoPic.BoolToInteger)
|
.Add(Name_GetTagged_VideoPic, GetTaggedData_VideoPic.BoolToInteger)
|
||||||
.Add(Name_PutImageVideoFolder, PutImageVideoFolder.BoolToInteger)
|
.Add(Name_PutImageVideoFolder, PutImageVideoFolder.BoolToInteger)
|
||||||
.Add(Name_TaggedChecked, TaggedChecked.BoolToInteger)
|
.Add(Name_TaggedChecked, TaggedChecked.BoolToInteger)
|
||||||
.Add(Name_NameTrue, _NameTrue)
|
.Add(Name_ForceUpdateUserName, ForceUpdateUserName.BoolToInteger)
|
||||||
|
.Add(Name_ForceUpdateUserInfo, ForceUpdateUserInfo.BoolToInteger)
|
||||||
End If
|
End If
|
||||||
End With
|
End With
|
||||||
End Sub
|
End Sub
|
||||||
@@ -165,6 +164,7 @@ Namespace API.Instagram
|
|||||||
Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object)
|
Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object)
|
||||||
If Not Obj Is Nothing AndAlso TypeOf Obj Is EditorExchangeOptions Then
|
If Not Obj Is Nothing AndAlso TypeOf Obj Is EditorExchangeOptions Then
|
||||||
With DirectCast(Obj, EditorExchangeOptions)
|
With DirectCast(Obj, EditorExchangeOptions)
|
||||||
|
.ApplyBase(Me)
|
||||||
GetTimeline = .GetTimeline
|
GetTimeline = .GetTimeline
|
||||||
GetReels = .GetReels
|
GetReels = .GetReels
|
||||||
GetStories = .GetStories
|
GetStories = .GetStories
|
||||||
@@ -178,6 +178,9 @@ Namespace API.Instagram
|
|||||||
GetTaggedData_VideoPic = .GetTagged_VideoPic
|
GetTaggedData_VideoPic = .GetTagged_VideoPic
|
||||||
|
|
||||||
PutImageVideoFolder = .PutImageVideoFolder
|
PutImageVideoFolder = .PutImageVideoFolder
|
||||||
|
|
||||||
|
ForceUpdateUserName = .ForceUpdateUserName
|
||||||
|
ForceUpdateUserInfo = .ForceUpdateUserInfo
|
||||||
End With
|
End With
|
||||||
End If
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
@@ -195,15 +198,32 @@ Namespace API.Instagram
|
|||||||
Private WwwClaimUse As Boolean = True
|
Private WwwClaimUse As Boolean = True
|
||||||
Private E560Thrown As Boolean = False
|
Private E560Thrown As Boolean = False
|
||||||
Friend Err5xx As Integer = -1
|
Friend Err5xx As Integer = -1
|
||||||
|
Private _ErrHandling As Integer = -1
|
||||||
|
Private Property ErrHandling As Integer
|
||||||
|
Get
|
||||||
|
Return _ErrHandling
|
||||||
|
End Get
|
||||||
|
Set(ByVal ErrCode As Integer)
|
||||||
|
_ErrHandling = ErrCode
|
||||||
|
Err5xx = ErrCode
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
Private ErrHandlingLog As Boolean = True
|
||||||
|
Private ErrHandlingSection As Sections = Sections.Timeline
|
||||||
|
Private Const ErrHandlingValue As Integer = 100
|
||||||
|
Private Const ErrHandlingValueStories As Integer = 150
|
||||||
Private Class ExitException : Inherits Exception
|
Private Class ExitException : Inherits Exception
|
||||||
Friend Property Is560 As Boolean = False
|
Friend Property Is560 As Boolean = False
|
||||||
Friend Property IsTokens As Boolean = False
|
Friend Property IsTokens As Boolean = False
|
||||||
Friend Property TokensData As String = String.Empty
|
Friend Property TokensData As String = String.Empty
|
||||||
Friend Shared Sub Throw560(ByRef Source As UserData)
|
Friend Shared Sub Throw560(ByRef Source As UserData)
|
||||||
If Not Source.E560Thrown Then
|
With Source
|
||||||
MyMainLOG = $"{Source.ToStringForLog}: ({IIf(Source.Err5xx > 0, Source.Err5xx, 560)}) Download skipped until next session"
|
If Not .E560Thrown Then
|
||||||
Source.E560Thrown = True
|
If .ErrHandling = -1 Or .ErrHandlingLog Then _
|
||||||
|
MyMainLOG = $"{ .ToStringForLog}: ({IIf(.Err5xx > 0, .Err5xx, 560)}) Download skipped {If(.ErrHandling = -1, "until next session", $"({ .ErrHandlingSection})")}"
|
||||||
|
.E560Thrown = True
|
||||||
End If
|
End If
|
||||||
|
End With
|
||||||
Throw New ExitException With {.Is560 = True}
|
Throw New ExitException With {.Is560 = True}
|
||||||
End Sub
|
End Sub
|
||||||
Friend Shared Sub ThrowTokens(ByRef Source As UserData, ByVal Data As String)
|
Friend Shared Sub ThrowTokens(ByRef Source As UserData, ByVal Data As String)
|
||||||
@@ -223,25 +243,28 @@ Namespace API.Instagram
|
|||||||
End If
|
End If
|
||||||
End Get
|
End Get
|
||||||
End Property
|
End Property
|
||||||
Protected Sub LoadSavePostsKV(ByVal Load As Boolean)
|
Friend Overloads Shared Sub LoadSavePostsKV(ByVal Load As Boolean, ByVal fPosts As SFile, ByRef List As List(Of PostKV))
|
||||||
Dim x As XmlFile
|
Dim x As XmlFile
|
||||||
Dim f As SFile = MyFilePostsKV
|
Dim f As SFile = fPosts
|
||||||
If Not f.IsEmptyString Then
|
If Not f.IsEmptyString Then
|
||||||
If Load Then
|
If Load Then
|
||||||
PostsKVIDs.Clear()
|
List.Clear()
|
||||||
x = New XmlFile(f, Protector.Modes.All, False) With {.AllowSameNames = True, .XmlReadOnly = True}
|
x = New XmlFile(f, Protector.Modes.All, False) With {.AllowSameNames = True, .XmlReadOnly = True}
|
||||||
x.LoadData()
|
x.LoadData()
|
||||||
If x.Count > 0 Then PostsKVIDs.ListAddList(x, LAP.IgnoreICopier)
|
If x.Count > 0 Then List.ListAddList(x, LAP.IgnoreICopier)
|
||||||
x.Dispose()
|
x.Dispose()
|
||||||
Else
|
Else
|
||||||
x = New XmlFile With {.AllowSameNames = True}
|
x = New XmlFile With {.AllowSameNames = True}
|
||||||
x.AddRange(PostsKVIDs)
|
x.AddRange(List)
|
||||||
x.Name = "Posts"
|
x.Name = "Posts"
|
||||||
x.Save(f, EDP.SendToLog)
|
x.Save(f, EDP.SendToLog)
|
||||||
x.Dispose()
|
x.Dispose()
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
|
Protected Overloads Sub LoadSavePostsKV(ByVal Load As Boolean)
|
||||||
|
LoadSavePostsKV(Load, MyFilePostsKV, PostsKVIDs)
|
||||||
|
End Sub
|
||||||
Protected Overloads Function PostKvExists(ByVal pkv As PostKV) As Boolean
|
Protected Overloads Function PostKvExists(ByVal pkv As PostKV) As Boolean
|
||||||
Return PostKvExists(pkv.ID, False, pkv.Section) OrElse PostKvExists(pkv.Code, True, pkv.Section)
|
Return PostKvExists(pkv.ID, False, pkv.Section) OrElse PostKvExists(pkv.Code, True, pkv.Section)
|
||||||
End Function
|
End Function
|
||||||
@@ -362,8 +385,25 @@ Namespace API.Instagram
|
|||||||
|
|
||||||
Dim s As Sections = Sections.Timeline
|
Dim s As Sections = Sections.Timeline
|
||||||
Dim errorFound As Boolean = False
|
Dim errorFound As Boolean = False
|
||||||
|
Dim firstWait As Boolean = False
|
||||||
|
Dim __firstWait As Action = Sub()
|
||||||
|
With MySiteSettings
|
||||||
|
If Not firstWait And .ActiveSessionLastProfileRequests And CInt(.SleepTimerRequestsNextProfile.Value) <> -1 Then
|
||||||
|
Dim ____v% = 0
|
||||||
|
If CInt(.SleepTimerRequestsNextProfile.Value) = -2 Then
|
||||||
|
____v = .SleepTimerRequestsNextProfileMax
|
||||||
|
Else
|
||||||
|
____v = CInt(.SleepTimerRequestsNextProfile.Value)
|
||||||
|
End If
|
||||||
|
If ____v > 0 Then firstWait = True : Thread.Sleep(____v)
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
End Sub
|
||||||
Try
|
Try
|
||||||
Err5xx = -1
|
Err5xx = -1
|
||||||
|
ErrHandling = -1
|
||||||
|
ErrHandlingLog = True
|
||||||
|
ErrHandlingSection = Sections.Timeline
|
||||||
_Limit = If(DownloadTopCount, -1)
|
_Limit = If(DownloadTopCount, -1)
|
||||||
_TotalPostsParsed = 0
|
_TotalPostsParsed = 0
|
||||||
LoadSavePostsKV(True)
|
LoadSavePostsKV(True)
|
||||||
@@ -372,9 +412,11 @@ Namespace API.Instagram
|
|||||||
ThrowAny(Token)
|
ThrowAny(Token)
|
||||||
HasError = False
|
HasError = False
|
||||||
Dim dt As Func(Of Boolean) = Function() (CBool(MySiteSettings.DownloadTimeline.Value) And GetTimeline) Or IsSavedPosts
|
Dim dt As Func(Of Boolean) = Function() (CBool(MySiteSettings.DownloadTimeline.Value) And GetTimeline) Or IsSavedPosts
|
||||||
|
If FirstLoadingDone Then LastCursor = String.Empty
|
||||||
If dt.Invoke And Not LastCursor.IsEmptyString Then
|
If dt.Invoke And Not LastCursor.IsEmptyString Then
|
||||||
s = IIf(IsSavedPosts, Sections.SavedPosts, Sections.Timeline)
|
s = IIf(IsSavedPosts, Sections.SavedPosts, Sections.Timeline)
|
||||||
upClaimRequest.Invoke
|
upClaimRequest.Invoke
|
||||||
|
__firstWait.Invoke
|
||||||
DownloadData(LastCursor, s, Token)
|
DownloadData(LastCursor, s, Token)
|
||||||
ProgressPre.Done()
|
ProgressPre.Done()
|
||||||
ThrowAny(Token)
|
ThrowAny(Token)
|
||||||
@@ -384,6 +426,7 @@ Namespace API.Instagram
|
|||||||
s = IIf(IsSavedPosts, Sections.SavedPosts, Sections.Timeline)
|
s = IIf(IsSavedPosts, Sections.SavedPosts, Sections.Timeline)
|
||||||
upClaimRequest.Invoke
|
upClaimRequest.Invoke
|
||||||
ChangeResponserMode(_UseGQL)
|
ChangeResponserMode(_UseGQL)
|
||||||
|
__firstWait.Invoke
|
||||||
DownloadData(String.Empty, s, Token)
|
DownloadData(String.Empty, s, Token)
|
||||||
ProgressPre.Done()
|
ProgressPre.Done()
|
||||||
ThrowAny(Token)
|
ThrowAny(Token)
|
||||||
@@ -399,6 +442,7 @@ Namespace API.Instagram
|
|||||||
DefaultParser_ElemNode = {"node", "media"}
|
DefaultParser_ElemNode = {"node", "media"}
|
||||||
upClaimRequest.Invoke
|
upClaimRequest.Invoke
|
||||||
ChangeResponserMode(True)
|
ChangeResponserMode(True)
|
||||||
|
__firstWait.Invoke
|
||||||
DownloadData(String.Empty, s, Token)
|
DownloadData(String.Empty, s, Token)
|
||||||
GetReelsGQL_SetEnvir = False
|
GetReelsGQL_SetEnvir = False
|
||||||
ProgressPre.Done()
|
ProgressPre.Done()
|
||||||
@@ -408,6 +452,7 @@ Namespace API.Instagram
|
|||||||
If CBool(MySiteSettings.DownloadStories.Value) And GetStories Then
|
If CBool(MySiteSettings.DownloadStories.Value) And GetStories Then
|
||||||
s = Sections.Stories
|
s = Sections.Stories
|
||||||
upClaimRequest.Invoke
|
upClaimRequest.Invoke
|
||||||
|
__firstWait.Invoke
|
||||||
DownloadData(String.Empty, s, Token)
|
DownloadData(String.Empty, s, Token)
|
||||||
ProgressPre.Done()
|
ProgressPre.Done()
|
||||||
End If
|
End If
|
||||||
@@ -416,6 +461,7 @@ Namespace API.Instagram
|
|||||||
If CBool(MySiteSettings.DownloadStoriesUser.Value) And GetStoriesUser Then
|
If CBool(MySiteSettings.DownloadStoriesUser.Value) And GetStoriesUser Then
|
||||||
s = Sections.UserStories
|
s = Sections.UserStories
|
||||||
upClaimRequest.Invoke
|
upClaimRequest.Invoke
|
||||||
|
__firstWait.Invoke
|
||||||
DownloadData(String.Empty, s, Token)
|
DownloadData(String.Empty, s, Token)
|
||||||
ProgressPre.Done()
|
ProgressPre.Done()
|
||||||
End If
|
End If
|
||||||
@@ -424,6 +470,7 @@ Namespace API.Instagram
|
|||||||
If CBool(MySiteSettings.DownloadTagged.Value) And GetTaggedData Then
|
If CBool(MySiteSettings.DownloadTagged.Value) And GetTaggedData Then
|
||||||
s = Sections.Tagged
|
s = Sections.Tagged
|
||||||
upClaimRequest.Invoke
|
upClaimRequest.Invoke
|
||||||
|
__firstWait.Invoke
|
||||||
DownloadData(String.Empty, s, Token)
|
DownloadData(String.Empty, s, Token)
|
||||||
ProgressPre.Done()
|
ProgressPre.Done()
|
||||||
DefaultParser_ElemNode = Nothing
|
DefaultParser_ElemNode = Nothing
|
||||||
@@ -444,18 +491,25 @@ Namespace API.Instagram
|
|||||||
If Not errorFound Then LoadSavePostsKV(False)
|
If Not errorFound Then LoadSavePostsKV(False)
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
Private Sub ValidateExtension()
|
Protected Sub ValidateExtension()
|
||||||
|
Dim tmpList As List(Of UserMedia) = Nothing
|
||||||
Try
|
Try
|
||||||
Const heic$ = "heic"
|
Const heic$ = "heic"
|
||||||
If _TempMediaList.Count > 0 AndAlso _TempMediaList.Exists(Function(mm) mm.File.Extension = heic) Then
|
If _TempMediaList.Count > 0 AndAlso _TempMediaList.Exists(Function(mm) mm.File.Extension = heic) Then
|
||||||
Dim m As UserMedia
|
Dim m As UserMedia
|
||||||
For i% = 0 To _TempMediaList.Count - 1
|
tmpList = New List(Of UserMedia)
|
||||||
m = _TempMediaList(i)
|
tmpList.ListAddList(_TempMediaList)
|
||||||
|
_TempMediaList.Clear()
|
||||||
|
For i% = 0 To tmpList.Count - 1
|
||||||
|
m = tmpList(i)
|
||||||
|
_TempMediaList.Add(m)
|
||||||
If m.Type = UTypes.Picture AndAlso Not m.File.Extension.IsEmptyString AndAlso m.File.Extension = heic Then _
|
If m.Type = UTypes.Picture AndAlso Not m.File.Extension.IsEmptyString AndAlso m.File.Extension = heic Then _
|
||||||
m.File.Extension = "jpg" : _TempMediaList(i) = m
|
m.File.Extension = "jpg" : _TempMediaList.Add(m)
|
||||||
Next
|
Next
|
||||||
|
tmpList.Clear()
|
||||||
End If
|
End If
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
|
If tmpList.ListExists Then _TempMediaList.Clear() : _TempMediaList.ListAddList(tmpList) : tmpList.Clear()
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
Protected Overridable Sub UpdateResponser()
|
Protected Overridable Sub UpdateResponser()
|
||||||
@@ -471,7 +525,7 @@ Namespace API.Instagram
|
|||||||
Protected Overrides Sub Responser_ResponseReceived(ByVal Sender As Object, ByVal e As EventArguments.WebDataResponse)
|
Protected Overrides Sub Responser_ResponseReceived(ByVal Sender As Object, ByVal e As EventArguments.WebDataResponse)
|
||||||
Declarations.UpdateResponser(e, Responser, WwwClaimUpdate)
|
Declarations.UpdateResponser(e, Responser, WwwClaimUpdate)
|
||||||
End Sub
|
End Sub
|
||||||
Protected Enum Sections : Timeline : Reels : Tagged : Stories : UserStories : SavedPosts : End Enum
|
Friend Enum Sections : Timeline : Reels : Tagged : Stories : UserStories : SavedPosts : End Enum
|
||||||
Protected Const StoriesFolder As String = "Stories"
|
Protected Const StoriesFolder As String = "Stories"
|
||||||
Private Const TaggedFolder As String = "Tagged"
|
Private Const TaggedFolder As String = "Tagged"
|
||||||
#Region "429 bypass"
|
#Region "429 bypass"
|
||||||
@@ -631,11 +685,13 @@ Namespace API.Instagram
|
|||||||
'Check environment
|
'Check environment
|
||||||
If Not IsSavedPosts Then
|
If Not IsSavedPosts Then
|
||||||
If ID.IsEmptyString Then GetUserData()
|
If ID.IsEmptyString Then GetUserData()
|
||||||
If ID.IsEmptyString Then Throw New Plugin.ExitException("can't get user ID")
|
If ID.IsEmptyString Then UserExists = False : _ForceSaveUserInfoOnException = True : Throw New Plugin.ExitException("can't get user ID")
|
||||||
If _UseGQL And Cursor.IsEmptyString And Not Section = Sections.SavedPosts Then
|
If _UseGQL And Cursor.IsEmptyString And Not Section = Sections.SavedPosts Then
|
||||||
If Not ValidateBaseTokens() Then GetPageTokens()
|
If Not ValidateBaseTokens() Then GetPageTokens()
|
||||||
If Not ValidateBaseTokens(TokensErrData) Then ValidateBaseTokens_Error(TokensErrData)
|
If Not ValidateBaseTokens(TokensErrData) Then ValidateBaseTokens_Error(TokensErrData)
|
||||||
End If
|
End If
|
||||||
|
If ForceUpdateUserName Then GetUserNameById()
|
||||||
|
If ForceUpdateUserInfo Then GetUserData()
|
||||||
End If
|
End If
|
||||||
|
|
||||||
'Create query
|
'Create query
|
||||||
@@ -718,6 +774,14 @@ Namespace API.Instagram
|
|||||||
Select Case Section
|
Select Case Section
|
||||||
Case Sections.Timeline
|
Case Sections.Timeline
|
||||||
With n
|
With n
|
||||||
|
If If(n("user")?.Count, 0) = 0 And Cursor.IsEmptyString Then
|
||||||
|
If Not UserNameRequested Then
|
||||||
|
ForceUpdateUserName = True
|
||||||
|
Continue Do
|
||||||
|
Else
|
||||||
|
UserExists = False
|
||||||
|
End If
|
||||||
|
End If
|
||||||
HasNextPage = .Value("more_available").FromXML(Of Boolean)(False)
|
HasNextPage = .Value("more_available").FromXML(Of Boolean)(False)
|
||||||
EndCursor = .Value("next_max_id")
|
EndCursor = .Value("next_max_id")
|
||||||
If If(.Item("items")?.Count, 0) > 0 Then
|
If If(.Item("items")?.Count, 0) > 0 Then
|
||||||
@@ -801,6 +865,11 @@ NextPageBlock:
|
|||||||
Throw eex
|
Throw eex
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
dValue = ProcessException(ex, Token, $"data downloading error [{URL}]",, Section, False)
|
dValue = ProcessException(ex, Token, $"data downloading error [{URL}]",, Section, False)
|
||||||
|
If dValue = ErrHandlingValue Then
|
||||||
|
ExitException.Throw560(Me)
|
||||||
|
ElseIf dValue = ErrHandlingValueStories Then
|
||||||
|
Exit Sub
|
||||||
|
End If
|
||||||
End Try
|
End Try
|
||||||
Loop
|
Loop
|
||||||
Catch jsonNull2 As JsonDocumentException When jsonNull2.State = WebDocumentEventArgs.States.Error And
|
Catch jsonNull2 As JsonDocumentException When jsonNull2.State = WebDocumentEventArgs.States.Error And
|
||||||
@@ -920,10 +989,12 @@ NextPageBlock:
|
|||||||
Dim PostIDKV As PostKV
|
Dim PostIDKV As PostKV
|
||||||
Dim Pinned As Boolean
|
Dim Pinned As Boolean
|
||||||
Dim PostDate$, PostOriginUrl$
|
Dim PostDate$, PostOriginUrl$
|
||||||
|
Dim PostText$ = String.Empty
|
||||||
Dim i%, before%
|
Dim i%, before%
|
||||||
Dim usePinFunc As Boolean = Not DefaultParser_Pinned Is Nothing
|
Dim usePinFunc As Boolean = Not DefaultParser_Pinned Is Nothing
|
||||||
Dim skipPostFuncExists As Boolean = Not DefaultParser_SkipPost Is Nothing
|
Dim skipPostFuncExists As Boolean = Not DefaultParser_SkipPost Is Nothing
|
||||||
Dim nn As EContainer
|
Dim nn As EContainer
|
||||||
|
Dim textMedia As UserMedia
|
||||||
If SpecFolder.IsEmptyString Then
|
If SpecFolder.IsEmptyString Then
|
||||||
Select Case Section
|
Select Case Section
|
||||||
Case Sections.Tagged : SpecFolder = TaggedFolder
|
Case Sections.Tagged : SpecFolder = TaggedFolder
|
||||||
@@ -958,9 +1029,17 @@ NextPageBlock:
|
|||||||
Case DateResult.Exit : If Not Pinned Then Return False
|
Case DateResult.Exit : If Not Pinned Then Return False
|
||||||
End Select
|
End Select
|
||||||
End If
|
End If
|
||||||
|
If DownloadTextPosts Then PostText = DefaultParser_GetCaption(.Self)
|
||||||
before = _TempMediaList.Count
|
before = _TempMediaList.Count
|
||||||
ObtainMedia(.Self, PostIDKV.ID, SpecFolder, PostDate,, PostOriginUrl, State, Attempts,, Section)
|
ObtainMedia(.Self, PostIDKV.ID, SpecFolder, PostDate,, PostOriginUrl, State, Attempts,, Section, PostText)
|
||||||
If Not before = _TempMediaList.Count Then _TotalPostsParsed += 1
|
If Not before = _TempMediaList.Count Then
|
||||||
|
_TotalPostsParsed += 1
|
||||||
|
ElseIf DownloadTextPosts And DownloadText And Not PostText.IsEmptyString Then
|
||||||
|
textMedia = MediaFromData(UTypes.Text, PostIDKV.ID, PostIDKV.ID, PostDate, SpecFolder, PostOriginUrl, State, Attempts, PostText)
|
||||||
|
textMedia.URL = PostIDKV.ID
|
||||||
|
textMedia.PostTextFile = $"{PostIDKV.ID}.txt"
|
||||||
|
_TempMediaList.ListAddValue(textMedia, LNC)
|
||||||
|
End If
|
||||||
If _Limit > 0 And _TotalPostsParsed >= _Limit Then Return False
|
If _Limit > 0 And _TotalPostsParsed >= _Limit Then Return False
|
||||||
End If
|
End If
|
||||||
Else
|
Else
|
||||||
@@ -973,6 +1052,9 @@ NextPageBlock:
|
|||||||
Return False
|
Return False
|
||||||
End If
|
End If
|
||||||
End Function
|
End Function
|
||||||
|
Protected Overridable Function DefaultParser_GetCaption(ByVal e As EContainer) As String
|
||||||
|
Return e.Value({"caption"}, "text")
|
||||||
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Code ID converters"
|
#Region "Code ID converters"
|
||||||
Protected Function CodeToID(ByVal Code As String) As String
|
Protected Function CodeToID(ByVal Code As String) As String
|
||||||
@@ -1021,7 +1103,8 @@ NextPageBlock:
|
|||||||
Optional ByVal PostOriginUrl As String = Nothing,
|
Optional ByVal PostOriginUrl As String = Nothing,
|
||||||
Optional ByVal State As UStates = UStates.Unknown, Optional ByVal Attempts As Integer = 0,
|
Optional ByVal State As UStates = UStates.Unknown, Optional ByVal Attempts As Integer = 0,
|
||||||
Optional ByVal TryExtractImage As Boolean = False,
|
Optional ByVal TryExtractImage As Boolean = False,
|
||||||
Optional ByVal Section As Sections = ObtainMedia_NoSection)
|
Optional ByVal Section As Sections = ObtainMedia_NoSection,
|
||||||
|
Optional ByVal Text As String = Nothing)
|
||||||
Try
|
Try
|
||||||
Dim maxSize As Func(Of EContainer, Integer) = Function(ByVal _ss As EContainer) As Integer
|
Dim maxSize As Func(Of EContainer, Integer) = Function(ByVal _ss As EContainer) As Integer
|
||||||
Dim w% = AConvert(Of Integer)(_ss.Value("width"), 0)
|
Dim w% = AConvert(Of Integer)(_ss.Value("width"), 0)
|
||||||
@@ -1056,6 +1139,7 @@ NextPageBlock:
|
|||||||
End Function
|
End Function
|
||||||
If Not ObtainMedia_SizeFuncVid Is Nothing Then ssVid = ObtainMedia_SizeFuncVid
|
If Not ObtainMedia_SizeFuncVid Is Nothing Then ssVid = ObtainMedia_SizeFuncVid
|
||||||
If Not ObtainMedia_SizeFuncPic Is Nothing Then ssPic = ObtainMedia_SizeFuncPic
|
If Not ObtainMedia_SizeFuncPic Is Nothing Then ssPic = ObtainMedia_SizeFuncPic
|
||||||
|
If DownloadTextPosts And Text.IsEmptyString Then Text = DefaultParser_GetCaption(n)
|
||||||
If n.Count > 0 Then
|
If n.Count > 0 Then
|
||||||
Dim l As New List(Of Sizes)
|
Dim l As New List(Of Sizes)
|
||||||
Dim d As EContainer
|
Dim d As EContainer
|
||||||
@@ -1068,12 +1152,30 @@ NextPageBlock:
|
|||||||
If TryExtractImage Then
|
If TryExtractImage Then
|
||||||
t = 1
|
t = 1
|
||||||
abstractDecision = True
|
abstractDecision = True
|
||||||
If Not SpecialFolder.IsEmptyString AndAlso PutImageVideoFolder Then
|
Dim endsAbs As Boolean
|
||||||
Dim endsAbs As Boolean = SpecialFolder.EndsWith("*")
|
Dim newFolderName$
|
||||||
If endsAbs Then SpecialFolder = SpecialFolder.TrimEnd("*")
|
If PutImageVideoFolder Then
|
||||||
If Not SpecialFolder.IsEmptyString Then SpecialFolder = $"{SpecialFolder.TrimEnd("\")}\{VideoFolderName}{IIf(Not endsAbs, "*", String.Empty)}"
|
If SpecialFolder.IsEmptyString Then
|
||||||
If endsAbs Then SpecialFolder &= "*"
|
newFolderName = $"{VideoFolderName}\*"
|
||||||
|
Else
|
||||||
|
endsAbs = SpecialFolder.EndsWith("*")
|
||||||
|
SpecialFolder = SpecialFolder.TrimEnd({CChar("\"), CChar("*")})
|
||||||
|
If Not endsAbs Then SpecialFolder = $"{SpecialFolder}\{VideoFolderName}"
|
||||||
|
newFolderName = $"{SpecialFolder}*"
|
||||||
End If
|
End If
|
||||||
|
'Dim endsAbs As Boolean = SpecialFolder.EndsWith("*")
|
||||||
|
'If endsAbs Then SpecialFolder = SpecialFolder.TrimEnd("*")
|
||||||
|
'If Not SpecialFolder.IsEmptyString Then SpecialFolder = $"{SpecialFolder.TrimEnd("\")}\{VideoFolderName}{IIf(Not endsAbs, "*", String.Empty)}"
|
||||||
|
'If endsAbs Then SpecialFolder &= "*"
|
||||||
|
ElseIf Not SpecialFolder.IsEmptyString Then
|
||||||
|
endsAbs = SpecialFolder.EndsWith("*")
|
||||||
|
SpecialFolder = SpecialFolder.TrimEnd({CChar("\"), CChar("*")})
|
||||||
|
If endsAbs Then SpecialFolder = $"{SpecialFolder}\Photos"
|
||||||
|
newFolderName = $"{SpecialFolder}*"
|
||||||
|
Else
|
||||||
|
newFolderName = SpecialFolder
|
||||||
|
End If
|
||||||
|
SpecialFolder = newFolderName
|
||||||
ElseIf t = -1 And InitialType = 8 And ObtainMedia_AllowAbstract Then
|
ElseIf t = -1 And InitialType = 8 And ObtainMedia_AllowAbstract Then
|
||||||
If n.Contains(vid) Then
|
If n.Contains(vid) Then
|
||||||
t = 2
|
t = 2
|
||||||
@@ -1097,7 +1199,7 @@ NextPageBlock:
|
|||||||
If l.Count > 0 Then l.RemoveAll(wrongData)
|
If l.Count > 0 Then l.RemoveAll(wrongData)
|
||||||
If l.Count > 0 Then
|
If l.Count > 0 Then
|
||||||
l.Sort()
|
l.Sort()
|
||||||
_TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, l.First.Data, PostID, DateObj, SpecialFolder, PostOriginUrl, State, Attempts), LNC)
|
_TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, l.First.Data, PostID, DateObj, SpecialFolder, PostOriginUrl, State, Attempts, Text), LNC)
|
||||||
l.Clear()
|
l.Clear()
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
@@ -1114,19 +1216,19 @@ NextPageBlock:
|
|||||||
If l.Count > 0 Then l.RemoveAll(wrongData)
|
If l.Count > 0 Then l.RemoveAll(wrongData)
|
||||||
If l.Count > 0 Then
|
If l.Count > 0 Then
|
||||||
l.Sort()
|
l.Sort()
|
||||||
_TempMediaList.ListAddValue(MediaFromData(UTypes.Video, l.First.Data, PostID, DateObj, SpecialFolder, PostOriginUrl, State, Attempts), LNC)
|
_TempMediaList.ListAddValue(MediaFromData(UTypes.Video, l.First.Data, PostID, DateObj, SpecialFolder, PostOriginUrl, State, Attempts, Text), LNC)
|
||||||
l.Clear()
|
l.Clear()
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
End With
|
End With
|
||||||
End If
|
End If
|
||||||
If Not TryExtractImage And Not Section = ObtainMedia_NoSection And ExtractImageFrom(Section) Then _
|
If Not TryExtractImage And Not Section = ObtainMedia_NoSection And ExtractImageFrom(Section) Then _
|
||||||
ObtainMedia(n, PostID, SpecialFolder, DateObj, InitialType, PostOriginUrl, State, Attempts, True, Section)
|
ObtainMedia(n, PostID, SpecialFolder, DateObj, InitialType, PostOriginUrl, State, Attempts, True, Section, Text)
|
||||||
Case 8 'gallery
|
Case 8 'gallery
|
||||||
DateObj = mDate(n)
|
DateObj = mDate(n)
|
||||||
With n("carousel_media").XmlIfNothing
|
With n("carousel_media").XmlIfNothing
|
||||||
If .Count > 0 Then
|
If .Count > 0 Then
|
||||||
For Each d In .Self : ObtainMedia(d, PostID, SpecialFolder, DateObj, 8, PostOriginUrl) : Next
|
For Each d In .Self : ObtainMedia(d, PostID, SpecialFolder, DateObj, 8, PostOriginUrl,,,,, Text) : Next
|
||||||
End If
|
End If
|
||||||
End With
|
End With
|
||||||
End Select
|
End Select
|
||||||
@@ -1141,6 +1243,7 @@ NextPageBlock:
|
|||||||
#Region "GetUserId, GetUserName"
|
#Region "GetUserId, GetUserName"
|
||||||
Private Sub GetUserData()
|
Private Sub GetUserData()
|
||||||
Dim __idFound As Boolean = False
|
Dim __idFound As Boolean = False
|
||||||
|
If ForceUpdateUserInfo Then ForceUpdateUserInfo = False : _ForceSaveUserInfo = True
|
||||||
Try
|
Try
|
||||||
ChangeResponserMode(False)
|
ChangeResponserMode(False)
|
||||||
UpdateRequestNumber()
|
UpdateRequestNumber()
|
||||||
@@ -1150,7 +1253,6 @@ NextPageBlock:
|
|||||||
If Not j Is Nothing AndAlso j.Contains({"data", "user"}) Then
|
If Not j Is Nothing AndAlso j.Contains({"data", "user"}) Then
|
||||||
With j({"data", "user"})
|
With j({"data", "user"})
|
||||||
ID = .Value("id")
|
ID = .Value("id")
|
||||||
_ForceSaveUserData = True
|
|
||||||
__idFound = True
|
__idFound = True
|
||||||
UserSiteNameUpdate(.Value("full_name"))
|
UserSiteNameUpdate(.Value("full_name"))
|
||||||
Dim descr$ = .Value("biography")
|
Dim descr$ = .Value("biography")
|
||||||
@@ -1159,18 +1261,17 @@ NextPageBlock:
|
|||||||
If Not eUrl.IsEmptyString AndAlso (descr.IsEmptyString OrElse Not descr.Contains(eUrl)) Then descr.StringAppendLine(eUrl)
|
If Not eUrl.IsEmptyString AndAlso (descr.IsEmptyString OrElse Not descr.Contains(eUrl)) Then descr.StringAppendLine(eUrl)
|
||||||
UserDescriptionUpdate(descr)
|
UserDescriptionUpdate(descr)
|
||||||
Dim f As New SFile With {.Path = DownloadContentDefault_GetRootDir(), .Name = "ProfilePicture", .Extension = "jpg"}
|
Dim f As New SFile With {.Path = DownloadContentDefault_GetRootDir(), .Name = "ProfilePicture", .Extension = "jpg"}
|
||||||
|
f = SFile.IndexReindex(f)
|
||||||
If Not f.Exists Then
|
If Not f.Exists Then
|
||||||
Dim profilePicture$ = .Value("profile_pic_url_hd")
|
If SimpleDownloadAvatar(.Value("profile_pic_url_hd"), Function(ff) f).IsEmptyString Then _
|
||||||
If profilePicture.IsEmptyString OrElse Not GetWebFile(profilePicture, f, EDP.ReturnValue) Then
|
SimpleDownloadAvatar(.Value("profile_pic_url"), Function(ff) f)
|
||||||
profilePicture = .Value("profile_pic_url")
|
|
||||||
If Not profilePicture.IsEmptyString Then GetWebFile(profilePicture, f, EDP.ReturnValue)
|
|
||||||
End If
|
|
||||||
End If
|
End If
|
||||||
End With
|
End With
|
||||||
End If
|
End If
|
||||||
End Using
|
End Using
|
||||||
End If
|
End If
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
|
UserExists = False
|
||||||
If Not __idFound Then
|
If Not __idFound Then
|
||||||
If Responser.StatusCode = HttpStatusCode.NotFound Or Responser.StatusCode = HttpStatusCode.BadRequest Then
|
If Responser.StatusCode = HttpStatusCode.NotFound Or Responser.StatusCode = HttpStatusCode.BadRequest Then
|
||||||
Throw ex
|
Throw ex
|
||||||
@@ -1184,6 +1285,7 @@ NextPageBlock:
|
|||||||
End Sub
|
End Sub
|
||||||
Private Function GetUserNameById() As Boolean
|
Private Function GetUserNameById() As Boolean
|
||||||
UserNameRequested = True
|
UserNameRequested = True
|
||||||
|
If ForceUpdateUserName Then ForceUpdateUserName = False : _ForceSaveUserInfo = True
|
||||||
Try
|
Try
|
||||||
If Not ID.IsEmptyString Then
|
If Not ID.IsEmptyString Then
|
||||||
UpdateRequestNumber()
|
UpdateRequestNumber()
|
||||||
@@ -1195,12 +1297,11 @@ NextPageBlock:
|
|||||||
If Not newName.IsEmptyString Then
|
If Not newName.IsEmptyString Then
|
||||||
Dim oldName$ = NameTrue
|
Dim oldName$ = NameTrue
|
||||||
If Not newName = oldName Then
|
If Not newName = oldName Then
|
||||||
MyMainLOG = $"{ToStringForLog()}: username changed from '{oldName}' to '{newName}'"
|
Dim uStr$ = $"username changed from '{oldName}' to '{newName}'"
|
||||||
_NameTrue = newName
|
LogError(Nothing, uStr)
|
||||||
Dim descr$ = $"Username changed from '{oldName}' to '{newName}' ({Now.ToStringDate(ADateTime.Formats.BaseDateTime)})!"
|
NameTrue = newName
|
||||||
descr.StringAppendLine(UserDescription)
|
UserDescriptionUpdate(uStr, True, True, True)
|
||||||
UserDescription = descr
|
_ForceSaveUserInfo = True
|
||||||
_ForceSaveUserData = True
|
|
||||||
End If
|
End If
|
||||||
Return True
|
Return True
|
||||||
End If
|
End If
|
||||||
@@ -1279,7 +1380,6 @@ NextPageBlock:
|
|||||||
End If
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
Private Function GetStoriesList() As List(Of String)
|
Private Function GetStoriesList() As List(Of String)
|
||||||
Try
|
|
||||||
UpdateRequestNumber()
|
UpdateRequestNumber()
|
||||||
Dim r$ = Responser.GetResponse($"https://i.instagram.com/api/v1/highlights/{ID}/highlights_tray/",, EDP.ThrowException)
|
Dim r$ = Responser.GetResponse($"https://i.instagram.com/api/v1/highlights/{ID}/highlights_tray/",, EDP.ThrowException)
|
||||||
If Not r.IsEmptyString Then
|
If Not r.IsEmptyString Then
|
||||||
@@ -1289,10 +1389,6 @@ NextPageBlock:
|
|||||||
End Using
|
End Using
|
||||||
End If
|
End If
|
||||||
Return Nothing
|
Return Nothing
|
||||||
Catch ex As Exception
|
|
||||||
DownloadingException(ex, "API.Instagram.GetStoriesList", False, Sections.Stories)
|
|
||||||
Return Nothing
|
|
||||||
End Try
|
|
||||||
End Function
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Download content"
|
#Region "Download content"
|
||||||
@@ -1338,11 +1434,26 @@ NextPageBlock:
|
|||||||
MyMainLOG = $"Number of requests before error 429: {RequestsCount}"
|
MyMainLOG = $"Number of requests before error 429: {RequestsCount}"
|
||||||
Return 1
|
Return 1
|
||||||
ElseIf Responser.StatusCode = 560 Or Responser.StatusCode = HttpStatusCode.InternalServerError Then '560, 500
|
ElseIf Responser.StatusCode = 560 Or Responser.StatusCode = HttpStatusCode.InternalServerError Then '560, 500
|
||||||
|
If Responser.StatusCode = 560 And s = Sections.Stories And MySiteSettings.IgnoreStoriesDownloadingErrors Then
|
||||||
|
MyMainLOG = $"{ToStringForLog()}: Stories downloading skipped (560)"
|
||||||
|
Return ErrHandlingValueStories
|
||||||
|
Else
|
||||||
MySiteSettings.SkipUntilNextSession = True
|
MySiteSettings.SkipUntilNextSession = True
|
||||||
Err5xx = Responser.StatusCode
|
Err5xx = Responser.StatusCode
|
||||||
|
End If
|
||||||
ElseIf Responser.StatusCode = -1 And Responser.Status = -1 Then
|
ElseIf Responser.StatusCode = -1 And Responser.Status = -1 Then
|
||||||
MySiteSettings.SkipUntilNextSession = True
|
MySiteSettings.SkipUntilNextSession = True
|
||||||
Err5xx = Responser.StatusCode
|
Err5xx = Responser.StatusCode
|
||||||
|
ElseIf MySiteSettings.ErrorSpecialHandling(Responser.StatusCode) Then
|
||||||
|
ErrHandlingLog = MySiteSettings.ErrorSpecialHandling_AddToLog(Responser.StatusCode)
|
||||||
|
ErrHandling = Responser.StatusCode
|
||||||
|
ErrHandlingSection = s
|
||||||
|
Return ErrHandlingValue
|
||||||
|
ElseIf MySiteSettings.ErrorSpecialHandling(Responser.Status) Then
|
||||||
|
ErrHandlingLog = MySiteSettings.ErrorSpecialHandling_AddToLog(Responser.Status)
|
||||||
|
ErrHandling = Responser.Status
|
||||||
|
ErrHandlingSection = s
|
||||||
|
Return ErrHandlingValue
|
||||||
Else
|
Else
|
||||||
MyMainLOG = $"Something is wrong. Your credentials may have expired [{CInt(Responser.StatusCode)}/{CInt(Responser.Status)}]: {ToString()} [{s}]"
|
MyMainLOG = $"Something is wrong. Your credentials may have expired [{CInt(Responser.StatusCode)}/{CInt(Responser.Status)}]: {ToString()} [{s}]"
|
||||||
DisableSection(s)
|
DisableSection(s)
|
||||||
@@ -1380,13 +1491,16 @@ NextPageBlock:
|
|||||||
#Region "Create media"
|
#Region "Create media"
|
||||||
Private Function MediaFromData(ByVal t As UTypes, ByVal _URL As String, ByVal PostID As String, ByVal PostDate As String,
|
Private Function MediaFromData(ByVal t As UTypes, ByVal _URL As String, ByVal PostID As String, ByVal PostDate As String,
|
||||||
Optional ByVal SpecialFolder As String = Nothing, Optional ByVal PostOriginUrl As String = Nothing,
|
Optional ByVal SpecialFolder As String = Nothing, Optional ByVal PostOriginUrl As String = Nothing,
|
||||||
Optional ByVal State As UStates = UStates.Unknown, Optional ByVal Attempts As Integer = 0) As UserMedia
|
Optional ByVal State As UStates = UStates.Unknown, Optional ByVal Attempts As Integer = 0,
|
||||||
|
Optional ByVal Text As String = Nothing) As UserMedia
|
||||||
_URL = LinkFormatterSecure(RegexReplace(_URL.Replace("\", String.Empty), LinkPattern))
|
_URL = LinkFormatterSecure(RegexReplace(_URL.Replace("\", String.Empty), LinkPattern))
|
||||||
Dim m As New UserMedia(_URL, t) With {.URL_BASE = PostOriginUrl.IfNullOrEmpty(_URL), .Post = New UserPost With {.ID = PostID}}
|
Dim m As New UserMedia(_URL, t) With {.URL_BASE = PostOriginUrl.IfNullOrEmpty(_URL), .Post = New UserPost With {.ID = PostID}}
|
||||||
If Not m.URL.IsEmptyString Then m.File = CStr(RegexReplace(m.URL, FilesPattern))
|
If Not m.URL.IsEmptyString Then m.File = CStr(RegexReplace(m.URL, FilesPattern))
|
||||||
If Not PostDate.IsEmptyString Then m.Post.Date = AConvert(Of Date)(PostDate, UnixDate32Provider, Nothing) Else m.Post.Date = Nothing
|
If Not PostDate.IsEmptyString Then m.Post.Date = AConvert(Of Date)(PostDate, UnixDate32Provider, Nothing) Else m.Post.Date = Nothing
|
||||||
m.SpecialFolder = SpecialFolder
|
m.SpecialFolder = SpecialFolder
|
||||||
If State = UStates.Missing Then m.State = UStates.Missing : m.Attempts = Attempts
|
If State = UStates.Missing Then m.State = UStates.Missing : m.Attempts = Attempts
|
||||||
|
m.PostText = Text
|
||||||
|
m.PostTextFileSpecialFolder = DownloadTextSpecialFolder
|
||||||
Return m
|
Return m
|
||||||
End Function
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ Namespace API.JustForFans
|
|||||||
Case NameOf(UserAgent) : If Not HeaderValue.IsEmptyString Then Responser.UserAgent = HeaderValue
|
Case NameOf(UserAgent) : If Not HeaderValue.IsEmptyString Then Responser.UserAgent = HeaderValue
|
||||||
End Select
|
End Select
|
||||||
End Sub
|
End Sub
|
||||||
|
<DoNotUse> Friend Overrides Property DownloadText As PropertyValue
|
||||||
|
<DoNotUse> Friend Overrides Property DownloadTextPosts As PropertyValue
|
||||||
|
<DoNotUse> Friend Overrides Property DownloadTextSpecialFolder As PropertyValue
|
||||||
Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean)
|
Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean)
|
||||||
MyBase.New("JustForFans", "justfor.fans", AccName, Temp, My.Resources.SiteResources.JFFIcon_64, My.Resources.SiteResources.JFFPic_76)
|
MyBase.New("JustForFans", "justfor.fans", AccName, Temp, My.Resources.SiteResources.JFFIcon_64, My.Resources.SiteResources.JFFPic_76)
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ Imports PersonalUtilities.Functions.RegularExpressions
|
|||||||
Namespace API.LPSG
|
Namespace API.LPSG
|
||||||
<Manifest("AndyProgram_LPSG")>
|
<Manifest("AndyProgram_LPSG")>
|
||||||
Friend Class SiteSettings : Inherits Base.SiteSettingsBase
|
Friend Class SiteSettings : Inherits Base.SiteSettingsBase
|
||||||
|
<DoNotUse> Friend Overrides Property DownloadText As PropertyValue
|
||||||
|
<DoNotUse> Friend Overrides Property DownloadTextPosts As PropertyValue
|
||||||
|
<DoNotUse> Friend Overrides Property DownloadTextSpecialFolder As PropertyValue
|
||||||
Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean)
|
Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean)
|
||||||
MyBase.New("LPSG", "www.lpsg.com", AccName, Temp, My.Resources.SiteResources.LPSGIcon_48, My.Resources.SiteResources.LPSGPic_32)
|
MyBase.New("LPSG", "www.lpsg.com", AccName, Temp, My.Resources.SiteResources.LPSGIcon_48, My.Resources.SiteResources.LPSGPic_32)
|
||||||
UrlPatternUser = "https://www.lpsg.com/threads/{0}/"
|
UrlPatternUser = "https://www.lpsg.com/threads/{0}/"
|
||||||
|
|||||||
@@ -106,7 +106,8 @@ Namespace API.LPSG
|
|||||||
End Sub
|
End Sub
|
||||||
Protected Overrides Function DownloadingException(ByVal ex As Exception, ByVal Message As String, Optional ByVal FromPE As Boolean = False,
|
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
|
Optional ByVal EObj As Object = Nothing) As Integer
|
||||||
If Responser.StatusCode = Net.HttpStatusCode.ServiceUnavailable Then '503
|
If Responser.StatusCode = Net.HttpStatusCode.ServiceUnavailable Or
|
||||||
|
Responser.StatusCode = Net.HttpStatusCode.Forbidden Then '503, 403
|
||||||
MyMainLOG = $"{ToStringForLog()}: LPSG not available"
|
MyMainLOG = $"{ToStringForLog()}: LPSG not available"
|
||||||
Return 1
|
Return 1
|
||||||
ElseIf Responser.StatusCode = Net.HttpStatusCode.NotFound Then '404
|
ElseIf Responser.StatusCode = Net.HttpStatusCode.NotFound Then '404
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ Namespace API.Mastodon
|
|||||||
<PSetting(Address:=SettingAddress.None)> Friend Overrides Property DownloadModelSearch As Boolean
|
<PSetting(Address:=SettingAddress.None)> Friend Overrides Property DownloadModelSearch As Boolean
|
||||||
<PSetting(Address:=SettingAddress.None)> Friend Overrides Property DownloadModelForceApply As Boolean
|
<PSetting(Address:=SettingAddress.None)> Friend Overrides Property DownloadModelForceApply As Boolean
|
||||||
<PSetting(Address:=SettingAddress.None)> Friend Overrides Property DownloadModelLikes As Boolean
|
<PSetting(Address:=SettingAddress.None)> Friend Overrides Property DownloadModelLikes As Boolean
|
||||||
|
<PSetting(Address:=SettingAddress.None)> Friend Overrides Property DownloadBroadcasts As Boolean
|
||||||
|
<PSetting(Address:=SettingAddress.None)> Friend Overrides Property UserName As String
|
||||||
Friend Sub New(ByVal s As SiteSettings)
|
Friend Sub New(ByVal s As SiteSettings)
|
||||||
MyBase.New(s)
|
MyBase.New(s)
|
||||||
End Sub
|
End Sub
|
||||||
|
|||||||
@@ -76,6 +76,9 @@ Namespace API.Mastodon
|
|||||||
<PropertyOption(IsAuth:=False, ControlText:="User related to my domain",
|
<PropertyOption(IsAuth:=False, ControlText:="User related to my domain",
|
||||||
ControlToolTip:="Open user profiles and user posts through my domain."), PXML, PClonable>
|
ControlToolTip:="Open user profiles and user posts through my domain."), PXML, PClonable>
|
||||||
Friend ReadOnly Property UserRelatedToMyDomain As PropertyValue
|
Friend ReadOnly Property UserRelatedToMyDomain As PropertyValue
|
||||||
|
<DoNotUse> Friend Overrides Property DownloadText As PropertyValue
|
||||||
|
<DoNotUse> Friend Overrides Property DownloadTextPosts As PropertyValue
|
||||||
|
<DoNotUse> Friend Overrides Property DownloadTextSpecialFolder As PropertyValue
|
||||||
#End Region
|
#End Region
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Initializer"
|
#Region "Initializer"
|
||||||
@@ -171,12 +174,12 @@ Namespace API.Mastodon
|
|||||||
With DirectCast(User, UserData)
|
With DirectCast(User, UserData)
|
||||||
If UserRelatedToMyDomain.Value Then
|
If UserRelatedToMyDomain.Value Then
|
||||||
If MyDomain.Value = .UserDomain Then
|
If MyDomain.Value = .UserDomain Then
|
||||||
Return $"https://{ .UserDomain}/@{ .TrueName}"
|
Return $"https://{ .UserDomain}/@{ .NameTrue}"
|
||||||
Else
|
Else
|
||||||
Return $"https://{MyDomain.Value}/@{ .TrueName}@{ .UserDomain}"
|
Return $"https://{MyDomain.Value}/@{ .NameTrue}@{ .UserDomain}"
|
||||||
End If
|
End If
|
||||||
Else
|
Else
|
||||||
Return $"https://{ .UserDomain}/@{ .TrueName}"
|
Return $"https://{ .UserDomain}/@{ .NameTrue}"
|
||||||
End If
|
End If
|
||||||
End With
|
End With
|
||||||
End Function
|
End Function
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ Namespace API.Mastodon
|
|||||||
_UserDomain = d
|
_UserDomain = d
|
||||||
End Set
|
End Set
|
||||||
End Property
|
End Property
|
||||||
Friend Property TrueName As String = String.Empty
|
|
||||||
Private ReadOnly Property MySettings As SiteSettings
|
Private ReadOnly Property MySettings As SiteSettings
|
||||||
Get
|
Get
|
||||||
Return HOST.Source
|
Return HOST.Source
|
||||||
@@ -52,22 +51,21 @@ Namespace API.Mastodon
|
|||||||
Dim l$() = Name.Split("@")
|
Dim l$() = Name.Split("@")
|
||||||
If l.ListExists(2) Then
|
If l.ListExists(2) Then
|
||||||
_UserDomain = l(0)
|
_UserDomain = l(0)
|
||||||
TrueName = l(1)
|
NameTrue = l(1)
|
||||||
Else
|
Else
|
||||||
_UserDomain = MySettings.MyDomain.Value
|
_UserDomain = MySettings.MyDomain.Value
|
||||||
TrueName = Name
|
NameTrue = Name
|
||||||
End If
|
End If
|
||||||
If FriendlyName.IsEmptyString Then FriendlyName = TrueName
|
If FriendlyName.IsEmptyString Then FriendlyName = NameTrue
|
||||||
End If
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
If Loading Then
|
If Loading Then
|
||||||
_UserDomain = Container.Value(Name_UserDomain)
|
_UserDomain = Container.Value(Name_UserDomain)
|
||||||
TrueName = Container.Value(Name_TrueName)
|
|
||||||
obtainNames.Invoke
|
obtainNames.Invoke
|
||||||
Else
|
Else
|
||||||
obtainNames.Invoke
|
obtainNames.Invoke
|
||||||
Container.Add(Name_UserDomain, _UserDomain)
|
Container.Add(Name_UserDomain, _UserDomain)
|
||||||
Container.Add(Name_TrueName, TrueName)
|
Container.Add(Name_TrueName, NameTrue(True))
|
||||||
Container.Value(Name_FriendlyName) = FriendlyName
|
Container.Value(Name_FriendlyName) = FriendlyName
|
||||||
End If
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
@@ -208,12 +206,12 @@ Namespace API.Mastodon
|
|||||||
Dim url$ = $"https://{MyCredentials.Domain}/api/v1/accounts/lookup?acct="
|
Dim url$ = $"https://{MyCredentials.Domain}/api/v1/accounts/lookup?acct="
|
||||||
If Not UserDomain.IsEmptyString Then
|
If Not UserDomain.IsEmptyString Then
|
||||||
If UserDomain = MyCredentials.Domain Then
|
If UserDomain = MyCredentials.Domain Then
|
||||||
url &= $"@{TrueName}"
|
url &= $"@{NameTrue}"
|
||||||
Else
|
Else
|
||||||
url &= $"@{TrueName}@{UserDomain}"
|
url &= $"@{NameTrue}@{UserDomain}"
|
||||||
End If
|
End If
|
||||||
Else
|
Else
|
||||||
url &= $"@{TrueName}"
|
url &= $"@{NameTrue}"
|
||||||
End If
|
End If
|
||||||
Dim r$ = Responser.GetResponse(url)
|
Dim r$ = Responser.GetResponse(url)
|
||||||
If Not r.IsEmptyString Then
|
If Not r.IsEmptyString Then
|
||||||
|
|||||||
@@ -3,5 +3,4 @@ https://github.com/riley-access-labs/onlyfans-dynamic-rules-1/blob/main/dynamicR
|
|||||||
https://github.com/riley-access-labs/onlyfans-dynamic-rules-1/blob/patch-1/dynamicRules.json
|
https://github.com/riley-access-labs/onlyfans-dynamic-rules-1/blob/patch-1/dynamicRules.json
|
||||||
https://github.com/DATAHOARDERS/dynamic-rules/blob/main/onlyfans.json
|
https://github.com/DATAHOARDERS/dynamic-rules/blob/main/onlyfans.json
|
||||||
https://github.com/DIGITALCRIMINAL/dynamic-rules/blob/main/onlyfans.json
|
https://github.com/DIGITALCRIMINAL/dynamic-rules/blob/main/onlyfans.json
|
||||||
https://github.com/deviint/onlyfans-dynamic-rules/blob/main/dynamicRules.json
|
|
||||||
https://github.com/rafa-9/dynamic-rules/blob/main/rules.json
|
https://github.com/rafa-9/dynamic-rules/blob/main/rules.json
|
||||||
@@ -4,8 +4,8 @@ https://github.com/riley-access-labs/onlyfans-dynamic-rules-1/blob/main/dynamicR
|
|||||||
https://github.com/riley-access-labs/onlyfans-dynamic-rules-1/blob/patch-1/dynamicRules.json
|
https://github.com/riley-access-labs/onlyfans-dynamic-rules-1/blob/patch-1/dynamicRules.json
|
||||||
https://github.com/DATAHOARDERS/dynamic-rules/blob/main/onlyfans.json
|
https://github.com/DATAHOARDERS/dynamic-rules/blob/main/onlyfans.json
|
||||||
https://github.com/DIGITALCRIMINAL/dynamic-rules/blob/main/onlyfans.json
|
https://github.com/DIGITALCRIMINAL/dynamic-rules/blob/main/onlyfans.json
|
||||||
https://github.com/deviint/onlyfans-dynamic-rules/blob/main/dynamicRules.json
|
|
||||||
https://github.com/rafa-9/dynamic-rules/blob/main/rules.json
|
https://github.com/rafa-9/dynamic-rules/blob/main/rules.json
|
||||||
|
|
||||||
https://github.com/SneakyOvis/onlyfans-dynamic-rules/blob/main/rules.json
|
https://github.com/SneakyOvis/onlyfans-dynamic-rules/blob/main/rules.json
|
||||||
https://github.com/Growik/onlyfans-dynamic-rules/blob/main/rules.json
|
https://github.com/Growik/onlyfans-dynamic-rules/blob/main/rules.json
|
||||||
|
https://github.com/deviint/onlyfans-dynamic-rules/blob/main/dynamicRules.json
|
||||||
@@ -19,6 +19,7 @@ Namespace API.OnlyFans
|
|||||||
#Region "Declarations"
|
#Region "Declarations"
|
||||||
#Region "Categories"
|
#Region "Categories"
|
||||||
Private Const CAT_OFS As String = "OF-Scraper support"
|
Private Const CAT_OFS As String = "OF-Scraper support"
|
||||||
|
Private Const CAT_ERRORS As String = "Errors"
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Options"
|
#Region "Options"
|
||||||
<PropertyOption(ControlText:="Download timeline", ControlToolTip:="Download user timeline", Category:=DN.CAT_UserDefs), PXML, PClonable>
|
<PropertyOption(ControlText:="Download timeline", ControlToolTip:="Download user timeline", Category:=DN.CAT_UserDefs), PXML, PClonable>
|
||||||
@@ -35,12 +36,20 @@ Namespace API.OnlyFans
|
|||||||
Private Const HeaderUserID As String = "User-Id"
|
Private Const HeaderUserID As String = "User-Id"
|
||||||
Friend Const HeaderXBC As String = "X-Bc"
|
Friend Const HeaderXBC As String = "X-Bc"
|
||||||
Friend Const HeaderAppToken As String = "App-Token"
|
Friend Const HeaderAppToken As String = "App-Token"
|
||||||
|
Private Const AppTokenDefault As String = "33d57ade8c02dbc5a333db99ff9ae26a"
|
||||||
|
Private Const BackendDefault As String = "aio"
|
||||||
|
Private Const Backendhttpx As String = "httpx"
|
||||||
<PropertyOption(ControlText:=HeaderUserID, AllowNull:=False, IsAuth:=True), PClonable(Clone:=False)>
|
<PropertyOption(ControlText:=HeaderUserID, AllowNull:=False, IsAuth:=True), PClonable(Clone:=False)>
|
||||||
Friend ReadOnly Property HH_USER_ID As PropertyValue
|
Friend ReadOnly Property HH_USER_ID As PropertyValue
|
||||||
<PropertyOption(ControlText:=HeaderXBC, AllowNull:=False, IsAuth:=True), PClonable(Clone:=False)>
|
<PropertyOption(ControlText:=HeaderXBC, AllowNull:=False, IsAuth:=True), PClonable(Clone:=False)>
|
||||||
Private ReadOnly Property HH_X_BC As PropertyValue
|
Private ReadOnly Property HH_X_BC As PropertyValue
|
||||||
<PropertyOption(ControlText:=HeaderAppToken, AllowNull:=False, IsAuth:=True), PClonable(Clone:=False)>
|
<PropertyOption(ControlText:=HeaderAppToken, AllowNull:=False, IsAuth:=True), PClonable(Clone:=False)>
|
||||||
Private ReadOnly Property HH_APP_TOKEN As PropertyValue
|
Private ReadOnly Property HH_APP_TOKEN As PropertyValue
|
||||||
|
<PropertyUpdater(NameOf(HH_APP_TOKEN))>
|
||||||
|
Private Function UpdateAppToken() As Boolean
|
||||||
|
HH_APP_TOKEN.Value = AppTokenDefault
|
||||||
|
Return True
|
||||||
|
End Function
|
||||||
<PropertyOption(ControlText:=HeaderBrowser, ControlToolTip:="Can be null", AllowNull:=True,
|
<PropertyOption(ControlText:=HeaderBrowser, ControlToolTip:="Can be null", AllowNull:=True,
|
||||||
InheritanceName:=SettingsCLS.HEADER_DEF_sec_ch_ua, IsAuth:=True), PClonable, PXML(OnlyForChecked:=True)>
|
InheritanceName:=SettingsCLS.HEADER_DEF_sec_ch_ua, IsAuth:=True), PClonable, PXML(OnlyForChecked:=True)>
|
||||||
Private ReadOnly Property HH_BROWSER As PropertyValue
|
Private ReadOnly Property HH_BROWSER As PropertyValue
|
||||||
@@ -72,6 +81,23 @@ Namespace API.OnlyFans
|
|||||||
End If
|
End If
|
||||||
Return String.Empty
|
Return String.Empty
|
||||||
End Function
|
End Function
|
||||||
|
<PropertyOption(ControlText:="Update cookies during requests",
|
||||||
|
ControlToolTip:="If unchecked, cookies will not be updated during requests. Initial cookies will always be used.", IsAuth:=True),
|
||||||
|
PClonable, PXML, HiddenControl>
|
||||||
|
Friend ReadOnly Property EnableCookiesUpdate As PropertyValue
|
||||||
|
#End Region
|
||||||
|
#Region "Errors"
|
||||||
|
<PClonable, PXML("UpdateRules401")> Private ReadOnly Property UpdateRules401_XML As PropertyValue
|
||||||
|
<PropertyOption(ControlText:="Try updating rules when you get a 401 error", Category:=CAT_ERRORS), HiddenControl>
|
||||||
|
Friend ReadOnly Property UpdateRules401 As PropertyValue
|
||||||
|
Get
|
||||||
|
If Not DefaultInstance Is Nothing Then
|
||||||
|
Return DirectCast(DefaultInstance, SiteSettings).UpdateRules401_XML
|
||||||
|
Else
|
||||||
|
Return UpdateRules401_XML
|
||||||
|
End If
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
#End Region
|
#End Region
|
||||||
#Region "OFScraper"
|
#Region "OFScraper"
|
||||||
<PClonable, PXML("OFScraperPath")> Private ReadOnly Property OFScraperPath_XML As PropertyValue
|
<PClonable, PXML("OFScraperPath")> Private ReadOnly Property OFScraperPath_XML As PropertyValue
|
||||||
@@ -98,7 +124,7 @@ Namespace API.OnlyFans
|
|||||||
End Property
|
End Property
|
||||||
Friend Const KeyModeDefault_Default As String = "cdrm"
|
Friend Const KeyModeDefault_Default As String = "cdrm"
|
||||||
<PClonable, PXML("KeyModeDefault")> Private ReadOnly Property KeyModeDefault_XML As PropertyValue
|
<PClonable, PXML("KeyModeDefault")> Private ReadOnly Property KeyModeDefault_XML As PropertyValue
|
||||||
<PropertyOption(ControlText:="key-mode-default", Category:=CAT_OFS)>
|
<PropertyOption(ControlText:="key-mode-default", ControlToolTip:="Examples: cdrm, cdrm2, keydb, manual", Category:=CAT_OFS)>
|
||||||
Friend ReadOnly Property KeyModeDefault As PropertyValue
|
Friend ReadOnly Property KeyModeDefault As PropertyValue
|
||||||
Get
|
Get
|
||||||
If Not DefaultInstance Is Nothing Then
|
If Not DefaultInstance Is Nothing Then
|
||||||
@@ -119,6 +145,80 @@ Namespace API.OnlyFans
|
|||||||
End If
|
End If
|
||||||
End Get
|
End Get
|
||||||
End Property
|
End Property
|
||||||
|
<PClonable, PXML("KEYS_Key")> Private ReadOnly Property OFS_KEYS_Key_XML As PropertyValue
|
||||||
|
<PropertyOption(ControlText:="Private key", ControlToolTip:="Path to the DRM key file 'private_key.pem'", Category:=CAT_OFS)>
|
||||||
|
Friend ReadOnly Property OFS_KEYS_Key As PropertyValue
|
||||||
|
Get
|
||||||
|
If Not DefaultInstance Is Nothing Then
|
||||||
|
Return DirectCast(DefaultInstance, SiteSettings).OFS_KEYS_Key_XML
|
||||||
|
Else
|
||||||
|
Return OFS_KEYS_Key_XML
|
||||||
|
End If
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
<PClonable, PXML("KEYS_ClientID")> Private ReadOnly Property OFS_KEYS_ClientID_XML As PropertyValue
|
||||||
|
<PropertyOption(ControlText:="Client ID", ControlToolTip:="Path to the DRM key file 'client_id.bin'", Category:=CAT_OFS)>
|
||||||
|
Friend ReadOnly Property OFS_KEYS_ClientID As PropertyValue
|
||||||
|
Get
|
||||||
|
If Not DefaultInstance Is Nothing Then
|
||||||
|
Return DirectCast(DefaultInstance, SiteSettings).OFS_KEYS_ClientID_XML
|
||||||
|
Else
|
||||||
|
Return OFS_KEYS_ClientID_XML
|
||||||
|
End If
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
<PropertiesDataChecker({NameOf(KeyModeDefault), NameOf(OFS_KEYS_Key), NameOf(OFS_KEYS_ClientID)})>
|
||||||
|
Private Function OFS_KEYS_CHECKER(ByVal p As IEnumerable(Of PropertyData)) As Boolean
|
||||||
|
Const manualMode$ = "manual"
|
||||||
|
If p.ListExists Then
|
||||||
|
Dim m$ = String.Empty, k$ = String.Empty, cid$ = String.Empty
|
||||||
|
For Each pp As PropertyData In p
|
||||||
|
Select Case pp.Name
|
||||||
|
Case NameOf(KeyModeDefault) : m = pp.Value
|
||||||
|
Case NameOf(OFS_KEYS_Key) : k = pp.Value
|
||||||
|
Case NameOf(OFS_KEYS_ClientID) : cid = pp.Value
|
||||||
|
Case Else : Throw New ArgumentException($"Property name '{pp.Name}' is not implemented", "Property Name")
|
||||||
|
End Select
|
||||||
|
Next
|
||||||
|
If k.IsEmptyString And cid.IsEmptyString Then
|
||||||
|
Return True
|
||||||
|
ElseIf Not k.IsEmptyString And Not cid.IsEmptyString Then
|
||||||
|
If m = manualMode Then
|
||||||
|
Return True
|
||||||
|
Else
|
||||||
|
Return MsgBoxE({$"You are using key files and have selected '{m}' mode." & vbCr &
|
||||||
|
$"To use key files, you should use the '{manualMode}' mode" & vbCr &
|
||||||
|
"Are you sure you want to use this mode?", "Incorrect mode"}, vbExclamation + vbYesNo) = vbYes
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Dim t As New MMessage("", "Key missing",, vbCritical)
|
||||||
|
If k.IsEmptyString Then
|
||||||
|
t.Text = "'Private key' is missing"
|
||||||
|
ElseIf cid.IsEmptyString Then
|
||||||
|
t.Text = "'Client ID' is missing"
|
||||||
|
End If
|
||||||
|
If Not t.Text.IsEmptyString Then t.Show()
|
||||||
|
End If
|
||||||
|
Return False
|
||||||
|
End Function
|
||||||
|
<PClonable, PXML("OFS_BACKEND")> Private ReadOnly Property OFS_BACKEND_XML As PropertyValue
|
||||||
|
<PropertyOption(ControlText:="backend", ControlToolTip:="The value of 'advanced_options' in the configuration" & vbCr &
|
||||||
|
"If you can't download the video, try using 'httpx'", AllowNull:=False, Category:=CAT_OFS)>
|
||||||
|
Friend ReadOnly Property OFS_BACKEND As PropertyValue
|
||||||
|
Get
|
||||||
|
If Not DefaultInstance Is Nothing Then
|
||||||
|
Return DirectCast(DefaultInstance, SiteSettings).OFS_BACKEND_XML
|
||||||
|
Else
|
||||||
|
Return OFS_BACKEND_XML
|
||||||
|
End If
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
<PropertyUpdater(NameOf(OFS_BACKEND))>
|
||||||
|
Private Function OFS_BACKEND_Update() As Boolean
|
||||||
|
DirectCast(If(DefaultInstance, Me), SiteSettings).OFS_BACKEND_XML.Value =
|
||||||
|
CStr(IIf(MsgBoxE({"Select a value for the 'backend' option", "'backend' value"}, vbQuestion,,, {BackendDefault, Backendhttpx}) = 0, BackendDefault, Backendhttpx))
|
||||||
|
Return True
|
||||||
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Initializer"
|
#Region "Initializer"
|
||||||
@@ -151,12 +251,14 @@ Namespace API.OnlyFans
|
|||||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.AcceptEncoding))
|
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.AcceptEncoding))
|
||||||
HH_USER_ID = New PropertyValue(.Value(HeaderUserID), GetType(String), Sub(v) UpdateHeader(NameOf(HH_USER_ID), v))
|
HH_USER_ID = New PropertyValue(.Value(HeaderUserID), GetType(String), Sub(v) UpdateHeader(NameOf(HH_USER_ID), v))
|
||||||
HH_X_BC = New PropertyValue(.Value(HeaderXBC), GetType(String), Sub(v) UpdateHeader(NameOf(HH_X_BC), v))
|
HH_X_BC = New PropertyValue(.Value(HeaderXBC), GetType(String), Sub(v) UpdateHeader(NameOf(HH_X_BC), v))
|
||||||
HH_APP_TOKEN = New PropertyValue(.Value(HeaderAppToken), GetType(String), Sub(v) UpdateHeader(NameOf(HH_APP_TOKEN), v))
|
HH_APP_TOKEN = New PropertyValue(.Value(HeaderAppToken).IfNullOrEmpty(AppTokenDefault), GetType(String), Sub(v) UpdateHeader(NameOf(HH_APP_TOKEN), v))
|
||||||
HH_BROWSER = New PropertyValue(.Value(HeaderBrowser), GetType(String), Sub(v) UpdateHeader(NameOf(HH_BROWSER), v))
|
HH_BROWSER = New PropertyValue(.Value(HeaderBrowser), GetType(String), Sub(v) UpdateHeader(NameOf(HH_BROWSER), v))
|
||||||
End With
|
End With
|
||||||
UserAgent = New PropertyValue(IIf(.UserAgentExists, .UserAgent, String.Empty), GetType(String), Sub(v) UpdateHeader(NameOf(UserAgent), v))
|
UserAgent = New PropertyValue(IIf(.UserAgentExists, .UserAgent, String.Empty), GetType(String), Sub(v) UpdateHeader(NameOf(UserAgent), v))
|
||||||
End With
|
End With
|
||||||
|
|
||||||
|
EnableCookiesUpdate = New PropertyValue(False)
|
||||||
|
|
||||||
DownloadTimeline = New PropertyValue(True)
|
DownloadTimeline = New PropertyValue(True)
|
||||||
DownloadStories = New PropertyValue(True)
|
DownloadStories = New PropertyValue(True)
|
||||||
DownloadHighlights = New PropertyValue(True)
|
DownloadHighlights = New PropertyValue(True)
|
||||||
@@ -177,11 +279,25 @@ Namespace API.OnlyFans
|
|||||||
OFScraperMP4decrypt_XML = New PropertyValue(String.Empty, GetType(String))
|
OFScraperMP4decrypt_XML = New PropertyValue(String.Empty, GetType(String))
|
||||||
KeyModeDefault_XML = New PropertyValue(KeyModeDefault_Default)
|
KeyModeDefault_XML = New PropertyValue(KeyModeDefault_Default)
|
||||||
Keydb_Api_XML = New PropertyValue(String.Empty, GetType(String))
|
Keydb_Api_XML = New PropertyValue(String.Empty, GetType(String))
|
||||||
|
OFS_KEYS_Key_XML = New PropertyValue(String.Empty, GetType(String))
|
||||||
|
OFS_KEYS_ClientID_XML = New PropertyValue(String.Empty, GetType(String))
|
||||||
|
OFS_BACKEND_XML = New PropertyValue(BackendDefault)
|
||||||
|
|
||||||
|
UpdateRules401_XML = New PropertyValue(False)
|
||||||
|
|
||||||
UserRegex = RParams.DMS(String.Format(UserRegexDefaultPattern, "onlyfans.com/"), 1, EDP.ReturnValue)
|
UserRegex = RParams.DMS(String.Format(UserRegexDefaultPattern, "onlyfans.com/"), 1, EDP.ReturnValue)
|
||||||
UrlPatternUser = "https://onlyfans.com/{0}"
|
UrlPatternUser = "https://onlyfans.com/{0}"
|
||||||
ImageVideoContains = "onlyfans.com"
|
ImageVideoContains = "onlyfans.com"
|
||||||
End Sub
|
End Sub
|
||||||
|
Private Const SettingsVersionCurrent As Integer = 1
|
||||||
|
Friend Overrides Sub EndInit()
|
||||||
|
If CInt(SettingsVersion.Value) < SettingsVersionCurrent Then
|
||||||
|
If CStr(HH_APP_TOKEN.Value).IsEmptyString Then HH_APP_TOKEN.Value = AppTokenDefault
|
||||||
|
EnableCookiesUpdate.Value = False
|
||||||
|
SettingsVersion.Value = SettingsVersionCurrent
|
||||||
|
End If
|
||||||
|
MyBase.EndInit()
|
||||||
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "GetInstance"
|
#Region "GetInstance"
|
||||||
Friend Overrides Function GetInstance(ByVal What As ISiteSettings.Download) As IPluginContentProvider
|
Friend Overrides Function GetInstance(ByVal What As ISiteSettings.Download) As IPluginContentProvider
|
||||||
@@ -232,7 +348,7 @@ Namespace API.OnlyFans
|
|||||||
#Region "GetUserUrl, GetUserPostUrl, UserOptions"
|
#Region "GetUserUrl, GetUserPostUrl, UserOptions"
|
||||||
Friend Const UserPostPattern As String = "https://onlyfans.com/{0}/{1}"
|
Friend Const UserPostPattern As String = "https://onlyfans.com/{0}/{1}"
|
||||||
Friend Overrides Function GetUserUrl(ByVal User As IPluginContentProvider) As String
|
Friend Overrides Function GetUserUrl(ByVal User As IPluginContentProvider) As String
|
||||||
Return String.Format(UrlPatternUser, If(User.ID.IsEmptyString, User.Name, $"u{User.ID}"))
|
Return String.Format(UrlPatternUser, If(User.ID.IsEmptyString, User.NameTrue.IfNullOrEmpty(User.Name), $"u{User.ID}"))
|
||||||
End Function
|
End Function
|
||||||
Friend Overrides Function GetUserPostUrl(ByVal User As UserDataBase, ByVal Media As UserMedia) As String
|
Friend Overrides Function GetUserPostUrl(ByVal User As UserDataBase, ByVal Media As UserMedia) As String
|
||||||
If Not Media.Post.ID.IsEmptyString Then
|
If Not Media.Post.ID.IsEmptyString Then
|
||||||
@@ -248,7 +364,8 @@ Namespace API.OnlyFans
|
|||||||
If p.IsEmptyString Then
|
If p.IsEmptyString Then
|
||||||
Return GetUserUrl(User)
|
Return GetUserUrl(User)
|
||||||
Else
|
Else
|
||||||
Return String.Format(UserPostPattern, p, If(User.ID.IsEmptyString, User.Name, $"u{User.ID}"))
|
'Return String.Format(UserPostPattern, p, If(User.ID.IsEmptyString, User.Name, $"u{User.ID}"))
|
||||||
|
Return String.Format(UserPostPattern, p, User.NameTrue)
|
||||||
End If
|
End If
|
||||||
Else
|
Else
|
||||||
Return String.Empty
|
Return String.Empty
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ Namespace API.OnlyFans
|
|||||||
Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object)
|
Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object)
|
||||||
If Not Obj Is Nothing AndAlso TypeOf Obj Is UserExchangeOptions Then
|
If Not Obj Is Nothing AndAlso TypeOf Obj Is UserExchangeOptions Then
|
||||||
With DirectCast(Obj, UserExchangeOptions)
|
With DirectCast(Obj, UserExchangeOptions)
|
||||||
|
.ApplyBase(Me)
|
||||||
MediaDownloadTimeline = .DownloadTimeline
|
MediaDownloadTimeline = .DownloadTimeline
|
||||||
MediaDownloadStories = .DownloadStories
|
MediaDownloadStories = .DownloadStories
|
||||||
MediaDownloadHighlights = .DownloadHighlights
|
MediaDownloadHighlights = .DownloadHighlights
|
||||||
@@ -84,6 +85,7 @@ Namespace API.OnlyFans
|
|||||||
Private _OFScraperExists As Boolean = False
|
Private _OFScraperExists As Boolean = False
|
||||||
Private OFSCache As CacheKeeper = Nothing
|
Private OFSCache As CacheKeeper = Nothing
|
||||||
Private _AbsMediaIndex As Integer = 0
|
Private _AbsMediaIndex As Integer = 0
|
||||||
|
Private _DownloadedPostsSession As Integer = 0
|
||||||
Private FunctionErr As Integer = FunctionErrDef
|
Private FunctionErr As Integer = FunctionErrDef
|
||||||
Private Const FunctionErrDef As Integer = -100
|
Private Const FunctionErrDef As Integer = -100
|
||||||
Private Sub ValidateOFScraper()
|
Private Sub ValidateOFScraper()
|
||||||
@@ -95,11 +97,12 @@ Namespace API.OnlyFans
|
|||||||
If Not MySettings.SessionAborted Then
|
If Not MySettings.SessionAborted Then
|
||||||
ValidateOFScraper()
|
ValidateOFScraper()
|
||||||
_AbsMediaIndex = 0
|
_AbsMediaIndex = 0
|
||||||
|
_DownloadedPostsSession = 0
|
||||||
FunctionErr = FunctionErrDef
|
FunctionErr = FunctionErrDef
|
||||||
If Not CCookie Is Nothing Then CCookie.Dispose()
|
If Not CCookie Is Nothing Then CCookie.Dispose()
|
||||||
CCookie = Responser.Cookies.Copy
|
CCookie = Responser.Cookies.Copy
|
||||||
Responser.Cookies.Clear()
|
Responser.Cookies.Clear()
|
||||||
AddHandler Responser.ResponseReceived, AddressOf Responser_ResponseReceived
|
If MySettings.EnableCookiesUpdate.Value Then AddHandler Responser.ResponseReceived, AddressOf Responser_ResponseReceived
|
||||||
UpdateCookieHeader()
|
UpdateCookieHeader()
|
||||||
|
|
||||||
If Not IsSavedPosts Then
|
If Not IsSavedPosts Then
|
||||||
@@ -113,13 +116,14 @@ Namespace API.OnlyFans
|
|||||||
If MediaDownloadHighlights And FunctionErr = FunctionErrDef Then DownloadHighlights(Token)
|
If MediaDownloadHighlights And FunctionErr = FunctionErrDef Then DownloadHighlights(Token)
|
||||||
If MediaDownloadChatMedia And FunctionErr = FunctionErrDef Then DownloadChatMedia(0, Token)
|
If MediaDownloadChatMedia And FunctionErr = FunctionErrDef Then DownloadChatMedia(0, Token)
|
||||||
End If
|
End If
|
||||||
|
If _TempMediaList.Count > 0 And Not _NameUpdated Then GetUserID(True)
|
||||||
End If
|
End If
|
||||||
Finally
|
Finally
|
||||||
Responser_ResponseReceived_RemoveHandler()
|
Responser_ResponseReceived_RemoveHandler()
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
Protected Overrides Sub Responser_ResponseReceived(ByVal Sender As Object, ByVal e As WebDataResponse)
|
Protected Overrides Sub Responser_ResponseReceived(ByVal Sender As Object, ByVal e As WebDataResponse)
|
||||||
If e.CookiesExists Then
|
If e.CookiesExists And CBool(MySettings.EnableCookiesUpdate.Value) Then
|
||||||
CCookie.Update(e.Cookies, CookieKeeper.UpdateModes.ReplaceByNameAll,, EDP.ReturnValue)
|
CCookie.Update(e.Cookies, CookieKeeper.UpdateModes.ReplaceByNameAll,, EDP.ReturnValue)
|
||||||
UpdateCookieHeader()
|
UpdateCookieHeader()
|
||||||
End If
|
End If
|
||||||
@@ -144,7 +148,7 @@ Namespace API.OnlyFans
|
|||||||
Dim tmpCursor$ = String.Empty
|
Dim tmpCursor$ = String.Empty
|
||||||
Dim hasMore As Boolean = False
|
Dim hasMore As Boolean = False
|
||||||
Dim path$ = String.Empty
|
Dim path$ = String.Empty
|
||||||
Dim postDate$, postID$
|
Dim postDate$, postID$, txt$
|
||||||
Dim n As EContainer
|
Dim n As EContainer
|
||||||
Dim mediaList As List(Of UserMedia)
|
Dim mediaList As List(Of UserMedia)
|
||||||
Dim mediaResult As Boolean
|
Dim mediaResult As Boolean
|
||||||
@@ -189,9 +193,21 @@ Namespace API.OnlyFans
|
|||||||
Case DateResult.Exit : Exit Sub
|
Case DateResult.Exit : Exit Sub
|
||||||
End Select
|
End Select
|
||||||
|
|
||||||
|
txt = n.Value("text")
|
||||||
|
|
||||||
mediaResult = False
|
mediaResult = False
|
||||||
mediaList = TryCreateMedia(n, postID, postDate, mediaResult)
|
mediaList = TryCreateMedia(n, postID, postDate, mediaResult,,,,, txt)
|
||||||
If mediaResult Then _TempMediaList.ListAddList(mediaList, LNC)
|
If mediaResult Then
|
||||||
|
_TempMediaList.ListAddList(mediaList, LNC)
|
||||||
|
_DownloadedPostsSession += 1
|
||||||
|
ElseIf Not txt.IsEmptyString Then
|
||||||
|
_TempMediaList.ListAddValue(New UserMedia(postID, UTypes.Text) With {
|
||||||
|
.Post = New UserPost(postID, AConvert(Of Date)(postDate, DateProvider, Nothing)),
|
||||||
|
.PostText = txt,
|
||||||
|
.PostTextFileSpecialFolder = DownloadTextSpecialFolder,
|
||||||
|
.PostTextFile = $"{postID}.txt"
|
||||||
|
}, LNC)
|
||||||
|
End If
|
||||||
Next
|
Next
|
||||||
Else
|
Else
|
||||||
hasMore = False
|
hasMore = False
|
||||||
@@ -202,7 +218,10 @@ Namespace API.OnlyFans
|
|||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
|
|
||||||
If hasMore Then
|
If DownloadTopCount.HasValue AndAlso DownloadTopCount.Value <= _DownloadedPostsSession Then
|
||||||
|
_complete = True
|
||||||
|
Exit Sub
|
||||||
|
ElseIf hasMore Then
|
||||||
If IsSavedPosts Then tmpCursor = CInt(Cursor.IfNullOrEmpty(0)) + 10
|
If IsSavedPosts Then tmpCursor = CInt(Cursor.IfNullOrEmpty(0)) + 10
|
||||||
DownloadTimeline(tmpCursor, Token)
|
DownloadTimeline(tmpCursor, Token)
|
||||||
End If
|
End If
|
||||||
@@ -405,14 +424,14 @@ Namespace API.OnlyFans
|
|||||||
Private Function TryCreateMedia(ByVal n As EContainer, ByVal PostID As String, Optional ByVal PostDate As String = Nothing,
|
Private Function TryCreateMedia(ByVal n As EContainer, ByVal PostID As String, Optional ByVal PostDate As String = Nothing,
|
||||||
Optional ByRef Result As Boolean = False, Optional ByVal IsHL As Boolean = False,
|
Optional ByRef Result As Boolean = False, Optional ByVal IsHL As Boolean = False,
|
||||||
Optional ByVal SpecFolder As String = Nothing, Optional ByVal PostUserID As String = Nothing,
|
Optional ByVal SpecFolder As String = Nothing, Optional ByVal PostUserID As String = Nothing,
|
||||||
Optional ByVal TryUseOFS As Boolean = True) As List(Of UserMedia)
|
Optional ByVal TryUseOFS As Boolean = True, Optional ByVal PostText As String = Nothing) As List(Of UserMedia)
|
||||||
Dim postUrl$, postUrlBase$, ext$
|
Dim postUrl$, postUrlBase$, ext$
|
||||||
Dim t As UTypes
|
Dim t As UTypes
|
||||||
Dim mList As New List(Of UserMedia)
|
Dim mList As New List(Of UserMedia)
|
||||||
Result = False
|
Result = False
|
||||||
With n("media")
|
With n("media")
|
||||||
If .ListExists Then
|
If .ListExists Then
|
||||||
For Each m In .Self
|
For Each m As EContainer In .Self
|
||||||
postUrl = GetMediaURL(m)
|
postUrl = GetMediaURL(m)
|
||||||
'If IsHL Then
|
'If IsHL Then
|
||||||
' 'postUrl = m.Value({"files", "source"}, "url")
|
' 'postUrl = m.Value({"files", "source"}, "url")
|
||||||
@@ -421,10 +440,11 @@ Namespace API.OnlyFans
|
|||||||
' 'postUrl = m.Value({"source"}, "source").IfNullOrEmpty(m.Value("full"))
|
' 'postUrl = m.Value({"source"}, "source").IfNullOrEmpty(m.Value("full"))
|
||||||
' postUrl = GetMediaURL(m)
|
' postUrl = GetMediaURL(m)
|
||||||
'End If
|
'End If
|
||||||
|
If m.Value("canView").FromXML(Of Boolean)(True) Then
|
||||||
postUrlBase = String.Empty
|
postUrlBase = String.Empty
|
||||||
Select Case m.Value("type")
|
Select Case m.Value("type")
|
||||||
Case "photo" : t = UTypes.Picture : ext = "jpg"
|
Case "photo" : t = UTypes.Picture : ext = "jpg"
|
||||||
Case "video"
|
Case "video", "gif"
|
||||||
t = UTypes.Video
|
t = UTypes.Video
|
||||||
ext = "mp4"
|
ext = "mp4"
|
||||||
If postUrl.IsEmptyString And Not IsHL And TryUseOFS Then
|
If postUrl.IsEmptyString And Not IsHL And TryUseOFS Then
|
||||||
@@ -438,7 +458,9 @@ Namespace API.OnlyFans
|
|||||||
If Not t = UTypes.Undefined And (Not postUrl.IsEmptyString Or t = UTypes.VideoPre) Then
|
If Not t = UTypes.Undefined And (Not postUrl.IsEmptyString Or t = UTypes.VideoPre) Then
|
||||||
Dim media As New UserMedia(postUrl.IfNullOrEmpty(IIf(t = UTypes.VideoPre, $"{t}{_AbsMediaIndex}", String.Empty)), t) With {
|
Dim media As New UserMedia(postUrl.IfNullOrEmpty(IIf(t = UTypes.VideoPre, $"{t}{_AbsMediaIndex}", String.Empty)), t) With {
|
||||||
.Post = New UserPost(PostID, AConvert(Of Date)(PostDate, DateProvider, Nothing)),
|
.Post = New UserPost(PostID, AConvert(Of Date)(PostDate, DateProvider, Nothing)),
|
||||||
.SpecialFolder = SpecFolder
|
.SpecialFolder = SpecFolder,
|
||||||
|
.PostText = PostText,
|
||||||
|
.PostTextFileSpecialFolder = DownloadTextSpecialFolder
|
||||||
}
|
}
|
||||||
If postUrlBase.IsEmptyString And Not IsSingleObjectDownload Then postUrlBase = GetPostUrl(Me, media)
|
If postUrlBase.IsEmptyString And Not IsSingleObjectDownload Then postUrlBase = GetPostUrl(Me, media)
|
||||||
If Not postUrlBase.IsEmptyString Then media.URL_BASE = postUrlBase
|
If Not postUrlBase.IsEmptyString Then media.URL_BASE = postUrlBase
|
||||||
@@ -446,37 +468,33 @@ Namespace API.OnlyFans
|
|||||||
Result = True
|
Result = True
|
||||||
mList.Add(media)
|
mList.Add(media)
|
||||||
End If
|
End If
|
||||||
|
End If
|
||||||
Next
|
Next
|
||||||
End If
|
End If
|
||||||
End With
|
End With
|
||||||
Return mList
|
Return mList
|
||||||
End Function
|
End Function
|
||||||
Private Sub GetUserID()
|
Private _NameUpdated As Boolean = False
|
||||||
|
Private Sub GetUserID(Optional ByVal UpdateNameOnly As Boolean = False)
|
||||||
Const brTag$ = "<br />"
|
Const brTag$ = "<br />"
|
||||||
Dim path$ = $"/api2/v2/users/{Name}"
|
Dim path$ = $"/api2/v2/users/{IIf(UpdateNameOnly, $"u{ID}", Name)}"
|
||||||
Dim url$ = String.Format(BaseUrlPattern, path)
|
Dim url$ = String.Format(BaseUrlPattern, path)
|
||||||
Try
|
Try
|
||||||
If ID.IsEmptyString AndAlso UpdateSignature(path) Then
|
If (ID.IsEmptyString Or UpdateNameOnly) AndAlso UpdateSignature(path) Then
|
||||||
Dim r$ = Responser.GetResponse(url)
|
Dim r$ = Responser.GetResponse(url)
|
||||||
If Not r.IsEmptyString Then
|
If Not r.IsEmptyString Then
|
||||||
Using j As EContainer = JsonDocument.Parse(r)
|
Using j As EContainer = JsonDocument.Parse(r)
|
||||||
If j.ListExists Then
|
If j.ListExists Then
|
||||||
|
NameTrue = j.Value("username")
|
||||||
|
_NameUpdated = True
|
||||||
|
If UpdateNameOnly Then Exit Sub
|
||||||
ID = j.Value("id")
|
ID = j.Value("id")
|
||||||
If Not ID.IsEmptyString Then _ForceSaveUserInfo = True
|
|
||||||
UserSiteNameUpdate(j.Value("name"))
|
UserSiteNameUpdate(j.Value("name"))
|
||||||
Dim descr$ = j.Value("about")
|
Dim descr$ = j.Value("about")
|
||||||
If Not descr.IsEmptyString Then descr = descr.Replace(brTag, String.Empty)
|
If Not descr.IsEmptyString Then descr = descr.Replace(brTag, String.Empty)
|
||||||
UserDescriptionUpdate(descr)
|
UserDescriptionUpdate(descr)
|
||||||
Dim a As Action(Of String) = Sub(ByVal address As String)
|
SimpleDownloadAvatar(j.Value("avatar"))
|
||||||
If Not address.IsEmptyString Then
|
SimpleDownloadAvatar(j.Value("header"))
|
||||||
Dim f As SFile = address
|
|
||||||
f.Separator = "\"
|
|
||||||
f.Path = DownloadContentDefault_GetRootDir()
|
|
||||||
If Not f.Exists Then GetWebFile(address, f, EDP.None)
|
|
||||||
End If
|
|
||||||
End Sub
|
|
||||||
a.Invoke(j.Value("avatar"))
|
|
||||||
a.Invoke(j.Value("header"))
|
|
||||||
End If
|
End If
|
||||||
End Using
|
End Using
|
||||||
End If
|
End If
|
||||||
@@ -608,11 +626,12 @@ Namespace API.OnlyFans
|
|||||||
Const requestPattern$ = """{0}"" manual --config ""{1}"" --url {2}"
|
Const requestPattern$ = """{0}"" manual --config ""{1}"" --url {2}"
|
||||||
Dim conf As SFile = OFS_CreateConfig()
|
Dim conf As SFile = OFS_CreateConfig()
|
||||||
If conf.Exists Then
|
If conf.Exists Then
|
||||||
|
If Not _NameUpdated Then GetUserID(True)
|
||||||
Dim command$ = String.Format(requestPattern, MySettings.OFScraperPath.Value, conf, URL)
|
Dim command$ = String.Format(requestPattern, MySettings.OFScraperPath.Value, conf, URL)
|
||||||
'#If DEBUG Then
|
'#If DEBUG Then
|
||||||
'Debug.WriteLine(command)
|
'Debug.WriteLine(command)
|
||||||
'#End If
|
'#End If
|
||||||
Using b As New TokenBatch(Token) : b.Execute(command) : End Using
|
Using b As New TokenBatch(Token) With {.DebugMode = False} : b.Execute(command) : End Using
|
||||||
Return SFile.GetFiles(conf, "*.mp4", IO.SearchOption.AllDirectories, EDP.ReturnValue)
|
Return SFile.GetFiles(conf, "*.mp4", IO.SearchOption.AllDirectories, EDP.ReturnValue)
|
||||||
End If
|
End If
|
||||||
Return Nothing
|
Return Nothing
|
||||||
@@ -623,7 +642,13 @@ Namespace API.OnlyFans
|
|||||||
Private Function OFS_CreateConfig() As SFile
|
Private Function OFS_CreateConfig() As SFile
|
||||||
Try
|
Try
|
||||||
Const confMainPattern$ = "{0}"": ""([^""]*)"""
|
Const confMainPattern$ = "{0}"": ""([^""]*)"""
|
||||||
|
Const confMainPattern_Keys$ = "{0}"": ([^,]*)"
|
||||||
Const confMainPatternRulesManual$ = "DYNAMIC_RULE"": (""[^""]*"")"
|
Const confMainPatternRulesManual$ = "DYNAMIC_RULE"": (""[^""]*"")"
|
||||||
|
|
||||||
|
Const m1 As Byte = 0 'not rules
|
||||||
|
Const m2 As Byte = 1 'rules
|
||||||
|
Const m3 As Byte = 2 'keys
|
||||||
|
|
||||||
If OFSCache Is Nothing Then OFSCache = If(IsSingleObjectDownload, Settings.Cache.NewInstance, CreateCache())
|
If OFSCache Is Nothing Then OFSCache = If(IsSingleObjectDownload, Settings.Cache.NewInstance, CreateCache())
|
||||||
Dim currentCache As CacheKeeper = OFSCache.NewInstance
|
Dim currentCache As CacheKeeper = OFSCache.NewInstance
|
||||||
currentCache.Validate()
|
currentCache.Validate()
|
||||||
@@ -637,35 +662,48 @@ Namespace API.OnlyFans
|
|||||||
CType(Function(input) replaceValue, Func(Of String, String)), String.Empty, EDP.ReturnValue)
|
CType(Function(input) replaceValue, Func(Of String, String)), String.Empty, EDP.ReturnValue)
|
||||||
Dim ff As SFile
|
Dim ff As SFile
|
||||||
configText = f.GetText
|
configText = f.GetText
|
||||||
Dim updateConf As Action(Of String, String, Boolean) =
|
Dim updateConf As Action(Of String, String, Byte) =
|
||||||
Sub(ByVal patternValue As String, ByVal __replaceValue As String, ByVal __isRules As Boolean)
|
Sub(ByVal patternValue As String, ByVal __replaceValue As String, ByVal mode As Byte)
|
||||||
rp.Pattern = String.Format(IIf(__isRules, confMainPatternRulesManual, confMainPattern), patternValue)
|
Select Case mode
|
||||||
|
Case m1 : rp.Pattern = String.Format(confMainPattern, patternValue)
|
||||||
|
Case m2 : rp.Pattern = String.Format(confMainPatternRulesManual, patternValue)
|
||||||
|
Case m3 : rp.Pattern = String.Format(confMainPattern_Keys, patternValue) : __replaceValue = $"""{__replaceValue}"""
|
||||||
|
Case Else : Throw New ArgumentException($"Mode '{mode}' is not implemented", "mode")
|
||||||
|
End Select
|
||||||
rp.Nothing = configText
|
rp.Nothing = configText
|
||||||
replaceValue = __replaceValue
|
replaceValue = __replaceValue
|
||||||
configText = RegexReplace(configText, rp)
|
configText = RegexReplace(configText, rp)
|
||||||
End Sub
|
End Sub
|
||||||
If Not configText.IsEmptyString Then
|
If Not configText.IsEmptyString Then
|
||||||
updateConf("save_location", cacheRoot.PathNoSeparator.Replace("\", "/"), False)
|
updateConf("save_location", cacheRoot.PathNoSeparator.Replace("\", "/"), m1)
|
||||||
If ACheck(MySettings.OFScraperMP4decrypt.Value) Then
|
If ACheck(MySettings.OFScraperMP4decrypt.Value) Then
|
||||||
ff = CStr(MySettings.OFScraperMP4decrypt.Value)
|
ff = CStr(MySettings.OFScraperMP4decrypt.Value)
|
||||||
If ff.Exists Then updateConf("mp4decrypt", ff.ToString.Replace("\", "/"), False)
|
If ff.Exists Then updateConf("mp4decrypt", ff.ToString.Replace("\", "/"), m1)
|
||||||
End If
|
End If
|
||||||
If Settings.FfmpegFile.Exists Then updateConf("ffmpeg", Settings.FfmpegFile.File.ToString.Replace("\", "/"), False)
|
If Settings.FfmpegFile.Exists Then updateConf("ffmpeg", Settings.FfmpegFile.File.ToString.Replace("\", "/"), m1)
|
||||||
updateConf("key-mode-default", CStr(MySettings.KeyModeDefault.Value).IfNullOrEmpty(SiteSettings.KeyModeDefault_Default), False)
|
|
||||||
updateConf("keydb_api", CStr(MySettings.Keydb_Api.Value), False)
|
updateConf("key-mode-default", CStr(MySettings.KeyModeDefault.Value).IfNullOrEmpty(SiteSettings.KeyModeDefault_Default), m1)
|
||||||
|
updateConf("keydb_api", CStr(MySettings.Keydb_Api.Value), m1)
|
||||||
|
updateConf("backend", CStr(MySettings.OFS_BACKEND.Value), m1)
|
||||||
|
|
||||||
|
If Not CStr(MySettings.OFS_KEYS_Key.Value).IsEmptyString And Not CStr(MySettings.OFS_KEYS_ClientID.Value).IsEmptyString Then
|
||||||
|
updateConf("private-key", CStr(MySettings.OFS_KEYS_Key.Value).Replace("\", "/"), m3)
|
||||||
|
updateConf("client-id", CStr(MySettings.OFS_KEYS_ClientID.Value).Replace("\", "/"), m3)
|
||||||
|
End If
|
||||||
|
|
||||||
If Rules.RulesReplaceConfig Then
|
If Rules.RulesReplaceConfig Then
|
||||||
If Rules.RulesConfigManualMode Then
|
If Rules.RulesConfigManualMode Then
|
||||||
updateConf(DynamicRulesEnv.DynamicRulesConfig_Mode_NodeName, "manual", False)
|
updateConf(DynamicRulesEnv.DynamicRulesConfig_Mode_NodeName, "manual", m1)
|
||||||
configText = configText.Replace(DynamicRulesEnv.DynamicRulesConfigNodeName_URL, DynamicRulesEnv.DynamicRulesConfigNodeName_RULES)
|
configText = configText.Replace(DynamicRulesEnv.DynamicRulesConfigNodeName_URL, DynamicRulesEnv.DynamicRulesConfigNodeName_RULES)
|
||||||
updateConf(DynamicRulesEnv.DynamicRulesConfigNodeName_RULES, Rules.CurrentContainerRulesText, True)
|
updateConf(DynamicRulesEnv.DynamicRulesConfigNodeName_RULES, Rules.CurrentContainerRulesText, m2)
|
||||||
Else
|
Else
|
||||||
Dim confUrlNode$ = If(Rules.RulesConstants.ContainsKey(DynamicRulesEnv.DynamicRulesConfigNodeName_URL_CONST_NAME),
|
Dim confUrlNode$ = If(Rules.RulesConstants.ContainsKey(DynamicRulesEnv.DynamicRulesConfigNodeName_URL_CONST_NAME),
|
||||||
Rules.RulesConstants(DynamicRulesEnv.DynamicRulesConfigNodeName_URL_CONST_NAME),
|
Rules.RulesConstants(DynamicRulesEnv.DynamicRulesConfigNodeName_URL_CONST_NAME),
|
||||||
DynamicRulesEnv.DynamicRulesConfigNodeName_URL)
|
DynamicRulesEnv.DynamicRulesConfigNodeName_URL)
|
||||||
updateConf(DynamicRulesEnv.DynamicRulesConfigNodeName_URL, Rules.CurrentRule.UrlRaw, False)
|
updateConf(DynamicRulesEnv.DynamicRulesConfigNodeName_URL, Rules.CurrentRule.UrlRaw, m1)
|
||||||
configText = configText.Replace(DynamicRulesEnv.DynamicRulesConfigNodeName_URL, confUrlNode)
|
configText = configText.Replace(DynamicRulesEnv.DynamicRulesConfigNodeName_URL, confUrlNode)
|
||||||
If Rules.RulesConstants.ContainsKey(DynamicRulesEnv.DynamicRulesConfig_Mode_NodeName) Then _
|
If Rules.RulesConstants.ContainsKey(DynamicRulesEnv.DynamicRulesConfig_Mode_NodeName) Then _
|
||||||
updateConf(DynamicRulesEnv.DynamicRulesConfig_Mode_NodeName, Rules.RulesConstants(DynamicRulesEnv.DynamicRulesConfig_Mode_NodeName), False)
|
updateConf(DynamicRulesEnv.DynamicRulesConfig_Mode_NodeName, Rules.RulesConstants(DynamicRulesEnv.DynamicRulesConfig_Mode_NodeName), m1)
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
f = currentCache
|
f = currentCache
|
||||||
@@ -720,6 +758,7 @@ Namespace API.OnlyFans
|
|||||||
If IsSingleObjectDownload Then
|
If IsSingleObjectDownload Then
|
||||||
URL = Media.URL_BASE
|
URL = Media.URL_BASE
|
||||||
Else
|
Else
|
||||||
|
If Not _NameUpdated Then GetUserID(True)
|
||||||
URL = GetPostUrl(Me, Media)
|
URL = GetPostUrl(Me, Media)
|
||||||
End If
|
End If
|
||||||
If Not URL.IsEmptyString Then
|
If Not URL.IsEmptyString Then
|
||||||
@@ -760,14 +799,20 @@ Namespace API.OnlyFans
|
|||||||
Private _DownloadingException_AuthFileUpdate As Boolean = False
|
Private _DownloadingException_AuthFileUpdate As Boolean = False
|
||||||
Protected Overrides Function DownloadingException(ByVal ex As Exception, ByVal Message As String, Optional ByVal FromPE As Boolean = False,
|
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
|
Optional ByVal EObj As Object = Nothing) As Integer
|
||||||
If Responser.StatusCode = Net.HttpStatusCode.BadRequest Then '400
|
If Responser.StatusCode = Net.HttpStatusCode.BadRequest Or
|
||||||
|
(Responser.StatusCode = Net.HttpStatusCode.Unauthorized And CBool(MySettings.UpdateRules401.Value)) Then '400, [401]
|
||||||
If Not _DownloadingException_AuthFileUpdate AndAlso Rules.Update(True) Then
|
If Not _DownloadingException_AuthFileUpdate AndAlso Rules.Update(True) Then
|
||||||
_DownloadingException_AuthFileUpdate = True
|
_DownloadingException_AuthFileUpdate = True
|
||||||
Return 2
|
Return 2
|
||||||
Else
|
Else
|
||||||
MySettings.SessionAborted = True
|
MySettings.SessionAborted = True
|
||||||
MyMainLOG = $"{ToStringForLog()} [{CInt(Responser.StatusCode)}]: OnlyFans credentials expired"
|
MyMainLOG = $"{ToStringForLog()} [{CInt(Responser.StatusCode)}]: OnlyFans credentials expired"
|
||||||
|
If Responser.StatusCode = Net.HttpStatusCode.BadRequest Then
|
||||||
Return 1
|
Return 1
|
||||||
|
Else
|
||||||
|
MyMainLOG = $"{ToStringForLog()}: Rules updated (401)"
|
||||||
|
Return 3
|
||||||
|
End If
|
||||||
End If
|
End If
|
||||||
ElseIf Responser.StatusCode = Net.HttpStatusCode.NotFound Then '404
|
ElseIf Responser.StatusCode = Net.HttpStatusCode.NotFound Then '404
|
||||||
UserExists = False
|
UserExists = False
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
' but WITHOUT ANY WARRANTY
|
' but WITHOUT ANY WARRANTY
|
||||||
Imports SCrawler.Plugin.Attributes
|
Imports SCrawler.Plugin.Attributes
|
||||||
Namespace API.OnlyFans
|
Namespace API.OnlyFans
|
||||||
Friend Class UserExchangeOptions
|
Friend Class UserExchangeOptions : Inherits Base.EditorExchangeOptionsBase
|
||||||
<PSetting(NameOf(SiteSettings.DownloadTimeline), NameOf(MySettings))>
|
<PSetting(NameOf(SiteSettings.DownloadTimeline), NameOf(MySettings))>
|
||||||
Friend Property DownloadTimeline As Boolean
|
Friend Property DownloadTimeline As Boolean
|
||||||
<PSetting(NameOf(SiteSettings.DownloadStories), NameOf(MySettings))>
|
<PSetting(NameOf(SiteSettings.DownloadStories), NameOf(MySettings))>
|
||||||
@@ -18,7 +18,12 @@ Namespace API.OnlyFans
|
|||||||
<PSetting(NameOf(SiteSettings.DownloadChatMedia), NameOf(MySettings))>
|
<PSetting(NameOf(SiteSettings.DownloadChatMedia), NameOf(MySettings))>
|
||||||
Friend Property DownloadChatMedia As Boolean
|
Friend Property DownloadChatMedia As Boolean
|
||||||
Private ReadOnly MySettings As SiteSettings
|
Private ReadOnly MySettings As SiteSettings
|
||||||
|
<PSetting(Address:=SettingAddress.None)> Friend Overrides Property UserName As String
|
||||||
|
Private Sub New()
|
||||||
|
End Sub
|
||||||
Friend Sub New(ByVal u As UserData)
|
Friend Sub New(ByVal u As UserData)
|
||||||
|
MyBase.New(u)
|
||||||
|
_ApplyBase_Name = False
|
||||||
DownloadTimeline = u.MediaDownloadTimeline
|
DownloadTimeline = u.MediaDownloadTimeline
|
||||||
DownloadStories = u.MediaDownloadStories
|
DownloadStories = u.MediaDownloadStories
|
||||||
DownloadHighlights = u.MediaDownloadHighlights
|
DownloadHighlights = u.MediaDownloadHighlights
|
||||||
@@ -26,6 +31,8 @@ Namespace API.OnlyFans
|
|||||||
MySettings = u.HOST.Source
|
MySettings = u.HOST.Source
|
||||||
End Sub
|
End Sub
|
||||||
Friend Sub New(ByVal s As SiteSettings)
|
Friend Sub New(ByVal s As SiteSettings)
|
||||||
|
MyBase.New(s)
|
||||||
|
_ApplyBase_Name = False
|
||||||
DownloadTimeline = s.DownloadTimeline.Value
|
DownloadTimeline = s.DownloadTimeline.Value
|
||||||
DownloadStories = s.DownloadStories.Value
|
DownloadStories = s.DownloadStories.Value
|
||||||
DownloadHighlights = s.DownloadHighlights.Value
|
DownloadHighlights = s.DownloadHighlights.Value
|
||||||
|
|||||||
@@ -7,9 +7,18 @@
|
|||||||
' 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.Globalization
|
Imports System.Globalization
|
||||||
|
Imports System.Text.RegularExpressions
|
||||||
|
Imports PersonalUtilities.Tools.Web.Clients
|
||||||
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
Namespace API.Pinterest
|
Namespace API.Pinterest
|
||||||
Friend Module Declarations
|
Friend Module Declarations
|
||||||
Friend ReadOnly DateProvider As ADateTime = GetDateProvider()
|
Friend ReadOnly DateProvider As ADateTime = GetDateProvider()
|
||||||
|
Friend ReadOnly PwsHeader As New HttpHeader("x-pinterest-pws-handler", "www/[username]/pins.js")
|
||||||
|
Friend ReadOnly GdlUrlPattern As RParams = RParams.DM(Base.GDL.GDLBatch.UrlLibStart.Replace("[", "\[").Replace("]", "\]") &
|
||||||
|
"([^""]+?)""(GET [^""]+)""", 0, EDP.ReturnValue)
|
||||||
|
Friend ReadOnly SubBoardRegEx As RParams = RParams.DMS("\[pinterest\]\[debug\] Using PinterestSectionExtractor for '[^']+id:(\d+)'", 1,
|
||||||
|
RegexOptions.IgnoreCase, EDP.ReturnValue)
|
||||||
|
Friend ReadOnly BoardInfoRootNode As String() = {"resource_response", "data"}
|
||||||
Private Function GetDateProvider() As ADateTime
|
Private Function GetDateProvider() As ADateTime
|
||||||
Dim n As DateTimeFormatInfo = CultureInfo.GetCultureInfo("en-us").DateTimeFormat.Clone
|
Dim n As DateTimeFormatInfo = CultureInfo.GetCultureInfo("en-us").DateTimeFormat.Clone
|
||||||
n.FullDateTimePattern = "ddd dd MMM yyyy HH:mm:ss"
|
n.FullDateTimePattern = "ddd dd MMM yyyy HH:mm:ss"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
|
' Copyright (C) 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,15 @@
|
|||||||
'
|
'
|
||||||
' 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 API.XVIDEOS
|
Imports SCrawler.Plugin.Attributes
|
||||||
Friend Class UserExchangeOptions : Inherits Xhamster.UserExchangeOptions
|
Namespace API.Pinterest
|
||||||
Friend Sub New()
|
Friend Class EditorExchangeOptions
|
||||||
End Sub
|
<PSetting(Caption:="Get Sub-Boards", ToolTip:="Extract the Sub-Boards from the boards and download them")>
|
||||||
|
Friend Property ExtractSubBoards As Boolean = True
|
||||||
Friend Sub New(ByVal u As UserData)
|
Friend Sub New(ByVal u As UserData)
|
||||||
QueryString = u.QueryString
|
ExtractSubBoards = u.ExtractSubBoards
|
||||||
|
End Sub
|
||||||
|
Friend Sub New()
|
||||||
End Sub
|
End Sub
|
||||||
End Class
|
End Class
|
||||||
End Namespace
|
End Namespace
|
||||||
@@ -11,7 +11,7 @@ Imports SCrawler.Plugin
|
|||||||
Imports SCrawler.Plugin.Attributes
|
Imports SCrawler.Plugin.Attributes
|
||||||
Imports PersonalUtilities.Functions.RegularExpressions
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
Namespace API.Pinterest
|
Namespace API.Pinterest
|
||||||
<Manifest("AndyProgram_Pinterest"), SavedPosts, SeparatedTasks>
|
<Manifest("AndyProgram_Pinterest"), SavedPosts, SeparatedTasks, SpecialForm(False)>
|
||||||
Friend Class SiteSettings : Inherits SiteSettingsBase
|
Friend Class SiteSettings : Inherits SiteSettingsBase
|
||||||
#Region "Declarations"
|
#Region "Declarations"
|
||||||
<PropertyOption(ControlText:=DeclaredNames.ConcurrentDownloadsCaption,
|
<PropertyOption(ControlText:=DeclaredNames.ConcurrentDownloadsCaption,
|
||||||
@@ -21,6 +21,9 @@ Namespace API.Pinterest
|
|||||||
Private ReadOnly Property MyConcurrentDownloadsProvider As IFormatProvider
|
Private ReadOnly Property MyConcurrentDownloadsProvider As IFormatProvider
|
||||||
<PropertyOption(ControlText:=DeclaredNames.SavedPostsUserNameCaption, ControlToolTip:=DeclaredNames.SavedPostsUserNameToolTip), PXML, PClonable(Clone:=False)>
|
<PropertyOption(ControlText:=DeclaredNames.SavedPostsUserNameCaption, ControlToolTip:=DeclaredNames.SavedPostsUserNameToolTip), PXML, PClonable(Clone:=False)>
|
||||||
Friend ReadOnly Property SavedPostsUserName As PropertyValue
|
Friend ReadOnly Property SavedPostsUserName As PropertyValue
|
||||||
|
<DoNotUse> Friend Overrides Property DownloadText As PropertyValue
|
||||||
|
<DoNotUse> Friend Overrides Property DownloadTextPosts As PropertyValue
|
||||||
|
<DoNotUse> Friend Overrides Property DownloadTextSpecialFolder As PropertyValue
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Initializer"
|
#Region "Initializer"
|
||||||
Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean)
|
Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean)
|
||||||
@@ -30,7 +33,8 @@ Namespace API.Pinterest
|
|||||||
MyConcurrentDownloadsProvider = New ConcurrentDownloadsProvider
|
MyConcurrentDownloadsProvider = New ConcurrentDownloadsProvider
|
||||||
CheckNetscapeCookiesOnEndInit = True
|
CheckNetscapeCookiesOnEndInit = True
|
||||||
UseNetscapeCookies = True
|
UseNetscapeCookies = True
|
||||||
UserRegex = RParams.DMS("https?://w{0,3}.?[^/]*?.?pinterest.com/([^/]+)/?(?(_)|([^/]*))", 0, RegexReturn.ListByMatch, EDP.ReturnValue)
|
UserRegex = RParams.DMS("https?://w{0,3}.?[^/]*?.?pinterest.com/([^/]+)/?(?(_)|([^/]*))/?([^/\?]*)", 0, RegexReturn.ListByMatch, EDP.ReturnValue)
|
||||||
|
UserOptionsType = GetType(EditorExchangeOptions)
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "GetInstance, Available"
|
#Region "GetInstance, Available"
|
||||||
@@ -41,13 +45,14 @@ Namespace API.Pinterest
|
|||||||
Return Settings.GalleryDLFile.Exists And (Not What = ISiteSettings.Download.SavedPosts OrElse ACheck(SavedPostsUserName.Value))
|
Return Settings.GalleryDLFile.Exists And (Not What = ISiteSettings.Download.SavedPosts OrElse ACheck(SavedPostsUserName.Value))
|
||||||
End Function
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
#Region "IsMyUser, IsMyImageVideo, GetUserUrl, GetUserPostUrl"
|
#Region "IsMyUser, IsMyImageVideo, GetUserUrl, GetUserPostUrl, UserOptions"
|
||||||
Friend Overrides Function IsMyUser(ByVal UserURL As String) As ExchangeOptions
|
Friend Overrides Function IsMyUser(ByVal UserURL As String) As ExchangeOptions
|
||||||
If Not UserURL.IsEmptyString Then
|
If Not UserURL.IsEmptyString Then
|
||||||
Dim l As List(Of String) = RegexReplace(UserURL, UserRegex)
|
Dim l As List(Of String) = RegexReplace(UserURL, UserRegex)
|
||||||
If l.ListExists(3) Then
|
If l.ListExists(3) Then
|
||||||
Dim n$ = l(1)
|
Dim n$ = l(1)
|
||||||
If Not l(2).IsEmptyString Then n &= $"@{l(2)}"
|
If Not l(2).IsEmptyString Then n &= $"@{l(2)}"
|
||||||
|
If l.Count > 3 AndAlso Not l(3).IsEmptyString Then n &= $"@{l(3)}"
|
||||||
Return New ExchangeOptions(Site, n) With {.Exists = True}
|
Return New ExchangeOptions(Site, n) With {.Exists = True}
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
|
|||||||
@@ -7,10 +7,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 System.Threading
|
Imports System.Threading
|
||||||
|
Imports System.Text.RegularExpressions
|
||||||
Imports SCrawler.API.Base
|
Imports SCrawler.API.Base
|
||||||
Imports SCrawler.API.Base.GDL
|
Imports SCrawler.API.Base.GDL
|
||||||
Imports SCrawler.API.YouTube.Objects
|
Imports SCrawler.API.YouTube.Objects
|
||||||
Imports PersonalUtilities.Functions.XML
|
Imports PersonalUtilities.Functions.XML
|
||||||
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
Imports PersonalUtilities.Tools.Web.Documents.JSON
|
Imports PersonalUtilities.Tools.Web.Documents.JSON
|
||||||
Namespace API.Pinterest
|
Namespace API.Pinterest
|
||||||
Friend Class UserData : Inherits UserDataBase
|
Friend Class UserData : Inherits UserDataBase
|
||||||
@@ -18,6 +20,8 @@ Namespace API.Pinterest
|
|||||||
Private Const Name_IsUser As String = "IsUser"
|
Private Const Name_IsUser As String = "IsUser"
|
||||||
Private Const Name_TrueUserName As String = "TrueUserName"
|
Private Const Name_TrueUserName As String = "TrueUserName"
|
||||||
Private Const Name_TrueBoardName As String = "TrueBoardName"
|
Private Const Name_TrueBoardName As String = "TrueBoardName"
|
||||||
|
Private Const Name_ExtractSubBoards As String = "ExtractSubBoards"
|
||||||
|
Private Const Name_IsSubBoard As String = "IsSubBoard"
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Structures"
|
#Region "Structures"
|
||||||
Private Structure BoardInfo
|
Private Structure BoardInfo
|
||||||
@@ -38,6 +42,8 @@ Namespace API.Pinterest
|
|||||||
Friend Property TrueUserName As String
|
Friend Property TrueUserName As String
|
||||||
Friend Property TrueBoardName As String
|
Friend Property TrueBoardName As String
|
||||||
Friend Property IsUser_NB As Boolean
|
Friend Property IsUser_NB As Boolean
|
||||||
|
Private Property IsSubBoard As Boolean = False
|
||||||
|
Friend Property ExtractSubBoards As Boolean = True
|
||||||
Private Const BoardLabelName As String = "Board"
|
Private Const BoardLabelName As String = "Board"
|
||||||
Friend Overrides ReadOnly Property SpecialLabels As IEnumerable(Of String)
|
Friend Overrides ReadOnly Property SpecialLabels As IEnumerable(Of String)
|
||||||
Get
|
Get
|
||||||
@@ -45,14 +51,18 @@ Namespace API.Pinterest
|
|||||||
End Get
|
End Get
|
||||||
End Property
|
End Property
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Load"
|
#Region "Load, Exchange"
|
||||||
Private Function ReconfUserName() As Boolean
|
Private Function ReconfUserName() As Boolean
|
||||||
If TrueUserName.IsEmptyString Then
|
If TrueUserName.IsEmptyString Then
|
||||||
Dim n$() = Name.Split("@")
|
Dim n$() = Name.Split("@")
|
||||||
If n.ListExists Then
|
If n.ListExists Then
|
||||||
TrueUserName = n(0)
|
TrueUserName = n(0)
|
||||||
IsUser_NB = True
|
IsUser_NB = True
|
||||||
If n.Length > 1 Then TrueBoardName = n(1) : IsUser_NB = False
|
If n.Length > 1 Then
|
||||||
|
TrueBoardName = n(1)
|
||||||
|
If n.Length > 2 AndAlso Not n(2).IsEmptyString Then TrueBoardName &= $"/{n(2)}" : IsSubBoard = True
|
||||||
|
IsUser_NB = False
|
||||||
|
End If
|
||||||
If Not IsSavedPosts And Not IsSingleObjectDownload Then
|
If Not IsSavedPosts And Not IsSingleObjectDownload Then
|
||||||
Dim l$ = IIf(IsUser_NB, UserLabelName, BoardLabelName)
|
Dim l$ = IIf(IsUser_NB, UserLabelName, BoardLabelName)
|
||||||
Settings.Labels.Add(l)
|
Settings.Labels.Add(l)
|
||||||
@@ -70,15 +80,25 @@ Namespace API.Pinterest
|
|||||||
TrueUserName = .Value(Name_TrueUserName)
|
TrueUserName = .Value(Name_TrueUserName)
|
||||||
TrueBoardName = .Value(Name_TrueBoardName)
|
TrueBoardName = .Value(Name_TrueBoardName)
|
||||||
IsUser_NB = .Value(Name_IsUser).FromXML(Of Boolean)(False)
|
IsUser_NB = .Value(Name_IsUser).FromXML(Of Boolean)(False)
|
||||||
|
ExtractSubBoards = .Value(Name_ExtractSubBoards).FromXML(Of Boolean)(True)
|
||||||
|
IsSubBoard = .Value(Name_IsSubBoard).FromXML(Of Boolean)(False)
|
||||||
ReconfUserName()
|
ReconfUserName()
|
||||||
Else
|
Else
|
||||||
If ReconfUserName() Then .Value(Name_LabelsName) = LabelsString
|
If ReconfUserName() Then .Value(Name_LabelsName) = LabelsString
|
||||||
.Add(Name_TrueUserName, TrueUserName)
|
.Add(Name_TrueUserName, TrueUserName)
|
||||||
.Add(Name_TrueBoardName, TrueBoardName)
|
.Add(Name_TrueBoardName, TrueBoardName)
|
||||||
.Add(Name_IsUser, IsUser_NB.BoolToInteger)
|
.Add(Name_IsUser, IsUser_NB.BoolToInteger)
|
||||||
|
.Add(Name_ExtractSubBoards, ExtractSubBoards.BoolToInteger)
|
||||||
|
.Add(Name_IsSubBoard, IsSubBoard.BoolToInteger)
|
||||||
End If
|
End If
|
||||||
End With
|
End With
|
||||||
End Sub
|
End Sub
|
||||||
|
Friend Overrides Function ExchangeOptionsGet() As Object
|
||||||
|
Return New EditorExchangeOptions(Me)
|
||||||
|
End Function
|
||||||
|
Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object)
|
||||||
|
If Not Obj Is Nothing AndAlso TypeOf Obj Is EditorExchangeOptions Then ExtractSubBoards = DirectCast(Obj, EditorExchangeOptions).ExtractSubBoards
|
||||||
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Download overrides"
|
#Region "Download overrides"
|
||||||
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
|
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
|
||||||
@@ -125,6 +145,19 @@ Namespace API.Pinterest
|
|||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Get boards, images"
|
#Region "Get boards, images"
|
||||||
|
Private Function GetBoardInfo(ByVal e As EContainer) As BoardInfo
|
||||||
|
If Not e Is Nothing Then
|
||||||
|
Dim b As New BoardInfo With {
|
||||||
|
.URL = e.Value("url"),
|
||||||
|
.Title = TitleHtmlConverter(e.Value("name")).IfNullOrEmpty(TitleHtmlConverter(e.Value("title"))),
|
||||||
|
.ID = e.Value("id")
|
||||||
|
}
|
||||||
|
If Not b.URL.IsEmptyString Then b.URL = $"https://www.pinterest.com/{b.URL.StringTrimStart("/").StringTrimEnd("/")}/"
|
||||||
|
Return b
|
||||||
|
Else
|
||||||
|
Return Nothing
|
||||||
|
End If
|
||||||
|
End Function
|
||||||
Private Function GetBoards(ByVal Token As CancellationToken) As List(Of BoardInfo)
|
Private Function GetBoards(ByVal Token As CancellationToken) As List(Of BoardInfo)
|
||||||
Dim URL$ = $"https://www.pinterest.com/{TrueUserName}/"
|
Dim URL$ = $"https://www.pinterest.com/{TrueUserName}/"
|
||||||
Try
|
Try
|
||||||
@@ -132,11 +165,12 @@ Namespace API.Pinterest
|
|||||||
Dim b As BoardInfo
|
Dim b As BoardInfo
|
||||||
Dim r$
|
Dim r$
|
||||||
Dim j As EContainer, jj As EContainer
|
Dim j As EContainer, jj As EContainer
|
||||||
Dim rootNode$() = {"resource_response", "data"}
|
|
||||||
Dim jErr As New ErrorsDescriber(EDP.SendToLog + EDP.ReturnValue)
|
Dim jErr As New ErrorsDescriber(EDP.SendToLog + EDP.ReturnValue)
|
||||||
Dim urls As List(Of String) = GetDataFromGalleryDL(URL, True, Token)
|
Dim urls As New List(Of String)
|
||||||
|
urls.ListAddList(GetDataFromGalleryDL(URL, True, Token), LNC)
|
||||||
If urls.ListExists Then urls.RemoveAll(Function(__url) Not __url.Contains("BoardsResource/get/"))
|
If urls.ListExists Then urls.RemoveAll(Function(__url) Not __url.Contains("BoardsResource/get/"))
|
||||||
If urls.ListExists Then
|
If urls.ListExists Then
|
||||||
|
Responser.Headers.Add(PwsHeader)
|
||||||
ProgressPre.ChangeMax(urls.Count)
|
ProgressPre.ChangeMax(urls.Count)
|
||||||
For Each URL In urls
|
For Each URL In urls
|
||||||
ProgressPre.Perform()
|
ProgressPre.Perform()
|
||||||
@@ -145,17 +179,10 @@ Namespace API.Pinterest
|
|||||||
If Not r.IsEmptyString Then
|
If Not r.IsEmptyString Then
|
||||||
j = JsonDocument.Parse(r, jErr)
|
j = JsonDocument.Parse(r, jErr)
|
||||||
If Not j Is Nothing Then
|
If Not j Is Nothing Then
|
||||||
If If(j(rootNode)?.Count, 0) > 0 Then
|
If If(j(BoardInfoRootNode)?.Count, 0) > 0 Then
|
||||||
For Each jj In j(rootNode)
|
For Each jj In j(BoardInfoRootNode)
|
||||||
b = New BoardInfo With {
|
b = GetBoardInfo(jj)
|
||||||
.URL = jj.Value("url"),
|
If Not b.URL.IsEmptyString Then boards.Add(b)
|
||||||
.Title = TitleHtmlConverter(jj.Value("name")),
|
|
||||||
.ID = jj.Value("id")
|
|
||||||
}
|
|
||||||
If Not b.URL.IsEmptyString Then
|
|
||||||
b.URL = $"https://www.pinterest.com/{b.URL.StringTrimStart("/").StringTrimEnd("/")}/"
|
|
||||||
boards.Add(b)
|
|
||||||
End If
|
|
||||||
Next
|
Next
|
||||||
End If
|
End If
|
||||||
j.Dispose()
|
j.Dispose()
|
||||||
@@ -167,36 +194,59 @@ Namespace API.Pinterest
|
|||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
ProcessException(ex, Token, $"data (gallery-dl boards) downloading error [{URL}]")
|
ProcessException(ex, Token, $"data (gallery-dl boards) downloading error [{URL}]")
|
||||||
Return Nothing
|
Return Nothing
|
||||||
|
Finally
|
||||||
|
Responser.Headers.Remove(PwsHeader)
|
||||||
End Try
|
End Try
|
||||||
End Function
|
End Function
|
||||||
Private Sub DownloadBoardImages(ByRef Board As BoardInfo, ByVal Token As CancellationToken)
|
Private Sub DownloadBoardImages(ByRef Board As BoardInfo, ByVal Token As CancellationToken)
|
||||||
Dim bUrl$ = String.Empty
|
Dim bUrl As GDLURL = Nothing
|
||||||
Try
|
Try
|
||||||
Dim r$
|
Dim r$
|
||||||
Dim j As EContainer, jj As EContainer
|
Dim j As EContainer, jj As EContainer
|
||||||
Dim u As UserMedia
|
Dim u As UserMedia
|
||||||
Dim folder$ = If(IsUser_NB, Board.Title.IfNullOrEmpty(Board.ID), String.Empty)
|
Dim __getBoardTitle As Func(Of BoardInfo, String) = Function(__board) __board.Title.IfNullOrEmpty(__board.ID)
|
||||||
|
Dim folderDef$ = If(IsUser_NB, __getBoardTitle(Board), String.Empty)
|
||||||
Dim titleExists As Boolean = Not Board.Title.IsEmptyString
|
Dim titleExists As Boolean = Not Board.Title.IsEmptyString
|
||||||
Dim i% = -1
|
Dim i% = -1
|
||||||
Dim jErr As New ErrorsDescriber(EDP.SendToLog + EDP.ReturnValue)
|
Dim jErr As New ErrorsDescriber(EDP.SendToLog + EDP.ReturnValue)
|
||||||
Dim rootNode$() = {"resource_response", "data"}
|
Dim rErr As New ErrorsDescriber(EDP.ReturnValue)
|
||||||
Dim images As List(Of Sizes)
|
Dim images As List(Of Sizes)
|
||||||
Dim imgSelector As Func(Of EContainer, Sizes) = Function(img) New Sizes(img.Value("width"), img.Value("url"))
|
Dim imgSelector As Func(Of EContainer, Sizes) = Function(img) New Sizes(img.Value("width"), img.Value("url"))
|
||||||
Dim fullData As Predicate(Of EContainer) = Function(e) e.Count > 5
|
Dim fullData As Predicate(Of EContainer) = Function(e) e.Count > 5
|
||||||
Dim l As List(Of String) = GetDataFromGalleryDL(Board.URL, False, Token)
|
Dim subBoard As BoardInfo = Nothing
|
||||||
If l.ListExists Then l.RemoveAll(Function(ll) Not ll.Contains("BoardFeedResource/get/"))
|
Dim subBoardAppender As Func(Of String) = Function() _
|
||||||
|
If(Not __getBoardTitle(subBoard).IsEmptyString,
|
||||||
|
$"{IIf(folderDef.IsEmptyString, String.Empty, "\")}{__getBoardTitle(subBoard)}",
|
||||||
|
String.Empty)
|
||||||
|
Dim __getSubBoard As Func(Of Boolean) = Function() ExtractSubBoards Or (IsSubBoard And i = -1)
|
||||||
|
Dim sbCount% = 0
|
||||||
|
Dim __getBoardInfo As Action(Of GDLURL) = Sub(ByVal sb As GDLURL)
|
||||||
|
sbCount += 1
|
||||||
|
r = Responser.GetResponse(sb.URL,, rErr)
|
||||||
|
If Not r.IsEmptyString Then
|
||||||
|
Using jsb As EContainer = JsonDocument.Parse(r, jErr)
|
||||||
|
If jsb.ListExists Then subBoard = GetBoardInfo(jsb(BoardInfoRootNode)) : Exit Sub
|
||||||
|
End Using
|
||||||
|
End If
|
||||||
|
subBoard = Nothing
|
||||||
|
End Sub
|
||||||
|
Dim l As List(Of GDLURL) = GetDataFromGalleryDL(Board.URL, False, Token)
|
||||||
|
If l.ListExists Then l.RemoveAll(Function(ll) ll.URL.IsEmptyString)
|
||||||
If l.ListExists Then
|
If l.ListExists Then
|
||||||
|
Responser.Headers.Add(PwsHeader)
|
||||||
ProgressPre.ChangeMax(l.Count)
|
ProgressPre.ChangeMax(l.Count)
|
||||||
For Each bUrl In l
|
For Each bUrl In l
|
||||||
ProgressPre.Perform()
|
ProgressPre.Perform()
|
||||||
ThrowAny(Token)
|
ThrowAny(Token)
|
||||||
r = Responser.GetResponse(bUrl,, EDP.ReturnValue)
|
|
||||||
|
If bUrl.URL.Contains("BoardFeedResource/get/") Or (bUrl.URL.Contains("BoardSectionPinsResource/get/") And (ExtractSubBoards Or (IsSubBoard And sbCount = 1))) Then
|
||||||
|
r = Responser.GetResponse(bUrl.URL,, rErr)
|
||||||
If Not r.IsEmptyString Then
|
If Not r.IsEmptyString Then
|
||||||
j = JsonDocument.Parse(r, jErr)
|
j = JsonDocument.Parse(r, jErr)
|
||||||
If Not j Is Nothing Then
|
If Not j Is Nothing Then
|
||||||
If If(j(rootNode)?.Count, 0) > 0 Then
|
If If(j(BoardInfoRootNode)?.Count, 0) > 0 Then
|
||||||
ProgressPre.ChangeMax(j(rootNode).Count)
|
ProgressPre.ChangeMax(j(BoardInfoRootNode).Count)
|
||||||
For Each jj In j(rootNode)
|
For Each jj In j(BoardInfoRootNode)
|
||||||
ProgressPre.Perform()
|
ProgressPre.Perform()
|
||||||
With jj
|
With jj
|
||||||
If .Contains("images") Then
|
If .Contains("images") Then
|
||||||
@@ -207,7 +257,7 @@ Namespace API.Pinterest
|
|||||||
u = New UserMedia(images(0).Data) With {
|
u = New UserMedia(images(0).Data) With {
|
||||||
.Post = New UserPost(jj.Value("id"), AConvert(Of Date)(jj.Value("created_at"), DateProvider, Nothing)),
|
.Post = New UserPost(jj.Value("id"), AConvert(Of Date)(jj.Value("created_at"), DateProvider, Nothing)),
|
||||||
.Type = UserMedia.Types.Picture,
|
.Type = UserMedia.Types.Picture,
|
||||||
.SpecialFolder = folder
|
.SpecialFolder = folderDef & subBoardAppender.Invoke
|
||||||
}
|
}
|
||||||
If i = 0 Then
|
If i = 0 Then
|
||||||
If Board.Title.IsEmptyString Or Board.ID.IsEmptyString Then
|
If Board.Title.IsEmptyString Or Board.ID.IsEmptyString Then
|
||||||
@@ -217,12 +267,8 @@ Namespace API.Pinterest
|
|||||||
Board.UserID = .Value({"board", "owner"}, "id")
|
Board.UserID = .Value({"board", "owner"}, "id")
|
||||||
Board.UserTitle = TitleHtmlConverter(.Value({"board", "owner"}, "full_name"))
|
Board.UserTitle = TitleHtmlConverter(.Value({"board", "owner"}, "full_name"))
|
||||||
If Not titleExists And IsUser_NB Then
|
If Not titleExists And IsUser_NB Then
|
||||||
If Not Board.Title.IsEmptyString Then
|
folderDef = Board.Title.IfNullOrEmpty(Board.ID).IfNullOrEmpty(folderDef)
|
||||||
folder = Board.Title
|
u.SpecialFolder = folderDef & subBoardAppender.Invoke
|
||||||
ElseIf Not Board.ID.IsEmptyString Then
|
|
||||||
folder = Board.ID
|
|
||||||
End If
|
|
||||||
u.SpecialFolder = folder
|
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
|
|
||||||
@@ -248,14 +294,61 @@ Namespace API.Pinterest
|
|||||||
j.Dispose()
|
j.Dispose()
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
|
ElseIf bUrl.URL.Contains("BoardSectionResource/get/") And (ExtractSubBoards Or (IsSubBoard And i = -1)) Then
|
||||||
|
__getBoardInfo(bUrl)
|
||||||
|
If IsSubBoard And i = -1 And Board.Title.IsEmptyString Then
|
||||||
|
Board.Title = subBoard.Title
|
||||||
|
If Board.ID.IsEmptyString Then Board.ID = subBoard.ID
|
||||||
|
subBoard = Nothing
|
||||||
|
folderDef = String.Empty
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
|
||||||
Next
|
Next
|
||||||
End If
|
End If
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
ProcessException(ex, Token, $"data (gallery-dl images) downloading error [{bUrl}]")
|
ProcessException(ex, Token, $"data (gallery-dl images) downloading error [{bUrl.URL}]")
|
||||||
|
Finally
|
||||||
|
Responser.Headers.Remove(PwsHeader)
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Gallery-DL Support"
|
#Region "Gallery-DL Support"
|
||||||
|
Private Structure GDLURL : Implements IRegExCreator
|
||||||
|
Friend URL As String
|
||||||
|
Friend BoardId As String
|
||||||
|
Public Shared Widening Operator CType(ByVal u As String) As GDLURL
|
||||||
|
Return New GDLURL With {.URL = u}
|
||||||
|
End Operator
|
||||||
|
Public Shared Widening Operator CType(ByVal u As GDLURL) As String
|
||||||
|
Return u.URL
|
||||||
|
End Operator
|
||||||
|
Private Function CreateFromArray(ByVal ParamsArray() As String) As Object Implements IRegExCreator.CreateFromArray
|
||||||
|
If ParamsArray.ListExists(2) Then
|
||||||
|
Dim u$ = ParamsArray(0).StringTrim.StringTrimEnd("/"), u2$
|
||||||
|
If Not u.IsEmptyString Then
|
||||||
|
u2 = ParamsArray(1).StringTrim
|
||||||
|
If Not u2.IsEmptyString AndAlso u2.StartsWith("GET", StringComparison.OrdinalIgnoreCase) Then
|
||||||
|
u2 = u2.Remove(0, 3).StringTrim.StringTrimStart("/")
|
||||||
|
If Not u2.IsEmptyString Then URL = $"{u}/{u2}"
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Return Me
|
||||||
|
End Function
|
||||||
|
Public Shared Operator =(ByVal x As GDLURL, ByVal y As GDLURL) As Boolean
|
||||||
|
Return x.URL = y.URL
|
||||||
|
End Operator
|
||||||
|
Public Shared Operator <>(ByVal x As GDLURL, ByVal y As GDLURL) As Boolean
|
||||||
|
Return Not x.URL = y.URL
|
||||||
|
End Operator
|
||||||
|
Public Overrides Function ToString() As String
|
||||||
|
Return URL
|
||||||
|
End Function
|
||||||
|
Public Overrides Function Equals(ByVal Obj As Object) As Boolean
|
||||||
|
Return URL = CType(Obj, String)
|
||||||
|
End Function
|
||||||
|
End Structure
|
||||||
Private Class GDLBatch : Inherits GDL.GDLBatch
|
Private Class GDLBatch : Inherits GDL.GDLBatch
|
||||||
Private ReadOnly Property Source As UserData
|
Private ReadOnly Property Source As UserData
|
||||||
Private ReadOnly IsBoardsRequested As Boolean
|
Private ReadOnly IsBoardsRequested As Boolean
|
||||||
@@ -286,14 +379,30 @@ Namespace API.Pinterest
|
|||||||
End If
|
End If
|
||||||
End Function
|
End Function
|
||||||
End Class
|
End Class
|
||||||
Private Function GetDataFromGalleryDL(ByVal URL As String, ByVal IsBoardsRequested As Boolean, ByVal Token As CancellationToken) As List(Of String)
|
Private Function GetDataFromGalleryDL(ByVal URL As String, ByVal IsBoardsRequested As Boolean, ByVal Token As CancellationToken) As List(Of GDLURL)
|
||||||
Dim command$ = $"""{Settings.GalleryDLFile.File}"" --verbose --simulate "
|
Dim command$ = $"""{Settings.GalleryDLFile.File}"" --verbose --simulate "
|
||||||
Try
|
Try
|
||||||
If Not URL.IsEmptyString Then
|
If Not URL.IsEmptyString Then
|
||||||
|
Dim urls As New List(Of GDLURL)
|
||||||
|
Dim u As GDLURL
|
||||||
|
Dim s$ = String.Empty
|
||||||
If MySettings.CookiesNetscapeFile.Exists Then command &= $"--cookies ""{MySettings.CookiesNetscapeFile}"" "
|
If MySettings.CookiesNetscapeFile.Exists Then command &= $"--cookies ""{MySettings.CookiesNetscapeFile}"" "
|
||||||
command &= URL
|
command &= URL
|
||||||
Using batch As New GDLBatch(Me, IsBoardsRequested, Token)
|
Using batch As New GDLBatch(Me, IsBoardsRequested, Token)
|
||||||
Return GetUrlsFromGalleryDl(batch, command)
|
With batch
|
||||||
|
.Execute(command)
|
||||||
|
If .ErrorOutputData.Count > 0 Then
|
||||||
|
For Each eValue$ In .ErrorOutputData
|
||||||
|
s = CStr(RegexReplace(eValue, SubBoardRegEx)).IfNullOrEmpty(s)
|
||||||
|
u = RegexFields(Of GDLURL)(eValue, {GdlUrlPattern}, {1, 2}, EDP.ReturnValue).ListIfNothing.FirstOrDefault
|
||||||
|
If Not u.URL.IsEmptyString Then
|
||||||
|
If Not s.IsEmptyString Then u.BoardId = s
|
||||||
|
urls.Add(u)
|
||||||
|
End If
|
||||||
|
Next
|
||||||
|
Return urls
|
||||||
|
End If
|
||||||
|
End With
|
||||||
End Using
|
End Using
|
||||||
End If
|
End If
|
||||||
Return Nothing
|
Return Nothing
|
||||||
|
|||||||
@@ -36,11 +36,12 @@ Namespace API.PornHub
|
|||||||
Friend ReadOnly Regex_Gif_UrlName As RParams = RParams.DMS("""name"":.*?""([^""]*)""[^\}]+?""contentUrl"":.*?""([^""]+)""", 0, RegexReturn.ListByMatch, EDP.ReturnValue)
|
Friend ReadOnly Regex_Gif_UrlName As RParams = RParams.DMS("""name"":.*?""([^""]*)""[^\}]+?""contentUrl"":.*?""([^""]+)""", 0, RegexReturn.ListByMatch, EDP.ReturnValue)
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Declarations photo"
|
#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_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,
|
Friend ReadOnly Regex_Photo_PornHub_PhotoBlocks2 As RParams = RParams.DM("albumInfoTitle"" href=""([^""]+)""\>([^\<]+)", 0, RegexReturn.List)
|
||||||
|
Friend ReadOnly Regex_Photo_PornHub_AlbumPhotoArr As RParams = RParams.DMS("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)))
|
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)
|
Friend ReadOnly Regex_Photo_PornHub_SinglePhoto As RParams = RParams.DM("data-image=""([^""]+)""\s*src=""([^""]+)""", 0, RegexReturn.ListByMatch, EDP.ReturnValue)
|
||||||
|
Friend ReadOnly Regex_Photo_PornHub_SinglePhoto2 As RParams = RParams.DMS("image:src"" content=""([^""]+)""", 1, EDP.ReturnValue)
|
||||||
Friend ReadOnly Regex_Photo_File As RParams = RParams.DM("\d+\.[\w]{3,4}", 0, EDP.ReturnValue)
|
Friend ReadOnly Regex_Photo_File As RParams = RParams.DM("\d+\.[\w]{3,4}", 0, EDP.ReturnValue)
|
||||||
#End Region
|
#End Region
|
||||||
End Module
|
End Module
|
||||||
|
|||||||
@@ -29,12 +29,11 @@ Namespace API.PornHub
|
|||||||
Friend ReadOnly Property DownloadGifs As PropertyValue
|
Friend ReadOnly Property DownloadGifs As PropertyValue
|
||||||
<PropertyOption(ControlText:="Download GIFs as mp4", ControlToolTip:="Download gifs in 'mp4' format instead of native 'webm'"), PXML, PClonable>
|
<PropertyOption(ControlText:="Download GIFs as mp4", ControlToolTip:="Download gifs in 'mp4' format instead of native 'webm'"), PXML, PClonable>
|
||||||
Friend ReadOnly Property DownloadGifsAsMp4 As PropertyValue
|
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, PClonable>
|
|
||||||
Friend ReadOnly Property DownloadPhotoOnlyFromModelHub As PropertyValue
|
|
||||||
<PropertyOption(ControlText:=DeclaredNames.SavedPostsUserNameCaption, ControlToolTip:=DeclaredNames.SavedPostsUserNameToolTip), PXML, PClonable(Clone:=False)>
|
<PropertyOption(ControlText:=DeclaredNames.SavedPostsUserNameCaption, ControlToolTip:=DeclaredNames.SavedPostsUserNameToolTip), PXML, PClonable(Clone:=False)>
|
||||||
Friend ReadOnly Property SavedPostsUserName As PropertyValue
|
Friend ReadOnly Property SavedPostsUserName As PropertyValue
|
||||||
|
<DoNotUse> Friend Overrides Property DownloadText As PropertyValue
|
||||||
|
<DoNotUse> Friend Overrides Property DownloadTextPosts As PropertyValue
|
||||||
|
<DoNotUse> Friend Overrides Property DownloadTextSpecialFolder As PropertyValue
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Initializer"
|
#Region "Initializer"
|
||||||
Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean)
|
Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean)
|
||||||
@@ -48,7 +47,6 @@ Namespace API.PornHub
|
|||||||
DownloadFavorite = New PropertyValue(False)
|
DownloadFavorite = New PropertyValue(False)
|
||||||
DownloadGifsAsMp4 = New PropertyValue(True)
|
DownloadGifsAsMp4 = New PropertyValue(True)
|
||||||
DownloadGifs = New PropertyValue(CInt(CheckState.Indeterminate), GetType(Integer))
|
DownloadGifs = New PropertyValue(CInt(CheckState.Indeterminate), GetType(Integer))
|
||||||
DownloadPhotoOnlyFromModelHub = New PropertyValue(True)
|
|
||||||
SavedPostsUserName = New PropertyValue(String.Empty, GetType(String))
|
SavedPostsUserName = New PropertyValue(String.Empty, GetType(String))
|
||||||
|
|
||||||
_SubscriptionsAllowed = True
|
_SubscriptionsAllowed = True
|
||||||
|
|||||||
@@ -15,20 +15,17 @@ Imports PersonalUtilities.Tools.Web.Clients
|
|||||||
Imports PersonalUtilities.Tools.Web.Documents.JSON
|
Imports PersonalUtilities.Tools.Web.Documents.JSON
|
||||||
Imports UTypes = SCrawler.API.Base.UserMedia.Types
|
Imports UTypes = SCrawler.API.Base.UserMedia.Types
|
||||||
Namespace API.PornHub
|
Namespace API.PornHub
|
||||||
Friend Class UserData : Inherits UserDataBase
|
Friend Class UserData : Inherits UserDataBase : Implements IPSite
|
||||||
Private Const UrlPattern As String = "https://www.pornhub.com/{0}"
|
Private Const UrlPattern As String = "https://www.pornhub.com/{0}"
|
||||||
#Region "Declarations"
|
#Region "Declarations"
|
||||||
#Region "XML names"
|
#Region "XML names"
|
||||||
Private Const Name_PersonType As String = "PersonType"
|
Private Const Name_PersonType As String = "PersonType"
|
||||||
Private Const Name_NameTrue As String = "NameTrue"
|
|
||||||
Private Const Name_PhotoPageModel As String = "PhotoPageModel"
|
|
||||||
Private Const Name_DownloadUHD As String = "DownloadUHD"
|
Private Const Name_DownloadUHD As String = "DownloadUHD"
|
||||||
Private Const Name_DownloadUploaded As String = "DownloadUploaded"
|
Private Const Name_DownloadUploaded As String = "DownloadUploaded"
|
||||||
Private Const Name_DownloadTagged As String = "DownloadTagged"
|
Private Const Name_DownloadTagged As String = "DownloadTagged"
|
||||||
Private Const Name_DownloadPrivate As String = "DownloadPrivate"
|
Private Const Name_DownloadPrivate As String = "DownloadPrivate"
|
||||||
Private Const Name_DownloadFavorite As String = "DownloadFavorite"
|
Private Const Name_DownloadFavorite As String = "DownloadFavorite"
|
||||||
Private Const Name_DownloadGifs As String = "DownloadGifs"
|
Private Const Name_DownloadGifs As String = "DownloadGifs"
|
||||||
Private Const Name_DownloadPhotoOnlyFromModelHub As String = "DownloadPhotoOnlyFromModelHub"
|
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Structures"
|
#Region "Structures"
|
||||||
Private Structure FlashVar : Implements IRegExCreator
|
Private Structure FlashVar : Implements IRegExCreator
|
||||||
@@ -98,11 +95,6 @@ Namespace API.PornHub
|
|||||||
End Structure
|
End Structure
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Enums"
|
#Region "Enums"
|
||||||
Private Enum PhotoPageModels As Integer
|
|
||||||
Undefined = 0
|
|
||||||
PornHubPage = 1
|
|
||||||
ModelHubPage = 2
|
|
||||||
End Enum
|
|
||||||
Private Enum VideoTypes
|
Private Enum VideoTypes
|
||||||
Undefined
|
Undefined
|
||||||
Uploaded
|
Uploaded
|
||||||
@@ -121,7 +113,6 @@ Namespace API.PornHub
|
|||||||
#End Region
|
#End Region
|
||||||
#Region "Person"
|
#Region "Person"
|
||||||
Friend Property PersonType As String
|
Friend Property PersonType As String
|
||||||
Friend Property NameTrue As String
|
|
||||||
Friend Overrides Property FriendlyName As String
|
Friend Overrides Property FriendlyName As String
|
||||||
Get
|
Get
|
||||||
If _FriendlyName.IsEmptyString Then Return NameTrue Else Return _FriendlyName
|
If _FriendlyName.IsEmptyString Then Return NameTrue Else Return _FriendlyName
|
||||||
@@ -137,21 +128,19 @@ Namespace API.PornHub
|
|||||||
Return IsUser Or SiteMode = SiteModes.Playlists
|
Return IsUser Or SiteMode = SiteModes.Playlists
|
||||||
End Get
|
End Get
|
||||||
End Property
|
End Property
|
||||||
Private Property PhotoPageModel As PhotoPageModels = PhotoPageModels.Undefined
|
|
||||||
Friend Property DownloadUHD As Boolean = False
|
Friend Property DownloadUHD As Boolean = False
|
||||||
Friend Property DownloadUploaded As Boolean = True
|
Friend Property DownloadUploaded As Boolean = True
|
||||||
Friend Property DownloadTagged As Boolean = False
|
Friend Property DownloadTagged As Boolean = False
|
||||||
Friend Property DownloadPrivate As Boolean = False
|
Friend Property DownloadPrivate As Boolean = False
|
||||||
Friend Property DownloadFavorite As Boolean = False
|
Friend Property DownloadFavorite As Boolean = False
|
||||||
Friend Property DownloadGifs As Boolean
|
Friend Property DownloadGifs As Boolean
|
||||||
Friend Property DownloadPhotoOnlyFromModelHub As Boolean = True
|
|
||||||
Friend Overrides ReadOnly Property IsUser As Boolean
|
Friend Overrides ReadOnly Property IsUser As Boolean
|
||||||
Get
|
Get
|
||||||
Return SiteMode = SiteModes.User
|
Return SiteMode = SiteModes.User
|
||||||
End Get
|
End Get
|
||||||
End Property
|
End Property
|
||||||
Friend Property SiteMode As SiteModes = SiteModes.User
|
Friend Property SiteMode As SiteModes = SiteModes.User
|
||||||
Friend Property QueryString As String
|
Friend Property QueryString As String Implements IPSite.QueryString
|
||||||
Get
|
Get
|
||||||
If IsUser Then
|
If IsUser Then
|
||||||
Return String.Empty
|
Return String.Empty
|
||||||
@@ -174,18 +163,7 @@ Namespace API.PornHub
|
|||||||
Return New UserExchangeOptions(Me)
|
Return New UserExchangeOptions(Me)
|
||||||
End Function
|
End Function
|
||||||
Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object)
|
Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object)
|
||||||
If Not Obj Is Nothing AndAlso TypeOf Obj Is UserExchangeOptions Then
|
If Not Obj Is Nothing AndAlso TypeOf Obj Is UserExchangeOptions Then DirectCast(Obj, UserExchangeOptions).Apply(Me)
|
||||||
With DirectCast(Obj, UserExchangeOptions)
|
|
||||||
DownloadUHD = .DownloadUHD
|
|
||||||
DownloadUploaded = .DownloadUploaded
|
|
||||||
DownloadTagged = .DownloadTagged
|
|
||||||
DownloadPrivate = .DownloadPrivate
|
|
||||||
DownloadFavorite = .DownloadFavorite
|
|
||||||
DownloadGifs = .DownloadGifs
|
|
||||||
DownloadPhotoOnlyFromModelHub = .DownloadPhotoOnlyFromModelHub
|
|
||||||
QueryString = .QueryString
|
|
||||||
End With
|
|
||||||
End If
|
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
Private ReadOnly Property MySettings As SiteSettings
|
Private ReadOnly Property MySettings As SiteSettings
|
||||||
@@ -207,7 +185,7 @@ Namespace API.PornHub
|
|||||||
If Not Force OrElse (Not IsUser AndAlso Not SiteMode = SiteModes.Playlists AndAlso Not NewUrl.IsEmptyString AndAlso MyFileSettings.Exists) Then
|
If Not Force OrElse (Not IsUser AndAlso Not SiteMode = SiteModes.Playlists AndAlso Not NewUrl.IsEmptyString AndAlso MyFileSettings.Exists) Then
|
||||||
Dim eObj As Plugin.ExchangeOptions = Nothing
|
Dim eObj As Plugin.ExchangeOptions = Nothing
|
||||||
If Force Then eObj = MySettings.IsMyUser(NewUrl)
|
If Force Then eObj = MySettings.IsMyUser(NewUrl)
|
||||||
If (Force And Not eObj.UserName.IsEmptyString) Or (Not Force And Not Name.IsEmptyString And NameTrue.IsEmptyString) Then
|
If (Force And Not eObj.UserName.IsEmptyString) Or (Not Force And Not Name.IsEmptyString And NameTrue(True).IsEmptyString) Then
|
||||||
If Not If(Force, eObj.Options, Options).IsEmptyString Then
|
If Not If(Force, eObj.Options, Options).IsEmptyString Then
|
||||||
If (IsUser Or SiteMode = SiteModes.Playlists) And Force Then
|
If (IsUser Or SiteMode = SiteModes.Playlists) And Force Then
|
||||||
Return False
|
Return False
|
||||||
@@ -244,29 +222,23 @@ Namespace API.PornHub
|
|||||||
With Container
|
With Container
|
||||||
If Loading Then
|
If Loading Then
|
||||||
PersonType = .Value(Name_PersonType)
|
PersonType = .Value(Name_PersonType)
|
||||||
NameTrue = .Value(Name_NameTrue)
|
|
||||||
PhotoPageModel = .Value(Name_PhotoPageModel).FromXML(Of Integer)(PhotoPageModels.Undefined)
|
|
||||||
DownloadUHD = .Value(Name_DownloadUHD).FromXML(Of Boolean)(False)
|
DownloadUHD = .Value(Name_DownloadUHD).FromXML(Of Boolean)(False)
|
||||||
DownloadUploaded = .Value(Name_DownloadUploaded).FromXML(Of Boolean)(True)
|
DownloadUploaded = .Value(Name_DownloadUploaded).FromXML(Of Boolean)(True)
|
||||||
DownloadTagged = .Value(Name_DownloadTagged).FromXML(Of Boolean)(False)
|
DownloadTagged = .Value(Name_DownloadTagged).FromXML(Of Boolean)(False)
|
||||||
DownloadPrivate = .Value(Name_DownloadPrivate).FromXML(Of Boolean)(False)
|
DownloadPrivate = .Value(Name_DownloadPrivate).FromXML(Of Boolean)(False)
|
||||||
DownloadFavorite = .Value(Name_DownloadFavorite).FromXML(Of Boolean)(False)
|
DownloadFavorite = .Value(Name_DownloadFavorite).FromXML(Of Boolean)(False)
|
||||||
DownloadGifs = .Value(Name_DownloadGifs).FromXML(Of Integer)(False)
|
DownloadGifs = .Value(Name_DownloadGifs).FromXML(Of Integer)(False)
|
||||||
DownloadPhotoOnlyFromModelHub = .Value(Name_DownloadPhotoOnlyFromModelHub).FromXML(Of Boolean)(True)
|
|
||||||
SiteMode = .Value(Name_SiteMode).FromXML(Of Integer)(SiteModes.User)
|
SiteMode = .Value(Name_SiteMode).FromXML(Of Integer)(SiteModes.User)
|
||||||
UpdateUserOptions()
|
UpdateUserOptions()
|
||||||
Else
|
Else
|
||||||
If UpdateUserOptions() Then .Value(Name_LabelsName) = LabelsString
|
If UpdateUserOptions() Then .Value(Name_LabelsName) = LabelsString : .Value(Name_TrueName) = NameTrue(True)
|
||||||
.Add(Name_PersonType, PersonType)
|
.Add(Name_PersonType, PersonType)
|
||||||
.Add(Name_NameTrue, NameTrue)
|
|
||||||
.Add(Name_PhotoPageModel, CInt(PhotoPageModel))
|
|
||||||
.Add(Name_DownloadUHD, DownloadUHD.BoolToInteger)
|
.Add(Name_DownloadUHD, DownloadUHD.BoolToInteger)
|
||||||
.Add(Name_DownloadUploaded, DownloadUploaded.BoolToInteger)
|
.Add(Name_DownloadUploaded, DownloadUploaded.BoolToInteger)
|
||||||
.Add(Name_DownloadTagged, DownloadTagged.BoolToInteger)
|
.Add(Name_DownloadTagged, DownloadTagged.BoolToInteger)
|
||||||
.Add(Name_DownloadPrivate, DownloadPrivate.BoolToInteger)
|
.Add(Name_DownloadPrivate, DownloadPrivate.BoolToInteger)
|
||||||
.Add(Name_DownloadFavorite, DownloadFavorite.BoolToInteger)
|
.Add(Name_DownloadFavorite, DownloadFavorite.BoolToInteger)
|
||||||
.Add(Name_DownloadGifs, DownloadGifs.BoolToInteger)
|
.Add(Name_DownloadGifs, DownloadGifs.BoolToInteger)
|
||||||
.Add(Name_DownloadPhotoOnlyFromModelHub, DownloadPhotoOnlyFromModelHub.BoolToInteger)
|
|
||||||
.Add(Name_SiteMode, CInt(SiteMode))
|
.Add(Name_SiteMode, CInt(SiteMode))
|
||||||
|
|
||||||
'Debug.WriteLine(GetNonUserUrl(0))
|
'Debug.WriteLine(GetNonUserUrl(0))
|
||||||
@@ -283,6 +255,7 @@ Namespace API.PornHub
|
|||||||
Private _PageVideosRepeat As Integer = 0
|
Private _PageVideosRepeat As Integer = 0
|
||||||
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
|
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
|
||||||
Try
|
Try
|
||||||
|
UpdateM3U8URLS = False
|
||||||
PlaylistToken = String.Empty
|
PlaylistToken = String.Empty
|
||||||
Responser.ResetStatus()
|
Responser.ResetStatus()
|
||||||
_PageVideosRepeat = 0
|
_PageVideosRepeat = 0
|
||||||
@@ -295,7 +268,6 @@ Namespace API.PornHub
|
|||||||
|
|
||||||
Dim limit% = If(DownloadTopCount, -1)
|
Dim limit% = If(DownloadTopCount, -1)
|
||||||
If DownloadVideos Then
|
If DownloadVideos Then
|
||||||
|
|
||||||
If SiteMode = SiteModes.Playlists Then
|
If SiteMode = SiteModes.Playlists Then
|
||||||
Responser.Mode = Responser.Modes.Default
|
Responser.Mode = Responser.Modes.Default
|
||||||
GetPlaylistToken(Token)
|
GetPlaylistToken(Token)
|
||||||
@@ -519,25 +491,12 @@ Namespace API.PornHub
|
|||||||
Dim pFile$ = RegexReplace(URL, Regex_Photo_File)
|
Dim pFile$ = RegexReplace(URL, Regex_Photo_File)
|
||||||
If Not pFile.IsEmptyString Then Return New SFile(pFile) Else Return File
|
If Not pFile.IsEmptyString Then Return New SFile(pFile) Else Return File
|
||||||
End Function
|
End Function
|
||||||
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 Const PhotoUrlPattern_PornHub As String = "https://www.pornhub.com/{0}/{1}/photos"
|
||||||
Private Sub DownloadUserPhotos(ByVal Token As CancellationToken)
|
Private Sub DownloadUserPhotos(ByVal Token As CancellationToken)
|
||||||
Try
|
Try
|
||||||
If IsSavedPosts Then
|
If IsSavedPosts Then
|
||||||
DownloadUserPhotos_SavedPosts(Token)
|
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 Not DownloadPhotoOnlyFromModelHub AndAlso
|
|
||||||
DownloadUserPhotos_PornHub(Token) Then PhotoPageModel = PhotoPageModels.PornHubPage
|
|
||||||
Else
|
Else
|
||||||
Select Case PhotoPageModel
|
|
||||||
Case PhotoPageModels.ModelHubPage : DownloadUserPhotos_ModelHub(Token)
|
|
||||||
Case PhotoPageModels.PornHubPage : If Not DownloadPhotoOnlyFromModelHub Then DownloadUserPhotos_PornHub(Token)
|
|
||||||
End Select
|
|
||||||
End If
|
|
||||||
ElseIf Not DownloadPhotoOnlyFromModelHub Then
|
|
||||||
DownloadUserPhotos_PornHub(Token)
|
DownloadUserPhotos_PornHub(Token)
|
||||||
End If
|
End If
|
||||||
ThrowAny(Token)
|
ThrowAny(Token)
|
||||||
@@ -545,48 +504,6 @@ Namespace API.PornHub
|
|||||||
ProcessException(ex, Token, "photos downloading error")
|
ProcessException(ex, Token, "photos downloading error")
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
Private Function DownloadUserPhotos_ModelHub(ByVal Token As CancellationToken) As Boolean
|
|
||||||
Dim URL$ = String.Empty
|
|
||||||
Try
|
|
||||||
Dim j As EContainer
|
|
||||||
Dim jErr As New ErrorsDescriber(EDP.SendToLog + 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}, EDP.ReturnValue)
|
|
||||||
If l.ListExists Then l.RemoveAll(Function(ll) ll.Data.IsEmptyString)
|
|
||||||
If l.ListExists Then
|
|
||||||
ProgressPre.ChangeMax(l.Count)
|
|
||||||
Dim albumRegex As RParams = RParams.DMS("", 1, EDP.ReturnValue)
|
|
||||||
For Each block As PhotoBlock In l
|
|
||||||
ProgressPre.Perform()
|
|
||||||
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
|
|
||||||
j = 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}\",
|
|
||||||
.File = CreatePhotoFile(.URL, .File)}), LNC)
|
|
||||||
End If
|
|
||||||
j.Dispose()
|
|
||||||
End If
|
|
||||||
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
|
Private Overloads Function DownloadUserPhotos_PornHub(ByVal Token As CancellationToken) As Boolean
|
||||||
Try
|
Try
|
||||||
Dim albumName$
|
Dim albumName$
|
||||||
@@ -594,6 +511,7 @@ Namespace API.PornHub
|
|||||||
Dim r$ = Responser.GetResponse(String.Format(PhotoUrlPattern_PornHub, PersonType, NameTrue))
|
Dim r$ = Responser.GetResponse(String.Format(PhotoUrlPattern_PornHub, PersonType, NameTrue))
|
||||||
If Not r.IsEmptyString Then
|
If Not r.IsEmptyString Then
|
||||||
Dim l As List(Of PhotoBlock) = RegexFields(Of PhotoBlock)(r, {Regex_Photo_PornHub_PhotoBlocks}, {2, 1}, EDP.ReturnValue)
|
Dim l As List(Of PhotoBlock) = RegexFields(Of PhotoBlock)(r, {Regex_Photo_PornHub_PhotoBlocks}, {2, 1}, EDP.ReturnValue)
|
||||||
|
l.ListAddList(RegexFields(Of PhotoBlock)(r, {Regex_Photo_PornHub_PhotoBlocks2}, {1, 2}, EDP.ReturnValue))
|
||||||
If l.ListExists Then l.RemoveAll(Function(ll) ll.AlbumID.IsEmptyString)
|
If l.ListExists Then l.RemoveAll(Function(ll) ll.AlbumID.IsEmptyString)
|
||||||
If l.ListExists Then
|
If l.ListExists Then
|
||||||
ProgressPre.ChangeMax(l.Count)
|
ProgressPre.ChangeMax(l.Count)
|
||||||
@@ -618,6 +536,14 @@ Namespace API.PornHub
|
|||||||
Return False
|
Return False
|
||||||
End Try
|
End Try
|
||||||
End Function
|
End Function
|
||||||
|
Private Function DownloadUserPhotos_PornHub_ParseSinglePhoto(ByVal r As String) As String
|
||||||
|
Dim url$ = String.Empty
|
||||||
|
With DirectCast(RegexReplace(r, Regex_Photo_PornHub_SinglePhoto), List(Of String))
|
||||||
|
If .ListExists(3) Then url = .Item(2).IfNullOrEmpty(.Item(1)).StringTrim
|
||||||
|
End With
|
||||||
|
If url.IsEmptyString Then url = RegexReplace(r, Regex_Photo_PornHub_SinglePhoto2)
|
||||||
|
Return url
|
||||||
|
End Function
|
||||||
Private Overloads Function DownloadUserPhotos_PornHub(ByVal Page As Integer, ByVal AlbumID As String, ByVal AlbumName As String,
|
Private Overloads Function DownloadUserPhotos_PornHub(ByVal Page As Integer, ByVal AlbumID As String, ByVal AlbumName As String,
|
||||||
ByVal Token As CancellationToken) As Boolean
|
ByVal Token As CancellationToken) As Boolean
|
||||||
Try
|
Try
|
||||||
@@ -633,7 +559,7 @@ Namespace API.PornHub
|
|||||||
Try
|
Try
|
||||||
r = Responser.GetResponse(url)
|
r = Responser.GetResponse(url)
|
||||||
If Not r.IsEmptyString Then
|
If Not r.IsEmptyString Then
|
||||||
url = RegexReplace(r, Regex_Photo_PornHub_SinglePhoto)
|
url = DownloadUserPhotos_PornHub_ParseSinglePhoto(r)
|
||||||
If Not url.IsEmptyString Then _
|
If Not url.IsEmptyString Then _
|
||||||
_TempMediaList.ListAddValue(New UserMedia(url, UTypes.Picture) With {
|
_TempMediaList.ListAddValue(New UserMedia(url, UTypes.Picture) With {
|
||||||
.SpecialFolder = $"Albums\{AlbumName}\",
|
.SpecialFolder = $"Albums\{AlbumName}\",
|
||||||
@@ -679,7 +605,7 @@ Namespace API.PornHub
|
|||||||
Try
|
Try
|
||||||
r = Responser.GetResponse(m.URL)
|
r = Responser.GetResponse(m.URL)
|
||||||
If Not r.IsEmptyString Then
|
If Not r.IsEmptyString Then
|
||||||
NewUrl = RegexReplace(r, Regex_Photo_PornHub_SinglePhoto)
|
NewUrl = DownloadUserPhotos_PornHub_ParseSinglePhoto(r)
|
||||||
If Not NewUrl.IsEmptyString Then
|
If Not NewUrl.IsEmptyString Then
|
||||||
m.URL = NewUrl
|
m.URL = NewUrl
|
||||||
pFile = RegexReplace(NewUrl, Regex_Photo_File)
|
pFile = RegexReplace(NewUrl, Regex_Photo_File)
|
||||||
@@ -852,11 +778,34 @@ Namespace API.PornHub
|
|||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Download content"
|
#Region "Download content"
|
||||||
|
Private UpdateM3U8URLS As Boolean = False
|
||||||
|
Private UpdateM3U8URLS_Error As Boolean = False
|
||||||
Protected Overrides Sub DownloadContent(ByVal Token As CancellationToken)
|
Protected Overrides Sub DownloadContent(ByVal Token As CancellationToken)
|
||||||
DownloadContentDefault(Token)
|
Try : DownloadContentDefault(Token) : Finally : UpdateM3U8URLS = False : End Try
|
||||||
End Sub
|
End Sub
|
||||||
Protected Overrides Function DownloadM3U8(ByVal URL As String, ByVal Media As UserMedia, ByVal DestinationFile As SFile, ByVal Token As CancellationToken) As SFile
|
Protected Overloads Overrides Function DownloadM3U8(ByVal URL As String, ByVal Media As UserMedia, ByVal DestinationFile As SFile,
|
||||||
Return M3U8.Download(URL, Responser, DestinationFile, DownloadUHD, Token, Progress, Not IsSingleObjectDownload)
|
ByVal Token As CancellationToken) As SFile
|
||||||
|
UpdateM3U8URLS_Error = False
|
||||||
|
Return DownloadM3U8(URL, Media, DestinationFile, Token, UpdateM3U8URLS)
|
||||||
|
End Function
|
||||||
|
Private Overloads Function DownloadM3U8(ByVal URL As String, ByVal Media As UserMedia, ByVal DestinationFile As SFile,
|
||||||
|
ByVal Token As CancellationToken, ByVal Second As Boolean) As SFile
|
||||||
|
Try
|
||||||
|
If Second Then
|
||||||
|
Dim r$ = Responser.Curl(Media.URL_BASE,, EDP.ReturnValue)
|
||||||
|
If Not r.IsEmptyString Then Media.URL = CreateVideoURL(r).IfNullOrEmpty(URL) : URL = Media.URL
|
||||||
|
End If
|
||||||
|
Dim f As SFile = M3U8.Download(URL, Responser, DestinationFile, DownloadUHD, Token, Progress, Not IsSingleObjectDownload)
|
||||||
|
If Not f.Exists And Not Second Then UpdateM3U8URLS = True : f = DownloadM3U8(URL, Media, DestinationFile, Token, True)
|
||||||
|
Return f
|
||||||
|
Catch ex As Exception
|
||||||
|
If Not UpdateM3U8URLS_Error Then
|
||||||
|
UpdateM3U8URLS_Error = True
|
||||||
|
Thread.Sleep(1000)
|
||||||
|
Return DownloadM3U8(URL, Media, DestinationFile, Token, True)
|
||||||
|
End If
|
||||||
|
Return Nothing
|
||||||
|
End Try
|
||||||
End Function
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
#Region "CreateVideoURL"
|
#Region "CreateVideoURL"
|
||||||
@@ -953,6 +902,7 @@ Namespace API.PornHub
|
|||||||
#End Region
|
#End Region
|
||||||
#Region "DownloadSingleObject"
|
#Region "DownloadSingleObject"
|
||||||
Protected Overrides Sub DownloadSingleObject_GetPosts(ByVal Data As IYouTubeMediaContainer, ByVal Token As CancellationToken)
|
Protected Overrides Sub DownloadSingleObject_GetPosts(ByVal Data As IYouTubeMediaContainer, ByVal Token As CancellationToken)
|
||||||
|
UpdateM3U8URLS = False
|
||||||
_TempMediaList.Add(New UserMedia(Data.URL, UTypes.VideoPre))
|
_TempMediaList.Add(New UserMedia(Data.URL, UTypes.VideoPre))
|
||||||
ReparseVideo(Token, True, Data)
|
ReparseVideo(Token, True, Data)
|
||||||
End Sub
|
End Sub
|
||||||
|
|||||||
@@ -6,9 +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 SCrawler.API.Base
|
||||||
Imports SCrawler.Plugin.Attributes
|
Imports SCrawler.Plugin.Attributes
|
||||||
Namespace API.PornHub
|
Namespace API.PornHub
|
||||||
Friend Class UserExchangeOptions : Inherits Xhamster.UserExchangeOptions
|
Friend Class UserExchangeOptions : Inherits EditorExchangeOptionsBase_P
|
||||||
<PSetting(NameOf(SiteSettings.DownloadUHD), NameOf(MySettings))>
|
<PSetting(NameOf(SiteSettings.DownloadUHD), NameOf(MySettings))>
|
||||||
Friend Property DownloadUHD As Boolean
|
Friend Property DownloadUHD As Boolean
|
||||||
<PSetting(NameOf(SiteSettings.DownloadUploaded), NameOf(MySettings))>
|
<PSetting(NameOf(SiteSettings.DownloadUploaded), NameOf(MySettings))>
|
||||||
@@ -21,21 +22,19 @@ Namespace API.PornHub
|
|||||||
Friend Property DownloadFavorite As Boolean
|
Friend Property DownloadFavorite As Boolean
|
||||||
<PSetting(Caption:="Download gifs")>
|
<PSetting(Caption:="Download gifs")>
|
||||||
Friend Property DownloadGifs As Boolean
|
Friend Property DownloadGifs As Boolean
|
||||||
<PSetting(NameOf(SiteSettings.DownloadPhotoOnlyFromModelHub), NameOf(MySettings), Caption:="Download photo only from ModelHub")>
|
|
||||||
Friend Property DownloadPhotoOnlyFromModelHub As Boolean
|
|
||||||
Private ReadOnly Property MySettings As SiteSettings
|
Private ReadOnly Property MySettings As SiteSettings
|
||||||
Friend Sub New(ByVal u As UserData)
|
Friend Sub New(ByVal u As UserData)
|
||||||
|
MyBase.New(u)
|
||||||
DownloadUHD = u.DownloadUHD
|
DownloadUHD = u.DownloadUHD
|
||||||
DownloadUploaded = u.DownloadUploaded
|
DownloadUploaded = u.DownloadUploaded
|
||||||
DownloadTagged = u.DownloadTagged
|
DownloadTagged = u.DownloadTagged
|
||||||
DownloadPrivate = u.DownloadPrivate
|
DownloadPrivate = u.DownloadPrivate
|
||||||
DownloadFavorite = u.DownloadFavorite
|
DownloadFavorite = u.DownloadFavorite
|
||||||
DownloadGifs = u.DownloadGifs
|
DownloadGifs = u.DownloadGifs
|
||||||
DownloadPhotoOnlyFromModelHub = u.DownloadPhotoOnlyFromModelHub
|
|
||||||
QueryString = u.QueryString
|
|
||||||
MySettings = u.HOST.Source
|
MySettings = u.HOST.Source
|
||||||
End Sub
|
End Sub
|
||||||
Friend Sub New(ByVal s As SiteSettings)
|
Friend Sub New(ByVal s As SiteSettings)
|
||||||
|
MyBase.New(s)
|
||||||
Dim v As CheckState = CInt(s.DownloadGifs.Value)
|
Dim v As CheckState = CInt(s.DownloadGifs.Value)
|
||||||
DownloadUHD = s.DownloadUHD.Value
|
DownloadUHD = s.DownloadUHD.Value
|
||||||
DownloadUploaded = s.DownloadUploaded.Value
|
DownloadUploaded = s.DownloadUploaded.Value
|
||||||
@@ -43,8 +42,18 @@ Namespace API.PornHub
|
|||||||
DownloadPrivate = s.DownloadPrivate.Value
|
DownloadPrivate = s.DownloadPrivate.Value
|
||||||
DownloadFavorite = s.DownloadFavorite.Value
|
DownloadFavorite = s.DownloadFavorite.Value
|
||||||
DownloadGifs = Not v = CheckState.Unchecked
|
DownloadGifs = Not v = CheckState.Unchecked
|
||||||
DownloadPhotoOnlyFromModelHub = s.DownloadPhotoOnlyFromModelHub.Value
|
|
||||||
MySettings = s
|
MySettings = s
|
||||||
End Sub
|
End Sub
|
||||||
|
Friend Overrides Sub Apply(ByRef u As IPSite)
|
||||||
|
MyBase.Apply(u)
|
||||||
|
With DirectCast(u, UserData)
|
||||||
|
.DownloadUHD = DownloadUHD
|
||||||
|
.DownloadUploaded = DownloadUploaded
|
||||||
|
.DownloadTagged = DownloadTagged
|
||||||
|
.DownloadPrivate = DownloadPrivate
|
||||||
|
.DownloadFavorite = DownloadFavorite
|
||||||
|
.DownloadGifs = DownloadGifs
|
||||||
|
End With
|
||||||
|
End Sub
|
||||||
End Class
|
End Class
|
||||||
End Namespace
|
End Namespace
|
||||||
@@ -88,14 +88,22 @@ Namespace API.Reddit
|
|||||||
End Property
|
End Property
|
||||||
Friend Property ViewMode As View = View.New Implements IRedditView.ViewMode
|
Friend Property ViewMode As View = View.New Implements IRedditView.ViewMode
|
||||||
Friend Property ViewPeriod As Period = Period.All Implements IRedditView.ViewPeriod
|
Friend Property ViewPeriod As Period = Period.All Implements IRedditView.ViewPeriod
|
||||||
|
Friend Property DownloadText As Boolean = False Implements IRedditView.DownloadText
|
||||||
|
Friend Property DownloadTextPosts As Boolean = False Implements IRedditView.DownloadTextPosts
|
||||||
|
Friend Property DownloadTextSpecialFolder As Boolean = False Implements IRedditView.DownloadTextSpecialFolder
|
||||||
Friend Property RedGifsAccount As String = String.Empty Implements IRedditView.RedGifsAccount
|
Friend Property RedGifsAccount As String = String.Empty Implements IRedditView.RedGifsAccount
|
||||||
Friend Property RedditAccount As String = String.Empty Implements IRedditView.RedditAccount
|
Friend Property RedditAccount As String = String.Empty Implements IRedditView.RedditAccount
|
||||||
Friend Sub SetView(ByVal Options As IRedditView) Implements IRedditView.SetView
|
Friend Sub SetView(ByVal Options As IRedditView) Implements IRedditView.SetView
|
||||||
If Not Options Is Nothing Then
|
If Not Options Is Nothing Then
|
||||||
ViewMode = Options.ViewMode
|
With Options
|
||||||
ViewPeriod = Options.ViewPeriod
|
ViewMode = .ViewMode
|
||||||
RedditAccount = Options.RedditAccount
|
ViewPeriod = .ViewPeriod
|
||||||
RedGifsAccount = Options.RedGifsAccount
|
DownloadText = .DownloadText
|
||||||
|
DownloadTextPosts = .DownloadTextPosts
|
||||||
|
DownloadTextSpecialFolder = .DownloadTextSpecialFolder
|
||||||
|
RedditAccount = .RedditAccount
|
||||||
|
RedGifsAccount = .RedGifsAccount
|
||||||
|
End With
|
||||||
End If
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
#Region "Statistics support"
|
#Region "Statistics support"
|
||||||
|
|||||||
@@ -21,6 +21,6 @@ Namespace API.Reddit
|
|||||||
Friend ReadOnly UrlBasePattern As RParams = RParams.DM("(?<=/)([^/]+?\.[\w]{3,4})(?=(\?|\Z))", 0)
|
Friend ReadOnly UrlBasePattern As RParams = RParams.DM("(?<=/)([^/]+?\.[\w]{3,4})(?=(\?|\Z))", 0)
|
||||||
Friend ReadOnly VideoRegEx As RParams = RParams.DM("http.{0,1}://[^" & Chr(34) & "]+?mp4", 0)
|
Friend ReadOnly VideoRegEx As RParams = RParams.DM("http.{0,1}://[^" & Chr(34) & "]+?mp4", 0)
|
||||||
Private ReadOnly EUR_PROVIDER As New ANumbers(ANumbers.Cultures.EUR)
|
Private ReadOnly EUR_PROVIDER As New ANumbers(ANumbers.Cultures.EUR)
|
||||||
Friend ReadOnly UnixDate32ProviderReddit As New CustomProvider(Function(v, d, p, n, e) ADateTime.ParseUnix32(AConvert(Of Integer)(v, EUR_PROVIDER, v), n, e))
|
<Obsolete("Use 'UnixDate32Provider'", True)> Friend ReadOnly UnixDate32ProviderReddit As New CustomProvider(Function(v, d, p, n, e) ADateTime.ParseUnix32(AConvert(Of Double)(v, EUR_PROVIDER, v), n, e))
|
||||||
End Module
|
End Module
|
||||||
End Namespace
|
End Namespace
|
||||||
@@ -12,6 +12,8 @@ Namespace API.Reddit
|
|||||||
[New] = 0
|
[New] = 0
|
||||||
Hot = 1
|
Hot = 1
|
||||||
Top = 2
|
Top = 2
|
||||||
|
Best = 3
|
||||||
|
Rising = 4
|
||||||
End Enum
|
End Enum
|
||||||
Enum Period As Integer
|
Enum Period As Integer
|
||||||
All = 0
|
All = 0
|
||||||
@@ -23,25 +25,45 @@ Namespace API.Reddit
|
|||||||
End Enum
|
End Enum
|
||||||
Property ViewMode As View
|
Property ViewMode As View
|
||||||
Property ViewPeriod As Period
|
Property ViewPeriod As Period
|
||||||
|
Property DownloadText As Boolean
|
||||||
|
Property DownloadTextPosts As Boolean
|
||||||
|
Property DownloadTextSpecialFolder As Boolean
|
||||||
Property RedGifsAccount As String
|
Property RedGifsAccount As String
|
||||||
Property RedditAccount As String
|
Property RedditAccount As String
|
||||||
Sub SetView(ByVal Options As IRedditView)
|
Sub SetView(ByVal Options As IRedditView)
|
||||||
End Interface
|
End Interface
|
||||||
Friend Class RedditViewExchange : Implements IRedditView
|
Friend Class RedditViewExchange : Inherits Base.EditorExchangeOptionsBase : Implements IRedditView
|
||||||
Friend Const Name_ViewMode As String = "ViewMode"
|
Friend Const Name_ViewMode As String = "ViewMode"
|
||||||
Friend Const Name_ViewPeriod As String = "ViewPeriod"
|
Friend Const Name_ViewPeriod As String = "ViewPeriod"
|
||||||
Friend Const Name_RedGifsAccount As String = "RedGifsAccount"
|
Friend Const Name_RedGifsAccount As String = "RedGifsAccount"
|
||||||
Friend Const Name_RedditAccount As String = "RedditAccount"
|
Friend Const Name_RedditAccount As String = "RedditAccount"
|
||||||
Friend Property ViewMode As IRedditView.View Implements IRedditView.ViewMode
|
Friend Property ViewMode As IRedditView.View Implements IRedditView.ViewMode
|
||||||
Friend Property ViewPeriod As IRedditView.Period Implements IRedditView.ViewPeriod
|
Friend Property ViewPeriod As IRedditView.Period Implements IRedditView.ViewPeriod
|
||||||
|
Friend Overrides Property DownloadText As Boolean Implements IRedditView.DownloadText
|
||||||
|
Friend Overrides Property DownloadTextPosts As Boolean Implements IRedditView.DownloadTextPosts
|
||||||
|
Friend Overrides Property DownloadTextSpecialFolder As Boolean Implements IRedditView.DownloadTextSpecialFolder
|
||||||
Friend Property RedGifsAccount As String Implements IRedditView.RedGifsAccount
|
Friend Property RedGifsAccount As String Implements IRedditView.RedGifsAccount
|
||||||
Friend Property RedditAccount As String Implements IRedditView.RedditAccount
|
Friend Property RedditAccount As String Implements IRedditView.RedditAccount
|
||||||
|
Friend Sub New(ByVal Options As IRedditView)
|
||||||
|
MyBase.New(DirectCast(Options, UserData))
|
||||||
|
SetView(Options)
|
||||||
|
_ApplyBase_Name = False
|
||||||
|
End Sub
|
||||||
|
Friend Sub New(ByVal s As SiteSettings)
|
||||||
|
MyBase.New(s)
|
||||||
|
_ApplyBase_Name = False
|
||||||
|
End Sub
|
||||||
Friend Sub SetView(ByVal Options As IRedditView) Implements IRedditView.SetView
|
Friend Sub SetView(ByVal Options As IRedditView) Implements IRedditView.SetView
|
||||||
If Not Options Is Nothing Then
|
If Not Options Is Nothing Then
|
||||||
ViewMode = Options.ViewMode
|
With Options
|
||||||
ViewPeriod = Options.ViewPeriod
|
ViewMode = .ViewMode
|
||||||
RedGifsAccount = Options.RedGifsAccount
|
ViewPeriod = .ViewPeriod
|
||||||
RedditAccount = Options.RedditAccount
|
DownloadText = .DownloadText
|
||||||
|
DownloadTextPosts = .DownloadTextPosts
|
||||||
|
DownloadTextSpecialFolder = .DownloadTextSpecialFolder
|
||||||
|
RedGifsAccount = .RedGifsAccount
|
||||||
|
RedditAccount = .RedditAccount
|
||||||
|
End With
|
||||||
End If
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
End Class
|
End Class
|
||||||
|
|||||||
154
SCrawler/API/Reddit/RedditViewSettingsForm.Designer.vb
generated
@@ -22,17 +22,21 @@ Namespace API.Reddit
|
|||||||
Private components As System.ComponentModel.IContainer
|
Private components As System.ComponentModel.IContainer
|
||||||
<System.Diagnostics.DebuggerStepThrough()>
|
<System.Diagnostics.DebuggerStepThrough()>
|
||||||
Private Sub InitializeComponent()
|
Private Sub InitializeComponent()
|
||||||
|
Me.components = New System.ComponentModel.Container()
|
||||||
Dim CONTAINER_MAIN As System.Windows.Forms.ToolStripContainer
|
Dim CONTAINER_MAIN As System.Windows.Forms.ToolStripContainer
|
||||||
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 ActionButton1 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
Dim ActionButton3 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||||
Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(RedditViewSettingsForm))
|
Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(RedditViewSettingsForm))
|
||||||
Dim ActionButton2 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
Dim ActionButton4 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||||
|
Dim TP_TEXT As System.Windows.Forms.TableLayoutPanel
|
||||||
Me.TP_MAIN = New System.Windows.Forms.TableLayoutPanel()
|
Me.TP_MAIN = New System.Windows.Forms.TableLayoutPanel()
|
||||||
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()
|
||||||
|
Me.OPT_VIEW_MODE_BEST = New System.Windows.Forms.RadioButton()
|
||||||
|
Me.OPT_VIEW_MODE_RISING = New System.Windows.Forms.RadioButton()
|
||||||
Me.TP_PERIOD = New System.Windows.Forms.TableLayoutPanel()
|
Me.TP_PERIOD = New System.Windows.Forms.TableLayoutPanel()
|
||||||
Me.OPT_PERIOD_ALL = New System.Windows.Forms.RadioButton()
|
Me.OPT_PERIOD_ALL = New System.Windows.Forms.RadioButton()
|
||||||
Me.OPT_PERIOD_HOUR = New System.Windows.Forms.RadioButton()
|
Me.OPT_PERIOD_HOUR = New System.Windows.Forms.RadioButton()
|
||||||
@@ -42,10 +46,15 @@ Namespace API.Reddit
|
|||||||
Me.OPT_PERIOD_YEAR = New System.Windows.Forms.RadioButton()
|
Me.OPT_PERIOD_YEAR = New System.Windows.Forms.RadioButton()
|
||||||
Me.CMB_REDGIFS_ACC = New PersonalUtilities.Forms.Controls.ComboBoxExtended()
|
Me.CMB_REDGIFS_ACC = New PersonalUtilities.Forms.Controls.ComboBoxExtended()
|
||||||
Me.CMB_REDDIT_ACC = New PersonalUtilities.Forms.Controls.ComboBoxExtended()
|
Me.CMB_REDDIT_ACC = New PersonalUtilities.Forms.Controls.ComboBoxExtended()
|
||||||
|
Me.CH_TXT_DOWN_TXT = New System.Windows.Forms.CheckBox()
|
||||||
|
Me.CH_TXT_DOWN_POSTS = New System.Windows.Forms.CheckBox()
|
||||||
|
Me.TT_MAIN = New System.Windows.Forms.ToolTip(Me.components)
|
||||||
|
Me.CH_TXT_DOWN_SPEC_FOLDER = New System.Windows.Forms.CheckBox()
|
||||||
CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer()
|
CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer()
|
||||||
TP_VIEW_MODE = New System.Windows.Forms.TableLayoutPanel()
|
TP_VIEW_MODE = New System.Windows.Forms.TableLayoutPanel()
|
||||||
LBL_VIEW_MODE = New System.Windows.Forms.Label()
|
LBL_VIEW_MODE = New System.Windows.Forms.Label()
|
||||||
LBL_PERIOD = New System.Windows.Forms.Label()
|
LBL_PERIOD = New System.Windows.Forms.Label()
|
||||||
|
TP_TEXT = New System.Windows.Forms.TableLayoutPanel()
|
||||||
CONTAINER_MAIN.ContentPanel.SuspendLayout()
|
CONTAINER_MAIN.ContentPanel.SuspendLayout()
|
||||||
CONTAINER_MAIN.SuspendLayout()
|
CONTAINER_MAIN.SuspendLayout()
|
||||||
Me.TP_MAIN.SuspendLayout()
|
Me.TP_MAIN.SuspendLayout()
|
||||||
@@ -53,6 +62,7 @@ Namespace API.Reddit
|
|||||||
Me.TP_PERIOD.SuspendLayout()
|
Me.TP_PERIOD.SuspendLayout()
|
||||||
CType(Me.CMB_REDGIFS_ACC, System.ComponentModel.ISupportInitialize).BeginInit()
|
CType(Me.CMB_REDGIFS_ACC, System.ComponentModel.ISupportInitialize).BeginInit()
|
||||||
CType(Me.CMB_REDDIT_ACC, System.ComponentModel.ISupportInitialize).BeginInit()
|
CType(Me.CMB_REDDIT_ACC, System.ComponentModel.ISupportInitialize).BeginInit()
|
||||||
|
TP_TEXT.SuspendLayout()
|
||||||
Me.SuspendLayout()
|
Me.SuspendLayout()
|
||||||
'
|
'
|
||||||
'CONTAINER_MAIN
|
'CONTAINER_MAIN
|
||||||
@@ -61,13 +71,13 @@ Namespace API.Reddit
|
|||||||
'CONTAINER_MAIN.ContentPanel
|
'CONTAINER_MAIN.ContentPanel
|
||||||
'
|
'
|
||||||
CONTAINER_MAIN.ContentPanel.Controls.Add(Me.TP_MAIN)
|
CONTAINER_MAIN.ContentPanel.Controls.Add(Me.TP_MAIN)
|
||||||
CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(477, 169)
|
CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(477, 222)
|
||||||
CONTAINER_MAIN.Dock = System.Windows.Forms.DockStyle.Fill
|
CONTAINER_MAIN.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
CONTAINER_MAIN.LeftToolStripPanelVisible = False
|
CONTAINER_MAIN.LeftToolStripPanelVisible = False
|
||||||
CONTAINER_MAIN.Location = New System.Drawing.Point(0, 0)
|
CONTAINER_MAIN.Location = New System.Drawing.Point(0, 0)
|
||||||
CONTAINER_MAIN.Name = "CONTAINER_MAIN"
|
CONTAINER_MAIN.Name = "CONTAINER_MAIN"
|
||||||
CONTAINER_MAIN.RightToolStripPanelVisible = False
|
CONTAINER_MAIN.RightToolStripPanelVisible = False
|
||||||
CONTAINER_MAIN.Size = New System.Drawing.Size(477, 169)
|
CONTAINER_MAIN.Size = New System.Drawing.Size(477, 222)
|
||||||
CONTAINER_MAIN.TabIndex = 0
|
CONTAINER_MAIN.TabIndex = 0
|
||||||
CONTAINER_MAIN.TopToolStripPanelVisible = False
|
CONTAINER_MAIN.TopToolStripPanelVisible = False
|
||||||
'
|
'
|
||||||
@@ -78,18 +88,20 @@ Namespace API.Reddit
|
|||||||
Me.TP_MAIN.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
Me.TP_MAIN.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||||
Me.TP_MAIN.Controls.Add(TP_VIEW_MODE, 0, 0)
|
Me.TP_MAIN.Controls.Add(TP_VIEW_MODE, 0, 0)
|
||||||
Me.TP_MAIN.Controls.Add(Me.TP_PERIOD, 0, 1)
|
Me.TP_MAIN.Controls.Add(Me.TP_PERIOD, 0, 1)
|
||||||
Me.TP_MAIN.Controls.Add(Me.CMB_REDGIFS_ACC, 0, 3)
|
Me.TP_MAIN.Controls.Add(Me.CMB_REDGIFS_ACC, 0, 4)
|
||||||
Me.TP_MAIN.Controls.Add(Me.CMB_REDDIT_ACC, 0, 2)
|
Me.TP_MAIN.Controls.Add(Me.CMB_REDDIT_ACC, 0, 3)
|
||||||
|
Me.TP_MAIN.Controls.Add(TP_TEXT, 0, 2)
|
||||||
Me.TP_MAIN.Dock = System.Windows.Forms.DockStyle.Fill
|
Me.TP_MAIN.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
Me.TP_MAIN.Location = New System.Drawing.Point(0, 0)
|
Me.TP_MAIN.Location = New System.Drawing.Point(0, 0)
|
||||||
Me.TP_MAIN.Name = "TP_MAIN"
|
Me.TP_MAIN.Name = "TP_MAIN"
|
||||||
Me.TP_MAIN.RowCount = 5
|
Me.TP_MAIN.RowCount = 6
|
||||||
Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
|
|
||||||
Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 56.0!))
|
Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 56.0!))
|
||||||
|
Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 56.0!))
|
||||||
|
Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||||
Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
|
Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
|
||||||
Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
|
Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
|
||||||
Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||||
Me.TP_MAIN.Size = New System.Drawing.Size(477, 169)
|
Me.TP_MAIN.Size = New System.Drawing.Size(477, 222)
|
||||||
Me.TP_MAIN.TabIndex = 0
|
Me.TP_MAIN.TabIndex = 0
|
||||||
'
|
'
|
||||||
'TP_VIEW_MODE
|
'TP_VIEW_MODE
|
||||||
@@ -103,14 +115,16 @@ Namespace API.Reddit
|
|||||||
TP_VIEW_MODE.Controls.Add(Me.OPT_VIEW_MODE_NEW, 1, 0)
|
TP_VIEW_MODE.Controls.Add(Me.OPT_VIEW_MODE_NEW, 1, 0)
|
||||||
TP_VIEW_MODE.Controls.Add(Me.OPT_VIEW_MODE_HOT, 2, 0)
|
TP_VIEW_MODE.Controls.Add(Me.OPT_VIEW_MODE_HOT, 2, 0)
|
||||||
TP_VIEW_MODE.Controls.Add(Me.OPT_VIEW_MODE_TOP, 3, 0)
|
TP_VIEW_MODE.Controls.Add(Me.OPT_VIEW_MODE_TOP, 3, 0)
|
||||||
|
TP_VIEW_MODE.Controls.Add(Me.OPT_VIEW_MODE_BEST, 1, 1)
|
||||||
|
TP_VIEW_MODE.Controls.Add(Me.OPT_VIEW_MODE_RISING, 2, 1)
|
||||||
TP_VIEW_MODE.Dock = System.Windows.Forms.DockStyle.Fill
|
TP_VIEW_MODE.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
TP_VIEW_MODE.Location = New System.Drawing.Point(1, 1)
|
TP_VIEW_MODE.Location = New System.Drawing.Point(1, 1)
|
||||||
TP_VIEW_MODE.Margin = New System.Windows.Forms.Padding(0)
|
TP_VIEW_MODE.Margin = New System.Windows.Forms.Padding(0)
|
||||||
TP_VIEW_MODE.Name = "TP_VIEW_MODE"
|
TP_VIEW_MODE.Name = "TP_VIEW_MODE"
|
||||||
TP_VIEW_MODE.RowCount = 1
|
TP_VIEW_MODE.RowCount = 2
|
||||||
TP_VIEW_MODE.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
TP_VIEW_MODE.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
|
||||||
TP_VIEW_MODE.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
|
TP_VIEW_MODE.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
|
||||||
TP_VIEW_MODE.Size = New System.Drawing.Size(475, 28)
|
TP_VIEW_MODE.Size = New System.Drawing.Size(475, 56)
|
||||||
TP_VIEW_MODE.TabIndex = 0
|
TP_VIEW_MODE.TabIndex = 0
|
||||||
'
|
'
|
||||||
'LBL_VIEW_MODE
|
'LBL_VIEW_MODE
|
||||||
@@ -160,6 +174,30 @@ Namespace API.Reddit
|
|||||||
Me.OPT_VIEW_MODE_TOP.Text = "Top"
|
Me.OPT_VIEW_MODE_TOP.Text = "Top"
|
||||||
Me.OPT_VIEW_MODE_TOP.UseVisualStyleBackColor = True
|
Me.OPT_VIEW_MODE_TOP.UseVisualStyleBackColor = True
|
||||||
'
|
'
|
||||||
|
'OPT_VIEW_MODE_BEST
|
||||||
|
'
|
||||||
|
Me.OPT_VIEW_MODE_BEST.AutoSize = True
|
||||||
|
Me.OPT_VIEW_MODE_BEST.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.OPT_VIEW_MODE_BEST.Location = New System.Drawing.Point(121, 31)
|
||||||
|
Me.OPT_VIEW_MODE_BEST.Name = "OPT_VIEW_MODE_BEST"
|
||||||
|
Me.OPT_VIEW_MODE_BEST.Size = New System.Drawing.Size(112, 22)
|
||||||
|
Me.OPT_VIEW_MODE_BEST.TabIndex = 4
|
||||||
|
Me.OPT_VIEW_MODE_BEST.TabStop = True
|
||||||
|
Me.OPT_VIEW_MODE_BEST.Text = "Best"
|
||||||
|
Me.OPT_VIEW_MODE_BEST.UseVisualStyleBackColor = True
|
||||||
|
'
|
||||||
|
'OPT_VIEW_MODE_RISING
|
||||||
|
'
|
||||||
|
Me.OPT_VIEW_MODE_RISING.AutoSize = True
|
||||||
|
Me.OPT_VIEW_MODE_RISING.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.OPT_VIEW_MODE_RISING.Location = New System.Drawing.Point(239, 31)
|
||||||
|
Me.OPT_VIEW_MODE_RISING.Name = "OPT_VIEW_MODE_RISING"
|
||||||
|
Me.OPT_VIEW_MODE_RISING.Size = New System.Drawing.Size(112, 22)
|
||||||
|
Me.OPT_VIEW_MODE_RISING.TabIndex = 5
|
||||||
|
Me.OPT_VIEW_MODE_RISING.TabStop = True
|
||||||
|
Me.OPT_VIEW_MODE_RISING.Text = "Rising"
|
||||||
|
Me.OPT_VIEW_MODE_RISING.UseVisualStyleBackColor = True
|
||||||
|
'
|
||||||
'TP_PERIOD
|
'TP_PERIOD
|
||||||
'
|
'
|
||||||
Me.TP_PERIOD.ColumnCount = 4
|
Me.TP_PERIOD.ColumnCount = 4
|
||||||
@@ -175,7 +213,7 @@ Namespace API.Reddit
|
|||||||
Me.TP_PERIOD.Controls.Add(Me.OPT_PERIOD_MONTH, 2, 1)
|
Me.TP_PERIOD.Controls.Add(Me.OPT_PERIOD_MONTH, 2, 1)
|
||||||
Me.TP_PERIOD.Controls.Add(Me.OPT_PERIOD_YEAR, 3, 1)
|
Me.TP_PERIOD.Controls.Add(Me.OPT_PERIOD_YEAR, 3, 1)
|
||||||
Me.TP_PERIOD.Dock = System.Windows.Forms.DockStyle.Fill
|
Me.TP_PERIOD.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
Me.TP_PERIOD.Location = New System.Drawing.Point(1, 30)
|
Me.TP_PERIOD.Location = New System.Drawing.Point(1, 58)
|
||||||
Me.TP_PERIOD.Margin = New System.Windows.Forms.Padding(0)
|
Me.TP_PERIOD.Margin = New System.Windows.Forms.Padding(0)
|
||||||
Me.TP_PERIOD.Name = "TP_PERIOD"
|
Me.TP_PERIOD.Name = "TP_PERIOD"
|
||||||
Me.TP_PERIOD.RowCount = 2
|
Me.TP_PERIOD.RowCount = 2
|
||||||
@@ -269,17 +307,17 @@ Namespace API.Reddit
|
|||||||
'
|
'
|
||||||
'CMB_REDGIFS_ACC
|
'CMB_REDGIFS_ACC
|
||||||
'
|
'
|
||||||
ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image)
|
ActionButton3.BackgroundImage = CType(resources.GetObject("ActionButton3.BackgroundImage"), System.Drawing.Image)
|
||||||
ActionButton1.Name = "ArrowDown"
|
ActionButton3.Name = "ArrowDown"
|
||||||
ActionButton1.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.ArrowDown
|
ActionButton3.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.ArrowDown
|
||||||
Me.CMB_REDGIFS_ACC.Buttons.Add(ActionButton1)
|
Me.CMB_REDGIFS_ACC.Buttons.Add(ActionButton3)
|
||||||
Me.CMB_REDGIFS_ACC.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.Label
|
Me.CMB_REDGIFS_ACC.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.Label
|
||||||
Me.CMB_REDGIFS_ACC.CaptionSizeType = System.Windows.Forms.SizeType.Percent
|
Me.CMB_REDGIFS_ACC.CaptionSizeType = System.Windows.Forms.SizeType.Percent
|
||||||
Me.CMB_REDGIFS_ACC.CaptionText = "RedGifs account"
|
Me.CMB_REDGIFS_ACC.CaptionText = "RedGifs account"
|
||||||
Me.CMB_REDGIFS_ACC.CaptionVisible = True
|
Me.CMB_REDGIFS_ACC.CaptionVisible = True
|
||||||
Me.CMB_REDGIFS_ACC.CaptionWidth = 26.0R
|
Me.CMB_REDGIFS_ACC.CaptionWidth = 26.0R
|
||||||
Me.CMB_REDGIFS_ACC.Dock = System.Windows.Forms.DockStyle.Fill
|
Me.CMB_REDGIFS_ACC.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
Me.CMB_REDGIFS_ACC.Location = New System.Drawing.Point(4, 119)
|
Me.CMB_REDGIFS_ACC.Location = New System.Drawing.Point(4, 173)
|
||||||
Me.CMB_REDGIFS_ACC.Name = "CMB_REDGIFS_ACC"
|
Me.CMB_REDGIFS_ACC.Name = "CMB_REDGIFS_ACC"
|
||||||
Me.CMB_REDGIFS_ACC.Size = New System.Drawing.Size(469, 22)
|
Me.CMB_REDGIFS_ACC.Size = New System.Drawing.Size(469, 22)
|
||||||
Me.CMB_REDGIFS_ACC.TabIndex = 4
|
Me.CMB_REDGIFS_ACC.TabIndex = 4
|
||||||
@@ -287,35 +325,89 @@ Namespace API.Reddit
|
|||||||
'
|
'
|
||||||
'CMB_REDDIT_ACC
|
'CMB_REDDIT_ACC
|
||||||
'
|
'
|
||||||
ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image)
|
ActionButton4.BackgroundImage = CType(resources.GetObject("ActionButton4.BackgroundImage"), System.Drawing.Image)
|
||||||
ActionButton2.Name = "ArrowDown"
|
ActionButton4.Name = "ArrowDown"
|
||||||
ActionButton2.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.ArrowDown
|
ActionButton4.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.ArrowDown
|
||||||
Me.CMB_REDDIT_ACC.Buttons.Add(ActionButton2)
|
Me.CMB_REDDIT_ACC.Buttons.Add(ActionButton4)
|
||||||
Me.CMB_REDDIT_ACC.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.Label
|
Me.CMB_REDDIT_ACC.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.Label
|
||||||
Me.CMB_REDDIT_ACC.CaptionSizeType = System.Windows.Forms.SizeType.Percent
|
Me.CMB_REDDIT_ACC.CaptionSizeType = System.Windows.Forms.SizeType.Percent
|
||||||
Me.CMB_REDDIT_ACC.CaptionText = "Reddit account"
|
Me.CMB_REDDIT_ACC.CaptionText = "Reddit account"
|
||||||
Me.CMB_REDDIT_ACC.CaptionVisible = True
|
Me.CMB_REDDIT_ACC.CaptionVisible = True
|
||||||
Me.CMB_REDDIT_ACC.CaptionWidth = 26.0R
|
Me.CMB_REDDIT_ACC.CaptionWidth = 26.0R
|
||||||
Me.CMB_REDDIT_ACC.Dock = System.Windows.Forms.DockStyle.Fill
|
Me.CMB_REDDIT_ACC.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
Me.CMB_REDDIT_ACC.Location = New System.Drawing.Point(4, 90)
|
Me.CMB_REDDIT_ACC.Location = New System.Drawing.Point(4, 144)
|
||||||
Me.CMB_REDDIT_ACC.Name = "CMB_REDDIT_ACC"
|
Me.CMB_REDDIT_ACC.Name = "CMB_REDDIT_ACC"
|
||||||
Me.CMB_REDDIT_ACC.Size = New System.Drawing.Size(469, 22)
|
Me.CMB_REDDIT_ACC.Size = New System.Drawing.Size(469, 22)
|
||||||
Me.CMB_REDDIT_ACC.TabIndex = 3
|
Me.CMB_REDDIT_ACC.TabIndex = 3
|
||||||
Me.CMB_REDDIT_ACC.TextBoxBorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
|
Me.CMB_REDDIT_ACC.TextBoxBorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
|
||||||
'
|
'
|
||||||
|
'TP_TEXT
|
||||||
|
'
|
||||||
|
TP_TEXT.ColumnCount = 3
|
||||||
|
TP_TEXT.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333!))
|
||||||
|
TP_TEXT.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333!))
|
||||||
|
TP_TEXT.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333!))
|
||||||
|
TP_TEXT.Controls.Add(Me.CH_TXT_DOWN_TXT, 0, 0)
|
||||||
|
TP_TEXT.Controls.Add(Me.CH_TXT_DOWN_POSTS, 1, 0)
|
||||||
|
TP_TEXT.Controls.Add(Me.CH_TXT_DOWN_SPEC_FOLDER, 2, 0)
|
||||||
|
TP_TEXT.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
TP_TEXT.Location = New System.Drawing.Point(1, 115)
|
||||||
|
TP_TEXT.Margin = New System.Windows.Forms.Padding(0)
|
||||||
|
TP_TEXT.Name = "TP_TEXT"
|
||||||
|
TP_TEXT.RowCount = 1
|
||||||
|
TP_TEXT.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||||
|
TP_TEXT.Size = New System.Drawing.Size(475, 25)
|
||||||
|
TP_TEXT.TabIndex = 5
|
||||||
|
'
|
||||||
|
'CH_TXT_DOWN_TXT
|
||||||
|
'
|
||||||
|
Me.CH_TXT_DOWN_TXT.AutoSize = True
|
||||||
|
Me.CH_TXT_DOWN_TXT.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.CH_TXT_DOWN_TXT.Location = New System.Drawing.Point(3, 3)
|
||||||
|
Me.CH_TXT_DOWN_TXT.Name = "CH_TXT_DOWN_TXT"
|
||||||
|
Me.CH_TXT_DOWN_TXT.Size = New System.Drawing.Size(152, 19)
|
||||||
|
Me.CH_TXT_DOWN_TXT.TabIndex = 0
|
||||||
|
Me.CH_TXT_DOWN_TXT.Text = "Download text"
|
||||||
|
Me.TT_MAIN.SetToolTip(Me.CH_TXT_DOWN_TXT, "Download text (if available) for posts with image and video")
|
||||||
|
Me.CH_TXT_DOWN_TXT.UseVisualStyleBackColor = True
|
||||||
|
'
|
||||||
|
'CH_TXT_DOWN_POSTS
|
||||||
|
'
|
||||||
|
Me.CH_TXT_DOWN_POSTS.AutoSize = True
|
||||||
|
Me.CH_TXT_DOWN_POSTS.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.CH_TXT_DOWN_POSTS.Location = New System.Drawing.Point(161, 3)
|
||||||
|
Me.CH_TXT_DOWN_POSTS.Name = "CH_TXT_DOWN_POSTS"
|
||||||
|
Me.CH_TXT_DOWN_POSTS.Size = New System.Drawing.Size(152, 19)
|
||||||
|
Me.CH_TXT_DOWN_POSTS.TabIndex = 1
|
||||||
|
Me.CH_TXT_DOWN_POSTS.Text = "Download text posts"
|
||||||
|
Me.TT_MAIN.SetToolTip(Me.CH_TXT_DOWN_POSTS, "Download text (if available) for text posts (no image and video)")
|
||||||
|
Me.CH_TXT_DOWN_POSTS.UseVisualStyleBackColor = True
|
||||||
|
'
|
||||||
|
'CH_TXT_DOWN_SPEC_FOLDER
|
||||||
|
'
|
||||||
|
Me.CH_TXT_DOWN_SPEC_FOLDER.AutoSize = True
|
||||||
|
Me.CH_TXT_DOWN_SPEC_FOLDER.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.CH_TXT_DOWN_SPEC_FOLDER.Location = New System.Drawing.Point(319, 3)
|
||||||
|
Me.CH_TXT_DOWN_SPEC_FOLDER.Name = "CH_TXT_DOWN_SPEC_FOLDER"
|
||||||
|
Me.CH_TXT_DOWN_SPEC_FOLDER.Size = New System.Drawing.Size(153, 19)
|
||||||
|
Me.CH_TXT_DOWN_SPEC_FOLDER.TabIndex = 2
|
||||||
|
Me.CH_TXT_DOWN_SPEC_FOLDER.Text = "Text special folder"
|
||||||
|
Me.TT_MAIN.SetToolTip(Me.CH_TXT_DOWN_SPEC_FOLDER, "If checked, text files will be saved to a separate folder")
|
||||||
|
Me.CH_TXT_DOWN_SPEC_FOLDER.UseVisualStyleBackColor = True
|
||||||
|
'
|
||||||
'RedditViewSettingsForm
|
'RedditViewSettingsForm
|
||||||
'
|
'
|
||||||
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
|
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
|
||||||
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
|
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
|
||||||
Me.ClientSize = New System.Drawing.Size(477, 169)
|
Me.ClientSize = New System.Drawing.Size(477, 222)
|
||||||
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.RedditIcon_128
|
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, 208)
|
Me.MaximumSize = New System.Drawing.Size(493, 261)
|
||||||
Me.MinimizeBox = False
|
Me.MinimizeBox = False
|
||||||
Me.MinimumSize = New System.Drawing.Size(493, 208)
|
Me.MinimumSize = New System.Drawing.Size(493, 261)
|
||||||
Me.Name = "RedditViewSettingsForm"
|
Me.Name = "RedditViewSettingsForm"
|
||||||
Me.ShowInTaskbar = False
|
Me.ShowInTaskbar = False
|
||||||
Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide
|
Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide
|
||||||
@@ -330,6 +422,8 @@ Namespace API.Reddit
|
|||||||
Me.TP_PERIOD.PerformLayout()
|
Me.TP_PERIOD.PerformLayout()
|
||||||
CType(Me.CMB_REDGIFS_ACC, System.ComponentModel.ISupportInitialize).EndInit()
|
CType(Me.CMB_REDGIFS_ACC, System.ComponentModel.ISupportInitialize).EndInit()
|
||||||
CType(Me.CMB_REDDIT_ACC, System.ComponentModel.ISupportInitialize).EndInit()
|
CType(Me.CMB_REDDIT_ACC, System.ComponentModel.ISupportInitialize).EndInit()
|
||||||
|
TP_TEXT.ResumeLayout(False)
|
||||||
|
TP_TEXT.PerformLayout()
|
||||||
Me.ResumeLayout(False)
|
Me.ResumeLayout(False)
|
||||||
|
|
||||||
End Sub
|
End Sub
|
||||||
@@ -346,5 +440,11 @@ Namespace API.Reddit
|
|||||||
Private WithEvents CMB_REDGIFS_ACC As PersonalUtilities.Forms.Controls.ComboBoxExtended
|
Private WithEvents CMB_REDGIFS_ACC As PersonalUtilities.Forms.Controls.ComboBoxExtended
|
||||||
Private WithEvents CMB_REDDIT_ACC As PersonalUtilities.Forms.Controls.ComboBoxExtended
|
Private WithEvents CMB_REDDIT_ACC As PersonalUtilities.Forms.Controls.ComboBoxExtended
|
||||||
Private WithEvents TP_MAIN As TableLayoutPanel
|
Private WithEvents TP_MAIN As TableLayoutPanel
|
||||||
|
Private WithEvents OPT_VIEW_MODE_BEST As RadioButton
|
||||||
|
Private WithEvents OPT_VIEW_MODE_RISING As RadioButton
|
||||||
|
Private WithEvents CH_TXT_DOWN_TXT As CheckBox
|
||||||
|
Private WithEvents TT_MAIN As ToolTip
|
||||||
|
Private WithEvents CH_TXT_DOWN_POSTS As CheckBox
|
||||||
|
Private WithEvents CH_TXT_DOWN_SPEC_FOLDER As CheckBox
|
||||||
End Class
|
End Class
|
||||||
End Namespace
|
End Namespace
|
||||||
@@ -130,184 +130,195 @@
|
|||||||
<value>False</value>
|
<value>False</value>
|
||||||
</metadata>
|
</metadata>
|
||||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||||
<data name="ActionButton1.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="ActionButton3.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
<value>
|
<value>
|
||||||
iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABGdBTUEAALGPC/xhBQAAE65JREFUeF7t
|
iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABGdBTUEAALGPC/xhBQAAE0xJREFUeF7t
|
||||||
3X2sJWddB/DdLi2lQG2hdOHuvfM887J7Cxca4ELTQMDWKigIFpBAEAgi9g+CJpJo9Q8NJhgBiYZIYspL
|
3X2MZWddB/BZSkspUFsoXZidOc/vnOfsTmGgARaaBgK2VkFBsIAEgkAQsX8QNJFEq39oMMEoSDREElOB
|
||||||
GlAKCkhEC4KgQlsLQkqhKi/lrYWWlxaw3dLddrerz/Q89+7dc2fbfTn3npf5fJJv2rS758z85nnOzJz5
|
EFAKCkhEAUGqQlsLQkoBlZfy1kJ5awH7QrvtbldzdndmZ597Snd37szce8/nk3xTQjsz5/zOefbO3vO9
|
||||||
nZktAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
58zNAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
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
|
||||||
k/LT6hD+Mu2oR/4rgXTW/+X02r+U3woAmDTtz/GaIv5F2nH/ZHhHfpS5J+Vf01n/S9LLbhu8OgAw0dpb
|
mQO/EFTVctfezxEXtlX9vLaqX9z9s6mqC5YWF+fLrwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
8TYL5XPTmfvb0o78v/MOvWtHvybtzXzKT1Qx/n5d1wv5pQCAaXXvAUFRLLXd+3WMFzZF+cKUl7X/rIri
|
|
||||||
gsWFhbn8RwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
|
||||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6LEtW/4flgYiLD1qeX0A
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
AAAASUVORK5CYII=
|
AAAAAAAAAAAAYIj+H5YGIizEb/aEAAAAAElFTkSuQmCC
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ActionButton2.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="ActionButton4.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
<value>
|
<value>
|
||||||
iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABGdBTUEAALGPC/xhBQAAE65JREFUeF7t
|
iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABGdBTUEAALGPC/xhBQAAE0xJREFUeF7t
|
||||||
3X2sJWddB/DdLi2lQG2hdOHuvfM887J7Cxca4ELTQMDWKigIFpBAEAgi9g+CJpJo9Q8NJhgBiYZIYspL
|
3X2MZWddB/BZSkspUFsoXZidOc/vnOfsTmGgARaaBgK2VkFBsIAEgkAQsX8QNJFEq39oMMEoSDREElOB
|
||||||
GlAKCkhEC4KgQlsLQkqhKi/lrYWWlxaw3dLddrerz/Q89+7dc2fbfTn3npf5fJJv2rS758z85nnOzJz5
|
EFAKCkhEAUGqQlsLQkoBlZfy1kJ5awH7QrvtbldzdndmZ597Snd37szce8/nk3xTQjsz5/zOefbO3vO9
|
||||||
nZktAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
58zNAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
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
|
||||||
k/LT6hD+Mu2oR/4rgXTW/+X02r+U3woAmDTtz/GaIv5F2nH/ZHhHfpS5J+Vf01n/S9LLbhu8OgAw0dpb
|
mQO/EFTVctfezxEXtlX9vLaqX9z9s6mqC5YWF+fLrwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
8TYL5XPTmfvb0o78v/MOvWtHvybtzXzKT1Qx/n5d1wv5pQCAaXXvAUFRLLXd+3WMFzZF+cKUl7X/rIri
|
|
||||||
gsWFhbn8RwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
|
||||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6LEtW/4flgYiLD1qeX0A
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
AAAASUVORK5CYII=
|
AAAAAAAAAAAAYIj+H5YGIizEb/aEAAAAAElFTkSuQmCC
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
|
<metadata name="TP_TEXT.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>False</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="TT_MAIN.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
|
<value>17, 17</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="TT_MAIN.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
|
<value>17, 17</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="LBL_VIEW_MODE.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>False</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="LBL_PERIOD.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>False</value>
|
||||||
|
</metadata>
|
||||||
</root>
|
</root>
|
||||||
@@ -38,6 +38,8 @@ Namespace API.Reddit
|
|||||||
Select Case MyOptions.ViewMode
|
Select Case MyOptions.ViewMode
|
||||||
Case CView.Hot : OPT_VIEW_MODE_HOT.Checked = True
|
Case CView.Hot : OPT_VIEW_MODE_HOT.Checked = True
|
||||||
Case CView.Top : OPT_VIEW_MODE_TOP.Checked = True
|
Case CView.Top : OPT_VIEW_MODE_TOP.Checked = True
|
||||||
|
Case CView.Best : OPT_VIEW_MODE_BEST.Checked = True
|
||||||
|
Case CView.Rising : OPT_VIEW_MODE_RISING.Checked = True
|
||||||
Case Else : OPT_VIEW_MODE_NEW.Checked = True
|
Case Else : OPT_VIEW_MODE_NEW.Checked = True
|
||||||
End Select
|
End Select
|
||||||
Select Case MyOptions.ViewPeriod
|
Select Case MyOptions.ViewPeriod
|
||||||
@@ -50,11 +52,15 @@ Namespace API.Reddit
|
|||||||
End Select
|
End Select
|
||||||
ChangePeriodEnabled()
|
ChangePeriodEnabled()
|
||||||
|
|
||||||
|
CH_TXT_DOWN_TXT.Checked = MyOptions.DownloadText
|
||||||
|
CH_TXT_DOWN_POSTS.Checked = MyOptions.DownloadTextPosts
|
||||||
|
CH_TXT_DOWN_SPEC_FOLDER.Checked = MyOptions.DownloadTextSpecialFolder
|
||||||
|
|
||||||
PopulateCMB(Settings(RedditSiteKey), CMB_REDDIT_ACC, MyOptions.RedditAccount)
|
PopulateCMB(Settings(RedditSiteKey), CMB_REDDIT_ACC, MyOptions.RedditAccount)
|
||||||
PopulateCMB(Settings(RedGifs.RedGifsSiteKey), CMB_REDGIFS_ACC, MyOptions.RedGifsAccount)
|
PopulateCMB(Settings(RedGifs.RedGifsSiteKey), CMB_REDGIFS_ACC, MyOptions.RedGifsAccount)
|
||||||
If IsUserSettings Then
|
If IsUserSettings Then
|
||||||
TP_MAIN.Controls.Remove(CMB_REDDIT_ACC)
|
TP_MAIN.Controls.Remove(CMB_REDDIT_ACC)
|
||||||
TP_MAIN.RowStyles(2).Height = 0
|
TP_MAIN.RowStyles(3).Height = 0
|
||||||
TP_MAIN.Refresh()
|
TP_MAIN.Refresh()
|
||||||
Dim s As Size = Size
|
Dim s As Size = Size
|
||||||
s.Height -= 28
|
s.Height -= 28
|
||||||
@@ -100,6 +106,8 @@ Namespace API.Reddit
|
|||||||
Select Case True
|
Select Case True
|
||||||
Case OPT_VIEW_MODE_HOT.Checked : .ViewMode = CView.Hot
|
Case OPT_VIEW_MODE_HOT.Checked : .ViewMode = CView.Hot
|
||||||
Case OPT_VIEW_MODE_TOP.Checked : .ViewMode = CView.Top
|
Case OPT_VIEW_MODE_TOP.Checked : .ViewMode = CView.Top
|
||||||
|
Case OPT_VIEW_MODE_BEST.Checked : .ViewMode = CView.Best
|
||||||
|
Case OPT_VIEW_MODE_RISING.Checked : .ViewMode = CView.Rising
|
||||||
Case Else : .ViewMode = CView.New
|
Case Else : .ViewMode = CView.New
|
||||||
End Select
|
End Select
|
||||||
Select Case True
|
Select Case True
|
||||||
@@ -110,6 +118,9 @@ Namespace API.Reddit
|
|||||||
Case OPT_PERIOD_YEAR.Checked : .ViewPeriod = CPeriod.Year
|
Case OPT_PERIOD_YEAR.Checked : .ViewPeriod = CPeriod.Year
|
||||||
Case Else : .ViewPeriod = CPeriod.All
|
Case Else : .ViewPeriod = CPeriod.All
|
||||||
End Select
|
End Select
|
||||||
|
.DownloadText = CH_TXT_DOWN_TXT.Checked
|
||||||
|
.DownloadTextPosts = CH_TXT_DOWN_POSTS.Checked
|
||||||
|
.DownloadTextSpecialFolder = CH_TXT_DOWN_SPEC_FOLDER.Checked
|
||||||
.RedGifsAccount = CMB_REDGIFS_ACC.Text
|
.RedGifsAccount = CMB_REDGIFS_ACC.Text
|
||||||
If Not IsUserSettings Then .RedditAccount = CMB_REDDIT_ACC.Text
|
If Not IsUserSettings Then .RedditAccount = CMB_REDDIT_ACC.Text
|
||||||
End With
|
End With
|
||||||
|
|||||||
@@ -9,26 +9,38 @@
|
|||||||
Imports SCrawler.API.Base
|
Imports SCrawler.API.Base
|
||||||
Imports SCrawler.Plugin
|
Imports SCrawler.Plugin
|
||||||
Imports SCrawler.Plugin.Attributes
|
Imports SCrawler.Plugin.Attributes
|
||||||
|
Imports System.Reflection
|
||||||
Imports PersonalUtilities.Tools.Web.Clients
|
Imports PersonalUtilities.Tools.Web.Clients
|
||||||
Imports PersonalUtilities.Tools.Web.Clients.Base
|
Imports PersonalUtilities.Tools.Web.Clients.Base
|
||||||
Imports PersonalUtilities.Tools.Web.Documents.JSON
|
Imports PersonalUtilities.Tools.Web.Documents.JSON
|
||||||
Imports PersonalUtilities.Functions.XML
|
Imports PersonalUtilities.Functions.XML
|
||||||
Imports PersonalUtilities.Functions.RegularExpressions
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
|
Imports DN = SCrawler.API.Base.DeclaredNames
|
||||||
Imports DownDetector = SCrawler.API.Base.DownDetector
|
Imports DownDetector = SCrawler.API.Base.DownDetector
|
||||||
Imports Download = SCrawler.Plugin.ISiteSettings.Download
|
Imports Download = SCrawler.Plugin.ISiteSettings.Download
|
||||||
Namespace API.Reddit
|
Namespace API.Reddit
|
||||||
<Manifest(RedditSiteKey), SavedPosts, SpecialForm(False)>
|
<Manifest(RedditSiteKey), SavedPosts, SeparatedTasks, SpecialForm(False), UseDownDetector>
|
||||||
Friend Class SiteSettings : Inherits SiteSettingsBase
|
Friend Class SiteSettings : Inherits SiteSettingsBase : Implements DownDetector.IDownDetector
|
||||||
#Region "Declarations"
|
#Region "Declarations"
|
||||||
#Region "Authorization"
|
#Region "Authorization"
|
||||||
|
Private Const ApiClientID_Default As String = "dYctRA-SIJxyykHe27lGZg"
|
||||||
|
Private Const ApiClientSecret_Default As String = "_5D6KzplRPDga-es1YlpzDIe9hiFlg"
|
||||||
<PropertyOption(ControlText:="Login", ControlToolTip:="Your authorization username", IsAuth:=True), PXML, PClonable(Clone:=False)>
|
<PropertyOption(ControlText:="Login", ControlToolTip:="Your authorization username", IsAuth:=True), PXML, PClonable(Clone:=False)>
|
||||||
Friend ReadOnly Property AuthUserName As PropertyValue
|
Friend ReadOnly Property AuthUserName As PropertyValue
|
||||||
<PropertyOption(ControlText:="Password", ControlToolTip:="Your authorization password", IsAuth:=True), PXML, PClonable(Clone:=False)>
|
<PropertyOption(ControlText:="Password", ControlToolTip:="Your authorization password", IsAuth:=True), PXML, PClonable(Clone:=False)>
|
||||||
Friend ReadOnly Property AuthPassword As PropertyValue
|
Friend ReadOnly Property AuthPassword As PropertyValue
|
||||||
<PropertyOption(ControlText:="Client ID", ControlToolTip:="Your registered app client ID", IsAuth:=True), PXML, PClonable(Clone:=False)>
|
<PropertyOption(ControlText:="Client ID", ControlToolTip:="Your registered app client ID", IsAuth:=True), PXML, PClonable(Clone:=False)>
|
||||||
Friend ReadOnly Property ApiClientID As PropertyValue
|
Friend ReadOnly Property ApiClientID As PropertyValue
|
||||||
|
<PropertyUpdater(NameOf(ApiClientID))> Private Function ApiClientID_SetDefault() As Boolean
|
||||||
|
ApiClientID.Value = ApiClientID_Default
|
||||||
|
Return True
|
||||||
|
End Function
|
||||||
<PropertyOption(ControlText:="Client Secret", ControlToolTip:="Your registered app client secret", IsAuth:=True), PXML, PClonable(Clone:=False)>
|
<PropertyOption(ControlText:="Client Secret", ControlToolTip:="Your registered app client secret", IsAuth:=True), PXML, PClonable(Clone:=False)>
|
||||||
Friend ReadOnly Property ApiClientSecret As PropertyValue
|
Friend ReadOnly Property ApiClientSecret As PropertyValue
|
||||||
|
<PropertyUpdater(NameOf(ApiClientSecret))> Private Function ApiClientSecret_SetDefault() As Boolean
|
||||||
|
ApiClientSecret.Value = ApiClientSecret_Default
|
||||||
|
Return True
|
||||||
|
End Function
|
||||||
<PropertyOption(ControlText:="Bearer token",
|
<PropertyOption(ControlText:="Bearer token",
|
||||||
ControlToolTip:="Bearer token (can be null)." & vbCr &
|
ControlToolTip:="Bearer token (can be null)." & vbCr &
|
||||||
"If you are using cookies to download the timeline, it is highly recommended that you add a token." & vbCr &
|
"If you are using cookies to download the timeline, it is highly recommended that you add a token." & vbCr &
|
||||||
@@ -58,14 +70,79 @@ Namespace API.Reddit
|
|||||||
Return {AuthUserName.Value, AuthPassword.Value, ApiClientID.Value, ApiClientSecret.Value}.All(Function(v$) Not v.IsEmptyString)
|
Return {AuthUserName.Value, AuthPassword.Value, ApiClientID.Value, ApiClientSecret.Value}.All(Function(v$) Not v.IsEmptyString)
|
||||||
End Get
|
End Get
|
||||||
End Property
|
End Property
|
||||||
|
<PropertiesDataChecker({NameOf(AuthUserName), NameOf(AuthPassword), NameOf(ApiClientID), NameOf(ApiClientSecret),
|
||||||
|
NameOf(UseTokenForTimelines), NameOf(UseCookiesForTimelines)})>
|
||||||
|
Private Function OAuthCredentialsChecker(ByVal p As IEnumerable(Of PropertyData)) As Boolean
|
||||||
|
Const msgTitle$ = "OAuth credentials"
|
||||||
|
If p.ListExists Then
|
||||||
|
Dim useToken As Boolean = False, useCookies As Boolean = False
|
||||||
|
Dim d$ = String.Empty
|
||||||
|
Dim dCount As Byte = 0
|
||||||
|
Dim members As IEnumerable(Of MemberInfo) = GetObjectMembers(Me)
|
||||||
|
Dim getPropText As Func(Of String, String) = Function(name) members.First(Function(m) m.Name = name).GetCustomAttribute(Of PropertyOption).ControlText
|
||||||
|
Dim dataStr As Action(Of String, String) = Sub(dd, name) If dd.IsEmptyString Then d.StringAppendLine(getPropText(name)) : dCount += 1
|
||||||
|
For Each pp As PropertyData In p
|
||||||
|
Select Case pp.Name
|
||||||
|
Case NameOf(AuthUserName) : dataStr(pp.Value, NameOf(AuthUserName))
|
||||||
|
Case NameOf(AuthPassword) : dataStr(pp.Value, NameOf(AuthPassword))
|
||||||
|
Case NameOf(ApiClientID) : dataStr(pp.Value, NameOf(ApiClientID))
|
||||||
|
Case NameOf(ApiClientSecret) : dataStr(pp.Value, NameOf(ApiClientSecret))
|
||||||
|
Case NameOf(UseTokenForTimelines) : useToken = pp.Value
|
||||||
|
Case NameOf(UseCookiesForTimelines) : useCookies = pp.Value
|
||||||
|
Case Else : Throw New ArgumentException($"Property name '{pp.Name}' is not implemented", "Property Name")
|
||||||
|
End Select
|
||||||
|
Next
|
||||||
|
If d.IsEmptyString Then
|
||||||
|
If useToken And useCookies Then
|
||||||
|
Return True
|
||||||
|
Else
|
||||||
|
If Not useToken Then d.StringAppendLine(getPropText(NameOf(UseTokenForTimelines)))
|
||||||
|
If Not useCookies Then d.StringAppendLine(getPropText(NameOf(UseCookiesForTimelines)))
|
||||||
|
MsgBoxE({$"You need to check the following options:{vbCr}{d}", msgTitle}, vbCritical)
|
||||||
|
Return False
|
||||||
|
End If
|
||||||
|
ElseIf dCount = 4 Then
|
||||||
|
Return MsgBoxE({$"You haven't configured OAuth. It's highly recommended to use OAuth.{vbCr}Do you still want to continue?", msgTitle},
|
||||||
|
vbExclamation,,, {"Process", "Cancel"}) = 0
|
||||||
|
Else
|
||||||
|
MsgBoxE({$"You haven't filled in the following fields:{vbCr}{d}.{vbCr}{vbCr}" &
|
||||||
|
"To use OAuth authorization, you must fill in all authorization fields.", msgTitle}, vbCritical)
|
||||||
|
Return False
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Return True
|
||||||
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Other"
|
#Region "Other"
|
||||||
<PropertyOption(ControlText:="Use M3U8", ControlToolTip:="Use M3U8 or mp4 for Reddit videos", IsAuth:=False), PXML, PClonable>
|
<PropertyOption(ControlText:="Use M3U8", ControlToolTip:="Use M3U8 or mp4 for Reddit videos"), PXML, PClonable, HiddenControl>
|
||||||
Friend ReadOnly Property UseM3U8 As PropertyValue
|
Friend ReadOnly Property UseM3U8 As PropertyValue
|
||||||
<PropertyOption(ControlText:="Check image", ControlToolTip:="Check the image if it exists before downloading (it makes downloading very slow)", IsAuth:=False), PXML, PClonable>
|
<PropertyOption(ControlText:="Check image", ControlToolTip:="Check the image if it exists before downloading (it makes downloading very slow)"), PXML, PClonable, HiddenControl>
|
||||||
Friend ReadOnly Property CheckImage As PropertyValue
|
Friend ReadOnly Property CheckImage As PropertyValue
|
||||||
<PropertyOption(ControlText:="Check image: get original", ControlToolTip:="Get the original image if it exists", IsAuth:=False), PXML, PClonable>
|
<PropertyOption(ControlText:="Check image: get original", ControlToolTip:="Get the original image if it exists"), PXML, PClonable, HiddenControl>
|
||||||
Friend ReadOnly Property CheckImageReturnOrig As PropertyValue
|
Friend ReadOnly Property CheckImageReturnOrig As PropertyValue
|
||||||
|
<PropertyOption(ControlText:=DN.ConcurrentDownloadsCaption,
|
||||||
|
ControlToolTip:=DN.ConcurrentDownloadsToolTip, AllowNull:=False), PXML, TaskCounter, PClonable>
|
||||||
|
Friend ReadOnly Property ConcurrentDownloads As PropertyValue
|
||||||
|
#End Region
|
||||||
|
#Region "IDownDetector Support"
|
||||||
|
Private ReadOnly Property IDownDetector_Value As Integer Implements DownDetector.IDownDetector.Value
|
||||||
|
Get
|
||||||
|
Return 100
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
Private ReadOnly Property IDownDetector_AddToLog As Boolean Implements DownDetector.IDownDetector.AddToLog
|
||||||
|
Get
|
||||||
|
Return False
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
Private ReadOnly Property IDownDetector_CheckSite As String Implements DownDetector.IDownDetector.CheckSite
|
||||||
|
Get
|
||||||
|
Return "reddit"
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
Private Function IDownDetector_Available(ByVal What As Download, ByVal Silent As Boolean) As Boolean Implements DownDetector.IDownDetector.Available
|
||||||
|
Return MDD.Available(What, Silent)
|
||||||
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Initializer"
|
#Region "Initializer"
|
||||||
@@ -76,6 +153,7 @@ Namespace API.Reddit
|
|||||||
With Responser
|
With Responser
|
||||||
Dim d% = .Decoders.Count
|
Dim d% = .Decoders.Count
|
||||||
.Decoders.ListAddList({SymbolsConverter.Converters.Unicode, SymbolsConverter.Converters.HTML}, LAP.NotContainsOnly)
|
.Decoders.ListAddList({SymbolsConverter.Converters.Unicode, SymbolsConverter.Converters.HTML}, LAP.NotContainsOnly)
|
||||||
|
.Accept = "application/json"
|
||||||
token = .Headers.Value(DeclaredNames.Header_Authorization)
|
token = .Headers.Value(DeclaredNames.Header_Authorization)
|
||||||
End With
|
End With
|
||||||
|
|
||||||
@@ -84,7 +162,7 @@ Namespace API.Reddit
|
|||||||
ApiClientID = New PropertyValue(String.Empty, GetType(String))
|
ApiClientID = New PropertyValue(String.Empty, GetType(String))
|
||||||
ApiClientSecret = New PropertyValue(String.Empty, GetType(String))
|
ApiClientSecret = New PropertyValue(String.Empty, GetType(String))
|
||||||
BearerToken = New PropertyValue(token, GetType(String), Sub(v) Responser.Headers.Add(DeclaredNames.Header_Authorization, v))
|
BearerToken = New PropertyValue(token, GetType(String), Sub(v) Responser.Headers.Add(DeclaredNames.Header_Authorization, v))
|
||||||
BearerTokenUseCurl = New PropertyValue(True)
|
BearerTokenUseCurl = New PropertyValue(False)
|
||||||
TokenUpdateInterval = New PropertyValue(360)
|
TokenUpdateInterval = New PropertyValue(360)
|
||||||
TokenUpdateIntervalProvider = New TokenRefreshIntervalProvider
|
TokenUpdateIntervalProvider = New TokenRefreshIntervalProvider
|
||||||
BearerTokenDateUpdate = New PropertyValue(Now.AddYears(-1))
|
BearerTokenDateUpdate = New PropertyValue(Now.AddYears(-1))
|
||||||
@@ -96,16 +174,22 @@ Namespace API.Reddit
|
|||||||
UseM3U8 = New PropertyValue(True)
|
UseM3U8 = New PropertyValue(True)
|
||||||
CheckImage = New PropertyValue(False)
|
CheckImage = New PropertyValue(False)
|
||||||
CheckImageReturnOrig = New PropertyValue(True)
|
CheckImageReturnOrig = New PropertyValue(True)
|
||||||
|
ConcurrentDownloads = New PropertyValue(1)
|
||||||
|
|
||||||
|
MDD = New MyDownDetector(Me)
|
||||||
|
|
||||||
UrlPatternUser = "https://www.reddit.com/{0}/{1}/"
|
UrlPatternUser = "https://www.reddit.com/{0}/{1}/"
|
||||||
ImageVideoContains = "reddit.com"
|
ImageVideoContains = "reddit.com"
|
||||||
UserRegex = RParams.DM("[htps:/]{7,8}.*?reddit.com/([user]{1,4})/([^/\?&]+)", 0, RegexReturn.ListByMatch, EDP.ReturnValue)
|
UserRegex = RParams.DM("[htps:/]{7,8}.*?reddit.com/([user]{1,4})/([^/\?&]+)", 0, RegexReturn.ListByMatch, EDP.ReturnValue)
|
||||||
End Sub
|
End Sub
|
||||||
Private Const SettingsVersionCurrent As Integer = 1
|
Private Const SettingsVersionCurrent As Integer = 3
|
||||||
Friend Overrides Sub EndInit()
|
Friend Overrides Sub EndInit()
|
||||||
If CInt(SettingsVersion.Value) < SettingsVersionCurrent Then
|
If CInt(SettingsVersion.Value) < SettingsVersionCurrent Then
|
||||||
SettingsVersion.Value = SettingsVersionCurrent
|
SettingsVersion.Value = SettingsVersionCurrent
|
||||||
TokenUpdateInterval.Value = 360
|
UseM3U8.Value = True
|
||||||
|
CheckImage.Value = False
|
||||||
|
CheckImageReturnOrig.Value = True
|
||||||
|
BearerTokenUseCurl.Value = False
|
||||||
End If
|
End If
|
||||||
MyBase.EndInit()
|
MyBase.EndInit()
|
||||||
End Sub
|
End Sub
|
||||||
@@ -116,81 +200,50 @@ Namespace API.Reddit
|
|||||||
End Function
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
#Region "DownloadStarted, ReadyToDownload, Available, DownloadDone, UpdateRedGifsToken"
|
#Region "DownloadStarted, ReadyToDownload, Available, DownloadDone, UpdateRedGifsToken"
|
||||||
Private ____DownloadStarted As Boolean = False
|
Private ReadOnly MDD As MyDownDetector
|
||||||
Friend Overrides Sub DownloadStarted(ByVal What As Download)
|
Private Class MyDownDetector : Inherits DownDetector.Checker(Of SiteSettings)
|
||||||
If What = Download.Main Then ____DownloadStarted = True
|
Private __TrueValue As Boolean = False
|
||||||
MyBase.DownloadStarted(What)
|
Friend Sub New(ByRef _Source As SiteSettings)
|
||||||
|
MyBase.New(_Source)
|
||||||
End Sub
|
End Sub
|
||||||
|
Protected Overrides Function AvailableImpl(ByVal What As Download, ByVal Silent As Boolean) As Boolean
|
||||||
|
__TrueValue = Source.AvailableTrueValue(What)
|
||||||
|
Return MyBase.AvailableImpl(What, Silent)
|
||||||
|
End Function
|
||||||
|
Protected Overrides Function AvailableImpl_TRUE() As Boolean
|
||||||
|
Return AvailableImpl_TrueValueReturn()
|
||||||
|
End Function
|
||||||
|
Protected Overrides Function AvailableImpl_FALSE_SILENT_NOT_MSG_YES() As Boolean
|
||||||
|
Return AvailableImpl_TrueValueReturn()
|
||||||
|
End Function
|
||||||
|
Private Function AvailableImpl_TrueValueReturn() As Boolean
|
||||||
|
If __TrueValue Then Source.UpdateRedGifsToken()
|
||||||
|
Return __TrueValue AndAlso Source.UpdateTokenIfRequired()
|
||||||
|
End Function
|
||||||
|
Friend Overrides Sub Reset()
|
||||||
|
__TrueValue = False
|
||||||
|
MyBase.Reset()
|
||||||
|
End Sub
|
||||||
|
End Class
|
||||||
Friend Property SessionInterrupted As Boolean = False
|
Friend Property SessionInterrupted As Boolean = False
|
||||||
|
Friend Property RequestCount As Integer = 0
|
||||||
Friend Overrides Function ReadyToDownload(ByVal What As Download) As Boolean
|
Friend Overrides Function ReadyToDownload(ByVal What As Download) As Boolean
|
||||||
If What = Download.Main Then
|
If What = Download.Main Then
|
||||||
Dim result As Boolean = Not SessionInterrupted
|
Return Not SessionInterrupted
|
||||||
If result Then
|
|
||||||
If ____DownloadStarted And ____AvailableRequested Then
|
|
||||||
____AvailableResult = AvailableImpl(What, ____AvailableSilent)
|
|
||||||
____AvailableChecked = True
|
|
||||||
____AvailableRequested = False
|
|
||||||
result = ____AvailableResult
|
|
||||||
ElseIf ____AvailableChecked Then
|
|
||||||
result = ____AvailableResult
|
|
||||||
End If
|
|
||||||
End If
|
|
||||||
Return result
|
|
||||||
Else
|
Else
|
||||||
Return True
|
Return True
|
||||||
End If
|
End If
|
||||||
End Function
|
End Function
|
||||||
Private ____AvailableRequested As Boolean = False
|
|
||||||
Private ____AvailableSilent As Boolean = True
|
|
||||||
Private ____AvailableChecked As Boolean = False
|
|
||||||
Private ____AvailableResult As Boolean = False
|
|
||||||
Friend Overrides Function Available(ByVal What As Download, ByVal Silent As Boolean) As Boolean
|
Friend Overrides Function Available(ByVal What As Download, ByVal Silent As Boolean) As Boolean
|
||||||
If What = Download.Main And ____DownloadStarted Then
|
Return AvailableTrueValue(What) AndAlso UpdateTokenIfRequired()
|
||||||
____AvailableRequested = True
|
|
||||||
____AvailableSilent = Silent
|
|
||||||
Return True
|
|
||||||
Else
|
|
||||||
Return AvailableImpl(What, Silent)
|
|
||||||
End If
|
|
||||||
End Function
|
End Function
|
||||||
Private Function AvailableImpl(ByVal What As Download, ByVal Silent As Boolean) As Boolean
|
Private Function AvailableTrueValue(ByVal What As Download) As Boolean
|
||||||
Try
|
Return Not What = Download.SavedPosts OrElse (Responser.CookiesExists And ACheck(SavedPostsUserName.Value))
|
||||||
AvailableText = String.Empty
|
|
||||||
Dim trueValue As Boolean = Not What = Download.SavedPosts OrElse (Responser.CookiesExists And ACheck(SavedPostsUserName.Value))
|
|
||||||
If Not trueValue Then Return False
|
|
||||||
Dim dl As List(Of DownDetector.Data) = DownDetector.GetData("reddit")
|
|
||||||
If dl.ListExists Then
|
|
||||||
dl = dl.Take(4).ToList
|
|
||||||
Dim avg% = dl.Average(Function(d) d.Value)
|
|
||||||
If avg > 100 Then
|
|
||||||
AvailableText = "Over the past hour, Reddit has received an average of " &
|
|
||||||
avg.NumToString(New ANumbers With {.FormatOptions = ANumbers.Options.GroupIntegral}) & " outage reports:" & vbCr &
|
|
||||||
dl.ListToString(vbCr)
|
|
||||||
If Silent Then
|
|
||||||
Return False
|
|
||||||
Else
|
|
||||||
If MsgBoxE({$"{AvailableText}{vbCr}{vbCr}Do you want to continue parsing Reddit data?", "There are outage reports on Reddit"}, vbYesNo) = vbYes Then
|
|
||||||
If trueValue Then UpdateRedGifsToken()
|
|
||||||
Return trueValue AndAlso UpdateTokenIfRequired()
|
|
||||||
Else
|
|
||||||
Return False
|
|
||||||
End If
|
|
||||||
End If
|
|
||||||
End If
|
|
||||||
End If
|
|
||||||
If trueValue Then UpdateRedGifsToken()
|
|
||||||
Return trueValue AndAlso UpdateTokenIfRequired()
|
|
||||||
Catch ex As Exception
|
|
||||||
Return ErrorsDescriber.Execute(EDP.SendToLog + EDP.ReturnValue, ex, "[API.Reddit.SiteSettings.Available]", True)
|
|
||||||
End Try
|
|
||||||
End Function
|
End Function
|
||||||
Friend Overrides Sub DownloadDone(ByVal What As Download)
|
Friend Overrides Sub DownloadDone(ByVal What As Download)
|
||||||
SessionInterrupted = False
|
SessionInterrupted = False
|
||||||
____DownloadStarted = False
|
RequestCount = 0
|
||||||
____AvailableRequested = False
|
MDD.Reset()
|
||||||
____AvailableChecked = False
|
|
||||||
____AvailableSilent = True
|
|
||||||
____AvailableResult = False
|
|
||||||
MyBase.DownloadDone(What)
|
MyBase.DownloadDone(What)
|
||||||
End Sub
|
End Sub
|
||||||
Private Sub UpdateRedGifsToken()
|
Private Sub UpdateRedGifsToken()
|
||||||
@@ -210,7 +263,7 @@ Namespace API.Reddit
|
|||||||
End If
|
End If
|
||||||
End Function
|
End Function
|
||||||
Friend Overrides Function GetUserUrl(ByVal User As IPluginContentProvider) As String
|
Friend Overrides Function GetUserUrl(ByVal User As IPluginContentProvider) As String
|
||||||
With DirectCast(User, UserData) : Return String.Format(UrlPatternUser, IIf(.IsChannel, ChannelOption, "user"), .TrueName) : End With
|
With DirectCast(User, UserData) : Return String.Format(UrlPatternUser, IIf(.IsChannel, ChannelOption, "user"), .NameTrue) : End With
|
||||||
End Function
|
End Function
|
||||||
Friend Overrides Function GetUserPostUrl(ByVal User As UserDataBase, ByVal Media As UserMedia) As String
|
Friend Overrides Function GetUserPostUrl(ByVal User As UserDataBase, ByVal Media As UserMedia) As String
|
||||||
If Not Media.Post.ID.IsEmptyString Then
|
If Not Media.Post.ID.IsEmptyString Then
|
||||||
@@ -222,7 +275,7 @@ Namespace API.Reddit
|
|||||||
#End Region
|
#End Region
|
||||||
#Region "UserOptions"
|
#Region "UserOptions"
|
||||||
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 RedditViewExchange Then Options = New RedditViewExchange
|
If Options Is Nothing OrElse Not TypeOf Options Is RedditViewExchange Then Options = New RedditViewExchange(Me)
|
||||||
If OpenForm Then
|
If OpenForm Then
|
||||||
Using f As New RedditViewSettingsForm(Options, True) : f.ShowDialog() : End Using
|
Using f As New RedditViewSettingsForm(Options, True) : f.ShowDialog() : End Using
|
||||||
End If
|
End If
|
||||||
@@ -243,24 +296,8 @@ Namespace API.Reddit
|
|||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Token"
|
#Region "Token"
|
||||||
<PropertiesDataChecker({NameOf(AuthUserName), NameOf(AuthPassword), NameOf(ApiClientID), NameOf(ApiClientSecret)})>
|
|
||||||
Private Function TokenPropertiesChecker(ByVal p As IEnumerable(Of PropertyData)) As Boolean
|
|
||||||
If p.ListExists Then
|
|
||||||
Dim wrong As New List(Of String)
|
|
||||||
For i% = 0 To p.Count - 1
|
|
||||||
If CStr(p(i).Value).IsEmptyString Then wrong.Add(p(i).Name)
|
|
||||||
Next
|
|
||||||
If wrong.Count > 0 And wrong.Count <> 4 Then
|
|
||||||
MsgBoxE({$"You have not completed the following fields: {wrong.ListToString}." & vbCr &
|
|
||||||
"To use OAuth authorization, all authorization fields must be filled in.", "Validate token fields"}, vbCritical)
|
|
||||||
Return False
|
|
||||||
Else
|
|
||||||
Return True
|
|
||||||
End If
|
|
||||||
End If
|
|
||||||
Return False
|
|
||||||
End Function
|
|
||||||
Private Function UpdateTokenIfRequired() As Boolean
|
Private Function UpdateTokenIfRequired() As Boolean
|
||||||
|
UpdateRedGifsToken()
|
||||||
If (CBool(UseTokenForTimelines.Value) Or CBool(UseTokenForSavedPosts.Value)) AndAlso CredentialsExists Then
|
If (CBool(UseTokenForTimelines.Value) Or CBool(UseTokenForSavedPosts.Value)) AndAlso CredentialsExists Then
|
||||||
If CDate(BearerTokenDateUpdate.Value).AddMinutes(TokenUpdateInterval.Value) <= Now Then Return UpdateToken()
|
If CDate(BearerTokenDateUpdate.Value).AddMinutes(TokenUpdateInterval.Value) <= Now Then Return UpdateToken()
|
||||||
End If
|
End If
|
||||||
|
|||||||
@@ -8,19 +8,20 @@
|
|||||||
' but WITHOUT ANY WARRANTY
|
' but WITHOUT ANY WARRANTY
|
||||||
Imports System.Net
|
Imports System.Net
|
||||||
Imports System.Threading
|
Imports System.Threading
|
||||||
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
|
Imports PersonalUtilities.Functions.XML
|
||||||
|
Imports PersonalUtilities.Tools.ImageRenderer
|
||||||
|
Imports PersonalUtilities.Tools.Web.Clients
|
||||||
|
Imports PersonalUtilities.Tools.Web.Clients.Base
|
||||||
|
Imports PersonalUtilities.Tools.Web.Documents.JSON
|
||||||
Imports SCrawler.API.Base
|
Imports SCrawler.API.Base
|
||||||
Imports SCrawler.API.Reddit.RedditViewExchange
|
Imports SCrawler.API.Reddit.RedditViewExchange
|
||||||
Imports SCrawler.API.YouTube.Objects
|
Imports SCrawler.API.YouTube.Objects
|
||||||
Imports SCrawler.Plugin.Hosts
|
Imports SCrawler.Plugin.Hosts
|
||||||
Imports PersonalUtilities.Functions.XML
|
Imports CPeriod = SCrawler.API.Reddit.IRedditView.Period
|
||||||
Imports PersonalUtilities.Functions.RegularExpressions
|
Imports CView = SCrawler.API.Reddit.IRedditView.View
|
||||||
Imports PersonalUtilities.Tools.ImageRenderer
|
|
||||||
Imports PersonalUtilities.Tools.Web.Clients
|
|
||||||
Imports PersonalUtilities.Tools.Web.Documents.JSON
|
|
||||||
Imports UStates = SCrawler.API.Base.UserMedia.States
|
Imports UStates = SCrawler.API.Base.UserMedia.States
|
||||||
Imports UTypes = SCrawler.API.Base.UserMedia.Types
|
Imports UTypes = SCrawler.API.Base.UserMedia.Types
|
||||||
Imports CView = SCrawler.API.Reddit.IRedditView.View
|
|
||||||
Imports CPeriod = SCrawler.API.Reddit.IRedditView.Period
|
|
||||||
Namespace API.Reddit
|
Namespace API.Reddit
|
||||||
Friend Class UserData : Inherits UserDataBase : Implements IChannelLimits, IRedditView
|
Friend Class UserData : Inherits UserDataBase : Implements IChannelLimits, IRedditView
|
||||||
#Region "Declarations"
|
#Region "Declarations"
|
||||||
@@ -33,7 +34,8 @@ Namespace API.Reddit
|
|||||||
End Property
|
End Property
|
||||||
Private ReadOnly Property DateTrueProvider(ByVal IsChannel As Boolean) As IFormatProvider
|
Private ReadOnly Property DateTrueProvider(ByVal IsChannel As Boolean) As IFormatProvider
|
||||||
Get
|
Get
|
||||||
Return If(IsChannel, UnixDate32ProviderReddit, UnixDate64Provider)
|
Return UnixDate32Provider
|
||||||
|
'Return If(IsChannel, UnixDate32ProviderReddit, UnixDate64Provider)
|
||||||
End Get
|
End Get
|
||||||
End Property
|
End Property
|
||||||
Private ReadOnly Property UseM3U8 As Boolean
|
Private ReadOnly Property UseM3U8 As Boolean
|
||||||
@@ -42,7 +44,6 @@ Namespace API.Reddit
|
|||||||
End Get
|
End Get
|
||||||
End Property
|
End Property
|
||||||
Friend Property IsChannel As Boolean = False
|
Friend Property IsChannel As Boolean = False
|
||||||
Friend Property TrueName As String = String.Empty
|
|
||||||
Friend Overrides ReadOnly Property SpecialLabels As IEnumerable(Of String)
|
Friend Overrides ReadOnly Property SpecialLabels As IEnumerable(Of String)
|
||||||
Get
|
Get
|
||||||
Return {CannelsLabelName, CannelsLabelName_ChannelsForm, UserLabelName}
|
Return {CannelsLabelName, CannelsLabelName_ChannelsForm, UserLabelName}
|
||||||
@@ -127,10 +128,16 @@ Namespace API.Reddit
|
|||||||
Friend Property ViewPeriod As CPeriod Implements IRedditView.ViewPeriod
|
Friend Property ViewPeriod As CPeriod Implements IRedditView.ViewPeriod
|
||||||
Friend Sub SetView(ByVal Options As IRedditView) Implements IRedditView.SetView
|
Friend Sub SetView(ByVal Options As IRedditView) Implements IRedditView.SetView
|
||||||
If Not Options Is Nothing Then
|
If Not Options Is Nothing Then
|
||||||
ViewMode = Options.ViewMode
|
With Options
|
||||||
ViewPeriod = Options.ViewPeriod
|
ViewMode = .ViewMode
|
||||||
RedGifsAccount = Options.RedGifsAccount
|
ViewPeriod = .ViewPeriod
|
||||||
RedditAccount = Options.RedditAccount
|
DownloadText = .DownloadText
|
||||||
|
DownloadTextPosts = .DownloadTextPosts
|
||||||
|
DownloadTextSpecialFolder = .DownloadTextSpecialFolder
|
||||||
|
RedGifsAccount = .RedGifsAccount
|
||||||
|
RedditAccount = .RedditAccount
|
||||||
|
If TypeOf Options Is RedditViewExchange Then DirectCast(Options, RedditViewExchange).ApplyBase(Me)
|
||||||
|
End With
|
||||||
End If
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
Private ReadOnly Property View As String
|
Private ReadOnly Property View As String
|
||||||
@@ -138,6 +145,8 @@ Namespace API.Reddit
|
|||||||
Select Case ViewMode
|
Select Case ViewMode
|
||||||
Case CView.Hot : Return "hot"
|
Case CView.Hot : Return "hot"
|
||||||
Case CView.Top : Return "top"
|
Case CView.Top : Return "top"
|
||||||
|
Case CView.Best : Return "best"
|
||||||
|
Case CView.Rising : Return "rising"
|
||||||
Case Else : Return "new"
|
Case Else : Return "new"
|
||||||
End Select
|
End Select
|
||||||
End Get
|
End Get
|
||||||
@@ -158,6 +167,9 @@ Namespace API.Reddit
|
|||||||
End If
|
End If
|
||||||
End Get
|
End Get
|
||||||
End Property
|
End Property
|
||||||
|
Friend Overrides Property DownloadText As Boolean Implements IRedditView.DownloadText
|
||||||
|
Friend Overrides Property DownloadTextPosts As Boolean Implements IRedditView.DownloadTextPosts
|
||||||
|
Friend Overrides Property DownloadTextSpecialFolder As Boolean Implements IRedditView.DownloadTextSpecialFolder
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Initializer"
|
#Region "Initializer"
|
||||||
Friend Sub New()
|
Friend Sub New()
|
||||||
@@ -173,16 +185,16 @@ Namespace API.Reddit
|
|||||||
#End Region
|
#End Region
|
||||||
#Region "Load and Update user info"
|
#Region "Load and Update user info"
|
||||||
Private Function UpdateNames() As Boolean
|
Private Function UpdateNames() As Boolean
|
||||||
If TrueName.IsEmptyString Then
|
If NameTrue(True).IsEmptyString Then
|
||||||
Dim n$() = Name.Split("@")
|
Dim n$() = Name.Split("@")
|
||||||
If n.ListExists Then
|
If n.ListExists Then
|
||||||
If n.Length = 2 Then
|
If n.Length = 2 Then
|
||||||
TrueName = n(0)
|
NameTrue = n(0)
|
||||||
IsChannel = True
|
IsChannel = True
|
||||||
ElseIf IsChannel Then
|
ElseIf IsChannel Then
|
||||||
TrueName = Name
|
NameTrue = Name
|
||||||
Else
|
Else
|
||||||
TrueName = n(0)
|
NameTrue = n(0)
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
If Not IsSavedPosts Then
|
If Not IsSavedPosts Then
|
||||||
@@ -201,7 +213,6 @@ Namespace API.Reddit
|
|||||||
ViewMode = .Value(Name_ViewMode).FromXML(Of Integer)(CInt(CView.New))
|
ViewMode = .Value(Name_ViewMode).FromXML(Of Integer)(CInt(CView.New))
|
||||||
ViewPeriod = .Value(Name_ViewPeriod).FromXML(Of Integer)(CInt(CPeriod.All))
|
ViewPeriod = .Value(Name_ViewPeriod).FromXML(Of Integer)(CInt(CPeriod.All))
|
||||||
IsChannel = .Value(Name_IsChannel).FromXML(Of Boolean)(False)
|
IsChannel = .Value(Name_IsChannel).FromXML(Of Boolean)(False)
|
||||||
TrueName = .Value(Name_TrueName)
|
|
||||||
RedGifsAccount = .Value(Name_RedGifsAccount)
|
RedGifsAccount = .Value(Name_RedGifsAccount)
|
||||||
RedditAccount = .Value(Name_RedditAccount)
|
RedditAccount = .Value(Name_RedditAccount)
|
||||||
UpdateNames()
|
UpdateNames()
|
||||||
@@ -210,14 +221,14 @@ Namespace API.Reddit
|
|||||||
.Add(Name_ViewMode, CInt(ViewMode))
|
.Add(Name_ViewMode, CInt(ViewMode))
|
||||||
.Add(Name_ViewPeriod, CInt(ViewPeriod))
|
.Add(Name_ViewPeriod, CInt(ViewPeriod))
|
||||||
.Add(Name_IsChannel, IsChannel.BoolToInteger)
|
.Add(Name_IsChannel, IsChannel.BoolToInteger)
|
||||||
.Add(Name_TrueName, TrueName)
|
.Add(Name_TrueName, NameTrue(True))
|
||||||
.Add(Name_RedGifsAccount, RedGifsAccount)
|
.Add(Name_RedGifsAccount, RedGifsAccount)
|
||||||
.Add(Name_RedditAccount, RedditAccount)
|
.Add(Name_RedditAccount, RedditAccount)
|
||||||
End If
|
End If
|
||||||
End With
|
End With
|
||||||
End Sub
|
End Sub
|
||||||
Friend Overrides Function ExchangeOptionsGet() As Object
|
Friend Overrides Function ExchangeOptionsGet() As Object
|
||||||
Return New RedditViewExchange With {.ViewMode = ViewMode, .ViewPeriod = ViewPeriod, .RedGifsAccount = RedGifsAccount, .RedditAccount = RedditAccount}
|
Return New RedditViewExchange(Me)
|
||||||
End Function
|
End Function
|
||||||
Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object)
|
Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object)
|
||||||
If Not Obj Is Nothing AndAlso TypeOf Obj Is IRedditView Then SetView(DirectCast(Obj, IRedditView))
|
If Not Obj Is Nothing AndAlso TypeOf Obj Is IRedditView Then SetView(DirectCast(Obj, IRedditView))
|
||||||
@@ -230,7 +241,7 @@ Namespace API.Reddit
|
|||||||
If CreatedByChannel And Settings.FromChannelDownloadTopUse And Settings.FromChannelDownloadTop > 0 Then _
|
If CreatedByChannel And Settings.FromChannelDownloadTopUse And Settings.FromChannelDownloadTop > 0 Then _
|
||||||
DownloadTopCount = Settings.FromChannelDownloadTop.Value
|
DownloadTopCount = Settings.FromChannelDownloadTop.Value
|
||||||
If IsChannel Or IsSavedPosts Then UseMD5Comparison = False
|
If IsChannel Or IsSavedPosts Then UseMD5Comparison = False
|
||||||
If IsSavedPosts Then TrueName = MySiteSettings.SavedPostsUserName.Value
|
If IsSavedPosts Then NameTrue = MySiteSettings.SavedPostsUserName.Value
|
||||||
UpdateNames()
|
UpdateNames()
|
||||||
If IsChannelForm Then
|
If IsChannelForm Then
|
||||||
UseMD5Comparison = False
|
UseMD5Comparison = False
|
||||||
@@ -259,6 +270,8 @@ Namespace API.Reddit
|
|||||||
End If
|
End If
|
||||||
End With
|
End With
|
||||||
|
|
||||||
|
Responser.ProcessExceptionDecision = AddressOf Err429Process
|
||||||
|
|
||||||
_TotalPostsDownloaded = 0
|
_TotalPostsDownloaded = 0
|
||||||
If IsSavedPosts Then
|
If IsSavedPosts Then
|
||||||
Responser.DecodersError = EDP.ReturnValue
|
Responser.DecodersError = EDP.ReturnValue
|
||||||
@@ -276,8 +289,13 @@ Namespace API.Reddit
|
|||||||
Else
|
Else
|
||||||
GetUserInfo()
|
GetUserInfo()
|
||||||
End If
|
End If
|
||||||
If SaveToCache AndAlso Not Responser.Decoders.Contains(SymbolsConverter.Converters.HTML) Then _
|
If SaveToCache Then
|
||||||
|
DownloadText = False
|
||||||
|
DownloadTextPosts = False
|
||||||
|
DownloadTextSpecialFolder = False
|
||||||
|
If Not Responser.Decoders.Contains(SymbolsConverter.Converters.HTML) Then _
|
||||||
Responser.Decoders.Add(SymbolsConverter.Converters.HTML)
|
Responser.Decoders.Add(SymbolsConverter.Converters.HTML)
|
||||||
|
End If
|
||||||
DownloadDataChannel(String.Empty, Token)
|
DownloadDataChannel(String.Empty, Token)
|
||||||
If ChannelInfo Is Nothing Then _TempPostsList.ListAddList(_TempMediaList.Select(Function(m) m.Post.ID), LNC)
|
If ChannelInfo Is Nothing Then _TempPostsList.ListAddList(_TempMediaList.Select(Function(m) m.Post.ID), LNC)
|
||||||
Else
|
Else
|
||||||
@@ -289,6 +307,7 @@ Namespace API.Reddit
|
|||||||
#End Region
|
#End Region
|
||||||
#Region "Download Functions (User, Channel)"
|
#Region "Download Functions (User, Channel)"
|
||||||
Private Err429Count As Integer = 0
|
Private Err429Count As Integer = 0
|
||||||
|
Private Err429TryAgain As Boolean = False
|
||||||
Private _TotalPostsDownloaded As Integer = 0
|
Private _TotalPostsDownloaded As Integer = 0
|
||||||
Private ReadOnly _CrossPosts As List(Of String)
|
Private ReadOnly _CrossPosts As List(Of String)
|
||||||
Private Const SiteGfycatKey As String = "gfycat"
|
Private Const SiteGfycatKey As String = "gfycat"
|
||||||
@@ -296,6 +315,28 @@ Namespace API.Reddit
|
|||||||
Private Const Node_CrosspostRootId As String = "crosspostRootId"
|
Private Const Node_CrosspostRootId As String = "crosspostRootId"
|
||||||
Private Const Node_CrosspostParentId As String = "crosspostParentId"
|
Private Const Node_CrosspostParentId As String = "crosspostParentId"
|
||||||
Private Const Node_CrosspostParent As String = "crosspost_parent"
|
Private Const Node_CrosspostParent As String = "crosspost_parent"
|
||||||
|
Private Sub Wait429()
|
||||||
|
With MySiteSettings
|
||||||
|
If Not Err429TryAgain Then .RequestCount += 1
|
||||||
|
Err429TryAgain = False
|
||||||
|
If (.RequestCount Mod 100) = 0 Then Thread.Sleep(60100)
|
||||||
|
End With
|
||||||
|
End Sub
|
||||||
|
Private Function Err429Process(ByVal Status As IResponserStatus, ByVal NullArg As Object, ByVal CurrErr As ErrorsDescriber) As ErrorsDescriber
|
||||||
|
If Not Status Is Nothing AndAlso Status.StatusCode = 429 Then
|
||||||
|
If Err429Count = 0 Then
|
||||||
|
Err429Count += 1
|
||||||
|
MySiteSettings.RequestCount = 100
|
||||||
|
Err429TryAgain = True
|
||||||
|
Return EDP.ReturnValue
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Return CurrErr
|
||||||
|
End Function
|
||||||
|
Private Sub Err429Reset()
|
||||||
|
Err429Count = 0
|
||||||
|
Err429TryAgain = False
|
||||||
|
End Sub
|
||||||
Private Sub DownloadDataUser(ByVal POST As String, ByVal Token As CancellationToken)
|
Private Sub DownloadDataUser(ByVal POST As String, ByVal Token As CancellationToken)
|
||||||
Dim eObj% = 0
|
Dim eObj% = 0
|
||||||
Dim round% = 0
|
Dim round% = 0
|
||||||
@@ -310,34 +351,41 @@ Namespace API.Reddit
|
|||||||
Dim NewPostDetected As Boolean = False
|
Dim NewPostDetected As Boolean = False
|
||||||
Dim ExistsDetected As Boolean = False
|
Dim ExistsDetected As Boolean = False
|
||||||
Dim IsCrossPost As Predicate(Of EContainer) = Function(e) Not e.Value(Node_CrosspostRootId).IsEmptyString Or Not e.Value(Node_CrosspostParentId).IsEmptyString Or Not e.Value(Node_CrosspostParent).IsEmptyString
|
Dim IsCrossPost As Predicate(Of EContainer) = Function(e) Not e.Value(Node_CrosspostRootId).IsEmptyString Or Not e.Value(Node_CrosspostParentId).IsEmptyString Or Not e.Value(Node_CrosspostParent).IsEmptyString
|
||||||
Dim CheckNode As Predicate(Of EContainer) = Function(e) Not ParseUserMediaOnly OrElse If(e("author")?.Value, "/").ToLower.Equals(TrueName.StringToLower)
|
Dim CheckNode As Predicate(Of EContainer) = Function(e) Not ParseUserMediaOnly OrElse If(e("author")?.Value, "/").ToLower.Equals(NameTrue.StringToLower)
|
||||||
Dim _PostID As Func(Of String) = Function() PostTmp.IfNullOrEmpty(PostID)
|
Dim _PostID As Func(Of String) = Function() PostTmp.IfNullOrEmpty(PostID)
|
||||||
|
|
||||||
URL = $"https://gateway.reddit.com/desktopapi/v1/user/{TrueName}/posts?rtj=only&allow_quarantined=true&allow_over18=1&include=identity&after={POST}&dist=25&sort={View}&t={Period}&layout=classic"
|
'URL = $"https://gateway.reddit.com/desktopapi/v1/user/{NameTrue}/posts?rtj=only&allow_quarantined=true&allow_over18=1&include=identity&after={POST}&dist=25&sort={View}&t={Period}&layout=classic"
|
||||||
|
URL = $"https://oauth.reddit.com/user/{NameTrue}/submitted.json?rtj=only&allow_quarantined=true&allow_over18=1&include=identity&after={POST}&dist=25&sort={View}&t={Period}&layout=classic"
|
||||||
ThrowAny(Token)
|
ThrowAny(Token)
|
||||||
|
Wait429()
|
||||||
Dim r$ = Responser.GetResponse(URL)
|
Dim r$ = Responser.GetResponse(URL)
|
||||||
If Not r.IsEmptyString Then
|
If Not r.IsEmptyString Then
|
||||||
|
Err429Reset()
|
||||||
Using w As EContainer = JsonDocument.Parse(r).XmlIfNothing
|
Using w As EContainer = JsonDocument.Parse(r).XmlIfNothing
|
||||||
If w.Count > 0 Then
|
If w.Count > 0 Then
|
||||||
n = w.GetNode(JsonNodesJson)
|
'n = w.GetNode(JsonNodesJson)
|
||||||
If Not n Is Nothing AndAlso n.Count > 0 Then
|
n = w.GetNode(ChannelJsonNodes)
|
||||||
|
If n.ListExists Then
|
||||||
ProgressPre.ChangeMax(n.Count)
|
ProgressPre.ChangeMax(n.Count)
|
||||||
For Each nn In n
|
For Each nn In n
|
||||||
ProgressPre.Perform()
|
ProgressPre.Perform()
|
||||||
ThrowAny(Token)
|
ThrowAny(Token)
|
||||||
If nn.Count > 0 Then
|
With nn("data")
|
||||||
If CheckNode(nn) Then
|
If .ListExists Then
|
||||||
|
If CheckNode(.Self) Then
|
||||||
|
|
||||||
'Obtain post ID
|
'Obtain post ID
|
||||||
PostTmp = nn.Name
|
PostID = String.Empty
|
||||||
If PostTmp.IsEmptyString Then PostTmp = nn.Value("id")
|
PostTmp = .Value("name") '.Name
|
||||||
|
If PostTmp.IsEmptyString Then PostTmp = .Value("id")
|
||||||
If PostTmp.IsEmptyString Then Continue For
|
If PostTmp.IsEmptyString Then Continue For
|
||||||
'Check for CrossPost
|
'Check for CrossPost
|
||||||
If IsCrossPost(nn) Then
|
If IsCrossPost(.Self) Then
|
||||||
_CrossPosts.ListAddList({nn.Value(Node_CrosspostRootId),
|
_CrossPosts.ListAddList({ .Value(Node_CrosspostRootId),
|
||||||
nn.Value(Node_CrosspostParentId),
|
.Value(Node_CrosspostParentId),
|
||||||
nn.Value(Node_CrosspostParent)}, LNC)
|
.Value(Node_CrosspostParent),
|
||||||
Continue For
|
PostTmp}, LNC)
|
||||||
|
If ParseUserMediaOnly Then Continue For
|
||||||
Else
|
Else
|
||||||
If Not _CrossPosts.Contains(PostTmp) Then PostID = PostTmp : PostTmp = String.Empty
|
If Not _CrossPosts.Contains(PostTmp) Then PostID = PostTmp : PostTmp = String.Empty
|
||||||
End If
|
End If
|
||||||
@@ -350,21 +398,24 @@ Namespace API.Reddit
|
|||||||
If Not _CrossPosts.Contains(_PostID()) Then ExistsDetected = True
|
If Not _CrossPosts.Contains(_PostID()) Then ExistsDetected = True
|
||||||
Continue For
|
Continue For
|
||||||
End If
|
End If
|
||||||
If nn.Contains("created") Then PostDate = nn("created").Value Else PostDate = String.Empty
|
PostDate = If(.Item("created")?.Value, String.Empty)
|
||||||
Select Case CheckDatesLimit(PostDate, DateTrueProvider(IsChannel))
|
Select Case CheckDatesLimit(PostDate, DateTrueProvider(IsChannel))
|
||||||
Case DateResult.Skip : Continue For
|
Case DateResult.Skip : Continue For
|
||||||
Case DateResult.Exit : Exit Sub
|
Case DateResult.Exit : Exit Sub
|
||||||
End Select
|
End Select
|
||||||
|
|
||||||
ParseContainer(nn, _PostID(), PostDate)
|
ParseContainer(.Self, _PostID(), PostDate,,, GetTextDocument(.Self))
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
|
End With
|
||||||
Next
|
Next
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
End Using
|
End Using
|
||||||
If POST.IsEmptyString And ExistsDetected Then Exit Sub
|
If POST.IsEmptyString And ExistsDetected Then Exit Sub
|
||||||
If Not _PostID().IsEmptyString And NewPostDetected Then DownloadDataUser(_PostID(), Token)
|
If Not _PostID().IsEmptyString And NewPostDetected Then DownloadDataUser(_PostID(), Token)
|
||||||
|
ElseIf Err429TryAgain Then
|
||||||
|
Continue Do
|
||||||
End If
|
End If
|
||||||
_completed = True
|
_completed = True
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
@@ -394,16 +445,18 @@ Namespace API.Reddit
|
|||||||
Dim lDate As Date?
|
Dim lDate As Date?
|
||||||
|
|
||||||
If IsSavedPosts Then
|
If IsSavedPosts Then
|
||||||
URL = $"https://www.reddit.com/user/{TrueName}/saved.json?after={POST}"
|
URL = $"https://www.reddit.com/user/{NameTrue}/saved.json?after={POST}"
|
||||||
If Not POST.IsEmptyString Then Thread.Sleep(savedPostsSleepTimer)
|
If Not POST.IsEmptyString Then Thread.Sleep(savedPostsSleepTimer)
|
||||||
Else
|
Else
|
||||||
URL = $"https://reddit.com/r/{TrueName}/{View}.json?allow_quarantined=true&allow_over18=1&include=identity&after={POST}&dist=25&sort={View}&t={Period}&layout=classic"
|
URL = $"https://reddit.com/r/{NameTrue}/{View}.json?allow_quarantined=true&allow_over18=1&include=identity&after={POST}&dist=25&sort={View}&t={Period}&layout=classic"
|
||||||
End If
|
End If
|
||||||
|
|
||||||
ThrowAny(Token)
|
ThrowAny(Token)
|
||||||
|
Wait429()
|
||||||
Dim r$ = Responser.GetResponse(URL)
|
Dim r$ = Responser.GetResponse(URL)
|
||||||
If IsSavedPosts Then Err429Count = 0
|
'If IsSavedPosts Then Err429Count = 0
|
||||||
If Not r.IsEmptyString Then
|
If Not r.IsEmptyString Then
|
||||||
|
Err429Reset()
|
||||||
Using w As EContainer = JsonDocument.Parse(r).XmlIfNothing
|
Using w As EContainer = JsonDocument.Parse(r).XmlIfNothing
|
||||||
If w.Count > 0 Then
|
If w.Count > 0 Then
|
||||||
n = w.GetNode(ChannelJsonNodes)
|
n = w.GetNode(ChannelJsonNodes)
|
||||||
@@ -452,7 +505,7 @@ Namespace API.Reddit
|
|||||||
Continue For
|
Continue For
|
||||||
End If
|
End If
|
||||||
|
|
||||||
ParseContainer(s, PostID, PostDate, _UserID)
|
ParseContainer(s, PostID, PostDate, _UserID,, If(Not SaveToCache, GetTextDocument(s), String.Empty))
|
||||||
End If
|
End If
|
||||||
Next
|
Next
|
||||||
End If
|
End If
|
||||||
@@ -460,6 +513,8 @@ Namespace API.Reddit
|
|||||||
End Using
|
End Using
|
||||||
If POST.IsEmptyString And ExistsDetected Then Exit Sub
|
If POST.IsEmptyString And ExistsDetected Then Exit Sub
|
||||||
If Not PostID.IsEmptyString And NewPostDetected Then DownloadDataChannel(PostID, Token)
|
If Not PostID.IsEmptyString And NewPostDetected Then DownloadDataChannel(PostID, Token)
|
||||||
|
ElseIf Err429TryAgain Then
|
||||||
|
Continue Do
|
||||||
End If
|
End If
|
||||||
_completed = True
|
_completed = True
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
@@ -477,11 +532,13 @@ Namespace API.Reddit
|
|||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "GetUserInfo"
|
#Region "GetUserInfo"
|
||||||
Private Sub GetUserInfo()
|
Private Sub GetUserInfo(Optional ByVal Round As Integer = 0)
|
||||||
Try
|
Try
|
||||||
If Not IsSavedPosts And ChannelInfo Is Nothing Then
|
If Not IsSavedPosts And ChannelInfo Is Nothing Then
|
||||||
Dim r$ = Responser.GetResponse($"https://reddit.com/{IIf(IsChannel, "r", "user")}/{TrueName}/about.json",, EDP.ReturnValue)
|
Wait429()
|
||||||
|
Dim r$ = Responser.GetResponse($"https://reddit.com/{IIf(IsChannel, "r", "user")}/{NameTrue}/about.json",, EDP.ReturnValue)
|
||||||
If Not r.IsEmptyString Then
|
If Not r.IsEmptyString Then
|
||||||
|
Err429Reset()
|
||||||
Using j As EContainer = JsonDocument.Parse(r)
|
Using j As EContainer = JsonDocument.Parse(r)
|
||||||
If Not j Is Nothing AndAlso j.Contains({"data", "subreddit"}) Then
|
If Not j Is Nothing AndAlso j.Contains({"data", "subreddit"}) Then
|
||||||
If ID.IsEmptyString Then ID = j.Value({"data"}, "id")
|
If ID.IsEmptyString Then ID = j.Value({"data"}, "id")
|
||||||
@@ -489,24 +546,16 @@ Namespace API.Reddit
|
|||||||
UserSiteNameUpdate(.Value("title"))
|
UserSiteNameUpdate(.Value("title"))
|
||||||
UserDescriptionUpdate(.Value("public_description"))
|
UserDescriptionUpdate(.Value("public_description"))
|
||||||
Dim dir As SFile = MyFile.CutPath
|
Dim dir As SFile = MyFile.CutPath
|
||||||
Dim __getFile As Action(Of String) = Sub(ByVal img As String)
|
Dim fileCrFunc As Func(Of String, SFile) = Function(img) CreateFileFromUrl(img)
|
||||||
If Not img.IsEmptyString Then
|
|
||||||
Dim f As SFile = CreateFileFromUrl(img)
|
|
||||||
If Not f.Name.IsEmptyString Then
|
|
||||||
If f.Extension.IsEmptyString Then f.Extension = "jpg"
|
|
||||||
f.Path = dir.Path
|
|
||||||
If Not f.Exists Then GetWebFile(img, f, EDP.ReturnValue)
|
|
||||||
If f.Exists Then IconBannerDownloaded = True
|
|
||||||
End If
|
|
||||||
End If
|
|
||||||
End Sub
|
|
||||||
If DownloadIconBanner Then
|
If DownloadIconBanner Then
|
||||||
__getFile.Invoke(.Value("icon_img"))
|
SimpleDownloadAvatar(.Value("icon_img"), fileCrFunc)
|
||||||
__getFile.Invoke(.Value("banner_img"))
|
SimpleDownloadAvatar(.Value("banner_img"), fileCrFunc)
|
||||||
End If
|
End If
|
||||||
End With
|
End With
|
||||||
End If
|
End If
|
||||||
End Using
|
End Using
|
||||||
|
ElseIf Err429TryAgain And Round < 2 Then
|
||||||
|
GetUserInfo(Round + 1)
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
@@ -515,7 +564,7 @@ Namespace API.Reddit
|
|||||||
#End Region
|
#End Region
|
||||||
#Region "ParseContainer"
|
#Region "ParseContainer"
|
||||||
Private Function ParseContainer(ByVal e As EContainer, ByVal PostID As String, ByVal PostDate As String, Optional ByVal UserID As String = Nothing,
|
Private Function ParseContainer(ByVal e As EContainer, ByVal PostID As String, ByVal PostDate As String, Optional ByVal UserID As String = Nothing,
|
||||||
Optional ByVal AllowReparse As Boolean = True) As Boolean
|
Optional ByVal AllowReparse As Boolean = True, Optional ByVal PostText As String = Nothing) As Boolean
|
||||||
If Not e Is Nothing Then
|
If Not e Is Nothing Then
|
||||||
Dim UPicType As Func(Of String, UTypes) = Function(input) IIf(input = "image", UTypes.Picture, UTypes.GIF)
|
Dim UPicType As Func(Of String, UTypes) = Function(input) IIf(input = "image", UTypes.Picture, UTypes.GIF)
|
||||||
Dim eCount As Predicate(Of EContainer) = Function(item) item.Count > 0
|
Dim eCount As Predicate(Of EContainer) = Function(item) item.Count > 0
|
||||||
@@ -525,24 +574,24 @@ Namespace API.Reddit
|
|||||||
If SaveToCache Then
|
If SaveToCache Then
|
||||||
tmpUrl = e.Value({"media", "oembed"}, "thumbnail_url")
|
tmpUrl = e.Value({"media", "oembed"}, "thumbnail_url")
|
||||||
If Not tmpUrl.IsEmptyString Then
|
If Not tmpUrl.IsEmptyString Then
|
||||||
_TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, tmpUrl, PostID, PostDate, UserID), LNC)
|
_TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, tmpUrl, PostID, PostDate, UserID,, PostText), LNC)
|
||||||
_TotalPostsDownloaded += 1
|
_TotalPostsDownloaded += 1
|
||||||
Else
|
Else
|
||||||
added = False
|
added = False
|
||||||
End If
|
End If
|
||||||
Else
|
Else
|
||||||
_TempMediaList.ListAddValue(MediaFromData(UTypes.VideoPre, tmpUrl, PostID, PostDate, UserID), LNC)
|
_TempMediaList.ListAddValue(MediaFromData(UTypes.VideoPre, tmpUrl, PostID, PostDate, UserID,, PostText), LNC)
|
||||||
_TotalPostsDownloaded += 1
|
_TotalPostsDownloaded += 1
|
||||||
End If
|
End If
|
||||||
ElseIf CreateImgurMedia(tmpUrl, PostID, PostDate, UserID, IsChannel) Then
|
ElseIf CreateImgurMedia(tmpUrl, PostID, PostDate, UserID, IsChannel, PostText) Then
|
||||||
_TotalPostsDownloaded += 1
|
_TotalPostsDownloaded += 1
|
||||||
ElseIf DownloadGallery(e, PostID, PostDate, UserID, SaveToCache) Then
|
ElseIf DownloadGallery(e, PostID, PostDate, UserID, SaveToCache, PostText) Then
|
||||||
_TotalPostsDownloaded += 1
|
_TotalPostsDownloaded += 1
|
||||||
ElseIf Not If(e({"media"}, "type")?.Value, String.Empty).IsEmptyString Then
|
ElseIf Not If(e({"media"}, "type")?.Value, String.Empty).IsEmptyString Then
|
||||||
With e("media")
|
With e("media")
|
||||||
Dim t$ = .Item("type").Value
|
Dim t$ = .Item("type").Value
|
||||||
Select Case t
|
Select Case t
|
||||||
Case "gallery" : If DownloadGallery(.Self, PostID, PostDate) Then _TotalPostsDownloaded += 1 Else added = False
|
Case "gallery" : If DownloadGallery(.Self, PostID, PostDate,,, PostText) Then _TotalPostsDownloaded += 1 Else added = False
|
||||||
Case "image", "gifvideo"
|
Case "image", "gifvideo"
|
||||||
|
|
||||||
Dim resolution As Sizes = Nothing
|
Dim resolution As Sizes = Nothing
|
||||||
@@ -577,17 +626,17 @@ Namespace API.Reddit
|
|||||||
End If
|
End If
|
||||||
|
|
||||||
If Not chosenVal.IsEmptyString Then
|
If Not chosenVal.IsEmptyString Then
|
||||||
_TempMediaList.ListAddValue(MediaFromData(UPicType(t), chosenVal, PostID, PostDate, UserID), LNC)
|
_TempMediaList.ListAddValue(MediaFromData(UPicType(t), chosenVal, PostID, PostDate, UserID,, PostText), LNC)
|
||||||
_TotalPostsDownloaded += 1
|
_TotalPostsDownloaded += 1
|
||||||
Else
|
Else
|
||||||
added = False
|
added = False
|
||||||
End If
|
End If
|
||||||
Case "video"
|
Case "video"
|
||||||
If UseM3U8 AndAlso .Item("hlsUrl").XmlIfNothingValue("/").ToLower.Contains("m3u8") Then
|
If UseM3U8 AndAlso .Item("hlsUrl").XmlIfNothingValue("/").ToLower.Contains("m3u8") Then
|
||||||
_TempMediaList.ListAddValue(MediaFromData(UTypes.m3u8, .Value("hlsUrl"), PostID, PostDate, UserID), LNC)
|
_TempMediaList.ListAddValue(MediaFromData(UTypes.m3u8, .Value("hlsUrl"), PostID, PostDate, UserID,, PostText), LNC)
|
||||||
_TotalPostsDownloaded += 1
|
_TotalPostsDownloaded += 1
|
||||||
ElseIf Not UseM3U8 AndAlso .Item("fallback_url").XmlIfNothingValue("/").ToLower.Contains("mp4") Then
|
ElseIf Not UseM3U8 AndAlso .Item("fallback_url").XmlIfNothingValue("/").ToLower.Contains("mp4") Then
|
||||||
_TempMediaList.ListAddValue(MediaFromData(UTypes.Video, .Value("fallback_url"), PostID, PostDate, UserID), LNC)
|
_TempMediaList.ListAddValue(MediaFromData(UTypes.Video, .Value("fallback_url"), PostID, PostDate, UserID,, PostText), LNC)
|
||||||
_TotalPostsDownloaded += 1
|
_TotalPostsDownloaded += 1
|
||||||
Else
|
Else
|
||||||
added = False
|
added = False
|
||||||
@@ -600,16 +649,16 @@ Namespace API.Reddit
|
|||||||
If SaveToCache Then
|
If SaveToCache Then
|
||||||
tmpUrl = GetVideoRedditPreview(e)
|
tmpUrl = GetVideoRedditPreview(e)
|
||||||
If Not tmpUrl.IsEmptyString Then
|
If Not tmpUrl.IsEmptyString Then
|
||||||
_TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, tmpUrl, PostID, PostDate, UserID, False), LNC)
|
_TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, tmpUrl, PostID, PostDate, UserID, False, PostText), LNC)
|
||||||
_TotalPostsDownloaded += 1
|
_TotalPostsDownloaded += 1
|
||||||
Else
|
Else
|
||||||
added = False
|
added = False
|
||||||
End If
|
End If
|
||||||
ElseIf UseM3U8 AndAlso Not If(e({"media", "reddit_video"}, "hls_url")?.Value, String.Empty).IsEmptyString Then
|
ElseIf UseM3U8 AndAlso Not If(e({"media", "reddit_video"}, "hls_url")?.Value, String.Empty).IsEmptyString Then
|
||||||
_TempMediaList.ListAddValue(MediaFromData(UTypes.m3u8, e.Value({"media", "reddit_video"}, "hls_url"), PostID, PostDate, UserID), LNC)
|
_TempMediaList.ListAddValue(MediaFromData(UTypes.m3u8, e.Value({"media", "reddit_video"}, "hls_url"), PostID, PostDate, UserID,, PostText), LNC)
|
||||||
_TotalPostsDownloaded += 1
|
_TotalPostsDownloaded += 1
|
||||||
Else
|
Else
|
||||||
_TempMediaList.ListAddValue(MediaFromData(UTypes.Video, tmpUrl, PostID, PostDate, UserID), LNC)
|
_TempMediaList.ListAddValue(MediaFromData(UTypes.Video, tmpUrl, PostID, PostDate, UserID,, PostText), LNC)
|
||||||
_TotalPostsDownloaded += 1
|
_TotalPostsDownloaded += 1
|
||||||
End If
|
End If
|
||||||
Else
|
Else
|
||||||
@@ -618,20 +667,25 @@ Namespace API.Reddit
|
|||||||
If Not added Then
|
If Not added Then
|
||||||
If AllowReparse Then
|
If AllowReparse Then
|
||||||
If If(e.ItemF({"crosspost_parent_list", 0})?.Count, 0) > 0 Then
|
If If(e.ItemF({"crosspost_parent_list", 0})?.Count, 0) > 0 Then
|
||||||
added = ParseContainer(e.ItemF({"crosspost_parent_list", 0}), PostID, PostDate, UserID, True)
|
added = ParseContainer(e.ItemF({"crosspost_parent_list", 0}), PostID, PostDate, UserID, True, PostText)
|
||||||
Else
|
Else
|
||||||
Dim tPostId$ = e.Value(Node_CrosspostParent).IfNullOrEmpty(e.Value(Node_CrosspostParentId)).IfNullOrEmpty(e.Value(Node_CrosspostRootId))
|
Dim tPostId$ = e.Value(Node_CrosspostParent).IfNullOrEmpty(e.Value(Node_CrosspostParentId)).IfNullOrEmpty(e.Value(Node_CrosspostRootId))
|
||||||
If Not PostID.IsEmptyString Then
|
If Not PostID.IsEmptyString Then
|
||||||
|
For ri% = 0 To 1
|
||||||
|
Wait429()
|
||||||
Dim r$ = Responser.GetResponse($"https://www.reddit.com/comments/{tPostId.Split("_").LastOrDefault}/.json",, EDP.ReturnValue)
|
Dim r$ = Responser.GetResponse($"https://www.reddit.com/comments/{tPostId.Split("_").LastOrDefault}/.json",, EDP.ReturnValue)
|
||||||
If Not r.IsEmptyString Then
|
If Not r.IsEmptyString Then
|
||||||
|
Err429Reset()
|
||||||
Using j As EContainer = JsonDocument.Parse(r, EDP.ReturnValue)
|
Using j As EContainer = JsonDocument.Parse(r, EDP.ReturnValue)
|
||||||
If j.ListExists Then
|
If j.ListExists Then
|
||||||
With j.ItemF({0, "data", "children", 0, "data"})
|
With j.ItemF({0, "data", "children", 0, "data"})
|
||||||
If .ListExists Then added = ParseContainer(.Self, PostID, PostDate, UserID, False)
|
If .ListExists Then added = ParseContainer(.Self, PostID, PostDate, UserID, False, PostText)
|
||||||
End With
|
End With
|
||||||
End If
|
End If
|
||||||
End Using
|
End Using
|
||||||
|
Exit For
|
||||||
End If
|
End If
|
||||||
|
Next
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
@@ -649,7 +703,7 @@ Namespace API.Reddit
|
|||||||
End Select
|
End Select
|
||||||
End With
|
End With
|
||||||
If Not tmpType = UTypes.Undefined Then
|
If Not tmpType = UTypes.Undefined Then
|
||||||
_TempMediaList.ListAddValue(MediaFromData(tmpType, node.Value, PostID, PostDate, UserID), LNC)
|
_TempMediaList.ListAddValue(MediaFromData(tmpType, node.Value, PostID, PostDate, UserID,, PostText), LNC)
|
||||||
added = True
|
added = True
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
@@ -672,7 +726,7 @@ Namespace API.Reddit
|
|||||||
If Not tmpUrl.IsEmptyString Then tmpType = UTypes.Picture
|
If Not tmpUrl.IsEmptyString Then tmpType = UTypes.Picture
|
||||||
End If
|
End If
|
||||||
If Not tmpUrl.IsEmptyString And Not tmpType = UTypes.Undefined Then
|
If Not tmpUrl.IsEmptyString And Not tmpType = UTypes.Undefined Then
|
||||||
Dim m As UserMedia = MediaFromData(tmpType, tmpUrl, PostID, PostDate, UserID)
|
Dim m As UserMedia = MediaFromData(tmpType, tmpUrl, PostID, PostDate, UserID,, PostText)
|
||||||
If tmpType = UTypes.Video Then m.File.Extension = "mp4"
|
If tmpType = UTypes.Video Then m.File.Extension = "mp4"
|
||||||
_TempMediaList.ListAddValue(m, LNC)
|
_TempMediaList.ListAddValue(m, LNC)
|
||||||
_TotalPostsDownloaded += 1
|
_TotalPostsDownloaded += 1
|
||||||
@@ -683,6 +737,7 @@ Namespace API.Reddit
|
|||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
|
If Not added And Not PostText.IsEmptyString Then _TempMediaList.ListAddValue(MediaFromData(UTypes.Text, String.Empty, PostID, PostDate, UserID,, PostText))
|
||||||
Return added
|
Return added
|
||||||
Else
|
Else
|
||||||
Return False
|
Return False
|
||||||
@@ -705,28 +760,45 @@ Namespace API.Reddit
|
|||||||
Return False
|
Return False
|
||||||
End Try
|
End Try
|
||||||
End Function
|
End Function
|
||||||
|
Private Function GetTextDocument(ByVal e As EContainer) As String
|
||||||
|
Dim t$ = String.Empty
|
||||||
|
Try
|
||||||
|
t = e.Value("title")
|
||||||
|
With e({"rtjson", "document"})
|
||||||
|
If .ListExists Then
|
||||||
|
For Each tt As EContainer In .Self
|
||||||
|
t.StringAppendLine(vbCrLf,, False)
|
||||||
|
t.StringAppendLine(If(tt.ItemF({"c", 0, "t"})?.Value, String.Empty))
|
||||||
|
Next
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
Catch
|
||||||
|
End Try
|
||||||
|
Return t
|
||||||
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Download Base Functions"
|
#Region "Download Base Functions"
|
||||||
Private Function CreateImgurMedia(ByVal _URL As String, ByVal PostID As String, ByVal PostDate As String,
|
Private Function CreateImgurMedia(ByVal _URL As String, ByVal PostID As String, ByVal PostDate As String,
|
||||||
Optional ByVal _UserID As String = "", Optional ByVal IsChannel As Boolean = False) As Boolean
|
Optional ByVal _UserID As String = "", Optional ByVal IsChannel As Boolean = False,
|
||||||
|
Optional ByVal PostText As String = Nothing) As Boolean
|
||||||
If Not _URL.IsEmptyString AndAlso _URL.Contains("imgur") Then
|
If Not _URL.IsEmptyString AndAlso _URL.Contains("imgur") Then
|
||||||
If _URL.StringContains({".jpg", ".png", ".jpeg"}) Then
|
If _URL.StringContains({".jpg", ".png", ".jpeg"}) Then
|
||||||
_TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, _URL, PostID, PostDate, _UserID), LNC)
|
_TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, _URL, PostID, PostDate, _UserID,, PostText), LNC)
|
||||||
ElseIf _URL.Contains(".gifv") Then
|
ElseIf _URL.Contains(".gifv") Then
|
||||||
If SaveToCache Then
|
If SaveToCache Then
|
||||||
_TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, _URL.Replace(".gifv", ".gif"), PostID, PostDate, _UserID), LNC)
|
_TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, _URL.Replace(".gifv", ".gif"), PostID, PostDate, _UserID,, PostText), LNC)
|
||||||
Else
|
Else
|
||||||
_TempMediaList.ListAddValue(MediaFromData(UTypes.Video, _URL.Replace(".gifv", ".mp4"), PostID, PostDate, _UserID), LNC)
|
_TempMediaList.ListAddValue(MediaFromData(UTypes.Video, _URL.Replace(".gifv", ".mp4"), PostID, PostDate, _UserID,, PostText), LNC)
|
||||||
End If
|
End If
|
||||||
ElseIf _URL.Contains(".mp4") Then
|
ElseIf _URL.Contains(".mp4") Then
|
||||||
_TempMediaList.ListAddValue(MediaFromData(UTypes.Video, _URL, PostID, PostDate, _UserID), LNC)
|
_TempMediaList.ListAddValue(MediaFromData(UTypes.Video, _URL, PostID, PostDate, _UserID,, PostText), LNC)
|
||||||
ElseIf _URL.Contains(".gif") Then
|
ElseIf _URL.Contains(".gif") Then
|
||||||
_TempMediaList.ListAddValue(MediaFromData(UTypes.GIF, _URL, PostID, PostDate, _UserID), LNC)
|
_TempMediaList.ListAddValue(MediaFromData(UTypes.GIF, _URL, PostID, PostDate, _UserID,, PostText), LNC)
|
||||||
Else
|
Else
|
||||||
Dim obj As IEnumerable(Of UserMedia) = Imgur.Envir.GetVideoInfo(_URL, EDP.ReturnValue)
|
Dim obj As IEnumerable(Of UserMedia) = Imgur.Envir.GetVideoInfo(_URL, EDP.ReturnValue)
|
||||||
If Not obj.ListExists Then
|
If Not obj.ListExists Then
|
||||||
If Not TryFile(_URL) Then _URL &= ".jpg"
|
If Not TryFile(_URL) Then _URL &= ".jpg"
|
||||||
_TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, _URL, PostID, PostDate, _UserID), LNC)
|
_TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, _URL, PostID, PostDate, _UserID,, PostText), LNC)
|
||||||
Else
|
Else
|
||||||
Dim ut As UTypes
|
Dim ut As UTypes
|
||||||
Dim m As UserMedia
|
Dim m As UserMedia
|
||||||
@@ -741,7 +813,7 @@ Namespace API.Reddit
|
|||||||
Case "gif" : ut = UTypes.GIF
|
Case "gif" : ut = UTypes.GIF
|
||||||
Case Else : ut = UTypes.Picture : .File.Extension = "jpg"
|
Case Else : ut = UTypes.Picture : .File.Extension = "jpg"
|
||||||
End Select
|
End Select
|
||||||
m = MediaFromData(ut, _URL, PostID, PostDate, _UserID)
|
m = MediaFromData(ut, _URL, PostID, PostDate, _UserID,, PostText)
|
||||||
m.URL = .URL
|
m.URL = .URL
|
||||||
m.File = .File.File
|
m.File = .File.File
|
||||||
_TempMediaList.ListAddValue(m, LNC)
|
_TempMediaList.ListAddValue(m, LNC)
|
||||||
@@ -757,7 +829,8 @@ Namespace API.Reddit
|
|||||||
End If
|
End If
|
||||||
End Function
|
End Function
|
||||||
Private Function DownloadGallery(ByVal e As EContainer, ByVal PostID As String, ByVal PostDate As String,
|
Private Function DownloadGallery(ByVal e As EContainer, ByVal PostID As String, ByVal PostDate As String,
|
||||||
Optional ByVal _UserID As String = Nothing, Optional ByVal FirstOnly As Boolean = False) As Boolean
|
Optional ByVal _UserID As String = Nothing, Optional ByVal FirstOnly As Boolean = False,
|
||||||
|
Optional ByVal PostText As String = Nothing) As Boolean
|
||||||
Try
|
Try
|
||||||
Dim added As Boolean = False
|
Dim added As Boolean = False
|
||||||
Dim node As EContainer = Nothing
|
Dim node As EContainer = Nothing
|
||||||
@@ -771,7 +844,7 @@ Namespace API.Reddit
|
|||||||
For Each n As EContainer In node
|
For Each n As EContainer In node
|
||||||
t = n.ItemF({"s", "u"})
|
t = n.ItemF({"s", "u"})
|
||||||
If Not t Is Nothing AndAlso Not t.Value.IsEmptyString Then
|
If Not t Is Nothing AndAlso Not t.Value.IsEmptyString Then
|
||||||
_TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, t.Value, PostID, PostDate, _UserID), LNC)
|
_TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, t.Value, PostID, PostDate, _UserID,, PostText), LNC)
|
||||||
added = True
|
added = True
|
||||||
If FirstOnly Then Exit For
|
If FirstOnly Then Exit For
|
||||||
End If
|
End If
|
||||||
@@ -878,7 +951,10 @@ Namespace API.Reddit
|
|||||||
End If
|
End If
|
||||||
Continue For
|
Continue For
|
||||||
Else
|
Else
|
||||||
|
Wait429()
|
||||||
r = Responser.GetResponse(m.URL,, e)
|
r = Responser.GetResponse(m.URL,, e)
|
||||||
|
If r.IsEmptyString And Err429TryAgain Then _repeatForRedgifs = True
|
||||||
|
If Not r.IsEmptyString Then Err429Reset()
|
||||||
End If
|
End If
|
||||||
Loop While _repeatForRedgifs
|
Loop While _repeatForRedgifs
|
||||||
Else
|
Else
|
||||||
@@ -888,7 +964,7 @@ Namespace API.Reddit
|
|||||||
If Not r.IsEmptyString Then
|
If Not r.IsEmptyString Then
|
||||||
v = RegexReplace(r, VideoRegEx)
|
v = RegexReplace(r, VideoRegEx)
|
||||||
If Not v.IsEmptyString Then
|
If Not v.IsEmptyString Then
|
||||||
_TempMediaList(i) = New UserMedia With {.Type = UTypes.Video, .URL = v, .File = v, .Post = m.Post}
|
_TempMediaList(i) = New UserMedia With {.Type = UTypes.Video, .URL = v, .File = v, .Post = m.Post, .PostText = m.PostText, .PostTextFile = m.PostTextFile}
|
||||||
Else
|
Else
|
||||||
_TempMediaList.RemoveAt(i)
|
_TempMediaList.RemoveAt(i)
|
||||||
End If
|
End If
|
||||||
@@ -916,11 +992,13 @@ Namespace API.Reddit
|
|||||||
RedGifsResponser = RedGifsHost.Responser.Copy
|
RedGifsResponser = RedGifsHost.Responser.Copy
|
||||||
Dim respNoHeaders As Responser = Responser.Copy
|
Dim respNoHeaders As Responser = Responser.Copy
|
||||||
Dim m As UserMedia, m2 As UserMedia
|
Dim m As UserMedia, m2 As UserMedia
|
||||||
Dim r$, url$
|
Dim r$ = String.Empty, url$
|
||||||
|
Dim ri As Byte
|
||||||
Dim j As EContainer
|
Dim j As EContainer
|
||||||
Dim lastCount%, li%
|
Dim lastCount%, li%
|
||||||
Dim rv As New ErrorsDescriber(EDP.ReturnValue)
|
Dim rv As New ErrorsDescriber(EDP.ReturnValue)
|
||||||
respNoHeaders.Headers.Clear()
|
respNoHeaders.Headers.Clear()
|
||||||
|
respNoHeaders.ProcessExceptionDecision = AddressOf Err429Process
|
||||||
ProgressPre.ChangeMax(_ContentList.Count)
|
ProgressPre.ChangeMax(_ContentList.Count)
|
||||||
For i% = 0 To _ContentList.Count - 1
|
For i% = 0 To _ContentList.Count - 1
|
||||||
m = _ContentList(i)
|
m = _ContentList(i)
|
||||||
@@ -928,15 +1006,20 @@ Namespace API.Reddit
|
|||||||
If m.State = UStates.Missing AndAlso Not m.Post.ID.IsEmptyString Then
|
If m.State = UStates.Missing AndAlso Not m.Post.ID.IsEmptyString Then
|
||||||
ThrowAny(Token)
|
ThrowAny(Token)
|
||||||
url = $"https://www.reddit.com/comments/{m.Post.ID.Split("_").LastOrDefault}/.json"
|
url = $"https://www.reddit.com/comments/{m.Post.ID.Split("_").LastOrDefault}/.json"
|
||||||
|
For ri = 0 To 1
|
||||||
|
Wait429()
|
||||||
r = Responser.GetResponse(url,, rv)
|
r = Responser.GetResponse(url,, rv)
|
||||||
If r.IsEmptyString Then r = respNoHeaders.GetResponse(url,, rv)
|
If r.IsEmptyString Then Wait429() : r = respNoHeaders.GetResponse(url,, rv)
|
||||||
|
If Not (r.IsEmptyString And Err429TryAgain) Then Exit For
|
||||||
|
Next
|
||||||
If Not r.IsEmptyString Then
|
If Not r.IsEmptyString Then
|
||||||
|
Err429Reset()
|
||||||
j = JsonDocument.Parse(r, rv)
|
j = JsonDocument.Parse(r, rv)
|
||||||
If Not j Is Nothing Then
|
If Not j Is Nothing Then
|
||||||
If j.Count > 0 Then
|
If j.Count > 0 Then
|
||||||
lastCount = _TempMediaList.Count
|
lastCount = _TempMediaList.Count
|
||||||
With j.GetNode(SingleJsonNodes)
|
With j.GetNode(SingleJsonNodes)
|
||||||
If .ListExists AndAlso ParseContainer(.Self, m.Post.ID, String.Empty) Then
|
If .ListExists AndAlso ParseContainer(.Self, m.Post.ID, String.Empty,,, GetTextDocument(.Self)) Then
|
||||||
If lastCount <> _TempMediaList.Count Then
|
If lastCount <> _TempMediaList.Count Then
|
||||||
For li = IIf(lastCount < 0, 0, lastCount) To _TempMediaList.Count - 1
|
For li = IIf(lastCount < 0, 0, lastCount) To _TempMediaList.Count - 1
|
||||||
m2 = _TempMediaList(i)
|
m2 = _TempMediaList(i)
|
||||||
@@ -983,13 +1066,15 @@ Namespace API.Reddit
|
|||||||
#End Region
|
#End Region
|
||||||
#Region "Structure creator"
|
#Region "Structure creator"
|
||||||
Private Function MediaFromData(ByVal t As UTypes, ByVal _URL As String, ByVal PostID As String, ByVal PostDate As String,
|
Private Function MediaFromData(ByVal t As UTypes, ByVal _URL As String, ByVal PostID As String, ByVal PostDate As String,
|
||||||
Optional ByVal _UserID As String = "", Optional ByVal ReplacePreview As Boolean = True) As UserMedia
|
Optional ByVal _UserID As String = "", Optional ByVal ReplacePreview As Boolean = True,
|
||||||
|
Optional ByVal PostText As String = Nothing) As UserMedia
|
||||||
If _URL.IsEmptyString And t = UTypes.Picture Then Return Nothing
|
If _URL.IsEmptyString And t = UTypes.Picture Then Return Nothing
|
||||||
_URL = LinkFormatterSecure(RegexReplace(_URL.Replace("\", String.Empty), LinkPattern))
|
_URL = LinkFormatterSecure(RegexReplace(_URL.Replace("\", String.Empty), LinkPattern))
|
||||||
Dim m As New UserMedia(_URL, t) With {.Post = New UserPost With {.ID = PostID, .UserID = _UserID}}
|
Dim m As New UserMedia(_URL, t) With {.Post = New UserPost With {.ID = PostID, .UserID = _UserID}}
|
||||||
If t = UTypes.Picture Or t = UTypes.GIF Then m.File = CreateFileFromUrl(m.URL) Else m.File = Nothing
|
If t = UTypes.Picture Or t = UTypes.GIF Then m.File = CreateFileFromUrl(m.URL) Else m.File = Nothing
|
||||||
If ReplacePreview And m.URL.Contains("preview") And Not t = UTypes.Picture Then m.URL = $"https://i.redd.it/{m.File.File}"
|
If ReplacePreview And m.URL.Contains("preview") And Not t = UTypes.Picture Then m.URL = $"https://i.redd.it/{m.File.File}"
|
||||||
If Not PostDate.IsEmptyString Then m.Post.Date = AConvert(Of Date)(PostDate, DateTrueProvider(IsChannel Or IsSavedPosts), Nothing) Else m.Post.Date = Nothing
|
If Not PostDate.IsEmptyString Then m.Post.Date = AConvert(Of Date)(PostDate, DateTrueProvider(IsChannel Or IsSavedPosts), Nothing) Else m.Post.Date = Nothing
|
||||||
|
If Not PostText.IsEmptyString Then m.PostText = PostText
|
||||||
Return m
|
Return m
|
||||||
End Function
|
End Function
|
||||||
Private Function TryFile(ByVal URL As String) As Boolean
|
Private Function TryFile(ByVal URL As String) As Boolean
|
||||||
@@ -1060,25 +1145,37 @@ Namespace API.Reddit
|
|||||||
ElseIf .StatusCode = HttpStatusCode.Forbidden Then '403
|
ElseIf .StatusCode = HttpStatusCode.Forbidden Then '403
|
||||||
UserSuspended = True
|
UserSuspended = True
|
||||||
ElseIf .StatusCode = HttpStatusCode.BadGateway Or .StatusCode = HttpStatusCode.ServiceUnavailable Then '502, 503
|
ElseIf .StatusCode = HttpStatusCode.BadGateway Or .StatusCode = HttpStatusCode.ServiceUnavailable Then '502, 503
|
||||||
MyMainLOG = $"{ToStringForLog()}: [{CInt(Responser.StatusCode)}] Reddit is currently unavailable"
|
LogError(Nothing, $"[{CInt(Responser.StatusCode)}] Reddit is currently unavailable")
|
||||||
Throw New Plugin.ExitException With {.Silent = True}
|
Throw New Plugin.ExitException With {.Silent = True}
|
||||||
ElseIf .StatusCode = HttpStatusCode.GatewayTimeout Then '504
|
ElseIf .StatusCode = HttpStatusCode.GatewayTimeout Then '504
|
||||||
Return 1
|
Return 1
|
||||||
ElseIf .StatusCode = HttpStatusCode.Unauthorized Then '401
|
ElseIf .StatusCode = HttpStatusCode.Unauthorized Then '401
|
||||||
MyMainLOG = $"{ToStringForLog()}: [{CInt(Responser.StatusCode)}] Reddit credentials expired"
|
LogError(Nothing, $"[{CInt(Responser.StatusCode)}] Reddit credentials expired")
|
||||||
MySiteSettings.SessionInterrupted = True
|
MySiteSettings.SessionInterrupted = True
|
||||||
Throw New Plugin.ExitException With {.Silent = True}
|
Throw New Plugin.ExitException With {.Silent = True}
|
||||||
ElseIf .StatusCode = HttpStatusCode.InternalServerError Then '500
|
ElseIf .StatusCode = HttpStatusCode.InternalServerError Then '500
|
||||||
If Not IsNothing(EObj) AndAlso IsNumeric(EObj) AndAlso CInt(EObj) = HttpStatusCode.InternalServerError Then Return 1
|
If Not IsNothing(EObj) AndAlso IsNumeric(EObj) AndAlso CInt(EObj) = HttpStatusCode.InternalServerError Then Return 1
|
||||||
Return HttpStatusCode.InternalServerError
|
Return HttpStatusCode.InternalServerError
|
||||||
ElseIf .StatusCode = 429 And IsSavedPosts And Err429Count = 0 Then
|
'ElseIf .StatusCode = 429 And IsSavedPosts And Err429Count = 0 Then '429 (saved)
|
||||||
Err429Count += 1
|
' Err429Count += 1
|
||||||
Return 429
|
' Return 429
|
||||||
ElseIf .StatusCode = 429 AndAlso
|
ElseIf .StatusCode = 429 Then '429 (all)
|
||||||
((Not IsSavedPosts And CBool(MySiteSettings.UseTokenForTimelines.Value)) Or (IsSavedPosts And CBool(MySiteSettings.UseTokenForSavedPosts.Value))) AndAlso
|
'If ((Not IsSavedPosts And CBool(MySiteSettings.UseTokenForTimelines.Value)) Or (IsSavedPosts And CBool(MySiteSettings.UseTokenForSavedPosts.Value))) AndAlso
|
||||||
Not MySiteSettings.CredentialsExists Then '429
|
' Not MySiteSettings.CredentialsExists Then
|
||||||
MyMainLOG = $"{ToStringForLog()}: [{CInt(Responser.StatusCode)}] You should use OAuth authorization or disable " &
|
' LogError(Nothing, "[429] You should use OAuth authorization or disable " &
|
||||||
IIf(IsSavedPosts, "token usage for downloading saved posts", "the use of token and cookies for downloading timelines")
|
' IIf(IsSavedPosts, "token usage for downloading saved posts", "the use of token and cookies for downloading timelines"))
|
||||||
|
'Else
|
||||||
|
' LogError(Nothing, "Too many requests (429). Try again later!")
|
||||||
|
'End If
|
||||||
|
'MySiteSettings.SessionInterrupted = True
|
||||||
|
'Throw New Plugin.ExitException With {.Silent = True}
|
||||||
|
If ((Not IsSavedPosts And CBool(MySiteSettings.UseTokenForTimelines.Value)) Or (IsSavedPosts And CBool(MySiteSettings.UseTokenForSavedPosts.Value))) AndAlso
|
||||||
|
Not MySiteSettings.CredentialsExists Then
|
||||||
|
LogError(Nothing, "[429] You should use OAuth authorization or disable " &
|
||||||
|
IIf(IsSavedPosts, "token usage for downloading saved posts", "the use of token and cookies for downloading timelines"))
|
||||||
|
Else
|
||||||
|
LogError(Nothing, "Too many requests (429). Try again later!")
|
||||||
|
End If
|
||||||
MySiteSettings.SessionInterrupted = True
|
MySiteSettings.SessionInterrupted = True
|
||||||
Throw New Plugin.ExitException With {.Silent = True}
|
Throw New Plugin.ExitException With {.Silent = True}
|
||||||
Else
|
Else
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ Namespace API.RedGifs
|
|||||||
Friend ReadOnly Property Token As PropertyValue
|
Friend ReadOnly Property Token As PropertyValue
|
||||||
<PropertyOption, ControlNumber(2), PClonable, HiddenControl>
|
<PropertyOption, ControlNumber(2), PClonable, HiddenControl>
|
||||||
Private ReadOnly Property UserAgent As PropertyValue
|
Private ReadOnly Property UserAgent As PropertyValue
|
||||||
|
<PXML> Friend ReadOnly Property UseCookies As PropertyValue
|
||||||
<PXML> Friend ReadOnly Property TokenLastDateUpdated As PropertyValue
|
<PXML> Friend ReadOnly Property TokenLastDateUpdated As PropertyValue
|
||||||
Private Const TokenName As String = "authorization"
|
Private Const TokenName As String = "authorization"
|
||||||
#Region "TokenUpdateInterval"
|
#Region "TokenUpdateInterval"
|
||||||
@@ -31,6 +32,9 @@ Namespace API.RedGifs
|
|||||||
<Provider(NameOf(TokenUpdateInterval), FieldsChecker:=True)>
|
<Provider(NameOf(TokenUpdateInterval), FieldsChecker:=True)>
|
||||||
Private ReadOnly Property TokenUpdateIntervalProvider As IFormatProvider
|
Private ReadOnly Property TokenUpdateIntervalProvider As IFormatProvider
|
||||||
#End Region
|
#End Region
|
||||||
|
<DoNotUse> Friend Overrides Property DownloadText As PropertyValue
|
||||||
|
<DoNotUse> Friend Overrides Property DownloadTextPosts As PropertyValue
|
||||||
|
<DoNotUse> Friend Overrides Property DownloadTextSpecialFolder As PropertyValue
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Initializer"
|
#Region "Initializer"
|
||||||
Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean)
|
Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean)
|
||||||
@@ -44,6 +48,7 @@ Namespace API.RedGifs
|
|||||||
End With
|
End With
|
||||||
Token = New PropertyValue(t, GetType(String), Sub(v) UpdateResponse(NameOf(Token), v))
|
Token = New PropertyValue(t, GetType(String), Sub(v) UpdateResponse(NameOf(Token), v))
|
||||||
UserAgent = New PropertyValue(If(Responser.UserAgentExists, Responser.UserAgent, String.Empty), GetType(String), Sub(v) UpdateResponse(NameOf(UserAgent), v))
|
UserAgent = New PropertyValue(If(Responser.UserAgentExists, Responser.UserAgent, String.Empty), GetType(String), Sub(v) UpdateResponse(NameOf(UserAgent), v))
|
||||||
|
UseCookies = New PropertyValue(False)
|
||||||
TokenLastDateUpdated = New PropertyValue(Now.AddYears(-1), GetType(Date))
|
TokenLastDateUpdated = New PropertyValue(Now.AddYears(-1), GetType(Date))
|
||||||
TokenUpdateInterval = New PropertyValue(60 * 12, GetType(Integer))
|
TokenUpdateInterval = New PropertyValue(60 * 12, GetType(Integer))
|
||||||
TokenUpdateIntervalProvider = New TokenRefreshIntervalProvider
|
TokenUpdateIntervalProvider = New TokenRefreshIntervalProvider
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ Namespace API.RedGifs
|
|||||||
#End Region
|
#End Region
|
||||||
#Region "Download functions"
|
#Region "Download functions"
|
||||||
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
|
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
|
||||||
|
If Not MySettings.UseCookies.Value Then Responser.Cookies.Clear()
|
||||||
DownloadData(1, Token)
|
DownloadData(1, Token)
|
||||||
End Sub
|
End Sub
|
||||||
Private Overloads Sub DownloadData(ByVal Page As Integer, ByVal Token As CancellationToken)
|
Private Overloads Sub DownloadData(ByVal Page As Integer, ByVal Token As CancellationToken)
|
||||||
|
|||||||
@@ -27,6 +27,9 @@ Namespace API.ThisVid
|
|||||||
"If true, then public videos will be stored in the 'Public' folder, private - in the 'Private' folder." & vbCr &
|
"If true, then public videos will be stored in the 'Public' folder, private - in the 'Private' folder." & vbCr &
|
||||||
"If false, all videos will be stored in the 'Video' folder."), PClonable>
|
"If false, all videos will be stored in the 'Video' folder."), PClonable>
|
||||||
Friend ReadOnly Property DifferentFolders As PropertyValue
|
Friend ReadOnly Property DifferentFolders As PropertyValue
|
||||||
|
<DoNotUse> Friend Overrides Property DownloadText As PropertyValue
|
||||||
|
<DoNotUse> Friend Overrides Property DownloadTextPosts As PropertyValue
|
||||||
|
<DoNotUse> Friend Overrides Property DownloadTextSpecialFolder As PropertyValue
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Initializer"
|
#Region "Initializer"
|
||||||
Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean)
|
Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ Imports PersonalUtilities.Functions.RegularExpressions
|
|||||||
Imports PersonalUtilities.Tools
|
Imports PersonalUtilities.Tools
|
||||||
Imports PersonalUtilities.Tools.Web.Documents.JSON
|
Imports PersonalUtilities.Tools.Web.Documents.JSON
|
||||||
Namespace API.ThisVid
|
Namespace API.ThisVid
|
||||||
Friend Class UserData : Inherits UserDataBase
|
Friend Class UserData : Inherits UserDataBase : Implements IPSite
|
||||||
#Region "XML names"
|
#Region "XML names"
|
||||||
Private Const Name_DownloadPublic As String = "DownloadPublic"
|
Private Const Name_DownloadPublic As String = "DownloadPublic"
|
||||||
Private Const Name_DownloadPrivate As String = "DownloadPrivate"
|
Private Const Name_DownloadPrivate As String = "DownloadPrivate"
|
||||||
@@ -44,7 +44,6 @@ Namespace API.ThisVid
|
|||||||
Friend Property DownloadPrivate As Boolean = True
|
Friend Property DownloadPrivate As Boolean = True
|
||||||
Friend Property DownloadFavourite As Boolean = False
|
Friend Property DownloadFavourite As Boolean = False
|
||||||
Friend Property DifferentFolders As Boolean = True
|
Friend Property DifferentFolders As Boolean = True
|
||||||
Friend Property TrueName As String = String.Empty
|
|
||||||
Friend Property SiteMode As SiteModes = SiteModes.User
|
Friend Property SiteMode As SiteModes = SiteModes.User
|
||||||
Private Property Arguments As String = String.Empty
|
Private Property Arguments As String = String.Empty
|
||||||
Friend Overrides ReadOnly Property SpecialLabels As IEnumerable(Of String)
|
Friend Overrides ReadOnly Property SpecialLabels As IEnumerable(Of String)
|
||||||
@@ -52,7 +51,7 @@ Namespace API.ThisVid
|
|||||||
Return {SearchRequestLabelName}
|
Return {SearchRequestLabelName}
|
||||||
End Get
|
End Get
|
||||||
End Property
|
End Property
|
||||||
Friend Property QueryString As String
|
Friend Property QueryString As String Implements IPSite.QueryString
|
||||||
Get
|
Get
|
||||||
If SiteMode = SiteModes.User Then
|
If SiteMode = SiteModes.User Then
|
||||||
Return String.Empty
|
Return String.Empty
|
||||||
@@ -80,7 +79,7 @@ Namespace API.ThisVid
|
|||||||
If Not Force OrElse (Not SiteMode = SiteModes.User AndAlso Not NewUrl.IsEmptyString AndAlso MyFileSettings.Exists) Then
|
If Not Force OrElse (Not SiteMode = SiteModes.User AndAlso Not NewUrl.IsEmptyString AndAlso MyFileSettings.Exists) Then
|
||||||
Dim eObj As Plugin.ExchangeOptions = Nothing
|
Dim eObj As Plugin.ExchangeOptions = Nothing
|
||||||
If Force Then eObj = MySettings.IsMyUser(NewUrl)
|
If Force Then eObj = MySettings.IsMyUser(NewUrl)
|
||||||
If (Force And Not eObj.UserName.IsEmptyString) Or (Not Force And TrueName.IsEmptyString) Then
|
If (Force And Not eObj.UserName.IsEmptyString) Or (Not Force And NameTrue(True).IsEmptyString) Then
|
||||||
Dim n$() = If(Force, eObj.UserName, Name).Split("@")
|
Dim n$() = If(Force, eObj.UserName, Name).Split("@")
|
||||||
If n.ListExists(2) Then
|
If n.ListExists(2) Then
|
||||||
|
|
||||||
@@ -98,8 +97,8 @@ Namespace API.ThisVid
|
|||||||
End If
|
End If
|
||||||
__TrueName = n(1)
|
__TrueName = n(1)
|
||||||
|
|
||||||
If Force AndAlso (Not TrueName = __TrueName Or Not SiteMode = __Mode) Then
|
If Force AndAlso (Not NameTrue(True) = __TrueName Or Not SiteMode = __Mode) Then
|
||||||
If ValidateChangeSearchOptions(ToStringForLog, $"{__Mode}: {__TrueName}", $"{SiteMode}: {TrueName}") Then
|
If ValidateChangeSearchOptions(ToStringForLog, $"{__Mode}: {__TrueName}", $"{SiteMode}: {NameTrue(True)}") Then
|
||||||
__ForceApply = True
|
__ForceApply = True
|
||||||
Else
|
Else
|
||||||
Return False
|
Return False
|
||||||
@@ -109,21 +108,21 @@ Namespace API.ThisVid
|
|||||||
Arguments = __Arguments
|
Arguments = __Arguments
|
||||||
Options = If(Force, eObj.Options, Options)
|
Options = If(Force, eObj.Options, Options)
|
||||||
If Not Force Then
|
If Not Force Then
|
||||||
TrueName = __TrueName
|
NameTrue = __TrueName
|
||||||
SiteMode = __Mode
|
SiteMode = __Mode
|
||||||
Settings.Labels.Add(SearchRequestLabelName)
|
Settings.Labels.Add(SearchRequestLabelName)
|
||||||
Labels.ListAddValue(SearchRequestLabelName, LNC)
|
Labels.ListAddValue(SearchRequestLabelName, LNC)
|
||||||
Labels.Sort()
|
Labels.Sort()
|
||||||
UserSiteName = $"{SiteMode}: {TrueName}"
|
UserSiteName = $"{SiteMode}: {NameTrue}"
|
||||||
If FriendlyName.IsEmptyString Then FriendlyName = UserSiteName
|
If FriendlyName.IsEmptyString Then FriendlyName = UserSiteName
|
||||||
ElseIf Force And __ForceApply Then
|
ElseIf Force And __ForceApply Then
|
||||||
TrueName = __TrueName
|
NameTrue = __TrueName
|
||||||
SiteMode = __Mode
|
SiteMode = __Mode
|
||||||
End If
|
End If
|
||||||
Return True
|
Return True
|
||||||
Else
|
Else
|
||||||
SiteMode = SiteModes.User
|
SiteMode = SiteModes.User
|
||||||
TrueName = Name
|
NameTrue = Name
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
@@ -136,7 +135,6 @@ Namespace API.ThisVid
|
|||||||
DownloadPrivate = .Value(Name_DownloadPrivate).FromXML(Of Boolean)(True)
|
DownloadPrivate = .Value(Name_DownloadPrivate).FromXML(Of Boolean)(True)
|
||||||
DownloadFavourite = .Value(Name_DownloadFavourite).FromXML(Of Boolean)(False)
|
DownloadFavourite = .Value(Name_DownloadFavourite).FromXML(Of Boolean)(False)
|
||||||
DifferentFolders = .Value(Name_DifferentFolders).FromXML(Of Boolean)(True)
|
DifferentFolders = .Value(Name_DifferentFolders).FromXML(Of Boolean)(True)
|
||||||
TrueName = .Value(Name_TrueName)
|
|
||||||
SiteMode = .Value(Name_SiteMode).FromXML(Of Integer)(SiteModes.User)
|
SiteMode = .Value(Name_SiteMode).FromXML(Of Integer)(SiteModes.User)
|
||||||
Arguments = .Value(Name_Arguments)
|
Arguments = .Value(Name_Arguments)
|
||||||
UpdateUserOptions()
|
UpdateUserOptions()
|
||||||
@@ -150,7 +148,7 @@ Namespace API.ThisVid
|
|||||||
.Add(Name_DownloadPrivate, DownloadPrivate.BoolToInteger)
|
.Add(Name_DownloadPrivate, DownloadPrivate.BoolToInteger)
|
||||||
.Add(Name_DownloadFavourite, DownloadFavourite.BoolToInteger)
|
.Add(Name_DownloadFavourite, DownloadFavourite.BoolToInteger)
|
||||||
.Add(Name_DifferentFolders, DifferentFolders.BoolToInteger)
|
.Add(Name_DifferentFolders, DifferentFolders.BoolToInteger)
|
||||||
.Add(Name_TrueName, TrueName)
|
.Add(Name_TrueName, NameTrue(True))
|
||||||
.Add(Name_SiteMode, CInt(SiteMode))
|
.Add(Name_SiteMode, CInt(SiteMode))
|
||||||
.Add(Name_Arguments, Arguments)
|
.Add(Name_Arguments, Arguments)
|
||||||
|
|
||||||
@@ -163,15 +161,7 @@ Namespace API.ThisVid
|
|||||||
Return New UserExchangeOptions(Me)
|
Return New UserExchangeOptions(Me)
|
||||||
End Function
|
End Function
|
||||||
Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object)
|
Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object)
|
||||||
If Not Obj Is Nothing AndAlso TypeOf Obj Is UserExchangeOptions Then
|
If Not Obj Is Nothing AndAlso TypeOf Obj Is UserExchangeOptions Then DirectCast(Obj, UserExchangeOptions).Apply(Me)
|
||||||
With DirectCast(Obj, UserExchangeOptions)
|
|
||||||
DownloadPublic = .DownloadPublic
|
|
||||||
DownloadPrivate = .DownloadPrivate
|
|
||||||
DownloadFavourite = .DownloadFavourite
|
|
||||||
DifferentFolders = .DifferentFolders
|
|
||||||
QueryString = .QueryString
|
|
||||||
End With
|
|
||||||
End If
|
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Initializer"
|
#Region "Initializer"
|
||||||
@@ -259,18 +249,18 @@ Namespace API.ThisVid
|
|||||||
Dim url$ = String.Empty
|
Dim url$ = String.Empty
|
||||||
Select Case SiteMode
|
Select Case SiteMode
|
||||||
Case SiteModes.Tags
|
Case SiteModes.Tags
|
||||||
url = $"https://thisvid.com/{SiteSettings.P_Tags}/{TrueName}/"
|
url = $"https://thisvid.com/{SiteSettings.P_Tags}/{NameTrue}/"
|
||||||
If Not Arguments.IsEmptyString Then url &= $"{Arguments}/"
|
If Not Arguments.IsEmptyString Then url &= $"{Arguments}/"
|
||||||
If Page > 1 Then url &= $"{Page}/"
|
If Page > 1 Then url &= $"{Page}/"
|
||||||
Case SiteModes.Categories
|
Case SiteModes.Categories
|
||||||
url = $"https://thisvid.com/{SiteSettings.P_Categories}/{TrueName}/"
|
url = $"https://thisvid.com/{SiteSettings.P_Categories}/{NameTrue}/"
|
||||||
If Not Arguments.IsEmptyString Then url &= $"{Arguments}/"
|
If Not Arguments.IsEmptyString Then url &= $"{Arguments}/"
|
||||||
If Page > 1 Then url &= $"{Page}/"
|
If Page > 1 Then url &= $"{Page}/"
|
||||||
Case SiteModes.Search
|
Case SiteModes.Search
|
||||||
If Not Arguments.IsEmptyString Then
|
If Not Arguments.IsEmptyString Then
|
||||||
url = $"https://thisvid.com/{Arguments}/"
|
url = $"https://thisvid.com/{Arguments}/"
|
||||||
If Page > 1 Then url &= $"{Page}/"
|
If Page > 1 Then url &= $"{Page}/"
|
||||||
url &= $"?q={TrueName}/"
|
url &= $"?q={NameTrue}/"
|
||||||
End If
|
End If
|
||||||
End Select
|
End Select
|
||||||
Return url
|
Return url
|
||||||
@@ -473,12 +463,16 @@ Namespace API.ThisVid
|
|||||||
Dim u As UserMedia
|
Dim u As UserMedia
|
||||||
Dim n$, r$
|
Dim n$, r$
|
||||||
Dim c% = 0
|
Dim c% = 0
|
||||||
|
Dim ii As Byte
|
||||||
|
Dim repeat As Boolean
|
||||||
Progress.Maximum += _TempMediaList.Count
|
Progress.Maximum += _TempMediaList.Count
|
||||||
For i% = _TempMediaList.Count - 1 To 0 Step -1
|
For i% = _TempMediaList.Count - 1 To 0 Step -1
|
||||||
Progress.Perform()
|
Progress.Perform()
|
||||||
u = _TempMediaList(i)
|
u = _TempMediaList(i)
|
||||||
If u.Type = UserMedia.Types.VideoPre Then
|
If u.Type = UserMedia.Types.VideoPre Then
|
||||||
If Not DownloadTopCount.HasValue OrElse c <= DownloadTopCount.Value Then
|
If Not DownloadTopCount.HasValue OrElse c <= DownloadTopCount.Value Then
|
||||||
|
repeat = False
|
||||||
|
For ii = 0 To 1
|
||||||
ThrowAny(Token)
|
ThrowAny(Token)
|
||||||
r = Responser.GetResponse(u.URL,, EDP.ReturnValue)
|
r = Responser.GetResponse(u.URL,, EDP.ReturnValue)
|
||||||
If Not r.IsEmptyString Then
|
If Not r.IsEmptyString Then
|
||||||
@@ -490,6 +484,12 @@ Namespace API.ThisVid
|
|||||||
u.File = $"{n}.mp4"
|
u.File = $"{n}.mp4"
|
||||||
u.PictureOption = n
|
u.PictureOption = n
|
||||||
u.URL = RegexReplace(r, Regex_VideosThumb_OG_IMAGE)
|
u.URL = RegexReplace(r, Regex_VideosThumb_OG_IMAGE)
|
||||||
|
If u.URL.IsEmptyString And Not repeat And ii = 0 Then
|
||||||
|
Thread.Sleep(250)
|
||||||
|
u = _TempMediaList(i)
|
||||||
|
repeat = True
|
||||||
|
Continue For
|
||||||
|
End If
|
||||||
If u.URL.IsEmptyString Then u.URL = RegexReplace(r, RegExVideosThumb1)
|
If u.URL.IsEmptyString Then u.URL = RegexReplace(r, RegExVideosThumb1)
|
||||||
If u.URL.IsEmptyString Then u.URL = RegexReplace(r, RegExVideosThumb2)
|
If u.URL.IsEmptyString Then u.URL = RegexReplace(r, RegExVideosThumb2)
|
||||||
If Not u.URL.IsEmptyString Then
|
If Not u.URL.IsEmptyString Then
|
||||||
@@ -502,6 +502,8 @@ Namespace API.ThisVid
|
|||||||
_TempMediaList.RemoveAt(i)
|
_TempMediaList.RemoveAt(i)
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
|
If Not repeat Then Exit For
|
||||||
|
Next
|
||||||
Else
|
Else
|
||||||
_TempMediaList.RemoveAt(i)
|
_TempMediaList.RemoveAt(i)
|
||||||
End If
|
End If
|
||||||
|
|||||||
@@ -6,9 +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 SCrawler.API.Base
|
||||||
Imports SCrawler.Plugin.Attributes
|
Imports SCrawler.Plugin.Attributes
|
||||||
Namespace API.ThisVid
|
Namespace API.ThisVid
|
||||||
Friend Class UserExchangeOptions : Inherits Xhamster.UserExchangeOptions
|
Friend Class UserExchangeOptions : Inherits EditorExchangeOptionsBase_P
|
||||||
<PSetting(Caption:="Download public videos")>
|
<PSetting(Caption:="Download public videos")>
|
||||||
Friend Property DownloadPublic As Boolean = True
|
Friend Property DownloadPublic As Boolean = True
|
||||||
<PSetting(Caption:="Download private videos")>
|
<PSetting(Caption:="Download private videos")>
|
||||||
@@ -19,6 +20,7 @@ Namespace API.ThisVid
|
|||||||
Friend Property DifferentFolders As Boolean = True
|
Friend Property DifferentFolders As Boolean = True
|
||||||
Private ReadOnly Property MySettings As SiteSettings
|
Private ReadOnly Property MySettings As SiteSettings
|
||||||
Friend Sub New(ByVal s As SiteSettings)
|
Friend Sub New(ByVal s As SiteSettings)
|
||||||
|
MyBase.New(s)
|
||||||
DownloadPublic = s.DownloadPublic.Value
|
DownloadPublic = s.DownloadPublic.Value
|
||||||
DownloadPrivate = s.DownloadPrivate.Value
|
DownloadPrivate = s.DownloadPrivate.Value
|
||||||
DownloadFavourite = s.DownloadFavourite.Value
|
DownloadFavourite = s.DownloadFavourite.Value
|
||||||
@@ -26,12 +28,21 @@ Namespace API.ThisVid
|
|||||||
MySettings = s
|
MySettings = s
|
||||||
End Sub
|
End Sub
|
||||||
Friend Sub New(ByVal u As UserData)
|
Friend Sub New(ByVal u As UserData)
|
||||||
|
MyBase.New(u)
|
||||||
DownloadPublic = u.DownloadPublic
|
DownloadPublic = u.DownloadPublic
|
||||||
DownloadPrivate = u.DownloadPrivate
|
DownloadPrivate = u.DownloadPrivate
|
||||||
DownloadFavourite = u.DownloadFavourite
|
DownloadFavourite = u.DownloadFavourite
|
||||||
DifferentFolders = u.DifferentFolders
|
DifferentFolders = u.DifferentFolders
|
||||||
QueryString = u.QueryString
|
|
||||||
MySettings = u.HOST.Source
|
MySettings = u.HOST.Source
|
||||||
End Sub
|
End Sub
|
||||||
|
Friend Overrides Sub Apply(ByRef u As IPSite)
|
||||||
|
MyBase.Apply(u)
|
||||||
|
With DirectCast(u, UserData)
|
||||||
|
.DownloadPublic = DownloadPublic
|
||||||
|
.DownloadPrivate = DownloadPrivate
|
||||||
|
.DownloadFavourite = DownloadFavourite
|
||||||
|
.DifferentFolders = DifferentFolders
|
||||||
|
End With
|
||||||
|
End Sub
|
||||||
End Class
|
End Class
|
||||||
End Namespace
|
End Namespace
|
||||||
@@ -15,7 +15,7 @@ Imports PersonalUtilities.Functions.RegularExpressions
|
|||||||
Imports IG = SCrawler.API.Instagram.SiteSettings
|
Imports IG = SCrawler.API.Instagram.SiteSettings
|
||||||
Imports DN = SCrawler.API.Base.DeclaredNames
|
Imports DN = SCrawler.API.Base.DeclaredNames
|
||||||
Namespace API.ThreadsNet
|
Namespace API.ThreadsNet
|
||||||
<Manifest("AndyProgram_ThreadsNet"), SavedPosts, SeparatedTasks(1)>
|
<Manifest("AndyProgram_ThreadsNet"), SavedPosts, SeparatedTasks(1), SpecialForm(False)>
|
||||||
Friend Class SiteSettings : Inherits SiteSettingsBase
|
Friend Class SiteSettings : Inherits SiteSettingsBase
|
||||||
#Region "Declarations"
|
#Region "Declarations"
|
||||||
#Region "Authorization"
|
#Region "Authorization"
|
||||||
@@ -89,7 +89,7 @@ Namespace API.ThreadsNet
|
|||||||
#End Region
|
#End Region
|
||||||
#Region "Initializer"
|
#Region "Initializer"
|
||||||
Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean)
|
Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean)
|
||||||
Me.New("Threads", "threads.net", AccName, Temp, My.Resources.SiteResources.ThreadsIcon_192, My.Resources.SiteResources.ThreadsIcon_192.ToBitmap)
|
Me.New("Threads", "threads.com", AccName, Temp, My.Resources.SiteResources.ThreadsIcon_192, My.Resources.SiteResources.ThreadsIcon_192.ToBitmap)
|
||||||
End Sub
|
End Sub
|
||||||
Protected Sub New(ByVal SiteName As String, ByVal CookiesDomain As String, ByVal AccName As String, ByVal Temp As Boolean,
|
Protected Sub New(ByVal SiteName As String, ByVal CookiesDomain As String, ByVal AccName As String, ByVal Temp As Boolean,
|
||||||
Optional ByVal __Icon As Icon = Nothing, Optional ByVal __Image As Image = Nothing)
|
Optional ByVal __Icon As Icon = Nothing, Optional ByVal __Image As Image = Nothing)
|
||||||
@@ -118,8 +118,8 @@ Namespace API.ThreadsNet
|
|||||||
browserExt = .Value(IG.Header_BrowserExt)
|
browserExt = .Value(IG.Header_BrowserExt)
|
||||||
platform = .Value(IG.Header_Platform_Verion)
|
platform = .Value(IG.Header_Platform_Verion)
|
||||||
End If
|
End If
|
||||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.Authority, "www.threads.net"))
|
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.Authority, "www.threads.com"))
|
||||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.Origin, "https://www.threads.net"))
|
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.Origin, "https://www.threads.com"))
|
||||||
.Add("Upgrade-Insecure-Requests", 1)
|
.Add("Upgrade-Insecure-Requests", 1)
|
||||||
.Add("Sec-Ch-Ua-Model", "")
|
.Add("Sec-Ch-Ua-Model", "")
|
||||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecChUaMobile, "?0"))
|
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecChUaMobile, "?0"))
|
||||||
@@ -152,9 +152,10 @@ Namespace API.ThreadsNet
|
|||||||
RequestsWaitTimer_AnyProvider = New IG.TimersChecker(0)
|
RequestsWaitTimer_AnyProvider = New IG.TimersChecker(0)
|
||||||
DownloadData_Impl = New PropertyValue(True)
|
DownloadData_Impl = New PropertyValue(True)
|
||||||
|
|
||||||
UrlPatternUser = "https://www.threads.net/@{0}"
|
UrlPatternUser = "https://www.threads.com/@{0}"
|
||||||
UserRegex = RParams.DMS(String.Format(UserRegexDefaultPattern, "threads.net/@"), 1)
|
UserRegex = RParams.DMS(String.Format(UserRegexDefaultPattern, "threads.(net|com)/@"), 2)
|
||||||
ImageVideoContains = "threads.net"
|
ImageVideoContains = "threads.com"
|
||||||
|
UserOptionsType = GetType(EditorExchangeOptionsBase)
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "UpdateResponserData"
|
#Region "UpdateResponserData"
|
||||||
@@ -180,14 +181,11 @@ Namespace API.ThreadsNet
|
|||||||
Friend Overrides Function BaseAuthExists() As Boolean
|
Friend Overrides Function BaseAuthExists() As Boolean
|
||||||
Return Responser.CookiesExists And {HH_CSRF_TOKEN, HH_IG_APP_ID}.All(Function(v) ACheck(Of String)(v.Value)) And CBool(DownloadData_Impl.Value)
|
Return Responser.CookiesExists And {HH_CSRF_TOKEN, HH_IG_APP_ID}.All(Function(v) ACheck(Of String)(v.Value)) And CBool(DownloadData_Impl.Value)
|
||||||
End Function
|
End Function
|
||||||
Friend Overrides Function GetUserUrl(ByVal User As IPluginContentProvider) As String
|
|
||||||
Return String.Format(UrlPatternUser, DirectCast(User, UserData).NameTrue)
|
|
||||||
End Function
|
|
||||||
Friend Overrides Function GetUserPostUrl(ByVal User As UserDataBase, ByVal Media As UserMedia) As String
|
Friend Overrides Function GetUserPostUrl(ByVal User As UserDataBase, ByVal Media As UserMedia) As String
|
||||||
Try
|
Try
|
||||||
Dim code$ = DirectCast(User, UserData).GetPostCodeById(Media.Post.ID)
|
Dim code$ = DirectCast(User, UserData).GetPostCodeById(Media.Post.ID)
|
||||||
Dim name$ = DirectCast(User, UserData).NameTrue
|
Dim name$ = DirectCast(User, UserData).NameTrue
|
||||||
If Not code.IsEmptyString Then Return $"https://www.threads.net/@{name}/post/{code}/" Else Return String.Empty
|
If Not code.IsEmptyString Then Return $"https://www.threads.com/@{name}/post/{code}/" Else Return String.Empty
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
Return ErrorsDescriber.Execute(EDP.SendToLog, ex, "Can't open user's post", String.Empty)
|
Return ErrorsDescriber.Execute(EDP.SendToLog, ex, "Can't open user's post", String.Empty)
|
||||||
End Try
|
End Try
|
||||||
|
|||||||
@@ -7,6 +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
|
||||||
Imports System.Threading
|
Imports System.Threading
|
||||||
|
Imports SCrawler.Plugin
|
||||||
Imports SCrawler.API.Base
|
Imports SCrawler.API.Base
|
||||||
Imports SCrawler.API.YouTube.Objects
|
Imports SCrawler.API.YouTube.Objects
|
||||||
Imports PersonalUtilities.Functions.XML
|
Imports PersonalUtilities.Functions.XML
|
||||||
@@ -51,9 +52,10 @@ Namespace API.ThreadsNet
|
|||||||
#End Region
|
#End Region
|
||||||
#Region "Exchange"
|
#Region "Exchange"
|
||||||
Friend Overrides Function ExchangeOptionsGet() As Object
|
Friend Overrides Function ExchangeOptionsGet() As Object
|
||||||
Return Nothing
|
Return New EditorExchangeOptionsBase(Me)
|
||||||
End Function
|
End Function
|
||||||
Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object)
|
Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object)
|
||||||
|
If Not Obj Is Nothing AndAlso TypeOf Obj Is EditorExchangeOptionsBase Then DirectCast(Obj, EditorExchangeOptionsBase).ApplyBase(Me)
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Initializer"
|
#Region "Initializer"
|
||||||
@@ -61,7 +63,7 @@ Namespace API.ThreadsNet
|
|||||||
ObtainMedia_SetReelsFunc()
|
ObtainMedia_SetReelsFunc()
|
||||||
ObtainMedia_AllowAbstract = True
|
ObtainMedia_AllowAbstract = True
|
||||||
DefaultParser_ElemNode = DefaultParser_ElemNode_Default
|
DefaultParser_ElemNode = DefaultParser_ElemNode_Default
|
||||||
DefaultParser_PostUrlCreator = Function(post) $"https://www.threads.net/@{NameTrue}/post/{post.Code}"
|
DefaultParser_PostUrlCreator = Function(post) $"https://www.threads.com/@{NameTrue}/post/{post.Code}"
|
||||||
_ResponserAutoUpdateCookies = True
|
_ResponserAutoUpdateCookies = True
|
||||||
_ResponserAddResponseReceivedHandler = True
|
_ResponserAddResponseReceivedHandler = True
|
||||||
DefaultParser_Pinned = AddressOf IsPinnedPost
|
DefaultParser_Pinned = AddressOf IsPinnedPost
|
||||||
@@ -73,12 +75,13 @@ Namespace API.ThreadsNet
|
|||||||
End Sub
|
End Sub
|
||||||
Private Sub DisableDownload()
|
Private Sub DisableDownload()
|
||||||
MySettings.DownloadData_Impl.Value = False
|
MySettings.DownloadData_Impl.Value = False
|
||||||
MyMainLOG = $"{Site} downloading is disabled until you update your credentials"
|
LogError(Nothing, $"{Site} downloading is disabled until you update your credentials")
|
||||||
End Sub
|
End Sub
|
||||||
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
|
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
|
||||||
If CBool(MySettings.DownloadData_Impl.Value) Then
|
If CBool(MySettings.DownloadData_Impl.Value) Then
|
||||||
Dim errorFound As Boolean = False
|
Dim errorFound As Boolean = False
|
||||||
Try
|
Try
|
||||||
|
_IdChanged = False
|
||||||
Responser.Method = "POST"
|
Responser.Method = "POST"
|
||||||
LoadSavePostsKV(True)
|
LoadSavePostsKV(True)
|
||||||
ResetBaseTokens()
|
ResetBaseTokens()
|
||||||
@@ -103,9 +106,9 @@ Namespace API.ThreadsNet
|
|||||||
End If
|
End If
|
||||||
If IsSavedPosts Then
|
If IsSavedPosts Then
|
||||||
DefaultParser_ElemNode = {"node", "thread_items", 0, "post"}
|
DefaultParser_ElemNode = {"node", "thread_items", 0, "post"}
|
||||||
DownloadSavedPosts(String.Empty, Token)
|
DownloadSavedPosts(String.Empty, 0, Token)
|
||||||
Else
|
Else
|
||||||
DownloadData(String.Empty, Token)
|
DownloadData(String.Empty, 0, Token)
|
||||||
End If
|
End If
|
||||||
If _TempMediaList.Count > 0 Then FirstLoadingDone = True : setMaxPostDate.Invoke(_TempMediaList)
|
If _TempMediaList.Count > 0 Then FirstLoadingDone = True : setMaxPostDate.Invoke(_TempMediaList)
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
@@ -115,6 +118,7 @@ Namespace API.ThreadsNet
|
|||||||
Responser.Method = "POST"
|
Responser.Method = "POST"
|
||||||
UpdateResponser()
|
UpdateResponser()
|
||||||
MySettings.UpdateResponserData(Responser)
|
MySettings.UpdateResponserData(Responser)
|
||||||
|
ValidateExtension()
|
||||||
If Not errorFound Then LoadSavePostsKV(False)
|
If Not errorFound Then LoadSavePostsKV(False)
|
||||||
End Try
|
End Try
|
||||||
End If
|
End If
|
||||||
@@ -124,10 +128,13 @@ Namespace API.ThreadsNet
|
|||||||
If IsSavedPosts Then
|
If IsSavedPosts Then
|
||||||
Return False
|
Return False
|
||||||
Else
|
Else
|
||||||
|
With Items(Index).ItemF(DefaultParser_ElemNode)
|
||||||
|
Return .Value({"text_post_app_info", "pinned_post_info"}, "is_pinned_to_profile").FromXML(Of Boolean)(False)
|
||||||
If MaxLastDownDate.HasValue Then
|
If MaxLastDownDate.HasValue Then
|
||||||
Dim d As Date? = AConvert(Of Date)(Items(Index).ItemF(DefaultParser_ElemNode_Default).Value("taken_at"), UnixDate32Provider, Nothing)
|
Dim d As Date? = AConvert(Of Date)(.Value("taken_at"), UnixDate32Provider, Nothing)
|
||||||
If d.HasValue Then Return d.Value < MaxLastDownDate.Value
|
If d.HasValue Then Return d.Value <= MaxLastDownDate.Value
|
||||||
End If
|
End If
|
||||||
|
End With
|
||||||
Return Not FirstLoadingDone
|
Return Not FirstLoadingDone
|
||||||
End If
|
End If
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
@@ -150,12 +157,14 @@ Namespace API.ThreadsNet
|
|||||||
Responser.Headers.Add(IGS.Header_CSRF_TOKEN, csrf)
|
Responser.Headers.Add(IGS.Header_CSRF_TOKEN, csrf)
|
||||||
End If
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
Private Const GQL_Q As String = "https://www.threads.net/api/graphql?lsd={0}&fb_dtsg={1}&doc_id={2}&fb_api_req_friendly_name={3}&server_timestamps=true&variables={4}"
|
'Private Const GQL_Q As String = "https://www.threads.com/api/graphql?lsd={0}&fb_dtsg={1}&doc_id={2}&fb_api_req_friendly_name={3}&server_timestamps=true&variables={4}"
|
||||||
Private Const GQL_P_DOC_ID As String = "6371597506283707"
|
Private Const GQL_Q2 As String = "https://www.threads.com/graphql/query"
|
||||||
Private Const GQL_P_NAME As String = "BarcelonaProfileThreadsTabRefetchableQuery"
|
Private Const PayloadData As String = "lsd={0}&fb_dtsg={1}&doc_id={2}&fb_api_req_friendly_name={3}&server_timestamps=true&variables={4}"
|
||||||
Private Const GQL_S_DOC_ID_1 As String = "7758166704280174"
|
Private Const GQL_P_DOC_ID As String = "9039187972876777" '"8779269398849532" '"6371597506283707"
|
||||||
Private Const GQL_S_NAME_1 As String = "BarcelonaSavedPageViewerQuery"
|
Private Const GQL_P_NAME As String = "BarcelonaProfileThreadsTabRefetchableDirectQuery" '"BarcelonaProfileThreadsTabRefetchableQuery"
|
||||||
Private Const GQL_S_DOC_ID_2 As String = "8617275414954442"
|
'Private Const GQL_S_DOC_ID_1 As String = "9227844190587889" '"7758166704280174"
|
||||||
|
'Private Const GQL_S_NAME_1 As String = "BarcelonaSavedPageViewerQuery"
|
||||||
|
Private Const GQL_S_DOC_ID_2 As String = "9116629201788321" '"8617275414954442"
|
||||||
Private Const GQL_S_NAME_2 As String = "BarcelonaSavedPageRefetchableQuery"
|
Private Const GQL_S_NAME_2 As String = "BarcelonaSavedPageRefetchableQuery"
|
||||||
Private Sub DownloadCheckCredentials()
|
Private Sub DownloadCheckCredentials()
|
||||||
If Not Valid Then
|
If Not Valid Then
|
||||||
@@ -165,32 +174,79 @@ Namespace API.ThreadsNet
|
|||||||
End If
|
End If
|
||||||
If Not Valid Then DisableDownload() : Throw New Plugin.ExitException("Some credentials are missing")
|
If Not Valid Then DisableDownload() : Throw New Plugin.ExitException("Some credentials are missing")
|
||||||
End Sub
|
End Sub
|
||||||
Private Overloads Sub DownloadData(ByVal Cursor As String, ByVal Token As CancellationToken)
|
Private Function CheckErrors(ByVal e As EContainer) As Boolean
|
||||||
Const var_init$ = """userID"":""{0}"""
|
Return e.ListExists AndAlso Not JsonErrorMessage(e).IsEmptyString
|
||||||
Const var_cursor$ = """after"":""{1}"",""before"":null,""first"":25,""last"":null,""userID"":""{0}"",""__relay_internal__pv__BarcelonaIsLoggedInrelayprovider"":true,""__relay_internal__pv__BarcelonaIsFeedbackHubEnabledrelayprovider"":false"
|
End Function
|
||||||
Dim URL$ = String.Empty
|
Private Function JsonErrorMessage(ByVal e As EContainer) As String
|
||||||
|
Return e.ItemF({"errors", 0, "summary"})?.Value
|
||||||
|
End Function
|
||||||
|
Private Sub ProcessJsonErrorException(ByVal uex As JsonErrorException, Optional ByVal ThrowEx As Boolean = True)
|
||||||
|
If uex.UserNotFound Then
|
||||||
|
UserExists = False
|
||||||
|
_ForceSaveUserInfo = True
|
||||||
|
_ForceSaveUserInfoOnException = True
|
||||||
|
ElseIf ThrowEx Then
|
||||||
|
Throw New ExitException(uex.ErrMessage) With {.SimpleLogLine = True}
|
||||||
|
Else
|
||||||
|
LogError(Nothing, uex.ErrMessage)
|
||||||
|
End If
|
||||||
|
End Sub
|
||||||
|
Private Class JsonErrorException : Inherits Exception
|
||||||
|
Friend Property UserNotFound As Boolean = False
|
||||||
|
Private _ErrMessage As String = String.Empty
|
||||||
|
Public Property ErrMessage As String
|
||||||
|
Get
|
||||||
|
Return _ErrMessage
|
||||||
|
End Get
|
||||||
|
Set(ByVal m As String)
|
||||||
|
_ErrMessage = m
|
||||||
|
UserNotFound = _ErrMessage.StringToLower = "not found"
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
Public Overrides ReadOnly Property Message As String
|
||||||
|
Get
|
||||||
|
Return _ErrMessage
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
Friend Sub New()
|
||||||
|
End Sub
|
||||||
|
Friend Sub New(ByVal Message As String)
|
||||||
|
ErrMessage = Message
|
||||||
|
End Sub
|
||||||
|
End Class
|
||||||
|
Private Overloads Sub DownloadData(ByVal Cursor As String, ByVal Round As Integer, ByVal Token As CancellationToken)
|
||||||
|
'Const var_init$ = """userID"":""{0}"""
|
||||||
|
'Const var_cursor$ = """after"":""{1}"",""before"":null,""first"":25,""last"":null,""userID"":""{0}"",""__relay_internal__pv__BarcelonaIsLoggedInrelayprovider"":true,""__relay_internal__pv__BarcelonaIsFeedbackHubEnabledrelayprovider"":false"
|
||||||
|
Const var_cursor2$ = """after"":{1},""before"":null,""first"":10,""last"":null,""userID"":""{0}"",""__relay_internal__pv__BarcelonaIsLoggedInrelayprovider"":true,""__relay_internal__pv__BarcelonaHasSelfReplyContextrelayprovider"":false,""__relay_internal__pv__BarcelonaShareableListsrelayprovider"":true,""__relay_internal__pv__BarcelonaIsSearchDiscoveryEnabledrelayprovider"":false,""__relay_internal__pv__BarcelonaOptionalCookiesEnabledrelayprovider"":true,""__relay_internal__pv__BarcelonaQuotedPostUFIEnabledrelayprovider"":false,""__relay_internal__pv__BarcelonaIsCrawlerrelayprovider"":false,""__relay_internal__pv__BarcelonaHasDisplayNamesrelayprovider"":false,""__relay_internal__pv__BarcelonaCanSeeSponsoredContentrelayprovider"":false,""__relay_internal__pv__BarcelonaShouldShowFediverseM075Featuresrelayprovider"":true,""__relay_internal__pv__BarcelonaShouldShowTagRedesignrelayprovider"":false,""__relay_internal__pv__BarcelonaIsInternalUserrelayprovider"":false"
|
||||||
Try
|
Try
|
||||||
DownloadCheckCredentials()
|
DownloadCheckCredentials()
|
||||||
|
|
||||||
Responser.Method = "POST"
|
With Responser
|
||||||
Responser.Referer = $"https://www.threads.net/@{NameTrue}"
|
.Method = "POST"
|
||||||
Responser.Headers.Add(GQL_HEADER_FB_LSD, Token_lsd)
|
.Referer = $"https://www.threads.com/@{NameTrue}"
|
||||||
Responser.Headers.Add(GQL_HEADER_FB_FRINDLY_NAME, GQL_P_NAME)
|
.ContentType = "application/x-www-form-urlencoded"
|
||||||
|
With .Headers
|
||||||
|
.Add(GQL_HEADER_FB_LSD, Token_lsd)
|
||||||
|
.Add(GQL_HEADER_FB_FRINDLY_NAME, GQL_P_NAME)
|
||||||
|
End With
|
||||||
|
End With
|
||||||
|
|
||||||
Dim nextCursor$ = String.Empty
|
Dim nextCursor$ = String.Empty
|
||||||
Dim dataFound As Boolean = False
|
Dim dataFound As Boolean = False
|
||||||
|
|
||||||
Dim vars$
|
Dim vars$ = String.Format(var_cursor2, ID, IIf(Cursor.IsEmptyString, "null", $"""{Cursor}"""))
|
||||||
If Cursor.IsEmptyString Then
|
'If Cursor.IsEmptyString Then
|
||||||
vars = String.Format(var_init, ID)
|
' vars = String.Format(var_init, ID)
|
||||||
Else
|
'Else
|
||||||
vars = String.Format(var_cursor, ID, Cursor)
|
' vars = String.Format(var_cursor, ID, Cursor)
|
||||||
End If
|
'End If
|
||||||
vars = SymbolsConverter.ASCII.EncodeSymbolsOnly("{" & vars & "}")
|
vars = String.Format(PayloadData, Token_lsd, Token_dtsg_Var, GQL_P_DOC_ID, GQL_P_NAME,
|
||||||
|
SymbolsConverter.ASCII.EncodeSymbolsOnly("{" & vars & "}"))
|
||||||
|
|
||||||
URL = String.Format(GQL_Q, Token_lsd, Token_dtsg_Var, GQL_P_DOC_ID, GQL_P_NAME, vars)
|
'URL = String.Format(GQL_Q, Token_lsd, Token_dtsg_Var, GQL_P_DOC_ID, GQL_P_NAME, vars)
|
||||||
|
|
||||||
Using j As EContainer = GetDocument(URL, Token)
|
Using j As EContainer = GetDocument(GQL_Q2, vars, Token)
|
||||||
|
If Not CheckErrors(j) Then
|
||||||
If j.ListExists Then
|
If j.ListExists Then
|
||||||
With j({"data", "mediaData"})
|
With j({"data", "mediaData"})
|
||||||
If .ListExists Then
|
If .ListExists Then
|
||||||
@@ -201,39 +257,61 @@ Namespace API.ThreadsNet
|
|||||||
End If
|
End If
|
||||||
End With
|
End With
|
||||||
End If
|
End If
|
||||||
|
Else
|
||||||
|
Throw New JsonErrorException(JsonErrorMessage(j))
|
||||||
|
End If
|
||||||
End Using
|
End Using
|
||||||
|
|
||||||
If dataFound And Not nextCursor.IsEmptyString Then DownloadData(nextCursor, Token)
|
If dataFound And Not nextCursor.IsEmptyString Then DownloadData(nextCursor, 0, Token)
|
||||||
|
Catch uex As JsonErrorException
|
||||||
|
If Round > 0 Then
|
||||||
|
ProcessJsonErrorException(uex)
|
||||||
|
ElseIf Not _IdChanged AndAlso UpdateCredentials() Then
|
||||||
|
DownloadData(Cursor, Round + 1, Token)
|
||||||
|
Else
|
||||||
|
ProcessJsonErrorException(uex)
|
||||||
|
End If
|
||||||
|
Catch eex As ExitException
|
||||||
|
Throw eex
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
ProcessException(ex, Token, $"data downloading error [{URL}]")
|
ProcessException(ex, Token, "data downloading error")
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
Private Sub DownloadSavedPosts(ByVal Cursor As String, ByVal Token As CancellationToken)
|
Private Sub DownloadSavedPosts(ByVal Cursor As String, ByVal Round As Integer, ByVal Token As CancellationToken)
|
||||||
Const var_init$ = """__relay_internal__pv__BarcelonaIsLoggedInrelayprovider"":true,""__relay_internal__pv__BarcelonaIsInlineReelsEnabledrelayprovider"":false,""__relay_internal__pv__BarcelonaUseCometVideoPlaybackEnginerelayprovider"":false,""__relay_internal__pv__BarcelonaOptionalCookiesEnabledrelayprovider"":true,""__relay_internal__pv__BarcelonaIsTextFragmentsEnabledForPostCaptionsrelayprovider"":true,""__relay_internal__pv__BarcelonaShouldShowFediverseM075Featuresrelayprovider"":true"
|
'Const var_init$ = """__relay_internal__pv__BarcelonaIsLoggedInrelayprovider"":true,""__relay_internal__pv__BarcelonaIsInlineReelsEnabledrelayprovider"":false,""__relay_internal__pv__BarcelonaUseCometVideoPlaybackEnginerelayprovider"":false,""__relay_internal__pv__BarcelonaOptionalCookiesEnabledrelayprovider"":true,""__relay_internal__pv__BarcelonaIsTextFragmentsEnabledForPostCaptionsrelayprovider"":true,""__relay_internal__pv__BarcelonaShouldShowFediverseM075Featuresrelayprovider"":true"
|
||||||
Const var_cursor$ = """after"":""{0}"",""first"":25,""__relay_internal__pv__BarcelonaIsLoggedInrelayprovider"":true,""__relay_internal__pv__BarcelonaIsInlineReelsEnabledrelayprovider"":false,""__relay_internal__pv__BarcelonaUseCometVideoPlaybackEnginerelayprovider"":false,""__relay_internal__pv__BarcelonaOptionalCookiesEnabledrelayprovider"":true,""__relay_internal__pv__BarcelonaIsTextFragmentsEnabledForPostCaptionsrelayprovider"":true,""__relay_internal__pv__BarcelonaShouldShowFediverseM075Featuresrelayprovider"":true"
|
'Const var_cursor$ = """after"":""{0}"",""first"":25,""__relay_internal__pv__BarcelonaIsLoggedInrelayprovider"":true,""__relay_internal__pv__BarcelonaIsInlineReelsEnabledrelayprovider"":false,""__relay_internal__pv__BarcelonaUseCometVideoPlaybackEnginerelayprovider"":false,""__relay_internal__pv__BarcelonaOptionalCookiesEnabledrelayprovider"":true,""__relay_internal__pv__BarcelonaIsTextFragmentsEnabledForPostCaptionsrelayprovider"":true,""__relay_internal__pv__BarcelonaShouldShowFediverseM075Featuresrelayprovider"":true"
|
||||||
Dim URL$ = String.Empty
|
Const var_cursor2$ = """after"":{0},""first"":25,""__relay_internal__pv__BarcelonaQuotedPostUFIEnabledrelayprovider"":false,""__relay_internal__pv__BarcelonaIsLoggedInrelayprovider"":true,""__relay_internal__pv__BarcelonaHasSelfReplyContextrelayprovider"":false,""__relay_internal__pv__BarcelonaShareableListsrelayprovider"":true,""__relay_internal__pv__BarcelonaIsSearchDiscoveryEnabledrelayprovider"":false,""__relay_internal__pv__BarcelonaOptionalCookiesEnabledrelayprovider"":true,""__relay_internal__pv__BarcelonaIsCrawlerrelayprovider"":false,""__relay_internal__pv__BarcelonaHasDisplayNamesrelayprovider"":false,""__relay_internal__pv__BarcelonaCanSeeSponsoredContentrelayprovider"":false,""__relay_internal__pv__BarcelonaShouldShowFediverseM075Featuresrelayprovider"":true,""__relay_internal__pv__BarcelonaShouldShowTagRedesignrelayprovider"":false,""__relay_internal__pv__BarcelonaIsInternalUserrelayprovider"":false"
|
||||||
Try
|
Try
|
||||||
DownloadCheckCredentials()
|
DownloadCheckCredentials()
|
||||||
|
|
||||||
Responser.Method = "POST"
|
With Responser
|
||||||
Responser.Referer = "https://www.threads.net/"
|
.Method = "POST"
|
||||||
Responser.Headers.Add(GQL_HEADER_FB_LSD, Token_lsd)
|
.Referer = "https://www.threads.com/"
|
||||||
Responser.Headers.Add(GQL_HEADER_FB_FRINDLY_NAME, If(Cursor.IsEmptyString, GQL_S_NAME_1, GQL_S_NAME_2))
|
.ContentType = "application/x-www-form-urlencoded"
|
||||||
|
With .Headers
|
||||||
|
.Add(GQL_HEADER_FB_LSD, Token_lsd)
|
||||||
|
'.Add(GQL_HEADER_FB_FRINDLY_NAME, If(Cursor.IsEmptyString, GQL_S_NAME_1, GQL_S_NAME_2))
|
||||||
|
.Add(GQL_HEADER_FB_FRINDLY_NAME, GQL_S_NAME_2)
|
||||||
|
End With
|
||||||
|
End With
|
||||||
|
|
||||||
Dim nextCursor$ = String.Empty
|
Dim nextCursor$ = String.Empty
|
||||||
Dim dataFound As Boolean = False
|
Dim dataFound As Boolean = False
|
||||||
|
|
||||||
Dim vars$ = SymbolsConverter.ASCII.EncodeSymbolsOnly("{" & If(Cursor.IsEmptyString, var_init, String.Format(var_cursor, Cursor)) & "}")
|
'Dim vars$ = SymbolsConverter.ASCII.EncodeSymbolsOnly("{" & If(Cursor.IsEmptyString, var_init, String.Format(var_cursor, Cursor)) & "}")
|
||||||
|
Dim vars$ = String.Format(PayloadData, Token_lsd, Token_dtsg_Var, GQL_S_DOC_ID_2, GQL_S_NAME_2,
|
||||||
|
SymbolsConverter.ASCII.EncodeSymbolsOnly("{" & String.Format(var_cursor2, IIf(Cursor.IsEmptyString, "null", $"""{Cursor}""")) & "}"))
|
||||||
|
|
||||||
If Cursor.IsEmptyString Then
|
'If Cursor.IsEmptyString Then
|
||||||
URL = String.Format(GQL_Q, Token_lsd, Token_dtsg_Var, GQL_S_DOC_ID_1, GQL_S_NAME_1, vars)
|
' URL = String.Format(GQL_Q, Token_lsd, Token_dtsg_Var, GQL_S_DOC_ID_1, GQL_S_NAME_1, vars)
|
||||||
Else
|
'Else
|
||||||
URL = String.Format(GQL_Q, Token_lsd, Token_dtsg_Var, GQL_S_DOC_ID_2, GQL_S_NAME_2, vars)
|
' URL = String.Format(GQL_Q, Token_lsd, Token_dtsg_Var, GQL_S_DOC_ID_2, GQL_S_NAME_2, vars)
|
||||||
End If
|
'End If
|
||||||
|
|
||||||
Using j As EContainer = GetDocument(URL, Token)
|
Using j As EContainer = GetDocument(GQL_Q2, vars, Token)
|
||||||
|
If Not CheckErrors(j) Then
|
||||||
If j.ListExists Then
|
If j.ListExists Then
|
||||||
With j({"data", "xdt_viewer", "text_app_saved_media"})
|
With j({"data", "xdt_text_app_viewer", "saved_media"})
|
||||||
If .ListExists Then
|
If .ListExists Then
|
||||||
nextCursor = .Value({"page_info"}, "end_cursor")
|
nextCursor = .Value({"page_info"}, "end_cursor")
|
||||||
With .Item({"edges"})
|
With .Item({"edges"})
|
||||||
@@ -242,31 +320,45 @@ Namespace API.ThreadsNet
|
|||||||
End If
|
End If
|
||||||
End With
|
End With
|
||||||
End If
|
End If
|
||||||
|
Else
|
||||||
|
Throw New JsonErrorException(JsonErrorMessage(j))
|
||||||
|
End If
|
||||||
End Using
|
End Using
|
||||||
|
|
||||||
If dataFound And Not nextCursor.IsEmptyString Then DownloadSavedPosts(nextCursor, Token)
|
If dataFound And Not nextCursor.IsEmptyString Then DownloadSavedPosts(nextCursor, 0, Token)
|
||||||
|
Catch uex As JsonErrorException
|
||||||
|
If Round > 0 Then
|
||||||
|
ProcessJsonErrorException(uex)
|
||||||
|
ElseIf Not _IdChanged AndAlso UpdateCredentials() Then
|
||||||
|
DownloadSavedPosts(Cursor, Round + 1, Token)
|
||||||
|
Else
|
||||||
|
ProcessJsonErrorException(uex)
|
||||||
|
End If
|
||||||
|
Catch eex As ExitException
|
||||||
|
Throw eex
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
ProcessException(ex, Token, $"saved posts downloading error [{URL}]")
|
ProcessException(ex, Token, "saved posts downloading error")
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
Private Function GetDocument(ByVal URL As String, ByVal Token As CancellationToken, Optional ByVal Round As Integer = 0) As EContainer
|
Private Function GetDocument(ByVal URL As String, ByVal PayLoad As String, ByVal Token As CancellationToken, Optional ByVal Round As Integer = 0) As EContainer
|
||||||
Try
|
Try
|
||||||
ThrowAny(Token)
|
ThrowAny(Token)
|
||||||
If Round > 0 AndAlso Not UpdateCredentials() Then DisableDownload() : Throw New Exception("Failed to update credentials")
|
If Round > 0 AndAlso Not UpdateCredentials() Then DisableDownload() : Throw New Exception("Failed to update credentials")
|
||||||
ThrowAny(Token)
|
ThrowAny(Token)
|
||||||
WaitTimer()
|
WaitTimer()
|
||||||
Dim r$ = Responser.GetResponse(URL)
|
Dim r$ = Responser.GetResponse(URL, PayLoad)
|
||||||
If Not r.IsEmptyString Then Return JsonDocument.Parse(r) Else Throw New Exception("Failed to get a response")
|
If Not r.IsEmptyString Then Return JsonDocument.Parse(r) Else Throw New Exception("Failed to get a response")
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
If Round = 0 Then
|
If Round = 0 Then
|
||||||
Return GetDocument(URL, Token, Round + 1)
|
Return GetDocument(URL, PayLoad, Token, Round + 1)
|
||||||
Else
|
Else
|
||||||
Throw ex
|
Throw ex
|
||||||
End If
|
End If
|
||||||
End Try
|
End Try
|
||||||
End Function
|
End Function
|
||||||
|
Private _IdChanged As Boolean = False
|
||||||
Private Function UpdateCredentials(Optional ByVal e As ErrorsDescriber = Nothing) As Boolean
|
Private Function UpdateCredentials(Optional ByVal e As ErrorsDescriber = Nothing) As Boolean
|
||||||
Dim URL$ = If(IsSavedPosts, "https://www.threads.net/", $"https://www.threads.net/@{NameTrue}")
|
Dim URL$ = If(IsSavedPosts, "https://www.threads.com/", $"https://www.threads.com/@{NameTrue}")
|
||||||
ResetBaseTokens()
|
ResetBaseTokens()
|
||||||
Dim headers As New HttpHeaderCollection
|
Dim headers As New HttpHeaderCollection
|
||||||
headers.AddRange(Responser.Headers)
|
headers.AddRange(Responser.Headers)
|
||||||
@@ -277,8 +369,8 @@ Namespace API.ThreadsNet
|
|||||||
With .Headers
|
With .Headers
|
||||||
.Clear()
|
.Clear()
|
||||||
.Add("dnt", 1)
|
.Add("dnt", 1)
|
||||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.Authority, "www.threads.net"))
|
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.Authority, "www.threads.com"))
|
||||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.Origin, "https://www.threads.net"))
|
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.Origin, "https://www.threads.com"))
|
||||||
.Add("Sec-Ch-Ua-Model", "")
|
.Add("Sec-Ch-Ua-Model", "")
|
||||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecChUaMobile, "?0"))
|
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecChUaMobile, "?0"))
|
||||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecChUaPlatform, """Windows"""))
|
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecChUaPlatform, """Windows"""))
|
||||||
@@ -293,9 +385,25 @@ Namespace API.ThreadsNet
|
|||||||
End With
|
End With
|
||||||
WaitTimer()
|
WaitTimer()
|
||||||
Dim r$ = Responser.GetResponse(URL,, EDP.ThrowException)
|
Dim r$ = Responser.GetResponse(URL,, EDP.ThrowException)
|
||||||
|
Dim newID$
|
||||||
|
Dim idStr$ = String.Empty
|
||||||
If Not r.IsEmptyString Then
|
If Not r.IsEmptyString Then
|
||||||
ParseTokens(r, 0)
|
ParseTokens(r, 0)
|
||||||
If ID.IsEmptyString Then ID = RegexReplace(r, RParams.DMS("""props"":\{""user_id"":""(\d+)""", 1, EDP.ReturnValue))
|
newID = RegexReplace(r, RParams.DMS("""props"":\{[^\{\}]*?""user_id"":""(\d+)""", 1, EDP.ReturnValue))
|
||||||
|
If ID.IsEmptyString OrElse ID = newID Then
|
||||||
|
_IdChanged = ID.IsEmptyString
|
||||||
|
ID = newID
|
||||||
|
Else
|
||||||
|
_IdChanged = True
|
||||||
|
idStr = $"user ID changed from {ID} to {newID}"
|
||||||
|
LogError(Nothing, idStr)
|
||||||
|
ID = newID
|
||||||
|
End If
|
||||||
|
If _IdChanged Then
|
||||||
|
If Not idStr.IsEmptyString Then UserDescriptionUpdate(idStr, True, True, True)
|
||||||
|
_ForceSaveUserInfo = True
|
||||||
|
_ForceSaveUserInfoOnException = True
|
||||||
|
End If
|
||||||
End If
|
End If
|
||||||
Return Valid
|
Return Valid
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
@@ -321,20 +429,22 @@ Namespace API.ThreadsNet
|
|||||||
#End Region
|
#End Region
|
||||||
#Region "ReparseMissing"
|
#Region "ReparseMissing"
|
||||||
Protected Overrides Sub ReparseMissing(ByVal Token As CancellationToken)
|
Protected Overrides Sub ReparseMissing(ByVal Token As CancellationToken)
|
||||||
Const varsPattern$ = """postID"":""{0}"",""userID"":""{1}"",""__relay_internal__pv__BarcelonaIsLoggedInrelayprovider"":true,""__relay_internal__pv__BarcelonaIsFeedbackHubEnabledrelayprovider"":false"
|
'Const varsPattern$ = """postID"":""{0}"",""userID"":""{1}"",""__relay_internal__pv__BarcelonaIsLoggedInrelayprovider"":true,""__relay_internal__pv__BarcelonaIsFeedbackHubEnabledrelayprovider"":false"
|
||||||
|
Const varsPattern$ = """postID"":""{0}"",""__relay_internal__pv__BarcelonaIsLoggedInrelayprovider"":true,""__relay_internal__pv__BarcelonaShouldShowFediverseM1Featuresrelayprovider"":true,""__relay_internal__pv__BarcelonaShareableListsrelayprovider"":true,""__relay_internal__pv__BarcelonaIsSearchDiscoveryEnabledrelayprovider"":false,""__relay_internal__pv__BarcelonaOptionalCookiesEnabledrelayprovider"":true,""__relay_internal__pv__BarcelonaQuotedPostUFIEnabledrelayprovider"":false,""__relay_internal__pv__BarcelonaIsCrawlerrelayprovider"":false,""__relay_internal__pv__BarcelonaHasDisplayNamesrelayprovider"":false,""__relay_internal__pv__BarcelonaCanSeeSponsoredContentrelayprovider"":false,""__relay_internal__pv__BarcelonaShouldShowFediverseM075Featuresrelayprovider"":true,""__relay_internal__pv__BarcelonaShouldShowTagRedesignrelayprovider"":false,""__relay_internal__pv__BarcelonaIsInternalUserrelayprovider"":false,""__relay_internal__pv__BarcelonaInlineComposerEnabledrelayprovider"":false"
|
||||||
'Const varsPattern$ = "{""postID"":""{0}"",""__relay_internal__pv__BarcelonaIsLoggedInrelayprovider"":true,""__relay_internal__pv__BarcelonaIsFeedbackHubEnabledrelayprovider"":false}"
|
'Const varsPattern$ = "{""postID"":""{0}"",""__relay_internal__pv__BarcelonaIsLoggedInrelayprovider"":true,""__relay_internal__pv__BarcelonaIsFeedbackHubEnabledrelayprovider"":false}"
|
||||||
Const urlPattern$ = "https://www.threads.net/api/graphql?lsd={0}&variables={1}&fb_api_req_friendly_name=BarcelonaPostPageQuery&server_timestamps=true&fb_dtsg={2}&doc_id=25460088156920903"
|
'Const urlPattern$ = "https://www.threads.com/api/graphql?lsd={0}&variables={1}&fb_api_req_friendly_name=BarcelonaPostPageQuery&server_timestamps=true&fb_dtsg={2}&doc_id=25460088156920903"
|
||||||
Dim rList As New List(Of Integer)
|
Dim rList As New List(Of Integer)
|
||||||
Dim URL$ = String.Empty
|
|
||||||
DefaultParser_ElemNode = Nothing
|
DefaultParser_ElemNode = Nothing
|
||||||
DefaultParser_IgnorePass = True
|
DefaultParser_IgnorePass = True
|
||||||
Try
|
Try
|
||||||
If ContentMissingExists Then
|
If ContentMissingExists Then
|
||||||
Responser.Method = "POST"
|
Responser.Method = "POST"
|
||||||
Responser.Referer = $"https://www.threads.net/@{NameTrue}"
|
Responser.ContentType = "application/x-www-form-urlencoded"
|
||||||
|
Responser.Referer = $"https://www.threads.com/@{NameTrue}"
|
||||||
If Not IsSingleObjectDownload AndAlso Not UpdateCredentials() Then Throw New Exception("Failed to update credentials")
|
If Not IsSingleObjectDownload AndAlso Not UpdateCredentials() Then Throw New Exception("Failed to update credentials")
|
||||||
Dim m As UserMedia
|
Dim m As UserMedia
|
||||||
Dim vars$
|
Dim vars$
|
||||||
|
Dim r As Byte
|
||||||
Dim j As EContainer
|
Dim j As EContainer
|
||||||
ProgressPre.ChangeMax(_ContentList.Count)
|
ProgressPre.ChangeMax(_ContentList.Count)
|
||||||
For i% = 0 To _ContentList.Count - 1
|
For i% = 0 To _ContentList.Count - 1
|
||||||
@@ -342,21 +452,39 @@ Namespace API.ThreadsNet
|
|||||||
m = _ContentList(i)
|
m = _ContentList(i)
|
||||||
If m.State = UserMedia.States.Missing And Not m.Post.ID.IsEmptyString Then
|
If m.State = UserMedia.States.Missing And Not m.Post.ID.IsEmptyString Then
|
||||||
ThrowAny(Token)
|
ThrowAny(Token)
|
||||||
vars = SymbolsConverter.ASCII.EncodeSymbolsOnly("{" & String.Format(varsPattern, m.Post.ID.Split("_").FirstOrDefault, ID) & "}")
|
'vars = SymbolsConverter.ASCII.EncodeSymbolsOnly("{" & String.Format(varsPattern, m.Post.ID.Split("_").FirstOrDefault, ID) & "}")
|
||||||
URL = String.Format(urlPattern, Token_lsd, vars, Token_dtsg_Var)
|
'URL = String.Format(urlPattern, Token_lsd, vars, Token_dtsg_Var)
|
||||||
|
|
||||||
j = GetDocument(URL, Token)
|
vars = String.Format(PayloadData, Token_lsd, Token_dtsg_Var, "9094233770675261", "BarcelonaPostPageDirectQuery",
|
||||||
|
SymbolsConverter.ASCII.EncodeSymbolsOnly("{" & String.Format(varsPattern, m.Post.ID) & "}"))
|
||||||
|
|
||||||
|
For r = 0 To 1
|
||||||
|
j = GetDocument(GQL_Q2, vars, Token)
|
||||||
|
If Not CheckErrors(j) Then
|
||||||
If j.ListExists Then
|
If j.ListExists Then
|
||||||
With j.ItemF({"data", "data", "edges", 0, "node", "thread_items", 0, "post"})
|
With j.ItemF({"data", "data", "edges", 0, "node", "thread_items", 0, "post"})
|
||||||
If .ListExists AndAlso DefaultParser({ .Self}, Sections.Timeline, Token) Then rList.Add(i)
|
If .ListExists AndAlso DefaultParser({ .Self}, Sections.Timeline, Token) Then rList.Add(i)
|
||||||
End With
|
End With
|
||||||
j.Dispose()
|
j.Dispose()
|
||||||
End If
|
End If
|
||||||
|
Else
|
||||||
|
j.DisposeIfReady(False)
|
||||||
|
If r > 0 Then
|
||||||
|
ProcessJsonErrorException(New JsonErrorException(JsonErrorMessage(j)))
|
||||||
|
ElseIf Not _IdChanged AndAlso UpdateCredentials() Then
|
||||||
|
Continue For
|
||||||
|
Else
|
||||||
|
ProcessJsonErrorException(New JsonErrorException(JsonErrorMessage(j)))
|
||||||
|
End If
|
||||||
End If
|
End If
|
||||||
Next
|
Next
|
||||||
End If
|
End If
|
||||||
|
Next
|
||||||
|
End If
|
||||||
|
Catch eex As ExitException
|
||||||
|
Throw eex
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
ProcessException(ex, Token, $"ReparseMissing error [{URL}]")
|
ProcessException(ex, Token, "reparseMissing error")
|
||||||
Finally
|
Finally
|
||||||
DefaultParser_ElemNode = DefaultParser_ElemNode_Default
|
DefaultParser_ElemNode = DefaultParser_ElemNode_Default
|
||||||
DefaultParser_IgnorePass = False
|
DefaultParser_IgnorePass = False
|
||||||
@@ -374,9 +502,9 @@ Namespace API.ThreadsNet
|
|||||||
If Not postCode.IsEmptyString Then
|
If Not postCode.IsEmptyString Then
|
||||||
Dim postId$ = CodeToID(postCode)
|
Dim postId$ = CodeToID(postCode)
|
||||||
If Not postId.IsEmptyString Then
|
If Not postId.IsEmptyString Then
|
||||||
_NameTrue = MySettings.IsMyUser(url).UserName
|
NameTrue = MySettings.IsMyUser(url).UserName
|
||||||
DefaultParser_PostUrlCreator = Function(post) url
|
DefaultParser_PostUrlCreator = Function(post) url
|
||||||
If Not _NameTrue.IsEmptyString AndAlso UpdateCredentials(EDP.ReturnValue) Then
|
If Not NameTrue(True).IsEmptyString AndAlso UpdateCredentials(EDP.ReturnValue) Then
|
||||||
_ContentList.Add(New UserMedia(url) With {.State = UserMedia.States.Missing, .Post = postId})
|
_ContentList.Add(New UserMedia(url) With {.State = UserMedia.States.Missing, .Post = postId})
|
||||||
ReparseMissing(Token)
|
ReparseMissing(Token)
|
||||||
End If
|
End If
|
||||||
|
|||||||
@@ -6,11 +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.Text.RegularExpressions
|
||||||
Imports PersonalUtilities.Functions.RegularExpressions
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
Namespace API.TikTok
|
Namespace API.TikTok
|
||||||
Friend Module Declarations
|
Friend Module Declarations
|
||||||
Friend ReadOnly SimpleDateConverter As New ADateTime("yyyyMMdd")
|
Friend ReadOnly SimpleDateConverter As New ADateTime("yyyyMMdd")
|
||||||
Friend ReadOnly RegexTagsReplacer As RParams = RParams.DM("#\w+\s?", -1, RegexReturn.Replace,
|
Friend ReadOnly RegexTagsReplacer As RParams = RParams.DM("#\w+\s?", -1, RegexReturn.Replace,
|
||||||
CType(Function(input$) String.Empty, Func(Of String, String)), EDP.ReturnValue)
|
CType(Function(input$) String.Empty, Func(Of String, String)), EDP.ReturnValue)
|
||||||
|
Friend ReadOnly RegexPhotoJson As RParams = RParams.DMS("UNIVERSAL_DATA_FOR_REHYDRATION__"" type=""application/json""\>([^\<]+)\<", 1,
|
||||||
|
RegexOptions.IgnoreCase, EDP.ReturnValue)
|
||||||
End Module
|
End Module
|
||||||
End Namespace
|
End Namespace
|
||||||
@@ -13,6 +13,15 @@ Imports PersonalUtilities.Functions.RegularExpressions
|
|||||||
Namespace API.TikTok
|
Namespace API.TikTok
|
||||||
<Manifest("AndyProgram_TikTok"), SpecialForm(False), SeparatedTasks(1)>
|
<Manifest("AndyProgram_TikTok"), SpecialForm(False), SeparatedTasks(1)>
|
||||||
Friend Class SiteSettings : Inherits SiteSettingsBase
|
Friend Class SiteSettings : Inherits SiteSettingsBase
|
||||||
|
#Region "Categories"
|
||||||
|
Private Const CAT_DOWN As String = "Download"
|
||||||
|
#End Region
|
||||||
|
#Region "Download"
|
||||||
|
<PropertyOption(ControlText:="Download videos", Category:=CAT_DOWN), PXML, PClonable>
|
||||||
|
Friend ReadOnly Property DownloadTTVideos As PropertyValue
|
||||||
|
<PropertyOption(ControlText:="Download photos", Category:=CAT_DOWN), PXML, PClonable>
|
||||||
|
Friend ReadOnly Property DownloadTTPhotos As PropertyValue
|
||||||
|
#End Region
|
||||||
<PropertyOption(ControlText:="Remove tags from title"), PXML, PClonable>
|
<PropertyOption(ControlText:="Remove tags from title"), PXML, PClonable>
|
||||||
Friend ReadOnly Property RemoveTagsFromTitle As PropertyValue
|
Friend ReadOnly Property RemoveTagsFromTitle As PropertyValue
|
||||||
<PropertyOption(ControlText:="Use native title", ControlToolTip:="Use a user-created video title for the filename instead of the video ID."), PXML, PClonable>
|
<PropertyOption(ControlText:="Use native title", ControlToolTip:="Use a user-created video title for the filename instead of the video ID."), PXML, PClonable>
|
||||||
@@ -34,8 +43,15 @@ Namespace API.TikTok
|
|||||||
<PropertyOption(ControlText:="Use video date as file date (standalone downloader)",
|
<PropertyOption(ControlText:="Use video date as file date (standalone downloader)",
|
||||||
ControlToolTip:="Set the file date to the date the video was added (website) (if available)."), PXML, PClonable>
|
ControlToolTip:="Set the file date to the date the video was added (website) (if available)."), PXML, PClonable>
|
||||||
Friend ReadOnly Property UseParsedVideoDateSTD As PropertyValue
|
Friend ReadOnly Property UseParsedVideoDateSTD As PropertyValue
|
||||||
|
<DoNotUse> Friend Overrides Property DownloadText As PropertyValue
|
||||||
|
<DoNotUse> Friend Overrides Property DownloadTextPosts As PropertyValue
|
||||||
|
<DoNotUse> Friend Overrides Property DownloadTextSpecialFolder As PropertyValue
|
||||||
Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean)
|
Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean)
|
||||||
MyBase.New("TikTok", "www.tiktok.com", AccName, Temp, My.Resources.SiteResources.TikTokIcon_32, My.Resources.SiteResources.TikTokPic_192)
|
MyBase.New("TikTok", "www.tiktok.com", AccName, Temp, My.Resources.SiteResources.TikTokIcon_32, My.Resources.SiteResources.TikTokPic_192)
|
||||||
|
|
||||||
|
DownloadTTVideos = New PropertyValue(True)
|
||||||
|
DownloadTTPhotos = New PropertyValue(True)
|
||||||
|
|
||||||
RemoveTagsFromTitle = New PropertyValue(False)
|
RemoveTagsFromTitle = New PropertyValue(False)
|
||||||
TitleUseNative = New PropertyValue(True)
|
TitleUseNative = New PropertyValue(True)
|
||||||
TitleUseNativeSTD = New PropertyValue(True)
|
TitleUseNativeSTD = New PropertyValue(True)
|
||||||
@@ -45,6 +61,7 @@ Namespace API.TikTok
|
|||||||
TitleUseRegexForTitle_Value = New PropertyValue(String.Empty, GetType(String))
|
TitleUseRegexForTitle_Value = New PropertyValue(String.Empty, GetType(String))
|
||||||
UseParsedVideoDate = New PropertyValue(True)
|
UseParsedVideoDate = New PropertyValue(True)
|
||||||
UseParsedVideoDateSTD = New PropertyValue(False)
|
UseParsedVideoDateSTD = New PropertyValue(False)
|
||||||
|
|
||||||
UseNetscapeCookies = True
|
UseNetscapeCookies = True
|
||||||
UrlPatternUser = "https://www.tiktok.com/@{0}/"
|
UrlPatternUser = "https://www.tiktok.com/@{0}/"
|
||||||
UserRegex = RParams.DMS(String.Format(UserRegexDefaultPattern, "tiktok.com/@"), 1)
|
UserRegex = RParams.DMS(String.Format(UserRegexDefaultPattern, "tiktok.com/@"), 1)
|
||||||
@@ -62,8 +79,5 @@ Namespace API.TikTok
|
|||||||
Using f As New InternalSettingsForm(Options, Me, False) : f.ShowDialog() : End Using
|
Using f As New InternalSettingsForm(Options, Me, False) : f.ShowDialog() : End Using
|
||||||
End If
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
Friend Overrides Function GetUserUrl(ByVal User As IPluginContentProvider) As String
|
|
||||||
Return String.Format(UrlPatternUser, DirectCast(User, UserData).TrueName)
|
|
||||||
End Function
|
|
||||||
End Class
|
End Class
|
||||||
End Namespace
|
End Namespace
|
||||||
@@ -13,6 +13,7 @@ Imports PersonalUtilities.Functions.XML
|
|||||||
Imports PersonalUtilities.Functions.RegularExpressions
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
Imports PersonalUtilities.Tools
|
Imports PersonalUtilities.Tools
|
||||||
Imports PersonalUtilities.Tools.Web.Documents.JSON
|
Imports PersonalUtilities.Tools.Web.Documents.JSON
|
||||||
|
Imports UTypes = SCrawler.API.Base.UserMedia.Types
|
||||||
Namespace API.TikTok
|
Namespace API.TikTok
|
||||||
Friend Class UserData : Inherits UserDataBase
|
Friend Class UserData : Inherits UserDataBase
|
||||||
#Region "XML names"
|
#Region "XML names"
|
||||||
@@ -23,6 +24,7 @@ Namespace API.TikTok
|
|||||||
Private Const Name_TitleUseRegexForTitle As String = "TitleUseRegexForTitle"
|
Private Const Name_TitleUseRegexForTitle As String = "TitleUseRegexForTitle"
|
||||||
Private Const Name_TitleUseRegexForTitle_Value As String = "TitleUseRegexForTitle_Value"
|
Private Const Name_TitleUseRegexForTitle_Value As String = "TitleUseRegexForTitle_Value"
|
||||||
Private Const Name_TitleUseGlobalRegexOptions As String = "TitleUseGlobalRegexOptions"
|
Private Const Name_TitleUseGlobalRegexOptions As String = "TitleUseGlobalRegexOptions"
|
||||||
|
Private Const Name_PhotosDownloaded As String = "PhotosDownloaded"
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Declarations"
|
#Region "Declarations"
|
||||||
Private ReadOnly Property MySettings As SiteSettings
|
Private ReadOnly Property MySettings As SiteSettings
|
||||||
@@ -62,15 +64,7 @@ Namespace API.TikTok
|
|||||||
Friend Property TitleUseRegexForTitle_Value As String = String.Empty
|
Friend Property TitleUseRegexForTitle_Value As String = String.Empty
|
||||||
Friend Property TitleUseGlobalRegexOptions As Boolean = True
|
Friend Property TitleUseGlobalRegexOptions As Boolean = True
|
||||||
Private Property LastDownloadDate As Date? = Nothing
|
Private Property LastDownloadDate As Date? = Nothing
|
||||||
Private _TrueName As String = String.Empty
|
Private Property PhotosDownloaded As Boolean = False
|
||||||
Friend Property TrueName As String
|
|
||||||
Get
|
|
||||||
Return _TrueName.IfNullOrEmpty(Name)
|
|
||||||
End Get
|
|
||||||
Set(ByVal NewName As String)
|
|
||||||
_TrueName = NewName
|
|
||||||
End Set
|
|
||||||
End Property
|
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Exchange"
|
#Region "Exchange"
|
||||||
Friend Overrides Function ExchangeOptionsGet() As Object
|
Friend Overrides Function ExchangeOptionsGet() As Object
|
||||||
@@ -98,19 +92,19 @@ Namespace API.TikTok
|
|||||||
TitleAddVideoID = .Value(Name_TitleAddVideoID).FromXML(Of Boolean)(True)
|
TitleAddVideoID = .Value(Name_TitleAddVideoID).FromXML(Of Boolean)(True)
|
||||||
LastDownloadDate = AConvert(Of Date)(.Value(Name_LastDownloadDate), ADateTime.Formats.BaseDateTime, Nothing)
|
LastDownloadDate = AConvert(Of Date)(.Value(Name_LastDownloadDate), ADateTime.Formats.BaseDateTime, Nothing)
|
||||||
If Not LastDownloadDate.HasValue Then LastDownloadDate = LastUpdated
|
If Not LastDownloadDate.HasValue Then LastDownloadDate = LastUpdated
|
||||||
_TrueName = .Value(Name_TrueName)
|
|
||||||
TitleUseRegexForTitle = .Value(Name_TitleUseRegexForTitle).FromXML(Of Boolean)(False)
|
TitleUseRegexForTitle = .Value(Name_TitleUseRegexForTitle).FromXML(Of Boolean)(False)
|
||||||
TitleUseRegexForTitle_Value = .Value(Name_TitleUseRegexForTitle_Value)
|
TitleUseRegexForTitle_Value = .Value(Name_TitleUseRegexForTitle_Value)
|
||||||
TitleUseGlobalRegexOptions = .Value(Name_TitleUseGlobalRegexOptions).FromXML(Of Boolean)(True)
|
TitleUseGlobalRegexOptions = .Value(Name_TitleUseGlobalRegexOptions).FromXML(Of Boolean)(True)
|
||||||
|
PhotosDownloaded = .Value(Name_PhotosDownloaded).FromXML(Of Boolean)(False)
|
||||||
Else
|
Else
|
||||||
.Add(Name_RemoveTagsFromTitle, RemoveTagsFromTitle.BoolToInteger)
|
.Add(Name_RemoveTagsFromTitle, RemoveTagsFromTitle.BoolToInteger)
|
||||||
.Add(Name_TitleUseNative, TitleUseNative.BoolToInteger)
|
.Add(Name_TitleUseNative, TitleUseNative.BoolToInteger)
|
||||||
.Add(Name_TitleAddVideoID, TitleAddVideoID.BoolToInteger)
|
.Add(Name_TitleAddVideoID, TitleAddVideoID.BoolToInteger)
|
||||||
.Add(Name_LastDownloadDate, AConvert(Of String)(LastDownloadDate, AModes.XML, ADateTime.Formats.BaseDateTime, String.Empty))
|
.Add(Name_LastDownloadDate, AConvert(Of String)(LastDownloadDate, AModes.XML, ADateTime.Formats.BaseDateTime, String.Empty))
|
||||||
.Add(Name_TrueName, _TrueName)
|
|
||||||
.Add(Name_TitleUseRegexForTitle, TitleUseRegexForTitle.BoolToInteger)
|
.Add(Name_TitleUseRegexForTitle, TitleUseRegexForTitle.BoolToInteger)
|
||||||
.Add(Name_TitleUseRegexForTitle_Value, TitleUseRegexForTitle_Value)
|
.Add(Name_TitleUseRegexForTitle_Value, TitleUseRegexForTitle_Value)
|
||||||
.Add(Name_TitleUseGlobalRegexOptions, TitleUseGlobalRegexOptions.BoolToInteger)
|
.Add(Name_TitleUseGlobalRegexOptions, TitleUseGlobalRegexOptions.BoolToInteger)
|
||||||
|
.Add(Name_PhotosDownloaded, PhotosDownloaded.BoolToInteger)
|
||||||
End If
|
End If
|
||||||
End With
|
End With
|
||||||
End Sub
|
End Sub
|
||||||
@@ -153,7 +147,7 @@ Namespace API.TikTok
|
|||||||
End Function
|
End Function
|
||||||
Private Function GetNewFileName(ByVal Title As String, ByVal Native As Boolean, ByVal RemoveTags As Boolean, ByVal AddVideoID As Boolean,
|
Private Function GetNewFileName(ByVal Title As String, ByVal Native As Boolean, ByVal RemoveTags As Boolean, ByVal AddVideoID As Boolean,
|
||||||
ByVal PostID As String, ByVal TitleRegex As RParams) As String
|
ByVal PostID As String, ByVal TitleRegex As RParams) As String
|
||||||
If Not Title.IsEmptyString Then Title = Left(Title, 150).StringTrim
|
If Not Title.IsEmptyString Then Title = TitleHtmlConverter(Left(Title, 150)).StringTrim
|
||||||
If Title.IsEmptyString Or Not Native Then
|
If Title.IsEmptyString Or Not Native Then
|
||||||
Title = PostID
|
Title = PostID
|
||||||
Else
|
Else
|
||||||
@@ -168,22 +162,33 @@ Namespace API.TikTok
|
|||||||
End If
|
End If
|
||||||
Return Title
|
Return Title
|
||||||
End Function
|
End Function
|
||||||
|
Private Function GetPhotoNode() As Object()
|
||||||
|
Return {"imageURL", "urlList", 0, 0}
|
||||||
|
End Function
|
||||||
Friend Overrides Sub DownloadData(ByVal Token As CancellationToken)
|
Friend Overrides Sub DownloadData(ByVal Token As CancellationToken)
|
||||||
MyBase.DownloadData(Token)
|
MyBase.DownloadData(Token)
|
||||||
UserCache.DisposeIfReady(False)
|
UserCache.DisposeIfReady(False)
|
||||||
UserCache = Nothing
|
UserCache = Nothing
|
||||||
End Sub
|
End Sub
|
||||||
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
|
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
|
||||||
Dim URL$ = $"https://www.tiktok.com/@{TrueName}"
|
Dim URL$ = $"https://www.tiktok.com/@{NameTrue}"
|
||||||
UserCache = CreateCache()
|
UserCache = CreateCache()
|
||||||
Try
|
Try
|
||||||
Dim postID$, title$, postUrl$, newName$
|
Const photoPrefix$ = "photo_"
|
||||||
|
Dim postID$, title$, postUrl$, newName$, t$, postID2$, imgUrl$
|
||||||
Dim postDate As Date?
|
Dim postDate As Date?
|
||||||
Dim dateAfterC As Date? = Nothing
|
Dim dateAfterC As Date? = Nothing
|
||||||
Dim dateBefore As Date? = DownloadDateTo
|
Dim dateBefore As Date? = DownloadDateTo
|
||||||
Dim dateAfter As Date? = DownloadDateFrom
|
Dim dateAfter As Date? = DownloadDateFrom
|
||||||
Dim baseDataObtained As Boolean = False
|
Dim baseDataObtained As Boolean = False
|
||||||
Dim titleRegex As RParams = GetTitleRegex()
|
Dim titleRegex As RParams = GetTitleRegex()
|
||||||
|
Dim vPath As SFile = Nothing, pPath As SFile = Nothing
|
||||||
|
Dim file As SFile
|
||||||
|
Dim j As EContainer, photo As EContainer
|
||||||
|
Dim photoNode As Object() = GetPhotoNode()
|
||||||
|
Dim c%, cc%, i%
|
||||||
|
Dim errDef As New ErrorsDescriber(EDP.ReturnValue)
|
||||||
|
Dim infoParsed As Boolean = False
|
||||||
|
|
||||||
If _ContentList.Count > 0 Then
|
If _ContentList.Count > 0 Then
|
||||||
With (From d In _ContentList Where d.Post.Date.HasValue Select d.Post.Date.Value)
|
With (From d In _ContentList Where d.Post.Date.HasValue Select d.Post.Date.Value)
|
||||||
@@ -209,41 +214,59 @@ Namespace API.TikTok
|
|||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
|
|
||||||
|
If DownloadVideos And Settings.YtdlpFile.Exists And CBool(MySettings.DownloadTTVideos.Value) Then
|
||||||
|
With UserCache.NewInstance : .Validate() : vPath = .RootDirectory : End With
|
||||||
Using b As New YTDLP.YTDLPBatch(Token) With {.TempPostsList = _TempPostsList}
|
Using b As New YTDLP.YTDLPBatch(Token) With {.TempPostsList = _TempPostsList}
|
||||||
b.Commands.Clear()
|
b.Commands.Clear()
|
||||||
b.ChangeDirectory(UserCache)
|
b.ChangeDirectory(vPath)
|
||||||
b.Encoding = BatchExecutor.UnicodeEncoding
|
b.Encoding = BatchExecutor.UnicodeEncoding
|
||||||
b.Execute(CreateYTCommand(UserCache.RootDirectory, URL, False, dateBefore, dateAfter))
|
b.Execute(CreateYTCommand(vPath, URL, False, dateBefore, dateAfter))
|
||||||
End Using
|
End Using
|
||||||
|
End If
|
||||||
|
|
||||||
|
If DownloadImages And Settings.GalleryDLFile.Exists And CBool(MySettings.DownloadTTPhotos.Value) Then
|
||||||
|
With UserCache.NewInstance : .Validate() : pPath = .RootDirectory : End With
|
||||||
|
Using b As New GDL.GDLBatch(Token)
|
||||||
|
With b
|
||||||
|
If PhotosDownloaded And _TempPostsList.Count > 0 Then
|
||||||
|
.TempPostsList = (From p As String In _TempPostsList
|
||||||
|
Where Not p.IsEmptyString AndAlso p.StartsWith(photoPrefix)
|
||||||
|
Select p.Replace(photoPrefix, String.Empty)).ListIfNothing
|
||||||
|
Else
|
||||||
|
.TempPostsList = New List(Of String)
|
||||||
|
End If
|
||||||
|
.ChangeDirectory(pPath)
|
||||||
|
.Encoding = BatchExecutor.UnicodeEncoding
|
||||||
|
.Execute(CreateGDLCommand(URL))
|
||||||
|
If Not PhotosDownloaded Then _ForceSaveUserInfo = True : _ForceSaveUserInfoOnException = True
|
||||||
|
PhotosDownloaded = True
|
||||||
|
End With
|
||||||
|
End Using
|
||||||
|
End If
|
||||||
|
|
||||||
ThrowAny(Token)
|
ThrowAny(Token)
|
||||||
|
|
||||||
Dim files As List(Of SFile) = SFile.GetFiles(UserCache, "*.json",, EDP.ReturnValue)
|
Dim files As List(Of SFile)
|
||||||
|
If Not vPath.IsEmptyString AndAlso vPath.Exists(SFO.Path, False) Then
|
||||||
|
files = SFile.GetFiles(vPath, "*.json",, errDef)
|
||||||
If files.ListExists Then
|
If files.ListExists Then
|
||||||
Dim j As EContainer
|
For Each file In files
|
||||||
For Each file As SFile In files
|
j = JsonDocument.Parse(file.GetText, errDef)
|
||||||
j = JsonDocument.Parse(file.GetText, EDP.ReturnValue)
|
|
||||||
If j.ListExists Then
|
If j.ListExists Then
|
||||||
If j.Value("_type").StringToLower = "video" Then
|
If j.Value("_type").StringToLower = "video" Then
|
||||||
If Not baseDataObtained Then
|
If Not baseDataObtained Then
|
||||||
baseDataObtained = True
|
baseDataObtained = True
|
||||||
If ID.IsEmptyString Then
|
If ID.IsEmptyString Then ID = j.Value("uploader_id")
|
||||||
ID = j.Value("uploader_id")
|
|
||||||
If Not ID.IsEmptyString Then _ForceSaveUserInfo = True
|
|
||||||
End If
|
|
||||||
newName = j.Value("uploader")
|
newName = j.Value("uploader")
|
||||||
If Not newName.IsEmptyString Then
|
If Not newName.IsEmptyString Then NameTrue = newName
|
||||||
If Not _TrueName = newName Then _ForceSaveUserInfo = True
|
|
||||||
_TrueName = newName
|
|
||||||
End If
|
|
||||||
newName = j.Value("creator")
|
newName = j.Value("creator")
|
||||||
If Not newName.IsEmptyString Then UserSiteName = newName
|
If Not newName.IsEmptyString Then UserSiteName = newName
|
||||||
End If
|
End If
|
||||||
postID = j.Value("id")
|
postID = j.Value("id")
|
||||||
If Not _TempPostsList.Contains(postID) Then
|
If Not _TempPostsList.Contains(postID) Then
|
||||||
_TempPostsList.Add(postID)
|
_TempPostsList.ListAddValue(postID, LNC)
|
||||||
Else
|
Else
|
||||||
Exit Sub
|
Exit For 'Exit Sub
|
||||||
End If
|
End If
|
||||||
title = GetNewFileName(j.Value("title").StringRemoveWinForbiddenSymbols,
|
title = GetNewFileName(j.Value("title").StringRemoveWinForbiddenSymbols,
|
||||||
TitleUseNative, RemoveTagsFromTitle, TitleAddVideoID, postID, titleRegex)
|
TitleUseNative, RemoveTagsFromTitle, TitleAddVideoID, postID, titleRegex)
|
||||||
@@ -251,18 +274,91 @@ Namespace API.TikTok
|
|||||||
If Not postDate.HasValue Then postDate = AConvert(Of Date)(j.Value("upload_date"), SimpleDateConverter, Nothing)
|
If Not postDate.HasValue Then postDate = AConvert(Of Date)(j.Value("upload_date"), SimpleDateConverter, Nothing)
|
||||||
Select Case CheckDatesLimit(postDate, SimpleDateConverter)
|
Select Case CheckDatesLimit(postDate, SimpleDateConverter)
|
||||||
Case DateResult.Skip : Continue For
|
Case DateResult.Skip : Continue For
|
||||||
Case DateResult.Exit : Exit Sub
|
Case DateResult.Exit : Exit For 'Exit Sub
|
||||||
End Select
|
End Select
|
||||||
|
|
||||||
postUrl = j.Value("webpage_url")
|
postUrl = j.Value("webpage_url")
|
||||||
If postUrl.IsEmptyString Then postUrl = $"https://www.tiktok.com/@{Name}/video/{postID}"
|
If postUrl.IsEmptyString Then postUrl = $"https://www.tiktok.com/@{Name}/video/{postID}"
|
||||||
_TempMediaList.Add(New UserMedia(postUrl, UserMedia.Types.Video) With {
|
_TempMediaList.Add(New UserMedia(postUrl, UTypes.Video) With {
|
||||||
.File = $"{title}.mp4", .Post = New UserPost(postID, postDate)})
|
.File = $"{title}.mp4", .Post = New UserPost(postID, postDate)})
|
||||||
End If
|
End If
|
||||||
j.Dispose()
|
j.Dispose()
|
||||||
End If
|
End If
|
||||||
Next
|
Next
|
||||||
End If
|
End If
|
||||||
|
End If
|
||||||
|
|
||||||
|
If Not pPath.IsEmptyString AndAlso pPath.Exists(SFO.Path, False) Then
|
||||||
|
files = SFile.GetFiles(pPath, "*.txt",, errDef)
|
||||||
|
If files.ListExists Then
|
||||||
|
For Each file In files
|
||||||
|
t = file.GetText(errDef)
|
||||||
|
If Not t.IsEmptyString Then t = RegexReplace(t, RegexPhotoJson)
|
||||||
|
If Not t.IsEmptyString Then
|
||||||
|
j = JsonDocument.Parse(t, errDef)
|
||||||
|
If j.ListExists Then
|
||||||
|
With j.ItemF({0, "webapp.video-detail", "itemInfo", "itemStruct"})
|
||||||
|
If .ListExists Then
|
||||||
|
postID = .Value("id")
|
||||||
|
postID2 = $"{photoPrefix}{postID}"
|
||||||
|
If Not _TempPostsList.Contains(postID2) Then _TempPostsList.ListAddValue(postID2, LNC) Else Exit For 'Exit Sub
|
||||||
|
postDate = AConvert(Of Date)(j.Value("createTime"), UnixDate32Provider, Nothing)
|
||||||
|
Select Case CheckDatesLimit(postDate, SimpleDateConverter)
|
||||||
|
Case DateResult.Skip : Continue For
|
||||||
|
Case DateResult.Exit : Exit For 'Exit Sub
|
||||||
|
End Select
|
||||||
|
|
||||||
|
If Not infoParsed Then
|
||||||
|
With .Item("author")
|
||||||
|
If .ListExists Then
|
||||||
|
infoParsed = True
|
||||||
|
SimpleDownloadAvatar(.Value("avatarLarger").IfNullOrEmpty(.Value("avatarMedium")).IfNullOrEmpty(.Value("avatarThumb")),
|
||||||
|
Function(ByVal ____url As String) As SFile
|
||||||
|
Dim ____f As SFile = CreateFileFromUrl(____url)
|
||||||
|
If Not ____f.Name.IsEmptyString Then ____f.Name = ____f.Name.Replace(":", "_").Replace("~", "-")
|
||||||
|
If Not ____f.Extension.IsEmptyString Then
|
||||||
|
If Not (____f.Extension = "jpg" Or ____f.Extension = "jpeg") Then
|
||||||
|
____f.Extension = RegexReplace(____f.Extension, RParams.DMS("(.+)\?", 1, EDP.ReturnValue))
|
||||||
|
If Not ____f.Extension.IsEmptyString AndAlso Not (____f.Extension = "jpg" Or ____f.Extension = "jpeg") Then ____f.Extension = String.Empty
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Return ____f
|
||||||
|
End Function)
|
||||||
|
UserSiteNameUpdate(.Value("nickname"))
|
||||||
|
UserDescriptionUpdate(.Value("signature"))
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
End If
|
||||||
|
|
||||||
|
title = GetNewFileName(j.Value({"imagePost"}, "title").StringRemoveWinForbiddenSymbols,
|
||||||
|
TitleUseNative, RemoveTagsFromTitle, TitleAddVideoID, postID, titleRegex)
|
||||||
|
postUrl = $"https://www.tiktok.com/@{Name}/photo/{postID}"
|
||||||
|
With .Item({"imagePost", "images"})
|
||||||
|
If .ListExists Then
|
||||||
|
i = 0
|
||||||
|
c = .Count
|
||||||
|
cc = Math.Max(c.ToString.Length, 3)
|
||||||
|
For Each photo In .Self
|
||||||
|
i += 1
|
||||||
|
imgUrl = photo.ItemF(photoNode).XmlIfNothingValue
|
||||||
|
If Not imgUrl.IsEmptyString Then _
|
||||||
|
_TempMediaList.Add(New UserMedia(imgUrl, UTypes.Picture) With {
|
||||||
|
.URL_BASE = postUrl,
|
||||||
|
.SpecialFolder = "Photo",
|
||||||
|
.File = $"{title}{IIf(c > 1, $"_{i.NumToString(ANumbers.Formats.NumberGroup, cc)}", String.Empty)}.jpg",
|
||||||
|
.Post = New UserPost(postID, postDate)})
|
||||||
|
Next
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
j.Dispose()
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Next
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
|
||||||
If _TempMediaList.Count > 0 Then LastDownloadDate = Now
|
If _TempMediaList.Count > 0 Then LastDownloadDate = Now
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
ProcessException(ex, Token, $"data downloading error [{URL}]")
|
ProcessException(ex, Token, $"data downloading error [{URL}]")
|
||||||
@@ -273,16 +369,41 @@ Namespace API.TikTok
|
|||||||
Protected Overrides Sub ReparseMissing(ByVal Token As CancellationToken)
|
Protected Overrides Sub ReparseMissing(ByVal Token As CancellationToken)
|
||||||
If ContentMissingExists Then
|
If ContentMissingExists Then
|
||||||
Dim m As UserMedia
|
Dim m As UserMedia
|
||||||
|
Dim d As IYouTubeMediaContainer = Nothing
|
||||||
Dim i%
|
Dim i%
|
||||||
Dim rList As New List(Of Integer)
|
Dim rList As New List(Of Integer)
|
||||||
|
Dim picIDs As New List(Of String)
|
||||||
|
Dim defDir As SFile = SFile.GetPath(DownloadContentDefault_GetRootDir())
|
||||||
|
Dim result As Boolean
|
||||||
For i = 0 To _ContentList.Count - 1
|
For i = 0 To _ContentList.Count - 1
|
||||||
If _ContentList(i).State = UserMedia.States.Missing Then
|
If _ContentList(i).State = UserMedia.States.Missing Then
|
||||||
m = _ContentList(i)
|
m = _ContentList(i)
|
||||||
m.URL = m.URL_BASE
|
result = False
|
||||||
_TempMediaList.Add(m)
|
Try
|
||||||
|
If m.Type = UTypes.Video Then
|
||||||
|
d = MySettings.GetSingleMediaInstance(m.URL_BASE, defDir)
|
||||||
|
result = False
|
||||||
|
If If(UserCache?.Disposed, True) Then UserCache = CreateCache()
|
||||||
|
DownloadSingleObject_GetPosts(d, Token, UserCache, result)
|
||||||
|
ElseIf m.Type = UTypes.Picture Then
|
||||||
|
If picIDs.Contains(m.Post.ID) Then
|
||||||
rList.Add(i)
|
rList.Add(i)
|
||||||
|
Else
|
||||||
|
d = MySettings.GetSingleMediaInstance(m.URL_BASE, defDir)
|
||||||
|
If If(UserCache?.Disposed, True) Then UserCache = CreateCache()
|
||||||
|
DownloadSingleObject_GetPosts(d, Token, UserCache, result)
|
||||||
|
picIDs.Add(m.Post.ID)
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Catch ex As Exception
|
||||||
|
result = False
|
||||||
|
ProcessException(ex, Token, "ReparseMissing")
|
||||||
|
End Try
|
||||||
|
If result Then rList.Add(i)
|
||||||
|
d.DisposeIfReady(False)
|
||||||
End If
|
End If
|
||||||
Next
|
Next
|
||||||
|
picIDs.Clear()
|
||||||
If rList.Count > 0 Then
|
If rList.Count > 0 Then
|
||||||
For i% = rList.Count - 1 To 0 Step -1 : _ContentList.RemoveAt(rList(i)) : Next
|
For i% = rList.Count - 1 To 0 Step -1 : _ContentList.RemoveAt(rList(i)) : Next
|
||||||
End If
|
End If
|
||||||
@@ -301,7 +422,11 @@ Namespace API.TikTok
|
|||||||
End If
|
End If
|
||||||
If DateBefore.HasValue Then command &= $"--datebefore {DateBefore.Value.AddDays(1).ToStringDate(SimpleDateConverter)} "
|
If DateBefore.HasValue Then command &= $"--datebefore {DateBefore.Value.AddDays(1).ToStringDate(SimpleDateConverter)} "
|
||||||
If DateAfter.HasValue Then command &= $"--dateafter {DateAfter.Value.AddDays(-1).ToStringDate(SimpleDateConverter)} "
|
If DateAfter.HasValue Then command &= $"--dateafter {DateAfter.Value.AddDays(-1).ToStringDate(SimpleDateConverter)} "
|
||||||
If Not CBool(If(IsSingleObjectDownload, MySettings.UseParsedVideoDateSTD, MySettings.UseParsedVideoDate).Value) Then command &= "--no-mtime "
|
If Not CBool(If(IsSingleObjectDownload, MySettings.UseParsedVideoDateSTD, MySettings.UseParsedVideoDate).Value) Then
|
||||||
|
command &= "--no-mtime "
|
||||||
|
Else
|
||||||
|
command &= "--mtime "
|
||||||
|
End If
|
||||||
If MySettings.CookiesNetscapeFile.Exists Then command &= $"--no-cookies-from-browser --cookies ""{MySettings.CookiesNetscapeFile}"" "
|
If MySettings.CookiesNetscapeFile.Exists Then command &= $"--no-cookies-from-browser --cookies ""{MySettings.CookiesNetscapeFile}"" "
|
||||||
command &= $"{URL} "
|
command &= $"{URL} "
|
||||||
If SupportOutput Then
|
If SupportOutput Then
|
||||||
@@ -317,10 +442,18 @@ Namespace API.TikTok
|
|||||||
Return command
|
Return command
|
||||||
End Function
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
|
#Region "GDL Support"
|
||||||
|
Private Function CreateGDLCommand(ByVal URL As String) As String
|
||||||
|
Return $"""{Settings.GalleryDLFile}"" --verbose --no-download --no-skip --write-pages {URL}"
|
||||||
|
End Function
|
||||||
|
#End Region
|
||||||
#Region "DownloadContent, DownloadFile"
|
#Region "DownloadContent, DownloadFile"
|
||||||
Protected Overrides Sub DownloadContent(ByVal Token As CancellationToken)
|
Protected Overrides Sub DownloadContent(ByVal Token As CancellationToken)
|
||||||
DownloadContentDefault(Token)
|
DownloadContentDefault(Token)
|
||||||
End Sub
|
End Sub
|
||||||
|
Protected Overrides Function ValidateDownloadFile(ByVal URL As String, ByVal Media As UserMedia, ByRef Interrupt As Boolean) As Boolean
|
||||||
|
Return Not Media.Type = UTypes.Picture
|
||||||
|
End Function
|
||||||
Protected Overrides Function DownloadFile(ByVal URL As String, ByVal Media As UserMedia, ByVal DestinationFile As SFile, ByVal Token As CancellationToken) As SFile
|
Protected Overrides Function DownloadFile(ByVal URL As String, ByVal Media As UserMedia, ByVal DestinationFile As SFile, ByVal Token As CancellationToken) As SFile
|
||||||
Using b As New TokenBatch(Token) With {.FileExchanger = RootCacheTikTok}
|
Using b As New TokenBatch(Token) With {.FileExchanger = RootCacheTikTok}
|
||||||
b.Encoding = BatchExecutor.UnicodeEncoding
|
b.Encoding = BatchExecutor.UnicodeEncoding
|
||||||
@@ -330,8 +463,18 @@ Namespace API.TikTok
|
|||||||
End Function
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
#Region "DownloadSingleObject"
|
#Region "DownloadSingleObject"
|
||||||
Protected Overrides Sub DownloadSingleObject_GetPosts(ByVal Data As IYouTubeMediaContainer, ByVal Token As CancellationToken)
|
Protected Overloads Overrides Sub DownloadSingleObject_GetPosts(ByVal Data As IYouTubeMediaContainer, ByVal Token As CancellationToken)
|
||||||
|
DownloadSingleObject_GetPosts(Data, Token, Nothing, Nothing)
|
||||||
|
End Sub
|
||||||
|
Private Overloads Sub DownloadSingleObject_GetPosts(ByVal Data As IYouTubeMediaContainer, ByVal Token As CancellationToken,
|
||||||
|
ByRef Cache As CacheKeeper, ByRef Result As Boolean)
|
||||||
Dim f$ = String.Empty
|
Dim f$ = String.Empty
|
||||||
|
Dim urlsList As New List(Of String)
|
||||||
|
Dim t As UTypes
|
||||||
|
Dim defName$ = New SFile(Data.URL).Name
|
||||||
|
If Data.URL.ToLower.Contains("/video/") Then
|
||||||
|
urlsList.Add(Data.URL)
|
||||||
|
t = UTypes.Video
|
||||||
If CBool(MySettings.TitleUseNativeSTD.Value) Then
|
If CBool(MySettings.TitleUseNativeSTD.Value) Then
|
||||||
Using b As New BatchExecutor(True) With {
|
Using b As New BatchExecutor(True) With {
|
||||||
.Encoding = BatchExecutor.UnicodeEncoding,
|
.Encoding = BatchExecutor.UnicodeEncoding,
|
||||||
@@ -349,14 +492,65 @@ Namespace API.TikTok
|
|||||||
End With
|
End With
|
||||||
End Using
|
End Using
|
||||||
End If
|
End If
|
||||||
Dim m As New UserMedia(Data.URL, UserMedia.Types.Video)
|
Else
|
||||||
If Not f.IsEmptyString Then f = TitleHtmlConverter(f)
|
t = UTypes.Picture
|
||||||
If Not f.IsEmptyString Then
|
Data.ContentType = Plugin.UserMediaTypes.Picture
|
||||||
f = GetNewFileName(f, MySettings.TitleUseNativeSTD.Value, MySettings.RemoveTagsFromTitle.Value, MySettings.TitleAddVideoIDSTD.Value,
|
Data.Title = defName
|
||||||
m.File.Name, GetTitleRegex)
|
Dim dir As SFile
|
||||||
If Not f.IsEmptyString Then m.File.Name = f.StringTrim
|
With If(Cache, Settings.Cache).NewInstance() : .Validate() : dir = .RootDirectory : End With
|
||||||
|
Using b As New GDL.GDLBatch(Token)
|
||||||
|
b.ChangeDirectory(dir)
|
||||||
|
b.Encoding = BatchExecutor.UnicodeEncoding
|
||||||
|
b.Execute(CreateGDLCommand(Data.URL))
|
||||||
|
End Using
|
||||||
|
Dim file As SFile = SFile.GetFiles(dir, "*.txt",, EDP.ReturnValue).FirstOrDefault
|
||||||
|
If file.Exists Then
|
||||||
|
Dim r$ = file.GetText(EDP.ReturnValue)
|
||||||
|
If Not r.IsEmptyString Then r = RegexReplace(r, RegexPhotoJson)
|
||||||
|
If Not r.IsEmptyString Then
|
||||||
|
Using j As EContainer = JsonDocument.Parse(r, EDP.ReturnValue)
|
||||||
|
If j.ListExists Then
|
||||||
|
With j.ItemF({0, "webapp.video-detail", "itemInfo", "itemStruct"})
|
||||||
|
If CBool(MySettings.TitleUseNativeSTD.Value) Then f = j.Value({"imagePost"}, "title").StringRemoveWinForbiddenSymbols
|
||||||
|
With .Item({"imagePost", "images"})
|
||||||
|
If .ListExists Then
|
||||||
|
For Each photo As EContainer In .Self : urlsList.Add(photo.ItemF(GetPhotoNode()).XmlIfNothingValue) : Next
|
||||||
End If
|
End If
|
||||||
|
End With
|
||||||
|
End With
|
||||||
|
End If
|
||||||
|
End Using
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
|
||||||
|
Dim m As UserMedia
|
||||||
|
Dim i% = 0, c%, cc%
|
||||||
|
Dim ff As Boolean = False
|
||||||
|
If urlsList.Count > 0 Then
|
||||||
|
c = urlsList.Count
|
||||||
|
cc = Math.Max(c.ToString.Length, 3)
|
||||||
|
For Each url$ In urlsList
|
||||||
|
i += 1
|
||||||
|
m = New UserMedia(url, t) With {.URL_BASE = Data.URL}
|
||||||
|
If Not f.IsEmptyString Then f = TitleHtmlConverter(f)
|
||||||
|
If Not f.IsEmptyString Or t = UTypes.Picture Then
|
||||||
|
If Not ff Then f = GetNewFileName(f, MySettings.TitleUseNativeSTD.Value, MySettings.RemoveTagsFromTitle.Value, MySettings.TitleAddVideoIDSTD.Value,
|
||||||
|
defName, GetTitleRegex)
|
||||||
|
ff = True
|
||||||
|
If Not f.IsEmptyString Then
|
||||||
|
m.File.Name = $"{f.StringTrim}{IIf(c > 1, $"_{i.NumToString(ANumbers.Formats.NumberGroup, cc)}", String.Empty)}"
|
||||||
|
If t = UTypes.Picture Then m.File.Extension = "jpg"
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
|
||||||
_TempMediaList.Add(m)
|
_TempMediaList.Add(m)
|
||||||
|
Result = True
|
||||||
|
Next
|
||||||
|
End If
|
||||||
|
End Sub
|
||||||
|
Protected Overrides Sub DownloadSingleObject_PostProcessing(ByVal Data As IYouTubeMediaContainer, Optional ByVal ResetTitle As Boolean = True)
|
||||||
|
MyBase.DownloadSingleObject_PostProcessing(Data, Not Data.ContentType = Plugin.UserMediaTypes.Picture)
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "EraseData"
|
#Region "EraseData"
|
||||||
|
|||||||
@@ -7,7 +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
|
||||||
Imports System.Globalization
|
Imports System.Globalization
|
||||||
Imports PersonalUtilities.Functions.XML.Base
|
Imports System.Text.RegularExpressions
|
||||||
Imports PersonalUtilities.Functions.RegularExpressions
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
Namespace API.Twitter
|
Namespace API.Twitter
|
||||||
Friend Module Declarations
|
Friend Module Declarations
|
||||||
@@ -16,6 +16,9 @@ Namespace API.Twitter
|
|||||||
Friend ReadOnly DateProvider As ADateTime = GetDateProvider()
|
Friend ReadOnly DateProvider As ADateTime = GetDateProvider()
|
||||||
Friend ReadOnly VideoSizeRegEx As RParams = RParams.DMS("\d+x(\d+)", 1, EDP.ReturnValue)
|
Friend ReadOnly VideoSizeRegEx As RParams = RParams.DMS("\d+x(\d+)", 1, EDP.ReturnValue)
|
||||||
Friend ReadOnly StatusRegEx As RParams = RParams.DM(".*?(twitter|x)\.com/\S+/status/\d+", 0, EDP.ReturnValue)
|
Friend ReadOnly StatusRegEx As RParams = RParams.DM(".*?(twitter|x)\.com/\S+/status/\d+", 0, EDP.ReturnValue)
|
||||||
|
Friend ReadOnly BroadcastsUrls As Object() = {"entities", "urls", 0, "expanded_url"}
|
||||||
|
Friend ReadOnly GdlLimitRegEx As RParams = RParams.DM("Waiting until[\s\W\d\:]+\(rate limit\)", 0, RegexOptions.IgnoreCase, EDP.ReturnValue)
|
||||||
|
Friend ReadOnly GdlPostCoutNumberNodes As String() = {"data", "user", "result", "legacy", "statuses_count"}
|
||||||
Private Function GetDateProvider() As ADateTime
|
Private Function GetDateProvider() As ADateTime
|
||||||
Dim n As DateTimeFormatInfo = CultureInfo.GetCultureInfo("en-us").DateTimeFormat.Clone
|
Dim n As DateTimeFormatInfo = CultureInfo.GetCultureInfo("en-us").DateTimeFormat.Clone
|
||||||
n.FullDateTimePattern = "ddd MMM dd HH:mm:ss +ffff yyyy"
|
n.FullDateTimePattern = "ddd MMM dd HH:mm:ss +ffff yyyy"
|
||||||
|
|||||||