diff --git a/Changelog.md b/Changelog.md index 0483056..d93f439 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,24 @@ +# 3.0.0.10 + +- Added + - **Downloading groups** + - **Download saved Twitter posts** (bookmarks) + - Ability to enable/disable progress form opening at the start of downloading + - Ability to enable/disable Info form opening at the start of downloading + - The ability to disable the opening of forms Info and Progress at the start of downloads if it was once closed + - Focusing the main window when opening Info or Progress forms + - Ability to execute a script/command when closing SCrawler + - Ability to execute a script/command after all downloads are completed + - Minor improvements +- Fixed + - Instagram tagged data not downloading (now requires one more parameter **x-csrftoken** to download tagged data) + - In some cases, Instagram Stories cannot be downloaded due to forbidden Windows characters + - Separate Instagram posts were not downloading via the Video Downloader form. + - In some cases, an Imgur video hosted on Reddit won't download + - Gfycat data not downloading from saved Reddit posts + - In some cases, the date and time are not added to the filename + - Unable to download photos from Twitter in full resolution (4K) + # 3.0.0.9 - Added diff --git a/ProgramScreenshots/GroupCreating.png b/ProgramScreenshots/GroupCreating.png new file mode 100644 index 0000000..eb476e3 Binary files /dev/null and b/ProgramScreenshots/GroupCreating.png differ diff --git a/ProgramScreenshots/MainWindowGroups.png b/ProgramScreenshots/MainWindowGroups.png new file mode 100644 index 0000000..225a380 Binary files /dev/null and b/ProgramScreenshots/MainWindowGroups.png differ diff --git a/ProgramScreenshots/SavedPosts.png b/ProgramScreenshots/SavedPosts.png index 81d12ce..09de824 100644 Binary files a/ProgramScreenshots/SavedPosts.png and b/ProgramScreenshots/SavedPosts.png differ diff --git a/ProgramScreenshots/SettingsGlobalBehavior.png b/ProgramScreenshots/SettingsGlobalBehavior.png index ec552f0..fa2ef58 100644 Binary files a/ProgramScreenshots/SettingsGlobalBehavior.png and b/ProgramScreenshots/SettingsGlobalBehavior.png differ diff --git a/SCrawler.Plugin.XVIDEOS/SiteSettings.vb b/SCrawler.Plugin.XVIDEOS/SiteSettings.vb index f79f6c7..84ff274 100644 --- a/SCrawler.Plugin.XVIDEOS/SiteSettings.vb +++ b/SCrawler.Plugin.XVIDEOS/SiteSettings.vb @@ -78,7 +78,7 @@ Public Class SiteSettings : Implements ISiteSettings If Not ACheck(SiteDomains.Value) Then SiteDomains.Value = DomainsDefault Domains.ListAddList(CStr(SiteDomains.Value).Split("|"), LAP.NotContainsOnly, LAP.ClearBeforeAdd) Domains.ListAddList(DomainsDefault.Split("|"), LAP.NotContainsOnly) - SiteDomains.Value = Domains.ListToString(, "|") + SiteDomains.Value = Domains.ListToString("|") _DomainsUpdateInProgress = False End If End Sub diff --git a/SCrawler/API/Base/UserDataBase.vb b/SCrawler/API/Base/UserDataBase.vb index d8c6692..0f51e3c 100644 --- a/SCrawler/API/Base/UserDataBase.vb +++ b/SCrawler/API/Base/UserDataBase.vb @@ -629,7 +629,7 @@ BlockNullPicture: x.Add(Name_ScriptUse, ScriptUse.BoolToInteger) x.Add(Name_ScriptData, ScriptData) x.Add(Name_CollectionName, CollectionName) - x.Add(Name_LabelsName, Labels.ListToString(, "|", EDP.ReturnValue)) + x.Add(Name_LabelsName, Labels.ListToString("|", EDP.ReturnValue)) x.Add(Name_DataMerging, DataMerging.BoolToInteger) LoadUserInformation_OptionalFields(x, False) @@ -765,7 +765,7 @@ BlockNullPicture: ReparseVideo(Token) ThrowAny(Token) - If _TempPostsList.Count > 0 And __SaveData Then TextSaver.SaveTextToFile(_TempPostsList.ListToString(, Environment.NewLine), MyFilePosts, True,, EDP.None) + If _TempPostsList.Count > 0 And __SaveData Then TextSaver.SaveTextToFile(_TempPostsList.ListToString(Environment.NewLine), MyFilePosts, True,, EDP.None) _ContentNew.ListAddList(_TempMediaList, LAP.ClearBeforeAdd) DownloadContent(Token) ThrowIfDisposed() @@ -913,6 +913,7 @@ BlockNullPicture: End Using End If End If + Catch iex As IndexOutOfRangeException When Disposed Catch oex As OperationCanceledException When Token.IsCancellationRequested Catch dex As ObjectDisposedException When Disposed Catch ex As Exception @@ -933,7 +934,7 @@ BlockNullPicture: Dim ff As SFile = Nothing Try If Not f.IsEmptyString AndAlso f.Exists Then - If Settings.FileReplaceNameByDate Then + If Settings.FileReplaceNameByDate Or Settings.FileAddTimeToFileName Then ff = f ff.Name = String.Format(FileDateAppenderPattern, f.Name, CStr(AConvert(Of String)(If(m.Post.Date, Now), FileDateAppenderProvider, String.Empty))) ff = SFile.Indexed_IndexFile(ff,, New NumberedFile(ff)) diff --git a/SCrawler/API/Instagram/SiteSettings.vb b/SCrawler/API/Instagram/SiteSettings.vb index 0e03fff..7988e9a 100644 --- a/SCrawler/API/Instagram/SiteSettings.vb +++ b/SCrawler/API/Instagram/SiteSettings.vb @@ -9,6 +9,7 @@ Imports SCrawler.API.Base Imports SCrawler.Plugin Imports SCrawler.Plugin.Attributes +Imports PersonalUtilities.Forms Imports PersonalUtilities.Tools Imports PersonalUtilities.Functions.XML Imports PersonalUtilities.Functions.XML.Base @@ -30,18 +31,27 @@ Namespace API.Instagram End Property #End Region #Region "Providers" - Private Class TimersChecker : Implements ICustomProvider + Private Class TimersChecker : Implements IFieldsCheckerProvider + Private Property ErrorMessage As String Implements IFieldsCheckerProvider.ErrorMessage + Private Property Name As String Implements IFieldsCheckerProvider.Name + Private Property TypeError As Boolean Implements IFieldsCheckerProvider.TypeError + Private ReadOnly LVProvider As New ANumbers With {.FormatOptions = ANumbers.Options.GroupIntegral} Private ReadOnly _LowestValue As Integer Friend Sub New(ByVal LowestValue As Integer) _LowestValue = LowestValue End Sub Private Function Convert(ByVal Value As Object, ByVal DestinationType As Type, ByVal Provider As IFormatProvider, Optional ByVal NothingArg As Object = Nothing, Optional ByVal e As ErrorsDescriber = Nothing) As Object Implements ICustomProvider.Convert - If ACheck(Of Integer)(Value) AndAlso CInt(Value) >= _LowestValue Then - Return Value + TypeError = False + ErrorMessage = String.Empty + If Not ACheck(Of Integer)(Value) Then + TypeError = True + ElseIf CInt(Value) < _LowestValue Then + ErrorMessage = $"The value of [{Name}] field must be greater than or equal to {_LowestValue.NumToString(LVProvider)}" Else - Return Nothing + Return Value End If + Return Nothing End Function Private Function GetFormat(ByVal FormatType As Type) As Object Implements IFormatProvider.GetFormat Throw New NotImplementedException() @@ -53,35 +63,37 @@ Namespace API.Instagram Friend ReadOnly Property Hash As PropertyValue Friend ReadOnly Property HashSavedPosts As PropertyValue - + + Friend ReadOnly Property CSRF_TOKEN As PropertyValue + Friend Property IG_APP_ID As PropertyValue - + Friend Property IG_WWW_CLAIM As PropertyValue - + Friend ReadOnly Property SavedPostsUserName As PropertyValue Friend ReadOnly Property StoriesAndTaggedReady As Boolean Get - Return ACheck(IG_APP_ID.Value) And ACheck(IG_WWW_CLAIM.Value) + Return ACheck(IG_APP_ID.Value) And ACheck(IG_WWW_CLAIM.Value) And ACheck(CSRF_TOKEN.Value) End Get End Property #End Region #Region "Download properties" Friend ReadOnly Property HashUpdateRequired As XMLValue(Of Boolean) - + Friend ReadOnly Property RequestsWaitTimer As PropertyValue Private ReadOnly Property RequestsWaitTimerProvider As IFormatProvider - + Friend ReadOnly Property RequestsWaitTimerTaskCount As PropertyValue Private ReadOnly Property RequestsWaitTimerTaskCountProvider As IFormatProvider - + Friend ReadOnly Property SleepTimerOnPostsLimit As PropertyValue Private ReadOnly Property SleepTimerOnPostsLimitProvider As IFormatProvider - + Friend ReadOnly Property GetStories As PropertyValue - + Friend ReadOnly Property GetTagged As PropertyValue #End Region #Region "429 bypass" @@ -119,7 +131,7 @@ Namespace API.Instagram LastApplyingValue = If(LastApplyingValue, 0) + 10 TooManyRequestsReadyForCatch = False MyMainLOG = $"Instagram downloading error: too many requests. Try again after {If(LastApplyingValue, 10)} minutes..." - End If + End If End If Else .ValueF = Nothing @@ -136,11 +148,13 @@ Namespace API.Instagram Dim app_id$ = String.Empty Dim www_claim$ = String.Empty + Dim token$ = String.Empty With Responser If .File.Exists Then .LoadSettings() With .Headers + If .ContainsKey(Header_CSRF_TOKEN) Then token = .Item(Header_CSRF_TOKEN) If .ContainsKey(Header_IG_APP_ID) Then app_id = .Item(Header_IG_APP_ID) If .ContainsKey(Header_IG_WWW_CLAIM) Then www_claim = .Item(Header_IG_WWW_CLAIM) End With @@ -157,6 +171,7 @@ Namespace API.Instagram HashUpdateRequired = New XMLValue(Of Boolean)("InstaHashUpdateRequired", True, _XML, n) Hash = New PropertyValue(String.Empty, GetType(String)) HashSavedPosts = New PropertyValue(String.Empty, GetType(String)) + CSRF_TOKEN = New PropertyValue(token, GetType(String), Sub(v) ChangeResponserFields(NameOf(CSRF_TOKEN), v)) IG_APP_ID = New PropertyValue(app_id, GetType(String), Sub(v) ChangeResponserFields(NameOf(IG_APP_ID), v)) IG_WWW_CLAIM = New PropertyValue(www_claim, GetType(String), Sub(v) ChangeResponserFields(NameOf(IG_WWW_CLAIM), v)) @@ -192,12 +207,14 @@ Namespace API.Instagram End Function Private Const Header_IG_APP_ID As String = "x-ig-app-id" Private Const Header_IG_WWW_CLAIM As String = "x-ig-www-claim" + Private Const Header_CSRF_TOKEN As String = "x-csrftoken" Private Sub ChangeResponserFields(ByVal PropName As String, ByVal Value As Object) If Not PropName.IsEmptyString Then Dim f$ = String.Empty Select Case PropName Case NameOf(IG_APP_ID) : f = Header_IG_APP_ID Case NameOf(IG_WWW_CLAIM) : f = Header_IG_WWW_CLAIM + Case NameOf(CSRF_TOKEN) : f = Header_CSRF_TOKEN End Select If Not f.IsEmptyString Then If Responser.Headers.Count > 0 AndAlso Responser.Headers.ContainsKey(f) Then Responser.Headers.Remove(f) @@ -303,7 +320,7 @@ Namespace API.Instagram End Try End Function Friend Overrides Function GetSpecialDataF(ByVal URL As String) As IEnumerable(Of UserMedia) - Return UserData.GetVideoInfo(URL, Responser) + Return UserData.GetVideoInfo(URL, Responser, Me) End Function Friend Overrides Sub UserOptions(ByRef Options As Object, ByVal OpenForm As Boolean) If Options Is Nothing OrElse Not TypeOf Options Is EditorExchangeOptions Then Options = New EditorExchangeOptions(Me) diff --git a/SCrawler/API/Instagram/UserData.vb b/SCrawler/API/Instagram/UserData.vb index a2a40e3..ea3fff5 100644 --- a/SCrawler/API/Instagram/UserData.vb +++ b/SCrawler/API/Instagram/UserData.vb @@ -14,6 +14,7 @@ Imports PersonalUtilities.Tools.WebDocuments.JSON Imports SCrawler.API.Base Imports System.Threading Imports System.Net +Imports System.Reflection Imports UTypes = SCrawler.API.Base.UserMedia.Types Namespace API.Instagram Friend Class UserData : Inherits UserDataBase @@ -262,8 +263,8 @@ Namespace API.Instagram TaggedCount = j.Value("total_count").FromXML(Of Integer)(0) TaggedChecked = True If TaggedCount > 200 Then - Dim a% = MsgBoxE({$"The number of tagged posts is {TaggedCount.NumToString(New ANumbers With { - .FormatOptions = ANumbers.Options.GroupIntegral})}" & vbCr & + Dim a% = MsgBoxE({$"The number of tagged posts by user [{ToString()}] is { _ + TaggedCount.NumToString(New ANumbers With {.FormatOptions = ANumbers.Options.GroupIntegral})}" & vbCr & "The tagged data download operation can take a long time.", "Too much tagged data"}, vbExclamation,,, {"Continue", New MsgBoxButton("Disable and cancel") With { @@ -277,11 +278,9 @@ Namespace API.Instagram End If End Select Else - If j.Value("status") = "ok" AndAlso j({"data", "user"}).XmlIfNothing.Count = 0 AndAlso _TempMediaList.Count = 0 Then - MySiteSettings.HashUpdateRequired.Value = True - UserExists = False - Throw New ExitException(_DownloadComplete) - End If + If j.Value("status") = "ok" AndAlso j({"data", "user"}).XmlIfNothing.Count = 0 AndAlso + _TempMediaList.Count = 0 AndAlso Section = Sections.Timeline Then _ + UserExists = False : Throw New ExitException(_DownloadComplete) End If End Using Else @@ -501,7 +500,7 @@ Namespace API.Instagram If StoriesList.ListExists Then tmpList = StoriesList.Take(5) If tmpList.ListExists Then - qStr = String.Format(ReqUrl, tmpList.Select(Function(q) $"reel_ids=highlight:{q}").ListToString(, "&")) + qStr = String.Format(ReqUrl, tmpList.Select(Function(q) $"reel_ids=highlight:{q}").ListToString("&")) r = Responser.GetResponse(qStr,, EDP.ThrowException) ThrowAny(Token) If Not r.IsEmptyString Then @@ -509,7 +508,7 @@ Namespace API.Instagram If j.Contains("reels") Then For Each jj In j("reels") i += 1 - sFolder = jj.Value("title") + sFolder = jj.Value("title").StringRemoveWinForbiddenSymbols storyID = jj.Value("id").Replace("highlight:", String.Empty) If sFolder.IsEmptyString Then sFolder = $"Story_{storyID}" If sFolder.IsEmptyString Then sFolder = $"Story_{i}" @@ -567,7 +566,7 @@ Namespace API.Instagram UserExists = False ElseIf Responser.StatusCode = HttpStatusCode.BadRequest Then HasError = True - MyMainLOG = "Instagram credentials have expired" + MyMainLOG = $"Instagram credentials have expired: {ToString()} [{s}]" MySiteSettings.HashUpdateRequired.Value = True ElseIf Responser.StatusCode = HttpStatusCode.Forbidden And s = Sections.Tagged Then Return 3 @@ -582,6 +581,7 @@ Namespace API.Instagram Return 1 Else MySiteSettings.HashUpdateRequired.Value = True + MyMainLOG = $"Instagram hash requested: {ToString()} [{s}]" If Not FromPE Then LogError(ex, Message) : HasError = True Return 0 End If @@ -596,12 +596,13 @@ Namespace API.Instagram m.SpecialFolder = SpecialFolder Return m End Function - Friend Shared Function GetVideoInfo(ByVal URL As String, ByVal r As Response) As IEnumerable(Of UserMedia) + Friend Shared Function GetVideoInfo(ByVal URL As String, ByVal r As Response, ByVal _Settings As SiteSettings) As IEnumerable(Of UserMedia) Try If Not URL.IsEmptyString AndAlso URL.Contains("instagram.com") Then Dim PID$ = RegexReplace(URL, RParams.DMS(".*?instagram.com/p/([_\w\d]+)", 1)) If Not PID.IsEmptyString Then Using t As New UserData + t.SetEnvironment(Settings(_Settings.GetType.GetCustomAttribute(Of Plugin.Attributes.Manifest)().GUID), Nothing, False, False) t.Responser = New Response t.Responser.Copy(r) t._SavedPostsIDs.Add(PID) diff --git a/SCrawler/API/Reddit/Channel.vb b/SCrawler/API/Reddit/Channel.vb index 584907d..3741b27 100644 --- a/SCrawler/API/Reddit/Channel.vb +++ b/SCrawler/API/Reddit/Channel.vb @@ -364,16 +364,16 @@ Namespace API.Reddit Dim l As New List(Of String) If Posts.Count > 0 Or PostsLatest.Count > 0 Then l.ListAddList((From p In PostsAll Where Not p.ID.IsEmptyString Select p.ID), LAP.NotContainsOnly) l.ListAddList(PostsNames, LAP.NotContainsOnly) - If l.Count > 0 Then TextSaver.SaveTextToFile(l.ListToString(, "|"), FilePosts, True,, EDP.SendInLog) + If l.Count > 0 Then TextSaver.SaveTextToFile(l.ListToString("|"), FilePosts, True,, EDP.SendInLog) End If Using x As New XmlFile With {.AllowSameNames = True, .Name = "Channel"} x.Add(Name_Name, Name) x.Add(Name_ID, ID) x.Add(Name_ViewMode, CInt(ViewMode)) x.Add(Name_ViewPeriod, CInt(ViewPeriod)) - x.Add(Name_UsersAdded, CountOfAddedUsers.ListToString(, "|")) - x.Add(Name_PostsDownloaded, CountOfLoadedPostsPerSession.ListToString(, "|")) - x.Add(Name_UsersExistent, ChannelExistentUserNames.ListToString(, "|")) + x.Add(Name_UsersAdded, CountOfAddedUsers.ListToString("|")) + x.Add(Name_PostsDownloaded, CountOfLoadedPostsPerSession.ListToString("|")) + x.Add(Name_UsersExistent, ChannelExistentUserNames.ListToString("|")) If Posts.Count > 0 Or PostsLatest.Count > 0 Then Dim tmpPostList As List(Of UserPost) = Nothing tmpPostList.ListAddList(Posts).ListAddList(PostsLatest) diff --git a/SCrawler/API/Reddit/M3U8.vb b/SCrawler/API/Reddit/M3U8.vb index 2b2ea8b..f9109c6 100644 --- a/SCrawler/API/Reddit/M3U8.vb +++ b/SCrawler/API/Reddit/M3U8.vb @@ -52,7 +52,7 @@ Namespace API.Reddit If Not r.IsEmptyString Then Dim lp As New ListAddParams(LAP.NotContainsOnly) With { .Converter = Function(input) $"{BaseUrl}/{input}", - .e = New ErrorsDescriber(False, False, True, New List(Of String))} + .Error = New ErrorsDescriber(False, False, True, New List(Of String))} Return ListAddList(Of String, List(Of String))(Nothing, DirectCast(RegexReplace(r, PlayListRegEx_2), List(Of String)), lp).ListIfNothing End If End If diff --git a/SCrawler/API/Reddit/SiteSettings.vb b/SCrawler/API/Reddit/SiteSettings.vb index 43d8c28..d6760d2 100644 --- a/SCrawler/API/Reddit/SiteSettings.vb +++ b/SCrawler/API/Reddit/SiteSettings.vb @@ -84,7 +84,7 @@ Namespace API.Reddit If avg > 100 Then Return MsgBoxE({"Over the past hour, Reddit has received an average of " & avg.NumToString(New ANumbers With {.FormatOptions = ANumbers.Options.GroupIntegral}) & " outage reports:" & vbCr & - dl.ListToString(, vbCr) & vbCr & vbCr & + dl.ListToString(vbCr) & vbCr & vbCr & "Do you want to continue parsing Reddit data?", "There are outage reports on Reddit"}, vbYesNo) = vbYes End If End If diff --git a/SCrawler/API/Reddit/UserData.vb b/SCrawler/API/Reddit/UserData.vb index 04d9c67..4c0cddc 100644 --- a/SCrawler/API/Reddit/UserData.vb +++ b/SCrawler/API/Reddit/UserData.vb @@ -348,7 +348,7 @@ Namespace API.Reddit End If tmpUrl = s.Value("url") - If Not tmpUrl.IsEmptyString AndAlso tmpUrl.Contains("redgifs.com") Then + If Not tmpUrl.IsEmptyString AndAlso tmpUrl.StringContains({"redgifs.com", "gfycat.com"}) Then If SaveToCache Then tmpUrl = s.Value({"media", "oembed"}, "thumbnail_url") If Not tmpUrl.IsEmptyString Then @@ -423,6 +423,8 @@ Namespace API.Reddit _TempMediaList.ListAddValue(MediaFromData(UTypes.Video, _URL.Replace(".gifv", ".mp4"), PostID, PostDate, _UserID, IsChannel), LNC) End If + ElseIf _URL.Contains(".mp4") Then + _TempMediaList.ListAddValue(MediaFromData(UTypes.Video, _URL, PostID, PostDate, _UserID, IsChannel), LNC) ElseIf _URL.Contains(".gif") Then _TempMediaList.ListAddValue(MediaFromData(UTypes.GIF, _URL, PostID, PostDate, _UserID, IsChannel), LNC) Else @@ -700,6 +702,7 @@ Namespace API.Reddit End Using End If End If + Catch iex As IndexOutOfRangeException When Disposed Catch oex As OperationCanceledException When Token.IsCancellationRequested Catch dex As ObjectDisposedException When Disposed Catch ex As Exception diff --git a/SCrawler/API/Twitter/SiteSettings.vb b/SCrawler/API/Twitter/SiteSettings.vb index 24de77d..c89bdbb 100644 --- a/SCrawler/API/Twitter/SiteSettings.vb +++ b/SCrawler/API/Twitter/SiteSettings.vb @@ -12,7 +12,7 @@ Imports PersonalUtilities.Tools Imports PersonalUtilities.Functions.RegularExpressions Imports SCrawler.API.Base Namespace API.Twitter - + Friend Class SiteSettings : Inherits SiteSettingsBase Friend Const Header_Authorization As String = "authorization" Friend Const Header_Token As String = "x-csrf-token" @@ -31,6 +31,8 @@ Namespace API.Twitter Private ReadOnly Property Auth As PropertyValue Private ReadOnly Property Token As PropertyValue + + Friend ReadOnly Property SavedPostsUserName As PropertyValue Friend Overrides ReadOnly Property Responser As WEB.Response Friend Sub New() MyBase.New(TwitterSite) @@ -70,6 +72,7 @@ Namespace API.Twitter Auth = New PropertyValue(a, GetType(String), Sub(v) ChangeResponserFields(NameOf(Auth), v)) Token = New PropertyValue(t, GetType(String), Sub(v) ChangeResponserFields(NameOf(Token), v)) + SavedPostsUserName = New PropertyValue(String.Empty, GetType(String)) UserRegex = RParams.DMS("[htps:/]{7,8}.*?twitter.com/([^/]+)", 1) UrlPatternUser = "https://twitter.com/{0}" @@ -90,7 +93,11 @@ Namespace API.Twitter End If End Sub Friend Overrides Function GetInstance(ByVal What As ISiteSettings.Download) As IPluginContentProvider - Return New UserData + If What = ISiteSettings.Download.SavedPosts Then + Return New UserData With {.IsSavedPosts = True, .User = New UserInfo With {.Name = CStr(AConvert(Of String)(SavedPostsUserName.Value, String.Empty))}} + Else + Return New UserData + End If End Function Friend Overrides Function GetSpecialDataF(ByVal URL As String) As IEnumerable(Of UserMedia) Return UserData.GetVideoInfo(URL, Responser) diff --git a/SCrawler/API/Twitter/UserData.vb b/SCrawler/API/Twitter/UserData.vb index 388577d..7fc9a4a 100644 --- a/SCrawler/API/Twitter/UserData.vb +++ b/SCrawler/API/Twitter/UserData.vb @@ -27,12 +27,19 @@ Namespace API.Twitter End Sub #Region "Download functions" Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken) - If _ContentList.Count > 0 Then _DataNames.ListAddList(_ContentList.Select(Function(c) c.File.File), LAP.ClearBeforeAdd, LAP.NotContainsOnly) - DownloadData(String.Empty, Token) + If IsSavedPosts Then + If _ContentList.Count > 0 Then _DataNames.ListAddList(_ContentList.Select(Function(c) c.Post.ID), LAP.ClearBeforeAdd, LAP.NotContainsOnly) + DownloadData(String.Empty, Token) + Else + If _ContentList.Count > 0 Then _DataNames.ListAddList(_ContentList.Select(Function(c) c.File.File), LAP.ClearBeforeAdd, LAP.NotContainsOnly) + DownloadData(String.Empty, Token) + End If End Sub Private Overloads Sub DownloadData(ByVal POST As String, ByVal Token As CancellationToken) Dim URL$ = String.Empty Try + Dim NextCursor$ = String.Empty + Dim __NextCursor As Predicate(Of EContainer) = Function(e) e.Value({"content", "operation", "cursor"}, "cursorType") = "Bottom" Dim PostID$ = String.Empty Dim PostDate$, dName$ Dim m As EContainer, nn As EContainer, s As EContainer @@ -42,24 +49,37 @@ Namespace API.Twitter Dim PicNode As Predicate(Of EContainer) = Function(e) e.Count > 0 AndAlso e.Contains("media_url") Dim UID As Func(Of EContainer, String) = Function(e) e.XmlIfNothing.Item({"user", "id"}).XmlIfNothingValue - URL = $"https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name={Name}&count=200&exclude_replies=false&include_rts=1&tweet_mode=extended" - If Not POST.IsEmptyString Then URL &= $"&max_id={POST}" + If IsSavedPosts Then + If Name.IsEmptyString Then Throw New ArgumentNullException With {.HelpLink = 1} + URL = $"https://api.twitter.com/2/timeline/bookmark.json?screen_name={Name}&count=200" & + "&tweet_mode=extended&include_entities=true&include_user_entities=true&include_ext_media_availability=true" + If Not POST.IsEmptyString Then URL &= $"&cursor={SymbolsConverter.ASCII.EncodeSymbolsOnly(POST)}" + Else + URL = $"https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name={Name}&count=200&exclude_replies=false&include_rts=1&tweet_mode=extended" + If Not POST.IsEmptyString Then URL &= $"&max_id={POST}" + End If ThrowAny(Token) Dim r$ = Responser.GetResponse(URL,, EDP.ThrowException) If Not r.IsEmptyString Then Using w As EContainer = JsonDocument.Parse(r) If Not w Is Nothing AndAlso w.Count > 0 Then - For Each nn In w + For Each nn In If(IsSavedPosts, w({"globalObjects", "tweets"}).XmlIfNothing, w) ThrowAny(Token) If nn.Count > 0 Then - PostID = nn.Value("id") - If ID.IsEmptyString Then - ID = UID(nn) - If Not ID.IsEmptyString Then UpdateUserInformation() + If IsSavedPosts Then + PostID = nn.Value + If PostID.IsEmptyString Then PostID = nn.Value("id_str") + Else + PostID = nn.Value("id") + If ID.IsEmptyString Then + ID = UID(nn) + If Not ID.IsEmptyString Then UpdateUserInformation() + End If End If - If UserDescriptionNeedToUpdate() AndAlso nn.Value({"user"}, "screen_name") = Name Then UserDescriptionUpdate(nn.Value({"user"}, "description")) + If Not IsSavedPosts AndAlso UserDescriptionNeedToUpdate() AndAlso nn.Value({"user"}, "screen_name") = Name Then _ + UserDescriptionUpdate(nn.Value({"user"}, "description")) 'Date Pattern: 'Sat Jan 01 01:10:15 +0000 2000 @@ -74,8 +94,8 @@ Namespace API.Twitter Continue For End If - If Not ParseUserMediaOnly OrElse (Not nn.Contains("retweeted_status") OrElse - (Not ID.IsEmptyString AndAlso UID(nn("retweeted_status")) = ID)) Then + If IsSavedPosts OrElse Not ParseUserMediaOnly OrElse (Not nn.Contains("retweeted_status") OrElse + (Not ID.IsEmptyString AndAlso UID(nn("retweeted_status")) = ID)) Then If Not CheckVideoNode(nn, PostID, PostDate) Then s = nn.ItemF({"extended_entities", "media"}) If s Is Nothing OrElse s.Count = 0 Then s = nn.ItemF({"retweeted_status", "extended_entities", "media"}) @@ -95,13 +115,25 @@ Namespace API.Twitter End If End If Next + + If IsSavedPosts Then + s = w.ItemF({"timeline", "instructions", 0, "addEntries", "entries"}).XmlIfNothing + If s.Count > 0 Then NextCursor = If(s.ItemF({__NextCursor})?.Value({"content", "operation", "cursor"}, "value"), String.Empty) + End If End If End Using - If POST.IsEmptyString And ExistsDetected Then Exit Sub - If Not PostID.IsEmptyString And NewPostDetected Then DownloadData(PostID, Token) + + If IsSavedPosts Then + If Not NextCursor.IsEmptyString And Not NextCursor = POST Then DownloadData(NextCursor, Token) + Else + If POST.IsEmptyString And ExistsDetected Then Exit Sub + If Not PostID.IsEmptyString And NewPostDetected Then DownloadData(PostID, Token) + End If End If + Catch ane As ArgumentNullException When ane.HelpLink = 1 + MyMainLOG = "Username not set for saved Twitter posts" Catch ex As Exception - ProcessException(ex, Token, $"data downloading error [{URL}]") + ProcessException(ex, Token, $"data downloading error{IIf(IsSavedPosts, " (Saved Posts)", String.Empty)} [{URL}]") End Try End Sub Friend Shared Function GetVideoInfo(ByVal URL As String, ByVal resp As Response) As IEnumerable(Of UserMedia) @@ -128,20 +160,34 @@ Namespace API.Twitter End Function #Region "Picture options" Private Function GetPictureOption(ByVal w As EContainer) As String + Const P4K As String = "4096x4096" Try Dim ww As EContainer = w("sizes") If Not ww Is Nothing AndAlso ww.Count > 0 Then Dim l As New List(Of Sizes) + Dim Orig As Sizes? = New Sizes(w.Value({"original_info"}, "height").FromXML(Of Integer)(-1), P4K) + If Orig.Value.Value = -1 Then Orig = Nothing Dim LargeContained As Boolean = ww.Contains("large") For Each v As EContainer In ww If v.Count > 0 AndAlso v.Contains("h") Then l.Add(New Sizes(v.Value("h"), v.Name)) Next If l.Count > 0 Then l.Sort() - If l(0).Data.IsEmptyString And LargeContained Then Return "large" Else Return l(0).Data + If Orig.HasValue AndAlso l(0).Value < Orig.Value.Value Then + Return P4K + ElseIf l(0).Data.IsEmptyString Then + If LargeContained Then Return "large" Else Return P4K + Else + Return l(0).Data + End If + Else + Return P4K End If + ElseIf Not w.Value({"original_info"}, "height").IsEmptyString Then + Return P4K + Else + Return String.Empty End If - Return String.Empty Catch ex As Exception LogError(ex, "[API.Twitter.UserData.GetPictureOption]") Return String.Empty diff --git a/SCrawler/Channels/ChannelViewForm.vb b/SCrawler/Channels/ChannelViewForm.vb index 66b4694..f031241 100644 --- a/SCrawler/Channels/ChannelViewForm.vb +++ b/SCrawler/Channels/ChannelViewForm.vb @@ -284,7 +284,7 @@ Friend Class ChannelViewForm : Implements IChannelLimits Private Sub AppendPendingUsers() If LIST_POSTS.CheckedIndices.Count > 0 Then Dim c As Channel = GetCurrentChannel(False) - Dim lp As New ListAddParams(LAP.NotContainsOnly) With {.OnAddAction = Sub(ByVal u As PendingUser) u.ChannelUserAdded()} + Dim lp As New ListAddParams(LAP.NotContainsOnly) With {.OnProcessAction = Sub(ByVal u As PendingUser) u.ChannelUserAdded()} PendingUsers.ListAddList((From p As ListViewItem In LIST_POSTS.Items Where p.Checked Select New PendingUser(p.Text, c, GetPostBySelected(CStr(p.Tag)).CachedFile)), lp) diff --git a/SCrawler/Channels/ChannelsStatsForm.vb b/SCrawler/Channels/ChannelsStatsForm.vb index 7447d08..65f183c 100644 --- a/SCrawler/Channels/ChannelsStatsForm.vb +++ b/SCrawler/Channels/ChannelsStatsForm.vb @@ -57,9 +57,9 @@ Friend Class ChannelsStatsForm : Implements IOkCancelDeleteToolbar Try Dim c As List(Of String) = CMB_CHANNELS.Items.CheckedItems.Select(Function(cc) CStr(cc.Value(1))).ListIfNothing If c.ListExists Then - If MsgBoxE({$"The following channels will be deleted:{vbCr}{c.ListToString(, vbCr)}", "Deleting channels"}, vbExclamation,,, {"Confirm", "Cancel"}) = 0 Then + If MsgBoxE({$"The following channels will be deleted:{vbCr}{c.ListToString(vbCr)}", "Deleting channels"}, vbExclamation,,, {"Confirm", "Cancel"}) = 0 Then For Each CID$ In c : Settings.Channels.Remove(Settings.Channels.Find(CID)) : Next - MyMainLOG = $"Deleted channels:{vbNewLine}{c.ListToString(, vbNewLine)}" + MyMainLOG = $"Deleted channels:{vbNewLine}{c.ListToString(vbNewLine)}" MsgBoxE("Channels deleted") DeletedChannels += c.Count c.Clear() diff --git a/SCrawler/Content/Icons/GroupBy_284.ico b/SCrawler/Content/Icons/GroupBy_284.ico new file mode 100644 index 0000000..f849cba Binary files /dev/null and b/SCrawler/Content/Icons/GroupBy_284.ico differ diff --git a/SCrawler/Download/ActiveDownloadingProgress.vb b/SCrawler/Download/ActiveDownloadingProgress.vb index 06cc470..67e4890 100644 --- a/SCrawler/Download/ActiveDownloadingProgress.vb +++ b/SCrawler/Download/ActiveDownloadingProgress.vb @@ -12,7 +12,12 @@ Namespace DownloadObjects Friend Class ActiveDownloadingProgress Private Const MinWidth As Integer = 450 Private MyView As FormsView - Friend Property Opened As Boolean = False + Private Opened As Boolean = False + Friend ReadOnly Property ReadyToOpen As Boolean + Get + Return Settings.DownloadOpenProgress And (Not Opened Or Settings.DownloadOpenProgress.Attribute) And Not Visible + End Get + End Property Private ReadOnly JobsList As List(Of DownloadProgress) Friend Property DisableProgressChange As Boolean = False Friend Sub New() diff --git a/SCrawler/Download/DownloadedInfoForm.vb b/SCrawler/Download/DownloadedInfoForm.vb index 406780d..f791985 100644 --- a/SCrawler/Download/DownloadedInfoForm.vb +++ b/SCrawler/Download/DownloadedInfoForm.vb @@ -13,7 +13,13 @@ Namespace DownloadObjects Friend Class DownloadedInfoForm Friend Event OnUserLooking(ByVal Key As String) Private MyView As FormsView - Private ReadOnly LParams As New ListAddParams(LAP.IgnoreICopier) With {.e = EDP.None} + Private ReadOnly LParams As New ListAddParams(LAP.IgnoreICopier) With {.Error = EDP.None} + Private Opened As Boolean = False + Friend ReadOnly Property ReadyToOpen As Boolean + Get + Return Settings.DownloadOpenInfo And (Not Opened Or Settings.DownloadOpenInfo.Attribute) And Not Visible + End Get + End Property Friend Enum ViewModes As Integer Session = 0 All = 1 @@ -50,6 +56,8 @@ Namespace DownloadObjects BTT_CLEAR.Visible = ViewMode = ViewModes.Session RefillList() Catch ex As Exception + Finally + Opened = True End Try End Sub Private Sub DownloadedInfoForm_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing diff --git a/SCrawler/Download/Groups/DownloadGroup.vb b/SCrawler/Download/Groups/DownloadGroup.vb new file mode 100644 index 0000000..e5194fc --- /dev/null +++ b/SCrawler/Download/Groups/DownloadGroup.vb @@ -0,0 +1,211 @@ +' 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.Functions.XML.Base +Imports SCrawler.API +Imports SCrawler.API.Base +Namespace DownloadObjects.Groups + Friend Class DownloadGroup : Implements IIndexable, IEContainerProvider, IDisposable + Friend Delegate Sub GroupEventHandler(ByVal Sender As DownloadGroup) + Friend Event Deleted As GroupEventHandler + Friend Event Updated As GroupEventHandler +#Region "XML Names" + Private Const Name_Name As String = "Name" + Private Const Name_Temporary As String = "Temporary" + Private Const Name_Favorite As String = "Favorite" + Private Const Name_ReadyForDownload As String = "RFD" + Private Const Name_ReadyForDownloadIgnore As String = "RFDI" +#End Region + Private WithEvents BTT_EDIT As ToolStripMenuItem + Private WithEvents BTT_DELETE As ToolStripMenuItem + Private WithEvents BTT_DOWNLOAD As ToolStripMenuItem + Private WithEvents BTT_DOWNLOAD_FULL As ToolStripMenuItem + Private ReadOnly SEP_1 As ToolStripSeparator + Private WithEvents BTT_MENU As ToolStripMenuItem + Friend Property Temporary As CheckState = CheckState.Indeterminate + Friend Property Favorite As CheckState = CheckState.Indeterminate + Friend Property ReadyForDownload As Boolean = True + Friend Property ReadyForDownloadIgnore As Boolean = False + Friend Property Name As String + Private _Key As String = String.Empty + Friend ReadOnly Property Key As String + Get + If _Key.IsEmptyString Then _Key = $"{Name}{Index}" + Return _Key + End Get + End Property + Private _Index As Integer = 0 + Friend Property Index As Integer Implements IIndexable.Index + Get + Return _Index + End Get + Set(ByVal NewIndex As Integer) + Dim b As Boolean = Not _Index = NewIndex + _Index = NewIndex + If b Then RaiseEvent Updated(Me) + End Set + End Property + Friend ReadOnly Property Labels As List(Of String) + Friend ReadOnly Property Count As Integer + Get + Return Labels.Count + End Get + End Property + Friend Sub New() + Labels = New List(Of String) + BTT_MENU = New ToolStripMenuItem With { + .ToolTipText = "Download users of this group", + .AutoToolTip = True, + .Image = My.Resources.GroupBy_284.ToBitmap + } + BTT_DELETE = New ToolStripMenuItem With { + .Image = PersonalUtilities.My.Resources.DeletePic_02_Red_24, + .BackColor = ColorBttDeleteBack, + .ForeColor = ColorBttDeleteFore, + .Text = "Delete", + .ToolTipText = String.Empty, + .AutoToolTip = False + } + BTT_EDIT = New ToolStripMenuItem With { + .Image = PersonalUtilities.My.Resources.PencilPic_01_48, + .BackColor = ColorBttEditBack, + .ForeColor = ColorBttEditFore, + .Text = "Edit", + .ToolTipText = String.Empty, + .AutoToolTip = False + } + SEP_1 = New ToolStripSeparator + BTT_DOWNLOAD = New ToolStripMenuItem With { + .Image = My.Resources.StartPic_01_Green_16, + .Text = "Download", + .ToolTipText = "Download users of this group (respect the 'Ready for download' parameter)", + .AutoToolTip = True + } + BTT_DOWNLOAD_FULL = New ToolStripMenuItem With { + .Image = My.Resources.StartPic_01_Green_16, + .Text = "Download FULL", + .ToolTipText = "Download users of this group (ignore the 'Ready for download' parameter)", + .AutoToolTip = True + } + BTT_MENU.DropDownItems.AddRange({BTT_EDIT, BTT_DELETE, SEP_1, BTT_DOWNLOAD, BTT_DOWNLOAD_FULL}) + End Sub + Friend Sub New(ByVal e As EContainer) + Me.New + Name = e.Attribute(Name_Name) + Temporary = e.Attribute(Name_Temporary).Value.FromXML(Of Integer)(CInt(CheckState.Indeterminate)) + Favorite = e.Attribute(Name_Favorite).Value.FromXML(Of Integer)(CInt(CheckState.Indeterminate)) + ReadyForDownload = e.Attribute(Name_ReadyForDownload).Value.FromXML(Of Boolean)(True) + ReadyForDownloadIgnore = e.Attribute(Name_ReadyForDownloadIgnore).Value.FromXML(Of Boolean)(False) + If Not e.Value.IsEmptyString Then Labels.ListAddList(e.Value.Split("|"), LAP.NotContainsOnly) + End Sub + Public Overrides Function ToString() As String + Return $"{IIf(Index >= 0 And Index <= 8, $"#{Index + 1}: ", String.Empty)}{Name}" + End Function + Private _ControlSent As Boolean = False + Friend Function GetControl() As ToolStripMenuItem + If Not _ControlSent Then + BTT_MENU.Text = ToString() + BTT_MENU.Tag = Key + _ControlSent = True + End If + Return BTT_MENU + End Function + Private Function SetIndex(ByVal Obj As Object, ByVal _Index As Integer) As Object Implements IIndexable.SetIndex + DirectCast(Obj, DownloadGroup).Index = _Index + Return Obj + End Function +#Region "Buttons" + Private Sub BTT_MENU_Click(sender As Object, e As EventArgs) Handles BTT_MENU.Click + DownloadUsers(True) + End Sub + Private Sub BTT_EDIT_Click(sender As Object, e As EventArgs) Handles BTT_EDIT.Click + Using f As New GroupEditorForm(Me) + f.ShowDialog() + If f.DialogResult = DialogResult.OK Then RaiseEvent Updated(Me) + End Using + End Sub + Private Sub BTT_DELETE_Click(sender As Object, e As EventArgs) Handles BTT_DELETE.Click + If MsgBoxE({$"Are you sure you want to delete the [{Name}] group?", "Deleting a group"}, vbExclamation + vbYesNo) = vbYes Then + RaiseEvent Deleted(Me) + MsgBoxE({$"Group [{Name}] deleted", "Deleting a group"}) + End If + End Sub + Private Sub BTT_DOWNLOAD_Click(sender As Object, e As EventArgs) Handles BTT_DOWNLOAD.Click + DownloadUsers(True) + End Sub + Private Sub BTT_DOWNLOAD_FULL_Click(sender As Object, e As EventArgs) Handles BTT_DOWNLOAD_FULL.Click + DownloadUsers(False) + End Sub + Friend Sub DownloadUsers(ByVal UseReadyOption As Boolean) + Try + If Settings.Users.Count > 0 Then + Dim CheckParams As Predicate(Of IUserData) = Function(user) _ + (Temporary = CheckState.Indeterminate Or user.Temporary = CBool(Temporary)) And + (Favorite = CheckState.Indeterminate Or (user.Favorite = CBool(Favorite))) And + (Not UseReadyOption Or ReadyForDownloadIgnore Or user.ReadyForDownload = ReadyForDownload) + Dim f As Func(Of IUserData, IEnumerable(Of IUserData)) = Function(ByVal user As IUserData) As IEnumerable(Of IUserData) + If user.IsCollection Then + With DirectCast(user, UserDataBind) + If Count > 0 Then Return .Collections.SelectMany(f) + End With + Else + If Labels.Count = 0 OrElse user.Labels.ListContains(Labels) Then + If CheckParams.Invoke(user) Then Return {user} + End If + End If + Return New IUserData() {} + End Function + Dim u As IEnumerable(Of IUserData) = Settings.Users.SelectMany(f) + If u.ListExists Then + Downloader.AddRange(u) + Else + MsgBoxE({$"No users found for group [{Name}].", "No users found"}, vbExclamation) + End If + End If + Catch ex As Exception + ErrorsDescriber.Execute(EDP.SendInLog, ex, "[DownloadGroup.DownloadUsers]") + End Try + End Sub +#End Region +#Region "IEContainerProvider Support" + Public Function ToEContainer(Optional ByVal e As ErrorsDescriber = Nothing) As EContainer Implements IEContainerProvider.ToEContainer + Return New EContainer("Group", Labels.ListToString("|"), {New EAttribute(Name_Name, Name), + New EAttribute(Name_Temporary, CInt(Temporary)), + New EAttribute(Name_Favorite, CInt(Favorite)), + New EAttribute(Name_ReadyForDownload, ReadyForDownload.BoolToInteger), + New EAttribute(Name_ReadyForDownloadIgnore, ReadyForDownloadIgnore.BoolToInteger)}) + End Function +#End Region +#Region "IDisposable Support" + Private disposedValue As Boolean = False + Protected Overridable Overloads Sub Dispose(ByVal disposing As Boolean) + If Not disposedValue Then + If disposing Then + Labels.Clear() + BTT_DELETE.Dispose() + BTT_EDIT.Dispose() + BTT_MENU.Dispose() + SEP_1.Dispose() + BTT_DOWNLOAD.Dispose() + BTT_DOWNLOAD_FULL.Dispose() + End If + disposedValue = True + End If + End Sub + Protected Overrides Sub Finalize() + Dispose(False) + MyBase.Finalize() + End Sub + Friend Overloads Sub Dispose() Implements IDisposable.Dispose + Dispose(True) + GC.SuppressFinalize(Me) + End Sub +#End Region + End Class +End Namespace \ No newline at end of file diff --git a/SCrawler/Download/Groups/DownloadGroupCollection.vb b/SCrawler/Download/Groups/DownloadGroupCollection.vb new file mode 100644 index 0000000..02b8c4c --- /dev/null +++ b/SCrawler/Download/Groups/DownloadGroupCollection.vb @@ -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 +Namespace DownloadObjects.Groups + Friend Class DownloadGroupCollection : Implements IEnumerable(Of DownloadGroup), IMyEnumerator(Of DownloadGroup) + Friend Event Deleted As DownloadGroup.GroupEventHandler + Friend Event Added As DownloadGroup.GroupEventHandler + Friend Event Updated As DownloadGroup.GroupEventHandler + Private ReadOnly GroupsList As List(Of DownloadGroup) + Private ReadOnly GroupFile As SFile = "Settings\Groups.xml" + Friend Sub New() + GroupsList = New List(Of DownloadGroup) + If GroupFile.Exists Then + Using x As New XmlFile(GroupFile,, False) With {.XmlReadOnly = True, .AllowSameNames = True} + x.LoadData() + If x.Count > 0 Then GroupsList.ListAddList(x, LAP.IgnoreICopier) + End Using + If GroupsList.Count > 0 Then GroupsList.ForEach(Sub(ByVal g As DownloadGroup) + AddHandler g.Deleted, AddressOf OnGroupDeleted + AddHandler g.Updated, AddressOf OnGroupUpdated + End Sub) + End If + GroupsList.ListReindex + End Sub + Friend Function GetLabels() As List(Of String) + Return ListAddList(Nothing, GroupsList.SelectMany(Function(g) g.Labels), LAP.NotContainsOnly) + End Function + Default Friend ReadOnly Property Item(ByVal Index As Integer) As DownloadGroup Implements IMyEnumerator(Of DownloadGroup).MyEnumeratorObject + Get + Return GroupsList(Index) + End Get + End Property + Friend ReadOnly Property Count As Integer Implements IMyEnumerator(Of DownloadGroup).MyEnumeratorCount + Get + Return GroupsList.Count + End Get + End Property + Friend Sub Update() + If Count > 0 Then + Using x As New XmlFile With {.Name = "Groups", .AllowSameNames = True} + x.AddRange(GroupsList) + x.Save(GroupFile) + End Using + Else + GroupFile.Delete() + End If + End Sub + Private Sub OnGroupUpdated(ByVal Sender As DownloadGroup) + Update() + RaiseEvent Updated(Sender) + End Sub + Private Sub OnGroupDeleted(ByVal Sender As DownloadGroup) + RaiseEvent Deleted(Sender) + Dim i% = GroupsList.FindIndex(Function(g) g.Key = Sender.Key) + If i >= 0 Then + GroupsList(i).Dispose() + GroupsList.RemoveAt(i) + GroupsList.ListReindex + Update() + End If + End Sub + Friend Sub Add() + Using f As New GroupEditorForm(Nothing) + f.ShowDialog() + If f.DialogResult = DialogResult.OK Then + GroupsList.Add(f.MyGroup) + GroupsList.ListReindex + RaiseEvent Added(GroupsList.Last) + Update() + End If + End Using + End Sub + Friend Function DownloadGroupIfExists(ByVal Index As Integer) As Boolean + If Index.ValueBetween(0, Count - 1) Then Item(Index).DownloadUsers(True) : Return True Else Return False + End Function + Private Function GetEnumerator() As IEnumerator(Of DownloadGroup) Implements IEnumerable(Of DownloadGroup).GetEnumerator + Return New MyEnumerator(Of DownloadGroup)(Me) + End Function + Private Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator + Return GetEnumerator() + End Function + End Class +End Namespace \ No newline at end of file diff --git a/SCrawler/Download/Groups/GroupEditorForm.Designer.vb b/SCrawler/Download/Groups/GroupEditorForm.Designer.vb new file mode 100644 index 0000000..9100646 --- /dev/null +++ b/SCrawler/Download/Groups/GroupEditorForm.Designer.vb @@ -0,0 +1,253 @@ +' Copyright (C) 2022 Andy +' This program is free software: you can redistribute it and/or modify +' it under the terms of the GNU General Public License as published by +' the Free Software Foundation, either version 3 of the License, or +' (at your option) any later version. +' +' This program is distributed in the hope that it will be useful, +' but WITHOUT ANY WARRANTY +Namespace DownloadObjects.Groups + + Partial Friend Class GroupEditorForm : Inherits System.Windows.Forms.Form + + 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 + + Private Sub InitializeComponent() + Dim CONTAINER_MAIN As System.Windows.Forms.ToolStripContainer + Dim TP_MAIN As System.Windows.Forms.TableLayoutPanel + Dim ActionButton7 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() + Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(GroupEditorForm)) + Dim ActionButton8 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() + Dim ActionButton9 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() + Dim TP_TEMP_FAV As System.Windows.Forms.TableLayoutPanel + Dim TP_READY_FOR_DOWN As System.Windows.Forms.TableLayoutPanel + Me.TXT_NAME = New PersonalUtilities.Forms.Controls.TextBoxExtended() + Me.TXT_LABELS = New PersonalUtilities.Forms.Controls.TextBoxExtended() + Me.CH_TEMPORARY = New System.Windows.Forms.CheckBox() + Me.CH_FAV = New System.Windows.Forms.CheckBox() + Me.CH_READY_FOR_DOWN = New System.Windows.Forms.CheckBox() + Me.CH_READY_FOR_DOWN_IGNORE = New System.Windows.Forms.CheckBox() + CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer() + TP_MAIN = New System.Windows.Forms.TableLayoutPanel() + TP_TEMP_FAV = New System.Windows.Forms.TableLayoutPanel() + TP_READY_FOR_DOWN = New System.Windows.Forms.TableLayoutPanel() + CONTAINER_MAIN.ContentPanel.SuspendLayout() + CONTAINER_MAIN.SuspendLayout() + TP_MAIN.SuspendLayout() + CType(Me.TXT_NAME, System.ComponentModel.ISupportInitialize).BeginInit() + CType(Me.TXT_LABELS, System.ComponentModel.ISupportInitialize).BeginInit() + TP_TEMP_FAV.SuspendLayout() + TP_READY_FOR_DOWN.SuspendLayout() + Me.SuspendLayout() + ' + 'CONTAINER_MAIN + ' + ' + 'CONTAINER_MAIN.ContentPanel + ' + CONTAINER_MAIN.ContentPanel.Controls.Add(TP_MAIN) + CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(476, 111) + CONTAINER_MAIN.Dock = System.Windows.Forms.DockStyle.Fill + CONTAINER_MAIN.LeftToolStripPanelVisible = False + CONTAINER_MAIN.Location = New System.Drawing.Point(0, 0) + CONTAINER_MAIN.Name = "CONTAINER_MAIN" + CONTAINER_MAIN.RightToolStripPanelVisible = False + CONTAINER_MAIN.Size = New System.Drawing.Size(476, 136) + CONTAINER_MAIN.TabIndex = 0 + CONTAINER_MAIN.TopToolStripPanelVisible = False + ' + 'TP_MAIN + ' + TP_MAIN.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single] + TP_MAIN.ColumnCount = 1 + TP_MAIN.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + TP_MAIN.Controls.Add(TP_READY_FOR_DOWN, 0, 2) + TP_MAIN.Controls.Add(Me.TXT_NAME, 0, 0) + TP_MAIN.Controls.Add(Me.TXT_LABELS, 0, 3) + TP_MAIN.Controls.Add(TP_TEMP_FAV, 0, 1) + TP_MAIN.Dock = System.Windows.Forms.DockStyle.Fill + TP_MAIN.Location = New System.Drawing.Point(0, 0) + TP_MAIN.Name = "TP_MAIN" + TP_MAIN.RowCount = 5 + TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) + TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) + TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) + TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) + TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20.0!)) + TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20.0!)) + TP_MAIN.Size = New System.Drawing.Size(476, 111) + TP_MAIN.TabIndex = 0 + ' + 'TXT_NAME + ' + ActionButton7.BackgroundImage = CType(resources.GetObject("ActionButton7.BackgroundImage"), System.Drawing.Image) + ActionButton7.Index = 0 + ActionButton7.Name = "BTT_CLEAR" + Me.TXT_NAME.Buttons.Add(ActionButton7) + Me.TXT_NAME.CaptionText = "Name" + Me.TXT_NAME.CaptionToolTipEnabled = True + Me.TXT_NAME.CaptionToolTipText = "Group name" + Me.TXT_NAME.CaptionWidth = 50.0R + Me.TXT_NAME.Dock = System.Windows.Forms.DockStyle.Fill + Me.TXT_NAME.Location = New System.Drawing.Point(4, 4) + Me.TXT_NAME.Name = "TXT_NAME" + Me.TXT_NAME.Size = New System.Drawing.Size(468, 22) + Me.TXT_NAME.TabIndex = 0 + ' + 'TXT_LABELS + ' + ActionButton8.BackgroundImage = CType(resources.GetObject("ActionButton8.BackgroundImage"), System.Drawing.Image) + ActionButton8.Index = 0 + ActionButton8.Name = "BTT_EDIT" + ActionButton9.BackgroundImage = CType(resources.GetObject("ActionButton9.BackgroundImage"), System.Drawing.Image) + ActionButton9.Index = 1 + ActionButton9.Name = "BTT_CLEAR" + Me.TXT_LABELS.Buttons.Add(ActionButton8) + Me.TXT_LABELS.Buttons.Add(ActionButton9) + Me.TXT_LABELS.CaptionText = "Labels" + Me.TXT_LABELS.CaptionToolTipEnabled = True + Me.TXT_LABELS.CaptionToolTipText = "Group labels" + Me.TXT_LABELS.CaptionWidth = 50.0R + Me.TXT_LABELS.ClearTextByButtonClear = False + Me.TXT_LABELS.Dock = System.Windows.Forms.DockStyle.Fill + Me.TXT_LABELS.Location = New System.Drawing.Point(4, 85) + Me.TXT_LABELS.Name = "TXT_LABELS" + Me.TXT_LABELS.Size = New System.Drawing.Size(468, 22) + Me.TXT_LABELS.TabIndex = 1 + ' + 'TP_TEMP_FAV + ' + TP_TEMP_FAV.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single] + TP_TEMP_FAV.ColumnCount = 2 + TP_TEMP_FAV.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!)) + TP_TEMP_FAV.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!)) + TP_TEMP_FAV.Controls.Add(Me.CH_TEMPORARY, 0, 0) + TP_TEMP_FAV.Controls.Add(Me.CH_FAV, 1, 0) + TP_TEMP_FAV.Dock = System.Windows.Forms.DockStyle.Fill + TP_TEMP_FAV.Location = New System.Drawing.Point(1, 30) + TP_TEMP_FAV.Margin = New System.Windows.Forms.Padding(0) + TP_TEMP_FAV.Name = "TP_TEMP_FAV" + TP_TEMP_FAV.RowCount = 1 + TP_TEMP_FAV.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + TP_TEMP_FAV.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20.0!)) + TP_TEMP_FAV.Size = New System.Drawing.Size(474, 25) + TP_TEMP_FAV.TabIndex = 2 + ' + 'TP_READY_FOR_DOWN + ' + TP_READY_FOR_DOWN.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single] + TP_READY_FOR_DOWN.ColumnCount = 2 + TP_READY_FOR_DOWN.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!)) + TP_READY_FOR_DOWN.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!)) + TP_READY_FOR_DOWN.Controls.Add(Me.CH_READY_FOR_DOWN, 0, 0) + TP_READY_FOR_DOWN.Controls.Add(Me.CH_READY_FOR_DOWN_IGNORE, 1, 0) + TP_READY_FOR_DOWN.Dock = System.Windows.Forms.DockStyle.Fill + TP_READY_FOR_DOWN.Location = New System.Drawing.Point(1, 56) + TP_READY_FOR_DOWN.Margin = New System.Windows.Forms.Padding(0) + TP_READY_FOR_DOWN.Name = "TP_READY_FOR_DOWN" + TP_READY_FOR_DOWN.RowCount = 1 + TP_READY_FOR_DOWN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + TP_READY_FOR_DOWN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20.0!)) + TP_READY_FOR_DOWN.Size = New System.Drawing.Size(474, 25) + TP_READY_FOR_DOWN.TabIndex = 3 + ' + 'CH_TEMPORARY + ' + Me.CH_TEMPORARY.AutoSize = True + Me.CH_TEMPORARY.Checked = True + Me.CH_TEMPORARY.CheckState = System.Windows.Forms.CheckState.Indeterminate + Me.CH_TEMPORARY.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_TEMPORARY.Location = New System.Drawing.Point(4, 4) + Me.CH_TEMPORARY.Name = "CH_TEMPORARY" + Me.CH_TEMPORARY.Size = New System.Drawing.Size(229, 17) + Me.CH_TEMPORARY.TabIndex = 0 + Me.CH_TEMPORARY.Text = "Temporary" + Me.CH_TEMPORARY.ThreeState = True + Me.CH_TEMPORARY.UseVisualStyleBackColor = True + ' + 'CH_FAV + ' + Me.CH_FAV.AutoSize = True + Me.CH_FAV.Checked = True + Me.CH_FAV.CheckState = System.Windows.Forms.CheckState.Indeterminate + Me.CH_FAV.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_FAV.Location = New System.Drawing.Point(240, 4) + Me.CH_FAV.Name = "CH_FAV" + Me.CH_FAV.Size = New System.Drawing.Size(230, 17) + Me.CH_FAV.TabIndex = 1 + Me.CH_FAV.Text = "Favorite" + Me.CH_FAV.ThreeState = True + Me.CH_FAV.UseVisualStyleBackColor = True + ' + 'CH_READY_FOR_DOWN + ' + Me.CH_READY_FOR_DOWN.AutoSize = True + Me.CH_READY_FOR_DOWN.Checked = True + Me.CH_READY_FOR_DOWN.CheckState = System.Windows.Forms.CheckState.Checked + Me.CH_READY_FOR_DOWN.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_READY_FOR_DOWN.Location = New System.Drawing.Point(4, 4) + Me.CH_READY_FOR_DOWN.Name = "CH_READY_FOR_DOWN" + Me.CH_READY_FOR_DOWN.Size = New System.Drawing.Size(229, 17) + Me.CH_READY_FOR_DOWN.TabIndex = 0 + Me.CH_READY_FOR_DOWN.Text = "Ready for download" + Me.CH_READY_FOR_DOWN.UseVisualStyleBackColor = True + ' + 'CH_READY_FOR_DOWN_IGNORE + ' + Me.CH_READY_FOR_DOWN_IGNORE.AutoSize = True + Me.CH_READY_FOR_DOWN_IGNORE.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_READY_FOR_DOWN_IGNORE.Location = New System.Drawing.Point(240, 4) + Me.CH_READY_FOR_DOWN_IGNORE.Name = "CH_READY_FOR_DOWN_IGNORE" + Me.CH_READY_FOR_DOWN_IGNORE.Size = New System.Drawing.Size(230, 17) + Me.CH_READY_FOR_DOWN_IGNORE.TabIndex = 1 + Me.CH_READY_FOR_DOWN_IGNORE.Text = "Ignore ready for download" + Me.CH_READY_FOR_DOWN_IGNORE.UseVisualStyleBackColor = True + ' + 'GroupEditorForm + ' + Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!) + Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font + Me.ClientSize = New System.Drawing.Size(476, 136) + Me.Controls.Add(CONTAINER_MAIN) + Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle + Me.KeyPreview = True + Me.MaximizeBox = False + Me.MaximumSize = New System.Drawing.Size(492, 175) + Me.MinimizeBox = False + Me.MinimumSize = New System.Drawing.Size(492, 175) + Me.Name = "GroupEditorForm" + Me.ShowIcon = False + Me.ShowInTaskbar = False + Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide + Me.Text = "Group" + CONTAINER_MAIN.ContentPanel.ResumeLayout(False) + CONTAINER_MAIN.ResumeLayout(False) + CONTAINER_MAIN.PerformLayout() + TP_MAIN.ResumeLayout(False) + CType(Me.TXT_NAME, System.ComponentModel.ISupportInitialize).EndInit() + CType(Me.TXT_LABELS, System.ComponentModel.ISupportInitialize).EndInit() + TP_TEMP_FAV.ResumeLayout(False) + TP_TEMP_FAV.PerformLayout() + TP_READY_FOR_DOWN.ResumeLayout(False) + TP_READY_FOR_DOWN.PerformLayout() + Me.ResumeLayout(False) + + End Sub + Private WithEvents TXT_NAME As PersonalUtilities.Forms.Controls.TextBoxExtended + Private WithEvents TXT_LABELS As PersonalUtilities.Forms.Controls.TextBoxExtended + Private WithEvents CH_READY_FOR_DOWN As CheckBox + Private WithEvents CH_READY_FOR_DOWN_IGNORE As CheckBox + Private WithEvents CH_TEMPORARY As CheckBox + Private WithEvents CH_FAV As CheckBox + End Class +End Namespace \ No newline at end of file diff --git a/SCrawler/Download/Groups/GroupEditorForm.resx b/SCrawler/Download/Groups/GroupEditorForm.resx new file mode 100644 index 0000000..8feac98 --- /dev/null +++ b/SCrawler/Download/Groups/GroupEditorForm.resx @@ -0,0 +1,207 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + False + + + False + + + False + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go + tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX + AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAACH + DwAAjA8AAP1SAACBQAAAfXkAAOmLAAA85QAAGcxzPIV3AAAKOWlDQ1BQaG90b3Nob3AgSUNDIHByb2Zp + bGUAAEjHnZZ3VFTXFofPvXd6oc0w0hl6ky4wgPQuIB0EURhmBhjKAMMMTWyIqEBEEREBRZCggAGjoUis + iGIhKKhgD0gQUGIwiqioZEbWSnx5ee/l5ffHvd/aZ+9z99l7n7UuACRPHy4vBZYCIJkn4Ad6ONNXhUfQ + sf0ABniAAaYAMFnpqb5B7sFAJC83F3q6yAn8i94MAUj8vmXo6U+ng/9P0qxUvgAAyF/E5mxOOkvE+SJO + yhSkiu0zIqbGJIoZRomZL0pQxHJijlvkpZ99FtlRzOxkHlvE4pxT2clsMfeIeHuGkCNixEfEBRlcTqaI + b4tYM0mYzBXxW3FsMoeZDgCKJLYLOKx4EZuImMQPDnQR8XIAcKS4LzjmCxZwsgTiQ7mkpGbzuXHxArou + S49uam3NoHtyMpM4AoGhP5OVyOSz6S4pyalMXjYAi2f+LBlxbemiIluaWltaGpoZmX5RqP+6+Dcl7u0i + vQr43DOI1veH7a/8UuoAYMyKarPrD1vMfgA6tgIgd/8Pm+YhACRFfWu/8cV5aOJ5iRcIUm2MjTMzM424 + HJaRuKC/6386/A198T0j8Xa/l4fuyollCpMEdHHdWClJKUI+PT2VyeLQDf88xP848K/zWBrIieXwOTxR + RKhoyri8OFG7eWyugJvCo3N5/6mJ/zDsT1qca5Eo9Z8ANcoISN2gAuTnPoCiEAESeVDc9d/75oMPBeKb + F6Y6sTj3nwX9+65wifiRzo37HOcSGExnCfkZi2viawnQgAAkARXIAxWgAXSBITADVsAWOAI3sAL4gWAQ + DtYCFogHyYAPMkEu2AwKQBHYBfaCSlAD6kEjaAEnQAc4DS6Ay+A6uAnugAdgBIyD52AGvAHzEARhITJE + geQhVUgLMoDMIAZkD7lBPlAgFA5FQ3EQDxJCudAWqAgqhSqhWqgR+hY6BV2ArkID0D1oFJqCfoXewwhM + gqmwMqwNG8MM2An2hoPhNXAcnAbnwPnwTrgCroOPwe3wBfg6fAcegZ/DswhAiAgNUUMMEQbigvghEUgs + wkc2IIVIOVKHtCBdSC9yCxlBppF3KAyKgqKjDFG2KE9UCIqFSkNtQBWjKlFHUe2oHtQt1ChqBvUJTUYr + oQ3QNmgv9Cp0HDoTXYAuRzeg29CX0HfQ4+g3GAyGhtHBWGE8MeGYBMw6TDHmAKYVcx4zgBnDzGKxWHms + AdYO64dlYgXYAux+7DHsOewgdhz7FkfEqeLMcO64CBwPl4crxzXhzuIGcRO4ebwUXgtvg/fDs/HZ+BJ8 + Pb4LfwM/jp8nSBN0CHaEYEICYTOhgtBCuER4SHhFJBLVidbEACKXuIlYQTxOvEIcJb4jyZD0SS6kSJKQ + tJN0hHSedI/0ikwma5MdyRFkAXknuZF8kfyY/FaCImEk4SXBltgoUSXRLjEo8UISL6kl6SS5VjJHslzy + pOQNyWkpvJS2lIsUU2qDVJXUKalhqVlpirSptJ90snSxdJP0VelJGayMtoybDFsmX+awzEWZMQpC0aC4 + UFiULZR6yiXKOBVD1aF6UROoRdRvqP3UGVkZ2WWyobJZslWyZ2RHaAhNm+ZFS6KV0E7QhmjvlygvcVrC + WbJjScuSwSVzcopyjnIcuUK5Vrk7cu/l6fJu8onyu+U75B8poBT0FQIUMhUOKlxSmFakKtoqshQLFU8o + 3leClfSVApXWKR1W6lOaVVZR9lBOVd6vfFF5WoWm4qiSoFKmclZlSpWiaq/KVS1TPaf6jC5Ld6In0Svo + PfQZNSU1TzWhWq1av9q8uo56iHqeeqv6Iw2CBkMjVqNMo1tjRlNV01czV7NZ874WXouhFa+1T6tXa05b + RztMe5t2h/akjpyOl06OTrPOQ12yroNumm6d7m09jB5DL1HvgN5NfVjfQj9ev0r/hgFsYGnANThgMLAU + vdR6KW9p3dJhQ5Khk2GGYbPhqBHNyMcoz6jD6IWxpnGE8W7jXuNPJhYmSSb1Jg9MZUxXmOaZdpn+aqZv + xjKrMrttTjZ3N99o3mn+cpnBMs6yg8vuWlAsfC22WXRbfLS0suRbtlhOWWlaRVtVWw0zqAx/RjHjijXa + 2tl6o/Vp63c2ljYCmxM2v9ga2ibaNtlOLtdZzllev3zMTt2OaVdrN2JPt4+2P2Q/4qDmwHSoc3jiqOHI + dmxwnHDSc0pwOub0wtnEme/c5jznYuOy3uW8K+Lq4Vro2u8m4xbiVun22F3dPc692X3Gw8Jjncd5T7Sn + t+duz2EvZS+WV6PXzAqrFetX9HiTvIO8K72f+Oj78H26fGHfFb57fB+u1FrJW9nhB/y8/Pb4PfLX8U/z + /z4AE+AfUBXwNNA0MDewN4gSFBXUFPQm2Dm4JPhBiG6IMKQ7VDI0MrQxdC7MNaw0bGSV8ar1q66HK4Rz + wzsjsBGhEQ0Rs6vdVu9dPR5pEVkQObRGZ03WmqtrFdYmrT0TJRnFjDoZjY4Oi26K/sD0Y9YxZ2O8Yqpj + ZlgurH2s52xHdhl7imPHKeVMxNrFlsZOxtnF7YmbineIL4+f5rpwK7kvEzwTahLmEv0SjyQuJIUltSbj + kqOTT/FkeIm8nhSVlKyUgVSD1ILUkTSbtL1pM3xvfkM6lL4mvVNAFf1M9Ql1hVuFoxn2GVUZbzNDM09m + SWfxsvqy9bN3ZE/kuOd8vQ61jrWuO1ctd3Pu6Hqn9bUboA0xG7o3amzM3zi+yWPT0c2EzYmbf8gzySvN + e70lbEtXvnL+pvyxrR5bmwskCvgFw9tst9VsR23nbu/fYb5j/45PhezCa0UmReVFH4pZxde+Mv2q4quF + nbE7+0ssSw7uwuzi7Rra7bD7aKl0aU7p2B7fPe1l9LLCstd7o/ZeLV9WXrOPsE+4b6TCp6Jzv+b+Xfs/ + VMZX3qlyrmqtVqreUT13gH1g8KDjwZYa5ZqimveHuIfu1nrUttdp15UfxhzOOPy0PrS+92vG140NCg1F + DR+P8I6MHA082tNo1djYpNRU0gw3C5unjkUeu/mN6zedLYYtta201qLj4Ljw+LNvo78dOuF9ovsk42TL + d1rfVbdR2grbofbs9pmO+I6RzvDOgVMrTnV32Xa1fW/0/ZHTaqerzsieKTlLOJt/duFczrnZ86nnpy/E + XRjrjup+cHHVxds9AT39l7wvXbnsfvlir1PvuSt2V05ftbl66hrjWsd1y+vtfRZ9bT9Y/NDWb9nffsPq + RudN65tdA8sHzg46DF645Xrr8m2v29fvrLwzMBQydHc4cnjkLvvu5L2key/vZ9yff7DpIfph4SOpR+WP + lR7X/aj3Y+uI5ciZUdfRvidBTx6Mscae/5T+04fx/Kfkp+UTqhONk2aTp6fcp24+W/1s/Hnq8/npgp+l + f65+ofviu18cf+mbWTUz/pL/cuHX4lfyr468Xva6e9Z/9vGb5Dfzc4Vv5d8efcd41/s+7P3EfOYH7IeK + j3ofuz55f3q4kLyw8Bv3hPP74uYdwgAAAAlwSFlzAAALEwAACxMBAJqcGAAAAahJREFUOE9j+P//P8l4 + vaOjPYyNIYkPO1lZsa1wdNy42sHh3Hxb22KQGFaF2LC4qjjroUP7n97s6vx/Ny/3/ypn54+LbGwisSpG + x+aaouwZren/u5f2/3/18tX/qzNn/l/i4XGSgYFBFasGZKwjzcJ6YVnU152blvw3LHH53zCl/ufatWu+ + T+1vDALJY9UEwxrijExHZgd+/Xy1Hcg98BNkCMglMM0gjKEJhuX5GVh2TvD+/O5c0///P9b///qo819P + lgmKZhBG0QTDMjwMzJs7XT+9OVHz///XFf+/PWj7j00zCKNwQFiah4FtXbPjp8d78////7bo/4/79Tg1 + gzAKR1mUg3lOocXbe9uz/v9/M/H/1zuVeDWDMJwhJcDBvK4p4tb1DQn//r/u+f/zRh5BzSAMZyyrdVh9 + c33B9//32159vZr2hxjNIAwm1GUE3e+ur/n9/+Ls/592Nf9fUun3khjNIMzAysTAv6g6+OT/E33/j09N + +zWpMuImsZpBmMHIQK9x19T8/03x1ufE+TkqsCnChxmUlFWuyEpJtAHTtT42BfjxfwYAtlm0ShMkSB4A + AAAASUVORK5CYII= + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go + tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX + AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC + + + + False + + \ No newline at end of file diff --git a/SCrawler/Download/Groups/GroupEditorForm.vb b/SCrawler/Download/Groups/GroupEditorForm.vb new file mode 100644 index 0000000..b5b4e3b --- /dev/null +++ b/SCrawler/Download/Groups/GroupEditorForm.vb @@ -0,0 +1,111 @@ +' Copyright (C) 2022 Andy +' This program is free software: you can redistribute it and/or modify +' it under the terms of the GNU General Public License as published by +' the Free Software Foundation, either version 3 of the License, or +' (at your option) any later version. +' +' This program is distributed in the hope that it will be useful, +' but WITHOUT ANY WARRANTY +Imports PersonalUtilities.Forms +Imports PersonalUtilities.Forms.Controls.Base +Imports PersonalUtilities.Forms.Toolbars +Namespace DownloadObjects.Groups + Friend Class GroupEditorForm : Implements IOkCancelToolbar + Private ReadOnly MyDefs As DefaultFormProps + Friend Property MyGroup As DownloadGroup + Private ReadOnly MyLabels As List(Of String) + Friend Sub New(ByRef g As DownloadGroup) + InitializeComponent() + MyGroup = g + MyLabels = New List(Of String) + If Not MyGroup Is Nothing Then MyLabels.ListAddList(MyGroup.Labels) + MyDefs = New DefaultFormProps + End Sub + Private Class NameChecker : Implements IFieldsCheckerProvider + Private Property ErrorMessage As String Implements IFieldsCheckerProvider.ErrorMessage + Private Property Name As String Implements IFieldsCheckerProvider.Name + Private Property TypeError As Boolean Implements IFieldsCheckerProvider.TypeError + Private ReadOnly ExistingGroupName As String + Friend Sub New(ByVal _ExistingGroupName As String) + ExistingGroupName = _ExistingGroupName + 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 Not ACheck(Value) Then + ErrorMessage = "Group name cannot be empty" + ElseIf Not ExistingGroupName.IsEmptyString AndAlso CStr(Value) = ExistingGroupName Then + Return Value + ElseIf Settings.Groups.Count > 0 AndAlso Settings.Groups.LongCount(Function(g) g.Name = CStr(Value)) > 0 Then + ErrorMessage = "A group with the same name already exists" + Else + Return Value + End If + Return Nothing + 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 + Private Sub GroupEditorForm_Load(sender As Object, e As EventArgs) Handles Me.Load + With MyDefs + .MyViewInitialize(Me, Settings.Design, True) + .AddOkCancelToolbar() + .DelegateClosingChecker() + If Not MyGroup Is Nothing Then + With MyGroup + TXT_NAME.Text = .Name + CH_TEMPORARY.CheckState = .Temporary + CH_FAV.CheckState = .Favorite + CH_READY_FOR_DOWN.Checked = .ReadyForDownload + CH_READY_FOR_DOWN_IGNORE.Checked = .ReadyForDownloadIgnore + TXT_LABELS.Text = MyLabels.ListToString + Text &= $" { .Name}" + End With + Else + Text = "New Group" + End If + .MyFieldsChecker = New FieldsChecker + DirectCast(.MyFieldsChecker, FieldsChecker).AddControl(Of String)(TXT_NAME, TXT_NAME.CaptionText,, New NameChecker(If(MyGroup?.Name, String.Empty))) + .MyFieldsChecker.EndLoaderOperations() + .AppendDetectors() + .EndLoaderOperations() + End With + End Sub + Private Sub GroupEditorForm_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed + MyLabels.Clear() + End Sub + Private Sub ToolbarBttOK() Implements IOkCancelToolbar.ToolbarBttOK + If MyDefs.MyFieldsChecker.AllParamsOK Then + If MyGroup Is Nothing Then MyGroup = New DownloadGroup + With MyGroup + .Name = TXT_NAME.Text + .Temporary = CH_TEMPORARY.CheckState + .Favorite = CH_FAV.CheckState + .ReadyForDownload = CH_READY_FOR_DOWN.Checked + .ReadyForDownloadIgnore = CH_READY_FOR_DOWN_IGNORE.Checked + .Labels.ListAddList(MyLabels, LAP.ClearBeforeAdd, LAP.NotContainsOnly) + End With + MyDefs.CloseForm() + End If + End Sub + Private Sub ToolbarBttCancel() Implements IOkCancelToolbar.ToolbarBttCancel + MyDefs.CloseForm(DialogResult.Cancel) + End Sub + Private Sub TXT_LABELS_ActionOnButtonClick(ByVal Sender As ActionButton) Handles TXT_LABELS.ActionOnButtonClick + Select Case Sender.DefaultButton + Case ActionButton.DefaultButtons.Edit + Using f As New LabelsForm(MyLabels) + f.ShowDialog() + If f.DialogResult = DialogResult.OK Then + MyLabels.ListAddList(f.LabelsList, LAP.NotContainsOnly, LAP.ClearBeforeAdd) + TXT_LABELS.Clear() + TXT_LABELS.Text = MyLabels.ListToString + End If + End Using + Case ActionButton.DefaultButtons.Clear + MyLabels.Clear() + TXT_LABELS.Clear() + End Select + End Sub + End Class +End Namespace \ No newline at end of file diff --git a/SCrawler/Download/TDownloader.vb b/SCrawler/Download/TDownloader.vb index 2e4881a..09b94f2 100644 --- a/SCrawler/Download/TDownloader.vb +++ b/SCrawler/Download/TDownloader.vb @@ -206,14 +206,15 @@ Namespace DownloadObjects End Sub Private CheckerThread As Thread Private Sub [Start]() - If Not MyProgressForm.Opened AndAlso Pool.LongCount(Function(p) p.Count > 0) > 1 Then MyProgressForm.Show() + If MyProgressForm.ReadyToOpen AndAlso Pool.LongCount(Function(p) p.Count > 0) > 1 Then MyProgressForm.Show() : MainFrameObj.Focus() If Not If(CheckerThread?.IsAlive, False) Then MainProgress.Enabled = True + If InfoForm.ReadyToOpen Then InfoForm.Show() : MainFrameObj.Focus() CheckerThread = New Thread(New ThreadStart(AddressOf JobsChecker)) CheckerThread.SetApartmentState(ApartmentState.MTA) CheckerThread.Start() End If - End Sub + End Sub Private Sub JobsChecker() Try MainProgress.TotalCount = 0 @@ -235,6 +236,7 @@ Namespace DownloadObjects End With MyProgressForm.DisableProgressChange = True If Pool.Count > 0 Then Pool.ForEach(Sub(p) If Not p.Progress Is Nothing Then p.Progress.TotalCount = 0) + ExecuteCommand(Settings.DownloadsCompleteCommand) End Try End Sub Private Sub StartDownloading(ByRef _Job As Job) diff --git a/SCrawler/Download/VideosDownloaderForm.vb b/SCrawler/Download/VideosDownloaderForm.vb index 21fa905..0f5eb42 100644 --- a/SCrawler/Download/VideosDownloaderForm.vb +++ b/SCrawler/Download/VideosDownloaderForm.vb @@ -63,7 +63,7 @@ Namespace DownloadObjects End Sub Private Sub UpdateUrlsFile() If UrlList.Count > 0 Then - TextSaver.SaveTextToFile(UrlList.ListToString(, Environment.NewLine), DownloadingUrlsFile, True,, EDP.SendInLog) + TextSaver.SaveTextToFile(UrlList.ListToString(Environment.NewLine), DownloadingUrlsFile, True,, EDP.SendInLog) Else DownloadingUrlsFile.Delete(, Settings.DeleteMode, EDP.SendInLog) End If diff --git a/SCrawler/Editors/GlobalSettingsForm.Designer.vb b/SCrawler/Editors/GlobalSettingsForm.Designer.vb index 07465ca..24f9080 100644 --- a/SCrawler/Editors/GlobalSettingsForm.Designer.vb +++ b/SCrawler/Editors/GlobalSettingsForm.Designer.vb @@ -41,6 +41,8 @@ Dim TP_DOWNLOADING As System.Windows.Forms.TableLayoutPanel Dim ActionButton8 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Dim ActionButton9 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() + Dim TP_OPEN_INFO As System.Windows.Forms.TableLayoutPanel + Dim TP_OPEN_PROGRESS As System.Windows.Forms.TableLayoutPanel Me.TXT_GLOBAL_PATH = New PersonalUtilities.Forms.Controls.TextBoxExtended() Me.TXT_IMAGE_LARGE = New PersonalUtilities.Forms.Controls.TextBoxExtended() Me.TXT_IMAGE_SMALL = New PersonalUtilities.Forms.Controls.TextBoxExtended() @@ -75,9 +77,15 @@ Me.CH_CLOSE_TO_TRAY = New System.Windows.Forms.CheckBox() Me.CH_SHOW_NOTIFY = New System.Windows.Forms.CheckBox() Me.CH_RECYCLE_DEL = New System.Windows.Forms.CheckBox() + Me.CH_DOWN_OPEN_INFO = New System.Windows.Forms.CheckBox() + Me.CH_DOWN_OPEN_PROGRESS = New System.Windows.Forms.CheckBox() + Me.TXT_CLOSE_SCRIPT = New PersonalUtilities.Forms.Controls.TextBoxExtended() Me.TXT_SCRIPT = New PersonalUtilities.Forms.Controls.TextBoxExtended() + Me.TXT_DOWN_COMPLETE_SCRIPT = New PersonalUtilities.Forms.Controls.TextBoxExtended() Me.TAB_MAIN = New System.Windows.Forms.TabControl() Me.CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer() + Me.CH_DOWN_OPEN_INFO_SUSPEND = New System.Windows.Forms.CheckBox() + Me.CH_DOWN_OPEN_PROGRESS_SUSPEND = New System.Windows.Forms.CheckBox() TP_BASIS = New System.Windows.Forms.TableLayoutPanel() TP_IMAGES = New System.Windows.Forms.TableLayoutPanel() TP_FILE_NAME = New System.Windows.Forms.TableLayoutPanel() @@ -94,6 +102,8 @@ TP_BEHAVIOR = New System.Windows.Forms.TableLayoutPanel() TAB_DOWN = New System.Windows.Forms.TabPage() TP_DOWNLOADING = New System.Windows.Forms.TableLayoutPanel() + TP_OPEN_INFO = New System.Windows.Forms.TableLayoutPanel() + TP_OPEN_PROGRESS = New System.Windows.Forms.TableLayoutPanel() TP_BASIS.SuspendLayout() CType(Me.TXT_GLOBAL_PATH, System.ComponentModel.ISupportInitialize).BeginInit() TP_IMAGES.SuspendLayout() @@ -117,12 +127,16 @@ TAB_BEHAVIOR.SuspendLayout() TP_BEHAVIOR.SuspendLayout() CType(Me.TXT_FOLDER_CMD, System.ComponentModel.ISupportInitialize).BeginInit() + CType(Me.TXT_CLOSE_SCRIPT, System.ComponentModel.ISupportInitialize).BeginInit() TAB_DOWN.SuspendLayout() TP_DOWNLOADING.SuspendLayout() CType(Me.TXT_SCRIPT, System.ComponentModel.ISupportInitialize).BeginInit() + CType(Me.TXT_DOWN_COMPLETE_SCRIPT, System.ComponentModel.ISupportInitialize).BeginInit() Me.TAB_MAIN.SuspendLayout() Me.CONTAINER_MAIN.ContentPanel.SuspendLayout() Me.CONTAINER_MAIN.SuspendLayout() + TP_OPEN_INFO.SuspendLayout() + TP_OPEN_PROGRESS.SuspendLayout() Me.SuspendLayout() ' 'TP_BASIS @@ -633,7 +647,7 @@ TAB_DEFAULTS.Location = New System.Drawing.Point(4, 22) TAB_DEFAULTS.Name = "TAB_DEFAULTS" TAB_DEFAULTS.Padding = New System.Windows.Forms.Padding(3) - TAB_DEFAULTS.Size = New System.Drawing.Size(576, 335) + TAB_DEFAULTS.Size = New System.Drawing.Size(576, 284) TAB_DEFAULTS.TabIndex = 1 TAB_DEFAULTS.Text = "Defaults" ' @@ -656,7 +670,7 @@ TP_DEFS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) TP_DEFS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) TP_DEFS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20.0!)) - TP_DEFS.Size = New System.Drawing.Size(570, 329) + TP_DEFS.Size = New System.Drawing.Size(570, 278) TP_DEFS.TabIndex = 0 ' 'TAB_DEFS_CHANNELS @@ -665,7 +679,7 @@ TAB_DEFS_CHANNELS.Location = New System.Drawing.Point(4, 22) TAB_DEFS_CHANNELS.Name = "TAB_DEFS_CHANNELS" TAB_DEFS_CHANNELS.Padding = New System.Windows.Forms.Padding(3) - TAB_DEFS_CHANNELS.Size = New System.Drawing.Size(576, 335) + TAB_DEFS_CHANNELS.Size = New System.Drawing.Size(576, 284) TAB_DEFS_CHANNELS.TabIndex = 4 TAB_DEFS_CHANNELS.Text = "Channels" ' @@ -689,7 +703,7 @@ TP_CHANNELS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) TP_CHANNELS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) TP_CHANNELS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) - TP_CHANNELS.Size = New System.Drawing.Size(570, 329) + TP_CHANNELS.Size = New System.Drawing.Size(570, 278) TP_CHANNELS.TabIndex = 0 ' 'TXT_CHANNEL_USER_POST_LIMIT @@ -717,7 +731,7 @@ TAB_BEHAVIOR.Controls.Add(TP_BEHAVIOR) TAB_BEHAVIOR.Location = New System.Drawing.Point(4, 22) TAB_BEHAVIOR.Name = "TAB_BEHAVIOR" - TAB_BEHAVIOR.Size = New System.Drawing.Size(576, 335) + TAB_BEHAVIOR.Size = New System.Drawing.Size(576, 284) TAB_BEHAVIOR.TabIndex = 5 TAB_BEHAVIOR.Text = "Behavior" ' @@ -726,25 +740,31 @@ TP_BEHAVIOR.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single] TP_BEHAVIOR.ColumnCount = 1 TP_BEHAVIOR.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) - TP_BEHAVIOR.Controls.Add(Me.TXT_FOLDER_CMD, 0, 5) + TP_BEHAVIOR.Controls.Add(Me.TXT_FOLDER_CMD, 0, 7) TP_BEHAVIOR.Controls.Add(Me.CH_EXIT_CONFIRM, 0, 0) TP_BEHAVIOR.Controls.Add(Me.CH_CLOSE_TO_TRAY, 0, 1) TP_BEHAVIOR.Controls.Add(Me.CH_SHOW_NOTIFY, 0, 2) TP_BEHAVIOR.Controls.Add(Me.CH_FAST_LOAD, 0, 3) + TP_BEHAVIOR.Controls.Add(Me.TXT_CLOSE_SCRIPT, 0, 8) + TP_BEHAVIOR.Controls.Add(TP_OPEN_INFO, 0, 5) TP_BEHAVIOR.Controls.Add(Me.CH_RECYCLE_DEL, 0, 4) + TP_BEHAVIOR.Controls.Add(TP_OPEN_PROGRESS, 0, 6) TP_BEHAVIOR.Dock = System.Windows.Forms.DockStyle.Fill TP_BEHAVIOR.Location = New System.Drawing.Point(0, 0) TP_BEHAVIOR.Name = "TP_BEHAVIOR" - TP_BEHAVIOR.RowCount = 7 + TP_BEHAVIOR.RowCount = 11 + TP_BEHAVIOR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) + TP_BEHAVIOR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) TP_BEHAVIOR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) TP_BEHAVIOR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) TP_BEHAVIOR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) TP_BEHAVIOR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) TP_BEHAVIOR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) TP_BEHAVIOR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) + TP_BEHAVIOR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) + TP_BEHAVIOR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) TP_BEHAVIOR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) - TP_BEHAVIOR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20.0!)) - TP_BEHAVIOR.Size = New System.Drawing.Size(576, 335) + TP_BEHAVIOR.Size = New System.Drawing.Size(576, 284) TP_BEHAVIOR.TabIndex = 0 ' 'TXT_FOLDER_CMD @@ -762,12 +782,12 @@ Me.TXT_FOLDER_CMD.CaptionToolTipText = "The command to open a folder." Me.TXT_FOLDER_CMD.Dock = System.Windows.Forms.DockStyle.Fill Me.TXT_FOLDER_CMD.LeaveDefaultButtons = True - Me.TXT_FOLDER_CMD.Location = New System.Drawing.Point(4, 134) + Me.TXT_FOLDER_CMD.Location = New System.Drawing.Point(4, 186) Me.TXT_FOLDER_CMD.Name = "TXT_FOLDER_CMD" Me.TXT_FOLDER_CMD.PlaceholderEnabled = True Me.TXT_FOLDER_CMD.PlaceholderText = "MyCommand /arg {0}" Me.TXT_FOLDER_CMD.Size = New System.Drawing.Size(568, 22) - Me.TXT_FOLDER_CMD.TabIndex = 5 + Me.TXT_FOLDER_CMD.TabIndex = 7 ' 'CH_EXIT_CONFIRM ' @@ -813,12 +833,48 @@ Me.CH_RECYCLE_DEL.Text = "Delete data to recycle bin" Me.CH_RECYCLE_DEL.UseVisualStyleBackColor = True ' + 'CH_DOWN_OPEN_INFO + ' + Me.CH_DOWN_OPEN_INFO.AutoSize = True + Me.CH_DOWN_OPEN_INFO.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_DOWN_OPEN_INFO.Location = New System.Drawing.Point(4, 4) + Me.CH_DOWN_OPEN_INFO.Name = "CH_DOWN_OPEN_INFO" + Me.CH_DOWN_OPEN_INFO.Size = New System.Drawing.Size(279, 17) + Me.CH_DOWN_OPEN_INFO.TabIndex = 0 + Me.CH_DOWN_OPEN_INFO.Text = "Open the 'Info' form when the download starts" + Me.CH_DOWN_OPEN_INFO.UseVisualStyleBackColor = True + ' + 'CH_DOWN_OPEN_PROGRESS + ' + Me.CH_DOWN_OPEN_PROGRESS.AutoSize = True + Me.CH_DOWN_OPEN_PROGRESS.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_DOWN_OPEN_PROGRESS.Location = New System.Drawing.Point(4, 4) + Me.CH_DOWN_OPEN_PROGRESS.Name = "CH_DOWN_OPEN_PROGRESS" + Me.CH_DOWN_OPEN_PROGRESS.Size = New System.Drawing.Size(279, 17) + Me.CH_DOWN_OPEN_PROGRESS.TabIndex = 0 + Me.CH_DOWN_OPEN_PROGRESS.Text = "Open the 'Progress' form when the download starts" + Me.CH_DOWN_OPEN_PROGRESS.UseVisualStyleBackColor = True + ' + 'TXT_CLOSE_SCRIPT + ' + Me.TXT_CLOSE_SCRIPT.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.CheckBox + Me.TXT_CLOSE_SCRIPT.CaptionText = "Close cmd" + Me.TXT_CLOSE_SCRIPT.CaptionToolTipEnabled = True + Me.TXT_CLOSE_SCRIPT.CaptionToolTipText = "This command will be executed when SCrawler is closed" + Me.TXT_CLOSE_SCRIPT.Dock = System.Windows.Forms.DockStyle.Fill + Me.TXT_CLOSE_SCRIPT.Location = New System.Drawing.Point(4, 215) + Me.TXT_CLOSE_SCRIPT.Name = "TXT_CLOSE_SCRIPT" + Me.TXT_CLOSE_SCRIPT.PlaceholderEnabled = True + Me.TXT_CLOSE_SCRIPT.PlaceholderText = "Enter command here..." + Me.TXT_CLOSE_SCRIPT.Size = New System.Drawing.Size(568, 22) + Me.TXT_CLOSE_SCRIPT.TabIndex = 8 + ' 'TAB_DOWN ' TAB_DOWN.Controls.Add(TP_DOWNLOADING) TAB_DOWN.Location = New System.Drawing.Point(4, 22) TAB_DOWN.Name = "TAB_DOWN" - TAB_DOWN.Size = New System.Drawing.Size(576, 335) + TAB_DOWN.Size = New System.Drawing.Size(576, 284) TAB_DOWN.TabIndex = 6 TAB_DOWN.Text = "Downloading" ' @@ -831,16 +887,18 @@ TP_DOWNLOADING.Controls.Add(TP_FILE_PATTERNS, 0, 2) TP_DOWNLOADING.Controls.Add(Me.TXT_SCRIPT, 0, 3) TP_DOWNLOADING.Controls.Add(Me.CH_UDESCR_UP, 0, 0) + TP_DOWNLOADING.Controls.Add(Me.TXT_DOWN_COMPLETE_SCRIPT, 0, 4) TP_DOWNLOADING.Dock = System.Windows.Forms.DockStyle.Fill TP_DOWNLOADING.Location = New System.Drawing.Point(0, 0) TP_DOWNLOADING.Name = "TP_DOWNLOADING" - TP_DOWNLOADING.RowCount = 5 + TP_DOWNLOADING.RowCount = 6 TP_DOWNLOADING.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) TP_DOWNLOADING.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30.0!)) TP_DOWNLOADING.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30.0!)) TP_DOWNLOADING.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) + TP_DOWNLOADING.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) TP_DOWNLOADING.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) - TP_DOWNLOADING.Size = New System.Drawing.Size(576, 335) + TP_DOWNLOADING.Size = New System.Drawing.Size(576, 284) TP_DOWNLOADING.TabIndex = 0 ' 'TXT_SCRIPT @@ -867,6 +925,21 @@ Me.TXT_SCRIPT.Size = New System.Drawing.Size(568, 22) Me.TXT_SCRIPT.TabIndex = 3 ' + 'TXT_DOWN_COMPLETE_SCRIPT + ' + Me.TXT_DOWN_COMPLETE_SCRIPT.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.CheckBox + Me.TXT_DOWN_COMPLETE_SCRIPT.CaptionText = "After download cmd" + Me.TXT_DOWN_COMPLETE_SCRIPT.CaptionToolTipEnabled = True + Me.TXT_DOWN_COMPLETE_SCRIPT.CaptionToolTipText = "This command will be executed after all downloads are completed" + Me.TXT_DOWN_COMPLETE_SCRIPT.CaptionWidth = 120.0R + Me.TXT_DOWN_COMPLETE_SCRIPT.Dock = System.Windows.Forms.DockStyle.Fill + Me.TXT_DOWN_COMPLETE_SCRIPT.Location = New System.Drawing.Point(4, 121) + Me.TXT_DOWN_COMPLETE_SCRIPT.Name = "TXT_DOWN_COMPLETE_SCRIPT" + Me.TXT_DOWN_COMPLETE_SCRIPT.PlaceholderEnabled = True + Me.TXT_DOWN_COMPLETE_SCRIPT.PlaceholderText = "Enter command here..." + Me.TXT_DOWN_COMPLETE_SCRIPT.Size = New System.Drawing.Size(568, 22) + Me.TXT_DOWN_COMPLETE_SCRIPT.TabIndex = 4 + ' 'TAB_MAIN ' Me.TAB_MAIN.Controls.Add(TAB_BASIS) @@ -878,7 +951,7 @@ Me.TAB_MAIN.Location = New System.Drawing.Point(0, 0) Me.TAB_MAIN.Name = "TAB_MAIN" Me.TAB_MAIN.SelectedIndex = 0 - Me.TAB_MAIN.Size = New System.Drawing.Size(584, 285) + Me.TAB_MAIN.Size = New System.Drawing.Size(584, 310) Me.TAB_MAIN.TabIndex = 1 ' 'CONTAINER_MAIN @@ -887,7 +960,7 @@ 'CONTAINER_MAIN.ContentPanel ' Me.CONTAINER_MAIN.ContentPanel.Controls.Add(Me.TAB_MAIN) - Me.CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(584, 285) + Me.CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(584, 310) Me.CONTAINER_MAIN.Dock = System.Windows.Forms.DockStyle.Fill Me.CONTAINER_MAIN.LeftToolStripPanelVisible = False Me.CONTAINER_MAIN.Location = New System.Drawing.Point(0, 0) @@ -897,6 +970,66 @@ Me.CONTAINER_MAIN.TabIndex = 0 Me.CONTAINER_MAIN.TopToolStripPanelVisible = False ' + 'TP_OPEN_INFO + ' + TP_OPEN_INFO.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single] + TP_OPEN_INFO.ColumnCount = 2 + TP_OPEN_INFO.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!)) + TP_OPEN_INFO.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!)) + TP_OPEN_INFO.Controls.Add(Me.CH_DOWN_OPEN_INFO, 0, 0) + TP_OPEN_INFO.Controls.Add(Me.CH_DOWN_OPEN_INFO_SUSPEND, 1, 0) + TP_OPEN_INFO.Dock = System.Windows.Forms.DockStyle.Fill + TP_OPEN_INFO.Location = New System.Drawing.Point(1, 131) + TP_OPEN_INFO.Margin = New System.Windows.Forms.Padding(0) + TP_OPEN_INFO.Name = "TP_OPEN_INFO" + TP_OPEN_INFO.RowCount = 1 + TP_OPEN_INFO.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + TP_OPEN_INFO.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20.0!)) + TP_OPEN_INFO.Size = New System.Drawing.Size(574, 25) + TP_OPEN_INFO.TabIndex = 5 + ' + 'TP_OPEN_PROGRESS + ' + TP_OPEN_PROGRESS.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single] + TP_OPEN_PROGRESS.ColumnCount = 2 + TP_OPEN_PROGRESS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!)) + TP_OPEN_PROGRESS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!)) + TP_OPEN_PROGRESS.Controls.Add(Me.CH_DOWN_OPEN_PROGRESS, 0, 0) + TP_OPEN_PROGRESS.Controls.Add(Me.CH_DOWN_OPEN_PROGRESS_SUSPEND, 1, 0) + TP_OPEN_PROGRESS.Dock = System.Windows.Forms.DockStyle.Fill + TP_OPEN_PROGRESS.Location = New System.Drawing.Point(1, 157) + TP_OPEN_PROGRESS.Margin = New System.Windows.Forms.Padding(0) + TP_OPEN_PROGRESS.Name = "TP_OPEN_PROGRESS" + TP_OPEN_PROGRESS.RowCount = 1 + TP_OPEN_PROGRESS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + TP_OPEN_PROGRESS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20.0!)) + TP_OPEN_PROGRESS.Size = New System.Drawing.Size(574, 25) + TP_OPEN_PROGRESS.TabIndex = 6 + ' + 'CH_DOWN_OPEN_INFO_SUSPEND + ' + Me.CH_DOWN_OPEN_INFO_SUSPEND.AutoSize = True + Me.CH_DOWN_OPEN_INFO_SUSPEND.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_DOWN_OPEN_INFO_SUSPEND.Location = New System.Drawing.Point(290, 4) + Me.CH_DOWN_OPEN_INFO_SUSPEND.Name = "CH_DOWN_OPEN_INFO_SUSPEND" + Me.CH_DOWN_OPEN_INFO_SUSPEND.Size = New System.Drawing.Size(280, 17) + Me.CH_DOWN_OPEN_INFO_SUSPEND.TabIndex = 1 + Me.CH_DOWN_OPEN_INFO_SUSPEND.Text = "Don't open again" + TT_MAIN.SetToolTip(Me.CH_DOWN_OPEN_INFO_SUSPEND, "Do not open the form automatically if it was once closed") + Me.CH_DOWN_OPEN_INFO_SUSPEND.UseVisualStyleBackColor = True + ' + 'CH_DOWN_OPEN_PROGRESS_SUSPEND + ' + Me.CH_DOWN_OPEN_PROGRESS_SUSPEND.AutoSize = True + Me.CH_DOWN_OPEN_PROGRESS_SUSPEND.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_DOWN_OPEN_PROGRESS_SUSPEND.Location = New System.Drawing.Point(290, 4) + Me.CH_DOWN_OPEN_PROGRESS_SUSPEND.Name = "CH_DOWN_OPEN_PROGRESS_SUSPEND" + Me.CH_DOWN_OPEN_PROGRESS_SUSPEND.Size = New System.Drawing.Size(280, 17) + Me.CH_DOWN_OPEN_PROGRESS_SUSPEND.TabIndex = 1 + Me.CH_DOWN_OPEN_PROGRESS_SUSPEND.Text = "Don't open again" + TT_MAIN.SetToolTip(Me.CH_DOWN_OPEN_PROGRESS_SUSPEND, "Do not open the form automatically if it was once closed") + Me.CH_DOWN_OPEN_PROGRESS_SUSPEND.UseVisualStyleBackColor = True + ' 'GlobalSettingsForm ' Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!) @@ -943,14 +1076,20 @@ TP_BEHAVIOR.ResumeLayout(False) TP_BEHAVIOR.PerformLayout() CType(Me.TXT_FOLDER_CMD, System.ComponentModel.ISupportInitialize).EndInit() + CType(Me.TXT_CLOSE_SCRIPT, System.ComponentModel.ISupportInitialize).EndInit() TAB_DOWN.ResumeLayout(False) TP_DOWNLOADING.ResumeLayout(False) TP_DOWNLOADING.PerformLayout() CType(Me.TXT_SCRIPT, System.ComponentModel.ISupportInitialize).EndInit() + CType(Me.TXT_DOWN_COMPLETE_SCRIPT, System.ComponentModel.ISupportInitialize).EndInit() Me.TAB_MAIN.ResumeLayout(False) Me.CONTAINER_MAIN.ContentPanel.ResumeLayout(False) Me.CONTAINER_MAIN.ResumeLayout(False) Me.CONTAINER_MAIN.PerformLayout() + TP_OPEN_INFO.ResumeLayout(False) + TP_OPEN_INFO.PerformLayout() + TP_OPEN_PROGRESS.ResumeLayout(False) + TP_OPEN_PROGRESS.PerformLayout() Me.ResumeLayout(False) End Sub @@ -992,5 +1131,11 @@ Private WithEvents TXT_SCRIPT As PersonalUtilities.Forms.Controls.TextBoxExtended Private WithEvents CH_SHOW_GROUPS As CheckBox Private WithEvents CH_USERS_GROUPING As CheckBox + Private WithEvents CH_DOWN_OPEN_INFO As CheckBox + Private WithEvents CH_DOWN_OPEN_PROGRESS As CheckBox + Private WithEvents TXT_CLOSE_SCRIPT As PersonalUtilities.Forms.Controls.TextBoxExtended + Private WithEvents TXT_DOWN_COMPLETE_SCRIPT As PersonalUtilities.Forms.Controls.TextBoxExtended + Private WithEvents CH_DOWN_OPEN_INFO_SUSPEND As CheckBox + Private WithEvents CH_DOWN_OPEN_PROGRESS_SUSPEND As CheckBox End Class End Namespace \ No newline at end of file diff --git a/SCrawler/Editors/GlobalSettingsForm.resx b/SCrawler/Editors/GlobalSettingsForm.resx index 0be48c3..f236247 100644 --- a/SCrawler/Editors/GlobalSettingsForm.resx +++ b/SCrawler/Editors/GlobalSettingsForm.resx @@ -243,6 +243,12 @@ If checked, videos will be stored in separate folder; otherwise, videos will be AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC + + False + + + False + False diff --git a/SCrawler/Editors/GlobalSettingsForm.vb b/SCrawler/Editors/GlobalSettingsForm.vb index c5818c3..b2b2727 100644 --- a/SCrawler/Editors/GlobalSettingsForm.vb +++ b/SCrawler/Editors/GlobalSettingsForm.vb @@ -11,10 +11,10 @@ Imports PersonalUtilities.Forms.Controls.Base Imports PersonalUtilities.Forms.Toolbars Namespace Editors Friend Class GlobalSettingsForm : Implements IOkCancelToolbar - Private ReadOnly MyDefs As DefaultFormProps(Of FieldsChecker) + Private ReadOnly MyDefs As DefaultFormProps Friend Sub New() InitializeComponent() - MyDefs = New DefaultFormProps(Of FieldsChecker) + MyDefs = New DefaultFormProps End Sub Private Sub GlobalSettingsForm_Load(sender As Object, e As EventArgs) Handles Me.Load Try @@ -40,8 +40,14 @@ Namespace Editors CH_SHOW_NOTIFY.Checked = .ShowNotifications CH_FAST_LOAD.Checked = .FastProfilesLoading CH_RECYCLE_DEL.Checked = .DeleteToRecycleBin + CH_DOWN_OPEN_INFO.Checked = .DownloadOpenInfo + CH_DOWN_OPEN_INFO_SUSPEND.Checked = Not .DownloadOpenInfo.Attribute + CH_DOWN_OPEN_PROGRESS.Checked = .DownloadOpenProgress + CH_DOWN_OPEN_PROGRESS_SUSPEND.Checked = Not .DownloadOpenProgress.Attribute TXT_FOLDER_CMD.Text = .OpenFolderInOtherProgram TXT_FOLDER_CMD.Checked = .OpenFolderInOtherProgram.Attribute + TXT_CLOSE_SCRIPT.Text = .ClosingCommand + TXT_CLOSE_SCRIPT.Checked = .ClosingCommand.Attribute 'Defaults CH_SEPARATE_VIDEO_FOLDER.Checked = .SeparateVideoFolder.Value CH_DEF_TEMP.Checked = .DefaultTemporary @@ -51,6 +57,8 @@ Namespace Editors CH_UDESCR_UP.Checked = .UpdateUserDescriptionEveryTime TXT_SCRIPT.Checked = .ScriptData.Attribute TXT_SCRIPT.Text = .ScriptData.Value + TXT_DOWN_COMPLETE_SCRIPT.Text = .DownloadsCompleteCommand + TXT_DOWN_COMPLETE_SCRIPT.Checked = .DownloadsCompleteCommand.Attribute 'Downloading: file names CH_FILE_NAME_CHANGE.Checked = .FileReplaceNameByDate Or .FileAddDateToFileName Or .FileAddTimeToFileName OPT_FILE_NAME_REPLACE.Checked = .FileReplaceNameByDate @@ -70,7 +78,7 @@ Namespace Editors CH_CHANNELS_USERS_TEMP.Checked = .ChannelsDefaultTemporary End With .MyFieldsChecker = New FieldsChecker - With .MyFieldsChecker + With DirectCast(.MyFieldsChecker, FieldsChecker) .AddControl(Of String)(TXT_GLOBAL_PATH, TXT_GLOBAL_PATH.CaptionText) .AddControl(Of String)(TXT_COLLECTIONS_PATH, TXT_COLLECTIONS_PATH.CaptionText) .EndLoaderOperations() @@ -132,8 +140,14 @@ Namespace Editors .ShowNotifications.Value = CH_SHOW_NOTIFY.Checked .FastProfilesLoading.Value = CH_FAST_LOAD.Checked .DeleteToRecycleBin.Value = CH_RECYCLE_DEL.Checked + .DownloadOpenInfo.Value = CH_DOWN_OPEN_INFO.Checked + .DownloadOpenInfo.Attribute.Value = Not CH_DOWN_OPEN_INFO_SUSPEND.Checked + .DownloadOpenProgress.Value = CH_DOWN_OPEN_PROGRESS.Checked + .DownloadOpenProgress.Attribute.Value = Not CH_DOWN_OPEN_PROGRESS_SUSPEND.Checked .OpenFolderInOtherProgram.Value = TXT_FOLDER_CMD.Text .OpenFolderInOtherProgram.Attribute.Value = TXT_FOLDER_CMD.Checked + .ClosingCommand.Value = TXT_CLOSE_SCRIPT.Text + .ClosingCommand.Attribute.Value = TXT_CLOSE_SCRIPT.Checked 'Defaults .SeparateVideoFolder.Value = CH_SEPARATE_VIDEO_FOLDER.Checked .DefaultTemporary.Value = CH_DEF_TEMP.Checked @@ -143,6 +157,8 @@ Namespace Editors .UpdateUserDescriptionEveryTime.Value = CH_UDESCR_UP.Checked .ScriptData.Value = TXT_SCRIPT.Text .ScriptData.Attribute.Value = TXT_SCRIPT.Checked + .DownloadsCompleteCommand.Value = TXT_DOWN_COMPLETE_SCRIPT.Text + .DownloadsCompleteCommand.Attribute.Value = TXT_DOWN_COMPLETE_SCRIPT.Checked 'Downloading: file names If CH_FILE_NAME_CHANGE.Checked Then .FileReplaceNameByDate.Value = OPT_FILE_NAME_REPLACE.Checked diff --git a/SCrawler/Editors/SiteEditorForm.vb b/SCrawler/Editors/SiteEditorForm.vb index 721b1d2..1e9a16a 100644 --- a/SCrawler/Editors/SiteEditorForm.vb +++ b/SCrawler/Editors/SiteEditorForm.vb @@ -18,13 +18,17 @@ Namespace Editors Friend Class SiteEditorForm : Implements IOkCancelToolbar Private ReadOnly LBL_AUTH As Label Private ReadOnly LBL_OTHER As Label - Private ReadOnly MyDefs As DefaultFormProps(Of FieldsChecker) + Private ReadOnly MyDefs As DefaultFormProps Private WithEvents SpecialButton As Button #Region "Providers" - Private Class SavedPostsChecker : Implements ICustomProvider + Private Class SavedPostsChecker : Implements IFieldsCheckerProvider + Private Property ErrorMessage As String Implements IFieldsCheckerProvider.ErrorMessage + Private Property Name As String Implements IFieldsCheckerProvider.Name + Private Property TypeError As Boolean Implements IFieldsCheckerProvider.TypeError Private Function Convert(ByVal Value As Object, ByVal DestinationType As Type, ByVal Provider As IFormatProvider, Optional ByVal NothingArg As Object = Nothing, Optional ByVal e As ErrorsDescriber = Nothing) As Object Implements ICustomProvider.Convert - If Not ACheck(Value) OrElse CStr(Value).Contains("/") Then + If ACheck(Value) AndAlso CStr(Value).Contains("/") Then + ErrorMessage = $"Path [{Name}] contains forbidden character ""/""" Return Nothing Else Return Value @@ -38,7 +42,7 @@ Namespace Editors Private ReadOnly Property Host As SettingsHost Friend Sub New(ByVal h As SettingsHost) InitializeComponent() - MyDefs = New DefaultFormProps(Of FieldsChecker) + MyDefs = New DefaultFormProps Host = h LBL_AUTH = New Label With {.Text = "Authorization", .TextAlign = ContentAlignment.MiddleCenter, .Dock = DockStyle.Fill} LBL_OTHER = New Label With {.Text = "Other Parameters", .TextAlign = ContentAlignment.MiddleCenter, .Dock = DockStyle.Fill} @@ -65,7 +69,7 @@ Namespace Editors SiteDefaultsFunctions.SetChecker(TP_SITE_PROPS, Host) - With MyDefs.MyFieldsChecker + With DirectCast(MyDefs.MyFieldsChecker, FieldsChecker) .AddControl(Of String)(TXT_PATH, TXT_PATH.CaptionText, True, New SavedPostsChecker) .AddControl(Of String)(TXT_PATH_SAVED_POSTS, TXT_PATH_SAVED_POSTS.CaptionText, True, New SavedPostsChecker) End With @@ -113,7 +117,8 @@ Namespace Editors AddTpControl(.Control, .ControlHeight) If .LeftOffset > offset Then offset = .LeftOffset If Not .Options.AllowNull Or Not .ProviderFieldsChecker Is Nothing Then - MyDefs.MyFieldsChecker.AddControl(.Control, .Options.ControlText, .Type, .Options.AllowNull, .ProviderFieldsChecker) + DirectCast(MyDefs.MyFieldsChecker, FieldsChecker). + AddControl(.Control, .Options.ControlText, .Type, .Options.AllowNull, .ProviderFieldsChecker) End If End If End With diff --git a/SCrawler/Editors/UserCreatorForm.vb b/SCrawler/Editors/UserCreatorForm.vb index f544913..68ac8c6 100644 --- a/SCrawler/Editors/UserCreatorForm.vb +++ b/SCrawler/Editors/UserCreatorForm.vb @@ -19,7 +19,7 @@ Imports ADB = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons Namespace Editors Friend Class UserCreatorForm : Implements IOkCancelToolbar - Private ReadOnly MyDef As DefaultFormProps(Of FieldsChecker) + Private ReadOnly MyDef As DefaultFormProps Friend Property User As UserInfo Friend Property UserInstance As IUserData Friend Property StartIndex As Integer = -1 @@ -97,7 +97,7 @@ Namespace Editors Friend Sub New() InitializeComponent() UserLabels = New List(Of String) - MyDef = New DefaultFormProps(Of FieldsChecker) + MyDef = New DefaultFormProps End Sub ''' Edit exist user Friend Sub New(ByVal _Instance As IUserData) @@ -163,7 +163,7 @@ Namespace Editors End If End If .MyFieldsChecker = New FieldsChecker - .MyFieldsChecker.AddControl(Of String)(TXT_USER, TXT_USER.CaptionText) + DirectCast(.MyFieldsChecker, FieldsChecker).AddControl(Of String)(TXT_USER, TXT_USER.CaptionText) .MyFieldsChecker.EndLoaderOperations() .AppendDetectors() .EndLoaderOperations() @@ -447,8 +447,8 @@ CloseForm: Dim m As New MMessage($"Added {Added} users (skipped (already exists and/or duplicated) {Skipped})") If BannedUsers.ListExists Or NonIdentified.Count > 0 Then Dim t$ = String.Empty - If BannedUsers.ListExists Then t.StringAppendLine($"Banned users:{vbNewLine}{BannedUsers.ListToString(, vbNewLine)}") - If NonIdentified.Count > 0 Then t.StringAppendLine($"Non-Identified users:{vbNewLine}{NonIdentified.ListToString(, vbNewLine)}", vbNewLine.StringDup(2)) + If BannedUsers.ListExists Then t.StringAppendLine($"Banned users:{vbNewLine}{BannedUsers.ListToString(vbNewLine)}") + If NonIdentified.Count > 0 Then t.StringAppendLine($"Non-Identified users:{vbNewLine}{NonIdentified.ListToString(vbNewLine)}", vbNewLine.StringDup(2)) m.Style = MsgBoxStyle.Exclamation m.Text.StringAppendLine("Some of users does not recognized and/or banned") m.Text.StringAppendLine(t, vbNewLine.StringDup(2)) diff --git a/SCrawler/LabelsKeeper.vb b/SCrawler/LabelsKeeper.vb index bd786fa..a2072cc 100644 --- a/SCrawler/LabelsKeeper.vb +++ b/SCrawler/LabelsKeeper.vb @@ -72,7 +72,7 @@ Friend Class LabelsKeeper : Implements ICollection(Of String), IMyEnumerator(Of Friend Sub Update() If LabelsList.Count > 0 Then LabelsList.Sort() - TextSaver.SaveTextToFile(LabelsList.ListToString(, vbNewLine), LabelsFile, True, False, EDP.SendInLog) + TextSaver.SaveTextToFile(LabelsList.ListToString(vbNewLine), LabelsFile, True, False, EDP.SendInLog) Else LabelsFile.Delete(, Settings.DeleteMode, EDP.SendInLog) End If diff --git a/SCrawler/MainFrame.Designer.vb b/SCrawler/MainFrame.Designer.vb index f792dcc..5d38f22 100644 --- a/SCrawler/MainFrame.Designer.vb +++ b/SCrawler/MainFrame.Designer.vb @@ -29,6 +29,7 @@ Partial Public Class MainFrame : Inherits System.Windows.Forms.Form Dim MENU_VIEW_SEP_2 As System.Windows.Forms.ToolStripSeparator Dim TRAY_SEP_1 As System.Windows.Forms.ToolStripSeparator Dim MENU_DOWN_ALL_SEP_1 As System.Windows.Forms.ToolStripSeparator + Dim MENU_DOWN_ALL_SEP_2 As System.Windows.Forms.ToolStripSeparator Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(MainFrame)) Me.MENU_SETTINGS = New System.Windows.Forms.ToolStripDropDownButton() Me.BTT_SETTINGS = New System.Windows.Forms.ToolStripMenuItem() @@ -46,6 +47,7 @@ Partial Public Class MainFrame : Inherits System.Windows.Forms.Form Me.BTT_DOWN_SITE = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_DOWN_ALL_FULL = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_DOWN_SITE_FULL = New System.Windows.Forms.ToolStripMenuItem() + Me.BTT_ADD_NEW_GROUP = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_DOWN_VIDEO = New System.Windows.Forms.ToolStripButton() Me.BTT_DOWN_STOP = New System.Windows.Forms.ToolStripButton() Me.MENU_VIEW = New System.Windows.Forms.ToolStripDropDownButton() @@ -65,6 +67,7 @@ Partial Public Class MainFrame : Inherits System.Windows.Forms.Form Me.BTT_SHOW_NO_LABELS = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_SHOW_EXCLUDED_LABELS = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_SHOW_EXCLUDED_LABELS_IGNORE = New System.Windows.Forms.ToolStripMenuItem() + Me.BTT_SHOW_SHOW_GROUPS = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_SHOW_LIMIT_DATES = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_LOG = New System.Windows.Forms.ToolStripButton() Me.BTT_VERSION_INFO = New System.Windows.Forms.ToolStripButton() @@ -98,7 +101,7 @@ Partial Public Class MainFrame : Inherits System.Windows.Forms.Form 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() - Me.BTT_SHOW_SHOW_GROUPS = New System.Windows.Forms.ToolStripMenuItem() + Me.BTT_TRAY_CLOSE_NO_SCRIPT = New System.Windows.Forms.ToolStripMenuItem() SEP_1 = New System.Windows.Forms.ToolStripSeparator() SEP_2 = New System.Windows.Forms.ToolStripSeparator() CONTEXT_SEP_1 = New System.Windows.Forms.ToolStripSeparator() @@ -114,6 +117,7 @@ Partial Public Class MainFrame : Inherits System.Windows.Forms.Form MENU_VIEW_SEP_2 = New System.Windows.Forms.ToolStripSeparator() TRAY_SEP_1 = New System.Windows.Forms.ToolStripSeparator() MENU_DOWN_ALL_SEP_1 = New System.Windows.Forms.ToolStripSeparator() + MENU_DOWN_ALL_SEP_2 = New System.Windows.Forms.ToolStripSeparator() Me.Toolbar_TOP.SuspendLayout() Me.Toolbar_BOTTOM.SuspendLayout() Me.USER_CONTEXT.SuspendLayout() @@ -188,13 +192,18 @@ Partial Public Class MainFrame : Inherits System.Windows.Forms.Form 'TRAY_SEP_1 ' TRAY_SEP_1.Name = "TRAY_SEP_1" - TRAY_SEP_1.Size = New System.Drawing.Size(130, 6) + TRAY_SEP_1.Size = New System.Drawing.Size(177, 6) ' 'MENU_DOWN_ALL_SEP_1 ' MENU_DOWN_ALL_SEP_1.Name = "MENU_DOWN_ALL_SEP_1" MENU_DOWN_ALL_SEP_1.Size = New System.Drawing.Size(228, 6) ' + 'MENU_DOWN_ALL_SEP_2 + ' + MENU_DOWN_ALL_SEP_2.Name = "MENU_DOWN_ALL_SEP_2" + MENU_DOWN_ALL_SEP_2.Size = New System.Drawing.Size(228, 6) + ' 'MENU_SETTINGS ' Me.MENU_SETTINGS.AutoToolTip = False @@ -295,7 +304,7 @@ Partial Public Class MainFrame : Inherits System.Windows.Forms.Form 'MENU_DOWN_ALL ' Me.MENU_DOWN_ALL.AutoToolTip = False - Me.MENU_DOWN_ALL.DropDownItems.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_DOWN_ALL, Me.BTT_DOWN_SITE, MENU_DOWN_ALL_SEP_1, Me.BTT_DOWN_ALL_FULL, Me.BTT_DOWN_SITE_FULL}) + Me.MENU_DOWN_ALL.DropDownItems.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_DOWN_ALL, Me.BTT_DOWN_SITE, MENU_DOWN_ALL_SEP_1, Me.BTT_DOWN_ALL_FULL, Me.BTT_DOWN_SITE_FULL, MENU_DOWN_ALL_SEP_2, Me.BTT_ADD_NEW_GROUP}) Me.MENU_DOWN_ALL.Image = Global.SCrawler.My.Resources.Resources.StartPic_01_Green_16 Me.MENU_DOWN_ALL.ImageTransparentColor = System.Drawing.Color.Magenta Me.MENU_DOWN_ALL.Name = "MENU_DOWN_ALL" @@ -339,6 +348,13 @@ Partial Public Class MainFrame : Inherits System.Windows.Forms.Form Me.BTT_DOWN_SITE_FULL.Text = "Download all site users [FULL]" Me.BTT_DOWN_SITE_FULL.ToolTipText = "Download all users from specific sites. The 'Ready for download' option will be i" & "gnored." + ' + 'BTT_ADD_NEW_GROUP + ' + Me.BTT_ADD_NEW_GROUP.Image = Global.SCrawler.My.Resources.Resources.PlusPIC + Me.BTT_ADD_NEW_GROUP.Name = "BTT_ADD_NEW_GROUP" + Me.BTT_ADD_NEW_GROUP.Size = New System.Drawing.Size(231, 22) + Me.BTT_ADD_NEW_GROUP.Text = "Add a new download group" ' 'BTT_DOWN_VIDEO ' @@ -471,6 +487,12 @@ Partial Public Class MainFrame : Inherits System.Windows.Forms.Form Me.BTT_SHOW_EXCLUDED_LABELS_IGNORE.Size = New System.Drawing.Size(231, 22) Me.BTT_SHOW_EXCLUDED_LABELS_IGNORE.Text = "Ignore excluded labels" ' + 'BTT_SHOW_SHOW_GROUPS + ' + Me.BTT_SHOW_SHOW_GROUPS.Name = "BTT_SHOW_SHOW_GROUPS" + Me.BTT_SHOW_SHOW_GROUPS.Size = New System.Drawing.Size(231, 22) + Me.BTT_SHOW_SHOW_GROUPS.Text = "Show groups instead of labels" + ' 'BTT_SHOW_LIMIT_DATES ' Me.BTT_SHOW_LIMIT_DATES.AutoToolTip = True @@ -697,14 +719,14 @@ Partial Public Class MainFrame : Inherits System.Windows.Forms.Form ' '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.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_TRAY_SHOW_HIDE, TRAY_SEP_1, Me.BTT_TRAY_CLOSE, Me.BTT_TRAY_CLOSE_NO_SCRIPT}) Me.TRAY_CONTEXT.Name = "TRAY_CONTEXT" - Me.TRAY_CONTEXT.Size = New System.Drawing.Size(134, 54) + Me.TRAY_CONTEXT.Size = New System.Drawing.Size(181, 98) ' '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.Size = New System.Drawing.Size(180, 22) Me.BTT_TRAY_SHOW_HIDE.Text = "Show/Hide" ' 'BTT_TRAY_CLOSE @@ -713,14 +735,18 @@ Partial Public Class MainFrame : Inherits System.Windows.Forms.Form 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.Size = New System.Drawing.Size(180, 22) Me.BTT_TRAY_CLOSE.Text = "Close" ' - 'BTT_SHOW_SHOW_GROUPS + 'BTT_TRAY_CLOSE_NO_SCRIPT ' - Me.BTT_SHOW_SHOW_GROUPS.Name = "BTT_SHOW_SHOW_GROUPS" - Me.BTT_SHOW_SHOW_GROUPS.Size = New System.Drawing.Size(231, 22) - Me.BTT_SHOW_SHOW_GROUPS.Text = "Show groups instead of labels" + Me.BTT_TRAY_CLOSE_NO_SCRIPT.BackColor = System.Drawing.Color.FromArgb(CType(CType(255, Byte), Integer), CType(CType(192, Byte), Integer), CType(CType(192, Byte), Integer)) + Me.BTT_TRAY_CLOSE_NO_SCRIPT.ForeColor = System.Drawing.Color.Maroon + Me.BTT_TRAY_CLOSE_NO_SCRIPT.Image = Global.SCrawler.My.Resources.Resources.Delete + Me.BTT_TRAY_CLOSE_NO_SCRIPT.Name = "BTT_TRAY_CLOSE_NO_SCRIPT" + Me.BTT_TRAY_CLOSE_NO_SCRIPT.Size = New System.Drawing.Size(160, 22) + Me.BTT_TRAY_CLOSE_NO_SCRIPT.Text = "Close (no script)" + Me.BTT_TRAY_CLOSE_NO_SCRIPT.Visible = False ' 'MainFrame ' @@ -794,7 +820,6 @@ Partial Public Class MainFrame : Inherits System.Windows.Forms.Form Private WithEvents BTT_CONTEXT_CHANGE_FOLDER As ToolStripMenuItem Private WithEvents BTT_DOWN_SAVED As ToolStripButton 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_DONATE As ToolStripButton @@ -814,4 +839,7 @@ Partial Public Class MainFrame : Inherits System.Windows.Forms.Form Private WithEvents BTT_SHOW_EXCLUDED_LABELS As ToolStripMenuItem Private WithEvents BTT_SHOW_EXCLUDED_LABELS_IGNORE As ToolStripMenuItem Private WithEvents BTT_SHOW_SHOW_GROUPS As ToolStripMenuItem + Private WithEvents BTT_ADD_NEW_GROUP As ToolStripMenuItem + Friend WithEvents BTT_TRAY_CLOSE_NO_SCRIPT As ToolStripMenuItem + Friend WithEvents TRAY_CONTEXT As ContextMenuStrip End Class \ No newline at end of file diff --git a/SCrawler/MainFrame.resx b/SCrawler/MainFrame.resx index bc999df..01d77b8 100644 --- a/SCrawler/MainFrame.resx +++ b/SCrawler/MainFrame.resx @@ -162,6 +162,9 @@ False + + False + 132, 17 diff --git a/SCrawler/MainFrame.vb b/SCrawler/MainFrame.vb index 3ed34cb..f98bad4 100644 --- a/SCrawler/MainFrame.vb +++ b/SCrawler/MainFrame.vb @@ -1,4 +1,4 @@ -' Copyright (C) 2022 Andy +' 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 @@ -45,6 +45,7 @@ Public Class MainFrame If _VideoDownloadingMode Then GoTo FormClosingInvoker Settings.DeleteCachePath() MainFrameObj = New MainFrameObjects(Me) + MainFrameObj.ChangeCloseVisible() MainProgress = New Toolbars.MyProgress(Toolbar_BOTTOM, PR_MAIN, LBL_STATUS, "Downloading profiles' data") With { .DropCurrentProgressOnTotalChange = False, .Enabled = False} Downloader = New TDownloader @@ -84,6 +85,14 @@ Public Class MainFrame BTT_SITE_ALL.Checked = Settings.SelectedSites.Count = 0 BTT_SITE_SPECIFIC.Checked = Settings.SelectedSites.Count > 0 BTT_SHOW_LIMIT_DATES.Checked = Settings.LastUpdatedDate.HasValue + With Settings.Groups + AddHandler .Added, AddressOf GROUPS_Added + AddHandler .Deleted, AddressOf GROUPS_Deleted + AddHandler .Updated, AddressOf GROUPS_Updated + If .Count > 0 Then + For Each ugroup As Groups.DownloadGroup In Settings.Groups : GROUPS_Added(ugroup) : Next + End If + End With _UFinit = False GoTo EndFunction FormClosingInvoker: @@ -94,6 +103,7 @@ EndFunction: Private _IgnoreTrayOptions As Boolean = False Private _IgnoreCloseConfirm As Boolean = False Private Async Sub MainFrame_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing + If _VideoDownloadingMode Then Exit Sub If Settings.CloseToTray And Not _IgnoreTrayOptions Then e.Cancel = True Hide() @@ -119,6 +129,7 @@ EndFunction: End Sub) End If Downloader.Dispose() + MyProgressForm.Dispose() InfoForm.Dispose() If Not MyChannels Is Nothing Then MyChannels.Dispose() If Not VideoDownloader Is Nothing Then VideoDownloader.Dispose() @@ -141,11 +152,15 @@ DropCloseParams: Exit Sub CloseContinue: If Not BATCH Is Nothing Then BATCH.Dispose() : BATCH = Nothing - If Not MyMainLOG.IsEmptyString Then SaveLogToFile() If _CloseInvoked Then Close() CloseResume: End If End Sub + Private _DisableClosingScript As Boolean = False + Private Sub MainFrame_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed + If Not _DisableClosingScript And Not _VideoDownloadingMode Then ExecuteCommand(Settings.ClosingCommand) + If Not MyMainLOG.IsEmptyString Then SaveLogToFile() + End Sub #Region "Tray" Private Sub TrayIcon_MouseClick(sender As Object, e As MouseEventArgs) Handles TrayIcon.MouseClick If e.Button = MouseButtons.Left Then @@ -156,6 +171,13 @@ CloseResume: 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 + ClosePressed(False) + End Sub + Private Sub BTT_TRAY_CLOSE_NO_SCRIPT_Click(sender As Object, e As EventArgs) Handles BTT_TRAY_CLOSE_NO_SCRIPT.Click + ClosePressed(True) + End Sub + Private Sub ClosePressed(ByVal DisableScript As Boolean) + _DisableClosingScript = DisableScript If CheckForClose(False) Then _IgnoreTrayOptions = True : _IgnoreCloseConfirm = True : Close() End Sub Private Function CheckForClose(ByVal _Ignore As Boolean) As Boolean @@ -177,10 +199,27 @@ CloseResume: Case Keys.F3 : EditSelectedUser() Case Keys.F5 : BTT_DOWN_SELECTED.PerformClick() Case Keys.F6 : If Settings.ShowingMode.Value = ShowingModes.All Then BTT_DOWN_ALL.PerformClick() - Case Else : b = False + Case Else : b = NumGroup(e) End Select If b Then e.Handled = True End Sub + Private Function NumGroup(ByVal e As KeyEventArgs) As Boolean + Dim GroupExists As Func(Of Integer, Boolean) = Function(i) Settings.Groups.DownloadGroupIfExists(i - 1) + If e.Control And Settings.Groups.Count > 0 Then + Select Case e.KeyCode + Case Keys.D1, Keys.NumPad1 : Return GroupExists(1) + Case Keys.D2, Keys.NumPad2 : Return GroupExists(2) + Case Keys.D3, Keys.NumPad3 : Return GroupExists(3) + Case Keys.D4, Keys.NumPad4 : Return GroupExists(4) + Case Keys.D5, Keys.NumPad5 : Return GroupExists(5) + Case Keys.D6, Keys.NumPad6 : Return GroupExists(6) + Case Keys.D7, Keys.NumPad7 : Return GroupExists(7) + Case Keys.D8, Keys.NumPad8 : Return GroupExists(8) + Case Keys.D9, Keys.NumPad9 : Return GroupExists(9) + End Select + End If + Return False + End Function Private Sub BTT_VERSION_INFO_Click(sender As Object, e As EventArgs) Handles BTT_VERSION_INFO.Click CheckVersion(True) End Sub @@ -357,6 +396,24 @@ CloseResume: End If End Using End Sub +#End Region +#Region "Download groups" + Private Sub BTT_ADD_NEW_GROUP_Click(sender As Object, e As EventArgs) Handles BTT_ADD_NEW_GROUP.Click + Settings.Groups.Add() + End Sub + Private Sub GROUPS_Added(ByVal Sender As Groups.DownloadGroup) + Dim i% = MENU_DOWN_ALL.DropDownItems.IndexOf(BTT_ADD_NEW_GROUP) + Dim a As Action = Sub() MENU_DOWN_ALL.DropDownItems.Insert(i, Sender.GetControl) + If Toolbar_TOP.InvokeRequired Then Toolbar_TOP.Invoke(a) Else a.Invoke + End Sub + Private Sub GROUPS_Updated(ByVal Sender As Groups.DownloadGroup) + Dim i% = MENU_DOWN_ALL.DropDownItems.IndexOf(Sender.GetControl) + Dim a As Action = Sub() MENU_DOWN_ALL.DropDownItems(i).Text = Sender.ToString + If Toolbar_TOP.InvokeRequired Then Toolbar_TOP.Invoke(a) Else a.Invoke + End Sub + Private Sub GROUPS_Deleted(ByVal Sender As Groups.DownloadGroup) + MENU_DOWN_ALL.DropDownItems.Remove(Sender.GetControl) + End Sub #End Region Private Sub BTT_DOWN_VIDEO_Click(sender As Object, e As EventArgs) Handles BTT_DOWN_VIDEO.Click DownloadVideoByURL() @@ -655,7 +712,7 @@ CloseResume: End Try End Sub Private Function AskForMassReplace(ByVal users As List(Of IUserData), ByVal param As String) As Boolean - Dim u$ = users.ListIfNothing.Take(20).Select(Function(uu) uu.Name).ListToString(, vbCr) + Dim u$ = users.ListIfNothing.Take(20).Select(Function(uu) uu.Name).ListToString(vbCr) If Not u.IsEmptyString And users.ListExists(21) Then u &= vbCr & "..." Return users.ListExists AndAlso (users.Count = 1 OrElse MsgBoxE({$"Do you really want to change [{param}] for {users.Count} users?{vbCr}{vbCr}{u}", "Users' parameters change"}, @@ -921,7 +978,7 @@ CloseResume: If users.ListExists Then If USER_CONTEXT.Visible Then USER_CONTEXT.Hide() Dim ugn As Func(Of IUserData, String) = Function(u) $"{IIf(u.IsCollection, "Collection", "User")}: {u.Name}" - Dim m As New MMessage(users.Select(ugn).ListToString(, vbNewLine), "Users deleting", + Dim m As New MMessage(users.Select(ugn).ListToString(vbNewLine), "Users deleting", {New Messaging.MsgBoxButton("Delete and ban") With {.ToolTip = "Users and their data will be deleted and added to the blacklist"}, New Messaging.MsgBoxButton("Delete user only and ban") With { .ToolTip = "Users will be deleted and added to the blacklist (user data will not be deleted)"}, @@ -980,8 +1037,8 @@ CloseResume: m.Text = "No one user deleted!" m.Style = MsgBoxStyle.Critical Else - m.Text = $"The following users were deleted:{vbNewLine}{removedUsers.ListToString(, vbNewLine)}{vbNewLine.StringDup(2)}" - m.Text &= $"The following users were NOT deleted:{vbNewLine}{leftUsers.ListToString(, vbNewLine)}" + m.Text = $"The following users were deleted:{vbNewLine}{removedUsers.ListToString(vbNewLine)}{vbNewLine.StringDup(2)}" + m.Text &= $"The following users were NOT deleted:{vbNewLine}{leftUsers.ListToString(vbNewLine)}" m.Style = MsgBoxStyle.Exclamation End If If b Then Settings.UpdateBlackList() @@ -1063,7 +1120,7 @@ ResumeDownloadingOperation: users(0).DownloadToDate = d Downloader.Add(users(0)) Else - Dim uStr$ = users.Select(Function(u) u.ToString()).ListToString(, vbNewLine) + Dim uStr$ = users.Select(Function(u) u.ToString()).ListToString(vbNewLine) If MsgBoxE({$"You are select {users.Count} users' profiles{vbNewLine}Do you want to download all of them?{vbNewLine.StringDup(2)}" & $"Selected users:{vbNewLine}{uStr}", "A few users selected"}, MsgBoxStyle.Question + MsgBoxStyle.YesNo) = MsgBoxResult.Yes Then @@ -1127,4 +1184,4 @@ ResumeDownloadingOperation: Private Sub BTT_PR_INFO_Click(sender As Object, e As EventArgs) Handles BTT_PR_INFO.Click If MyProgressForm.Visible Then MyProgressForm.BringToFront() Else MyProgressForm.Show() End Sub -End Class +End Class \ No newline at end of file diff --git a/SCrawler/MainFrameObjects.vb b/SCrawler/MainFrameObjects.vb index f4c7583..6d216df 100644 --- a/SCrawler/MainFrameObjects.vb +++ b/SCrawler/MainFrameObjects.vb @@ -34,4 +34,11 @@ Friend Class MainFrameObjects Catch ex As Exception End Try End Sub + Friend Sub Focus() + If MF.Visible Then MF.BringToFront() : MF.Activate() + End Sub + Friend Sub ChangeCloseVisible() + Dim a As Action = Sub() MF.BTT_TRAY_CLOSE_NO_SCRIPT.Visible = Settings.ClosingCommand.Attribute And Not Settings.ClosingCommand.IsEmptyString + If MF.TRAY_CONTEXT.InvokeRequired Then MF.TRAY_CONTEXT.Invoke(a) Else a.Invoke + End Sub End Class \ No newline at end of file diff --git a/SCrawler/MainMod.vb b/SCrawler/MainMod.vb index 4328942..0c5f8dc 100644 --- a/SCrawler/MainMod.vb +++ b/SCrawler/MainMod.vb @@ -54,6 +54,20 @@ Friend Module MainMod End If End Try End Sub + Friend Sub ExecuteCommand(ByVal Obj As XMLValueAttribute(Of String, Boolean)) + Try + If Obj.Attribute And Not Obj.IsEmptyString Then + Using b As New BatchExecutor With {.RedirectStandardError = True} + With b + .Execute({Obj.Value}, EDP.SendInLog + EDP.ThrowException) + If .HasError Or Not .ErrorOutput.IsEmptyString Then Throw New Exception(.ErrorOutput, .ErrorException) + End With + End Using + End If + Catch ex As Exception + ErrorsDescriber.Execute(EDP.SendInLog, ex, $"[{Obj.Name}] command: [{Obj.Value}]") + End Try + End Sub Friend Enum ViewModes As Integer IconLarge = View.LargeIcon IconSmall = View.SmallIcon @@ -449,14 +463,14 @@ Friend Module MainMod m.Text = $"This user is banned:{vbNewLine}User: {Found(0).Name}" If Not Found(0).Reason.IsEmptyString Then m.Text.StringAppendLine($"Reason: {Found(0).Reason}") Else - m.Text = $"These users was banned:{vbNewLine.StringDup(2)}{Found.Select(Function(u) u.Info).ListToString(, vbNewLine)}" + m.Text = $"These users was banned:{vbNewLine.StringDup(2)}{Found.Select(Function(u) u.Info).ListToString(vbNewLine)}" End If Dim r% = MsgBoxE(m) If r = 2 Then Return Found.Select(Function(u) u.Name).ToArray Else If r = 0 Then - Settings.BlackList.ListDisposeRemove(Found, False) + Settings.BlackList.ListDisposeRemove(Found) Settings.UpdateBlackList() End If End If diff --git a/SCrawler/My Project/AssemblyInfo.vb b/SCrawler/My Project/AssemblyInfo.vb index 696a527..0c86b2e 100644 --- a/SCrawler/My Project/AssemblyInfo.vb +++ b/SCrawler/My Project/AssemblyInfo.vb @@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices ' by using the '*' as shown below: ' - - + + diff --git a/SCrawler/My Project/Resources.Designer.vb b/SCrawler/My Project/Resources.Designer.vb index 54bcdab..c130c2b 100644 --- a/SCrawler/My Project/Resources.Designer.vb +++ b/SCrawler/My Project/Resources.Designer.vb @@ -110,6 +110,16 @@ Namespace My.Resources End Get End Property + ''' + ''' Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + ''' + Friend ReadOnly Property GroupBy_284() As System.Drawing.Icon + Get + Dim obj As Object = ResourceManager.GetObject("GroupBy_284", resourceCulture) + Return CType(obj,System.Drawing.Icon) + End Get + End Property + ''' ''' Looks up a localized resource of type System.Drawing.Bitmap. ''' diff --git a/SCrawler/My Project/Resources.resx b/SCrawler/My Project/Resources.resx index 2c52e69..ba1a7ba 100644 --- a/SCrawler/My Project/Resources.resx +++ b/SCrawler/My Project/Resources.resx @@ -193,4 +193,7 @@ ..\Content\Pictures\ScriptPic32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Content\Icons\GroupBy_284.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/SCrawler/SCrawler.vbproj b/SCrawler/SCrawler.vbproj index 5ef3ef6..e99b93f 100644 --- a/SCrawler/SCrawler.vbproj +++ b/SCrawler/SCrawler.vbproj @@ -160,7 +160,15 @@ Form + + + + GroupEditorForm.vb + + + Form + @@ -314,6 +322,9 @@ DownloadSavedPostsForm.vb + + GroupEditorForm.vb + CollectionEditorForm.vb @@ -380,6 +391,7 @@ + PreserveNewest diff --git a/SCrawler/SettingsCLS.vb b/SCrawler/SettingsCLS.vb index 666dc48..752990d 100644 --- a/SCrawler/SettingsCLS.vb +++ b/SCrawler/SettingsCLS.vb @@ -33,6 +33,7 @@ Friend Class SettingsCLS : Implements IDisposable Friend ReadOnly Property UsersList As List(Of UserInfo) Friend Property Channels As Reddit.ChannelsCollection Friend ReadOnly Property Labels As LabelsKeeper + Friend ReadOnly Property Groups As Groups.DownloadGroupCollection Friend ReadOnly Property BlackList As List(Of UserBan) Private ReadOnly BlackListFile As SFile = $"{SettingsFolderName}\BlackList.txt" Private ReadOnly UsersSettingsFile As SFile = $"{SettingsFolderName}\Users.xml" @@ -69,6 +70,11 @@ Friend Class SettingsCLS : Implements IDisposable FastProfilesLoading = New XMLValue(Of Boolean)("FastProfilesLoading", False, MyXML) MaxLargeImageHeigh = New XMLValue(Of Integer)("MaxLargeImageHeigh", 150, MyXML) MaxSmallImageHeigh = New XMLValue(Of Integer)("MaxSmallImageHeigh", 15, MyXML) + DownloadOpenInfo = New XMLValueAttribute(Of Boolean, Boolean)("DownloadOpenInfo", "OpenAgain", False, False, MyXML) + DownloadOpenProgress = New XMLValueAttribute(Of Boolean, Boolean)("DownloadOpenProgress", "OpenAgain", False, False, MyXML) + DownloadsCompleteCommand = New XMLValueAttribute(Of String, Boolean)("DownloadsCompleteCommand", "Use",,, MyXML) + ClosingCommand = New XMLValueAttribute(Of String, Boolean)("ClosingCommand", "Use",,, MyXML) + AddHandler ClosingCommand.OnValueChanged, Sub(s, __n, v) MainFrameObj?.ChangeCloseVisible() InfoViewMode = New XMLValue(Of Integer)("InfoViewMode", DownloadedInfoForm.ViewModes.Session, MyXML) ViewMode = New XMLValue(Of Integer)("ViewMode", ViewModes.IconLarge, MyXML) ShowingMode = New XMLValue(Of Integer)("ShowingMode", ShowingModes.All, MyXML) @@ -124,6 +130,8 @@ Friend Class SettingsCLS : Implements IDisposable DeleteToRecycleBin = New XMLValue(Of Boolean)("DeleteToRecycleBin", True, MyXML) Labels = New LabelsKeeper(MyXML) + Groups = New Groups.DownloadGroupCollection + Labels.AddRange(Groups.GetLabels, False) MyXML.EndUpdate() If MyXML.ChangesDetected Then MyXML.Sort() : MyXML.UpdateData() @@ -316,7 +324,7 @@ Friend Class SettingsCLS : Implements IDisposable #End Region Friend Sub UpdateBlackList() If BlackList.Count > 0 Then - TextSaver.SaveTextToFile(BlackList.ListToString(, vbNewLine), BlackListFile, True, False, EDP.None) + TextSaver.SaveTextToFile(BlackList.ListToString(vbNewLine), BlackListFile, True, False, EDP.None) Else BlackListFile.Delete(, Settings.DeleteMode) End If @@ -398,6 +406,10 @@ Friend Class SettingsCLS : Implements IDisposable Friend ReadOnly Property FastProfilesLoading As XMLValue(Of Boolean) Friend ReadOnly Property MaxLargeImageHeigh As XMLValue(Of Integer) Friend ReadOnly Property MaxSmallImageHeigh As XMLValue(Of Integer) + Friend ReadOnly Property DownloadOpenInfo As XMLValueAttribute(Of Boolean, Boolean) + Friend ReadOnly Property DownloadOpenProgress As XMLValueAttribute(Of Boolean, Boolean) + Friend ReadOnly Property DownloadsCompleteCommand As XMLValueAttribute(Of String, Boolean) + Friend ReadOnly Property ClosingCommand As XMLValueAttribute(Of String, Boolean) Friend ReadOnly Property InfoViewMode As XMLValue(Of Integer) Friend ReadOnly Property ViewMode As XMLValue(Of Integer) Friend ReadOnly Property ViewModeIsPicture As Boolean