Compare commits
32 Commits
2023.11.25
...
2024.2.25.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09760a6926 | ||
|
|
75039ac4d2 | ||
|
|
03e3a07947 | ||
|
|
d283d9c9f9 | ||
|
|
b9100bd3c1 | ||
|
|
0ea2156ada | ||
|
|
520280b038 | ||
|
|
10516f229b | ||
|
|
c3f0831768 | ||
|
|
74a0404670 | ||
|
|
52a43b9207 | ||
|
|
5bc559c448 | ||
|
|
b37f641582 | ||
|
|
e00dfec701 | ||
|
|
94edf23570 | ||
|
|
0246af9b69 | ||
|
|
c458f1cd1d | ||
|
|
e3da1bf1d3 | ||
|
|
dde024276b | ||
|
|
7a33c02497 | ||
|
|
5bd79ff3c2 | ||
|
|
3268bca0d3 | ||
|
|
1455a31879 | ||
|
|
64d6e6b28c | ||
|
|
da7cddc720 | ||
|
|
72be6b09ff | ||
|
|
3a0837a1b0 | ||
|
|
0657f3d195 | ||
|
|
c92314d8e8 | ||
|
|
d99243ce46 | ||
|
|
3dae40b696 | ||
|
|
ee0c773c37 |
@@ -5,7 +5,12 @@ I welcome requests! Follow these steps to contribute:
|
|||||||
1. Find an [issue](https://github.com/AAndyProgram/SCrawler/issues) that needs assistance.
|
1. Find an [issue](https://github.com/AAndyProgram/SCrawler/issues) that needs assistance.
|
||||||
1. Let me know you are working on it by posting a comment on the issue.
|
1. Let me know you are working on it by posting a comment on the issue.
|
||||||
1. If you find an error in the code, please provide a link to the file and the line number.
|
1. If you find an error in the code, please provide a link to the file and the line number.
|
||||||
1. If you have a code change suggestion, you can post a replacement code block. I also accept pull requests.
|
1. If you have a code change suggestion, you can post a replacement code block.<!-- I also accept pull requests.-->
|
||||||
|
|
||||||
|
# How to report a problem
|
||||||
|
1. Attach a **profile URL** that you cannot download.
|
||||||
|
1. Attach the **LOG** if it exists.
|
||||||
|
1. **Attach information to the issue with data copied from SCrawler (click the top right info button in the main window, then the `Environment` button, then the `Copy` button, and paste the copied text into the issue).**
|
||||||
|
|
||||||
# How to build from source
|
# How to build from source
|
||||||
1. Delete the `PersonalUtilities` project from the solution.
|
1. Delete the `PersonalUtilities` project from the solution.
|
||||||
|
|||||||
160
Changelog.md
@@ -1,3 +1,163 @@
|
|||||||
|
# 2024.2.25.0
|
||||||
|
|
||||||
|
*2024-02-25*
|
||||||
|
|
||||||
|
- Added
|
||||||
|
- A `Feed` button has been added to notifications
|
||||||
|
- Feed:
|
||||||
|
- ability to merge multiple special feeds into one
|
||||||
|
- ability to select all/none media
|
||||||
|
- ability to add to a special feed(s) with removal from the current one
|
||||||
|
- the name of the loaded feed is now displayed in the form title
|
||||||
|
- `Refresh` button now refreshes the loaded feed
|
||||||
|
- ability to move/copy media
|
||||||
|
- Scheduler: the ability to move tasks (higher, lower) *(just a view attribute, doesn't affect the scheduler)*
|
||||||
|
- YouTube (standalone app): add `Open file` to the context menu
|
||||||
|
- YouTube (standalone app): **the ability to edit each playlist item**
|
||||||
|
- YouTube (standalone app): **embed thumbnail in the audio/video as cover art** (Settings: `Defaults Audio` - `Embed thumbnail`; `Defaults Video` - `Embed thumbnail (video)`)
|
||||||
|
- Instagram: the `csrftoken` can now be automatically extracted from cookies
|
||||||
|
- Instagram: remove `x-ig-www-claim` from settings
|
||||||
|
- Threads: the `csrftoken` can now be automatically extracted from cookies
|
||||||
|
- Threads: simplify 500 error when updating tokens
|
||||||
|
- Facebook: simplify token update errors
|
||||||
|
- OnlyFans: handle 500 error
|
||||||
|
- Plugins: added `ReplaceInternalPluginAttribute` attribute
|
||||||
|
- Other improvements
|
||||||
|
- Fixed
|
||||||
|
- Main window: incorrect sorting of profiles and collections
|
||||||
|
- Standalone downloader: url array form doesn't show scrollbars
|
||||||
|
- Feed: image rendering bug
|
||||||
|
- YouTube (standalone app): audio codec does not change when changing audio/video in the video options form
|
||||||
|
- Instagram: error downloading single post
|
||||||
|
- TikTok: files with long names aren't downloaded
|
||||||
|
- Minor bugs
|
||||||
|
|
||||||
|
# 2024.1.26.0
|
||||||
|
|
||||||
|
*2024-01-26*
|
||||||
|
|
||||||
|
- Added
|
||||||
|
- YouTube (standalone app): **the ability to reduce video FPS**
|
||||||
|
- TikTok: the ability to use a regex to clean the title
|
||||||
|
- YouTube (SCrawler): the ability to ignore community errors
|
||||||
|
- Fixed
|
||||||
|
- Instagram: stories (user) downloading with the wrong aspect ratio for some users
|
||||||
|
- Minor bugs
|
||||||
|
|
||||||
|
# 2024.1.20.0
|
||||||
|
|
||||||
|
*2024-01-20*
|
||||||
|
|
||||||
|
- Added
|
||||||
|
- Instagram: **the ability to download reels**
|
||||||
|
- LPSG: handle 404 error
|
||||||
|
|
||||||
|
# 2024.1.18.0
|
||||||
|
|
||||||
|
*2024-01-18*
|
||||||
|
|
||||||
|
- Fixed
|
||||||
|
- Main window: incorrect collection sorting
|
||||||
|
- xHamster: some user videos were not downloaded
|
||||||
|
- YouTube (standalone app): URL array form doesn't show scrollbars
|
||||||
|
- Minor bugs
|
||||||
|
|
||||||
|
# 2024.1.12.1
|
||||||
|
|
||||||
|
*2024-01-12*
|
||||||
|
|
||||||
|
- Added
|
||||||
|
- YouTube (SCrawler): data downloading by dates
|
||||||
|
- Feed: ability to merge multiple session feeds into one
|
||||||
|
- Feed: remove session number from special feeds
|
||||||
|
- Fixed
|
||||||
|
- **Instagram**: stories (user) downloading with the wrong aspect ratio for some users
|
||||||
|
- YouTube: incorrect opening of a post from the feed
|
||||||
|
- YouTube: wrong date to data parsing
|
||||||
|
|
||||||
|
# 2024.1.12.0
|
||||||
|
|
||||||
|
*2024-01-12*
|
||||||
|
|
||||||
|
- Added
|
||||||
|
- Feed: added a prompt before clearing the current session
|
||||||
|
- xHamster: creators
|
||||||
|
- YouTube communities: add error to log
|
||||||
|
- Added scheduler to tray menu
|
||||||
|
- Other improvements
|
||||||
|
- Fixed
|
||||||
|
- Feed: there is no option to create a new feed when adding checked items
|
||||||
|
- **Instagram**: downloading of tagged posts
|
||||||
|
- xHamster: profiles are not downloading
|
||||||
|
- Minor bugs
|
||||||
|
|
||||||
|
# 2023.12.27.0
|
||||||
|
|
||||||
|
*2023-12-27*
|
||||||
|
|
||||||
|
- Added
|
||||||
|
- Notification of new log data
|
||||||
|
- OnlyFans: **OF-Scrapper support to download DRM protected videos**
|
||||||
|
- Other improvements
|
||||||
|
- Fixed
|
||||||
|
- The default options are changed (`Favorite`, `Temporary`, etc.) when changing an account for a created user
|
||||||
|
- When changing the account for a created user, the new account does not apply to that user until SCrawler is restarted
|
||||||
|
- Saved posts: session file is not updated when new data is added
|
||||||
|
- Minor bugs
|
||||||
|
|
||||||
|
# 2023.12.15.0
|
||||||
|
|
||||||
|
*2023-12-15*
|
||||||
|
|
||||||
|
- Fixed
|
||||||
|
- Twitter: some twitter profiles don't download completely
|
||||||
|
- Minor bugs
|
||||||
|
|
||||||
|
# 2023.12.14.0
|
||||||
|
|
||||||
|
*2023-12-14*
|
||||||
|
|
||||||
|
- Added
|
||||||
|
- YouTube: options `Create thumbnail files (video)` and `Create thumbnail files (music)`
|
||||||
|
- YouTube: `Select all` and `Select none` buttons
|
||||||
|
|
||||||
|
# 2023.12.13.0
|
||||||
|
|
||||||
|
*2023-12-13*
|
||||||
|
|
||||||
|
- Added
|
||||||
|
- YouTube (standalone app): additional options for downloading channels
|
||||||
|
- Updated
|
||||||
|
- gallery-dl up to version 1.26.4
|
||||||
|
- Fixed
|
||||||
|
- Feed: saved posts are added to the end of the feed
|
||||||
|
- xHamster: some videos won't download
|
||||||
|
|
||||||
|
# 2023.12.10.0
|
||||||
|
|
||||||
|
*2023-12-10*
|
||||||
|
|
||||||
|
- Updated
|
||||||
|
- gallery-dl up to version 1.26.4-dev
|
||||||
|
- Fixed
|
||||||
|
- Twitter: data is not downloading
|
||||||
|
|
||||||
|
# 2023.12.7.0
|
||||||
|
|
||||||
|
*2023-12-07*
|
||||||
|
|
||||||
|
- Added
|
||||||
|
- Saved posts: add downloaded saved posts to the feed
|
||||||
|
- **YouTube (SCrawler): the ability to download YouTube user community feeds**
|
||||||
|
- Main window: add `Alt+A` hotkey to show scheduler
|
||||||
|
- Main window: add `Alt+P` hotkey to show progress form
|
||||||
|
- YouTube: check of adding a URL if it has already been downloaded
|
||||||
|
- YouTube: ability to check for a new version at start
|
||||||
|
- **Updater**
|
||||||
|
- Fixed
|
||||||
|
- Standalone downloader: URL files are not deleted along with the file
|
||||||
|
- Minor bugs
|
||||||
|
|
||||||
# 2023.11.25.0
|
# 2023.11.25.0
|
||||||
|
|
||||||
*2023-11-25*
|
*2023-11-25*
|
||||||
|
|||||||
21
FAQ.md
@@ -14,8 +14,6 @@ Any other questions I will keep in this file.
|
|||||||
|
|
||||||
A: https://github.com/AAndyProgram/SCrawler/wiki/Settings#how-to-set-up-cookies
|
A: https://github.com/AAndyProgram/SCrawler/wiki/Settings#how-to-set-up-cookies
|
||||||
|
|
||||||
<!---**ATTENTION! If you need to use cookies but cannot import them, I highly recommend that you don't use SCrawler and use another program. Don't create issues, discussions, or write to me on Discord. Any issue or discussion about cookies will be deleted immediately without a response. Any user who asks me about cookies on Discord will be banned.**--->
|
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
#### Q: **Does this program have GUI or CLI.**
|
#### Q: **Does this program have GUI or CLI.**
|
||||||
@@ -41,13 +39,16 @@ A: NO.
|
|||||||
|
|
||||||
A: Check your credentials and **[SITES REQUIREMENTS](https://github.com/AAndyProgram/SCrawler/wiki/Settings#sites-requirements)**. If all settings are set, but nothing works, go to [create a new issue](https://github.com/AAndyProgram/SCrawler/issues). Don't forget to attach the LOG.
|
A: Check your credentials and **[SITES REQUIREMENTS](https://github.com/AAndyProgram/SCrawler/wiki/Settings#sites-requirements)**. If all settings are set, but nothing works, go to [create a new issue](https://github.com/AAndyProgram/SCrawler/issues). Don't forget to attach the LOG.
|
||||||
|
|
||||||
|
**You also can join our Discord server**: https://discord.gg/uFNUXvFFmg
|
||||||
|
<br/>*You can get help faster there!*
|
||||||
|
|
||||||
**ATTENTION! Issues without URLs will be closed without a response!**
|
**ATTENTION! Issues without URLs will be closed without a response!**
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
#### Q: **I have set credentials but still nothing is downloading**
|
#### Q: **I have set credentials but still nothing is downloading**
|
||||||
|
|
||||||
A: Click the ```Start downloading``` button
|
A: Click the `Start downloading` button or press `F5`
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
@@ -59,7 +60,7 @@ A: https://github.com/AAndyProgram/SCrawler/releases/latest
|
|||||||
|
|
||||||
#### Q: **How to run the program?**
|
#### Q: **How to run the program?**
|
||||||
|
|
||||||
A: Double-click ```SCrawler.exe```
|
A: Double-click `SCrawler.exe`
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
@@ -77,19 +78,19 @@ A: The program stored posts IDs in users' folders. For the first time, the progr
|
|||||||
|
|
||||||
#### Q: **How to redownload all data**
|
#### Q: **How to redownload all data**
|
||||||
|
|
||||||
A: Double-click on the user you want to redownload. In the opened window open folder setting. Delete the files ending with ```_Data.xml``` and ```_Posts.txt```. Restart SCrawler. Download this user again.
|
A: https://github.com/AAndyProgram/SCrawler/wiki#redownload-user
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
#### Q: **How to remove the label**
|
#### Q: **How to remove the label**
|
||||||
|
|
||||||
A: There is no functionality to remove an individual label. You can open the ```Labels.txt``` file in the program settings folder and delete any label you want. You also can delete this file (```Labels.txt```). In this case, when the program starts, the list of labels list will be updated with only existing labels (from the user data files).
|
A: There is no functionality to remove an individual label. You can open the `Labels.txt` file in the program settings folder and delete any label you want. You also can delete this file (`Labels.txt`). In this case, when the program starts, the list of labels list will be updated with only existing labels (from the user data files).
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
#### Q: **How to remove a user from the blacklist**
|
#### Q: **How to remove a user from the blacklist**
|
||||||
|
|
||||||
A: Just add that user back to the program. In the dialog box that opens, click on the ```Add and remove from blacklist``` button.
|
A: Just add that user back to the program. In the dialog box that opens, click on the `Add and remove from blacklist` button.
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
@@ -113,4 +114,8 @@ A: I can only [suggest](#q-you-lost-me-your-program-is-too-complicated) you find
|
|||||||
|
|
||||||
#### Q: **Can you add a step-by-step guide or video on how to use the program?**
|
#### Q: **Can you add a step-by-step guide or video on how to use the program?**
|
||||||
|
|
||||||
A: **NO! NEVER!** The guide fully covers all the functionality of SCrawler! If you don't respect my work, I don't waste my time. If you want, you can create a video tutorial and send it to me. Then I add it. All options and what each option does described on the wiki. The wiki also contains a description of all settings and how-to configure them. For complex settings, there is a steep-by-steep guide. Read the [main](README.md) information and [GUIDE](https://github.com/AAndyProgram/SCrawler/wiki/) and you won't have any problems. I have developed a program with an intuitive interface. There is a Settings button, download buttons, a context menu that drops down when a user is clicked, and other controls. Anyone can use it.
|
A: **NO!** The guide fully covers all the functionality of SCrawler! If you don't respect my work, I don't waste my time. If you want, you can create a video tutorial and send it to me. Then I add it. All options and what each option does described on the wiki. The wiki also contains a description of all settings and how-to configure them. For complex settings, there is a steep-by-steep guide. Read the [main](README.md) information and [GUIDE](https://github.com/AAndyProgram/SCrawler/wiki/) and you won't have any problems. I have developed a program with an intuitive interface. There is a Settings button, download buttons, a context menu that drops down when a user is clicked, and other controls. Anyone can use it.
|
||||||
|
|
||||||
|
**The following video was recorded by a user who loves SCrawler and demonstrates how to add credentials using Instagram as an example:**
|
||||||
|
|
||||||
|
[](https://www.youtube.com/watch?v=XDn7zG4I700)
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
You can create a plugin for any site you want. **To create a plugin, read [this guide](https://github.com/AAndyProgram/SCrawler/wiki/Plugins).**
|
||||||
|
|
||||||
|
If you've created a plugin, you can create a [new issue](https://github.com/AAndyProgram/SCrawler/issues/new?assignees=&labels=New+Plugin&projects=&template=plugin_add.md&title=%5BNEW+PLUGIN%5D) and I'll add your plugin to the list below.
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
List of available plugins:
|
List of available plugins:
|
||||||
|
|
||||||
Tools:
|
Tools:
|
||||||
|
|||||||
BIN
ProgramScreenshots/FeedMoveCopyTo.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 491 KiB After Width: | Height: | Size: 472 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 35 KiB |
BIN
ProgramScreenshots/SettingsSiteInstagramData.png
Normal file
|
After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 21 KiB |
@@ -6,11 +6,19 @@ https://github.com/yt-dlp/yt-dlp/
|
|||||||
|
|
||||||
SCrawler has advanced user management, collections, labels, groups, automatic downloads, a beautiful view, GUI, the ability to add plugins for other sites and much more. Just try it and compare.
|
SCrawler has advanced user management, collections, labels, groups, automatic downloads, a beautiful view, GUI, the ability to add plugins for other sites and much more. Just try it and compare.
|
||||||
|
|
||||||
|
# gallery-dl
|
||||||
|
|
||||||
|
https://github.com/mikf/gallery-dl
|
||||||
|
|
||||||
|
**Great powerful CLI tool that supports hundreds of sites.**
|
||||||
|
|
||||||
|
SCrawler has advanced user management, collections, labels, groups, automatic downloads, a beautiful view, GUI, the ability to add plugins for other sites and much more. Just try it and compare.
|
||||||
|
|
||||||
# 4K Video Downloader
|
# 4K Video Downloader
|
||||||
|
|
||||||
https://www.4kdownload.com/-plbrz/video-downloader
|
https://www.4kdownload.com/-plbrz/video-downloader
|
||||||
|
|
||||||
| Option | SCrawler | 4K Stogram |
|
| Option | SCrawler | 4K Video Downloader |
|
||||||
| ---- | ---- | ---- |
|
| ---- | ---- | ---- |
|
||||||
| User managament | **Advanced** | No |
|
| User managament | **Advanced** | No |
|
||||||
| Automatic downloads | **Yes** | No |
|
| Automatic downloads | **Yes** | No |
|
||||||
@@ -121,10 +129,3 @@ https://github.com/RipMeApp/ripme
|
|||||||
| Other sites support | **Yes** | No |
|
| Other sites support | **Yes** | No |
|
||||||
| Still supported | **Yes** | **No (last release date May 4, 2021)** |
|
| Still supported | **Yes** | **No (last release date May 4, 2021)** |
|
||||||
|
|
||||||
# gallery-dl
|
|
||||||
|
|
||||||
https://github.com/mikf/gallery-dl
|
|
||||||
|
|
||||||
**CLI tool**
|
|
||||||
|
|
||||||
SCrawler has advanced user management, collections, labels, groups, automatic downloads, a beautiful view, GUI, the ability to add plugins for other sites and much more. Just try it and compare.
|
|
||||||
30
README.md
@@ -1,6 +1,6 @@
|
|||||||
<!-- # :rainbow_flag: Happy LGBT Pride Month :tada:
|
<!-- # :rainbow_flag: Happy LGBT Pride Month :tada:
|
||||||
-->
|
-->
|
||||||
# :rainbow_flag: Social networks crawler :rainbow_flag:
|
# 🏳️🌈 Social networks crawler 🏳️🌈
|
||||||
|
|
||||||
[](https://github.com/AAndyProgram/SCrawler/releases/latest)
|
[](https://github.com/AAndyProgram/SCrawler/releases/latest)
|
||||||
[](https://github.com/AAndyProgram/SCrawler/blob/main/LICENSE)
|
[](https://github.com/AAndyProgram/SCrawler/blob/main/LICENSE)
|
||||||
@@ -15,6 +15,10 @@
|
|||||||
A program to download photo and video from [any site](#supported-sites) (e.g. YouTube, YouTube Music, OnlyFans, Reddit, Twitter, Mastodon, Instagram, Threads, Facebook, TikTok, RedGifs, JustForFans, PornHub, XHamster, XVIDEOS, ThisVid, LPSG, Pinterest).
|
A program to download photo and video from [any site](#supported-sites) (e.g. YouTube, YouTube Music, OnlyFans, Reddit, Twitter, Mastodon, Instagram, Threads, Facebook, TikTok, RedGifs, JustForFans, PornHub, XHamster, XVIDEOS, ThisVid, LPSG, Pinterest).
|
||||||
|
|
||||||
**If you like SCrawler, please like the program on [this site](https://alternativeto.net/software/scrawler/about/) and/or [this](https://www.softpedia.com/get/Internet/Download-Managers/Social-networks-crawler.shtml)**
|
**If you like SCrawler, please like the program on [this site](https://alternativeto.net/software/scrawler/about/) and/or [this](https://www.softpedia.com/get/Internet/Download-Managers/Social-networks-crawler.shtml)**
|
||||||
|
|
||||||
|
**Join our Discord server**: https://discord.gg/uFNUXvFFmg
|
||||||
|
<br/>*If you have problems using the program, you can get help faster on our Discord server!*
|
||||||
|
|
||||||
<!---Do you like this program? Consider adding to my coffee fund by making a donation to show your support. :blush:
|
<!---Do you like this program? Consider adding to my coffee fund by making a donation to show your support. :blush:
|
||||||
[](https://ko-fi.com/andyprogram)--->
|
[](https://ko-fi.com/andyprogram)--->
|
||||||
**Bitcoin**: BC1Q0NH839FT5TA44DD7L7RLR97XDQAG9V8D6N7XET
|
**Bitcoin**: BC1Q0NH839FT5TA44DD7L7RLR97XDQAG9V8D6N7XET
|
||||||
@@ -30,7 +34,7 @@ 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 users' profiles and subreddits:
|
- Download pictures and videos from users' profiles and subreddits:
|
||||||
- YouTube videos, shorts, 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, saved posts;
|
||||||
- Redgifs videos (https://www.redgifs.com/);
|
- Redgifs videos (https://www.redgifs.com/);
|
||||||
- Twitter images and videos, saved (bookmarked) posts;
|
- Twitter images and videos, saved (bookmarked) posts;
|
||||||
@@ -39,7 +43,7 @@ A program to download photo and video from [any site](#supported-sites) (e.g. Yo
|
|||||||
- 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, tagged posts, stories, saved posts;
|
||||||
- Threads images and videos;
|
- Threads images and videos;
|
||||||
- Facebook images and videos, saved posts;
|
- Facebook images and videos, stories, saved posts;
|
||||||
- TikTok videos;
|
- TikTok videos;
|
||||||
- Pinterest boards, users, saved posts;
|
- Pinterest boards, users, saved posts;
|
||||||
- Imgur images, galleries and videos;
|
- Imgur images, galleries and videos;
|
||||||
@@ -74,12 +78,12 @@ A program to download photo and video from [any site](#supported-sites) (e.g. Yo
|
|||||||
- **YouTube Music**
|
- **YouTube Music**
|
||||||
- **Reddit**
|
- **Reddit**
|
||||||
- **Twitter**
|
- **Twitter**
|
||||||
- **OnlyFans**
|
- **OnlyFans** *(partial support)*[^1]
|
||||||
- **Mastodon**
|
- **Mastodon**
|
||||||
- **Instagram**
|
- **Instagram**
|
||||||
- **Threads**
|
- **Threads**
|
||||||
- **Facebook**
|
- **Facebook**
|
||||||
- JustForFans
|
- JustForFans *(partial support)*[^1]
|
||||||
- TikTok
|
- TikTok
|
||||||
- RedGifs
|
- RedGifs
|
||||||
- Pinterest
|
- Pinterest
|
||||||
@@ -145,15 +149,25 @@ First, the program downloads the full profile. After the program downloads only
|
|||||||
|
|
||||||
**Full guide you can find [here](https://github.com/AAndyProgram/SCrawler/wiki)**
|
**Full guide you can find [here](https://github.com/AAndyProgram/SCrawler/wiki)**
|
||||||
|
|
||||||
|
**Video on how to configure**
|
||||||
|
|
||||||
|
[](https://www.youtube.com/watch?v=XDn7zG4I700)
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
|
|
||||||
**Just download the [latest release](https://github.com/AAndyProgram/SCrawler/releases/latest), unzip the program archive to any folder and enjoy.** :blush:
|
**Just download the [latest release](https://github.com/AAndyProgram/SCrawler/releases/latest), unzip the program archive to any folder and enjoy.** :blush:
|
||||||
|
|
||||||
**Don't put program in the ```Program Files``` system folder (this is portable program and program settings are stored in the program folder)**
|
**Don't put program in the ```Program Files``` system folder (this is portable program and program settings are stored in the program folder)**
|
||||||
|
|
||||||
|
**I highly doubt you can run SCrawler on Linux or Mac. SCrawler is a program that is heavily dependent on Windows.**
|
||||||
|
|
||||||
# Updating
|
# Updating
|
||||||
|
|
||||||
Just download [latest](https://github.com/AAndyProgram/SCrawler/releases/latest) version and unpack it into the program folder. **Before starting a new version, I recommend making a backup copy of the program settings folder.**
|
Just download [latest](https://github.com/AAndyProgram/SCrawler/releases/latest) version and unpack it into the program folder. **Before launching a new version, I recommend making a backup copy of the program settings folder and user settings/data files.**
|
||||||
|
|
||||||
|
**You can also use the updater included in the release package.**
|
||||||
|
|
||||||
|
# [How to report a problem](CONTRIBUTING.md#how-to-report-a-problem)
|
||||||
|
|
||||||
# [How to build from source](CONTRIBUTING.md#how-to-build-from-source)
|
# [How to build from source](CONTRIBUTING.md#how-to-build-from-source)
|
||||||
|
|
||||||
@@ -167,6 +181,8 @@ The program has an intuitive interface.
|
|||||||
|
|
||||||
**[SITES REQUIREMENTS](https://github.com/AAndyProgram/SCrawler/wiki/Settings#sites-requirements)**
|
**[SITES REQUIREMENTS](https://github.com/AAndyProgram/SCrawler/wiki/Settings#sites-requirements)**
|
||||||
|
|
||||||
|
[](https://www.youtube.com/watch?v=XDn7zG4I700)
|
||||||
|
|
||||||
Just add a user profile and **click the ```Download``` button**.
|
Just add a user profile and **click the ```Download``` button**.
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
@@ -210,3 +226,5 @@ Discord server: https://discord.gg/uFNUXvFFmg
|
|||||||
|
|
||||||
[Wire](https://account.wire.com/user-profile/?id=93985052-cf2c-4b72-ac75-bbe3231cf544): @andyprogram
|
[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.
|
||||||
@@ -188,4 +188,13 @@ Namespace Plugin.Attributes
|
|||||||
Repository = RepoName
|
Repository = RepoName
|
||||||
End Sub
|
End Sub
|
||||||
End Class
|
End Class
|
||||||
|
''' <summary>Replace internal plugin with the current one</summary>
|
||||||
|
<AttributeUsage(AttributeTargets.Class, AllowMultiple:=False, Inherited:=False)> Public NotInheritable Class ReplaceInternalPluginAttribute : Inherits Attribute
|
||||||
|
Public ReadOnly SiteName As String
|
||||||
|
Public ReadOnly PluginKey As String
|
||||||
|
Public Sub New(ByVal PluginKey As String, Optional ByVal SiteName As String = Nothing)
|
||||||
|
Me.PluginKey = PluginKey
|
||||||
|
Me.SiteName = SiteName
|
||||||
|
End Sub
|
||||||
|
End Class
|
||||||
End Namespace
|
End Namespace
|
||||||
@@ -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.11.24.0")>
|
<Assembly: AssemblyVersion("2024.2.25.0")>
|
||||||
<Assembly: AssemblyFileVersion("2023.11.24.0")>
|
<Assembly: AssemblyFileVersion("2024.2.25.0")>
|
||||||
<Assembly: NeutralResourcesLanguage("en")>
|
<Assembly: NeutralResourcesLanguage("en")>
|
||||||
|
|||||||
3
SCrawler.Shared/.editorconfig
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[*.vb]
|
||||||
|
# Modifier preferences
|
||||||
|
file_header_template = Copyright (C) Andy https://github.com/AAndyProgram\nThis program is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program. If not, see <https://www.gnu.org/licenses/>
|
||||||
33
SCrawler.Shared/Functions.vb
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
' 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 [Shared]
|
||||||
|
Public Module Functions
|
||||||
|
Public Const NewReleaseFolderName As String = "__NewRelease"
|
||||||
|
Public Function GetCurrentMaxVer(Optional ByVal Path As SFile = Nothing) As Version
|
||||||
|
Try
|
||||||
|
If Path.IsEmptyString Then Path = Application.StartupPath.CSFileP
|
||||||
|
If Path.Exists(SFO.Path, False) Then
|
||||||
|
Dim versions As New List(Of Version)
|
||||||
|
Dim v As FileVersionInfo
|
||||||
|
With SFile.GetFiles(Path, "*.exe",, EDP.ReturnValue).ListIfNothing.Where(Function(f) f.Name = "SCrawler" Or f.Name = "YouTubeDownloader")
|
||||||
|
If .ListExists Then
|
||||||
|
For Each f As SFile In .Self
|
||||||
|
v = FileVersionInfo.GetVersionInfo(f)
|
||||||
|
versions.Add(New Version(v.ProductVersion))
|
||||||
|
Next
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
If versions.Count > 0 Then Return versions.Max
|
||||||
|
End If
|
||||||
|
Catch
|
||||||
|
End Try
|
||||||
|
Return Nothing
|
||||||
|
End Function
|
||||||
|
End Module
|
||||||
|
End Namespace
|
||||||
13
SCrawler.Shared/My Project/Application.Designer.vb
generated
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
'------------------------------------------------------------------------------
|
||||||
|
' <auto-generated>
|
||||||
|
' This code was generated by a tool.
|
||||||
|
' Runtime Version:4.0.30319.42000
|
||||||
|
'
|
||||||
|
' Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
' the code is regenerated.
|
||||||
|
' </auto-generated>
|
||||||
|
'------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Option Strict On
|
||||||
|
Option Explicit On
|
||||||
|
|
||||||
10
SCrawler.Shared/My Project/Application.myapp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<MyApplicationData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||||
|
<MySubMain>false</MySubMain>
|
||||||
|
<SingleInstance>false</SingleInstance>
|
||||||
|
<ShutdownMode>0</ShutdownMode>
|
||||||
|
<EnableVisualStyles>true</EnableVisualStyles>
|
||||||
|
<AuthenticationMode>0</AuthenticationMode>
|
||||||
|
<ApplicationType>1</ApplicationType>
|
||||||
|
<SaveMySettingsOnExit>true</SaveMySettingsOnExit>
|
||||||
|
</MyApplicationData>
|
||||||
37
SCrawler.Shared/My Project/AssemblyInfo.vb
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
Imports System.Resources
|
||||||
|
Imports System
|
||||||
|
Imports System.Reflection
|
||||||
|
Imports System.Runtime.InteropServices
|
||||||
|
|
||||||
|
' General Information about an assembly is controlled through the following
|
||||||
|
' set of attributes. Change these attribute values to modify the information
|
||||||
|
' associated with an assembly.
|
||||||
|
|
||||||
|
' Review the values of the assembly attributes
|
||||||
|
|
||||||
|
<Assembly: AssemblyTitle("SCrawler.Shared")>
|
||||||
|
<Assembly: AssemblyDescription("SCrawler shared functions")>
|
||||||
|
<Assembly: AssemblyCompany("AndyProgram")>
|
||||||
|
<Assembly: AssemblyProduct("SCrawler.Shared")>
|
||||||
|
<Assembly: AssemblyCopyright("Copyright © 2024")>
|
||||||
|
<Assembly: AssemblyTrademark("AndyProgram")>
|
||||||
|
|
||||||
|
<Assembly: ComVisible(False)>
|
||||||
|
|
||||||
|
'The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
<Assembly: Guid("75a22c7c-6f90-49cb-852b-078ea0b8f2b6")>
|
||||||
|
|
||||||
|
' Version information for an assembly consists of the following four values:
|
||||||
|
'
|
||||||
|
' Major Version
|
||||||
|
' Minor Version
|
||||||
|
' Build Number
|
||||||
|
' Revision
|
||||||
|
'
|
||||||
|
' You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
' by using the '*' as shown below:
|
||||||
|
' <Assembly: AssemblyVersion("1.0.*")>
|
||||||
|
|
||||||
|
<Assembly: AssemblyVersion("2023.12.15.0")>
|
||||||
|
<Assembly: AssemblyFileVersion("2023.12.15.0")>
|
||||||
|
<Assembly: NeutralResourcesLanguage("en")>
|
||||||
63
SCrawler.Shared/My Project/Resources.Designer.vb
generated
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
'------------------------------------------------------------------------------
|
||||||
|
' <auto-generated>
|
||||||
|
' This code was generated by a tool.
|
||||||
|
' Runtime Version:4.0.30319.42000
|
||||||
|
'
|
||||||
|
' Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
' the code is regenerated.
|
||||||
|
' </auto-generated>
|
||||||
|
'------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Option Strict On
|
||||||
|
Option Explicit On
|
||||||
|
|
||||||
|
Imports System
|
||||||
|
|
||||||
|
Namespace My.Resources
|
||||||
|
|
||||||
|
'This class was auto-generated by the StronglyTypedResourceBuilder
|
||||||
|
'class via a tool like ResGen or Visual Studio.
|
||||||
|
'To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
|
'with the /str option, or rebuild your VS project.
|
||||||
|
'''<summary>
|
||||||
|
''' A strongly-typed resource class, for looking up localized strings, etc.
|
||||||
|
'''</summary>
|
||||||
|
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0"), _
|
||||||
|
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
|
||||||
|
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
|
||||||
|
Global.Microsoft.VisualBasic.HideModuleNameAttribute()> _
|
||||||
|
Friend Module Resources
|
||||||
|
|
||||||
|
Private resourceMan As Global.System.Resources.ResourceManager
|
||||||
|
|
||||||
|
Private resourceCulture As Global.System.Globalization.CultureInfo
|
||||||
|
|
||||||
|
'''<summary>
|
||||||
|
''' Returns the cached ResourceManager instance used by this class.
|
||||||
|
'''</summary>
|
||||||
|
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||||
|
Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager
|
||||||
|
Get
|
||||||
|
If Object.ReferenceEquals(resourceMan, Nothing) Then
|
||||||
|
Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("SCrawler.Resources", GetType(Resources).Assembly)
|
||||||
|
resourceMan = temp
|
||||||
|
End If
|
||||||
|
Return resourceMan
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
|
||||||
|
'''<summary>
|
||||||
|
''' Overrides the current thread's CurrentUICulture property for all
|
||||||
|
''' resource lookups using this strongly typed resource class.
|
||||||
|
'''</summary>
|
||||||
|
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||||
|
Friend Property Culture() As Global.System.Globalization.CultureInfo
|
||||||
|
Get
|
||||||
|
Return resourceCulture
|
||||||
|
End Get
|
||||||
|
Set
|
||||||
|
resourceCulture = value
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
End Module
|
||||||
|
End Namespace
|
||||||
117
SCrawler.Shared/My Project/Resources.resx
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
<?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.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: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" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
</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" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
</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=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
</root>
|
||||||
73
SCrawler.Shared/My Project/Settings.Designer.vb
generated
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
'------------------------------------------------------------------------------
|
||||||
|
' <auto-generated>
|
||||||
|
' This code was generated by a tool.
|
||||||
|
' Runtime Version:4.0.30319.42000
|
||||||
|
'
|
||||||
|
' Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
' the code is regenerated.
|
||||||
|
' </auto-generated>
|
||||||
|
'------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Option Strict On
|
||||||
|
Option Explicit On
|
||||||
|
|
||||||
|
|
||||||
|
Namespace My
|
||||||
|
|
||||||
|
<Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
|
||||||
|
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.10.0.0"), _
|
||||||
|
Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||||
|
Partial Friend NotInheritable Class MySettings
|
||||||
|
Inherits Global.System.Configuration.ApplicationSettingsBase
|
||||||
|
|
||||||
|
Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings()),MySettings)
|
||||||
|
|
||||||
|
#Region "My.Settings Auto-Save Functionality"
|
||||||
|
#If _MyType = "WindowsForms" Then
|
||||||
|
Private Shared addedHandler As Boolean
|
||||||
|
|
||||||
|
Private Shared addedHandlerLockObject As New Object
|
||||||
|
|
||||||
|
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||||
|
Private Shared Sub AutoSaveSettings(sender As Global.System.Object, e As Global.System.EventArgs)
|
||||||
|
If My.Application.SaveMySettingsOnExit Then
|
||||||
|
My.Settings.Save()
|
||||||
|
End If
|
||||||
|
End Sub
|
||||||
|
#End If
|
||||||
|
#End Region
|
||||||
|
|
||||||
|
Public Shared ReadOnly Property [Default]() As MySettings
|
||||||
|
Get
|
||||||
|
|
||||||
|
#If _MyType = "WindowsForms" Then
|
||||||
|
If Not addedHandler Then
|
||||||
|
SyncLock addedHandlerLockObject
|
||||||
|
If Not addedHandler Then
|
||||||
|
AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings
|
||||||
|
addedHandler = True
|
||||||
|
End If
|
||||||
|
End SyncLock
|
||||||
|
End If
|
||||||
|
#End If
|
||||||
|
Return defaultInstance
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
End Class
|
||||||
|
End Namespace
|
||||||
|
|
||||||
|
Namespace My
|
||||||
|
|
||||||
|
<Global.Microsoft.VisualBasic.HideModuleNameAttribute(), _
|
||||||
|
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
|
||||||
|
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute()> _
|
||||||
|
Friend Module MySettingsProperty
|
||||||
|
|
||||||
|
<Global.System.ComponentModel.Design.HelpKeywordAttribute("My.Settings")> _
|
||||||
|
Friend ReadOnly Property Settings() As Global.SCrawler.My.MySettings
|
||||||
|
Get
|
||||||
|
Return Global.SCrawler.My.MySettings.Default
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
End Module
|
||||||
|
End Namespace
|
||||||
7
SCrawler.Shared/My Project/Settings.settings
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" UseMySettingsClassName="true">
|
||||||
|
<Profiles>
|
||||||
|
<Profile Name="(Default)" />
|
||||||
|
</Profiles>
|
||||||
|
<Settings />
|
||||||
|
</SettingsFile>
|
||||||
151
SCrawler.Shared/SCrawler.Shared.vbproj
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{DC634700-24C7-42DD-BF8F-87E6CC54E625}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<RootNamespace>SCrawler</RootNamespace>
|
||||||
|
<AssemblyName>SCrawler.Shared</AssemblyName>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<MyType>Windows</MyType>
|
||||||
|
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||||
|
<Deterministic>true</Deterministic>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<DefineDebug>true</DefineDebug>
|
||||||
|
<DefineTrace>true</DefineTrace>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DocumentationFile>
|
||||||
|
</DocumentationFile>
|
||||||
|
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<DefineDebug>false</DefineDebug>
|
||||||
|
<DefineTrace>true</DefineTrace>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DocumentationFile>
|
||||||
|
</DocumentationFile>
|
||||||
|
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<OptionExplicit>On</OptionExplicit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<OptionCompare>Binary</OptionCompare>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<OptionStrict>Off</OptionStrict>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<OptionInfer>On</OptionInfer>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DefineDebug>true</DefineDebug>
|
||||||
|
<DefineTrace>true</DefineTrace>
|
||||||
|
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||||
|
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||||
|
<DefineTrace>true</DefineTrace>
|
||||||
|
<OutputPath>bin\x64\Release\</OutputPath>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DefineDebug>true</DefineDebug>
|
||||||
|
<DefineTrace>true</DefineTrace>
|
||||||
|
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||||
|
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||||
|
<DefineTrace>true</DefineTrace>
|
||||||
|
<OutputPath>bin\x86\Release\</OutputPath>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Windows.Forms" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Import Include="Microsoft.VisualBasic" />
|
||||||
|
<Import Include="PersonalUtilities.Functions" />
|
||||||
|
<Import Include="System" />
|
||||||
|
<Import Include="System.Collections" />
|
||||||
|
<Import Include="System.Collections.Generic" />
|
||||||
|
<Import Include="System.Data" />
|
||||||
|
<Import Include="System.Diagnostics" />
|
||||||
|
<Import Include="System.Linq" />
|
||||||
|
<Import Include="System.Windows.Forms" />
|
||||||
|
<Import Include="System.Xml.Linq" />
|
||||||
|
<Import Include="System.Threading.Tasks" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Functions.vb" />
|
||||||
|
<Compile Include="My Project\AssemblyInfo.vb" />
|
||||||
|
<Compile Include="My Project\Application.Designer.vb">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Application.myapp</DependentUpon>
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="My Project\Resources.Designer.vb">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<DependentUpon>Resources.resx</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="My Project\Settings.Designer.vb">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Settings.settings</DependentUpon>
|
||||||
|
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="My Project\Resources.resx">
|
||||||
|
<Generator>VbMyResourcesResXFileCodeGenerator</Generator>
|
||||||
|
<LastGenOutput>Resources.Designer.vb</LastGenOutput>
|
||||||
|
<CustomToolNamespace>My.Resources</CustomToolNamespace>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</EmbeddedResource>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include=".editorconfig" />
|
||||||
|
<None Include="My Project\Application.myapp">
|
||||||
|
<Generator>MyApplicationCodeGenerator</Generator>
|
||||||
|
<LastGenOutput>Application.Designer.vb</LastGenOutput>
|
||||||
|
</None>
|
||||||
|
<None Include="My Project\Settings.settings">
|
||||||
|
<Generator>SettingsSingleFileGenerator</Generator>
|
||||||
|
<CustomToolNamespace>My</CustomToolNamespace>
|
||||||
|
<LastGenOutput>Settings.Designer.vb</LastGenOutput>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\MyUtilities\PersonalUtilities\PersonalUtilities.vbproj">
|
||||||
|
<Project>{8405896b-2685-4916-bc93-1fb514c323a9}</Project>
|
||||||
|
<Name>PersonalUtilities</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
|
||||||
|
</Project>
|
||||||
3
SCrawler.Updater/.editorconfig
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[*.vb]
|
||||||
|
# Modifier preferences
|
||||||
|
file_header_template = Copyright (C) Andy https://github.com/AAndyProgram\nThis program is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program. If not, see <https://www.gnu.org/licenses/>
|
||||||
6
SCrawler.Updater/App.config
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
|
||||||
|
</startup>
|
||||||
|
</configuration>
|
||||||
BIN
SCrawler.Updater/Content/Icons/RainbowIcon_48.ico
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
229
SCrawler.Updater/MainMod.vb
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
' 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.Net
|
||||||
|
Imports System.IO.Compression
|
||||||
|
Imports PersonalUtilities.Functions
|
||||||
|
Imports PersonalUtilities.Functions.XML
|
||||||
|
Imports PersonalUtilities.Tools.Web.Clients
|
||||||
|
Imports PersonalUtilities.Tools.Web.Documents.JSON
|
||||||
|
Imports SCrawler.Shared
|
||||||
|
Public Module MainMod
|
||||||
|
Private MyProcessID As Integer = -1
|
||||||
|
Private MyWorkingPath As SFile = Nothing
|
||||||
|
Private ReadOnly ProcessNames As String() = {"SCrawler", "YouTubeDownloader", "Updater"}
|
||||||
|
Private Silent As Boolean = False
|
||||||
|
Private Function GetConsoleResponse(ByVal Request As String) As String
|
||||||
|
Console.Write(Request)
|
||||||
|
Return Console.ReadLine
|
||||||
|
End Function
|
||||||
|
Private Function DownloadFile(ByVal URL As String, ByVal Destination As SFile) As Boolean
|
||||||
|
Try
|
||||||
|
Dim lastPerc% = -1
|
||||||
|
Dim currentCursor% = Console.CursorTop
|
||||||
|
Using w As New RWebClient With {.AsyncMode = True}
|
||||||
|
AddHandler w.DownloadProgressChanged,
|
||||||
|
New DownloadProgressChangedEventHandler(Sub(ByVal Sender As Object, ByVal e As DownloadProgressChangedEventArgs)
|
||||||
|
If lastPerc < e.ProgressPercentage Then
|
||||||
|
lastPerc = e.ProgressPercentage
|
||||||
|
Console.SetCursorPosition(0, currentCursor)
|
||||||
|
Console.Write("{0}% completed", e.ProgressPercentage)
|
||||||
|
End If
|
||||||
|
End Sub)
|
||||||
|
Return w.DownloadFile(URL, Destination, EDP.ReturnValue)
|
||||||
|
End Using
|
||||||
|
Catch ex As Exception
|
||||||
|
Return False
|
||||||
|
End Try
|
||||||
|
End Function
|
||||||
|
Public Sub Main()
|
||||||
|
Try
|
||||||
|
MyWorkingPath = AppDomain.CurrentDomain.BaseDirectory.CSFileP
|
||||||
|
MyProcessID = Process.GetCurrentProcess.Id
|
||||||
|
Console.Title = "SCrawler updater"
|
||||||
|
With Environment.GetCommandLineArgs
|
||||||
|
If .ListExists(2) Then Silent = .Self()(1).FromXML(Of Boolean)(False)
|
||||||
|
End With
|
||||||
|
|
||||||
|
Dim currentDir As SFile = MyWorkingPath.CutPath
|
||||||
|
Dim extractionDir As SFile = $"{currentDir.CSFilePS}{NewReleaseFolderName}\"
|
||||||
|
If extractionDir.Exists(SFO.Path, False) Then extractionDir.Delete(SFO.Path, SFODelete.DeletePermanently, EDP.None)
|
||||||
|
|
||||||
|
Dim currVer As Version = GetCurrentMaxVer(currentDir)
|
||||||
|
If currVer Is Nothing Then
|
||||||
|
Console.WriteLine("The current version of the program cannot be determined")
|
||||||
|
Else
|
||||||
|
Console.WriteLine($"The current version is {currVer} (x{IIf(Environment.Is64BitProcess, 64, 86)})")
|
||||||
|
Dim release As GitRelease = GetGitRelease()
|
||||||
|
If Not release.URL.IsEmptyString And Not release.Version Is Nothing Then
|
||||||
|
If release.Version > currVer Then
|
||||||
|
Console.WriteLine($"The new version is {release.Version} ({release.Name})")
|
||||||
|
|
||||||
|
If Not Silent AndAlso GetConsoleResponse("Do you want to update the program? (y/n): ").IfNullOrEmpty("n") = "n" Then Exit Sub
|
||||||
|
|
||||||
|
If ActiveProcessesExist() Then
|
||||||
|
Console.WriteLine("One of the SCrawler programs is still running. Waiting for all SCrawler programs to close.")
|
||||||
|
While ActiveProcessesExist() : Threading.Thread.Sleep(100) : End While
|
||||||
|
Console.WriteLine("All SCrawler programs are closed.")
|
||||||
|
End If
|
||||||
|
|
||||||
|
If extractionDir.Exists(SFO.Path, True) Then
|
||||||
|
Dim destFile As SFile = $"{extractionDir.CSFilePS}{New SFile(release.URL).File}"
|
||||||
|
Console.WriteLine("Downloading new version...")
|
||||||
|
If DownloadFile(release.URL, destFile) Then
|
||||||
|
Console.WriteLine("")
|
||||||
|
Console.WriteLine("New version downloaded!")
|
||||||
|
Console.WriteLine("Extracting files...")
|
||||||
|
ZipFile.ExtractToDirectory(destFile, extractionDir)
|
||||||
|
Console.WriteLine("Files extracted!")
|
||||||
|
destFile.Delete(SFO.File, SFODelete.DeletePermanently, EDP.None)
|
||||||
|
If Not MoveFiles(extractionDir, currentDir) Then GetConsoleResponse("Unable to update the program. Press Enter to exit") : Exit Sub
|
||||||
|
Else
|
||||||
|
extractionDir.Delete(SFO.Path, SFODelete.DeletePermanently, EDP.None)
|
||||||
|
Console.WriteLine("Unable to download new version")
|
||||||
|
End If
|
||||||
|
Else
|
||||||
|
Console.WriteLine("Unable to create temp directory")
|
||||||
|
End If
|
||||||
|
Else
|
||||||
|
Console.WriteLine("The program is up to date")
|
||||||
|
End If
|
||||||
|
Else
|
||||||
|
Console.WriteLine("Unable to get information about new version")
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Catch ex As Exception
|
||||||
|
Console.WriteLine("An error occurred during update")
|
||||||
|
Console.WriteLine(ex.Message)
|
||||||
|
Finally
|
||||||
|
GetConsoleResponse("Press Enter to exit")
|
||||||
|
End Try
|
||||||
|
End Sub
|
||||||
|
Private Function MoveFiles(ByVal Source As SFile, ByVal Destination As SFile) As Boolean
|
||||||
|
Console.WriteLine("Updating files")
|
||||||
|
Try
|
||||||
|
|
||||||
|
Dim oldFiles As List(Of SFile) = SFile.GetFiles(Destination,,, EDP.ReturnValue)
|
||||||
|
Dim oldFolders As List(Of SFile) = SFile.GetDirectories(Destination,,, EDP.ReturnValue)
|
||||||
|
|
||||||
|
Dim newFiles As List(Of SFile) = SFile.GetFiles(Source,,, EDP.ReturnValue)
|
||||||
|
Dim newFolders As List(Of SFile) = SFile.GetDirectories(Source,,, EDP.ReturnValue)
|
||||||
|
|
||||||
|
Dim obj As SFile = Nothing
|
||||||
|
Dim wSegment As String = MyWorkingPath.Segments.Last
|
||||||
|
Dim filesPredicate As Predicate(Of SFile) = Function(ByVal f As SFile) As Boolean
|
||||||
|
If obj = f Or obj.Name = f.Name Then
|
||||||
|
f.Delete(SFO.File, SFODelete.DeleteToRecycleBin, EDP.None)
|
||||||
|
Return True
|
||||||
|
Else
|
||||||
|
Return False
|
||||||
|
End If
|
||||||
|
End Function
|
||||||
|
Dim foldersPredicate As Predicate(Of SFile) = Function(ByVal f As SFile) As Boolean
|
||||||
|
Dim ls$ = f.Segments.Last
|
||||||
|
If ls = obj.Segments.Last And Not ls = NewReleaseFolderName And Not ls = wSegment Then
|
||||||
|
f.Delete(SFO.Path, SFODelete.DeleteToRecycleBin, EDP.None)
|
||||||
|
Return True
|
||||||
|
Else
|
||||||
|
Return False
|
||||||
|
End If
|
||||||
|
End Function
|
||||||
|
|
||||||
|
Dim getDestFile As Func(Of SFile, Boolean, SFile) = Function(ByVal f As SFile, ByVal isFolder As Boolean) As SFile
|
||||||
|
Dim ff As SFile = f
|
||||||
|
If isFolder Then
|
||||||
|
ff = $"{Destination.PathWithSeparator}{f.Segments.Last}\"
|
||||||
|
Else
|
||||||
|
ff.Path = Destination.Path
|
||||||
|
End If
|
||||||
|
Console.WriteLine(ff)
|
||||||
|
Return ff
|
||||||
|
End Function
|
||||||
|
If newFiles.ListExists Then
|
||||||
|
If oldFiles.ListExists Then
|
||||||
|
For Each obj In newFiles : oldFiles.RemoveAll(filesPredicate) : Next
|
||||||
|
End If
|
||||||
|
newFiles.ForEach(Sub(ff) SFile.Move(ff, getDestFile(ff, False), SFO.File, True, SFODelete.DeleteToRecycleBin, EDP.None))
|
||||||
|
End If
|
||||||
|
|
||||||
|
If newFolders.ListExists Then
|
||||||
|
If oldFolders.ListExists Then
|
||||||
|
For Each obj In newFolders : oldFolders.RemoveAll(foldersPredicate) : Next
|
||||||
|
End If
|
||||||
|
newFolders.ForEach(Sub(ff) If Not ff.Segments.Last = wSegment Then _
|
||||||
|
SFile.Move(ff, getDestFile(ff, True), SFO.Path, True, SFODelete.DeleteToRecycleBin, EDP.None))
|
||||||
|
End If
|
||||||
|
|
||||||
|
Console.WriteLine("Files updated")
|
||||||
|
Return True
|
||||||
|
Catch
|
||||||
|
Return False
|
||||||
|
End Try
|
||||||
|
End Function
|
||||||
|
Private Function ActiveProcessesExist() As Boolean
|
||||||
|
Try
|
||||||
|
Return Process.GetProcesses.Any(Function(p) ProcessNames.Contains(p.ProcessName) And Not p.Id = MyProcessID)
|
||||||
|
Catch
|
||||||
|
Return True
|
||||||
|
End Try
|
||||||
|
End Function
|
||||||
|
Private Structure GitRelease
|
||||||
|
Friend URL As String
|
||||||
|
Friend Name As String
|
||||||
|
Friend Version As Version
|
||||||
|
End Structure
|
||||||
|
Private Function GetGitRelease() As GitRelease
|
||||||
|
Try
|
||||||
|
Dim nameEnd$ = $"_x{IIf(Environment.Is64BitProcess, 64, 86)}.zip"
|
||||||
|
Dim name$, relName$, relTag$
|
||||||
|
|
||||||
|
Using resp As New Responser With {.Accept = "application/vnd.github.v3+json"}
|
||||||
|
Dim r$ = resp.GetResponse("https://api.github.com/repos/AAndyProgram/SCrawler/releases",, EDP.ReturnValue)
|
||||||
|
If Not r.IsEmptyString Then
|
||||||
|
Dim getver As Func(Of String, Version) = Function(ByVal input As String) As Version
|
||||||
|
Try
|
||||||
|
If Not input.IsEmptyString Then
|
||||||
|
If input.ToLower.StartsWith("scrawler") Then
|
||||||
|
Return New Version(input.Split("_")(1))
|
||||||
|
Else
|
||||||
|
Return New Version(input)
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Catch
|
||||||
|
End Try
|
||||||
|
Return Nothing
|
||||||
|
End Function
|
||||||
|
Using j As EContainer = JsonDocument.Parse(r, EDP.ReturnValue)
|
||||||
|
If j.ListExists Then
|
||||||
|
With j.FirstOrDefault(Function(e) Not e.Value("draft").FromXML(Of Boolean) And Not e.Value("prerelease").FromXML(Of Boolean))
|
||||||
|
If .ListExists Then
|
||||||
|
relName = .Value("name")
|
||||||
|
relTag = .Value("tag_name")
|
||||||
|
With .Item("assets")
|
||||||
|
If .ListExists Then
|
||||||
|
For Each asset As EContainer In .Self
|
||||||
|
name = asset.Value("name")
|
||||||
|
If Not name.IsEmptyString AndAlso name.EndsWith(nameEnd) Then _
|
||||||
|
Return New GitRelease With {
|
||||||
|
.Name = name,
|
||||||
|
.URL = asset.Value("browser_download_url"),
|
||||||
|
.Version = getver(name).IfNullOrEmpty(getver(relName).IfNullOrEmpty(getver(relTag)))}
|
||||||
|
Next
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
End If
|
||||||
|
End Using
|
||||||
|
End If
|
||||||
|
End Using
|
||||||
|
Catch
|
||||||
|
End Try
|
||||||
|
Return Nothing
|
||||||
|
End Function
|
||||||
|
End Module
|
||||||
13
SCrawler.Updater/My Project/Application.Designer.vb
generated
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
'------------------------------------------------------------------------------
|
||||||
|
' <auto-generated>
|
||||||
|
' This code was generated by a tool.
|
||||||
|
' Runtime Version:4.0.30319.42000
|
||||||
|
'
|
||||||
|
' Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
' the code is regenerated.
|
||||||
|
' </auto-generated>
|
||||||
|
'------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Option Strict On
|
||||||
|
Option Explicit On
|
||||||
|
|
||||||
10
SCrawler.Updater/My Project/Application.myapp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<MyApplicationData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||||
|
<MySubMain>false</MySubMain>
|
||||||
|
<SingleInstance>false</SingleInstance>
|
||||||
|
<ShutdownMode>0</ShutdownMode>
|
||||||
|
<EnableVisualStyles>true</EnableVisualStyles>
|
||||||
|
<AuthenticationMode>0</AuthenticationMode>
|
||||||
|
<ApplicationType>2</ApplicationType>
|
||||||
|
<SaveMySettingsOnExit>true</SaveMySettingsOnExit>
|
||||||
|
</MyApplicationData>
|
||||||
37
SCrawler.Updater/My Project/AssemblyInfo.vb
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
Imports System.Resources
|
||||||
|
Imports System
|
||||||
|
Imports System.Reflection
|
||||||
|
Imports System.Runtime.InteropServices
|
||||||
|
|
||||||
|
' General Information about an assembly is controlled through the following
|
||||||
|
' set of attributes. Change these attribute values to modify the information
|
||||||
|
' associated with an assembly.
|
||||||
|
|
||||||
|
' Review the values of the assembly attributes
|
||||||
|
|
||||||
|
<Assembly: AssemblyTitle("SCrawler updater")>
|
||||||
|
<Assembly: AssemblyDescription("SCrawler updater")>
|
||||||
|
<Assembly: AssemblyCompany("AndyProgram")>
|
||||||
|
<Assembly: AssemblyProduct("SCrawler.Updater")>
|
||||||
|
<Assembly: AssemblyCopyright("Copyright © 2024")>
|
||||||
|
<Assembly: AssemblyTrademark("AndyProgram")>
|
||||||
|
|
||||||
|
<Assembly: ComVisible(False)>
|
||||||
|
|
||||||
|
'The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
<Assembly: Guid("df008b29-ad5e-4271-acfe-650396d15c40")>
|
||||||
|
|
||||||
|
' Version information for an assembly consists of the following four values:
|
||||||
|
'
|
||||||
|
' Major Version
|
||||||
|
' Minor Version
|
||||||
|
' Build Number
|
||||||
|
' Revision
|
||||||
|
'
|
||||||
|
' You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
' by using the '*' as shown below:
|
||||||
|
' <Assembly: AssemblyVersion("1.0.*")>
|
||||||
|
|
||||||
|
<Assembly: AssemblyVersion("2023.12.7.0")>
|
||||||
|
<Assembly: AssemblyFileVersion("2023.12.7.0")>
|
||||||
|
<Assembly: NeutralResourcesLanguage("en")>
|
||||||
73
SCrawler.Updater/My Project/Resources.Designer.vb
generated
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
'------------------------------------------------------------------------------
|
||||||
|
' <auto-generated>
|
||||||
|
' This code was generated by a tool.
|
||||||
|
' Runtime Version:4.0.30319.42000
|
||||||
|
'
|
||||||
|
' Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
' the code is regenerated.
|
||||||
|
' </auto-generated>
|
||||||
|
'------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Option Strict On
|
||||||
|
Option Explicit On
|
||||||
|
|
||||||
|
Imports System
|
||||||
|
|
||||||
|
Namespace My.Resources
|
||||||
|
|
||||||
|
'This class was auto-generated by the StronglyTypedResourceBuilder
|
||||||
|
'class via a tool like ResGen or Visual Studio.
|
||||||
|
'To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
|
'with the /str option, or rebuild your VS project.
|
||||||
|
'''<summary>
|
||||||
|
''' A strongly-typed resource class, for looking up localized strings, etc.
|
||||||
|
'''</summary>
|
||||||
|
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0"), _
|
||||||
|
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
|
||||||
|
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
|
||||||
|
Global.Microsoft.VisualBasic.HideModuleNameAttribute()> _
|
||||||
|
Friend Module Resources
|
||||||
|
|
||||||
|
Private resourceMan As Global.System.Resources.ResourceManager
|
||||||
|
|
||||||
|
Private resourceCulture As Global.System.Globalization.CultureInfo
|
||||||
|
|
||||||
|
'''<summary>
|
||||||
|
''' Returns the cached ResourceManager instance used by this class.
|
||||||
|
'''</summary>
|
||||||
|
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||||
|
Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager
|
||||||
|
Get
|
||||||
|
If Object.ReferenceEquals(resourceMan, Nothing) Then
|
||||||
|
Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("SCrawler.Resources", GetType(Resources).Assembly)
|
||||||
|
resourceMan = temp
|
||||||
|
End If
|
||||||
|
Return resourceMan
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
|
||||||
|
'''<summary>
|
||||||
|
''' Overrides the current thread's CurrentUICulture property for all
|
||||||
|
''' resource lookups using this strongly typed resource class.
|
||||||
|
'''</summary>
|
||||||
|
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||||
|
Friend Property Culture() As Global.System.Globalization.CultureInfo
|
||||||
|
Get
|
||||||
|
Return resourceCulture
|
||||||
|
End Get
|
||||||
|
Set
|
||||||
|
resourceCulture = value
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
|
||||||
|
'''<summary>
|
||||||
|
''' Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
|
||||||
|
'''</summary>
|
||||||
|
Friend ReadOnly Property RainbowIcon_48() As System.Drawing.Icon
|
||||||
|
Get
|
||||||
|
Dim obj As Object = ResourceManager.GetObject("RainbowIcon_48", resourceCulture)
|
||||||
|
Return CType(obj,System.Drawing.Icon)
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
End Module
|
||||||
|
End Namespace
|
||||||
124
SCrawler.Updater/My Project/Resources.resx
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||||
|
<data name="RainbowIcon_48" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
|
<value>..\Content\Icons\RainbowIcon_48.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
||||||
73
SCrawler.Updater/My Project/Settings.Designer.vb
generated
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
'------------------------------------------------------------------------------
|
||||||
|
' <auto-generated>
|
||||||
|
' This code was generated by a tool.
|
||||||
|
' Runtime Version:4.0.30319.42000
|
||||||
|
'
|
||||||
|
' Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
' the code is regenerated.
|
||||||
|
' </auto-generated>
|
||||||
|
'------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Option Strict On
|
||||||
|
Option Explicit On
|
||||||
|
|
||||||
|
|
||||||
|
Namespace My
|
||||||
|
|
||||||
|
<Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
|
||||||
|
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.10.0.0"), _
|
||||||
|
Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||||
|
Partial Friend NotInheritable Class MySettings
|
||||||
|
Inherits Global.System.Configuration.ApplicationSettingsBase
|
||||||
|
|
||||||
|
Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings()),MySettings)
|
||||||
|
|
||||||
|
#Region "My.Settings Auto-Save Functionality"
|
||||||
|
#If _MyType = "WindowsForms" Then
|
||||||
|
Private Shared addedHandler As Boolean
|
||||||
|
|
||||||
|
Private Shared addedHandlerLockObject As New Object
|
||||||
|
|
||||||
|
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||||
|
Private Shared Sub AutoSaveSettings(sender As Global.System.Object, e As Global.System.EventArgs)
|
||||||
|
If My.Application.SaveMySettingsOnExit Then
|
||||||
|
My.Settings.Save()
|
||||||
|
End If
|
||||||
|
End Sub
|
||||||
|
#End If
|
||||||
|
#End Region
|
||||||
|
|
||||||
|
Public Shared ReadOnly Property [Default]() As MySettings
|
||||||
|
Get
|
||||||
|
|
||||||
|
#If _MyType = "WindowsForms" Then
|
||||||
|
If Not addedHandler Then
|
||||||
|
SyncLock addedHandlerLockObject
|
||||||
|
If Not addedHandler Then
|
||||||
|
AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings
|
||||||
|
addedHandler = True
|
||||||
|
End If
|
||||||
|
End SyncLock
|
||||||
|
End If
|
||||||
|
#End If
|
||||||
|
Return defaultInstance
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
End Class
|
||||||
|
End Namespace
|
||||||
|
|
||||||
|
Namespace My
|
||||||
|
|
||||||
|
<Global.Microsoft.VisualBasic.HideModuleNameAttribute(), _
|
||||||
|
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
|
||||||
|
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute()> _
|
||||||
|
Friend Module MySettingsProperty
|
||||||
|
|
||||||
|
<Global.System.ComponentModel.Design.HelpKeywordAttribute("My.Settings")> _
|
||||||
|
Friend ReadOnly Property Settings() As Global.SCrawler.My.MySettings
|
||||||
|
Get
|
||||||
|
Return Global.SCrawler.My.MySettings.Default
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
End Module
|
||||||
|
End Namespace
|
||||||
7
SCrawler.Updater/My Project/Settings.settings
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" UseMySettingsClassName="true">
|
||||||
|
<Profiles>
|
||||||
|
<Profile Name="(Default)" />
|
||||||
|
</Profiles>
|
||||||
|
<Settings />
|
||||||
|
</SettingsFile>
|
||||||
79
SCrawler.Updater/My Project/app.manifest
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
|
||||||
|
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||||
|
<security>
|
||||||
|
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<!-- UAC Manifest Options
|
||||||
|
If you want to change the Windows User Account Control level replace the
|
||||||
|
requestedExecutionLevel node with one of the following.
|
||||||
|
|
||||||
|
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||||
|
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||||
|
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
|
||||||
|
|
||||||
|
Specifying requestedExecutionLevel element will disable file and registry virtualization.
|
||||||
|
Remove this element if your application requires this virtualization for backwards
|
||||||
|
compatibility.
|
||||||
|
-->
|
||||||
|
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||||
|
</requestedPrivileges>
|
||||||
|
</security>
|
||||||
|
</trustInfo>
|
||||||
|
|
||||||
|
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||||
|
<application>
|
||||||
|
<!-- A list of the Windows versions that this application has been tested on
|
||||||
|
and is designed to work with. Uncomment the appropriate elements
|
||||||
|
and Windows will automatically select the most compatible environment. -->
|
||||||
|
|
||||||
|
<!-- Windows Vista -->
|
||||||
|
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->
|
||||||
|
|
||||||
|
<!-- Windows 7 -->
|
||||||
|
<!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />-->
|
||||||
|
|
||||||
|
<!-- Windows 8 -->
|
||||||
|
<!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />-->
|
||||||
|
|
||||||
|
<!-- Windows 8.1 -->
|
||||||
|
<!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />-->
|
||||||
|
|
||||||
|
<!-- Windows 10 -->
|
||||||
|
<!--<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />-->
|
||||||
|
|
||||||
|
</application>
|
||||||
|
</compatibility>
|
||||||
|
|
||||||
|
<!-- Indicates that the application is DPI-aware and will not be automatically scaled by Windows at higher
|
||||||
|
DPIs. Windows Presentation Foundation (WPF) applications are automatically DPI-aware and do not need
|
||||||
|
to opt in. Windows Forms applications targeting .NET Framework 4.6 that opt into this setting, should
|
||||||
|
also set the 'EnableWindowsFormsHighDpiAutoResizing' setting to 'true' in their app.config.
|
||||||
|
|
||||||
|
Makes the application long-path aware. See https://docs.microsoft.com/windows/win32/fileio/maximum-file-path-limitation -->
|
||||||
|
<!--
|
||||||
|
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<windowsSettings>
|
||||||
|
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
|
||||||
|
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
|
||||||
|
</windowsSettings>
|
||||||
|
</application>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Enable themes for Windows common controls and dialogs (Windows XP and later) -->
|
||||||
|
<!--
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity
|
||||||
|
type="win32"
|
||||||
|
name="Microsoft.Windows.Common-Controls"
|
||||||
|
version="6.0.0.0"
|
||||||
|
processorArchitecture="*"
|
||||||
|
publicKeyToken="6595b64144ccf1df"
|
||||||
|
language="*"
|
||||||
|
/>
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
-->
|
||||||
|
|
||||||
|
</assembly>
|
||||||
173
SCrawler.Updater/SCrawler.Updater.vbproj
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{71263EEE-E25F-44DD-B0A9-F09047C0BEEA}</ProjectGuid>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<StartupObject>Sub Main</StartupObject>
|
||||||
|
<RootNamespace>SCrawler</RootNamespace>
|
||||||
|
<AssemblyName>Updater</AssemblyName>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<MyType>Console</MyType>
|
||||||
|
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
<Deterministic>true</Deterministic>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<DefineDebug>true</DefineDebug>
|
||||||
|
<DefineTrace>true</DefineTrace>
|
||||||
|
<OutputPath>bin\Debug\Updater\</OutputPath>
|
||||||
|
<DocumentationFile>
|
||||||
|
</DocumentationFile>
|
||||||
|
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<DefineDebug>false</DefineDebug>
|
||||||
|
<DefineTrace>true</DefineTrace>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\Updater\</OutputPath>
|
||||||
|
<DocumentationFile>
|
||||||
|
</DocumentationFile>
|
||||||
|
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<OptionExplicit>On</OptionExplicit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<OptionCompare>Binary</OptionCompare>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<OptionStrict>Off</OptionStrict>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<OptionInfer>On</OptionInfer>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<ApplicationIcon>Content\Icons\RainbowIcon_48.ico</ApplicationIcon>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<ApplicationManifest>My Project\app.manifest</ApplicationManifest>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DefineDebug>true</DefineDebug>
|
||||||
|
<DefineTrace>true</DefineTrace>
|
||||||
|
<OutputPath>bin\x64\Debug\Updater\</OutputPath>
|
||||||
|
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||||
|
<DefineTrace>true</DefineTrace>
|
||||||
|
<OutputPath>bin\x64\Release\Updater\</OutputPath>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DefineDebug>true</DefineDebug>
|
||||||
|
<DefineTrace>true</DefineTrace>
|
||||||
|
<OutputPath>bin\x86\Debug\Updater\</OutputPath>
|
||||||
|
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||||
|
<DefineTrace>true</DefineTrace>
|
||||||
|
<OutputPath>bin\x86\Release\Updater\</OutputPath>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Deployment" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
|
<Reference Include="System.IO.Compression" />
|
||||||
|
<Reference Include="System.IO.Compression.FileSystem" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Import Include="Microsoft.VisualBasic" />
|
||||||
|
<Import Include="System" />
|
||||||
|
<Import Include="System.Collections" />
|
||||||
|
<Import Include="System.Collections.Generic" />
|
||||||
|
<Import Include="System.Data" />
|
||||||
|
<Import Include="System.Diagnostics" />
|
||||||
|
<Import Include="System.Linq" />
|
||||||
|
<Import Include="System.Xml.Linq" />
|
||||||
|
<Import Include="System.Threading.Tasks" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="MainMod.vb" />
|
||||||
|
<Compile Include="My Project\AssemblyInfo.vb" />
|
||||||
|
<Compile Include="My Project\Application.Designer.vb">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Application.myapp</DependentUpon>
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="My Project\Resources.Designer.vb">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<DependentUpon>Resources.resx</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="My Project\Settings.Designer.vb">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Settings.settings</DependentUpon>
|
||||||
|
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="My Project\Resources.resx">
|
||||||
|
<Generator>VbMyResourcesResXFileCodeGenerator</Generator>
|
||||||
|
<LastGenOutput>Resources.Designer.vb</LastGenOutput>
|
||||||
|
<CustomToolNamespace>My.Resources</CustomToolNamespace>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</EmbeddedResource>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include=".editorconfig" />
|
||||||
|
<None Include="My Project\app.manifest" />
|
||||||
|
<None Include="My Project\Application.myapp">
|
||||||
|
<Generator>MyApplicationCodeGenerator</Generator>
|
||||||
|
<LastGenOutput>Application.Designer.vb</LastGenOutput>
|
||||||
|
</None>
|
||||||
|
<None Include="My Project\Settings.settings">
|
||||||
|
<Generator>SettingsSingleFileGenerator</Generator>
|
||||||
|
<CustomToolNamespace>My</CustomToolNamespace>
|
||||||
|
<LastGenOutput>Settings.Designer.vb</LastGenOutput>
|
||||||
|
</None>
|
||||||
|
<None Include="App.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="Content\Icons\RainbowIcon_48.ico" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\MyUtilities\PersonalUtilities\PersonalUtilities.vbproj">
|
||||||
|
<Project>{8405896b-2685-4916-bc93-1fb514c323a9}</Project>
|
||||||
|
<Name>PersonalUtilities</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\SCrawler.Shared\SCrawler.Shared.vbproj">
|
||||||
|
<Project>{dc634700-24c7-42dd-bf8f-87e6cc54e625}</Project>
|
||||||
|
<Name>SCrawler.Shared</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
|
||||||
|
</Project>
|
||||||
@@ -62,6 +62,14 @@ Namespace API.YouTube.Base
|
|||||||
Channel = 2
|
Channel = 2
|
||||||
PlayList = 3
|
PlayList = 3
|
||||||
End Enum
|
End Enum
|
||||||
|
<Editor(GetType(EnumDropDownEditor), GetType(UITypeEditor)), Flags>
|
||||||
|
Public Enum YouTubeChannelTab As Integer
|
||||||
|
<EnumValue(IsNullValue:=True)>
|
||||||
|
All = 0
|
||||||
|
Videos = 1
|
||||||
|
Shorts = 3
|
||||||
|
Playlists = 10
|
||||||
|
End Enum
|
||||||
<Editor(GetType(EnumDropDownEditor), GetType(UITypeEditor))>
|
<Editor(GetType(EnumDropDownEditor), GetType(UITypeEditor))>
|
||||||
Public Enum Protocols As Integer
|
Public Enum Protocols As Integer
|
||||||
<EnumValue(ExcludeFromList:=True)>
|
<EnumValue(ExcludeFromList:=True)>
|
||||||
|
|||||||
@@ -43,11 +43,35 @@ Namespace API.YouTube.Base
|
|||||||
Return URL
|
Return URL
|
||||||
End Try
|
End Try
|
||||||
End Function
|
End Function
|
||||||
|
Public Shared Function StandardizeURL_Channel(ByVal URL As String, Optional ByVal Process As Boolean = True) As String
|
||||||
|
Try
|
||||||
|
Dim ct As YouTubeChannelTab = YouTubeChannelTab.All
|
||||||
|
Dim isMusic As Boolean = False
|
||||||
|
If Process AndAlso Info_GetUrlType(URL, isMusic,,,, ct) = YouTubeMediaType.Channel AndAlso Not isMusic Then
|
||||||
|
If Not ct = YouTubeChannelTab.All Then
|
||||||
|
Dim rValue$ = String.Empty
|
||||||
|
Select Case ct
|
||||||
|
Case YouTubeChannelTab.Videos : rValue = "/videos"
|
||||||
|
Case YouTubeChannelTab.Shorts : rValue = "/shorts"
|
||||||
|
Case YouTubeChannelTab.Playlists : rValue = "/playlists"
|
||||||
|
End Select
|
||||||
|
If Not rValue.IsEmptyString Then
|
||||||
|
Dim startIndx% = InStr(URL, rValue)
|
||||||
|
If startIndx > 0 Then URL = URL.Remove(startIndx - 1)
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Return URL
|
||||||
|
Catch ex As Exception
|
||||||
|
Return URL
|
||||||
|
End Try
|
||||||
|
End Function
|
||||||
Public Shared Function IsMyUrl(ByVal URL As String) As Boolean
|
Public Shared Function IsMyUrl(ByVal URL As String) As Boolean
|
||||||
Return Not Info_GetUrlType(URL) = YouTubeMediaType.Undefined
|
Return Not Info_GetUrlType(URL) = YouTubeMediaType.Undefined
|
||||||
End Function
|
End Function
|
||||||
Public Shared Function Info_GetUrlType(ByVal URL As String, Optional ByRef IsMusic As Boolean = False, Optional ByRef IsShorts As Boolean = False,
|
Public Shared Function Info_GetUrlType(ByVal URL As String, Optional ByRef IsMusic As Boolean = False, Optional ByRef IsShorts As Boolean = False,
|
||||||
Optional ByRef IsChannelUser As Boolean = False, Optional ByRef Id As String = Nothing) As YouTubeMediaType
|
Optional ByRef IsChannelUser As Boolean = False, Optional ByRef Id As String = Nothing,
|
||||||
|
Optional ByRef ChannelOptions As YouTubeChannelTab = YouTubeChannelTab.All) As YouTubeMediaType
|
||||||
If Not URL.IsEmptyString Then
|
If Not URL.IsEmptyString Then
|
||||||
IsMusic = URL.Contains("music.youtube.com")
|
IsMusic = URL.Contains("music.youtube.com")
|
||||||
IsChannelUser = False
|
IsChannelUser = False
|
||||||
@@ -60,7 +84,17 @@ Namespace API.YouTube.Base
|
|||||||
Case "watch" : Return YouTubeMediaType.Single
|
Case "watch" : Return YouTubeMediaType.Single
|
||||||
Case "shorts" : IsShorts = True : Return YouTubeMediaType.Single
|
Case "shorts" : IsShorts = True : Return YouTubeMediaType.Single
|
||||||
Case "playlist" : Return YouTubeMediaType.PlayList
|
Case "playlist" : Return YouTubeMediaType.PlayList
|
||||||
Case UserChannelOption, "@" : IsChannelUser = data(2).ToLower = UserChannelOption : Return YouTubeMediaType.Channel
|
Case UserChannelOption, "@"
|
||||||
|
IsChannelUser = data(2).ToLower = UserChannelOption
|
||||||
|
If data.Count > 6 Then
|
||||||
|
Select Case data(6).StringToLower.StringTrimStart("/")
|
||||||
|
Case "videos" : ChannelOptions = YouTubeChannelTab.Videos
|
||||||
|
Case "shorts" : ChannelOptions = YouTubeChannelTab.Shorts
|
||||||
|
Case "playlists" : ChannelOptions = YouTubeChannelTab.Playlists
|
||||||
|
Case Else : ChannelOptions = YouTubeChannelTab.All
|
||||||
|
End Select
|
||||||
|
End If
|
||||||
|
Return YouTubeMediaType.Channel
|
||||||
End Select
|
End Select
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
@@ -82,27 +116,25 @@ Namespace API.YouTube.Base
|
|||||||
''' <exception cref="InvalidOperationException"></exception>
|
''' <exception cref="InvalidOperationException"></exception>
|
||||||
Public Shared Function Parse(ByVal URL As String, Optional ByVal UseCookies As Boolean? = Nothing,
|
Public Shared Function Parse(ByVal URL As String, Optional ByVal UseCookies As Boolean? = Nothing,
|
||||||
Optional ByVal Token As Threading.CancellationToken = Nothing, Optional ByVal Progress As IMyProgress = Nothing,
|
Optional ByVal Token As Threading.CancellationToken = Nothing, Optional ByVal Progress As IMyProgress = Nothing,
|
||||||
Optional ByVal GetDefault As Boolean? = Nothing, Optional ByVal GetShorts As Boolean? = Nothing,
|
Optional ByVal DateAfter As Date? = Nothing, Optional ByVal DateBefore As Date? = Nothing,
|
||||||
Optional ByVal DateAfter As Date? = Nothing, Optional ByVal DateBefore As Date? = Nothing) As IYouTubeMediaContainer
|
Optional ByVal ChannelOption As YouTubeChannelTab? = Nothing, Optional ByVal UrlAsIs As Boolean = False) As IYouTubeMediaContainer
|
||||||
If URL.IsEmptyString Then Throw New ArgumentNullException("URL", "URL cannot be null")
|
If URL.IsEmptyString Then Throw New ArgumentNullException("URL", "URL cannot be null")
|
||||||
If Not MyYouTubeSettings.YTDLP.Value.Exists Then Throw New IO.FileNotFoundException("Path to 'yt-dlp.exe' not set or program not found at destination", MyYouTubeSettings.YTDLP.Value.ToString)
|
If Not MyYouTubeSettings.YTDLP.Value.Exists Then Throw New IO.FileNotFoundException("Path to 'yt-dlp.exe' not set or program not found at destination", MyYouTubeSettings.YTDLP.Value.ToString)
|
||||||
Dim urlOrig$ = URL
|
Dim urlOrig$ = URL
|
||||||
URL = RegexReplace(URL, TrueUrlRegEx)
|
URL = RegexReplace(URL, TrueUrlRegEx)
|
||||||
If URL.IsEmptyString Then Throw New ArgumentNullException("URL", $"Can't get true URL from [{urlOrig}]")
|
If URL.IsEmptyString Then Throw New ArgumentNullException("URL", $"Can't get true URL from [{urlOrig}]")
|
||||||
Dim isMusic As Boolean = False, isShorts As Boolean = False
|
Dim isMusic As Boolean = False, isShorts As Boolean = False
|
||||||
Dim objType As YouTubeMediaType = Info_GetUrlType(URL, isMusic, isShorts)
|
Dim channelTab As YouTubeChannelTab = YouTubeChannelTab.All
|
||||||
|
Dim objType As YouTubeMediaType = Info_GetUrlType(URL, isMusic, isShorts,,, channelTab)
|
||||||
|
If ChannelOption.HasValue Then channelTab = ChannelOption.Value
|
||||||
If Not objType = YouTubeMediaType.Undefined Then
|
If Not objType = YouTubeMediaType.Undefined Then
|
||||||
Dim __GetDefault As Boolean = If(GetDefault, True)
|
|
||||||
Dim __GetShorts As Boolean = If(GetShorts, True)
|
|
||||||
If isMusic Then __GetShorts = False
|
|
||||||
Dim container As IYouTubeMediaContainer
|
Dim container As IYouTubeMediaContainer
|
||||||
Dim pattern$ = "%(channel_id)s_%(id)s_%(playlist_index)s"
|
Dim pattern$ = "%(channel_id)s_%(id)s_%(playlist_index)s"
|
||||||
|
|
||||||
Select Case objType
|
Select Case objType
|
||||||
Case YouTubeMediaType.Single
|
Case YouTubeMediaType.Single
|
||||||
__GetShorts = False
|
|
||||||
If isMusic Then container = New Track Else container = New Video
|
If isMusic Then container = New Track Else container = New Video
|
||||||
Case YouTubeMediaType.PlayList : container = New PlayList : pattern = "%(playlist_index)s_%(id)s" : __GetShorts = False
|
Case YouTubeMediaType.PlayList : container = New PlayList : pattern = "%(playlist_index)s_%(id)s"
|
||||||
Case YouTubeMediaType.Channel
|
Case YouTubeMediaType.Channel
|
||||||
container = New Channel
|
container = New Channel
|
||||||
If isMusic Then pattern = "%(playlist_id)s/%(channel_id)s_%(id)s_%(playlist_index)s"
|
If isMusic Then pattern = "%(playlist_id)s/%(channel_id)s_%(id)s_%(playlist_index)s"
|
||||||
@@ -121,11 +153,11 @@ Namespace API.YouTube.Base
|
|||||||
Dim useCookiesForce As Boolean = UseCookies.HasValue AndAlso UseCookies.Value AndAlso cookiesExists
|
Dim useCookiesForce As Boolean = UseCookies.HasValue AndAlso UseCookies.Value AndAlso cookiesExists
|
||||||
If UseCookies.HasValue AndAlso UseCookies.Value Then
|
If UseCookies.HasValue AndAlso UseCookies.Value Then
|
||||||
withCookieRequested = True
|
withCookieRequested = True
|
||||||
result = Parse_Internal(URL, pattern, _CachePathDefault, True, YouTubeCookieNetscapeFile, DateAfter, DateBefore, __GetDefault, __GetShorts)
|
result = Parse_Internal(URL, pattern, _CachePathDefault, True, YouTubeCookieNetscapeFile, DateAfter, DateBefore, objType, channelTab, isMusic, UrlAsIs)
|
||||||
End If
|
End If
|
||||||
If Not result And Not withCookieRequested Then
|
If Not result And Not withCookieRequested Then
|
||||||
If Not UseCookies.HasValue OrElse Not UseCookies.Value Then result = Parse_Internal(URL, pattern, _CachePathDefault, False, YouTubeCookieNetscapeFile, DateAfter, DateBefore, __GetDefault, __GetShorts)
|
If Not UseCookies.HasValue OrElse Not UseCookies.Value Then result = Parse_Internal(URL, pattern, _CachePathDefault, False, YouTubeCookieNetscapeFile, DateAfter, DateBefore, objType, channelTab, isMusic, UrlAsIs)
|
||||||
If Not result And Not UseCookies.HasValue And cookiesExists Then result = Parse_Internal(URL, pattern, _CachePathDefault, True, YouTubeCookieNetscapeFile, DateAfter, DateBefore, __GetDefault, __GetShorts)
|
If Not result And Not UseCookies.HasValue And cookiesExists Then result = Parse_Internal(URL, pattern, _CachePathDefault, True, YouTubeCookieNetscapeFile, DateAfter, DateBefore, objType, channelTab, isMusic, UrlAsIs)
|
||||||
End If
|
End If
|
||||||
|
|
||||||
If result Then
|
If result Then
|
||||||
@@ -139,21 +171,40 @@ Namespace API.YouTube.Base
|
|||||||
Private Shared Function Parse_Internal(ByVal URL As String, ByVal OutputPattern As String, ByVal OutputPath As SFile,
|
Private Shared Function Parse_Internal(ByVal URL As String, ByVal OutputPattern As String, ByVal OutputPath As SFile,
|
||||||
ByVal UseCookies As Boolean, ByVal CookiesFile As SFile,
|
ByVal UseCookies As Boolean, ByVal CookiesFile As SFile,
|
||||||
ByVal DateAfter As Date?, ByVal DateBefore As Date?,
|
ByVal DateAfter As Date?, ByVal DateBefore As Date?,
|
||||||
ByVal GetDefault As Boolean, ByVal GetShorts As Boolean) As Boolean
|
ByVal ObjType As YouTubeMediaType, ByVal ChannelTab As YouTubeChannelTab,
|
||||||
|
ByVal IsMusic As Boolean, ByVal UrlAsIs As Boolean) As Boolean
|
||||||
Try
|
Try
|
||||||
Dim command$ = "yt-dlp --write-info-json --skip-download"
|
Dim command$ = "yt-dlp --write-info-json --skip-download"
|
||||||
command.StringAppend(GetCookiesCommand(UseCookies, CookiesFile), " ")
|
command.StringAppend(GetCookiesCommand(UseCookies, CookiesFile), " ")
|
||||||
If DateAfter.HasValue Then command.StringAppend($"--dateafter {DateAfter.Value:yyyyMMdd}", " ")
|
If DateAfter.HasValue Then command.StringAppend($"--dateafter {DateAfter.Value:yyyyMMdd}", " ")
|
||||||
If DateBefore.HasValue Then command.StringAppend($"--datebefore {DateBefore.Value:yyyyMMdd}", " ")
|
If DateBefore.HasValue Then command.StringAppend($"--datebefore {DateBefore.Value:yyyyMMdd}", " ")
|
||||||
command.StringAppend("{0}" & $" -o ""{OutputPattern}""", " ")
|
command.StringAppend("{0}" & $" -o ""{OutputPattern}""", " ")
|
||||||
|
'#If DEBUG Then
|
||||||
|
'Debug.WriteLine(String.Format(command, URL))
|
||||||
|
'#End If
|
||||||
|
Dim debugString As Func(Of String, String) = Function(ByVal input As String) As String
|
||||||
#If DEBUG Then
|
#If DEBUG Then
|
||||||
Debug.WriteLine(String.Format(command, URL))
|
Debug.WriteLine(input)
|
||||||
#End If
|
#End If
|
||||||
|
Return input
|
||||||
|
End Function
|
||||||
Using batch As New BatchExecutor(True)
|
Using batch As New BatchExecutor(True)
|
||||||
With batch
|
With batch
|
||||||
.CommandPermanent = BatchExecutor.GetDirectoryCommand(MyYouTubeSettings.YTDLP.Value)
|
.CommandPermanent = BatchExecutor.GetDirectoryCommand(MyYouTubeSettings.YTDLP.Value)
|
||||||
If GetDefault Then .Execute(String.Format(command, URL))
|
If ObjType = YouTubeMediaType.Channel And Not IsMusic And Not UrlAsIs Then
|
||||||
If GetShorts Then .Execute(String.Format(command, $"{URL.StringTrimEnd("/")}/shorts"))
|
Dim ct As List(Of YouTubeChannelTab) = EnumExtract(Of YouTubeChannelTab)(ChannelTab,, True).ListIfNothing
|
||||||
|
If ct.Count = 0 Then
|
||||||
|
.Execute(debugString(String.Format(command, $"{URL.StringTrimEnd("/")}/videos")))
|
||||||
|
.Execute(debugString(String.Format(command, $"{URL.StringTrimEnd("/")}/shorts")))
|
||||||
|
.Execute(debugString(String.Format(command, $"{URL.StringTrimEnd("/")}/playlists")))
|
||||||
|
Else
|
||||||
|
If ct.Contains(YouTubeChannelTab.Videos) Then .Execute(debugString(String.Format(command, $"{URL.StringTrimEnd("/")}/videos")))
|
||||||
|
If ct.Contains(YouTubeChannelTab.Shorts) Then .Execute(debugString(String.Format(command, $"{URL.StringTrimEnd("/")}/shorts")))
|
||||||
|
If ct.Contains(YouTubeChannelTab.Playlists) Then .Execute(debugString(String.Format(command, $"{URL.StringTrimEnd("/")}/playlists")))
|
||||||
|
End If
|
||||||
|
Else
|
||||||
|
.Execute(debugString(String.Format(command, URL)))
|
||||||
|
End If
|
||||||
End With
|
End With
|
||||||
End Using
|
End Using
|
||||||
Return SFile.GetFiles(OutputPath,, IO.SearchOption.AllDirectories, EDP.ReturnValue).Count > 0
|
Return SFile.GetFiles(OutputPath,, IO.SearchOption.AllDirectories, EDP.ReturnValue).Count > 0
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ Imports PersonalUtilities.Forms
|
|||||||
Imports PersonalUtilities.Functions.XML
|
Imports PersonalUtilities.Functions.XML
|
||||||
Imports PersonalUtilities.Functions.XML.Base
|
Imports PersonalUtilities.Functions.XML.Base
|
||||||
Imports PersonalUtilities.Functions.XML.Objects
|
Imports PersonalUtilities.Functions.XML.Objects
|
||||||
|
Imports PersonalUtilities.Functions.XML.Attributes
|
||||||
Imports PersonalUtilities.Functions.XML.Attributes.Specialized
|
Imports PersonalUtilities.Functions.XML.Attributes.Specialized
|
||||||
Imports PersonalUtilities.Tools
|
Imports PersonalUtilities.Tools
|
||||||
Imports PersonalUtilities.Tools.Grid.Base
|
Imports PersonalUtilities.Tools.Grid.Base
|
||||||
@@ -132,6 +133,8 @@ Namespace API.YouTube.Base
|
|||||||
OpenFolderInOtherProgram.Value = command
|
OpenFolderInOtherProgram.Value = command
|
||||||
End Set
|
End Set
|
||||||
End Property
|
End Property
|
||||||
|
<Browsable(True), GridVisible(False), XMLVN({"Environment"}, True), Category("Environment"), DisplayName("Check new version at start")>
|
||||||
|
Friend ReadOnly Property CheckUpdatesAtStart As XMLValue(Of Boolean)
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Info"
|
#Region "Info"
|
||||||
<Browsable(True), GridVisible, XMLVN({"Info"}), Category("Info"), DisplayName("Create URL files"),
|
<Browsable(True), GridVisible, XMLVN({"Info"}), Category("Info"), DisplayName("Create URL files"),
|
||||||
@@ -145,6 +148,12 @@ 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 thumbnail files (video)"),
|
||||||
|
Description("Create video thumbnail files. Default: true.")>
|
||||||
|
Public ReadOnly Property CreateThumbnails_Video As XMLValue(Of Boolean)
|
||||||
|
<Browsable(True), GridVisible, XMLVN({"Info"}, True), Category("Info"), DisplayName("Create thumbnail files (music)"),
|
||||||
|
Description("Create music thumbnail files (covers). Default: true.")>
|
||||||
|
Public ReadOnly Property CreateThumbnails_Music As XMLValue(Of Boolean)
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Defaults"
|
#Region "Defaults"
|
||||||
<Browsable(True), GridVisible, XMLVN({"Defaults"}, True), Category("Defaults"), DisplayName("Standardize URLs"),
|
<Browsable(True), GridVisible, XMLVN({"Defaults"}, True), Category("Defaults"), DisplayName("Standardize URLs"),
|
||||||
@@ -221,6 +230,38 @@ Namespace API.YouTube.Base
|
|||||||
Description("Add some additional info to the program info if you need")>
|
Description("Add some additional info to the program info if you need")>
|
||||||
Friend ReadOnly Property ProgramDescription As XMLValue(Of String)
|
Friend ReadOnly Property ProgramDescription As XMLValue(Of String)
|
||||||
#End Region
|
#End Region
|
||||||
|
#Region "Defaults ChannelsDownload"
|
||||||
|
<Browsable(True), GridVisible, XMLVN({"Defaults", "Channels"}), Category("Defaults"), DisplayName("Default download tabs for channels"),
|
||||||
|
Description("Default download tabs for downloading channels"), TypeConverter(GetType(YouTubeChannelTabConverter))>
|
||||||
|
Public ReadOnly Property ChannelsDownload As XMLValue(Of YouTubeChannelTab)
|
||||||
|
Private Class YouTubeChannelTabConverter : Inherits TypeConverter
|
||||||
|
Public Overrides Function ConvertTo(ByVal Context As ITypeDescriptorContext, ByVal Culture As CultureInfo, ByVal Value As Object,
|
||||||
|
ByVal DestinationType As Type) As Object
|
||||||
|
If Not DestinationType Is Nothing Then
|
||||||
|
If DestinationType Is GetType(String) Then
|
||||||
|
If IsNothing(Value) Then
|
||||||
|
Return YouTubeChannelTab.All.ToString
|
||||||
|
Else
|
||||||
|
Dim v As List(Of YouTubeChannelTab) = EnumExtract(Of YouTubeChannelTab)(Value,,, EDP.ReturnValue).ListIfNothing
|
||||||
|
If v.ListExists Then
|
||||||
|
v.Sort()
|
||||||
|
Return v.ListToStringE(, New ANumbers.EnumToStringProvider(GetType(YouTubeChannelTab)))
|
||||||
|
Else
|
||||||
|
Return YouTubeChannelTab.All.ToString
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Else
|
||||||
|
If IsNothing(Value) Then
|
||||||
|
Return YouTubeChannelTab.All
|
||||||
|
Else
|
||||||
|
Return Value
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Return MyBase.ConvertTo(Context, Culture, Value, DestinationType)
|
||||||
|
End Function
|
||||||
|
End Class
|
||||||
|
#End Region
|
||||||
#Region "Defaults Video"
|
#Region "Defaults Video"
|
||||||
<Browsable(True), GridVisible, XMLVN({"DefaultsVideo"}, "MKV"), Category("Defaults Video"), DisplayName("Default format"),
|
<Browsable(True), GridVisible, XMLVN({"DefaultsVideo"}, "MKV"), Category("Defaults Video"), DisplayName("Default format"),
|
||||||
TypeConverter(GetType(FieldsTypeConverter)), GridStandardValuesProvider(NameOf(AvailableVideoFormats_Impl)),
|
TypeConverter(GetType(FieldsTypeConverter)), GridStandardValuesProvider(NameOf(AvailableVideoFormats_Impl)),
|
||||||
@@ -232,9 +273,77 @@ 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"}, False), Category("Defaults Video"), DisplayName("Embed thumbnail (video)"),
|
||||||
|
Description("Embed thumbnail in the video as cover art. Default: true.")>
|
||||||
|
Public ReadOnly Property DefaultVideoEmbedThumbnail As XMLValue(Of Boolean)
|
||||||
<Browsable(True), GridVisible, XMLVN({"DefaultsVideo"}), Category("Defaults Video"), DisplayName("Include zero size formats"),
|
<Browsable(True), GridVisible, XMLVN({"DefaultsVideo"}), Category("Defaults Video"), DisplayName("Include zero size formats"),
|
||||||
Description("Include formats with zero size (or undefined size).")>
|
Description("Include formats with zero size (or undefined size).")>
|
||||||
Public ReadOnly Property DefaultVideoIncludeNullSize As XMLValue(Of Boolean)
|
Public ReadOnly Property DefaultVideoIncludeNullSize As XMLValue(Of Boolean)
|
||||||
|
<Browsable(False), XMLV("DefaultVideoFPS", {"DefaultsVideo"}, -1)>
|
||||||
|
Private ReadOnly Property DefaultVideoFPS_XML As XMLValue(Of Double)
|
||||||
|
<Browsable(True), GridVisible, Category("Defaults Video"), DisplayName("Default video FPS"),
|
||||||
|
Description("Set default video FPS (only to reduce video FPS). Default: -1 (disabled)."),
|
||||||
|
TypeConverter(GetType(FieldsTypeConverter)), GridFormatProvider(GetType(FpsFormatProvider))>
|
||||||
|
Public Property DefaultVideoFPS As Double
|
||||||
|
Get
|
||||||
|
Return DefaultVideoFPS_XML
|
||||||
|
End Get
|
||||||
|
Set(ByVal fps As Double)
|
||||||
|
DefaultVideoFPS_XML.Value = fps
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
Private Function ShouldSerializeDefaultVideoFPS() As Boolean
|
||||||
|
Return DefaultVideoFPS <> DefaultVideoFPS_XML.Value
|
||||||
|
End Function
|
||||||
|
Private Sub ResetDefaultVideoFPS()
|
||||||
|
DefaultVideoFPS = -1
|
||||||
|
End Sub
|
||||||
|
Friend Class FpsFormatProvider : Implements IGridConversionProvider
|
||||||
|
Private Property Converter As TypeConverter Implements IGridConversionProvider.Converter
|
||||||
|
Private Property Context As ITypeDescriptorContext Implements IGridConversionProvider.Context
|
||||||
|
Private Property DataType As Type Implements IGridConversionProvider.DataType
|
||||||
|
Private Property Instance As Object Implements IGridConversionProvider.Instance
|
||||||
|
Friend Shared ReadOnly Property MyProviderDefault As ANumbers
|
||||||
|
Get
|
||||||
|
Return New ANumbers(ANumbers.Cultures.Primitive) With {.DecimalDigits = 5, .TrimDecimalDigits = True}
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
Friend Const ErrorMessageDefault As String = "The fps value must be a number"
|
||||||
|
Private ReadOnly MyProvider As ANumbers = MyProviderDefault
|
||||||
|
Friend Function ToObject(ByVal Context As ITypeDescriptorContext, ByVal Culture As CultureInfo, ByVal Value As Object) As Object Implements IGridConversionProvider.ToObject
|
||||||
|
Return AConvert(Of Double)(Value, MyProvider, -1)
|
||||||
|
End Function
|
||||||
|
Friend Overloads Function ToString(ByVal Context As ITypeDescriptorContext, ByVal Culture As CultureInfo, ByVal Value As Object,
|
||||||
|
ByVal DestinationType As Type) As Object Implements IGridConversionProvider.ToString
|
||||||
|
If ACheck(Of Double)(Value, AModes.Var, MyProvider) Then
|
||||||
|
Return Value.ToString
|
||||||
|
Else
|
||||||
|
Return -1
|
||||||
|
End If
|
||||||
|
End Function
|
||||||
|
Friend Function CreateInstance(ByVal Context As ITypeDescriptorContext, ByVal NewValue As Object, ByRef RefreshGrid As Boolean) As Object Implements IGridConversionProvider.CreateInstance
|
||||||
|
If ACheck(Of Double)(NewValue, AModes.Var, MyProvider) Then
|
||||||
|
Return NewValue
|
||||||
|
Else
|
||||||
|
RefreshGrid = True
|
||||||
|
Return -1
|
||||||
|
End If
|
||||||
|
End Function
|
||||||
|
Friend Function Convert(ByVal Value As Object, ByVal DestinationType As Type, ByVal Provider As IFormatProvider,
|
||||||
|
Optional ByVal NothingArg As Object = Nothing, Optional ByVal e As ErrorsDescriber = Nothing) As Object Implements ICustomProvider.Convert
|
||||||
|
Return AConvert(Value, AModes.Var, DestinationType,, True, -1, MyProvider, EDP.ReturnValue)
|
||||||
|
End Function
|
||||||
|
Friend Function IsValid(ByVal Context As ITypeDescriptorContext, ByVal Value As Object, ByVal DestinationType As Type) As Boolean Implements IGridValidator.IsValid
|
||||||
|
If ACheck(Of Double)(Value, AModes.Var, MyProvider) Then
|
||||||
|
Return True
|
||||||
|
Else
|
||||||
|
Throw New FormatException(ErrorMessageDefault)
|
||||||
|
End If
|
||||||
|
End Function
|
||||||
|
Private Function GetFormat(ByVal FormatType As Type) As Object Implements IFormatProvider.GetFormat
|
||||||
|
Throw New NotImplementedException("'GetFormat' is not available in 'FpsFormatProvider'")
|
||||||
|
End Function
|
||||||
|
End Class
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Defaults Audio"
|
#Region "Defaults Audio"
|
||||||
<Browsable(True), GridVisible, XMLVN({"DefaultsAudio"}, "AAC"), Category("Defaults Audio"), DisplayName("Default codec"),
|
<Browsable(True), GridVisible, XMLVN({"DefaultsAudio"}, "AAC"), Category("Defaults Audio"), DisplayName("Default codec"),
|
||||||
@@ -254,6 +363,9 @@ Namespace API.YouTube.Base
|
|||||||
TypeConverter(GetType(ValueCollectionConverter)),
|
TypeConverter(GetType(ValueCollectionConverter)),
|
||||||
Description("Additional audio format for downloading videos. This means that the audio will be extracted and saved as a separate file in these formats.")>
|
Description("Additional audio format for downloading videos. This means that the audio will be extracted and saved as a separate file in these formats.")>
|
||||||
Public ReadOnly Property DefaultAudioCodecAddit As XMLValuesCollection(Of String)
|
Public ReadOnly Property DefaultAudioCodecAddit As XMLValuesCollection(Of String)
|
||||||
|
<Browsable(True), GridVisible, XMLVN({"DefaultsAudio"}, True), Category("Defaults Audio"), DisplayName("Embed thumbnail"),
|
||||||
|
Description("Embed thumbnail in the audio as cover art. Default: true.")>
|
||||||
|
Public ReadOnly Property DefaultAudioEmbedThumbnail As XMLValue(Of Boolean)
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Defaults Subtitles"
|
#Region "Defaults Subtitles"
|
||||||
<XMLVN({"DefaultsSubtitles"}, {"en"}, CollectionMode:=IXMLValuesCollection.Modes.String)>
|
<XMLVN({"DefaultsSubtitles"}, {"en"}, CollectionMode:=IXMLValuesCollection.Modes.String)>
|
||||||
|
|||||||
179
SCrawler.YouTube/Controls/ChannelTabsChooserForm.Designer.vb
generated
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
' 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 ChannelTabsChooserForm : Inherits System.Windows.Forms.Form
|
||||||
|
<System.Diagnostics.DebuggerNonUserCode()>
|
||||||
|
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
|
||||||
|
Try
|
||||||
|
If disposing AndAlso components IsNot Nothing Then
|
||||||
|
components.Dispose()
|
||||||
|
End If
|
||||||
|
Finally
|
||||||
|
MyBase.Dispose(disposing)
|
||||||
|
End Try
|
||||||
|
End Sub
|
||||||
|
Private components As System.ComponentModel.IContainer
|
||||||
|
<System.Diagnostics.DebuggerStepThrough()>
|
||||||
|
Private Sub InitializeComponent()
|
||||||
|
Dim CONTAINER_MAIN As System.Windows.Forms.ToolStripContainer
|
||||||
|
Dim TP_MAIN As System.Windows.Forms.TableLayoutPanel
|
||||||
|
Me.CH_ALL = New System.Windows.Forms.CheckBox()
|
||||||
|
Me.CH_VIDEOS = New System.Windows.Forms.CheckBox()
|
||||||
|
Me.CH_SHORTS = New System.Windows.Forms.CheckBox()
|
||||||
|
Me.CH_PLS = New System.Windows.Forms.CheckBox()
|
||||||
|
Me.TXT_URL = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
||||||
|
Me.CH_URL_ASIS = New System.Windows.Forms.CheckBox()
|
||||||
|
CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer()
|
||||||
|
TP_MAIN = New System.Windows.Forms.TableLayoutPanel()
|
||||||
|
CONTAINER_MAIN.ContentPanel.SuspendLayout()
|
||||||
|
CONTAINER_MAIN.SuspendLayout()
|
||||||
|
TP_MAIN.SuspendLayout()
|
||||||
|
CType(Me.TXT_URL, System.ComponentModel.ISupportInitialize).BeginInit()
|
||||||
|
Me.SuspendLayout()
|
||||||
|
'
|
||||||
|
'CONTAINER_MAIN
|
||||||
|
'
|
||||||
|
'
|
||||||
|
'CONTAINER_MAIN.ContentPanel
|
||||||
|
'
|
||||||
|
CONTAINER_MAIN.ContentPanel.Controls.Add(TP_MAIN)
|
||||||
|
CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(474, 159)
|
||||||
|
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(474, 184)
|
||||||
|
CONTAINER_MAIN.TabIndex = 0
|
||||||
|
CONTAINER_MAIN.TopToolStripPanelVisible = False
|
||||||
|
'
|
||||||
|
'TP_MAIN
|
||||||
|
'
|
||||||
|
TP_MAIN.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single]
|
||||||
|
TP_MAIN.ColumnCount = 1
|
||||||
|
TP_MAIN.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||||
|
TP_MAIN.Controls.Add(Me.CH_ALL, 0, 2)
|
||||||
|
TP_MAIN.Controls.Add(Me.CH_VIDEOS, 0, 3)
|
||||||
|
TP_MAIN.Controls.Add(Me.CH_SHORTS, 0, 4)
|
||||||
|
TP_MAIN.Controls.Add(Me.CH_PLS, 0, 5)
|
||||||
|
TP_MAIN.Controls.Add(Me.TXT_URL, 0, 0)
|
||||||
|
TP_MAIN.Controls.Add(Me.CH_URL_ASIS, 0, 1)
|
||||||
|
TP_MAIN.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
TP_MAIN.Location = New System.Drawing.Point(0, 0)
|
||||||
|
TP_MAIN.Name = "TP_MAIN"
|
||||||
|
TP_MAIN.RowCount = 7
|
||||||
|
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
|
||||||
|
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||||
|
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||||
|
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||||
|
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||||
|
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||||
|
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||||
|
TP_MAIN.Size = New System.Drawing.Size(474, 159)
|
||||||
|
TP_MAIN.TabIndex = 0
|
||||||
|
'
|
||||||
|
'CH_ALL
|
||||||
|
'
|
||||||
|
Me.CH_ALL.AutoSize = True
|
||||||
|
Me.CH_ALL.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.CH_ALL.Location = New System.Drawing.Point(4, 59)
|
||||||
|
Me.CH_ALL.Name = "CH_ALL"
|
||||||
|
Me.CH_ALL.Size = New System.Drawing.Size(466, 19)
|
||||||
|
Me.CH_ALL.TabIndex = 2
|
||||||
|
Me.CH_ALL.Text = "ALL"
|
||||||
|
Me.CH_ALL.UseVisualStyleBackColor = True
|
||||||
|
'
|
||||||
|
'CH_VIDEOS
|
||||||
|
'
|
||||||
|
Me.CH_VIDEOS.AutoSize = True
|
||||||
|
Me.CH_VIDEOS.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.CH_VIDEOS.Location = New System.Drawing.Point(4, 85)
|
||||||
|
Me.CH_VIDEOS.Name = "CH_VIDEOS"
|
||||||
|
Me.CH_VIDEOS.Size = New System.Drawing.Size(466, 19)
|
||||||
|
Me.CH_VIDEOS.TabIndex = 3
|
||||||
|
Me.CH_VIDEOS.Text = "Videos"
|
||||||
|
Me.CH_VIDEOS.UseVisualStyleBackColor = True
|
||||||
|
'
|
||||||
|
'CH_SHORTS
|
||||||
|
'
|
||||||
|
Me.CH_SHORTS.AutoSize = True
|
||||||
|
Me.CH_SHORTS.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.CH_SHORTS.Location = New System.Drawing.Point(4, 111)
|
||||||
|
Me.CH_SHORTS.Name = "CH_SHORTS"
|
||||||
|
Me.CH_SHORTS.Size = New System.Drawing.Size(466, 19)
|
||||||
|
Me.CH_SHORTS.TabIndex = 4
|
||||||
|
Me.CH_SHORTS.Text = "Shorts"
|
||||||
|
Me.CH_SHORTS.UseVisualStyleBackColor = True
|
||||||
|
'
|
||||||
|
'CH_PLS
|
||||||
|
'
|
||||||
|
Me.CH_PLS.AutoSize = True
|
||||||
|
Me.CH_PLS.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.CH_PLS.Location = New System.Drawing.Point(4, 137)
|
||||||
|
Me.CH_PLS.Name = "CH_PLS"
|
||||||
|
Me.CH_PLS.Size = New System.Drawing.Size(466, 19)
|
||||||
|
Me.CH_PLS.TabIndex = 5
|
||||||
|
Me.CH_PLS.Text = "Playlists"
|
||||||
|
Me.CH_PLS.UseVisualStyleBackColor = True
|
||||||
|
'
|
||||||
|
'TXT_URL
|
||||||
|
'
|
||||||
|
Me.TXT_URL.CaptionText = "Channel URL"
|
||||||
|
Me.TXT_URL.CaptionWidth = 80.0R
|
||||||
|
Me.TXT_URL.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.TXT_URL.Location = New System.Drawing.Point(4, 4)
|
||||||
|
Me.TXT_URL.Name = "TXT_URL"
|
||||||
|
Me.TXT_URL.Size = New System.Drawing.Size(466, 22)
|
||||||
|
Me.TXT_URL.TabIndex = 0
|
||||||
|
'
|
||||||
|
'CH_URL_ASIS
|
||||||
|
'
|
||||||
|
Me.CH_URL_ASIS.AutoSize = True
|
||||||
|
Me.CH_URL_ASIS.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.CH_URL_ASIS.Location = New System.Drawing.Point(4, 33)
|
||||||
|
Me.CH_URL_ASIS.Name = "CH_URL_ASIS"
|
||||||
|
Me.CH_URL_ASIS.Size = New System.Drawing.Size(466, 19)
|
||||||
|
Me.CH_URL_ASIS.TabIndex = 1
|
||||||
|
Me.CH_URL_ASIS.Text = "Download URL as is"
|
||||||
|
Me.CH_URL_ASIS.UseVisualStyleBackColor = True
|
||||||
|
'
|
||||||
|
'ChannelTabsChooserForm
|
||||||
|
'
|
||||||
|
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
|
||||||
|
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
|
||||||
|
Me.ClientSize = New System.Drawing.Size(474, 184)
|
||||||
|
Me.Controls.Add(CONTAINER_MAIN)
|
||||||
|
Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle
|
||||||
|
Me.Icon = Global.SCrawler.My.Resources.SiteYouTube.YouTubeIcon_32
|
||||||
|
Me.MaximizeBox = False
|
||||||
|
Me.MaximumSize = New System.Drawing.Size(490, 223)
|
||||||
|
Me.MinimizeBox = False
|
||||||
|
Me.MinimumSize = New System.Drawing.Size(490, 223)
|
||||||
|
Me.Name = "ChannelTabsChooserForm"
|
||||||
|
Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide
|
||||||
|
Me.Text = "Tabs"
|
||||||
|
CONTAINER_MAIN.ContentPanel.ResumeLayout(False)
|
||||||
|
CONTAINER_MAIN.ResumeLayout(False)
|
||||||
|
CONTAINER_MAIN.PerformLayout()
|
||||||
|
TP_MAIN.ResumeLayout(False)
|
||||||
|
TP_MAIN.PerformLayout()
|
||||||
|
CType(Me.TXT_URL, System.ComponentModel.ISupportInitialize).EndInit()
|
||||||
|
Me.ResumeLayout(False)
|
||||||
|
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
Private WithEvents CH_ALL As CheckBox
|
||||||
|
Private WithEvents CH_VIDEOS As CheckBox
|
||||||
|
Private WithEvents CH_SHORTS As CheckBox
|
||||||
|
Private WithEvents CH_PLS As CheckBox
|
||||||
|
Private WithEvents TXT_URL As PersonalUtilities.Forms.Controls.TextBoxExtended
|
||||||
|
Private WithEvents CH_URL_ASIS As CheckBox
|
||||||
|
End Class
|
||||||
|
End Namespace
|
||||||
126
SCrawler.YouTube/Controls/ChannelTabsChooserForm.resx
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<metadata name="CONTAINER_MAIN.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>False</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="TP_MAIN.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>False</value>
|
||||||
|
</metadata>
|
||||||
|
</root>
|
||||||
85
SCrawler.YouTube/Controls/ChannelTabsChooserForm.vb
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
' 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.Forms
|
||||||
|
Imports PersonalUtilities.Functions.XML
|
||||||
|
Imports PersonalUtilities.Functions.XML.Base
|
||||||
|
Imports SCrawler.API.YouTube.Base
|
||||||
|
Namespace API.YouTube.Controls
|
||||||
|
Friend Class ChannelTabsChooserForm : Implements IDesignXMLContainer
|
||||||
|
Private WithEvents MyDefs As DefaultFormOptions
|
||||||
|
Friend Property DesignXML As EContainer Implements IDesignXMLContainer.DesignXML
|
||||||
|
Private Property DesignXMLNodes As String() Implements IDesignXMLContainer.DesignXMLNodes
|
||||||
|
Private Property DesignXMLNodeName As String Implements IDesignXMLContainer.DesignXMLNodeName
|
||||||
|
Private _Result As YouTubeChannelTab = YouTubeChannelTab.All
|
||||||
|
Friend ReadOnly Property Result As YouTubeChannelTab
|
||||||
|
Get
|
||||||
|
Return _Result
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
Friend ReadOnly Property URL As String
|
||||||
|
Get
|
||||||
|
Return TXT_URL.Text
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
Friend ReadOnly Property MyUrlAsIs As Boolean
|
||||||
|
Get
|
||||||
|
Return CH_URL_ASIS.Checked
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
Friend Sub New(ByVal InitVal As YouTubeChannelTab, ByVal _URL As String)
|
||||||
|
InitializeComponent()
|
||||||
|
MyDefs = New DefaultFormOptions(Me)
|
||||||
|
_Result = InitVal
|
||||||
|
TXT_URL.Text = _URL
|
||||||
|
End Sub
|
||||||
|
Private Sub ChannelTabsChooserForm_Load(sender As Object, e As EventArgs) Handles Me.Load
|
||||||
|
Try
|
||||||
|
With MyDefs
|
||||||
|
MyDefs.MyXML = DesignXML
|
||||||
|
If Not DesignXML Is Nothing Then .MyViewInitialize(True)
|
||||||
|
.AddOkCancelToolbar()
|
||||||
|
If _Result = YouTubeChannelTab.All And Not MyYouTubeSettings Is Nothing Then _Result = MyYouTubeSettings.ChannelsDownload
|
||||||
|
Dim r() As YouTubeChannelTab = _Result.EnumExtract(Of YouTubeChannelTab)
|
||||||
|
If r.ListExists Then
|
||||||
|
For Each value As YouTubeChannelTab In r
|
||||||
|
Select Case value
|
||||||
|
Case YouTubeChannelTab.All : CH_ALL.Checked = True
|
||||||
|
Case YouTubeChannelTab.Videos : CH_VIDEOS.Checked = True
|
||||||
|
Case YouTubeChannelTab.Shorts : CH_SHORTS.Checked = True
|
||||||
|
Case YouTubeChannelTab.Playlists : CH_PLS.Checked = True
|
||||||
|
End Select
|
||||||
|
Next
|
||||||
|
Else
|
||||||
|
CH_ALL.Checked = True
|
||||||
|
End If
|
||||||
|
UpdateCheckBoxes()
|
||||||
|
.EndLoaderOperations()
|
||||||
|
.MyOkCancel.EnableOK = True
|
||||||
|
End With
|
||||||
|
Catch ex As Exception
|
||||||
|
MyDefs.InvokeLoaderError(ex)
|
||||||
|
End Try
|
||||||
|
End Sub
|
||||||
|
Private Sub MyDefs_ButtonOkClick(ByVal Sender As Object, ByVal e As KeyHandleEventArgs) Handles MyDefs.ButtonOkClick
|
||||||
|
_Result = YouTubeChannelTab.All
|
||||||
|
If Not CH_ALL.Checked And {CH_VIDEOS, CH_SHORTS, CH_PLS}.Any(Function(c) c.Checked) Then
|
||||||
|
If CH_VIDEOS.Checked Then _Result += YouTubeChannelTab.Videos
|
||||||
|
If CH_SHORTS.Checked Then _Result += YouTubeChannelTab.Shorts
|
||||||
|
If CH_PLS.Checked Then _Result += YouTubeChannelTab.Playlists
|
||||||
|
End If
|
||||||
|
MyDefs.CloseForm()
|
||||||
|
End Sub
|
||||||
|
Private Sub UpdateCheckBoxes() Handles CH_ALL.CheckedChanged, CH_URL_ASIS.CheckedChanged
|
||||||
|
Dim e As Boolean = Not CH_ALL.Checked And Not CH_URL_ASIS.Checked
|
||||||
|
CH_VIDEOS.Enabled = e
|
||||||
|
CH_SHORTS.Enabled = e
|
||||||
|
CH_PLS.Enabled = e
|
||||||
|
End Sub
|
||||||
|
End Class
|
||||||
|
End Namespace
|
||||||
@@ -100,6 +100,7 @@ Namespace API.YouTube.Controls
|
|||||||
Me.TXT_URLS.MaxLength = 2147483647
|
Me.TXT_URLS.MaxLength = 2147483647
|
||||||
Me.TXT_URLS.Multiline = True
|
Me.TXT_URLS.Multiline = True
|
||||||
Me.TXT_URLS.Name = "TXT_URLS"
|
Me.TXT_URLS.Name = "TXT_URLS"
|
||||||
|
Me.TXT_URLS.ScrollBars = System.Windows.Forms.ScrollBars.Both
|
||||||
Me.TXT_URLS.Size = New System.Drawing.Size(372, 261)
|
Me.TXT_URLS.Size = New System.Drawing.Size(372, 261)
|
||||||
Me.TXT_URLS.TabIndex = 0
|
Me.TXT_URLS.TabIndex = 0
|
||||||
'
|
'
|
||||||
|
|||||||
134
SCrawler.YouTube/Controls/VideoOptionsForm.Designer.vb
generated
@@ -50,6 +50,7 @@ Namespace API.YouTube.Controls
|
|||||||
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()
|
||||||
Dim ActionButton10 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
Dim ActionButton10 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||||
|
Dim ActionButton11 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||||
Me.ICON_VIDEO = New System.Windows.Forms.PictureBox()
|
Me.ICON_VIDEO = New System.Windows.Forms.PictureBox()
|
||||||
Me.LBL_TITLE = New System.Windows.Forms.Label()
|
Me.LBL_TITLE = New System.Windows.Forms.Label()
|
||||||
Me.TP_HEADER_INFO_2 = New System.Windows.Forms.TableLayoutPanel()
|
Me.TP_HEADER_INFO_2 = New System.Windows.Forms.TableLayoutPanel()
|
||||||
@@ -71,6 +72,7 @@ Namespace API.YouTube.Controls
|
|||||||
Me.CMB_FORMAT = New System.Windows.Forms.ComboBox()
|
Me.CMB_FORMAT = New System.Windows.Forms.ComboBox()
|
||||||
Me.CMB_AUDIO_CODEC = New System.Windows.Forms.ComboBox()
|
Me.CMB_AUDIO_CODEC = New System.Windows.Forms.ComboBox()
|
||||||
Me.NUM_RES = New System.Windows.Forms.NumericUpDown()
|
Me.NUM_RES = New System.Windows.Forms.NumericUpDown()
|
||||||
|
Me.TXT_FPS = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
||||||
Me.TP_CONTROLS = New System.Windows.Forms.TableLayoutPanel()
|
Me.TP_CONTROLS = New System.Windows.Forms.TableLayoutPanel()
|
||||||
Me.TXT_SUBS_ADDIT = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
Me.TXT_SUBS_ADDIT = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
||||||
Me.TXT_EXTRA_AUDIO_FORMATS = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
Me.TXT_EXTRA_AUDIO_FORMATS = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
||||||
@@ -105,6 +107,7 @@ Namespace API.YouTube.Controls
|
|||||||
Me.TP_MAIN.SuspendLayout()
|
Me.TP_MAIN.SuspendLayout()
|
||||||
Me.TP_OPTIONS.SuspendLayout()
|
Me.TP_OPTIONS.SuspendLayout()
|
||||||
CType(Me.NUM_RES, System.ComponentModel.ISupportInitialize).BeginInit()
|
CType(Me.NUM_RES, System.ComponentModel.ISupportInitialize).BeginInit()
|
||||||
|
CType(Me.TXT_FPS, System.ComponentModel.ISupportInitialize).BeginInit()
|
||||||
CType(Me.TXT_SUBS_ADDIT, System.ComponentModel.ISupportInitialize).BeginInit()
|
CType(Me.TXT_SUBS_ADDIT, System.ComponentModel.ISupportInitialize).BeginInit()
|
||||||
CType(Me.TXT_EXTRA_AUDIO_FORMATS, System.ComponentModel.ISupportInitialize).BeginInit()
|
CType(Me.TXT_EXTRA_AUDIO_FORMATS, System.ComponentModel.ISupportInitialize).BeginInit()
|
||||||
Me.SuspendLayout()
|
Me.SuspendLayout()
|
||||||
@@ -123,7 +126,7 @@ Namespace API.YouTube.Controls
|
|||||||
TP_HEADER.Name = "TP_HEADER"
|
TP_HEADER.Name = "TP_HEADER"
|
||||||
TP_HEADER.RowCount = 1
|
TP_HEADER.RowCount = 1
|
||||||
TP_HEADER.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
TP_HEADER.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||||
TP_HEADER.Size = New System.Drawing.Size(599, 63)
|
TP_HEADER.Size = New System.Drawing.Size(719, 63)
|
||||||
TP_HEADER.TabIndex = 0
|
TP_HEADER.TabIndex = 0
|
||||||
'
|
'
|
||||||
'ICON_VIDEO
|
'ICON_VIDEO
|
||||||
@@ -152,7 +155,7 @@ Namespace API.YouTube.Controls
|
|||||||
TP_HEADER_INFO.RowCount = 2
|
TP_HEADER_INFO.RowCount = 2
|
||||||
TP_HEADER_INFO.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
|
TP_HEADER_INFO.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
|
||||||
TP_HEADER_INFO.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
|
TP_HEADER_INFO.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
|
||||||
TP_HEADER_INFO.Size = New System.Drawing.Size(469, 63)
|
TP_HEADER_INFO.Size = New System.Drawing.Size(589, 63)
|
||||||
TP_HEADER_INFO.TabIndex = 0
|
TP_HEADER_INFO.TabIndex = 0
|
||||||
'
|
'
|
||||||
'LBL_TITLE
|
'LBL_TITLE
|
||||||
@@ -161,7 +164,7 @@ Namespace API.YouTube.Controls
|
|||||||
Me.LBL_TITLE.Font = New System.Drawing.Font("Arial", 9.0!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, CType(204, Byte))
|
Me.LBL_TITLE.Font = New System.Drawing.Font("Arial", 9.0!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, CType(204, Byte))
|
||||||
Me.LBL_TITLE.Location = New System.Drawing.Point(3, 0)
|
Me.LBL_TITLE.Location = New System.Drawing.Point(3, 0)
|
||||||
Me.LBL_TITLE.Name = "LBL_TITLE"
|
Me.LBL_TITLE.Name = "LBL_TITLE"
|
||||||
Me.LBL_TITLE.Size = New System.Drawing.Size(463, 31)
|
Me.LBL_TITLE.Size = New System.Drawing.Size(583, 31)
|
||||||
Me.LBL_TITLE.TabIndex = 0
|
Me.LBL_TITLE.TabIndex = 0
|
||||||
Me.LBL_TITLE.Text = "Video title"
|
Me.LBL_TITLE.Text = "Video title"
|
||||||
Me.LBL_TITLE.TextAlign = System.Drawing.ContentAlignment.MiddleLeft
|
Me.LBL_TITLE.TextAlign = System.Drawing.ContentAlignment.MiddleLeft
|
||||||
@@ -183,7 +186,7 @@ Namespace API.YouTube.Controls
|
|||||||
Me.TP_HEADER_INFO_2.Name = "TP_HEADER_INFO_2"
|
Me.TP_HEADER_INFO_2.Name = "TP_HEADER_INFO_2"
|
||||||
Me.TP_HEADER_INFO_2.RowCount = 1
|
Me.TP_HEADER_INFO_2.RowCount = 1
|
||||||
Me.TP_HEADER_INFO_2.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
Me.TP_HEADER_INFO_2.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||||
Me.TP_HEADER_INFO_2.Size = New System.Drawing.Size(469, 32)
|
Me.TP_HEADER_INFO_2.Size = New System.Drawing.Size(589, 32)
|
||||||
Me.TP_HEADER_INFO_2.TabIndex = 1
|
Me.TP_HEADER_INFO_2.TabIndex = 1
|
||||||
'
|
'
|
||||||
'ICON_CLOCK
|
'ICON_CLOCK
|
||||||
@@ -230,7 +233,7 @@ Namespace API.YouTube.Controls
|
|||||||
Me.LBL_URL.LinkColor = System.Drawing.Color.FromArgb(CType(CType(0, Byte), Integer), CType(CType(0, Byte), Integer), CType(CType(192, Byte), Integer))
|
Me.LBL_URL.LinkColor = System.Drawing.Color.FromArgb(CType(CType(0, Byte), Integer), CType(CType(0, Byte), Integer), CType(CType(192, Byte), Integer))
|
||||||
Me.LBL_URL.Location = New System.Drawing.Point(115, 0)
|
Me.LBL_URL.Location = New System.Drawing.Point(115, 0)
|
||||||
Me.LBL_URL.Name = "LBL_URL"
|
Me.LBL_URL.Name = "LBL_URL"
|
||||||
Me.LBL_URL.Size = New System.Drawing.Size(351, 32)
|
Me.LBL_URL.Size = New System.Drawing.Size(471, 32)
|
||||||
Me.LBL_URL.TabIndex = 1
|
Me.LBL_URL.TabIndex = 1
|
||||||
Me.LBL_URL.TabStop = True
|
Me.LBL_URL.TabStop = True
|
||||||
Me.LBL_URL.Text = "https://www.youtube.com/watch?v=abcdefghijk"
|
Me.LBL_URL.Text = "https://www.youtube.com/watch?v=abcdefghijk"
|
||||||
@@ -250,7 +253,7 @@ Namespace API.YouTube.Controls
|
|||||||
TP_FOOTER.RowCount = 2
|
TP_FOOTER.RowCount = 2
|
||||||
TP_FOOTER.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
|
TP_FOOTER.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
|
||||||
TP_FOOTER.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
|
TP_FOOTER.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
|
||||||
TP_FOOTER.Size = New System.Drawing.Size(589, 52)
|
TP_FOOTER.Size = New System.Drawing.Size(709, 52)
|
||||||
TP_FOOTER.TabIndex = 5
|
TP_FOOTER.TabIndex = 5
|
||||||
'
|
'
|
||||||
'TP_DESTINATION
|
'TP_DESTINATION
|
||||||
@@ -266,7 +269,7 @@ Namespace API.YouTube.Controls
|
|||||||
TP_DESTINATION.Name = "TP_DESTINATION"
|
TP_DESTINATION.Name = "TP_DESTINATION"
|
||||||
TP_DESTINATION.RowCount = 1
|
TP_DESTINATION.RowCount = 1
|
||||||
TP_DESTINATION.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
TP_DESTINATION.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||||
TP_DESTINATION.Size = New System.Drawing.Size(589, 26)
|
TP_DESTINATION.Size = New System.Drawing.Size(709, 26)
|
||||||
TP_DESTINATION.TabIndex = 0
|
TP_DESTINATION.TabIndex = 0
|
||||||
'
|
'
|
||||||
'TXT_FILE
|
'TXT_FILE
|
||||||
@@ -290,14 +293,14 @@ Namespace API.YouTube.Controls
|
|||||||
Me.TXT_FILE.Location = New System.Drawing.Point(1, 1)
|
Me.TXT_FILE.Location = New System.Drawing.Point(1, 1)
|
||||||
Me.TXT_FILE.Margin = New System.Windows.Forms.Padding(1)
|
Me.TXT_FILE.Margin = New System.Windows.Forms.Padding(1)
|
||||||
Me.TXT_FILE.Name = "TXT_FILE"
|
Me.TXT_FILE.Name = "TXT_FILE"
|
||||||
Me.TXT_FILE.Size = New System.Drawing.Size(507, 22)
|
Me.TXT_FILE.Size = New System.Drawing.Size(627, 22)
|
||||||
Me.TXT_FILE.TabIndex = 0
|
Me.TXT_FILE.TabIndex = 0
|
||||||
Me.TXT_FILE.TextBoxBorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
|
Me.TXT_FILE.TextBoxBorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
|
||||||
'
|
'
|
||||||
'BTT_BROWSE
|
'BTT_BROWSE
|
||||||
'
|
'
|
||||||
Me.BTT_BROWSE.Dock = System.Windows.Forms.DockStyle.Fill
|
Me.BTT_BROWSE.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
Me.BTT_BROWSE.Location = New System.Drawing.Point(512, 2)
|
Me.BTT_BROWSE.Location = New System.Drawing.Point(632, 2)
|
||||||
Me.BTT_BROWSE.Margin = New System.Windows.Forms.Padding(3, 2, 3, 2)
|
Me.BTT_BROWSE.Margin = New System.Windows.Forms.Padding(3, 2, 3, 2)
|
||||||
Me.BTT_BROWSE.Name = "BTT_BROWSE"
|
Me.BTT_BROWSE.Name = "BTT_BROWSE"
|
||||||
Me.BTT_BROWSE.Size = New System.Drawing.Size(74, 22)
|
Me.BTT_BROWSE.Size = New System.Drawing.Size(74, 22)
|
||||||
@@ -321,13 +324,13 @@ Namespace API.YouTube.Controls
|
|||||||
TP_OK_CANCEL.RowCount = 1
|
TP_OK_CANCEL.RowCount = 1
|
||||||
TP_OK_CANCEL.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
TP_OK_CANCEL.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||||
TP_OK_CANCEL.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 26.0!))
|
TP_OK_CANCEL.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 26.0!))
|
||||||
TP_OK_CANCEL.Size = New System.Drawing.Size(589, 26)
|
TP_OK_CANCEL.Size = New System.Drawing.Size(709, 26)
|
||||||
TP_OK_CANCEL.TabIndex = 1
|
TP_OK_CANCEL.TabIndex = 1
|
||||||
'
|
'
|
||||||
'BTT_DOWN
|
'BTT_DOWN
|
||||||
'
|
'
|
||||||
Me.BTT_DOWN.Dock = System.Windows.Forms.DockStyle.Fill
|
Me.BTT_DOWN.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
Me.BTT_DOWN.Location = New System.Drawing.Point(432, 2)
|
Me.BTT_DOWN.Location = New System.Drawing.Point(552, 2)
|
||||||
Me.BTT_DOWN.Margin = New System.Windows.Forms.Padding(3, 2, 3, 2)
|
Me.BTT_DOWN.Margin = New System.Windows.Forms.Padding(3, 2, 3, 2)
|
||||||
Me.BTT_DOWN.Name = "BTT_DOWN"
|
Me.BTT_DOWN.Name = "BTT_DOWN"
|
||||||
Me.BTT_DOWN.Size = New System.Drawing.Size(74, 22)
|
Me.BTT_DOWN.Size = New System.Drawing.Size(74, 22)
|
||||||
@@ -339,7 +342,7 @@ Namespace API.YouTube.Controls
|
|||||||
'
|
'
|
||||||
Me.BTT_CANCEL.DialogResult = System.Windows.Forms.DialogResult.Cancel
|
Me.BTT_CANCEL.DialogResult = System.Windows.Forms.DialogResult.Cancel
|
||||||
Me.BTT_CANCEL.Dock = System.Windows.Forms.DockStyle.Fill
|
Me.BTT_CANCEL.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
Me.BTT_CANCEL.Location = New System.Drawing.Point(512, 2)
|
Me.BTT_CANCEL.Location = New System.Drawing.Point(632, 2)
|
||||||
Me.BTT_CANCEL.Margin = New System.Windows.Forms.Padding(3, 2, 3, 2)
|
Me.BTT_CANCEL.Margin = New System.Windows.Forms.Padding(3, 2, 3, 2)
|
||||||
Me.BTT_CANCEL.Name = "BTT_CANCEL"
|
Me.BTT_CANCEL.Name = "BTT_CANCEL"
|
||||||
Me.BTT_CANCEL.Size = New System.Drawing.Size(74, 22)
|
Me.BTT_CANCEL.Size = New System.Drawing.Size(74, 22)
|
||||||
@@ -354,7 +357,7 @@ Namespace API.YouTube.Controls
|
|||||||
LB_SEP_1.Location = New System.Drawing.Point(6, 179)
|
LB_SEP_1.Location = New System.Drawing.Point(6, 179)
|
||||||
LB_SEP_1.Margin = New System.Windows.Forms.Padding(6, 0, 6, 0)
|
LB_SEP_1.Margin = New System.Windows.Forms.Padding(6, 0, 6, 0)
|
||||||
LB_SEP_1.Name = "LB_SEP_1"
|
LB_SEP_1.Name = "LB_SEP_1"
|
||||||
LB_SEP_1.Size = New System.Drawing.Size(589, 1)
|
LB_SEP_1.Size = New System.Drawing.Size(709, 1)
|
||||||
LB_SEP_1.TabIndex = 3
|
LB_SEP_1.TabIndex = 3
|
||||||
'
|
'
|
||||||
'LB_SEP_2
|
'LB_SEP_2
|
||||||
@@ -364,7 +367,7 @@ Namespace API.YouTube.Controls
|
|||||||
LB_SEP_2.Location = New System.Drawing.Point(6, 209)
|
LB_SEP_2.Location = New System.Drawing.Point(6, 209)
|
||||||
LB_SEP_2.Margin = New System.Windows.Forms.Padding(6, 0, 6, 0)
|
LB_SEP_2.Margin = New System.Windows.Forms.Padding(6, 0, 6, 0)
|
||||||
LB_SEP_2.Name = "LB_SEP_2"
|
LB_SEP_2.Name = "LB_SEP_2"
|
||||||
LB_SEP_2.Size = New System.Drawing.Size(589, 1)
|
LB_SEP_2.Size = New System.Drawing.Size(709, 1)
|
||||||
LB_SEP_2.TabIndex = 5
|
LB_SEP_2.TabIndex = 5
|
||||||
'
|
'
|
||||||
'TP_WHAT
|
'TP_WHAT
|
||||||
@@ -436,7 +439,7 @@ Namespace API.YouTube.Controls
|
|||||||
'
|
'
|
||||||
LBL_SUBS_FORMAT.AutoSize = True
|
LBL_SUBS_FORMAT.AutoSize = True
|
||||||
LBL_SUBS_FORMAT.Dock = System.Windows.Forms.DockStyle.Fill
|
LBL_SUBS_FORMAT.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
LBL_SUBS_FORMAT.Location = New System.Drawing.Point(432, 0)
|
LBL_SUBS_FORMAT.Location = New System.Drawing.Point(552, 0)
|
||||||
LBL_SUBS_FORMAT.Name = "LBL_SUBS_FORMAT"
|
LBL_SUBS_FORMAT.Name = "LBL_SUBS_FORMAT"
|
||||||
LBL_SUBS_FORMAT.Size = New System.Drawing.Size(74, 28)
|
LBL_SUBS_FORMAT.Size = New System.Drawing.Size(74, 28)
|
||||||
LBL_SUBS_FORMAT.TabIndex = 2
|
LBL_SUBS_FORMAT.TabIndex = 2
|
||||||
@@ -448,7 +451,7 @@ Namespace API.YouTube.Controls
|
|||||||
'
|
'
|
||||||
Me.LBL_AUDIO_CODEC.AutoSize = True
|
Me.LBL_AUDIO_CODEC.AutoSize = True
|
||||||
Me.LBL_AUDIO_CODEC.Dock = System.Windows.Forms.DockStyle.Fill
|
Me.LBL_AUDIO_CODEC.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
Me.LBL_AUDIO_CODEC.Location = New System.Drawing.Point(432, 0)
|
Me.LBL_AUDIO_CODEC.Location = New System.Drawing.Point(552, 0)
|
||||||
Me.LBL_AUDIO_CODEC.Name = "LBL_AUDIO_CODEC"
|
Me.LBL_AUDIO_CODEC.Name = "LBL_AUDIO_CODEC"
|
||||||
Me.LBL_AUDIO_CODEC.Size = New System.Drawing.Size(74, 28)
|
Me.LBL_AUDIO_CODEC.Size = New System.Drawing.Size(74, 28)
|
||||||
Me.LBL_AUDIO_CODEC.TabIndex = 5
|
Me.LBL_AUDIO_CODEC.TabIndex = 5
|
||||||
@@ -470,7 +473,7 @@ Namespace API.YouTube.Controls
|
|||||||
Me.TP_HEADER_BASE.RowCount = 1
|
Me.TP_HEADER_BASE.RowCount = 1
|
||||||
Me.TP_HEADER_BASE.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
Me.TP_HEADER_BASE.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||||
Me.TP_HEADER_BASE.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 64.0!))
|
Me.TP_HEADER_BASE.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 64.0!))
|
||||||
Me.TP_HEADER_BASE.Size = New System.Drawing.Size(601, 65)
|
Me.TP_HEADER_BASE.Size = New System.Drawing.Size(721, 65)
|
||||||
Me.TP_HEADER_BASE.TabIndex = 6
|
Me.TP_HEADER_BASE.TabIndex = 6
|
||||||
'
|
'
|
||||||
'TP_SUBS
|
'TP_SUBS
|
||||||
@@ -488,7 +491,7 @@ Namespace API.YouTube.Controls
|
|||||||
Me.TP_SUBS.Name = "TP_SUBS"
|
Me.TP_SUBS.Name = "TP_SUBS"
|
||||||
Me.TP_SUBS.RowCount = 1
|
Me.TP_SUBS.RowCount = 1
|
||||||
Me.TP_SUBS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
Me.TP_SUBS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||||
Me.TP_SUBS.Size = New System.Drawing.Size(589, 28)
|
Me.TP_SUBS.Size = New System.Drawing.Size(709, 28)
|
||||||
Me.TP_SUBS.TabIndex = 2
|
Me.TP_SUBS.TabIndex = 2
|
||||||
'
|
'
|
||||||
'TXT_SUBS
|
'TXT_SUBS
|
||||||
@@ -516,7 +519,7 @@ Namespace API.YouTube.Controls
|
|||||||
Me.TXT_SUBS.Dock = System.Windows.Forms.DockStyle.Fill
|
Me.TXT_SUBS.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
Me.TXT_SUBS.Location = New System.Drawing.Point(3, 3)
|
Me.TXT_SUBS.Location = New System.Drawing.Point(3, 3)
|
||||||
Me.TXT_SUBS.Name = "TXT_SUBS"
|
Me.TXT_SUBS.Name = "TXT_SUBS"
|
||||||
Me.TXT_SUBS.Size = New System.Drawing.Size(423, 22)
|
Me.TXT_SUBS.Size = New System.Drawing.Size(543, 22)
|
||||||
Me.TXT_SUBS.TabIndex = 0
|
Me.TXT_SUBS.TabIndex = 0
|
||||||
Me.TXT_SUBS.TextBoxReadOnly = True
|
Me.TXT_SUBS.TextBoxReadOnly = True
|
||||||
'
|
'
|
||||||
@@ -525,7 +528,7 @@ Namespace API.YouTube.Controls
|
|||||||
Me.CMB_SUBS_FORMAT.Dock = System.Windows.Forms.DockStyle.Fill
|
Me.CMB_SUBS_FORMAT.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
Me.CMB_SUBS_FORMAT.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList
|
Me.CMB_SUBS_FORMAT.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList
|
||||||
Me.CMB_SUBS_FORMAT.FormattingEnabled = True
|
Me.CMB_SUBS_FORMAT.FormattingEnabled = True
|
||||||
Me.CMB_SUBS_FORMAT.Location = New System.Drawing.Point(512, 3)
|
Me.CMB_SUBS_FORMAT.Location = New System.Drawing.Point(632, 3)
|
||||||
Me.CMB_SUBS_FORMAT.Name = "CMB_SUBS_FORMAT"
|
Me.CMB_SUBS_FORMAT.Name = "CMB_SUBS_FORMAT"
|
||||||
Me.CMB_SUBS_FORMAT.Size = New System.Drawing.Size(74, 21)
|
Me.CMB_SUBS_FORMAT.Size = New System.Drawing.Size(74, 21)
|
||||||
Me.CMB_SUBS_FORMAT.TabIndex = 1
|
Me.CMB_SUBS_FORMAT.TabIndex = 1
|
||||||
@@ -557,31 +560,33 @@ Namespace API.YouTube.Controls
|
|||||||
Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 5.0!))
|
Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 5.0!))
|
||||||
Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 58.0!))
|
Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 58.0!))
|
||||||
Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle())
|
Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle())
|
||||||
Me.TP_MAIN.Size = New System.Drawing.Size(601, 271)
|
Me.TP_MAIN.Size = New System.Drawing.Size(721, 271)
|
||||||
Me.TP_MAIN.TabIndex = 0
|
Me.TP_MAIN.TabIndex = 0
|
||||||
'
|
'
|
||||||
'TP_OPTIONS
|
'TP_OPTIONS
|
||||||
'
|
'
|
||||||
Me.TP_OPTIONS.ColumnCount = 6
|
Me.TP_OPTIONS.ColumnCount = 7
|
||||||
Me.TP_OPTIONS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
Me.TP_OPTIONS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||||
Me.TP_OPTIONS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 80.0!))
|
Me.TP_OPTIONS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 80.0!))
|
||||||
Me.TP_OPTIONS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 80.0!))
|
Me.TP_OPTIONS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 80.0!))
|
||||||
Me.TP_OPTIONS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 80.0!))
|
Me.TP_OPTIONS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 80.0!))
|
||||||
|
Me.TP_OPTIONS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 120.0!))
|
||||||
Me.TP_OPTIONS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 80.0!))
|
Me.TP_OPTIONS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 80.0!))
|
||||||
Me.TP_OPTIONS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 80.0!))
|
Me.TP_OPTIONS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 80.0!))
|
||||||
Me.TP_OPTIONS.Controls.Add(LBL_FORMAT, 1, 0)
|
Me.TP_OPTIONS.Controls.Add(LBL_FORMAT, 1, 0)
|
||||||
Me.TP_OPTIONS.Controls.Add(TP_WHAT, 0, 0)
|
Me.TP_OPTIONS.Controls.Add(TP_WHAT, 0, 0)
|
||||||
Me.TP_OPTIONS.Controls.Add(Me.CMB_FORMAT, 2, 0)
|
Me.TP_OPTIONS.Controls.Add(Me.CMB_FORMAT, 2, 0)
|
||||||
Me.TP_OPTIONS.Controls.Add(Me.LBL_AUDIO_CODEC, 4, 0)
|
Me.TP_OPTIONS.Controls.Add(Me.LBL_AUDIO_CODEC, 5, 0)
|
||||||
Me.TP_OPTIONS.Controls.Add(Me.CMB_AUDIO_CODEC, 5, 0)
|
Me.TP_OPTIONS.Controls.Add(Me.CMB_AUDIO_CODEC, 6, 0)
|
||||||
Me.TP_OPTIONS.Controls.Add(Me.NUM_RES, 3, 0)
|
Me.TP_OPTIONS.Controls.Add(Me.NUM_RES, 3, 0)
|
||||||
|
Me.TP_OPTIONS.Controls.Add(Me.TXT_FPS, 4, 0)
|
||||||
Me.TP_OPTIONS.Dock = System.Windows.Forms.DockStyle.Fill
|
Me.TP_OPTIONS.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
Me.TP_OPTIONS.Location = New System.Drawing.Point(6, 65)
|
Me.TP_OPTIONS.Location = New System.Drawing.Point(6, 65)
|
||||||
Me.TP_OPTIONS.Margin = New System.Windows.Forms.Padding(6, 0, 6, 0)
|
Me.TP_OPTIONS.Margin = New System.Windows.Forms.Padding(6, 0, 6, 0)
|
||||||
Me.TP_OPTIONS.Name = "TP_OPTIONS"
|
Me.TP_OPTIONS.Name = "TP_OPTIONS"
|
||||||
Me.TP_OPTIONS.RowCount = 1
|
Me.TP_OPTIONS.RowCount = 1
|
||||||
Me.TP_OPTIONS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
Me.TP_OPTIONS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||||
Me.TP_OPTIONS.Size = New System.Drawing.Size(589, 28)
|
Me.TP_OPTIONS.Size = New System.Drawing.Size(709, 28)
|
||||||
Me.TP_OPTIONS.TabIndex = 1
|
Me.TP_OPTIONS.TabIndex = 1
|
||||||
'
|
'
|
||||||
'CMB_FORMAT
|
'CMB_FORMAT
|
||||||
@@ -599,7 +604,7 @@ Namespace API.YouTube.Controls
|
|||||||
Me.CMB_AUDIO_CODEC.Dock = System.Windows.Forms.DockStyle.Fill
|
Me.CMB_AUDIO_CODEC.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
Me.CMB_AUDIO_CODEC.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList
|
Me.CMB_AUDIO_CODEC.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList
|
||||||
Me.CMB_AUDIO_CODEC.FormattingEnabled = True
|
Me.CMB_AUDIO_CODEC.FormattingEnabled = True
|
||||||
Me.CMB_AUDIO_CODEC.Location = New System.Drawing.Point(512, 3)
|
Me.CMB_AUDIO_CODEC.Location = New System.Drawing.Point(632, 3)
|
||||||
Me.CMB_AUDIO_CODEC.Name = "CMB_AUDIO_CODEC"
|
Me.CMB_AUDIO_CODEC.Name = "CMB_AUDIO_CODEC"
|
||||||
Me.CMB_AUDIO_CODEC.Size = New System.Drawing.Size(74, 21)
|
Me.CMB_AUDIO_CODEC.Size = New System.Drawing.Size(74, 21)
|
||||||
Me.CMB_AUDIO_CODEC.TabIndex = 3
|
Me.CMB_AUDIO_CODEC.TabIndex = 3
|
||||||
@@ -616,6 +621,24 @@ Namespace API.YouTube.Controls
|
|||||||
Me.NUM_RES.TextAlign = System.Windows.Forms.HorizontalAlignment.Center
|
Me.NUM_RES.TextAlign = System.Windows.Forms.HorizontalAlignment.Center
|
||||||
Me.NUM_RES.Value = New Decimal(New Integer() {1080, 0, 0, 0})
|
Me.NUM_RES.Value = New Decimal(New Integer() {1080, 0, 0, 0})
|
||||||
'
|
'
|
||||||
|
'TXT_FPS
|
||||||
|
'
|
||||||
|
ActionButton5.BackgroundImage = CType(resources.GetObject("ActionButton5.BackgroundImage"), System.Drawing.Image)
|
||||||
|
ActionButton5.Name = "Clear"
|
||||||
|
ActionButton5.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
||||||
|
Me.TXT_FPS.Buttons.Add(ActionButton5)
|
||||||
|
Me.TXT_FPS.CaptionText = "FPS"
|
||||||
|
Me.TXT_FPS.CaptionToolTipEnabled = True
|
||||||
|
Me.TXT_FPS.CaptionToolTipText = "You can reduce the video FPS by setting the FPS value in this field."
|
||||||
|
Me.TXT_FPS.CaptionWidth = 30.0R
|
||||||
|
Me.TXT_FPS.Dock = System.Windows.Forms.DockStyle.Fill
|
||||||
|
Me.TXT_FPS.Location = New System.Drawing.Point(432, 2)
|
||||||
|
Me.TXT_FPS.Margin = New System.Windows.Forms.Padding(3, 2, 3, 3)
|
||||||
|
Me.TXT_FPS.Name = "TXT_FPS"
|
||||||
|
Me.TXT_FPS.Size = New System.Drawing.Size(114, 22)
|
||||||
|
Me.TXT_FPS.TabIndex = 6
|
||||||
|
Me.TXT_FPS.TextBoxWidthMinimal = 30
|
||||||
|
'
|
||||||
'TP_CONTROLS
|
'TP_CONTROLS
|
||||||
'
|
'
|
||||||
Me.TP_CONTROLS.ColumnCount = 1
|
Me.TP_CONTROLS.ColumnCount = 1
|
||||||
@@ -626,29 +649,29 @@ Namespace API.YouTube.Controls
|
|||||||
Me.TP_CONTROLS.Name = "TP_CONTROLS"
|
Me.TP_CONTROLS.Name = "TP_CONTROLS"
|
||||||
Me.TP_CONTROLS.RowCount = 1
|
Me.TP_CONTROLS.RowCount = 1
|
||||||
Me.TP_CONTROLS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
Me.TP_CONTROLS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||||
Me.TP_CONTROLS.Size = New System.Drawing.Size(595, 25)
|
Me.TP_CONTROLS.Size = New System.Drawing.Size(715, 25)
|
||||||
Me.TP_CONTROLS.TabIndex = 0
|
Me.TP_CONTROLS.TabIndex = 0
|
||||||
'
|
'
|
||||||
'TXT_SUBS_ADDIT
|
'TXT_SUBS_ADDIT
|
||||||
'
|
'
|
||||||
ActionButton5.BackgroundImage = CType(resources.GetObject("ActionButton5.BackgroundImage"), System.Drawing.Image)
|
|
||||||
ActionButton5.Enabled = False
|
|
||||||
ActionButton5.Name = "Open"
|
|
||||||
ActionButton5.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Open
|
|
||||||
ActionButton5.ToolTipText = "Choose additional formats"
|
|
||||||
ActionButton6.BackgroundImage = CType(resources.GetObject("ActionButton6.BackgroundImage"), System.Drawing.Image)
|
ActionButton6.BackgroundImage = CType(resources.GetObject("ActionButton6.BackgroundImage"), System.Drawing.Image)
|
||||||
ActionButton6.Enabled = False
|
ActionButton6.Enabled = False
|
||||||
ActionButton6.Name = "Refresh"
|
ActionButton6.Name = "Open"
|
||||||
ActionButton6.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Refresh
|
ActionButton6.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Open
|
||||||
ActionButton6.ToolTipText = "Fill in additional formats from the defaults"
|
ActionButton6.ToolTipText = "Choose additional formats"
|
||||||
ActionButton7.BackgroundImage = CType(resources.GetObject("ActionButton7.BackgroundImage"), System.Drawing.Image)
|
ActionButton7.BackgroundImage = CType(resources.GetObject("ActionButton7.BackgroundImage"), System.Drawing.Image)
|
||||||
ActionButton7.Enabled = False
|
ActionButton7.Enabled = False
|
||||||
ActionButton7.Name = "Clear"
|
ActionButton7.Name = "Refresh"
|
||||||
ActionButton7.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
ActionButton7.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Refresh
|
||||||
ActionButton7.ToolTipText = "Remove all additional formats"
|
ActionButton7.ToolTipText = "Fill in additional formats from the defaults"
|
||||||
Me.TXT_SUBS_ADDIT.Buttons.Add(ActionButton5)
|
ActionButton8.BackgroundImage = CType(resources.GetObject("ActionButton8.BackgroundImage"), System.Drawing.Image)
|
||||||
|
ActionButton8.Enabled = False
|
||||||
|
ActionButton8.Name = "Clear"
|
||||||
|
ActionButton8.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
||||||
|
ActionButton8.ToolTipText = "Remove all additional formats"
|
||||||
Me.TXT_SUBS_ADDIT.Buttons.Add(ActionButton6)
|
Me.TXT_SUBS_ADDIT.Buttons.Add(ActionButton6)
|
||||||
Me.TXT_SUBS_ADDIT.Buttons.Add(ActionButton7)
|
Me.TXT_SUBS_ADDIT.Buttons.Add(ActionButton7)
|
||||||
|
Me.TXT_SUBS_ADDIT.Buttons.Add(ActionButton8)
|
||||||
Me.TXT_SUBS_ADDIT.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.CheckBox
|
Me.TXT_SUBS_ADDIT.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.CheckBox
|
||||||
Me.TXT_SUBS_ADDIT.CaptionText = "Additional subtitle formats"
|
Me.TXT_SUBS_ADDIT.CaptionText = "Additional subtitle formats"
|
||||||
Me.TXT_SUBS_ADDIT.CaptionToolTipEnabled = True
|
Me.TXT_SUBS_ADDIT.CaptionToolTipEnabled = True
|
||||||
@@ -659,31 +682,31 @@ Namespace API.YouTube.Controls
|
|||||||
Me.TXT_SUBS_ADDIT.Location = New System.Drawing.Point(6, 124)
|
Me.TXT_SUBS_ADDIT.Location = New System.Drawing.Point(6, 124)
|
||||||
Me.TXT_SUBS_ADDIT.Margin = New System.Windows.Forms.Padding(6, 3, 6, 3)
|
Me.TXT_SUBS_ADDIT.Margin = New System.Windows.Forms.Padding(6, 3, 6, 3)
|
||||||
Me.TXT_SUBS_ADDIT.Name = "TXT_SUBS_ADDIT"
|
Me.TXT_SUBS_ADDIT.Name = "TXT_SUBS_ADDIT"
|
||||||
Me.TXT_SUBS_ADDIT.Size = New System.Drawing.Size(589, 22)
|
Me.TXT_SUBS_ADDIT.Size = New System.Drawing.Size(709, 22)
|
||||||
Me.TXT_SUBS_ADDIT.TabIndex = 3
|
Me.TXT_SUBS_ADDIT.TabIndex = 3
|
||||||
Me.TXT_SUBS_ADDIT.Tag = "s"
|
Me.TXT_SUBS_ADDIT.Tag = "s"
|
||||||
Me.TXT_SUBS_ADDIT.TextBoxReadOnly = True
|
Me.TXT_SUBS_ADDIT.TextBoxReadOnly = True
|
||||||
'
|
'
|
||||||
'TXT_EXTRA_AUDIO_FORMATS
|
'TXT_EXTRA_AUDIO_FORMATS
|
||||||
'
|
'
|
||||||
ActionButton8.BackgroundImage = CType(resources.GetObject("ActionButton8.BackgroundImage"), System.Drawing.Image)
|
|
||||||
ActionButton8.Enabled = False
|
|
||||||
ActionButton8.Name = "Open"
|
|
||||||
ActionButton8.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Open
|
|
||||||
ActionButton8.ToolTipText = "Choose additional formats"
|
|
||||||
ActionButton9.BackgroundImage = CType(resources.GetObject("ActionButton9.BackgroundImage"), System.Drawing.Image)
|
ActionButton9.BackgroundImage = CType(resources.GetObject("ActionButton9.BackgroundImage"), System.Drawing.Image)
|
||||||
ActionButton9.Enabled = False
|
ActionButton9.Enabled = False
|
||||||
ActionButton9.Name = "Refresh"
|
ActionButton9.Name = "Open"
|
||||||
ActionButton9.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Refresh
|
ActionButton9.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Open
|
||||||
ActionButton9.ToolTipText = "Fill in additional formats from the defaults"
|
ActionButton9.ToolTipText = "Choose additional formats"
|
||||||
ActionButton10.BackgroundImage = CType(resources.GetObject("ActionButton10.BackgroundImage"), System.Drawing.Image)
|
ActionButton10.BackgroundImage = CType(resources.GetObject("ActionButton10.BackgroundImage"), System.Drawing.Image)
|
||||||
ActionButton10.Enabled = False
|
ActionButton10.Enabled = False
|
||||||
ActionButton10.Name = "Clear"
|
ActionButton10.Name = "Refresh"
|
||||||
ActionButton10.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
ActionButton10.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Refresh
|
||||||
ActionButton10.ToolTipText = "Choose additional formats"
|
ActionButton10.ToolTipText = "Fill in additional formats from the defaults"
|
||||||
Me.TXT_EXTRA_AUDIO_FORMATS.Buttons.Add(ActionButton8)
|
ActionButton11.BackgroundImage = CType(resources.GetObject("ActionButton11.BackgroundImage"), System.Drawing.Image)
|
||||||
|
ActionButton11.Enabled = False
|
||||||
|
ActionButton11.Name = "Clear"
|
||||||
|
ActionButton11.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
||||||
|
ActionButton11.ToolTipText = "Choose additional formats"
|
||||||
Me.TXT_EXTRA_AUDIO_FORMATS.Buttons.Add(ActionButton9)
|
Me.TXT_EXTRA_AUDIO_FORMATS.Buttons.Add(ActionButton9)
|
||||||
Me.TXT_EXTRA_AUDIO_FORMATS.Buttons.Add(ActionButton10)
|
Me.TXT_EXTRA_AUDIO_FORMATS.Buttons.Add(ActionButton10)
|
||||||
|
Me.TXT_EXTRA_AUDIO_FORMATS.Buttons.Add(ActionButton11)
|
||||||
Me.TXT_EXTRA_AUDIO_FORMATS.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.CheckBox
|
Me.TXT_EXTRA_AUDIO_FORMATS.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.CheckBox
|
||||||
Me.TXT_EXTRA_AUDIO_FORMATS.CaptionText = "Additional audio formats"
|
Me.TXT_EXTRA_AUDIO_FORMATS.CaptionText = "Additional audio formats"
|
||||||
Me.TXT_EXTRA_AUDIO_FORMATS.CaptionToolTipEnabled = True
|
Me.TXT_EXTRA_AUDIO_FORMATS.CaptionToolTipEnabled = True
|
||||||
@@ -693,7 +716,7 @@ Namespace API.YouTube.Controls
|
|||||||
Me.TXT_EXTRA_AUDIO_FORMATS.Location = New System.Drawing.Point(6, 152)
|
Me.TXT_EXTRA_AUDIO_FORMATS.Location = New System.Drawing.Point(6, 152)
|
||||||
Me.TXT_EXTRA_AUDIO_FORMATS.Margin = New System.Windows.Forms.Padding(6, 3, 6, 3)
|
Me.TXT_EXTRA_AUDIO_FORMATS.Margin = New System.Windows.Forms.Padding(6, 3, 6, 3)
|
||||||
Me.TXT_EXTRA_AUDIO_FORMATS.Name = "TXT_EXTRA_AUDIO_FORMATS"
|
Me.TXT_EXTRA_AUDIO_FORMATS.Name = "TXT_EXTRA_AUDIO_FORMATS"
|
||||||
Me.TXT_EXTRA_AUDIO_FORMATS.Size = New System.Drawing.Size(589, 22)
|
Me.TXT_EXTRA_AUDIO_FORMATS.Size = New System.Drawing.Size(709, 22)
|
||||||
Me.TXT_EXTRA_AUDIO_FORMATS.TabIndex = 4
|
Me.TXT_EXTRA_AUDIO_FORMATS.TabIndex = 4
|
||||||
Me.TXT_EXTRA_AUDIO_FORMATS.Tag = "a"
|
Me.TXT_EXTRA_AUDIO_FORMATS.Tag = "a"
|
||||||
Me.TXT_EXTRA_AUDIO_FORMATS.TextBoxReadOnly = True
|
Me.TXT_EXTRA_AUDIO_FORMATS.TextBoxReadOnly = True
|
||||||
@@ -704,13 +727,14 @@ Namespace API.YouTube.Controls
|
|||||||
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.CancelButton = Me.BTT_CANCEL
|
Me.CancelButton = Me.BTT_CANCEL
|
||||||
Me.ClientSize = New System.Drawing.Size(601, 271)
|
Me.ClientSize = New System.Drawing.Size(721, 271)
|
||||||
Me.Controls.Add(Me.TP_MAIN)
|
Me.Controls.Add(Me.TP_MAIN)
|
||||||
Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle
|
Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle
|
||||||
Me.Icon = Global.SCrawler.My.Resources.SiteYouTube.YouTubeIcon_32
|
Me.Icon = Global.SCrawler.My.Resources.SiteYouTube.YouTubeIcon_32
|
||||||
Me.KeyPreview = True
|
Me.KeyPreview = True
|
||||||
Me.MaximizeBox = False
|
Me.MaximizeBox = False
|
||||||
Me.MinimizeBox = False
|
Me.MinimizeBox = False
|
||||||
|
Me.MinimumSize = New System.Drawing.Size(737, 310)
|
||||||
Me.Name = "VideoOptionsForm"
|
Me.Name = "VideoOptionsForm"
|
||||||
Me.ShowInTaskbar = False
|
Me.ShowInTaskbar = False
|
||||||
Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide
|
Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide
|
||||||
@@ -736,6 +760,7 @@ Namespace API.YouTube.Controls
|
|||||||
Me.TP_OPTIONS.ResumeLayout(False)
|
Me.TP_OPTIONS.ResumeLayout(False)
|
||||||
Me.TP_OPTIONS.PerformLayout()
|
Me.TP_OPTIONS.PerformLayout()
|
||||||
CType(Me.NUM_RES, System.ComponentModel.ISupportInitialize).EndInit()
|
CType(Me.NUM_RES, System.ComponentModel.ISupportInitialize).EndInit()
|
||||||
|
CType(Me.TXT_FPS, System.ComponentModel.ISupportInitialize).EndInit()
|
||||||
CType(Me.TXT_SUBS_ADDIT, System.ComponentModel.ISupportInitialize).EndInit()
|
CType(Me.TXT_SUBS_ADDIT, System.ComponentModel.ISupportInitialize).EndInit()
|
||||||
CType(Me.TXT_EXTRA_AUDIO_FORMATS, System.ComponentModel.ISupportInitialize).EndInit()
|
CType(Me.TXT_EXTRA_AUDIO_FORMATS, System.ComponentModel.ISupportInitialize).EndInit()
|
||||||
Me.ResumeLayout(False)
|
Me.ResumeLayout(False)
|
||||||
@@ -765,5 +790,6 @@ Namespace API.YouTube.Controls
|
|||||||
Private WithEvents BTT_DOWN As Button
|
Private WithEvents BTT_DOWN As Button
|
||||||
Private WithEvents BTT_CANCEL As Button
|
Private WithEvents BTT_CANCEL As Button
|
||||||
Private WithEvents TP_HEADER_INFO_2 As TableLayoutPanel
|
Private WithEvents TP_HEADER_INFO_2 As TableLayoutPanel
|
||||||
|
Private WithEvents TXT_FPS As PersonalUtilities.Forms.Controls.TextBoxExtended
|
||||||
End Class
|
End Class
|
||||||
End Namespace
|
End Namespace
|
||||||
@@ -289,6 +289,14 @@
|
|||||||
</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>
|
||||||
|
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||||
|
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
|
||||||
|
tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX
|
||||||
|
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
|
||||||
|
</value>
|
||||||
|
</data>
|
||||||
|
<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+oZAAAAR5JREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbGujg3ZATZPKYdC6FQhPwlAMkg3dP
|
||||||
@@ -299,7 +307,7 @@
|
|||||||
cMaRN0UdBBkAAAAASUVORK5CYII=
|
cMaRN0UdBBkAAAAASUVORK5CYII=
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ActionButton6.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/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6
|
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6
|
||||||
JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsTAAALEwEAmpwYAAACOElE
|
JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsTAAALEwEAmpwYAAACOElE
|
||||||
@@ -315,7 +323,7 @@
|
|||||||
VnR1MIwhwMTCyqEQ37qEmZVDFF0OE/9nAACtFF4Ey6OP+wAAAABJRU5ErkJggg==
|
VnR1MIwhwMTCyqEQ37qEmZVDFF0OE/9nAACtFF4Ey6OP+wAAAABJRU5ErkJggg==
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ActionButton7.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>
|
||||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||||
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
|
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
|
||||||
@@ -323,7 +331,7 @@
|
|||||||
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
|
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ActionButton8.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
|
||||||
wwAADsMBx2+oZAAAAR5JREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbGujg3ZATZPKYdC6FQhPwlAMkg3dP
|
wwAADsMBx2+oZAAAAR5JREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbGujg3ZATZPKYdC6FQhPwlAMkg3dP
|
||||||
@@ -334,7 +342,7 @@
|
|||||||
cMaRN0UdBBkAAAAASUVORK5CYII=
|
cMaRN0UdBBkAAAAASUVORK5CYII=
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ActionButton9.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="ActionButton10.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
<value>
|
<value>
|
||||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6
|
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6
|
||||||
JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsTAAALEwEAmpwYAAACOElE
|
JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsTAAALEwEAmpwYAAACOElE
|
||||||
@@ -350,7 +358,7 @@
|
|||||||
VnR1MIwhwMTCyqEQ37qEmZVDFF0OE/9nAACtFF4Ey6OP+wAAAABJRU5ErkJggg==
|
VnR1MIwhwMTCyqEQ37qEmZVDFF0OE/9nAACtFF4Ey6OP+wAAAABJRU5ErkJggg==
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ActionButton10.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="ActionButton11.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
|
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ Namespace API.YouTube.Controls
|
|||||||
Friend Class VideoOptionsForm : Implements IDesignXMLContainer
|
Friend Class VideoOptionsForm : Implements IDesignXMLContainer
|
||||||
#Region "Declarations"
|
#Region "Declarations"
|
||||||
Private MyView As FormView
|
Private MyView As FormView
|
||||||
|
Private ReadOnly MyFieldsChecker As FieldsChecker
|
||||||
Friend Property DesignXML As EContainer Implements IDesignXMLContainer.DesignXML
|
Friend Property DesignXML As EContainer Implements IDesignXMLContainer.DesignXML
|
||||||
Private Property DesignXMLNodes As String() Implements IDesignXMLContainer.DesignXMLNodes
|
Private Property DesignXMLNodes As String() Implements IDesignXMLContainer.DesignXMLNodes
|
||||||
Private Property DesignXMLNodeName As String Implements IDesignXMLContainer.DesignXMLNodeName
|
Private Property DesignXMLNodeName As String Implements IDesignXMLContainer.DesignXMLNodeName
|
||||||
@@ -29,14 +30,34 @@ Namespace API.YouTube.Controls
|
|||||||
Private ReadOnly Property CNT_PROCESSOR As TableControlsProcessor
|
Private ReadOnly Property CNT_PROCESSOR As TableControlsProcessor
|
||||||
Friend Property MyContainer As YouTubeMediaContainerBase
|
Friend Property MyContainer As YouTubeMediaContainerBase
|
||||||
Private Initialization As Boolean = True
|
Private Initialization As Boolean = True
|
||||||
Private ReadOnly IsSavedObject As Boolean
|
Private ReadOnly InheritsFromContainer As Boolean
|
||||||
|
Private Class FpsFieldChecker : Inherits FieldsCheckerProviderBase
|
||||||
|
Private ReadOnly MyProvider As ANumbers = YouTubeSettings.FpsFormatProvider.MyProviderDefault
|
||||||
|
Public Overrides Property ErrorMessage As String
|
||||||
|
Get
|
||||||
|
Return IIf(HasError, YouTubeSettings.FpsFormatProvider.ErrorMessageDefault, String.Empty)
|
||||||
|
End Get
|
||||||
|
Set : End Set
|
||||||
|
End Property
|
||||||
|
Public Overrides Function Convert(ByVal Value As Object, ByVal DestinationType As Type, ByVal Provider As IFormatProvider,
|
||||||
|
Optional ByVal NothingArg As Object = Nothing, Optional ByVal e As ErrorsDescriber = Nothing) As Object
|
||||||
|
If ACheck(Of Double)(Value, AModes.Var, MyProvider) Then
|
||||||
|
Return Value
|
||||||
|
Else
|
||||||
|
HasError = True
|
||||||
|
TypeError = True
|
||||||
|
Return Nothing
|
||||||
|
End If
|
||||||
|
End Function
|
||||||
|
End Class
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Initializers"
|
#Region "Initializers"
|
||||||
Friend Sub New(ByVal Container As YouTubeMediaContainerBase, Optional ByVal IsSavedObject As Boolean = False)
|
Friend Sub New(ByVal Container As YouTubeMediaContainerBase, Optional ByVal InheritsFromContainer As Boolean = False)
|
||||||
InitializeComponent()
|
InitializeComponent()
|
||||||
MyContainer = Container
|
MyContainer = Container
|
||||||
CNT_PROCESSOR = New TableControlsProcessor(TP_CONTROLS)
|
CNT_PROCESSOR = New TableControlsProcessor(TP_CONTROLS)
|
||||||
Me.IsSavedObject = IsSavedObject
|
Me.InheritsFromContainer = InheritsFromContainer
|
||||||
|
MyFieldsChecker = New FieldsChecker
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Form handlers"
|
#Region "Form handlers"
|
||||||
@@ -68,8 +89,8 @@ Namespace API.YouTube.Controls
|
|||||||
If Not .PlaylistTitle.IsEmptyString Or Not .Title.IsEmptyString Then Text &= $" - { .PlaylistTitle.IfNullOrEmpty(.Title)}"
|
If Not .PlaylistTitle.IsEmptyString Or Not .Title.IsEmptyString Then Text &= $" - { .PlaylistTitle.IfNullOrEmpty(.Title)}"
|
||||||
TP_MAIN.Controls.Remove(TP_HEADER_BASE)
|
TP_MAIN.Controls.Remove(TP_HEADER_BASE)
|
||||||
TP_MAIN.RowStyles(0).Height = 0
|
TP_MAIN.RowStyles(0).Height = 0
|
||||||
Dim def% = If(IsSavedObject, .ArrayMaxResolution, MyYouTubeSettings.DefaultVideoDefinition.Value)
|
Dim def% = If(InheritsFromContainer, .ArrayMaxResolution, MyYouTubeSettings.DefaultVideoDefinition.Value)
|
||||||
If IsSavedObject Then
|
If InheritsFromContainer Then
|
||||||
__audioOnly = def = -2
|
__audioOnly = def = -2
|
||||||
If def <= 0 Then def = MyYouTubeSettings.DefaultVideoDefinition
|
If def <= 0 Then def = MyYouTubeSettings.DefaultVideoDefinition
|
||||||
Else
|
Else
|
||||||
@@ -98,7 +119,7 @@ Namespace API.YouTube.Controls
|
|||||||
LBL_URL.Text = .URL
|
LBL_URL.Text = .URL
|
||||||
End If
|
End If
|
||||||
|
|
||||||
If .IsMusic Or __audioOnly Then
|
If .IsMusic Or __audioOnly Or (InheritsFromContainer And .IsAudioSelected) Then
|
||||||
OPT_AUDIO.Checked = True
|
OPT_AUDIO.Checked = True
|
||||||
Else
|
Else
|
||||||
OPT_VIDEO.Checked = True
|
OPT_VIDEO.Checked = True
|
||||||
@@ -107,7 +128,7 @@ Namespace API.YouTube.Controls
|
|||||||
|
|
||||||
arr = AvailableVideoFormats
|
arr = AvailableVideoFormats
|
||||||
CMB_FORMAT.Items.AddRange(arr)
|
CMB_FORMAT.Items.AddRange(arr)
|
||||||
If IsSavedObject Then
|
If InheritsFromContainer Then
|
||||||
__optionValue = .OutputVideoExtension.IfNullOrEmpty(MyYouTubeSettings.DefaultVideoFormat.Value)
|
__optionValue = .OutputVideoExtension.IfNullOrEmpty(MyYouTubeSettings.DefaultVideoFormat.Value)
|
||||||
Else
|
Else
|
||||||
__optionValue = MyYouTubeSettings.DefaultVideoFormat.Value
|
__optionValue = MyYouTubeSettings.DefaultVideoFormat.Value
|
||||||
@@ -116,7 +137,7 @@ Namespace API.YouTube.Controls
|
|||||||
|
|
||||||
arr = AvailableAudioFormats
|
arr = AvailableAudioFormats
|
||||||
CMB_AUDIO_CODEC.Items.AddRange(arr)
|
CMB_AUDIO_CODEC.Items.AddRange(arr)
|
||||||
If IsSavedObject Then
|
If InheritsFromContainer Then
|
||||||
__optionValue = .OutputAudioCodec.IfNullOrEmpty(IIf(.IsMusic, MyYouTubeSettings.DefaultAudioCodecMusic.Value, MyYouTubeSettings.DefaultAudioCodec.Value))
|
__optionValue = .OutputAudioCodec.IfNullOrEmpty(IIf(.IsMusic, MyYouTubeSettings.DefaultAudioCodecMusic.Value, MyYouTubeSettings.DefaultAudioCodec.Value))
|
||||||
Else
|
Else
|
||||||
__optionValue = IIf(.IsMusic, MyYouTubeSettings.DefaultAudioCodecMusic.Value, MyYouTubeSettings.DefaultAudioCodec.Value)
|
__optionValue = IIf(.IsMusic, MyYouTubeSettings.DefaultAudioCodecMusic.Value, MyYouTubeSettings.DefaultAudioCodec.Value)
|
||||||
@@ -125,13 +146,20 @@ Namespace API.YouTube.Controls
|
|||||||
|
|
||||||
arr = AvailableSubtitlesFormats
|
arr = AvailableSubtitlesFormats
|
||||||
CMB_SUBS_FORMAT.Items.AddRange(arr)
|
CMB_SUBS_FORMAT.Items.AddRange(arr)
|
||||||
If IsSavedObject Then
|
If InheritsFromContainer Then
|
||||||
__optionValue = .OutputSubtitlesFormat.IfNullOrEmpty(IIf(.IsMusic, "LRC", MyYouTubeSettings.DefaultSubtitlesFormat.Value))
|
__optionValue = .OutputSubtitlesFormat.IfNullOrEmpty(IIf(.IsMusic, "LRC", MyYouTubeSettings.DefaultSubtitlesFormat.Value))
|
||||||
Else
|
Else
|
||||||
__optionValue = IIf(.IsMusic, "LRC", MyYouTubeSettings.DefaultSubtitlesFormat.Value)
|
__optionValue = IIf(.IsMusic, "LRC", MyYouTubeSettings.DefaultSubtitlesFormat.Value)
|
||||||
End If
|
End If
|
||||||
setDef(CMB_SUBS_FORMAT, __optionValue)
|
setDef(CMB_SUBS_FORMAT, __optionValue)
|
||||||
|
|
||||||
|
If InheritsFromContainer Then
|
||||||
|
If .OutputVideoFPS > 0 Then TXT_FPS.Text = .OutputVideoFPS
|
||||||
|
Else
|
||||||
|
If MyYouTubeSettings.DefaultVideoFPS > 0 Then TXT_FPS.Text = MyYouTubeSettings.DefaultVideoFPS
|
||||||
|
End If
|
||||||
|
MyFieldsChecker.AddControl(Of Double)(TXT_FPS, TXT_FPS.CaptionText, True, New FpsFieldChecker)
|
||||||
|
MyFieldsChecker.EndLoaderOperations()
|
||||||
TP_SUBS.Enabled = .Subtitles.Count > 0
|
TP_SUBS.Enabled = .Subtitles.Count > 0
|
||||||
TXT_SUBS_ADDIT.Enabled = .Subtitles.Count > 0
|
TXT_SUBS_ADDIT.Enabled = .Subtitles.Count > 0
|
||||||
RefillTextBoxes()
|
RefillTextBoxes()
|
||||||
@@ -151,6 +179,7 @@ Namespace API.YouTube.Controls
|
|||||||
End Sub
|
End Sub
|
||||||
Private Sub VideoOptionsForm_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
|
Private Sub VideoOptionsForm_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
|
||||||
MyView.DisposeIfReady()
|
MyView.DisposeIfReady()
|
||||||
|
MyFieldsChecker.DisposeIfReady()
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Refill"
|
#Region "Refill"
|
||||||
@@ -183,7 +212,7 @@ Namespace API.YouTube.Controls
|
|||||||
Dim data As IEnumerable(Of Control)
|
Dim data As IEnumerable(Of Control)
|
||||||
|
|
||||||
If .HasElements Then
|
If .HasElements Then
|
||||||
data = .Elements.Select(Function(ee) New MediaItem(ee) With {.Dock = DockStyle.Fill, .Checked = ee.Checked, .IgnoreDownloadState = True})
|
data = .Elements.Select(Function(ee) New MediaItem(ee, True) With {.Dock = DockStyle.Fill, .Checked = ee.Checked})
|
||||||
Else
|
Else
|
||||||
data = (From m As MediaObject In .Self.MediaObjects
|
data = (From m As MediaObject In .Self.MediaObjects
|
||||||
Where m.Type = __contentType
|
Where m.Type = __contentType
|
||||||
@@ -204,6 +233,8 @@ Namespace API.YouTube.Controls
|
|||||||
If MyContainer.HasElements Then
|
If MyContainer.HasElements Then
|
||||||
With DirectCast(d, MediaItem)
|
With DirectCast(d, MediaItem)
|
||||||
AddHandler .CheckedChanged, AddressOf MediaItem_CheckedChanged
|
AddHandler .CheckedChanged, AddressOf MediaItem_CheckedChanged
|
||||||
|
AddHandler .BeforeOpenEditor, AddressOf MediaItem_BeforeOpenEditor
|
||||||
|
AddHandler .BeforeOpenEditorFull, AddressOf MediaItem_BeforeOpenEditorFull
|
||||||
AddHandler .Click, AddressOf CNT_PROCESSOR.MediaItem_Click
|
AddHandler .Click, AddressOf CNT_PROCESSOR.MediaItem_Click
|
||||||
AddHandler .KeyDown, AddressOf CNT_PROCESSOR.MediaItem_KeyDown
|
AddHandler .KeyDown, AddressOf CNT_PROCESSOR.MediaItem_KeyDown
|
||||||
End With
|
End With
|
||||||
@@ -271,10 +302,33 @@ Namespace API.YouTube.Controls
|
|||||||
Private Sub MediaItem_CheckedChanged(ByVal Sender As MediaItem, ByVal Container As IYouTubeMediaContainer)
|
Private Sub MediaItem_CheckedChanged(ByVal Sender As MediaItem, ByVal Container As IYouTubeMediaContainer)
|
||||||
ControlInvokeFast(TP_CONTROLS, Sub() Container.Checked = Sender.Checked, EDP.None)
|
ControlInvokeFast(TP_CONTROLS, Sub() Container.Checked = Sender.Checked, EDP.None)
|
||||||
End Sub
|
End Sub
|
||||||
|
Private Sub MediaItem_BeforeOpenEditor(ByVal Sender As MediaItem, ByVal Container As IYouTubeMediaContainer)
|
||||||
|
MediaItem_BeforeOpenEditorImpl(Sender, Container, False)
|
||||||
|
End Sub
|
||||||
|
Private Sub MediaItem_BeforeOpenEditorFull(ByVal Sender As MediaItem, ByVal Container As IYouTubeMediaContainer)
|
||||||
|
MediaItem_BeforeOpenEditorImpl(Sender, Container, True)
|
||||||
|
End Sub
|
||||||
|
Private Sub MediaItem_BeforeOpenEditorImpl(ByVal Sender As MediaItem, ByVal Container As IYouTubeMediaContainer, ByVal Full As Boolean)
|
||||||
|
If MyContainer.HasElements Then
|
||||||
|
ControlInvokeFast(TP_CONTROLS, Sub()
|
||||||
|
With DirectCast(Container, YouTubeMediaContainerBase)
|
||||||
|
.File = $"{TXT_FILE.Text.CSFilePS}{ .File.File}"
|
||||||
|
If Full Then
|
||||||
|
.OutputVideoExtension = CMB_FORMAT.Text.StringToLower
|
||||||
|
.OutputVideoFPS = AConvert(Of Double)(TXT_FPS.Text, YouTubeSettings.FpsFormatProvider.MyProviderDefault, -1)
|
||||||
|
.OutputAudioCodec = CMB_AUDIO_CODEC.Text.StringToLower
|
||||||
|
.OutputSubtitlesFormat = CMB_SUBS_FORMAT.Text.StringToLower
|
||||||
|
.IsAudioSelected = OPT_AUDIO.Checked
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
End Sub, EDP.None)
|
||||||
|
End If
|
||||||
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "OK, Cancel"
|
#Region "OK, Cancel"
|
||||||
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
|
||||||
Try
|
Try
|
||||||
|
If Not MyFieldsChecker.AllParamsOK Then Exit Sub
|
||||||
Dim f As SFile
|
Dim f As SFile
|
||||||
If MyContainer.HasElements Then
|
If MyContainer.HasElements Then
|
||||||
f = TXT_FILE.Text.CSFileP
|
f = TXT_FILE.Text.CSFileP
|
||||||
@@ -284,6 +338,7 @@ Namespace API.YouTube.Controls
|
|||||||
If f.IsEmptyString Then Throw New ArgumentNullException("File", "The output file cannot be null")
|
If f.IsEmptyString Then Throw New ArgumentNullException("File", "The output file cannot be null")
|
||||||
With MyContainer
|
With MyContainer
|
||||||
.OutputVideoExtension = CMB_FORMAT.Text.StringToLower
|
.OutputVideoExtension = CMB_FORMAT.Text.StringToLower
|
||||||
|
.OutputVideoFPS = AConvert(Of Double)(TXT_FPS.Text, YouTubeSettings.FpsFormatProvider.MyProviderDefault, -1)
|
||||||
.OutputAudioCodec = CMB_AUDIO_CODEC.Text.StringToLower
|
.OutputAudioCodec = CMB_AUDIO_CODEC.Text.StringToLower
|
||||||
.OutputSubtitlesFormat = CMB_SUBS_FORMAT.Text.StringToLower
|
.OutputSubtitlesFormat = CMB_SUBS_FORMAT.Text.StringToLower
|
||||||
|
|
||||||
@@ -346,6 +401,19 @@ Namespace API.YouTube.Controls
|
|||||||
Private Sub OPT_VIDEO_AUDIO_CheckedChanged(sender As Object, e As EventArgs) Handles OPT_VIDEO.CheckedChanged, OPT_AUDIO.CheckedChanged
|
Private Sub OPT_VIDEO_AUDIO_CheckedChanged(sender As Object, e As EventArgs) Handles OPT_VIDEO.CheckedChanged, OPT_AUDIO.CheckedChanged
|
||||||
If Not Initialization Then
|
If Not Initialization Then
|
||||||
CMB_FORMAT.Enabled = OPT_VIDEO.Checked
|
CMB_FORMAT.Enabled = OPT_VIDEO.Checked
|
||||||
|
Dim upFormat As Action(Of String) = Sub(ByVal format As String)
|
||||||
|
If Not format.IsEmptyString Then
|
||||||
|
format = format.ToLower
|
||||||
|
Dim fIndex% = CMB_AUDIO_CODEC.Items.Cast(Of String).ListIndexOf(Function(f) f.ToLower = format)
|
||||||
|
If fIndex >= 0 Then CMB_AUDIO_CODEC.SelectedIndex = fIndex
|
||||||
|
End If
|
||||||
|
End Sub
|
||||||
|
If OPT_VIDEO.Checked Then
|
||||||
|
upFormat(MyYouTubeSettings.DefaultAudioCodec)
|
||||||
|
Else
|
||||||
|
upFormat(MyYouTubeSettings.DefaultAudioCodecMusic)
|
||||||
|
End If
|
||||||
|
|
||||||
If MyContainer.HasElements Then
|
If MyContainer.HasElements Then
|
||||||
NUM_RES.Enabled = OPT_VIDEO.Checked
|
NUM_RES.Enabled = OPT_VIDEO.Checked
|
||||||
Else
|
Else
|
||||||
|
|||||||
@@ -108,5 +108,16 @@ Namespace API.YouTube
|
|||||||
Throw New NotImplementedException("'GetFormat' is not available in the 'DurationXmlConverter' context")
|
Throw New NotImplementedException("'GetFormat' is not available in the 'DurationXmlConverter' context")
|
||||||
End Function
|
End Function
|
||||||
End Class
|
End Class
|
||||||
|
Friend Sub CheckVersion(ByVal Force As Boolean)
|
||||||
|
If Not MyYouTubeSettings Is Nothing Then
|
||||||
|
With MyYouTubeSettings
|
||||||
|
If .CheckUpdatesAtStart Or Force Then
|
||||||
|
ShowProgramInfo(.ProgramText.Value.IfNullOrEmpty("YouTube Downloader"),
|
||||||
|
SCrawler.Shared.GetCurrentMaxVer(Application.StartupPath.CSFileP).IfNullOrEmpty(My.Application.Info.Version),
|
||||||
|
True, Force, .Self, True,, False, .ProgramDescription)
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
End If
|
||||||
|
End Sub
|
||||||
End Module
|
End Module
|
||||||
End Namespace
|
End Namespace
|
||||||
59
SCrawler.YouTube/Downloader/MediaItem.Designer.vb
generated
@@ -30,11 +30,16 @@ Namespace DownloadObjects.STDownloader
|
|||||||
Me.BTT_DOWN = New System.Windows.Forms.ToolStripMenuItem()
|
Me.BTT_DOWN = New System.Windows.Forms.ToolStripMenuItem()
|
||||||
Me.SEP_DOWN = New System.Windows.Forms.ToolStripSeparator()
|
Me.SEP_DOWN = New System.Windows.Forms.ToolStripSeparator()
|
||||||
Me.BTT_OPEN_FOLDER = New System.Windows.Forms.ToolStripMenuItem()
|
Me.BTT_OPEN_FOLDER = New System.Windows.Forms.ToolStripMenuItem()
|
||||||
|
Me.BTT_OPEN_FILE = New System.Windows.Forms.ToolStripMenuItem()
|
||||||
Me.SEP_FOLDER = New System.Windows.Forms.ToolStripSeparator()
|
Me.SEP_FOLDER = New System.Windows.Forms.ToolStripSeparator()
|
||||||
|
Me.BTT_PLS_ITEM_EDIT = New System.Windows.Forms.ToolStripMenuItem()
|
||||||
|
Me.BTT_PLS_ITEM_EDIT_FULL = New System.Windows.Forms.ToolStripMenuItem()
|
||||||
|
Me.SEP_PLS_ITEM_EDIT = New System.Windows.Forms.ToolStripSeparator()
|
||||||
Me.BTT_COPY_LINK = New System.Windows.Forms.ToolStripMenuItem()
|
Me.BTT_COPY_LINK = New System.Windows.Forms.ToolStripMenuItem()
|
||||||
Me.BTT_OPEN_IN_BROWSER = New System.Windows.Forms.ToolStripMenuItem()
|
Me.BTT_OPEN_IN_BROWSER = New System.Windows.Forms.ToolStripMenuItem()
|
||||||
Me.SEP_DOWN_AGAIN = New System.Windows.Forms.ToolStripSeparator()
|
Me.SEP_DOWN_AGAIN = New System.Windows.Forms.ToolStripSeparator()
|
||||||
Me.BTT_DOWN_AGAIN = New System.Windows.Forms.ToolStripMenuItem()
|
Me.BTT_DOWN_AGAIN = New System.Windows.Forms.ToolStripMenuItem()
|
||||||
|
Me.BTT_VIEW_SETTINGS = New System.Windows.Forms.ToolStripMenuItem()
|
||||||
Me.SEP_DEL = New System.Windows.Forms.ToolStripSeparator()
|
Me.SEP_DEL = New System.Windows.Forms.ToolStripSeparator()
|
||||||
Me.BTT_REMOVE_FROM_LIST = New System.Windows.Forms.ToolStripMenuItem()
|
Me.BTT_REMOVE_FROM_LIST = New System.Windows.Forms.ToolStripMenuItem()
|
||||||
Me.BTT_DELETE_FILE = New System.Windows.Forms.ToolStripMenuItem()
|
Me.BTT_DELETE_FILE = New System.Windows.Forms.ToolStripMenuItem()
|
||||||
@@ -42,7 +47,6 @@ Namespace DownloadObjects.STDownloader
|
|||||||
Me.TP_CHECKED_TITLE = New System.Windows.Forms.TableLayoutPanel()
|
Me.TP_CHECKED_TITLE = New System.Windows.Forms.TableLayoutPanel()
|
||||||
Me.LBL_TITLE = New System.Windows.Forms.Label()
|
Me.LBL_TITLE = New System.Windows.Forms.Label()
|
||||||
Me.CH_CHECKED = New System.Windows.Forms.CheckBox()
|
Me.CH_CHECKED = New System.Windows.Forms.CheckBox()
|
||||||
Me.BTT_VIEW_SETTINGS = New System.Windows.Forms.ToolStripMenuItem()
|
|
||||||
TP_MAIN = New System.Windows.Forms.TableLayoutPanel()
|
TP_MAIN = New System.Windows.Forms.TableLayoutPanel()
|
||||||
TP_MAIN.SuspendLayout()
|
TP_MAIN.SuspendLayout()
|
||||||
CType(Me.ICON_VIDEO, System.ComponentModel.ISupportInitialize).BeginInit()
|
CType(Me.ICON_VIDEO, System.ComponentModel.ISupportInitialize).BeginInit()
|
||||||
@@ -83,10 +87,10 @@ Namespace DownloadObjects.STDownloader
|
|||||||
'
|
'
|
||||||
'CONTEXT_MAIN
|
'CONTEXT_MAIN
|
||||||
'
|
'
|
||||||
Me.CONTEXT_MAIN.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_DOWN, Me.SEP_DOWN, Me.BTT_OPEN_FOLDER, Me.SEP_FOLDER, Me.BTT_COPY_LINK, Me.BTT_OPEN_IN_BROWSER, Me.SEP_DOWN_AGAIN, Me.BTT_DOWN_AGAIN, Me.BTT_VIEW_SETTINGS, Me.SEP_DEL, Me.BTT_REMOVE_FROM_LIST, Me.BTT_DELETE_FILE})
|
Me.CONTEXT_MAIN.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_DOWN, Me.SEP_DOWN, Me.BTT_OPEN_FOLDER, Me.BTT_OPEN_FILE, Me.SEP_FOLDER, Me.BTT_PLS_ITEM_EDIT, Me.BTT_PLS_ITEM_EDIT_FULL, Me.SEP_PLS_ITEM_EDIT, Me.BTT_COPY_LINK, Me.BTT_OPEN_IN_BROWSER, Me.SEP_DOWN_AGAIN, Me.BTT_DOWN_AGAIN, Me.BTT_VIEW_SETTINGS, Me.SEP_DEL, Me.BTT_REMOVE_FROM_LIST, Me.BTT_DELETE_FILE})
|
||||||
Me.CONTEXT_MAIN.Name = "CONTEXT_MAIN"
|
Me.CONTEXT_MAIN.Name = "CONTEXT_MAIN"
|
||||||
Me.CONTEXT_MAIN.ShowItemToolTips = False
|
Me.CONTEXT_MAIN.ShowItemToolTips = False
|
||||||
Me.CONTEXT_MAIN.Size = New System.Drawing.Size(185, 226)
|
Me.CONTEXT_MAIN.Size = New System.Drawing.Size(185, 298)
|
||||||
'
|
'
|
||||||
'BTT_DOWN
|
'BTT_DOWN
|
||||||
'
|
'
|
||||||
@@ -107,11 +111,42 @@ Namespace DownloadObjects.STDownloader
|
|||||||
Me.BTT_OPEN_FOLDER.Size = New System.Drawing.Size(184, 22)
|
Me.BTT_OPEN_FOLDER.Size = New System.Drawing.Size(184, 22)
|
||||||
Me.BTT_OPEN_FOLDER.Text = "Open folder"
|
Me.BTT_OPEN_FOLDER.Text = "Open folder"
|
||||||
'
|
'
|
||||||
|
'BTT_OPEN_FILE
|
||||||
|
'
|
||||||
|
Me.BTT_OPEN_FILE.Image = CType(resources.GetObject("BTT_OPEN_FILE.Image"), System.Drawing.Image)
|
||||||
|
Me.BTT_OPEN_FILE.Name = "BTT_OPEN_FILE"
|
||||||
|
Me.BTT_OPEN_FILE.Size = New System.Drawing.Size(184, 22)
|
||||||
|
Me.BTT_OPEN_FILE.Text = "Open file"
|
||||||
|
'
|
||||||
'SEP_FOLDER
|
'SEP_FOLDER
|
||||||
'
|
'
|
||||||
Me.SEP_FOLDER.Name = "SEP_FOLDER"
|
Me.SEP_FOLDER.Name = "SEP_FOLDER"
|
||||||
Me.SEP_FOLDER.Size = New System.Drawing.Size(181, 6)
|
Me.SEP_FOLDER.Size = New System.Drawing.Size(181, 6)
|
||||||
'
|
'
|
||||||
|
'BTT_PLS_ITEM_EDIT
|
||||||
|
'
|
||||||
|
Me.BTT_PLS_ITEM_EDIT.Image = CType(resources.GetObject("BTT_PLS_ITEM_EDIT.Image"), System.Drawing.Image)
|
||||||
|
Me.BTT_PLS_ITEM_EDIT.Name = "BTT_PLS_ITEM_EDIT"
|
||||||
|
Me.BTT_PLS_ITEM_EDIT.Size = New System.Drawing.Size(184, 22)
|
||||||
|
Me.BTT_PLS_ITEM_EDIT.Text = "Edit"
|
||||||
|
Me.BTT_PLS_ITEM_EDIT.Visible = False
|
||||||
|
'
|
||||||
|
'BTT_PLS_ITEM_EDIT_FULL
|
||||||
|
'
|
||||||
|
Me.BTT_PLS_ITEM_EDIT_FULL.AutoToolTip = True
|
||||||
|
Me.BTT_PLS_ITEM_EDIT_FULL.Image = CType(resources.GetObject("BTT_PLS_ITEM_EDIT_FULL.Image"), System.Drawing.Image)
|
||||||
|
Me.BTT_PLS_ITEM_EDIT_FULL.Name = "BTT_PLS_ITEM_EDIT_FULL"
|
||||||
|
Me.BTT_PLS_ITEM_EDIT_FULL.Size = New System.Drawing.Size(184, 22)
|
||||||
|
Me.BTT_PLS_ITEM_EDIT_FULL.Text = "Edit (inherit settings)"
|
||||||
|
Me.BTT_PLS_ITEM_EDIT_FULL.ToolTipText = "Inherit settings selected in the form"
|
||||||
|
Me.BTT_PLS_ITEM_EDIT_FULL.Visible = False
|
||||||
|
'
|
||||||
|
'SEP_PLS_ITEM_EDIT
|
||||||
|
'
|
||||||
|
Me.SEP_PLS_ITEM_EDIT.Name = "SEP_PLS_ITEM_EDIT"
|
||||||
|
Me.SEP_PLS_ITEM_EDIT.Size = New System.Drawing.Size(181, 6)
|
||||||
|
Me.SEP_PLS_ITEM_EDIT.Visible = False
|
||||||
|
'
|
||||||
'BTT_COPY_LINK
|
'BTT_COPY_LINK
|
||||||
'
|
'
|
||||||
Me.BTT_COPY_LINK.Image = Global.SCrawler.My.Resources.Resources.LinkPic_32
|
Me.BTT_COPY_LINK.Image = Global.SCrawler.My.Resources.Resources.LinkPic_32
|
||||||
@@ -138,6 +173,13 @@ Namespace DownloadObjects.STDownloader
|
|||||||
Me.BTT_DOWN_AGAIN.Size = New System.Drawing.Size(184, 22)
|
Me.BTT_DOWN_AGAIN.Size = New System.Drawing.Size(184, 22)
|
||||||
Me.BTT_DOWN_AGAIN.Text = "Download again"
|
Me.BTT_DOWN_AGAIN.Text = "Download again"
|
||||||
'
|
'
|
||||||
|
'BTT_VIEW_SETTINGS
|
||||||
|
'
|
||||||
|
Me.BTT_VIEW_SETTINGS.Image = Global.SCrawler.My.Resources.Resources.SettingsPic_16
|
||||||
|
Me.BTT_VIEW_SETTINGS.Name = "BTT_VIEW_SETTINGS"
|
||||||
|
Me.BTT_VIEW_SETTINGS.Size = New System.Drawing.Size(184, 22)
|
||||||
|
Me.BTT_VIEW_SETTINGS.Text = "View settings"
|
||||||
|
'
|
||||||
'SEP_DEL
|
'SEP_DEL
|
||||||
'
|
'
|
||||||
Me.SEP_DEL.Name = "SEP_DEL"
|
Me.SEP_DEL.Name = "SEP_DEL"
|
||||||
@@ -212,13 +254,6 @@ Namespace DownloadObjects.STDownloader
|
|||||||
Me.CH_CHECKED.TabIndex = 0
|
Me.CH_CHECKED.TabIndex = 0
|
||||||
Me.CH_CHECKED.UseVisualStyleBackColor = True
|
Me.CH_CHECKED.UseVisualStyleBackColor = True
|
||||||
'
|
'
|
||||||
'BTT_VIEW_SETTINGS
|
|
||||||
'
|
|
||||||
Me.BTT_VIEW_SETTINGS.Image = Global.SCrawler.My.Resources.Resources.SettingsPic_16
|
|
||||||
Me.BTT_VIEW_SETTINGS.Name = "BTT_VIEW_SETTINGS"
|
|
||||||
Me.BTT_VIEW_SETTINGS.Size = New System.Drawing.Size(184, 22)
|
|
||||||
Me.BTT_VIEW_SETTINGS.Text = "View settings"
|
|
||||||
'
|
|
||||||
'MediaItem
|
'MediaItem
|
||||||
'
|
'
|
||||||
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
|
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
|
||||||
@@ -253,5 +288,9 @@ Namespace DownloadObjects.STDownloader
|
|||||||
Private WithEvents SEP_DOWN_AGAIN As ToolStripSeparator
|
Private WithEvents SEP_DOWN_AGAIN As ToolStripSeparator
|
||||||
Private WithEvents SEP_DEL As ToolStripSeparator
|
Private WithEvents SEP_DEL As ToolStripSeparator
|
||||||
Private WithEvents BTT_VIEW_SETTINGS As ToolStripMenuItem
|
Private WithEvents BTT_VIEW_SETTINGS As ToolStripMenuItem
|
||||||
|
Private WithEvents BTT_OPEN_FILE As ToolStripMenuItem
|
||||||
|
Private WithEvents BTT_PLS_ITEM_EDIT As ToolStripMenuItem
|
||||||
|
Private WithEvents SEP_PLS_ITEM_EDIT As ToolStripSeparator
|
||||||
|
Private WithEvents BTT_PLS_ITEM_EDIT_FULL As ToolStripMenuItem
|
||||||
End Class
|
End Class
|
||||||
End Namespace
|
End Namespace
|
||||||
@@ -138,6 +138,138 @@
|
|||||||
PNWfb/GWbyQQ2Z/pgjaJ9XsI91sIjr1H+fgUVeYh/KVrFs8Itp6O1B2RR+fAdhzupEHDXnw3U3GVpuAq
|
PNWfb/GWbyQQ2Z/pgjaJ9XsI91sIjr1H+fgUVeYh/KVrFs8Itp6O1B2RR+fAdhzupEHDXnw3U3GVpuAq
|
||||||
+w/y3l2wnHCNxMrhGIGMcp2WpkyYWeqcC30Co5OYu0gvwZIRtc4b606cpoUYtF9y3BgvNkFSmhcSO25a
|
+w/y3l2wnHCNxMrhGIGMcp2WpkyYWeqcC30Co5OYu0gvwZIRtc4b606cpoUYtF9y3BgvNkFSmhcSO25a
|
||||||
TGCkk99shOQwl9bXawAAAABJRU5ErkJggg==
|
TGCkk99shOQwl9bXawAAAABJRU5ErkJggg==
|
||||||
|
</value>
|
||||||
|
</data>
|
||||||
|
<data name="BTT_OPEN_FILE.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>
|
||||||
|
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||||
|
wwAADsMBx2+oZAAAAk9JREFUOE+Nk0tIVGEUgKcWZlZWEK1aZEmZUlmpEQUtrF1Q0WNfUUgtCqKZLMXQ
|
||||||
|
UPJRmuY4TYYKmbPJcVSCAkuFQislzCx7rSo3Oc5T7zzu17njdZosxMXH/bn/+b97zn/ONfBjAJoPQctR
|
||||||
|
sB2bH1rsw8OEvnVj0BbUbdNJ19HW2+fmbgZO4wIR2MRm3irIQcsO2RA0Qe3mf9EOajGRuEycuXEiaDky
|
||||||
|
vdlXTfjrc0Kfu1BfVkJjtqR68G80cfRDIrgSL4Km/fCinFC/GU9JEs7CTUy25hAafYIy8hhl2IEy2Iwy
|
||||||
|
0IzacRaq1kNNClizdEHjPhiw4nFcRClKFLukWZvG1PWVuI0GPMVr8LYb8XZcRvX/gqEH0HZSskmPEbyu
|
||||||
|
w9N+CaV41bS9/Qx86oQPdhh1EOwuwesw4bGdY7LvPoHhNgIlq5nIS5gl0DLoyIF3LfgbDjBhFap348uL
|
||||||
|
Q5EDyrVEgvZT+Htv4ytYiit/WYzAfh6lIgl1bBB/xQYmi1YQqkomVJmMapbLswhN2ajfX+ErW8dU+Vpc
|
||||||
|
eUtiBRcIPDpBoKcU99V4uJf1p2Va+2q3QE8hSvcN3PkJUL9r5g6kXW8sUoKRqSE7vlupBCUTrJl6u3SB
|
||||||
|
PNWfb/GWbyQQ2Z/pgjaJ9XsI91sIjr1H+fgUVeYh/KVrFs8Itp6O1B2RR+fAdhzupEHDXnw3U3GVpuAq
|
||||||
|
+w/y3l2wnHCNxMrhGIGMcp2WpkyYWeqcC30Co5OYu0gvwZIRtc4b606cpoUYtF9y3BgvNkFSmhcSO25a
|
||||||
|
TGCkk99shOQwl9bXawAAAABJRU5ErkJggg==
|
||||||
|
</value>
|
||||||
|
</data>
|
||||||
|
<data name="BTT_PLS_ITEM_EDIT.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>
|
||||||
|
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
|
||||||
|
AAAASUVORK5CYII=
|
||||||
|
</value>
|
||||||
|
</data>
|
||||||
|
<data name="BTT_PLS_ITEM_EDIT_FULL.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>
|
||||||
|
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
|
||||||
|
AAAASUVORK5CYII=
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="BTT_OPEN_IN_BROWSER.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="BTT_OPEN_IN_BROWSER.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ Namespace DownloadObjects.STDownloader
|
|||||||
Public Event DownloadAgain As MediaItemEventHandler
|
Public Event DownloadAgain As MediaItemEventHandler
|
||||||
Public Event DownloadRequested As MediaItemEventHandler
|
Public Event DownloadRequested As MediaItemEventHandler
|
||||||
Public Event CheckedChanged As MediaItemEventHandler
|
Public Event CheckedChanged As MediaItemEventHandler
|
||||||
|
Public Event BeforeOpenEditor As MediaItemEventHandler
|
||||||
|
Public Event BeforeOpenEditorFull As MediaItemEventHandler
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Declarations"
|
#Region "Declarations"
|
||||||
#Region "Controls"
|
#Region "Controls"
|
||||||
@@ -51,8 +53,8 @@ Namespace DownloadObjects.STDownloader
|
|||||||
ControlInvokeFast(CH_CHECKED, Sub() CH_CHECKED.Checked = _Checked, EDP.None)
|
ControlInvokeFast(CH_CHECKED, Sub() CH_CHECKED.Checked = _Checked, EDP.None)
|
||||||
End Set
|
End Set
|
||||||
End Property
|
End Property
|
||||||
<Browsable(False)> Public Property IgnoreDownloadState As Boolean = False
|
|
||||||
Private ReadOnly FileOption As SFO = SFO.File
|
Private ReadOnly FileOption As SFO = SFO.File
|
||||||
|
Private ReadOnly ContainerHasElements As Boolean = False
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Initializers"
|
#Region "Initializers"
|
||||||
Public Sub New()
|
Public Sub New()
|
||||||
@@ -111,16 +113,18 @@ Namespace DownloadObjects.STDownloader
|
|||||||
.ContextMenuStrip = CONTEXT_MAIN
|
.ContextMenuStrip = CONTEXT_MAIN
|
||||||
}
|
}
|
||||||
End Sub
|
End Sub
|
||||||
Public Sub New(ByVal Container As IYouTubeMediaContainer)
|
Public Sub New(ByVal Container As IYouTubeMediaContainer, Optional ByVal HasElements As Boolean = False)
|
||||||
Me.New
|
Me.New
|
||||||
Const d$ = " " & ChrW(183) & " "
|
Const d$ = " " & ChrW(183) & " "
|
||||||
MyContainer = Container
|
MyContainer = Container
|
||||||
|
ContainerHasElements = HasElements
|
||||||
With MyContainer
|
With MyContainer
|
||||||
.Progress = MyProgress
|
.Progress = MyProgress
|
||||||
|
If HasElements Then BTT_PLS_ITEM_EDIT.Visible = True : BTT_PLS_ITEM_EDIT_FULL.Visible = True : SEP_PLS_ITEM_EDIT.Visible = True
|
||||||
If .HasElements Then FileOption = SFO.Path Else FileOption = SFO.File
|
If .HasElements Then FileOption = SFO.Path Else FileOption = SFO.File
|
||||||
If .DownloadState = Plugin.UserMediaStates.Downloaded AndAlso
|
If .DownloadState = Plugin.UserMediaStates.Downloaded AndAlso
|
||||||
(.ObjectType = Base.YouTubeMediaType.Channel Or .ObjectType = Base.YouTubeMediaType.PlayList) AndAlso FileOption = SFO.File AndAlso
|
(.ObjectType = Base.YouTubeMediaType.Channel Or .ObjectType = Base.YouTubeMediaType.PlayList) AndAlso FileOption = SFO.File AndAlso
|
||||||
Not .File.Exists AndAlso .File.Exists(SFO.Path, False) Then FileOption = SFO.Path
|
Not .File.Exists AndAlso .File.Exists(SFO.Path, False) Then FileOption = SFO.Path : BTT_OPEN_FILE.Visible = False
|
||||||
If Not .SiteKey = YouTubeSiteKey Then
|
If Not .SiteKey = YouTubeSiteKey Then
|
||||||
BTT_DOWN_AGAIN.Visible = False
|
BTT_DOWN_AGAIN.Visible = False
|
||||||
SEP_DOWN_AGAIN.Visible = False
|
SEP_DOWN_AGAIN.Visible = False
|
||||||
@@ -224,11 +228,17 @@ Namespace DownloadObjects.STDownloader
|
|||||||
.Controls.Clear()
|
.Controls.Clear()
|
||||||
.ColumnStyles.Clear()
|
.ColumnStyles.Clear()
|
||||||
.ColumnCount = 0
|
.ColumnCount = 0
|
||||||
If IgnoreDownloadState Or MyContainer.MediaState = Plugin.UserMediaStates.Downloaded Then
|
If ContainerHasElements Or MyContainer.MediaState = Plugin.UserMediaStates.Downloaded Then
|
||||||
If Not MyContainer.SiteKey = YouTubeSiteKey Then UpdateMediaIcon()
|
If Not MyContainer.SiteKey = YouTubeSiteKey Then UpdateMediaIcon()
|
||||||
If IgnoreDownloadState Then
|
If ContainerHasElements Then
|
||||||
BTT_OPEN_FOLDER.Visible = False
|
BTT_OPEN_FOLDER.Visible = False
|
||||||
|
BTT_OPEN_FILE.Visible = False
|
||||||
SEP_FOLDER.Visible = False
|
SEP_FOLDER.Visible = False
|
||||||
|
If Not ContainerHasElements Then
|
||||||
|
BTT_PLS_ITEM_EDIT.Visible = False
|
||||||
|
BTT_PLS_ITEM_EDIT_FULL.Visible = False
|
||||||
|
SEP_PLS_ITEM_EDIT.Visible = False
|
||||||
|
End If
|
||||||
BTT_DOWN_AGAIN.Visible = False
|
BTT_DOWN_AGAIN.Visible = False
|
||||||
SEP_DOWN_AGAIN.Visible = False
|
SEP_DOWN_AGAIN.Visible = False
|
||||||
BTT_REMOVE_FROM_LIST.Visible = False
|
BTT_REMOVE_FROM_LIST.Visible = False
|
||||||
@@ -369,7 +379,7 @@ Namespace DownloadObjects.STDownloader
|
|||||||
ICON_WHAT.DoubleClick, LBL_TIME.DoubleClick, ICON_SIZE.DoubleClick, LBL_INFO.DoubleClick,
|
ICON_WHAT.DoubleClick, LBL_TIME.DoubleClick, ICON_SIZE.DoubleClick, LBL_INFO.DoubleClick,
|
||||||
LBL_PROGRESS.DoubleClick, PR_MAIN.DoubleClick
|
LBL_PROGRESS.DoubleClick, PR_MAIN.DoubleClick
|
||||||
Controls_Click(sender, e)
|
Controls_Click(sender, e)
|
||||||
If Not IgnoreDownloadState AndAlso Not MyDownloaderSettings.OnItemDoubleClick = DoubleClickBehavior.None Then
|
If Not ContainerHasElements AndAlso Not MyDownloaderSettings.OnItemDoubleClick = DoubleClickBehavior.None Then
|
||||||
Dim m As New MMessage("The specified path was not found.", "Open file/folder",, vbExclamation)
|
Dim m As New MMessage("The specified path was not found.", "Open file/folder",, vbExclamation)
|
||||||
If MyDownloaderSettings.OnItemDoubleClick = DoubleClickBehavior.File Then
|
If MyDownloaderSettings.OnItemDoubleClick = DoubleClickBehavior.File Then
|
||||||
If FileOption = SFO.File And MyContainer.File.Exists(SFO.File, False) Then
|
If FileOption = SFO.File And MyContainer.File.Exists(SFO.File, False) Then
|
||||||
@@ -405,6 +415,27 @@ Namespace DownloadObjects.STDownloader
|
|||||||
Private Sub BTT_OPEN_FOLDER_Click(sender As Object, e As EventArgs) Handles BTT_OPEN_FOLDER.Click
|
Private Sub BTT_OPEN_FOLDER_Click(sender As Object, e As EventArgs) Handles BTT_OPEN_FOLDER.Click
|
||||||
If MyContainer.File.Exists(FileOption, False) Then GlobalOpenPath(MyContainer.File)
|
If MyContainer.File.Exists(FileOption, False) Then GlobalOpenPath(MyContainer.File)
|
||||||
End Sub
|
End Sub
|
||||||
|
Private Sub BTT_OPEN_FILE_Click(sender As Object, e As EventArgs) Handles BTT_OPEN_FILE.Click
|
||||||
|
If MyContainer.File.Exists(SFO.File) Then MyContainer.File.Open(,, EDP.ShowAllMsg)
|
||||||
|
End Sub
|
||||||
|
Private Sub BTT_PLS_ITEM_EDIT_Click(sender As Object, e As EventArgs) Handles BTT_PLS_ITEM_EDIT.Click, BTT_PLS_ITEM_EDIT_FULL.Click
|
||||||
|
If ContainerHasElements Then
|
||||||
|
With DirectCast(MyContainer, YouTubeMediaContainerBase)
|
||||||
|
Dim initProtected As Boolean = .Protected
|
||||||
|
Dim isFull As Boolean = sender Is BTT_PLS_ITEM_EDIT_FULL
|
||||||
|
.Protected = False
|
||||||
|
If isFull Then
|
||||||
|
RaiseEvent BeforeOpenEditorFull(Me, MyContainer)
|
||||||
|
Else
|
||||||
|
RaiseEvent BeforeOpenEditor(Me, MyContainer)
|
||||||
|
End If
|
||||||
|
Using f As New VideoOptionsForm(MyContainer, initProtected Or isFull)
|
||||||
|
f.ShowDialog()
|
||||||
|
.Protected = IIf(f.DialogResult = DialogResult.OK, True, initProtected)
|
||||||
|
End Using
|
||||||
|
End With
|
||||||
|
End If
|
||||||
|
End Sub
|
||||||
Private Sub BTT_COPY_LINK_Click(sender As Object, e As EventArgs) Handles BTT_COPY_LINK.Click
|
Private Sub BTT_COPY_LINK_Click(sender As Object, e As EventArgs) Handles BTT_COPY_LINK.Click
|
||||||
If Not MyContainer.URL.IsEmptyString Then
|
If Not MyContainer.URL.IsEmptyString Then
|
||||||
BufferText = MyContainer.URL
|
BufferText = MyContainer.URL
|
||||||
|
|||||||
@@ -24,14 +24,15 @@ Namespace DownloadObjects.STDownloader
|
|||||||
Private Sub InitializeComponent()
|
Private Sub InitializeComponent()
|
||||||
Dim SEP_2 As System.Windows.Forms.ToolStripSeparator
|
Dim SEP_2 As System.Windows.Forms.ToolStripSeparator
|
||||||
Dim SEP_3 As System.Windows.Forms.ToolStripSeparator
|
Dim SEP_3 As System.Windows.Forms.ToolStripSeparator
|
||||||
Dim MENU_ADD_SEP_1 As System.Windows.Forms.ToolStripSeparator
|
|
||||||
Dim MENU_DEL_CLEAR As System.Windows.Forms.ToolStripDropDownButton
|
Dim MENU_DEL_CLEAR As System.Windows.Forms.ToolStripDropDownButton
|
||||||
Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(VideoListForm))
|
Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(VideoListForm))
|
||||||
Dim MENU_DEL_SEP_1 As System.Windows.Forms.ToolStripSeparator
|
Dim MENU_DEL_SEP_1 As System.Windows.Forms.ToolStripSeparator
|
||||||
|
Dim MENU_DEL_SEP_2 As System.Windows.Forms.ToolStripSeparator
|
||||||
Me.BTT_DELETE = New System.Windows.Forms.ToolStripMenuItem()
|
Me.BTT_DELETE = New System.Windows.Forms.ToolStripMenuItem()
|
||||||
Me.BTT_CLEAR_SELECTED = New System.Windows.Forms.ToolStripMenuItem()
|
Me.BTT_CLEAR_SELECTED = New System.Windows.Forms.ToolStripMenuItem()
|
||||||
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.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()
|
||||||
@@ -42,8 +43,6 @@ 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_ADD_NO_SHORTS = New PersonalUtilities.Forms.Controls.KeyClick.ToolStripMenuItemKeyClick()
|
|
||||||
Me.BTT_ADD_SHORTS_ONLY = New PersonalUtilities.Forms.Controls.KeyClick.ToolStripMenuItemKeyClick()
|
|
||||||
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()
|
||||||
@@ -51,11 +50,12 @@ 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()
|
||||||
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_ADD_SEP_1 = New System.Windows.Forms.ToolStripSeparator()
|
|
||||||
MENU_DEL_CLEAR = New System.Windows.Forms.ToolStripDropDownButton()
|
MENU_DEL_CLEAR = New System.Windows.Forms.ToolStripDropDownButton()
|
||||||
MENU_DEL_SEP_1 = New System.Windows.Forms.ToolStripSeparator()
|
MENU_DEL_SEP_1 = New System.Windows.Forms.ToolStripSeparator()
|
||||||
|
MENU_DEL_SEP_2 = New System.Windows.Forms.ToolStripSeparator()
|
||||||
Me.TOOLBAR_BOTTOM.SuspendLayout()
|
Me.TOOLBAR_BOTTOM.SuspendLayout()
|
||||||
Me.TOOLBAR_TOP.SuspendLayout()
|
Me.TOOLBAR_TOP.SuspendLayout()
|
||||||
Me.SuspendLayout()
|
Me.SuspendLayout()
|
||||||
@@ -70,15 +70,10 @@ Namespace DownloadObjects.STDownloader
|
|||||||
SEP_3.Name = "SEP_3"
|
SEP_3.Name = "SEP_3"
|
||||||
SEP_3.Size = New System.Drawing.Size(6, 25)
|
SEP_3.Size = New System.Drawing.Size(6, 25)
|
||||||
'
|
'
|
||||||
'MENU_ADD_SEP_1
|
|
||||||
'
|
|
||||||
MENU_ADD_SEP_1.Name = "MENU_ADD_SEP_1"
|
|
||||||
MENU_ADD_SEP_1.Size = New System.Drawing.Size(181, 6)
|
|
||||||
'
|
|
||||||
'MENU_DEL_CLEAR
|
'MENU_DEL_CLEAR
|
||||||
'
|
'
|
||||||
MENU_DEL_CLEAR.AutoToolTip = False
|
MENU_DEL_CLEAR.AutoToolTip = False
|
||||||
MENU_DEL_CLEAR.DropDownItems.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_DELETE, MENU_DEL_SEP_1, Me.BTT_CLEAR_SELECTED, Me.BTT_CLEAR_DONE, Me.BTT_CLEAR_ALL})
|
MENU_DEL_CLEAR.DropDownItems.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_DELETE, MENU_DEL_SEP_1, Me.BTT_CLEAR_SELECTED, Me.BTT_CLEAR_DONE, Me.BTT_CLEAR_ALL, MENU_DEL_SEP_2, Me.BTT_SELECT_ALL, Me.BTT_SELECT_NONE})
|
||||||
MENU_DEL_CLEAR.Image = CType(resources.GetObject("MENU_DEL_CLEAR.Image"), System.Drawing.Image)
|
MENU_DEL_CLEAR.Image = CType(resources.GetObject("MENU_DEL_CLEAR.Image"), System.Drawing.Image)
|
||||||
MENU_DEL_CLEAR.ImageTransparentColor = System.Drawing.Color.Magenta
|
MENU_DEL_CLEAR.ImageTransparentColor = System.Drawing.Color.Magenta
|
||||||
MENU_DEL_CLEAR.Name = "MENU_DEL_CLEAR"
|
MENU_DEL_CLEAR.Name = "MENU_DEL_CLEAR"
|
||||||
@@ -128,6 +123,17 @@ Namespace DownloadObjects.STDownloader
|
|||||||
Me.BTT_CLEAR_ALL.Text = "Clear all"
|
Me.BTT_CLEAR_ALL.Text = "Clear all"
|
||||||
Me.BTT_CLEAR_ALL.ToolTipText = "Remove all items from the list"
|
Me.BTT_CLEAR_ALL.ToolTipText = "Remove all items from the list"
|
||||||
'
|
'
|
||||||
|
'MENU_DEL_SEP_2
|
||||||
|
'
|
||||||
|
MENU_DEL_SEP_2.Name = "MENU_DEL_SEP_2"
|
||||||
|
MENU_DEL_SEP_2.Size = New System.Drawing.Size(182, 6)
|
||||||
|
'
|
||||||
|
'BTT_SELECT_ALL
|
||||||
|
'
|
||||||
|
Me.BTT_SELECT_ALL.Name = "BTT_SELECT_ALL"
|
||||||
|
Me.BTT_SELECT_ALL.Size = New System.Drawing.Size(185, 22)
|
||||||
|
Me.BTT_SELECT_ALL.Text = "Select all"
|
||||||
|
'
|
||||||
'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})
|
||||||
@@ -186,7 +192,7 @@ Namespace DownloadObjects.STDownloader
|
|||||||
'MENU_ADD
|
'MENU_ADD
|
||||||
'
|
'
|
||||||
Me.MENU_ADD.AutoToolTip = False
|
Me.MENU_ADD.AutoToolTip = False
|
||||||
Me.MENU_ADD.DropDownItems.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_ADD, Me.BTT_ADD_PLS_ARR, MENU_ADD_SEP_1, Me.BTT_ADD_NO_SHORTS, Me.BTT_ADD_SHORTS_ONLY})
|
Me.MENU_ADD.DropDownItems.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_ADD, Me.BTT_ADD_PLS_ARR})
|
||||||
Me.MENU_ADD.Image = CType(resources.GetObject("MENU_ADD.Image"), System.Drawing.Image)
|
Me.MENU_ADD.Image = CType(resources.GetObject("MENU_ADD.Image"), System.Drawing.Image)
|
||||||
Me.MENU_ADD.ImageTransparentColor = System.Drawing.Color.Magenta
|
Me.MENU_ADD.ImageTransparentColor = System.Drawing.Color.Magenta
|
||||||
Me.MENU_ADD.Name = "MENU_ADD"
|
Me.MENU_ADD.Name = "MENU_ADD"
|
||||||
@@ -199,7 +205,7 @@ Namespace DownloadObjects.STDownloader
|
|||||||
Me.BTT_ADD.Image = CType(resources.GetObject("BTT_ADD.Image"), System.Drawing.Image)
|
Me.BTT_ADD.Image = CType(resources.GetObject("BTT_ADD.Image"), System.Drawing.Image)
|
||||||
Me.BTT_ADD.ImageTransparentColor = System.Drawing.Color.Magenta
|
Me.BTT_ADD.ImageTransparentColor = System.Drawing.Color.Magenta
|
||||||
Me.BTT_ADD.Name = "BTT_ADD"
|
Me.BTT_ADD.Name = "BTT_ADD"
|
||||||
Me.BTT_ADD.Size = New System.Drawing.Size(184, 22)
|
Me.BTT_ADD.Size = New System.Drawing.Size(149, 22)
|
||||||
Me.BTT_ADD.Tag = "a"
|
Me.BTT_ADD.Tag = "a"
|
||||||
Me.BTT_ADD.Text = "Add (Ins)"
|
Me.BTT_ADD.Text = "Add (Ins)"
|
||||||
Me.BTT_ADD.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.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" &
|
||||||
@@ -211,35 +217,11 @@ Namespace DownloadObjects.STDownloader
|
|||||||
Me.BTT_ADD_PLS_ARR.Image = CType(resources.GetObject("BTT_ADD_PLS_ARR.Image"), System.Drawing.Image)
|
Me.BTT_ADD_PLS_ARR.Image = CType(resources.GetObject("BTT_ADD_PLS_ARR.Image"), System.Drawing.Image)
|
||||||
Me.BTT_ADD_PLS_ARR.ImageTransparentColor = System.Drawing.Color.Magenta
|
Me.BTT_ADD_PLS_ARR.ImageTransparentColor = System.Drawing.Color.Magenta
|
||||||
Me.BTT_ADD_PLS_ARR.Name = "BTT_ADD_PLS_ARR"
|
Me.BTT_ADD_PLS_ARR.Name = "BTT_ADD_PLS_ARR"
|
||||||
Me.BTT_ADD_PLS_ARR.Size = New System.Drawing.Size(184, 22)
|
Me.BTT_ADD_PLS_ARR.Size = New System.Drawing.Size(149, 22)
|
||||||
Me.BTT_ADD_PLS_ARR.Tag = "pls"
|
Me.BTT_ADD_PLS_ARR.Tag = "pls"
|
||||||
Me.BTT_ADD_PLS_ARR.Text = "Add playlist 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_ADD_NO_SHORTS
|
|
||||||
'
|
|
||||||
Me.BTT_ADD_NO_SHORTS.AutoToolTip = True
|
|
||||||
Me.BTT_ADD_NO_SHORTS.Image = CType(resources.GetObject("BTT_ADD_NO_SHORTS.Image"), System.Drawing.Image)
|
|
||||||
Me.BTT_ADD_NO_SHORTS.ImageTransparentColor = System.Drawing.Color.Magenta
|
|
||||||
Me.BTT_ADD_NO_SHORTS.Name = "BTT_ADD_NO_SHORTS"
|
|
||||||
Me.BTT_ADD_NO_SHORTS.Size = New System.Drawing.Size(184, 22)
|
|
||||||
Me.BTT_ADD_NO_SHORTS.Tag = "ans"
|
|
||||||
Me.BTT_ADD_NO_SHORTS.Text = "Add (without Shorts)"
|
|
||||||
Me.BTT_ADD_NO_SHORTS.ToolTipText = "Download all videos except 'Shorts'." & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Click to add." & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Ctrl+click to use cookies fo" &
|
|
||||||
"r download (if supported)." & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Shift to add without downloading."
|
|
||||||
'
|
|
||||||
'BTT_ADD_SHORTS_ONLY
|
|
||||||
'
|
|
||||||
Me.BTT_ADD_SHORTS_ONLY.AutoToolTip = True
|
|
||||||
Me.BTT_ADD_SHORTS_ONLY.Image = CType(resources.GetObject("BTT_ADD_SHORTS_ONLY.Image"), System.Drawing.Image)
|
|
||||||
Me.BTT_ADD_SHORTS_ONLY.ImageTransparentColor = System.Drawing.Color.Magenta
|
|
||||||
Me.BTT_ADD_SHORTS_ONLY.Name = "BTT_ADD_SHORTS_ONLY"
|
|
||||||
Me.BTT_ADD_SHORTS_ONLY.Size = New System.Drawing.Size(184, 22)
|
|
||||||
Me.BTT_ADD_SHORTS_ONLY.Tag = "as"
|
|
||||||
Me.BTT_ADD_SHORTS_ONLY.Text = "Add (Shorts only)"
|
|
||||||
Me.BTT_ADD_SHORTS_ONLY.ToolTipText = "Download only 'Shorts' videos." & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Click to add." & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Ctrl+click to use cookies for down" &
|
|
||||||
"load (if supported)." & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Shift to add without downloading."
|
|
||||||
'
|
'
|
||||||
'BTT_DOWN
|
'BTT_DOWN
|
||||||
'
|
'
|
||||||
@@ -304,6 +286,12 @@ 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
|
||||||
|
'
|
||||||
|
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"
|
||||||
|
'
|
||||||
'VideoListForm
|
'VideoListForm
|
||||||
'
|
'
|
||||||
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
|
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
|
||||||
@@ -343,11 +331,11 @@ Namespace DownloadObjects.STDownloader
|
|||||||
Private WithEvents BTT_DONATE As ToolStripButton
|
Private WithEvents BTT_DONATE As ToolStripButton
|
||||||
Protected WithEvents BTT_ADD As PersonalUtilities.Forms.Controls.KeyClick.ToolStripMenuItemKeyClick
|
Protected WithEvents BTT_ADD As PersonalUtilities.Forms.Controls.KeyClick.ToolStripMenuItemKeyClick
|
||||||
Protected WithEvents BTT_ADD_PLS_ARR As PersonalUtilities.Forms.Controls.KeyClick.ToolStripMenuItemKeyClick
|
Protected WithEvents BTT_ADD_PLS_ARR As PersonalUtilities.Forms.Controls.KeyClick.ToolStripMenuItemKeyClick
|
||||||
Protected WithEvents BTT_ADD_NO_SHORTS As PersonalUtilities.Forms.Controls.KeyClick.ToolStripMenuItemKeyClick
|
|
||||||
Protected WithEvents BTT_ADD_SHORTS_ONLY As PersonalUtilities.Forms.Controls.KeyClick.ToolStripMenuItemKeyClick
|
|
||||||
Protected WithEvents MENU_ADD As ToolStripDropDownButton
|
Protected WithEvents MENU_ADD As ToolStripDropDownButton
|
||||||
Protected WithEvents BTT_DOWN As ToolStripButton
|
Protected WithEvents BTT_DOWN As ToolStripButton
|
||||||
Private WithEvents BTT_BUG_REPORT As ToolStripButton
|
Private WithEvents BTT_BUG_REPORT As ToolStripButton
|
||||||
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_NONE As ToolStripMenuItem
|
||||||
End Class
|
End Class
|
||||||
End Namespace
|
End Namespace
|
||||||
@@ -123,9 +123,6 @@
|
|||||||
<metadata name="SEP_3.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
<metadata name="SEP_3.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
<value>False</value>
|
<value>False</value>
|
||||||
</metadata>
|
</metadata>
|
||||||
<metadata name="MENU_ADD_SEP_1.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
|
||||||
<value>False</value>
|
|
||||||
</metadata>
|
|
||||||
<metadata name="MENU_DEL_CLEAR.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
<metadata name="MENU_DEL_CLEAR.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
<value>False</value>
|
<value>False</value>
|
||||||
</metadata>
|
</metadata>
|
||||||
@@ -134,29 +131,29 @@
|
|||||||
<value>
|
<value>
|
||||||
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
|
||||||
9iQAAAAASUVORK5CYII=
|
HR8AAAAASUVORK5CYII=
|
||||||
</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">
|
||||||
@@ -195,87 +192,90 @@
|
|||||||
<value>
|
<value>
|
||||||
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAVDSURBVEhLjZVtTFNXGMcLQmdHO6AdarLSOcTxXqC3lls3
|
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAVDSURBVEhLjZVtTFNXGMcLQmdHO6AdarLSOcTxXqC3lls3
|
||||||
FceLFC3YUkHHiJpRcQXFF5QoRmM00fiSLNmH7cP2YctMZtwyXZaNCaNsTsAJAzdcENBhLaXvhctekkV6
|
FeVFihZsqaBjRM2ouILiC0oUozGaaBSTJfuwfdg+bJnJnFuiyzKZMOp8ATJl4IYLAjqspfS9cNlLskjP
|
||||||
9j+l1RnLxpP8cnvPec7/+fc5597LozFQVBRjTkp6v3PJkpGrMtl766XSFzAcFZj8nxhWqdjfZLJro4sX
|
/qe0OmPZeJJfbu85z/k//z7n3Ht5NPqLimLMSUkfXV20aPiKTPbhOqn0FQxHBSb/J4ZUKvY3mez6yMKF
|
||||||
919OTjZgKAZEBCZpDJpMwptFRZ8ONzeTsfPnyXdNTf6rLNuRJxItx3T0bFb4GGKYV21bttznzpwh0+fO
|
fReTkw0YigERgUkaAyaT8FZR0ZdDzc1k9OxZ0tHU5L/Csp15ItFSTEfPZIWPQYZ507Z580Pu9Gky1dpK
|
||||||
kZHKSs87qan1stjYeEzPFulYtuzdO/v2kXvHj5OxY8eIFcmWgwdJK8tek4tELyMlbJFRtfo1iFu4s2cJ
|
hisrPe+nptbLYmPjMT1TpHPJkg/u7d1LHhw7RkaPHiVWJFsOHCBtLHtdLhK9jpSwRUbU6jUQt3BnzhAO
|
||||||
h7VcSwuZPnqU3NFqvV9IpW8jRQyieJ0SiZWK32tqIvcPHyZWJE2cOkW6m5v9V1WqH7JEohQkPlEEbSm2
|
a7mWFjJ15Ai5p9V6v5ZK30OKGETxrkokVir+oKmJPDx0iFiRNH7yJLnW3Oy/olLdyBKJUpD4TBG0pdhW
|
||||||
VVVZqXMqPg1x7sABMg1jvpoaYk5IuI00Foh47YmJF0Zqa8kYCliA9dAhYsMCx8mT5Aba1c6y3ZlCYSqS
|
VWWlzqn4FMS5/fvJFIz5amqIOSHhLtJYIOJ1JCaeG66tJaMoYAHWgweJDQscJ06QG2hXB8t2ZwqFqUgO
|
||||||
A0WGFYriicpK69Tp04SDmWmY4rBueu9eMrlzJ2lVqVxbJZJLSC0FYp5+6dIXW5XKa53bt/sfIGkcTMCN
|
FBlSKIrHKyutk6dOEQ5mpmCKw7qpPXvIxI4dpE2lcm2RSC4gtRSIefrFi19tUyqvt2/b5n+EpDEwDjcO
|
||||||
A3viRsuc+/eTThTJFQrTfmKYonGDwTZ14kSgJRwcc2gv19hIpiBuzs31pAgEH0HYCOSAbjgvmpFIUlGk
|
7IkbLXPu20euokiuUJj2E8MUjRkMtsnjxwMt4eCYQ3u5xkYyCXFzbq4nRSD4FMJGIAd0w3nRjESSiiLd
|
||||||
27J1K7Ht2kXsDQ3EsWcPcaGYF0K9DQ3+HrX61t3ycit35EjAMYc5Drlcff0j8TSB4AL0akFGUDwSBIKf
|
li1biG3nTmJvaCCO3buJC8W8EOpuaPD3qNV37peXW7nDhwOOOcxxyOXq65+IpwkE56BXCzKC4pEgEPxc
|
||||||
KxanfaNQdHVVV/vtdXXECdwmE/FAwIdivt27yRTcTlFh3HO4D4ijvV1KpVcuFFJx6jwdLASPj2ow+Cqx
|
sTjtO4Wi64fqar+9ro44gdtkIh4I+FDMt2sXmYTbSSqMew73AXG0t0up9MqFQipOnaeD+eDpUQ0GXyUW
|
||||||
OL09O7vbtmkTcW7bRtzAazQSHxxOouAkNnCyvJz41q4lPrWaeEBXXp4vRyS6iPU7AHUuAE+Jh4K/Ij4+
|
p3dkZ3fbNm4kzq1biRt4jUbig8MJFJzABk6UlxPf6tXEp1YTD+jKy/PliETnsX47oM4F4DnxUPCXxcdn
|
||||||
o10u7x7MyXno2byZuDUa4mYY4pJKiUskIq7oaOJasID0CoX+tqQkLxsXRze0DmSCZ8Gc4qEItOumXD4w
|
dMjl3QMZGY89mzYRt0ZD3AxDXFIpcYlExBUdTVzz5pFuodDfnpTkZePi6IbWgUzwIphVPBSBdt2Sy/vH
|
||||||
AUE7xBzACahwgKgo0p+d/ZchNfUr5L8FssC8xANhq6kx2dRqi10geFoc0LHB5OSHZq32blpiYjmWxIL5
|
IWiHmAM4ARUOEBVF+rKz/zKkpn6L/HdBFpiTeCBsNTUmm1ptsQsEz4sDOjaQnPzYrNXeT0tMLMeSWDA3
|
||||||
ifuMxv2uggKXHe7nEh8H94ElI4P063S3X1+5MgdL//O1Egi30djiXLfObY+JeUrcid7TdlHxMTASGUkG
|
cZ/RuM9VUOCyw/1s4mPgIbBkZJA+ne7uW8uX52Dpf75WAuE2Gluca9e67TExz4k70XvaLio+CoYjI8kA
|
||||||
QXtOjn+gouJXA8vSNs1dxLtjx2FHSYknnHOnREIelJT8fSMlxU/Fh4PifaALmBlmZoD+k7mK4Ci22AsK
|
uJyT4++vqPjVwLK0TbMX8W7ffshRUuIJ59wpkZBHJSV/30hJ8VPxoaB4L+gCZoaZ7qf/ZLYiOIot9oIC
|
||||||
vHahMCD8RFsWLSJDpaW/n1i9uqdvw4YJS1oa+QWiveA6+J4WoKxYMfOjwXCrQC6nL8jHr3pPbW0zFXeE
|
r10oDAg/05YFC8hgaenvx1eu7Oldv37ckpZGfoHobXATXKMFKMuWTf9oMNwpkMvpC/Lpq95TW9tMxR3h
|
||||||
E09IIENr1vxRzzDtSG0oycx843ZZ2d0h9D4k3gHaQCstolLN9FRU9H2o1dKN54MInmfjRqsjLi68c4jX
|
xBMSyOCqVX/UM0wHUhtKMjPfvltWdn8QvQ+Jd4J20EaLqFTTPRUVvZ9otXTj+SCC59mwweqIiwvvHOJ1
|
||||||
KRRtSDQBupHiPfn5r/Tr9aO3srIeiX8NvgRXwEB6+sNevf4OcpcCPs+u0w15ZLKwzk0M8y2S6oPioS8V
|
CkU7Ek2AbqR4d37+G316/cidrKwn4pfBN+AS6E9Pf3xbr7+H3MWAz7PrdIMemSyscxPDfI+k+qB46EvF
|
||||||
f29hIdtfUTF6OSvL/2/xzyIiSC8KmDWaceQVgXheT3X1lgmNxu2GaMj5YHHxn7vCi4eC35ifn4eNHbmZ
|
31NYyPZVVIxcyMry/1v8q4gIchsFzBrNGPKKQDyvp7p687hG43ZDNOR8oLj4z53hxUPBb8zPz8PGDt/K
|
||||||
nU0uB8XNeXkzn2g0D0qXL/8AObMFEAvbKiuPWMvKvH0s66fOG5XKDozPJR4KvnHVKgVtx+dYZ1arZy7B
|
ziYXg+LmvLzpzzWaR6VLl36MnJkCiPntlZWHrWVl3h6W9VPnjUplJ8ZnEw8F37hihYK24wusM6vV0xfg
|
||||||
+XMCwTnM6cBsixARTFJSbJ9e//G9sjLnxcJCnL7IRowzQEjnadIcwb9SVfXmzzrd+HWt1lWSkkK/BXog
|
/CWBoBVzOjDTIkQEk5QU26vXf/agrMx5vrAQpy+yEeMMENJ5mjRL8C9VVb3zs043dlOrdZWkpNBvgR5I
|
||||||
BfS4PlpLf8QBJVgfvM738X8G0KNJT84G8BII+8AtANQx/VjTK72fT1AT9P3/fBBaMGiMx/sHXLrYtE2a
|
AT2uT9bSH3FACdYFr3N9/F8A9GjSk7MevAbCPnDzAHVMP9b0Su/nEtQEff+/HIQWDBrj8f4B7zPYbtFn
|
||||||
9iQAAAAASUVORK5CYII=
|
HR8AAAAASUVORK5CYII=
|
||||||
</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>
|
||||||
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
|
||||||
9iQAAAAASUVORK5CYII=
|
HR8AAAAASUVORK5CYII=
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
|
<metadata name="MENU_DEL_SEP_2.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>False</value>
|
||||||
|
</metadata>
|
||||||
<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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
|
||||||
22tl8CvUAAAAAElFTkSuQmCC
|
dCWdzmEAAAAASUVORK5CYII=
|
||||||
</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,135 +287,93 @@
|
|||||||
<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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
|
||||||
jZbUijkXhD9w0a0SO8Tg+AAAAABJRU5ErkJggg==
|
hKygM1JCJAAAAABJRU5ErkJggg==
|
||||||
</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
|
||||||
</value>
|
|
||||||
</data>
|
|
||||||
<data name="BTT_ADD_NO_SHORTS.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
|
||||||
<value>
|
|
||||||
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
|
||||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAN6SURBVEhLrZVJTFNRFIYfQhgkQA1OZTCKoqLBVgRRpEpb
|
|
||||||
hQpqrAwiBYJIQTCiBCpxSuO41GjcGRfEGOPGYFw5LJAYFQco8opQIKUTFEkw7K/5PfelRBYEDL6T/GmT
|
|
||||||
e/N/55733/eEhSr0XnBb2P1gzCW+Fti2+OJGabZUpuvR4ECvBgaRZNeg2KmXIIFtiy9ukvE9lS3tFBD9
|
|
||||||
UUDsFwHx30Jg9ubLB9glprKYTwJWfAnC2p4wqMVoXPAXygfYQwDeeZItDGn9McgZWIWbk+XyAbRiGkuy
|
|
||||||
hSOjX4E8RxzNfwPuTdXKB6gWd7F0uwL5jniUjW5CrUuNR9ON8gGaxRxmGEpAhSsFDe40NHuy8GTa8m+A
|
|
||||||
+XI+I3Of7ne5azPOutPROqbBNX8u2n61YPnTiHmlfB7ZJnWon8k45btgQINjDh0qnXk46zmCi75i3PJX
|
|
||||||
0v90XPLtxXV/Hm5MGNA21YLHUxYJ9HCqEXcna3B9woQLviIaYQEaXMehbI+EBODm0R8o410CEnpCoaIY
|
|
||||||
8qQYR5Jw0rUV5zyZuDymJQMDbk/kS4Br47lkpkGtW42SkWToB1dDZY9GYncoFORz3G78C+Cdc3O+qLJH
|
|
||||||
0WYlCgPm572ZuOLT4YbfQIBcXB3XweLLpmexA1WjW3B0eB32DaxEqhiFuJ4QKD4LiKBLWdg7C1DQr8Ea
|
|
||||||
MldTB3qHUoqh2a1Ck3cnLo3l4AqZXvTtg8WbjfOeDNTRWoVrCw4Pr8VeOqlk3h0Cfhm5edBrAcbPswAn
|
|
||||||
HPuxuz+WYpgAk3MzGulhtlBSWsmQmzZ7syQ10ajqaCQ8TYeG1yD7x0qk9EVC+TUYUTTi8A4BwitSOwHe
|
|
||||||
zwLUD2Qxy5COWUcrmNV1ilnddczqqaXf0+ym4wx78LOezHfC7FKhdHQj8ocT0eqphMlm+F0j6lm5qGWl
|
|
||||||
JB1J+530jdSlZRKAx3SuiM2Ib7oz1MrM7m0odSbjIJ0yk07b4C6V1uYVj+lCxTfedjSxEnoueYPx2EE3
|
|
||||||
er0tAlXOY5JJYNvii5tYfzSw3ME46UXH36axlJQyR2DG/1sSQKxh2+0xSKCkLKM4829D0UzO/7e4SaNo
|
|
||||||
YondYVBQDJe+ExD8hlJikxFQLeoYNw+nzpfwGL4kwCcZASaKXwR1LtAFEl6QnhGgU0ZAUZ9RGomxi0QX
|
|
||||||
yNhBeisXgLLMjebUgjkXhD+4Jq73JQ87ogAAAABJRU5ErkJggg==
|
|
||||||
</value>
|
|
||||||
</data>
|
|
||||||
<data name="BTT_ADD_SHORTS_ONLY.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
|
||||||
<value>
|
|
||||||
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
|
||||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAN6SURBVEhLrZVJTFNRFIYfQhgkQA1OZTCKoqLBVgRRpEpb
|
|
||||||
hQpqrAwiBYJIQTCiBCpxSuO41GjcGRfEGOPGYFw5LJAYFQco8opQIKUTFEkw7K/5PfelRBYEDL6T/GmT
|
|
||||||
e/N/55733/eEhSr0XnBb2P1gzCW+Fti2+OJGabZUpuvR4ECvBgaRZNeg2KmXIIFtiy9ukvE9lS3tFBD9
|
|
||||||
UUDsFwHx30Jg9ubLB9glprKYTwJWfAnC2p4wqMVoXPAXygfYQwDeeZItDGn9McgZWIWbk+XyAbRiGkuy
|
|
||||||
hSOjX4E8RxzNfwPuTdXKB6gWd7F0uwL5jniUjW5CrUuNR9ON8gGaxRxmGEpAhSsFDe40NHuy8GTa8m+A
|
|
||||||
+XI+I3Of7ne5azPOutPROqbBNX8u2n61YPnTiHmlfB7ZJnWon8k45btgQINjDh0qnXk46zmCi75i3PJX
|
|
||||||
0v90XPLtxXV/Hm5MGNA21YLHUxYJ9HCqEXcna3B9woQLviIaYQEaXMehbI+EBODm0R8o410CEnpCoaIY
|
|
||||||
8qQYR5Jw0rUV5zyZuDymJQMDbk/kS4Br47lkpkGtW42SkWToB1dDZY9GYncoFORz3G78C+Cdc3O+qLJH
|
|
||||||
0WYlCgPm572ZuOLT4YbfQIBcXB3XweLLpmexA1WjW3B0eB32DaxEqhiFuJ4QKD4LiKBLWdg7C1DQr8Ea
|
|
||||||
MldTB3qHUoqh2a1Ck3cnLo3l4AqZXvTtg8WbjfOeDNTRWoVrCw4Pr8VeOqlk3h0Cfhm5edBrAcbPswAn
|
|
||||||
HPuxuz+WYpgAk3MzGulhtlBSWsmQmzZ7syQ10ajqaCQ8TYeG1yD7x0qk9EVC+TUYUTTi8A4BwitSOwHe
|
|
||||||
zwLUD2Qxy5COWUcrmNV1ilnddczqqaXf0+ym4wx78LOezHfC7FKhdHQj8ocT0eqphMlm+F0j6lm5qGWl
|
|
||||||
JB1J+530jdSlZRKAx3SuiM2Ib7oz1MrM7m0odSbjIJ0yk07b4C6V1uYVj+lCxTfedjSxEnoueYPx2EE3
|
|
||||||
er0tAlXOY5JJYNvii5tYfzSw3ME46UXH36axlJQyR2DG/1sSQKxh2+0xSKCkLKM4829D0UzO/7e4SaNo
|
|
||||||
YondYVBQDJe+ExD8hlJikxFQLeoYNw+nzpfwGL4kwCcZASaKXwR1LtAFEl6QnhGgU0ZAUZ9RGomxi0QX
|
|
||||||
yNhBeisXgLLMjebUgjkXhD+4Jq73JQ87ogAAAABJRU5ErkJggg==
|
|
||||||
</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>
|
||||||
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAN7SURBVEhLrZVbSJNhGMe/Ujwk6sKy5iHKsqysaVojcbnN
|
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAN5SURBVEhLrZVJTFNRFIafljBIgBqcymAU54oWGSRCK1oU
|
||||||
cksrWmqZJ8o8pJEluqQTo6zuIoruoguJiG7C6KrDhUlUdnDTvk23jLmTzQSj+zf+Pe/HJC9Ew74H/mzw
|
KqixAoIyiMqgGBAChYCaOsed0bgzLogxxo3RuHJYqDEqKFD1tUItKZ2gaIJxf8nvuc8SWRAw8E7yp03u
|
||||||
vvx/z/t8//f7hPkq4nZYd+SdMMwmvhbatvDiRtm2TKa3arBnUAOjSLJrUO4ulCChbQsvbpI7lMmW9AmI
|
zf+de95/3xNmquCbis6QWwpMJb4W2Db74kaJFjXT9+mw+7MOBpFk1aHImS1BAttmX9xE80XNFrwREPle
|
||||||
eycg4aOA5M/haPAXywdQi5ks/r2A5R8XYbU1ElliHM4FS+UD5BGAd55mi8Q2Rzy0IytwbbJaPoBWzGZp
|
QPRHAbE9Qaj25skHSBbVLOqDgMUf52FFXwiSxEi0+gvkA6QRgHeeYAlBsi0KO/qX4srPMvkAmWIiS7CE
|
||||||
tihsdyhgcCXR/Nfh9lSjfIA6Uc1y7QoUu5JRObYBjZ4s3P/VKh+gXSxgxq8pqPFsRIt3G9p9eXj4y/xv
|
Is2mRK49hua/GjfHauQDHBeTWapViTx7LI4MrUONKwl3fzfIB2gWM5jhexzKXRtQ505GsycD93+b/g8w
|
||||||
gLlyPq36Id3vak8GTntz0TmuwZVgEbp/dmDZo+g5pXwS0y11WDidccp3yYgGh1x61LoNOO07gPOBclwP
|
Xc4ndLQna7zMtR717lS0Detw0Z+Dzl8tWPQgbFqpHoV3Sh1mT2Sc8p3fr8NBux4VzlzUe/aj3VeEq/4K
|
||||||
1tL/XFwI7MLVoAFdE0Z0T3XgwZRZAt2basWtyXpcnajCuUAZjbAELZ4jUPbEQAJw87i3lPF+ASnWCKgo
|
+p+KDt92XPLn4vKoAZ1jLbg3ZpJAd8YacONnFS6NlqLVV0gjzEedqxiqx+GQANw88h1lvEtAXF8wNBRD
|
||||||
hjwppm9pOO7ZjDM+NS6O68jAiBsTxRLgyvciMtOg0ZuFw9/SUehcCZU9DqkDEVCQzxG76S+Ad87N+aLK
|
nhTjYAKOuTbijCcdZ4d3koEB10bzJMDFkRwy06HGnYRDg2uQPbAMGmsk4nuDoSSfYqvxH4B3zs35osYa
|
||||||
HkublSgNmZ/1q3EpoEdX0EiAIlz+roc5kE/PIgfHxjbh4OgaFIwkYosYiyRrOBQfBETTpSwdnAEocWiw
|
QZtVKAiYN3rTcc6nx2W/gQA5OD+ih8mnpWeRgsohNQ44ViKrfwk2iRGI6QuCsltAGF3Kgs+TAPk2HZaT
|
||||||
isyzqINCl1KKYYNXhTb/DlwY1+ISmZ4PFMDsz8dZ33Y00VqNZxP2j67GLjqpZD4QDn4ZufmiFwJMH2YA
|
eRJ1kG1XSTGsdmvQ5N2KjuEdOEem7b4smLxaNHrSUEtr5S419jlWYDudVDLvDQK/jNx83nMBxu5JgMP2
|
||||||
jrp2Y6cjgWKYgip3BlrpYXZQUjrJkJu2+/MktdGommgkPE37RlchfzgRG7/EQPkpDLE04qheAcJzUg8B
|
Xdhmi6YYxqHUuR4N9DBbKCltZMhNm70ZkppoVLU0Ep6mvY7l0H5bgg1fw6H6pEAEjTj0lQDhGekxAd5O
|
||||||
3swANA/vZGaXjlncNcwydoJZPE3M4m2k35Osy3mK3f3RTOY70OBRoWJsPYpHU9Hpq0Wl1fC7XtSzalHL
|
ApwSU5nJqmVmezkzfz/BzI5aZh6sod+TzCyeZrd/nCLzrah2aVAytBZ5jni0eSpQ1K0frxJ1rEzMZCUk
|
||||||
Kkg6knaI9JnUr2USgMd0tohNi2+66epkDd6tqHCnYy+dUk2nbfFWSGtzisd0vuIbrzvb2GF6LgZnMnLo
|
LSnzC6mH1JXJJACP6VQRmxDfdN3axqrdm1HiXIM9dMp0Om2du0Ram1Y8pjMV33hBbGKH6LnkDsQihW70
|
||||||
Rq+1ReOY+5BkEtq28OImFkcLK3ImSS86/jZNoKRUukIz/t+SAGI9y7bHI4WSspTizL8NZdM5/9/iJq1i
|
KksYKp0HJZPAttkXNzGLdSxnIEZ60fG3aTQl5Yg9MOO51l9AFdtijUIcJWUhxZl/Gwoncj7X4iYNYimL
|
||||||
FUsdiISCYrjktYCwl5QSm4yAOlHHuHkUdb6Yx/AZAd7LCKii+EVT5wJdIOEp6TEB+mQElH0xSSMx9ZPo
|
7w2BkmK44LUAxQtKiUVGwHFRy7h5KHU+n8fwKQE+yAgopfiFUecCXSDhCekhAd7ICCj8apRGYuwi0QUy
|
||||||
Apl6Sa/kAlCWudGsmjfngvAH4HCuyOLK/ToAAAAASUVORK5CYII=
|
viK9lAtAWeZGU2rGnAvCHy5drfKWDYjrAAAAAElFTkSuQmCC
|
||||||
</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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
|
||||||
ugAAAABJRU5ErkJggg==
|
bAAAAABJRU5ErkJggg==
|
||||||
</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">
|
||||||
|
|||||||
@@ -237,8 +237,7 @@ Namespace DownloadObjects.STDownloader
|
|||||||
Protected Overridable Sub BTT_SETTINGS_Click(sender As Object, e As EventArgs) Handles BTT_SETTINGS.Click
|
Protected Overridable Sub BTT_SETTINGS_Click(sender As Object, e As EventArgs) Handles BTT_SETTINGS.Click
|
||||||
MyYouTubeSettings.ShowForm(AppMode)
|
MyYouTubeSettings.ShowForm(AppMode)
|
||||||
End Sub
|
End Sub
|
||||||
Protected Overridable Sub BTT_ADD_KeyClick(ByVal Sender As ToolStripMenuItemKeyClick, ByVal e As KeyClickEventArgs) Handles BTT_ADD.KeyClick, BTT_ADD_PLS_ARR.KeyClick,
|
Protected Overridable Sub BTT_ADD_KeyClick(ByVal Sender As ToolStripMenuItemKeyClick, ByVal e As KeyClickEventArgs) Handles BTT_ADD.KeyClick, BTT_ADD_PLS_ARR.KeyClick
|
||||||
BTT_ADD_NO_SHORTS.KeyClick, BTT_ADD_SHORTS_ONLY.KeyClick
|
|
||||||
Dim pForm As ParsingProgressForm = Nothing
|
Dim pForm As ParsingProgressForm = Nothing
|
||||||
Try
|
Try
|
||||||
Dim useCookies As Boolean = MyYouTubeSettings.DefaultUseCookies
|
Dim useCookies As Boolean = MyYouTubeSettings.DefaultUseCookies
|
||||||
@@ -252,8 +251,6 @@ Namespace DownloadObjects.STDownloader
|
|||||||
|
|
||||||
Dim c As IYouTubeMediaContainer = Nothing
|
Dim c As IYouTubeMediaContainer = Nothing
|
||||||
Dim url$ = String.Empty
|
Dim url$ = String.Empty
|
||||||
Dim GetDefault As Boolean = True
|
|
||||||
Dim GetShorts As Boolean = True
|
|
||||||
|
|
||||||
If sTag = "pls" Then
|
If sTag = "pls" Then
|
||||||
Using pf As New PlaylistArrayForm With {.DesignXML = DesignXML}
|
Using pf As New PlaylistArrayForm With {.DesignXML = DesignXML}
|
||||||
@@ -266,7 +263,7 @@ Namespace DownloadObjects.STDownloader
|
|||||||
pForm.SetInitialValues(.Count, "Parsing playlists...")
|
pForm.SetInitialValues(.Count, "Parsing playlists...")
|
||||||
Dim containers As New List(Of IYouTubeMediaContainer)
|
Dim containers As New List(Of IYouTubeMediaContainer)
|
||||||
For Each u$ In .Self
|
For Each u$ In .Self
|
||||||
containers.Add(YouTubeFunctions.Parse(standardize(u), useCookiesParse, pForm.Token, pForm.MyProgress, True, False))
|
containers.Add(YouTubeFunctions.Parse(standardize(u), useCookiesParse, pForm.Token, pForm.MyProgress))
|
||||||
pForm.NextPlaylist()
|
pForm.NextPlaylist()
|
||||||
pForm.MyProgress.Perform()
|
pForm.MyProgress.Perform()
|
||||||
Next
|
Next
|
||||||
@@ -295,20 +292,36 @@ Namespace DownloadObjects.STDownloader
|
|||||||
End If
|
End If
|
||||||
End Using
|
End Using
|
||||||
Else
|
Else
|
||||||
Select Case sTag
|
|
||||||
Case "ans" : GetShorts = False
|
|
||||||
Case "as" : GetDefault = False : GetShorts = True
|
|
||||||
End Select
|
|
||||||
url = BufferText
|
url = BufferText
|
||||||
If url.IsEmptyString OrElse Not YouTubeFunctions.IsMyUrl(url) Then url = InputBoxE("Enter a valid URL to the YouTube video:", "YouTube link")
|
If url.IsEmptyString OrElse Not YouTubeFunctions.IsMyUrl(url) Then url = InputBoxE("Enter a valid URL to the YouTube video:", "YouTube link")
|
||||||
End If
|
End If
|
||||||
|
|
||||||
If Not c Is Nothing OrElse YouTubeFunctions.IsMyUrl(url) Then
|
If Not c Is Nothing OrElse YouTubeFunctions.IsMyUrl(url) Then
|
||||||
If c Is Nothing Then
|
If c Is Nothing Then
|
||||||
|
Dim downAsIs As Boolean = False
|
||||||
|
Dim channelTab As YouTubeChannelTab? = Nothing
|
||||||
|
Dim __channelTab As YouTubeChannelTab = YouTubeChannelTab.All
|
||||||
|
Dim oType As YouTubeMediaType = YouTubeFunctions.Info_GetUrlType(url,,,,, __channelTab)
|
||||||
|
If oType = YouTubeMediaType.Channel Then
|
||||||
|
channelTab = __channelTab
|
||||||
|
Using channelTabForm As New ChannelTabsChooserForm(__channelTab, url) With {.DesignXML = DesignXML}
|
||||||
|
With channelTabForm
|
||||||
|
.ShowDialog()
|
||||||
|
If .DialogResult = DialogResult.OK Then
|
||||||
|
channelTab = .Result
|
||||||
|
downAsIs = .MyUrlAsIs
|
||||||
|
url = YouTubeFunctions.StandardizeURL_Channel(.URL, Not downAsIs)
|
||||||
|
Else
|
||||||
|
Exit Sub
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
End Using
|
||||||
|
End If
|
||||||
pForm = New ParsingProgressForm
|
pForm = New ParsingProgressForm
|
||||||
pForm.Show(Me)
|
pForm.Show(Me)
|
||||||
pForm.SetInitialValues(1, "Parsing data...")
|
pForm.SetInitialValues(1, "Parsing data...")
|
||||||
c = YouTubeFunctions.Parse(standardize(url), useCookiesParse, pForm.Token, pForm.MyProgress, GetDefault, GetShorts)
|
c = YouTubeFunctions.Parse(standardize(url), useCookiesParse, pForm.Token, pForm.MyProgress,,, channelTab,
|
||||||
|
oType <> YouTubeMediaType.Channel Or downAsIs)
|
||||||
pForm.Dispose()
|
pForm.Dispose()
|
||||||
End If
|
End If
|
||||||
If Not c Is Nothing Then
|
If Not c Is Nothing Then
|
||||||
@@ -326,7 +339,7 @@ Namespace DownloadObjects.STDownloader
|
|||||||
If Not f Is Nothing Then
|
If Not f Is Nothing Then
|
||||||
If TypeOf f Is IDesignXMLContainer Then DirectCast(f, IDesignXMLContainer).DesignXML = DesignXML
|
If TypeOf f Is IDesignXMLContainer Then DirectCast(f, IDesignXMLContainer).DesignXML = DesignXML
|
||||||
f.ShowDialog()
|
f.ShowDialog()
|
||||||
If f.DialogResult = DialogResult.OK Then ControlCreateAndAdd(c, disableDown)
|
If f.DialogResult = DialogResult.OK AndAlso ValidateContainerURL(c) Then ControlCreateAndAdd(c, disableDown)
|
||||||
f.Dispose()
|
f.Dispose()
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
@@ -340,6 +353,61 @@ Namespace DownloadObjects.STDownloader
|
|||||||
If Not pForm Is Nothing Then pForm.Dispose()
|
If Not pForm Is Nothing Then pForm.Dispose()
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
|
Protected Function ValidateContainerURL(ByVal c As IYouTubeMediaContainer) As Boolean
|
||||||
|
Try
|
||||||
|
If Not c Is Nothing AndAlso Not c.IsMusic Then
|
||||||
|
Dim urls As List(Of String) = Nothing
|
||||||
|
Dim files As List(Of SFile) = Nothing
|
||||||
|
Dim msg As New MMessage("The media file to be added is already downloaded. Do you want to download it again?", "Download media file", {"Process", "Cancel"}, vbExclamation)
|
||||||
|
If TP_CONTROLS.Controls.Count > 0 Then
|
||||||
|
With TP_CONTROLS.Controls.Cast(Of MediaItem)
|
||||||
|
urls.ListAddList(.SelectMany(Function(ByVal m As MediaItem) As IEnumerable(Of String)
|
||||||
|
If Not m.MyContainer Is Nothing Then
|
||||||
|
Return DirectCast(m.MyContainer, YouTubeMediaContainerBase).GetUrls()
|
||||||
|
Else
|
||||||
|
Return New String() {}
|
||||||
|
End If
|
||||||
|
End Function), LAP.NotContainsOnly, EDP.ReturnValue)
|
||||||
|
files.ListAddList(.SelectMany(Function(ByVal m As MediaItem) As IEnumerable(Of SFile)
|
||||||
|
If Not m.MyContainer Is Nothing Then
|
||||||
|
Return DirectCast(m.MyContainer, YouTubeMediaContainerBase).GetFiles()
|
||||||
|
Else
|
||||||
|
Return New SFile() {}
|
||||||
|
End If
|
||||||
|
End Function), LAP.NotContainsOnly, EDP.ReturnValue)
|
||||||
|
End With
|
||||||
|
End If
|
||||||
|
If urls.ListExists Then
|
||||||
|
Dim cUrls As New List(Of String)
|
||||||
|
cUrls.ListAddList({c.URL, c.URL_BASE}, LAP.NotContainsOnly)
|
||||||
|
If urls.ListContains(cUrls) Then Return msg.Show = 0
|
||||||
|
End If
|
||||||
|
If files.ListExists And Not c.File.IsEmptyString Then Return Not files.Contains(c.File) OrElse msg.Show = 0
|
||||||
|
If c.ObjectType = YouTubeMediaType.Single AndAlso c.File.Exists Then
|
||||||
|
Dim callBack As MsgBoxButtonCallBack = Sub(r, m, b)
|
||||||
|
Dim __sfo As SFO = IIf(r.Button.CallBackObject = 0, SFO.File, SFO.Path)
|
||||||
|
If __sfo = SFO.File Then
|
||||||
|
c.File.Open(__sfo)
|
||||||
|
Else
|
||||||
|
GlobalOpenPath(c.File)
|
||||||
|
End If
|
||||||
|
End Sub
|
||||||
|
Return MsgBoxE(New MMessage("The following file already exists at the destination." & vbCr &
|
||||||
|
"Do you want to download it again?" & vbCr & vbCr &
|
||||||
|
$"File: {c.File}", "Download media file",
|
||||||
|
{"Process",
|
||||||
|
New MsgBoxButton("Open file") With {.IsDialogResultButton = False, .CallBackObject = 0, .CallBack = callBack},
|
||||||
|
New MsgBoxButton("Open folder") With {.IsDialogResultButton = False, .CallBackObject = 1, .CallBack = callBack},
|
||||||
|
"Cancel"}, vbExclamation) With {.ButtonsPerRow = 4}) = 0
|
||||||
|
End If
|
||||||
|
urls.ListClearDispose
|
||||||
|
files.ListClearDispose
|
||||||
|
End If
|
||||||
|
Return True
|
||||||
|
Catch ex As Exception
|
||||||
|
Return ErrorsDescriber.Execute(EDP.SendToLog + EDP.ReturnValue, ex, "[VideoListForm.ValidateContainerURL]", True)
|
||||||
|
End Try
|
||||||
|
End Function
|
||||||
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
|
||||||
@@ -367,6 +435,19 @@ Namespace DownloadObjects.STDownloader
|
|||||||
Protected Overridable Sub BTT_CLEAR_ALL_Click(sender As Object, e As EventArgs) Handles BTT_CLEAR_ALL.Click
|
Protected Overridable Sub BTT_CLEAR_ALL_Click(sender As Object, e As EventArgs) Handles BTT_CLEAR_ALL.Click
|
||||||
RemoveControls(, False)
|
RemoveControls(, False)
|
||||||
End Sub
|
End Sub
|
||||||
|
Private Sub BTT_SELECT_ALL_Click(sender As Object, e As EventArgs) Handles BTT_SELECT_ALL.Click, BTT_SELECT_NONE.Click
|
||||||
|
Try
|
||||||
|
Dim checked As Boolean = sender Is BTT_SELECT_ALL
|
||||||
|
ControlInvokeFast(TP_CONTROLS, Sub()
|
||||||
|
With TP_CONTROLS.Controls
|
||||||
|
If .Count > 0 Then
|
||||||
|
For Each cnt As MediaItem In .Self : cnt.Checked = checked : Next
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
End Sub, EDP.None)
|
||||||
|
Catch
|
||||||
|
End Try
|
||||||
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
Private Sub BTT_LOG_Click(sender As Object, e As EventArgs) Handles BTT_LOG.Click
|
Private Sub BTT_LOG_Click(sender As Object, e As EventArgs) Handles BTT_LOG.Click
|
||||||
MyMainLOG_ShowForm(DesignXML,,,, AddressOf UpdateLogButton)
|
MyMainLOG_ShowForm(DesignXML,,,, AddressOf UpdateLogButton)
|
||||||
@@ -387,8 +468,10 @@ Namespace DownloadObjects.STDownloader
|
|||||||
Try : Process.Start("https://github.com/AAndyProgram/SCrawler/blob/main/HowToSupport.md") : Catch : End Try
|
Try : Process.Start("https://github.com/AAndyProgram/SCrawler/blob/main/HowToSupport.md") : Catch : End Try
|
||||||
End Sub
|
End Sub
|
||||||
Private Sub BTT_INFO_Click(sender As Object, e As EventArgs) Handles BTT_INFO.Click
|
Private Sub BTT_INFO_Click(sender As Object, e As EventArgs) Handles BTT_INFO.Click
|
||||||
ShowProgramInfo(MyYouTubeSettings.ProgramText.Value.IfNullOrEmpty("YouTube Downloader"),
|
CheckVersionImpl(True)
|
||||||
My.Application.Info.Version, False, True, MyYouTubeSettings, True,, False, MyYouTubeSettings.ProgramDescription)
|
End Sub
|
||||||
|
Protected Sub CheckVersionImpl(ByVal Force As Boolean)
|
||||||
|
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)
|
||||||
ControlInvokeFast(TP_CONTROLS, Sub()
|
ControlInvokeFast(TP_CONTROLS, Sub()
|
||||||
@@ -441,16 +524,23 @@ Namespace DownloadObjects.STDownloader
|
|||||||
RemoveControls(Sender, False)
|
RemoveControls(Sender, False)
|
||||||
End Sub
|
End Sub
|
||||||
Private Sub MediaControl_DownloadAgain(ByVal Sender As MediaItem, ByVal Container As IYouTubeMediaContainer)
|
Private Sub MediaControl_DownloadAgain(ByVal Sender As MediaItem, ByVal Container As IYouTubeMediaContainer)
|
||||||
If Not Container.URL.IsEmptyString Then BufferText = Container.URL : BTT_ADD.PerformClick()
|
Try
|
||||||
|
If Not Container.URL.IsEmptyString Then BufferText = Container.URL : BTT_ADD.PerformClick()
|
||||||
|
Catch ex As Exception
|
||||||
|
ErrorsDescriber.Execute(EDP.SendToLog, ex, "[VideoListForm.DownloadAgain]")
|
||||||
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
Private Sub MediaControl_DownloadRequested(ByVal Sender As MediaItem, ByVal Container As IYouTubeMediaContainer)
|
Private Sub MediaControl_DownloadRequested(ByVal Sender As MediaItem, ByVal Container As IYouTubeMediaContainer)
|
||||||
AddToDownload(Sender, True)
|
AddToDownload(Sender, True)
|
||||||
End Sub
|
End Sub
|
||||||
Private Sub MediaControl_CheckedChanged(ByVal Sender As MediaItem, ByVal Container As IYouTubeMediaContainer)
|
Private Sub MediaControl_CheckedChanged(ByVal Sender As MediaItem, ByVal Container As IYouTubeMediaContainer)
|
||||||
With TP_CONTROLS.Controls
|
Try
|
||||||
ControlInvokeFast(TOOLBAR_TOP, BTT_DELETE,
|
With TP_CONTROLS.Controls
|
||||||
Sub() BTT_DELETE.Enabled = .Count > 0 AndAlso .Cast(Of MediaItem).ListExists(Function(cnt) cnt.Checked), EDP.None)
|
ControlInvokeFast(TOOLBAR_TOP, BTT_DELETE,
|
||||||
End With
|
Sub() BTT_DELETE.Enabled = .Count > 0 AndAlso .Cast(Of MediaItem).ListExists(Function(cnt) cnt.Checked), EDP.None)
|
||||||
|
End With
|
||||||
|
Catch
|
||||||
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#End Region
|
#End Region
|
||||||
|
|||||||
@@ -6,6 +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 System.Threading
|
||||||
Imports PersonalUtilities.Tools
|
Imports PersonalUtilities.Tools
|
||||||
Imports PersonalUtilities.Tools.Web
|
Imports PersonalUtilities.Tools.Web
|
||||||
Imports PersonalUtilities.Functions.Messaging
|
Imports PersonalUtilities.Functions.Messaging
|
||||||
@@ -38,19 +39,54 @@ Public Module MainModShared
|
|||||||
End If
|
End If
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
|
Public Sub CheckNewReleaseFolder()
|
||||||
|
Try
|
||||||
|
Const updaterFolderName$ = "Updater\"
|
||||||
|
Dim f As SFile = SCrawler.Shared.NewReleaseFolderName.CSFileP
|
||||||
|
If f.Exists(SFO.Path, False) Then
|
||||||
|
Dim updater As SFile = updaterFolderName
|
||||||
|
Dim updaterNR As SFile = f.PathWithSeparator & updaterFolderName
|
||||||
|
If updaterNR.Exists(SFO.Path, False) Then
|
||||||
|
If updater.Exists(SFO.Path, False) Then updater.Delete(SFO.Path, SFODelete.DeletePermanently, EDP.ReturnValue)
|
||||||
|
SFile.Move(updaterNR, updater, SFO.Path, True, SFODelete.DeletePermanently, EDP.ReturnValue)
|
||||||
|
End If
|
||||||
|
f.Delete(SFO.Path, SFODelete.DeletePermanently, EDP.None)
|
||||||
|
End If
|
||||||
|
Catch ex As Exception
|
||||||
|
End Try
|
||||||
|
End Sub
|
||||||
Public Sub ShowProgramInfo(ByVal ProgramText As String, ByVal CurrentVersion As Version, ByVal CheckForUpdate As Boolean, ByVal Force As Boolean,
|
Public Sub ShowProgramInfo(ByVal ProgramText As String, ByVal CurrentVersion As Version, ByVal CheckForUpdate As Boolean, ByVal Force As Boolean,
|
||||||
ByVal EnvirData As IDownloaderSettings, ByVal IsYouTube As Boolean,
|
ByVal EnvirData As IDownloaderSettings, ByVal IsYouTube As Boolean,
|
||||||
Optional ByRef NewVersionDestination As String = Nothing, Optional ByVal ShowNewVersionNotification As Boolean = True,
|
Optional ByRef NewVersionDestination As String = Nothing, Optional ByRef ShowNewVersionNotification As Boolean = True,
|
||||||
Optional ByVal AdditText As String = Nothing)
|
Optional ByVal AdditText As String = Nothing)
|
||||||
Try
|
Try
|
||||||
Dim GoToSite As New MsgBoxButton("Go to site") With {.CallBack = Sub(r, n, b) Process.Start("https://github.com/AAndyProgram/SCrawler/releases/latest")}
|
Dim GoToSite As New MsgBoxButton("Go to site") With {.CallBack = Sub(r, n, b) Process.Start("https://github.com/AAndyProgram/SCrawler/releases/latest")}
|
||||||
If CheckForUpdate AndAlso GitHub.NewVersionExists(CurrentVersion, "AAndyProgram", "SCrawler", NewVersionDestination) Then
|
If CheckForUpdate AndAlso GitHub.NewVersionExists(CurrentVersion, "AAndyProgram", "SCrawler", NewVersionDestination) Then
|
||||||
If ShowNewVersionNotification Or Force Then
|
If ShowNewVersionNotification Or Force Then
|
||||||
If MsgBoxE(New MMessage($"{ProgramText}: new version detected" & vbCr &
|
Dim b As New List(Of MsgBoxButton)
|
||||||
$"Current version: {CurrentVersion}" & vbCr &
|
Dim updaterFile As SFile = Nothing
|
||||||
$"New version: {NewVersionDestination}",
|
Dim updateBtt As New MsgBoxButton("Update", "Update the program using the updater") With {
|
||||||
"New version",
|
.CallBack = Sub(r, n, btt)
|
||||||
{"OK", GoToSite, "Disable notifications"})) = 2 Then ShowNewVersionNotification = False
|
Dim th As New Thread(Sub() Process.Start(New ProcessStartInfo(updaterFile, 1))) With {.IsBackground = True}
|
||||||
|
th.SetApartmentState(ApartmentState.MTA)
|
||||||
|
th.Start()
|
||||||
|
End Sub}
|
||||||
|
With SFile.GetFiles("Updater\", "*.exe",, EDP.ReturnValue).ListIfNothing
|
||||||
|
If .ListExists Then
|
||||||
|
With .FirstOrDefault(Function(f) f.Name = "Updater")
|
||||||
|
If Not .IsEmptyString Then updaterFile = .Self
|
||||||
|
End With
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
b.AddRange({"OK", GoToSite})
|
||||||
|
If Not updaterFile.IsEmptyString Then b.Add(updateBtt)
|
||||||
|
b.Add(New MsgBoxButton("Disable notifications") With {.CallBackObject = 10})
|
||||||
|
If AConvert(Of Integer)(
|
||||||
|
MsgBoxE(New MMessage($"{ProgramText}: new version detected" & vbCr &
|
||||||
|
$"Current version: {CurrentVersion}" & vbCr &
|
||||||
|
$"New version: {NewVersionDestination}",
|
||||||
|
"New version", b) With {.ButtonsPerRow = 4}).Button.CallBackObject, -1) = 10 Then _
|
||||||
|
ShowNewVersionNotification = False
|
||||||
End If
|
End If
|
||||||
Else
|
Else
|
||||||
If Force Then
|
If Force Then
|
||||||
|
|||||||
@@ -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.11.24.0")>
|
<Assembly: AssemblyVersion("2024.2.25.0")>
|
||||||
<Assembly: AssemblyFileVersion("2023.11.24.0")>
|
<Assembly: AssemblyFileVersion("2024.2.25.0")>
|
||||||
<Assembly: NeutralResourcesLanguage("en")>
|
<Assembly: NeutralResourcesLanguage("en")>
|
||||||
|
|||||||
@@ -139,22 +139,26 @@ Namespace API.YouTube.Objects
|
|||||||
#End Region
|
#End Region
|
||||||
#Region "Data info"
|
#Region "Data info"
|
||||||
Friend ReadOnly Property MediaObjects As List(Of MediaObject) Implements IYouTubeMediaContainer.MediaObjects
|
Friend ReadOnly Property MediaObjects As List(Of MediaObject) Implements IYouTubeMediaContainer.MediaObjects
|
||||||
|
Friend Property [Protected] As Boolean = False
|
||||||
|
Friend Property IsAudioSelected As Boolean = False
|
||||||
#Region "Array"
|
#Region "Array"
|
||||||
''' <summary>[-10] = disabled; [-1] = max; [-2] = audio only</summary>
|
''' <summary>[-10] = disabled; [-1] = max; [-2] = audio only</summary>
|
||||||
<XMLEC> Friend Property ArrayMaxResolution As Integer = -10
|
<XMLEC> Friend Property ArrayMaxResolution As Integer = -10
|
||||||
''' <param name="Value">[-1] = max; [-2] = audio only</param>
|
''' <param name="Value">[-1] = max; [-2] = audio only</param>
|
||||||
Friend Sub SetMaxResolution(ByVal Value As Integer)
|
Friend Sub SetMaxResolution(ByVal Value As Integer)
|
||||||
ArrayMaxResolution = Value
|
If Not [Protected] Then
|
||||||
SelectedVideoIndex = -1
|
ArrayMaxResolution = Value
|
||||||
If MediaObjects.Count > 0 And Value <> -2 Then
|
SelectedVideoIndex = -1
|
||||||
If Value = -1 Then
|
If MediaObjects.Count > 0 And Value <> -2 Then
|
||||||
SelectedVideoIndex = MediaObjects.FindIndex(Function(mo) mo.Type = UMTypes.Video)
|
If Value = -1 Then
|
||||||
Else
|
SelectedVideoIndex = MediaObjects.FindIndex(Function(mo) mo.Type = UMTypes.Video)
|
||||||
SelectedVideoIndex = MediaObjects.FindIndex(Function(mo) mo.Type = UMTypes.Video And mo.Height <= Value)
|
Else
|
||||||
If SelectedVideoIndex = -1 Then SelectedVideoIndex = MediaObjects.FindIndex(Function(mo) mo.Type = UMTypes.Video)
|
SelectedVideoIndex = MediaObjects.FindIndex(Function(mo) mo.Type = UMTypes.Video And mo.Height <= Value)
|
||||||
|
If SelectedVideoIndex = -1 Then SelectedVideoIndex = MediaObjects.FindIndex(Function(mo) mo.Type = UMTypes.Video)
|
||||||
|
End If
|
||||||
End If
|
End If
|
||||||
|
If HasElements Then Elements.ForEach(Sub(e As YouTubeMediaContainerBase) e.SetMaxResolution(Value))
|
||||||
End If
|
End If
|
||||||
If HasElements Then Elements.ForEach(Sub(e As YouTubeMediaContainerBase) e.SetMaxResolution(Value))
|
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Thumbnails"
|
#Region "Thumbnails"
|
||||||
@@ -213,8 +217,22 @@ Namespace API.YouTube.Objects
|
|||||||
Return _OutputVideoExtension
|
Return _OutputVideoExtension
|
||||||
End Get
|
End Get
|
||||||
Set(ByVal _OutputVideoExtension As String)
|
Set(ByVal _OutputVideoExtension As String)
|
||||||
Me._OutputVideoExtension = _OutputVideoExtension
|
If Not [Protected] Then
|
||||||
If HasElements Then Elements.ForEach(Sub(e) e.OutputVideoExtension = _OutputVideoExtension)
|
Me._OutputVideoExtension = _OutputVideoExtension
|
||||||
|
If HasElements Then Elements.ForEach(Sub(e) e.OutputVideoExtension = _OutputVideoExtension)
|
||||||
|
End If
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
<XMLEC("OutputVideoFPS")> Protected _OutputVideoFPS As Double = -1
|
||||||
|
Friend Property OutputVideoFPS As Double
|
||||||
|
Get
|
||||||
|
Return _OutputVideoFPS
|
||||||
|
End Get
|
||||||
|
Set(ByVal fps As Double)
|
||||||
|
If Not [Protected] Then
|
||||||
|
_OutputVideoFPS = fps
|
||||||
|
If HasElements Then Elements.ForEach(Sub(elem) DirectCast(elem, YouTubeMediaContainerBase).OutputVideoFPS = fps)
|
||||||
|
End If
|
||||||
End Set
|
End Set
|
||||||
End Property
|
End Property
|
||||||
#End Region
|
#End Region
|
||||||
@@ -231,8 +249,10 @@ Namespace API.YouTube.Objects
|
|||||||
Return _OutputAudioCodec
|
Return _OutputAudioCodec
|
||||||
End Get
|
End Get
|
||||||
Set(ByVal _OutputAudioCodec As String)
|
Set(ByVal _OutputAudioCodec As String)
|
||||||
Me._OutputAudioCodec = _OutputAudioCodec
|
If Not [Protected] Then
|
||||||
If HasElements Then Elements.ForEach(Sub(e) e.OutputAudioCodec = _OutputAudioCodec)
|
Me._OutputAudioCodec = _OutputAudioCodec
|
||||||
|
If HasElements Then Elements.ForEach(Sub(e) e.OutputAudioCodec = _OutputAudioCodec)
|
||||||
|
End If
|
||||||
End Set
|
End Set
|
||||||
End Property
|
End Property
|
||||||
<XMLEC(CollectionMode:=CollectionModes.String)>
|
<XMLEC(CollectionMode:=CollectionModes.String)>
|
||||||
@@ -272,8 +292,10 @@ Namespace API.YouTube.Objects
|
|||||||
Return _OutputSubtitlesFormat
|
Return _OutputSubtitlesFormat
|
||||||
End Get
|
End Get
|
||||||
Set(ByVal _OutputSubtitlesFormat As String)
|
Set(ByVal _OutputSubtitlesFormat As String)
|
||||||
Me._OutputSubtitlesFormat = _OutputSubtitlesFormat
|
If Not [Protected] Then
|
||||||
If HasElements Then Elements.ForEach(Sub(e) e.OutputSubtitlesFormat = _OutputSubtitlesFormat)
|
Me._OutputSubtitlesFormat = _OutputSubtitlesFormat
|
||||||
|
If HasElements Then Elements.ForEach(Sub(e) e.OutputSubtitlesFormat = _OutputSubtitlesFormat)
|
||||||
|
End If
|
||||||
End Set
|
End Set
|
||||||
End Property
|
End Property
|
||||||
<XMLEC(CollectionMode:=CollectionModes.String)>
|
<XMLEC(CollectionMode:=CollectionModes.String)>
|
||||||
@@ -496,6 +518,12 @@ Namespace API.YouTube.Objects
|
|||||||
_IUserMedia_URL_BASE = u
|
_IUserMedia_URL_BASE = u
|
||||||
End Set
|
End Set
|
||||||
End Property
|
End Property
|
||||||
|
Friend Function GetUrls() As IEnumerable(Of String)
|
||||||
|
Dim urls As New List(Of String)
|
||||||
|
urls.ListAddList({URL, IUserMedia_URL_BASE}, LAP.NotContainsOnly)
|
||||||
|
If HasElements And Not IsMusic Then urls.ListAddList(Elements.SelectMany(Function(elem As YouTubeMediaContainerBase) elem.GetUrls()), LAP.NotContainsOnly)
|
||||||
|
Return urls
|
||||||
|
End Function
|
||||||
Protected Overridable Sub GenerateFileName()
|
Protected Overridable Sub GenerateFileName()
|
||||||
End Sub
|
End Sub
|
||||||
Protected Function GetPlayListTitle() As String
|
Protected Function GetPlayListTitle() As String
|
||||||
@@ -531,7 +559,7 @@ Namespace API.YouTube.Objects
|
|||||||
If ObjectType = YouTubeMediaType.Single AndAlso Not GetPlayListTitle.IsEmptyString Then _SpecialPath.StringAppend(GetPlayListTitle(), "\")
|
If ObjectType = YouTubeMediaType.Single AndAlso Not GetPlayListTitle.IsEmptyString Then _SpecialPath.StringAppend(GetPlayListTitle(), "\")
|
||||||
If Elements.Count > 0 Then Elements.ForEach(Sub(e) e.SpecialFolder = Path)
|
If Elements.Count > 0 Then Elements.ForEach(Sub(e) e.SpecialFolder = Path)
|
||||||
End Sub
|
End Sub
|
||||||
<XMLEC> Friend ReadOnly Property Files As List(Of SFile) Implements IYouTubeMediaContainer.Files
|
<XMLEC> Protected Friend ReadOnly Property Files As List(Of SFile) Implements IYouTubeMediaContainer.Files
|
||||||
<XMLEC> Protected _File As SFile
|
<XMLEC> Protected _File As SFile
|
||||||
<XMLEC> Protected Friend Property FileSetManually As Boolean = False
|
<XMLEC> Protected Friend Property FileSetManually As Boolean = False
|
||||||
Public Property FileIgnorePlaylist As Boolean = False
|
Public Property FileIgnorePlaylist As Boolean = False
|
||||||
@@ -549,8 +577,10 @@ Namespace API.YouTube.Objects
|
|||||||
Return _AbsolutePath
|
Return _AbsolutePath
|
||||||
End Get
|
End Get
|
||||||
Set(ByVal ap As Boolean)
|
Set(ByVal ap As Boolean)
|
||||||
_AbsolutePath = ap
|
If Not [Protected] Then
|
||||||
If Elements.Count > 0 Then Elements.ForEach(Sub(e As YouTubeMediaContainerBase) e.AbsolutePath = ap)
|
_AbsolutePath = ap
|
||||||
|
If Elements.Count > 0 Then Elements.ForEach(Sub(e As YouTubeMediaContainerBase) e.AbsolutePath = ap)
|
||||||
|
End If
|
||||||
End Set
|
End Set
|
||||||
End Property
|
End Property
|
||||||
Public Overridable Property File As SFile Implements IYouTubeMediaContainer.File
|
Public Overridable Property File As SFile Implements IYouTubeMediaContainer.File
|
||||||
@@ -558,28 +588,30 @@ Namespace API.YouTube.Objects
|
|||||||
Return _File
|
Return _File
|
||||||
End Get
|
End Get
|
||||||
Set(ByVal f As SFile)
|
Set(ByVal f As SFile)
|
||||||
Select Case ObjectType
|
If Not [Protected] Then
|
||||||
Case YouTubeMediaType.Channel : _File = f.Path
|
Select Case ObjectType
|
||||||
Case YouTubeMediaType.PlayList
|
Case YouTubeMediaType.Channel : _File = f.Path
|
||||||
If AbsolutePath Then
|
Case YouTubeMediaType.PlayList
|
||||||
_File.Path = f.Path
|
If AbsolutePath Then
|
||||||
Else
|
_File.Path = f.Path
|
||||||
_File.Path = $"{f.PathWithSeparator}{GetPlayListTitle()}"
|
Else
|
||||||
End If
|
_File.Path = $"{f.PathWithSeparator}{GetPlayListTitle()}"
|
||||||
Case YouTubeMediaType.Single
|
End If
|
||||||
If PlaylistCount > 0 And Not FileIgnorePlaylist Then
|
Case YouTubeMediaType.Single
|
||||||
_File.Path = f.Path
|
If PlaylistCount > 0 And Not FileIgnorePlaylist Then
|
||||||
Dim pls$ = If(AbsolutePath, String.Empty, GetPlayListTitle())
|
_File.Path = f.Path
|
||||||
If Not _File.Path.Contains(pls) Then _File.Path = $"{_File.PathWithSeparator(Not pls.IsEmptyString)}{pls}"
|
Dim pls$ = If(AbsolutePath, String.Empty, GetPlayListTitle())
|
||||||
ElseIf Not f.Name.IsEmptyString Then
|
If Not _File.Path.Contains(pls) Then _File.Path = $"{_File.PathWithSeparator(Not pls.IsEmptyString)}{pls}"
|
||||||
_File = f
|
ElseIf Not f.Name.IsEmptyString Then
|
||||||
Else
|
_File = f
|
||||||
_File.Path = f.Path
|
Else
|
||||||
End If
|
_File.Path = f.Path
|
||||||
Case Else : _File = f
|
End If
|
||||||
End Select
|
Case Else : _File = f
|
||||||
GenerateFileName()
|
End Select
|
||||||
If HasElements Then Elements.ForEach(Sub(e) e.File = _File)
|
GenerateFileName()
|
||||||
|
If HasElements Then Elements.ForEach(Sub(e) e.File = _File)
|
||||||
|
End If
|
||||||
End Set
|
End Set
|
||||||
End Property
|
End Property
|
||||||
Public Property FileSettings As SFile
|
Public Property FileSettings As SFile
|
||||||
@@ -591,6 +623,11 @@ Namespace API.YouTube.Objects
|
|||||||
File = f
|
File = f
|
||||||
End Set
|
End Set
|
||||||
End Property
|
End Property
|
||||||
|
Friend Function GetFiles() As IEnumerable(Of SFile)
|
||||||
|
Dim urls As New List(Of String)({File})
|
||||||
|
If HasElements And Not IsMusic Then urls.ListAddList(Elements.SelectMany(Function(elem As YouTubeMediaContainerBase) elem.GetFiles()), LAP.NotContainsOnly)
|
||||||
|
Return urls
|
||||||
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
#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
|
||||||
@@ -603,6 +640,7 @@ Namespace API.YouTube.Objects
|
|||||||
If Not File.IsEmptyString Then
|
If Not File.IsEmptyString Then
|
||||||
If File.Exists Then File = SFile.IndexReindex(File)
|
If File.Exists Then File = SFile.IndexReindex(File)
|
||||||
Dim cmd$ = String.Empty, formats$ = String.Empty, subs$ = String.Empty, remux$ = String.Empty
|
Dim cmd$ = String.Empty, formats$ = String.Empty, subs$ = String.Empty, remux$ = String.Empty
|
||||||
|
Dim embedThumbArgAdded As Boolean = False
|
||||||
_Size = 0
|
_Size = 0
|
||||||
Height = 0
|
Height = 0
|
||||||
Bitrate = 0
|
Bitrate = 0
|
||||||
@@ -615,6 +653,10 @@ Namespace API.YouTube.Objects
|
|||||||
_MediaType = UMTypes.Video
|
_MediaType = UMTypes.Video
|
||||||
Height = SelectedVideo.Height
|
Height = SelectedVideo.Height
|
||||||
_File.Extension = OutputVideoExtension
|
_File.Extension = OutputVideoExtension
|
||||||
|
If Not embedThumbArgAdded And MyYouTubeSettings.DefaultVideoEmbedThumbnail Then
|
||||||
|
formats.StringAppend("--embed-thumbnail", " ")
|
||||||
|
embedThumbArgAdded = True
|
||||||
|
End If
|
||||||
Else
|
Else
|
||||||
formats.StringAppend("--extract-audio", " ")
|
formats.StringAppend("--extract-audio", " ")
|
||||||
_MediaType = UMTypes.Audio
|
_MediaType = UMTypes.Audio
|
||||||
@@ -632,7 +674,13 @@ Namespace API.YouTube.Objects
|
|||||||
formats.StringAppend($"--audio-format {OutputAudioCodec.StringToLower}", " ")
|
formats.StringAppend($"--audio-format {OutputAudioCodec.StringToLower}", " ")
|
||||||
atCodec = OutputAudioCodec.StringToLower
|
atCodec = OutputAudioCodec.StringToLower
|
||||||
End If
|
End If
|
||||||
If SelectedVideoIndex = -1 Then formats.StringAppend("--add-metadata", " ")
|
If SelectedVideoIndex = -1 Then
|
||||||
|
formats.StringAppend("--add-metadata", " ")
|
||||||
|
If Not embedThumbArgAdded And MyYouTubeSettings.DefaultAudioEmbedThumbnail Then
|
||||||
|
formats.StringAppend("--embed-thumbnail", " ")
|
||||||
|
embedThumbArgAdded = True
|
||||||
|
End If
|
||||||
|
End If
|
||||||
_Size += SelectedAudio.Size
|
_Size += SelectedAudio.Size
|
||||||
If _MediaType = UMTypes.Undefined Then _MediaType = UMTypes.Audio
|
If _MediaType = UMTypes.Undefined Then _MediaType = UMTypes.Audio
|
||||||
Bitrate = SelectedAudio.Bitrate
|
Bitrate = SelectedAudio.Bitrate
|
||||||
@@ -725,7 +773,7 @@ Namespace API.YouTube.Objects
|
|||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Download"
|
#Region "Download"
|
||||||
Protected Shared Sub CreateUrlFile(ByVal URL As String, ByVal File As SFile)
|
Protected Shared Function CreateUrlFile(ByVal URL As String, ByVal File As SFile) As SFile
|
||||||
Try
|
Try
|
||||||
File.Extension = "url"
|
File.Extension = "url"
|
||||||
Using t As New TextSaver(File)
|
Using t As New TextSaver(File)
|
||||||
@@ -735,9 +783,11 @@ Namespace API.YouTube.Objects
|
|||||||
t.AppendLine()
|
t.AppendLine()
|
||||||
t.Save(EDP.None)
|
t.Save(EDP.None)
|
||||||
End Using
|
End Using
|
||||||
|
Return File
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
|
Return Nothing
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Function
|
||||||
Private ReadOnly DownloadProgressPattern As RParams = RParams.DMS("\[download\]\s*([\d\.,]+)", 1, EDP.ReturnValue)
|
Private ReadOnly DownloadProgressPattern As RParams = RParams.DMS("\[download\]\s*([\d\.,]+)", 1, EDP.ReturnValue)
|
||||||
Public Property Progress As MyProgress Implements IYouTubeMediaContainer.Progress
|
Public Property Progress As MyProgress Implements IYouTubeMediaContainer.Progress
|
||||||
Private Property IDownloadableMedia_Progress As Object Implements IDownloadableMedia.Progress
|
Private Property IDownloadableMedia_Progress As Object Implements IDownloadableMedia.Progress
|
||||||
@@ -843,33 +893,35 @@ Namespace API.YouTube.Objects
|
|||||||
CreateUrlFile(url, ff)
|
CreateUrlFile(url, ff)
|
||||||
If ff.Exists Then Files.Add(ff)
|
If ff.Exists Then Files.Add(ff)
|
||||||
End If
|
End If
|
||||||
Using resp As New Responser
|
If MyYouTubeSettings.CreateThumbnails_Music Then
|
||||||
If UseCookies And MyYouTubeSettings.Cookies.Count > 0 Then resp.Cookies.AddRange(MyYouTubeSettings.Cookies,, EDP.SendToLog)
|
Using resp As New Responser
|
||||||
r = resp.GetResponse(url,, EDP.ReturnValue)
|
If UseCookies And MyYouTubeSettings.Cookies.Count > 0 Then resp.Cookies.AddRange(MyYouTubeSettings.Cookies,, EDP.SendToLog)
|
||||||
If Not r.IsEmptyString Then
|
r = resp.GetResponse(url,, EDP.ReturnValue)
|
||||||
Dim p As RParams = RParams.DM("(?<=https:[\\/]{2,4})[^\.]*[\.]?googleusercontent.com[^\,]+?w(\d+).h(\d+)[^\,]+?(?=\\x22)", 0, RegexReturn.List, EDP.ReturnValue)
|
If Not r.IsEmptyString Then
|
||||||
Dim l As List(Of String) = RegexReplace(r, p)
|
Dim p As RParams = RParams.DM("(?<=https:[\\/]{2,4})[^\.]*[\.]?googleusercontent.com[^\,]+?w(\d+).h(\d+)[^\,]+?(?=\\x22)", 0, RegexReturn.List, EDP.ReturnValue)
|
||||||
If l.ListExists Then l.RemoveAll(Function(uu) uu.IsEmptyString)
|
Dim l As List(Of String) = RegexReplace(r, p)
|
||||||
If l.ListExists Then
|
If l.ListExists Then l.RemoveAll(Function(uu) uu.IsEmptyString)
|
||||||
Dim u$ = l.Last
|
If l.ListExists Then
|
||||||
u = u.Replace("\/", "/").TrimStart("/")
|
Dim u$ = l.Last
|
||||||
Dim position%
|
u = u.Replace("\/", "/").TrimStart("/")
|
||||||
Dim ch$
|
Dim position%
|
||||||
Do
|
Dim ch$
|
||||||
position = InStr(u, "\")
|
Do
|
||||||
If position > 0 Then
|
position = InStr(u, "\")
|
||||||
ch = $"%{Mid(u, position + 2, 2)}"
|
If position > 0 Then
|
||||||
ch = SymbolsConverter.ASCII.Decode(ch, New ErrorsDescriber(False, False, False, String.Empty))
|
ch = $"%{Mid(u, position + 2, 2)}"
|
||||||
u = u.Replace(Mid(u, position, 4), ch)
|
ch = SymbolsConverter.ASCII.Decode(ch, New ErrorsDescriber(False, False, False, String.Empty))
|
||||||
End If
|
u = u.Replace(Mid(u, position, 4), ch)
|
||||||
Loop While position > 0
|
End If
|
||||||
url = LinkFormatterSecure(u)
|
Loop While position > 0
|
||||||
f.Name = "cover"
|
url = LinkFormatterSecure(u)
|
||||||
f.Extension = "jpg"
|
f.Name = "cover"
|
||||||
If resp.DownloadFile(url, f, EDP.ReturnValue) And f.Exists Then CoverDownloaded = True
|
f.Extension = "jpg"
|
||||||
|
If resp.DownloadFile(url, f, EDP.ReturnValue) And f.Exists Then CoverDownloaded = True
|
||||||
|
End If
|
||||||
End If
|
End If
|
||||||
End If
|
End Using
|
||||||
End Using
|
End If
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
ErrorsDescriber.Execute(EDP.SendToLog, ex, $"DownloadPlaylistCover({PlsId}, {f})")
|
ErrorsDescriber.Execute(EDP.SendToLog, ex, $"DownloadPlaylistCover({PlsId}, {f})")
|
||||||
End Try
|
End Try
|
||||||
@@ -938,7 +990,9 @@ Namespace API.YouTube.Objects
|
|||||||
_ThumbnailFile = File
|
_ThumbnailFile = File
|
||||||
_ThumbnailFile.Name &= "_thumb"
|
_ThumbnailFile.Name &= "_thumb"
|
||||||
_ThumbnailFile.Extension = "jpg"
|
_ThumbnailFile.Extension = "jpg"
|
||||||
If Not ThumbnailUrl.IsEmptyString Then GetWebFile(ThumbnailUrl, _ThumbnailFile, EDP.None)
|
If Not ThumbnailUrl.IsEmptyString And
|
||||||
|
If(IsMusic, MyYouTubeSettings.CreateThumbnails_Music, MyYouTubeSettings.CreateThumbnails_Video).Value Then _
|
||||||
|
GetWebFile(ThumbnailUrl, _ThumbnailFile, EDP.None)
|
||||||
|
|
||||||
ThrowAny(Token)
|
ThrowAny(Token)
|
||||||
If MyYouTubeSettings.FFMPEG.Value.Exists Then
|
If MyYouTubeSettings.FFMPEG.Value.Exists Then
|
||||||
@@ -1009,6 +1063,16 @@ Namespace API.YouTube.Objects
|
|||||||
If fAacAudio.Exists And Not aacRequested Then fAacAudio.Delete()
|
If fAacAudio.Exists And Not aacRequested Then fAacAudio.Delete()
|
||||||
If fAc3Audio.Exists And Not ac3Requested And SelectedVideoIndex >= 0 Then fAc3Audio.Delete()
|
If fAc3Audio.Exists And Not ac3Requested And SelectedVideoIndex >= 0 Then fAc3Audio.Delete()
|
||||||
End If
|
End If
|
||||||
|
|
||||||
|
If SelectedVideoIndex >= 0 AndAlso OutputVideoFPS > 0 AndAlso SelectedVideo.Bitrate > OutputVideoFPS Then
|
||||||
|
f = File
|
||||||
|
f.Name &= "tmp00"
|
||||||
|
.Execute($"ffmpeg -i ""{File}"" -filter:v fps={OutputVideoFPS.ToString.Replace(",", ".")} -c:a copy ""{f}""")
|
||||||
|
If f.Exists Then
|
||||||
|
File.Delete()
|
||||||
|
SFile.Rename(f, File,, EDP.LogMessageValue)
|
||||||
|
End If
|
||||||
|
End If
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
End With
|
End With
|
||||||
|
|||||||
@@ -115,6 +115,12 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Attributes\GridVisibleAttribute.vb" />
|
<Compile Include="Attributes\GridVisibleAttribute.vb" />
|
||||||
<Compile Include="Base\TableControlsProcessor.vb" />
|
<Compile Include="Base\TableControlsProcessor.vb" />
|
||||||
|
<Compile Include="Controls\ChannelTabsChooserForm.Designer.vb">
|
||||||
|
<DependentUpon>ChannelTabsChooserForm.vb</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Controls\ChannelTabsChooserForm.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>
|
||||||
@@ -208,6 +214,9 @@
|
|||||||
<Compile Include="Base\YouTubeSettings.vb" />
|
<Compile Include="Base\YouTubeSettings.vb" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="Controls\ChannelTabsChooserForm.resx">
|
||||||
|
<DependentUpon>ChannelTabsChooserForm.vb</DependentUpon>
|
||||||
|
</EmbeddedResource>
|
||||||
<EmbeddedResource Include="Controls\PlayListParserForm.resx">
|
<EmbeddedResource Include="Controls\PlayListParserForm.resx">
|
||||||
<DependentUpon>PlayListParserForm.vb</DependentUpon>
|
<DependentUpon>PlayListParserForm.vb</DependentUpon>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
@@ -273,6 +282,10 @@
|
|||||||
<Project>{d4650f6b-5a54-44b6-999b-6c675b7116b1}</Project>
|
<Project>{d4650f6b-5a54-44b6-999b-6c675b7116b1}</Project>
|
||||||
<Name>SCrawler.PluginProvider</Name>
|
<Name>SCrawler.PluginProvider</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\SCrawler.Shared\SCrawler.Shared.vbproj">
|
||||||
|
<Project>{dc634700-24c7-42dd-bf8f-87e6cc54e625}</Project>
|
||||||
|
<Name>SCrawler.Shared</Name>
|
||||||
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="Content\Pictures\YouTubeMusicPic_96.png" />
|
<None Include="Content\Pictures\YouTubeMusicPic_96.png" />
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ Public Class MainFrame
|
|||||||
Protected Overrides Sub VideoListForm_Load(sender As Object, e As EventArgs)
|
Protected Overrides Sub VideoListForm_Load(sender As Object, e As EventArgs)
|
||||||
MyBase.VideoListForm_Load(sender, e)
|
MyBase.VideoListForm_Load(sender, e)
|
||||||
TRAY_ICON.Visible = MyYouTubeSettings.CloseToTray
|
TRAY_ICON.Visible = MyYouTubeSettings.CloseToTray
|
||||||
|
CheckNewReleaseFolder()
|
||||||
|
CheckVersionImpl(False)
|
||||||
End Sub
|
End Sub
|
||||||
Private _CloseInvoked As Boolean = False
|
Private _CloseInvoked As Boolean = False
|
||||||
Private _IgnoreTrayOptions As Boolean = False
|
Private _IgnoreTrayOptions As Boolean = 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("2023.11.24.0")>
|
<Assembly: AssemblyVersion("2024.2.25.0")>
|
||||||
<Assembly: AssemblyFileVersion("2023.11.24.0")>
|
<Assembly: AssemblyFileVersion("2024.2.25.0")>
|
||||||
<Assembly: NeutralResourcesLanguage("en")>
|
<Assembly: NeutralResourcesLanguage("en")>
|
||||||
|
|||||||
31
SCrawler.sln
@@ -4,6 +4,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
|||||||
VisualStudioVersion = 16.0.31515.178
|
VisualStudioVersion = 16.0.31515.178
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "SCrawler", "SCrawler\SCrawler.vbproj", "{4A016FAD-9F07-4957-8BB2-AE86C88BA342}"
|
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "SCrawler", "SCrawler\SCrawler.vbproj", "{4A016FAD-9F07-4957-8BB2-AE86C88BA342}"
|
||||||
|
ProjectSection(ProjectDependencies) = postProject
|
||||||
|
{71263EEE-E25F-44DD-B0A9-F09047C0BEEA} = {71263EEE-E25F-44DD-B0A9-F09047C0BEEA}
|
||||||
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "PersonalUtilities", "..\..\MyUtilities\PersonalUtilities\PersonalUtilities.vbproj", "{8405896B-2685-4916-BC93-1FB514C323A9}"
|
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "PersonalUtilities", "..\..\MyUtilities\PersonalUtilities\PersonalUtilities.vbproj", "{8405896B-2685-4916-BC93-1FB514C323A9}"
|
||||||
EndProject
|
EndProject
|
||||||
@@ -22,6 +25,10 @@ Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "SCrawler.YouTube", "SCrawle
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "SCrawler.YouTubeDownloader", "SCrawler.YouTubeDownloader\SCrawler.YouTubeDownloader.vbproj", "{3F2F2C29-4ADB-48B5-A66E-EE0F51D0DCEF}"
|
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "SCrawler.YouTubeDownloader", "SCrawler.YouTubeDownloader\SCrawler.YouTubeDownloader.vbproj", "{3F2F2C29-4ADB-48B5-A66E-EE0F51D0DCEF}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "SCrawler.Updater", "SCrawler.Updater\SCrawler.Updater.vbproj", "{71263EEE-E25F-44DD-B0A9-F09047C0BEEA}"
|
||||||
|
EndProject
|
||||||
|
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "SCrawler.Shared", "SCrawler.Shared\SCrawler.Shared.vbproj", "{DC634700-24C7-42DD-BF8F-87E6CC54E625}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -104,6 +111,30 @@ Global
|
|||||||
{3F2F2C29-4ADB-48B5-A66E-EE0F51D0DCEF}.Release|x64.Build.0 = Release|x64
|
{3F2F2C29-4ADB-48B5-A66E-EE0F51D0DCEF}.Release|x64.Build.0 = Release|x64
|
||||||
{3F2F2C29-4ADB-48B5-A66E-EE0F51D0DCEF}.Release|x86.ActiveCfg = Release|x86
|
{3F2F2C29-4ADB-48B5-A66E-EE0F51D0DCEF}.Release|x86.ActiveCfg = Release|x86
|
||||||
{3F2F2C29-4ADB-48B5-A66E-EE0F51D0DCEF}.Release|x86.Build.0 = Release|x86
|
{3F2F2C29-4ADB-48B5-A66E-EE0F51D0DCEF}.Release|x86.Build.0 = Release|x86
|
||||||
|
{71263EEE-E25F-44DD-B0A9-F09047C0BEEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{71263EEE-E25F-44DD-B0A9-F09047C0BEEA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{71263EEE-E25F-44DD-B0A9-F09047C0BEEA}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{71263EEE-E25F-44DD-B0A9-F09047C0BEEA}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{71263EEE-E25F-44DD-B0A9-F09047C0BEEA}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
|
{71263EEE-E25F-44DD-B0A9-F09047C0BEEA}.Debug|x86.Build.0 = Debug|x86
|
||||||
|
{71263EEE-E25F-44DD-B0A9-F09047C0BEEA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{71263EEE-E25F-44DD-B0A9-F09047C0BEEA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{71263EEE-E25F-44DD-B0A9-F09047C0BEEA}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{71263EEE-E25F-44DD-B0A9-F09047C0BEEA}.Release|x64.Build.0 = Release|x64
|
||||||
|
{71263EEE-E25F-44DD-B0A9-F09047C0BEEA}.Release|x86.ActiveCfg = Release|x86
|
||||||
|
{71263EEE-E25F-44DD-B0A9-F09047C0BEEA}.Release|x86.Build.0 = Release|x86
|
||||||
|
{DC634700-24C7-42DD-BF8F-87E6CC54E625}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{DC634700-24C7-42DD-BF8F-87E6CC54E625}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{DC634700-24C7-42DD-BF8F-87E6CC54E625}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{DC634700-24C7-42DD-BF8F-87E6CC54E625}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{DC634700-24C7-42DD-BF8F-87E6CC54E625}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
|
{DC634700-24C7-42DD-BF8F-87E6CC54E625}.Debug|x86.Build.0 = Debug|x86
|
||||||
|
{DC634700-24C7-42DD-BF8F-87E6CC54E625}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{DC634700-24C7-42DD-BF8F-87E6CC54E625}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{DC634700-24C7-42DD-BF8F-87E6CC54E625}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{DC634700-24C7-42DD-BF8F-87E6CC54E625}.Release|x64.Build.0 = Release|x64
|
||||||
|
{DC634700-24C7-42DD-BF8F-87E6CC54E625}.Release|x86.ActiveCfg = Release|x86
|
||||||
|
{DC634700-24C7-42DD-BF8F-87E6CC54E625}.Release|x86.Build.0 = Release|x86
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
@@ -18,8 +18,30 @@ Namespace API.Base
|
|||||||
Friend ReadOnly TsFilesRegEx As RParams = RParams.DM(".+?\.ts[^\r\n]*", 0, RegexReturn.List)
|
Friend ReadOnly TsFilesRegEx As RParams = RParams.DM(".+?\.ts[^\r\n]*", 0, RegexReturn.List)
|
||||||
End Module
|
End Module
|
||||||
End Namespace
|
End Namespace
|
||||||
|
Friend Structure M3U8URL
|
||||||
|
Friend URL As String
|
||||||
|
Friend Extension As String
|
||||||
|
Friend Sub New(ByVal _URL As String, Optional ByVal _Extension As String = Nothing)
|
||||||
|
URL = _URL
|
||||||
|
Extension = _Extension
|
||||||
|
End Sub
|
||||||
|
Public Shared Widening Operator CType(ByVal URL As String) As M3U8URL
|
||||||
|
Return New M3U8URL(URL)
|
||||||
|
End Operator
|
||||||
|
Public Overrides Function Equals(ByVal Obj As Object) As Boolean
|
||||||
|
If Not IsNothing(Obj) Then
|
||||||
|
If TypeOf Obj Is M3U8URL Then
|
||||||
|
Return CType(Obj, M3U8URL).URL = URL
|
||||||
|
Else
|
||||||
|
Return CStr(Obj) = URL
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Return False
|
||||||
|
End Function
|
||||||
|
End Structure
|
||||||
Friend NotInheritable Class M3U8Base
|
Friend NotInheritable Class M3U8Base
|
||||||
Friend Const TempCacheFolderName As String = "tmpCache"
|
Friend Const TempCacheFolderName As String = "tmpCache"
|
||||||
|
Friend Const TempFilePrefix As String = "ConPart_"
|
||||||
Private Sub New()
|
Private Sub New()
|
||||||
End Sub
|
End Sub
|
||||||
Friend Shared Function CreateUrl(ByVal Appender As String, ByVal File As String) As String
|
Friend Shared Function CreateUrl(ByVal Appender As String, ByVal File As String) As String
|
||||||
@@ -32,9 +54,17 @@ Namespace API.Base
|
|||||||
Return $"{Appender.StringTrimEnd("/")}/{File}"
|
Return $"{Appender.StringTrimEnd("/")}/{File}"
|
||||||
End If
|
End If
|
||||||
End Function
|
End Function
|
||||||
Friend Shared Function Download(ByVal URLs As List(Of String), ByVal DestinationFile As SFile, Optional ByVal Responser As Responser = Nothing,
|
Friend Overloads Shared Function Download(ByVal URLs As List(Of String), ByVal DestinationFile As SFile, Optional ByVal Responser As Responser = Nothing,
|
||||||
Optional ByVal Token As CancellationToken = Nothing, Optional ByVal Progress As MyProgress = Nothing,
|
Optional ByVal Token As CancellationToken = Nothing, Optional ByVal Progress As MyProgress = Nothing,
|
||||||
Optional ByVal UsePreProgress As Boolean = True, Optional ByVal ExistingCache As CacheKeeper = Nothing) As SFile
|
Optional ByVal UsePreProgress As Boolean = True, Optional ByVal ExistingCache As CacheKeeper = Nothing,
|
||||||
|
Optional ByVal OnlyDownload As Boolean = False) As SFile
|
||||||
|
Return Download(URLs.ListCast(Of M3U8URL), DestinationFile, Responser, Token, Progress, UsePreProgress, ExistingCache, OnlyDownload)
|
||||||
|
End Function
|
||||||
|
Friend Overloads Shared Function Download(ByVal URLs As List(Of M3U8URL), ByVal DestinationFile As SFile, Optional ByVal Responser As Responser = Nothing,
|
||||||
|
Optional ByVal Token As CancellationToken = Nothing, Optional ByVal Progress As MyProgress = Nothing,
|
||||||
|
Optional ByVal UsePreProgress As Boolean = True, Optional ByVal ExistingCache As CacheKeeper = Nothing,
|
||||||
|
Optional ByVal OnlyDownload As Boolean = False) As SFile
|
||||||
|
Const defaultExtension$ = "ts"
|
||||||
Dim Cache As CacheKeeper = Nothing
|
Dim Cache As CacheKeeper = Nothing
|
||||||
Using tmpPr As New PreProgress(Progress)
|
Using tmpPr As New PreProgress(Progress)
|
||||||
Try
|
Try
|
||||||
@@ -59,10 +89,13 @@ Namespace API.Base
|
|||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
Dim p As SFileNumbers = SFileNumbers.Default(ConcatFile.Name)
|
Dim p As SFileNumbers = SFileNumbers.Default(ConcatFile.Name)
|
||||||
|
Dim pNum As ANumbers = SFileNumbers.NumberProviderDefault
|
||||||
|
p.NumberProvider = pNum
|
||||||
|
DirectCast(p.NumberProvider, ANumbers).GroupSize = {URLs.Count.ToString.Length, 3}.Max
|
||||||
ConcatFile = SFile.IndexReindex(ConcatFile,,, p, EDP.ReturnValue)
|
ConcatFile = SFile.IndexReindex(ConcatFile,,, p, EDP.ReturnValue)
|
||||||
Dim i%
|
Dim i%
|
||||||
Dim dFile As SFile = cache2.RootDirectory
|
Dim dFile As SFile = cache2.RootDirectory
|
||||||
dFile.Extension = "ts"
|
dFile.Extension = defaultExtension
|
||||||
Using w As New DownloadObjects.WebClient2(Responser)
|
Using w As New DownloadObjects.WebClient2(Responser)
|
||||||
For i = 0 To URLs.Count - 1
|
For i = 0 To URLs.Count - 1
|
||||||
If progressExists Then
|
If progressExists Then
|
||||||
@@ -73,12 +106,14 @@ Namespace API.Base
|
|||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
Token.ThrowIfCancellationRequested()
|
Token.ThrowIfCancellationRequested()
|
||||||
dFile.Name = $"ConPart_{i}"
|
dFile.Name = $"{TempFilePrefix}{i.NumToString(pNum)}"
|
||||||
w.DownloadFile(URLs(i), dFile)
|
dFile.Extension = URLs(i).Extension.IfNullOrEmpty(defaultExtension)
|
||||||
|
w.DownloadFile(URLs(i).URL, dFile)
|
||||||
cache2.AddFile(dFile, True)
|
cache2.AddFile(dFile, True)
|
||||||
Next
|
Next
|
||||||
End Using
|
End Using
|
||||||
DestinationFile = FFMPEG.ConcatenateFiles(cache2, Settings.FfmpegFile.File, ConcatFile, Settings.CMDEncoding, p, EDP.ThrowException)
|
If Not OnlyDownload Then _
|
||||||
|
DestinationFile = FFMPEG.ConcatenateFiles(cache2, Settings.FfmpegFile.File, ConcatFile, Settings.CMDEncoding, p, EDP.ThrowException)
|
||||||
Return DestinationFile
|
Return DestinationFile
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
|
|||||||
@@ -10,12 +10,21 @@ Imports System.Threading
|
|||||||
Imports SCrawler.Plugin.Hosts
|
Imports SCrawler.Plugin.Hosts
|
||||||
Imports PersonalUtilities.Forms.Toolbars
|
Imports PersonalUtilities.Forms.Toolbars
|
||||||
Imports PDownload = SCrawler.Plugin.ISiteSettings.Download
|
Imports PDownload = SCrawler.Plugin.ISiteSettings.Download
|
||||||
|
Imports UserMediaD = SCrawler.DownloadObjects.TDownloader.UserMediaD
|
||||||
Namespace API.Base
|
Namespace API.Base
|
||||||
Friend NotInheritable Class ProfileSaved
|
Friend NotInheritable Class ProfileSaved
|
||||||
Private ReadOnly Property HOST As SettingsHostCollection
|
Private ReadOnly Property HOST As SettingsHostCollection
|
||||||
Private ReadOnly Property Progress As MyProgress
|
Private ReadOnly Property Progress As MyProgress
|
||||||
Private _Unavailable As Integer, _NotReady As Integer, _ErrorCount As Integer
|
Private _Unavailable As Integer, _NotReady As Integer, _ErrorCount As Integer
|
||||||
Private _TotalImages As Integer, _TotalVideos As Integer
|
Private _TotalImages As Integer, _TotalVideos As Integer
|
||||||
|
Friend Property Session As Integer
|
||||||
|
Friend Property IncludeInTheFeed As Boolean = False
|
||||||
|
Private _FeedDataExists As Boolean = False
|
||||||
|
Friend ReadOnly Property FeedDataExists As Boolean
|
||||||
|
Get
|
||||||
|
Return _FeedDataExists
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
Friend Sub New(ByRef h As SettingsHostCollection, ByRef Bar As MyProgress)
|
Friend Sub New(ByRef h As SettingsHostCollection, ByRef Bar As MyProgress)
|
||||||
HOST = h
|
HOST = h
|
||||||
Progress = Bar
|
Progress = Bar
|
||||||
@@ -23,6 +32,7 @@ Namespace API.Base
|
|||||||
Friend Overloads Sub Download(ByVal Token As CancellationToken, ByVal Multiple As Boolean)
|
Friend Overloads Sub Download(ByVal Token As CancellationToken, ByVal Multiple As Boolean)
|
||||||
Dim n% = 0
|
Dim n% = 0
|
||||||
Dim c% = HOST.Sum(Function(h) IIf(h.DownloadSavedPosts, 1, 0))
|
Dim c% = HOST.Sum(Function(h) IIf(h.DownloadSavedPosts, 1, 0))
|
||||||
|
_FeedDataExists = False
|
||||||
_Unavailable = 0
|
_Unavailable = 0
|
||||||
_NotReady = 0
|
_NotReady = 0
|
||||||
_ErrorCount = 0
|
_ErrorCount = 0
|
||||||
@@ -30,13 +40,14 @@ Namespace API.Base
|
|||||||
_TotalVideos = 0
|
_TotalVideos = 0
|
||||||
If c > 0 Then
|
If c > 0 Then
|
||||||
For i% = 0 To HOST.Count - 1
|
For i% = 0 To HOST.Count - 1
|
||||||
If HOST(i).DownloadSavedPosts Then n += 1 : Download(HOST(i), n, c, Token, Multiple)
|
If Not Token.IsCancellationRequested And HOST(i).DownloadSavedPosts Then n += 1 : Download(HOST(i), n, c, Token, Multiple)
|
||||||
Next
|
Next
|
||||||
If c > 1 Then
|
If c > 1 Then
|
||||||
Dim s% = {_Unavailable, _NotReady, _ErrorCount}.Sum
|
Dim s% = {_Unavailable, _NotReady, _ErrorCount}.Sum
|
||||||
Progress.InformationTemporary = $"{HOST.Name} ({c - s}/{c}) Images: {_TotalImages}; Videos: {_TotalVideos}"
|
Progress.InformationTemporary = $"{HOST.Name} ({c - s}/{c}) Images: {_TotalImages}; Videos: {_TotalVideos}"
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
|
If _FeedDataExists Then Downloader.Files.Sort() : Downloader.FilesSave()
|
||||||
End Sub
|
End Sub
|
||||||
Private Overloads Sub Download(ByVal Host As SettingsHost, ByVal Number As Integer, ByVal Count As Integer,
|
Private Overloads Sub Download(ByVal Host As SettingsHost, ByVal Number As Integer, ByVal Count As Integer,
|
||||||
ByVal Token As CancellationToken, ByVal Multiple As Boolean)
|
ByVal Token As CancellationToken, ByVal Multiple As Boolean)
|
||||||
@@ -55,13 +66,19 @@ Namespace API.Base
|
|||||||
.LoadUserInformation()
|
.LoadUserInformation()
|
||||||
.Progress = Progress
|
.Progress = Progress
|
||||||
If Not .FileExists Then .UpdateUserInformation()
|
If Not .FileExists Then .UpdateUserInformation()
|
||||||
|
.IncludeInTheFeed = IncludeInTheFeed
|
||||||
|
|
||||||
|
Host.BeforeStartDownload(.Self, PDownload.SavedPosts)
|
||||||
|
.DownloadData(Token)
|
||||||
|
_TotalImages += .DownloadedPictures(False)
|
||||||
|
_TotalVideos += .DownloadedVideos(False)
|
||||||
|
If IncludeInTheFeed And .LatestData.Count > 0 Then
|
||||||
|
_FeedDataExists = True
|
||||||
|
Downloader.Files.AddRange(.LatestData.Select(Function(m) New UserMediaD(m, .Self, Session) With {.IsSavedPosts = True}))
|
||||||
|
End If
|
||||||
|
Progress.InformationTemporary = $"{Host.Name}{aStr} Images: { .DownloadedPictures(False)}; Videos: { .DownloadedVideos(False)}"
|
||||||
|
Host.AfterDownload(.Self, PDownload.SavedPosts)
|
||||||
End With
|
End With
|
||||||
Host.BeforeStartDownload(user, PDownload.SavedPosts)
|
|
||||||
user.DownloadData(Token)
|
|
||||||
_TotalImages += user.DownloadedPictures(False)
|
|
||||||
_TotalVideos += user.DownloadedVideos(False)
|
|
||||||
Progress.InformationTemporary = $"{Host.Name}{aStr} Images: {user.DownloadedPictures(False)}; Videos: {user.DownloadedVideos(False)}"
|
|
||||||
Host.AfterDownload(user, PDownload.SavedPosts)
|
|
||||||
End If
|
End If
|
||||||
End Using
|
End Using
|
||||||
Else
|
Else
|
||||||
@@ -72,6 +89,9 @@ Namespace API.Base
|
|||||||
_NotReady += 1
|
_NotReady += 1
|
||||||
Progress.InformationTemporary = $"Host [{Host.Name}{aStr}] is not ready"
|
Progress.InformationTemporary = $"Host [{Host.Name}{aStr}] is not ready"
|
||||||
End If
|
End If
|
||||||
|
Catch oex As OperationCanceledException When Token.IsCancellationRequested
|
||||||
|
_ErrorCount += 1
|
||||||
|
Progress.InformationTemporary = $"{Host.Name}{aStr} downloading canceled"
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
_ErrorCount += 1
|
_ErrorCount += 1
|
||||||
Progress.InformationTemporary = $"{Host.Name}{aStr} downloading error"
|
Progress.InformationTemporary = $"{Host.Name}{aStr} downloading error"
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ Namespace API.Base
|
|||||||
Set : End Set
|
Set : End Set
|
||||||
End Property
|
End Property
|
||||||
Protected Sub UpdateResponserFile()
|
Protected Sub UpdateResponserFile()
|
||||||
Dim acc$ = If(Not AccountName.IsEmptyString, $"_{AccountName}", String.Empty)
|
Dim acc$ = If(AccountName.IsEmptyString OrElse AccountName = Hosts.SettingsHost.NameAccountNameDefault, String.Empty, $"_{AccountName}")
|
||||||
Responser.File = $"{SettingsFolderName}\Responser_{Site}{acc}.xml"
|
Responser.File = $"{SettingsFolderName}\Responser_{Site}{acc}.xml"
|
||||||
_CookiesNetscapeFile = Responser.File
|
_CookiesNetscapeFile = Responser.File
|
||||||
_CookiesNetscapeFile.Name &= "_Cookies_Netscape"
|
_CookiesNetscapeFile.Name &= "_Cookies_Netscape"
|
||||||
@@ -285,7 +285,7 @@ Namespace API.Base
|
|||||||
'1 = clone
|
'1 = clone
|
||||||
'2 = any
|
'2 = any
|
||||||
Dim filterUC As Func(Of MemberInfo, Byte, Boolean) = Function(ByVal m As MemberInfo, ByVal __mode As Byte) As Boolean
|
Dim filterUC As Func(Of MemberInfo, Byte, Boolean) = Function(ByVal m As MemberInfo, ByVal __mode As Byte) As Boolean
|
||||||
If m.GetCustomAttribute(Of DoNotUse) Is Nothing Then
|
If If(m.GetCustomAttribute(Of DoNotUse)?.Value, False) Then
|
||||||
Return False
|
Return False
|
||||||
Else
|
Else
|
||||||
With m.GetCustomAttribute(Of PClonableAttribute)
|
With m.GetCustomAttribute(Of PClonableAttribute)
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ Imports PersonalUtilities.Tools.Web.Clients
|
|||||||
Imports PersonalUtilities.Tools.ImageRenderer
|
Imports PersonalUtilities.Tools.ImageRenderer
|
||||||
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 CookieUpdateModes = PersonalUtilities.Tools.Web.Cookies.CookieKeeper.UpdateModes
|
||||||
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"
|
||||||
@@ -202,10 +203,10 @@ Namespace API.Base
|
|||||||
End Get
|
End Get
|
||||||
Set(ByVal h As SettingsHost)
|
Set(ByVal h As SettingsHost)
|
||||||
_HOST = h
|
_HOST = h
|
||||||
_HostKey = h.Key
|
If Not h Is Nothing Then _HostKey = h.Key
|
||||||
End Set
|
End Set
|
||||||
End Property
|
End Property
|
||||||
Private Sub ResetHost()
|
Friend Sub ResetHost()
|
||||||
_HostObtained = False
|
_HostObtained = False
|
||||||
End Sub
|
End Sub
|
||||||
Friend Property HostStatic As Boolean = False Implements IUserData.HostStatic
|
Friend Property HostStatic As Boolean = False Implements IUserData.HostStatic
|
||||||
@@ -1079,6 +1080,7 @@ BlockNullPicture:
|
|||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
Friend Overridable Sub OpenFolder() Implements IUserData.OpenFolder
|
Friend Overridable Sub OpenFolder() Implements IUserData.OpenFolder
|
||||||
|
If MyFile.IsEmptyString And IsSavedPosts Then UpdateDataFiles()
|
||||||
GlobalOpenPath(MyFile.CutPath)
|
GlobalOpenPath(MyFile.CutPath)
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
@@ -1149,6 +1151,8 @@ BlockNullPicture:
|
|||||||
Private _EnvirChanged As Boolean = False
|
Private _EnvirChanged As Boolean = False
|
||||||
Private _PictureExists As Boolean
|
Private _PictureExists As Boolean
|
||||||
Private _EnvirInvokeUserUpdated As Boolean = False
|
Private _EnvirInvokeUserUpdated As Boolean = False
|
||||||
|
Protected _ResponserAutoUpdateCookies As Boolean = False
|
||||||
|
Protected _ResponserAddResponseReceivedHandler As Boolean = False
|
||||||
Protected Sub EnvirDownloadSet()
|
Protected Sub EnvirDownloadSet()
|
||||||
TokenPersonal = Nothing
|
TokenPersonal = Nothing
|
||||||
ProgressPre.Reset()
|
ProgressPre.Reset()
|
||||||
@@ -1190,7 +1194,14 @@ BlockNullPicture:
|
|||||||
If Not Responser Is Nothing Then Responser.Dispose()
|
If Not Responser Is Nothing Then Responser.Dispose()
|
||||||
Responser = New Responser
|
Responser = New Responser
|
||||||
If Not HOST.Responser Is Nothing Then Responser.Copy(HOST.Responser)
|
If Not HOST.Responser Is Nothing Then Responser.Copy(HOST.Responser)
|
||||||
|
If Not Responser Is Nothing And _ResponserAutoUpdateCookies Then
|
||||||
|
If _ResponserAutoUpdateCookies Then
|
||||||
|
Responser.CookiesUpdateMode = CookieUpdateModes.ReplaceByNameAll
|
||||||
|
Responser.CookiesExtractMode = Responser.CookiesExtractModes.Any
|
||||||
|
Responser.CookiesExtractedAutoSave = False
|
||||||
|
End If
|
||||||
|
If _ResponserAddResponseReceivedHandler Then AddHandler Responser.ResponseReceived, AddressOf Responser_ResponseReceived
|
||||||
|
End If
|
||||||
Responser.DecodersError = New ErrorsDescriber(EDP.SendToLog + EDP.ReturnValue) With {
|
Responser.DecodersError = New ErrorsDescriber(EDP.SendToLog + EDP.ReturnValue) With {
|
||||||
.DeclaredMessage = New MMessage($"SymbolsConverter error: [{ToStringForLog()}]", ToStringForLog())}
|
.DeclaredMessage = New MMessage($"SymbolsConverter error: [{ToStringForLog()}]", ToStringForLog())}
|
||||||
|
|
||||||
@@ -1283,9 +1294,9 @@ BlockNullPicture:
|
|||||||
Catch exit_ex As ExitException
|
Catch exit_ex As ExitException
|
||||||
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 canceled (exit) ({exit_ex.Message})"
|
MyMainLOG = $"{ToStringForLog()}: downloading interrupted (exit) ({exit_ex.Message})"
|
||||||
Else
|
Else
|
||||||
ErrorsDescriber.Execute(EDP.SendToLog, exit_ex, $"{ToStringForLog()}: downloading canceled (exit)")
|
ErrorsDescriber.Execute(EDP.SendToLog, exit_ex, $"{ToStringForLog()}: downloading interrupted (exit)")
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
Canceled = True
|
Canceled = True
|
||||||
@@ -1310,6 +1321,7 @@ BlockNullPicture:
|
|||||||
ProgressPre.Done()
|
ProgressPre.Done()
|
||||||
__DOWNLOAD_IN_PROGRESS = False
|
__DOWNLOAD_IN_PROGRESS = False
|
||||||
OnUserDownloadStateChanged(False)
|
OnUserDownloadStateChanged(False)
|
||||||
|
If _ResponserAddResponseReceivedHandler Then Responser_ResponseReceived_RemoveHandler()
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
Protected Sub UpdateDataFiles()
|
Protected Sub UpdateDataFiles()
|
||||||
@@ -1332,6 +1344,13 @@ BlockNullPicture:
|
|||||||
End If
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
Protected MustOverride Sub DownloadDataF(ByVal Token As CancellationToken)
|
Protected MustOverride Sub DownloadDataF(ByVal Token As CancellationToken)
|
||||||
|
Protected Overridable Sub Responser_ResponseReceived(ByVal Sender As Object, ByVal e As EventArguments.WebDataResponse)
|
||||||
|
End Sub
|
||||||
|
Protected Sub Responser_ResponseReceived_RemoveHandler()
|
||||||
|
If Not Responser Is Nothing And _ResponserAddResponseReceivedHandler And Not Disposed Then
|
||||||
|
Try : RemoveHandler Responser.ResponseReceived, AddressOf Responser_ResponseReceived : Catch : End Try
|
||||||
|
End If
|
||||||
|
End Sub
|
||||||
Protected Function CreateCache() As CacheKeeper
|
Protected Function CreateCache() As CacheKeeper
|
||||||
Dim Cache As New CacheKeeper($"{DownloadContentDefault_GetRootDir()}\_tCache\")
|
Dim Cache As New CacheKeeper($"{DownloadContentDefault_GetRootDir()}\_tCache\")
|
||||||
Cache.CacheDeleteError = CacheDeletionError(Cache)
|
Cache.CacheDeleteError = CacheDeletionError(Cache)
|
||||||
@@ -1402,7 +1421,7 @@ BlockNullPicture:
|
|||||||
End If
|
End If
|
||||||
ff.Name &= "_thumb"
|
ff.Name &= "_thumb"
|
||||||
ff.Extension = "jpg"
|
ff.Extension = "jpg"
|
||||||
f = Web.FFMPEG.TakeSnapshot(f, ff, Settings.FfmpegFile, TimeSpan.FromSeconds(1),,, EDP.LogMessageValue)
|
f = Web.FFMPEG.TakeSnapshot(f, ff, Settings.FfmpegFile, TimeSpan.FromSeconds(1),,, EDP.SendToLog + EDP.ReturnValue)
|
||||||
If f.Exists Then DirectCast(Data, IDownloadableMedia).ThumbnailFile = f
|
If f.Exists Then DirectCast(Data, IDownloadableMedia).ThumbnailFile = f
|
||||||
End If
|
End If
|
||||||
Else
|
Else
|
||||||
@@ -2056,7 +2075,7 @@ BlockNullPicture:
|
|||||||
End Function
|
End Function
|
||||||
Private Class FilesCopyingException : Inherits ErrorsDescriberException
|
Private Class FilesCopyingException : Inherits ErrorsDescriberException
|
||||||
Friend Sub New(ByVal User As IUserData, ByVal Msg As String, ByVal Path As SFile)
|
Friend Sub New(ByVal User As IUserData, ByVal Msg As String, ByVal Path As SFile)
|
||||||
SendInLogOnlyMessage = True
|
SendToLogOnlyMessage = True
|
||||||
If User.IncludedInCollection Then _MainMessage = $"[{User.CollectionName}] - "
|
If User.IncludedInCollection Then _MainMessage = $"[{User.CollectionName}] - "
|
||||||
_MainMessage &= $"[{User.Site}] - [{User.Name}]. {Msg}: {Path.Path}."
|
_MainMessage &= $"[{User.Site}] - [{User.Name}]. {Msg}: {Path.Path}."
|
||||||
End Sub
|
End Sub
|
||||||
@@ -2180,18 +2199,20 @@ BlockNullPicture:
|
|||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "IComparable Support"
|
#Region "IComparable Support"
|
||||||
Friend Overridable Function CompareTo(ByVal Other As UserDataBase) As Integer Implements IComparable(Of UserDataBase).CompareTo
|
Friend Overridable Overloads Function CompareTo(ByVal Other As UserDataBase) As Integer Implements IComparable(Of UserDataBase).CompareTo
|
||||||
If IsCollection Then
|
If TypeOf Other Is UserDataBind Then
|
||||||
|
Return 1
|
||||||
|
ElseIf IsCollection Then
|
||||||
Return Name.CompareTo(Other.Name)
|
Return Name.CompareTo(Other.Name)
|
||||||
Else
|
Else
|
||||||
Return FriendlyName.IfNullOrEmpty(Name).StringTrim.CompareTo(Other.FriendlyName.IfNullOrEmpty(Other.Name).StringTrim)
|
Return FriendlyName.IfNullOrEmpty(Name).StringTrim.CompareTo(Other.FriendlyName.IfNullOrEmpty(Other.Name).StringTrim)
|
||||||
End If
|
End If
|
||||||
End Function
|
End Function
|
||||||
Friend Overridable Function CompareTo(ByVal Obj As Object) As Integer Implements IComparable.CompareTo
|
Friend Overridable Overloads Function CompareTo(ByVal Obj As Object) As Integer Implements IComparable.CompareTo
|
||||||
If Not Obj Is Nothing AndAlso TypeOf Obj Is UserDataBase Then
|
If Not Obj Is Nothing AndAlso TypeOf Obj Is UserDataBase Then
|
||||||
Return CompareTo(DirectCast(Obj, UserDataBase))
|
Return CompareTo(DirectCast(Obj, UserDataBase))
|
||||||
Else
|
Else
|
||||||
Return False
|
Return 0
|
||||||
End If
|
End If
|
||||||
End Function
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
@@ -2199,7 +2220,7 @@ BlockNullPicture:
|
|||||||
Friend Overridable Overloads Function Equals(ByVal Other As UserDataBase) As Boolean Implements IEquatable(Of UserDataBase).Equals
|
Friend Overridable Overloads Function Equals(ByVal Other As UserDataBase) As Boolean Implements IEquatable(Of UserDataBase).Equals
|
||||||
Return LVIKey = Other.LVIKey And IsSavedPosts = Other.IsSavedPosts
|
Return LVIKey = Other.LVIKey And IsSavedPosts = Other.IsSavedPosts
|
||||||
End Function
|
End Function
|
||||||
Public Overrides Function Equals(ByVal Obj As Object) As Boolean
|
Public Overloads Overrides Function Equals(ByVal Obj As Object) As Boolean
|
||||||
If Not Obj Is Nothing AndAlso TypeOf Obj Is UserDataBase Then
|
If Not Obj Is Nothing AndAlso TypeOf Obj Is UserDataBase Then
|
||||||
Return Equals(DirectCast(Obj, UserDataBase))
|
Return Equals(DirectCast(Obj, UserDataBase))
|
||||||
Else
|
Else
|
||||||
|
|||||||
@@ -107,7 +107,23 @@ Namespace API.Facebook
|
|||||||
End With
|
End With
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
|
#Region "Initializer"
|
||||||
|
Friend Sub New()
|
||||||
|
_ResponserAutoUpdateCookies = True
|
||||||
|
End Sub
|
||||||
|
#End Region
|
||||||
#Region "Download functions"
|
#Region "Download functions"
|
||||||
|
Private Class TokensException : Inherits Plugin.ExitException
|
||||||
|
Friend ReadOnly Property BasicTokens As Boolean
|
||||||
|
Public Sub New(ByVal Message As String, ByVal _BasicTokens As Boolean)
|
||||||
|
MyBase.New(Message)
|
||||||
|
BasicTokens = _BasicTokens
|
||||||
|
End Sub
|
||||||
|
Friend Shared Sub SendToLog(ByVal Source As UserData, ByVal ex As TokensException, ByVal f As String)
|
||||||
|
ErrorsDescriber.Execute(EDP.SendToLog, New ErrorsDescriberException($"{Source.ToStringForLog()} ({f}): {ex.Message}",,, ex) With {
|
||||||
|
.SendToLogOnlyMessage = True, .ReplaceMainMessage = True})
|
||||||
|
End Sub
|
||||||
|
End Class
|
||||||
Private Token_dtsg As String = String.Empty
|
Private Token_dtsg As String = String.Empty
|
||||||
Private Token_lsd As String = String.Empty
|
Private Token_lsd As String = String.Empty
|
||||||
Private Token_Photosby As String = String.Empty
|
Private Token_Photosby As String = String.Empty
|
||||||
@@ -149,7 +165,7 @@ Namespace API.Facebook
|
|||||||
Dim pid As PostKV
|
Dim pid As PostKV
|
||||||
|
|
||||||
ValidateBaseTokens()
|
ValidateBaseTokens()
|
||||||
If Token_Photosby.IsEmptyString Then Throw New ArgumentNullException("Token_Photosby", "Unable to obtain token")
|
If Token_Photosby.IsEmptyString Then Throw New TokensException("Unable to obtain token 'Token_Photosby'", False)
|
||||||
|
|
||||||
URL = String.Format(Graphql_UrlPattern, Token_lsd, DocID_Photo, Header_fb_fr_name_Photo,
|
URL = String.Format(Graphql_UrlPattern, Token_lsd, DocID_Photo, Header_fb_fr_name_Photo,
|
||||||
SymbolsConverter.ASCII.EncodeSymbolsOnly(Token_dtsg),
|
SymbolsConverter.ASCII.EncodeSymbolsOnly(Token_dtsg),
|
||||||
@@ -199,6 +215,8 @@ Namespace API.Facebook
|
|||||||
End If
|
End If
|
||||||
|
|
||||||
If newPostsDetected And Not nextCursor.IsEmptyString Then DownloadData_Photo(nextCursor, Token)
|
If newPostsDetected And Not nextCursor.IsEmptyString Then DownloadData_Photo(nextCursor, Token)
|
||||||
|
Catch tex As TokensException When Not tex.BasicTokens
|
||||||
|
TokensException.SendToLog(Me, tex, "data (photo)")
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
ProcessException(ex, Token, $"data (photo) downloading error [{URL}]",, Responser)
|
ProcessException(ex, Token, $"data (photo) downloading error [{URL}]",, Responser)
|
||||||
End Try
|
End Try
|
||||||
@@ -212,7 +230,7 @@ Namespace API.Facebook
|
|||||||
Dim pid As PostKV
|
Dim pid As PostKV
|
||||||
|
|
||||||
If VideoPageID.IsEmptyString Then GetVideoPageID(Token)
|
If VideoPageID.IsEmptyString Then GetVideoPageID(Token)
|
||||||
If VideoPageID.IsEmptyString Then Throw New ArgumentNullException("VideoPageID", "Unable to obtain VideoPageID")
|
If VideoPageID.IsEmptyString Then Throw New TokensException("Unable to obtain 'VideoPageID'", False)
|
||||||
ValidateBaseTokens()
|
ValidateBaseTokens()
|
||||||
|
|
||||||
URL = String.Format(Graphql_UrlPattern, Token_lsd, DocID_Video, Header_fb_fr_name_Video,
|
URL = String.Format(Graphql_UrlPattern, Token_lsd, DocID_Video, Header_fb_fr_name_Video,
|
||||||
@@ -252,6 +270,8 @@ Namespace API.Facebook
|
|||||||
End If
|
End If
|
||||||
|
|
||||||
If newPostsDetected And Not nextCursor.IsEmptyString Then DownloadData_Video(nextCursor, Token)
|
If newPostsDetected And Not nextCursor.IsEmptyString Then DownloadData_Video(nextCursor, Token)
|
||||||
|
Catch tex As TokensException When Not tex.BasicTokens
|
||||||
|
TokensException.SendToLog(Me, tex, "data (video)")
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
ProcessException(ex, Token, $"data (video) downloading error [{URL}]",, Responser)
|
ProcessException(ex, Token, $"data (video) downloading error [{URL}]",, Responser)
|
||||||
End Try
|
End Try
|
||||||
@@ -266,7 +286,7 @@ Namespace API.Facebook
|
|||||||
Dim postDate As Date?
|
Dim postDate As Date?
|
||||||
|
|
||||||
ValidateBaseTokens()
|
ValidateBaseTokens()
|
||||||
If StoryBucket.IsEmptyString Then Throw New ArgumentNullException("StoryBucket", "Unable to obtain StoryBucket")
|
If StoryBucket.IsEmptyString Then Throw New TokensException("Unable to obtain 'StoryBucket'", False)
|
||||||
|
|
||||||
URL = String.Format(Graphql_UrlPattern, Token_lsd, DocID_Stories, Header_fb_fr_name_Stories,
|
URL = String.Format(Graphql_UrlPattern, Token_lsd, DocID_Stories, Header_fb_fr_name_Stories,
|
||||||
SymbolsConverter.ASCII.EncodeSymbolsOnly(Token_dtsg),
|
SymbolsConverter.ASCII.EncodeSymbolsOnly(Token_dtsg),
|
||||||
@@ -320,6 +340,8 @@ Namespace API.Facebook
|
|||||||
End If
|
End If
|
||||||
End Using
|
End Using
|
||||||
End If
|
End If
|
||||||
|
Catch tex As TokensException When Not tex.BasicTokens
|
||||||
|
TokensException.SendToLog(Me, tex, "data (stories)")
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
ProcessException(ex, Token, $"data (stories) downloading error [{URL}]",, Responser)
|
ProcessException(ex, Token, $"data (stories) downloading error [{URL}]",, Responser)
|
||||||
End Try
|
End Try
|
||||||
@@ -467,8 +489,10 @@ Namespace API.Facebook
|
|||||||
#Region "ValidateBaseTokens, GetVideoPageID, GetUserTokens"
|
#Region "ValidateBaseTokens, GetVideoPageID, GetUserTokens"
|
||||||
''' <exception cref="ArgumentNullException"></exception>
|
''' <exception cref="ArgumentNullException"></exception>
|
||||||
Private Sub ValidateBaseTokens()
|
Private Sub ValidateBaseTokens()
|
||||||
If Token_dtsg.IsEmptyString Then Throw New ArgumentNullException("Token_dtsg", "Unable to obtain token")
|
Dim tokens$ = String.Empty
|
||||||
If Token_lsd.IsEmptyString Then Throw New ArgumentNullException("Token_lsd", "Unable to obtain token")
|
If Token_dtsg.IsEmptyString Then tokens.StringAppend("Token_dtsg")
|
||||||
|
If Token_lsd.IsEmptyString Then tokens.StringAppend("Token_lsd")
|
||||||
|
If Not tokens.IsEmptyString Then Throw New TokensException($"Unable to obtain token(s) ({tokens}){vbCr}Your credentials may have expired.", True)
|
||||||
End Sub
|
End Sub
|
||||||
Private Sub GetVideoPageID(ByVal Token As CancellationToken)
|
Private Sub GetVideoPageID(ByVal Token As CancellationToken)
|
||||||
Dim URL$ = $"{GetProfileUrl()}\videos"
|
Dim URL$ = $"{GetProfileUrl()}\videos"
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ Namespace API.Instagram
|
|||||||
Friend Const InstagramSite As String = "Instagram"
|
Friend Const InstagramSite As String = "Instagram"
|
||||||
Friend Const InstagramSiteKey As String = "AndyProgram_Instagram"
|
Friend Const InstagramSiteKey As String = "AndyProgram_Instagram"
|
||||||
Friend ReadOnly FilesPattern As RParams = RParams.DMS(".+?([^/\?]+?\.[\w\d]{3,4})(?=(\?|\Z))", 1, EDP.ReturnValue)
|
Friend ReadOnly FilesPattern As RParams = RParams.DMS(".+?([^/\?]+?\.[\w\d]{3,4})(?=(\?|\Z))", 1, EDP.ReturnValue)
|
||||||
|
Friend ReadOnly ObtainMedia_SizeFuncPic_RegexP As RParams = RParams.DMS("_p(\d+)x(\d+)", 1, EDP.ReturnValue)
|
||||||
|
Friend ReadOnly ObtainMedia_SizeFuncPic_RegexS As RParams = RParams.DMS("_s(\d+)x(\d+)", 1, EDP.ReturnValue)
|
||||||
|
Friend Const PageTokenRegexPatternDefault As String = "\[\],{""token"":""(.*?)""},\d+\]"
|
||||||
Friend Sub UpdateResponser(ByVal Source As IResponse, ByRef Destination As Responser)
|
Friend Sub UpdateResponser(ByVal Source As IResponse, ByRef Destination As Responser)
|
||||||
Const r_wwwClaimName$ = "x-ig-set-www-claim"
|
Const r_wwwClaimName$ = "x-ig-set-www-claim"
|
||||||
Const r_tokenName$ = SiteSettings.Header_CSRF_TOKEN_COOKIE
|
Const r_tokenName$ = SiteSettings.Header_CSRF_TOKEN_COOKIE
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ Namespace API.Instagram
|
|||||||
Friend Class EditorExchangeOptions
|
Friend Class EditorExchangeOptions
|
||||||
<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
|
||||||
|
<PSetting(Caption:="Get reels", ToolTip:="Download user reels")>
|
||||||
|
Friend Property GetReels As Boolean
|
||||||
<PSetting(Caption:="Get stories", ToolTip:="Download user stories (pinned)")>
|
<PSetting(Caption:="Get stories", ToolTip:="Download user stories (pinned)")>
|
||||||
Friend Property GetStories As Boolean
|
Friend Property GetStories As Boolean
|
||||||
<PSetting(Caption:="Get stories: user", ToolTip:="Download user stories")>
|
<PSetting(Caption:="Get stories: user", ToolTip:="Download user stories")>
|
||||||
@@ -20,6 +22,7 @@ Namespace API.Instagram
|
|||||||
Friend Sub New(ByVal u As UserData)
|
Friend Sub New(ByVal u As UserData)
|
||||||
With u
|
With u
|
||||||
GetTimeline = .GetTimeline
|
GetTimeline = .GetTimeline
|
||||||
|
GetReels = .GetReels
|
||||||
GetStories = .GetStories
|
GetStories = .GetStories
|
||||||
GetStoriesUser = .GetStoriesUser
|
GetStoriesUser = .GetStoriesUser
|
||||||
GetTagged = .GetTaggedData
|
GetTagged = .GetTaggedData
|
||||||
@@ -28,6 +31,7 @@ Namespace API.Instagram
|
|||||||
Friend Sub New(ByVal s As SiteSettings)
|
Friend Sub New(ByVal s As SiteSettings)
|
||||||
With s
|
With s
|
||||||
GetTimeline = CBool(.GetTimeline.Value)
|
GetTimeline = CBool(.GetTimeline.Value)
|
||||||
|
GetReels = CBool(.GetReels.Value)
|
||||||
GetStories = CBool(.GetStories.Value)
|
GetStories = CBool(.GetStories.Value)
|
||||||
GetStoriesUser = CBool(.GetStoriesUser.Value)
|
GetStoriesUser = CBool(.GetStoriesUser.Value)
|
||||||
GetTagged = CBool(.GetTagged.Value)
|
GetTagged = CBool(.GetTagged.Value)
|
||||||
|
|||||||
@@ -63,15 +63,14 @@ 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 As String = "Sec-Ch-Ua-Platform-Version"
|
Friend Const Header_Platform As String = "Sec-Ch-Ua-Platform-Version"
|
||||||
<PropertyOption(ControlText:="Hash", ControlToolTip:="Instagram session hash for tagged posts", IsAuth:=True), PXML("InstaHash"), ControlNumber(0), PClonable(Clone:=False)>
|
<PropertyOption(ControlText:="x-csrftoken", ControlToolTip:="Can be automatically extracted from cookies", IsAuth:=True, AllowNull:=True), ControlNumber(2), PClonable(Clone:=False)>
|
||||||
Friend ReadOnly Property HashTagged As PropertyValue
|
|
||||||
<PropertyOption(ControlText:="x-csrftoken", IsAuth:=True, AllowNull:=False), ControlNumber(2), PClonable(Clone:=False)>
|
|
||||||
Friend ReadOnly Property HH_CSRF_TOKEN As PropertyValue
|
Friend ReadOnly Property HH_CSRF_TOKEN As PropertyValue
|
||||||
<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), ControlNumber(3), PClonable(Clone:=False)>
|
||||||
Friend Property HH_IG_APP_ID As PropertyValue
|
Friend 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), ControlNumber(4), PClonable(Clone:=False)>
|
||||||
Friend Property HH_ASBD_ID As PropertyValue
|
Friend Property HH_ASBD_ID As PropertyValue
|
||||||
<PropertyOption(ControlText:="x-ig-www-claim", IsAuth:=True, AllowNull:=True), ControlNumber(5), PClonable(Clone:=False)>
|
'PropertyOption(ControlText:="x-ig-www-claim", IsAuth:=True, AllowNull:=True)
|
||||||
|
<ControlNumber(5), PClonable(Clone:=False)>
|
||||||
Friend Property HH_IG_WWW_CLAIM As PropertyValue
|
Friend Property HH_IG_WWW_CLAIM As PropertyValue
|
||||||
<PropertyOption(ControlText:="sec-ch-ua", IsAuth:=True, AllowNull:=True), ControlNumber(6), PClonable>
|
<PropertyOption(ControlText:="sec-ch-ua", IsAuth:=True, AllowNull:=True), ControlNumber(6), PClonable>
|
||||||
Private Property HH_BROWSER As PropertyValue
|
Private Property HH_BROWSER As PropertyValue
|
||||||
@@ -123,11 +122,13 @@ Namespace API.Instagram
|
|||||||
Private ReadOnly Property SleepTimerOnPostsLimitProvider As IFormatProvider
|
Private ReadOnly Property SleepTimerOnPostsLimitProvider As IFormatProvider
|
||||||
<PropertyOption(ControlText:="Get timeline", ControlToolTip:="Default value for new users"), PXML, ControlNumber(23), PClonable>
|
<PropertyOption(ControlText:="Get timeline", ControlToolTip:="Default value for new users"), PXML, ControlNumber(23), PClonable>
|
||||||
Friend ReadOnly Property GetTimeline As PropertyValue
|
Friend ReadOnly Property GetTimeline As PropertyValue
|
||||||
<PropertyOption(ControlText:="Get stories", ControlToolTip:="Default value for new users"), PXML, ControlNumber(24), PClonable>
|
<PropertyOption(ControlText:="Get reels", ControlToolTip:="Default value for new users"), PXML, ControlNumber(24), PClonable>
|
||||||
|
Friend ReadOnly Property GetReels As PropertyValue
|
||||||
|
<PropertyOption(ControlText:="Get stories", ControlToolTip:="Default value for new users"), PXML, ControlNumber(25), PClonable>
|
||||||
Friend ReadOnly Property GetStories As PropertyValue
|
Friend ReadOnly Property GetStories As PropertyValue
|
||||||
<PropertyOption(ControlText:="Get stories: user", ControlToolTip:="Default value for new users"), PXML, ControlNumber(25), PClonable>
|
<PropertyOption(ControlText:="Get stories: user", ControlToolTip:="Default value for new users"), PXML, ControlNumber(26), PClonable>
|
||||||
Friend ReadOnly Property GetStoriesUser As PropertyValue
|
Friend ReadOnly Property GetStoriesUser As PropertyValue
|
||||||
<PropertyOption(ControlText:="Get tagged photos", ControlToolTip:="Default value for new users"), PXML, ControlNumber(26), PClonable>
|
<PropertyOption(ControlText:="Get tagged photos", ControlToolTip:="Default value for new users"), PXML, ControlNumber(27), PClonable>
|
||||||
Friend ReadOnly Property GetTagged As PropertyValue
|
Friend ReadOnly Property GetTagged 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 &
|
||||||
@@ -139,11 +140,13 @@ Namespace API.Instagram
|
|||||||
#Region "Download ready"
|
#Region "Download ready"
|
||||||
<PropertyOption(ControlText:="Download timeline", ControlToolTip:="Download timeline"), PXML, ControlNumber(10), PClonable>
|
<PropertyOption(ControlText:="Download timeline", ControlToolTip:="Download timeline"), PXML, ControlNumber(10), PClonable>
|
||||||
Friend ReadOnly Property DownloadTimeline As PropertyValue
|
Friend ReadOnly Property DownloadTimeline As PropertyValue
|
||||||
<PropertyOption(ControlText:="Download stories", ControlToolTip:="Download stories"), PXML, ControlNumber(11), PClonable>
|
<PropertyOption(ControlText:="Download reels", ControlToolTip:="Download reels"), PXML, ControlNumber(11), PClonable>
|
||||||
|
Friend ReadOnly Property DownloadReels As PropertyValue
|
||||||
|
<PropertyOption(ControlText:="Download stories", ControlToolTip:="Download stories"), PXML, ControlNumber(12), PClonable>
|
||||||
Friend ReadOnly Property DownloadStories As PropertyValue
|
Friend ReadOnly Property DownloadStories As PropertyValue
|
||||||
<PropertyOption(ControlText:="Download stories: user", ControlToolTip:="Download stories (user)"), PXML, ControlNumber(12), PClonable>
|
<PropertyOption(ControlText:="Download stories: user", ControlToolTip:="Download stories (user)"), PXML, ControlNumber(13), PClonable>
|
||||||
Friend ReadOnly Property DownloadStoriesUser As PropertyValue
|
Friend ReadOnly Property DownloadStoriesUser As PropertyValue
|
||||||
<PropertyOption(ControlText:="Download tagged", ControlToolTip:="Download tagged posts"), PXML, ControlNumber(13), PClonable>
|
<PropertyOption(ControlText:="Download tagged", ControlToolTip:="Download tagged posts"), PXML, ControlNumber(14), PClonable>
|
||||||
Friend ReadOnly Property DownloadTagged As PropertyValue
|
Friend ReadOnly Property DownloadTagged As PropertyValue
|
||||||
#End Region
|
#End Region
|
||||||
#Region "429 bypass"
|
#Region "429 bypass"
|
||||||
@@ -236,7 +239,6 @@ Namespace API.Instagram
|
|||||||
.CookiesExtractedAutoSave = False
|
.CookiesExtractedAutoSave = False
|
||||||
End With
|
End With
|
||||||
|
|
||||||
HashTagged = New PropertyValue(String.Empty, GetType(String))
|
|
||||||
HH_CSRF_TOKEN = New PropertyValue(token, GetType(String), Sub(v) ChangeResponserFields(NameOf(HH_CSRF_TOKEN), v))
|
HH_CSRF_TOKEN = New PropertyValue(token, GetType(String), Sub(v) ChangeResponserFields(NameOf(HH_CSRF_TOKEN), v))
|
||||||
HH_IG_APP_ID = New PropertyValue(app_id, GetType(String), Sub(v) ChangeResponserFields(NameOf(HH_IG_APP_ID), v))
|
HH_IG_APP_ID = New PropertyValue(app_id, GetType(String), Sub(v) ChangeResponserFields(NameOf(HH_IG_APP_ID), v))
|
||||||
HH_ASBD_ID = New PropertyValue(asbd, GetType(String), Sub(v) ChangeResponserFields(NameOf(HH_ASBD_ID), v))
|
HH_ASBD_ID = New PropertyValue(asbd, GetType(String), Sub(v) ChangeResponserFields(NameOf(HH_ASBD_ID), v))
|
||||||
@@ -247,6 +249,7 @@ Namespace API.Instagram
|
|||||||
HH_USER_AGENT = New PropertyValue(useragent, GetType(String), Sub(v) ChangeResponserFields(NameOf(HH_USER_AGENT), v))
|
HH_USER_AGENT = New PropertyValue(useragent, GetType(String), Sub(v) ChangeResponserFields(NameOf(HH_USER_AGENT), v))
|
||||||
|
|
||||||
DownloadTimeline = New PropertyValue(True)
|
DownloadTimeline = New PropertyValue(True)
|
||||||
|
DownloadReels = New PropertyValue(False)
|
||||||
DownloadStories = New PropertyValue(True)
|
DownloadStories = New PropertyValue(True)
|
||||||
DownloadStoriesUser = New PropertyValue(True)
|
DownloadStoriesUser = New PropertyValue(True)
|
||||||
DownloadTagged = New PropertyValue(False)
|
DownloadTagged = New PropertyValue(False)
|
||||||
@@ -259,6 +262,7 @@ Namespace API.Instagram
|
|||||||
SleepTimerOnPostsLimitProvider = New TimersChecker(10000)
|
SleepTimerOnPostsLimitProvider = New TimersChecker(10000)
|
||||||
|
|
||||||
GetTimeline = New PropertyValue(True)
|
GetTimeline = New PropertyValue(True)
|
||||||
|
GetReels = New PropertyValue(False)
|
||||||
GetStories = New PropertyValue(False)
|
GetStories = New PropertyValue(False)
|
||||||
GetStoriesUser = New PropertyValue(False)
|
GetStoriesUser = New PropertyValue(False)
|
||||||
GetTagged = New PropertyValue(False)
|
GetTagged = New PropertyValue(False)
|
||||||
@@ -273,7 +277,7 @@ Namespace API.Instagram
|
|||||||
|
|
||||||
_AllowUserAgentUpdate = False
|
_AllowUserAgentUpdate = False
|
||||||
UrlPatternUser = "https://www.instagram.com/{0}/"
|
UrlPatternUser = "https://www.instagram.com/{0}/"
|
||||||
UserRegex = RParams.DMS("[htps:/]{7,8}.*?instagram.com/([^/]+)", 1)
|
UserRegex = RParams.DMS(String.Format(UserRegexDefaultPattern, "instagram.com/"), 1)
|
||||||
ImageVideoContains = "instagram.com"
|
ImageVideoContains = "instagram.com"
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
@@ -349,6 +353,50 @@ Namespace API.Instagram
|
|||||||
SkipUntilNextSession = False
|
SkipUntilNextSession = False
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
|
#Region "Settings"
|
||||||
|
Private ____HH_CSRF_TOKEN As String = String.Empty
|
||||||
|
Private ____HH_IG_APP_ID As String = String.Empty
|
||||||
|
Private ____HH_ASBD_ID As String = String.Empty
|
||||||
|
Private ____HH_BROWSER As String = String.Empty
|
||||||
|
Private ____HH_BROWSER_EXT As String = String.Empty
|
||||||
|
Private ____HH_PLATFORM As String = String.Empty
|
||||||
|
Private ____HH_USER_AGENT As String = String.Empty
|
||||||
|
Private ____Cookies As CookieKeeper = Nothing
|
||||||
|
Friend Overrides Sub BeginEdit()
|
||||||
|
____HH_CSRF_TOKEN = AConvert(Of String)(HH_CSRF_TOKEN.Value, String.Empty)
|
||||||
|
____HH_IG_APP_ID = AConvert(Of String)(HH_IG_APP_ID.Value, String.Empty)
|
||||||
|
____HH_ASBD_ID = AConvert(Of String)(HH_ASBD_ID.Value, String.Empty)
|
||||||
|
____HH_BROWSER = AConvert(Of String)(HH_BROWSER.Value, String.Empty)
|
||||||
|
____HH_BROWSER_EXT = AConvert(Of String)(HH_BROWSER_EXT.Value, String.Empty)
|
||||||
|
____HH_PLATFORM = AConvert(Of String)(HH_PLATFORM.Value, String.Empty)
|
||||||
|
____HH_USER_AGENT = AConvert(Of String)(HH_USER_AGENT.Value, String.Empty)
|
||||||
|
____Cookies = Responser.Cookies.Copy
|
||||||
|
MyBase.BeginEdit()
|
||||||
|
End Sub
|
||||||
|
Friend Overrides Sub Update()
|
||||||
|
If _SiteEditorFormOpened Then
|
||||||
|
Dim vals() = {New With {.ValueOld = ____HH_CSRF_TOKEN, .ValueNew = AConvert(Of String)(HH_CSRF_TOKEN.Value, String.Empty).ToString},
|
||||||
|
New With {.ValueOld = ____HH_IG_APP_ID, .ValueNew = AConvert(Of String)(HH_IG_APP_ID.Value, String.Empty).ToString},
|
||||||
|
New With {.ValueOld = ____HH_ASBD_ID, .ValueNew = AConvert(Of String)(HH_ASBD_ID.Value, String.Empty).ToString},
|
||||||
|
New With {.ValueOld = ____HH_BROWSER, .ValueNew = AConvert(Of String)(HH_BROWSER.Value, String.Empty).ToString},
|
||||||
|
New With {.ValueOld = ____HH_BROWSER_EXT, .ValueNew = AConvert(Of String)(HH_BROWSER_EXT.Value, String.Empty).ToString},
|
||||||
|
New With {.ValueOld = ____HH_PLATFORM, .ValueNew = AConvert(Of String)(HH_PLATFORM.Value, String.Empty).ToString},
|
||||||
|
New With {.ValueOld = ____HH_USER_AGENT, .ValueNew = AConvert(Of String)(HH_USER_AGENT.Value, String.Empty).ToString}
|
||||||
|
}
|
||||||
|
If vals.Any(Function(v) Not v.ValueOld = v.ValueNew) OrElse
|
||||||
|
Not Responser.Cookies.ListEquals(____Cookies) Then HH_IG_WWW_CLAIM.Value = 0
|
||||||
|
If Responser.CookiesExists Then
|
||||||
|
Dim csrf$ = If(Responser.Cookies.FirstOrDefault(Function(c) c.Name.StringToLower = Header_CSRF_TOKEN_COOKIE)?.Value, String.Empty)
|
||||||
|
If Not csrf.IsEmptyString Then HH_CSRF_TOKEN.Value = csrf
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
MyBase.Update()
|
||||||
|
End Sub
|
||||||
|
Friend Overrides Sub EndEdit()
|
||||||
|
If _SiteEditorFormOpened Then ____Cookies.DisposeIfReady(False) : ____Cookies = Nothing
|
||||||
|
MyBase.EndEdit()
|
||||||
|
End Sub
|
||||||
|
#End Region
|
||||||
#Region "UserOptions, GetUserUrl, GetUserPostUrl"
|
#Region "UserOptions, GetUserUrl, GetUserPostUrl"
|
||||||
Friend Overrides Sub UserOptions(ByRef Options As Object, ByVal OpenForm As Boolean)
|
Friend Overrides Sub UserOptions(ByRef Options As Object, ByVal OpenForm As Boolean)
|
||||||
If Options Is Nothing OrElse Not TypeOf Options Is EditorExchangeOptions Then Options = New EditorExchangeOptions(Me)
|
If Options Is Nothing OrElse Not TypeOf Options Is EditorExchangeOptions Then Options = New EditorExchangeOptions(Me)
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ Imports PersonalUtilities.Functions.XML.Base
|
|||||||
Imports PersonalUtilities.Functions.Messaging
|
Imports PersonalUtilities.Functions.Messaging
|
||||||
Imports PersonalUtilities.Functions.RegularExpressions
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
Imports PersonalUtilities.Tools.Web.Clients
|
Imports PersonalUtilities.Tools.Web.Clients
|
||||||
|
Imports PersonalUtilities.Tools.Web.Clients.Base
|
||||||
|
Imports PersonalUtilities.Tools.Web.Documents
|
||||||
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
|
||||||
Imports UStates = SCrawler.API.Base.UserMedia.States
|
Imports UStates = SCrawler.API.Base.UserMedia.States
|
||||||
@@ -24,6 +26,7 @@ Namespace API.Instagram
|
|||||||
Private Const Name_LastCursor As String = "LastCursor"
|
Private Const Name_LastCursor As String = "LastCursor"
|
||||||
Private Const Name_FirstLoadingDone As String = "FirstLoadingDone"
|
Private Const Name_FirstLoadingDone As String = "FirstLoadingDone"
|
||||||
Private Const Name_GetTimeline As String = "GetTimeline"
|
Private Const Name_GetTimeline As String = "GetTimeline"
|
||||||
|
Private Const Name_GetReels As String = "GetReels"
|
||||||
Private Const Name_GetStories As String = "GetStories"
|
Private Const Name_GetStories As String = "GetStories"
|
||||||
Private Const Name_GetStoriesUser As String = "GetStoriesUser"
|
Private Const Name_GetStoriesUser As String = "GetStoriesUser"
|
||||||
Private Const Name_GetTagged As String = "GetTaggedData"
|
Private Const Name_GetTagged As String = "GetTaggedData"
|
||||||
@@ -66,6 +69,7 @@ Namespace API.Instagram
|
|||||||
Return New EContainer("Post", ID, {New EAttribute(Name_Section, CInt(Section)), New EAttribute(Name_Code, Code)})
|
Return New EContainer("Post", ID, {New EAttribute(Name_Section, CInt(Section)), New EAttribute(Name_Code, Code)})
|
||||||
End Function
|
End Function
|
||||||
End Structure
|
End Structure
|
||||||
|
Friend Const Header_FB_LSD As String = "x-fb-lsd"
|
||||||
Private ReadOnly Property MySiteSettings As SiteSettings
|
Private ReadOnly Property MySiteSettings As SiteSettings
|
||||||
Get
|
Get
|
||||||
Return DirectCast(HOST.Source, SiteSettings)
|
Return DirectCast(HOST.Source, SiteSettings)
|
||||||
@@ -76,6 +80,7 @@ Namespace API.Instagram
|
|||||||
Private LastCursor As String = String.Empty
|
Private LastCursor As String = String.Empty
|
||||||
Private FirstLoadingDone As Boolean = False
|
Private FirstLoadingDone As Boolean = False
|
||||||
Friend Property GetTimeline As Boolean = True
|
Friend Property GetTimeline As Boolean = True
|
||||||
|
Friend Property GetReels As Boolean = False
|
||||||
Friend Property GetStories As Boolean
|
Friend Property GetStories As Boolean
|
||||||
Friend Property GetStoriesUser As Boolean
|
Friend Property GetStoriesUser As Boolean
|
||||||
Friend Property GetTaggedData As Boolean
|
Friend Property GetTaggedData As Boolean
|
||||||
@@ -94,6 +99,7 @@ Namespace API.Instagram
|
|||||||
LastCursor = .Value(Name_LastCursor)
|
LastCursor = .Value(Name_LastCursor)
|
||||||
FirstLoadingDone = .Value(Name_FirstLoadingDone).FromXML(Of Boolean)(False)
|
FirstLoadingDone = .Value(Name_FirstLoadingDone).FromXML(Of Boolean)(False)
|
||||||
GetTimeline = .Value(Name_GetTimeline).FromXML(Of Boolean)(CBool(MySiteSettings.GetTimeline.Value))
|
GetTimeline = .Value(Name_GetTimeline).FromXML(Of Boolean)(CBool(MySiteSettings.GetTimeline.Value))
|
||||||
|
GetReels = .Value(Name_GetReels).FromXML(Of Boolean)(MySiteSettings.GetReels.Value)
|
||||||
GetStories = .Value(Name_GetStories).FromXML(Of Boolean)(CBool(MySiteSettings.GetStories.Value))
|
GetStories = .Value(Name_GetStories).FromXML(Of Boolean)(CBool(MySiteSettings.GetStories.Value))
|
||||||
GetStoriesUser = .Value(Name_GetStoriesUser).FromXML(Of Boolean)(MySiteSettings.GetStoriesUser.Value)
|
GetStoriesUser = .Value(Name_GetStoriesUser).FromXML(Of Boolean)(MySiteSettings.GetStoriesUser.Value)
|
||||||
GetTaggedData = .Value(Name_GetTagged).FromXML(Of Boolean)(CBool(MySiteSettings.GetTagged.Value))
|
GetTaggedData = .Value(Name_GetTagged).FromXML(Of Boolean)(CBool(MySiteSettings.GetTagged.Value))
|
||||||
@@ -103,6 +109,7 @@ Namespace API.Instagram
|
|||||||
.Add(Name_LastCursor, LastCursor)
|
.Add(Name_LastCursor, LastCursor)
|
||||||
.Add(Name_FirstLoadingDone, FirstLoadingDone.BoolToInteger)
|
.Add(Name_FirstLoadingDone, FirstLoadingDone.BoolToInteger)
|
||||||
.Add(Name_GetTimeline, GetTimeline.BoolToInteger)
|
.Add(Name_GetTimeline, GetTimeline.BoolToInteger)
|
||||||
|
.Add(Name_GetReels, GetReels.BoolToInteger)
|
||||||
.Add(Name_GetStories, GetStories.BoolToInteger)
|
.Add(Name_GetStories, GetStories.BoolToInteger)
|
||||||
.Add(Name_GetStoriesUser, GetStoriesUser.BoolToInteger)
|
.Add(Name_GetStoriesUser, GetStoriesUser.BoolToInteger)
|
||||||
.Add(Name_GetTagged, GetTaggedData.BoolToInteger)
|
.Add(Name_GetTagged, GetTaggedData.BoolToInteger)
|
||||||
@@ -120,6 +127,7 @@ Namespace API.Instagram
|
|||||||
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)
|
||||||
GetTimeline = .GetTimeline
|
GetTimeline = .GetTimeline
|
||||||
|
GetReels = .GetReels
|
||||||
GetStories = .GetStories
|
GetStories = .GetStories
|
||||||
GetStoriesUser = .GetStoriesUser
|
GetStoriesUser = .GetStoriesUser
|
||||||
GetTaggedData = .GetTagged
|
GetTaggedData = .GetTagged
|
||||||
@@ -131,17 +139,20 @@ Namespace API.Instagram
|
|||||||
Friend Sub New()
|
Friend Sub New()
|
||||||
PostsKVIDs = New List(Of PostKV)
|
PostsKVIDs = New List(Of PostKV)
|
||||||
PostsToReparse = New List(Of PostKV)
|
PostsToReparse = New List(Of PostKV)
|
||||||
|
_ResponserAutoUpdateCookies = True
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Download data"
|
#Region "Download data"
|
||||||
Private E560Thrown As Boolean = False
|
Private E560Thrown As Boolean = False
|
||||||
|
Friend Err5xx As Integer = -1
|
||||||
Private Class ExitException : Inherits Exception
|
Private Class ExitException : Inherits Exception
|
||||||
|
Friend Property Is560 As Boolean = False
|
||||||
Friend Shared Sub Throw560(ByRef Source As UserData)
|
Friend Shared Sub Throw560(ByRef Source As UserData)
|
||||||
If Not Source.E560Thrown Then
|
If Not Source.E560Thrown Then
|
||||||
MyMainLOG = $"{Source.ToStringForLog}: (560) Download skipped until next session"
|
MyMainLOG = $"{Source.ToStringForLog}: ({IIf(Source.Err5xx > 0, Source.Err5xx, 560)}) Download skipped until next session"
|
||||||
Source.E560Thrown = True
|
Source.E560Thrown = True
|
||||||
End If
|
End If
|
||||||
Throw New ExitException
|
Throw New ExitException With {.Is560 = True}
|
||||||
End Sub
|
End Sub
|
||||||
End Class
|
End Class
|
||||||
Private ReadOnly Property MyFilePostsKV As SFile
|
Private ReadOnly Property MyFilePostsKV As SFile
|
||||||
@@ -229,6 +240,7 @@ 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
|
||||||
Try
|
Try
|
||||||
|
Err5xx = -1
|
||||||
_Limit = If(DownloadTopCount, -1)
|
_Limit = If(DownloadTopCount, -1)
|
||||||
_TotalPostsParsed = 0
|
_TotalPostsParsed = 0
|
||||||
LoadSavePostsKV(True)
|
LoadSavePostsKV(True)
|
||||||
@@ -253,9 +265,22 @@ Namespace API.Instagram
|
|||||||
End If
|
End If
|
||||||
If FirstLoadingDone Then LastCursor = String.Empty
|
If FirstLoadingDone Then LastCursor = String.Empty
|
||||||
If Not IsSavedPosts AndAlso MySiteSettings.BaseAuthExists() Then
|
If Not IsSavedPosts AndAlso MySiteSettings.BaseAuthExists() Then
|
||||||
|
If CBool(MySiteSettings.DownloadReels.Value) And GetReels Then
|
||||||
|
s = Sections.Reels
|
||||||
|
DefaultParser_ElemNode = {"node", "media"}
|
||||||
|
DownloadData(String.Empty, s, Token)
|
||||||
|
DefaultParser_ElemNode = Nothing
|
||||||
|
DownloadReels_SetEnvir = False
|
||||||
|
ProgressPre.Done()
|
||||||
|
End If
|
||||||
If CBool(MySiteSettings.DownloadStories.Value) And GetStories Then s = Sections.Stories : DownloadData(String.Empty, s, Token) : ProgressPre.Done()
|
If CBool(MySiteSettings.DownloadStories.Value) And GetStories Then s = Sections.Stories : DownloadData(String.Empty, s, Token) : ProgressPre.Done()
|
||||||
If CBool(MySiteSettings.DownloadStoriesUser.Value) And GetStoriesUser Then s = Sections.UserStories : DownloadData(String.Empty, s, Token) : ProgressPre.Done()
|
If CBool(MySiteSettings.DownloadStoriesUser.Value) And GetStoriesUser Then s = Sections.UserStories : DownloadData(String.Empty, s, Token) : ProgressPre.Done()
|
||||||
If CBool(MySiteSettings.DownloadTagged.Value) And ACheck(MySiteSettings.HashTagged.Value) And GetTaggedData Then s = Sections.Tagged : DownloadData(String.Empty, s, Token) : ProgressPre.Done()
|
If CBool(MySiteSettings.DownloadTagged.Value) And GetTaggedData Then
|
||||||
|
s = Sections.Tagged
|
||||||
|
DownloadData(String.Empty, s, Token)
|
||||||
|
ProgressPre.Done()
|
||||||
|
If PostsToReparse.Count > 0 Then DownloadPosts(Token, True)
|
||||||
|
End If
|
||||||
End If
|
End If
|
||||||
If WaitNotificationMode = WNM.SkipTemp Or WaitNotificationMode = WNM.SkipCurrent Then WaitNotificationMode = WNM.Notify
|
If WaitNotificationMode = WNM.SkipTemp Or WaitNotificationMode = WNM.SkipCurrent Then WaitNotificationMode = WNM.Notify
|
||||||
Catch eex As ExitException
|
Catch eex As ExitException
|
||||||
@@ -263,6 +288,8 @@ Namespace API.Instagram
|
|||||||
errorFound = True
|
errorFound = True
|
||||||
Throw ex
|
Throw ex
|
||||||
Finally
|
Finally
|
||||||
|
DefaultParser_ElemNode = Nothing
|
||||||
|
DownloadReels_SetEnvir = False
|
||||||
E560Thrown = False
|
E560Thrown = False
|
||||||
UpdateResponser()
|
UpdateResponser()
|
||||||
ValidateExtension()
|
ValidateExtension()
|
||||||
@@ -287,16 +314,16 @@ Namespace API.Instagram
|
|||||||
Try
|
Try
|
||||||
If _DownloadingInProgress AndAlso Not Responser Is Nothing AndAlso Not Responser.Disposed Then
|
If _DownloadingInProgress AndAlso Not Responser Is Nothing AndAlso Not Responser.Disposed Then
|
||||||
_DownloadingInProgress = False
|
_DownloadingInProgress = False
|
||||||
RemoveHandler Responser.ResponseReceived, AddressOf Responser_ResponseReceived
|
Responser_ResponseReceived_RemoveHandler()
|
||||||
Declarations.UpdateResponser(Responser, MySiteSettings.Responser)
|
Declarations.UpdateResponser(Responser, MySiteSettings.Responser)
|
||||||
End If
|
End If
|
||||||
Catch
|
Catch
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
Protected Overridable 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)
|
Declarations.UpdateResponser(e, Responser)
|
||||||
End Sub
|
End Sub
|
||||||
Protected Enum Sections : Timeline : Tagged : Stories : UserStories : SavedPosts : End Enum
|
Protected 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"
|
||||||
@@ -436,6 +463,7 @@ Namespace API.Instagram
|
|||||||
ReconfigureAwaiter()
|
ReconfigureAwaiter()
|
||||||
|
|
||||||
Try
|
Try
|
||||||
|
Dim r$ = String.Empty
|
||||||
Dim n As EContainer, nn As EContainer
|
Dim n As EContainer, nn As EContainer
|
||||||
Dim HasNextPage As Boolean = False
|
Dim HasNextPage As Boolean = False
|
||||||
Dim EndCursor$ = String.Empty
|
Dim EndCursor$ = String.Empty
|
||||||
@@ -456,16 +484,17 @@ Namespace API.Instagram
|
|||||||
URL = $"https://www.instagram.com/api/v1/feed/user/{NameTrue}/username/?count=50" &
|
URL = $"https://www.instagram.com/api/v1/feed/user/{NameTrue}/username/?count=50" &
|
||||||
If(Cursor.IsEmptyString, String.Empty, $"&max_id={Cursor}")
|
If(Cursor.IsEmptyString, String.Empty, $"&max_id={Cursor}")
|
||||||
ENode = Nothing
|
ENode = Nothing
|
||||||
|
Case Sections.Reels
|
||||||
|
r = DownloadReels(Cursor, Token)
|
||||||
|
ENode = {"data", "xdt_api__v1__clips__user__connection_v2"}
|
||||||
Case Sections.SavedPosts
|
Case Sections.SavedPosts
|
||||||
SavedPostsDownload(String.Empty, Token)
|
SavedPostsDownload(String.Empty, Token)
|
||||||
Exit Sub
|
Exit Sub
|
||||||
Case Sections.Tagged
|
Case Sections.Tagged
|
||||||
Dim h$ = AConvert(Of String)(MySiteSettings.HashTagged.Value, String.Empty)
|
|
||||||
If h.IsEmptyString Then Throw New ExitException
|
|
||||||
Dim vars$ = "{""id"":" & ID & ",""first"":50,""after"":""" & Cursor & """}"
|
Dim vars$ = "{""id"":" & ID & ",""first"":50,""after"":""" & Cursor & """}"
|
||||||
vars = SymbolsConverter.ASCII.EncodeSymbolsOnly(vars)
|
vars = SymbolsConverter.ASCII.EncodeSymbolsOnly(vars)
|
||||||
URL = $"https://www.instagram.com/graphql/query/?query_hash={h}&variables={vars}"
|
URL = $"https://www.instagram.com/graphql/query/?doc_id=17946422347485809&variables={vars}"
|
||||||
ENode = {"data", "user", 0}
|
ENode = {"data", "user", "edge_user_to_photos_of_you"}
|
||||||
SpecFolder = TaggedFolder
|
SpecFolder = TaggedFolder
|
||||||
Case Sections.Stories
|
Case Sections.Stories
|
||||||
If Not StoriesRequested Then
|
If Not StoriesRequested Then
|
||||||
@@ -493,7 +522,7 @@ Namespace API.Instagram
|
|||||||
End Select
|
End Select
|
||||||
|
|
||||||
'Get response
|
'Get response
|
||||||
Dim r$ = Responser.GetResponse(URL,, EDP.ThrowException)
|
If Not Section = Sections.Reels Then r = Responser.GetResponse(URL,, EDP.ThrowException)
|
||||||
MySiteSettings.TooManyRequests(False)
|
MySiteSettings.TooManyRequests(False)
|
||||||
RequestsCount += 1
|
RequestsCount += 1
|
||||||
ThrowAny(Token)
|
ThrowAny(Token)
|
||||||
@@ -515,6 +544,20 @@ Namespace API.Instagram
|
|||||||
HasNextPage = False
|
HasNextPage = False
|
||||||
End If
|
End If
|
||||||
End With
|
End With
|
||||||
|
Case Sections.Reels
|
||||||
|
With n
|
||||||
|
If .Contains("page_info") Then
|
||||||
|
With .Item("page_info")
|
||||||
|
HasNextPage = .Value("has_next_page").FromXML(Of Boolean)(False)
|
||||||
|
EndCursor = .Value("end_cursor")
|
||||||
|
End With
|
||||||
|
Else
|
||||||
|
HasNextPage = False
|
||||||
|
End If
|
||||||
|
If If(.Item("edges")?.Count, 0) > 0 Then
|
||||||
|
If Not DefaultParser(.Item("edges"), Section, Token, "Reels*") Then Throw New ExitException
|
||||||
|
End If
|
||||||
|
End With
|
||||||
Case Sections.Tagged
|
Case Sections.Tagged
|
||||||
With n
|
With n
|
||||||
If .Contains("page_info") Then
|
If .Contains("page_info") Then
|
||||||
@@ -567,25 +610,33 @@ Namespace API.Instagram
|
|||||||
End If
|
End If
|
||||||
dValue = 0
|
dValue = 0
|
||||||
If HasNextPage And Not EndCursor.IsEmptyString Then DownloadData(EndCursor, Section, Token)
|
If HasNextPage And Not EndCursor.IsEmptyString Then DownloadData(EndCursor, Section, Token)
|
||||||
|
Catch jsonNull As JsonDocumentException When jsonNull.State = WebDocumentEventArgs.States.Error And Section = Sections.Reels
|
||||||
|
Throw jsonNull
|
||||||
Catch eex As ExitException
|
Catch eex As ExitException
|
||||||
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)
|
||||||
End Try
|
End Try
|
||||||
Loop
|
Loop
|
||||||
|
Catch jsonNull2 As JsonDocumentException When jsonNull2.State = WebDocumentEventArgs.States.Error And Section = Sections.Reels
|
||||||
Catch eex2 As ExitException
|
Catch eex2 As ExitException
|
||||||
If (Section = Sections.Timeline Or Section = Sections.Tagged) And Not Cursor.IsEmptyString Then Throw eex2
|
If eex2.Is560 Then
|
||||||
|
Throw New Plugin.ExitException With {.Silent = True}
|
||||||
|
Else
|
||||||
|
If Not Section = Sections.Reels And (Section = Sections.Timeline Or Section = Sections.Tagged) And Not Cursor.IsEmptyString Then Throw eex2
|
||||||
|
End If
|
||||||
Catch oex2 As OperationCanceledException When Token.IsCancellationRequested Or oex2.HelpLink = InstAborted
|
Catch oex2 As OperationCanceledException When Token.IsCancellationRequested Or oex2.HelpLink = InstAborted
|
||||||
If oex2.HelpLink = InstAborted Then HasError = True
|
If oex2.HelpLink = InstAborted Then HasError = True
|
||||||
Catch DoEx As Exception
|
Catch DoEx As Exception
|
||||||
ProcessException(DoEx, Token, $"data downloading error [{URL}]",, Section)
|
ProcessException(DoEx, Token, $"data downloading error [{URL}]",, Section)
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
Private Sub DownloadPosts(ByVal Token As CancellationToken)
|
Private Sub DownloadPosts(ByVal Token As CancellationToken, Optional ByVal IsTagged As Boolean = False)
|
||||||
Dim URL$ = String.Empty
|
Dim URL$ = String.Empty
|
||||||
Dim dValue% = 1
|
Dim dValue% = 1
|
||||||
Dim _Index% = 0
|
Dim _Index% = 0
|
||||||
Dim before%
|
Dim before%
|
||||||
|
Dim specFolder$ = IIf(IsTagged, "Tagged", String.Empty)
|
||||||
If PostsToReparse.Count > 0 Then ProgressPre.ChangeMax(PostsToReparse.Count)
|
If PostsToReparse.Count > 0 Then ProgressPre.ChangeMax(PostsToReparse.Count)
|
||||||
Try
|
Try
|
||||||
Do While dValue = 1
|
Do While dValue = 1
|
||||||
@@ -616,7 +667,7 @@ Namespace API.Instagram
|
|||||||
With j("items")
|
With j("items")
|
||||||
For Each jj In .Self
|
For Each jj In .Self
|
||||||
before = _TempMediaList.Count
|
before = _TempMediaList.Count
|
||||||
ObtainMedia(jj, PostsToReparse(i).ID)
|
ObtainMedia(jj, PostsToReparse(i).ID, specFolder)
|
||||||
If Not before = _TempMediaList.Count Then _TotalPostsParsed += 1
|
If Not before = _TempMediaList.Count Then _TotalPostsParsed += 1
|
||||||
If _Limit > 0 And _TotalPostsParsed >= _Limit Then Throw New ExitException
|
If _Limit > 0 And _TotalPostsParsed >= _Limit Then Throw New ExitException
|
||||||
Next
|
Next
|
||||||
@@ -664,6 +715,7 @@ Namespace API.Instagram
|
|||||||
End Sub
|
End Sub
|
||||||
Protected DefaultParser_ElemNode() As Object = Nothing
|
Protected DefaultParser_ElemNode() As Object = Nothing
|
||||||
Protected DefaultParser_IgnorePass As Boolean = False
|
Protected DefaultParser_IgnorePass As Boolean = False
|
||||||
|
Private ReadOnly DefaultParser_PostUrlCreator_Default As Func(Of PostKV, String) = Function(post) $"https://www.instagram.com/p/{post.Code}/"
|
||||||
Protected DefaultParser_PostUrlCreator As Func(Of PostKV, String) = Function(post) $"https://www.instagram.com/p/{post.Code}/"
|
Protected DefaultParser_PostUrlCreator As Func(Of PostKV, String) = Function(post) $"https://www.instagram.com/p/{post.Code}/"
|
||||||
Protected Function DefaultParser(ByVal Items As IEnumerable(Of EContainer), ByVal Section As Sections, ByVal Token As CancellationToken,
|
Protected Function DefaultParser(ByVal Items As IEnumerable(Of EContainer), ByVal Section As Sections, ByVal Token As CancellationToken,
|
||||||
Optional ByVal SpecFolder As String = Nothing, Optional ByVal State As UStates = UStates.Unknown,
|
Optional ByVal SpecFolder As String = Nothing, Optional ByVal State As UStates = UStates.Unknown,
|
||||||
@@ -713,6 +765,106 @@ Namespace API.Instagram
|
|||||||
End If
|
End If
|
||||||
End Function
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
|
#Region "Get reels"
|
||||||
|
Private _GetReels_LSD As String = String.Empty
|
||||||
|
Private _GetReels_dtsg As String = String.Empty
|
||||||
|
Private ReadOnly Property DownloadReels_Tokens_Valid As Boolean
|
||||||
|
Get
|
||||||
|
Return Not _GetReels_LSD.IsEmptyString And Not _GetReels_dtsg.IsEmptyString
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
Private WriteOnly Property DownloadReels_SetEnvir As Boolean
|
||||||
|
Set(ByVal init As Boolean)
|
||||||
|
If init Then
|
||||||
|
ObtainMedia_SetReelsFunc()
|
||||||
|
DefaultParser_PostUrlCreator = Function(post) $"{MySiteSettings.GetUserUrl(Me).TrimEnd("/")}/reel/{post.Code}"
|
||||||
|
Else
|
||||||
|
ObtainMedia_SizeFuncPic = Nothing
|
||||||
|
ObtainMedia_SizeFuncVid = Nothing
|
||||||
|
DefaultParser_PostUrlCreator = DefaultParser_PostUrlCreator_Default
|
||||||
|
End If
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
Private Class Responser2 : Inherits Responser
|
||||||
|
Friend Sub New(ByVal Source As Responser)
|
||||||
|
MyBase.New
|
||||||
|
Copy(Source)
|
||||||
|
ErrorProcessor = New ResponserErrorProcessor(Source)
|
||||||
|
End Sub
|
||||||
|
End Class
|
||||||
|
''' <returns>Response</returns>
|
||||||
|
Private Function DownloadReels(ByVal Cursor As String, ByVal Token As CancellationToken) As String
|
||||||
|
Const requestPattern$ = "https://www.instagram.com/api/graphql?fb_dtsg={0}&fb_api_req_friendly_name=PolarisProfileReelsTabContentQuery&lsd={1}&doc_id=7191572580905225&variables={2}"
|
||||||
|
|
||||||
|
DownloadReels_SetEnvir = True
|
||||||
|
|
||||||
|
If Cursor.IsEmptyString And Not DownloadReels_Tokens_Valid Then GetPageTokens()
|
||||||
|
If Cursor.IsEmptyString And Not DownloadReels_Tokens_Valid Then Throw New ExitException
|
||||||
|
|
||||||
|
Using resp As New Responser2(Responser)
|
||||||
|
Try
|
||||||
|
resp.Method = "POST"
|
||||||
|
AddHandler resp.ResponseReceived, AddressOf Responser_ResponseReceived
|
||||||
|
resp.Headers.Add(Header_FB_LSD, _GetReels_LSD)
|
||||||
|
|
||||||
|
Dim vars$ = """data"":{""include_feed_video"":true,""page_size"":50,""target_user_id"":""" & ID & """}"
|
||||||
|
If Not Cursor.IsEmptyString Then vars = $"""after"":""{Cursor}"",""before"":null,{vars},""first"":4,""last"":null"
|
||||||
|
vars = "{" & vars & "}"
|
||||||
|
|
||||||
|
Dim url$ = String.Format(requestPattern, _GetReels_dtsg, _GetReels_LSD, SymbolsConverter.ASCII.EncodeSymbolsOnly(vars))
|
||||||
|
|
||||||
|
Return resp.GetResponse(url,, EDP.ThrowException)
|
||||||
|
Finally
|
||||||
|
With resp
|
||||||
|
Responser.Cookies.Update(.Cookies)
|
||||||
|
With .Headers
|
||||||
|
If .Contains(SiteSettings.Header_IG_WWW_CLAIM) Then Responser.Headers.Add(SiteSettings.Header_IG_WWW_CLAIM, .Value(SiteSettings.Header_IG_WWW_CLAIM))
|
||||||
|
If .Contains(SiteSettings.Header_CSRF_TOKEN) Then Responser.Headers.Add(SiteSettings.Header_CSRF_TOKEN, .Value(SiteSettings.Header_CSRF_TOKEN))
|
||||||
|
End With
|
||||||
|
End With
|
||||||
|
End Try
|
||||||
|
End Using
|
||||||
|
End Function
|
||||||
|
Private Function GetPageTokens() As Boolean
|
||||||
|
_GetReels_LSD = String.Empty
|
||||||
|
_GetReels_dtsg = String.Empty
|
||||||
|
Try
|
||||||
|
Dim r$ = Responser.GetResponse(MySiteSettings.GetUserUrl(Me),, EDP.ThrowException)
|
||||||
|
If Not r.IsEmptyString Then
|
||||||
|
Dim rr As RParams = RParams.DM(PageTokenRegexPatternDefault, 0, RegexReturn.List, EDP.ReturnValue)
|
||||||
|
Dim tokens As List(Of String) = RegexReplace(r, rr)
|
||||||
|
Dim tt$, ttVal$
|
||||||
|
If tokens.ListExists Then
|
||||||
|
With rr
|
||||||
|
.Match = Nothing
|
||||||
|
.MatchSub = 1
|
||||||
|
.WhatGet = RegexReturn.Value
|
||||||
|
End With
|
||||||
|
For Each tt In tokens
|
||||||
|
If Not _GetReels_LSD.IsEmptyString And Not _GetReels_dtsg.IsEmptyString Then
|
||||||
|
Exit For
|
||||||
|
Else
|
||||||
|
ttVal = RegexReplace(tt, rr)
|
||||||
|
If Not ttVal.IsEmptyString Then
|
||||||
|
If ttVal.Contains(":") Then
|
||||||
|
If _GetReels_dtsg.IsEmptyString Then _GetReels_dtsg = ttVal
|
||||||
|
Else
|
||||||
|
If _GetReels_LSD.IsEmptyString Then _GetReels_LSD = ttVal
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Next
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Catch ex As Exception
|
||||||
|
Dim notFound$ = String.Empty
|
||||||
|
If _GetReels_dtsg.IsEmptyString Then notFound.StringAppend(Header_FB_LSD)
|
||||||
|
If _GetReels_LSD.IsEmptyString Then notFound.StringAppend("lsd")
|
||||||
|
LogError(ex, $"failed to update some{IIf(notFound.IsEmptyString, String.Empty, $" ({notFound})")} credentials", EDP.SendToLog)
|
||||||
|
End Try
|
||||||
|
Return DownloadReels_Tokens_Valid
|
||||||
|
End Function
|
||||||
|
#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
|
||||||
Const CodeSymbols$ = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
|
Const CodeSymbols$ = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||||
@@ -737,15 +889,38 @@ Namespace API.Instagram
|
|||||||
Protected ObtainMedia_SizeFuncVid As Func(Of EContainer, Sizes) = Nothing
|
Protected ObtainMedia_SizeFuncVid As Func(Of EContainer, Sizes) = Nothing
|
||||||
Protected ObtainMedia_SizeFuncPic As Func(Of EContainer, Sizes) = Nothing
|
Protected ObtainMedia_SizeFuncPic As Func(Of EContainer, Sizes) = Nothing
|
||||||
Protected ObtainMedia_AllowAbstract As Boolean = False
|
Protected ObtainMedia_AllowAbstract As Boolean = False
|
||||||
|
Protected Sub ObtainMedia_SetReelsFunc()
|
||||||
|
ObtainMedia_SizeFuncPic = Function(ByVal ss As EContainer) As Sizes
|
||||||
|
If ss.Value("url").IsEmptyString Then
|
||||||
|
Return New Sizes("----", "")
|
||||||
|
ElseIf Not ss.Value("width").IsEmptyString Or Not ss.Value("width").IsEmptyString Then
|
||||||
|
Return New Sizes(CInt(AConvert(Of Integer)(ss.Value("width"), 0)) +
|
||||||
|
CInt(AConvert(Of Integer)(ss.Value("height"), 0)), ss.Value("url"))
|
||||||
|
Else
|
||||||
|
Dim rval$ = RegexReplace(ss.Value("url"), ObtainMedia_SizeFuncPic_RegexP)
|
||||||
|
If Not rval.IsEmptyString Then Return New Sizes(rval, ss.Value("url"))
|
||||||
|
rval = RegexReplace(ss.Value("url"), ObtainMedia_SizeFuncPic_RegexS)
|
||||||
|
If Not rval.IsEmptyString Then Return New Sizes(AConvert(Of Integer)(rval, 1) * -1, ss.Value("url"))
|
||||||
|
Return New Sizes(10000, ss.Value("url"))
|
||||||
|
End If
|
||||||
|
End Function
|
||||||
|
ObtainMedia_SizeFuncVid = Function(ss) If(ss.Value("url").IsEmptyString, New Sizes("----", ""), New Sizes(10000, ss.Value("url")))
|
||||||
|
End Sub
|
||||||
Protected Sub ObtainMedia(ByVal n As EContainer, ByVal PostID As String, Optional ByVal SpecialFolder As String = Nothing,
|
Protected Sub ObtainMedia(ByVal n As EContainer, ByVal PostID As String, Optional ByVal SpecialFolder As String = Nothing,
|
||||||
Optional ByVal DateObj As String = Nothing, Optional ByVal InitialType As Integer = -1,
|
Optional ByVal DateObj As String = Nothing, Optional ByVal InitialType As Integer = -1,
|
||||||
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)
|
||||||
Try
|
Try
|
||||||
|
Dim maxSize As Func(Of EContainer, Integer) = Function(ByVal _ss As EContainer) As Integer
|
||||||
|
Dim w% = AConvert(Of Integer)(_ss.Value("width"), 0)
|
||||||
|
Dim h% = AConvert(Of Integer)(_ss.Value("height"), 0)
|
||||||
|
'Return w + h
|
||||||
|
Return Math.Max(w, h)
|
||||||
|
End Function
|
||||||
Dim wrongData As Predicate(Of Sizes) = Function(_ss) _ss.HasError Or _ss.Data.IsEmptyString
|
Dim wrongData As Predicate(Of Sizes) = Function(_ss) _ss.HasError Or _ss.Data.IsEmptyString
|
||||||
Dim img As Predicate(Of EContainer) = Function(_img) Not _img.Name.IsEmptyString AndAlso _img.Name.StartsWith("image_versions") AndAlso _img.Count > 0
|
Dim img As Predicate(Of EContainer) = Function(_img) Not _img.Name.IsEmptyString AndAlso _img.Name.StartsWith("image_versions") AndAlso _img.Count > 0
|
||||||
Dim vid As Predicate(Of EContainer) = Function(_vid) Not _vid.Name.IsEmptyString AndAlso _vid.Name.StartsWith("video_versions") AndAlso _vid.Count > 0
|
Dim vid As Predicate(Of EContainer) = Function(_vid) Not _vid.Name.IsEmptyString AndAlso _vid.Name.StartsWith("video_versions") AndAlso _vid.Count > 0
|
||||||
Dim ss As Func(Of EContainer, Sizes) = Function(_ss) New Sizes(_ss.Value("width"), _ss.Value("url"))
|
Dim ss As Func(Of EContainer, Sizes) = Function(_ss) New Sizes(maxSize(_ss), _ss.Value("url"))
|
||||||
Dim ssVid As Func(Of EContainer, Sizes) = ss
|
Dim ssVid As Func(Of EContainer, Sizes) = ss
|
||||||
Dim ssPic As Func(Of EContainer, Sizes) = ss
|
Dim ssPic As Func(Of EContainer, Sizes) = ss
|
||||||
Dim mDate As Func(Of EContainer, String) = Function(ByVal elem As EContainer) As String
|
Dim mDate As Func(Of EContainer, String) = Function(ByVal elem As EContainer) As String
|
||||||
@@ -1028,6 +1203,7 @@ Namespace API.Instagram
|
|||||||
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
|
||||||
MySiteSettings.SkipUntilNextSession = True
|
MySiteSettings.SkipUntilNextSession = True
|
||||||
|
Err5xx = Responser.StatusCode
|
||||||
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)
|
||||||
@@ -1041,11 +1217,12 @@ Namespace API.Instagram
|
|||||||
Dim s As Sections = DirectCast(Section, Sections)
|
Dim s As Sections = DirectCast(Section, Sections)
|
||||||
Select Case s
|
Select Case s
|
||||||
Case Sections.Timeline : MySiteSettings.DownloadTimeline.Value = False
|
Case Sections.Timeline : MySiteSettings.DownloadTimeline.Value = False
|
||||||
|
Case Sections.Reels : MySiteSettings.DownloadReels.Value = False
|
||||||
|
Case Sections.Tagged : MySiteSettings.DownloadTagged.Value = False
|
||||||
Case Sections.Stories, Sections.UserStories
|
Case Sections.Stories, Sections.UserStories
|
||||||
MySiteSettings.DownloadTimeline.Value = False
|
MySiteSettings.DownloadTimeline.Value = False
|
||||||
MySiteSettings.DownloadStories.Value = False
|
MySiteSettings.DownloadStories.Value = False
|
||||||
MySiteSettings.DownloadStoriesUser.Value = False
|
MySiteSettings.DownloadStoriesUser.Value = False
|
||||||
Case Else : MySiteSettings.DownloadTagged.Value = False
|
|
||||||
End Select
|
End Select
|
||||||
MyMainLOG = $"[{s}] downloading is disabled until you update your credentials".ToUpper
|
MyMainLOG = $"[{s}] downloading is disabled until you update your credentials".ToUpper
|
||||||
End If
|
End If
|
||||||
@@ -1066,7 +1243,7 @@ Namespace API.Instagram
|
|||||||
#End Region
|
#End Region
|
||||||
#Region "Standalone downloader"
|
#Region "Standalone downloader"
|
||||||
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)
|
||||||
Dim PID$ = RegexReplace(Data.URL, RParams.DMS(".*?instagram.com/p/([_\w\d]+)", 1))
|
Dim PID$ = RegexReplace(Data.URL, RParams.DMS(String.Format(UserRegexDefaultPattern, "instagram.com/p/"), 1))
|
||||||
If Not PID.IsEmptyString AndAlso Not ACheck(Of Long)(PID) Then PID = CodeToID(PID)
|
If Not PID.IsEmptyString AndAlso Not ACheck(Of Long)(PID) Then PID = CodeToID(PID)
|
||||||
If Not PID.IsEmptyString Then
|
If Not PID.IsEmptyString Then
|
||||||
PostsToReparse.Add(New PostKV With {.ID = PID})
|
PostsToReparse.Add(New PostKV With {.ID = PID})
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ Namespace API.JustForFans
|
|||||||
UserAgent = New PropertyValue(If(Responser.UserAgentExists, Responser.UserAgent, String.Empty), GetType(String), Sub(v) UpdateHeader(NameOf(UserAgent), v))
|
UserAgent = New PropertyValue(If(Responser.UserAgentExists, Responser.UserAgent, String.Empty), GetType(String), Sub(v) UpdateHeader(NameOf(UserAgent), v))
|
||||||
|
|
||||||
_AllowUserAgentUpdate = False
|
_AllowUserAgentUpdate = False
|
||||||
UserRegex = RParams.DMS("https://justfor.fans/([^/\?]+)", 1, EDP.ReturnValue)
|
UserRegex = RParams.DMS(String.Format(UserRegexDefaultPattern, "justfor.fans/"), 1, EDP.ReturnValue)
|
||||||
UrlPatternUser = "https://justfor.fans/{0}"
|
UrlPatternUser = "https://justfor.fans/{0}"
|
||||||
ImageVideoContains = "justfor.fans"
|
ImageVideoContains = "justfor.fans"
|
||||||
End Sub
|
End Sub
|
||||||
|
|||||||
@@ -168,6 +168,7 @@ Namespace API.JustForFans
|
|||||||
#Region "Initializer"
|
#Region "Initializer"
|
||||||
Friend Sub New()
|
Friend Sub New()
|
||||||
UseInternalM3U8Function = True
|
UseInternalM3U8Function = True
|
||||||
|
_ResponserAutoUpdateCookies = True
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Download functions"
|
#Region "Download functions"
|
||||||
@@ -191,11 +192,11 @@ Namespace API.JustForFans
|
|||||||
DownloadData(0, Token)
|
DownloadData(0, Token)
|
||||||
Finally
|
Finally
|
||||||
If DownloadTopCount.HasValue Then DownloadTopCount = Nothing
|
If DownloadTopCount.HasValue Then DownloadTopCount = Nothing
|
||||||
Try : RemoveHandler Responser.ResponseReceived, AddressOf Responser_ResponseReceived : Catch : End Try
|
Responser_ResponseReceived_RemoveHandler()
|
||||||
MySettings.UpdateResponser(Responser)
|
MySettings.UpdateResponser(Responser)
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
Private Sub Responser_ResponseReceived(ByVal Source As Object, ByVal e As EventArguments.WebDataResponse)
|
Protected Overrides Sub Responser_ResponseReceived(ByVal Source As Object, ByVal e As EventArguments.WebDataResponse)
|
||||||
If e.CookiesExists Then
|
If e.CookiesExists Then
|
||||||
Dim hv$ = If(e.Cookies.FirstOrDefault(Function(cc) cc.Name.StringToLower = SiteSettings.UserHash4_CookieName)?.Value, String.Empty)
|
Dim hv$ = If(e.Cookies.FirstOrDefault(Function(cc) cc.Name.StringToLower = SiteSettings.UserHash4_CookieName)?.Value, String.Empty)
|
||||||
If Not hv.IsEmptyString And Not _UserHash4 = hv Then _UserHash4 = hv
|
If Not hv.IsEmptyString And Not _UserHash4 = hv Then _UserHash4 = hv
|
||||||
|
|||||||
@@ -106,9 +106,12 @@ 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
|
If Responser.StatusCode = Net.HttpStatusCode.ServiceUnavailable Then '503
|
||||||
MyMainLOG = $"{ToStringForLog()}: LPSG not available"
|
MyMainLOG = $"{ToStringForLog()}: LPSG not available"
|
||||||
Return 1
|
Return 1
|
||||||
|
ElseIf Responser.StatusCode = Net.HttpStatusCode.NotFound Then '404
|
||||||
|
UserExists = False
|
||||||
|
Return 1
|
||||||
Else
|
Else
|
||||||
Return 0
|
Return 0
|
||||||
End If
|
End If
|
||||||
|
|||||||
77
SCrawler/API/OnlyFans/OFResources.Designer.vb
generated
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
'------------------------------------------------------------------------------
|
||||||
|
' <auto-generated>
|
||||||
|
' This code was generated by a tool.
|
||||||
|
' Runtime Version:4.0.30319.42000
|
||||||
|
'
|
||||||
|
' Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
' the code is regenerated.
|
||||||
|
' </auto-generated>
|
||||||
|
'------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Option Strict On
|
||||||
|
Option Explicit On
|
||||||
|
|
||||||
|
Imports System
|
||||||
|
|
||||||
|
Namespace My.Resources
|
||||||
|
|
||||||
|
'This class was auto-generated by the StronglyTypedResourceBuilder
|
||||||
|
'class via a tool like ResGen or Visual Studio.
|
||||||
|
'To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
|
'with the /str option, or rebuild your VS project.
|
||||||
|
'''<summary>
|
||||||
|
''' A strongly-typed resource class, for looking up localized strings, etc.
|
||||||
|
'''</summary>
|
||||||
|
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0"), _
|
||||||
|
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
|
||||||
|
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute()> _
|
||||||
|
Friend Class OFResources
|
||||||
|
|
||||||
|
Private Shared resourceMan As Global.System.Resources.ResourceManager
|
||||||
|
|
||||||
|
Private Shared resourceCulture As Global.System.Globalization.CultureInfo
|
||||||
|
|
||||||
|
<Global.System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")> _
|
||||||
|
Friend Sub New()
|
||||||
|
MyBase.New
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
'''<summary>
|
||||||
|
''' Returns the cached ResourceManager instance used by this class.
|
||||||
|
'''</summary>
|
||||||
|
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||||
|
Friend Shared ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager
|
||||||
|
Get
|
||||||
|
If Object.ReferenceEquals(resourceMan, Nothing) Then
|
||||||
|
Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("SCrawler.OFResources", GetType(OFResources).Assembly)
|
||||||
|
resourceMan = temp
|
||||||
|
End If
|
||||||
|
Return resourceMan
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
|
||||||
|
'''<summary>
|
||||||
|
''' Overrides the current thread's CurrentUICulture property for all
|
||||||
|
''' resource lookups using this strongly typed resource class.
|
||||||
|
'''</summary>
|
||||||
|
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||||
|
Friend Shared Property Culture() As Global.System.Globalization.CultureInfo
|
||||||
|
Get
|
||||||
|
Return resourceCulture
|
||||||
|
End Get
|
||||||
|
Set
|
||||||
|
resourceCulture = value
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
|
||||||
|
'''<summary>
|
||||||
|
''' Looks up a localized resource of type System.Byte[].
|
||||||
|
'''</summary>
|
||||||
|
Friend Shared ReadOnly Property OFScraperConfigPattern() As Byte()
|
||||||
|
Get
|
||||||
|
Dim obj As Object = ResourceManager.GetObject("OFScraperConfigPattern", resourceCulture)
|
||||||
|
Return CType(obj,Byte())
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
End Class
|
||||||
|
End Namespace
|
||||||
124
SCrawler/API/OnlyFans/OFResources.resx
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||||
|
<data name="OFScraperConfigPattern" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
|
<value>OFScraperConfigPattern.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
||||||
61
SCrawler/API/OnlyFans/OFScraperConfigPattern.json
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"main_profile": "main_profile",
|
||||||
|
"metadata": "{configpath}/{profile}/.data/{model_username}_{model_id}",
|
||||||
|
"discord": "",
|
||||||
|
"file_options": {
|
||||||
|
"save_location": "",
|
||||||
|
"dir_format": "",
|
||||||
|
"file_format": "{filename}.{ext}",
|
||||||
|
"textlength": 0,
|
||||||
|
"space-replacer": " ",
|
||||||
|
"date": "YYYY-MM-DD"
|
||||||
|
},
|
||||||
|
"download_options": {
|
||||||
|
"file_size_limit": 0,
|
||||||
|
"file_size_min": 0,
|
||||||
|
"filter": [
|
||||||
|
"Images",
|
||||||
|
"Audios",
|
||||||
|
"Videos"
|
||||||
|
],
|
||||||
|
"auto_resume": false
|
||||||
|
},
|
||||||
|
"binary_options": {
|
||||||
|
"mp4decrypt": "",
|
||||||
|
"ffmpeg": ""
|
||||||
|
},
|
||||||
|
"cdm_options": {
|
||||||
|
"private-key": null,
|
||||||
|
"client-id": null,
|
||||||
|
"key-mode-default": "cdrm",
|
||||||
|
"keydb_api": ""
|
||||||
|
},
|
||||||
|
"performance_options": {
|
||||||
|
"download-sems": 6,
|
||||||
|
"maxfile-sem": 0,
|
||||||
|
"threads": 5
|
||||||
|
},
|
||||||
|
"advanced_options": {
|
||||||
|
"code-execution": false,
|
||||||
|
"dynamic-mode-default": "deviint",
|
||||||
|
"backend": "aio",
|
||||||
|
"downloadbars": false,
|
||||||
|
"cache-mode": "sqlite",
|
||||||
|
"appendlog": true,
|
||||||
|
"custom": null,
|
||||||
|
"sanitize_text": false,
|
||||||
|
"avatar": true
|
||||||
|
},
|
||||||
|
"responsetype": {
|
||||||
|
"timeline": "Posts",
|
||||||
|
"message": "Messages",
|
||||||
|
"archived": "Archived",
|
||||||
|
"paid": "Messages",
|
||||||
|
"stories": "Stories",
|
||||||
|
"highlights": "Stories",
|
||||||
|
"profile": "Profile",
|
||||||
|
"pinned": "Posts"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,8 +26,8 @@ Namespace API.OnlyFans
|
|||||||
#Region "Headers"
|
#Region "Headers"
|
||||||
Private Const HeaderBrowser As String = "sec-ch-ua"
|
Private Const HeaderBrowser As String = "sec-ch-ua"
|
||||||
Private Const HeaderUserID As String = "User-Id"
|
Private Const HeaderUserID As String = "User-Id"
|
||||||
Private Const HeaderXBC As String = "X-Bc"
|
Friend Const HeaderXBC As String = "X-Bc"
|
||||||
Private Const HeaderAppToken As String = "App-Token"
|
Friend Const HeaderAppToken As String = "App-Token"
|
||||||
<PropertyOption(ControlText:=HeaderUserID, AllowNull:=False), PClonable(Clone:=False)>
|
<PropertyOption(ControlText:=HeaderUserID, AllowNull:=False), PClonable(Clone:=False)>
|
||||||
Friend ReadOnly Property HH_USER_ID As PropertyValue
|
Friend ReadOnly Property HH_USER_ID As PropertyValue
|
||||||
<PropertyOption(ControlText:=HeaderXBC, AllowNull:=False), PClonable(Clone:=False)>
|
<PropertyOption(ControlText:=HeaderXBC, AllowNull:=False), PClonable(Clone:=False)>
|
||||||
@@ -37,7 +37,7 @@ Namespace API.OnlyFans
|
|||||||
<PropertyOption(ControlText:=HeaderBrowser, ControlToolTip:="Can be null", AllowNull:=True), PClonable>
|
<PropertyOption(ControlText:=HeaderBrowser, ControlToolTip:="Can be null", AllowNull:=True), PClonable>
|
||||||
Private ReadOnly Property HH_BROWSER As PropertyValue
|
Private ReadOnly Property HH_BROWSER As PropertyValue
|
||||||
<PropertyOption(AllowNull:=False), PClonable>
|
<PropertyOption(AllowNull:=False), PClonable>
|
||||||
Private ReadOnly Property UserAgent As PropertyValue
|
Friend ReadOnly Property UserAgent As PropertyValue
|
||||||
Private Sub UpdateHeader(ByVal PropertyName As String, ByVal Value As String)
|
Private Sub UpdateHeader(ByVal PropertyName As String, ByVal Value As String)
|
||||||
Dim hName$ = String.Empty
|
Dim hName$ = String.Empty
|
||||||
Dim isUserAgent As Boolean = False
|
Dim isUserAgent As Boolean = False
|
||||||
@@ -78,6 +78,42 @@ Namespace API.OnlyFans
|
|||||||
"Change this value only if you know what you are doing."), PXML, PClonable>
|
"Change this value only if you know what you are doing."), PXML, PClonable>
|
||||||
Friend ReadOnly Property DynamicRules As PropertyValue
|
Friend ReadOnly Property DynamicRules As PropertyValue
|
||||||
#End Region
|
#End Region
|
||||||
|
#Region "OFScraper"
|
||||||
|
<PClonable, PXML("OFScraperPath")> Private ReadOnly Property OFScraperPath_XML As PropertyValue
|
||||||
|
<PropertyOption(ControlText:="OF-Scraper path", ControlToolTip:="The path to the 'ofscraper.exe'")>
|
||||||
|
Friend ReadOnly Property OFScraperPath As PropertyValue
|
||||||
|
Get
|
||||||
|
If Not DefaultInstance Is Nothing Then
|
||||||
|
Return DirectCast(DefaultInstance, SiteSettings).OFScraperPath_XML
|
||||||
|
Else
|
||||||
|
Return OFScraperPath_XML
|
||||||
|
End If
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
<PClonable, PXML("OFScraperMP4decrypt")> Private ReadOnly Property OFScraperMP4decrypt_XML As PropertyValue
|
||||||
|
<PropertyOption(ControlText:="mp4decrypt path", ControlToolTip:="The path to the 'mp4decrypt.exe'")>
|
||||||
|
Friend ReadOnly Property OFScraperMP4decrypt As PropertyValue
|
||||||
|
Get
|
||||||
|
If Not DefaultInstance Is Nothing Then
|
||||||
|
Return DirectCast(DefaultInstance, SiteSettings).OFScraperMP4decrypt_XML
|
||||||
|
Else
|
||||||
|
Return OFScraperMP4decrypt_XML
|
||||||
|
End If
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
Friend Const KeyModeDefault_Default As String = "cdrm"
|
||||||
|
<PClonable, PXML("KeyModeDefault")> Private ReadOnly Property KeyModeDefault_XML As PropertyValue
|
||||||
|
<PropertyOption(ControlText:="key-mode-default")>
|
||||||
|
Friend ReadOnly Property KeyModeDefault As PropertyValue
|
||||||
|
Get
|
||||||
|
If Not DefaultInstance Is Nothing Then
|
||||||
|
Return DirectCast(DefaultInstance, SiteSettings).KeyModeDefault_XML
|
||||||
|
Else
|
||||||
|
Return KeyModeDefault_XML
|
||||||
|
End If
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
#End Region
|
||||||
#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)
|
||||||
@@ -112,12 +148,28 @@ Namespace API.OnlyFans
|
|||||||
DownloadChatMedia = New PropertyValue(True)
|
DownloadChatMedia = New PropertyValue(True)
|
||||||
|
|
||||||
LastDateUpdated_XML = New PropertyValue(Now.AddYears(-1), GetType(Date))
|
LastDateUpdated_XML = New PropertyValue(Now.AddYears(-1), GetType(Date))
|
||||||
UseOldAuthRules = New PropertyValue(False)
|
'URGENT: OF [UseOldAuthRules = True]
|
||||||
|
UseOldAuthRules = New PropertyValue(True)
|
||||||
DynamicRulesUpdateInterval = New PropertyValue(60 * 24)
|
DynamicRulesUpdateInterval = New PropertyValue(60 * 24)
|
||||||
DynamicRulesUpdateIntervalProvider = New FieldsCheckerProviderSimple(Function(v) IIf(AConvert(Of Integer)(v, 0) > 0, v, Nothing),
|
DynamicRulesUpdateIntervalProvider = New FieldsCheckerProviderSimple(Function(v) IIf(AConvert(Of Integer)(v, 0) > 0, v, Nothing),
|
||||||
"The value of [{0}] field must be greater than 0")
|
"The value of [{0}] field must be greater than 0")
|
||||||
DynamicRules = New PropertyValue(String.Empty, GetType(String))
|
DynamicRules = New PropertyValue(String.Empty, GetType(String))
|
||||||
UserRegex = RParams.DMS("onlyfans.com/([\w\._]+)", 1, EDP.ReturnValue)
|
OFScraperPath_XML = New PropertyValue(String.Empty, GetType(String))
|
||||||
|
If ACheck(OFScraperPath_XML.Value) Then
|
||||||
|
Dim f As SFile = OFScraperPath_XML.Value
|
||||||
|
If Not f.Exists AndAlso f.Exists(SFO.Path, False) Then
|
||||||
|
With SFile.GetFiles(f, "*.exe",, EDP.ReturnValue)
|
||||||
|
If .ListExists Then
|
||||||
|
f = .FirstOrDefault(Function(ff) ff.Name.StringToLower.StartsWith("ofscraper"))
|
||||||
|
If f.Exists Then OFScraperPath_XML.Value = f.ToString
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
OFScraperMP4decrypt_XML = New PropertyValue(String.Empty, GetType(String))
|
||||||
|
KeyModeDefault_XML = New PropertyValue(KeyModeDefault_Default)
|
||||||
|
|
||||||
|
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
|
||||||
@@ -151,6 +203,7 @@ Namespace API.OnlyFans
|
|||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "GetUserUrl, GetUserPostUrl, UserOptions"
|
#Region "GetUserUrl, GetUserPostUrl, UserOptions"
|
||||||
|
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.Name, $"u{User.ID}"))
|
||||||
End Function
|
End Function
|
||||||
@@ -168,7 +221,7 @@ Namespace API.OnlyFans
|
|||||||
If p.IsEmptyString Then
|
If p.IsEmptyString Then
|
||||||
Return GetUserUrl(User)
|
Return GetUserUrl(User)
|
||||||
Else
|
Else
|
||||||
Return String.Format("https://onlyfans.com/{0}/{1}", p, If(User.ID.IsEmptyString, User.Name, $"u{User.ID}"))
|
Return String.Format(UserPostPattern, p, If(User.ID.IsEmptyString, User.Name, $"u{User.ID}"))
|
||||||
End If
|
End If
|
||||||
Else
|
Else
|
||||||
Return String.Empty
|
Return String.Empty
|
||||||
|
|||||||
@@ -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.YouTube.Objects
|
Imports SCrawler.API.YouTube.Objects
|
||||||
Imports PersonalUtilities.Functions.XML
|
Imports PersonalUtilities.Functions.XML
|
||||||
Imports PersonalUtilities.Functions.RegularExpressions
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
|
Imports PersonalUtilities.Tools
|
||||||
Imports PersonalUtilities.Tools.Web.Clients
|
Imports PersonalUtilities.Tools.Web.Clients
|
||||||
Imports PersonalUtilities.Tools.Web.Clients.EventArguments
|
Imports PersonalUtilities.Tools.Web.Clients.EventArguments
|
||||||
Imports PersonalUtilities.Tools.Web.Cookies
|
Imports PersonalUtilities.Tools.Web.Cookies
|
||||||
@@ -65,24 +67,40 @@ Namespace API.OnlyFans
|
|||||||
#Region "Initializer"
|
#Region "Initializer"
|
||||||
Friend Sub New()
|
Friend Sub New()
|
||||||
HighlightsList = New List(Of String)
|
HighlightsList = New List(Of String)
|
||||||
|
UseInternalDownloadFileFunction = True
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Download functions"
|
#Region "Download functions"
|
||||||
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
|
Private _OFScraperExists As Boolean = False
|
||||||
If Not MySettings.SessionAborted Then
|
Private OFSCache As CacheKeeper = Nothing
|
||||||
If Not CCookie Is Nothing Then CCookie.Dispose()
|
Private _AbsMediaIndex As Integer = 0
|
||||||
CCookie = Responser.Cookies.Copy
|
Private FunctionErr As Integer = FunctionErrDef
|
||||||
Responser.Cookies.Clear()
|
Private Const FunctionErrDef As Integer = -100
|
||||||
AddHandler Responser.ResponseReceived, AddressOf OnResponseReceived
|
Private Sub ValidateOFScraper()
|
||||||
UpdateCookieHeader()
|
_OFScraperExists = ACheck(MySettings.OFScraperPath.Value) AndAlso CStr(MySettings.OFScraperPath.Value).CSFile.Exists
|
||||||
DownloadTimeline(IIf(IsSavedPosts, 0, String.Empty), Token)
|
|
||||||
If Not IsSavedPosts Then
|
|
||||||
If MediaDownloadHighlights Then DownloadHighlights(Token)
|
|
||||||
If MediaDownloadChatMedia Then DownloadChatMedia(0, Token)
|
|
||||||
End If
|
|
||||||
End If
|
|
||||||
End Sub
|
End Sub
|
||||||
Private Sub OnResponseReceived(ByVal Sender As Object, ByVal e As WebDataResponse)
|
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
|
||||||
|
Try
|
||||||
|
If Not MySettings.SessionAborted Then
|
||||||
|
ValidateOFScraper()
|
||||||
|
_AbsMediaIndex = 0
|
||||||
|
FunctionErr = FunctionErrDef
|
||||||
|
If Not CCookie Is Nothing Then CCookie.Dispose()
|
||||||
|
CCookie = Responser.Cookies.Copy
|
||||||
|
Responser.Cookies.Clear()
|
||||||
|
AddHandler Responser.ResponseReceived, AddressOf Responser_ResponseReceived
|
||||||
|
UpdateCookieHeader()
|
||||||
|
DownloadTimeline(IIf(IsSavedPosts, 0, String.Empty), Token)
|
||||||
|
If Not IsSavedPosts Then
|
||||||
|
If MediaDownloadHighlights And FunctionErr = FunctionErrDef Then DownloadHighlights(Token)
|
||||||
|
If MediaDownloadChatMedia And FunctionErr = FunctionErrDef Then DownloadChatMedia(0, Token)
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Finally
|
||||||
|
Responser_ResponseReceived_RemoveHandler()
|
||||||
|
End Try
|
||||||
|
End Sub
|
||||||
|
Protected Overrides Sub Responser_ResponseReceived(ByVal Sender As Object, ByVal e As WebDataResponse)
|
||||||
If e.CookiesExists Then
|
If e.CookiesExists Then
|
||||||
CCookie.Update(e.Cookies, CookieKeeper.UpdateModes.ReplaceByNameAll,, EDP.ReturnValue)
|
CCookie.Update(e.Cookies, CookieKeeper.UpdateModes.ReplaceByNameAll,, EDP.ReturnValue)
|
||||||
UpdateCookieHeader()
|
UpdateCookieHeader()
|
||||||
@@ -91,6 +109,10 @@ Namespace API.OnlyFans
|
|||||||
Private Sub UpdateCookieHeader()
|
Private Sub UpdateCookieHeader()
|
||||||
Responser.Headers.Add("Cookie", CCookie.ToString(False))
|
Responser.Headers.Add("Cookie", CCookie.ToString(False))
|
||||||
End Sub
|
End Sub
|
||||||
|
Private Function ProcessFunctionErrComplete(ByVal ErrValue As Integer) As Boolean
|
||||||
|
If ErrValue <= 0 Or (ErrValue > 0 And ErrValue <> 2) Then FunctionErr = ErrValue
|
||||||
|
Return ErrValue <> 2
|
||||||
|
End Function
|
||||||
Friend Const A_HIGHLIGHT As String = "HL"
|
Friend Const A_HIGHLIGHT As String = "HL"
|
||||||
Friend Const A_MESSAGE As String = "MSG"
|
Friend Const A_MESSAGE As String = "MSG"
|
||||||
Private Const BaseUrlPattern As String = "https://onlyfans.com{0}"
|
Private Const BaseUrlPattern As String = "https://onlyfans.com{0}"
|
||||||
@@ -169,7 +191,7 @@ Namespace API.OnlyFans
|
|||||||
DownloadTimeline(tmpCursor, Token)
|
DownloadTimeline(tmpCursor, Token)
|
||||||
End If
|
End If
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
_complete = Not ProcessException(ex, Token, $"data downloading error [{url}]") = 2
|
_complete = ProcessFunctionErrComplete(ProcessException(ex, Token, $"data downloading error [{url}]"))
|
||||||
End Try
|
End Try
|
||||||
Loop While Not _complete
|
Loop While Not _complete
|
||||||
End Sub
|
End Sub
|
||||||
@@ -208,7 +230,7 @@ Namespace API.OnlyFans
|
|||||||
End If
|
End If
|
||||||
If hasMore Then DownloadHighlights(Cursor + 5, Token)
|
If hasMore Then DownloadHighlights(Cursor + 5, Token)
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
_complete = Not ProcessException(ex, Token, $"highlights downloading error [{url}]") = 2
|
_complete = ProcessFunctionErrComplete(ProcessException(ex, Token, $"highlights downloading error [{url}]"))
|
||||||
End Try
|
End Try
|
||||||
Loop While Not _complete
|
Loop While Not _complete
|
||||||
End Sub
|
End Sub
|
||||||
@@ -253,7 +275,7 @@ Namespace API.OnlyFans
|
|||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
_complete = Not ProcessException(ex, Token, $"highlights downloading error [{url}]") = 2
|
_complete = ProcessFunctionErrComplete(ProcessException(ex, Token, $"highlights downloading error [{url}]"))
|
||||||
End Try
|
End Try
|
||||||
Loop While Not _complete
|
Loop While Not _complete
|
||||||
End Sub
|
End Sub
|
||||||
@@ -300,15 +322,15 @@ Namespace API.OnlyFans
|
|||||||
End If
|
End If
|
||||||
If hasMore Then DownloadChatMedia(Cursor + 20, Token)
|
If hasMore Then DownloadChatMedia(Cursor + 20, Token)
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
_complete = Not ProcessException(ex, Token, $"chats downloading error [{url}]") = 2
|
_complete = ProcessFunctionErrComplete(ProcessException(ex, Token, $"chats downloading error [{url}]"))
|
||||||
End Try
|
End Try
|
||||||
Loop While Not _complete
|
Loop While Not _complete
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
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) As List(Of UserMedia)
|
Optional ByVal SpecFolder As String = Nothing, Optional ByVal PostUserID As String = Nothing) As List(Of UserMedia)
|
||||||
Dim postUrl$, 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
|
||||||
@@ -320,16 +342,27 @@ Namespace API.OnlyFans
|
|||||||
Else
|
Else
|
||||||
postUrl = m.Value({"source"}, "source").IfNullOrEmpty(m.Value("full"))
|
postUrl = m.Value({"source"}, "source").IfNullOrEmpty(m.Value("full"))
|
||||||
End If
|
End If
|
||||||
|
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" : t = UTypes.Video : ext = "mp4"
|
Case "video"
|
||||||
|
t = UTypes.Video
|
||||||
|
ext = "mp4"
|
||||||
|
If postUrl.IsEmptyString And Not IsHL Then
|
||||||
|
t = UTypes.VideoPre
|
||||||
|
_AbsMediaIndex += 1
|
||||||
|
If Not PostUserID.IsEmptyString And IsSingleObjectDownload Then _
|
||||||
|
postUrlBase = String.Format(SiteSettings.UserPostPattern, PostID, $"u{PostUserID}")
|
||||||
|
End If
|
||||||
Case Else : t = UTypes.Undefined : ext = String.Empty
|
Case Else : t = UTypes.Undefined : ext = String.Empty
|
||||||
End Select
|
End Select
|
||||||
If Not t = UTypes.Undefined And Not postUrl.IsEmptyString Then
|
If Not t = UTypes.Undefined And (Not postUrl.IsEmptyString Or t = UTypes.VideoPre) Then
|
||||||
Dim media As New UserMedia(postUrl, 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
|
||||||
}
|
}
|
||||||
|
If postUrlBase.IsEmptyString And Not IsSingleObjectDownload Then postUrlBase = GetPostUrl(Me, media)
|
||||||
|
If Not postUrlBase.IsEmptyString Then media.URL_BASE = postUrlBase
|
||||||
media.File.Extension = ext
|
media.File.Extension = ext
|
||||||
Result = True
|
Result = True
|
||||||
mList.Add(media)
|
mList.Add(media)
|
||||||
@@ -387,7 +420,7 @@ Namespace API.OnlyFans
|
|||||||
End Function
|
End Function
|
||||||
Dim mList As List(Of UserMedia)
|
Dim mList As List(Of UserMedia)
|
||||||
Dim mediaResult As Boolean
|
Dim mediaResult As Boolean
|
||||||
Dim r$, path$, postDate$
|
Dim r$, path$, postDate$, postUserID$
|
||||||
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
|
||||||
@@ -404,8 +437,9 @@ Namespace API.OnlyFans
|
|||||||
j = JsonDocument.Parse(r)
|
j = JsonDocument.Parse(r)
|
||||||
If Not j Is Nothing Then
|
If Not j Is Nothing Then
|
||||||
postDate = j.Value("postedAt")
|
postDate = j.Value("postedAt")
|
||||||
|
postUserID = j.Value({"author"}, "id")
|
||||||
mediaResult = False
|
mediaResult = False
|
||||||
mList = TryCreateMedia(j, m.Post.ID, postDate, mediaResult)
|
mList = TryCreateMedia(j, m.Post.ID, postDate, mediaResult,,, postUserID)
|
||||||
If mediaResult Then
|
If mediaResult Then
|
||||||
_TempMediaList.ListAddList(mList.ListForEachCopy(stateRefill, True), LNC)
|
_TempMediaList.ListAddList(mList.ListForEachCopy(stateRefill, True), LNC)
|
||||||
rList.Add(i)
|
rList.Add(i)
|
||||||
@@ -531,10 +565,145 @@ Namespace API.OnlyFans
|
|||||||
Return result
|
Return result
|
||||||
End Function
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
|
#Region "OFScraper support"
|
||||||
|
Private Function OFS_DownloadFile(ByVal URL As String, ByVal Token As CancellationToken) As List(Of SFile)
|
||||||
|
Try
|
||||||
|
Const requestPattern$ = """{0}"" manual --config ""{1}"" --url {2}"
|
||||||
|
Dim conf As SFile = OFS_CreateConfig()
|
||||||
|
If conf.Exists Then
|
||||||
|
Dim command$ = String.Format(requestPattern, MySettings.OFScraperPath.Value, conf, URL)
|
||||||
|
'#If DEBUG Then
|
||||||
|
'Debug.WriteLine(command)
|
||||||
|
'#End If
|
||||||
|
Using b As New TokenBatch(Token) : b.Execute(command) : End Using
|
||||||
|
Return SFile.GetFiles(conf, "*.mp4", IO.SearchOption.AllDirectories, EDP.ReturnValue)
|
||||||
|
End If
|
||||||
|
Return Nothing
|
||||||
|
Catch ex As Exception
|
||||||
|
Return ErrorsDescriber.Execute(EDP.SendToLog, ex, "OnlyFans.UserData.OFS_DownloadFile", Nothing)
|
||||||
|
End Try
|
||||||
|
End Function
|
||||||
|
Private Function OFS_CreateConfig() As SFile
|
||||||
|
Try
|
||||||
|
Const confMainPattern$ = "{0}"": ""([^""]*)"""
|
||||||
|
If OFSCache Is Nothing Then OFSCache = If(IsSingleObjectDownload, Settings.Cache.NewInstance, CreateCache())
|
||||||
|
Dim currentCache As CacheKeeper = OFSCache.NewInstance
|
||||||
|
currentCache.Validate()
|
||||||
|
Dim cacheRoot As SFile = currentCache.NewPath
|
||||||
|
cacheRoot.Exists(SFO.Path, True, EDP.ThrowException)
|
||||||
|
Dim f As SFile = $"{SettingsFolderName}\OFScraperConfigPattern.json"
|
||||||
|
Dim configText$
|
||||||
|
If Not f.Exists Then
|
||||||
|
configText = Text.Encoding.UTF8.GetString(My.Resources.OFResources.OFScraperConfigPattern)
|
||||||
|
TextSaver.SaveTextToFile(configText, f, True)
|
||||||
|
End If
|
||||||
|
If f.Exists Then
|
||||||
|
Dim replaceValue$ = String.Empty
|
||||||
|
Dim rp As RParams = RParams.DMS(String.Empty, 1, RegexReturn.Replace, RegexOptions.IgnoreCase,
|
||||||
|
CType(Function(input) replaceValue, Func(Of String, String)), String.Empty, EDP.ReturnValue)
|
||||||
|
Dim ff As SFile
|
||||||
|
configText = f.GetText
|
||||||
|
Dim updateConf As Action(Of String, String) = Sub(ByVal patternValue As String, ByVal __replaceValue As String)
|
||||||
|
rp.Pattern = String.Format(confMainPattern, patternValue)
|
||||||
|
rp.Nothing = configText
|
||||||
|
replaceValue = __replaceValue
|
||||||
|
configText = RegexReplace(configText, rp)
|
||||||
|
End Sub
|
||||||
|
If Not configText.IsEmptyString Then
|
||||||
|
updateConf("save_location", cacheRoot.PathNoSeparator.Replace("\", "/"))
|
||||||
|
If ACheck(MySettings.OFScraperMP4decrypt.Value) Then
|
||||||
|
ff = CStr(MySettings.OFScraperMP4decrypt.Value)
|
||||||
|
If ff.Exists Then updateConf("mp4decrypt", ff.ToString.Replace("\", "/"))
|
||||||
|
End If
|
||||||
|
If Settings.FfmpegFile.Exists Then updateConf("ffmpeg", Settings.FfmpegFile.File.ToString.Replace("\", "/"))
|
||||||
|
updateConf("key-mode-default", CStr(MySettings.KeyModeDefault.Value).IfNullOrEmpty(SiteSettings.KeyModeDefault_Default))
|
||||||
|
f = currentCache
|
||||||
|
f.Name = "config"
|
||||||
|
f.Extension = "json"
|
||||||
|
If TextSaver.SaveTextToFile(configText, f, True).Exists AndAlso OFS_CreateAuth(currentCache) Then Return f
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Return Nothing
|
||||||
|
Catch ex As Exception
|
||||||
|
Return ErrorsDescriber.Execute(EDP.SendToLog, ex, "OnlyFans.UserData.OFS_CreateConfig", Nothing)
|
||||||
|
End Try
|
||||||
|
End Function
|
||||||
|
Private Function OFS_CreateAuth(ByVal DestinationPath As SFile) As Boolean
|
||||||
|
Const authText$ = """user_agent"": ""{0}"",""app-token"": ""{1}"",""x-bc"": ""{2}"",""auth_id"": ""{3}"",""sess"": ""{4}"",""auth_uid_"": ""{3}"",""cookie"": ""{5}"""
|
||||||
|
Try
|
||||||
|
Dim sess$ = If(If(CCookie, Responser.Cookies).FirstOrDefault(Function(c) c.Name.StringToLower = "sess")?.Value, String.Empty)
|
||||||
|
Dim outText$ = "{""auth"":{" &
|
||||||
|
String.Format(authText,
|
||||||
|
MySettings.UserAgent.Value,
|
||||||
|
Responser.Headers.Value(SiteSettings.HeaderAppToken),
|
||||||
|
Responser.Headers.Value(SiteSettings.HeaderXBC),
|
||||||
|
MySettings.HH_USER_ID.Value,
|
||||||
|
sess,
|
||||||
|
If(CCookie, Responser.Cookies).ToString()) &
|
||||||
|
"}}"
|
||||||
|
If DestinationPath.Exists(SFO.Path, False) Then
|
||||||
|
Dim f As SFile = $"{DestinationPath.PathWithSeparator}main_profile\auth.json"
|
||||||
|
Return TextSaver.SaveTextToFile(outText, f, True).Exists
|
||||||
|
End If
|
||||||
|
Return False
|
||||||
|
Catch ex As Exception
|
||||||
|
Return ErrorsDescriber.Execute(EDP.SendToLog, ex, "OnlyFans.UserData.OFS_CreateAuth", False)
|
||||||
|
End Try
|
||||||
|
End Function
|
||||||
|
#End Region
|
||||||
#Region "DownloadContent"
|
#Region "DownloadContent"
|
||||||
|
Private OFSPostFiles As Dictionary(Of String, List(Of SFile)) = Nothing
|
||||||
Protected Overrides Sub DownloadContent(ByVal Token As CancellationToken)
|
Protected Overrides Sub DownloadContent(ByVal Token As CancellationToken)
|
||||||
DownloadContentDefault(Token)
|
DownloadContentDefault(Token)
|
||||||
|
OFSCache.DisposeIfReady
|
||||||
|
OFSPostFiles.ListClearDispose
|
||||||
End Sub
|
End Sub
|
||||||
|
Protected Overrides Function ValidateDownloadFile(ByVal URL As String, ByVal Media As UserMedia, ByRef Interrupt As Boolean) As Boolean
|
||||||
|
Return Media.Type = UTypes.VideoPre
|
||||||
|
End Function
|
||||||
|
Protected Overrides Function DownloadFile(ByVal URL As String, ByVal Media As UserMedia, ByVal DestinationFile As SFile,
|
||||||
|
ByVal Token As CancellationToken) As SFile
|
||||||
|
ValidateOFScraper()
|
||||||
|
If _OFScraperExists Then
|
||||||
|
If OFSPostFiles Is Nothing Then OFSPostFiles = New Dictionary(Of String, List(Of SFile))
|
||||||
|
If IsSingleObjectDownload Then
|
||||||
|
URL = Media.URL_BASE
|
||||||
|
Else
|
||||||
|
URL = GetPostUrl(Me, Media)
|
||||||
|
End If
|
||||||
|
If Not URL.IsEmptyString Then
|
||||||
|
Dim f As SFile = Nothing
|
||||||
|
If OFSPostFiles.Count > 0 AndAlso OFSPostFiles.ContainsKey(Media.Post.ID) AndAlso OFSPostFiles(Media.Post.ID).Count > 0 Then
|
||||||
|
f = OFSPostFiles(Media.Post.ID)(0)
|
||||||
|
OFSPostFiles(Media.Post.ID).RemoveAt(0)
|
||||||
|
Else
|
||||||
|
Dim files As List(Of SFile) = OFS_DownloadFile(URL, Token)
|
||||||
|
If files.ListExists Then
|
||||||
|
Dim ff As SFile
|
||||||
|
For i% = files.Count - 1 To 0 Step -1
|
||||||
|
ff = files(i)
|
||||||
|
DestinationFile.Name = ff.Name
|
||||||
|
DestinationFile.Extension = ff.Extension
|
||||||
|
If SFile.Move(ff, DestinationFile,,,, EDP.ThrowException) Then
|
||||||
|
files(i) = DestinationFile
|
||||||
|
Else
|
||||||
|
files.RemoveAt(i)
|
||||||
|
End If
|
||||||
|
Next
|
||||||
|
If files.Count > 0 Then
|
||||||
|
f = files(0)
|
||||||
|
files.RemoveAt(0)
|
||||||
|
If files.Count > 0 Then OFSPostFiles.Add(Media.Post.ID, files)
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Return f
|
||||||
|
End If
|
||||||
|
Return Nothing
|
||||||
|
Else
|
||||||
|
Throw New InvalidProgramException("OF-Scraper not found")
|
||||||
|
End If
|
||||||
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
#Region "DownloadingException"
|
#Region "DownloadingException"
|
||||||
Private _DownloadingException_AuthFileUpdate As Boolean = False
|
Private _DownloadingException_AuthFileUpdate As Boolean = False
|
||||||
@@ -546,20 +715,22 @@ Namespace API.OnlyFans
|
|||||||
Return 2
|
Return 2
|
||||||
Else
|
Else
|
||||||
MySettings.SessionAborted = True
|
MySettings.SessionAborted = True
|
||||||
MyMainLOG = $"{ToStringForLog()}: OnlyFans credentials expired"
|
MyMainLOG = $"{ToStringForLog()} [{CInt(Responser.StatusCode)}]: OnlyFans credentials expired"
|
||||||
Return 1
|
Return 1
|
||||||
End If
|
End If
|
||||||
ElseIf Responser.StatusCode = Net.HttpStatusCode.NotFound Then '404
|
ElseIf Responser.StatusCode = Net.HttpStatusCode.NotFound Then '404
|
||||||
UserExists = False
|
UserExists = False
|
||||||
Return 1
|
Return 3
|
||||||
ElseIf Responser.StatusCode = Net.HttpStatusCode.GatewayTimeout Or Responser.StatusCode = 429 Then '504, 429
|
ElseIf Responser.StatusCode = Net.HttpStatusCode.GatewayTimeout Or Responser.StatusCode = 429 Then '504, 429
|
||||||
If Responser.StatusCode = 429 Then MyMainLOG = $"[429] OnlyFans too many requests ({ToStringForLog()})"
|
If Responser.StatusCode = 429 Then MyMainLOG = $"[429] OnlyFans too many requests ({ToStringForLog()})"
|
||||||
MySettings.SessionAborted = True
|
MySettings.SessionAborted = True
|
||||||
Return 1
|
Return 3
|
||||||
ElseIf Responser.StatusCode = Net.HttpStatusCode.Unauthorized Then '401
|
ElseIf Responser.StatusCode = Net.HttpStatusCode.Unauthorized Then '401
|
||||||
MySettings.SessionAborted = True
|
MySettings.SessionAborted = True
|
||||||
MyMainLOG = $"{ToStringForLog()}: OnlyFans credentials expired"
|
MyMainLOG = $"{ToStringForLog()} [{CInt(Responser.StatusCode)}]: OnlyFans credentials expired"
|
||||||
Return 1
|
Return 3
|
||||||
|
ElseIf Responser.StatusCode = Net.HttpStatusCode.InternalServerError Then '500
|
||||||
|
Return 3
|
||||||
Else
|
Else
|
||||||
Return 0
|
Return 0
|
||||||
End If
|
End If
|
||||||
@@ -567,7 +738,13 @@ Namespace API.OnlyFans
|
|||||||
#End Region
|
#End Region
|
||||||
#Region "IDisposable Support"
|
#Region "IDisposable Support"
|
||||||
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
|
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
|
||||||
If Not disposedValue And disposing Then CCookie.DisposeIfReady(False) : CCookie = Nothing : HighlightsList.Clear()
|
If Not disposedValue And disposing Then
|
||||||
|
CCookie.DisposeIfReady(False)
|
||||||
|
CCookie = Nothing
|
||||||
|
HighlightsList.Clear()
|
||||||
|
OFSCache.DisposeIfReady
|
||||||
|
OFSPostFiles.ListClearDispose
|
||||||
|
End If
|
||||||
MyBase.Dispose(disposing)
|
MyBase.Dispose(disposing)
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ Namespace API.Reddit
|
|||||||
|
|
||||||
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
|
||||||
#End Region
|
#End Region
|
||||||
#Region "GetInstance"
|
#Region "GetInstance"
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ Namespace API.RedGifs
|
|||||||
TokenUpdateIntervalProvider = New TokenRefreshIntervalProvider
|
TokenUpdateIntervalProvider = New TokenRefreshIntervalProvider
|
||||||
_AllowUserAgentUpdate = False
|
_AllowUserAgentUpdate = False
|
||||||
UrlPatternUser = "https://www.redgifs.com/users/{0}/"
|
UrlPatternUser = "https://www.redgifs.com/users/{0}/"
|
||||||
UserRegex = RParams.DMS("[htps:/]{7,8}.*?redgifs.com/users/([^/]+)", 1)
|
UserRegex = RParams.DMS(String.Format(UserRegexDefaultPattern, "redgifs.com/users/"), 1)
|
||||||
ImageVideoContains = "redgifs"
|
ImageVideoContains = "redgifs"
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
|
|||||||
@@ -55,8 +55,7 @@ Namespace API.ThisVid
|
|||||||
#End Region
|
#End Region
|
||||||
#Region "UpdateCookies"
|
#Region "UpdateCookies"
|
||||||
Friend Sub UpdateCookies(ByVal Source As Responser)
|
Friend Sub UpdateCookies(ByVal Source As Responser)
|
||||||
Responser.Cookies.Clear()
|
Responser.Cookies.Update(Source.Cookies)
|
||||||
Responser.Cookies.AddRange(Source.Cookies)
|
|
||||||
Update_SaveCookiesNetscape(True)
|
Update_SaveCookiesNetscape(True)
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
|
|||||||
@@ -178,6 +178,7 @@ Namespace API.ThisVid
|
|||||||
Friend Sub New()
|
Friend Sub New()
|
||||||
UseClientTokens = True
|
UseClientTokens = True
|
||||||
SessionPosts = New List(Of String)
|
SessionPosts = New List(Of String)
|
||||||
|
_ResponserAutoUpdateCookies = True
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Validation"
|
#Region "Validation"
|
||||||
@@ -225,31 +226,34 @@ Namespace API.ThisVid
|
|||||||
Private AddedCount As Integer = 0
|
Private AddedCount As Integer = 0
|
||||||
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)
|
||||||
SessionPosts.Clear()
|
Try
|
||||||
AddedCount = 0
|
SessionPosts.Clear()
|
||||||
_PageVideosRepeat = 0
|
AddedCount = 0
|
||||||
SessionPosts.Clear()
|
_PageVideosRepeat = 0
|
||||||
Responser.Cookies.ChangedAllowInternalDrop = False
|
SessionPosts.Clear()
|
||||||
Responser.Cookies.Changed = False
|
Responser.Cookies.ChangedAllowInternalDrop = False
|
||||||
If ID.IsEmptyString Then ID = Name
|
Responser.Cookies.Changed = False
|
||||||
If Not IsUser OrElse IsValid() Then
|
If ID.IsEmptyString Then ID = Name
|
||||||
If IsSavedPosts Then
|
If Not IsUser OrElse IsValid() Then
|
||||||
DownloadData(1, 0, Token)
|
If IsSavedPosts Then
|
||||||
DownloadData_Images(Token)
|
|
||||||
Else
|
|
||||||
If IsUser Then
|
|
||||||
If DownloadVideos Then
|
|
||||||
If DownloadPublic Then DownloadData(1, 0, Token)
|
|
||||||
If DownloadPrivate Then DownloadData(1, 1, Token)
|
|
||||||
If DownloadFavourite Then DownloadData(1, 2, Token)
|
|
||||||
End If
|
|
||||||
If DownloadImages And Not IsSubscription Then DownloadData_Images(Token)
|
|
||||||
Else
|
|
||||||
DownloadData(1, 0, Token)
|
DownloadData(1, 0, Token)
|
||||||
|
DownloadData_Images(Token)
|
||||||
|
Else
|
||||||
|
If IsUser Then
|
||||||
|
If DownloadVideos Then
|
||||||
|
If DownloadPublic Then DownloadData(1, 0, Token)
|
||||||
|
If DownloadPrivate Then DownloadData(1, 1, Token)
|
||||||
|
If DownloadFavourite Then DownloadData(1, 2, Token)
|
||||||
|
End If
|
||||||
|
If DownloadImages And Not IsSubscription Then DownloadData_Images(Token)
|
||||||
|
Else
|
||||||
|
DownloadData(1, 0, Token)
|
||||||
|
End If
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
End If
|
Finally
|
||||||
If Responser.Cookies.Changed Then MySettings.UpdateCookies(Responser) : Responser.Cookies.Changed = False
|
If Responser.Cookies.Changed Then MySettings.UpdateCookies(Responser) : Responser.Cookies.Changed = False
|
||||||
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
Friend Function GetNonUserUrl(ByVal Page As Integer) As String
|
Friend Function GetNonUserUrl(ByVal Page As Integer) As String
|
||||||
Dim url$ = String.Empty
|
Dim url$ = String.Empty
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ Namespace API.ThreadsNet
|
|||||||
#Region "Declarations"
|
#Region "Declarations"
|
||||||
#Region "Authorization"
|
#Region "Authorization"
|
||||||
<PClonable(Clone:=False)> Protected ReadOnly __HH_CSRF_TOKEN As PropertyValue
|
<PClonable(Clone:=False)> Protected ReadOnly __HH_CSRF_TOKEN As PropertyValue
|
||||||
<PropertyOption(ControlText:="x-csrftoken", AllowNull:=False, IsAuth:=True), ControlNumber(0)>
|
<PropertyOption(ControlText:="x-csrftoken", AllowNull:=True, IsAuth:=True), ControlNumber(0)>
|
||||||
Friend Overridable ReadOnly Property HH_CSRF_TOKEN As PropertyValue
|
Friend Overridable ReadOnly Property HH_CSRF_TOKEN As PropertyValue
|
||||||
Get
|
Get
|
||||||
Return __HH_CSRF_TOKEN
|
Return __HH_CSRF_TOKEN
|
||||||
@@ -126,7 +126,7 @@ Namespace API.ThreadsNet
|
|||||||
HH_USER_AGENT = New PropertyValue(useragent, GetType(String), Sub(v) ChangeResponserFields(NameOf(HH_USER_AGENT), v))
|
HH_USER_AGENT = New PropertyValue(useragent, GetType(String), Sub(v) ChangeResponserFields(NameOf(HH_USER_AGENT), v))
|
||||||
|
|
||||||
UrlPatternUser = "https://www.threads.net/@{0}"
|
UrlPatternUser = "https://www.threads.net/@{0}"
|
||||||
UserRegex = RParams.DMS("threads.net/@([^/\?&]+)", 1)
|
UserRegex = RParams.DMS(String.Format(UserRegexDefaultPattern, "threads.net/@"), 1)
|
||||||
ImageVideoContains = "threads.net"
|
ImageVideoContains = "threads.net"
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
@@ -165,6 +165,15 @@ Namespace API.ThreadsNet
|
|||||||
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
|
||||||
End Function
|
End Function
|
||||||
|
#End Region
|
||||||
|
#Region "Update"
|
||||||
|
Friend Overrides Sub Update()
|
||||||
|
If _SiteEditorFormOpened And Responser.CookiesExists Then
|
||||||
|
Dim csrf$ = If(Responser.Cookies.FirstOrDefault(Function(c) c.Name.StringToLower = IG.Header_CSRF_TOKEN_COOKIE)?.Value, String.Empty)
|
||||||
|
If Not csrf.IsEmptyString Then HH_CSRF_TOKEN.Value = csrf
|
||||||
|
End If
|
||||||
|
MyBase.Update()
|
||||||
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
End Class
|
End Class
|
||||||
End Namespace
|
End Namespace
|
||||||
@@ -18,14 +18,11 @@ Imports IGS = SCrawler.API.Instagram.SiteSettings
|
|||||||
Namespace API.ThreadsNet
|
Namespace API.ThreadsNet
|
||||||
Friend Class UserData : Inherits Instagram.UserData
|
Friend Class UserData : Inherits Instagram.UserData
|
||||||
#Region "Declarations"
|
#Region "Declarations"
|
||||||
Friend Const Header_FB_LSD As String = "x-fb-lsd"
|
|
||||||
Private ReadOnly Property MySettings As SiteSettings
|
Private ReadOnly Property MySettings As SiteSettings
|
||||||
Get
|
Get
|
||||||
Return HOST.Source
|
Return HOST.Source
|
||||||
End Get
|
End Get
|
||||||
End Property
|
End Property
|
||||||
Private ReadOnly ObtainMedia_SizeFuncPic_RegexP As RParams = RParams.DMS("_p(\d+)x(\d+)", 1, EDP.ReturnValue)
|
|
||||||
Private ReadOnly ObtainMedia_SizeFuncPic_RegexS As RParams = RParams.DMS("_s(\d+)x(\d+)", 1, EDP.ReturnValue)
|
|
||||||
Private ReadOnly DefaultParser_ElemNode_Default() As Object = {"node", "thread_items", 0, "post"}
|
Private ReadOnly DefaultParser_ElemNode_Default() As Object = {"node", "thread_items", 0, "post"}
|
||||||
Private OPT_LSD As String = String.Empty
|
Private OPT_LSD As String = String.Empty
|
||||||
Private OPT_FB_DTSG As String = String.Empty
|
Private OPT_FB_DTSG As String = String.Empty
|
||||||
@@ -48,23 +45,12 @@ Namespace API.ThreadsNet
|
|||||||
#End Region
|
#End Region
|
||||||
#Region "Initializer"
|
#Region "Initializer"
|
||||||
Friend Sub New()
|
Friend Sub New()
|
||||||
ObtainMedia_SizeFuncPic = Function(ByVal ss As EContainer) As Sizes
|
ObtainMedia_SetReelsFunc()
|
||||||
If ss.Value("url").IsEmptyString Then
|
|
||||||
Return New Sizes("----", "")
|
|
||||||
ElseIf Not ss.Value("width").IsEmptyString Then
|
|
||||||
Return New Sizes(ss.Value("height").IfNullOrEmpty(ss.Value("width")), ss.Value("url"))
|
|
||||||
Else
|
|
||||||
Dim rval$ = RegexReplace(ss.Value("url"), ObtainMedia_SizeFuncPic_RegexP)
|
|
||||||
If Not rval.IsEmptyString Then Return New Sizes(rval, ss.Value("url"))
|
|
||||||
rval = RegexReplace(ss.Value("url"), ObtainMedia_SizeFuncPic_RegexS)
|
|
||||||
If Not rval.IsEmptyString Then Return New Sizes(AConvert(Of Integer)(rval, 1) * -1, ss.Value("url"))
|
|
||||||
Return New Sizes(10000, ss.Value("url"))
|
|
||||||
End If
|
|
||||||
End Function
|
|
||||||
ObtainMedia_SizeFuncVid = Function(ss) If(ss.Value("url").IsEmptyString, New Sizes("----", ""), New Sizes(10000, ss.Value("url")))
|
|
||||||
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.net/@{NameTrue}/post/{post.Code}"
|
||||||
|
_ResponserAutoUpdateCookies = True
|
||||||
|
_ResponserAddResponseReceivedHandler = True
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Download functions"
|
#Region "Download functions"
|
||||||
@@ -72,7 +58,6 @@ Namespace API.ThreadsNet
|
|||||||
Dim errorFound As Boolean = False
|
Dim errorFound As Boolean = False
|
||||||
Try
|
Try
|
||||||
Responser.Method = "POST"
|
Responser.Method = "POST"
|
||||||
AddHandler Responser.ResponseReceived, AddressOf Responser_ResponseReceived
|
|
||||||
LoadSavePostsKV(True)
|
LoadSavePostsKV(True)
|
||||||
OPT_LSD = String.Empty
|
OPT_LSD = String.Empty
|
||||||
OPT_FB_DTSG = String.Empty
|
OPT_FB_DTSG = String.Empty
|
||||||
@@ -170,11 +155,11 @@ Namespace API.ThreadsNet
|
|||||||
Responser.Method = "GET"
|
Responser.Method = "GET"
|
||||||
Responser.Referer = URL
|
Responser.Referer = URL
|
||||||
Responser.Headers.Remove(Header_FB_LSD)
|
Responser.Headers.Remove(Header_FB_LSD)
|
||||||
Dim r$ = Responser.GetResponse(URL,, EDP.SendToLog + EDP.ThrowException)
|
Dim r$ = Responser.GetResponse(URL,, EDP.ThrowException)
|
||||||
Dim rr As RParams
|
Dim rr As RParams
|
||||||
Dim tt$, ttVal$
|
Dim tt$, ttVal$
|
||||||
If Not r.IsEmptyString Then
|
If Not r.IsEmptyString Then
|
||||||
rr = RParams.DM("\[\],{""token"":""(.*?)""},\d+\]", 0, RegexReturn.List, EDP.ReturnValue)
|
rr = RParams.DM(Instagram.PageTokenRegexPatternDefault, 0, RegexReturn.List, EDP.ReturnValue)
|
||||||
Dim tokens As List(Of String) = RegexReplace(r, rr)
|
Dim tokens As List(Of String) = RegexReplace(r, rr)
|
||||||
If tokens.ListExists Then
|
If tokens.ListExists Then
|
||||||
With rr
|
With rr
|
||||||
@@ -205,7 +190,12 @@ Namespace API.ThreadsNet
|
|||||||
If OPT_FB_DTSG.IsEmptyString Then notFound.StringAppend(Header_FB_LSD)
|
If OPT_FB_DTSG.IsEmptyString Then notFound.StringAppend(Header_FB_LSD)
|
||||||
If OPT_LSD.IsEmptyString Then notFound.StringAppend("lsd")
|
If OPT_LSD.IsEmptyString Then notFound.StringAppend("lsd")
|
||||||
If ID.IsEmptyString Then notFound.StringAppend("User ID")
|
If ID.IsEmptyString Then notFound.StringAppend("User ID")
|
||||||
LogError(ex, $"failed to update some{IIf(notFound.IsEmptyString, String.Empty, $" ({notFound})")} credentials", e)
|
Dim eex As New ErrorsDescriberException($"{ToStringForLog()}: failed to update some{IIf(notFound.IsEmptyString, String.Empty, $" ({notFound})")} credentials",,, ex) With {
|
||||||
|
.ReplaceMainMessage = True,
|
||||||
|
.SendToLogOnlyMessage = Responser.StatusCode = Net.HttpStatusCode.InternalServerError And Responser.Status = Net.WebExceptionStatus.ProtocolError
|
||||||
|
}
|
||||||
|
'LogError(ex, $"failed to update some{IIf(notFound.IsEmptyString, String.Empty, $" ({notFound})")} credentials", e)
|
||||||
|
LogError(eex, String.Empty, e)
|
||||||
Return False
|
Return False
|
||||||
End Try
|
End Try
|
||||||
End Function
|
End Function
|
||||||
|
|||||||
@@ -22,6 +22,10 @@ Namespace API.TikTok
|
|||||||
Friend ReadOnly Property TitleUseNativeSTD As PropertyValue
|
Friend ReadOnly Property TitleUseNativeSTD As PropertyValue
|
||||||
<PropertyOption(ControlText:="Add video ID to video title"), PXML, PClonable>
|
<PropertyOption(ControlText:="Add video ID to video title"), PXML, PClonable>
|
||||||
Friend ReadOnly Property TitleAddVideoID As PropertyValue
|
Friend ReadOnly Property TitleAddVideoID As PropertyValue
|
||||||
|
<PropertyOption(ControlText:="Use regex to clean video title"), PXML, PClonable>
|
||||||
|
Friend ReadOnly Property TitleUseRegexForTitle As PropertyValue
|
||||||
|
<PropertyOption(ControlText:="Title regex", ControlToolTip:="Regex to clean video title"), PXML, PClonable>
|
||||||
|
Friend ReadOnly Property TitleUseRegexForTitle_Value As PropertyValue
|
||||||
<PropertyOption(ControlText:="Use video date as file date",
|
<PropertyOption(ControlText:="Use video date as file date",
|
||||||
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 UseParsedVideoDate As PropertyValue
|
Friend ReadOnly Property UseParsedVideoDate As PropertyValue
|
||||||
@@ -31,10 +35,12 @@ Namespace API.TikTok
|
|||||||
TitleUseNative = New PropertyValue(True)
|
TitleUseNative = New PropertyValue(True)
|
||||||
TitleUseNativeSTD = New PropertyValue(False)
|
TitleUseNativeSTD = New PropertyValue(False)
|
||||||
TitleAddVideoID = New PropertyValue(True)
|
TitleAddVideoID = New PropertyValue(True)
|
||||||
|
TitleUseRegexForTitle = New PropertyValue(False)
|
||||||
|
TitleUseRegexForTitle_Value = New PropertyValue(String.Empty, GetType(String))
|
||||||
UseParsedVideoDate = New PropertyValue(True)
|
UseParsedVideoDate = New PropertyValue(True)
|
||||||
UseNetscapeCookies = True
|
UseNetscapeCookies = True
|
||||||
UrlPatternUser = "https://www.tiktok.com/@{0}/"
|
UrlPatternUser = "https://www.tiktok.com/@{0}/"
|
||||||
UserRegex = RParams.DMS("[htps:/]{7,8}.*?tiktok.com/@([^/]+)", 1)
|
UserRegex = RParams.DMS(String.Format(UserRegexDefaultPattern, "tiktok.com/@"), 1)
|
||||||
ImageVideoContains = "tiktok.com"
|
ImageVideoContains = "tiktok.com"
|
||||||
End Sub
|
End Sub
|
||||||
Friend Overrides Function GetInstance(ByVal What As ISiteSettings.Download) As IPluginContentProvider
|
Friend Overrides Function GetInstance(ByVal What As ISiteSettings.Download) As IPluginContentProvider
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ Namespace API.TikTok
|
|||||||
Private Const Name_TitleUseNative As String = "TitleUseNative"
|
Private Const Name_TitleUseNative As String = "TitleUseNative"
|
||||||
Private Const Name_TitleAddVideoID As String = "TitleAddVideoID"
|
Private Const Name_TitleAddVideoID As String = "TitleAddVideoID"
|
||||||
Private Const Name_LastDownloadDate As String = "LastDownloadDate"
|
Private Const Name_LastDownloadDate As String = "LastDownloadDate"
|
||||||
|
Private Const Name_TitleUseRegexForTitle As String = "TitleUseRegexForTitle"
|
||||||
|
Private Const Name_TitleUseRegexForTitle_Value As String = "TitleUseRegexForTitle_Value"
|
||||||
|
Private Const Name_TitleUseGlobalRegexOptions As String = "TitleUseGlobalRegexOptions"
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Declarations"
|
#Region "Declarations"
|
||||||
Private ReadOnly Property MySettings As SiteSettings
|
Private ReadOnly Property MySettings As SiteSettings
|
||||||
@@ -27,26 +30,37 @@ Namespace API.TikTok
|
|||||||
Return HOST.Source
|
Return HOST.Source
|
||||||
End Get
|
End Get
|
||||||
End Property
|
End Property
|
||||||
|
Private UserCache As CacheKeeper = Nothing
|
||||||
Private ReadOnly Property RootCacheTikTok As ICacheKeeper
|
Private ReadOnly Property RootCacheTikTok As ICacheKeeper
|
||||||
Get
|
Get
|
||||||
With Settings.Cache
|
If Not UserCache Is Nothing AndAlso Not UserCache.Disposed Then
|
||||||
Dim f As SFile = $"{Settings.Cache.RootDirectory.PathWithSeparator}TikTokCache\"
|
With DirectCast(UserCache.NewInstance(Of BatchFileExchanger), BatchFileExchanger)
|
||||||
If .ContainsFolder(f) Then
|
.Validate()
|
||||||
Return .GetInstance(f)
|
Return .Self
|
||||||
Else
|
End With
|
||||||
f.Exists(SFO.Path, True)
|
Else
|
||||||
With .NewInstance(Of BatchFileExchanger)(f)
|
With Settings.Cache
|
||||||
.DeleteCacheOnDispose = False
|
Dim f As SFile = $"{Settings.Cache.RootDirectory.PathWithSeparator}TikTokCache\"
|
||||||
.DeleteRootOnDispose = False
|
If .ContainsFolder(f) Then
|
||||||
Return .Self
|
Return .GetInstance(f)
|
||||||
End With
|
Else
|
||||||
End If
|
f.Exists(SFO.Path, True)
|
||||||
End With
|
With .NewInstance(Of BatchFileExchanger)(f)
|
||||||
|
.DeleteCacheOnDispose = False
|
||||||
|
.DeleteRootOnDispose = False
|
||||||
|
Return .Self
|
||||||
|
End With
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
End If
|
||||||
End Get
|
End Get
|
||||||
End Property
|
End Property
|
||||||
Friend Property RemoveTagsFromTitle As Boolean = False
|
Friend Property RemoveTagsFromTitle As Boolean = False
|
||||||
Friend Property TitleUseNative As Boolean = True
|
Friend Property TitleUseNative As Boolean = True
|
||||||
Friend Property TitleAddVideoID As Boolean = True
|
Friend Property TitleAddVideoID As Boolean = True
|
||||||
|
Friend Property TitleUseRegexForTitle As Boolean = False
|
||||||
|
Friend Property TitleUseRegexForTitle_Value As String = String.Empty
|
||||||
|
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 _TrueName As String = String.Empty
|
||||||
Friend Property TrueName As String
|
Friend Property TrueName As String
|
||||||
@@ -68,6 +82,9 @@ Namespace API.TikTok
|
|||||||
RemoveTagsFromTitle = .RemoveTagsFromTitle
|
RemoveTagsFromTitle = .RemoveTagsFromTitle
|
||||||
TitleUseNative = .TitleUseNative
|
TitleUseNative = .TitleUseNative
|
||||||
TitleAddVideoID = .TitleAddVideoID
|
TitleAddVideoID = .TitleAddVideoID
|
||||||
|
TitleUseRegexForTitle = .TitleUseRegexForTitle
|
||||||
|
TitleUseRegexForTitle_Value = .TitleUseRegexForTitle_Value
|
||||||
|
TitleUseGlobalRegexOptions = .TitleUseGlobalRegexOptions
|
||||||
End With
|
End With
|
||||||
End If
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
@@ -82,12 +99,18 @@ Namespace API.TikTok
|
|||||||
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)
|
_TrueName = .Value(Name_TrueName)
|
||||||
|
TitleUseRegexForTitle = .Value(Name_TitleUseRegexForTitle).FromXML(Of Boolean)(False)
|
||||||
|
TitleUseRegexForTitle_Value = .Value(Name_TitleUseRegexForTitle_Value)
|
||||||
|
TitleUseGlobalRegexOptions = .Value(Name_TitleUseGlobalRegexOptions).FromXML(Of Boolean)(True)
|
||||||
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_TrueName, _TrueName)
|
||||||
|
.Add(Name_TitleUseRegexForTitle, TitleUseRegexForTitle.BoolToInteger)
|
||||||
|
.Add(Name_TitleUseRegexForTitle_Value, TitleUseRegexForTitle_Value)
|
||||||
|
.Add(Name_TitleUseGlobalRegexOptions, TitleUseGlobalRegexOptions.BoolToInteger)
|
||||||
End If
|
End If
|
||||||
End With
|
End With
|
||||||
End Sub
|
End Sub
|
||||||
@@ -99,110 +122,146 @@ Namespace API.TikTok
|
|||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Download functions"
|
#Region "Download functions"
|
||||||
|
Private Function GetTitleRegex() As RParams
|
||||||
|
Dim titleRegex As RParams = Nothing
|
||||||
|
If TitleUseGlobalRegexOptions Then
|
||||||
|
If CBool(MySettings.TitleUseRegexForTitle.Value) AndAlso Not CStr(MySettings.TitleUseRegexForTitle_Value.Value).IsEmptyString Then _
|
||||||
|
titleRegex = RParams.DM(MySettings.TitleUseRegexForTitle_Value.Value, 0, RegexReturn.List, EDP.ReturnValue)
|
||||||
|
ElseIf TitleUseRegexForTitle And Not TitleUseRegexForTitle_Value.IsEmptyString Then
|
||||||
|
titleRegex = RParams.DM(TitleUseRegexForTitle_Value, 0, RegexReturn.List, EDP.ReturnValue)
|
||||||
|
End If
|
||||||
|
If Not titleRegex Is Nothing Then
|
||||||
|
titleRegex.NothingExists = True
|
||||||
|
titleRegex.Nothing = New List(Of String)
|
||||||
|
titleRegex.Converter = Function(input) input.StringTrim
|
||||||
|
End If
|
||||||
|
Return titleRegex
|
||||||
|
End Function
|
||||||
|
Private Function ChangeTitleRegex(ByVal Title As String, ByVal Regex As RParams) As String
|
||||||
|
Try
|
||||||
|
If Not Regex Is Nothing Then
|
||||||
|
With DirectCast(RegexReplace(Title, Regex), List(Of String))
|
||||||
|
If .ListExists Then
|
||||||
|
Dim newTitle$ = .ListToString(String.Empty, EDP.ReturnValue).StringTrim
|
||||||
|
If Not newTitle.IsEmptyString Then Return newTitle
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
End If
|
||||||
|
Catch ex As Exception
|
||||||
|
End Try
|
||||||
|
Return Title
|
||||||
|
End Function
|
||||||
|
Friend Overrides Sub DownloadData(ByVal Token As CancellationToken)
|
||||||
|
MyBase.DownloadData(Token)
|
||||||
|
UserCache.DisposeIfReady(False)
|
||||||
|
UserCache = Nothing
|
||||||
|
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/@{TrueName}"
|
||||||
Using cache As CacheKeeper = CreateCache()
|
UserCache = CreateCache()
|
||||||
Try
|
Try
|
||||||
Dim postID$, title$, postUrl$, newName$
|
Dim postID$, title$, postUrl$, newName$
|
||||||
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()
|
||||||
|
|
||||||
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)
|
||||||
If .ListExists Then dateAfterC = .Min
|
If .ListExists Then dateAfterC = .Min
|
||||||
End With
|
|
||||||
End If
|
|
||||||
|
|
||||||
With {CStr(AConvert(Of String)(dateAfter, SimpleDateConverter, String.Empty)).FromXML(Of Integer)(-1),
|
|
||||||
CStr(AConvert(Of String)(dateAfterC, SimpleDateConverter, String.Empty)).FromXML(Of Integer)(-1)}.ListWithRemove(Function(d) d = -1)
|
|
||||||
If .ListExists Then dateAfter = AConvert(Of Date)(CStr(.Min), SimpleDateConverter, Nothing)
|
|
||||||
End With
|
End With
|
||||||
|
End If
|
||||||
|
|
||||||
If LastDownloadDate.HasValue Then
|
With {CStr(AConvert(Of String)(dateAfter, SimpleDateConverter, String.Empty)).FromXML(Of Integer)(-1),
|
||||||
If Not DownloadDateTo.HasValue And Not DownloadDateFrom.HasValue Then
|
CStr(AConvert(Of String)(dateAfterC, SimpleDateConverter, String.Empty)).FromXML(Of Integer)(-1)}.ListWithRemove(Function(d) d = -1)
|
||||||
If LastDownloadDate.Value.AddDays(1) <= Now Then
|
If .ListExists Then dateAfter = AConvert(Of Date)(CStr(.Min), SimpleDateConverter, Nothing)
|
||||||
dateAfter = LastDownloadDate.Value
|
End With
|
||||||
Else
|
|
||||||
dateAfter = LastDownloadDate.Value.AddDays(-1)
|
If LastDownloadDate.HasValue Then
|
||||||
End If
|
If Not DownloadDateTo.HasValue And Not DownloadDateFrom.HasValue Then
|
||||||
dateBefore = Nothing
|
If LastDownloadDate.Value.AddDays(1) <= Now Then
|
||||||
ElseIf dateAfter.HasValue And Not DownloadDateFrom.HasValue Then
|
dateAfter = LastDownloadDate.Value
|
||||||
If (LastDownloadDate.Value - dateAfter.Value).TotalDays > 1 Then dateAfter = dateAfter.Value.AddDays(1)
|
Else
|
||||||
|
dateAfter = LastDownloadDate.Value.AddDays(-1)
|
||||||
End If
|
End If
|
||||||
|
dateBefore = Nothing
|
||||||
|
ElseIf dateAfter.HasValue And Not DownloadDateFrom.HasValue Then
|
||||||
|
If (LastDownloadDate.Value - dateAfter.Value).TotalDays > 1 Then dateAfter = dateAfter.Value.AddDays(1)
|
||||||
End If
|
End If
|
||||||
|
End If
|
||||||
|
|
||||||
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(cache)
|
b.ChangeDirectory(UserCache)
|
||||||
b.Encoding = BatchExecutor.UnicodeEncoding
|
b.Encoding = BatchExecutor.UnicodeEncoding
|
||||||
b.Execute(CreateYTCommand(cache.RootDirectory, URL, False, dateBefore, dateAfter))
|
b.Execute(CreateYTCommand(UserCache.RootDirectory, URL, False, dateBefore, dateAfter))
|
||||||
End Using
|
End Using
|
||||||
|
|
||||||
ThrowAny(Token)
|
ThrowAny(Token)
|
||||||
|
|
||||||
Dim files As List(Of SFile) = SFile.GetFiles(cache, "*.json",, EDP.ReturnValue)
|
Dim files As List(Of SFile) = SFile.GetFiles(UserCache, "*.json",, EDP.ReturnValue)
|
||||||
If files.ListExists Then
|
If files.ListExists Then
|
||||||
Dim j As EContainer
|
Dim j As EContainer
|
||||||
For Each file As SFile In files
|
For Each file As SFile In files
|
||||||
j = JsonDocument.Parse(file.GetText, EDP.ReturnValue)
|
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
|
If Not ID.IsEmptyString Then _ForceSaveUserInfo = True
|
||||||
End If
|
|
||||||
newName = j.Value("uploader")
|
|
||||||
If Not newName.IsEmptyString Then
|
|
||||||
If Not _TrueName = newName Then _ForceSaveUserInfo = True
|
|
||||||
_TrueName = newName
|
|
||||||
End If
|
|
||||||
newName = j.Value("creator")
|
|
||||||
If Not newName.IsEmptyString Then UserSiteName = newName
|
|
||||||
End If
|
End If
|
||||||
postID = j.Value("id")
|
newName = j.Value("uploader")
|
||||||
If Not _TempPostsList.Contains(postID) Then
|
If Not newName.IsEmptyString Then
|
||||||
_TempPostsList.Add(postID)
|
If Not _TrueName = newName Then _ForceSaveUserInfo = True
|
||||||
Else
|
_TrueName = newName
|
||||||
Exit Sub
|
|
||||||
End If
|
End If
|
||||||
title = j.Value("title").StringRemoveWinForbiddenSymbols
|
newName = j.Value("creator")
|
||||||
If title.IsEmptyString Or Not TitleUseNative Then
|
If Not newName.IsEmptyString Then UserSiteName = newName
|
||||||
title = postID
|
|
||||||
Else
|
|
||||||
If RemoveTagsFromTitle Then title = RegexReplace(title, RegexTagsReplacer)
|
|
||||||
title = title.StringTrim
|
|
||||||
If title.IsEmptyString Then
|
|
||||||
title = postID
|
|
||||||
ElseIf TitleAddVideoID Then
|
|
||||||
title &= $" ({postID})"
|
|
||||||
End If
|
|
||||||
End If
|
|
||||||
postDate = AConvert(Of Date)(j.Value("timestamp"), UnixDate32Provider, Nothing)
|
|
||||||
If Not postDate.HasValue Then postDate = AConvert(Of Date)(j.Value("upload_date"), SimpleDateConverter, Nothing)
|
|
||||||
Select Case CheckDatesLimit(postDate, SimpleDateConverter)
|
|
||||||
Case DateResult.Skip : Continue For
|
|
||||||
Case DateResult.Exit : Exit Sub
|
|
||||||
End Select
|
|
||||||
|
|
||||||
postUrl = j.Value("webpage_url")
|
|
||||||
If postUrl.IsEmptyString Then postUrl = $"https://www.tiktok.com/@{Name}/video/{postID}"
|
|
||||||
_TempMediaList.Add(New UserMedia(postUrl, UserMedia.Types.Video) With {
|
|
||||||
.File = $"{title}.mp4", .Post = New UserPost(postID, postDate)})
|
|
||||||
End If
|
End If
|
||||||
j.Dispose()
|
postID = j.Value("id")
|
||||||
|
If Not _TempPostsList.Contains(postID) Then
|
||||||
|
_TempPostsList.Add(postID)
|
||||||
|
Else
|
||||||
|
Exit Sub
|
||||||
|
End If
|
||||||
|
title = j.Value("title").StringRemoveWinForbiddenSymbols
|
||||||
|
If Not title.IsEmptyString Then title = Left(title, 150)
|
||||||
|
If title.IsEmptyString Or Not TitleUseNative Then
|
||||||
|
title = postID
|
||||||
|
Else
|
||||||
|
If RemoveTagsFromTitle Then title = RegexReplace(title, RegexTagsReplacer)
|
||||||
|
title = title.StringTrim
|
||||||
|
If title.IsEmptyString Then
|
||||||
|
title = postID
|
||||||
|
ElseIf TitleAddVideoID Then
|
||||||
|
title &= $" ({postID})"
|
||||||
|
End If
|
||||||
|
title = ChangeTitleRegex(title, titleRegex)
|
||||||
|
End If
|
||||||
|
postDate = AConvert(Of Date)(j.Value("timestamp"), UnixDate32Provider, Nothing)
|
||||||
|
If Not postDate.HasValue Then postDate = AConvert(Of Date)(j.Value("upload_date"), SimpleDateConverter, Nothing)
|
||||||
|
Select Case CheckDatesLimit(postDate, SimpleDateConverter)
|
||||||
|
Case DateResult.Skip : Continue For
|
||||||
|
Case DateResult.Exit : Exit Sub
|
||||||
|
End Select
|
||||||
|
|
||||||
|
postUrl = j.Value("webpage_url")
|
||||||
|
If postUrl.IsEmptyString Then postUrl = $"https://www.tiktok.com/@{Name}/video/{postID}"
|
||||||
|
_TempMediaList.Add(New UserMedia(postUrl, UserMedia.Types.Video) With {
|
||||||
|
.File = $"{title}.mp4", .Post = New UserPost(postID, postDate)})
|
||||||
End If
|
End If
|
||||||
Next
|
j.Dispose()
|
||||||
End If
|
End If
|
||||||
If _TempMediaList.Count > 0 Then LastDownloadDate = Now
|
Next
|
||||||
Catch ex As Exception
|
End If
|
||||||
ProcessException(ex, Token, $"data downloading error [{URL}]")
|
If _TempMediaList.Count > 0 Then LastDownloadDate = Now
|
||||||
End Try
|
Catch ex As Exception
|
||||||
End Using
|
ProcessException(ex, Token, $"data downloading error [{URL}]")
|
||||||
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "ReparseMissing"
|
#Region "ReparseMissing"
|
||||||
@@ -262,7 +321,7 @@ Namespace API.TikTok
|
|||||||
b.Encoding = BatchExecutor.UnicodeEncoding
|
b.Encoding = BatchExecutor.UnicodeEncoding
|
||||||
b.Execute(CreateYTCommand(DestinationFile, URL, True))
|
b.Execute(CreateYTCommand(DestinationFile, URL, True))
|
||||||
End Using
|
End Using
|
||||||
Return DestinationFile
|
If DestinationFile.Exists Then Return DestinationFile Else Return Nothing
|
||||||
End Function
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
#Region "DownloadSingleObject"
|
#Region "DownloadSingleObject"
|
||||||
@@ -292,6 +351,7 @@ Namespace API.TikTok
|
|||||||
f = f.StringTrim
|
f = f.StringTrim
|
||||||
If Not f.IsEmptyString Then
|
If Not f.IsEmptyString Then
|
||||||
If CBool(MySettings.TitleAddVideoID.Value) Then f &= $" ({m.File.Name})"
|
If CBool(MySettings.TitleAddVideoID.Value) Then f &= $" ({m.File.Name})"
|
||||||
|
f = ChangeTitleRegex(f, GetTitleRegex)
|
||||||
m.File.Name = f
|
m.File.Name = f
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
@@ -303,6 +363,15 @@ Namespace API.TikTok
|
|||||||
Optional ByVal EObj As Object = Nothing) As Integer
|
Optional ByVal EObj As Object = Nothing) As Integer
|
||||||
Return 0
|
Return 0
|
||||||
End Function
|
End Function
|
||||||
|
#End Region
|
||||||
|
#Region "IDisposable Support"
|
||||||
|
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
|
||||||
|
If Not disposedValue And disposing Then
|
||||||
|
UserCache.DisposeIfReady(False)
|
||||||
|
UserCache = Nothing
|
||||||
|
End If
|
||||||
|
MyBase.Dispose(disposing)
|
||||||
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
End Class
|
End Class
|
||||||
End Namespace
|
End Namespace
|
||||||
@@ -15,18 +15,29 @@ Namespace API.TikTok
|
|||||||
Friend Property TitleUseNative As Boolean
|
Friend Property TitleUseNative As Boolean
|
||||||
<PSetting(NameOf(SiteSettings.TitleAddVideoID), NameOf(MySettings))>
|
<PSetting(NameOf(SiteSettings.TitleAddVideoID), NameOf(MySettings))>
|
||||||
Friend Property TitleAddVideoID As Boolean
|
Friend Property TitleAddVideoID As Boolean
|
||||||
|
<PSetting(NameOf(SiteSettings.TitleUseRegexForTitle), NameOf(MySettings))>
|
||||||
|
Friend Property TitleUseRegexForTitle As Boolean
|
||||||
|
<PSetting(NameOf(SiteSettings.TitleUseRegexForTitle_Value), NameOf(MySettings))>
|
||||||
|
Friend Property TitleUseRegexForTitle_Value As String
|
||||||
|
<PSetting(Caption:="Use global regex", ToolTip:="Use the global regex from the site settings to clean the video title")>
|
||||||
|
Friend Property TitleUseGlobalRegexOptions As Boolean = True
|
||||||
Private ReadOnly MySettings As SiteSettings
|
Private ReadOnly MySettings As SiteSettings
|
||||||
Friend Sub New(ByVal u As UserData)
|
Friend Sub New(ByVal u As UserData)
|
||||||
MySettings = u.HOST.Source
|
MySettings = u.HOST.Source
|
||||||
RemoveTagsFromTitle = u.RemoveTagsFromTitle
|
RemoveTagsFromTitle = u.RemoveTagsFromTitle
|
||||||
TitleUseNative = u.TitleUseNative
|
TitleUseNative = u.TitleUseNative
|
||||||
TitleAddVideoID = u.TitleAddVideoID
|
TitleAddVideoID = u.TitleAddVideoID
|
||||||
|
TitleUseRegexForTitle = u.TitleUseRegexForTitle
|
||||||
|
TitleUseRegexForTitle_Value = u.TitleUseRegexForTitle_Value
|
||||||
|
TitleUseGlobalRegexOptions = u.TitleUseGlobalRegexOptions
|
||||||
End Sub
|
End Sub
|
||||||
Friend Sub New(ByVal s As SiteSettings)
|
Friend Sub New(ByVal s As SiteSettings)
|
||||||
MySettings = s
|
MySettings = s
|
||||||
RemoveTagsFromTitle = s.RemoveTagsFromTitle.Value
|
RemoveTagsFromTitle = s.RemoveTagsFromTitle.Value
|
||||||
TitleUseNative = s.TitleUseNative.Value
|
TitleUseNative = s.TitleUseNative.Value
|
||||||
TitleAddVideoID = s.TitleAddVideoID.Value
|
TitleAddVideoID = s.TitleAddVideoID.Value
|
||||||
|
TitleUseRegexForTitle = s.TitleUseRegexForTitle.Value
|
||||||
|
TitleUseRegexForTitle_Value = s.TitleUseRegexForTitle_Value.Value
|
||||||
End Sub
|
End Sub
|
||||||
End Class
|
End Class
|
||||||
End Namespace
|
End Namespace
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ Namespace API.Twitter
|
|||||||
ConcurrentDownloads = New PropertyValue(1)
|
ConcurrentDownloads = New PropertyValue(1)
|
||||||
MyConcurrentDownloadsProvider = New ConcurrentDownloadsProvider
|
MyConcurrentDownloadsProvider = New ConcurrentDownloadsProvider
|
||||||
|
|
||||||
UserRegex = RParams.DMS("[htps:/]{7,8}.*?twitter.com/([^/]+)", 1)
|
UserRegex = RParams.DMS(String.Format(UserRegexDefaultPattern, "/(twitter|x).com/"), 2)
|
||||||
UrlPatternUser = "https://twitter.com/{0}"
|
UrlPatternUser = "https://twitter.com/{0}"
|
||||||
ImageVideoContains = "twitter"
|
ImageVideoContains = "twitter"
|
||||||
CheckNetscapeCookiesOnEndInit = True
|
CheckNetscapeCookiesOnEndInit = True
|
||||||
|
|||||||
@@ -136,7 +136,9 @@ Namespace API.Twitter
|
|||||||
Private Function GetContainerSubnodes() As List(Of String())
|
Private Function GetContainerSubnodes() As List(Of String())
|
||||||
Return New List(Of String()) From {
|
Return New List(Of String()) From {
|
||||||
{{"content", "itemContent", "tweet_results", "result", "legacy"}},
|
{{"content", "itemContent", "tweet_results", "result", "legacy"}},
|
||||||
{{"content", "itemContent", "tweet_results", "result", "tweet", "legacy"}}
|
{{"content", "itemContent", "tweet_results", "result", "tweet", "legacy"}},
|
||||||
|
{{"item", "itemContent", "tweet_results", "result", "legacy"}},
|
||||||
|
{{"item", "itemContent", "tweet_results", "result", "tweet", "legacy"}}
|
||||||
}
|
}
|
||||||
End Function
|
End Function
|
||||||
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
|
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
|
||||||
@@ -155,12 +157,11 @@ Namespace API.Twitter
|
|||||||
Private Sub DownloadData_Timeline(ByVal Token As CancellationToken)
|
Private Sub DownloadData_Timeline(ByVal Token As CancellationToken)
|
||||||
Dim URL$ = String.Empty
|
Dim URL$ = String.Empty
|
||||||
Dim tCache As CacheKeeper = Nothing
|
Dim tCache As CacheKeeper = Nothing
|
||||||
Dim jsonArgs As New WebDocumentEventArgs With {.DeclaredError = EDP.ThrowException}
|
|
||||||
Try
|
Try
|
||||||
Const entry$ = "entry"
|
Const entry$ = "entry"
|
||||||
Dim PostID$ = String.Empty
|
Dim PostID$ = String.Empty
|
||||||
Dim PostDate$, tmpUserId$
|
Dim PostDate$, tmpUserId$
|
||||||
Dim i%
|
Dim i%, nodeIndx%
|
||||||
Dim dirIndx% = -1
|
Dim dirIndx% = -1
|
||||||
Dim nodes As List(Of String()) = GetContainerSubnodes()
|
Dim nodes As List(Of String()) = GetContainerSubnodes()
|
||||||
Dim node$()
|
Dim node$()
|
||||||
@@ -168,10 +169,12 @@ Namespace API.Twitter
|
|||||||
Dim pinNode As Predicate(Of EContainer) = Function(ee) ee.Value("type").StringToLower = "timelinepinentry"
|
Dim pinNode As Predicate(Of EContainer) = Function(ee) ee.Value("type").StringToLower = "timelinepinentry"
|
||||||
Dim entriesNode As Predicate(Of EContainer) = Function(ee) ee.Name = "entries" Or ee.Name = entry
|
Dim entriesNode As Predicate(Of EContainer) = Function(ee) ee.Name = "entries" Or ee.Name = entry
|
||||||
Dim sourceIdPredicate As Predicate(Of EContainer) = Function(ee) ee.Name = "source_user_id_str" Or ee.Name = "source_user_id"
|
Dim sourceIdPredicate As Predicate(Of EContainer) = Function(ee) ee.Name = "source_user_id_str" Or ee.Name = "source_user_id"
|
||||||
|
Dim moduleItemsPredicate As Predicate(Of EContainer) = Function(ee) ee.Name.StringToLower = "moduleitems"
|
||||||
|
Dim newTwitterNodes() As Object = {0, "content", "items"}
|
||||||
Dim p As Predicate(Of EContainer)
|
Dim p As Predicate(Of EContainer)
|
||||||
Dim pIndx%
|
Dim pIndx%
|
||||||
Dim isOneNode As Boolean, isPins As Boolean, ExistsDetected As Boolean, userInfoParsed As Boolean = False
|
Dim isOneNode As Boolean, isPins As Boolean, ExistsDetected As Boolean, userInfoParsed As Boolean = False
|
||||||
Dim j As EContainer, rootNode As EContainer, tmpNode As EContainer, nn As EContainer = Nothing
|
Dim j As EContainer, rootNode As EContainer, optionalNode As EContainer, workingNode As EContainer, tmpNode As EContainer, nn As EContainer = Nothing
|
||||||
|
|
||||||
Dim __parseContainer As Func(Of EContainer, Boolean) =
|
Dim __parseContainer As Func(Of EContainer, Boolean) =
|
||||||
Function(ByVal ee As EContainer) As Boolean
|
Function(ByVal ee As EContainer) As Boolean
|
||||||
@@ -233,8 +236,7 @@ Namespace API.Twitter
|
|||||||
For i = 0 To timelineFiles.Count - 1 : timelineFiles(i) = RenameGdlFile(timelineFiles(i), i) : Next
|
For i = 0 To timelineFiles.Count - 1 : timelineFiles(i) = RenameGdlFile(timelineFiles(i), i) : Next
|
||||||
'parse files
|
'parse files
|
||||||
For i = 0 To timelineFiles.Count - 1
|
For i = 0 To timelineFiles.Count - 1
|
||||||
j = JsonDocument.Parse(timelineFiles(i).GetText, jsonArgs)
|
j = JsonDocument.Parse(timelineFiles(i).GetText)
|
||||||
jsonArgs.Reset()
|
|
||||||
If Not j Is Nothing Then
|
If Not j Is Nothing Then
|
||||||
If i = 0 Then
|
If i = 0 Then
|
||||||
If Not userInfoParsed Then
|
If Not userInfoParsed Then
|
||||||
@@ -286,18 +288,21 @@ Namespace API.Twitter
|
|||||||
End If
|
End If
|
||||||
Else
|
Else
|
||||||
For pIndx = 0 To IIf(dirIndx < 2, 1, 0)
|
For pIndx = 0 To IIf(dirIndx < 2, 1, 0)
|
||||||
|
optionalNode = Nothing
|
||||||
Select Case dirIndx
|
Select Case dirIndx
|
||||||
Case 0, 1
|
Case 0, 1
|
||||||
rootNode = j({"data", "user", "result", "timeline_v2", "timeline", "instructions"})
|
rootNode = j({"data", "user", "result", "timeline_v2", "timeline", "instructions"})
|
||||||
If rootNode.ListExists Then
|
If rootNode.ListExists Then
|
||||||
p = If(pIndx = 0, pinNode, timelineNode)
|
p = If(pIndx = 0, pinNode, timelineNode)
|
||||||
isPins = pIndx = 0
|
isPins = pIndx = 0
|
||||||
|
optionalNode = rootNode
|
||||||
rootNode = rootNode.Find(p, False)
|
rootNode = rootNode.Find(p, False)
|
||||||
If rootNode.ListExists Then rootNode = rootNode.Find(entriesNode, False)
|
If rootNode.ListExists Then rootNode = rootNode.Find(entriesNode, False)
|
||||||
End If
|
End If
|
||||||
Case Else
|
Case Else
|
||||||
isPins = False
|
isPins = False
|
||||||
rootNode = j({"globalObjects", "tweets"})
|
rootNode = j({"globalObjects", "tweets"})
|
||||||
|
optionalNode = rootNode
|
||||||
End Select
|
End Select
|
||||||
|
|
||||||
If rootNode.ListExists Then
|
If rootNode.ListExists Then
|
||||||
@@ -308,9 +313,23 @@ Namespace API.Twitter
|
|||||||
ProgressPre.Perform()
|
ProgressPre.Perform()
|
||||||
If Not __parseContainer(.Self) Then Exit For
|
If Not __parseContainer(.Self) Then Exit For
|
||||||
Else
|
Else
|
||||||
For Each tmpNode In .Self
|
For nodeIndx = 0 To 1
|
||||||
ProgressPre.Perform()
|
If nodeIndx = 0 Then
|
||||||
If Not __parseContainer(tmpNode) Then Exit For
|
workingNode = rootNode
|
||||||
|
Else
|
||||||
|
workingNode = optionalNode
|
||||||
|
If workingNode.ListExists Then workingNode = workingNode.Find(moduleItemsPredicate, True)
|
||||||
|
End If
|
||||||
|
If workingNode.ListExists Then
|
||||||
|
With workingNode
|
||||||
|
For Each tmpNode In If(If(.ItemF(newTwitterNodes)?.Count, 0) > 0,
|
||||||
|
.ItemF(newTwitterNodes),
|
||||||
|
.Self)
|
||||||
|
ProgressPre.Perform()
|
||||||
|
If Not __parseContainer(tmpNode) Then Exit For
|
||||||
|
Next
|
||||||
|
End With
|
||||||
|
End If
|
||||||
Next
|
Next
|
||||||
End If
|
End If
|
||||||
End With
|
End With
|
||||||
@@ -342,15 +361,14 @@ Namespace API.Twitter
|
|||||||
End If
|
End If
|
||||||
DownloadModelForceApply = False
|
DownloadModelForceApply = False
|
||||||
FirstDownloadComplete = True
|
FirstDownloadComplete = True
|
||||||
Catch jsonNull_ex As ArgumentNullException When jsonArgs.State = WebDocumentEventArgs.States.Error
|
Catch jsonNull_ex As JsonDocumentException When jsonNull_ex.State = WebDocumentEventArgs.States.Error
|
||||||
Throw New Plugin.ExitException($"{ToStringForLog()}: No deserialized data found")
|
Throw New Plugin.ExitException("No deserialized data found")
|
||||||
Catch limit_ex As TwitterLimitException
|
Catch limit_ex As TwitterLimitException
|
||||||
Throw limit_ex
|
Throw limit_ex
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
ProcessException(ex, Token, $"data downloading error [{URL}]")
|
ProcessException(ex, Token, $"data downloading error [{URL}]")
|
||||||
Finally
|
Finally
|
||||||
If Not tCache Is Nothing Then tCache.Dispose()
|
If Not tCache Is Nothing Then tCache.Dispose()
|
||||||
jsonArgs.DisposeIfReady
|
|
||||||
If _TempPostsList.Count > 0 Then _TempPostsList.Sort()
|
If _TempPostsList.Count > 0 Then _TempPostsList.Sort()
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
|
|||||||
@@ -741,6 +741,15 @@ Namespace API
|
|||||||
Return GetEnumerator()
|
Return GetEnumerator()
|
||||||
End Function
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
|
#Region "IComparable Support"
|
||||||
|
Friend Overrides Function CompareTo(ByVal Other As UserDataBase) As Integer
|
||||||
|
If TypeOf Other Is UserDataBind Then
|
||||||
|
Return CollectionName.CompareTo(Other.CollectionName)
|
||||||
|
Else
|
||||||
|
Return -1
|
||||||
|
End If
|
||||||
|
End Function
|
||||||
|
#End Region
|
||||||
#Region "IEquatable support"
|
#Region "IEquatable support"
|
||||||
Friend Overrides Function Equals(ByVal Other As UserDataBase) As Boolean
|
Friend Overrides Function Equals(ByVal Other As UserDataBase) As Boolean
|
||||||
If Other.IsCollection Then
|
If Other.IsCollection Then
|
||||||
|
|||||||
@@ -14,5 +14,6 @@ Namespace API.Xhamster
|
|||||||
Friend ReadOnly HtmlScript As RParams = RParams.DMS("\<script id='initials-script'\>window.initials=(\{.+?\});\</script\>", 1, EDP.ReturnValue,
|
Friend ReadOnly HtmlScript As RParams = RParams.DMS("\<script id='initials-script'\>window.initials=(\{.+?\});\</script\>", 1, EDP.ReturnValue,
|
||||||
CType(Function(Input$) Input.StringTrim, Func(Of String, String)))
|
CType(Function(Input$) Input.StringTrim, Func(Of String, String)))
|
||||||
Friend ReadOnly FirstM3U8FileRegEx As RParams = RParams.DM("RESOLUTION=\d+x(\d+).*?[\r\n]+?([^#]*?\.m3u8.*)", 0, RegexReturn.List)
|
Friend ReadOnly FirstM3U8FileRegEx As RParams = RParams.DM("RESOLUTION=\d+x(\d+).*?[\r\n]+?([^#]*?\.m3u8.*)", 0, RegexReturn.List)
|
||||||
|
Friend ReadOnly SecondM3U8FileRegEx As RParams = RParams.DM("(#EXT-X-MAP.URI=""([^""]+((?<=\.)([^\?\.]{2,5})(?=(\?|\Z|"")))(.+|))""|#EXTINF[^\r\n]*[\r\n]+(([^\r\n]+((?<=\.)([^\?\.\r\n]{2,5})(?=(\?[^\r\n]+|[\r\n]+)))([^\r\n]+|))([\r\n]+|\Z)))", 0, RegexReturn.List)
|
||||||
End Module
|
End Module
|
||||||
End Namespace
|
End Namespace
|
||||||
@@ -10,6 +10,7 @@ Imports System.Threading
|
|||||||
Imports SCrawler.API.Base
|
Imports SCrawler.API.Base
|
||||||
Imports SCrawler.API.Base.M3U8Declarations
|
Imports SCrawler.API.Base.M3U8Declarations
|
||||||
Imports PersonalUtilities.Forms.Toolbars
|
Imports PersonalUtilities.Forms.Toolbars
|
||||||
|
Imports PersonalUtilities.Tools
|
||||||
Imports PersonalUtilities.Tools.Web.Clients
|
Imports PersonalUtilities.Tools.Web.Clients
|
||||||
Imports PersonalUtilities.Functions.RegularExpressions
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
Namespace API.Xhamster
|
Namespace API.Xhamster
|
||||||
@@ -40,18 +41,40 @@ Namespace API.Xhamster
|
|||||||
Next
|
Next
|
||||||
Return String.Empty
|
Return String.Empty
|
||||||
End Function
|
End Function
|
||||||
Private Shared Function ParseSecondM3U8(ByVal URL As String, ByVal Responser As Responser, ByVal Appender As String) As List(Of String)
|
Private Shared Function ParseSecondM3U8(ByVal URL As String, ByVal Responser As Responser, ByVal Appender As String) As List(Of M3U8URL)
|
||||||
Dim r$
|
Dim r$
|
||||||
Dim l As List(Of String)
|
Dim l As List(Of String)
|
||||||
|
Dim ll As List(Of M3U8URL) = Nothing
|
||||||
|
Dim u As M3U8URL
|
||||||
|
Dim rmsF As Func(Of RegexMatchStruct, M3U8URL) =
|
||||||
|
Function(ByVal rms As RegexMatchStruct) As M3U8URL
|
||||||
|
With rms
|
||||||
|
If .Arr(0).IsEmptyString Then
|
||||||
|
Return New M3U8URL(.Arr(3).IfNullOrEmpty(.Arr(4)), .Arr(5).IfNullOrEmpty(.Arr(6)))
|
||||||
|
Else
|
||||||
|
Return New M3U8URL(.Arr(0), .Arr(1).IfNullOrEmpty(.Arr(2)))
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
End Function
|
||||||
For i% = 0 To 1
|
For i% = 0 To 1
|
||||||
Try
|
Try
|
||||||
Responser.UseGZipStream = i
|
Responser.UseGZipStream = i
|
||||||
r = Responser.GetResponse(URL)
|
r = Responser.GetResponse(URL)
|
||||||
If Not r.IsEmptyString Then
|
If Not r.IsEmptyString Then
|
||||||
l = RegexReplace(r, TsFilesRegEx)
|
l = RegexReplace(r, TsFilesRegEx)
|
||||||
If l.ListExists Then
|
If Not l.ListExists Then
|
||||||
For indx% = 0 To l.Count - 1 : l(indx) = M3U8Base.CreateUrl(Appender, l(indx)) : Next
|
With RegexFields(Of RegexMatchStruct)(r, {SecondM3U8FileRegEx}, {2, 4, 3, 8, 7, 10, 9}, EDP.ReturnValue)
|
||||||
Return l
|
If .ListExists Then ll = .Select(rmsF).ListWithRemove(Function(v) v.URL.IsEmptyString)
|
||||||
|
End With
|
||||||
|
End If
|
||||||
|
If Not ll.ListExists And l.ListExists Then ll = l.ListCast(Of M3U8URL)
|
||||||
|
If ll.ListExists Then
|
||||||
|
For indx% = 0 To ll.Count - 1
|
||||||
|
u = ll(indx)
|
||||||
|
u.URL = M3U8Base.CreateUrl(Appender, u.URL)
|
||||||
|
ll(indx) = u
|
||||||
|
Next
|
||||||
|
Return ll
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
Catch
|
Catch
|
||||||
@@ -59,14 +82,19 @@ Namespace API.Xhamster
|
|||||||
Next
|
Next
|
||||||
Return Nothing
|
Return Nothing
|
||||||
End Function
|
End Function
|
||||||
Private Shared Function ObtainUrls(ByVal URL As String, ByVal Responser As Responser, ByVal UHD As Boolean) As List(Of String)
|
Private Shared Function ObtainUrls(ByVal URL As String, ByVal Responser As Responser, ByVal UHD As Boolean) As List(Of M3U8URL)
|
||||||
Try
|
Try
|
||||||
|
Const sk$ = "/key="
|
||||||
Dim file$ = ParseFirstM3U8(URL, Responser, UHD)
|
Dim file$ = ParseFirstM3U8(URL, Responser, UHD)
|
||||||
If Not file.IsEmptyString Then
|
If Not file.IsEmptyString Then
|
||||||
Responser.UseGZipStream = False
|
Responser.UseGZipStream = False
|
||||||
Dim appender$ = URL.Replace(URL.Split("/").LastOrDefault, String.Empty)
|
Dim appender$ = URL.Replace(URL.Split("/").LastOrDefault, String.Empty)
|
||||||
|
If file.StartsWith(sk) Then
|
||||||
|
Dim position% = InStr(URL, sk)
|
||||||
|
If position > 0 Then appender = URL.Remove(position - 1)
|
||||||
|
End If
|
||||||
URL = M3U8Base.CreateUrl(appender, file)
|
URL = M3U8Base.CreateUrl(appender, file)
|
||||||
Dim l As List(Of String) = ParseSecondM3U8(URL, Responser, appender)
|
Dim l As List(Of M3U8URL) = ParseSecondM3U8(URL, Responser, appender)
|
||||||
If l.ListExists Then Return l
|
If l.ListExists Then Return l
|
||||||
End If
|
End If
|
||||||
Return Nothing
|
Return Nothing
|
||||||
@@ -75,8 +103,57 @@ Namespace API.Xhamster
|
|||||||
End Try
|
End Try
|
||||||
End Function
|
End Function
|
||||||
Friend Shared Function Download(ByVal Media As UserMedia, ByVal Responser As Responser, ByVal UHD As Boolean,
|
Friend Shared Function Download(ByVal Media As UserMedia, ByVal Responser As Responser, ByVal UHD As Boolean,
|
||||||
ByVal Token As CancellationToken, ByVal Progress As MyProgress, ByVal UsePreProgress As Boolean) As SFile
|
ByVal Token As CancellationToken, ByVal Progress As MyProgress, ByVal UsePreProgress As Boolean,
|
||||||
Return M3U8Base.Download(ObtainUrls(Media.URL, Responser, UHD), Media.File, Responser, Token, Progress, UsePreProgress)
|
ByVal ReencodeVideos As Boolean) As SFile
|
||||||
|
'Return M3U8Base.Download(ObtainUrls(Media.URL, Responser, UHD), Media.File, Responser, Token, Progress, UsePreProgress)
|
||||||
|
Dim Cache As CacheKeeper = Nothing
|
||||||
|
Try
|
||||||
|
Dim urls As List(Of M3U8URL) = ObtainUrls(Media.URL, Responser, UHD)
|
||||||
|
If urls.ListExists Then
|
||||||
|
Cache = New CacheKeeper($"{Media.File.PathWithSeparator}_{M3U8Base.TempCacheFolderName}\") With {.DisposeSuspended = True}
|
||||||
|
Cache.CacheDeleteError = CacheDeletionError(Cache)
|
||||||
|
|
||||||
|
Dim isNewWay As Boolean = Not urls(0).Extension.IsEmptyString AndAlso urls(0).Extension = "mp4" AndAlso urls.Count > 1 AndAlso
|
||||||
|
urls.Exists(Function(u) Not u.Extension = urls(0).Extension)
|
||||||
|
|
||||||
|
Dim f As SFile = M3U8Base.Download(urls, Media.File, Responser, Token, Progress, UsePreProgress, Cache, isNewWay)
|
||||||
|
|
||||||
|
If isNewWay Then
|
||||||
|
f = Media.File
|
||||||
|
With DirectCast(Cache.CurrentInstance, CacheKeeper)
|
||||||
|
If .Count > 0 Then
|
||||||
|
Using batch As New BatchExecutor With {.Encoding = Settings.CMDEncoding}
|
||||||
|
batch.ChangeDirectory(.Self.RootDirectory)
|
||||||
|
Using bat As New TextSaver($"{ .RootDirectory.PathWithSeparator}Merge.bat")
|
||||||
|
Dim tmpFile As SFile
|
||||||
|
Dim tmpFileStr$
|
||||||
|
If ReencodeVideos Then
|
||||||
|
tmpFile = $"{ .Self.RootDirectory.PathWithSeparator}NewVideo.{urls(1).Extension}"
|
||||||
|
tmpFileStr = tmpFile.File
|
||||||
|
.AddFile(tmpFile)
|
||||||
|
Else
|
||||||
|
tmpFile = Media.File
|
||||||
|
tmpFileStr = $"""{tmpFile}"""
|
||||||
|
End If
|
||||||
|
|
||||||
|
bat.AppendLine($"copy /b { .First.File} + {M3U8Base.TempFilePrefix}*.{urls(1).Extension} {tmpFileStr}")
|
||||||
|
If ReencodeVideos Then bat.AppendLine($"""{Settings.FfmpegFile}"" -i ""{tmpFile}"" ""{Media.File}""")
|
||||||
|
bat.Save()
|
||||||
|
.AddFile(bat.File)
|
||||||
|
batch.Execute($"""{bat.File}""")
|
||||||
|
If f.Exists Then Return f
|
||||||
|
End Using
|
||||||
|
End Using
|
||||||
|
End If
|
||||||
|
End With
|
||||||
|
ElseIf f.Exists Then
|
||||||
|
Return f
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Return Nothing
|
||||||
|
Finally
|
||||||
|
Cache.DisposeIfReady(False)
|
||||||
|
End Try
|
||||||
End Function
|
End Function
|
||||||
End Class
|
End Class
|
||||||
End Namespace
|
End Namespace
|
||||||
@@ -28,7 +28,11 @@ Namespace API.Xhamster
|
|||||||
End Get
|
End Get
|
||||||
End Property
|
End Property
|
||||||
<PropertyOption(ControlText:="Download UHD", ControlToolTip:="Download UHD (4K) content"), PXML, PClonable>
|
<PropertyOption(ControlText:="Download UHD", ControlToolTip:="Download UHD (4K) content"), PXML, PClonable>
|
||||||
Friend Property DownloadUHD As PropertyValue
|
Friend ReadOnly Property DownloadUHD As PropertyValue
|
||||||
|
<PropertyOption(ControlText:="Re-encode downloaded videos if necessary",
|
||||||
|
ControlToolTip:="If enabled and the video is downloaded in a non-native format, the video will be re-encoded." & vbCr &
|
||||||
|
"Attention! Enabling this setting results in maximum CPU usage."), PXML, PClonable>
|
||||||
|
Friend ReadOnly Property ReencodeVideos 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)
|
||||||
@@ -38,10 +42,11 @@ Namespace API.Xhamster
|
|||||||
SiteDomains = New PropertyValue(Domains.DomainsDefault, GetType(String))
|
SiteDomains = New PropertyValue(Domains.DomainsDefault, GetType(String))
|
||||||
Domains.DestinationProp = SiteDomains
|
Domains.DestinationProp = SiteDomains
|
||||||
DownloadUHD = New PropertyValue(False)
|
DownloadUHD = New PropertyValue(False)
|
||||||
|
ReencodeVideos = New PropertyValue(False)
|
||||||
|
|
||||||
_SubscriptionsAllowed = True
|
_SubscriptionsAllowed = True
|
||||||
UrlPatternUser = "https://xhamster.com/{0}/{1}"
|
UrlPatternUser = "https://xhamster.com/{0}/{1}"
|
||||||
UserRegex = RParams.DMS($"/({UserOption}|{ChannelOption})/([^/]+)(\Z|.*)", 0, RegexReturn.ListByMatch)
|
UserRegex = RParams.DMS($"/({UserOption}|{ChannelOption}|{P_Creators})/([^/]+)(\Z|.*)", 0, RegexReturn.ListByMatch)
|
||||||
ImageVideoContains = "xhamster"
|
ImageVideoContains = "xhamster"
|
||||||
End Sub
|
End Sub
|
||||||
Friend Overrides Sub EndInit()
|
Friend Overrides Sub EndInit()
|
||||||
@@ -91,8 +96,9 @@ Namespace API.Xhamster
|
|||||||
Friend Const P_Search As String = "search"
|
Friend Const P_Search As String = "search"
|
||||||
Friend Const P_Tags As String = "tags"
|
Friend Const P_Tags As String = "tags"
|
||||||
Friend Const P_Categories As String = "categories"
|
Friend Const P_Categories As String = "categories"
|
||||||
Friend Const P_Pornstars = "pornstars"
|
Friend Const P_Pornstars As String = "pornstars"
|
||||||
Private ReadOnly NonUsersRegex As RParams = RParams.DM("https?://[^/]+/((gay)/|(shemale)/|)(pornstars|tags|categories|search)/([^/\?]+)[/\?]?(.*)", 0,
|
Friend Const P_Creators As String = "creators"
|
||||||
|
Private ReadOnly NonUsersRegex As RParams = RParams.DM("https?://[^/]+/((gay)/|(shemale)/|)(pornstars|creators|tags|categories|search)/([^/\?]+)[/\?]?(.*)", 0,
|
||||||
RegexReturn.ListByMatch, EDP.ReturnValue)
|
RegexReturn.ListByMatch, EDP.ReturnValue)
|
||||||
Private ReadOnly PageRemover_1 As RParams = RParams.DM("[\?&]?[Pp]age=\d+", 0, RegexReturn.Replace, EDP.ReturnValue,
|
Private ReadOnly PageRemover_1 As RParams = RParams.DM("[\?&]?[Pp]age=\d+", 0, RegexReturn.Replace, EDP.ReturnValue,
|
||||||
CType(Function(input) String.Empty, Func(Of String, String)))
|
CType(Function(input) String.Empty, Func(Of String, String)))
|
||||||
@@ -101,12 +107,23 @@ Namespace API.Xhamster
|
|||||||
Friend Overrides Function IsMyUser(ByVal UserURL As String) As ExchangeOptions
|
Friend Overrides Function IsMyUser(ByVal UserURL As String) As ExchangeOptions
|
||||||
If Not UserURL.IsEmptyString AndAlso Domains.Domains.Count > 0 AndAlso Domains.Domains.Exists(Function(d) UserURL.ToLower.Contains(d.ToLower)) Then
|
If Not UserURL.IsEmptyString AndAlso Domains.Domains.Count > 0 AndAlso Domains.Domains.Exists(Function(d) UserURL.ToLower.Contains(d.ToLower)) Then
|
||||||
Dim n$, opt$
|
Dim n$, opt$
|
||||||
|
Dim tryNext As Boolean = False
|
||||||
Dim data As List(Of String) = RegexReplace(UserURL, UserRegex)
|
Dim data As List(Of String) = RegexReplace(UserURL, UserRegex)
|
||||||
If data.ListExists(3) AndAlso Not data(2).IsEmptyString Then
|
If data.ListExists(3) AndAlso Not data(2).IsEmptyString Then
|
||||||
n = data(2)
|
n = data(2)
|
||||||
If Not data(1).IsEmptyString AndAlso data(1) = ChannelOption Then n &= $"@{data(1)}"
|
If Not data(1).IsEmptyString Then
|
||||||
Return New ExchangeOptions(Site, n)
|
If data(1) = ChannelOption Then
|
||||||
|
n &= $"@{data(1)}"
|
||||||
|
ElseIf data(1) = P_Creators Then
|
||||||
|
tryNext = True
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
If Not tryNext Then Return New ExchangeOptions(Site, n)
|
||||||
Else
|
Else
|
||||||
|
tryNext = True
|
||||||
|
End If
|
||||||
|
|
||||||
|
If tryNext Then
|
||||||
data = RegexReplace(UserURL, NonUsersRegex)
|
data = RegexReplace(UserURL, NonUsersRegex)
|
||||||
If data.ListExists(7) AndAlso Not data(5).IsEmptyString Then
|
If data.ListExists(7) AndAlso Not data(5).IsEmptyString Then
|
||||||
n = data(5).StringRemoveWinForbiddenSymbols
|
n = data(5).StringRemoveWinForbiddenSymbols
|
||||||
@@ -117,6 +134,7 @@ Namespace API.Xhamster
|
|||||||
Case P_Tags : mode = SiteModes.Tags
|
Case P_Tags : mode = SiteModes.Tags
|
||||||
Case P_Categories : mode = SiteModes.Categories
|
Case P_Categories : mode = SiteModes.Categories
|
||||||
Case P_Pornstars : mode = SiteModes.Pornstars
|
Case P_Pornstars : mode = SiteModes.Pornstars
|
||||||
|
Case P_Creators : mode = SiteModes.User
|
||||||
Case Else : Return Nothing
|
Case Else : Return Nothing
|
||||||
End Select
|
End Select
|
||||||
n = $"{CInt(mode)}@{n}"
|
n = $"{CInt(mode)}@{n}"
|
||||||
|
|||||||