Site settings have been expanded, some functions and dependencies have been changed.
Removed unused elements in UserDataBase, added additional xml fields, added error executor.
Created a basic download function.
Added Instagram saved posts and 429 bypass.
Added channel statistics.
Added site redgifs.
Updated sites algorithms.
Other improvements.
Updated downloader algorithm.
This commit is contained in:
Andy
2022-01-23 05:34:09 +03:00
parent 7da1ccf1ae
commit f1ba2ecd77
56 changed files with 5056 additions and 1293 deletions

View File

@@ -1,6 +1,6 @@
# Contributor's Guide # Contributor's Guide
I welcome pull requests! Follow these steps to contribute: 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.
2. Let me know you are working on it by posting a comment on the issue. 2. Let me know you are working on it by posting a comment on the issue.
@@ -21,11 +21,22 @@ I welcome pull requests! Follow these steps to contribute:
2. If you don't find anything, create a new issue with your request. I usually reply as soon as possible (within the next few hours). 2. If you don't find anything, create a new issue with your request. I usually reply as soon as possible (within the next few hours).
- If I'm interested in a site you want to add, it may be added in future releases. - If I'm interested in a site you want to add, it may be added in future releases.
- If the site has an API that does not require authorization, it may be added in the coming releases. - If the site has an API that does not require authorization, it may be added in the coming releases.
- You can make it faster by posting a link to the API. I don't use OAuth authentication in my application, so if it's not too hard to make a new parsing algorithm without OAuth authorization, I can start developing it in the coming days. Otherwise, I need time to figure out how to do it. - You can make it faster by posting a link to the API. **I don't use OAuth authentication** in my application, so if it's not too hard to make a new parsing algorithm **without OAuth** authorization, I can start developing it in the coming days. Otherwise, I need time to figure out how to do it.
- If the site does not have an API that does not require authorization, this may take some time. - If the site does not have an API that does not require authorization, this may take some time.
- If you will be posting request urls **without OAuth** authentication, I might consider adding your site if I have time.
- If I'm **not** interested in the site you want to add, you can pay to have it added by making a donation of approximately $10. **But before that, you still need to create an issue. If I'm not interested, you can offer me a deal to develop it for money. I'll check the site you want to add, check the availability of the API and tell you how much time I need to develop it and the price. If you agree, I will do it.** [![ko-fi](https://www.ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/andyprogram) - If I'm **not** interested in the site you want to add, you can pay to have it added by making a donation of approximately $10. **But before that, you still need to create an issue. If I'm not interested, you can offer me a deal to develop it for money. I'll check the site you want to add, check the availability of the API and tell you how much time I need to develop it and the price. If you agree, I will do it.** [![ko-fi](https://www.ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/andyprogram)
# Sites I will never develop # Sites I will never develop
- Facebook - Facebook
# Sites requested by users
- TikTok
- API for receiving data without authorization was not found. Therefore, I don't have time to start developing this site parsing algorithm. If anyone knows of requests that may collect data without OAuth authentication, please let me know.
# Contact me
[Element messenger](https://element.io/): @andyprogram:matrix.org
https://matrix.to/#/@andyprogram:matrix.org

View File

@@ -1,3 +1,25 @@
# 2.0.0.2
**This is the last release that supports program settings of version 1.0.0.4 and lower. Compatibility of program settings with version 1.0.0.4 and lower will be removed in future releases. It is strongly recommended that you upgrade to this release before future releases. Otherwise, you will have to configure the program settings again. If your program version is 1.0.1.0 or higher, you should not pay attention to this message.**
- Added
- Tray icon
- Close program to tray
- Close confirmation dialog
- **Separated thread for downloading Instagram profiles**
- **Wait timers to bypass Instagram error "Too Many Requests" (429)**
- **Downloading saved Instagram posts** *(requires a second InstaHash)*
- Downloading saved posts (from Reddit and Instagram) form
- Tray notification when download is complete (Instagram notification separate from other)
- Downloading not downloaded Instagram posts when a 429 error is encountered and/or the user stops downloading
- Separate progress bar for downloading Instagram profiles
- Clear information about downloaded profiles of the current session in the "Download info form"
- Increased the number of Instagram posts (from 12 to 50) received per request
- Channels' statistics
- **RedGisf profiles support**
- Fixed
- The program was showing incorrect information about the total numbers of images and videos downloaded when a Reddit user was created from a channel
# 2.0.0.1 # 2.0.0.1
- Added - Added

View File

@@ -1,6 +1,6 @@
# Social networks crawler # Social networks crawler
Program for downloading photo and video from Reddit, Twitter and Instagram A program to download photo and video from Reddit, Twitter, Instagram, [etc](#supported-sites).
Do you like this program? Consider adding to my coffee fund by making a donation to show your support. :) Do you like this program? Consider adding to my coffee fund by making a donation to show your support. :)
@@ -11,23 +11,30 @@ Do you like this program? Consider adding to my coffee fund by making a donation
- Reddit images; - Reddit images;
- Reddit galleries of images; - Reddit galleries of images;
- Redgifs hosted videos (https://www.redgifs.com/); - Redgifs hosted videos (https://www.redgifs.com/);
- Reddit hosted videos (downloading Reddit hosted video is going through ffmpeg); - Reddit hosted videos (downloading Reddit hosted video is going through ffmpeg (**ffmpeg only works with the x64 program**));
- Twitter images and videos; - Twitter images and videos;
- Instagram images and videos. - Instagram images and videos.
- Parse [channel and view data](https://github.com/AAndyProgram/SCrawler/wiki/Channels). - Parse [channel and view data](https://github.com/AAndyProgram/SCrawler/wiki/Channels).
- Download [saved Reddit posts](https://github.com/AAndyProgram/SCrawler/wiki/Home#saved-posts). - Download [saved Reddit and Instagram posts](https://github.com/AAndyProgram/SCrawler/wiki/Home#saved-posts).
- Add users from parsed channel. - Add users from parsed channel.
- Labeling users. - Labeling users.
- Filter exists users by label or group. - Filter exists users by label or group.
- Selection of media types you want to download (images only, videos only, both) - Selection of media types you want to download (images only, videos only, both)
# Supported sites
- Reddit
- Twitter
- Instagram
- RedGifs
# How does it works: # How does it works:
## Reddit ## Reddit
The program parses all user posts, obtain MD5 images hash and compares them with existing ones to remove duplicates. Then the media will be downloaded. The program parses all user posts, obtain MD5 images hash and compares them with existing ones to remove duplicates. Then the media will be downloaded.
## Twitter and Instagram ## Other sites
The program parses all user posts and compares file names with existing ones to remove duplicates. Then the media will be downloaded. The program parses all user posts and compares file names with existing ones to remove duplicates. Then the media will be downloaded.
@@ -42,7 +49,7 @@ Read [here](https://github.com/AAndyProgram/SCrawler/blob/main/CONTRIBUTING.md#h
- Windows 7, 8, 9, 10, 11 with NET Framework 4.6.1 or higher - Windows 7, 8, 9, 10, 11 with NET Framework 4.6.1 or higher
- Authorization cookies and tokens for Twitter (if you want to download data from Twitter) - Authorization cookies and tokens for Twitter (if you want to download data from Twitter)
- Authorization cookies Instagram (if you want to download data from Instagram) - Authorization cookies Instagram (if you want to download data from Instagram)
- ffmpeg library for downloading videos hosted on Reddit (you can download it from the [official repo](https://github.com/GyanD/codexffmpeg/releases/tag/2021-01-12-git-ca21cb1e36) or [from my first release](https://github.com/AAndyProgram/SCrawler/releases/download/1.0.0.0/ffmpeg.zip)) - ffmpeg library for downloading videos hosted on Reddit (you can download it from the [official repo](https://github.com/GyanD/codexffmpeg/releases/tag/2021-01-12-git-ca21cb1e36) or [from my first release](https://github.com/AAndyProgram/SCrawler/releases/download/1.0.0.0/ffmpeg.zip)). **ffmpeg only works with the x64 version of the program.**
- **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)**
- **Just unzip the program archive to any folder, copy the file ```ffmpeg.exe``` into it and enjoy. :)** - **Just unzip the program archive to any folder, copy the file ```ffmpeg.exe``` into it and enjoy. :)**
@@ -69,6 +76,7 @@ You can add users by patterns:
- https://twitter.com/SomeUserName - https://twitter.com/SomeUserName
- https://reddit.com/user/SomeUserName - https://reddit.com/user/SomeUserName
- https://reddit.com/r/SomeSubredditName - https://reddit.com/r/SomeSubredditName
- https://www.redgifs.com/users/SomeUserName
- u/SomeUserName - u/SomeUserName
- r/SomeSubredditName - r/SomeSubredditName
- SomeUserName (in this case, you need to select the user's site) - SomeUserName (in this case, you need to select the user's site)
@@ -83,3 +91,8 @@ Read more about adding users and subreddits [here](https://github.com/AAndyProgr
Create a shortcut for the program. Open shortcut properties. In the ```Shortcut``` tab, in the ```Target``` field, just add the letter ```v``` at the end across the space. Create a shortcut for the program. Open shortcut properties. In the ```Shortcut``` tab, in the ```Target``` field, just add the letter ```v``` at the end across the space.
Example: ```D:\Programs\SCrawler\SCrawler.exe v``` Example: ```D:\Programs\SCrawler\SCrawler.exe v```
# Contact me
[Element messenger](https://element.io/): @andyprogram:matrix.org
https://matrix.to/#/@andyprogram:matrix.org

View File

@@ -11,13 +11,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
.gitignore = .gitignore .gitignore = .gitignore
Changelog.md = Changelog.md Changelog.md = Changelog.md
Info\InstaAlgo.txt = Info\InstaAlgo.txt
Info\InstagramInfo.txt = Info\InstagramInfo.txt
README.md = README.md README.md = README.md
Info\RedditUrlsInfo.txt = Info\RedditUrlsInfo.txt
ToDo.txt = ToDo.txt ToDo.txt = ToDo.txt
Info\TwitterNewAlgo.txt = Info\TwitterNewAlgo.txt
Info\TwitterUrlsInfo.txt = Info\TwitterUrlsInfo.txt
EndProjectSection EndProjectSection
EndProject EndProject
Global Global

View File

@@ -25,7 +25,9 @@ Namespace API.Base
_Path.Value = NewFile _Path.Value = NewFile
End Set End Set
End Property End Property
#Region "Instagram"
Friend ReadOnly Property InstaHash As XMLValue(Of String) Friend ReadOnly Property InstaHash As XMLValue(Of String)
Friend ReadOnly Property InstaHash_SP As XMLValue(Of String)
Friend ReadOnly Property InstaHashUpdateRequired As XMLValue(Of Boolean) Friend ReadOnly Property InstaHashUpdateRequired As XMLValue(Of Boolean)
Friend ReadOnly Property InstagramDownloadingErrorDate As XMLValue(Of Date) Friend ReadOnly Property InstagramDownloadingErrorDate As XMLValue(Of Date)
Friend Property InstagramLastApplyingValue As Integer? = Nothing Friend Property InstagramLastApplyingValue As Integer? = Nothing
@@ -40,7 +42,18 @@ Namespace API.Base
End With End With
End Get End Get
End Property End Property
Friend Property InstagramTooManyRequestsReadyForCatch As Boolean = True Friend ReadOnly Property InstagramLastDownloadDate As XMLValue(Of Date)
Friend ReadOnly Property InstagramLastRequestsCount As XMLValue(Of Integer)
Private InstagramTooManyRequestsReadyForCatch As Boolean = True
Friend Function GetInstaWaitDate() As Date
With InstagramDownloadingErrorDate
If .ValueF.Exists Then
Return .ValueF.Value.AddMinutes(If(InstagramLastApplyingValue, 10))
Else
Return Now
End If
End With
End Function
Friend Sub InstagramTooManyRequests(ByVal Catched As Boolean) Friend Sub InstagramTooManyRequests(ByVal Catched As Boolean)
With InstagramDownloadingErrorDate With InstagramDownloadingErrorDate
If Catched Then If Catched Then
@@ -55,9 +68,14 @@ Namespace API.Base
Else Else
.ValueF = Nothing .ValueF = Nothing
InstagramLastApplyingValue = Nothing InstagramLastApplyingValue = Nothing
InstagramTooManyRequestsReadyForCatch = True
End If End If
End With End With
End Sub End Sub
Friend ReadOnly Property RequestsWaitTimer As XMLValue(Of Integer)
Friend ReadOnly Property RequestsWaitTimerTaskCount As XMLValue(Of Integer)
Friend ReadOnly Property SleepTimerOnPostsLimit As XMLValue(Of Integer)
#End Region
Friend ReadOnly Property Temporary As XMLValue(Of Boolean) Friend ReadOnly Property Temporary As XMLValue(Of Boolean)
Friend ReadOnly Property DownloadImages As XMLValue(Of Boolean) Friend ReadOnly Property DownloadImages As XMLValue(Of Boolean)
Friend ReadOnly Property DownloadVideos As XMLValue(Of Boolean) Friend ReadOnly Property DownloadVideos As XMLValue(Of Boolean)
@@ -98,6 +116,7 @@ Namespace API.Base
Responser.CookiesDomain = "reddit.com" Responser.CookiesDomain = "reddit.com"
Responser.Decoders.Add(SymbolsConverter.Converters.Unicode) Responser.Decoders.Add(SymbolsConverter.Converters.Unicode)
Case Sites.Instagram : Responser.CookiesDomain = "instagram.com" Case Sites.Instagram : Responser.CookiesDomain = "instagram.com"
Case Sites.RedGifs : Responser.CookiesDomain = "redgifs.com"
End Select End Select
Responser.SaveSettings() Responser.SaveSettings()
End If End If
@@ -126,20 +145,30 @@ Namespace API.Base
GetUserMediaOnly = New XMLValue(Of Boolean) GetUserMediaOnly = New XMLValue(Of Boolean)
End If End If
CreateProp(InstaHashUpdateRequired, Sites.Instagram, "InstaHashUpdateRequired", True, _XML, n)
CreateProp(InstaHash, Sites.Instagram, "InstaHash", String.Empty, _XML, n)
If Site = Sites.Instagram AndAlso (InstaHash.IsEmptyString Or InstaHashUpdateRequired) AndAlso Responser.Cookies.ListExists Then GatherInstaHash()
CreateProp(InstaHash_SP, Sites.Instagram, "InstaHashSavedPosts", String.Empty, _XML, n)
CreateProp(InstagramLastDownloadDate, Sites.Instagram, "LastDownloadDate", Now.AddDays(-1), _XML, n)
CreateProp(InstagramLastRequestsCount, Sites.Instagram, "LastRequestsCount", 0, _XML, n)
CreateProp(RequestsWaitTimer, Sites.Instagram, "RequestsWaitTimer", 1000, _XML, n)
CreateProp(RequestsWaitTimerTaskCount, Sites.Instagram, "RequestsWaitTimerTaskCount", 1, _XML, n)
CreateProp(SleepTimerOnPostsLimit, Sites.Instagram, "SleepTimerOnPostsLimit", 60000, _XML, n)
If Site = Sites.Instagram Then If Site = Sites.Instagram Then
InstaHash = New XMLValue(Of String)("InstaHash", String.Empty, _XML, n)
InstaHashUpdateRequired = New XMLValue(Of Boolean)("InstaHashUpdateRequired", True, _XML, n)
If (InstaHash.IsEmptyString Or InstaHashUpdateRequired) And Responser.Cookies.ListExists Then GatherInstaHash()
InstagramDownloadingErrorDate = New XMLValue(Of Date) With {.ToStringFunction = Function(ss, vv) AConvert(Of String)(vv, Nothing)} InstagramDownloadingErrorDate = New XMLValue(Of Date) With {.ToStringFunction = Function(ss, vv) AConvert(Of String)(vv, Nothing)}
InstagramDownloadingErrorDate.SetExtended("InstagramDownloadingErrorDate", Now.AddYears(-10), _XML, n) InstagramDownloadingErrorDate.SetExtended("InstagramDownloadingErrorDate", Now.AddYears(-10), _XML, n)
Else Else
InstaHash = New XMLValue(Of String) InstagramDownloadingErrorDate = New XMLValue(Of Date)
InstaHashUpdateRequired = New XMLValue(Of Boolean)
End If End If
If Site = Sites.Reddit Then
SavedPostsUserName = New XMLValue(Of String)("SavedPostsUserName", String.Empty, _XML, n) SavedPostsUserName = New XMLValue(Of String)("SavedPostsUserName", String.Empty, _XML, n)
End Sub
Private Sub CreateProp(Of T)(ByRef p As XMLValue(Of T), ByVal s As Sites,
ByVal p_Name As String, ByVal p_Value As T, ByRef x As XmlFile, ByVal n() As String)
If Site = s Then
p = New XMLValue(Of T)(p_Name, p_Value, x, n)
Else Else
SavedPostsUserName = New XMLValue(Of String) p = New XMLValue(Of T)
End If End If
End Sub End Sub
Friend Sub Update() Friend Sub Update()

View File

@@ -85,5 +85,21 @@ Namespace API.Base
Return v Return v
End Function End Function
End Structure End Structure
Friend Structure Sizes : Implements IComparable(Of Sizes)
Friend Value As Integer
Friend Data As String
Friend ReadOnly HasError As Boolean
Friend Sub New(ByVal _Value As String, ByVal _Data As String)
Try
Value = _Value
Data = _Data
Catch ex As Exception
HasError = True
End Try
End Sub
Friend Function CompareTo(ByVal Other As Sizes) As Integer Implements IComparable(Of Sizes).CompareTo
Return Value.CompareTo(Other.Value) * -1
End Function
End Structure
End Module End Module
End Namespace End Namespace

View File

@@ -7,9 +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 PersonalUtilities.Functions.XML Imports PersonalUtilities.Functions.XML
Imports PersonalUtilities.Forms.Toolbars
Imports System.IO Imports System.IO
Imports System.Net
Imports System.Threading Imports System.Threading
Imports UState = SCrawler.API.Base.UserMedia.States Imports UStates = SCrawler.API.Base.UserMedia.States
Imports UTypes = SCrawler.API.Base.UserMedia.Types
Namespace API.Base Namespace API.Base
Friend MustInherit Class UserDataBase : Implements IUserData Friend MustInherit Class UserDataBase : Implements IUserData
Friend Const UserFileAppender As String = "User" Friend Const UserFileAppender As String = "User"
@@ -77,10 +80,17 @@ Namespace API.Base
#End Region #End Region
#Region "Declarations" #Region "Declarations"
Friend MustOverride Property Site As Sites Implements IContentProvider.Site Friend MustOverride Property Site As Sites Implements IContentProvider.Site
Protected _Progress As MyProgress
Friend Overridable Property Progress As MyProgress
Get
If _Progress Is Nothing Then Return MainProgress Else Return _Progress
End Get
Set(ByVal p As MyProgress)
_Progress = p
End Set
End Property
Friend User As UserInfo Friend User As UserInfo
Friend Property IsSavedPosts As Boolean Friend Property IsSavedPosts As Boolean
Protected Const NonExistendUserHelp As String = "404"
Protected Const SuspendedUserHelp As String = "403"
Friend Overridable Property UserExists As Boolean = True Implements IUserData.Exists Friend Overridable Property UserExists As Boolean = True Implements IUserData.Exists
Friend Overridable Property UserSuspended As Boolean = False Implements IUserData.Suspended Friend Overridable Property UserSuspended As Boolean = False Implements IUserData.Suspended
Friend Overridable Property Name As String Implements IContentProvider.Name Friend Overridable Property Name As String Implements IContentProvider.Name
@@ -288,7 +298,7 @@ BlockNullPicture:
#End Region #End Region
#Region "Information" #Region "Information"
Protected _CountVideo As Integer = 0 Protected _CountVideo As Integer = 0
Protected _CountPictures As Integer = 0 Protected Property _CountPictures As Integer = 0
Friend Overridable Property LastUpdated As Date? Friend Overridable Property LastUpdated As Date?
Friend ReadOnly Property TotalContentCount As Integer Friend ReadOnly Property TotalContentCount As Integer
Get Get
@@ -339,7 +349,7 @@ BlockNullPicture:
Friend ReadOnly Property LVIKey As String Implements IUserData.LVIKey Friend ReadOnly Property LVIKey As String Implements IUserData.LVIKey
Get Get
If Not _IsCollection Then If Not _IsCollection Then
Return $"{Interaction.Switch(Site = Sites.Reddit, "R", Site = Sites.Twitter, "T", Site = Sites.Instagram, "I")}_{Name}" Return $"{Site.ToString.ToUpper.Substring(0, 1)}_{Name}"
Else Else
Return $"CCCC_{CollectionName}" Return $"CCCC_{CollectionName}"
End If End If
@@ -436,6 +446,7 @@ BlockNullPicture:
End If End If
Case Sites.Twitter : Return New Twitter.UserData(u, _LoadUserInformation) Case Sites.Twitter : Return New Twitter.UserData(u, _LoadUserInformation)
Case Sites.Instagram : Return New Instagram.UserData(u, _LoadUserInformation) Case Sites.Instagram : Return New Instagram.UserData(u, _LoadUserInformation)
Case Sites.RedGifs : Return New RedGifs.UserData(u, _LoadUserInformation)
Case Else : Throw New ArgumentOutOfRangeException("Site", $"Site [{u.Site}] information does not recognized by loader") Case Else : Throw New ArgumentOutOfRangeException("Site", $"Site [{u.Site}] information does not recognized by loader")
End Select End Select
End Function End Function
@@ -469,6 +480,7 @@ BlockNullPicture:
DataMerging = x.Value(Name_DataMerging).FromXML(Of Boolean)(False) DataMerging = x.Value(Name_DataMerging).FromXML(Of Boolean)(False)
ChangeCollectionName(x.Value(Name_CollectionName), False) ChangeCollectionName(x.Value(Name_CollectionName), False)
Labels.ListAddList(x.Value(Name_LabelsName).StringToList(Of String, List(Of String))("|", EDP.ReturnValue), LAP.NotContainsOnly, LAP.ClearBeforeAdd) Labels.ListAddList(x.Value(Name_LabelsName).StringToList(Of String, List(Of String))("|", EDP.ReturnValue), LAP.NotContainsOnly, LAP.ClearBeforeAdd)
LoadUserInformation_OptionalFields(x, True)
End Using End Using
UpdateDataFiles() UpdateDataFiles()
End If End If
@@ -506,6 +518,8 @@ BlockNullPicture:
x.Add(Name_LabelsName, Labels.ListToString(, "|", EDP.ReturnValue)) x.Add(Name_LabelsName, Labels.ListToString(, "|", EDP.ReturnValue))
x.Add(Name_DataMerging, DataMerging.BoolToInteger) x.Add(Name_DataMerging, DataMerging.BoolToInteger)
LoadUserInformation_OptionalFields(x, False)
x.Save(MyFile) x.Save(MyFile)
End Using End Using
If Not IsSavedPosts Then Settings.UpdateUsersList(User) If Not IsSavedPosts Then Settings.UpdateUsersList(User)
@@ -513,16 +527,15 @@ BlockNullPicture:
LogError(ex, "user information saving error") LogError(ex, "user information saving error")
End Try End Try
End Sub End Sub
''' <param name="Loading"><see langword="True"/>: Loading; <see langword="False"/>: Saving</param>
Protected MustOverride Sub LoadUserInformation_OptionalFields(ByRef Container As XmlFile, ByVal Loading As Boolean)
#End Region #End Region
#Region "User data" #Region "User data"
Friend Overridable Overloads Sub LoadContentInformation() Friend Overridable Overloads Sub LoadContentInformation()
UpdateDataFiles()
LoadContentInformation(_ContentList, MyFileData)
End Sub
Private Overloads Sub LoadContentInformation(ByRef _CLIST As List(Of UserMedia), ByVal f As SFile)
Try Try
If Not f.Exists Then Exit Sub UpdateDataFiles()
Using x As New XmlFile(f, Protector.Modes.All, False) With {.XmlReadOnly = True, .AllowSameNames = True} If Not MyFileData.Exists Then Exit Sub
Using x As New XmlFile(MyFileData, Protector.Modes.All, False) With {.XmlReadOnly = True, .AllowSameNames = True}
x.LoadData() x.LoadData()
If x.Count > 0 Then If x.Count > 0 Then
Dim fs$ = MyFile.CutPath.PathWithSeparator Dim fs$ = MyFile.CutPath.PathWithSeparator
@@ -538,7 +551,7 @@ BlockNullPicture:
End If End If
End Function End Function
For Each v As EContainer In x For Each v As EContainer In x
_CLIST.Add(New UserMedia With { _ContentList.Add(New UserMedia With {
.Type = AConvert(Of Integer)(v.Attribute(Name_MediaType).Value, 0), .Type = AConvert(Of Integer)(v.Attribute(Name_MediaType).Value, 0),
.URL = v.Attribute(Name_MediaURL).Value, .URL = v.Attribute(Name_MediaURL).Value,
.URL_BASE = v.Value, .URL_BASE = v.Value,
@@ -556,14 +569,14 @@ BlockNullPicture:
LogError(ex, "history loading error") LogError(ex, "history loading error")
End Try End Try
End Sub End Sub
Friend Sub UpdateContentInformation(ByRef _CLIST As List(Of UserMedia), ByVal f As SFile) Friend Sub UpdateContentInformation()
Try Try
UpdateDataFiles() UpdateDataFiles()
If f.IsEmptyString Then Exit Sub If MyFileData.IsEmptyString Then Exit Sub
f.Exists(SFO.Path) MyFileData.Exists(SFO.Path)
Using x As New XmlFile With {.AllowSameNames = True, .Name = "Data"} Using x As New XmlFile With {.AllowSameNames = True, .Name = "Data"}
If _CLIST.Count > 0 Then If _ContentList.Count > 0 Then
For Each i As UserMedia In _CLIST For Each i As UserMedia In _ContentList
x.Add(New EContainer("MediaData", i.URL_BASE, x.Add(New EContainer("MediaData", i.URL_BASE,
{New EAttribute(Name_MediaType, CInt(i.Type)), {New EAttribute(Name_MediaType, CInt(i.Type)),
New EAttribute(Name_MediaURL, i.URL), New EAttribute(Name_MediaURL, i.URL),
@@ -631,9 +644,9 @@ BlockNullPicture:
ThrowAny(Token) ThrowAny(Token)
If _TempMediaList.Count > 0 Then If _TempMediaList.Count > 0 Then
If Not DownloadImages Then _TempMediaList.RemoveAll(Function(m) m.Type = UserMedia.Types.GIF Or m.Type = UserMedia.Types.Picture) If Not DownloadImages Then _TempMediaList.RemoveAll(Function(m) m.Type = UTypes.GIF Or m.Type = UTypes.Picture)
If Not DownloadVideos Then _TempMediaList.RemoveAll(Function(m) m.Type = UserMedia.Types.Video Or If Not DownloadVideos Then _TempMediaList.RemoveAll(Function(m) m.Type = UTypes.Video Or
m.Type = UserMedia.Types.VideoPre Or m.Type = UserMedia.Types.m3u8) m.Type = UTypes.VideoPre Or m.Type = UTypes.m3u8)
End If End If
ReparseVideo(Token) ReparseVideo(Token)
@@ -642,14 +655,14 @@ BlockNullPicture:
_ContentNew.ListAddList(_TempMediaList, LAP.ClearBeforeAdd) _ContentNew.ListAddList(_TempMediaList, LAP.ClearBeforeAdd)
DownloadContent(Token) DownloadContent(Token)
ThrowIfDisposed() ThrowIfDisposed()
_ContentList.ListAddList(_ContentNew.Where(Function(c) c.State = UState.Downloaded), LNC) _ContentList.ListAddList(_ContentNew.Where(Function(c) c.State = UStates.Downloaded), LNC)
_CountPictures = _ContentList.LongCount(Function(c) c.Type = UserMedia.Types.Picture) _CountPictures = _ContentList.LongCount(Function(c) c.Type = UTypes.Picture)
_CountVideo = _ContentList.LongCount(Function(c) c.Type = UserMedia.Types.Video) _CountVideo = _ContentList.LongCount(Function(c) c.Type = UTypes.Video)
If DownloadedPictures + DownloadedVideos > 0 Or EnvirChanged.Invoke Then If DownloadedPictures + DownloadedVideos > 0 Or EnvirChanged.Invoke Then
If __SaveData Then If __SaveData Then
LastUpdated = Now LastUpdated = Now
If Labels.Contains(LabelsKeeper.NoParsedUser) Then Labels.Remove(LabelsKeeper.NoParsedUser) If Labels.Contains(LabelsKeeper.NoParsedUser) Then Labels.Remove(LabelsKeeper.NoParsedUser)
UpdateContentInformation(_ContentList, MyFileData) UpdateContentInformation()
Else Else
_CountVideo = 0 _CountVideo = 0
_CountPictures = 0 _CountPictures = 0
@@ -660,8 +673,10 @@ BlockNullPicture:
UpdateUserInformation() UpdateUserInformation()
End If End If
ThrowIfDisposed() ThrowIfDisposed()
_DownloadedPicturesTotal += _DownloadedPicturesSession If Not CreatedByChannel Then
_DownloadedVideosTotal += _DownloadedVideosSession _DownloadedPicturesTotal += _DownloadedPicturesSession
_DownloadedVideosTotal += _DownloadedVideosSession
End If
If UpPic Or EnvirChanged.Invoke Then Raise_OnUserUpdated() If UpPic Or EnvirChanged.Invoke Then Raise_OnUserUpdated()
Catch oex As OperationCanceledException When Token.IsCancellationRequested Catch oex As OperationCanceledException When Token.IsCancellationRequested
MyMainLOG = $"{Site} - {Name}: downloading canceled" MyMainLOG = $"{Site} - {Name}: downloading canceled"
@@ -692,6 +707,99 @@ BlockNullPicture:
Protected MustOverride Sub DownloadDataF(ByVal Token As CancellationToken) Protected MustOverride Sub DownloadDataF(ByVal Token As CancellationToken)
Protected MustOverride Sub ReparseVideo(ByVal Token As CancellationToken) Protected MustOverride Sub ReparseVideo(ByVal Token As CancellationToken)
Protected MustOverride Sub DownloadContent(ByVal Token As CancellationToken) Protected MustOverride Sub DownloadContent(ByVal Token As CancellationToken)
Protected Sub DownloadContentDefault(ByVal Token As CancellationToken)
Try
Dim i%
Dim dCount% = 0, dTotal% = 0
ThrowAny(Token)
If _ContentNew.Count > 0 Then
_ContentNew.RemoveAll(Function(c) c.URL.IsEmptyString)
If _ContentNew.Count > 0 Then
MyFile.Exists(SFO.Path)
Dim MyDir$ = MyFile.CutPath.PathNoSeparator
Dim vsf As Boolean = SeparateVideoFolderF
Dim __isVideo As Boolean
Dim f As SFile
Dim v As UserMedia
Using w As New WebClient
If vsf Then SFileShares.SFileExists($"{MyDir}\Video\", SFO.Path)
Progress.TotalCount += _ContentNew.Count
For i = 0 To _ContentNew.Count - 1
ThrowAny(Token)
v = _ContentNew(i)
v.State = UStates.Tried
If v.File.IsEmptyString Then
f = v.URL
Else
f = v.File
End If
f.Separator = "\"
f.Path = MyDir
If v.URL_BASE.IsEmptyString Then v.URL_BASE = v.URL
If Not v.File.IsEmptyString And Not v.URL_BASE.IsEmptyString Then
Try
__isVideo = v.Type = UTypes.Video Or f.Extension = "mp4"
If f.Extension.IsEmptyString Then
Select Case v.Type
Case UTypes.Picture : f.Extension = "jpg"
Case UTypes.Video : f.Extension = "mp4"
Case UTypes.GIF : f.Extension = "gif"
End Select
End If
If __isVideo And vsf Then f.Path = $"{f.PathWithSeparator}Video"
w.DownloadFile(v.URL_BASE, f.ToString)
If __isVideo Then
v.Type = UTypes.Video
DownloadedVideos += 1
_CountVideo += 1
Else
v.Type = UTypes.Picture
DownloadedPictures += 1
_CountPictures += 1
End If
v.File = ChangeFileNameByProvider(f, v)
v.State = UStates.Downloaded
dCount += 1
Catch wex As Exception
ErrorDownloading(f, v.URL_BASE)
End Try
Else
v.State = UStates.Skipped
End If
_ContentNew(i) = v
If DownloadTopCount.HasValue AndAlso dCount >= DownloadTopCount.Value Then
Progress.Perform(_ContentNew.Count - dTotal)
Exit Sub
Else
dTotal += 1
Progress.Perform()
End If
Next
End Using
End If
End If
Catch oex As OperationCanceledException When Token.IsCancellationRequested
Catch dex As ObjectDisposedException When Disposed
Catch ex As Exception
LogError(ex, "content downloading error")
HasError = True
End Try
End Sub
''' <param name="RDE">Request DownloadingException</param>
Protected Sub ProcessException(ByVal ex As Exception, ByVal Token As CancellationToken, ByVal Message As String, Optional ByVal RDE As Boolean = True)
If Not ((TypeOf ex Is OperationCanceledException And Token.IsCancellationRequested) Or
(TypeOf ex Is ObjectDisposedException And Disposed)) Then
If RDE AndAlso DownloadingException(ex, Message, True) = 0 Then LogError(ex, Message) : HasError = True
End If
End Sub
''' <summary>0 - Execute LogError and set HasError</summary>
Protected MustOverride Function DownloadingException(ByVal ex As Exception, ByVal Message As String, Optional ByVal FromPE As Boolean = False) As Integer
Protected Function ChangeFileNameByProvider(ByVal f As SFile, ByVal m As UserMedia) As SFile Protected Function ChangeFileNameByProvider(ByVal f As SFile, ByVal m As UserMedia) As SFile
Dim ff As SFile = Nothing Dim ff As SFile = Nothing
Try Try
@@ -1020,7 +1128,7 @@ BlockNullPicture:
''' 0 - Nothing removed<br/> ''' 0 - Nothing removed<br/>
''' 1 - User removed<br/> ''' 1 - User removed<br/>
''' 2 - Collection removed<br/> ''' 2 - Collection removed<br/>
''' 3 - Collection splitted ''' 3 - Collection split
''' </summary> ''' </summary>
Function Delete() As Integer Function Delete() As Integer
Function MoveFiles(ByVal CollectionName As String) As Boolean Function MoveFiles(ByVal CollectionName As String) As Boolean

View File

@@ -46,8 +46,7 @@ Namespace API.Imgur
End If End If
Return Nothing Return Nothing
Catch ex As Exception Catch ex As Exception
If Not e.Exists Then e = New ErrorsDescriber(EDP.ReturnValue + EDP.SendInLog) Return DownloadingException(ex, $"[API.Imgur.Envir.GetGallery({URL})]", Nothing, e)
Return ErrorsDescriber.Execute(e, ex, $"[API.Imgur.Envir.GetGallery({URL})]", Nothing)
End Try End Try
End Function End Function
Friend Shared Function GetImage(ByVal URL As String, Optional ByVal e As ErrorsDescriber = Nothing) As String Friend Shared Function GetImage(ByVal URL As String, Optional ByVal e As ErrorsDescriber = Nothing) As String
@@ -64,8 +63,7 @@ Namespace API.Imgur
End If End If
Return String.Empty Return String.Empty
Catch ex As Exception Catch ex As Exception
If Not e.Exists Then e = New ErrorsDescriber(EDP.ReturnValue + EDP.SendInLog) Return DownloadingException(ex, $"[API.Imgur.Envir.GetImage({URL})]", String.Empty, e)
Return ErrorsDescriber.Execute(e, ex, $"[API.Imgur.Envir.GetImage({URL})]", String.Empty)
End Try End Try
End Function End Function
Friend Shared Function GetVideoInfo(ByVal URL As String) As IEnumerable(Of UserMedia) Friend Shared Function GetVideoInfo(ByVal URL As String) As IEnumerable(Of UserMedia)
@@ -83,5 +81,21 @@ Namespace API.Imgur
Return ErrorsDescriber.Execute(EDP.ShowMainMsg + EDP.SendInLog, ex, "Imgur standalone downloader: fetch media error") Return ErrorsDescriber.Execute(EDP.ShowMainMsg + EDP.SendInLog, ex, "Imgur standalone downloader: fetch media error")
End Try End Try
End Function End Function
Private Shared Function DownloadingException(ByVal ex As Exception, ByVal Message As String,
ByVal NullArg As Object, ByVal e As ErrorsDescriber) As Object
If TypeOf ex Is WebException Then
Dim obj As HttpWebResponse = TryCast(DirectCast(ex, WebException).Response, HttpWebResponse)
If Not obj Is Nothing Then
If obj.StatusCode = HttpStatusCode.NotFound Then
Return NullArg
ElseIf obj.StatusCode = HttpStatusCode.Unauthorized Then
MyMainLOG = "Imgur credentials expired"
Return NullArg
End If
End If
End If
If Not e.Exists Then e = New ErrorsDescriber(EDP.ReturnValue + EDP.SendInLog)
Return ErrorsDescriber.Execute(e, ex, Message, NullArg)
End Function
End Class End Class
End Namespace End Namespace

View File

@@ -8,7 +8,7 @@
' but WITHOUT ANY WARRANTY ' but WITHOUT ANY WARRANTY
Namespace API.Instagram Namespace API.Instagram
Friend Module Declarations Friend Module Declarations
Friend ReadOnly FilesPattern As New RegexStructure("[^\./]+?\.\w+", True, False, 2,,,, String.Empty, EDP.ReturnValue) Friend ReadOnly FilesPattern As New RegexStructure(".+?([^/\?]+?\.[\w\d]{3,4})(?=(\?|\Z))",,,, 1,,, String.Empty, EDP.ReturnValue)
Friend ReadOnly Property DateProvider As New JsonDate Friend ReadOnly Property DateProvider As New JsonDate
Friend Class JsonDate : Implements ICustomProvider Friend Class JsonDate : Implements ICustomProvider
Friend Function Convert(ByVal Value As Object, ByVal DestinationType As Type, ByVal Provider As IFormatProvider, Friend Function Convert(ByVal Value As Object, ByVal DestinationType As Type, ByVal Provider As IFormatProvider,

View File

@@ -0,0 +1,44 @@
' Copyright (C) 2022 Andy
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY
Imports SCrawler.API.Base
Imports System.Threading
Imports PersonalUtilities.Forms.Toolbars
Namespace API.Instagram
Friend NotInheritable Class ProfileSaved
Friend Shared ReadOnly Property DataPath As SFile = $"{Settings(Sites.Instagram).Path.PathNoSeparator}\!Saved\"
Private Sub New()
End Sub
Friend Shared Sub Download(ByRef Bar As MyProgress, ByVal Token As CancellationToken)
Try
Dim u As New UserInfo(Settings(Sites.Instagram).SavedPostsUserName.Value, Sites.Instagram) With {.SpecialPath = DataPath}
u.UpdateUserFile()
Using user As New UserData(u,, False)
DirectCast(user.Self, UserDataBase).IsSavedPosts = True
user.Progress = Bar
If Not user.FileExists Then user.UpdateUserInformation()
If Settings(Sites.Instagram).InstagramLastDownloadDate.Value < Now.AddMinutes(60) Then
user.RequestsCount = Settings(Sites.Instagram).InstagramLastRequestsCount
End If
user.DownloadData(Token)
Bar.InformationTemporary = $"Images: {user.DownloadedPictures}; Videos: {user.DownloadedVideos}"
With Settings
.BeginUpdate()
With .Site(Sites.Instagram)
.InstagramLastDownloadDate.Value = Now
.InstagramLastRequestsCount.Value = user.RequestsCount
End With
.EndUpdate()
End With
End Using
Catch ex As Exception
ErrorsDescriber.Execute(EDP.SendInLog, ex, "[API.Instagram.ProfileSaved.Download]")
End Try
End Sub
End Class
End Namespace

View File

@@ -7,103 +7,275 @@
' This program is distributed in the hope that it will be useful, ' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY ' but WITHOUT ANY WARRANTY
Imports PersonalUtilities.Functions.XML Imports PersonalUtilities.Functions.XML
Imports PersonalUtilities.Functions.Messaging
Imports PersonalUtilities.Tools.WebDocuments.JSON Imports PersonalUtilities.Tools.WebDocuments.JSON
Imports PersonalUtilities.Forms.Toolbars
Imports SCrawler.API.Base Imports SCrawler.API.Base
Imports System.Threading Imports System.Threading
Imports System.Net Imports System.Net
Imports UStates = SCrawler.API.Base.UserMedia.States
Imports UTypes = SCrawler.API.Base.UserMedia.Types Imports UTypes = SCrawler.API.Base.UserMedia.Types
Namespace API.Instagram Namespace API.Instagram
Friend Class UserData : Inherits UserDataBase Friend Class UserData : Inherits UserDataBase
Private Const MaxPostsCount As Integer = 200
Private Const Name_LastCursor As String = "LastCursor"
Private Const Name_FirstLoadingDone As String = "FirstLoadingDone"
Friend Overrides Property Site As Sites = Sites.Instagram Friend Overrides Property Site As Sites = Sites.Instagram
Friend Overrides Property Progress As MyProgress
Get
If Not _Progress Is Nothing Then Return _Progress Else Return MainProgressInst
End Get
Set(ByVal p As MyProgress)
_Progress = p
End Set
End Property
Private ReadOnly _SavedPostsIDs As New List(Of String)
Private LastCursor As String = String.Empty
Private FirstLoadingDone As Boolean = True
''' <summary>Video downloader initializer</summary> ''' <summary>Video downloader initializer</summary>
Private Sub New() Private Sub New()
End Sub End Sub
''' <summary>Default initializer</summary> ''' <summary>Default initializer</summary>
Friend Sub New(ByVal u As UserInfo, Optional ByVal _LoadUserInformation As Boolean = True) Friend Sub New(ByVal u As UserInfo, Optional ByVal _LoadUserInformation As Boolean = True, Optional ByVal InvokeImageHandler As Boolean = True)
MyBase.New(InvokeImageHandler)
User = u User = u
If _LoadUserInformation Then LoadUserInformation() If _LoadUserInformation Then LoadUserInformation()
End Sub End Sub
Protected Overrides Sub LoadUserInformation_OptionalFields(ByRef Container As XmlFile, ByVal Loading As Boolean)
If Loading Then
LastCursor = Container.Value(Name_LastCursor)
FirstLoadingDone = Container.Value(Name_FirstLoadingDone).FromXML(Of Boolean)(False)
Else
Container.Add(Name_LastCursor, LastCursor)
Container.Add(Name_FirstLoadingDone, FirstLoadingDone.BoolToInteger)
End If
End Sub
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken) Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
DownloadData(String.Empty, Token) Try
_InstaHash = String.Empty
HasError = False
If Not LastCursor.IsEmptyString Then
DownloadData(LastCursor, Token)
ThrowAny(Token)
If Not HasError Then FirstLoadingDone = True
End If
If Not HasError Then
DownloadData(String.Empty, Token)
ThrowAny(Token)
If Not HasError Then FirstLoadingDone = True
End If
If FirstLoadingDone Then LastCursor = String.Empty
If IsSavedPosts Then DownloadPosts(Token)
If WaitNotificationMode = WNM.SkipTemp Or WaitNotificationMode = WNM.SkipCurrent Then WaitNotificationMode = WNM.Notify
Catch ex As Exception
ProcessException(ex, Token, "[API.Instagram.UserData.DownloadDataF", False)
End Try
End Sub End Sub
Private _InstaHash As String = String.Empty Private _InstaHash As String = String.Empty
#Region "429 bypass"
Friend RequestsCount As Integer = 0
Friend Enum WNM As Integer
Notify = 0
SkipCurrent = 1
SkipAll = 2
SkipTemp = 3
End Enum
Friend WaitNotificationMode As WNM = WNM.Notify
Private Caught429 As Boolean = False
Private ProgressTempSet As Boolean = False
Private Const InstAborted As String = "InstAborted"
Private Function Ready() As Boolean
With Settings(Sites.Instagram)
If Not .InstagramReadyForDownload Then
If WaitNotificationMode = WNM.Notify Then
Dim m As New MMessage("Instagram [too many requests] error." & vbCr &
$"The program suggests waiting {If(Settings(Sites.Instagram).InstagramLastApplyingValue, 0)} minutes." & vbCr &
"What do you want to do?", "Waiting for Instagram download...",
{
New MsgBoxButton("Wait") With {.ToolTip = "Wait and ask again when the error is found."},
New MsgBoxButton("Wait (disable current") With {.ToolTip = "Wait and skip future prompts while downloading the current profile."},
New MsgBoxButton("Abort") With {.ToolTip = "Abort operation"},
New MsgBoxButton("Wait (disable all)") With {.ToolTip = "Wait and skip future prompts while downloading the current session."}
},
vbExclamation) With {.ButtonsPerRow = 2, .DefaultButton = 0, .CancelButton = 2}
Select Case MsgBoxE(m).Index
Case 1 : WaitNotificationMode = WNM.SkipCurrent
Case 2 : Throw New OperationCanceledException("Instagram download operation aborted") With {.HelpLink = InstAborted}
Case 3 : WaitNotificationMode = WNM.SkipAll
Case Else : WaitNotificationMode = WNM.SkipTemp
End Select
End If
If Not ProgressTempSet Then Progress.InformationTemporary = $"Waiting until {Settings(Sites.Instagram).GetInstaWaitDate().ToString(ParsersDataDateProvider)}"
ProgressTempSet = True
Return False
Else
Return True
End If
End With
End Function
Private Sub ReconfigureAwaiter()
If WaitNotificationMode = WNM.SkipTemp Then WaitNotificationMode = WNM.Notify
If Caught429 Then Caught429 = False : RequestsCount = 0
ProgressTempSet = False
End Sub
Private Sub NextRequest(ByVal StartWait As Boolean)
With Settings(Sites.Instagram)
If StartWait And (RequestsCount Mod .RequestsWaitTimerTaskCount.Value) = 0 Then Thread.Sleep(.RequestsWaitTimer)
If RequestsCount >= MaxPostsCount - 5 Then Thread.Sleep(.SleepTimerOnPostsLimit)
End With
End Sub
#End Region
Private Overloads Sub DownloadData(ByVal Cursor As String, ByVal Token As CancellationToken) Private Overloads Sub DownloadData(ByVal Cursor As String, ByVal Token As CancellationToken)
Dim URL$ = String.Empty Dim URL$ = String.Empty
Dim _DownloadComplete As Boolean = False
LastCursor = Cursor
Try Try
Dim n As EContainer, nn As EContainer, node As EContainer Do While Not _DownloadComplete
Dim HasNextPage As Boolean = False If Not Ready() Then Thread.Sleep(10000) : ThrowAny(Token) : Continue Do
Dim EndCursor$ = String.Empty ReconfigureAwaiter()
Dim PostID$ = String.Empty, PostDate$ = String.Empty
'Check environment Try
If Cursor.IsEmptyString And _InstaHash.IsEmptyString Then _InstaHash = Settings(Sites.Instagram).InstaHash Dim n As EContainer, nn As EContainer, node As EContainer
If _InstaHash.IsEmptyString Then Throw New ArgumentNullException("InstHash", "Query hash is null") Dim HasNextPage As Boolean = False
If ID.IsEmptyString Then GetUserId() Dim EndCursor$ = String.Empty
If ID.IsEmptyString Then Throw New ArgumentException("User ID is not detected", "ID") Dim PostID$ = String.Empty, PostDate$ = String.Empty
'Create query NextRequest(True)
Dim vars$ = "{""id"":" & ID & ",""first"":12,""after"":""" & Cursor & """}"
vars = SymbolsConverter.ASCII.EncodeSymbolsOnly(vars)
URL = $"https://www.instagram.com/graphql/query/?query_hash={_InstaHash}&variables={vars}"
'Get response 'Check environment
Dim r$ = Responser.GetResponse(URL,, EDP.ThrowException) If Cursor.IsEmptyString And _InstaHash.IsEmptyString Then _
Settings(Sites.Instagram).InstagramTooManyRequests(False) _InstaHash = If(IsSavedPosts, Settings(Sites.Instagram).InstaHash_SP, Settings(Sites.Instagram).InstaHash).Value
ThrowAny(Token) If _InstaHash.IsEmptyString Then Throw New ArgumentNullException(IIf(IsSavedPosts, "InstaHashSavedPosts", "InstaHash"), "Query hash is null")
If ID.IsEmptyString Then GetUserId()
If ID.IsEmptyString Then Throw New ArgumentException("User ID is not detected", "ID")
'Data 'Create query
If Not r.IsEmptyString Then Dim vars$ = "{""id"":" & ID & ",""first"":50,""after"":""" & Cursor & """}"
Using j As EContainer = JsonDocument.Parse(r).XmlIfNothing vars = SymbolsConverter.ASCII.EncodeSymbolsOnly(vars)
n = j.ItemF({"data", "user", 0}).XmlIfNothing URL = $"https://www.instagram.com/graphql/query/?query_hash={_InstaHash}&variables={vars}"
If n.Count > 0 Then
If n.Contains("page_info") Then
With n("page_info")
HasNextPage = .Value("has_next_page").FromXML(Of Boolean)(False)
EndCursor = .Value("end_cursor")
End With
End If
n = n("edges").XmlIfNothing
If n.Count > 0 Then
For Each nn In n
ThrowAny(Token)
node = nn(0).XmlIfNothing
PostID = node.Value("id") 'Get response
If Not PostID.IsEmptyString And _TempPostsList.Contains(PostID) Then Exit Sub Dim r$ = Responser.GetResponse(URL,, EDP.ThrowException)
_TempPostsList.Add(PostID) Settings(Sites.Instagram).InstagramTooManyRequests(False)
PostDate = node.Value("taken_at_timestamp") RequestsCount += 1
ThrowAny(Token)
ObtainMedia(node, PostID, PostDate) 'Data
Next If Not r.IsEmptyString Then
End If Using j As EContainer = JsonDocument.Parse(r).XmlIfNothing
n = j.ItemF({"data", "user", 0}).XmlIfNothing
If n.Count > 0 Then
If n.Contains("page_info") Then
With n("page_info")
HasNextPage = .Value("has_next_page").FromXML(Of Boolean)(False)
EndCursor = .Value("end_cursor")
End With
End If
n = n("edges").XmlIfNothing
If n.Count > 0 Then
For Each nn In n
ThrowAny(Token)
node = nn(0).XmlIfNothing
If IsSavedPosts Then
PostID = node.Value("shortcode")
If Not PostID.IsEmptyString Then
If _TempPostsList.Contains(PostID) Then Exit Sub Else _SavedPostsIDs.Add(PostID)
End If
Else
PostID = node.Value("id")
If Not PostID.IsEmptyString And _TempPostsList.Contains(PostID) Then Exit Sub
_TempPostsList.Add(PostID)
PostDate = node.Value("taken_at_timestamp")
ObtainMedia(node, PostID, PostDate)
End If
Next
End If
Else
If j.Value("status") = "ok" AndAlso j({"data", "user"}).XmlIfNothing.Count = 0 AndAlso _TempMediaList.Count = 0 Then
Settings(Sites.Instagram).InstaHashUpdateRequired.Value = True
UserExists = False
_DownloadComplete = True
Exit Sub
End If
End If
End Using
Else Else
If j.Value("status") = "ok" AndAlso j({"data", "user"}).XmlIfNothing.Count = 0 AndAlso _TempMediaList.Count = 0 Then _DownloadComplete = True
Settings(Sites.Instagram).InstaHashUpdateRequired.Value = True Exit Sub
UserExists = False
Exit Sub
End If
End If End If
End Using _DownloadComplete = True
End If If HasNextPage And Not EndCursor.IsEmptyString Then DownloadData(EndCursor, Token)
If HasNextPage And Not EndCursor.IsEmptyString Then DownloadData(EndCursor, Token) Catch oex As OperationCanceledException When Token.IsCancellationRequested
Catch oex As OperationCanceledException When Token.IsCancellationRequested Exit Do
Catch dex As ObjectDisposedException When Disposed Catch dex As ObjectDisposedException When Disposed
Catch ex As Exception Exit Do
If Responser.StatusCode = HttpStatusCode.NotFound Then Catch ex As Exception
UserExists = False If DownloadingException(ex, $"data downloading error [{URL}]") = 1 Then Continue Do Else Exit Do
ElseIf Responser.StatusCode = HttpStatusCode.BadRequest Then End Try
MyMainLOG = "Instagram credentials have expired" Loop
Settings(Sites.Instagram).InstaHashUpdateRequired.Value = True Catch oex2 As OperationCanceledException When Token.IsCancellationRequested Or oex2.HelpLink = InstAborted
ElseIf Responser.StatusCode = 429 Then If oex2.HelpLink = InstAborted Then HasError = True
Settings(Sites.Instagram).InstagramTooManyRequests(True) Catch DoEx As Exception
Else ProcessException(DoEx, Token, $"data downloading error [{URL}]")
Settings(Sites.Instagram).InstaHashUpdateRequired.Value = True End Try
LogError(ex, $"data downloading error [{URL}]") End Sub
End If Private Sub DownloadPosts(ByVal Token As CancellationToken)
HasError = True Dim URL$ = String.Empty
Finally Dim _DownloadComplete As Boolean = False
_InstaHash = String.Empty Dim _Index% = 0
Try
Do While Not _DownloadComplete
If Not Ready() Then Thread.Sleep(10000) : ThrowAny(Token) : Continue Do
ReconfigureAwaiter()
Try
Dim r$
Dim j As EContainer, jj As EContainer
Dim _MediaObtained As Boolean
If _SavedPostsIDs.Count > 0 And _Index <= _SavedPostsIDs.Count - 1 Then
Dim e As New ErrorsDescriber(EDP.ThrowException)
For i% = _Index To _SavedPostsIDs.Count - 1
_Index = i
URL = $"https://instagram.com/p/{_SavedPostsIDs(i)}/?__a=1"
ThrowAny(Token)
NextRequest((i + 1 Mod 5) = 0)
ThrowAny(Token)
r = Responser.GetResponse(URL,, e)
Settings(Sites.Instagram).InstagramTooManyRequests(False)
RequestsCount += 1
If Not r.IsEmptyString Then
j = JsonDocument.Parse(r)
If Not j Is Nothing Then
_MediaObtained = False
If j.Contains({"graphql", "shortcode_media"}) Then
With j({"graphql", "shortcode_media"}).XmlIfNothing
If .Count > 0 Then ObtainMedia(.Self, _SavedPostsIDs(i), String.Empty) : _MediaObtained = True
End With
End If
If Not _MediaObtained AndAlso j.Contains("items") Then
With j("items")
If .Count > 0 Then
For Each jj In .Self : ObtainMedia2(jj, _SavedPostsIDs(i)) : Next
End If
End With
End If
j.Dispose()
End If
End If
Next
_DownloadComplete = True
End If
Catch oex As OperationCanceledException When Token.IsCancellationRequested
Exit Do
Catch dex As ObjectDisposedException When Disposed
Exit Do
Catch ex As Exception
If DownloadingException(ex, $"downloading saved posts error [{URL}]") = 1 Then Continue Do Else Exit Do
End Try
Loop
Catch oex2 As OperationCanceledException When Token.IsCancellationRequested Or oex2.HelpLink = InstAborted
If oex2.HelpLink = InstAborted Then HasError = True
Catch DoEx As Exception
ProcessException(DoEx, Token, $"downloading saved posts error [{URL}]")
End Try End Try
End Sub End Sub
Private Sub ObtainMedia(ByVal node As EContainer, ByVal PostID As String, ByVal PostDate As String) Private Sub ObtainMedia(ByVal node As EContainer, ByVal PostID As String, ByVal PostDate As String)
@@ -124,6 +296,66 @@ Namespace API.Instagram
CreateMedia(node) CreateMedia(node)
End If End If
End Sub End Sub
Private Sub ObtainMedia2(ByVal n As EContainer, ByVal PostID As String)
Try
Dim img As Predicate(Of EContainer) = Function(_img) Not _img.Name.IsEmptyString AndAlso _img.Name.StartsWith("image_versions") AndAlso _img.Count > 0
Dim vid As Predicate(Of EContainer) = Function(_vid) Not _vid.Name.IsEmptyString AndAlso _vid.Name.StartsWith("video_versions") AndAlso _vid.Count > 0
Dim ss As Func(Of EContainer, Sizes) = Function(_ss) New Sizes(_ss.Value("width"), _ss.Value("url"))
If n.Count > 0 Then
Dim l As New List(Of Sizes)
Dim d As EContainer
Dim t%
'8 - gallery
'2 - one video
'1 - one picture
t = n.Value("media_type").FromXML(Of Integer)(-1)
If t >= 0 Then
Select Case t
Case 1
If n.Contains(img) Then
t = n.Value("media_type").FromXML(Of Integer)(-1)
If t >= 0 Then
With n.ItemF({img, "candidates"}).XmlIfNothing
If .Count > 0 Then
l.Clear()
l.ListAddList(.Select(ss), LNC)
If l.Count > 0 Then
l.Sort()
_TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, l.First.Data, PostID, Nothing), LNC)
l.Clear()
End If
End If
End With
End If
End If
Case 2
If n.Contains(vid) Then
With n.ItemF({vid}).XmlIfNothing
If .Count > 0 Then
l.Clear()
l.ListAddList(.Select(ss), LNC)
If l.Count > 0 Then
l.Sort()
_TempMediaList.ListAddValue(MediaFromData(UTypes.Video, l.First.Data, PostID, Nothing), LNC)
l.Clear()
End If
End If
End With
End If
Case 8
With n("carousel_media").XmlIfNothing
If .Count > 0 Then
For Each d In .Self : ObtainMedia2(d, PostID) : Next
End If
End With
End Select
End If
l.Clear()
End If
Catch ex As Exception
ErrorsDescriber.Execute(EDP.SendInLog, ex, "API.Instagram.GetGallery")
End Try
End Sub
Private Sub GetUserId() Private Sub GetUserId()
Try Try
Dim r$ = Responser.GetResponse($"https://www.instagram.com/{Name}/?__a=1",, EDP.ThrowException) Dim r$ = Responser.GetResponse($"https://www.instagram.com/{Name}/?__a=1",, EDP.ThrowException)
@@ -136,106 +368,71 @@ Namespace API.Instagram
If Responser.StatusCode = HttpStatusCode.NotFound Or Responser.StatusCode = HttpStatusCode.BadRequest Then If Responser.StatusCode = HttpStatusCode.NotFound Or Responser.StatusCode = HttpStatusCode.BadRequest Then
Throw ex Throw ex
Else Else
LogError(ex, "get instagram user id") LogError(ex, "get Instagram user id")
End If End If
End Try End Try
End Sub End Sub
Protected Overrides Sub ReparseVideo(ByVal Token As CancellationToken) Protected Overrides Sub ReparseVideo(ByVal Token As CancellationToken)
End Sub End Sub
Protected Overrides Sub DownloadContent(ByVal Token As CancellationToken) Protected Overrides Sub DownloadContent(ByVal Token As CancellationToken)
Try DownloadContentDefault(Token)
Dim i%
Dim dCount% = 0, dTotal% = 0
ThrowAny(Token)
If _ContentNew.Count > 0 Then
_ContentNew.RemoveAll(Function(c) c.URL.IsEmptyString)
If _ContentNew.Count > 0 Then
MyFile.Exists(SFO.Path)
Dim MyDir$ = MyFile.CutPath.PathNoSeparator
Dim vsf As Boolean = SeparateVideoFolderF
Dim f As SFile
Dim v As UserMedia
Using w As New WebClient
If vsf Then SFileShares.SFileExists($"{MyDir}\Video\", SFO.Path)
MainProgress.TotalCount += _ContentNew.Count
For i = 0 To _ContentNew.Count - 1
ThrowAny(Token)
v = _ContentNew(i)
v.State = UStates.Tried
If v.File.IsEmptyString Then
f = v.URL
Else
f = v.File
End If
f.Separator = "\"
f.Path = MyDir
If v.URL_BASE.IsEmptyString Then v.URL_BASE = v.URL
If Not v.File.IsEmptyString AndAlso Not v.URL_BASE.IsEmptyString Then
Try
If v.Type = UTypes.Video And vsf Then f.Path = $"{f.PathWithSeparator}Video"
w.DownloadFile(v.URL_BASE, f.ToString)
Select Case v.Type
Case UTypes.Video : DownloadedVideos += 1 : _CountVideo += 1
Case UTypes.Picture : DownloadedPictures += 1 : _CountPictures += 1
End Select
v.File = ChangeFileNameByProvider(f, v)
v.State = UStates.Downloaded
Catch wex As Exception
ErrorDownloading(f, v.URL_BASE)
End Try
Else
v.State = UStates.Skipped
End If
_ContentNew(i) = v
If DownloadTopCount.HasValue AndAlso dCount >= DownloadTopCount.Value Then
MainProgress.Perform(_ContentNew.Count - dTotal)
Exit Sub
Else
dTotal += 1
MainProgress.Perform()
End If
Next
End Using
End If
End If
Catch oex As OperationCanceledException When Token.IsCancellationRequested
Catch dex As ObjectDisposedException When Disposed
Catch ex As Exception
LogError(ex, "content downloading error")
HasError = True
End Try
End Sub End Sub
''' <summary>
''' <inheritdoc cref="UserDataBase.DownloadingException(Exception, String)"/><br/>
''' 1 - continue
''' </summary>
Protected Overrides Function DownloadingException(ByVal ex As Exception, ByVal Message As String, Optional ByVal FromPE As Boolean = False) As Integer
If Responser.StatusCode = HttpStatusCode.NotFound Then
UserExists = False
ElseIf Responser.StatusCode = HttpStatusCode.BadRequest Then
HasError = True
MyMainLOG = "Instagram credentials have expired"
Settings(Sites.Instagram).InstaHashUpdateRequired.Value = True
ElseIf Responser.StatusCode = 429 Then
With Settings(Sites.Instagram)
Dim WaiterExists As Boolean = .InstagramLastApplyingValue.HasValue
.InstagramTooManyRequests(True)
If Not WaiterExists Then .InstagramLastApplyingValue = 2
End With
Caught429 = True
MyMainLOG = $"Number of requests before error 429: {RequestsCount}"
Return 1
Else
Settings(Sites.Instagram).InstaHashUpdateRequired.Value = True
If Not FromPE Then LogError(ex, Message) : HasError = True
Return 0
End If
Return 2
End Function
Private Shared Function MediaFromData(ByVal t As UTypes, ByVal _URL As String, ByVal PostID As String, ByVal PostDate As String) As UserMedia Private Shared Function MediaFromData(ByVal t As UTypes, ByVal _URL As String, ByVal PostID As String, ByVal PostDate As String) As UserMedia
_URL = LinkFormatterSecure(RegexReplace(_URL.Replace("\", String.Empty), LinkPattern)) _URL = LinkFormatterSecure(RegexReplace(_URL.Replace("\", String.Empty), LinkPattern))
Dim m As New UserMedia(_URL, t) With {.Post = New UserPost With {.ID = PostID}} Dim m As New UserMedia(_URL, t) With {.Post = New UserPost With {.ID = PostID}}
If Not m.URL.IsEmptyString Then m.File = CStr(RegexReplace(m.URL, FilesPattern)) If Not m.URL.IsEmptyString Then m.File = CStr(RegexReplace(m.URL, FilesPattern))
If Not PostDate.IsEmptyString Then m.Post.Date = AConvert(Of Date)(PostDate, Declarations.DateProvider, Nothing) Else m.Post.Date = Nothing If Not PostDate.IsEmptyString Then m.Post.Date = AConvert(Of Date)(PostDate, DateProvider, Nothing) Else m.Post.Date = Nothing
Return m Return m
End Function End Function
Friend Shared Function GetVideoInfo(ByVal URL As String) As IEnumerable(Of UserMedia) Friend Shared Function GetVideoInfo(ByVal URL As String) As IEnumerable(Of UserMedia)
Try Try
If Not URL.IsEmptyString AndAlso URL.Contains("instagram.com") Then If Not URL.IsEmptyString AndAlso URL.Contains("instagram.com") Then
Do While Right(URL, 1) = "/" : URL = Left(URL, URL.Length - 1) : Loop Dim PID$ = RegexReplace(URL, New RegexStructure(".*?instagram.com/p/([_\w\d]+)", 1))
URL = $"{URL}/?__a=1" If Not PID.IsEmptyString Then
Using t As New UserData Using t As New UserData
t.Responser = New PersonalUtilities.Tools.WEB.Response t.Responser = New PersonalUtilities.Tools.WEB.Response
t.Responser.Copy(Settings(Sites.Instagram).Responser) t.Responser.Copy(Settings(Sites.Instagram).Responser)
Dim r$ = t.Responser.GetResponse(URL,, EDP.ThrowException) t._SavedPostsIDs.Add(PID)
If Not r.IsEmptyString Then t.DownloadPosts(Nothing)
Using j As EContainer = JsonDocument.Parse(r).XmlIfNothing Return ListAddList(Nothing, t._TempMediaList)
Dim node As EContainer = j({"graphql", "shortcode_media"}).XmlIfNothing End Using
If node.Count > 0 Then t.ObtainMedia(node, String.Empty, String.Empty) End If
End Using
End If
If t._TempMediaList.Count > 0 Then Return ListAddList(Nothing, t._TempMediaList)
End Using
End If End If
Return Nothing Return Nothing
Catch ex As Exception Catch ex As Exception
Return ErrorsDescriber.Execute(EDP.ShowMainMsg + EDP.SendInLog, ex, "Instagram standalone downloader: fetch media error") Return ErrorsDescriber.Execute(EDP.ShowMainMsg + EDP.SendInLog, ex, "Instagram standalone downloader: fetch media error")
End Try End Try
End Function End Function
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If Not disposedValue And disposing Then _SavedPostsIDs.Clear()
MyBase.Dispose(disposing)
End Sub
End Class End Class
End Namespace End Namespace

View File

@@ -19,6 +19,8 @@ Namespace API.Reddit
Private Const Name_ID As String = "ID" Private Const Name_ID As String = "ID"
Private Const Name_Date As String = "Date" Private Const Name_Date As String = "Date"
Private Const Name_PostsNode As String = "Posts" Private Const Name_PostsNode As String = "Posts"
Private Const Name_UsersAdded As String = "UsersAdded"
Private Const Name_PostsDownloaded As String = "PostsDownloaded"
#End Region #End Region
Friend Const DefaultDownloadLimitCount As Integer = 1000 Friend Const DefaultDownloadLimitCount As Integer = 1000
#Region "IUserData Support" #Region "IUserData Support"
@@ -311,6 +313,31 @@ Namespace API.Reddit
End Get End Get
End Property End Property
Private ReadOnly Property Range As RangeSwitcher(Of UserPost) Private ReadOnly Property Range As RangeSwitcher(Of UserPost)
Friend ReadOnly Property CountOfAddedUsers As List(Of Integer)
Friend ReadOnly Property CountOfLoadedPostsPerSession As List(Of Integer)
Private _FirstUserAdded As Boolean = False
Friend Sub UserAdded(Optional ByVal IsAdded As Boolean = True)
If Not _FirstUserAdded Then CountOfAddedUsers.Add(0) : _FirstUserAdded = True
Dim v% = CountOfAddedUsers.Last
v += IIf(IsAdded, 1, -1)
If v < 0 Then v = 0
CountOfAddedUsers(CountOfAddedUsers.Count - 1) = v
End Sub
Friend Function GetChannelStats(ByVal Extended As Boolean) As String
Dim s$ = String.Empty
Dim p As New ANumbers With {.FormatOptions = ANumbers.Options.GroupIntegral}
If Extended Then
s.StringAppendLine($"Users added from this channel: {CountOfAddedUsers.Sum.NumToString(p)}")
s.StringAppendLine($"Users added from this channel (avg): {CountOfAddedUsers.DefaultIfEmpty(0).Average.RoundDown.NumToString(p)}")
s.StringAppendLine($"Users added from this channel (session): {CountOfAddedUsers.LastOrDefault.NumToString(p)}")
s.StringAppendLine($"Posts downloaded (avg): {CountOfLoadedPostsPerSession.DefaultIfEmpty(0).Average.RoundUp.NumToString(p)}")
s.StringAppendLine($"Posts downloaded (session): {CountOfLoadedPostsPerSession.LastOrDefault.NumToString(p)}")
Else
s.StringAppend($"Users: {CountOfAddedUsers.Sum.NumToString(p)} (avg: {CountOfAddedUsers.DefaultIfEmpty(0).Average.RoundDown.NumToString(p)}; s: {CountOfAddedUsers.LastOrDefault.NumToString(p)})")
s.StringAppend($"Posts: {CountOfLoadedPostsPerSession.DefaultIfEmpty(0).Average.RoundUp.NumToString(p)} (s: {CountOfLoadedPostsPerSession.LastOrDefault.NumToString(p)})", "; ")
End If
Return s
End Function
#Region "Limits Support" #Region "Limits Support"
Private _DownloadLimitCount As Integer? = Nothing Private _DownloadLimitCount As Integer? = Nothing
Friend Property DownloadLimitCount As Integer? Implements IChannelLimits.DownloadLimitCount Friend Property DownloadLimitCount As Integer? Implements IChannelLimits.DownloadLimitCount
@@ -379,6 +406,8 @@ Namespace API.Reddit
Posts = New List(Of UserPost) Posts = New List(Of UserPost)
PostsLatest = New List(Of UserPost) PostsLatest = New List(Of UserPost)
Range = New RangeSwitcher(Of UserPost)(Me) Range = New RangeSwitcher(Of UserPost)(Me)
CountOfAddedUsers = New List(Of Integer)
CountOfLoadedPostsPerSession = New List(Of Integer)
End Sub End Sub
Friend Sub New(ByVal f As SFile) Friend Sub New(ByVal f As SFile)
Me.New Me.New
@@ -422,7 +451,9 @@ Namespace API.Reddit
} }
d.SetLimit(Me) d.SetLimit(Me)
d.DownloadData(Token) d.DownloadData(Token)
Dim b% = Posts.Count
Posts.ListAddList(d.GetNewChannelPosts(), LAP.NotContainsOnly) Posts.ListAddList(d.GetNewChannelPosts(), LAP.NotContainsOnly)
If Posts.Count - b > 0 Then CountOfLoadedPostsPerSession.Add(Posts.Count - b)
Posts.Sort() Posts.Sort()
LatestParsedDate = If(Posts.FirstOrDefault(Function(pp) pp.Date.HasValue).Date, LatestParsedDate) LatestParsedDate = If(Posts.FirstOrDefault(Function(pp) pp.Date.HasValue).Date, LatestParsedDate)
End Using End Using
@@ -525,6 +556,8 @@ Namespace API.Reddit
Name = x.Value(Name_Name) Name = x.Value(Name_Name)
ID = x.Value(Name_ID) ID = x.Value(Name_ID)
LatestParsedDate = AConvert(Of Date)(x.Value(Name_Date), XMLDateProvider, Nothing) LatestParsedDate = AConvert(Of Date)(x.Value(Name_Date), XMLDateProvider, Nothing)
CountOfAddedUsers.ListAddList(x.Value(Name_UsersAdded).StringToList(Of Integer)("|"), LAP.ClearBeforeAdd)
CountOfLoadedPostsPerSession.ListAddList(x.Value(Name_PostsDownloaded).StringToList(Of Integer)("|"), LAP.ClearBeforeAdd)
If Not PartialLoad Then If Not PartialLoad Then
With x(Name_PostsNode).XmlIfNothing With x(Name_PostsNode).XmlIfNothing
If .Count > 0 Then .ForEach(Sub(ee) PostsLatest.Add(New UserPost With { If .Count > 0 Then .ForEach(Sub(ee) PostsLatest.Add(New UserPost With {
@@ -549,6 +582,8 @@ Namespace API.Reddit
LatestParsedDate = tmpPostList.FirstOrDefault(Function(pd) pd.Date.HasValue).Date LatestParsedDate = tmpPostList.FirstOrDefault(Function(pd) pd.Date.HasValue).Date
x.Add(Name_Date, AConvert(Of String)(LatestParsedDate, XMLDateProvider, String.Empty)) x.Add(Name_Date, AConvert(Of String)(LatestParsedDate, XMLDateProvider, String.Empty))
x.Add(Name_PostsNode, String.Empty) x.Add(Name_PostsNode, String.Empty)
x.Add(Name_UsersAdded, CountOfAddedUsers.ListToString(, "|"))
x.Add(Name_PostsDownloaded, CountOfLoadedPostsPerSession.ListToString(, "|"))
With x(Name_PostsNode) With x(Name_PostsNode)
tmpPostList.Take(200).ToList.ForEach(Sub(p) .Add(New EContainer("Post", tmpPostList.Take(200).ToList.ForEach(Sub(p) .Add(New EContainer("Post",
String.Empty, String.Empty,
@@ -578,6 +613,8 @@ Namespace API.Reddit
If disposing Then If disposing Then
Posts.Clear() Posts.Clear()
PostsLatest.Clear() PostsLatest.Clear()
CountOfAddedUsers.Clear()
CountOfLoadedPostsPerSession.Clear()
Range.Dispose() Range.Dispose()
If Not Instance Is Nothing Then Instance.Dispose() If Not Instance Is Nothing Then Instance.Dispose()
If CachePath.Exists(SFO.Path, False) Then CachePath.Delete(SFO.Path, False, False, EDP.SendInLog) If CachePath.Exists(SFO.Path, False) Then CachePath.Delete(SFO.Path, False, False, EDP.SendInLog)

View File

@@ -74,7 +74,6 @@ Namespace API.Reddit
Next Next
End If End If
Throw New ArgumentException($"Channel ID [{ChannelID}] does not found in channels collection", "ChannelID") With {.HelpLink = 1} Throw New ArgumentException($"Channel ID [{ChannelID}] does not found in channels collection", "ChannelID") With {.HelpLink = 1}
'Return Nothing
End Get End Get
End Property End Property
Friend Sub DownloadData(ByVal Token As CancellationToken, Optional ByVal SkipExists As Boolean = True, Friend Sub DownloadData(ByVal Token As CancellationToken, Optional ByVal SkipExists As Boolean = True,
@@ -111,7 +110,7 @@ Namespace API.Reddit
Return Count > 0 AndAlso Channels.Contains(_Item) Return Count > 0 AndAlso Channels.Contains(_Item)
End Function End Function
Friend Function Remove(ByVal _Item As Channel) As Boolean Implements ICollection(Of Channel).Remove Friend Function Remove(ByVal _Item As Channel) As Boolean Implements ICollection(Of Channel).Remove
If Count > 0 Then If Count > 0 And Not _Item Is Nothing Then
Dim i% = Channels.IndexOf(_Item) Dim i% = Channels.IndexOf(_Item)
If i >= 0 Then If i >= 0 Then
With Channels(i) : .Delete() : .Dispose() : End With With Channels(i) : .Delete() : .Dispose() : End With

View File

@@ -16,9 +16,8 @@ Namespace API.Reddit
Friend ReadOnly VideoRegEx As New RegexStructure("http.{0,1}://[^" & Chr(34) & "]+?mp4", True, False) Friend ReadOnly VideoRegEx As New RegexStructure("http.{0,1}://[^" & Chr(34) & "]+?mp4", True, False)
Friend ReadOnly DateProvider As New JsonDate Friend ReadOnly DateProvider As New JsonDate
Friend ReadOnly DateProviderChannel As New JsonDateChannel Friend ReadOnly DateProviderChannel As New JsonDateChannel
Private ReadOnly EUR_PROVIDER As New ANumbers(ANumbers.Modes.EUR) Private ReadOnly EUR_PROVIDER As New ANumbers(ANumbers.Cultures.EUR)
Friend Class JsonDate : Implements ICustomProvider Friend Class JsonDate : Implements ICustomProvider
''' <inheritdoc cref="ADateTime.ParseUnicodeJS(Object, Object, ErrorsDescriber)"/>
Friend Function Convert(ByVal Value As Object, ByVal DestinationType As Type, ByVal Provider As IFormatProvider, 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 Optional ByVal NothingArg As Object = Nothing, Optional ByVal e As ErrorsDescriber = Nothing) As Object Implements ICustomProvider.Convert
Return ADateTime.ParseUnicodeJS(Value, NothingArg, e) Return ADateTime.ParseUnicodeJS(Value, NothingArg, e)
@@ -28,7 +27,6 @@ Namespace API.Reddit
End Function End Function
End Class End Class
Friend Class JsonDateChannel : Implements ICustomProvider Friend Class JsonDateChannel : Implements ICustomProvider
''' <inheritdoc cref="ADateTime.ParseUnicodeJS(Object, Object, ErrorsDescriber)"/>
Friend Function Convert(ByVal Value As Object, ByVal DestinationType As Type, ByVal Provider As IFormatProvider, 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 Optional ByVal NothingArg As Object = Nothing, Optional ByVal e As ErrorsDescriber = Nothing) As Object Implements ICustomProvider.Convert
Return ADateTime.ParseUnicode(AConvert(Of Integer)(Value, EUR_PROVIDER, Value), NothingArg, e) Return ADateTime.ParseUnicode(AConvert(Of Integer)(Value, EUR_PROVIDER, Value), NothingArg, e)

View File

@@ -74,7 +74,7 @@ Namespace API.Reddit
ConcatFile.Extension = "mp4" ConcatFile.Extension = "mp4"
CachePath = $"{f.PathWithSeparator}_Cache\{SFile.GetDirectories($"{f.PathWithSeparator}_Cache\",,, EDP.ReturnValue).ListIfNothing.Count + 1}\" CachePath = $"{f.PathWithSeparator}_Cache\{SFile.GetDirectories($"{f.PathWithSeparator}_Cache\",,, EDP.ReturnValue).ListIfNothing.Count + 1}\"
If CachePath.Exists(SFO.Path) Then If CachePath.Exists(SFO.Path) Then
Dim p As New SFileNumbers(ConcatFile.Name,,, New ANumbers(ANumbers.Modes.USA) With {.GroupSeparator = String.Empty, .FormatMode = ANumbers.Formats.General}) Dim p As New SFileNumbers(ConcatFile.Name,,, New ANumbers With {.Format = ANumbers.Formats.General})
ConcatFile = SFile.Indexed_IndexFile(ConcatFile,, p, EDP.ReturnValue) ConcatFile = SFile.Indexed_IndexFile(ConcatFile,, p, EDP.ReturnValue)
Dim i% Dim i%
Dim eFiles As New List(Of SFile) Dim eFiles As New List(Of SFile)

View File

@@ -7,29 +7,23 @@
' This program is distributed in the hope that it will be useful, ' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY ' but WITHOUT ANY WARRANTY
Imports SCrawler.API.Base Imports SCrawler.API.Base
Imports System.Threading
Imports PersonalUtilities.Forms.Toolbars
Namespace API.Reddit Namespace API.Reddit
Friend NotInheritable Class ProfileSaved Friend NotInheritable Class ProfileSaved
Friend Shared ReadOnly Property DataPath As SFile = $"{Settings(Sites.Reddit).Path.PathNoSeparator}\!Saved\"
Private Sub New() Private Sub New()
End Sub End Sub
Friend Shared Sub Download(ByRef Toolbar As StatusStrip, ByRef PR As ToolStripProgressBar) Friend Shared Sub Download(ByRef Bar As MyProgress, ByVal Token As CancellationToken)
Try Try
Dim Bar = New PersonalUtilities.Forms.Toolbars.MyProgress(Toolbar, PR, Nothing) Dim u As New UserInfo(Settings(Sites.Reddit).SavedPostsUserName.Value, Sites.Reddit) With {.IsChannel = True, .SpecialPath = DataPath}
Dim u As New UserInfo(Settings(Sites.Reddit).SavedPostsUserName.Value, Sites.Reddit) With {
.IsChannel = True,
.SpecialPath = $"{Settings(Sites.Reddit).Path.PathWithSeparator}\!Saved\"
}
u.UpdateUserFile() u.UpdateUserFile()
Using user As IUserData = UserDataBase.GetInstance(u) Using user As New UserData(u,, False)
DirectCast(user.Self, UserDataBase).IsSavedPosts = True DirectCast(user.Self, UserDataBase).IsSavedPosts = True
Bar.Enabled = True user.Progress = Bar
DirectCast(user.Self, UserData).Progress = Bar
If Not user.FileExists Then user.UpdateUserInformation() If Not user.FileExists Then user.UpdateUserInformation()
user.DownloadData(Nothing) user.DownloadData(Token)
Dim m As New MMessage("Reddit saved posts download complete", "Saved posts downloading", {"OK", "Open folder"}) Bar.InformationTemporary = $"Images: {user.DownloadedPictures}; Videos: {user.DownloadedVideos}"
m.Text.StringAppendLine($"Downloaded images: {user.DownloadedPictures}")
m.Text.StringAppendLine($"Downloaded videos: {user.DownloadedVideos}")
If MsgBoxE(m) = 1 Then u.File.CutPath.Open(SFO.Path)
Bar.Enabled = False
End Using End Using
Catch ex As Exception Catch ex As Exception
ErrorsDescriber.Execute(EDP.SendInLog, ex, "[API.Reddit.ProfileSaved.Download]") ErrorsDescriber.Execute(EDP.SendInLog, ex, "[API.Reddit.ProfileSaved.Download]")

View File

@@ -7,7 +7,6 @@
' This program is distributed in the hope that it will be useful, ' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY ' but WITHOUT ANY WARRANTY
Imports PersonalUtilities.Functions.XML Imports PersonalUtilities.Functions.XML
Imports PersonalUtilities.Forms.Toolbars
Imports PersonalUtilities.Tools.ImageRenderer Imports PersonalUtilities.Tools.ImageRenderer
Imports PersonalUtilities.Tools.WebDocuments.JSON Imports PersonalUtilities.Tools.WebDocuments.JSON
Imports System.Net Imports System.Net
@@ -50,15 +49,6 @@ Namespace API.Reddit
Select c.Post) Else Return Nothing Select c.Post) Else Return Nothing
End Function End Function
#End Region #End Region
Private _Progress As MyProgress
Friend Property Progress As MyProgress
Get
If _Progress Is Nothing Then Return MainProgress Else Return _Progress
End Get
Set(ByVal p As MyProgress)
_Progress = p
End Set
End Property
#Region "Initializers" #Region "Initializers"
''' <summary>Video downloader initializer</summary> ''' <summary>Video downloader initializer</summary>
Private Sub New() Private Sub New()
@@ -74,9 +64,13 @@ Namespace API.Reddit
If _LoadUserInformation Then LoadUserInformation() If _LoadUserInformation Then LoadUserInformation()
End Sub End Sub
#End Region #End Region
#Region "Load and Update user info"
Protected Overrides Sub LoadUserInformation_OptionalFields(ByRef Container As XmlFile, ByVal Loading As Boolean)
End Sub
#End Region
#Region "Download Overrides" #Region "Download Overrides"
Friend Overrides Sub DownloadData(ByVal Token As CancellationToken) Friend Overrides Sub DownloadData(ByVal Token As CancellationToken)
If IsChannel AndAlso Not ChannelInfo.IsRegularChannel Then If Not IsSavedPosts AndAlso (IsChannel AndAlso Not ChannelInfo.IsRegularChannel) Then
If Not Responser Is Nothing Then Responser.Dispose() If Not Responser Is Nothing Then Responser.Dispose()
Responser = New PersonalUtilities.Tools.WEB.Response Responser = New PersonalUtilities.Tools.WEB.Response
Responser.Copy(Settings(Sites.Reddit).Responser) Responser.Copy(Settings(Sites.Reddit).Responser)
@@ -92,7 +86,9 @@ Namespace API.Reddit
End Sub End Sub
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken) Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
_TotalPostsDownloaded = 0 _TotalPostsDownloaded = 0
If IsChannel Then If IsSavedPosts Then
DownloadDataChannel(String.Empty, Token)
ElseIf IsChannel Then
If ChannelInfo.IsRegularChannel Then If ChannelInfo.IsRegularChannel Then
ChannelPostsNames.ListAddList(_TempPostsList, LNC) ChannelPostsNames.ListAddList(_TempPostsList, LNC)
If ChannelPostsNames.Count > 0 Then If ChannelPostsNames.Count > 0 Then
@@ -129,7 +125,7 @@ Namespace API.Reddit
URL = $"https://gateway.reddit.com/desktopapi/v1/user/{Name}/posts?rtj=only&allow_quarantined=true&allow_over18=1&include=identity&after={POST}&dist=25&sort=new&t=all&layout=classic" URL = $"https://gateway.reddit.com/desktopapi/v1/user/{Name}/posts?rtj=only&allow_quarantined=true&allow_over18=1&include=identity&after={POST}&dist=25&sort=new&t=all&layout=classic"
ThrowAny(Token) ThrowAny(Token)
Dim r$ = GetSiteResponse(URL) Dim r$ = Responser.GetResponse(URL,, EDP.ThrowException)
If Not r.IsEmptyString Then If Not r.IsEmptyString Then
Using w As EContainer = JsonDocument.Parse(r).XmlIfNothing Using w As EContainer = JsonDocument.Parse(r).XmlIfNothing
If w.Count > 0 Then If w.Count > 0 Then
@@ -203,17 +199,8 @@ Namespace API.Reddit
If POST.IsEmptyString And ExistsDetected Then Exit Sub If POST.IsEmptyString And ExistsDetected Then Exit Sub
If Not PostID.IsEmptyString And NewPostDetected Then DownloadDataUser(PostID, Token) If Not PostID.IsEmptyString And NewPostDetected Then DownloadDataUser(PostID, Token)
End If End If
Catch oex As OperationCanceledException When Token.IsCancellationRequested
Catch dex As ObjectDisposedException When Disposed
Catch ex As Exception Catch ex As Exception
If ex.HelpLink = NonExistendUserHelp Then ProcessException(ex, Token, $"data downloading error [{URL}]")
UserExists = False
ElseIf ex.HelpLink = SuspendedUserHelp Then
UserSuspended = True
Else
LogError(ex, $"data downloading error [{URL}]")
HasError = True
End If
End Try End Try
End Sub End Sub
Private Sub DownloadDataChannel(ByVal POST As String, ByVal Token As CancellationToken) Private Sub DownloadDataChannel(ByVal POST As String, ByVal Token As CancellationToken)
@@ -234,7 +221,7 @@ Namespace API.Reddit
End If End If
ThrowAny(Token) ThrowAny(Token)
Dim r$ = GetSiteResponse(URL) Dim r$ = Responser.GetResponse(URL,, EDP.ThrowException)
If Not r.IsEmptyString Then If Not r.IsEmptyString Then
Using w As EContainer = JsonDocument.Parse(r).XmlIfNothing Using w As EContainer = JsonDocument.Parse(r).XmlIfNothing
If w.Count > 0 Then If w.Count > 0 Then
@@ -296,17 +283,8 @@ Namespace API.Reddit
If POST.IsEmptyString And ExistsDetected Then Exit Sub If POST.IsEmptyString And ExistsDetected Then Exit Sub
If Not PostID.IsEmptyString And NewPostDetected Then DownloadDataChannel(PostID, Token) If Not PostID.IsEmptyString And NewPostDetected Then DownloadDataChannel(PostID, Token)
End If End If
Catch oex As OperationCanceledException When Token.IsCancellationRequested
Catch dex As ObjectDisposedException When Disposed
Catch ex As Exception Catch ex As Exception
If ex.HelpLink = NonExistendUserHelp Then ProcessException(ex, Token, $"channel data downloading error [{URL}]")
UserExists = False
ElseIf ex.HelpLink = SuspendedUserHelp Then
UserSuspended = True
Else
LogError(ex, $"channel data downloading error [{URL}]")
HasError = True
End If
End Try End Try
End Sub End Sub
#End Region #End Region
@@ -366,8 +344,7 @@ Namespace API.Reddit
End If End If
Return added Return added
Catch ex As Exception Catch ex As Exception
LogError(ex, "gallery parsing error") ProcessException(ex, Nothing, "gallery parsing error", False)
HasError = True
Return False Return False
End Try End Try
End Function End Function
@@ -382,7 +359,7 @@ Namespace API.Reddit
ThrowAny(Token) ThrowAny(Token)
If _TempMediaList(i).Type = UTypes.VideoPre Then If _TempMediaList(i).Type = UTypes.VideoPre Then
m = _TempMediaList(i) m = _TempMediaList(i)
r = GetSiteResponse(m.URL, e) r = Responser.GetResponse(m.URL,, e)
_TempMediaList(i) = New UserMedia _TempMediaList(i) = New UserMedia
If Not r.IsEmptyString Then If Not r.IsEmptyString Then
v = RegexReplace(r, VideoRegEx) v = RegexReplace(r, VideoRegEx)
@@ -395,10 +372,8 @@ Namespace API.Reddit
End If End If
Next Next
End If End If
Catch oex As OperationCanceledException When Token.IsCancellationRequested
Catch dex As ObjectDisposedException When Disposed
Catch ex As Exception Catch ex As Exception
LogError(ex, "video reparsing error") ProcessException(ex, Token, "video reparsing error", False)
End Try End Try
End Sub End Sub
Friend Shared Function GetVideoInfo(ByVal URL As String) As IEnumerable(Of UserMedia) Friend Shared Function GetVideoInfo(ByVal URL As String) As IEnumerable(Of UserMedia)
@@ -433,7 +408,7 @@ Namespace API.Reddit
Try Try
If Not URL.IsEmptyString AndAlso URL.StringContains({".jpg", ".png", ".jpeg"}) Then If Not URL.IsEmptyString AndAlso URL.StringContains({".jpg", ".png", ".jpeg"}) Then
Dim f As SFile = CStr(RegexReplace(URL, FilesPattern)) Dim f As SFile = CStr(RegexReplace(URL, FilesPattern))
Return Not f.IsEmptyString And Not f.File.IsEmptyString Return Not f.File.IsEmptyString
End If End If
Return False Return False
Catch ex As Exception Catch ex As Exception
@@ -454,7 +429,7 @@ Namespace API.Reddit
If _ContentNew.Count > 0 Then If _ContentNew.Count > 0 Then
MyFile.Exists(SFO.Path) MyFile.Exists(SFO.Path)
Dim MyDir$ Dim MyDir$
If IsChannel And SaveToCache Then If Not IsSavedPosts AndAlso (IsChannel And SaveToCache) Then
MyDir = ChannelInfo.CachePath.PathNoSeparator MyDir = ChannelInfo.CachePath.PathNoSeparator
Else Else
MyDir = MyFile.CutPath.PathNoSeparator MyDir = MyFile.CutPath.PathNoSeparator
@@ -605,29 +580,20 @@ Namespace API.Reddit
HasError = True HasError = True
End Try End Try
End Sub End Sub
Protected Function GetSiteResponse(ByVal URL As String, Optional ByVal e As ErrorsDescriber = Nothing) As String Protected Overrides Function DownloadingException(ByVal ex As Exception, ByVal Message As String, Optional ByVal FromPE As Boolean = False) As Integer
Try If Responser.StatusCode = HttpStatusCode.NotFound Then
Return Responser.GetResponse(URL,, EDP.ThrowException) UserExists = False
Catch ex As Exception ElseIf Responser.StatusCode = HttpStatusCode.Forbidden Then
HasError = True UserSuspended = True
Dim OptText$ = String.Empty ElseIf Responser.StatusCode = HttpStatusCode.BadGateway Or
If Not e.Exists Then Responser.StatusCode = HttpStatusCode.ServiceUnavailable Or
Dim ee As EDP = EDP.SendInLog Responser.StatusCode = HttpStatusCode.GatewayTimeout Then
If Responser.StatusCode = HttpStatusCode.NotFound Then MyMainLOG = "Reddit is currently unavailable"
ee = EDP.ThrowException Else
OptText = ": USER NOT FOUND" If Not FromPE Then LogError(ex, Message) : HasError = True
ex.HelpLink = NonExistendUserHelp Return 0
ElseIf Responser.StatusCode = HttpStatusCode.Forbidden Then End If
ee = EDP.ThrowException Return 1
OptText = ": USER PROFILE SUSPENDED"
ex.HelpLink = SuspendedUserHelp
Else
ee += EDP.ReturnValue
End If
e = New ErrorsDescriber(ee)
End If
Return ErrorsDescriber.Execute(e, ex, $"[{Site} - {Name}: GetSiteResponse([{URL}])]{OptText}", String.Empty)
End Try
End Function End Function
Protected Overrides Sub Dispose(ByVal disposing As Boolean) Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If Not disposedValue And disposing Then ChannelPostsNames.Clear() : _ExistsUsersNames.Clear() If Not disposedValue And disposing Then ChannelPostsNames.Clear() : _ExistsUsersNames.Clear()

View File

@@ -0,0 +1,22 @@
' Copyright (C) 2022 Andy
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY
Namespace API.RedGifs
Friend Module Declarations
Friend ReadOnly DateProvider As New JsonDate
Friend Class JsonDate : Implements ICustomProvider
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 ADateTime.ParseUnicode(Value, NothingArg, e)
End Function
Private Function GetFormat(ByVal FormatType As Type) As Object Implements IFormatProvider.GetFormat
Throw New NotImplementedException("GetFormat is not available in this context")
End Function
End Class
End Module
End Namespace

View File

@@ -0,0 +1,90 @@
' Copyright (C) 2022 Andy
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY
Imports PersonalUtilities.Functions.XML
Imports PersonalUtilities.Tools.WebDocuments.JSON
Imports System.Threading
Imports System.Net
Imports SCrawler.API.Base
Imports UTypes = SCrawler.API.Base.UserMedia.Types
Namespace API.RedGifs
Friend Class UserData : Inherits UserDataBase
Friend Overrides Property Site As Sites = Sites.RedGifs
Friend Sub New(ByVal u As UserInfo, Optional ByVal _LoadUserInformation As Boolean = True)
User = u
If _LoadUserInformation Then LoadUserInformation()
End Sub
Protected Overrides Sub LoadUserInformation_OptionalFields(ByRef Container As XmlFile, ByVal Loading As Boolean)
End Sub
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
DownloadData(1, Token)
End Sub
Private Overloads Sub DownloadData(ByVal Page As Integer, ByVal Token As CancellationToken)
Dim URL$ = String.Empty
Try
URL = $"https://api.redgifs.com/v2/users/{Name}/search?order=recent&page={Page}"
Dim r$ = Responser.GetResponse(URL,, EDP.ThrowException)
Dim postDate$, postID$
Dim pTotal% = 0
Dim u$
Dim ut As UTypes
If Not r.IsEmptyString Then
Using j As EContainer = JsonDocument.Parse(r).XmlIfNothing
If j.Contains("gifs") Then
pTotal = j.Value("pages").FromXML(Of Integer)(0)
For Each g As EContainer In j("gifs")
postDate = g.Value("createDate")
postID = g.Value("id")
If Not _TempPostsList.Contains(postID) Then _TempPostsList.Add(postID) Else Exit For
With g("urls")
If .ListExists Then
u = If(.Item("hd"), .Item("sd")).XmlIfNothingValue
If Not u.IsEmptyString Then
ut = UTypes.Undefined
'Type 1: video
'Type 2: image
Select Case g.Value("type").FromXML(Of Integer)(0)
Case 1 : ut = UTypes.Video
Case 2 : ut = UTypes.Picture
End Select
If Not ut = UTypes.Undefined Then _TempMediaList.ListAddValue(MediaFromData(ut, u, postID, postDate))
End If
End If
End With
Next
End If
End Using
End If
If pTotal > 0 And Page < pTotal Then DownloadData(Page + 1, Token)
Catch ex As Exception
ProcessException(ex, Token, $"data downloading error [{URL}]")
End Try
End Sub
Protected Overrides Sub ReparseVideo(ByVal Token As CancellationToken)
End Sub
Protected Overrides Sub DownloadContent(ByVal Token As CancellationToken)
DownloadContentDefault(Token)
End Sub
Private Shared Function MediaFromData(ByVal t As UTypes, ByVal _URL As String, ByVal PostID As String, ByVal PostDate As String) As UserMedia
_URL = LinkFormatterSecure(RegexReplace(_URL.Replace("\", String.Empty), LinkPattern))
Dim m As New UserMedia(_URL, t) With {.Post = New UserPost With {.ID = PostID}}
If Not m.URL.IsEmptyString Then m.File = CStr(RegexReplace(m.URL, FilesPattern)) : m.URL_BASE = m.URL
If Not PostDate.IsEmptyString Then m.Post.Date = AConvert(Of Date)(PostDate, DateProvider, Nothing) Else m.Post.Date = Nothing
Return m
End Function
Protected Overrides Function DownloadingException(ByVal ex As Exception, ByVal Message As String, Optional ByVal FromPE As Boolean = False) As Integer
If Responser.StatusCode = HttpStatusCode.NotFound Then
UserExists = False
Else
If Not FromPE Then LogError(ex, Message) : HasError = True
Return 0
End If
Return 1
End Function
End Class
End Namespace

View File

@@ -12,35 +12,10 @@ Imports PersonalUtilities.Functions.XML
Imports System.Net Imports System.Net
Imports System.Threading Imports System.Threading
Imports SCrawler.API.Base Imports SCrawler.API.Base
Imports UStates = SCrawler.API.Base.UserMedia.States
Namespace API.Twitter Namespace API.Twitter
Friend Class UserData : Inherits UserDataBase Friend Class UserData : Inherits UserDataBase
#Region "Declarations" #Region "Declarations"
Friend Overrides Property Site As Sites = Sites.Twitter Friend Overrides Property Site As Sites = Sites.Twitter
Private Structure Sizes : Implements IComparable(Of Sizes)
Friend Value As Integer
Friend Name As String
Friend ReadOnly HasError As Boolean
Friend Sub New(ByVal _Value As String, ByVal _Name As String)
Try
Value = _Value
Name = _Name
Catch ex As Exception
HasError = True
End Try
End Sub
Friend Function CompareTo(ByVal Other As Sizes) As Integer Implements IComparable(Of Sizes).CompareTo
Return Value.CompareTo(Other.Value) * -1
End Function
Friend Shared Function Reparse(ByRef Current As Sizes, ByVal Other As Sizes, ByVal LargeContained As Boolean) As Sizes
If LargeContained And Current.Name.IsEmptyString And Current.Value > Other.Value Then Current.Name = "large"
Return Current
End Function
Friend Shared Function ApplyLarge(ByRef s As Sizes) As Sizes
s.Name = "large"
Return s
End Function
End Structure
#End Region #End Region
#Region "Initializer" #Region "Initializer"
Friend Sub New(ByVal u As UserInfo, Optional ByVal _LoadUserInformation As Boolean = True) Friend Sub New(ByVal u As UserInfo, Optional ByVal _LoadUserInformation As Boolean = True)
@@ -48,6 +23,10 @@ Namespace API.Twitter
If _LoadUserInformation Then LoadUserInformation() If _LoadUserInformation Then LoadUserInformation()
End Sub End Sub
#End Region #End Region
#Region "Load and Update user info"
Protected Overrides Sub LoadUserInformation_OptionalFields(ByRef Container As XmlFile, ByVal Loading As Boolean)
End Sub
#End Region
#Region "Download functions" #Region "Download functions"
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken) Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
DownloadData(String.Empty, Token) DownloadData(String.Empty, Token)
@@ -115,19 +94,8 @@ Namespace API.Twitter
If POST.IsEmptyString And ExistsDetected Then Exit Sub If POST.IsEmptyString And ExistsDetected Then Exit Sub
If Not PostID.IsEmptyString And NewPostDetected Then DownloadData(PostID, Token) If Not PostID.IsEmptyString And NewPostDetected Then DownloadData(PostID, Token)
End If End If
Catch oex As OperationCanceledException When Token.IsCancellationRequested
Catch dex As ObjectDisposedException When Disposed
Catch ex As Exception Catch ex As Exception
If Responser.StatusCode = HttpStatusCode.NotFound Then ProcessException(ex, Token, $"data downloading error [{URL}]")
UserExists = False
ElseIf Responser.StatusCode = HttpStatusCode.Unauthorized Then
UserSuspended = True
ElseIf Responser.StatusCode = HttpStatusCode.BadRequest Then
MyMainLOG = "Twitter has invalid credentials"
Else
LogError(ex, $"data downloading error [{URL}]")
HasError = True
End If
End Try End Try
End Sub End Sub
Friend Shared Function GetVideoInfo(ByVal URL As String) As IEnumerable(Of UserMedia) Friend Shared Function GetVideoInfo(ByVal URL As String) As IEnumerable(Of UserMedia)
@@ -164,12 +132,12 @@ Namespace API.Twitter
Next Next
If l.Count > 0 Then If l.Count > 0 Then
l.Sort() l.Sort()
If l(0).Name.IsEmptyString And LargeContained Then Return "large" Else Return l(0).Name If l(0).Data.IsEmptyString And LargeContained Then Return "large" Else Return l(0).Data
End If End If
End If End If
Return String.Empty Return String.Empty
Catch ex As Exception Catch ex As Exception
LogError(ex, "[GetPictureOption]") LogError(ex, "[API.Twitter.UserData.GetPictureOption]")
Return String.Empty Return String.Empty
End Try End Try
End Function End Function
@@ -181,7 +149,7 @@ Namespace API.Twitter
If Not URL.IsEmptyString Then _TempMediaList.ListAddValue(MediaFromData(URL, PostID, PostDate), LNC) : Return True If Not URL.IsEmptyString Then _TempMediaList.ListAddValue(MediaFromData(URL, PostID, PostDate), LNC) : Return True
Return False Return False
Catch ex As Exception Catch ex As Exception
LogError(ex, "[CheckVideoNode]") LogError(ex, "[API.Twitter.UserData.CheckVideoNode]")
Return False Return False
End Try End Try
End Function End Function
@@ -202,7 +170,7 @@ Namespace API.Twitter
End If End If
Next Next
If l.Count > 0 Then l.RemoveAll(Function(s) s.HasError) If l.Count > 0 Then l.RemoveAll(Function(s) s.HasError)
If l.Count > 0 Then l.Sort() : Return l(0).Name If l.Count > 0 Then l.Sort() : Return l(0).Data
End If End If
Return String.Empty Return String.Empty
End Function End Function
@@ -222,70 +190,20 @@ Namespace API.Twitter
End Function End Function
#End Region #End Region
Protected Overrides Sub DownloadContent(ByVal Token As CancellationToken) Protected Overrides Sub DownloadContent(ByVal Token As CancellationToken)
Try DownloadContentDefault(Token)
Dim i%
Dim dCount% = 0, dTotal% = 0
ThrowAny(Token)
If _ContentNew.Count > 0 Then
_ContentNew.RemoveAll(Function(c) c.URL.IsEmptyString)
If _ContentNew.Count > 0 Then
MyFile.Exists(SFO.Path)
Dim MyDir$ = MyFile.CutPath.PathNoSeparator
Dim vsf As Boolean = SeparateVideoFolderF
Dim f As SFile
Dim v As UserMedia
Using w As New WebClient
If vsf Then SFileShares.SFileExists($"{MyDir}\Video\", SFO.Path)
MainProgress.TotalCount += _ContentNew.Count
For i = 0 To _ContentNew.Count - 1
ThrowAny(Token)
v = _ContentNew(i)
v.State = UStates.Tried
If v.File.IsEmptyString Then
f = v.URL
Else
f = v.File
End If
f.Separator = "\"
f.Path = MyDir
If v.URL_BASE.IsEmptyString Then v.URL_BASE = v.URL
If Not v.File.IsEmptyString AndAlso Not v.URL_BASE.IsEmptyString Then
Try
If f.Extension = "mp4" And vsf Then f.Path = $"{f.PathWithSeparator}Video"
w.DownloadFile(v.URL_BASE, f.ToString)
Select Case f.Extension
Case "mp4" : v.Type = UserMedia.Types.Video : DownloadedVideos += 1 : _CountVideo += 1
Case Else : v.Type = UserMedia.Types.Picture : DownloadedPictures += 1 : _CountPictures += 1
End Select
v.File = ChangeFileNameByProvider(f, v)
v.State = UStates.Downloaded
dCount += 1
Catch wex As Exception
ErrorDownloading(f, v.URL_BASE)
End Try
Else
v.State = UStates.Skipped
End If
_ContentNew(i) = v
If DownloadTopCount.HasValue AndAlso dCount >= DownloadTopCount.Value Then
MainProgress.Perform(_ContentNew.Count - dTotal)
Exit Sub
Else
dTotal += 1
MainProgress.Perform()
End If
Next
End Using
End If
End If
Catch oex As OperationCanceledException When Token.IsCancellationRequested
Catch dex As ObjectDisposedException When Disposed
Catch ex As Exception
LogError(ex, "content downloading error")
HasError = True
End Try
End Sub End Sub
Protected Overrides Function DownloadingException(ByVal ex As Exception, ByVal Message As String, Optional ByVal FromPE As Boolean = False) As Integer
If Responser.StatusCode = HttpStatusCode.NotFound Then
UserExists = False
ElseIf Responser.StatusCode = HttpStatusCode.Unauthorized Then
UserSuspended = True
ElseIf Responser.StatusCode = HttpStatusCode.BadRequest Then
MyMainLOG = "Twitter has invalid credentials"
Else
If Not FromPE Then LogError(ex, Message) : HasError = True
Return 0
End If
Return 1
End Function
End Class End Class
End Namespace End Namespace

View File

@@ -7,6 +7,7 @@
' This program is distributed in the hope that it will be useful, ' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY ' but WITHOUT ANY WARRANTY
Imports PersonalUtilities.Tools Imports PersonalUtilities.Tools
Imports PersonalUtilities.Functions.XML
Imports System.Threading Imports System.Threading
Imports SCrawler.API.Base Imports SCrawler.API.Base
Namespace API Namespace API
@@ -271,6 +272,8 @@ Namespace API
Friend Overrides Sub LoadContentInformation() Friend Overrides Sub LoadContentInformation()
If Count > 0 Then Collections.ForEach(Sub(c) DirectCast(c.Self, UserDataBase).LoadContentInformation()) If Count > 0 Then Collections.ForEach(Sub(c) DirectCast(c.Self, UserDataBase).LoadContentInformation())
End Sub End Sub
Protected Overrides Sub LoadUserInformation_OptionalFields(ByRef Container As XmlFile, ByVal Loading As Boolean)
End Sub
Friend Overrides Property DownloadTopCount As Integer? Friend Overrides Property DownloadTopCount As Integer?
Get Get
If Count > 0 Then If Count > 0 Then
@@ -292,6 +295,9 @@ Namespace API
End Sub End Sub
Protected Overrides Sub DownloadContent(ByVal Token As CancellationToken) Protected Overrides Sub DownloadContent(ByVal Token As CancellationToken)
End Sub End Sub
Protected Overrides Function DownloadingException(ByVal ex As Exception, ByVal Message As String, Optional ByVal FromPE As Boolean = False) As Integer
Return 0
End Function
Private Sub User_OnUserUpdated(ByVal User As IUserData) Private Sub User_OnUserUpdated(ByVal User As IUserData)
Raise_OnUserUpdated() Raise_OnUserUpdated()
End Sub End Sub
@@ -338,16 +344,16 @@ Namespace API
End Sub End Sub
''' <summary>FOR SETTINGS START LOADING ONLY</summary> ''' <summary>FOR SETTINGS START LOADING ONLY</summary>
Friend Overloads Sub Add(ByVal u As UserInfo, Optional ByVal _LoadData As Boolean = True) Friend Overloads Sub Add(ByVal u As UserInfo, Optional ByVal _LoadData As Boolean = True)
Select Case u.Site Collections.Add(GetInstance(u, _LoadData))
Case Sites.Reddit : Collections.Add(New Reddit.UserData(u, _LoadData)) If Not Collections.Last Is Nothing Then
Case Sites.Twitter : Collections.Add(New Twitter.UserData(u, _LoadData)) With DirectCast(Collections.Last.Self, UserDataBase)
Case Else : Exit Sub .CreateButtons(Count - 1)
End Select AddHandler .BTT_CONTEXT_DELETE.Click, AddressOf BTT_CONTEXT_DELETE_Click
With DirectCast(Collections.Last.Self, UserDataBase) End With
.CreateButtons(Count - 1) AddHandler Collections.Last.OnUserUpdated, AddressOf User_OnUserUpdated
AddHandler .BTT_CONTEXT_DELETE.Click, AddressOf BTT_CONTEXT_DELETE_Click Else
End With Collections.RemoveAt(Count - 1)
AddHandler Collections.Last.OnUserUpdated, AddressOf User_OnUserUpdated End If
End Sub End Sub
Friend Sub AddRange(ByVal _Items As IEnumerable(Of IUserData)) Friend Sub AddRange(ByVal _Items As IEnumerable(Of IUserData))
If Not _Items Is Nothing AndAlso _Items.Count > 0 Then If Not _Items Is Nothing AndAlso _Items.Count > 0 Then

View File

@@ -19,20 +19,26 @@ Imports CmbDefaultButtons = PersonalUtilities.Forms.Controls.Base.ActionButton.D
Imports RButton = PersonalUtilities.Tools.RangeSwitcherButton.Types Imports RButton = PersonalUtilities.Tools.RangeSwitcherButton.Types
Friend Class ChannelViewForm : Implements IChannelLimits Friend Class ChannelViewForm : Implements IChannelLimits
Friend Event OnUsersAdded(ByVal StartIndex As Integer) Friend Event OnUsersAdded(ByVal StartIndex As Integer)
Friend Event OnDownloadDone(ByVal Message As String)
#Region "Appended user structure" #Region "Appended user structure"
Private Structure PendingUser Private Structure PendingUser
Friend ID As String Friend ID As String
Friend File As SFile Friend File As SFile
Friend Sub New(ByVal _ID As String, Optional ByVal _File As SFile = Nothing) Friend Channel As Channel
Friend Sub New(ByVal _ID As String, ByRef _Channel As Channel, Optional ByVal _File As SFile = Nothing)
ID = _ID ID = _ID
Channel = _Channel
If Settings.FromChannelCopyImageToUser Then File = _File If Settings.FromChannelCopyImageToUser Then File = _File
End Sub End Sub
Public Shared Widening Operator CType(ByVal _ID As String) As PendingUser Public Shared Widening Operator CType(ByVal _ID As String) As PendingUser
Return New PendingUser(_ID, False) Return New PendingUser(_ID, Nothing)
End Operator End Operator
Public Shared Widening Operator CType(ByVal u As PendingUser) As String Public Shared Widening Operator CType(ByVal u As PendingUser) As String
Return u.ToString Return u.ToString
End Operator End Operator
Friend Sub ChannelUserAdded(Optional ByVal IsAdded As Boolean = True)
If Not Channel Is Nothing Then Channel.UserAdded(IsAdded)
End Sub
Public Overrides Function ToString() As String Public Overrides Function ToString() As String
Return ID Return ID
End Function End Function
@@ -53,6 +59,7 @@ Friend Class ChannelViewForm : Implements IChannelLimits
Private WithEvents OPT_LIMITS_COUNT As RadioButton Private WithEvents OPT_LIMITS_COUNT As RadioButton
Private WithEvents OPT_LIMITS_POST As RadioButton Private WithEvents OPT_LIMITS_POST As RadioButton
Private WithEvents OPT_LIMITS_DATE As RadioButton Private WithEvents OPT_LIMITS_DATE As RadioButton
Private WithEvents BTT_SHOW_STATS As ToolStripButton
#End Region #End Region
Private ReadOnly CProvider As ANumbers Private ReadOnly CProvider As ANumbers
Private ReadOnly CProgress As MyProgress Private ReadOnly CProgress As MyProgress
@@ -134,7 +141,7 @@ Friend Class ChannelViewForm : Implements IChannelLimits
InitializeComponent() InitializeComponent()
MyDefs = New DefaultFormProps MyDefs = New DefaultFormProps
CProgress = New MyProgress(ToolbarBOTTOM, PR_CN, LBL_STATUS, "Downloading data") With {.PerformMod = 10, .DropCurrentProgressOnTotalChange = False} CProgress = New MyProgress(ToolbarBOTTOM, PR_CN, LBL_STATUS, "Downloading data") With {.PerformMod = 10, .DropCurrentProgressOnTotalChange = False}
CProvider = New ANumbers(ANumbers.Modes.USA) With {.GroupSize = 3, .DecimalDigits = 0} CProvider = New ANumbers With {.FormatOptions = ANumbers.Options.GroupIntegral}
LimitProvider = New ADateTime("dd.MM.yyyy HH:mm") LimitProvider = New ADateTime("dd.MM.yyyy HH:mm")
PendingUsers = New List(Of PendingUser) PendingUsers = New List(Of PendingUser)
@@ -149,7 +156,8 @@ Friend Class ChannelViewForm : Implements IChannelLimits
} }
CMB_CHANNELS.Buttons.AddRange({CmbDefaultButtons.Refresh, CmbDefaultButtons.Add, CmbDefaultButtons.Delete, CMB_CHANNELS.Buttons.AddRange({CmbDefaultButtons.Refresh, CmbDefaultButtons.Add, CmbDefaultButtons.Delete,
New ActionButton(CmbDefaultButtons.Up) With {.ToolTipText = "Previous item (F1)"}, New ActionButton(CmbDefaultButtons.Up) With {.ToolTipText = "Previous item (F1)"},
New ActionButton(CmbDefaultButtons.Down) With {.ToolTipText = "Next item (F4)"}}) New ActionButton(CmbDefaultButtons.Down) With {.ToolTipText = "Next item (F4)"},
CmbDefaultButtons.Info})
TXT_LIMIT = New TextBoxExtended With { TXT_LIMIT = New TextBoxExtended With {
.CaptionText = "Limit", .CaptionText = "Limit",
.Margin = New Padding(2), .Margin = New Padding(2),
@@ -168,6 +176,9 @@ Friend Class ChannelViewForm : Implements IChannelLimits
OPT_LIMITS_DATE = New RadioButton With {.Text = "Date", .BackColor = Color.Transparent, .Margin = New Padding(2)} OPT_LIMITS_DATE = New RadioButton With {.Text = "Date", .BackColor = Color.Transparent, .Margin = New Padding(2)}
CH_HIDE_EXISTS_USERS = New CheckBox With {.Text = "Hide exists users", .BackColor = Color.Transparent, .Margin = New Padding(2), CH_HIDE_EXISTS_USERS = New CheckBox With {.Text = "Hide exists users", .BackColor = Color.Transparent, .Margin = New Padding(2),
.Checked = Settings.ChannelsHideExistsUser} .Checked = Settings.ChannelsHideExistsUser}
BTT_SHOW_STATS = New ToolStripButton With {.Text = "Info", .Image = PersonalUtilities.My.Resources.InfoPic_32,
.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText, .Alignment = ToolStripItemAlignment.Right,
.AutoToolTip = True, .ToolTipText = "Show channels statistic"}
TT_MAIN.SetToolTip(CH_HIDE_EXISTS_USERS, "Hide users which already exists in collection") TT_MAIN.SetToolTip(CH_HIDE_EXISTS_USERS, "Hide users which already exists in collection")
TT_MAIN.SetToolTip(OPT_LIMITS_COUNT, "Total posts count limit") TT_MAIN.SetToolTip(OPT_LIMITS_COUNT, "Total posts count limit")
@@ -182,8 +193,9 @@ Friend Class ChannelViewForm : Implements IChannelLimits
TXT_LIMIT.GetControlHost, TXT_LIMIT.GetControlHost,
LBL_LIMIT_TEXT, LBL_LIMIT_TEXT,
New ToolStripSeparator, New ToolStripSeparator,
New ToolStripControlHost(CH_HIDE_EXISTS_USERS)}) New ToolStripControlHost(CH_HIDE_EXISTS_USERS),
MyRange = New RangeSwitcher(Of UserPost) With {.Selector = Function(p) Not Settings.UserExists(Sites.Reddit, p.UserID)} BTT_SHOW_STATS})
MyRange = New RangeSwitcher(Of UserPost) With {.Selector = SelectorExpression}
With MyRange With MyRange
.Limit = ImagesInRow * ImagesRows .Limit = ImagesInRow * ImagesRows
.InsertButtons(ToolbarTOP, {RButton.Previous, RButton.Next}, 5) .InsertButtons(ToolbarTOP, {RButton.Previous, RButton.Next}, 5)
@@ -192,7 +204,6 @@ Friend Class ChannelViewForm : Implements IChannelLimits
.BindForm(Me) .BindForm(Me)
.LabelNumbersProvider = CProvider .LabelNumbersProvider = CProvider
.UpdateControls() .UpdateControls()
.Selector = SelectorExpression
End With End With
AddHandler Settings.ChannelsImagesColumns.OnValueChanged, AddressOf ImagesCountChanged AddHandler Settings.ChannelsImagesColumns.OnValueChanged, AddressOf ImagesCountChanged
AddHandler Settings.ChannelsImagesRows.OnValueChanged, AddressOf ImagesCountChanged AddHandler Settings.ChannelsImagesRows.OnValueChanged, AddressOf ImagesCountChanged
@@ -225,6 +236,8 @@ Friend Class ChannelViewForm : Implements IChannelLimits
OPT_LIMITS_COUNT.Dispose() OPT_LIMITS_COUNT.Dispose()
OPT_LIMITS_POST.Dispose() OPT_LIMITS_POST.Dispose()
LBL_LIMIT_TEXT.Dispose() LBL_LIMIT_TEXT.Dispose()
BTT_SHOW_STATS.Dispose()
MyRange.Dispose()
PendingUsers.Clear() PendingUsers.Clear()
MyDefs.Dispose() MyDefs.Dispose()
End Sub End Sub
@@ -266,9 +279,11 @@ Friend Class ChannelViewForm : Implements IChannelLimits
#Region "Images refill methods" #Region "Images refill methods"
Private Sub AppendPendingUsers() Private Sub AppendPendingUsers()
If LIST_POSTS.CheckedIndices.Count > 0 Then If LIST_POSTS.CheckedIndices.Count > 0 Then
Dim c As Channel = GetCurrentChannel(False)
Dim lp As New ListAddParams(LAP.NotContainsOnly) With {.OnAddAction = Sub(ByVal u As PendingUser) u.ChannelUserAdded()}
PendingUsers.ListAddList((From p As ListViewItem In LIST_POSTS.Items PendingUsers.ListAddList((From p As ListViewItem In LIST_POSTS.Items
Where p.Checked Where p.Checked
Select New PendingUser(p.Text, GetPostBySelected(CStr(p.Tag)).CachedFile)), LNC) Select New PendingUser(p.Text, c, GetPostBySelected(CStr(p.Tag)).CachedFile)), lp)
Dim a As Action = Sub() BTT_ADD_USERS.Text = $"Add ({PendingUsers.Count.ToString(CProvider)})" Dim a As Action = Sub() BTT_ADD_USERS.Text = $"Add ({PendingUsers.Count.ToString(CProvider)})"
If ToolbarTOP.InvokeRequired Then ToolbarTOP.Invoke(a) Else a.Invoke If ToolbarTOP.InvokeRequired Then ToolbarTOP.Invoke(a) Else a.Invoke
End If End If
@@ -324,6 +339,7 @@ Friend Class ChannelViewForm : Implements IChannelLimits
TXT_LIMIT.Enabled = False TXT_LIMIT.Enabled = False
CH_HIDE_EXISTS_USERS.Enabled = False CH_HIDE_EXISTS_USERS.Enabled = False
CMB_CHANNELS.Enabled(True) = False CMB_CHANNELS.Enabled(True) = False
BTT_SHOW_STATS.Enabled = False
MyRange.EnableButton(RButton.Previous, False) MyRange.EnableButton(RButton.Previous, False)
MyRange.EnableButton(RButton.Next, False) MyRange.EnableButton(RButton.Next, False)
End If End If
@@ -337,6 +353,7 @@ Friend Class ChannelViewForm : Implements IChannelLimits
_CollectionDownloading = True _CollectionDownloading = True
Settings.Channels.SetLimit(Me) Settings.Channels.SetLimit(Me)
Await Task.Run(Sub() Settings.Channels.DownloadData(Token, CH_HIDE_EXISTS_USERS.Checked, CProgress)) Await Task.Run(Sub() Settings.Channels.DownloadData(Token, CH_HIDE_EXISTS_USERS.Checked, CProgress))
RaiseEvent OnDownloadDone("All channels downloaded")
Token.ThrowIfCancellationRequested() Token.ThrowIfCancellationRequested()
c = GetCurrentChannel() c = GetCurrentChannel()
Else Else
@@ -345,6 +362,7 @@ Friend Class ChannelViewForm : Implements IChannelLimits
InvokeToken.Invoke() InvokeToken.Invoke()
c.SetLimit(Me) c.SetLimit(Me)
Await Task.Run(Sub() c.DownloadData(Token, CH_HIDE_EXISTS_USERS.Checked, CProgress)) Await Task.Run(Sub() c.DownloadData(Token, CH_HIDE_EXISTS_USERS.Checked, CProgress))
RaiseEvent OnDownloadDone($"Channel [{c.Name}] downloaded")
Token.ThrowIfCancellationRequested() Token.ThrowIfCancellationRequested()
End If End If
End If End If
@@ -377,6 +395,7 @@ Friend Class ChannelViewForm : Implements IChannelLimits
TXT_LIMIT.Enabled = True TXT_LIMIT.Enabled = True
CH_HIDE_EXISTS_USERS.Enabled = True CH_HIDE_EXISTS_USERS.Enabled = True
CMB_CHANNELS.Enabled(True) = True CMB_CHANNELS.Enabled(True) = True
BTT_SHOW_STATS.Enabled = True
CMB_CHANNELS_ActionOnCheckedChange(CMB_CHANNELS.Checked) CMB_CHANNELS_ActionOnCheckedChange(CMB_CHANNELS.Checked)
With MyRange With MyRange
.EnableButton(RButton.Previous, .Count > 0 AndAlso .CurrentIndex > 0) .EnableButton(RButton.Previous, .Count > 0 AndAlso .CurrentIndex > 0)
@@ -524,12 +543,13 @@ Friend Class ChannelViewForm : Implements IChannelLimits
If Not c Is Nothing Then MyRange.ChangeSource(c, EDP.SendInLog) If Not c Is Nothing Then MyRange.ChangeSource(c, EDP.SendInLog)
End Sub End Sub
Private Sub CMB_CHANNELS_ActionOnButtonClick(ByVal Sender As ActionButton) Handles CMB_CHANNELS.ActionOnButtonClick Private Sub CMB_CHANNELS_ActionOnButtonClick(ByVal Sender As ActionButton) Handles CMB_CHANNELS.ActionOnButtonClick
Dim c As Channel
Select Case Sender.DefaultButton Select Case Sender.DefaultButton
Case CmbDefaultButtons.Refresh : RefillChannels() Case CmbDefaultButtons.Refresh : RefillChannels()
Case CmbDefaultButtons.Add : AddNewChannel() Case CmbDefaultButtons.Add : AddNewChannel()
Case CmbDefaultButtons.Delete Case CmbDefaultButtons.Delete
Try Try
Dim c As Channel = GetCurrentChannel() c = GetCurrentChannel()
If Not c Is Nothing AndAlso MsgBoxE($"Do you really want to delete channel [{c}]?", MsgBoxStyle.Exclamation + MsgBoxStyle.YesNo) = 0 Then If Not c Is Nothing AndAlso MsgBoxE($"Do you really want to delete channel [{c}]?", MsgBoxStyle.Exclamation + MsgBoxStyle.YesNo) = 0 Then
Settings.Channels.Remove(c) Settings.Channels.Remove(c)
RefillChannels() RefillChannels()
@@ -539,6 +559,13 @@ Friend Class ChannelViewForm : Implements IChannelLimits
End Try End Try
Case CmbDefaultButtons.Up : ChangeComboIndex(-1) Case CmbDefaultButtons.Up : ChangeComboIndex(-1)
Case CmbDefaultButtons.Down : ChangeComboIndex(1) Case CmbDefaultButtons.Down : ChangeComboIndex(1)
Case CmbDefaultButtons.Info
Try
c = GetCurrentChannel()
If Not c Is Nothing Then MsgBoxE({c.GetChannelStats(True), "Channel statistics"})
Catch info_ex As Exception
ErrorsDescriber.Execute(EDP.LogMessageValue, info_ex, "Error on trying to show channel info")
End Try
End Select End Select
End Sub End Sub
Private Sub CMB_CHANNELS_ActionOnCheckedChange(ByVal Mode As Boolean) Handles CMB_CHANNELS.ActionOnCheckedChange Private Sub CMB_CHANNELS_ActionOnCheckedChange(ByVal Mode As Boolean) Handles CMB_CHANNELS.ActionOnCheckedChange
@@ -602,6 +629,12 @@ Friend Class ChannelViewForm : Implements IChannelLimits
MyRange.Update() MyRange.Update()
End If End If
End Sub End Sub
Private Sub BTT_SHOW_STATS_Click(sender As Object, e As EventArgs) Handles BTT_SHOW_STATS.Click
Using f As New ChannelsStatsForm
f.ShowDialog()
If f.DeletedChannels > 0 Then RefillChannels()
End Using
End Sub
#End Region #End Region
#Region "CONTEXT" #Region "CONTEXT"
Private Sub BTT_C_OPEN_USER_Click(sender As Object, e As EventArgs) Handles BTT_C_OPEN_USER.Click Private Sub BTT_C_OPEN_USER_Click(sender As Object, e As EventArgs) Handles BTT_C_OPEN_USER.Click
@@ -634,10 +667,14 @@ Friend Class ChannelViewForm : Implements IChannelLimits
Dim u$ = GetPostBySelected().UserID Dim u$ = GetPostBySelected().UserID
If Not u.IsEmptyString Then If Not u.IsEmptyString Then
Dim uRemoved As Boolean = False Dim uRemoved As Boolean = False
If PendingUsers.Contains(u) Then PendingUsers.Remove(u) : uRemoved = True Dim i% = PendingUsers.IndexOf(u)
If i >= 0 Then
PendingUsers(i).ChannelUserAdded(False)
PendingUsers.RemoveAt(i)
uRemoved = True
End If
With LIST_POSTS With LIST_POSTS
If .Items.Count > 0 Then If .Items.Count > 0 Then
Dim i%
Dim a As Action = Sub() .Items(i).Checked = False Dim a As Action = Sub() .Items(i).Checked = False
For i = 0 To .Items.Count - 1 For i = 0 To .Items.Count - 1
If .Items(i).Text = u And .Items(i).Checked Then If .Items(i).Text = u And .Items(i).Checked Then

View File

@@ -0,0 +1,112 @@
' Copyright (C) 2022 Andy
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()>
Partial Friend Class ChannelsStatsForm : Inherits System.Windows.Forms.Form
<System.Diagnostics.DebuggerNonUserCode()>
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
Try
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
Finally
MyBase.Dispose(disposing)
End Try
End Sub
Private components As System.ComponentModel.IContainer
<System.Diagnostics.DebuggerStepThrough()>
Private Sub InitializeComponent()
Dim CONTAINER_MAIN As System.Windows.Forms.ToolStripContainer
Dim ActionButton1 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(ChannelsStatsForm))
Dim ActionButton2 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim ActionButton3 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim ListColumn1 As PersonalUtilities.Forms.Controls.Base.ListColumn = New PersonalUtilities.Forms.Controls.Base.ListColumn()
Dim ListColumn2 As PersonalUtilities.Forms.Controls.Base.ListColumn = New PersonalUtilities.Forms.Controls.Base.ListColumn()
Me.CMB_CHANNELS = New PersonalUtilities.Forms.Controls.ComboBoxExtended()
CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer()
CONTAINER_MAIN.ContentPanel.SuspendLayout()
CONTAINER_MAIN.SuspendLayout()
CType(Me.CMB_CHANNELS, System.ComponentModel.ISupportInitialize).BeginInit()
Me.SuspendLayout()
'
'CONTAINER_MAIN
'
'
'CONTAINER_MAIN.ContentPanel
'
CONTAINER_MAIN.ContentPanel.Controls.Add(Me.CMB_CHANNELS)
CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(384, 261)
CONTAINER_MAIN.Dock = System.Windows.Forms.DockStyle.Fill
CONTAINER_MAIN.LeftToolStripPanelVisible = False
CONTAINER_MAIN.Location = New System.Drawing.Point(0, 0)
CONTAINER_MAIN.Name = "CONTAINER_MAIN"
CONTAINER_MAIN.RightToolStripPanelVisible = False
CONTAINER_MAIN.Size = New System.Drawing.Size(384, 261)
CONTAINER_MAIN.TabIndex = 0
CONTAINER_MAIN.TopToolStripPanelVisible = False
'
'CMB_CHANNELS
'
ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image)
ActionButton1.Index = 0
ActionButton1.Name = "BTT_COMBOBOX_ARROW"
ActionButton1.Visible = False
ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image)
ActionButton2.Index = 1
ActionButton2.Name = "BTT_CLEAR"
ActionButton3.BackgroundImage = CType(resources.GetObject("ActionButton3.BackgroundImage"), System.Drawing.Image)
ActionButton3.Index = 2
ActionButton3.Name = "BTT_DELETE"
Me.CMB_CHANNELS.Buttons.Add(ActionButton1)
Me.CMB_CHANNELS.Buttons.Add(ActionButton2)
Me.CMB_CHANNELS.Buttons.Add(ActionButton3)
Me.CMB_CHANNELS.ClearTextByButtonClear = False
ListColumn1.DisplayMember = True
ListColumn1.Name = "COL_INFO"
ListColumn1.Text = "Information"
ListColumn1.Width = -2
ListColumn2.Name = "COL_VALUE"
ListColumn2.Text = "Channel"
ListColumn2.ValueMember = True
ListColumn2.Visible = False
Me.CMB_CHANNELS.Columns.Add(ListColumn1)
Me.CMB_CHANNELS.Columns.Add(ListColumn2)
Me.CMB_CHANNELS.Dock = System.Windows.Forms.DockStyle.Fill
Me.CMB_CHANNELS.ListCheckBoxes = True
Me.CMB_CHANNELS.ListDropDownStyle = PersonalUtilities.Forms.Controls.ComboBoxExtended.ListMode.Simple
Me.CMB_CHANNELS.ListGridVisible = True
Me.CMB_CHANNELS.ListMultiSelect = True
Me.CMB_CHANNELS.Location = New System.Drawing.Point(0, 0)
Me.CMB_CHANNELS.Name = "CMB_CHANNELS"
Me.CMB_CHANNELS.Size = New System.Drawing.Size(386, 262)
Me.CMB_CHANNELS.TabIndex = 0
'
'ChannelsStatsForm
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(384, 261)
Me.Controls.Add(CONTAINER_MAIN)
Me.Icon = CType(resources.GetObject("$this.Icon"), System.Drawing.Icon)
Me.KeyPreview = True
Me.MinimizeBox = False
Me.MinimumSize = New System.Drawing.Size(400, 300)
Me.Name = "ChannelsStatsForm"
Me.ShowInTaskbar = False
Me.Text = "Channels statistics"
CONTAINER_MAIN.ContentPanel.ResumeLayout(False)
CONTAINER_MAIN.ResumeLayout(False)
CONTAINER_MAIN.PerformLayout()
CType(Me.CMB_CHANNELS, System.ComponentModel.ISupportInitialize).EndInit()
Me.ResumeLayout(False)
End Sub
Private WithEvents CMB_CHANNELS As PersonalUtilities.Forms.Controls.ComboBoxExtended
End Class

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,84 @@
' Copyright (C) 2022 Andy
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY
Imports System.ComponentModel
Imports PersonalUtilities.Forms
Imports PersonalUtilities.Forms.Controls.Base
Imports PersonalUtilities.Forms.Toolbars
Friend Class ChannelsStatsForm : Implements IOkCancelDeleteToolbar
Private ReadOnly MyDefs As DefaultFormProps
Friend Property DeletedChannels As Integer = 0
Friend Sub New()
InitializeComponent()
MyDefs = New DefaultFormProps
End Sub
Private Sub ChannelsStatsForm_Load(sender As Object, e As EventArgs) Handles Me.Load
Try
With MyDefs
.MyViewInitialize(Me, Settings.Design)
.AddOkCancelToolbar()
.DelegateClosingChecker()
.MyOkCancel.EnableDelete = False
If Settings.Channels.Count > 0 Then
RefillList()
Else
MsgBoxE("Channels not found", vbExclamation)
End If
.AppendDetectors()
.EndLoaderOperations()
End With
Catch ex As Exception
MyDefs.InvokeLoaderError(ex)
End Try
End Sub
Private Sub ChannelsStatsForm_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
MyDefs.Dispose()
End Sub
Private Sub RefillList()
CMB_CHANNELS.Items.Clear()
If Settings.Channels.Count > 0 Then
CMB_CHANNELS.BeginUpdate()
CMB_CHANNELS.Items.AddRange(Settings.Channels.Select(Function(c) New ListItem({$"[{c.ID}]: {c.GetChannelStats(False)}", c.ID})))
CMB_CHANNELS.EndUpdate()
End If
End Sub
Private Sub ToolbarBttOK() Implements IOkCancelToolbar.ToolbarBttOK
MyDefs.CloseForm()
End Sub
Private Sub ToolbarBttCancel() Implements IOkCancelToolbar.ToolbarBttCancel
MyDefs.CloseForm(DialogResult.Cancel)
End Sub
Private Sub ToolbarBttDelete() Implements IOkCancelDeleteToolbar.ToolbarBttDelete
Try
Dim c As List(Of String) = CMB_CHANNELS.Items.CheckedItems.Select(Function(cc) CStr(cc.Value(1))).ListIfNothing
If c.ListExists Then
If MsgBoxE({$"The following channels will be deleted:{vbCr}{c.ListToString(, vbCr)}", "Deleting channels"}, vbExclamation,,, {"Confirm", "Cancel"}) = 0 Then
For Each CID$ In c : Settings.Channels.Remove(Settings.Channels.Find(CID)) : Next
MyMainLOG = $"Deleted channels:{vbNewLine}{c.ListToString(, vbNewLine)}"
MsgBoxE("Channels deleted")
DeletedChannels += c.Count
c.Clear()
MyDefs.ChangesDetected = False
RefillList()
Else
MsgBoxE("Operation canceled")
End If
Else
MsgBoxE("No one channel checked", vbExclamation)
End If
Catch ex As Exception
ErrorsDescriber.Execute(EDP.LogMessageValue, ex, "Deleting channels")
End Try
End Sub
Private Sub CMB_CHANNELS_ActionOnChangeDetected(ByVal c As Boolean) Handles CMB_CHANNELS.ActionOnChangeDetected
If Not MyDefs.Initializing Then MyDefs.MyOkCancel.EnableDelete = CMB_CHANNELS.ListCheckedIndexes.Count > 0
End Sub
Private Sub CMB_CHANNELS_ActionOnButtonClearClick() Handles CMB_CHANNELS.ActionOnButtonClearClick
CMB_CHANNELS.ListCheckedIndexes = Nothing
End Sub
End Class

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 525 B

View File

@@ -0,0 +1,336 @@
' Copyright (C) 2022 Andy
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()>
Partial Friend Class DownloadSavedPostsForm : Inherits System.Windows.Forms.Form
<System.Diagnostics.DebuggerNonUserCode()>
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
Try
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
Finally
MyBase.Dispose(disposing)
End Try
End Sub
Private components As System.ComponentModel.IContainer
<System.Diagnostics.DebuggerStepThrough()>
Private Sub InitializeComponent()
Me.components = New System.ComponentModel.Container()
Dim TP_MAIN As System.Windows.Forms.TableLayoutPanel
Dim TP_BUTTONS As System.Windows.Forms.TableLayoutPanel
Dim TP_REDDIT As System.Windows.Forms.TableLayoutPanel
Dim TP_REDDIT_PR As System.Windows.Forms.TableLayoutPanel
Dim TP_INST As System.Windows.Forms.TableLayoutPanel
Dim TP_INST_PR As System.Windows.Forms.TableLayoutPanel
Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(DownloadSavedPostsForm))
Dim TT_MAIN As System.Windows.Forms.ToolTip
Me.BTT_DOWN_ALL = New System.Windows.Forms.Button()
Me.BTT_STOP_ALL = New System.Windows.Forms.Button()
Me.BTT_REDDIT_START = New System.Windows.Forms.Button()
Me.BTT_REDDIT_STOP = New System.Windows.Forms.Button()
Me.PR_REDDIT = New System.Windows.Forms.ProgressBar()
Me.BTT_REDDIT_OPEN = New System.Windows.Forms.Button()
Me.LBL_REDDIT = New System.Windows.Forms.Label()
Me.BTT_INST_START = New System.Windows.Forms.Button()
Me.BTT_INST_STOP = New System.Windows.Forms.Button()
Me.PR_INST = New System.Windows.Forms.ProgressBar()
Me.BTT_INST_OPEN = New System.Windows.Forms.Button()
Me.LBL_INST = New System.Windows.Forms.Label()
TP_MAIN = New System.Windows.Forms.TableLayoutPanel()
TP_BUTTONS = New System.Windows.Forms.TableLayoutPanel()
TP_REDDIT = New System.Windows.Forms.TableLayoutPanel()
TP_REDDIT_PR = New System.Windows.Forms.TableLayoutPanel()
TP_INST = New System.Windows.Forms.TableLayoutPanel()
TP_INST_PR = New System.Windows.Forms.TableLayoutPanel()
TT_MAIN = New System.Windows.Forms.ToolTip(Me.components)
TP_MAIN.SuspendLayout()
TP_BUTTONS.SuspendLayout()
TP_REDDIT.SuspendLayout()
TP_REDDIT_PR.SuspendLayout()
TP_INST.SuspendLayout()
TP_INST_PR.SuspendLayout()
Me.SuspendLayout()
'
'TP_MAIN
'
TP_MAIN.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.Inset
TP_MAIN.ColumnCount = 1
TP_MAIN.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_MAIN.Controls.Add(TP_BUTTONS, 0, 0)
TP_MAIN.Controls.Add(TP_REDDIT, 0, 1)
TP_MAIN.Controls.Add(TP_INST, 0, 2)
TP_MAIN.Dock = System.Windows.Forms.DockStyle.Fill
TP_MAIN.Location = New System.Drawing.Point(0, 0)
TP_MAIN.Name = "TP_MAIN"
TP_MAIN.RowCount = 3
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30.0!))
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
TP_MAIN.Size = New System.Drawing.Size(484, 156)
TP_MAIN.TabIndex = 0
'
'TP_BUTTONS
'
TP_BUTTONS.ColumnCount = 2
TP_BUTTONS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
TP_BUTTONS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
TP_BUTTONS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20.0!))
TP_BUTTONS.Controls.Add(Me.BTT_DOWN_ALL, 0, 0)
TP_BUTTONS.Controls.Add(Me.BTT_STOP_ALL, 1, 0)
TP_BUTTONS.Dock = System.Windows.Forms.DockStyle.Fill
TP_BUTTONS.Location = New System.Drawing.Point(2, 2)
TP_BUTTONS.Margin = New System.Windows.Forms.Padding(0)
TP_BUTTONS.Name = "TP_BUTTONS"
TP_BUTTONS.RowCount = 1
TP_BUTTONS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_BUTTONS.Size = New System.Drawing.Size(480, 30)
TP_BUTTONS.TabIndex = 0
'
'BTT_DOWN_ALL
'
Me.BTT_DOWN_ALL.Dock = System.Windows.Forms.DockStyle.Fill
Me.BTT_DOWN_ALL.Location = New System.Drawing.Point(3, 3)
Me.BTT_DOWN_ALL.Name = "BTT_DOWN_ALL"
Me.BTT_DOWN_ALL.Size = New System.Drawing.Size(234, 24)
Me.BTT_DOWN_ALL.TabIndex = 0
Me.BTT_DOWN_ALL.Text = "Download ALL"
Me.BTT_DOWN_ALL.UseVisualStyleBackColor = True
'
'BTT_STOP_ALL
'
Me.BTT_STOP_ALL.Dock = System.Windows.Forms.DockStyle.Fill
Me.BTT_STOP_ALL.Location = New System.Drawing.Point(243, 3)
Me.BTT_STOP_ALL.Name = "BTT_STOP_ALL"
Me.BTT_STOP_ALL.Size = New System.Drawing.Size(234, 24)
Me.BTT_STOP_ALL.TabIndex = 1
Me.BTT_STOP_ALL.Text = "Stop ALL"
Me.BTT_STOP_ALL.UseVisualStyleBackColor = True
'
'TP_REDDIT
'
TP_REDDIT.ColumnCount = 1
TP_REDDIT.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_REDDIT.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20.0!))
TP_REDDIT.Controls.Add(TP_REDDIT_PR, 0, 0)
TP_REDDIT.Controls.Add(Me.LBL_REDDIT, 0, 1)
TP_REDDIT.Dock = System.Windows.Forms.DockStyle.Fill
TP_REDDIT.Location = New System.Drawing.Point(2, 34)
TP_REDDIT.Margin = New System.Windows.Forms.Padding(0)
TP_REDDIT.Name = "TP_REDDIT"
TP_REDDIT.RowCount = 2
TP_REDDIT.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
TP_REDDIT.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
TP_REDDIT.Size = New System.Drawing.Size(480, 59)
TP_REDDIT.TabIndex = 1
'
'TP_REDDIT_PR
'
TP_REDDIT_PR.ColumnCount = 4
TP_REDDIT_PR.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 30.0!))
TP_REDDIT_PR.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 30.0!))
TP_REDDIT_PR.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 30.0!))
TP_REDDIT_PR.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_REDDIT_PR.Controls.Add(Me.BTT_REDDIT_START, 0, 0)
TP_REDDIT_PR.Controls.Add(Me.BTT_REDDIT_STOP, 1, 0)
TP_REDDIT_PR.Controls.Add(Me.PR_REDDIT, 3, 0)
TP_REDDIT_PR.Controls.Add(Me.BTT_REDDIT_OPEN, 2, 0)
TP_REDDIT_PR.Dock = System.Windows.Forms.DockStyle.Fill
TP_REDDIT_PR.Location = New System.Drawing.Point(0, 0)
TP_REDDIT_PR.Margin = New System.Windows.Forms.Padding(0)
TP_REDDIT_PR.Name = "TP_REDDIT_PR"
TP_REDDIT_PR.RowCount = 1
TP_REDDIT_PR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_REDDIT_PR.Size = New System.Drawing.Size(480, 29)
TP_REDDIT_PR.TabIndex = 0
'
'BTT_REDDIT_START
'
Me.BTT_REDDIT_START.BackgroundImage = Global.SCrawler.My.Resources.Resources.StartPic_01_Green_16
Me.BTT_REDDIT_START.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom
Me.BTT_REDDIT_START.Dock = System.Windows.Forms.DockStyle.Fill
Me.BTT_REDDIT_START.Location = New System.Drawing.Point(3, 3)
Me.BTT_REDDIT_START.Name = "BTT_REDDIT_START"
Me.BTT_REDDIT_START.Size = New System.Drawing.Size(24, 23)
Me.BTT_REDDIT_START.TabIndex = 0
TT_MAIN.SetToolTip(Me.BTT_REDDIT_START, "Start downloading saved Reddit posts")
Me.BTT_REDDIT_START.UseVisualStyleBackColor = True
'
'BTT_REDDIT_STOP
'
Me.BTT_REDDIT_STOP.BackgroundImage = Global.SCrawler.My.Resources.Resources.Delete
Me.BTT_REDDIT_STOP.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom
Me.BTT_REDDIT_STOP.Dock = System.Windows.Forms.DockStyle.Fill
Me.BTT_REDDIT_STOP.Enabled = False
Me.BTT_REDDIT_STOP.Location = New System.Drawing.Point(33, 3)
Me.BTT_REDDIT_STOP.Name = "BTT_REDDIT_STOP"
Me.BTT_REDDIT_STOP.Size = New System.Drawing.Size(24, 23)
Me.BTT_REDDIT_STOP.TabIndex = 1
TT_MAIN.SetToolTip(Me.BTT_REDDIT_STOP, "Stop downloading saved Reddit posts")
Me.BTT_REDDIT_STOP.UseVisualStyleBackColor = True
'
'PR_REDDIT
'
Me.PR_REDDIT.Dock = System.Windows.Forms.DockStyle.Fill
Me.PR_REDDIT.Location = New System.Drawing.Point(93, 3)
Me.PR_REDDIT.Name = "PR_REDDIT"
Me.PR_REDDIT.Size = New System.Drawing.Size(384, 23)
Me.PR_REDDIT.TabIndex = 2
'
'BTT_REDDIT_OPEN
'
Me.BTT_REDDIT_OPEN.BackgroundImage = CType(resources.GetObject("BTT_REDDIT_OPEN.BackgroundImage"), System.Drawing.Image)
Me.BTT_REDDIT_OPEN.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom
Me.BTT_REDDIT_OPEN.Dock = System.Windows.Forms.DockStyle.Fill
Me.BTT_REDDIT_OPEN.Location = New System.Drawing.Point(63, 3)
Me.BTT_REDDIT_OPEN.Name = "BTT_REDDIT_OPEN"
Me.BTT_REDDIT_OPEN.Size = New System.Drawing.Size(24, 23)
Me.BTT_REDDIT_OPEN.TabIndex = 3
Me.BTT_REDDIT_OPEN.UseVisualStyleBackColor = True
'
'LBL_REDDIT
'
Me.LBL_REDDIT.AutoSize = True
Me.LBL_REDDIT.Dock = System.Windows.Forms.DockStyle.Fill
Me.LBL_REDDIT.Location = New System.Drawing.Point(3, 29)
Me.LBL_REDDIT.Name = "LBL_REDDIT"
Me.LBL_REDDIT.Size = New System.Drawing.Size(474, 30)
Me.LBL_REDDIT.TabIndex = 1
Me.LBL_REDDIT.Text = "Reddit"
Me.LBL_REDDIT.TextAlign = System.Drawing.ContentAlignment.TopCenter
'
'TP_INST
'
TP_INST.ColumnCount = 1
TP_INST.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_INST.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20.0!))
TP_INST.Controls.Add(TP_INST_PR, 0, 0)
TP_INST.Controls.Add(Me.LBL_INST, 0, 1)
TP_INST.Dock = System.Windows.Forms.DockStyle.Fill
TP_INST.Location = New System.Drawing.Point(2, 95)
TP_INST.Margin = New System.Windows.Forms.Padding(0)
TP_INST.Name = "TP_INST"
TP_INST.RowCount = 2
TP_INST.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
TP_INST.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
TP_INST.Size = New System.Drawing.Size(480, 59)
TP_INST.TabIndex = 2
'
'TP_INST_PR
'
TP_INST_PR.ColumnCount = 4
TP_INST_PR.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 30.0!))
TP_INST_PR.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 30.0!))
TP_INST_PR.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 30.0!))
TP_INST_PR.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_INST_PR.Controls.Add(Me.BTT_INST_START, 0, 0)
TP_INST_PR.Controls.Add(Me.BTT_INST_STOP, 1, 0)
TP_INST_PR.Controls.Add(Me.PR_INST, 3, 0)
TP_INST_PR.Controls.Add(Me.BTT_INST_OPEN, 2, 0)
TP_INST_PR.Dock = System.Windows.Forms.DockStyle.Fill
TP_INST_PR.Location = New System.Drawing.Point(0, 0)
TP_INST_PR.Margin = New System.Windows.Forms.Padding(0)
TP_INST_PR.Name = "TP_INST_PR"
TP_INST_PR.RowCount = 1
TP_INST_PR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_INST_PR.Size = New System.Drawing.Size(480, 29)
TP_INST_PR.TabIndex = 0
'
'BTT_INST_START
'
Me.BTT_INST_START.BackgroundImage = Global.SCrawler.My.Resources.Resources.StartPic_01_Green_16
Me.BTT_INST_START.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom
Me.BTT_INST_START.Dock = System.Windows.Forms.DockStyle.Fill
Me.BTT_INST_START.Location = New System.Drawing.Point(3, 3)
Me.BTT_INST_START.Name = "BTT_INST_START"
Me.BTT_INST_START.Size = New System.Drawing.Size(24, 23)
Me.BTT_INST_START.TabIndex = 0
TT_MAIN.SetToolTip(Me.BTT_INST_START, "Start downloading saved Instagram posts")
Me.BTT_INST_START.UseVisualStyleBackColor = True
'
'BTT_INST_STOP
'
Me.BTT_INST_STOP.BackgroundImage = Global.SCrawler.My.Resources.Resources.Delete
Me.BTT_INST_STOP.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom
Me.BTT_INST_STOP.Dock = System.Windows.Forms.DockStyle.Fill
Me.BTT_INST_STOP.Enabled = False
Me.BTT_INST_STOP.Location = New System.Drawing.Point(33, 3)
Me.BTT_INST_STOP.Name = "BTT_INST_STOP"
Me.BTT_INST_STOP.Size = New System.Drawing.Size(24, 23)
Me.BTT_INST_STOP.TabIndex = 1
TT_MAIN.SetToolTip(Me.BTT_INST_STOP, "Stop downloading saved Instagram posts")
Me.BTT_INST_STOP.UseVisualStyleBackColor = True
'
'PR_INST
'
Me.PR_INST.Dock = System.Windows.Forms.DockStyle.Fill
Me.PR_INST.Location = New System.Drawing.Point(93, 3)
Me.PR_INST.Name = "PR_INST"
Me.PR_INST.Size = New System.Drawing.Size(384, 23)
Me.PR_INST.TabIndex = 2
'
'BTT_INST_OPEN
'
Me.BTT_INST_OPEN.BackgroundImage = CType(resources.GetObject("BTT_INST_OPEN.BackgroundImage"), System.Drawing.Image)
Me.BTT_INST_OPEN.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom
Me.BTT_INST_OPEN.Dock = System.Windows.Forms.DockStyle.Fill
Me.BTT_INST_OPEN.Location = New System.Drawing.Point(63, 3)
Me.BTT_INST_OPEN.Name = "BTT_INST_OPEN"
Me.BTT_INST_OPEN.Size = New System.Drawing.Size(24, 23)
Me.BTT_INST_OPEN.TabIndex = 3
Me.BTT_INST_OPEN.UseVisualStyleBackColor = True
'
'LBL_INST
'
Me.LBL_INST.AutoSize = True
Me.LBL_INST.Dock = System.Windows.Forms.DockStyle.Fill
Me.LBL_INST.Location = New System.Drawing.Point(3, 29)
Me.LBL_INST.Name = "LBL_INST"
Me.LBL_INST.Size = New System.Drawing.Size(474, 30)
Me.LBL_INST.TabIndex = 1
Me.LBL_INST.Text = "Instagram"
Me.LBL_INST.TextAlign = System.Drawing.ContentAlignment.TopCenter
'
'DownloadSavedPostsForm
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(484, 156)
Me.Controls.Add(TP_MAIN)
Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle
Me.Icon = CType(resources.GetObject("$this.Icon"), System.Drawing.Icon)
Me.MaximizeBox = False
Me.MaximumSize = New System.Drawing.Size(500, 195)
Me.MinimumSize = New System.Drawing.Size(500, 195)
Me.Name = "DownloadSavedPostsForm"
Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide
Me.Text = "Saved posts"
TP_MAIN.ResumeLayout(False)
TP_BUTTONS.ResumeLayout(False)
TP_REDDIT.ResumeLayout(False)
TP_REDDIT.PerformLayout()
TP_REDDIT_PR.ResumeLayout(False)
TP_INST.ResumeLayout(False)
TP_INST.PerformLayout()
TP_INST_PR.ResumeLayout(False)
Me.ResumeLayout(False)
End Sub
Private WithEvents BTT_DOWN_ALL As Button
Private WithEvents BTT_STOP_ALL As Button
Private WithEvents BTT_REDDIT_START As Button
Private WithEvents BTT_REDDIT_STOP As Button
Private WithEvents PR_REDDIT As ProgressBar
Private WithEvents LBL_REDDIT As Label
Private WithEvents BTT_INST_START As Button
Private WithEvents BTT_INST_STOP As Button
Private WithEvents PR_INST As ProgressBar
Private WithEvents LBL_INST As Label
Private WithEvents BTT_REDDIT_OPEN As Button
Private WithEvents BTT_INST_OPEN As Button
End Class

View File

@@ -0,0 +1,492 @@
<?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="TP_MAIN.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="TP_BUTTONS.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="TP_REDDIT.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="TP_REDDIT_PR.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="TP_INST.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="TP_INST_PR.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="BTT_INST_OPEN.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
wwAADsMBx2+oZAAAAR5JREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbGujg3ZATZPKYdC6FQhPwlAMkg3dP
WQwhyWIyJIUW5NqyPb7oCVtIlhVTwYf8nv7/t2zJagel9KmqKsIACYL9RjI8UHz5zshougZr/AEvbxEP
aZCDBY3VslixaJvX3wzkkDiOwbZtDRGA5vdNAg+TL27qgmt5XkBG/gTdAG7Gt+3PP9oOaEGFCVEC6rp+
5g9MfM/c5e4OsEZMZkQEtGL5H2DdZ5JRArDwPA+iKII0TfkC9vroC9j5vq8JTWw3WzWgLMtZGIaa0MR8
vlAD8PYlSaIJTTiOowY0p0Bc19XEJo6HE59FAPuMzyAINKGJ1XLFZxHALtMrnkBXOIQIIIQ8YvF/KrgB
cMaRN0UdBBkAAAAASUVORK5CYII=
</value>
</data>
<metadata name="TP_REDDIT_PR.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="TT_MAIN.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="TT_MAIN.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<data name="BTT_REDDIT_OPEN.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
wwAADsMBx2+oZAAAAR5JREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbGujg3ZATZPKYdC6FQhPwlAMkg3dP
WQwhyWIyJIUW5NqyPb7oCVtIlhVTwYf8nv7/t2zJagel9KmqKsIACYL9RjI8UHz5zshougZr/AEvbxEP
aZCDBY3VslixaJvX3wzkkDiOwbZtDRGA5vdNAg+TL27qgmt5XkBG/gTdAG7Gt+3PP9oOaEGFCVEC6rp+
5g9MfM/c5e4OsEZMZkQEtGL5H2DdZ5JRArDwPA+iKII0TfkC9vroC9j5vq8JTWw3WzWgLMtZGIaa0MR8
vlAD8PYlSaIJTTiOowY0p0Bc19XEJo6HE59FAPuMzyAINKGJ1XLFZxHALtMrnkBXOIQIIIQ8YvF/KrgB
cMaRN0UdBBkAAAAASUVORK5CYII=
</value>
</data>
<metadata name="TT_MAIN.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="TT_MAIN.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAUAEBAAAAEAIABoBAAAVgAAABgYAAABACAAiAkAAL4EAAAgIAAAAQAgAKgQAABGDgAAMDAAAAEA
IACoJQAA7h4AABAQAAABACAAaAQAAJZEAAAoAAAAEAAAACAAAAABACAAAAAAAAAEAADDDgAAww4AAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD29vb/9vb2/wAAAAAAAAAAAAAAAAAAAAD29vb/9vb2/wAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b2
9v8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29v9kZGT/1NTU//b29v/29vb/1NTU/2Rk
ZP/29vb/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD29vb/QkJC/0JCQv+cnJz/nJyc/0JC
Qv9CQkL/9vb2/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9vb2/0JCQv9CQkL/QkJC/0JC
Qv9CQkL/QkJC//b29v8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29v9CQkL/QkJC/0JC
Qv9CQkL/QkJC/0JCQv/29vb/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD29vb/QkJC/0JC
Qv9CQkL/QkJC/0JCQv9CQkL/9vb2/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9vb2/0JC
Qv9CQkL/QkJC/0JCQv9CQkL/QkJC//b29v8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb2
9v9CQkL/QkJC/0JCQv9CQkL/QkJC/0JCQv/29vb/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAD29vb/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/9vb2/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA9vb2/0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC//b29v8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAPb29v9CQkL/QkJC/0JCQv9CQkL/QkJC/0JCQv/29vb/AAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAD29vb/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/9vb2/wAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v8AAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAP//AADzzwAA8A8AAPAPAADwDwAA8A8AAPAPAADwDwAA8A8AAPAPAADwDwAA8A8AAPAP
AADwDwAA8A8AAP//AAAoAAAAGAAAADAAAAABACAAAAAAAAAJAADDDgAAww4AAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYV9vb2Z/b2
9oT29vZn9vb2Ffb29gAAAAAAAAAAAPb29gD29vYV9vb2Z/b29oT29vZn9vb2Ffb29gAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYr9vb21Pf39//39/fb9/f3Tvf39yP29vYr9vb2K/f3
9yP39/dO9/f32/f39//29vbU9vb2K/b29gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb2
9gD29vYr9vb21Pb29v/39/f49vb22/b29tP29vbU9vb21Pb29tP29vbb9/f3+Pb29v/29vbU9vb2K/b2
9gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD5+fkr9/f31NHR0f+4uLj/4ODg//T0
9P/5+fn/+fn5//T09P/g4OD/uLi4/9HR0f/39/fU+fn5K/b29gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAPb29gD9/f0r9/f31Kmpqf9sbGz/qqqq/9XV1f/o6Oj/6Ojo/9XV1f+qqqr/bGxs/6mp
qf/39/fU/f39K/b29gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD+/v4r9/f31KGh
of9ISEj/VVVV/4SEhP+tra3/ra2t/4SEhP9VVVX/SEhI/6Ghof/39/fU/v7+K/b29gAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD+/v4r9/f31J+fn/8/Pz//PDw8/1RUVP9tbW3/bW1t/1RU
VP88PDz/Pz8//5+fn//39/fU/v7+K/b29gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb2
9gD+/v4r9/f31J+fn/9BQUH/QUFB/0JCQv9BQUH/QUFB/0JCQv9BQUH/QUFB/5+fn//39/fU/v7+K/b2
9gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD+/v4r9/f31J+fn/9BQUH/QUFB/0JC
Qv9BQUH/QUFB/0JCQv9BQUH/QUFB/5+fn//39/fU/v7+K/b29gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAPb29gD+/v4r9/f31J+fn/9BQUH/QUFB/0JCQv9CQkL/QkJC/0JCQv9BQUH/QUFB/5+f
n//39/fU/v7+K/b29gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD+/v4r9/f31J+f
n/9BQUH/QUFB/0JCQv9CQkL/QkJC/0JCQv9BQUH/QUFB/5+fn//39/fU/v7+K/b29gAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD+/v4r9/f31J+fn/9BQUH/QUFB/0JCQv9CQkL/QkJC/0JC
Qv9BQUH/QUFB/5+fn//39/fU/v7+K/b29gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb2
9gD+/v4r9/f31J+fn/9BQUH/QUFB/0JCQv9CQkL/QkJC/0JCQv9BQUH/QUFB/5+fn//39/fU/v7+K/b2
9gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD+/v4r9/f31J+fn/9BQUH/QUFB/0JC
Qv9CQkL/QkJC/0JCQv9BQUH/QUFB/5+fn//39/fU/v7+K/b29gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAPb29gD+/v4r9/f31J+fn/9BQUH/QUFB/0JCQv9CQkL/QkJC/0JCQv9BQUH/QUFB/5+f
n//39/fU/v7+K/b29gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD+/v4r9/f31J+f
n/9BQUH/QUFB/0JCQv9CQkL/QkJC/0JCQv9BQUH/QUFB/5+fn//39/fU/v7+K/b29gAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD+/v4r9/f31J+fn/9BQUH/QUFB/0JCQv9CQkL/QkJC/0JC
Qv9BQUH/QUFB/5+fn//39/fU/v7+K/b29gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb2
9gD+/v4r9/f31J+fn/9BQUH/QUFB/0JCQv9CQkL/QkJC/0JCQv9BQUH/QUFB/5+fn//39/fU/v7+K/b2
9gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD+/v4r9/f31JycnP87Ozv/Ojo6/zw8
PP88PDz/PDw8/zw8PP86Ojr/Ozs7/5ycnP/39/fU/v7+K/b29gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAPb29gD9/f0r9/f31K6urv9gYGD/YGBg/2FhYf9hYWH/YWFh/2FhYf9gYGD/YGBg/66u
rv/39/fU/f39K/b29gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD39/cr9vb21Ojo
6P/Y2Nj/2NjY/9jY2P/Y2Nj/2NjY/9jY2P/Y2Nj/2NjY/+jo6P/29vbU9/f3K/b29gAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYV9vb2Z/r6+oD///97////e////3v///97////e///
/3v///97////e/r6+oD29vZn9vb2Ffb29gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA////APg8HwD4AB8A+AAfAPgAHwD4AB8A+AAfAPgAHwD4AB8A+AAfAPgA
HwD4AB8A+AAfAPgAHwD4AB8A+AAfAPgAHwD4AB8A+AAfAPgAHwD4AB8A+AAfAPgAHwD///8AKAAAACAA
AABAAAAAAQAgAAAAAAAAEAAAww4AAMMOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAD29vYA9vb2APb29g/29vYu9vb2Pvb29j729vYu9vb2D/b29gD29vYAAAAAAAAAAAD29vYA9vb2APb2
9g/29vYu9vb2Pvb29j729vYu9vb2D/b29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAPb29gD29vYA9vb2Lvb29pH29vbG9vb2xvb29pH29vYu9vb2APb29gAAAAAAAAAAAPb2
9gD29vYA9vb2Lvb29pH29vbG9vb2xvb29pH29vYu9vb2APb29gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA9vb2APb29gD29vY+9vb2wff39//4+Pj/+Pj40Pj4+Gz4+Pg59vb2O/b2
9j729vY+9vb2O/j4+Dn4+Phs+Pj40Pj4+P/39/f/9vb2wfb29j729vYA9vb2AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD29vYA9vb2APb29j729vbB9/f3//n5+f/5+fnw+Pj40Pf3
98D29vbB9vb2wfb29sH29vbB9/f3wPj4+ND5+fnw+fn5//f39//29vbB9vb2Pvb29gD29vYAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA+Pj4Pvf398Ht7e3/29vb/9nZ
2f/o6Oj/8/Pz//b29v/4+Pj/+Pj4//b29v/z8/P/6Ojo/9nZ2f/b29v/7e3t//f398H4+Pg+9vb2APb2
9gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9vb2APb29gD9/f0++fn5wdvb
2/+ioqL/mpqa/8nJyf/o6Oj/9PT0//n5+f/5+fn/9PT0/+jo6P/Jycn/mpqa/6Kiov/b29v/+fn5wf39
/T729vYA9vb2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD29vYA9vb2AP//
/z77+/vB0NDQ/35+fv9paWn/l5eX/76+vv/X19f/5OTk/+Tk5P/X19f/vr6+/5eXl/9paWn/fn5+/9DQ
0P/7+/vB////Pvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb2
9gD29vYA////Pvv7+8HNzc3/c3Nz/0pKSv9ZWVn/eHh4/6Ghof+3t7f/t7e3/6Ghof94eHj/WVlZ/0pK
Sv9zc3P/zc3N//v7+8H///8+9vb2APb29gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA9vb2APb29gD///8+/Pz8wcvLy/9vb2//Ozs7/zs7O/9PT0//c3Nz/4eHh/+Hh4f/c3Nz/09P
T/87Ozv/Ozs7/29vb//Ly8v//Pz8wf///z729vYA9vb2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAD29vYA9vb2AP///z78/PzBy8vL/29vb/89PT3/PT09/0VFRf9RUVH/V1dX/1dX
V/9RUVH/RUVF/z09Pf89PT3/b29v/8vLy//8/PzB////Pvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA////Pvz8/MHMzMz/b29v/z4+Pv8/Pz//QUFB/0BA
QP9AQED/QEBA/0BAQP9BQUH/Pz8//z4+Pv9vb2//zMzM//z8/MH///8+9vb2APb29gAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9vb2APb29gD///8+/Pz8wczMzP9vb2//Pj4+/z8/
P/9CQkL/QUFB/0FBQf9BQUH/QUFB/0JCQv8/Pz//Pj4+/29vb//MzMz//Pz8wf///z729vYA9vb2AAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD29vYA9vb2AP///z78/PzBzMzM/29v
b/8+Pj7/Pz8//0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC/z8/P/8+Pj7/b29v/8zMzP/8/PzB////Pvb2
9gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA////Pvz8
/MHMzMz/b29v/z4+Pv8/Pz//QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/Pz8//z4+Pv9vb2//zMzM//z8
/MH///8+9vb2APb29gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9vb2APb2
9gD///8+/Pz8wczMzP9vb2//Pj4+/z8/P/9CQkL/QkJC/0JCQv9CQkL/QkJC/0JCQv8/Pz//Pj4+/29v
b//MzMz//Pz8wf///z729vYA9vb2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAD29vYA9vb2AP///z78/PzBzMzM/29vb/8+Pj7/Pz8//0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC/z8/
P/8+Pj7/b29v/8zMzP/8/PzB////Pvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAPb29gD29vYA////Pvz8/MHMzMz/b29v/z4+Pv8/Pz//QkJC/0JCQv9CQkL/QkJC/0JC
Qv9CQkL/Pz8//z4+Pv9vb2//zMzM//z8/MH///8+9vb2APb29gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA9vb2APb29gD///8+/Pz8wczMzP9vb2//Pj4+/z8/P/9CQkL/QkJC/0JC
Qv9CQkL/QkJC/0JCQv8/Pz//Pj4+/29vb//MzMz//Pz8wf///z729vYA9vb2AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD29vYA9vb2AP///z78/PzBzMzM/29vb/8+Pj7/Pz8//0JC
Qv9CQkL/QkJC/0JCQv9CQkL/QkJC/z8/P/8+Pj7/b29v/8zMzP/8/PzB////Pvb29gD29vYAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA////Pvz8/MHMzMz/b29v/z4+
Pv8/Pz//QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/Pz8//z4+Pv9vb2//zMzM//z8/MH///8+9vb2APb2
9gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9vb2APb29gD///8+/Pz8wczM
zP9vb2//Pj4+/z8/P/9CQkL/QkJC/0JCQv9CQkL/QkJC/0JCQv8/Pz//Pj4+/29vb//MzMz//Pz8wf//
/z729vYA9vb2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD29vYA9vb2AP//
/z78/PzBzMzM/29vb/8+Pj7/Pz8//0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC/z8/P/8+Pj7/b29v/8zM
zP/8/PzB////Pvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb2
9gD29vYA////Pvz8/MHMzMz/b29v/z4+Pv8/Pz//QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/Pz8//z4+
Pv9vb2//zMzM//z8/MH///8+9vb2APb29gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA9vb2APb29gD///8+/Pz8wczMzP9vb2//Pj4+/z8/P/9CQkL/QkJC/0JCQv9CQkL/QkJC/0JC
Qv8/Pz//Pj4+/29vb//MzMz//Pz8wf///z729vYA9vb2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAD29vYA9vb2AP///z78/PzBy8vL/21tbf87Ozv/PT09/z8/P/8/Pz//Pz8//z8/
P/8/Pz//Pz8//z09Pf87Ozv/bW1t/8vLy//8/PzB////Pvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA////Pvz8/MHLy8v/bGxs/zk5Of87Ozv/Pj4+/z4+
Pv8+Pj7/Pj4+/z4+Pv8+Pj7/Ozs7/zk5Of9sbGz/y8vL//z8/MH///8+9vb2APb29gAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9vb2APb29gD+/v4++vr6wdbW1v+RkZH/bGxs/21t
bf9vb2//b29v/29vb/9vb2//b29v/29vb/9tbW3/bGxs/5GRkf/W1tb/+vr6wf7+/j729vYA9vb2AAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD29vYA9vb2APn5+T739/fB7Ozs/9bW
1v/Ly8v/y8vL/8zMzP/MzMz/zMzM/8zMzP/MzMz/zMzM/8vLy//Ly8v/1tbW/+zs7P/39/fB+fn5Pvb2
9gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Lvb2
9pH39/fD+vr6wfz8/L/8/Py//Pz8v/z8/L/8/Py//Pz8v/z8/L/8/Py//Pz8v/z8/L/6+vrB9/f3w/b2
9pH29vYu9vb2APb29gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9vb2APb2
9gD19fUP9vb2Lvj4+D79/f09////PP///zz///88////PP///zz///88////PP///zz///88////PP39
/T34+Pg+9vb2LvX19Q/29vYA9vb2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////gfgf/4H
4H/+AAB//gAAf/4AAH/+AAB//gAAf/4AAH/+AAB//gAAf/4AAH/+AAB//gAAf/4AAH/+AAB//gAAf/4A
AH/+AAB//gAAf/4AAH/+AAB//gAAf/4AAH/+AAB//gAAf/4AAH/+AAB//gAAf/4AAH/+AAB//////ygA
AAAwAAAAYAAAAAEAIAAAAAAAACQAAMMOAADDDgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Afb29gX29vYK9vb2Dvb29hD29vYQ9vb2Dvb2
9gr29vYF9vb2Afb29gD29vYAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Afb29gX29vYK9vb2Dvb2
9hD29vYQ9vb2Dvb29gr29vYF9vb2Afb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2BPb29hr29vY29vb2S/b2
9lT29vZU9vb2S/b29jb29vYa9vb2BPb29gD29vYAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2BPb2
9hr29vY29vb2S/b29lT29vZU9vb2S/b29jb29vYa9vb2BPb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Cfb2
9jf29vZy9vb2n/b29rL29vay9vb2n/b29nL29vY39vb2Cfb29gD29vYAAAAAAAAAAAAAAAAAAAAAAPb2
9gD29vYA9vb2Cfb29jf29vZy9vb2n/b29rL29vay9vb2n/b29nL29vY39vb2Cfb29gD29vYAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb2
9gD29vYA9vb2Dfb29k729vaj9vb24/b29v729vb+9vb25Pb29qj29vZX9vb2G/b29gf29vYJ9vb2Dvb2
9g729vYO9vb2Dvb29gn29vYH9vb2G/b29lf29vao9vb25Pb29v729vb+9vb24/b29qP29vZO9vb2Dfb2
9gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAPb29gD29vYA9vb2Dvb29lL29vat9vb28ff39//4+Pj/+fn59fn5+cf5+fmK+Pj4XPf3
90339/dO9vb2Uvb29lL29vZS9vb2Uvf390739/dN+Pj4XPn5+Yr5+fnH+fn59fj4+P/39/f/9vb28fb2
9q329vZS9vb2Dvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Dvb29lL29vat9vb28fj4+P/5+fn/+vr6+vr6
+uT5+fnH+Pj4sff396r29var9vb2rfb29q329vat9vb2rfb29qv39/eq+Pj4sfn5+cf6+vrk+vr6+vn5
+f/4+Pj/9vb28fb29q329vZS9vb2Dvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Dvf391L29vat9vb28fPz
8//w8PD/7+/v/u/v7/ry8vL19PT08vX19fD29vbx9vb28fb29vH29vbx9vb28fb29vH19fXw9PT08vLy
8vXv7+/67+/v/vDw8P/z8/P/9vb28fb29q339/dS9vb2Dvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Dvn5
+VL4+Pit8/Pz8efn5//W1tb/zMzM/9LS0v/h4eH/7e3t//Pz8//29vb/9/f3//j4+P/4+Pj/9/f3//b2
9v/z8/P/7e3t/+Hh4f/S0tL/zMzM/9bW1v/n5+f/8/Pz8fj4+K35+flS9vb2Dvb29gD29vYAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb2
9gD29vYA9vb2Dv39/VL7+/ut8PDw8dbW1v+zs7P/np6e/6qqqv/Hx8f/4eHh/+7u7v/09PT/+Pj4//r6
+v/6+vr/+Pj4//T09P/u7u7/4eHh/8fHx/+qqqr/np6e/7Ozs//W1tb/8PDw8fv7+639/f1S9vb2Dvb2
9gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAPb29gD29vYA9vb2Dv///1L9/f2t7u7u8cjIyP+Wlpb/eHh4/4WFhf+pqan/ysrK/9zc
3P/o6Oj/7+/v//Pz8//z8/P/7+/v/+jo6P/c3Nz/ysrK/6mpqf+FhYX/eHh4/5aWlv/IyMj/7u7u8f39
/a3///9S9vb2Dvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Dv///1L+/v6t7Ozs8cLCwv+IiIj/YmJi/2dn
Z/+FhYX/oqKi/7i4uP/Ly8v/2NjY/97e3v/e3t7/2NjY/8vLy/+4uLj/oqKi/4WFhf9nZ2f/YmJi/4iI
iP/CwsL/7Ozs8f7+/q3///9S9vb2Dvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Dv///1L+/v6t7Ozs8b+/
v/+Dg4P/VVVV/09PT/9dXV3/cnJy/4qKiv+kpKT/uLi4/8DAwP/AwMD/uLi4/6SkpP+Kior/cnJy/11d
Xf9PT0//VVVV/4ODg/+/v7//7Ozs8f7+/q3///9S9vb2Dvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Dv//
/1L///+t7Ozs8b6+vv+AgID/Tk5O/z4+Pv9BQUH/Tk5O/2VlZf+CgoL/l5eX/6Ghof+hoaH/l5eX/4KC
gv9lZWX/Tk5O/0FBQf8+Pj7/Tk5O/4CAgP++vr7/7Ozs8f///63///9S9vb2Dvb29gD29vYAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb2
9gD29vYA9vb2Dv///1L///+t6+vr8b29vf9+fn7/S0tL/zg4OP84ODj/QUFB/1FRUf9oaGj/eHh4/39/
f/9/f3//eHh4/2hoaP9RUVH/QUFB/zg4OP84ODj/S0tL/35+fv+9vb3/6+vr8f///63///9S9vb2Dvb2
9gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAPb29gD29vYA9vb2Dv///1L///+t6+vr8b6+vv9+fn7/S0tL/zo6Ov86Ojr/QUFB/0hI
SP9TU1P/W1tb/19fX/9fX1//W1tb/1NTU/9ISEj/QUFB/zo6Ov86Ojr/S0tL/35+fv++vr7/6+vr8f//
/63///9S9vb2Dvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Dv///1L///+t6+vr8b6+vv9/f3//TExM/zw8
PP8+Pj7/QkJC/0RERP9FRUX/R0dH/0dHR/9HR0f/R0dH/0VFRf9ERET/QkJC/z4+Pv88PDz/TExM/39/
f/++vr7/6+vr8f///63///9S9vb2Dvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Dv///1L///+t6+vr8b6+
vv9/f3//TExM/zw8PP8+Pj7/QkJC/0FBQf9AQED/Pz8//z8/P/8/Pz//Pz8//0BAQP9BQUH/QkJC/z4+
Pv88PDz/TExM/39/f/++vr7/6+vr8f///63///9S9vb2Dvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Dv//
/1L///+t6+vr8b6+vv9/f3//TExM/zw8PP8+Pj7/QkJC/0FBQf9BQUH/QEBA/0BAQP9AQED/QEBA/0FB
Qf9BQUH/QkJC/z4+Pv88PDz/TExM/39/f/++vr7/6+vr8f///63///9S9vb2Dvb29gD29vYAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb2
9gD29vYA9vb2Dv///1L///+t6+vr8b6+vv9/f3//TExM/zw8PP8+Pj7/QkJC/0JCQv9CQkL/QkJC/0JC
Qv9CQkL/QkJC/0JCQv9CQkL/QkJC/z4+Pv88PDz/TExM/39/f/++vr7/6+vr8f///63///9S9vb2Dvb2
9gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAPb29gD29vYA9vb2Dv///1L///+t6+vr8b6+vv9/f3//TExM/zw8PP8+Pj7/QkJC/0JC
Qv9CQkL/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC/z4+Pv88PDz/TExM/39/f/++vr7/6+vr8f//
/63///9S9vb2Dvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Dv///1L///+t6+vr8b6+vv9/f3//TExM/zw8
PP8+Pj7/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC/z4+Pv88PDz/TExM/39/
f/++vr7/6+vr8f///63///9S9vb2Dvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Dv///1L///+t6+vr8b6+
vv9/f3//TExM/zw8PP8+Pj7/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC/z4+
Pv88PDz/TExM/39/f/++vr7/6+vr8f///63///9S9vb2Dvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Dv//
/1L///+t6+vr8b6+vv9/f3//TExM/zw8PP8+Pj7/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC/0JC
Qv9CQkL/QkJC/z4+Pv88PDz/TExM/39/f/++vr7/6+vr8f///63///9S9vb2Dvb29gD29vYAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb2
9gD29vYA9vb2Dv///1L///+t6+vr8b6+vv9/f3//TExM/zw8PP8+Pj7/QkJC/0JCQv9CQkL/QkJC/0JC
Qv9CQkL/QkJC/0JCQv9CQkL/QkJC/z4+Pv88PDz/TExM/39/f/++vr7/6+vr8f///63///9S9vb2Dvb2
9gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAPb29gD29vYA9vb2Dv///1L///+t6+vr8b6+vv9/f3//TExM/zw8PP8+Pj7/QkJC/0JC
Qv9CQkL/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC/z4+Pv88PDz/TExM/39/f/++vr7/6+vr8f//
/63///9S9vb2Dvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Dv///1L///+t6+vr8b6+vv9/f3//TExM/zw8
PP8+Pj7/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC/z4+Pv88PDz/TExM/39/
f/++vr7/6+vr8f///63///9S9vb2Dvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Dv///1L///+t6+vr8b6+
vv9/f3//TExM/zw8PP8+Pj7/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC/z4+
Pv88PDz/TExM/39/f/++vr7/6+vr8f///63///9S9vb2Dvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Dv//
/1L///+t6+vr8b6+vv9/f3//TExM/zw8PP8+Pj7/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC/0JC
Qv9CQkL/QkJC/z4+Pv88PDz/TExM/39/f/++vr7/6+vr8f///63///9S9vb2Dvb29gD29vYAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb2
9gD29vYA9vb2Dv///1L///+t6+vr8b6+vv9/f3//TExM/zw8PP8+Pj7/QkJC/0JCQv9CQkL/QkJC/0JC
Qv9CQkL/QkJC/0JCQv9CQkL/QkJC/z4+Pv88PDz/TExM/39/f/++vr7/6+vr8f///63///9S9vb2Dvb2
9gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAPb29gD29vYA9vb2Dv///1L///+t6+vr8b6+vv9/f3//TExM/zw8PP8+Pj7/QkJC/0JC
Qv9CQkL/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC/z4+Pv88PDz/TExM/39/f/++vr7/6+vr8f//
/63///9S9vb2Dvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Dv///1L///+t6+vr8b6+vv9/f3//TExM/zw8
PP8+Pj7/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC/z4+Pv88PDz/TExM/39/
f/++vr7/6+vr8f///63///9S9vb2Dvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Dv///1L///+t6+vr8b6+
vv9/f3//TExM/zw8PP8+Pj7/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC/z4+
Pv88PDz/TExM/39/f/++vr7/6+vr8f///63///9S9vb2Dvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Dv//
/1L///+t6+vr8b6+vv9/f3//TExM/zw8PP8+Pj7/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC/0JC
Qv9CQkL/QkJC/z4+Pv88PDz/TExM/39/f/++vr7/6+vr8f///63///9S9vb2Dvb29gD29vYAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb2
9gD29vYA9vb2Dv///1L///+t6+vr8b6+vv9/f3//TExM/zw8PP8+Pj7/QkJC/0JCQv9CQkL/QkJC/0JC
Qv9CQkL/QkJC/0JCQv9CQkL/QkJC/z4+Pv88PDz/TExM/39/f/++vr7/6+vr8f///63///9S9vb2Dvb2
9gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAPb29gD29vYA9vb2Dv///1L///+t6+vr8b6+vv9/f3//TExM/zw8PP8+Pj7/QkJC/0JC
Qv9CQkL/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC/z4+Pv88PDz/TExM/39/f/++vr7/6+vr8f//
/63///9S9vb2Dvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Dv///1L///+t6+vr8b6+vv9/f3//TExM/zw8
PP8+Pj7/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC/z4+Pv88PDz/TExM/39/
f/++vr7/6+vr8f///63///9S9vb2Dvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Dv///1L///+t6+vr8b6+
vv9/f3//TExM/zw8PP8+Pj7/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC/z4+
Pv88PDz/TExM/39/f/++vr7/6+vr8f///63///9S9vb2Dvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Dv//
/1L///+t6+vr8by8vP98fHz/SEhI/zg4OP86Ojr/Pj4+/z4+Pv8+Pj7/Pj4+/z4+Pv8+Pj7/Pj4+/z4+
Pv8+Pj7/Pj4+/zo6Ov84ODj/SEhI/3x8fP+8vLz/6+vr8f///63///9S9vb2Dvb29gD29vYAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb2
9gD29vYA9vb2Dv///1L///+t6+vr8by8vP97e3v/RkZG/zY2Nv84ODj/PDw8/zw8PP88PDz/PDw8/zw8
PP88PDz/PDw8/zw8PP88PDz/PDw8/zg4OP82Njb/RkZG/3t7e/+8vLz/6+vr8f///63///9S9vb2Dvb2
9gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAPb29gD29vYA9vb2Dv///1L+/v6t7Ozs8cHBwf+FhYX/VVVV/0ZGRv9ISEj/TExM/0xM
TP9MTEz/TExM/0xMTP9MTEz/TExM/0xMTP9MTEz/TExM/0hISP9GRkb/VVVV/4WFhf/BwcH/7Ozs8f7+
/q3///9S9vb2Dvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Dv7+/lL8/Pyt7+/v8dHR0f+np6f/hYWF/3t7
e/98fHz/f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//3x8fP97e3v/hYWF/6en
p//R0dH/7+/v8fz8/K3+/v5S9vb2Dvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Dvr6+lL5+fmt8/Pz8eTk
5P/R0dH/wcHB/7y8vP+8vLz/vr6+/76+vv++vr7/vr6+/76+vv++vr7/vr6+/76+vv++vr7/vr6+/7y8
vP+8vLz/wcHB/9HR0f/k5OT/8/Pz8fn5+a36+vpS9vb2Dvb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Dff3
90739/ej9fX14/Pz8/nv7+/27Ozs8evr6/Hr6+vx6+vr8evr6/Hr6+vx6+vr8evr6/Hr6+vx6+vr8evr
6/Hr6+vx6+vr8evr6/Hr6+vx7Ozs8e/v7/bz8/P59fX14/f396P39/dO9vb2Dfb29gD29vYAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb2
9gD29vYA9vb2CfX19Tf29vZy9/f3n/n5+a78/Pyt/v7+qf///6n///+p////qf///6n///+p////qf//
/6n///+p////qf///6n///+p////qf///6n///+p/v7+qfz8/K35+fmu9/f3n/b29nL19fU39vb2Cfb2
9gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAPb29gD29vYA9vb2BPX19Rr29vY29/f3S/n5+VL8/PxS////UP///1D///9Q////UP//
/1D///9Q////UP///1D///9Q////UP///1D///9Q////UP///1D///9Q////UPz8/FL5+flS9/f3S/b2
9jb19fUa9vb2BPb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29gD29vYA9vb2Afb29gX29vYK9vb2Dvb29g/29vYP9vb2D/b2
9g/29vYP9vb2D/b29g/29vYP9vb2D/b29g/29vYP9vb2D/b29g/29vYP9vb2D/b29g/29vYP9vb2D/b2
9g/29vYP9vb2Dvb29gr29vYF9vb2Afb29gD29vYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAD///////8AAP/AD/AD/wAA/8AP8AP/AAD/wA/wA/8AAP/AAAAD/wAA/8AAAAP/
AAD/wAAAA/8AAP/AAAAD/wAA/8AAAAP/AAD/wAAAA/8AAP/AAAAD/wAA/8AAAAP/AAD/wAAAA/8AAP/A
AAAD/wAA/8AAAAP/AAD/wAAAA/8AAP/AAAAD/wAA/8AAAAP/AAD/wAAAA/8AAP/AAAAD/wAA/8AAAAP/
AAD/wAAAA/8AAP/AAAAD/wAA/8AAAAP/AAD/wAAAA/8AAP/AAAAD/wAA/8AAAAP/AAD/wAAAA/8AAP/A
AAAD/wAA/8AAAAP/AAD/wAAAA/8AAP/AAAAD/wAA/8AAAAP/AAD/wAAAA/8AAP/AAAAD/wAA/8AAAAP/
AAD/wAAAA/8AAP/AAAAD/wAA/8AAAAP/AAD/wAAAA/8AAP/AAAAD/wAA/8AAAAP/AAD/wAAAA/8AAP/A
AAAD/wAA/8AAAAP/AAD/wAAAA/8AAP/AAAAD/wAA////////AAAoAAAAEAAAACAAAAABACAAAAAAAAAE
AADDDgAAww4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD29vb/9vb2/wAAAAAAAAAAAAAAAAAA
AAD29vb/9vb2/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9vb2//b29v/29vb/9vb2//b2
9v/29vb/9vb2//b29v8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29v9kZGT/1NTU//b2
9v/29vb/1NTU/2RkZP/29vb/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD29vb/QkJC/0JC
Qv+cnJz/nJyc/0JCQv9CQkL/9vb2/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9vb2/0JC
Qv9CQkL/QkJC/0JCQv9CQkL/QkJC//b29v8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb2
9v9CQkL/QkJC/0JCQv9CQkL/QkJC/0JCQv/29vb/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAD29vb/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/9vb2/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA9vb2/0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC//b29v8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAPb29v9CQkL/QkJC/0JCQv9CQkL/QkJC/0JCQv/29vb/AAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAD29vb/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/9vb2/wAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA9vb2/0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC//b29v8AAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPb29v9CQkL/QkJC/0JCQv9CQkL/QkJC/0JCQv/29vb/AAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD29vb/QkJC/0JCQv9CQkL/QkJC/0JCQv9CQkL/9vb2/wAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b2
9v8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//AADzzwAA8A8AAPAPAADwDwAA8A8AAPAPAADwDwAA8A8AAPAP
AADwDwAA8A8AAPAPAADwDwAA8A8AAP//AAA=
</value>
</data>
</root>

View File

@@ -0,0 +1,157 @@
' Copyright (C) 2022 Andy
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY
Imports System.ComponentModel
Imports System.Threading
Imports PersonalUtilities.Forms
Imports PersonalUtilities.Forms.Toolbars
Imports SCrawler.API
Imports Job = SCrawler.TDownloader.Job
Friend Class DownloadSavedPostsForm
Friend Event OnDownloadDone(ByVal Message As String)
Private MyView As FormsView
Private ReadOnly ProgressReddit As MyProgress
Private ReadOnly ProgressInstgram As MyProgress
Private JobReddit As Job
Private JobInstagram As Job
Friend ReadOnly Property Working As Boolean
Get
Return JobReddit Or JobInstagram
End Get
End Property
#Region "Start and Stop functions"
Friend Overloads Sub [Stop]()
[Stop](Sites.Reddit)
[Stop](Sites.Instagram)
End Sub
Private Overloads Sub [Stop](ByVal Site As Sites)
Select Case Site
Case Sites.Reddit : If JobReddit Then JobReddit.Stop()
Case Sites.Instagram : If JobInstagram Then JobInstagram.Stop()
End Select
End Sub
Private Overloads Sub [Start]()
Start(Sites.Reddit)
Start(Sites.Instagram)
End Sub
Private Overloads Sub [Start](ByVal Site As Sites)
Select Case Site
Case Sites.Reddit : If Not JobReddit Then JobReddit.Start(New ThreadStart(Sub() DownloadData(Sites.Reddit)))
Case Sites.Instagram
If Not JobInstagram Then
If Not Downloader.Working(Sites.Instagram) Then
Downloader.InstagramSavedPostsDownloading = True
JobInstagram.Start(New ThreadStart(Sub() DownloadData(Sites.Instagram)))
Else
MsgBoxE({$"Downloading Instagram profiles still works.{vbCr}Wait for this to be done before starting.{vbCr}Operation canceled",
"Instagram saved posts"}, MsgBoxStyle.Critical)
End If
End If
End Select
End Sub
#End Region
#Region "Form functions"
Friend Sub New()
InitializeComponent()
ProgressReddit = New MyProgress(PR_REDDIT, LBL_REDDIT)
ProgressInstgram = New MyProgress(PR_INST, LBL_INST)
JobReddit = New Job(ProgressReddit) With {.Site = Sites.Reddit}
JobInstagram = New Job(ProgressInstgram) With {.Site = Sites.Instagram}
End Sub
Private Sub DownloadSavedPostsForm_Load(sender As Object, e As EventArgs) Handles Me.Load
MyView = New FormsView(Me) With {.LocationOnly = True}
MyView.ImportFromXML(Settings.Design)
MyView.SetMeSize()
End Sub
Private Sub DownloadSavedPostsForm_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
e.Cancel = True
Hide()
End Sub
Private Sub DownloadSavedPostsForm_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed
[Stop]()
MyView.Dispose(Settings.Design)
End Sub
#End Region
#Region "Controls"
Private Sub BTT_DOWN_ALL_Click(sender As Object, e As EventArgs) Handles BTT_DOWN_ALL.Click
Start()
End Sub
Private Sub BTT_STOP_ALL_Click(sender As Object, e As EventArgs) Handles BTT_STOP_ALL.Click
[Stop]()
End Sub
#Region "Reddit"
Private Sub BTT_REDDIT_START_Click(sender As Object, e As EventArgs) Handles BTT_REDDIT_START.Click
Start(Sites.Reddit)
End Sub
Private Sub BTT_REDDIT_STOP_Click(sender As Object, e As EventArgs) Handles BTT_REDDIT_STOP.Click
[Stop](Sites.Reddit)
End Sub
Private Sub BTT_REDDIT_OPEN_Click(sender As Object, e As EventArgs) Handles BTT_REDDIT_OPEN.Click
OpenPath(Reddit.ProfileSaved.DataPath)
End Sub
Private Sub LBL_REDDIT_DoubleClick(sender As Object, e As EventArgs) Handles LBL_REDDIT.DoubleClick
OpenPath(Reddit.ProfileSaved.DataPath)
End Sub
#End Region
#Region "Instagram"
Private Sub BTT_INST_START_Click(sender As Object, e As EventArgs) Handles BTT_INST_START.Click
Start(Sites.Instagram)
End Sub
Private Sub BTT_INST_STOP_Click(sender As Object, e As EventArgs) Handles BTT_INST_STOP.Click
[Stop](Sites.Instagram)
End Sub
Private Sub BTT_INST_OPEN_Click(sender As Object, e As EventArgs) Handles BTT_INST_OPEN.Click
OpenPath(Instagram.ProfileSaved.DataPath)
End Sub
Private Sub LBL_INST_DoubleClick(sender As Object, e As EventArgs) Handles LBL_INST.DoubleClick
OpenPath(Instagram.ProfileSaved.DataPath)
End Sub
#End Region
#End Region
Private Sub DownloadData(ByVal Site As Sites)
Dim btte As Action(Of Button, Boolean) = Sub(b, e) If b.InvokeRequired Then b.Invoke(Sub() b.Enabled = e) Else b.Enabled = e
Try
Select Case Site
Case Sites.Reddit
btte(BTT_REDDIT_START, False)
btte(BTT_REDDIT_STOP, True)
JobReddit.Progress.InformationTemporary = "Reddit downloading started"
JobReddit.Start()
Reddit.ProfileSaved.Download(JobReddit.Progress, JobReddit)
Case Sites.Instagram
btte(BTT_INST_START, False)
btte(BTT_INST_STOP, True)
JobInstagram.Progress.InformationTemporary = "Instagram downloading started"
JobInstagram.Start()
Instagram.ProfileSaved.Download(JobInstagram.Progress, JobInstagram)
End Select
RaiseEvent OnDownloadDone($"Downloading saved {Site} posts is completed")
Catch ex As Exception
Select Case Site
Case Sites.Reddit : JobReddit.Progress.InformationTemporary = "Reddit downloading error"
Case Sites.Instagram : JobInstagram.Progress.InformationTemporary = "Instagram downloading error"
End Select
ErrorsDescriber.Execute(EDP.LogMessageValue, ex, {$"{Site} saved posts downloading error", "Saved posts"})
Finally
Select Case Site
Case Sites.Reddit
JobReddit.Stopped()
btte(BTT_REDDIT_START, True)
btte(BTT_REDDIT_STOP, False)
Case Sites.Instagram
JobInstagram.Stopped()
btte(BTT_INST_START, True)
btte(BTT_INST_STOP, False)
Downloader.InstagramSavedPostsDownloading = False
End Select
End Try
End Sub
Private Sub OpenPath(ByVal f As SFile)
If f.Exists(SFO.Path, False) Then f.Open(SFO.Path)
End Sub
End Class

View File

@@ -14,6 +14,7 @@ Partial Friend Class DownloadedInfoForm : Inherits System.Windows.Forms.Form
<System.Diagnostics.DebuggerStepThrough()> <System.Diagnostics.DebuggerStepThrough()>
Private Sub InitializeComponent() Private Sub InitializeComponent()
Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(DownloadedInfoForm)) Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(DownloadedInfoForm))
Dim SEP_1 As System.Windows.Forms.ToolStripSeparator
Me.ToolbarTOP = New System.Windows.Forms.ToolStrip() Me.ToolbarTOP = New System.Windows.Forms.ToolStrip()
Me.MENU_VIEW = New System.Windows.Forms.ToolStripDropDownButton() Me.MENU_VIEW = New System.Windows.Forms.ToolStripDropDownButton()
Me.MENU_VIEW_SESSION = New System.Windows.Forms.ToolStripMenuItem() Me.MENU_VIEW_SESSION = New System.Windows.Forms.ToolStripMenuItem()
@@ -21,13 +22,15 @@ Partial Friend Class DownloadedInfoForm : Inherits System.Windows.Forms.Form
Me.BTT_REFRESH = New System.Windows.Forms.ToolStripButton() Me.BTT_REFRESH = New System.Windows.Forms.ToolStripButton()
Me.ToolbarBOTTOM = New System.Windows.Forms.StatusStrip() Me.ToolbarBOTTOM = New System.Windows.Forms.StatusStrip()
Me.LIST_DOWN = New System.Windows.Forms.ListBox() Me.LIST_DOWN = New System.Windows.Forms.ListBox()
Me.BTT_CLEAR = New System.Windows.Forms.ToolStripButton()
SEP_1 = New System.Windows.Forms.ToolStripSeparator()
Me.ToolbarTOP.SuspendLayout() Me.ToolbarTOP.SuspendLayout()
Me.SuspendLayout() Me.SuspendLayout()
' '
'ToolbarTOP 'ToolbarTOP
' '
Me.ToolbarTOP.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden Me.ToolbarTOP.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden
Me.ToolbarTOP.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.MENU_VIEW, Me.BTT_REFRESH}) Me.ToolbarTOP.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.MENU_VIEW, Me.BTT_REFRESH, SEP_1, Me.BTT_CLEAR})
Me.ToolbarTOP.Location = New System.Drawing.Point(0, 0) Me.ToolbarTOP.Location = New System.Drawing.Point(0, 0)
Me.ToolbarTOP.Name = "ToolbarTOP" Me.ToolbarTOP.Name = "ToolbarTOP"
Me.ToolbarTOP.Size = New System.Drawing.Size(554, 25) Me.ToolbarTOP.Size = New System.Drawing.Size(554, 25)
@@ -48,7 +51,7 @@ Partial Friend Class DownloadedInfoForm : Inherits System.Windows.Forms.Form
' '
Me.MENU_VIEW_SESSION.AutoToolTip = True Me.MENU_VIEW_SESSION.AutoToolTip = True
Me.MENU_VIEW_SESSION.Name = "MENU_VIEW_SESSION" Me.MENU_VIEW_SESSION.Name = "MENU_VIEW_SESSION"
Me.MENU_VIEW_SESSION.Size = New System.Drawing.Size(180, 22) Me.MENU_VIEW_SESSION.Size = New System.Drawing.Size(113, 22)
Me.MENU_VIEW_SESSION.Text = "Session" Me.MENU_VIEW_SESSION.Text = "Session"
Me.MENU_VIEW_SESSION.ToolTipText = "Show downloaded users by this session" Me.MENU_VIEW_SESSION.ToolTipText = "Show downloaded users by this session"
' '
@@ -56,7 +59,7 @@ Partial Friend Class DownloadedInfoForm : Inherits System.Windows.Forms.Form
' '
Me.MENU_VIEW_ALL.AutoToolTip = True Me.MENU_VIEW_ALL.AutoToolTip = True
Me.MENU_VIEW_ALL.Name = "MENU_VIEW_ALL" Me.MENU_VIEW_ALL.Name = "MENU_VIEW_ALL"
Me.MENU_VIEW_ALL.Size = New System.Drawing.Size(180, 22) Me.MENU_VIEW_ALL.Size = New System.Drawing.Size(113, 22)
Me.MENU_VIEW_ALL.Text = "All" Me.MENU_VIEW_ALL.Text = "All"
Me.MENU_VIEW_ALL.ToolTipText = "Show all users (sorted by latest download)" Me.MENU_VIEW_ALL.ToolTipText = "Show all users (sorted by latest download)"
' '
@@ -85,6 +88,21 @@ Partial Friend Class DownloadedInfoForm : Inherits System.Windows.Forms.Form
Me.LIST_DOWN.Size = New System.Drawing.Size(554, 364) Me.LIST_DOWN.Size = New System.Drawing.Size(554, 364)
Me.LIST_DOWN.TabIndex = 2 Me.LIST_DOWN.TabIndex = 2
' '
'SEP_1
'
SEP_1.Name = "SEP_1"
SEP_1.Size = New System.Drawing.Size(6, 25)
'
'BTT_CLEAR
'
Me.BTT_CLEAR.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text
Me.BTT_CLEAR.Image = CType(resources.GetObject("BTT_CLEAR.Image"), System.Drawing.Image)
Me.BTT_CLEAR.ImageTransparentColor = System.Drawing.Color.Magenta
Me.BTT_CLEAR.Name = "BTT_CLEAR"
Me.BTT_CLEAR.Size = New System.Drawing.Size(38, 22)
Me.BTT_CLEAR.Text = "Clear"
Me.BTT_CLEAR.ToolTipText = "Clear info list"
'
'DownloadedInfoForm 'DownloadedInfoForm
' '
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!) Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
@@ -112,4 +130,5 @@ Partial Friend Class DownloadedInfoForm : Inherits System.Windows.Forms.Form
Private WithEvents BTT_REFRESH As ToolStripButton Private WithEvents BTT_REFRESH As ToolStripButton
Private WithEvents ToolbarBOTTOM As StatusStrip Private WithEvents ToolbarBOTTOM As StatusStrip
Private WithEvents LIST_DOWN As ListBox Private WithEvents LIST_DOWN As ListBox
Private WithEvents BTT_CLEAR As ToolStripButton
End Class End Class

View File

@@ -134,6 +134,24 @@
mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+
kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D
TgDQASA1MVpwzwAAAABJRU5ErkJggg== TgDQASA1MVpwzwAAAABJRU5ErkJggg==
</value>
</data>
<metadata name="SEP_1.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<data name="BTT_CLEAR.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG
YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9
0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw
bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc
VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9
c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32
Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo
mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+
kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D
TgDQASA1MVpwzwAAAABJRU5ErkJggg==
</value> </value>
</data> </data>
<metadata name="ToolbarBOTTOM.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <metadata name="ToolbarBOTTOM.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">

View File

@@ -45,6 +45,7 @@ Friend Class DownloadedInfoForm
MyView.ImportFromXML(Settings.Design) MyView.ImportFromXML(Settings.Design)
MyView.SetMeSize() MyView.SetMeSize()
End If End If
BTT_CLEAR.Visible = ViewMode = ViewModes.Session
RefillList() RefillList()
Catch ex As Exception Catch ex As Exception
End Try End Try
@@ -104,17 +105,25 @@ Friend Class DownloadedInfoForm
MENU_VIEW_SESSION.Checked = True MENU_VIEW_SESSION.Checked = True
MENU_VIEW_ALL.Checked = False MENU_VIEW_ALL.Checked = False
ViewMode = ViewModes.Session ViewMode = ViewModes.Session
BTT_CLEAR.Visible = True
RefillList() RefillList()
End Sub End Sub
Private Sub MENU_VIEW_ALL_Click(sender As Object, e As EventArgs) Handles MENU_VIEW_ALL.Click Private Sub MENU_VIEW_ALL_Click(sender As Object, e As EventArgs) Handles MENU_VIEW_ALL.Click
MENU_VIEW_SESSION.Checked = False MENU_VIEW_SESSION.Checked = False
MENU_VIEW_ALL.Checked = True MENU_VIEW_ALL.Checked = True
ViewMode = ViewModes.All ViewMode = ViewModes.All
BTT_CLEAR.Visible = False
RefillList() RefillList()
End Sub End Sub
Private Sub BTT_REFRESH_Click(sender As Object, e As EventArgs) Handles BTT_REFRESH.Click Private Sub BTT_REFRESH_Click(sender As Object, e As EventArgs) Handles BTT_REFRESH.Click
RefillList() RefillList()
End Sub End Sub
Private Sub BTT_CLEAR_Click(sender As Object, e As EventArgs) Handles BTT_CLEAR.Click
If LIST_DOWN.Items.Count > 0 Then
Downloader.Downloaded.Clear()
RefillList()
End If
End Sub
Private _LatestSelected As Integer = -1 Private _LatestSelected As Integer = -1
Private Sub LIST_DOWN_SelectedIndexChanged(sender As Object, e As EventArgs) Handles LIST_DOWN.SelectedIndexChanged Private Sub LIST_DOWN_SelectedIndexChanged(sender As Object, e As EventArgs) Handles LIST_DOWN.SelectedIndexChanged
_LatestSelected = LIST_DOWN.SelectedIndex _LatestSelected = LIST_DOWN.SelectedIndex

View File

@@ -6,7 +6,6 @@
' '
' 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.ComponentModel
Imports PersonalUtilities.Forms Imports PersonalUtilities.Forms
Imports PersonalUtilities.Forms.Controls.Base Imports PersonalUtilities.Forms.Controls.Base
Imports PersonalUtilities.Forms.Toolbars Imports PersonalUtilities.Forms.Toolbars
@@ -28,50 +27,40 @@ Namespace Editors
Try Try
With MyDefs With MyDefs
.MyViewInitialize(Me, Settings.Design) .MyViewInitialize(Me, Settings.Design)
.MyOkCancel = New OkCancelToolbar(Me, Me, CONTAINER_MAIN.BottomToolStripPanel) .AddOkCancelToolbar()
.MyOkCancel.AddThisToolbar() .DelegateClosingChecker()
Collections.ListAddList((From c In Settings.Users Where c.IsCollection Select c.CollectionName), LAP.NotContainsOnly, EDP.ThrowException) Collections.ListAddList((From c In Settings.Users Where c.IsCollection Select c.CollectionName), LAP.NotContainsOnly, EDP.ThrowException)
If Collections.ListExists Then CMB_COLLECTIONS.Items.AddRange(From c In Collections Select New Controls.Base.ListItem(c)) If Collections.ListExists Then Collections.Sort() : CMB_COLLECTIONS.Items.AddRange(From c In Collections Select New ListItem(c))
If Not Collection.IsEmptyString And Collections.Contains(Collection) Then CMB_COLLECTIONS.SelectedIndex = Collections.IndexOf(Collection) If Not Collection.IsEmptyString And Collections.Contains(Collection) Then CMB_COLLECTIONS.SelectedIndex = Collections.IndexOf(Collection)
End With End With
Catch ex As Exception Catch ex As Exception
MyDefs.InvokeLoaderError(ex) MyDefs.InvokeLoaderError(ex)
End Try End Try
End Sub End Sub
Private Sub CollectionEditorForm_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing Private Sub CollectionEditorForm_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed
If Not BeforeCloseChecker(MyDefs.ChangesDetected) Then Collections.Clear()
e.Cancel = True
Else
Collections.Clear()
MyDefs.Dispose()
End If
End Sub End Sub
Private Sub CollectionEditorForm_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown Private Sub CollectionEditorForm_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
If e.KeyCode = Keys.Insert Then If e.KeyCode = Keys.Insert Then AddNewCollection() : e.Handled = True Else e.Handled = False
AddNewCollection()
e.Handled = True
Else
e.Handled = False
End If
End Sub End Sub
Private Sub ToolbarBttOK() Implements IOkCancelToolbar.ToolbarBttOK Private Sub ToolbarBttOK() Implements IOkCancelToolbar.ToolbarBttOK
If CMB_COLLECTIONS.SelectedIndex >= 0 Then If CMB_COLLECTIONS.SelectedIndex >= 0 Then
Collection = CMB_COLLECTIONS.Value.ToString Collection = CMB_COLLECTIONS.Value.ToString
MyDefs.ChangesDetected = False MyDefs.CloseForm()
DialogResult = DialogResult.OK
Close()
Else Else
MsgBoxE("Collection does not selected", MsgBoxStyle.Exclamation) MsgBoxE("Collection not selected", MsgBoxStyle.Exclamation)
End If End If
End Sub End Sub
Private Sub ToolbarBttCancel() Implements IOkCancelToolbar.ToolbarBttCancel Private Sub ToolbarBttCancel() Implements IOkCancelToolbar.ToolbarBttCancel
MyDefs.ChangesDetected = False MyDefs.CloseForm(DialogResult.Cancel)
DialogResult = DialogResult.Cancel
Close()
End Sub End Sub
Private Sub CMB_COLLECTIONS_ActionOnButtonClick(ByVal Sender As ActionButton) Handles CMB_COLLECTIONS.ActionOnButtonClick Private Sub CMB_COLLECTIONS_ActionOnButtonClick(ByVal Sender As ActionButton) Handles CMB_COLLECTIONS.ActionOnButtonClick
If Sender.DefaultButton = ActionButton.DefaultButtons.Add Then AddNewCollection() If Sender.DefaultButton = ActionButton.DefaultButtons.Add Then AddNewCollection()
End Sub End Sub
Private Sub CMB_COLLECTIONS_ActionOnListDoubleClick(ByVal _Item As ListViewItem) Handles CMB_COLLECTIONS.ActionOnListDoubleClick
_Item.Selected = True
ToolbarBttOK()
End Sub
Private Sub AddNewCollection() Private Sub AddNewCollection()
Dim c$ = InputBoxE("Enter new collection name:", "Collection name") Dim c$ = InputBoxE("Enter new collection name:", "Collection name")
If Not c.IsEmptyString Then If Not c.IsEmptyString Then

File diff suppressed because it is too large Load Diff

View File

@@ -214,9 +214,6 @@ If checked, videos will be stored in separate folder; otherwise, videos will be
<metadata name="TP_CHANNELS_IMGS.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <metadata name="TP_CHANNELS_IMGS.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value> <value>False</value>
</metadata> </metadata>
<metadata name="TAB_MAIN.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="TAB_BASIS.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <metadata name="TAB_BASIS.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value> <value>False</value>
</metadata> </metadata>
@@ -235,18 +232,9 @@ If checked, videos will be stored in separate folder; otherwise, videos will be
<metadata name="TAB_DEFS_REDDIT.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <metadata name="TAB_DEFS_REDDIT.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value> <value>False</value>
</metadata> </metadata>
<metadata name="TP_REDDIT.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="TAB_DEFS_TWITTER.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <metadata name="TAB_DEFS_TWITTER.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value> <value>False</value>
</metadata> </metadata>
<metadata name="TP_TWITTER.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="TP_INSTAGRAM.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> <data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value> <value>
AAABAA8AAAAQAAEABAAwOgAA9gAAADAwEAABAAQAaAYAACg7AAAgIBAAAQAEAOgCAACQQQAAGBgQAAEA AAABAA8AAAAQAAEABAAwOgAA9gAAADAwEAABAAQAaAYAACg7AAAgIBAAAQAEAOgCAACQQQAAGBgQAAEA

View File

@@ -12,6 +12,7 @@ Imports PersonalUtilities.Forms.Toolbars
Namespace Editors Namespace Editors
Friend Class GlobalSettingsForm : Implements IOkCancelToolbar Friend Class GlobalSettingsForm : Implements IOkCancelToolbar
Private ReadOnly MyDefs As DefaultFormProps(Of FieldsChecker) Private ReadOnly MyDefs As DefaultFormProps(Of FieldsChecker)
#Region "Checkers declarations"
Private Class SavedPostsChecker : Implements ICustomProvider Private Class SavedPostsChecker : Implements ICustomProvider
Private Function Convert(ByVal Value As Object, ByVal DestinationType As Type, ByVal Provider As IFormatProvider, Private Function Convert(ByVal Value As Object, ByVal DestinationType As Type, ByVal Provider As IFormatProvider,
Optional ByVal NothingArg As Object = Nothing, Optional ByVal e As ErrorsDescriber = Nothing) As Object Implements ICustomProvider.Convert Optional ByVal NothingArg As Object = Nothing, Optional ByVal e As ErrorsDescriber = Nothing) As Object Implements ICustomProvider.Convert
@@ -25,6 +26,24 @@ Namespace Editors
Throw New NotImplementedException() Throw New NotImplementedException()
End Function End Function
End Class End Class
Private Class InstaTimersChecker : Implements ICustomProvider
Private ReadOnly _LowestValue As Integer
Friend Sub New(ByVal LowestValue As Integer)
_LowestValue = LowestValue
End Sub
Private Function Convert(ByVal Value As Object, ByVal DestinationType As Type, ByVal Provider As IFormatProvider,
Optional ByVal NothingArg As Object = Nothing, Optional ByVal e As ErrorsDescriber = Nothing) As Object Implements ICustomProvider.Convert
If ACheck(Of Integer)(Value) AndAlso CInt(Value) >= _LowestValue Then
Return Value
Else
Return Nothing
End If
End Function
Private Function GetFormat(ByVal FormatType As Type) As Object Implements IFormatProvider.GetFormat
Throw New NotImplementedException()
End Function
End Class
#End Region
Friend Sub New() Friend Sub New()
InitializeComponent() InitializeComponent()
MyDefs = New DefaultFormProps(Of FieldsChecker) MyDefs = New DefaultFormProps(Of FieldsChecker)
@@ -65,32 +84,39 @@ Namespace Editors
CH_FILE_TIME.Checked = .FileAddTimeToFileName CH_FILE_TIME.Checked = .FileAddTimeToFileName
OPT_FILE_DATE_START.Checked = Not .FileDateTimePositionEnd OPT_FILE_DATE_START.Checked = Not .FileDateTimePositionEnd
OPT_FILE_DATE_END.Checked = .FileDateTimePositionEnd OPT_FILE_DATE_END.Checked = .FileDateTimePositionEnd
'Other program settings
CH_EXIT_CONFIRM.Checked = .ExitConfirm
CH_CLOSE_TO_TRAY.Checked = .CloseToTray
CH_SHOW_NOTIFY.Checked = .ShowNotifications
'Reddit 'Reddit
With .Site(Sites.Reddit) With .Site(Sites.Reddit)
SetChecker(CH_REDDIT_TEMP, .Temporary) SetChecker(DEFS_REDDIT, Sites.Reddit)
SetChecker(CH_REDDIT_DOWN_IMG, .DownloadImages)
SetChecker(CH_REDDIT_DOWN_VID, .DownloadVideos)
TXT_REDDIT_SAVED_POSTS_USER.Text = .SavedPostsUserName TXT_REDDIT_SAVED_POSTS_USER.Text = .SavedPostsUserName
End With End With
'Twitter 'Twitter
With .Site(Sites.Twitter) With .Site(Sites.Twitter)
SetChecker(CH_TWITTER_TEMP, .Temporary) SetChecker(DEFS_TWITTER, Sites.Twitter)
SetChecker(CH_TWITTER_DOWN_IMG, .DownloadImages)
SetChecker(CH_TWITTER_DOWN_VID, .DownloadVideos)
CH_TWITTER_USER_MEDIA.Checked = .GetUserMediaOnly CH_TWITTER_USER_MEDIA.Checked = .GetUserMediaOnly
End With End With
'Instagram 'Instagram
With .Site(Sites.Instagram) With .Site(Sites.Instagram)
SetChecker(CH_INSTA_TEMP, .Temporary) SetChecker(DEFS_INST, Sites.Instagram)
SetChecker(CH_INSTA_DOWN_IMG, .DownloadImages) TXT_REQ_WAIT_TIMER.Text = .RequestsWaitTimer
SetChecker(CH_INSTA_DOWN_VID, .DownloadVideos) TXT_REQ_COUNT.Text = .RequestsWaitTimerTaskCount
TXT_LIMIT_TIMER.Text = .SleepTimerOnPostsLimit
TXT_INST_SAVED_POSTS_USER.Text = .SavedPostsUserName
End With End With
'RedGifs
SetChecker(DEFS_REDGIFS, Sites.RedGifs)
End With End With
.MyFieldsChecker = New FieldsChecker .MyFieldsChecker = New FieldsChecker
With .MyFieldsChecker With .MyFieldsChecker
.AddControl(Of String)(TXT_GLOBAL_PATH, TXT_GLOBAL_PATH.CaptionText) .AddControl(Of String)(TXT_GLOBAL_PATH, TXT_GLOBAL_PATH.CaptionText)
.AddControl(Of String)(TXT_COLLECTIONS_PATH, TXT_COLLECTIONS_PATH.CaptionText) .AddControl(Of String)(TXT_COLLECTIONS_PATH, TXT_COLLECTIONS_PATH.CaptionText)
.AddControl(Of String)(TXT_REDDIT_SAVED_POSTS_USER, TXT_REDDIT_SAVED_POSTS_USER.CaptionText, True, New SavedPostsChecker) .AddControl(Of String)(TXT_REDDIT_SAVED_POSTS_USER, TXT_REDDIT_SAVED_POSTS_USER.CaptionText, True, New SavedPostsChecker)
.AddControl(Of Integer)(TXT_REQ_WAIT_TIMER, TXT_REQ_WAIT_TIMER.CaptionText,, New InstaTimersChecker(100))
.AddControl(Of Integer)(TXT_REQ_COUNT, TXT_REQ_COUNT.CaptionText,, New InstaTimersChecker(1))
.AddControl(Of Integer)(TXT_LIMIT_TIMER, TXT_LIMIT_TIMER.CaptionText,, New InstaTimersChecker(10000))
.EndLoaderOperations() .EndLoaderOperations()
End With End With
.AppendDetectors() .AppendDetectors()
@@ -101,15 +127,30 @@ Namespace Editors
MyDefs.InvokeLoaderError(ex) MyDefs.InvokeLoaderError(ex)
End Try End Try
End Sub End Sub
Private Sub SetChecker(ByRef CH As CheckBox, ByVal Prop As XML.Base.XMLValue(Of Boolean)) Private Overloads Sub SetChecker(ByRef CH As SiteDefaults, ByVal s As Sites)
With Settings(s)
SetChecker(CH.MyTemporary, .Temporary)
SetChecker(CH.MyImagesDown, .DownloadImages)
SetChecker(CH.MyVideosDown, .DownloadVideos)
End With
End Sub
Private Overloads Sub SetChecker(ByRef State As CheckState, ByVal Prop As XML.Base.XMLValue(Of Boolean))
If Prop.ValueF.Exists Then If Prop.ValueF.Exists Then
CH.Checked = Prop.Value State = If(Prop.Value, CheckState.Checked, CheckState.Unchecked)
Else Else
CH.CheckState = CheckState.Indeterminate State = CheckState.Indeterminate
End If End If
End Sub End Sub
Private Sub SetPropByChecker(ByRef Prop As XML.Base.XMLValue(Of Boolean), ByRef CH As CheckBox) Private Overloads Sub SetPropByChecker(ByRef CH As SiteDefaults, ByVal s As Sites)
Select Case CH.CheckState With Settings(s)
SetPropByChecker(CH.MyTemporary, .Temporary)
SetPropByChecker(CH.MyTemporary, .Temporary)
SetPropByChecker(CH.MyImagesDown, .DownloadImages)
SetPropByChecker(CH.MyVideosDown, .DownloadVideos)
End With
End Sub
Private Overloads Sub SetPropByChecker(ByVal State As CheckState, ByRef Prop As XML.Base.XMLValue(Of Boolean))
Select Case State
Case CheckState.Checked : Prop.Value = True Case CheckState.Checked : Prop.Value = True
Case CheckState.Unchecked : Prop.Value = False Case CheckState.Unchecked : Prop.Value = False
Case CheckState.Indeterminate : Prop.ValueF = Nothing Case CheckState.Indeterminate : Prop.ValueF = Nothing
@@ -167,6 +208,10 @@ Namespace Editors
.FromChannelDownloadTopUse.Value = TXT_CHANNEL_USER_POST_LIMIT.Checked .FromChannelDownloadTopUse.Value = TXT_CHANNEL_USER_POST_LIMIT.Checked
.FromChannelCopyImageToUser.Value = CH_COPY_CHANNEL_USER_IMAGE.Checked .FromChannelCopyImageToUser.Value = CH_COPY_CHANNEL_USER_IMAGE.Checked
.ChannelsDefaultTemporary.Value = CH_CHANNELS_USERS_TEMP.Checked .ChannelsDefaultTemporary.Value = CH_CHANNELS_USERS_TEMP.Checked
'Other program settings
.ExitConfirm.Value = CH_EXIT_CONFIRM.Checked
.CloseToTray.Value = CH_CLOSE_TO_TRAY.Checked
.ShowNotifications.Value = CH_SHOW_NOTIFY.Checked
If CH_FILE_NAME_CHANGE.Checked Then If CH_FILE_NAME_CHANGE.Checked Then
.FileReplaceNameByDate.Value = OPT_FILE_NAME_REPLACE.Checked .FileReplaceNameByDate.Value = OPT_FILE_NAME_REPLACE.Checked
@@ -180,24 +225,24 @@ Namespace Editors
End If End If
'Reddit 'Reddit
With .Site(Sites.Reddit) With .Site(Sites.Reddit)
SetPropByChecker(.Temporary, CH_REDDIT_TEMP) SetPropByChecker(DEFS_REDDIT, Sites.Reddit)
SetPropByChecker(.DownloadImages, CH_REDDIT_DOWN_IMG)
SetPropByChecker(.DownloadVideos, CH_REDDIT_DOWN_VID)
.SavedPostsUserName.Value = TXT_REDDIT_SAVED_POSTS_USER.Text .SavedPostsUserName.Value = TXT_REDDIT_SAVED_POSTS_USER.Text
End With End With
'Twitter 'Twitter
With .Site(Sites.Twitter) With .Site(Sites.Twitter)
SetPropByChecker(.Temporary, CH_TWITTER_TEMP) SetPropByChecker(DEFS_TWITTER, Sites.Twitter)
SetPropByChecker(.DownloadImages, CH_TWITTER_DOWN_IMG)
SetPropByChecker(.DownloadVideos, CH_TWITTER_DOWN_VID)
.GetUserMediaOnly.Value = CH_TWITTER_USER_MEDIA.Checked .GetUserMediaOnly.Value = CH_TWITTER_USER_MEDIA.Checked
End With End With
'Instagram 'Instagram
With .Site(Sites.Instagram) With .Site(Sites.Instagram)
SetPropByChecker(.Temporary, CH_INSTA_TEMP) SetPropByChecker(DEFS_INST, Sites.Instagram)
SetPropByChecker(.DownloadImages, CH_INSTA_DOWN_IMG) .RequestsWaitTimer.Value = AConvert(Of Integer)(TXT_REQ_WAIT_TIMER.Text)
SetPropByChecker(.DownloadVideos, CH_INSTA_DOWN_VID) .RequestsWaitTimerTaskCount.Value = AConvert(Of Integer)(TXT_REQ_COUNT.Text)
.SleepTimerOnPostsLimit.Value = AConvert(Of Integer)(TXT_LIMIT_TIMER.Text)
.SavedPostsUserName.Value = TXT_INST_SAVED_POSTS_USER.Text
End With End With
'RedGifs
SetPropByChecker(DEFS_REDGIFS, Sites.RedGifs)
.EndUpdate() .EndUpdate()
End With End With

View File

@@ -13,10 +13,10 @@ Partial Friend Class LabelsForm : Inherits System.Windows.Forms.Form
Private components As System.ComponentModel.IContainer Private components As System.ComponentModel.IContainer
<System.Diagnostics.DebuggerStepThrough()> <System.Diagnostics.DebuggerStepThrough()>
Private Sub InitializeComponent() Private Sub InitializeComponent()
Dim ActionButton4 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Dim ActionButton1 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(LabelsForm)) Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(LabelsForm))
Dim ActionButton5 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Dim ActionButton2 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim ActionButton6 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Dim ActionButton3 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Me.CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer() Me.CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer()
Me.CMB_LABELS = New PersonalUtilities.Forms.Controls.ComboBoxExtended() Me.CMB_LABELS = New PersonalUtilities.Forms.Controls.ComboBoxExtended()
Me.CONTAINER_MAIN.ContentPanel.SuspendLayout() Me.CONTAINER_MAIN.ContentPanel.SuspendLayout()
@@ -42,21 +42,21 @@ Partial Friend Class LabelsForm : Inherits System.Windows.Forms.Form
' '
'CMB_LABELS 'CMB_LABELS
' '
ActionButton4.BackgroundImage = CType(resources.GetObject("ActionButton4.BackgroundImage"), System.Drawing.Image) ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image)
ActionButton4.Index = 0 ActionButton1.Index = 0
ActionButton4.Name = "BTT_COMBOBOX_ARROW" ActionButton1.Name = "BTT_COMBOBOX_ARROW"
ActionButton4.Visible = False ActionButton1.Visible = False
ActionButton5.BackgroundImage = CType(resources.GetObject("ActionButton5.BackgroundImage"), System.Drawing.Image) ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image)
ActionButton5.Index = 1 ActionButton2.Index = 1
ActionButton5.Name = "BTT_ADD" ActionButton2.Name = "BTT_ADD"
ActionButton5.ToolTipText = "Add new label (Insert)" ActionButton2.ToolTipText = "Add new label (Insert)"
ActionButton6.BackgroundImage = CType(resources.GetObject("ActionButton6.BackgroundImage"), System.Drawing.Image) ActionButton3.BackgroundImage = CType(resources.GetObject("ActionButton3.BackgroundImage"), System.Drawing.Image)
ActionButton6.Index = 2 ActionButton3.Index = 2
ActionButton6.Name = "BTT_CLEAR" ActionButton3.Name = "BTT_CLEAR"
ActionButton6.ToolTipText = "Clear checked labels" ActionButton3.ToolTipText = "Clear checked labels"
Me.CMB_LABELS.Buttons.Add(ActionButton4) Me.CMB_LABELS.Buttons.Add(ActionButton1)
Me.CMB_LABELS.Buttons.Add(ActionButton5) Me.CMB_LABELS.Buttons.Add(ActionButton2)
Me.CMB_LABELS.Buttons.Add(ActionButton6) Me.CMB_LABELS.Buttons.Add(ActionButton3)
Me.CMB_LABELS.Dock = System.Windows.Forms.DockStyle.Fill Me.CMB_LABELS.Dock = System.Windows.Forms.DockStyle.Fill
Me.CMB_LABELS.ListCheckBoxes = True Me.CMB_LABELS.ListCheckBoxes = True
Me.CMB_LABELS.ListDropDownStyle = PersonalUtilities.Forms.Controls.ComboBoxExtended.ListMode.Simple Me.CMB_LABELS.ListDropDownStyle = PersonalUtilities.Forms.Controls.ComboBoxExtended.ListMode.Simple

View File

@@ -118,7 +118,7 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="ActionButton4.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> <data name="ActionButton1.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value> <value>
iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABGdBTUEAALGPC/xhBQAAE65JREFUeF7t iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABGdBTUEAALGPC/xhBQAAE65JREFUeF7t
3X2sJWddB/DdLi2lQG2hdOHuvfM887J7Cxca4ELTQMDWKigIFpBAEAgi9g+CJpJo9Q8NJhgBiYZIYspL 3X2sJWddB/DdLi2lQG2hdOHuvfM887J7Cxca4ELTQMDWKigIFpBAEAgi9g+CJpJo9Q8NJhgBiYZIYspL
@@ -208,7 +208,7 @@
AAAASUVORK5CYII= AAAASUVORK5CYII=
</value> </value>
</data> </data>
<data name="ActionButton5.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> <data name="ActionButton2.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value> <value>
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6 iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6
JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsTAAALEwEAmpwYAAADmUlE JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsTAAALEwEAmpwYAAADmUlE
@@ -230,7 +230,7 @@
0AUyNxOP1DOwcaG/8I+/LRB+At7psBnyDBG0AAAAAElFTkSuQmCC 0AUyNxOP1DOwcaG/8I+/LRB+At7psBnyDBG0AAAAAElFTkSuQmCC
</value> </value>
</data> </data>
<data name="ActionButton6.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> <data name="ActionButton3.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value> <value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go

View File

@@ -27,21 +27,18 @@ Friend Class LabelsForm : Implements IOkCancelToolbar
Try Try
With MyDefs With MyDefs
.MyViewInitialize(Me, Settings.Design) .MyViewInitialize(Me, Settings.Design)
.MyOkCancel = New OkCancelToolbar(Me, Me, CONTAINER_MAIN.BottomToolStripPanel) .AddOkCancelToolbar()
.MyOkCancel.AddThisToolbar()
.DelegateClosingChecker() .DelegateClosingChecker()
If Settings.Labels.Count > 0 Then If Settings.Labels.Count > 0 Then
Dim items As New List(Of Integer) Dim items As New List(Of Integer)
CMB_LABELS.BeginUpdate() CMB_LABELS.BeginUpdate()
For i% = 0 To Settings.Labels.Count - 1 For i% = 0 To Settings.Labels.Count - 1
If LabelsList.Contains(Settings.Labels(i)) Then items.Add(i) If LabelsList.Contains(Settings.Labels(i)) Then items.Add(i)
CMB_LABELS.Items.Add(New ListItem(Settings.Labels(i))) CMB_LABELS.Items.Add(Settings.Labels(i))
Next Next
CMB_LABELS.EndUpdate() CMB_LABELS.EndUpdate()
CMB_LABELS.ListCheckedIndexes = items CMB_LABELS.ListCheckedIndexes = items
End If End If
.AppendDetectors() .AppendDetectors()
.EndLoaderOperations() .EndLoaderOperations()
End With End With
@@ -60,8 +57,8 @@ Friend Class LabelsForm : Implements IOkCancelToolbar
If MultiUser Then If MultiUser Then
Dim m As New MMessage("You are changing labels for more one user" & vbNewLine & "What do you want to do?", Dim m As New MMessage("You are changing labels for more one user" & vbNewLine & "What do you want to do?",
"MultiUser labels changing", "MultiUser labels changing",
{New MsgBoxButton("Replace exists") With {.ToolTip = "For each user: all exists labels will be deleted and replaced to these labels"}, {New MsgBoxButton("Replace exists") With {.ToolTip = "Per user: all existing labels will be removed and replaced with these labels"},
New MsgBoxButton("Add to exists") With {.ToolTip = "For each user: these labels will be appended to exists labels"}, New MsgBoxButton("Add to exists") With {.ToolTip = "Per user: these labels will be add to existing labels"},
New MsgBoxButton("Cancel")}, New MsgBoxButton("Cancel")},
MsgBoxStyle.Exclamation) MsgBoxStyle.Exclamation)
Select Case MsgBoxE(m).Index Select Case MsgBoxE(m).Index
@@ -70,11 +67,7 @@ Friend Class LabelsForm : Implements IOkCancelToolbar
Case 2 : Exit Sub Case 2 : Exit Sub
End Select End Select
End If End If
LabelsList.Clear() LabelsList.ListAddList(CMB_LABELS.Items.CheckedItems.Select(Function(l) CStr(l.Value(0))), LAP.ClearBeforeAdd, LAP.NotContainsOnly)
Dim s As List(Of Integer) = CMB_LABELS.ListCheckedIndexes.ListIfNothing
If s.Count > 0 Then
For Each i% In s : LabelsList.Add(Settings.Labels(i)) : Next
End If
If _AnyLabelAdd Then Settings.Labels.Update() If _AnyLabelAdd Then Settings.Labels.Update()
MyDefs.CloseForm() MyDefs.CloseForm()
Catch ex As Exception Catch ex As Exception
@@ -98,7 +91,7 @@ Friend Class LabelsForm : Implements IOkCancelToolbar
Else Else
Settings.Labels.Add(nl) Settings.Labels.Add(nl)
_AnyLabelAdd = True _AnyLabelAdd = True
CMB_LABELS.Items.Add(New ListItem(nl)) CMB_LABELS.Items.Add(nl)
End If End If
End If End If
End Sub End Sub

View File

@@ -0,0 +1,102 @@
' Copyright (C) 2022 Andy
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY
Imports System.ComponentModel
Namespace Editors
Public Class SiteDefaults : Inherits TableLayoutPanel
Private ReadOnly CH_TEMP As CheckBox
Private ReadOnly CH_IMG As CheckBox
Private ReadOnly CH_VID As CheckBox
Public Sub New()
InitCheckBox(CH_TEMP, "Temporary")
InitCheckBox(CH_IMG, "Download images")
InitCheckBox(CH_VID, "Download videos")
End Sub
Private Sub InitCheckBox(ByRef CH As CheckBox, ByVal Caption As String)
CH = New CheckBox With {.Text = Caption, .Dock = DockStyle.Fill, .UseVisualStyleBackColor = True,
.ThreeState = True, .CheckState = CheckState.Indeterminate}
AddHandler CH.CheckedChanged, AddressOf Checker_CheckedChanged
AddHandler CH.CheckStateChanged, AddressOf Checker_CheckedChanged
End Sub
Private Sub SiteDefaults_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed
CH_TEMP.Dispose()
CH_IMG.Dispose()
CH_VID.Dispose()
End Sub
Protected Overrides Sub InitLayout()
MyBase.InitLayout()
If ColumnStyles.Count = 2 Or RowStyles.Count = 2 Then
ColumnStyles.Clear()
RowStyles.Clear()
CellBorderStyle = TableLayoutPanelCellBorderStyle.Single
ColumnCount = 1
ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 100))
RowCount = 4
RowStyles.Add(New RowStyle(SizeType.Absolute, 25))
RowStyles.Add(New RowStyle(SizeType.Absolute, 25))
RowStyles.Add(New RowStyle(SizeType.Absolute, 25))
RowStyles.Add(New RowStyle(SizeType.Percent, 100))
End If
Controls.Add(CH_TEMP, 0, 0)
Controls.Add(CH_IMG, 0, 1)
Controls.Add(CH_VID, 0, 2)
End Sub
Private _BaseControlsPadding As New Padding(0)
<Browsable(True), EditorBrowsable(EditorBrowsableState.Always), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
Category("Values"), DisplayName("Controls padding"), Description("Base controls padding")>
Public Property BaseControlsPadding As Padding
Get
Return _BaseControlsPadding
End Get
Set(ByVal p As Padding)
_BaseControlsPadding = p
CH_TEMP.Padding = p
CH_IMG.Padding = p
CH_VID.Padding = p
End Set
End Property
Private Function ShouldSerializeBaseControlsPadding() As Boolean
Return Not _BaseControlsPadding.Equals(New Padding(0))
End Function
<Browsable(False), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)>
Public Property ChangesDetected As Boolean = False
Private Sub Checker_CheckedChanged(sender As Object, e As EventArgs)
ChangesDetected = True
End Sub
<Browsable(True), EditorBrowsable(EditorBrowsableState.Always), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
Category("Values"), DefaultValue(CheckState.Indeterminate), DisplayName("Temporary"), Description("Temporary profile")>
Public Property MyTemporary As CheckState
Get
Return CH_TEMP.CheckState
End Get
Set(ByVal s As CheckState)
CH_TEMP.CheckState = s
End Set
End Property
<Browsable(True), EditorBrowsable(EditorBrowsableState.Always), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
Category("Values"), DefaultValue(CheckState.Indeterminate), DisplayName("Images"), Description("Download images")>
Public Property MyImagesDown As CheckState
Get
Return CH_IMG.CheckState
End Get
Set(ByVal s As CheckState)
CH_IMG.CheckState = s
End Set
End Property
<Browsable(True), EditorBrowsable(EditorBrowsableState.Always), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
Category("Values"), DefaultValue(CheckState.Indeterminate), DisplayName("Videos"), Description("Download videos")>
Public Property MyVideosDown As CheckState
Get
Return CH_VID.CheckState
End Get
Set(ByVal s As CheckState)
CH_VID.CheckState = s
End Set
End Property
End Class
End Namespace

View File

@@ -44,24 +44,28 @@ Namespace Editors
TXT_AUTH.Text = .Headers(API.Base.SiteSettings.Header_Twitter_Authorization) TXT_AUTH.Text = .Headers(API.Base.SiteSettings.Header_Twitter_Authorization)
End If End If
End With End With
If MySite = Sites.Instagram Then TXT_TOKEN.Text = .InstaHash If MySite = Sites.Instagram Then
TXT_TOKEN.Text = .InstaHash
TXT_AUTH.Text = .InstaHash_SP
End If
End With End With
If Not MySite = Sites.Twitter Then If MySite = Sites.Twitter Or MySite = Sites.Instagram Then
Dim p As PaddingE = PaddingE.GetOf({TP_MAIN}) If MySite = Sites.Instagram Then
Dim s As New Size(Size.Width, Size.Height - p.Vertical - TXT_AUTH.NeededHeight)
TXT_AUTH.Visible = False
If Not MySite = Sites.Instagram Then
s.Height -= (p.Vertical + TXT_TOKEN.NeededHeight)
TXT_TOKEN.Visible = False
Else
TXT_TOKEN.CaptionText = "Hash" TXT_TOKEN.CaptionText = "Hash"
TXT_TOKEN.CaptionToolTipText = "Instagram session hash" TXT_TOKEN.CaptionToolTipText = "Instagram session hash"
TXT_TOKEN.Buttons.Clear() TXT_TOKEN.Buttons.Clear()
TXT_TOKEN.Buttons.AddRange({ActionButton.DefaultButtons.Refresh, ActionButton.DefaultButtons.Clear}) TXT_TOKEN.Buttons.AddRange({ActionButton.DefaultButtons.Refresh, ActionButton.DefaultButtons.Clear})
TXT_AUTH.CaptionText = "Hash 2"
TXT_AUTH.CaptionToolTipText = "Instagram session hash for saved posts"
End If End If
Else
TXT_AUTH.Visible = False
TXT_TOKEN.Visible = False
Dim p As PaddingE = PaddingE.GetOf({TP_MAIN})
Dim s As New Size(Size.Width, Size.Height - p.Vertical(2) - TXT_AUTH.NeededHeight - TXT_TOKEN.NeededHeight)
With TP_MAIN With TP_MAIN
If Not MySite = Sites.Instagram Then .RowStyles(2).Height = 0 .RowStyles(2).Height = 0
.RowStyles(3).Height = 0 .RowStyles(3).Height = 0
End With End With
MinimumSize = s MinimumSize = s
@@ -71,9 +75,9 @@ Namespace Editors
.MyFieldsChecker = New FieldsChecker .MyFieldsChecker = New FieldsChecker
With .MyFieldsChecker With .MyFieldsChecker
If MySite = Sites.Twitter Then If MySite = Sites.Twitter Or MySite = Sites.Instagram Then
.AddControl(Of String)(TXT_TOKEN, TXT_TOKEN.CaptionText) .AddControl(Of String)(TXT_TOKEN, TXT_TOKEN.CaptionText)
.AddControl(Of String)(TXT_AUTH, TXT_AUTH.CaptionText) .AddControl(Of String)(TXT_AUTH, TXT_AUTH.CaptionText, MySite = Sites.Instagram)
End If End If
.EndLoaderOperations() .EndLoaderOperations()
End With End With
@@ -86,6 +90,12 @@ Namespace Editors
End Sub End Sub
Private Sub ToolbarBttOK() Implements IOkCancelToolbar.ToolbarBttOK Private Sub ToolbarBttOK() Implements IOkCancelToolbar.ToolbarBttOK
If MyDefs.MyFieldsChecker.AllParamsOK Then If MyDefs.MyFieldsChecker.AllParamsOK Then
If MySite = Sites.Instagram Then
If Not TXT_TOKEN.IsEmptyString AndAlso Not TXT_AUTH.IsEmptyString AndAlso TXT_TOKEN.Text = TXT_AUTH.Text Then
MsgBoxE({"InstaHash for saved posts must be different from InstaHash!", "InstaHash are equal"}, vbCritical)
Exit Sub
End If
End If
With Settings(MySite) With Settings(MySite)
If TXT_PATH.IsEmptyString Then .Path = Nothing Else .Path = TXT_PATH.Text If TXT_PATH.IsEmptyString Then .Path = Nothing Else .Path = TXT_PATH.Text
Select Case MySite Select Case MySite
@@ -96,6 +106,7 @@ Namespace Editors
End With End With
Case Sites.Instagram Case Sites.Instagram
.InstaHash.Value = TXT_TOKEN.Text .InstaHash.Value = TXT_TOKEN.Text
.InstaHash_SP.Value = TXT_AUTH.Text
End Select End Select
.Update() .Update()
End With End With

View File

@@ -25,15 +25,11 @@ Namespace Editors
.DelegateClosingChecker() .DelegateClosingChecker()
.AddOkCancelToolbar() .AddOkCancelToolbar()
CMB_SITES.BeginUpdate() CMB_SITES.BeginUpdate()
CMB_SITES.Items.AddRange({New ListItem({Sites.Reddit.ToString, CInt(Sites.Reddit)}), Dim sl As List(Of Sites) = ListAddList(Of Sites)(Nothing, [Enum].GetValues(GetType(Sites))).ListWithRemove(Sites.Undefined)
New ListItem({Sites.Twitter.ToString, CInt(Sites.Twitter)}), CMB_SITES.Items.AddRange(sl.Select(Function(s) New ListItem({s.ToString, CInt(s)})))
New ListItem({Sites.Instagram.ToString, CInt(Sites.Instagram)})})
Dim l As New List(Of Integer) Dim l As New List(Of Integer)
If SelectedSites.Count > 0 Then If SelectedSites.Count > 0 Then sl.ForEach(Sub(s) If SelectedSites.Contains(s) Then l.Add(sl.IndexOf(s)))
If SelectedSites.Contains(Sites.Reddit) Then l.Add(0) sl.Clear()
If SelectedSites.Contains(Sites.Twitter) Then l.Add(1)
If SelectedSites.Contains(Sites.Instagram) Then l.Add(2)
End If
CMB_SITES.EndUpdate() CMB_SITES.EndUpdate()
If l.Count > 0 Then CMB_SITES.ListCheckedIndexes = l : l.Clear() If l.Count > 0 Then CMB_SITES.ListCheckedIndexes = l : l.Clear()
.EndLoaderOperations() .EndLoaderOperations()
@@ -45,17 +41,7 @@ Namespace Editors
End Sub End Sub
Public Sub ToolbarBttOK() Implements IOkCancelToolbar.ToolbarBttOK Public Sub ToolbarBttOK() Implements IOkCancelToolbar.ToolbarBttOK
Try Try
SelectedSites.Clear() SelectedSites.ListAddList(CMB_SITES.Items.CheckedItems.Select(Function(i) DirectCast(i.Value(1), Sites)), LAP.ClearBeforeAdd)
Dim l As List(Of Integer) = CMB_SITES.ListCheckedIndexes
If l.ListExists Then
For Each i% In l
Select Case i
Case 0 : SelectedSites.Add(Sites.Reddit)
Case 1 : SelectedSites.Add(Sites.Twitter)
Case 2 : SelectedSites.Add(Sites.Instagram)
End Select
Next
End If
MyDefs.CloseForm() MyDefs.CloseForm()
Catch ex As Exception Catch ex As Exception
ErrorsDescriber.Execute(EDP.LogMessageValue, ex) ErrorsDescriber.Execute(EDP.LogMessageValue, ex)

View File

@@ -16,7 +16,6 @@
Private Sub InitializeComponent() Private Sub InitializeComponent()
Me.components = New System.ComponentModel.Container() Me.components = New System.ComponentModel.Container()
Dim TP_MAIN As System.Windows.Forms.TableLayoutPanel Dim TP_MAIN As System.Windows.Forms.TableLayoutPanel
Dim TP_SITE As System.Windows.Forms.TableLayoutPanel
Dim TP_PARAMS As System.Windows.Forms.TableLayoutPanel Dim TP_PARAMS As System.Windows.Forms.TableLayoutPanel
Dim TP_OTHER As System.Windows.Forms.TableLayoutPanel Dim TP_OTHER As System.Windows.Forms.TableLayoutPanel
Dim ActionButton1 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Dim ActionButton1 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
@@ -28,10 +27,12 @@
Dim ActionButton5 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Dim ActionButton5 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim TT_MAIN As System.Windows.Forms.ToolTip Dim TT_MAIN As System.Windows.Forms.ToolTip
Me.TXT_USER = New PersonalUtilities.Forms.Controls.TextBoxExtended() Me.TXT_USER = New PersonalUtilities.Forms.Controls.TextBoxExtended()
Me.TP_SITE = New System.Windows.Forms.TableLayoutPanel()
Me.OPT_REDDIT = New System.Windows.Forms.RadioButton() Me.OPT_REDDIT = New System.Windows.Forms.RadioButton()
Me.OPT_TWITTER = New System.Windows.Forms.RadioButton() Me.OPT_TWITTER = New System.Windows.Forms.RadioButton()
Me.CH_IS_CHANNEL = New System.Windows.Forms.CheckBox() Me.CH_IS_CHANNEL = New System.Windows.Forms.CheckBox()
Me.OPT_INSTAGRAM = New System.Windows.Forms.RadioButton() Me.OPT_INSTAGRAM = New System.Windows.Forms.RadioButton()
Me.OPT_REDGIFS = New System.Windows.Forms.RadioButton()
Me.CH_TEMP = New System.Windows.Forms.CheckBox() Me.CH_TEMP = New System.Windows.Forms.CheckBox()
Me.CH_FAV = New System.Windows.Forms.CheckBox() Me.CH_FAV = New System.Windows.Forms.CheckBox()
Me.CH_PARSE_USER_MEDIA = New System.Windows.Forms.CheckBox() Me.CH_PARSE_USER_MEDIA = New System.Windows.Forms.CheckBox()
@@ -47,14 +48,13 @@
Me.TXT_SPEC_FOLDER = New PersonalUtilities.Forms.Controls.TextBoxExtended() Me.TXT_SPEC_FOLDER = New PersonalUtilities.Forms.Controls.TextBoxExtended()
Me.CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer() Me.CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer()
TP_MAIN = New System.Windows.Forms.TableLayoutPanel() TP_MAIN = New System.Windows.Forms.TableLayoutPanel()
TP_SITE = New System.Windows.Forms.TableLayoutPanel()
TP_PARAMS = New System.Windows.Forms.TableLayoutPanel() TP_PARAMS = New System.Windows.Forms.TableLayoutPanel()
TP_OTHER = New System.Windows.Forms.TableLayoutPanel() TP_OTHER = New System.Windows.Forms.TableLayoutPanel()
TP_DOWN_OPTIONS = New System.Windows.Forms.TableLayoutPanel() TP_DOWN_OPTIONS = New System.Windows.Forms.TableLayoutPanel()
TT_MAIN = New System.Windows.Forms.ToolTip(Me.components) TT_MAIN = New System.Windows.Forms.ToolTip(Me.components)
TP_MAIN.SuspendLayout() TP_MAIN.SuspendLayout()
CType(Me.TXT_USER, System.ComponentModel.ISupportInitialize).BeginInit() CType(Me.TXT_USER, System.ComponentModel.ISupportInitialize).BeginInit()
TP_SITE.SuspendLayout() Me.TP_SITE.SuspendLayout()
TP_PARAMS.SuspendLayout() TP_PARAMS.SuspendLayout()
TP_OTHER.SuspendLayout() TP_OTHER.SuspendLayout()
CType(Me.TXT_DESCR, System.ComponentModel.ISupportInitialize).BeginInit() CType(Me.TXT_DESCR, System.ComponentModel.ISupportInitialize).BeginInit()
@@ -73,7 +73,7 @@
TP_MAIN.ColumnCount = 1 TP_MAIN.ColumnCount = 1
TP_MAIN.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) TP_MAIN.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_MAIN.Controls.Add(Me.TXT_USER, 0, 0) TP_MAIN.Controls.Add(Me.TXT_USER, 0, 0)
TP_MAIN.Controls.Add(TP_SITE, 0, 3) TP_MAIN.Controls.Add(Me.TP_SITE, 0, 3)
TP_MAIN.Controls.Add(TP_PARAMS, 0, 4) TP_MAIN.Controls.Add(TP_PARAMS, 0, 4)
TP_MAIN.Controls.Add(TP_OTHER, 0, 6) TP_MAIN.Controls.Add(TP_OTHER, 0, 6)
TP_MAIN.Controls.Add(Me.TXT_DESCR, 0, 9) TP_MAIN.Controls.Add(Me.TXT_DESCR, 0, 9)
@@ -112,24 +112,26 @@
' '
'TP_SITE 'TP_SITE
' '
TP_SITE.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single] Me.TP_SITE.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single]
TP_SITE.ColumnCount = 4 Me.TP_SITE.ColumnCount = 5
TP_SITE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25.0!)) Me.TP_SITE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 20.0!))
TP_SITE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25.0!)) Me.TP_SITE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 20.0!))
TP_SITE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25.0!)) Me.TP_SITE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 20.0!))
TP_SITE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25.0!)) Me.TP_SITE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 20.0!))
TP_SITE.Controls.Add(Me.OPT_REDDIT, 0, 0) Me.TP_SITE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 20.0!))
TP_SITE.Controls.Add(Me.OPT_TWITTER, 2, 0) Me.TP_SITE.Controls.Add(Me.OPT_REDDIT, 0, 0)
TP_SITE.Controls.Add(Me.CH_IS_CHANNEL, 1, 0) Me.TP_SITE.Controls.Add(Me.OPT_TWITTER, 2, 0)
TP_SITE.Controls.Add(Me.OPT_INSTAGRAM, 3, 0) Me.TP_SITE.Controls.Add(Me.CH_IS_CHANNEL, 1, 0)
TP_SITE.Dock = System.Windows.Forms.DockStyle.Fill Me.TP_SITE.Controls.Add(Me.OPT_INSTAGRAM, 3, 0)
TP_SITE.Location = New System.Drawing.Point(1, 88) Me.TP_SITE.Controls.Add(Me.OPT_REDGIFS, 4, 0)
TP_SITE.Margin = New System.Windows.Forms.Padding(0) Me.TP_SITE.Dock = System.Windows.Forms.DockStyle.Fill
TP_SITE.Name = "TP_SITE" Me.TP_SITE.Location = New System.Drawing.Point(1, 88)
TP_SITE.RowCount = 1 Me.TP_SITE.Margin = New System.Windows.Forms.Padding(0)
TP_SITE.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) Me.TP_SITE.Name = "TP_SITE"
TP_SITE.Size = New System.Drawing.Size(452, 31) Me.TP_SITE.RowCount = 1
TP_SITE.TabIndex = 3 Me.TP_SITE.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
Me.TP_SITE.Size = New System.Drawing.Size(452, 31)
Me.TP_SITE.TabIndex = 3
' '
'OPT_REDDIT 'OPT_REDDIT
' '
@@ -137,7 +139,7 @@
Me.OPT_REDDIT.Dock = System.Windows.Forms.DockStyle.Fill Me.OPT_REDDIT.Dock = System.Windows.Forms.DockStyle.Fill
Me.OPT_REDDIT.Location = New System.Drawing.Point(4, 4) Me.OPT_REDDIT.Location = New System.Drawing.Point(4, 4)
Me.OPT_REDDIT.Name = "OPT_REDDIT" Me.OPT_REDDIT.Name = "OPT_REDDIT"
Me.OPT_REDDIT.Size = New System.Drawing.Size(105, 23) Me.OPT_REDDIT.Size = New System.Drawing.Size(83, 23)
Me.OPT_REDDIT.TabIndex = 0 Me.OPT_REDDIT.TabIndex = 0
Me.OPT_REDDIT.TabStop = True Me.OPT_REDDIT.TabStop = True
Me.OPT_REDDIT.Text = "Reddit" Me.OPT_REDDIT.Text = "Reddit"
@@ -147,9 +149,9 @@
' '
Me.OPT_TWITTER.AutoSize = True Me.OPT_TWITTER.AutoSize = True
Me.OPT_TWITTER.Dock = System.Windows.Forms.DockStyle.Fill Me.OPT_TWITTER.Dock = System.Windows.Forms.DockStyle.Fill
Me.OPT_TWITTER.Location = New System.Drawing.Point(228, 4) Me.OPT_TWITTER.Location = New System.Drawing.Point(184, 4)
Me.OPT_TWITTER.Name = "OPT_TWITTER" Me.OPT_TWITTER.Name = "OPT_TWITTER"
Me.OPT_TWITTER.Size = New System.Drawing.Size(105, 23) Me.OPT_TWITTER.Size = New System.Drawing.Size(83, 23)
Me.OPT_TWITTER.TabIndex = 1 Me.OPT_TWITTER.TabIndex = 1
Me.OPT_TWITTER.TabStop = True Me.OPT_TWITTER.TabStop = True
Me.OPT_TWITTER.Text = "Twitter" Me.OPT_TWITTER.Text = "Twitter"
@@ -159,9 +161,9 @@
' '
Me.CH_IS_CHANNEL.AutoSize = True Me.CH_IS_CHANNEL.AutoSize = True
Me.CH_IS_CHANNEL.Dock = System.Windows.Forms.DockStyle.Fill Me.CH_IS_CHANNEL.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_IS_CHANNEL.Location = New System.Drawing.Point(116, 4) Me.CH_IS_CHANNEL.Location = New System.Drawing.Point(94, 4)
Me.CH_IS_CHANNEL.Name = "CH_IS_CHANNEL" Me.CH_IS_CHANNEL.Name = "CH_IS_CHANNEL"
Me.CH_IS_CHANNEL.Size = New System.Drawing.Size(105, 23) Me.CH_IS_CHANNEL.Size = New System.Drawing.Size(83, 23)
Me.CH_IS_CHANNEL.TabIndex = 2 Me.CH_IS_CHANNEL.TabIndex = 2
Me.CH_IS_CHANNEL.Text = "Channel" Me.CH_IS_CHANNEL.Text = "Channel"
Me.CH_IS_CHANNEL.UseVisualStyleBackColor = True Me.CH_IS_CHANNEL.UseVisualStyleBackColor = True
@@ -170,14 +172,26 @@
' '
Me.OPT_INSTAGRAM.AutoSize = True Me.OPT_INSTAGRAM.AutoSize = True
Me.OPT_INSTAGRAM.Dock = System.Windows.Forms.DockStyle.Fill Me.OPT_INSTAGRAM.Dock = System.Windows.Forms.DockStyle.Fill
Me.OPT_INSTAGRAM.Location = New System.Drawing.Point(340, 4) Me.OPT_INSTAGRAM.Location = New System.Drawing.Point(274, 4)
Me.OPT_INSTAGRAM.Name = "OPT_INSTAGRAM" Me.OPT_INSTAGRAM.Name = "OPT_INSTAGRAM"
Me.OPT_INSTAGRAM.Size = New System.Drawing.Size(108, 23) Me.OPT_INSTAGRAM.Size = New System.Drawing.Size(83, 23)
Me.OPT_INSTAGRAM.TabIndex = 3 Me.OPT_INSTAGRAM.TabIndex = 3
Me.OPT_INSTAGRAM.TabStop = True Me.OPT_INSTAGRAM.TabStop = True
Me.OPT_INSTAGRAM.Text = "Instagram" Me.OPT_INSTAGRAM.Text = "Instagram"
Me.OPT_INSTAGRAM.UseVisualStyleBackColor = True Me.OPT_INSTAGRAM.UseVisualStyleBackColor = True
' '
'OPT_REDGIFS
'
Me.OPT_REDGIFS.AutoSize = True
Me.OPT_REDGIFS.Dock = System.Windows.Forms.DockStyle.Fill
Me.OPT_REDGIFS.Location = New System.Drawing.Point(364, 4)
Me.OPT_REDGIFS.Name = "OPT_REDGIFS"
Me.OPT_REDGIFS.Size = New System.Drawing.Size(84, 23)
Me.OPT_REDGIFS.TabIndex = 4
Me.OPT_REDGIFS.TabStop = True
Me.OPT_REDGIFS.Text = "RedGifs"
Me.OPT_REDGIFS.UseVisualStyleBackColor = True
'
'TP_PARAMS 'TP_PARAMS
' '
TP_PARAMS.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single] TP_PARAMS.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single]
@@ -442,8 +456,8 @@
Me.Text = "Create User" Me.Text = "Create User"
TP_MAIN.ResumeLayout(False) TP_MAIN.ResumeLayout(False)
CType(Me.TXT_USER, System.ComponentModel.ISupportInitialize).EndInit() CType(Me.TXT_USER, System.ComponentModel.ISupportInitialize).EndInit()
TP_SITE.ResumeLayout(False) Me.TP_SITE.ResumeLayout(False)
TP_SITE.PerformLayout() Me.TP_SITE.PerformLayout()
TP_PARAMS.ResumeLayout(False) TP_PARAMS.ResumeLayout(False)
TP_PARAMS.PerformLayout() TP_PARAMS.PerformLayout()
TP_OTHER.ResumeLayout(False) TP_OTHER.ResumeLayout(False)
@@ -482,5 +496,7 @@
Private WithEvents CH_IS_CHANNEL As CheckBox Private WithEvents CH_IS_CHANNEL As CheckBox
Private WithEvents OPT_INSTAGRAM As RadioButton Private WithEvents OPT_INSTAGRAM As RadioButton
Private WithEvents TXT_SPEC_FOLDER As PersonalUtilities.Forms.Controls.TextBoxExtended Private WithEvents TXT_SPEC_FOLDER As PersonalUtilities.Forms.Controls.TextBoxExtended
Private WithEvents OPT_REDGIFS As RadioButton
Private WithEvents TP_SITE As TableLayoutPanel
End Class End Class
End Namespace End Namespace

View File

@@ -120,9 +120,6 @@
<metadata name="TP_MAIN.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <metadata name="TP_MAIN.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value> <value>False</value>
</metadata> </metadata>
<metadata name="TP_SITE.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="TP_PARAMS.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <metadata name="TP_PARAMS.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value> <value>False</value>
</metadata> </metadata>

View File

@@ -8,7 +8,6 @@
' but WITHOUT ANY WARRANTY ' but WITHOUT ANY WARRANTY
Imports System.ComponentModel Imports System.ComponentModel
Imports PersonalUtilities.Forms Imports PersonalUtilities.Forms
Imports PersonalUtilities.Forms.Controls
Imports PersonalUtilities.Forms.Controls.Base Imports PersonalUtilities.Forms.Controls.Base
Imports PersonalUtilities.Forms.Toolbars Imports PersonalUtilities.Forms.Toolbars
Imports SCrawler.API.Base Imports SCrawler.API.Base
@@ -119,13 +118,11 @@ Namespace Editors
Case Sites.Reddit : OPT_REDDIT.Checked = True : CH_PARSE_USER_MEDIA.Enabled = False Case Sites.Reddit : OPT_REDDIT.Checked = True : CH_PARSE_USER_MEDIA.Enabled = False
Case Sites.Twitter : OPT_TWITTER.Checked = True Case Sites.Twitter : OPT_TWITTER.Checked = True
Case Sites.Instagram : OPT_INSTAGRAM.Checked = True Case Sites.Instagram : OPT_INSTAGRAM.Checked = True
Case Sites.RedGifs : OPT_REDGIFS.Checked = True
End Select End Select
SetParamsBySite() SetParamsBySite()
OPT_REDDIT.Enabled = False TP_SITE.Enabled = False
OPT_TWITTER.Enabled = False
OPT_INSTAGRAM.Enabled = False
CH_IS_CHANNEL.Checked = User.IsChannel CH_IS_CHANNEL.Checked = User.IsChannel
CH_IS_CHANNEL.Enabled = False
If Not UserInstance Is Nothing Then If Not UserInstance Is Nothing Then
TXT_USER.Enabled = False TXT_USER.Enabled = False
TXT_SPEC_FOLDER.TextBoxReadOnly = True TXT_SPEC_FOLDER.TextBoxReadOnly = True
@@ -179,6 +176,7 @@ Namespace Editors
Case OPT_REDDIT.Checked : Return Sites.Reddit Case OPT_REDDIT.Checked : Return Sites.Reddit
Case OPT_TWITTER.Checked : Return Sites.Twitter Case OPT_TWITTER.Checked : Return Sites.Twitter
Case OPT_INSTAGRAM.Checked : Return Sites.Instagram Case OPT_INSTAGRAM.Checked : Return Sites.Instagram
Case OPT_REDGIFS.Checked : Return Sites.RedGifs
Case Else : Return Sites.Undefined Case Else : Return Sites.Undefined
End Select End Select
End Function End Function
@@ -239,6 +237,7 @@ CloseForm:
Private ReadOnly RedditChannelRegEx1 As New RegexStructure("[htps:/]{7,8}.*?reddit.com/r/([^/]+)", 1) Private ReadOnly RedditChannelRegEx1 As New RegexStructure("[htps:/]{7,8}.*?reddit.com/r/([^/]+)", 1)
Private ReadOnly RedditChannelRegEx2 As New RegexStructure(".?r/([^/]+)", 1) Private ReadOnly RedditChannelRegEx2 As New RegexStructure(".?r/([^/]+)", 1)
Private ReadOnly InstagramRegEx As New RegexStructure("[htps:/]{7,8}.*?instagram.com/([^/]+)", 1) Private ReadOnly InstagramRegEx As New RegexStructure("[htps:/]{7,8}.*?instagram.com/([^/]+)", 1)
Private ReadOnly RedGifsRegEx As New RegexStructure("[htps:/]{7,8}.*?redgifs.com/users/([^/]+)", 1)
Private _TextChangeInvoked As Boolean = False Private _TextChangeInvoked As Boolean = False
Private Sub TXT_USER_ActionOnTextChange() Handles TXT_USER.ActionOnTextChange Private Sub TXT_USER_ActionOnTextChange() Handles TXT_USER.ActionOnTextChange
Try Try
@@ -250,6 +249,7 @@ CloseForm:
Case Sites.Twitter : OPT_TWITTER.Checked = True Case Sites.Twitter : OPT_TWITTER.Checked = True
Case Sites.Reddit : OPT_REDDIT.Checked = True Case Sites.Reddit : OPT_REDDIT.Checked = True
Case Sites.Instagram : OPT_INSTAGRAM.Checked = True Case Sites.Instagram : OPT_INSTAGRAM.Checked = True
Case Sites.RedGifs : OPT_REDGIFS.Checked = True
Case Else : OPT_TWITTER.Checked = False : OPT_REDDIT.Checked = False : OPT_INSTAGRAM.Checked = False Case Else : OPT_TWITTER.Checked = False : OPT_REDDIT.Checked = False : OPT_INSTAGRAM.Checked = False
End Select End Select
CH_IS_CHANNEL.Checked = CBool(s(1)) CH_IS_CHANNEL.Checked = CBool(s(1))
@@ -269,6 +269,8 @@ CloseForm:
Return {Sites.Reddit, True} Return {Sites.Reddit, True}
ElseIf CheckRegex(TXT, InstagramRegEx) Then ElseIf CheckRegex(TXT, InstagramRegEx) Then
Return {Sites.Instagram, False} Return {Sites.Instagram, False}
ElseIf CheckRegex(TXT, RedGifsRegEx) Then
Return {Sites.RedGifs, False}
End If End If
End If End If
Return {Sites.Undefined, False} Return {Sites.Undefined, False}
@@ -286,6 +288,9 @@ CloseForm:
Private Sub OPT_INSTAGRAM_CheckedChanged(sender As Object, e As EventArgs) Handles OPT_INSTAGRAM.CheckedChanged Private Sub OPT_INSTAGRAM_CheckedChanged(sender As Object, e As EventArgs) Handles OPT_INSTAGRAM.CheckedChanged
If OPT_INSTAGRAM.Checked Then CH_IS_CHANNEL.Checked = False : CH_IS_CHANNEL.Enabled = False : SetParamsBySite() If OPT_INSTAGRAM.Checked Then CH_IS_CHANNEL.Checked = False : CH_IS_CHANNEL.Enabled = False : SetParamsBySite()
End Sub End Sub
Private Sub OPT_REDGIFS_CheckedChanged(sender As Object, e As EventArgs) Handles OPT_REDGIFS.CheckedChanged
If OPT_REDGIFS.Checked Then CH_IS_CHANNEL.Checked = False : CH_IS_CHANNEL.Enabled = False : SetParamsBySite()
End Sub
Private Sub TXT_SPEC_FOLDER_ActionOnButtonClick(ByVal Sender As ActionButton) Handles TXT_SPEC_FOLDER.ActionOnButtonClick Private Sub TXT_SPEC_FOLDER_ActionOnButtonClick(ByVal Sender As ActionButton) Handles TXT_SPEC_FOLDER.ActionOnButtonClick
If Sender.DefaultButton = ActionButton.DefaultButtons.Open Then If Sender.DefaultButton = ActionButton.DefaultButtons.Open Then
Dim f As SFile = Nothing Dim f As SFile = Nothing

View File

@@ -1,8 +1,5 @@
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> <Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()>
Partial Class MainFrame Partial Public Class MainFrame : Inherits System.Windows.Forms.Form
Inherits System.Windows.Forms.Form
'Form overrides dispose to clean up the component list.
<System.Diagnostics.DebuggerNonUserCode()> <System.Diagnostics.DebuggerNonUserCode()>
Protected Overrides Sub Dispose(ByVal disposing As Boolean) Protected Overrides Sub Dispose(ByVal disposing As Boolean)
Try Try
@@ -13,13 +10,7 @@ Partial Class MainFrame
MyBase.Dispose(disposing) MyBase.Dispose(disposing)
End Try End Try
End Sub End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> <System.Diagnostics.DebuggerStepThrough()>
Private Sub InitializeComponent() Private Sub InitializeComponent()
Me.components = New System.ComponentModel.Container() Me.components = New System.ComponentModel.Container()
@@ -37,10 +28,12 @@ Partial Class MainFrame
Dim MENU_VIEW_SEP_1 As System.Windows.Forms.ToolStripSeparator Dim MENU_VIEW_SEP_1 As System.Windows.Forms.ToolStripSeparator
Dim MENU_VIEW_SEP_3 As System.Windows.Forms.ToolStripSeparator Dim MENU_VIEW_SEP_3 As System.Windows.Forms.ToolStripSeparator
Dim MENU_VIEW_SEP_2 As System.Windows.Forms.ToolStripSeparator Dim MENU_VIEW_SEP_2 As System.Windows.Forms.ToolStripSeparator
Dim TRAY_SEP_1 As System.Windows.Forms.ToolStripSeparator
Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(MainFrame)) Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(MainFrame))
Me.BTT_SETTINGS_REDDIT = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_SETTINGS_REDDIT = New System.Windows.Forms.ToolStripMenuItem()
Me.BTT_SETTINGS_TWITTER = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_SETTINGS_TWITTER = New System.Windows.Forms.ToolStripMenuItem()
Me.BTT_SETTINGS_INSTAGRAM = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_SETTINGS_INSTAGRAM = New System.Windows.Forms.ToolStripMenuItem()
Me.BTT_SETTINGS_REDGIFS = New System.Windows.Forms.ToolStripMenuItem()
Me.BTT_SETTINGS = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_SETTINGS = New System.Windows.Forms.ToolStripMenuItem()
Me.Toolbar_TOP = New System.Windows.Forms.ToolStrip() Me.Toolbar_TOP = New System.Windows.Forms.ToolStrip()
Me.BTT_ADD_USER = New System.Windows.Forms.ToolStripButton() Me.BTT_ADD_USER = New System.Windows.Forms.ToolStripButton()
@@ -69,11 +62,14 @@ Partial Class MainFrame
Me.BTT_SELECT_LABELS = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_SELECT_LABELS = New System.Windows.Forms.ToolStripMenuItem()
Me.BTT_LOG = New System.Windows.Forms.ToolStripButton() Me.BTT_LOG = New System.Windows.Forms.ToolStripButton()
Me.BTT_VERSION_INFO = New System.Windows.Forms.ToolStripButton() Me.BTT_VERSION_INFO = New System.Windows.Forms.ToolStripButton()
Me.BTT_DONATE = New System.Windows.Forms.ToolStripButton()
Me.Toolbar_BOTTOM = New System.Windows.Forms.StatusStrip() Me.Toolbar_BOTTOM = New System.Windows.Forms.StatusStrip()
Me.PR_SAVED = New System.Windows.Forms.ToolStripProgressBar()
Me.PR_MAIN = New System.Windows.Forms.ToolStripProgressBar() Me.PR_MAIN = New System.Windows.Forms.ToolStripProgressBar()
Me.LBL_JOBS_COUNT = New System.Windows.Forms.ToolStripStatusLabel() Me.LBL_JOBS_COUNT = New System.Windows.Forms.ToolStripStatusLabel()
Me.LBL_STATUS = New System.Windows.Forms.ToolStripStatusLabel() Me.LBL_STATUS = New System.Windows.Forms.ToolStripStatusLabel()
Me.PR_INST = New System.Windows.Forms.ToolStripProgressBar()
Me.LBL_JOBS_INST_COUNT = New System.Windows.Forms.ToolStripStatusLabel()
Me.LBL_STATUS_INST = New System.Windows.Forms.ToolStripStatusLabel()
Me.LIST_PROFILES = New System.Windows.Forms.ListView() Me.LIST_PROFILES = New System.Windows.Forms.ListView()
Me.USER_CONTEXT = New System.Windows.Forms.ContextMenuStrip(Me.components) Me.USER_CONTEXT = New System.Windows.Forms.ContextMenuStrip(Me.components)
Me.BTT_CONTEXT_DOWN = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_CONTEXT_DOWN = New System.Windows.Forms.ToolStripMenuItem()
@@ -91,6 +87,10 @@ Partial Class MainFrame
Me.BTT_CONTEXT_OPEN_PATH = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_CONTEXT_OPEN_PATH = New System.Windows.Forms.ToolStripMenuItem()
Me.BTT_CONTEXT_OPEN_SITE = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_CONTEXT_OPEN_SITE = New System.Windows.Forms.ToolStripMenuItem()
Me.BTT_CONTEXT_INFO = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_CONTEXT_INFO = New System.Windows.Forms.ToolStripMenuItem()
Me.TrayIcon = New System.Windows.Forms.NotifyIcon(Me.components)
Me.TRAY_CONTEXT = New System.Windows.Forms.ContextMenuStrip(Me.components)
Me.BTT_TRAY_SHOW_HIDE = New System.Windows.Forms.ToolStripMenuItem()
Me.BTT_TRAY_CLOSE = New System.Windows.Forms.ToolStripMenuItem()
SEP_1 = New System.Windows.Forms.ToolStripSeparator() SEP_1 = New System.Windows.Forms.ToolStripSeparator()
SEP_2 = New System.Windows.Forms.ToolStripSeparator() SEP_2 = New System.Windows.Forms.ToolStripSeparator()
CONTEXT_SEP_1 = New System.Windows.Forms.ToolStripSeparator() CONTEXT_SEP_1 = New System.Windows.Forms.ToolStripSeparator()
@@ -105,9 +105,11 @@ Partial Class MainFrame
MENU_VIEW_SEP_1 = New System.Windows.Forms.ToolStripSeparator() MENU_VIEW_SEP_1 = New System.Windows.Forms.ToolStripSeparator()
MENU_VIEW_SEP_3 = New System.Windows.Forms.ToolStripSeparator() MENU_VIEW_SEP_3 = New System.Windows.Forms.ToolStripSeparator()
MENU_VIEW_SEP_2 = New System.Windows.Forms.ToolStripSeparator() MENU_VIEW_SEP_2 = New System.Windows.Forms.ToolStripSeparator()
TRAY_SEP_1 = New System.Windows.Forms.ToolStripSeparator()
Me.Toolbar_TOP.SuspendLayout() Me.Toolbar_TOP.SuspendLayout()
Me.Toolbar_BOTTOM.SuspendLayout() Me.Toolbar_BOTTOM.SuspendLayout()
Me.USER_CONTEXT.SuspendLayout() Me.USER_CONTEXT.SuspendLayout()
Me.TRAY_CONTEXT.SuspendLayout()
Me.SuspendLayout() Me.SuspendLayout()
' '
'SEP_1 'SEP_1
@@ -128,7 +130,7 @@ Partial Class MainFrame
'MENU_SETTINGS 'MENU_SETTINGS
' '
MENU_SETTINGS.AutoToolTip = False MENU_SETTINGS.AutoToolTip = False
MENU_SETTINGS.DropDownItems.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_SETTINGS_REDDIT, Me.BTT_SETTINGS_TWITTER, Me.BTT_SETTINGS_INSTAGRAM, MENU_SETTINGS_SEP_1, Me.BTT_SETTINGS}) MENU_SETTINGS.DropDownItems.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_SETTINGS_REDDIT, Me.BTT_SETTINGS_TWITTER, Me.BTT_SETTINGS_INSTAGRAM, Me.BTT_SETTINGS_REDGIFS, MENU_SETTINGS_SEP_1, Me.BTT_SETTINGS})
MENU_SETTINGS.ImageTransparentColor = System.Drawing.Color.Magenta MENU_SETTINGS.ImageTransparentColor = System.Drawing.Color.Magenta
MENU_SETTINGS.Name = "MENU_SETTINGS" MENU_SETTINGS.Name = "MENU_SETTINGS"
MENU_SETTINGS.Size = New System.Drawing.Size(62, 22) MENU_SETTINGS.Size = New System.Drawing.Size(62, 22)
@@ -155,6 +157,12 @@ Partial Class MainFrame
Me.BTT_SETTINGS_INSTAGRAM.Size = New System.Drawing.Size(127, 22) Me.BTT_SETTINGS_INSTAGRAM.Size = New System.Drawing.Size(127, 22)
Me.BTT_SETTINGS_INSTAGRAM.Text = "Instagram" Me.BTT_SETTINGS_INSTAGRAM.Text = "Instagram"
' '
'BTT_SETTINGS_REDGIFS
'
Me.BTT_SETTINGS_REDGIFS.Name = "BTT_SETTINGS_REDGIFS"
Me.BTT_SETTINGS_REDGIFS.Size = New System.Drawing.Size(127, 22)
Me.BTT_SETTINGS_REDGIFS.Text = "RedGifs"
'
'MENU_SETTINGS_SEP_1 'MENU_SETTINGS_SEP_1
' '
MENU_SETTINGS_SEP_1.Name = "MENU_SETTINGS_SEP_1" MENU_SETTINGS_SEP_1.Name = "MENU_SETTINGS_SEP_1"
@@ -212,10 +220,15 @@ Partial Class MainFrame
MENU_VIEW_SEP_2.Name = "MENU_VIEW_SEP_2" MENU_VIEW_SEP_2.Name = "MENU_VIEW_SEP_2"
MENU_VIEW_SEP_2.Size = New System.Drawing.Size(141, 6) MENU_VIEW_SEP_2.Size = New System.Drawing.Size(141, 6)
' '
'TRAY_SEP_1
'
TRAY_SEP_1.Name = "TRAY_SEP_1"
TRAY_SEP_1.Size = New System.Drawing.Size(130, 6)
'
'Toolbar_TOP 'Toolbar_TOP
' '
Me.Toolbar_TOP.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden Me.Toolbar_TOP.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden
Me.Toolbar_TOP.Items.AddRange(New System.Windows.Forms.ToolStripItem() {MENU_SETTINGS, SEP_1, Me.BTT_ADD_USER, Me.BTT_EDIT_USER, Me.BTT_DELETE_USER, Me.BTT_REFRESH, Me.BTT_SHOW_INFO, Me.BTT_CHANNELS, Me.BTT_DOWN_SAVED, SEP_2, Me.BTT_DOWN_SELECTED, Me.BTT_DOWN_ALL, Me.BTT_DOWN_VIDEO, Me.BTT_DOWN_STOP, SEP_3, Me.MENU_VIEW, SEP_4, Me.BTT_LOG, Me.BTT_VERSION_INFO}) Me.Toolbar_TOP.Items.AddRange(New System.Windows.Forms.ToolStripItem() {MENU_SETTINGS, SEP_1, Me.BTT_ADD_USER, Me.BTT_EDIT_USER, Me.BTT_DELETE_USER, Me.BTT_REFRESH, Me.BTT_SHOW_INFO, Me.BTT_CHANNELS, Me.BTT_DOWN_SAVED, SEP_2, Me.BTT_DOWN_SELECTED, Me.BTT_DOWN_ALL, Me.BTT_DOWN_VIDEO, Me.BTT_DOWN_STOP, SEP_3, Me.MENU_VIEW, SEP_4, Me.BTT_LOG, Me.BTT_VERSION_INFO, Me.BTT_DONATE})
Me.Toolbar_TOP.Location = New System.Drawing.Point(0, 0) Me.Toolbar_TOP.Location = New System.Drawing.Point(0, 0)
Me.Toolbar_TOP.Name = "Toolbar_TOP" Me.Toolbar_TOP.Name = "Toolbar_TOP"
Me.Toolbar_TOP.Size = New System.Drawing.Size(934, 25) Me.Toolbar_TOP.Size = New System.Drawing.Size(934, 25)
@@ -426,20 +439,25 @@ Partial Class MainFrame
Me.BTT_VERSION_INFO.Text = "Info" Me.BTT_VERSION_INFO.Text = "Info"
Me.BTT_VERSION_INFO.ToolTipText = "Show program information and check for new version" Me.BTT_VERSION_INFO.ToolTipText = "Show program information and check for new version"
' '
'BTT_DONATE
'
Me.BTT_DONATE.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right
Me.BTT_DONATE.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image
Me.BTT_DONATE.Image = Global.SCrawler.My.Resources.Resources.HeartPic_32
Me.BTT_DONATE.ImageTransparentColor = System.Drawing.Color.Magenta
Me.BTT_DONATE.Name = "BTT_DONATE"
Me.BTT_DONATE.Size = New System.Drawing.Size(23, 20)
Me.BTT_DONATE.Text = "Donate"
Me.BTT_DONATE.ToolTipText = "Donate"
'
'Toolbar_BOTTOM 'Toolbar_BOTTOM
' '
Me.Toolbar_BOTTOM.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.PR_SAVED, Me.PR_MAIN, Me.LBL_JOBS_COUNT, Me.LBL_STATUS}) Me.Toolbar_BOTTOM.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.PR_MAIN, Me.LBL_JOBS_COUNT, Me.LBL_STATUS, Me.PR_INST, Me.LBL_JOBS_INST_COUNT, Me.LBL_STATUS_INST})
Me.Toolbar_BOTTOM.Location = New System.Drawing.Point(0, 439) Me.Toolbar_BOTTOM.Location = New System.Drawing.Point(0, 439)
Me.Toolbar_BOTTOM.Name = "Toolbar_BOTTOM" Me.Toolbar_BOTTOM.Name = "Toolbar_BOTTOM"
Me.Toolbar_BOTTOM.Size = New System.Drawing.Size(934, 22) Me.Toolbar_BOTTOM.Size = New System.Drawing.Size(934, 22)
Me.Toolbar_BOTTOM.TabIndex = 2 Me.Toolbar_BOTTOM.TabIndex = 2
' '
'PR_SAVED
'
Me.PR_SAVED.Name = "PR_SAVED"
Me.PR_SAVED.Size = New System.Drawing.Size(100, 16)
Me.PR_SAVED.Visible = False
'
'PR_MAIN 'PR_MAIN
' '
Me.PR_MAIN.Name = "PR_MAIN" Me.PR_MAIN.Name = "PR_MAIN"
@@ -456,6 +474,22 @@ Partial Class MainFrame
Me.LBL_STATUS.Name = "LBL_STATUS" Me.LBL_STATUS.Name = "LBL_STATUS"
Me.LBL_STATUS.Size = New System.Drawing.Size(0, 17) Me.LBL_STATUS.Size = New System.Drawing.Size(0, 17)
' '
'PR_INST
'
Me.PR_INST.Name = "PR_INST"
Me.PR_INST.Size = New System.Drawing.Size(200, 16)
Me.PR_INST.Visible = False
'
'LBL_JOBS_INST_COUNT
'
Me.LBL_JOBS_INST_COUNT.Name = "LBL_JOBS_INST_COUNT"
Me.LBL_JOBS_INST_COUNT.Size = New System.Drawing.Size(0, 17)
'
'LBL_STATUS_INST
'
Me.LBL_STATUS_INST.Name = "LBL_STATUS_INST"
Me.LBL_STATUS_INST.Size = New System.Drawing.Size(0, 17)
'
'LIST_PROFILES 'LIST_PROFILES
' '
Me.LIST_PROFILES.Activation = System.Windows.Forms.ItemActivation.OneClick Me.LIST_PROFILES.Activation = System.Windows.Forms.ItemActivation.OneClick
@@ -580,6 +614,35 @@ Partial Class MainFrame
Me.BTT_CONTEXT_INFO.Size = New System.Drawing.Size(221, 22) Me.BTT_CONTEXT_INFO.Size = New System.Drawing.Size(221, 22)
Me.BTT_CONTEXT_INFO.Text = "Information" Me.BTT_CONTEXT_INFO.Text = "Information"
' '
'TrayIcon
'
Me.TrayIcon.BalloonTipIcon = System.Windows.Forms.ToolTipIcon.Info
Me.TrayIcon.BalloonTipTitle = "Social networks crawler"
Me.TrayIcon.ContextMenuStrip = Me.TRAY_CONTEXT
Me.TrayIcon.Icon = CType(resources.GetObject("TrayIcon.Icon"), System.Drawing.Icon)
Me.TrayIcon.Text = "Social networks crawler"
'
'TRAY_CONTEXT
'
Me.TRAY_CONTEXT.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_TRAY_SHOW_HIDE, TRAY_SEP_1, Me.BTT_TRAY_CLOSE})
Me.TRAY_CONTEXT.Name = "TRAY_CONTEXT"
Me.TRAY_CONTEXT.Size = New System.Drawing.Size(134, 54)
'
'BTT_TRAY_SHOW_HIDE
'
Me.BTT_TRAY_SHOW_HIDE.Name = "BTT_TRAY_SHOW_HIDE"
Me.BTT_TRAY_SHOW_HIDE.Size = New System.Drawing.Size(133, 22)
Me.BTT_TRAY_SHOW_HIDE.Text = "Show/Hide"
'
'BTT_TRAY_CLOSE
'
Me.BTT_TRAY_CLOSE.BackColor = System.Drawing.Color.FromArgb(CType(CType(255, Byte), Integer), CType(CType(192, Byte), Integer), CType(CType(192, Byte), Integer))
Me.BTT_TRAY_CLOSE.ForeColor = System.Drawing.Color.Maroon
Me.BTT_TRAY_CLOSE.Image = CType(resources.GetObject("BTT_TRAY_CLOSE.Image"), System.Drawing.Image)
Me.BTT_TRAY_CLOSE.Name = "BTT_TRAY_CLOSE"
Me.BTT_TRAY_CLOSE.Size = New System.Drawing.Size(133, 22)
Me.BTT_TRAY_CLOSE.Text = "Close"
'
'MainFrame 'MainFrame
' '
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!) Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
@@ -598,6 +661,7 @@ Partial Class MainFrame
Me.Toolbar_BOTTOM.ResumeLayout(False) Me.Toolbar_BOTTOM.ResumeLayout(False)
Me.Toolbar_BOTTOM.PerformLayout() Me.Toolbar_BOTTOM.PerformLayout()
Me.USER_CONTEXT.ResumeLayout(False) Me.USER_CONTEXT.ResumeLayout(False)
Me.TRAY_CONTEXT.ResumeLayout(False)
Me.ResumeLayout(False) Me.ResumeLayout(False)
Me.PerformLayout() Me.PerformLayout()
@@ -654,6 +718,14 @@ Partial Class MainFrame
Private WithEvents BTT_SITE_ALL As ToolStripMenuItem Private WithEvents BTT_SITE_ALL As ToolStripMenuItem
Private WithEvents BTT_SITE_SPECIFIC As ToolStripMenuItem Private WithEvents BTT_SITE_SPECIFIC As ToolStripMenuItem
Private WithEvents BTT_CONTEXT_CHANGE_FOLDER As ToolStripMenuItem Private WithEvents BTT_CONTEXT_CHANGE_FOLDER As ToolStripMenuItem
Private WithEvents PR_SAVED As ToolStripProgressBar
Private WithEvents BTT_DOWN_SAVED As ToolStripButton Private WithEvents BTT_DOWN_SAVED As ToolStripButton
End Class Private WithEvents PR_INST As ToolStripProgressBar
Private WithEvents LBL_JOBS_INST_COUNT As ToolStripStatusLabel
Private WithEvents LBL_STATUS_INST As ToolStripStatusLabel
Private WithEvents TrayIcon As NotifyIcon
Private WithEvents TRAY_CONTEXT As ContextMenuStrip
Private WithEvents BTT_TRAY_SHOW_HIDE As ToolStripMenuItem
Private WithEvents BTT_TRAY_CLOSE As ToolStripMenuItem
Private WithEvents BTT_SETTINGS_REDGIFS As ToolStripMenuItem
Private WithEvents BTT_DONATE As ToolStripButton
End Class

View File

@@ -159,6 +159,9 @@
<metadata name="MENU_VIEW_SEP_2.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <metadata name="MENU_VIEW_SEP_2.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value> <value>False</value>
</metadata> </metadata>
<metadata name="TRAY_SEP_1.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="Toolbar_TOP.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <metadata name="Toolbar_TOP.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>132, 17</value> <value>132, 17</value>
</metadata> </metadata>
@@ -295,6 +298,207 @@
At+48gfYvPlXp/n+iqDm2Lj4f73w4kt1S+yWJa3+1e9fQ5Bp8ZkfwPMCwN9yOBn2+KfAk+ChX8G+Dps/ At+48gfYvPlXp/n+iqDm2Lj4f73w4kt1S+yWJa3+1e9fQ5Bp8ZkfwPMCwN9yOBn2+KfAk+ChX8G+Dps/
r1u/xd3D6+rf/v5+9YqVq6Sv/vF9Xh2XnFf8yCt5XGzeWrdeY+/glPLrtRte+M1bG1dBlPfP4uvT/xKb r1u/xd3D6+rf/v5+9YqVq6Sv/vF9Xh2XnFf8yCt5XGzeWrdeY+/glPLrtRte+M1bG1dBlPfP4uvT/xKb
N95xYLfifeVScsnnXMZvA+8pi/7fhb+CbP4D9GPXvMEwYYwAAAAASUVORK5CYII= N95xYLfifeVScsnnXMZvA+8pi/7fhb+CbP4D9GPXvMEwYYwAAAAASUVORK5CYII=
</value>
</data>
<metadata name="TrayIcon.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>525, 17</value>
</metadata>
<metadata name="TRAY_CONTEXT.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>623, 17</value>
</metadata>
<data name="BTT_TRAY_CLOSE.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAABl0RVh0U29m
dHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAVoSURBVEhLhZVrTJNXGMdfrtNSQIoadKRz2o0CorU3
WkDIVBRaaGNbwAteh+AARRQlitEYTTRekiX7sH3YPmyZH9wtziybigLRCWTaCW5sCBWhlrb0Ci9zSxbo
2f+UliGX7SS/tO85z/k9T57zXhhCCPO7Wh3VIhB83JKQ0Nu4bNlHm5YseZ1hmHC69n+Y5HLFcz7/ft/S
pY+vr1hhwL4oEBJcZ0x793If5uZ+1VNfT/qvXCHP6+p8tzMymqRxcW8hMGKqbDo9MlmWddu2AfbiRTJ6
+TIZKC52fyAUVi2JiYkLJmGaBYIPnx4+TPrOnCH9p08TC4LNx46RWwrF/ZXR0W/PleRZZuY669atZvbS
JcJiL9vQQEZPnSKmwkLPjcTE97GPB8KZlvh4C5X31dWRgRMniAVBtvPnyWB9ve+2XP7jmtjYpOlJTOnp
G60lJRZaOZWPQs4ePUpGUZh3xw7SnJDQhT0KEM3c5fOv9paVkX4kMAPL8ePEig1D584RG9rVpFS2rY6J
EQaTmKTSjbbiYsvIhQuERTGjKIrFvtHaWjK8fz9plsudexYu/BLxKsBj9ALBGzel0vt9e/b4XiBoENhQ
zRDOxIWWOY4cIS0KRZs4Nja5QyLJtRoM1pGzZ/0tYVExi/ayNTVkBPJ76enuJA7nM4j3gVWAHjgTIYqL
E96SStvMu3YR64EDxF5dTYYOHSJOJPNA5Kiu9rUrlZ1mrdbCnjzpr5jFGotYtqpqQi6TuVM4nKvwlYHU
gDzU31OMSGl8fPJtsbjVsn27z15RQRzAVVlJ3BB4kcx78CAZQbUjVIxrFtd+OdrbmpHhEXG5VE4rTwHz
wMRdFDw4jEgFj5dyRyRqsxYVEcfu3cQFPPv2ES8qHEbCYRzgsFZLvO+8Q7xKJXGDVoXCK46Ovob95YBW
Ph/8+xwE/wSTyHi81OZVq9qsGs2Ye8sW4srPJy6JhDgTE4kzOpo4IyKIMyyMOLhcX9Py5R4lj0cPtAKs
BBwwKfc7p174J5BEhHY9FIk6bBDaIRuiQkDFfsLDSbdU+pdBKPwe8e+BNDBD7vdNn6BYd+6stK5da7bP
nz9TDujcoEAw1lJY+CyFz9dCHDubnDJjwltRccS5fr3TjurnlIMBYE5NJY8Nhq7SrCwREsz6xL9y4S4v
b3Bt2uSyR0XNkDvQe9ouKu8HvaGh5FfQIxL5OgyG30qUStqmGUkm/3jKy0+48vLcs1XuiI8nL/Ly/rYl
JfmovCcgN4JW+l8iGe8oKuoqzcyckSQob3CpVB47l+sXv9KWxYtJt0r1x9ns7HZjQYHNnJxMfoH0EXgA
7oFm0CmTjRsNhs6Na9bQF+Tkq57xlJXVu9Rqz9Bs8kWLSG9BwcsqieQONlXnpaaWdul0z7rR+6C8CTSC
m8Aol4+36/XGT7VaevCRIIRx6/WWoQULZq2cyveLxY0IrAT0IHm1OTmZT3Q6U2da2qT8B/Ad+BZ05OSM
GXW6p4hdBiIZZ1FRt5vPn6vyuwiqCsj9Xyq6qXbDBkWnXm/6OS3NN1X+dUgIeZSdPXZPoxlEXC6IY9pL
S7faNBqXC9Iplf95YBb5ZF+RpGbdunQcbO/D1avJ9YC8LT19/Iv8/BeqpKRPEDORAGNeY3HxSYtG43Eq
FL5etfpljUzWhPlZ5VOTlGVliR+hHUbs+0mpHP9GpRqM5XAuY20zmGgRRohYKIx9rNd/3qfTOa7l5uLu
C63BvARw6fp0eRCMyBslJe8+2bx58EFhoVMlFNJvgQ4kgggQEgykvV0ApEAd+J3z8Z8KxmuA3pr0zikA
b4LJZ2FqYBigFdOPNf0NC679Fxi0OPr+XxiAJgwURph/AJfOQQebMR8TAAAAAElFTkSuQmCC
</value>
</data>
<data name="TrayIcon.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAEAMDAAAAEAIACoJQAAFgAAACgAAAAwAAAAYAAAAAEAIAAAAAAAACQAAMMOAADDDgAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAACOMzL/jjMy/44zMv+OMzL/jjMy/44zMv9Ts2//U7Nv/1Ozb/9Ts2//U7Nv/1Oz
b/891/H/Pdfx/z3X8f891/H/Pdfx/z3X8f8ukuD/LpLg/y6S4P8ukuD/LpLg/y6S4P8vOs7/LzrO/y86
zv8vOs7/LzrO/y86zv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAI8vLx+OMzL/jjMy/44zMv+OMzL/jjMy/4w4NOJTs2//U7Nv/1Oz
b/9Ts2//U7Nv/1O0cuI91/H/Pdfx/z3X8f891/H/Pdfx/z3X8f8ukuD/LpLg/y6S4P8ukuD/LpLg/y6S
4P8vOs7/LzrO/y86zv8vOs7/LzrO/y86zv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI0yMjeOMzL/jjMy/44zMv+OMzL/jjMy/4tD
N9NTs2//U7Nv/1Ozb/9Ts2//U7Nv/1K1fNM91/H/Pdfx/z3X8f891/H/Pdfx/zzW8OkukuD/LpLg/y6S
4P8ukuD/LpLg/y6R4PcvOs7/LzrO/y86zv8vOs7/LzrO/y86zuYAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIwzM0+OMzL/jjMy/44z
Mv+OMzL/jjMy/4hRPcdTs2//U7Nv/1Ozb/9Ts2//U7Nv/1G4h8c91/H/Pdfx/z3X8f891/H/Pdfx/zzV
8eIukuD/LpLg/y6S4P8ukuD/LpLg/y2R4OIvOs7/LzrO/y86zv8vOs7/LzrO/y46zd4AAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI4z
MZ6OMzL/jjMy/44zMv+OMzL/jjMy/4NiRMBTs2//U7Nv/1Ozb/9Ts2//U7Nv/067mMA91/H/Pdfx/z3X
8f891/H/Pdfx/zzR78sukuD/LpLg/y6S4P8ukuD/LpLg/y2Q39cvOs7/LzrO/y86zv8vOs7/LzrO/y86
ztYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAI0zMu6OMzL/jjMy/44zMv+OMzL/jjMy/26RXMdTs2//U7Nv/1Ozb/9Ts2//U7Nv/0vB
rr491/H/Pdfx/z3X8f891/H/Pdfx/zjI7b8ukuD/LpLg/y6S4P8ukuD/LpLg/y2J3cUvOs7/LzrO/y86
zv8vOs7/LzrO/y46zq4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAjzMzP44zMv+OMzL/jjMy/44zMv+OMzL/jjIx91SwbvZTs2//U7Nv/1Oz
b/9Ts2//U7Nv/0XM1M491/H/Pdfx/z3X8f891/H/Pdfx/za66cAukuD/LpLg/y6S4P8ukuD/LpLg/y55
2b4vOs7/LzrO/y86zv8vOs7/LzrO/y46zo4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjjIxro4zMv+OMzL/jjMy/44zMv+OMzL/iUw7y1Oz
b/9Ts2//U7Nv/1Ozb/9Ts2//U7Nv7z3X8f891/H/Pdfx/z3X8f891/H/Pdfx/zCk49cukuD/LpLg/y6S
4P8ukuD/LpLg/y1p1ccvOs7/LzrO/y86zv8vOs7/LzrO/y46zWcAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACPNC4vjjMy/44zMv+OMzL/jjMy/44z
Mv+OMzL/dIdXwlOzb/9Ts2//U7Nv/1Ozb/9Ts2//T7qSwj3X8f891/H/Pdfx/z3X8f891/H/PNXx4i6S
4P8ukuD/LpLg/y6S4P8ukuD/LpLg/y5N0OIvOs7/LzrO/y86zv8vOs7/LzrO/y07zDcAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACNMjLOjjMy/44z
Mv+OMzL/jjMy/44zMv+NNDLvWqpr6FOzb/9Ts2//U7Nv/1Ozb/9Ts2//RsnKxz3X8f891/H/Pdfx/z3X
8f891/H/OcvtwC6S4P8ukuD/LpLg/y6S4P8ukuD/LZHg4i86zv8vOs7/LzrO/y86zv8vOs7/LzrO/y4+
zw8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI4z
MHeOMzL/jjMy/44zMv+OMzL/jjMy/44zMv95flG/U7Nv/1Ozb/9Ts2//U7Nv/1Ozb/9Ssm/3PdXt9j3X
8f891/H/Pdfx/z3X8f891/H/M63myi6S4P8ukuD/LpLg/y6S4P8ukuD/Lobcwi86zv8vOs7/LzrO/y86
zv8vOs7/LjnNzgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAjDMzT44zMv+OMzL/jjMy/44zMv+OMzL/jjMy/441MulUsG72U7Nv/1Ozb/9Ts2//U7Nv/1Oz
b/9PuI3FPdfx/z3X8f891/H/Pdfx/z3X8f881/HvLpTh9i6S4P8ukuD/LpLg/y6S4P8ukuD/LXDXwi86
zv8vOs7/LzrO/y86zv8vOs7/LjrOjgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAACvhoQ4jzg39o4zMv+OMzL/jjMy/44zMv+OMzL/jjMy/3SHV8JTs2//U7Nv/1Oz
b/9Ts2//U7Nv/1Ozb/9D0NzXPdfx/z3X8f891/H/Pdfx/z3X8f87zu7FLpLg/y6S4P8ukuD/LpLg/y6S
4P8ukuD/Lk3Q4i86zv8vOs7/LzrO/y86zv8vOs7/LznMTwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAALKPjmi5mpn4roaG/485OP+OMzL/jjMy/44zMv+OMzL/i0c5zlOz
b/9Ts2//U7Nv/1Ozb/9Ts2//U7Nv/067mMA91/H/Pdfx/z3X8f891/H/Pdfx/z3X8f82uOjCLpLg/y6S
4P8ukuD/LpLg/y6S4P8ujt/ULzrO/y86zv8vOs7/LzrO/y86zv8vOs7/Lj7PDwAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtJKSkrmamv+5mpr/uZqa/66Ghv+POTj/jjMy/44z
Mv+MODTiWqpr6FOzb/9Ts2//U7Nv/1Ozb/9Ts2//UrJv9z/U5+g91/H/Pdfx/z3X8f891/H/Pdfx/zzW
8OkulOH2LpLg/y6S4P8ukuD/LpLg/y6S4P8ucdfFLzrO/y86zv8vOs7/LzrO/y86zv8uOs6+AAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALKPj1+4l5fguZqa/7mamv+5mpr/uZqa/7ma
mv+uhob/jzk4/44yMfdkoGTXU7Nv/1Ozb/9Ts2//U7Nv/1Ozb/9Ts2//Tr2dvz3X8f891/H/Pdfx/z3X
8f891/H/Pdfx/za46MIukuD/LpLg/y6S4P8ukuD/LpLg/y6R4PcvQ8/2LzrO/y86zv8vOs7/LzrO/y86
zv8uOs1nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKd+fhuzkJBxtZKS2bmamv+5mpr/uZqa/7ma
mv+5mpr/uZqa/7mamv+5mpr/roaG/3GTYMdTs2//U7Nv/1Ozb/9Ts2//U7Nv/1Ozb/9SsnHpP9Tn6D3X
8f891/H/Pdfx/z3X8f891/H/PNXw1y6S4P8ukuD/LpLg/y6S4P8ukuD/LpLg/y6C278vOs7/LzrO/y86
zv8vOs7/LzrO/y85zvYuPs8PAAAAAAAAAACzjY1Ns42NTbOQkHG0kpKSt5aWzLmamv+5mpr/uZqa/7ma
mv+5mpr/uZqa/7mamv+5mpr/uZqa/7mamv+7nZzzssOu2ZHGnf9WtHH/U7Nv/1Ozb/9Ts2//U7Nv/1Ky
b/dFzNTOPdfx/z3X8f891/H/Pdfx/z3X8f891/H/NLDmxy6S4P8ukuD/LpLg/y6S4P8ukuD/LpHg9y5K
0OgvOs7/LzrO/y86zv8vOs7/LzrO/y46zq4AAAAAAAAAAAAAAAC5mpr/uZqa/7mamv+5mpr/uZqa/7ma
mv+5mpr/uZqa/7mamv+5mpr/uZqa/7mamv+5mpr/uZqa/72hoOerya7mos2s/6LNrP+Rxp3/VrRx/1Oz
b/9Ts2//U7Nv/0nFusA91/H/Pdfx/z3X8f891/H/Pdfx/z3X8f880vDOLpLg/y6S4P8ukuD/LpLg/y6S
4P8ukuD/LoDbyS86zv8vOs7/LzrO/y86zv8vOs7/LzrO/y85zE8AAAAAAAAAAAAAAAC5mpr/uZqa/7ma
mv+5mpr/uZqa/7mamv+5mpr/uZqa/7mamv+5mpr/uZqa/7mamv+5mpr/vaml2qbMrPOizaz/os2s/6LN
rP+izaz/kcad/1a0cf9Ts2//Tr2dvz3X8f891/H/Pdfx/z3X8f891/H/Pdfx/z3X8f8wpOPXLpLg/y6S
4P8ukuD/LpLg/y6S4P8ukODpLkDP9i86zv8vOs7/LzrO/y86zv8vOs7/LjnNzgAAAAAAAAAAAAAAAAAA
AAC5mpr/uZqa/7mamv+5mpr/uZqa/7mamv+5mpr/uZqa/7mamv+5mpr/uZqa/72jouOyw67Zos2s/6LN
rP+izaz/os2s/6LNrP+izaz/os2s/5HGnf9VuIbLPdfx/z3X8f891/H/Pdfx/z3X8f891/H/Pdfx/zjG
7L4ukuD/LpLg/y6S4P8ukuD/LpLg/y6S4P8td9i/LzrO/y86zv8vOs7/LzrO/y86zv8vOs7/LznMTwAA
AAAAAAAAAAAAAAAAAAC5mpr/uZqa/7mamv+5mpr/uZqa/7mamv+5mpr/uZqa/7mamv+8np7vtr6t1KLN
rP+izaz/os2s/6LNrP+izaz/os2s/6LNrP+izaz/os2s/6vUvdeK3/H3Qtfx/z3X8f891/H/Pdfx/z3X
8f891/H/O9Dvxy6S4P8ukuD/LpLg/y6S4P8ukuD/LpLg/y6Q4OsuQM/2LzrO/y86zv8vOs7/LzrO/y86
zv8uOc3OAAAAAAAAAAAAAAAAAAAAAAAAAAC5mpr/uZqa/7mamv+5mpr/uZqa/7mamv+8oJ/qvLGp07LD
rtmizaz/os2s/6LNrP+izaz/os2s/6LNrP+izaz/os2s/6LNrP+izaz/rNjL0Zzk9f+c5PX/ieD0/0LX
8f891/H/Pdfx/z3X8f871O/eLpTh9i6S4P8ukuD/LpLg/y6S4P8ukuD/LpLg/y1p1ccvOs7/LzrO/y86
zv8vOs7/LzrO/y86zv8vOcxPAAAAAAAAAAAAAAAAAAAAAAAAAAC+p6Tcvqek3L2vqNS6t6vSurms0a3H
reOizaz/os2s/6LNrP+izaz/os2s/6LNrP+izaz/os2s/6LNrP+izaz/os2s/6PNrfmp3dzVnOT1/5zk
9f+c5PX/nOT1/4ng9P9C1/H/Pdfx/zzX8fAwnuLiLpLg/y6S4P8ukuD/LpLg/y6S4P8ukuD/Lo3e0C86
zv8vOs7/LzrO/y86zv8vOs7/LzrO/y45zc4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACizaz/os2s/6LN
rP+izaz/os2s/6LNrP+izaz/os2s/6LNrP+izaz/os2s/6LNrP+izaz/os2s/6LNrP+izaz/pc6v76Xg
5d+c5PX/nOT1/5zk9f+c5PX/nOT1/5zk9f+J4PT/Qdbw9zKr5dQukuD/LpLg/y6S4P8ukuD/LpLg/y6S
4P8tkeDjLkPO7y86zv8vOs7/LzrO/y86zv8vOs7/LzrO/y46zy8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AACizaz/os2s/6LNrP+izaz/os2s/6LNrP+izaz/os2s/6LNrP+izaz/os2s/6LNrP+izaz/os2s/6TP
rvOr2tDRnePy+Jzk9f+c5PX/nOT1/5zk9f+c5PX/nOT1/5zk9f+d4/T5j8nt2TST4P8ukuD/LpLg/y6S
4P8ukuD/LpLg/y6R4PcuVdHkLzrO/y86zv8vOs7/LzrO/y86zv8vOs7/LjnOngAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAACizaz/os2s/6LNrP+izaz/os2s/6LNrP+izaz/os2s/6LNrP+izaz/os2s/6LN
rP+jza35rNjI0p/j8fOc5PX/nOT1/5zk9f+c5PX/nOT1/5zk9f+c5PX/nOT1/5/k9e+hyu7jmbvq/4Wx
5/80k+D/LpLg/y6S4P8ukuD/LpLg/y5o1cwvOs7/LzrO/y86zv8vOs7/LzrO/y86zv8uOc3uKTTJFwAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACizaz/os2s/6LNrP+izaz/os2s/6LNrP+izaz/os2s/6LN
rP+izaz/ptCx6qvXxdOh4e3qnOT1/5zk9f+c5PX/nOT1/5zk9f+c5PX/nOT1/5zk9f+c5PX/ouP15JzD
6/SZu+r/mbvq/5m76v+Fsef/NJPg/y6S4P8ukuD/LXvZxi86zv8vOs7/LzrO/y86zv8vOs7/LzrO/y86
zv8uOM1HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACizaz/os2s/6LNrP+izaz/os2s/6LN
rP+izaz/p9Cz56vZztKk4ejjnOT1/5zk9f+c5PX/nOT1/5zk9f+c5PX/nOT1/5zk9f+c5PX/nOT1/5zk
9f+l4PTZmr3q+Jm76v+Zu+r/mbvq/5m76v+Zu+r/hbHn/zST4P8uiN3MLzrO/y86zv8vOs7/LzrO/y86
zv8vOs7/LzrO/y84zG8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACp0rjcqdK43KvW
wtSr2c7Sq9rQ0aff5Nyh4e3qnOT1/5zk9f+c5PX/nOT1/5zk9f+c5PX/nOT1/5zk9f+c5PX/nOT1/5zk
9f+c5PX/nOT1/6ba8teZu+r/mbvq/5m76v+Zu+r/mbvq/5m76v+Zu+r/mbvq/42z5941Rc/2LzrO/y86
zv8vOs7/LzrO/y86zv8vOs7/LznOlgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AACc5PX/nOT1/5zk9f+c5PX/nOT1/5zk9f+c5PX/nOT1/5zk9f+c5PX/nOT1/5zk9f+c5PX/nOT1/5zk
9f+c5PX/nOT1/5zk9f+l4fTbncPr75m76v+Zu+r/mbvq/5m76v+Zu+r/mbvq/5m76v+Zu+r/o73p2Zqe
3/iFiNr/NT/O/y86zv8vOs7/LzrO/y86zv8uOs6+HD2+BwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAACc5PX/nOT1/5zk9f+c5PX/nOT1/5zk9f+c5PX/nOT1/5zk9f+c5PX/nOT1/5zk
9f+c5PX/nOT1/5zk9f+c5PX/pOL13qHK7uOZu+r/mbvq/5m76v+Zu+r/mbvq/5m76v+Zu+r/mbvq/5m7
6v+ltufVmZve/5mb3v+Zm97/hYja/zU/zv8vOs7/LzrO/y46zd4uPs8PAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACc5PX/nOT1/5zk9f+c5PX/nOT1/5zk9f+c5PX/nOT1/5zk
9f+c5PX/nOT1/5zk9f+c5PX/nOT1/6Hj9Oeiz+/fmbvq/5m76v+Zu+r/mbvq/5m76v+Zu+r/mbvq/5m7
6v+Zu+r/nL3q86Ku5N6Zm97/mZve/5mb3v+Zm97/mZve/4WI2v81P87/LjnN7iw5zCcAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACc5PX/nOT1/5zk9f+c5PX/nOT1/5zk
9f+c5PX/nOT1/5zk9f+c5PX/nOT1/6Hj9eun3vPSoszu4Jm76v+Zu+r/mbvq/5m76v+Zu+r/mbvq/5m7
6v+Zu+r/mbvq/5m76v+fvurnn6fh5pmb3v+Zm97/mZve/5mb3v+Zm97/mZve/5mb3v+Fh9n3LjjNRwAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACc5PX/nOT1/5zk
9f+c5PX/nOT1/5zk9f+c5PX/nOT1/6Tk9OCn2PHSoMfs5pm76v+Zu+r/mbvq/5m76v+Zu+r/mbvq/5m7
6v+Zu+r/mbvq/5m76v+Zu+r/mbvq/6O/6tqcoN/zmZve/5mb3v+Zm97/mZve/5mb3v+Zm97/mZve/5aY
3fJ/gtlJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AACl4/XcpeP13KXj9dyl4/Xcp93z0afY8dKjze7cnMDr85m76v+Zu+r/mbvq/5m76v+Zu+r/mbvq/5m7
6v+Zu+r/mbvq/5m76v+Zu+r/mbvq/5m76v+gv+rjoq7j3Jmb3v+Zm97/mZve/5mb3v+Zm97/mZve/5mb
3v+Zm97/lJbc2X6A2SUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAACZu+r/mbvq/5m76v+Zu+r/mbvq/5m76v+Zu+r/mbvq/5m76v+Zu+r/mbvq/5m7
6v+Zu+r/mbvq/5m76v+Zu+r/mbvq/5m76v+Zu+r/nr7q6qWz5dWZm97/mZve/5mb3v+Zm97/mZve/5mb
3v+Zm97/mZve/5mb3v+Sld2+aXDWEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZu+r/mbvq/5m76v+Zu+r/mbvq/5m76v+Zu+r/mbvq/5m7
6v+Zu+r/mbvq/5m76v+Zu+r/mbvq/5m76v+Zu+r/mbvq/5y96vOmuOfSmp7f+Jmb3v+Zm97/mZve/5mb
3v+Zm97/mZve/5mb3v+Zm97/mZve/4mL2pYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZu+r/mbvq/5m76v+Zu+r/mbvq/5m7
6v+Zu+r/mbvq/5m76v+Zu+r/mbvq/5m76v+Zu+r/mbvq/5m76v+dvervprrn0pyg3/OZm97/mZve/5mb
3v+Zm97/mZve/5mb3v+Zm97/mZve/5mb3v+WmN34io3aZgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZu+r/mbvq/5m7
6v+Zu+r/mbvq/5m76v+Zu+r/mbvq/5m76v+Zu+r/mbvq/5m76v+avOr5pL7q1qOw5NmZm97/mZve/5mb
3v+Zm97/mZve/5mb3v+Zm97/mZve/5mb3v+Zm97/mZve/5OW3eyEh9o4AAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AACZu+r/mbvq/5m76v+Zu+r/mbvq/5m76v+Zu+r/mbvq/5m76v+iv+rcprrn0qKu49yZm97/mZve/5mb
3v+Zm97/mZve/5mb3v+Zm97/mZve/5mb3v+Zm97/mZve/5mb3v+Zm974i43al4SLzwgAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAACiv+rcor/q3KK/6tyiv+rcpL7q16a659KksuXXoKni45mb3v+Zm97/mZve/5mb
3v+Zm97/mZve/5mb3v+Zm97/mZve/5mb3v+Zm97/mZve/5mb3v+Zm97/mZve/5SW3cWEh9gvAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZm97/mZve/5mb3v+Zm97/mZve/5mb3v+Zm97/mZve/5mb
3v+Zm97/mZve/5mb3v+Zm97/mZve/5mb3v+Zm97/mZve/5mb3v+Zm97/mZve/5mb3v+Vl93MjY/cTQAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZm97/mZve/5mb3v+Zm97/mZve/5mb
3v+Zm97/mZve/5mb3v+Zm97/mZve/5mb3v+Zm97/mZve/5mb3v+Zm97/mZve/5mb3v+Zm97/kJLcy42P
3E0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZm97/mZve/5mb
3v+Zm97/mZve/5mb3v+Zm97/mZve/5mb3v+Zm97/mZve/5mb3v+Zm97/mZve/5mb3v+Zm97/lZfd7I2P
26aEh9o4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AACZm97/mZve/5mb3v+Zm97/mZve/5mb3v+Zm97/mZve/5mb3v+Zm97/mZve/5mb3v+Zm97/mJre7JOV
3bCHitlUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAACZm97/mZve/5mb3v+Zm97/mZve/5mb3v+Zm97/mZve/5mb3v+Ymt3ylJbdvo+R
23mMj9oxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACVl93MlZfdzJWX3cyVl93MlJbdxZGT25KPkdpxjY/cTYSL
zwgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//8AAAAAAAP//gAAAAAAA//+AAAAA
AAD//4AAAAAAAP//gAAAAAAA//+AAAAAAAD//wAAAAAAAP//AAAAAAAA//4AAAAAAAD//gAAAAAAAP/8
AAAAAQAA//gAAAABAAD/8AAAAAEAAP/gAAAAAQAA/8AAAAADAAD/AAAAAAMAAPgAAAAAAwAAAAAAAAAH
AAAAAAAAAAcAAAAAAAAADwAAAAAAAAAPAAAAAAAAAB8AAAAAAAAAHwAAAAAAAAA/AAAAAAAAAD8AAAAA
AAAAfwAAAAAAAAB/AAAAAAAAAP8AAAAAAAAB/wAAAAAAAAP/AAAAAAAAA/8AAAAAAAAH/wAAAAAAAA//
AAAAAAAAH/8AAAAAAAA//wAAAAAAAH//AAAAAAAA//8AAAAAAAP//wAAAAAAB///AAAAAAAP//8AAAAA
AB///wAAAAAAf///AAAAAAH///8AAAAAB////wAAAAAf////AAAAAP////8AAAAH/////wAAAH//////
AAA=
</value> </value>
</data> </data>
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> <data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">

View File

@@ -17,6 +17,7 @@ Public Class MainFrame
Private MyView As FormsView Private MyView As FormsView
Private ReadOnly _VideoDownloadingMode As Boolean = False Private ReadOnly _VideoDownloadingMode As Boolean = False
Private MyChannels As ChannelViewForm Private MyChannels As ChannelViewForm
Private MySavedPosts As DownloadSavedPostsForm
Private _UFinit As Boolean = True Private _UFinit As Boolean = True
Public Sub New() Public Sub New()
InitializeComponent() InitializeComponent()
@@ -29,21 +30,24 @@ Public Class MainFrame
If Args.ListExists(2) AndAlso Args(1) = "v" Then If Args.ListExists(2) AndAlso Args(1) = "v" Then
Using f As New VideosDownloaderForm : f.ShowDialog() : End Using Using f As New VideosDownloaderForm : f.ShowDialog() : End Using
_VideoDownloadingMode = True _VideoDownloadingMode = True
Else
Downloader = New TDownloader
End If End If
End Sub End Sub
Private Sub MainFrame_Load(sender As Object, e As EventArgs) Handles Me.Load Private Sub MainFrame_Load(sender As Object, e As EventArgs) Handles Me.Load
If _VideoDownloadingMode Then GoTo FormClosingInvoker If _VideoDownloadingMode Then GoTo FormClosingInvoker
Settings.DeleteCachPath()
MainProgress = New Toolbars.MyProgress(Toolbar_BOTTOM, PR_MAIN, LBL_STATUS) With {.DropCurrentProgressOnTotalChange = False, .Enabled = False}
MainProgressInst = New Toolbars.MyProgress(Toolbar_BOTTOM, PR_INST, LBL_STATUS_INST) With {.DropCurrentProgressOnTotalChange = False, .Enabled = False}
Downloader = New TDownloader
InfoForm = New DownloadedInfoForm InfoForm = New DownloadedInfoForm
AddHandler Downloader.OnJobsChange, AddressOf Downloader_UpdateJobsCount AddHandler Downloader.OnJobsChange, AddressOf Downloader_UpdateJobsCount
AddHandler Downloader.OnDownloading, AddressOf Downloader_OnDownloading AddHandler Downloader.OnDownloading, AddressOf Downloader_OnDownloading
AddHandler Downloader.OnDownloadCountChange, AddressOf InfoForm.Downloader_OnDownloadCountChange AddHandler Downloader.OnDownloadCountChange, AddressOf InfoForm.Downloader_OnDownloadCountChange
AddHandler Downloader.SendNotification, AddressOf NotificationMessage
Settings.LoadUsers() Settings.LoadUsers()
MyView = New FormsView(Me) MyView = New FormsView(Me)
MyView.ImportFromXML(Settings.Design) MyView.ImportFromXML(Settings.Design)
MyView.SetMeSize() MyView.SetMeSize()
MainProgress = New Toolbars.MyProgress(Toolbar_BOTTOM, PR_MAIN, LBL_STATUS) With {.DropCurrentProgressOnTotalChange = False} If Settings.CloseToTray Then TrayIcon.Visible = True
Dim gk$ Dim gk$
With LIST_PROFILES.Groups With LIST_PROFILES.Groups
'Collections 'Collections
@@ -92,40 +96,80 @@ FormClosingInvoker:
EndFunction: EndFunction:
End Sub End Sub
Private _CloseInvoked As Boolean = False Private _CloseInvoked As Boolean = False
Private _IgnoreTrayOptions As Boolean = False
Private _IgnoreCloseConfirm As Boolean = False
Private Async Sub MainFrame_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing Private Async Sub MainFrame_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
If Not _VideoDownloadingMode Then If Settings.CloseToTray And Not _IgnoreTrayOptions Then
If _CloseInvoked Then GoTo CloseResume e.Cancel = True
Dim ChannelsWorking As Func(Of Boolean) = Function() If(MyChannels?.Working, False) Hide()
If (Not Downloader.Working And Not ChannelsWorking.Invoke) OrElse Else
MsgBoxE({"Program still downloading something..." & vbNewLine & If Not _VideoDownloadingMode Then
"Do you really want to stop downloading and exit of program?", If CheckForClose(_IgnoreCloseConfirm) Then
"Downloading in progress"}, If _CloseInvoked Then GoTo CloseResume
MsgBoxStyle.Exclamation,,, Dim ChannelsWorking As Func(Of Boolean) = Function() If(MyChannels?.Working, False)
{"Stop downloading and close", "Cancel"}) = 0 Then Dim SP_Working As Func(Of Boolean) = Function() If(MySavedPosts?.Working, False)
If Downloader.Working Then _CloseInvoked = True : Downloader.Stop() : Downloader.DownloadSavedPostsStop() If (Not Downloader.Working And Not ChannelsWorking.Invoke And Not SP_Working.Invoke) OrElse
If Downloader.SavedPostsDownloading Then _CloseInvoked = True : Downloader.DownloadSavedPostsStop() MsgBoxE({"Program still downloading something..." & vbNewLine &
If ChannelsWorking.Invoke Then _CloseInvoked = True : MyChannels.Stop(False) "Do you really want to stop downloading and exit of program?",
If _CloseInvoked Then "Downloading in progress"},
e.Cancel = True MsgBoxStyle.Exclamation,,,
Await Task.Run(Sub() {"Stop downloading and close", "Cancel"}) = 0 Then
While Downloader.Working Or ChannelsWorking.Invoke Or Downloader.SavedPostsDownloading : Thread.Sleep(500) : End While If Downloader.Working Then _CloseInvoked = True : Downloader.Stop()
End Sub) If ChannelsWorking.Invoke Then _CloseInvoked = True : MyChannels.Stop(False)
If SP_Working.Invoke Then _CloseInvoked = True : MySavedPosts.Stop()
If _CloseInvoked Then
e.Cancel = True
Await Task.Run(Sub()
While Downloader.Working Or ChannelsWorking.Invoke Or SP_Working.Invoke : Thread.Sleep(500) : End While
End Sub)
End If
Downloader.Dispose()
InfoForm.Dispose()
If Not MyChannels Is Nothing Then MyChannels.Dispose()
If Not VideoDownloader Is Nothing Then VideoDownloader.Dispose()
If Not MySavedPosts Is Nothing Then MySavedPosts.Dispose()
MyView.Dispose(Settings.Design)
Settings.Dispose()
Else
GoTo DropCloseParams
End If
Else
GoTo DropCloseParams
End If End If
Downloader.Dispose()
InfoForm.Dispose()
If Not MyChannels Is Nothing Then MyChannels.Dispose()
If Not VideoDownloader Is Nothing Then VideoDownloader.Dispose()
MyView.Dispose(Settings.Design)
Settings.Dispose()
Else
e.Cancel = True
Exit Sub
End If End If
End If GoTo CloseContinue
If Not MyMainLOG.IsEmptyString Then SaveLogToFile() DropCloseParams:
If _CloseInvoked Then Close() e.Cancel = True
_IgnoreTrayOptions = False
_IgnoreCloseConfirm = False
_CloseInvoked = False
Exit Sub
CloseContinue:
If Not MyMainLOG.IsEmptyString Then SaveLogToFile()
If _CloseInvoked Then Close()
CloseResume: CloseResume:
End If
End Sub End Sub
#Region "Tray"
Private Sub TrayIcon_MouseClick(sender As Object, e As MouseEventArgs) Handles TrayIcon.MouseClick
If e.Button = MouseButtons.Left Then
If Visible Then Hide() Else Show()
End If
End Sub
Private Sub BTT_TRAY_SHOW_HIDE_Click(sender As Object, e As EventArgs) Handles BTT_TRAY_SHOW_HIDE.Click
If Visible Then Hide() Else Show()
End Sub
Private Sub BTT_TRAY_CLOSE_Click(sender As Object, e As EventArgs) Handles BTT_TRAY_CLOSE.Click
If CheckForClose(False) Then _IgnoreTrayOptions = True : _IgnoreCloseConfirm = True : Close()
End Sub
Private Function CheckForClose(ByVal _Ignore As Boolean) As Boolean
If Settings.ExitConfirm And Not _Ignore Then
Return MsgBoxE({"Do you want to close the program?", "Closing the program"}, MsgBoxStyle.YesNo) = MsgBoxResult.Yes
Else
Return True
End If
End Function
#End Region
Private Sub MainFrame_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown Private Sub MainFrame_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
Dim b As Boolean = True Dim b As Boolean = True
Select Case e.KeyCode Select Case e.KeyCode
@@ -262,6 +306,9 @@ CloseResume:
Private Sub BTT_SETTINGS_INSTAGRAM_Click(sender As Object, e As EventArgs) Handles BTT_SETTINGS_INSTAGRAM.Click Private Sub BTT_SETTINGS_INSTAGRAM_Click(sender As Object, e As EventArgs) Handles BTT_SETTINGS_INSTAGRAM.Click
Using f As New SiteEditorForm(Sites.Instagram) : f.ShowDialog() : End Using Using f As New SiteEditorForm(Sites.Instagram) : f.ShowDialog() : End Using
End Sub End Sub
Private Sub BTT_SETTINGS_REDGIFS_Click(sender As Object, e As EventArgs) Handles BTT_SETTINGS_REDGIFS.Click
Using f As New SiteEditorForm(Sites.RedGifs) : f.ShowDialog() : End Using
End Sub
Private Sub BTT_SETTINGS_Click(sender As Object, e As EventArgs) Handles BTT_SETTINGS.Click Private Sub BTT_SETTINGS_Click(sender As Object, e As EventArgs) Handles BTT_SETTINGS.Click
Dim mhl% = Settings.MaxLargeImageHeigh.Value Dim mhl% = Settings.MaxLargeImageHeigh.Value
Dim mhs% = Settings.MaxSmallImageHeigh.Value Dim mhs% = Settings.MaxSmallImageHeigh.Value
@@ -269,6 +316,7 @@ CloseResume:
f.ShowDialog() f.ShowDialog()
If f.DialogResult = DialogResult.OK Then If f.DialogResult = DialogResult.OK Then
If Not Settings.MaxLargeImageHeigh = mhl Or Not Settings.MaxSmallImageHeigh = mhs Then RefillList() If Not Settings.MaxLargeImageHeigh = mhl Or Not Settings.MaxSmallImageHeigh = mhs Then RefillList()
TrayIcon.Visible = Settings.CloseToTray
End If End If
End Using End Using
End Sub End Sub
@@ -356,11 +404,18 @@ CloseResume:
If MyChannels Is Nothing Then If MyChannels Is Nothing Then
MyChannels = New ChannelViewForm MyChannels = New ChannelViewForm
AddHandler MyChannels.OnUsersAdded, AddressOf OnUsersAddedHandler AddHandler MyChannels.OnUsersAdded, AddressOf OnUsersAddedHandler
AddHandler MyChannels.OnDownloadDone, AddressOf NotificationMessage
End If End If
If MyChannels.Visible Then MyChannels.BringToFront() Else MyChannels.Show() If MyChannels.Visible Then MyChannels.BringToFront() Else MyChannels.Show()
End Sub End Sub
Private Sub BTT_DOWN_SAVED_Click(sender As Object, e As EventArgs) Handles BTT_DOWN_SAVED.Click Private Sub BTT_DOWN_SAVED_Click(sender As Object, e As EventArgs) Handles BTT_DOWN_SAVED.Click
Downloader.DownloadSavedPostsStart(Toolbar_BOTTOM, PR_SAVED) If MySavedPosts Is Nothing Then
MySavedPosts = New DownloadSavedPostsForm
AddHandler MySavedPosts.OnDownloadDone, AddressOf NotificationMessage
End If
With MySavedPosts
If .Visible Then .BringToFront() Else .Show()
End With
End Sub End Sub
#End Region #End Region
#Region "Download" #Region "Download"
@@ -507,6 +562,9 @@ CloseResume:
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(Settings.Design) MyMainLOG_ShowForm(Settings.Design)
End Sub End Sub
Private Sub BTT_DONATE_Click(sender As Object, e As EventArgs) Handles BTT_DONATE.Click
Try : Process.Start("https://ko-fi.com/andyprogram") : Catch : End Try
End Sub
#Region "List functions" #Region "List functions"
Private _LatestSelected As Integer = -1 Private _LatestSelected As Integer = -1
Private Sub LIST_PROFILES_SelectedIndexChanged(sender As Object, e As EventArgs) Handles LIST_PROFILES.SelectedIndexChanged Private Sub LIST_PROFILES_SelectedIndexChanged(sender As Object, e As EventArgs) Handles LIST_PROFILES.SelectedIndexChanged
@@ -988,18 +1046,30 @@ ResumeDownloadingOperation:
Friend Sub User_OnUserUpdated(ByVal User As IUserData) Friend Sub User_OnUserUpdated(ByVal User As IUserData)
UserListUpdate(User, False) UserListUpdate(User, False)
End Sub End Sub
Private _LogVisible As Boolean = False Private _LogColorChanged As Boolean = False
Private Sub Downloader_UpdateJobsCount(ByVal TotalCount As Integer) Private Sub Downloader_UpdateJobsCount(ByVal Site As Sites, ByVal TotalCount As Integer)
Dim a As Action = Sub() LBL_JOBS_COUNT.Text = IIf(TotalCount = 0, String.Empty, $"[Jobs {TotalCount}]") Dim a As Action
If Site = Sites.Instagram Then
a = Sub() LBL_JOBS_INST_COUNT.Text = IIf(TotalCount = 0, String.Empty, $"[Jobs {TotalCount}]")
Else
a = Sub() LBL_JOBS_COUNT.Text = IIf(TotalCount = 0, String.Empty, $"[Jobs {TotalCount}]")
End If
If Toolbar_BOTTOM.InvokeRequired Then Toolbar_BOTTOM.Invoke(a) Else a.Invoke If Toolbar_BOTTOM.InvokeRequired Then Toolbar_BOTTOM.Invoke(a) Else a.Invoke
If Not _LogVisible AndAlso Not MyMainLOG.IsEmptyString Then If Not _LogColorChanged AndAlso Not MyMainLOG.IsEmptyString Then
a = Sub() BTT_LOG.ControlChangeColor(False) a = Sub() BTT_LOG.ControlChangeColor(False)
If Toolbar_TOP.InvokeRequired Then Toolbar_TOP.Invoke(a) Else a.Invoke If Toolbar_TOP.InvokeRequired Then Toolbar_TOP.Invoke(a) Else a.Invoke
_LogVisible = True _LogColorChanged = True
ElseIf _LogColorChanged And MyMainLOG.IsEmptyString Then
a = Sub() BTT_LOG.ControlChangeColor(SystemColors.Control, SystemColors.ControlText)
If Toolbar_TOP.InvokeRequired Then Toolbar_TOP.Invoke(a) Else a.Invoke
_LogColorChanged = False
End If End If
End Sub End Sub
Private Sub Downloader_OnDownloading(ByVal Value As Boolean) Private Sub Downloader_OnDownloading(ByVal Value As Boolean)
Dim a As Action = Sub() BTT_DOWN_STOP.Enabled = Value Dim a As Action = Sub() BTT_DOWN_STOP.Enabled = Value
If Toolbar_TOP.InvokeRequired Then Toolbar_TOP.Invoke(a) Else a.Invoke If Toolbar_TOP.InvokeRequired Then Toolbar_TOP.Invoke(a) Else a.Invoke
End Sub End Sub
Private Sub NotificationMessage(ByVal Message As String)
If Settings.ShowNotifications Then TrayIcon.ShowBalloonTip(2000, TrayIcon.BalloonTipTitle, Message, ToolTipIcon.Info)
End Sub
End Class End Class

View File

@@ -8,6 +8,7 @@
' but WITHOUT ANY WARRANTY ' but WITHOUT ANY WARRANTY
Imports PersonalUtilities.Functions.XML Imports PersonalUtilities.Functions.XML
Imports PersonalUtilities.Tools.WEB Imports PersonalUtilities.Tools.WEB
Imports PersonalUtilities.Forms.Toolbars
Imports SCrawler.API Imports SCrawler.API
Imports SCrawler.API.Base Imports SCrawler.API.Base
Friend Module MainMod Friend Module MainMod
@@ -44,11 +45,12 @@ Friend Module MainMod
Friend Class NumberedFile : Inherits SFileNumbers Friend Class NumberedFile : Inherits SFileNumbers
Friend Sub New(ByVal f As SFile) Friend Sub New(ByVal f As SFile)
FileName = f.Name FileName = f.Name
NumberProvider = New ANumbers With {.FormatMode = ANumbers.Formats.NumberGroup, .GroupSize = 5} NumberProvider = New ANumbers With {.Format = ANumbers.Formats.NumberGroup, .GroupSize = 5}
End Sub End Sub
End Class End Class
#End Region #End Region
Friend Property MainProgress As PersonalUtilities.Forms.Toolbars.MyProgress Friend Property MainProgress As MyProgress
Friend Property MainProgressInst As MyProgress
Friend Function GetLviGroupName(ByVal Site As Sites, ByVal Temp As Boolean, ByVal Fav As Boolean, Friend Function GetLviGroupName(ByVal Site As Sites, ByVal Temp As Boolean, ByVal Fav As Boolean,
ByVal IsCollection As Boolean, ByVal IsChannel As Boolean) As String ByVal IsCollection As Boolean, ByVal IsChannel As Boolean) As String
Dim Opt$ = String.Empty Dim Opt$ = String.Empty
@@ -71,6 +73,7 @@ Friend Module MainMod
Reddit = 1 Reddit = 1
Twitter = 2 Twitter = 2
Instagram = 3 Instagram = 3
RedGifs = 4
End Enum End Enum
Friend Structure UserInfo : Implements IComparable(Of UserInfo), IEquatable(Of UserInfo), ICloneable Friend Structure UserInfo : Implements IComparable(Of UserInfo), IEquatable(Of UserInfo), ICloneable
Friend Const Name_Site As String = "Site" Friend Const Name_Site As String = "Site"
@@ -208,7 +211,7 @@ Friend Module MainMod
End Function End Function
Friend Function GetNewVideoURL() As String Friend Function GetNewVideoURL() As String
Dim b$ = GetCurrentBuffer() Dim b$ = GetCurrentBuffer()
Dim URL$ = InputBox("Enter video URL:", "Download video by URL", b) Dim URL$ = InputBoxE("Enter video URL:", "Download video by URL", b)
If Not URL.IsEmptyString Then Return URL Else Return String.Empty If Not URL.IsEmptyString Then Return URL Else Return String.Empty
End Function End Function
Friend Sub DownloadVideoByURL() Friend Sub DownloadVideoByURL()

View File

@@ -10,7 +10,7 @@ Imports System.Runtime.InteropServices
' Review the values of the assembly attributes ' Review the values of the assembly attributes
<Assembly: AssemblyTitle("Socials media data Crawler")> <Assembly: AssemblyTitle("Socials media data Crawler")>
<Assembly: AssemblyDescription("Twitter and Reddit media crawler")> <Assembly: AssemblyDescription("Social networks media downloader")>
<Assembly: AssemblyCompany("AndyProgram")> <Assembly: AssemblyCompany("AndyProgram")>
<Assembly: AssemblyProduct("SCrawler")> <Assembly: AssemblyProduct("SCrawler")>
<Assembly: AssemblyCopyright("Copyright © 2022")> <Assembly: AssemblyCopyright("Copyright © 2022")>
@@ -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("2.0.0.1")> <Assembly: AssemblyVersion("2.0.0.2")>
<Assembly: AssemblyFileVersion("2.0.0.1")> <Assembly: AssemblyFileVersion("2.0.0.2")>
<Assembly: NeutralResourcesLanguage("en")> <Assembly: NeutralResourcesLanguage("en")>

View File

@@ -110,6 +110,16 @@ Namespace My.Resources
End Get End Get
End Property End Property
'''<summary>
''' Looks up a localized resource of type System.Drawing.Bitmap.
'''</summary>
Friend ReadOnly Property HeartPic_32() As System.Drawing.Bitmap
Get
Dim obj As Object = ResourceManager.GetObject("HeartPic_32", resourceCulture)
Return CType(obj,System.Drawing.Bitmap)
End Get
End Property
'''<summary> '''<summary>
''' Looks up a localized resource of type System.Drawing.Bitmap. ''' Looks up a localized resource of type System.Drawing.Bitmap.
'''</summary> '''</summary>

View File

@@ -124,12 +124,18 @@
<data name="PrevPIC2" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="PrevPIC2" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Content\Pictures\PrevPIC2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>..\Content\Pictures\PrevPIC2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data> </data>
<data name="StartPic_01_Green_16" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Content\Pictures\StartPic_01_Green_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="PencilPic_01_16" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="PencilPic_01_16" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Content\Pictures\PencilPic_01_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>..\Content\Pictures\PencilPic_01_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data> </data>
<data name="NextPIC2" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="NextPIC2" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Content\Pictures\NextPIC2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>..\Content\Pictures\NextPIC2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data> </data>
<data name="BookmarkBlack_16" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Content\Pictures\BookmarkBlack_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Folder_32" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="Folder_32" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Content\Pictures\Folder_32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>..\Content\Pictures\Folder_32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data> </data>
@@ -142,14 +148,11 @@
<data name="TwitterIcon" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="TwitterIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Content\Icons\TwitterIcon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>..\Content\Icons\TwitterIcon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data> </data>
<data name="SettingsPic_16" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Content\Pictures\SettingsPic_16.bmp;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Delete" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="Delete" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Content\Pictures\Delete.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>..\Content\Pictures\Delete.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data> </data>
<data name="InfoPic_32" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="InstagramPic76" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Content\Pictures\InfoPic_32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>..\Content\Pictures\InstagramPic76.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data> </data>
<data name="InstagramIcon" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="InstagramIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Content\Icons\InstagramIcon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>..\Content\Icons\InstagramIcon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
@@ -157,18 +160,18 @@
<data name="GlobeBlue_32" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="GlobeBlue_32" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Content\Pictures\GlobeBlue_32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>..\Content\Pictures\GlobeBlue_32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data> </data>
<data name="PicturePic_32" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="InfoPic_32" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Content\Pictures\PicturePic_32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>..\Content\Pictures\InfoPic_32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data> </data>
<data name="Refresh" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="Refresh" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Content\Pictures\Refresh.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>..\Content\Pictures\Refresh.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data> </data>
<data name="PicturePic_32" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Content\Pictures\PicturePic_32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="RedditIcon" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="RedditIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Content\Icons\RedditIcon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>..\Content\Icons\RedditIcon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data> </data>
<data name="InstagramPic76" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Content\Pictures\InstagramPic76.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Rainbow" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="Rainbow" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Content\Icons\Rainbow.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>..\Content\Icons\Rainbow.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data> </data>
@@ -181,10 +184,10 @@
<data name="DBPic_32" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="DBPic_32" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Content\Pictures\DBPic_32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>..\Content\Pictures\DBPic_32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data> </data>
<data name="StartPic_01_Green_16" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="SettingsPic_16" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Content\Pictures\StartPic_01_Green_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>..\Content\Pictures\SettingsPic_16.bmp;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data> </data>
<data name="BookmarkBlack_16" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="HeartPic_32" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Content\Pictures\BookmarkBlack_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>..\Content\Pictures\HeartPic_32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data> </data>
</root> </root>

View File

@@ -139,6 +139,7 @@
<Compile Include="API\Base\UserDataBase.vb" /> <Compile Include="API\Base\UserDataBase.vb" />
<Compile Include="API\Imgur\Envir.vb" /> <Compile Include="API\Imgur\Envir.vb" />
<Compile Include="API\Instagram\Declarations.vb" /> <Compile Include="API\Instagram\Declarations.vb" />
<Compile Include="API\Instagram\ProfileSaved.vb" />
<Compile Include="API\Instagram\UserData.vb" /> <Compile Include="API\Instagram\UserData.vb" />
<Compile Include="API\Reddit\Channel.vb" /> <Compile Include="API\Reddit\Channel.vb" />
<Compile Include="API\Reddit\ChannelsCollection.vb" /> <Compile Include="API\Reddit\ChannelsCollection.vb" />
@@ -146,9 +147,17 @@
<Compile Include="API\Reddit\M3U8.vb" /> <Compile Include="API\Reddit\M3U8.vb" />
<Compile Include="API\Reddit\ProfileSaved.vb" /> <Compile Include="API\Reddit\ProfileSaved.vb" />
<Compile Include="API\Reddit\UserData.vb" /> <Compile Include="API\Reddit\UserData.vb" />
<Compile Include="API\Redgifs\Declarations.vb" />
<Compile Include="API\Redgifs\UserData.vb" />
<Compile Include="API\Twitter\Declarations.vb" /> <Compile Include="API\Twitter\Declarations.vb" />
<Compile Include="API\Twitter\UserData.vb" /> <Compile Include="API\Twitter\UserData.vb" />
<Compile Include="API\UserDataBind.vb" /> <Compile Include="API\UserDataBind.vb" />
<Compile Include="Channels\ChannelsStatsForm.Designer.vb">
<DependentUpon>ChannelsStatsForm.vb</DependentUpon>
</Compile>
<Compile Include="Channels\ChannelsStatsForm.vb">
<SubType>Form</SubType>
</Compile>
<Compile Include="Channels\ChannelViewForm.Designer.vb"> <Compile Include="Channels\ChannelViewForm.Designer.vb">
<DependentUpon>ChannelViewForm.vb</DependentUpon> <DependentUpon>ChannelViewForm.vb</DependentUpon>
</Compile> </Compile>
@@ -161,6 +170,12 @@
<Compile Include="DownloadedInfoForm.vb"> <Compile Include="DownloadedInfoForm.vb">
<SubType>Form</SubType> <SubType>Form</SubType>
</Compile> </Compile>
<Compile Include="DownloadSavedPostsForm.Designer.vb">
<DependentUpon>DownloadSavedPostsForm.vb</DependentUpon>
</Compile>
<Compile Include="DownloadSavedPostsForm.vb">
<SubType>Form</SubType>
</Compile>
<Compile Include="Editors\CollectionEditorForm.Designer.vb"> <Compile Include="Editors\CollectionEditorForm.Designer.vb">
<DependentUpon>CollectionEditorForm.vb</DependentUpon> <DependentUpon>CollectionEditorForm.vb</DependentUpon>
</Compile> </Compile>
@@ -179,6 +194,9 @@
<Compile Include="Editors\LabelsForm.vb"> <Compile Include="Editors\LabelsForm.vb">
<SubType>Form</SubType> <SubType>Form</SubType>
</Compile> </Compile>
<Compile Include="Editors\SiteDefaults.vb">
<SubType>Component</SubType>
</Compile>
<Compile Include="Editors\SiteSelectionForm.Designer.vb"> <Compile Include="Editors\SiteSelectionForm.Designer.vb">
<DependentUpon>SiteSelectionForm.vb</DependentUpon> <DependentUpon>SiteSelectionForm.vb</DependentUpon>
</Compile> </Compile>
@@ -233,12 +251,18 @@
</Compile> </Compile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="Channels\ChannelsStatsForm.resx">
<DependentUpon>ChannelsStatsForm.vb</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Channels\ChannelViewForm.resx"> <EmbeddedResource Include="Channels\ChannelViewForm.resx">
<DependentUpon>ChannelViewForm.vb</DependentUpon> <DependentUpon>ChannelViewForm.vb</DependentUpon>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Include="DownloadedInfoForm.resx"> <EmbeddedResource Include="DownloadedInfoForm.resx">
<DependentUpon>DownloadedInfoForm.vb</DependentUpon> <DependentUpon>DownloadedInfoForm.vb</DependentUpon>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Include="DownloadSavedPostsForm.resx">
<DependentUpon>DownloadSavedPostsForm.vb</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Editors\CollectionEditorForm.resx"> <EmbeddedResource Include="Editors\CollectionEditorForm.resx">
<DependentUpon>CollectionEditorForm.vb</DependentUpon> <DependentUpon>CollectionEditorForm.vb</DependentUpon>
</EmbeddedResource> </EmbeddedResource>
@@ -296,6 +320,7 @@
<None Include="Content\Pictures\TwitterPic400.png" /> <None Include="Content\Pictures\TwitterPic400.png" />
<None Include="Content\Pictures\InstagramPic76.png" /> <None Include="Content\Pictures\InstagramPic76.png" />
<None Include="Content\Pictures\BookmarkBlack_16.png" /> <None Include="Content\Pictures\BookmarkBlack_16.png" />
<None Include="Content\Pictures\HeartPic_32.png" />
<Content Include="ffmpeg.exe"> <Content Include="ffmpeg.exe">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>

View File

@@ -61,7 +61,8 @@ Friend Class SettingsCLS : Implements IDisposable
MySites = New Dictionary(Of Sites, SiteSettings) From { MySites = New Dictionary(Of Sites, SiteSettings) From {
{Sites.Reddit, New SiteSettings(Sites.Reddit, MyXML, GlobalPath.Value, DefaultTemporary, DefaultDownloadImages, DefaultDownloadVideos)}, {Sites.Reddit, New SiteSettings(Sites.Reddit, MyXML, GlobalPath.Value, DefaultTemporary, DefaultDownloadImages, DefaultDownloadVideos)},
{Sites.Twitter, New SiteSettings(Sites.Twitter, MyXML, GlobalPath.Value, DefaultTemporary, DefaultDownloadImages, DefaultDownloadVideos)}, {Sites.Twitter, New SiteSettings(Sites.Twitter, MyXML, GlobalPath.Value, DefaultTemporary, DefaultDownloadImages, DefaultDownloadVideos)},
{Sites.Instagram, New SiteSettings(Sites.Instagram, MyXML, GlobalPath.Value, DefaultTemporary, DefaultDownloadImages, DefaultDownloadVideos)} {Sites.Instagram, New SiteSettings(Sites.Instagram, MyXML, GlobalPath.Value, DefaultTemporary, DefaultDownloadImages, DefaultDownloadVideos)},
{Sites.RedGifs, New SiteSettings(Sites.RedGifs, MyXML, GlobalPath.Value, DefaultTemporary, DefaultDownloadImages, DefaultDownloadVideos)}
} }
MySites(Sites.Reddit).Responser.Decoders.Add(SymbolsConverter.Converters.Unicode) MySites(Sites.Reddit).Responser.Decoders.Add(SymbolsConverter.Converters.Unicode)
@@ -120,7 +121,12 @@ Friend Class SettingsCLS : Implements IDisposable
ShowNewVersionNotification = New XMLValue(Of Boolean)("ShowNewVersionNotification", True, MyXML) ShowNewVersionNotification = New XMLValue(Of Boolean)("ShowNewVersionNotification", True, MyXML)
LatestVersion = New XMLValue(Of String)("LatestVersion", String.Empty, MyXML) LatestVersion = New XMLValue(Of String)("LatestVersion", String.Empty, MyXML)
ExitConfirm = New XMLValue(Of Boolean)("ExitConfirm", True, MyXML)
CloseToTray = New XMLValue(Of Boolean)("CloseToTray", True, MyXML)
ShowNotifications = New XMLValue(Of Boolean)("ShowNotifications", True, MyXML)
If MyXML.ChangesDetected Then MyXML.Sort() : MyXML.UpdateData() If MyXML.ChangesDetected Then MyXML.Sort() : MyXML.UpdateData()
Labels = New LabelsKeeper Labels = New LabelsKeeper
If Not LatestSelectedLabels.IsEmptyString Then Labels.CurrentSelection.ListAddList(LatestSelectedLabels.Value.StringToList(Of String, List(Of String))("|")) If Not LatestSelectedLabels.IsEmptyString Then Labels.CurrentSelection.ListAddList(LatestSelectedLabels.Value.StringToList(Of String, List(Of String))("|"))
If BlackListFile.Exists Then If BlackListFile.Exists Then
@@ -253,6 +259,10 @@ Friend Class SettingsCLS : Implements IDisposable
If BlackListFile.Exists Then BlackListFile.Delete() If BlackListFile.Exists Then BlackListFile.Delete()
End If End If
End Sub End Sub
Friend Sub DeleteCachPath()
If Reddit.ChannelsCollection.ChannelsPathCache.Exists(SFO.Path, False) Then _
Reddit.ChannelsCollection.ChannelsPathCache.Delete(SFO.Path, False, False, EDP.None)
End Sub
Friend Overloads Function UserExists(ByVal s As Sites, ByVal UserID As String) As Boolean Friend Overloads Function UserExists(ByVal s As Sites, ByVal UserID As String) As Boolean
Dim UserFinderBase As Predicate(Of IUserData) = Function(user) user.Site = s And user.Name = UserID Dim UserFinderBase As Predicate(Of IUserData) = Function(user) user.Site = s And user.Name = UserID
Dim UserFinder As Predicate(Of IUserData) = Function(ByVal user As IUserData) As Boolean Dim UserFinder As Predicate(Of IUserData) = Function(ByVal user As IUserData) As Boolean
@@ -369,6 +379,11 @@ Friend Class SettingsCLS : Implements IDisposable
Friend ReadOnly Property ShowNewVersionNotification As XMLValue(Of Boolean) Friend ReadOnly Property ShowNewVersionNotification As XMLValue(Of Boolean)
Friend ReadOnly Property LatestVersion As XMLValue(Of String) Friend ReadOnly Property LatestVersion As XMLValue(Of String)
#End Region #End Region
#Region "Other program properties"
Friend ReadOnly Property ExitConfirm As XMLValue(Of Boolean)
Friend ReadOnly Property CloseToTray As XMLValue(Of Boolean)
Friend ReadOnly Property ShowNotifications As XMLValue(Of Boolean)
#End Region
#Region "IDisposable Support" #Region "IDisposable Support"
Private disposedValue As Boolean = False Private disposedValue As Boolean = False
Protected Overridable Overloads Sub Dispose(ByVal disposing As Boolean) Protected Overridable Overloads Sub Dispose(ByVal disposing As Boolean)
@@ -377,8 +392,7 @@ Friend Class SettingsCLS : Implements IDisposable
If UserListUpdateRequired Then UpdateUsersList() If UserListUpdateRequired Then UpdateUsersList()
If Not Channels Is Nothing Then If Not Channels Is Nothing Then
Channels.Dispose() Channels.Dispose()
If Reddit.ChannelsCollection.ChannelsPathCache.Exists(SFO.Path, False) Then _ DeleteCachPath()
Reddit.ChannelsCollection.ChannelsPathCache.Delete(SFO.Path, False, False, EDP.None)
End If End If
For Each kv In MySites : kv.Value.Dispose() : Next For Each kv In MySites : kv.Value.Dispose() : Next
MySites.Clear() MySites.Clear()

View File

@@ -7,102 +7,206 @@
' 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 EOptions = PersonalUtilities.Forms.Toolbars.MyProgress.EnableOptions Imports PersonalUtilities.Forms.Toolbars
Imports EOptions = PersonalUtilities.Forms.Toolbars.IMyProgress.EnableOptions
Imports SCrawler.API Imports SCrawler.API
Imports SCrawler.API.Base Imports SCrawler.API.Base
Friend Class TDownloader : Implements IDisposable Friend Class TDownloader : Implements IDisposable
Friend Event OnJobsChange(ByVal JobsCount As Integer) Friend Event OnJobsChange(ByVal Site As Sites, ByVal JobsCount As Integer)
Friend Event OnDownloadCountChange() Friend Event OnDownloadCountChange()
Friend Event OnDownloading(ByVal Value As Boolean) Friend Event OnDownloading(ByVal Value As Boolean)
Private TokenSource As CancellationTokenSource Friend Event SendNotification(ByVal Message As String)
Private ReadOnly Items As List(Of IUserData)
Friend ReadOnly Property Downloaded As List(Of IUserData) Friend ReadOnly Property Downloaded As List(Of IUserData)
Private ReadOnly NProv As IFormatProvider Private ReadOnly NProv As IFormatProvider
Private _Working As Boolean = False Friend ReadOnly Property Working(Optional ByVal Site As Sites = Sites.Undefined) As Boolean
Friend ReadOnly Property Working As Boolean
Get Get
Return _Working If Site = Sites.Instagram Then
Return JobInst.Working
Else
Return JobDefault.Working Or JobInst.Working
End If
End Get End Get
End Property End Property
Private DThread As Thread Friend Property InstagramSavedPostsDownloading As Boolean = False
Friend ReadOnly Property Count As Integer #Region "Jobs"
Get Friend Structure Job
Return Items.Count Friend Site As Sites
End Get Private TokenSource As CancellationTokenSource
End Property Private Token As CancellationToken
Friend Sub New() Private [Thread] As Thread
Items = New List(Of IUserData) Private _Working As Boolean
Downloaded = New List(Of IUserData) Friend ReadOnly Items As List(Of IUserData)
NProv = New ANumbers(ANumbers.Modes.USA) With { Friend ReadOnly Property Count As Integer
.FormatMode = ANumbers.Formats.Number, Get
.GroupSize = 3, Return Items.Count
.GroupSeparator = ANumbers.DefaultGroupSeparator, End Get
.DecimalDigits = 0 End Property
} Friend ReadOnly Property Working As Boolean
End Sub Get
Friend Sub [Start]() Return _Working OrElse If(Thread?.IsAlive, False)
If Not _Working AndAlso Count > 0 AndAlso Not If(DThread?.IsAlive, False) Then End Get
DThread = New Thread(New ThreadStart(AddressOf StartDownloading)) End Property
DThread.SetApartmentState(ApartmentState.MTA) Friend ReadOnly Progress As MyProgress
DThread.Start() Friend Sub New(ByRef _Progress As MyProgress)
End If Progress = _Progress
End Sub Items = New List(Of IUserData)
Private Sub StartDownloading() End Sub
Dim Token As CancellationToken Public Shared Widening Operator CType(ByVal j As Job) As CancellationToken
RaiseEvent OnDownloading(True) Return j.Token
Try End Operator
_Working = True Public Shared Widening Operator CType(ByVal j As Job) As Boolean
Return j.Working
End Operator
Public Shared Operator And(ByVal x As Job, ByVal y As Job) As Boolean
Return x.Working And y.Working
End Operator
Public Shared Operator And(ByVal x As Job, ByVal y As Boolean) As Boolean
Return x.Working And y
End Operator
Public Shared Operator And(ByVal x As Boolean, ByVal y As Job) As Boolean
Return x And y.Working
End Operator
Public Shared Operator Or(ByVal x As Job, ByVal y As Job) As Boolean
Return x.Working Or y.Working
End Operator
Public Shared Operator Or(ByVal x As Job, ByVal y As Boolean) As Boolean
Return x.Working Or y
End Operator
Public Shared Operator Or(ByVal x As Boolean, ByVal y As Job) As Boolean
Return x Or y.Working
End Operator
Public Shared Operator Not(ByVal j As Job) As Boolean
Return Not j.Working
End Operator
Friend Sub ThrowIfCancellationRequested()
Token.ThrowIfCancellationRequested()
End Sub
Friend ReadOnly Property IsCancellationRequested As Boolean
Get
Return Token.IsCancellationRequested
End Get
End Property
Friend ReadOnly Property IsInstagram As Boolean
Get
Return Site = Sites.Instagram
End Get
End Property
Friend Sub [Start](ByVal [ThreadStart] As ThreadStart)
Thread = New Thread(ThreadStart) With {.IsBackground = True}
Thread.SetApartmentState(ApartmentState.MTA)
Thread.Start()
End Sub
Friend Sub [Start]()
TokenSource = New CancellationTokenSource TokenSource = New CancellationTokenSource
Token = TokenSource.Token Token = TokenSource.Token
MainProgress.TotalCount = 0 _Working = True
MainProgress.CurrentCounter = 0 End Sub
Do While Count > 0 Friend Sub [Stop]()
Token.ThrowIfCancellationRequested() If Not TokenSource Is Nothing Then TokenSource.Cancel()
UpdateJobsLabel() End Sub
DownloadData(Token) Friend Sub Stopped()
Token.ThrowIfCancellationRequested()
Thread.Sleep(500)
Loop
MainProgress.InformationTemporary = "All data downloaded"
Catch oex As OperationCanceledException When Token.IsCancellationRequested
MainProgress.InformationTemporary = "Downloading canceled"
Catch ex As Exception
MainProgress.InformationTemporary = "Downloading error"
ErrorsDescriber.Execute(EDP.SendInLog, ex, "TDownloader.Start")
Finally
_Working = False _Working = False
TokenSource = Nothing TokenSource = Nothing
UpdateJobsLabel() Try
If Settings(Sites.Instagram).InstaHashUpdateRequired Then MyMainLOG = "Check your Instagram credentials" If Not Thread Is Nothing Then
If Thread.IsAlive Then Thread.Abort()
Thread = Nothing
End If
Catch ex As Exception
End Try
End Sub
End Structure
Private JobDefault As Job
Private JobInst As Job
#End Region
Friend Sub New()
Downloaded = New List(Of IUserData)
NProv = New ANumbers With {.FormatOptions = ANumbers.Options.GroupIntegral}
JobDefault = New Job(MainProgress)
JobInst = New Job(MainProgressInst) With {.Site = Sites.Instagram}
End Sub
Friend Sub [Start]()
If Not JobDefault.Working And JobDefault.Count > 0 Then JobDefault.Start(New ThreadStart(Sub() StartDownloading(JobDefault)))
If Not JobInst.Working And JobInst.Count > 0 And Not InstagramSavedPostsDownloading Then _
JobInst.Start(New ThreadStart(Sub() StartDownloading(JobInst)))
End Sub
Private Sub StartDownloading(ByRef _Job As Job)
RaiseEvent OnDownloading(True)
Dim isInst As Boolean = _Job.IsInstagram
Dim pt As Func(Of String, String) = Function(ByVal t As String) As String
Dim _t$ = If(isInst, $"Instagram {Left(t, 1).ToLower}{Right(t, t.Length - 1)}", t)
RaiseEvent SendNotification(_t)
Return _t
End Function
Try
_Job.Start()
_Job.Progress.TotalCount = 0
_Job.Progress.CurrentCounter = 0
_Job.Progress.Enabled = True
Do While _Job.Count > 0
_Job.ThrowIfCancellationRequested()
UpdateJobsLabel(_Job)
DownloadData(_Job, _Job)
_Job.ThrowIfCancellationRequested()
Thread.Sleep(500)
Loop
_Job.Progress.InformationTemporary = pt("All data downloaded")
Catch oex As OperationCanceledException When _Job.IsCancellationRequested
_Job.Progress.InformationTemporary = pt("Downloading canceled")
Catch ex As Exception
_Job.Progress.InformationTemporary = pt("Downloading error")
ErrorsDescriber.Execute(EDP.SendInLog, ex, "TDownloader.Start")
Finally
_Job.Stopped()
UpdateJobsLabel(_Job)
If _Job.Site = Sites.Instagram Then
Settings(Sites.Instagram).InstagramLastDownloadDate.Value = Now
If Settings(Sites.Instagram).InstaHashUpdateRequired Then MyMainLOG = "Check your Instagram credentials"
End If
_Job.Progress.Enabled(EOptions.ProgressBar) = False
RaiseEvent OnDownloading(False) RaiseEvent OnDownloading(False)
End Try End Try
End Sub End Sub
Friend Sub [Stop]() Friend Sub [Stop]()
If _Working Then TokenSource.Cancel() If JobDefault.Working Then JobDefault.Stop()
If JobInst.Working Then JobInst.Stop()
End Sub End Sub
Private Sub UpdateJobsLabel() Private Overloads Sub UpdateJobsLabel()
RaiseEvent OnJobsChange(Count) UpdateJobsLabel(JobDefault)
UpdateJobsLabel(JobInst)
End Sub End Sub
Private _CurrentDownloadingTasks As Integer = 0 Private Overloads Sub UpdateJobsLabel(ByVal _Job As Job)
Private Sub DownloadData(ByVal Token As CancellationToken) RaiseEvent OnJobsChange(_Job.Site, _Job.Count)
End Sub
Private _InstagramNextWNM As Instagram.UserData.WNM = Instagram.UserData.WNM.Notify
Private Sub DownloadData(ByRef _Job As Job, ByVal Token As CancellationToken)
Try Try
If Items.Count > 0 Then If _Job.Count > 0 Then
Const nf As ANumbers.Formats = ANumbers.Formats.Number Const nf As ANumbers.Formats = ANumbers.Formats.Number
Dim t As New List(Of Task) Dim t As New List(Of Task)
Dim i% = -1 Dim i% = -1
Dim j% = Settings.MaxUsersJobsCount - 1 Dim j% = Settings.MaxUsersJobsCount - 1
Dim limit% = IIf(_Job.Site = Sites.Instagram, 1, j)
Dim Keys As New List(Of String) Dim Keys As New List(Of String)
Dim h As Boolean = False Dim h As Boolean = False
Dim InstaReady As Boolean = Settings(Sites.Instagram).InstagramReadyForDownload Dim InstaReady As Boolean = Settings(Sites.Instagram).InstagramReadyForDownload
For Each _Item As IUserData In Items For Each _Item As IUserData In _Job.Items
If Not _Item.Disposed Then If Not _Item.Disposed Then
Keys.Add(_Item.LVIKey) Keys.Add(_Item.LVIKey)
If Not _Item.Site = Sites.Instagram Or InstaReady Then If Not _Item.Site = Sites.Instagram Or InstaReady Then
If _Item.Site = Sites.Instagram Then h = True : Settings(Sites.Instagram).InstagramTooManyRequestsReadyForCatch = True If _Item.Site = Sites.Instagram Then
Token.ThrowIfCancellationRequested() h = True
With DirectCast(_Item, Instagram.UserData)
.WaitNotificationMode = _InstagramNextWNM
If Settings(Sites.Instagram).InstagramLastDownloadDate.Value < Now.AddMinutes(60) Then
.RequestsCount = Settings(Sites.Instagram).InstagramLastRequestsCount
End If
End With
End If
_Job.ThrowIfCancellationRequested()
t.Add(Task.Run(Sub() _Item.DownloadData(Token))) t.Add(Task.Run(Sub() _Item.DownloadData(Token)))
i += 1 i += 1
If i >= j Then Exit For If i >= limit Then Exit For
End If End If
End If End If
Next Next
@@ -112,38 +216,46 @@ Friend Class TDownloader : Implements IDisposable
If .InstaHash.IsEmptyString Or .InstaHashUpdateRequired Then .GatherInstaHash() If .InstaHash.IsEmptyString Or .InstaHashUpdateRequired Then .GatherInstaHash()
End With End With
End If End If
_CurrentDownloadingTasks = t.Count With _Job.Progress
With MainProgress
.Enabled(EOptions.All) = True .Enabled(EOptions.All) = True
.Information = $"Downloading {_CurrentDownloadingTasks.NumToString(nf, NProv)}/{Items.Count.NumToString(nf, NProv)} profiles' data" .Information = IIf(_Job.IsInstagram, "Instagram d", "D")
.Information &= $"ownloading {t.Count.NumToString(nf, NProv)}/{_Job.Items.Count.NumToString(nf, NProv)} profiles' data"
.InformationTemporary = .Information .InformationTemporary = .Information
End With End With
If t.Count > 0 Then Task.WaitAll(t.ToArray) If t.Count > 0 Then Task.WaitAll(t.ToArray)
Dim dcc As Boolean = False Dim dcc As Boolean = False
If Keys.Count > 0 Then If Keys.Count > 0 Then
For Each k$ In Keys For Each k$ In Keys
i = Items.FindIndex(Function(ii) ii.LVIKey = k) i = _Job.Items.FindIndex(Function(ii) ii.LVIKey = k)
If i >= 0 Then If i >= 0 Then
With Items(i) With _Job.Items(i)
If _Job.Site = Sites.Instagram Then
With DirectCast(.Self, Instagram.UserData)
_InstagramNextWNM = .WaitNotificationMode
If _InstagramNextWNM = Instagram.UserData.WNM.SkipTemp Or _InstagramNextWNM = Instagram.UserData.WNM.SkipCurrent Then _
_InstagramNextWNM = Instagram.UserData.WNM.Notify
Settings(Sites.Instagram).InstagramLastRequestsCount.Value = .RequestsCount
End With
End If
If Not .Disposed AndAlso Not .IsCollection AndAlso .DownloadedTotal(False) > 0 Then If Not .Disposed AndAlso Not .IsCollection AndAlso .DownloadedTotal(False) > 0 Then
If Not Downloaded.Contains(.Self) Then Downloaded.Add(GetUserFromMainCollection(.Self)) If Not Downloaded.Contains(.Self) Then Downloaded.Add(GetUserFromMainCollection(.Self))
dcc = True dcc = True
End If End If
End With End With
Items.RemoveAt(i) _Job.Items.RemoveAt(i)
End If End If
Next Next
End If End If
Keys.Clear() Keys.Clear()
Items.RemoveAll(Function(ii) ii.Disposed) _Job.Items.RemoveAll(Function(ii) ii.Disposed)
If dcc Then Downloaded.RemoveAll(Function(u) u Is Nothing) If dcc Then Downloaded.RemoveAll(Function(u) u Is Nothing)
If dcc And Downloaded.Count > 0 Then RaiseEvent OnDownloadCountChange() If dcc And Downloaded.Count > 0 Then RaiseEvent OnDownloadCountChange()
t.Clear() t.Clear()
End If End If
End If End If
Catch aoex As ArgumentOutOfRangeException Catch aoex As ArgumentOutOfRangeException
ErrorsDescriber.Execute(EDP.SendInLog, aoex, $"TDownloader.DownloadData: index out of range ({Count})") ErrorsDescriber.Execute(EDP.SendInLog, aoex, $"TDownloader.DownloadData: index out of range ({_Job.Count})")
Catch oex As OperationCanceledException When Token.IsCancellationRequested Catch oex As OperationCanceledException When _Job.IsCancellationRequested
Catch ex As Exception Catch ex As Exception
ErrorsDescriber.Execute(EDP.SendInLog, ex, "TDownloader.DownloadData") ErrorsDescriber.Execute(EDP.SendInLog, ex, "TDownloader.DownloadData")
Finally Finally
@@ -151,7 +263,7 @@ Friend Class TDownloader : Implements IDisposable
Task.WaitAll(Task.Run(Sub() Task.WaitAll(Task.Run(Sub()
While Settings.UserListUpdateRequired : Settings.UpdateUsersList() : End While While Settings.UserListUpdateRequired : Settings.UpdateUsersList() : End While
End Sub)) End Sub))
MainProgress.Enabled(EOptions.ProgressBar) = False If _Job.Site = Sites.Instagram Then Settings(Sites.Instagram).InstagramLastDownloadDate.Value = Now
End Try End Try
End Sub End Sub
Private Function GetUserFromMainCollection(ByVal User As IUserData) As IUserData Private Function GetUserFromMainCollection(ByVal User As IUserData) As IUserData
@@ -178,50 +290,37 @@ Friend Class TDownloader : Implements IDisposable
End If End If
Return Nothing Return Nothing
End Function End Function
#Region "Saved posts downloading" Private Sub AddItem(ByVal Item As IUserData, ByVal _UpdateJobsLabel As Boolean)
Friend ReadOnly Property SavedPostsDownloading As Boolean If Not Contains(Item) Then
Get If Item.IsCollection Then
Return If(_SavedPostsThread?.IsAlive, False) Item.DownloadData(Nothing)
End Get ElseIf Item.Site = Sites.Instagram Then
End Property JobInst.Items.Add(Item)
Private _SavedPostsThread As Thread If _UpdateJobsLabel Then UpdateJobsLabel(JobInst)
Friend Sub DownloadSavedPostsStart(ByVal Toolbar As StatusStrip, ByVal PR As ToolStripProgressBar)
If Not SavedPostsDownloading Then
If Settings(Sites.Reddit).SavedPostsUserName.IsEmptyString Then
MsgBoxE($"Username of saved posts not set{vbNewLine}Operation canceled", MsgBoxStyle.Critical)
Else Else
_SavedPostsThread = New Thread(New ThreadStart(Sub() Reddit.ProfileSaved.Download(Toolbar, PR))) JobDefault.Items.Add(Item)
_SavedPostsThread.SetApartmentState(ApartmentState.MTA) If _UpdateJobsLabel Then UpdateJobsLabel(JobDefault)
_SavedPostsThread.Start()
End If End If
Else
MsgBoxE("Saved posts are already downloading", MsgBoxStyle.Exclamation)
End If End If
End Sub End Sub
Friend Sub DownloadSavedPostsStop()
Try
If SavedPostsDownloading Then _SavedPostsThread.Abort()
Catch ex As Exception
End Try
End Sub
#End Region
Friend Sub Add(ByVal Item As IUserData) Friend Sub Add(ByVal Item As IUserData)
If Not Items.Contains(Item) Then AddItem(Item, True)
If Item.IsCollection Then Item.DownloadData(Nothing) Else Items.Add(Item) If JobDefault.Count > 0 Or JobInst.Count > 0 Then Start()
UpdateJobsLabel()
End If
If Items.Count > 0 Then Start()
End Sub End Sub
Friend Sub AddRange(ByVal _Items As IEnumerable(Of IUserData)) Friend Sub AddRange(ByVal _Items As IEnumerable(Of IUserData))
If _Items.ListExists Then If _Items.ListExists Then
For i% = 0 To _Items.Count - 1 For i% = 0 To _Items.Count - 1 : AddItem(_Items(i), False) : Next
'If i = 5 Then UpdateJobsLabel() : Start()
If _Items(i).IsCollection Then _Items(i).DownloadData(Nothing) Else Items.Add(_Items(i))
Next
UpdateJobsLabel() UpdateJobsLabel()
End If End If
If Items.Count > 0 Then Start() If JobDefault.Count > 0 Or JobInst.Count > 0 Then Start()
End Sub End Sub
Private Function Contains(ByVal _Item As IUserData)
If _Item.Site = Sites.Instagram Then
Return JobInst.Items.Contains(_Item)
Else
Return JobDefault.Items.Contains(_Item)
End If
End Function
Friend Sub UserRemove(ByVal _Item As IUserData) Friend Sub UserRemove(ByVal _Item As IUserData)
If Downloaded.Count > 0 AndAlso Downloaded.Contains(_Item) Then Downloaded.Remove(_Item) : RaiseEvent OnDownloadCountChange() If Downloaded.Count > 0 AndAlso Downloaded.Contains(_Item) Then Downloaded.Remove(_Item) : RaiseEvent OnDownloadCountChange()
End Sub End Sub
@@ -231,7 +330,8 @@ Friend Class TDownloader : Implements IDisposable
If Not disposedValue Then If Not disposedValue Then
If disposing Then If disposing Then
[Stop]() [Stop]()
Items.Clear() JobDefault.Items.Clear()
JobInst.Items.Clear()
Downloaded.Clear() Downloaded.Clear()
End If End If
disposedValue = True disposedValue = True