From 38c81b7a0bdbee21aedeb60d3da495e5721d9e90 Mon Sep 17 00:00:00 2001 From: Andy <88590076+AAndyProgram@users.noreply.github.com> Date: Mon, 2 Jan 2023 18:53:24 +0300 Subject: [PATCH] 2022.1.2.0 Redgifs: added token refresh interval; reduced interval value Updated labels collection PornHub: fixed bugs Notifications: pressing any button opens SCrawler User list loader finished --- CONTRIBUTING.md | 8 +- Changelog.md | 15 ++ FAQ.md | 2 +- ProgramScreenshots/SettingsSiteRedGifs.png | Bin 14475 -> 15826 bytes SCrawler/API/Instagram/UserData.vb | 7 +- SCrawler/API/PornHub/SiteSettings.vb | 1 + SCrawler/API/PornHub/UserData.vb | 3 +- SCrawler/API/Reddit/UserData.vb | 1 + SCrawler/API/Redgifs/SiteSettings.vb | 40 ++++- .../Download/Automation/AutoDownloader.vb | 11 +- SCrawler/Download/Automation/Scheduler.vb | 9 +- .../Groups/DownloadGroupCollection.vb | 3 - SCrawler/Editors/LabelsForm.vb | 2 +- SCrawler/LabelsKeeper.vb | 30 ++-- SCrawler/ListImagesLoader.vb | 143 ++++++++++-------- SCrawler/MainFrame.vb | 51 ++++--- SCrawler/MainFrameObjects.vb | 6 +- SCrawler/MainMod.vb | 9 ++ SCrawler/My Project/AssemblyInfo.vb | 4 +- SCrawler/SettingsCLS.vb | 11 +- 20 files changed, 218 insertions(+), 138 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 935df46..4f0f6b1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,10 +11,10 @@ I welcome requests! Follow these steps to contribute: 1. Delete the "PersonalUtilities" project from the solution. 1. Delete the "PersonalUtilities.Notifications" project from the solution. 1. The following libraries must be added to project references with the '**Copy to output folder**' option: - - ```PersonalUtilities.dll``` - - ```PersonalUtilities.Notifications.dll``` - - ```Microsoft.Toolkit.Uwp.Notifications.dll``` - - ```System.ValueTuple.dll``` + - ```PersonalUtilities.dll``` + - ```PersonalUtilities.Notifications.dll``` + - ```Microsoft.Toolkit.Uwp.Notifications.dll``` + - ```System.ValueTuple.dll``` 1. Import PersonalUtilities.Functions for the whole project. **Always use the correct libraries. You must download libraries from the same release date as the code commit date.** diff --git a/Changelog.md b/Changelog.md index 55073ee..72c26af 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,18 @@ +# 2023.1.2.0 + +*2023-01-02* + +- Added + - RedGifs: an ability to customize token refresh interval + - RedGifs: token refresh interval changed from 24 hours to 12 hours + - Updated labels collection +- Fixed + - PornHub: bug in the downloader + - PornHub: download additional non-user videos + - Reddit: bug in standalone downloader + - Fixed a bug in the user list loading algorithm + - Notifications: pressing any button opens SCrawler + # 2022.12.27.0 *2022-12-27* diff --git a/FAQ.md b/FAQ.md index 5c31122..f165970 100644 --- a/FAQ.md +++ b/FAQ.md @@ -42,7 +42,7 @@ A: How to request a new site you can read [here](CONTRIBUTING.md#how-to-request- #### Q: **Twitter/Instagram download failed.** -A: Check your credentials. Both of these sites require cookies. Check your [Twitter tokens](https://github.com/AAndyProgram/SCrawler/wiki/Settings#how-to-find-twitter-tokens) and [Instagram settings](https://github.com/AAndyProgram/SCrawler/wiki/Settings#instagram-settings). If all settings are set, but nothing works, go to [create a new issue](https://github.com/AAndyProgram/SCrawler/issues). Don't forget to attach the LOG. +A: Check your credentials. Both of these sites require cookies. Check your [Twitter tokens](https://github.com/AAndyProgram/SCrawler/wiki/Settings#how-to-find-twitter-tokens) and [Instagram settings](https://github.com/AAndyProgram/SCrawler/wiki/Settings#instagram). If all settings are set, but nothing works, go to [create a new issue](https://github.com/AAndyProgram/SCrawler/issues). Don't forget to attach the LOG. **[SITES REQUIREMENTS](https://github.com/AAndyProgram/SCrawler/wiki/Settings#sites-requirements)** diff --git a/ProgramScreenshots/SettingsSiteRedGifs.png b/ProgramScreenshots/SettingsSiteRedGifs.png index e5ed2425b66e5a726a6350bf28807a306823422f..bc718283220eb3e86ac64d45b3e08a24cb118416 100644 GIT binary patch literal 15826 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 U`o|#UV%!}S1x-kW-19g83%t+oXaE2J diff --git a/SCrawler/API/Instagram/UserData.vb b/SCrawler/API/Instagram/UserData.vb index 01485be..c16c2e0 100644 --- a/SCrawler/API/Instagram/UserData.vb +++ b/SCrawler/API/Instagram/UserData.vb @@ -202,14 +202,14 @@ Namespace API.Instagram AddHandler Responser.ResponseReceived, AddressOf Responser_ResponseReceived ThrowAny(Token) HasError = False - Dim dt As Boolean = (CBool(MySiteSettings.DownloadTimeline.Value) And GetTimeline) Or IsSavedPosts - If dt And Not LastCursor.IsEmptyString Then + Dim dt As Func(Of Boolean) = Function() (CBool(MySiteSettings.DownloadTimeline.Value) And GetTimeline) Or IsSavedPosts + If dt.Invoke And Not LastCursor.IsEmptyString Then s = IIf(IsSavedPosts, Sections.SavedPosts, Sections.Timeline) DownloadData(LastCursor, s, Token) ThrowAny(Token) If Not HasError Then FirstLoadingDone = True End If - If dt And Not HasError Then + If dt.Invoke And Not HasError Then s = IIf(IsSavedPosts, Sections.SavedPosts, Sections.Timeline) DownloadData(String.Empty, s, Token) ThrowAny(Token) @@ -398,7 +398,6 @@ Namespace API.Instagram If ID.IsEmptyString Then Throw New ArgumentException("User ID is not detected", "ID") End If - 'Create query Select Case Section Case Sections.Timeline diff --git a/SCrawler/API/PornHub/SiteSettings.vb b/SCrawler/API/PornHub/SiteSettings.vb index d083cc5..e5e931d 100644 --- a/SCrawler/API/PornHub/SiteSettings.vb +++ b/SCrawler/API/PornHub/SiteSettings.vb @@ -41,6 +41,7 @@ Namespace API.PornHub Friend Sub New() MyBase.New("PornHub", "pornhub.com") Responser.CurlPath = $"cURL\curl.exe" + Responser.CurlArgumentsRight = "--ssl-no-revoke" CurlPathExists = Responser.CurlPath.Exists Responser.DeclaredError = EDP.ThrowException diff --git a/SCrawler/API/PornHub/UserData.vb b/SCrawler/API/PornHub/UserData.vb index 91fe281..eace7f2 100644 --- a/SCrawler/API/PornHub/UserData.vb +++ b/SCrawler/API/PornHub/UserData.vb @@ -210,6 +210,7 @@ Namespace API.PornHub If __continue And Not __videoDone Then Do While DownloadUserVideos(page, Token) = DataDownloaded And page < 100 : page += 1 : Loop End If + If _TempMediaList.Count > 0 Then _TempMediaList.RemoveAll(Function(m) Not m.Type = UTypes.m3u8 And Not m.Type = UTypes.VideoPre) End If Responser.Method = "GET" @@ -256,7 +257,7 @@ Namespace API.PornHub If PersonType = PersonTypeUser And r.Contains(HtmlPageNotFoundVideo) Then Return DataDownloaded_NotFound Dim l As List(Of UserVideo) = RegexFields(Of UserVideo)(r, {RegexVideo_Video_All}, {1, 2}) Dim lw As List(Of UserVideo) = Nothing - If Not PersonType = PersonTypeUser Then RegexFields(Of UserVideo)(r, {RegexVideo_Video_Wrong}, RegexVideo_Video_Wrong_Fields) + If Not PersonType = PersonTypeUser Then lw = RegexFields(Of UserVideo)(r, {RegexVideo_Video_Wrong}, RegexVideo_Video_Wrong_Fields) If l.ListExists Then If lw.ListExists Then l.ListWithRemove(lw) If l.Count > 0 Then diff --git a/SCrawler/API/Reddit/UserData.vb b/SCrawler/API/Reddit/UserData.vb index 669d992..1043d5b 100644 --- a/SCrawler/API/Reddit/UserData.vb +++ b/SCrawler/API/Reddit/UserData.vb @@ -662,6 +662,7 @@ Namespace API.Reddit Try If Not URL.IsEmptyString Then Using r As New UserData + r.SetEnvironment(Settings(RedditSiteKey), Nothing, False, False) r.Responser = New Responser r.Responser.Copy(resp) r.ParsePost(URL) diff --git a/SCrawler/API/Redgifs/SiteSettings.vb b/SCrawler/API/Redgifs/SiteSettings.vb index 5b4bb27..dfdb5b5 100644 --- a/SCrawler/API/Redgifs/SiteSettings.vb +++ b/SCrawler/API/Redgifs/SiteSettings.vb @@ -9,10 +9,10 @@ Imports SCrawler.API.Base Imports SCrawler.Plugin Imports SCrawler.Plugin.Attributes +Imports PersonalUtilities.Forms Imports PersonalUtilities.Functions.XML Imports PersonalUtilities.Functions.RegularExpressions Imports PersonalUtilities.Tools.Web.Clients -Imports PersonalUtilities.Tools.Web.Cookies Imports PersonalUtilities.Tools.Web.Documents.JSON Imports UTypes = SCrawler.API.Base.UserMedia.Types Imports UStates = SCrawler.API.Base.UserMedia.States @@ -30,10 +30,38 @@ Namespace API.RedGifs Return My.Resources.SiteResources.RedGifsPic_32 End Get End Property - - Friend Property Token As PropertyValue - Friend Property TokenLastDateUpdated As PropertyValue + + Friend ReadOnly Property Token As PropertyValue + Friend ReadOnly Property TokenLastDateUpdated As PropertyValue Private Const TokenName As String = "authorization" +#Region "TokenUpdateInterval" + + Friend ReadOnly Property TokenUpdateInterval As PropertyValue + Private Class TokenIntervalProvider : 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 + TypeError = False + ErrorMessage = String.Empty + If Not ACheck(Of Integer)(Value) Then + TypeError = True + ElseIf CInt(Value) > 0 Then + Return Value + Else + ErrorMessage = $"The value of [{Name}] field must be greater than or equal to 1" + 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 the context of [TokenIntervalProvider]") + End Function + End Class + + Private ReadOnly Property TokenUpdateIntervalProvider As IFormatProvider +#End Region #End Region #Region "Initializer" Friend Sub New() @@ -47,6 +75,8 @@ Namespace API.RedGifs End With Token = New PropertyValue(t, GetType(String), Sub(v) UpdateResponse(v)) TokenLastDateUpdated = New PropertyValue(Now.AddYears(-1), GetType(Date)) + TokenUpdateInterval = New PropertyValue(60 * 12, GetType(Integer)) + TokenUpdateIntervalProvider = New TokenIntervalProvider UrlPatternUser = "https://www.redgifs.com/users/{0}/" UserRegex = RParams.DMS("[htps:/]{7,8}.*?redgifs.com/users/([^/]+)", 1) ImageVideoContains = "redgifs" @@ -61,7 +91,7 @@ Namespace API.RedGifs #Region "Token updaters" Friend Function UpdateTokenIfRequired() As Boolean Dim d As Date? = AConvert(Of Date)(TokenLastDateUpdated.Value, AModes.Var, Nothing) - If Not d.HasValue OrElse d.Value < Now.AddDays(-1) Then + If Not d.HasValue OrElse d.Value < Now.AddMinutes(-CInt(TokenUpdateInterval.Value)) Then Return UpdateToken() Else Return True diff --git a/SCrawler/Download/Automation/AutoDownloader.vb b/SCrawler/Download/Automation/AutoDownloader.vb index 70c1367..a34c14c 100644 --- a/SCrawler/Download/Automation/AutoDownloader.vb +++ b/SCrawler/Download/Automation/AutoDownloader.vb @@ -143,7 +143,8 @@ Namespace DownloadObjects ''' True to activate Friend Function Open(ByVal _Key As String) As Boolean If Not User Is Nothing Then - If Key = _Key Then + If KeyDismiss = _Key Then + ElseIf Key = _Key Then Return True ElseIf KeyFolder = _Key Then User.OpenFolder() @@ -152,6 +153,8 @@ Namespace DownloadObjects ElseIf Images.ContainsKey(_Key) Then Images(_Key).Open(, EDP.None) End If + Else + Return True End If Return False End Function @@ -548,10 +551,12 @@ Namespace DownloadObjects UserKeys.Last.ShowNotification() End If End Sub - Friend Function NotificationClicked(ByVal Key As String) As Boolean + Friend Function NotificationClicked(ByVal Key As String, ByRef Found As Boolean, ByRef ActivateForm As Boolean) As Boolean Dim i% = UserKeys.IndexOf(Key) If i >= 0 Then - MainFrameObj.FocusUser(UserKeys(i).IUserDataKey, UserKeys(i).Open(Key)) + Found = True + ActivateForm = UserKeys(i).Open(Key) + MainFrameObj.FocusUser(UserKeys(i).IUserDataKey, ActivateForm) Return True Else Return False diff --git a/SCrawler/Download/Automation/Scheduler.vb b/SCrawler/Download/Automation/Scheduler.vb index f2fb9f9..b44741f 100644 --- a/SCrawler/Download/Automation/Scheduler.vb +++ b/SCrawler/Download/Automation/Scheduler.vb @@ -52,8 +52,13 @@ Namespace DownloadObjects Return Plans.Count End Get End Property - Friend Function NotificationClicked(ByVal Key As String) As Boolean - Return Count > 0 AndAlso Plans.Exists(Function(p) p.NotificationClicked(Key)) + Friend Function NotificationClicked(ByVal Key As String, ByRef Found As Boolean, ByRef ActivateForm As Boolean) As Boolean + If Count > 0 Then + For Each plan As AutoDownloader In Plans + If plan.NotificationClicked(Key, Found, ActivateForm) Then Return True + Next + End If + Return False End Function Friend Sub Add(ByVal Plan As AutoDownloader) Plan.Source = Me diff --git a/SCrawler/Download/Groups/DownloadGroupCollection.vb b/SCrawler/Download/Groups/DownloadGroupCollection.vb index 4d5b1b5..8ed4cfe 100644 --- a/SCrawler/Download/Groups/DownloadGroupCollection.vb +++ b/SCrawler/Download/Groups/DownloadGroupCollection.vb @@ -34,9 +34,6 @@ Namespace DownloadObjects.Groups 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) diff --git a/SCrawler/Editors/LabelsForm.vb b/SCrawler/Editors/LabelsForm.vb index 81eebdd..70ab06e 100644 --- a/SCrawler/Editors/LabelsForm.vb +++ b/SCrawler/Editors/LabelsForm.vb @@ -72,7 +72,7 @@ Friend Class LabelsForm Private Sub MyDefs_ButtonOkClick(ByVal Sender As Object, ByVal e As KeyHandleEventArgs) Handles MyDefs.ButtonOkClick Try LabelsList.ListAddList(CMB_LABELS.Items.CheckedItems.Select(Function(l) CStr(l.Value(0))), LAP.ClearBeforeAdd, LAP.NotContainsOnly) - If _AnyLabelAdd And _Source Is Nothing Then Settings.Labels.Update() + If _Source Is Nothing Then Settings.Labels.Update() MyDefs.CloseForm() Catch ex As Exception ErrorsDescriber.Execute(EDP.LogMessageValue, ex, "Label selection") diff --git a/SCrawler/LabelsKeeper.vb b/SCrawler/LabelsKeeper.vb index a859446..6302478 100644 --- a/SCrawler/LabelsKeeper.vb +++ b/SCrawler/LabelsKeeper.vb @@ -25,30 +25,16 @@ Friend Class LabelsKeeper : Implements ICollection(Of String), IMyEnumerator(Of Friend ReadOnly Property Current As XMLValuesCollection(Of String) Friend ReadOnly Property Excluded As XMLValuesCollection(Of String) Friend ReadOnly Property ExcludedIgnore As XMLValue(Of Boolean) - Private ReadOnly Property SourceXML As XmlFile Friend Sub New(ByRef x As XmlFile) - SourceXML = x LabelsList = New List(Of String) NewLabels = New List(Of String) If LabelsFile.Exists Then LabelsList.ListAddList(IO.File.ReadAllLines(LabelsFile), LAP.NotContainsOnly) Current = New XMLValuesCollection(Of String)(XMLValueBase.ListModes.String, "LatestSelectedLabels", x) With {.ListAddParameters = LAP.NotContainsOnly} Excluded = New XMLValuesCollection(Of String)(XMLValueBase.ListModes.String, "LatestExcludedLabels", x) With {.ListAddParameters = LAP.NotContainsOnly} ExcludedIgnore = New XMLValue(Of Boolean)("LatestExcludedLabelsIgnore", False, x) - End Sub - Friend Sub Verify() - SourceXML.BeginUpdate() - Dim r As Predicate(Of String) = Function(l) Not LabelsList.Contains(l) - Dim c% = Current.Count - If c > 0 Then - Current.ValuesList.RemoveAll(r) - If Not Current.Count = c Then Current.Update() - End If - c = Excluded.Count - If c > 0 Then - Excluded.ValuesList.RemoveAll(r) - If Not c = Excluded.Count Then Excluded.Update() - End If - SourceXML.EndUpdate() + Dim lp As New ListAddParams(LAP.NotContainsOnly + LAP.IgnoreICopier) + If Current.Count > 0 Then LabelsList.ListAddList(Current, lp) + If Excluded.Count > 0 Then LabelsList.ListAddList(Excluded, lp) End Sub Friend ReadOnly Property ToList As List(Of String) Get @@ -69,10 +55,14 @@ Friend Class LabelsKeeper : Implements ICollection(Of String), IMyEnumerator(Of LabelsList.Clear() NewLabels.Clear() End Sub - Friend Sub Update() + Friend Sub Update(Optional ByVal Force As Boolean = False) If LabelsList.Count > 0 Then - LabelsList.Sort() - TextSaver.SaveTextToFile(LabelsList.ListToString(vbNewLine), LabelsFile, True, False, EDP.SendInLog) + If NewLabelsExists Or Force Then + If LabelsList.Contains(NoParsedUser) Then LabelsList.Remove(NoParsedUser) + LabelsList.Sort() + TextSaver.SaveTextToFile(LabelsList.ListToString(vbNewLine), LabelsFile, True, False, EDP.SendInLog) + If NewLabels.Count > 0 Then NewLabels.Clear() + End If Else LabelsFile.Delete(, Settings.DeleteMode, EDP.SendInLog) End If diff --git a/SCrawler/ListImagesLoader.vb b/SCrawler/ListImagesLoader.vb index bd68adb..53a5cef 100644 --- a/SCrawler/ListImagesLoader.vb +++ b/SCrawler/ListImagesLoader.vb @@ -40,20 +40,26 @@ Friend Class ListImagesLoader ImageThread = New Thread(New ThreadStart(Sub() Dim ar As IAsyncResult = Nothing Dim a As Action = Sub() - If UserDataList.ListExists Then - For i% = 0 To UserDataList.Count - 1 - With UserDataList(i).User - Select Case Settings.ViewMode.Value - Case View.LargeIcon : MyList.LargeImageList.Images.Add(.Key, .GetPicture()) - Case View.SmallIcon : MyList.SmallImageList.Images.Add(.Key, .GetPicture()) - End Select - End With - Application.DoEvents() - Next - UserDataList.Clear() - GC.Collect() - End If + Try + If UserDataList.ListExists Then + For i% = 0 To UserDataList.Count - 1 + With UserDataList(i).User + Select Case Settings.ViewMode.Value + Case View.LargeIcon : MyList.LargeImageList.Images.Add(.Key, .GetPicture()) + Case View.SmallIcon : MyList.SmallImageList.Images.Add(.Key, .GetPicture()) + End Select + End With + Application.DoEvents() + Next + UserDataList.Clear() + GC.Collect() + End If + Catch iex As ArgumentOutOfRangeException + Catch ex As Exception + ErrorsDescriber.Execute(EDP.SendInLog, ex, "[ListImagesLoader.UpdateImages]") + End Try If Not ar Is Nothing Then MyList.EndInvoke(ar) + UpdateInProgress = False End Sub If MyList.InvokeRequired Then ar = MyList.BeginInvoke(a) @@ -65,62 +71,81 @@ Friend Class ListImagesLoader ImageThread.Start() End If End Sub + Private Sub InterruptUpdate() + Try + If UserDataList.ListExists Then UserDataList.Clear() : Application.DoEvents() + If If(ImageThread?.IsAlive, False) Then ImageThread.Abort() : Application.DoEvents() + Catch ex As Exception + ErrorsDescriber.Execute(EDP.SendInLog, ex, "[ListImagesLoader.InterruptUpdate]") + End Try + End Sub Friend Sub Update() - If Not UpdateInProgress Then - UpdateInProgress = True - Dim a As Action = Sub() - With MyList - .Items.Clear() - If Not .LargeImageList Is Nothing Then .LargeImageList.Images.Clear() - .LargeImageList = New ImageList - If Not .SmallImageList Is Nothing Then .SmallImageList.Images.Clear() - .SmallImageList = New ImageList - If Settings.ViewModeIsPicture Then - .LargeImageList.ColorDepth = ColorDepth.Depth32Bit - .SmallImageList.ColorDepth = ColorDepth.Depth32Bit - .LargeImageList.ImageSize = New Size(DivideWithZeroChecking(Settings.MaxLargeImageHeight.Value, 100) * 75, Settings.MaxLargeImageHeight.Value) - .SmallImageList.ImageSize = New Size(DivideWithZeroChecking(Settings.MaxSmallImageHeight.Value, 100) * 75, Settings.MaxSmallImageHeight.Value) - End If - End With - End Sub - If MyList.InvokeRequired Then MyList.Invoke(a) Else a.Invoke - If Settings.Users.Count > 0 Then - Settings.Users.Sort() - Dim v As View = Settings.ViewMode.Value + Try + If UpdateInProgress Then InterruptUpdate() + If Not UpdateInProgress Then + UpdateInProgress = True + Dim a As Action = Sub() + With MyList + .Items.Clear() + If Not .LargeImageList Is Nothing Then .LargeImageList.Images.Clear() + .LargeImageList = New ImageList + If Not .SmallImageList Is Nothing Then .SmallImageList.Images.Clear() + .SmallImageList = New ImageList + If Settings.ViewModeIsPicture Then + .LargeImageList.ColorDepth = ColorDepth.Depth32Bit + .SmallImageList.ColorDepth = ColorDepth.Depth32Bit + .LargeImageList.ImageSize = New Size(DivideWithZeroChecking(Settings.MaxLargeImageHeight.Value, 100) * 75, Settings.MaxLargeImageHeight.Value) + .SmallImageList.ImageSize = New Size(DivideWithZeroChecking(Settings.MaxSmallImageHeight.Value, 100) * 75, Settings.MaxSmallImageHeight.Value) + End If + End With + End Sub + If MyList.InvokeRequired Then MyList.Invoke(a) Else a.Invoke + If Settings.Users.Count > 0 Then + Settings.Users.Sort() + Dim v As View = Settings.ViewMode.Value - With MyList - MyList.BeginUpdate() + With MyList + MyList.BeginUpdate() - If Settings.FastProfilesLoading Then - Settings.Users.ListReindex + If Settings.FastProfilesLoading Then + Settings.Users.ListReindex - UserDataList = (From u As IUserData In Settings.Users Where u.FitToAddParams Select New UserOption(u, MyList)).ListIfNothing - If UserDataList.ListExists Then UserDataList.Sort() + UserDataList = (From u As IUserData In Settings.Users Where u.FitToAddParams Select New UserOption(u, MyList)).ListIfNothing + If UserDataList.ListExists Then UserDataList.Sort() - If UserDataList.ListExists Then - .Items.AddRange(UserDataList.Select(Function(u) u.LVI).ToArray) - If Settings.ViewModeIsPicture Then MyList.EndUpdate() : UpdateImages() Else UserDataList.Clear() - End If - Else - Dim t As New List(Of Task) - For Each User As IUserData In Settings.Users - If User.FitToAddParams Then + If UserDataList.ListExists Then + .Items.AddRange(UserDataList.Select(Function(u) u.LVI).ToArray) If Settings.ViewModeIsPicture Then - t.Add(Task.Run(Sub() UpdateUser(User, True))) + MyList.EndUpdate() + UpdateImages() Else - UpdateUser(User, True) + UserDataList.Clear() + UpdateInProgress = False End If End If - Next - If t.Count > 0 Then Task.WhenAll(t.ToArray) : t.Clear() - End If - End With - MyList.EndUpdate() + Else + Dim t As New List(Of Task) + For Each User As IUserData In Settings.Users + If User.FitToAddParams Then + If Settings.ViewModeIsPicture Then + t.Add(Task.Run(Sub() UpdateUser(User, True))) + Else + UpdateUser(User, True) + End If + End If + Next + If t.Count > 0 Then Task.WhenAll(t.ToArray) : t.Clear() + UpdateInProgress = False + End If + End With + MyList.EndUpdate() + End If + Else + MsgBoxE({"User list update aborted. Click the 'Refresh' button to refresh the user list.", "Update user list"}, vbExclamation) End If - UpdateInProgress = False - Else - MsgBoxE({"The user list is currently being updated. Please wait for the update operation to complete and try again.", "Update user list"}, vbExclamation) - End If + Catch ex As Exception + ErrorsDescriber.Execute(EDP.SendInLog, ex, "[ListImagesLoader.Update]") + End Try End Sub Friend Sub UpdateUser(ByVal User As IUserData, ByVal Add As Boolean) Try diff --git a/SCrawler/MainFrame.vb b/SCrawler/MainFrame.vb index 58af93c..b5127fe 100644 --- a/SCrawler/MainFrame.vb +++ b/SCrawler/MainFrame.vb @@ -88,32 +88,33 @@ Public Class MainFrame LIST_PROFILES.ShowGroups = .UseGrouping ApplyViewPattern(.ViewMode.Value) AddHandler .Labels.NewLabelAdded, AddressOf UpdateLabelsGroups + UserListLoader = New ListImagesLoader(LIST_PROFILES) + RefillList() + UpdateLabelsGroups() + SetShowButtonsCheckers(.ShowingMode.Value) + CheckVersion(False) + BTT_SITE_ALL.Checked = .SelectedSites.Count = 0 + BTT_SITE_SPECIFIC.Checked = .SelectedSites.Count > 0 + BTT_SHOW_LIMIT_DATES_NOT.Tag = ShowingDates.Not + BTT_SHOW_LIMIT_DATES_NOT.Checked = .ViewDateMode.Value = ShowingDates.Not + BTT_SHOW_LIMIT_DATES_IN.Tag = ShowingDates.In + BTT_SHOW_LIMIT_DATES_IN.Checked = .ViewDateMode.Value = ShowingDates.In + With .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 + .Automation = New Scheduler + AddHandler .Groups.Updated, AddressOf .Automation.GROUPS_Updated + AddHandler .Groups.Deleted, AddressOf .Automation.GROUPS_Deleted + AddHandler .Automation.PauseDisabled, AddressOf MainFrameObj.PauseButtons.UpdatePauseButtons + If .Automation.Count > 0 Then .Labels.AddRange(.Automation.GetGroupsLabels, False) : .Labels.Update() + _UFinit = False + Await .Automation.Start(True) End With - UserListLoader = New ListImagesLoader(LIST_PROFILES) - RefillList() - UpdateLabelsGroups() - SetShowButtonsCheckers(Settings.ShowingMode.Value) - CheckVersion(False) - BTT_SITE_ALL.Checked = Settings.SelectedSites.Count = 0 - BTT_SITE_SPECIFIC.Checked = Settings.SelectedSites.Count > 0 - BTT_SHOW_LIMIT_DATES_NOT.Tag = ShowingDates.Not - BTT_SHOW_LIMIT_DATES_NOT.Checked = Settings.ViewDateMode.Value = ShowingDates.Not - BTT_SHOW_LIMIT_DATES_IN.Tag = ShowingDates.In - BTT_SHOW_LIMIT_DATES_IN.Checked = Settings.ViewDateMode.Value = ShowingDates.In - 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 - Settings.Automation = New Scheduler - AddHandler Settings.Groups.Updated, AddressOf Settings.Automation.GROUPS_Updated - AddHandler Settings.Groups.Deleted, AddressOf Settings.Automation.GROUPS_Deleted - AddHandler Settings.Automation.PauseDisabled, AddressOf MainFrameObj.PauseButtons.UpdatePauseButtons - _UFinit = False - Await Settings.Automation.Start(True) UpdatePauseButtonsVisibility() GoTo EndFunction FormClosingInvoker: diff --git a/SCrawler/MainFrameObjects.vb b/SCrawler/MainFrameObjects.vb index b7be299..3c137db 100644 --- a/SCrawler/MainFrameObjects.vb +++ b/SCrawler/MainFrameObjects.vb @@ -74,14 +74,18 @@ Friend Class MainFrameObjects End Sub Private Sub Notificator_OnClicked(ByVal Key As String) Handles Notificator.OnClicked If Not Key.IsEmptyString Then + Dim found As Boolean = False + Dim activateForm As Boolean = False If Key.StartsWith(NotificationInternalKey) Then Select Case Key Case $"{NotificationInternalKey}_{NotifyObj.Channels}" : MF.MyChannels.FormShowS() Case $"{NotificationInternalKey}_{NotifyObj.SavedPosts}" : MF.MySavedPosts.FormShowS() Case Else : Focus(True) End Select - ElseIf Settings.Automation Is Nothing OrElse Not Settings.Automation.NotificationClicked(Key) Then + ElseIf Settings.Automation Is Nothing OrElse Not Settings.Automation.NotificationClicked(Key, found, activateForm) Then Focus(True) + ElseIf found Then + Focus(activateForm) Else Focus(True) End If diff --git a/SCrawler/MainMod.vb b/SCrawler/MainMod.vb index d7abb30..1272ab1 100644 --- a/SCrawler/MainMod.vb +++ b/SCrawler/MainMod.vb @@ -6,6 +6,7 @@ ' ' This program is distributed in the hope that it will be useful, ' but WITHOUT ANY WARRANTY +Imports System.Runtime.CompilerServices Imports PersonalUtilities.Functions.XML.Base Imports PersonalUtilities.Functions.RegularExpressions Imports PersonalUtilities.Forms.Toolbars @@ -147,6 +148,14 @@ Friend Module MainMod Return $"{If(Host?.Name, String.Empty)}{Opt}" End If End Function + Friend Function GetGroupsLabels(Of T As Groups.IGroup)(ByVal Groups As IEnumerable(Of T)) As List(Of String) + If Groups.ListExists Then + Return ListAddList(Nothing, Groups.SelectMany(Function(g) g.Labels), LAP.NotContainsOnly). + ListAddList(Groups.SelectMany(Function(g) g.LabelsExcluded), LAP.NotContainsOnly) + Else + Return Nothing + End If + End Function #Region "Standalone video download functions" Friend Function GetCurrentBuffer() As String Dim b$ = BufferText diff --git a/SCrawler/My Project/AssemblyInfo.vb b/SCrawler/My Project/AssemblyInfo.vb index e6cd1ab..f41e4c0 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/SettingsCLS.vb b/SCrawler/SettingsCLS.vb index 184f873..fa66328 100644 --- a/SCrawler/SettingsCLS.vb +++ b/SCrawler/SettingsCLS.vb @@ -119,7 +119,7 @@ Friend Class SettingsCLS : Implements IDisposable If tmpPluginList.ListExists Then Plugins.AddRange(tmpPluginList) CookiesEncrypted.Value = True - FastProfilesLoading = New XMLValue(Of Boolean)("FastProfilesLoading", False, MyXML) + FastProfilesLoading = New XMLValue(Of Boolean)("FastProfilesLoading", True, MyXML) MaxLargeImageHeight = New XMLValue(Of Integer)("MaxLargeImageHeight", 150, MyXML) MaxSmallImageHeight = New XMLValue(Of Integer)("MaxSmallImageHeight", 15, MyXML) DownloadOpenInfo = New XMLValueAttribute(Of Boolean, Boolean)("DownloadOpenInfo", "OpenAgain", False, False, MyXML) @@ -206,7 +206,7 @@ Friend Class SettingsCLS : Implements IDisposable Labels = New LabelsKeeper(MyXML) Groups = New Groups.DownloadGroupCollection - Labels.AddRange(Groups.GetLabels, False) + Labels.AddRange(Groups.GetGroupsLabels, False) MyXML.EndUpdate() If MyXML.ChangesDetected Then MyXML.Sort() : MyXML.UpdateData() @@ -317,11 +317,8 @@ Friend Class SettingsCLS : Implements IDisposable If NeedUpdate Then UpdateUsersList() End If If Users.Count > 0 Then - Dim tul As IEnumerable(Of String) = Users.SelectMany(Function(u) u.Labels) - Labels.AddRange(tul, False) - If Labels.NewLabelsExists Or - (tul.ListExists AndAlso Not tul.Contains(LabelsKeeper.NoParsedUser) AndAlso Labels.Remove(LabelsKeeper.NoParsedUser)) Then _ - Labels.Update() : Labels.NewLabels.Clear() : Labels.Verify() + Labels.AddRange(Users.SelectMany(Function(u) u.Labels), False) + Labels.Update() End If Catch ex As Exception End Try