From e0dc66e0dac37ef382136bc284572fba148ac3b0 Mon Sep 17 00:00:00 2001 From: Andy <88590076+AAndyProgram@users.noreply.github.com> Date: Thu, 7 Jul 2022 14:11:18 +0300 Subject: [PATCH] 2022.7.7.0 Brushed the code in some classes Extended PropertyOption attribute Removed AuthNullException Moved ExitException to UserData class Removed Instagram HashUpdateRequired and its environment Changed Reddit response status code check Twitter images bug Added Scheduler, task startup delay, webp to jpg Fixed Stop button bug Minor changes --- Changelog.md | 16 + ProgramScreenshots/SettingsAutoDownloader.png | Bin 13389 -> 15744 bytes ProgramScreenshots/SettingsGlobalDefaults.png | Bin 9565 -> 10264 bytes ProgramScreenshots/SettingsScheduler.png | Bin 0 -> 7778 bytes ProgramScreenshots/SettingsSiteInstagram.png | Bin 26714 -> 26962 bytes README.md | 4 +- .../My Project/AssemblyInfo.vb | 4 +- .../My Project/AssemblyInfo.vb | 4 +- .../SettingsForm.Designer.vb | 53 +- SCrawler.Plugin.XVIDEOS/SettingsForm.resx | 53 -- SCrawler.Plugin.XVIDEOS/SettingsForm.vb | 20 +- SCrawler.Plugin.XVIDEOS/SiteSettings.vb | 7 +- .../Attributes/Attributes.vb | 4 + .../My Project/AssemblyInfo.vb | 4 +- SCrawler/API/Base/DownDetector.vb | 4 +- SCrawler/API/Base/ProfileSaved.vb | 2 +- SCrawler/API/Base/SiteSettingsBase.vb | 6 +- SCrawler/API/Base/Structures.vb | 2 +- SCrawler/API/Base/UserDataBase.vb | 155 +++--- SCrawler/API/Imgur/Envir.vb | 2 +- SCrawler/API/Instagram/AuthNullException.vb | 36 -- SCrawler/API/Instagram/Declarations.vb | 4 +- .../API/Instagram/EditorExchangeOptions.vb | 4 +- SCrawler/API/Instagram/ExitException.vb | 15 - SCrawler/API/Instagram/OptionsForm.vb | 4 +- SCrawler/API/Instagram/SiteSettings.vb | 137 +++-- SCrawler/API/Instagram/UserData.vb | 44 +- SCrawler/API/Reddit/Channel.vb | 4 +- SCrawler/API/Reddit/RedditViewSettingsForm.vb | 4 +- SCrawler/API/Reddit/UserData.vb | 6 +- SCrawler/API/Twitter/SiteSettings.vb | 2 +- SCrawler/API/Twitter/UserData.vb | 3 +- SCrawler/API/UserDataBind.vb | 14 +- SCrawler/Channels/ChannelViewForm.Designer.vb | 42 +- SCrawler/Channels/ChannelViewForm.resx | 12 +- SCrawler/Channels/ChannelViewForm.vb | 84 ++- .../Channels/ChannelsStatsForm.Designer.vb | 11 +- SCrawler/Channels/ChannelsStatsForm.resx | 74 +-- SCrawler/Channels/ChannelsStatsForm.vb | 4 +- .../ActiveDownloadingProgress.Designer.vb | 4 +- SCrawler/Download/AutoDownloader.vb | 176 ++++-- .../AutoDownloaderEditorForm.Designer.vb | 77 ++- .../Download/AutoDownloaderEditorForm.resx | 16 + SCrawler/Download/AutoDownloaderEditorForm.vb | 57 +- .../Download/DownloadedInfoForm.Designer.vb | 2 +- SCrawler/Download/DownloadedInfoForm.resx | 503 ++++++++++++++++++ SCrawler/Download/DownloadedInfoForm.vb | 2 +- SCrawler/Download/Groups/DownloadGroup.vb | 4 - SCrawler/Download/Groups/GroupDefaults.vb | 22 +- .../Groups/GroupEditorForm.Designer.vb | 34 +- SCrawler/Download/Groups/GroupEditorForm.resx | 9 - SCrawler/Download/Groups/GroupEditorForm.vb | 23 +- SCrawler/Download/Groups/GroupParameters.vb | 3 + SCrawler/Download/Scheduler.vb | 149 ++++++ .../Download/SchedulerEditorForm.Designer.vb | 77 +++ SCrawler/Download/SchedulerEditorForm.resx | 120 +++++ SCrawler/Download/SchedulerEditorForm.vb | 117 ++++ SCrawler/Download/TDownloader.vb | 39 +- .../Editors/CollectionEditorForm.Designer.vb | 10 +- SCrawler/Editors/CollectionEditorForm.resx | 44 +- SCrawler/Editors/CollectionEditorForm.vb | 6 +- .../Editors/GlobalSettingsForm.Designer.vb | 85 ++- SCrawler/Editors/GlobalSettingsForm.resx | 12 +- SCrawler/Editors/GlobalSettingsForm.vb | 24 +- SCrawler/Editors/LabelsForm.Designer.vb | 15 +- SCrawler/Editors/LabelsForm.resx | 60 +-- SCrawler/Editors/LabelsForm.vb | 4 +- SCrawler/Editors/SiteEditorForm.Designer.vb | 18 +- SCrawler/Editors/SiteEditorForm.vb | 4 +- .../Editors/SiteSelectionForm.Designer.vb | 3 +- SCrawler/Editors/SiteSelectionForm.vb | 6 +- SCrawler/Editors/UserCreatorForm.Designer.vb | 32 +- SCrawler/Editors/UserCreatorForm.vb | 115 ++-- SCrawler/FDatePickerForm.vb | 34 +- SCrawler/MainFrame.vb | 14 +- SCrawler/MainFrameObjects.vb | 4 +- SCrawler/My Project/AssemblyInfo.vb | 4 +- .../Hosts/PropertyValueHost.vb | 66 ++- SCrawler/SCrawler.vbproj | 12 +- SCrawler/SettingsCLS.vb | 4 +- 80 files changed, 1884 insertions(+), 970 deletions(-) create mode 100644 ProgramScreenshots/SettingsScheduler.png delete mode 100644 SCrawler/API/Instagram/AuthNullException.vb delete mode 100644 SCrawler/API/Instagram/ExitException.vb create mode 100644 SCrawler/Download/Scheduler.vb create mode 100644 SCrawler/Download/SchedulerEditorForm.Designer.vb create mode 100644 SCrawler/Download/SchedulerEditorForm.resx create mode 100644 SCrawler/Download/SchedulerEditorForm.vb diff --git a/Changelog.md b/Changelog.md index 61500c1..f150012 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,19 @@ +# 2022.7.7.0 + +- Added + - **Scheduler** (creating multiple automation tasks) + - Automation startup delay + - Download ```webp``` in ```jpg``` format + - Development: the ability to create a label control, that provides some information +- Removed + - Instagram auto-fill hash from cookies +- Updated + - Plugins +- Fixed + - ```Stop``` option not working properly + - In some cases, Twitter image is not downloading + - Minor bugs + # 2022.6.10.0 **Attention! From now on, Instagram requires Cookies, Hash and authorization headers!** diff --git a/ProgramScreenshots/SettingsAutoDownloader.png b/ProgramScreenshots/SettingsAutoDownloader.png index b38f96fab4658a05af3fc3c194dfd6e2e07a5b1c..0ad48e70b3d1bde1579974436e2ecac7a263f4d9 100644 GIT binary patch literal 15744 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 Py`m(q{uJ@#`K$i{ri8F` literal 13389 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 diff --git a/ProgramScreenshots/SettingsGlobalDefaults.png b/ProgramScreenshots/SettingsGlobalDefaults.png index 2390592b826da3fffd709167f0c09349acf55b83..7d3848e41d1194a374d6a41fa048e64644d11ab5 100644 GIT binary patch literal 10264 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 literal 9565 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

buT8X|35Dv0X^vqI)QUzbDY?zP*bjAV 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 literal 0 HcmV?d00001 diff --git a/ProgramScreenshots/SettingsSiteInstagram.png b/ProgramScreenshots/SettingsSiteInstagram.png index 00fd91118a7fdcc6c19aa8888c09de8188cba598..c04ae6be60c90ac9c277c710795a9c1c75e409ee 100644 GIT binary patch literal 26962 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 OIb?Ul7H9MG#eV=i-w%lZ diff --git a/README.md b/README.md index 70803bc..5d5a42d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,4 @@ -# :rainbow_flag: Happy LGBT Pride Month :tada: - -# Social networks crawler +# :rainbow_flag: Social networks crawler :rainbow_flag: [![GitHub release (latest by date)](https://img.shields.io/github/v/release/AAndyProgram/SCrawler)](https://github.com/AAndyProgram/SCrawler/releases/latest) [![GitHub license](https://img.shields.io/github/license/AAndyProgram/SCrawler)](https://github.com/AAndyProgram/SCrawler/blob/main/LICENSE) diff --git a/SCrawler.Plugin.LPSG/My Project/AssemblyInfo.vb b/SCrawler.Plugin.LPSG/My Project/AssemblyInfo.vb index aff7654..74db492 100644 --- a/SCrawler.Plugin.LPSG/My Project/AssemblyInfo.vb +++ b/SCrawler.Plugin.LPSG/My Project/AssemblyInfo.vb @@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices ' by using the '*' as shown below: ' - - + + diff --git a/SCrawler.Plugin.XVIDEOS/My Project/AssemblyInfo.vb b/SCrawler.Plugin.XVIDEOS/My Project/AssemblyInfo.vb index 75cb7a4..905d15a 100644 --- a/SCrawler.Plugin.XVIDEOS/My Project/AssemblyInfo.vb +++ b/SCrawler.Plugin.XVIDEOS/My Project/AssemblyInfo.vb @@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices ' by using the '*' as shown below: ' - - + + diff --git a/SCrawler.Plugin.XVIDEOS/SettingsForm.Designer.vb b/SCrawler.Plugin.XVIDEOS/SettingsForm.Designer.vb index cbbfb97..fc5a4b3 100644 --- a/SCrawler.Plugin.XVIDEOS/SettingsForm.Designer.vb +++ b/SCrawler.Plugin.XVIDEOS/SettingsForm.Designer.vb @@ -25,14 +25,9 @@ Partial Public Class SettingsForm : Inherits System.Windows.Forms.Form Dim CONTAINER_MAIN As System.Windows.Forms.ToolStripContainer Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(SettingsForm)) Me.LIST_DOMAINS = New System.Windows.Forms.ListBox() - Me.ToolbarTOP = New System.Windows.Forms.ToolStrip() - Me.BTT_ADD = New System.Windows.Forms.ToolStripButton() - Me.BTT_DELETE = New System.Windows.Forms.ToolStripButton() CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer() CONTAINER_MAIN.ContentPanel.SuspendLayout() - CONTAINER_MAIN.TopToolStripPanel.SuspendLayout() CONTAINER_MAIN.SuspendLayout() - Me.ToolbarTOP.SuspendLayout() Me.SuspendLayout() ' 'CONTAINER_MAIN @@ -41,7 +36,7 @@ Partial Public Class SettingsForm : Inherits System.Windows.Forms.Form 'CONTAINER_MAIN.ContentPanel ' CONTAINER_MAIN.ContentPanel.Controls.Add(Me.LIST_DOMAINS) - CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(384, 266) + CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(384, 291) CONTAINER_MAIN.Dock = System.Windows.Forms.DockStyle.Fill CONTAINER_MAIN.LeftToolStripPanelVisible = False CONTAINER_MAIN.Location = New System.Drawing.Point(0, 0) @@ -50,52 +45,15 @@ Partial Public Class SettingsForm : Inherits System.Windows.Forms.Form CONTAINER_MAIN.Size = New System.Drawing.Size(384, 291) CONTAINER_MAIN.TabIndex = 0 ' - 'CONTAINER_MAIN.TopToolStripPanel - ' - CONTAINER_MAIN.TopToolStripPanel.Controls.Add(Me.ToolbarTOP) - ' 'LIST_DOMAINS ' Me.LIST_DOMAINS.Dock = System.Windows.Forms.DockStyle.Fill Me.LIST_DOMAINS.FormattingEnabled = True Me.LIST_DOMAINS.Location = New System.Drawing.Point(0, 0) Me.LIST_DOMAINS.Name = "LIST_DOMAINS" - Me.LIST_DOMAINS.Size = New System.Drawing.Size(384, 266) + Me.LIST_DOMAINS.Size = New System.Drawing.Size(384, 291) Me.LIST_DOMAINS.TabIndex = 0 ' - 'ToolbarTOP - ' - Me.ToolbarTOP.Dock = System.Windows.Forms.DockStyle.None - Me.ToolbarTOP.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden - Me.ToolbarTOP.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_ADD, Me.BTT_DELETE}) - Me.ToolbarTOP.Location = New System.Drawing.Point(0, 0) - Me.ToolbarTOP.Name = "ToolbarTOP" - Me.ToolbarTOP.Size = New System.Drawing.Size(384, 25) - Me.ToolbarTOP.Stretch = True - Me.ToolbarTOP.TabIndex = 0 - ' - 'BTT_ADD - ' - Me.BTT_ADD.AutoToolTip = False - Me.BTT_ADD.BackColor = System.Drawing.Color.FromArgb(CType(CType(192, Byte), Integer), CType(CType(255, Byte), Integer), CType(CType(192, Byte), Integer)) - Me.BTT_ADD.ForeColor = System.Drawing.Color.DarkGreen - Me.BTT_ADD.Image = CType(resources.GetObject("BTT_ADD.Image"), System.Drawing.Image) - Me.BTT_ADD.ImageTransparentColor = System.Drawing.Color.Magenta - Me.BTT_ADD.Name = "BTT_ADD" - Me.BTT_ADD.Size = New System.Drawing.Size(49, 22) - Me.BTT_ADD.Text = "Add" - ' - 'BTT_DELETE - ' - Me.BTT_DELETE.AutoToolTip = False - Me.BTT_DELETE.BackColor = System.Drawing.Color.FromArgb(CType(CType(255, Byte), Integer), CType(CType(192, Byte), Integer), CType(CType(192, Byte), Integer)) - Me.BTT_DELETE.ForeColor = System.Drawing.Color.Maroon - Me.BTT_DELETE.Image = CType(resources.GetObject("BTT_DELETE.Image"), System.Drawing.Image) - Me.BTT_DELETE.ImageTransparentColor = System.Drawing.Color.Magenta - Me.BTT_DELETE.Name = "BTT_DELETE" - Me.BTT_DELETE.Size = New System.Drawing.Size(60, 22) - Me.BTT_DELETE.Text = "Delete" - ' 'SettingsForm ' Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!) @@ -112,18 +70,11 @@ Partial Public Class SettingsForm : Inherits System.Windows.Forms.Form Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide Me.Text = "Settings" CONTAINER_MAIN.ContentPanel.ResumeLayout(False) - CONTAINER_MAIN.TopToolStripPanel.ResumeLayout(False) - CONTAINER_MAIN.TopToolStripPanel.PerformLayout() CONTAINER_MAIN.ResumeLayout(False) CONTAINER_MAIN.PerformLayout() - Me.ToolbarTOP.ResumeLayout(False) - Me.ToolbarTOP.PerformLayout() Me.ResumeLayout(False) End Sub Private WithEvents LIST_DOMAINS As Windows.Forms.ListBox - Private WithEvents ToolbarTOP As Windows.Forms.ToolStrip - Private WithEvents BTT_ADD As Windows.Forms.ToolStripButton - Private WithEvents BTT_DELETE As Windows.Forms.ToolStripButton End Class \ No newline at end of file diff --git a/SCrawler.Plugin.XVIDEOS/SettingsForm.resx b/SCrawler.Plugin.XVIDEOS/SettingsForm.resx index 7083d71..ee5b946 100644 --- a/SCrawler.Plugin.XVIDEOS/SettingsForm.resx +++ b/SCrawler.Plugin.XVIDEOS/SettingsForm.resx @@ -120,60 +120,7 @@ False - - 17, 17 - - - - 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 - FHW1qQAAAABJRU5ErkJggg== - - AAABAAUAEBAAAAEAIABoBAAAVgAAABgYAAABACAAiAkAAL4EAAAgIAAAAQAIAKgIAABGDgAAMDAAAAEA diff --git a/SCrawler.Plugin.XVIDEOS/SettingsForm.vb b/SCrawler.Plugin.XVIDEOS/SettingsForm.vb index 3f47857..824f346 100644 --- a/SCrawler.Plugin.XVIDEOS/SettingsForm.vb +++ b/SCrawler.Plugin.XVIDEOS/SettingsForm.vb @@ -8,18 +8,19 @@ ' but WITHOUT ANY WARRANTY Imports PersonalUtilities.Forms.Toolbars Imports PersonalUtilities.Forms -Public Class SettingsForm : Implements IOkCancelToolbar - Private ReadOnly MyDefs As DefaultFormProps +Public Class SettingsForm + Private WithEvents MyDefs As DefaultFormOptions Private ReadOnly Property Settings As SiteSettings - Friend Sub New(ByRef s As SiteSettings) + Friend Sub New(ByRef s As SiteSettings, ByRef Design As XML.XmlFile) InitializeComponent() - MyDefs = New DefaultFormProps Settings = s + MyDefs = New DefaultFormOptions(Me, Design) End Sub Private Sub SettingsForm_Load(sender As Object, e As EventArgs) Handles Me.Load Try With MyDefs - .MyViewInitialize(Me, Settings.Design, True) + .MyViewInitialize(True) + .AddEditToolbar({EditToolbar.ControlItem.Add, EditToolbar.ControlItem.Delete}) .AddOkCancelToolbar() If Settings.Domains.Count > 0 Then Settings.Domains.ForEach(Sub(d) LIST_DOMAINS.Items.Add(d)) .EndLoaderOperations() @@ -28,7 +29,7 @@ Public Class SettingsForm : Implements IOkCancelToolbar MyDefs.InvokeLoaderError(ex) End Try End Sub - Private Sub OK() Implements IOkCancelToolbar.OK + Private Sub MyDefs_ButtonOkClick() Handles MyDefs.ButtonOkClick Settings.Domains.Clear() With LIST_DOMAINS If .Items.Count > 0 Then @@ -38,10 +39,7 @@ Public Class SettingsForm : Implements IOkCancelToolbar Settings.UpdateDomains() MyDefs.CloseForm() End Sub - Private Sub Cancel() Implements IOkCancelToolbar.Cancel - MyDefs.CloseForm(Windows.Forms.DialogResult.Cancel) - End Sub - Private Sub BTT_ADD_Click(sender As Object, e As EventArgs) Handles BTT_ADD.Click + Private Sub MyDefs_ButtonAddClick() Handles MyDefs.ButtonAddClick Dim nd$ = InputBoxE("Enter a new domain using the pattern [xvideos.com]:", "New domain") If Not nd.IsEmptyString Then If Not LIST_DOMAINS.Items.Contains(nd) Then @@ -51,7 +49,7 @@ Public Class SettingsForm : Implements IOkCancelToolbar End If End If End Sub - Private Sub BTT_DELETE_Click(sender As Object, e As EventArgs) Handles BTT_DELETE.Click + Private Sub MyDefs_ButtonDeleteClick() Handles MyDefs.ButtonDeleteClickE If _LatestSelected.ValueBetween(0, LIST_DOMAINS.Items.Count - 1) Then Dim n$ = LIST_DOMAINS.Items(_LatestSelected) If MsgBoxE({$"Are you sure you want to delete the [{n}] domain?", diff --git a/SCrawler.Plugin.XVIDEOS/SiteSettings.vb b/SCrawler.Plugin.XVIDEOS/SiteSettings.vb index 6adce0a..3714131 100644 --- a/SCrawler.Plugin.XVIDEOS/SiteSettings.vb +++ b/SCrawler.Plugin.XVIDEOS/SiteSettings.vb @@ -41,7 +41,6 @@ Public Class SiteSettings : Implements ISiteSettings Public ReadOnly Property Responser As Response Private Const DomainsDefault As String = "xvideos.com|xnxx.com" Private _Initialized As Boolean = False - Friend Design As XmlFile Public Sub New() Responser = New Response($"Settings\Responser_{Site}.xml") With Responser @@ -109,10 +108,8 @@ Public Class SiteSettings : Implements ISiteSettings Public Sub Reset() Implements ISiteSettings.Reset End Sub Public Sub OpenSettingsForm() Implements ISiteSettings.OpenSettingsForm - Using f As New SettingsForm(Me) - Design = New XmlFile("Settings\Design_XVIDEOS.xml") - f.ShowDialog() - Design.Dispose() + Using Design As New XmlFile("Settings\Design_XVIDEOS.xml") + Using f As New SettingsForm(Me, Design) : f.ShowDialog() : End Using End Using End Sub Public Sub UserOptions(ByRef Options As Object, ByVal OpenForm As Boolean) Implements ISiteSettings.UserOptions diff --git a/SCrawler.PluginProvider/Attributes/Attributes.vb b/SCrawler.PluginProvider/Attributes/Attributes.vb index f1a2174..daa2628 100644 --- a/SCrawler.PluginProvider/Attributes/Attributes.vb +++ b/SCrawler.PluginProvider/Attributes/Attributes.vb @@ -32,6 +32,10 @@ Namespace Plugin.Attributes Public Property AllowNull As Boolean = True '''

Offset the control from the left border of the form.
Default: 100
Public Property LeftOffset As Integer = 100 + ''' This control is an information label.
Default:
+ Public Property IsInformationLabel As Boolean = False + ''' Label text alignment.
Default:
+ Public Property LabelTextAlign As Drawing.ContentAlignment = Drawing.ContentAlignment.TopCenter ''' This is an authorization property Public Property IsAuth As Boolean = False ''' Initialize a new property option attribute diff --git a/SCrawler.PluginProvider/My Project/AssemblyInfo.vb b/SCrawler.PluginProvider/My Project/AssemblyInfo.vb index 5d309d8..237504a 100644 --- a/SCrawler.PluginProvider/My Project/AssemblyInfo.vb +++ b/SCrawler.PluginProvider/My Project/AssemblyInfo.vb @@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices ' by using the '*' as shown below: ' - - + + diff --git a/SCrawler/API/Base/DownDetector.vb b/SCrawler/API/Base/DownDetector.vb index 9079dfd..d8bb2e7 100644 --- a/SCrawler/API/Base/DownDetector.vb +++ b/SCrawler/API/Base/DownDetector.vb @@ -16,7 +16,7 @@ Namespace API.Base Friend Structure Data : Implements IRegExCreator, IComparable(Of Data) Friend [Date] As Date Friend Value As Integer - Friend Function CreateFromArray(ByVal ParamsArray() As String) As Object Implements IRegExCreator.CreateFromArray + Private Function CreateFromArray(ByVal ParamsArray() As String) As Object Implements IRegExCreator.CreateFromArray If ParamsArray.ListExists Then Try : [Date] = Date.Parse(ParamsArray(0)) : Catch : End Try If ParamsArray.Length > 1 Then Value = AConvert(Of Integer)(ParamsArray(1), 0) @@ -26,7 +26,7 @@ Namespace API.Base Public Overrides Function ToString() As String Return $"{AConvert(Of String)([Date], ADateTime.Formats.BaseDateTime, String.Empty)} [{Value}]" End Function - Friend Function CompareTo(ByVal Other As Data) As Integer Implements IComparable(Of Data).CompareTo + Private Function CompareTo(ByVal Other As Data) As Integer Implements IComparable(Of Data).CompareTo Return [Date].CompareTo(Other.Date) * -1 End Function End Structure diff --git a/SCrawler/API/Base/ProfileSaved.vb b/SCrawler/API/Base/ProfileSaved.vb index 525cb8d..5929fd0 100644 --- a/SCrawler/API/Base/ProfileSaved.vb +++ b/SCrawler/API/Base/ProfileSaved.vb @@ -40,7 +40,7 @@ Namespace API.Base End With HOST.BeforeStartDownload(user, PDownload.SavedPosts) user.DownloadData(Token) - Progress.InformationTemporary = $"Images: {user.DownloadedPictures(False)}; Videos: {user.DownloadedVideos(False)}" + Progress.InformationTemporary = $"{HOST.Name} Images: {user.DownloadedPictures(False)}; Videos: {user.DownloadedVideos(False)}" HOST.AfterDownload(user, PDownload.SavedPosts) End If End Using diff --git a/SCrawler/API/Base/SiteSettingsBase.vb b/SCrawler/API/Base/SiteSettingsBase.vb index 6dcb635..4263934 100644 --- a/SCrawler/API/Base/SiteSettingsBase.vb +++ b/SCrawler/API/Base/SiteSettingsBase.vb @@ -6,15 +6,15 @@ ' ' This program is distributed in the hope that it will be useful, ' but WITHOUT ANY WARRANTY -Imports SCrawler.Plugin Imports PersonalUtilities.Functions.RegularExpressions Imports PersonalUtilities.Tools.WEB +Imports SCrawler.Plugin Imports Download = SCrawler.Plugin.ISiteSettings.Download Namespace API.Base Friend MustInherit Class SiteSettingsBase : Implements ISiteSettings Friend ReadOnly Property Site As String Implements ISiteSettings.Site - Friend Overridable ReadOnly Property Icon As Icon = Nothing Implements ISiteSettings.Icon - Friend Overridable ReadOnly Property Image As Image = Nothing Implements ISiteSettings.Image + Friend Overridable ReadOnly Property Icon As Icon Implements ISiteSettings.Icon + Friend Overridable ReadOnly Property Image As Image Implements ISiteSettings.Image Private Property Logger As ILogProvider = LogConnector Implements ISiteSettings.Logger Friend Overridable ReadOnly Property Responser As Response Friend MustOverride Function GetInstance(ByVal What As Download) As IPluginContentProvider Implements ISiteSettings.GetInstance diff --git a/SCrawler/API/Base/Structures.vb b/SCrawler/API/Base/Structures.vb index eb1d131..3c425ae 100644 --- a/SCrawler/API/Base/Structures.vb +++ b/SCrawler/API/Base/Structures.vb @@ -106,12 +106,12 @@ Namespace API.Base Friend Function CompareTo(ByVal Other As UserPost) As Integer Implements IComparable(Of UserPost).CompareTo Return GetCompareValue(Me).CompareTo(GetCompareValue(Other)) End Function -#End Region Private Function GetCompareValue(ByVal Post As UserPost) As Long Dim v& = 0 If Post.Date.HasValue Then v = Post.Date.Value.Ticks * -1 Return v End Function +#End Region End Structure Friend Structure Sizes : Implements IComparable(Of Sizes) Friend Value As Integer diff --git a/SCrawler/API/Base/UserDataBase.vb b/SCrawler/API/Base/UserDataBase.vb index ac67729..243a9e0 100644 --- a/SCrawler/API/Base/UserDataBase.vb +++ b/SCrawler/API/Base/UserDataBase.vb @@ -9,8 +9,8 @@ Imports PersonalUtilities.Functions.XML Imports PersonalUtilities.Functions.RegularExpressions Imports PersonalUtilities.Forms.Toolbars -Imports PersonalUtilities.Tools.WEB Imports PersonalUtilities.Tools +Imports PersonalUtilities.Tools.WEB Imports System.IO Imports System.Net Imports System.Threading @@ -21,28 +21,33 @@ Imports UTypes = SCrawler.API.Base.UserMedia.Types Namespace API.Base Friend MustInherit Class UserDataBase : Implements IUserData, IPluginContentProvider, IThrower Friend Const UserFileAppender As String = "User" - Private ReadOnly _OnUserUpdatedHandlers As List(Of IUserData.OnUserUpdatedEventHandler) - Friend Custom Event OnUserUpdated As IUserData.OnUserUpdatedEventHandler Implements IUserData.OnUserUpdated - AddHandler(ByVal e As IUserData.OnUserUpdatedEventHandler) - If Not _OnUserUpdatedHandlers.Contains(e) Then _OnUserUpdatedHandlers.Add(e) +#Region "Events" + Private ReadOnly UserUpdatedEventHandlers As List(Of IUserData.UserUpdatedEventHandler) + Friend Custom Event UserUpdated As IUserData.UserUpdatedEventHandler Implements IUserData.UserUpdated + AddHandler(ByVal e As IUserData.UserUpdatedEventHandler) + If Not UserUpdatedEventHandlers.Contains(e) Then UserUpdatedEventHandlers.Add(e) End AddHandler - RemoveHandler(ByVal e As IUserData.OnUserUpdatedEventHandler) - If _OnUserUpdatedHandlers.Contains(e) Then _OnUserUpdatedHandlers.Remove(e) + RemoveHandler(ByVal e As IUserData.UserUpdatedEventHandler) + If UserUpdatedEventHandlers.Contains(e) Then UserUpdatedEventHandlers.Remove(e) End RemoveHandler RaiseEvent(ByVal User As IUserData) - If _OnUserUpdatedHandlers.Count > 0 Then - For Each e As IUserData.OnUserUpdatedEventHandler In _OnUserUpdatedHandlers - Try : e.Invoke(User) : Catch : End Try - Next - End If + Try + If UserUpdatedEventHandlers.Count > 0 Then + For i% = 0 To UserUpdatedEventHandlers.Count - 1 + Try : UserUpdatedEventHandlers(i).Invoke(User) : Catch : End Try + Next + End If + Catch + End Try End RaiseEvent End Event - Protected Sub RaiseEvent_OnUserUpdated() - RaiseEvent OnUserUpdated(Me) + Protected Sub OnUserUpdated() + RaiseEvent UserUpdated(Me) End Sub Friend Sub RemoveUpdateHandlers() - _OnUserUpdatedHandlers.Clear() + UserUpdatedEventHandlers.Clear() End Sub +#End Region #Region "Collection buttons" Private _CollectionButtonsExists As Boolean = False Private _CollectionButtonsColorsSet As Boolean = False @@ -130,12 +135,21 @@ Namespace API.Base #End Region #End Region #Region "Declarations" +#Region "Host, Site, Progress, Self" + Friend Property HOST As SettingsHost Implements IUserData.HOST Friend ReadOnly Property Site As String Implements IContentProvider.Site Get Return HOST.Name End Get End Property Friend Property Progress As MyProgress + Friend ReadOnly Property Self As IUserData Implements IUserData.Self + Get + Return Me + End Get + End Property +#End Region +#Region "User name, ID, exist, suspend" Friend User As UserInfo Friend Property IsSavedPosts As Boolean Implements IPluginContentProvider.IsSavedPosts Friend Overridable Property UserExists As Boolean = True Implements IUserData.Exists, IPluginContentProvider.UserExists @@ -152,7 +166,8 @@ Namespace API.Base End Property Friend Overridable Property ID As String = String.Empty Implements IContentProvider.ID, IPluginContentProvider.ID Friend Overridable Property FriendlyName As String = String.Empty Implements IContentProvider.FriendlyName -#Region "UserDescription" +#End Region +#Region "Description" Friend Property UserDescription As String = String.Empty Implements IContentProvider.Description, IPluginContentProvider.UserDescription Protected _DescriptionEveryTime As Boolean = False Protected _DescriptionChecked As Boolean = False @@ -174,7 +189,7 @@ Namespace API.Base _DescriptionEveryTime = Settings.UpdateUserDescriptionEveryTime End Sub #End Region - Friend Property ParseUserMediaOnly As Boolean = False Implements IUserData.ParseUserMediaOnly, IPluginContentProvider.ParseUserMediaOnly +#Region "Favorite, Temporary" Protected _Favorite As Boolean = False Friend Overridable Property Favorite As Boolean Implements IContentProvider.Favorite Get @@ -195,17 +210,15 @@ Namespace API.Base If _Temporary Then _Favorite = False End Set End Property +#End Region +#Region "Channel" Friend Overridable ReadOnly Property IsChannel As Boolean Implements IUserData.IsChannel Get Return User.IsChannel End Get End Property Friend Property CreatedByChannel As Boolean = False - Friend ReadOnly Property Self As IUserData Implements IUserData.Self - Get - Return Me - End Get - End Property +#End Region #Region "Images" Friend Overridable Function GetUserPicture() As Image Implements IUserData.GetPicture If Settings.ViewModeIsPicture Then @@ -303,7 +316,7 @@ BlockNullPicture: End Get End Property #End Region -#Region "Collections support" +#Region "Collections" Protected _IsCollection As Boolean = False Protected Friend ReadOnly Property IsCollection As Boolean Implements IUserData.IsCollection Get @@ -332,9 +345,10 @@ BlockNullPicture: End Sub Friend Overridable ReadOnly Property Labels As List(Of String) Implements IUserData.Labels #End Region -#Region "Downloading params" +#Region "Downloading" Protected _DataLoaded As Boolean = False Protected _DataParsed As Boolean = False + Friend Property ParseUserMediaOnly As Boolean = False Implements IUserData.ParseUserMediaOnly, IPluginContentProvider.ParseUserMediaOnly Friend Overridable Property ReadyForDownload As Boolean = True Implements IUserData.ReadyForDownload Friend Property DownloadImages As Boolean = True Implements IUserData.DownloadImages Friend Property DownloadVideos As Boolean = True Implements IUserData.DownloadVideos @@ -378,7 +392,7 @@ BlockNullPicture: End Set End Property #End Region -#Region "Information" +#Region "Information, counters, error, update date" Friend Overridable Property LastUpdated As Date? Friend Overridable Property HasError As Boolean = False Implements IUserData.HasError Private _DownloadedPicturesTotal As Integer = 0 @@ -422,6 +436,25 @@ BlockNullPicture: $" (P - {DownloadedPictures(True)}; V - {DownloadedVideos(True)})" End Get End Property + Friend Overridable Function GetUserInformation() As String + Dim OutStr$ = $"User: {Name}" + OutStr.StringAppendLine($"Path: {MyFile.CutPath.Path}") + OutStr.StringAppendLine($"Total downloaded ({DownloadedTotal(True).NumToString(ANumbers.Formats.Number, 3)}):") + OutStr.StringAppendLine($"Pictures: {DownloadedPictures(True).NumToString(ANumbers.Formats.Number, 3)}") + OutStr.StringAppendLine($"Videos: {DownloadedVideos(True).NumToString(ANumbers.Formats.Number, 3)}") + If Not UserDescription.IsEmptyString Then + OutStr.StringAppendLine(String.Empty) + OutStr.StringAppendLine(UserDescription) + End If + OutStr.StringAppendLine(String.Empty) + OutStr.StringAppendLine($"Last updated at: {AConvert(Of String)(LastUpdated, ADateTime.Formats.BaseDateTime, "not yet")}") + If _DataParsed Then + OutStr.StringAppendLine("Downloaded now:") + OutStr.StringAppendLine($"Pictures: {DownloadedTotal(False).NumToString(ANumbers.Formats.Number, 3)}") + OutStr.StringAppendLine($"Videos: {DownloadedVideos(False).NumToString(ANumbers.Formats.Number, 3)}") + End If + Return OutStr + End Function #End Region #Region "Script" Friend Overridable Property ScriptUse As Boolean = False Implements IUserData.ScriptUse @@ -431,7 +464,6 @@ BlockNullPicture: #Region "Plugins Support" Protected Event ProgressChanged As IPluginContentProvider.ProgressChangedEventHandler Implements IPluginContentProvider.ProgressChanged Protected Event TotalCountChanged As IPluginContentProvider.TotalCountChangedEventHandler Implements IPluginContentProvider.TotalCountChanged - Friend Property HOST As SettingsHost Implements IUserData.HOST Private Property IPluginContentProvider_Settings As ISiteSettings Implements IPluginContentProvider.Settings Get Return HOST.Source @@ -524,37 +556,16 @@ BlockNullPicture: Return Destination.Groups.Item(LabelsKeeper.NoLabeledName) End Try End Function - Friend Overridable Function GetUserInformation() As String - Dim OutStr$ = $"User: {Name}" - OutStr.StringAppendLine($"Path: {MyFile.CutPath.Path}") - OutStr.StringAppendLine($"Total downloaded ({DownloadedTotal(True).NumToString(ANumbers.Formats.Number, 3)}):") - OutStr.StringAppendLine($"Pictures: {DownloadedPictures(True).NumToString(ANumbers.Formats.Number, 3)}") - OutStr.StringAppendLine($"Videos: {DownloadedVideos(True).NumToString(ANumbers.Formats.Number, 3)}") - If Not UserDescription.IsEmptyString Then - OutStr.StringAppendLine(String.Empty) - OutStr.StringAppendLine(UserDescription) - End If - OutStr.StringAppendLine(String.Empty) - OutStr.StringAppendLine($"Last updated at: {AConvert(Of String)(LastUpdated, ADateTime.Formats.BaseDateTime, "not yet")}") - If _DataParsed Then - OutStr.StringAppendLine("Downloaded now:") - OutStr.StringAppendLine($"Pictures: {DownloadedTotal(False).NumToString(ANumbers.Formats.Number, 3)}") - OutStr.StringAppendLine($"Videos: {DownloadedVideos(False).NumToString(ANumbers.Formats.Number, 3)}") - End If - Return OutStr - End Function #End Region #Region "Initializer" - Private ReadOnly _InvokeImageHandler As Boolean ''' By using this constructor you must set UserName and MyFile manually Friend Sub New(Optional ByVal InvokeImageHandler As Boolean = True) - _InvokeImageHandler = InvokeImageHandler _ContentList = New List(Of UserMedia) _ContentNew = New List(Of UserMedia) _TempMediaList = New List(Of UserMedia) _TempPostsList = New List(Of String) Labels = New List(Of String) - _OnUserUpdatedHandlers = New List(Of IUserData.OnUserUpdatedEventHandler) + UserUpdatedEventHandlers = New List(Of IUserData.UserUpdatedEventHandler) If InvokeImageHandler Then ImageHandler(Me) End Sub Friend Sub SetEnvironment(ByRef h As SettingsHost, ByVal u As UserInfo, ByVal _LoadUserInformation As Boolean, @@ -680,15 +691,16 @@ BlockNullPicture: End Function For Each v As EContainer In x _ContentList.Add(New UserMedia With { - .Type = AConvert(Of Integer)(v.Attribute(Name_MediaType).Value, 0), - .URL = v.Attribute(Name_MediaURL).Value, - .URL_BASE = v.Value, - .MD5 = v.Attribute(Name_MediaHash).Value, - .File = fs & gfn.Invoke(v.Attribute(Name_MediaFile).Value), - .Post = New UserPost With { - .ID = v.Attribute(Name_MediaPostID).Value, - .[Date] = AConvert(Of Date)(v.Attribute(Name_MediaPostDate).Value, ParsersDataDateProvider, Nothing)} - }) + .Type = AConvert(Of Integer)(v.Attribute(Name_MediaType).Value, 0), + .URL = v.Attribute(Name_MediaURL).Value, + .URL_BASE = v.Value, + .MD5 = v.Attribute(Name_MediaHash).Value, + .File = fs & gfn.Invoke(v.Attribute(Name_MediaFile).Value), + .Post = New UserPost With { + .ID = v.Attribute(Name_MediaPostID).Value, + .[Date] = AConvert(Of Date)(v.Attribute(Name_MediaPostDate).Value, ParsersDataDateProvider, Nothing) + } + }) Next End If _DataLoaded = True @@ -705,14 +717,15 @@ BlockNullPicture: Using x As New XmlFile With {.AllowSameNames = True, .Name = "Data"} If _ContentList.Count > 0 Then For Each i As UserMedia In _ContentList - x.Add(New EContainer("MediaData", i.URL_BASE, - {New EAttribute(Name_MediaType, CInt(i.Type)), - New EAttribute(Name_MediaURL, i.URL), - New EAttribute(Name_MediaHash, i.MD5), - New EAttribute(Name_MediaFile, i.File.File), - New EAttribute(Name_MediaPostID, i.Post.ID), - New EAttribute(Name_MediaPostDate, AConvert(Of String)(i.Post.Date, ParsersDataDateProvider, String.Empty)) - })) + x.Add(New EContainer("MediaData", i.URL_BASE, {New EAttribute(Name_MediaType, CInt(i.Type)), + New EAttribute(Name_MediaURL, i.URL), + New EAttribute(Name_MediaHash, i.MD5), + New EAttribute(Name_MediaFile, i.File.File), + New EAttribute(Name_MediaPostID, i.Post.ID), + New EAttribute(Name_MediaPostDate, AConvert(Of String)(i.Post.Date, ParsersDataDateProvider, String.Empty)) + } + ) + ) Next End If x.Save(MyFileData) @@ -730,7 +743,7 @@ BlockNullPicture: If Not URL.IsEmptyString Then Process.Start(URL) Catch ex As Exception If Not e.Exists Then e = New ErrorsDescriber(EDP.ShowAllMsg) - MsgBoxE($"Error on trying to open [{Site}] page of user [{Name}]", MsgBoxStyle.Critical, e) + MsgBoxE({$"Error on trying to open [{Site}] page of user [{Name}]", $"User [{ToString()}]"}, MsgBoxStyle.Critical, e, ex) End Try End Sub Friend Overridable Sub OpenFolder() Implements IUserData.OpenFolder @@ -803,7 +816,7 @@ BlockNullPicture: If _CollectionButtonsExists AndAlso EnvirChanged.Invoke Then UpdateButtonsColor() End If ThrowIfDisposed() - If UpPic Or EnvirChanged.Invoke Then RaiseEvent_OnUserUpdated() + If UpPic Or EnvirChanged.Invoke Then OnUserUpdated() Catch oex As OperationCanceledException When Token.IsCancellationRequested MyMainLOG = $"{Site} - {Name}: downloading canceled" Canceled = True @@ -814,7 +827,7 @@ BlockNullPicture: HasError = True Finally If Not Responser Is Nothing Then Responser.Dispose() : Responser = Nothing - If Not Canceled Then _DataParsed = True ': LastUpdated = Now + If Not Canceled Then _DataParsed = True _ContentNew.Clear() DownloadTopCount = Nothing DownloadToDate = Nothing @@ -886,6 +899,8 @@ BlockNullPicture: Case UTypes.Video : f.Extension = "mp4" Case UTypes.GIF : f.Extension = "gif" End Select + ElseIf f.Extension = "webp" And Settings.DownloadNativeImageFormat Then + f.Extension = "jpg" End If If Not v.SpecialFolder.IsEmptyString Then @@ -1201,7 +1216,7 @@ BlockNullPicture: If Not BTT_CONTEXT_DELETE Is Nothing Then BTT_CONTEXT_DELETE.Dispose() If Not BTT_CONTEXT_OPEN_PATH Is Nothing Then BTT_CONTEXT_OPEN_PATH.Dispose() If Not BTT_CONTEXT_OPEN_SITE Is Nothing Then BTT_CONTEXT_OPEN_SITE.Dispose() - _OnUserUpdatedHandlers.Clear() + UserUpdatedEventHandlers.Clear() End If disposedValue = True End If @@ -1228,7 +1243,7 @@ BlockNullPicture: Sub DownloadData(ByVal Token As CancellationToken) End Interface Friend Interface IUserData : Inherits IContentProvider, IComparable(Of UserDataBase), IComparable, IEquatable(Of UserDataBase), IIndexable, IDisposable - Event OnUserUpdated(ByVal User As IUserData) + Event UserUpdated(ByVal User As IUserData) Property ParseUserMediaOnly As Boolean #Region "Images" Function GetPicture() As Image diff --git a/SCrawler/API/Imgur/Envir.vb b/SCrawler/API/Imgur/Envir.vb index 36f25bc..b9b99e7 100644 --- a/SCrawler/API/Imgur/Envir.vb +++ b/SCrawler/API/Imgur/Envir.vb @@ -10,8 +10,8 @@ Imports PersonalUtilities.Functions.XML Imports PersonalUtilities.Functions.RegularExpressions Imports PersonalUtilities.Tools.WebDocuments.JSON Imports System.Net -Imports SCrawler.API.Imgur.Declarations Imports SCrawler.API.Base +Imports SCrawler.API.Imgur.Declarations Namespace API.Imgur Namespace Declarations Friend Module Imgur_Declarations diff --git a/SCrawler/API/Instagram/AuthNullException.vb b/SCrawler/API/Instagram/AuthNullException.vb deleted file mode 100644 index cc1e6f4..0000000 --- a/SCrawler/API/Instagram/AuthNullException.vb +++ /dev/null @@ -1,36 +0,0 @@ -' 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 Sections = SCrawler.API.Instagram.UserData.Sections -Namespace API.Instagram - Friend Class AuthNullException : Inherits ArgumentNullException - Public Overrides ReadOnly Property ParamName As String - Public Overrides ReadOnly Property Message As String - Friend Sub New(ByVal s As Sections, ByVal IsSavedPosts As Boolean) - If IsSavedPosts Then - ParamName = "HashSavedPosts" - ElseIf s = Sections.Timeline Then - ParamName = "Hash" - Else - ParamName = "IG_APP_ID, IG_WWW_CLAIM" - End If - Message = $"Instagram auth for [{s}] is not set" - End Sub - Friend Shared Sub ThrowIfNull(ByVal s As Sections, ByVal IsSavedPosts As Boolean, ByVal Host As SiteSettings) - Dim b As Boolean = False - If IsSavedPosts Then - If Not ACheck(Host.HashSavedPosts.Value) Then b = True - ElseIf s = Sections.Timeline Then - If Not ACheck(Host.Hash.Value) Then Host.HashUpdateRequired.Value = True : b = True - Else - If Not Host.StoriesAndTaggedReady Then b = True - End If - If b Then Throw New AuthNullException(s, IsSavedPosts) - End Sub - End Class -End Namespace \ No newline at end of file diff --git a/SCrawler/API/Instagram/Declarations.vb b/SCrawler/API/Instagram/Declarations.vb index e2c0974..62285aa 100644 --- a/SCrawler/API/Instagram/Declarations.vb +++ b/SCrawler/API/Instagram/Declarations.vb @@ -13,8 +13,8 @@ Namespace API.Instagram Friend ReadOnly FilesPattern As RParams = RParams.DMS(".+?([^/\?]+?\.[\w\d]{3,4})(?=(\?|\Z))", 1, EDP.ReturnValue) Friend ReadOnly Property DateProvider As New JsonDate Friend Class JsonDate : Implements ICustomProvider - Friend Function Convert(ByVal Value As Object, ByVal DestinationType As Type, ByVal Provider As IFormatProvider, - Optional ByVal NothingArg As Object = Nothing, Optional ByVal e As ErrorsDescriber = Nothing) As Object Implements ICustomProvider.Convert + 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 Return ADateTime.ParseUnicode(Value) End Function Private Function GetFormat(ByVal FormatType As Type) As Object Implements IFormatProvider.GetFormat diff --git a/SCrawler/API/Instagram/EditorExchangeOptions.vb b/SCrawler/API/Instagram/EditorExchangeOptions.vb index 9ed3b3b..bc42809 100644 --- a/SCrawler/API/Instagram/EditorExchangeOptions.vb +++ b/SCrawler/API/Instagram/EditorExchangeOptions.vb @@ -11,10 +11,8 @@ Namespace API.Instagram Friend Class EditorExchangeOptions Friend Property GetStories As Boolean Friend Property GetTagged As Boolean - Private ReadOnly Property MySiteSettings As SiteSettings Friend Sub New(ByVal h As ISiteSettings) - MySiteSettings = DirectCast(h, SiteSettings) - With MySiteSettings + With DirectCast(h, SiteSettings) GetStories = CBool(.GetStories.Value) GetTagged = CBool(.GetTagged.Value) End With diff --git a/SCrawler/API/Instagram/ExitException.vb b/SCrawler/API/Instagram/ExitException.vb deleted file mode 100644 index 32033df..0000000 --- a/SCrawler/API/Instagram/ExitException.vb +++ /dev/null @@ -1,15 +0,0 @@ -' Copyright (C) 2022 Andy -' This program is free software: you can redistribute it and/or modify -' it under the terms of the GNU General Public License as published by -' the Free Software Foundation, either version 3 of the License, or -' (at your option) any later version. -' -' This program is distributed in the hope that it will be useful, -' but WITHOUT ANY WARRANTY -Namespace API.Instagram - Friend Class ExitException : Inherits Exception - Friend Sub New(ByRef CompleteArg As Boolean) - CompleteArg = True - End Sub - End Class -End Namespace \ No newline at end of file diff --git a/SCrawler/API/Instagram/OptionsForm.vb b/SCrawler/API/Instagram/OptionsForm.vb index 3b96b4e..d6b3058 100644 --- a/SCrawler/API/Instagram/OptionsForm.vb +++ b/SCrawler/API/Instagram/OptionsForm.vb @@ -10,12 +10,12 @@ Imports PersonalUtilities.Forms Imports PersonalUtilities.Forms.Toolbars Namespace API.Instagram Friend Class OptionsForm : Implements IOkCancelToolbar - Private ReadOnly MyDefs As DefaultFormProps + Private ReadOnly MyDefs As DefaultFormOptions Private ReadOnly Property MyExchangeOptions As EditorExchangeOptions Friend Sub New(ByRef ExchangeOptions As EditorExchangeOptions) InitializeComponent() MyExchangeOptions = ExchangeOptions - MyDefs = New DefaultFormProps + MyDefs = New DefaultFormOptions End Sub Private Sub OptionsForm_Load(sender As Object, e As EventArgs) Handles Me.Load With MyDefs diff --git a/SCrawler/API/Instagram/SiteSettings.vb b/SCrawler/API/Instagram/SiteSettings.vb index bd03f70..cbb67a2 100644 --- a/SCrawler/API/Instagram/SiteSettings.vb +++ b/SCrawler/API/Instagram/SiteSettings.vb @@ -18,7 +18,8 @@ Imports Download = SCrawler.Plugin.ISiteSettings.Download Namespace API.Instagram Friend Class SiteSettings : Inherits SiteSettingsBase -#Region "Interface Declarations" +#Region "Declarations" +#Region "Images" Friend Overrides ReadOnly Property Icon As Icon Get Return My.Resources.InstagramIcon @@ -89,14 +90,31 @@ Namespace API.Instagram Friend Property IG_WWW_CLAIM As PropertyValue Friend ReadOnly Property SavedPostsUserName As PropertyValue - Friend ReadOnly Property StoriesAndTaggedReady As Boolean + Friend ReadOnly Property BaseAuthExists As Boolean Get - Return ACheck(IG_APP_ID.Value) And ACheck(IG_WWW_CLAIM.Value) And ACheck(CSRF_TOKEN.Value) + Return Responser.Cookies.Count > 0 And ACheck(IG_APP_ID.Value) And ACheck(IG_WWW_CLAIM.Value) And ACheck(CSRF_TOKEN.Value) End Get End Property + 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) + If Not CStr(Value).IsEmptyString Then Responser.Headers.Add(f, CStr(Value)) + Responser.SaveSettings() + End If + End If + End Sub #End Region #Region "Download properties" - Friend ReadOnly Property HashUpdateRequired As XMLValue(Of Boolean) Friend ReadOnly Property RequestsWaitTimer As PropertyValue @@ -121,7 +139,7 @@ Namespace API.Instagram Private ReadOnly Property TaggedNotifyLimitProvider As IFormatProvider #End Region #Region "429 bypass" - Friend ReadOnly Property DownloadingErrorDate As XMLValue(Of Date) + Private ReadOnly Property DownloadingErrorDate As XMLValue(Of Date) Friend Property LastApplyingValue As Integer? = Nothing Friend ReadOnly Property ReadyForDownload As Boolean Get @@ -134,8 +152,11 @@ Namespace API.Instagram End With End Get End Property - Friend ReadOnly Property LastDownloadDate As XMLValue(Of Date) - Friend ReadOnly Property LastRequestsCount As XMLValue(Of Integer) + Private ReadOnly Property LastDownloadDate As XMLValue(Of Date) + Private ReadOnly Property LastRequestsCount As XMLValue(Of Integer) + + Private Property LastRequestsCountLabel As PropertyValue + Private ReadOnly LastRequestsCountLabelStr As Func(Of Integer, String) = Function(r) $"Number of spent requests: {r.NumToGroupIntegral}" Private TooManyRequestsReadyForCatch As Boolean = True Friend Function GetWaitDate() As Date With DownloadingErrorDate @@ -155,7 +176,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 @@ -166,6 +187,9 @@ Namespace API.Instagram End Sub #End Region Friend Overrides ReadOnly Property Responser As WEB.Response + Private Initialized As Boolean = False +#End Region +#Region "Initializer" Friend Sub New(ByRef _XML As XmlFile, ByVal GlobalPath As SFile) MyBase.New(InstagramSite) Responser = New WEB.Response($"{SettingsFolderName}\Responser_{Site}.xml") @@ -192,7 +216,6 @@ Namespace API.Instagram SavedPostsUserName = New PropertyValue(String.Empty, GetType(String)) - 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)) @@ -216,39 +239,20 @@ Namespace API.Instagram DownloadingErrorDate.SetExtended("InstagramDownloadingErrorDate", Now.AddYears(-10), _XML, n) LastDownloadDate = New XMLValue(Of Date)("LastDownloadDate", Now.AddDays(-1), _XML, n) LastRequestsCount = New XMLValue(Of Integer)("LastRequestsCount", 0, _XML, n) + LastRequestsCountLabel = New PropertyValue(LastRequestsCountLabelStr.Invoke(LastRequestsCount.Value)) + AddHandler LastRequestsCount.OnValueChanged, Sub(sender, __name, __value) LastRequestsCountLabel.Value = LastRequestsCountLabelStr.Invoke(__value) UrlPatternUser = "https://www.instagram.com/{0}/" UserRegex = RParams.DMS("[htps:/]{7,8}.*?instagram.com/([^/]+)", 1) ImageVideoContains = "instagram.com" End Sub - Friend Overrides Function GetInstance(ByVal What As Download) As IPluginContentProvider - Select Case What - Case Download.Main : Return New UserData - Case Download.SavedPosts - Dim u As New UserData - DirectCast(u, UserDataBase).User = New UserInfo With {.Name = CStr(AConvert(Of String)(SavedPostsUserName.Value, String.Empty))} - Return u - End Select - Return Nothing - 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) - If Not CStr(Value).IsEmptyString Then Responser.Headers.Add(f, CStr(Value)) - Responser.SaveSettings() - End If - End If + Friend Overrides Sub BeginInit() End Sub + Friend Overrides Sub EndInit() + Initialized = True + End Sub +#End Region +#Region "PropertiesDataChecker" Private Function CheckHashControls(ByVal p As IEnumerable(Of PropertyData)) As Boolean If p.ListExists(2) Then @@ -292,20 +296,32 @@ Namespace API.Instagram End If Return False End Function - Friend Overrides Sub BeginInit() - End Sub - Friend Overrides Sub EndInit() - If (CStr(Hash.Value).IsEmptyString Or HashUpdateRequired) AndAlso Responser.Cookies.ListExists Then GatherInstaHash() - End Sub - Friend Overrides Function ReadyToDownload(ByVal What As Download) As Boolean - Return ActiveJobs < 2 AndAlso ReadyForDownload +#End Region +#Region "Plugin functions" + Friend Overrides Function GetInstance(ByVal What As Download) As IPluginContentProvider + Select Case What + Case Download.Main : Return New UserData + Case Download.SavedPosts + Dim u As New UserData + DirectCast(u, UserDataBase).User = New UserInfo With {.Name = CStr(AConvert(Of String)(SavedPostsUserName.Value, String.Empty))} + Return u + End Select + Return Nothing End Function #Region "Downloading" + Friend Overrides Function ReadyToDownload(ByVal What As Download) As Boolean + If ActiveJobs < 2 AndAlso ReadyForDownload AndAlso BaseAuthExists Then + Select Case What + Case Download.Main : Return ACheck(Hash.Value) + Case Download.SavedPosts : Return ACheck(HashSavedPosts.Value) + End Select + End If + Return False + End Function Private ActiveJobs As Integer = 0 Private _NextWNM As UserData.WNM = UserData.WNM.Notify Private _NextTagged As Boolean = True Friend Overrides Sub DownloadStarted(ByVal What As Download) - If CStr(Hash.Value).IsEmptyString Or HashUpdateRequired Then GatherInstaHash() ActiveJobs += 1 End Sub Friend Overrides Sub BeforeStartDownload(ByVal User As Object, ByVal What As Download) @@ -336,40 +352,8 @@ Namespace API.Instagram _NextTagged = True LastDownloadDate.Value = Now ActiveJobs -= 1 - If HashUpdateRequired Then MyMainLOG = "Check your Instagram credentials" End Sub #End Region - - Friend Function GatherInstaHash() As Boolean - Try - If Not Responser.Cookies.ListExists Then Throw New Exception("Instagram cookies does not set") - Dim rs As New RParams("preload"" href=""(https://static.cdninstagram.com/rsrc.php/[^""]+?.js[^""]*)""", Nothing, 1, RegexReturn.List) With {.MatchTimeOut = 10} - Dim h$ - Dim r$ = Responser.GetResponse("https://www.instagram.com",, EDP.ThrowException) - If Not r.IsEmptyString Then - Dim JsUrls As List(Of String) = RegexReplace(r, rs) - If JsUrls.ListExists Then - rs = New RParams("\{.+?var h=""([\w\d\S]+?)"".+?\)\.generatePaginationActionCreators", Nothing, 1) With {.MatchTimeOut = 10} - For Each url$ In JsUrls - r = Responser.GetResponse(url,, EDP.ReturnValue) - If Not r.IsEmptyString Then - h = RegexReplace(r, rs) - If Not h.IsEmptyString AndAlso h.Length > 30 Then - Hash.Value = h - HashUpdateRequired.Value = False - Return True - End If - End If - Next - End If - End If - Return False - Catch ex As Exception - HashUpdateRequired.Value = True - Hash.Value = String.Empty - Return ErrorsDescriber.Execute(EDP.SendInLog + EDP.ReturnValue, ex, "[SiteSettings.GaterInstaHash]", False) - End Try - End Function Friend Overrides Function GetSpecialDataF(ByVal URL As String) As IEnumerable(Of UserMedia) Return UserData.GetVideoInfo(URL, Responser, Me) End Function @@ -379,5 +363,6 @@ Namespace API.Instagram Using f As New OptionsForm(Options) : f.ShowDialog() : End Using End If End Sub +#End Region End Class End Namespace \ No newline at end of file diff --git a/SCrawler/API/Instagram/UserData.vb b/SCrawler/API/Instagram/UserData.vb index 598bb60..52e632d 100644 --- a/SCrawler/API/Instagram/UserData.vb +++ b/SCrawler/API/Instagram/UserData.vb @@ -12,18 +12,20 @@ Imports PersonalUtilities.Functions.RegularExpressions Imports PersonalUtilities.Tools.WEB Imports PersonalUtilities.Tools.WebDocuments.JSON Imports SCrawler.API.Base -Imports System.Threading Imports System.Net +Imports System.Threading Imports System.Reflection Imports UTypes = SCrawler.API.Base.UserMedia.Types Namespace API.Instagram Friend Class UserData : Inherits UserDataBase - Private Const MaxPostsCount As Integer = 200 +#Region "XML Names" Private Const Name_LastCursor As String = "LastCursor" Private Const Name_FirstLoadingDone As String = "FirstLoadingDone" Private Const Name_GetStories As String = "GetStories" Private Const Name_GetTagged As String = "GetTaggedData" Private Const Name_TaggedChecked As String = "TaggedChecked" +#End Region +#Region "Declarations" Private ReadOnly Property MySiteSettings As SiteSettings Get Return DirectCast(HOST.Source, SiteSettings) @@ -34,6 +36,8 @@ Namespace API.Instagram Private FirstLoadingDone As Boolean = False Friend Property GetStories As Boolean Friend Property GetTaggedData As Boolean +#End Region +#Region "Exchange options" Friend Overrides Function ExchangeOptionsGet() As Object Return New EditorExchangeOptions(HOST.Source) With {.GetStories = GetStories, .GetTagged = GetTaggedData} End Function @@ -45,6 +49,8 @@ Namespace API.Instagram End With End If End Sub +#End Region +#Region "Initializer, loader" Friend Sub New() End Sub Protected Overrides Sub LoadUserInformation_OptionalFields(ByRef Container As XmlFile, ByVal Loading As Boolean) @@ -62,7 +68,13 @@ Namespace API.Instagram Container.Add(Name_TaggedChecked, TaggedChecked.BoolToInteger) End If End Sub +#End Region #Region "Download data" + Private Class ExitException : Inherits Exception + Friend Sub New(ByRef CompleteArg As Boolean) + CompleteArg = True + End Sub + End Class Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken) Try _InstaHash = String.Empty @@ -80,7 +92,7 @@ Namespace API.Instagram If FirstLoadingDone Then LastCursor = String.Empty If IsSavedPosts Then DownloadPosts(Token) - ElseIf MySiteSettings.StoriesAndTaggedReady Then + ElseIf MySiteSettings.BaseAuthExists Then DownloadedTags = 0 If GetStories Then DownloadData(String.Empty, Sections.Stories, Token) If GetTaggedData Then DownloadData(String.Empty, Sections.Tagged, Token) @@ -100,6 +112,7 @@ Namespace API.Instagram Private Const StoriesFolder As String = "Stories" Private Const TaggedFolder As String = "Tagged" #Region "429 bypass" + Private Const MaxPostsCount As Integer = 200 Friend Property RequestsCount As Integer = 0 Friend Enum WNM As Integer Notify = 0 @@ -247,7 +260,6 @@ Namespace API.Instagram 'Check environment If Cursor.IsEmptyString And _InstaHash.IsEmptyString Then _ _InstaHash = CStr(If(IsSavedPosts, MySiteSettings.HashSavedPosts, MySiteSettings.Hash).Value) - AuthNullException.ThrowIfNull(Section, IsSavedPosts, MySiteSettings) If ID.IsEmptyString Then GetUserId() If ID.IsEmptyString Then Throw New ArgumentException("User ID is not detected", "ID") @@ -351,9 +363,6 @@ Namespace API.Instagram End If _DownloadComplete = True If HasNextPage And Not EndCursor.IsEmptyString Then DownloadData(EndCursor, Section, Token) - Catch iane As AuthNullException - ErrorsDescriber.Execute(EDP.SendInLog, iane) - Throw New ExitException(_DownloadComplete) Catch eex As ExitException Throw eex Catch oex As OperationCanceledException When Token.IsCancellationRequested @@ -433,6 +442,9 @@ Namespace API.Instagram ProcessException(DoEx, Token, $"downloading saved posts error [{URL}]") End Try End Sub + Protected Overrides Sub ReparseVideo(ByVal Token As CancellationToken) + End Sub + #End Region #Region "Obtain Media" Private Sub ObtainMedia(ByVal node As EContainer, ByVal PostID As String, ByVal PostDate As String, ByVal SpecFolder As String) @@ -630,11 +642,12 @@ Namespace API.Instagram End Try End Function #End Region - Protected Overrides Sub ReparseVideo(ByVal Token As CancellationToken) - End Sub +#Region "Download content" Protected Overrides Sub DownloadContent(ByVal Token As CancellationToken) DownloadContentDefault(Token) End Sub +#End Region +#Region "Exceptions" ''' '''
''' 1 - continue @@ -647,8 +660,7 @@ Namespace API.Instagram UserExists = False ElseIf Responser.StatusCode = HttpStatusCode.BadRequest Then HasError = True - MyMainLOG = $"Instagram credentials have expired: {ToString()} [{s}]" - MySiteSettings.HashUpdateRequired.Value = True + MyMainLOG = $"Instagram credentials have expired [{CInt(Responser.StatusCode)}]: {ToString()} [{s}]" ElseIf Responser.StatusCode = HttpStatusCode.Forbidden And s = Sections.Tagged Then Return 3 ElseIf Responser.StatusCode = 429 Then @@ -661,13 +673,14 @@ Namespace API.Instagram MyMainLOG = $"Number of requests before error 429: {RequestsCount}" Return 1 Else - MySiteSettings.HashUpdateRequired.Value = True - MyMainLOG = $"Instagram hash requested: {ToString()} [{s}]" + MyMainLOG = $"Instagram hash requested [{CInt(Responser.StatusCode)}]: {ToString()} [{s}]" If Not FromPE Then LogError(ex, Message) : HasError = True Return 0 End If Return 2 End Function +#End Region +#Region "Create media" Private Shared Function MediaFromData(ByVal t As UTypes, ByVal _URL As String, ByVal PostID As String, ByVal PostDate As String, Optional ByVal SpecialFolder As String = Nothing) As UserMedia _URL = LinkFormatterSecure(RegexReplace(_URL.Replace("\", String.Empty), LinkPattern)) @@ -677,6 +690,8 @@ Namespace API.Instagram m.SpecialFolder = SpecialFolder Return m End Function +#End Region +#Region "Standalone downloader" 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 @@ -697,9 +712,12 @@ Namespace API.Instagram Return ErrorsDescriber.Execute(EDP.ShowMainMsg + EDP.SendInLog, ex, "Instagram standalone downloader: fetch media error") End Try End Function +#End Region +#Region "IDisposable Support" Protected Overrides Sub Dispose(ByVal disposing As Boolean) If Not disposedValue And disposing Then _SavedPostsIDs.Clear() MyBase.Dispose(disposing) End Sub +#End Region End Class End Namespace \ No newline at end of file diff --git a/SCrawler/API/Reddit/Channel.vb b/SCrawler/API/Reddit/Channel.vb index 3741b27..968e111 100644 --- a/SCrawler/API/Reddit/Channel.vb +++ b/SCrawler/API/Reddit/Channel.vb @@ -44,10 +44,12 @@ Namespace API.Reddit Return ListAddList(Nothing, Posts).ListAddList(PostsLatest).ListSort End Get End Property - Private ReadOnly Property Source As IEnumerable(Of UserPost) Implements IRangeSwitcherContainer(Of UserPost).Source + Private Property Source As IEnumerable(Of UserPost) Implements IRangeSwitcherContainer(Of UserPost).Source Get Return Posts End Get + Set(ByVal s As IEnumerable(Of UserPost)) + End Set End Property Friend Property LatestParsedDate As Date? = Nothing Private _Downloading As Boolean = False diff --git a/SCrawler/API/Reddit/RedditViewSettingsForm.vb b/SCrawler/API/Reddit/RedditViewSettingsForm.vb index ee1c689..48c7cb6 100644 --- a/SCrawler/API/Reddit/RedditViewSettingsForm.vb +++ b/SCrawler/API/Reddit/RedditViewSettingsForm.vb @@ -12,12 +12,12 @@ Imports CView = SCrawler.API.Reddit.IRedditView.View Imports CPeriod = SCrawler.API.Reddit.IRedditView.Period Namespace API.Reddit Friend Class RedditViewSettingsForm : Implements IOkCancelToolbar - Private ReadOnly MyDefs As DefaultFormProps + Private ReadOnly MyDefs As DefaultFormOptions Private ReadOnly Property MyOptions As IRedditView Friend Sub New(ByRef opt As IRedditView) InitializeComponent() MyOptions = opt - MyDefs = New DefaultFormProps + MyDefs = New DefaultFormOptions End Sub Private Sub ChannelSettingsForm_Load(sender As Object, e As EventArgs) Handles Me.Load Try diff --git a/SCrawler/API/Reddit/UserData.vb b/SCrawler/API/Reddit/UserData.vb index 43a30bd..4ef07ba 100644 --- a/SCrawler/API/Reddit/UserData.vb +++ b/SCrawler/API/Reddit/UserData.vb @@ -664,6 +664,7 @@ Namespace API.Reddit f = SFile.Indexed_IndexFile(f,,, EDP.ReturnValue) End If End If + If f.Extension = "webp" And Settings.DownloadNativeImageFormat Then f.Extension = "jpg" f.Path = MyDir Try If (v.Type = UTypes.Video Or v.Type = UTypes.m3u8 Or (ImgurUrls.Count > 0 AndAlso f.Extension = "mp4")) And @@ -728,9 +729,10 @@ Namespace API.Reddit ElseIf Responser.StatusCode = HttpStatusCode.Forbidden Then UserSuspended = True ElseIf Responser.StatusCode = HttpStatusCode.BadGateway Or - Responser.StatusCode = HttpStatusCode.ServiceUnavailable Or - Responser.StatusCode = HttpStatusCode.GatewayTimeout Then + Responser.StatusCode = HttpStatusCode.ServiceUnavailable Then MyMainLOG = $"[{CInt(Responser.StatusCode)}] Reddit is currently unavailable ({ToString()})" + ElseIf Responser.StatusCode = HttpStatusCode.GatewayTimeout Then + Return 1 Else If Not FromPE Then LogError(ex, Message) : HasError = True Return 0 diff --git a/SCrawler/API/Twitter/SiteSettings.vb b/SCrawler/API/Twitter/SiteSettings.vb index c89bdbb..427ea16 100644 --- a/SCrawler/API/Twitter/SiteSettings.vb +++ b/SCrawler/API/Twitter/SiteSettings.vb @@ -6,11 +6,11 @@ ' ' This program is distributed in the hope that it will be useful, ' but WITHOUT ANY WARRANTY +Imports SCrawler.API.Base Imports SCrawler.Plugin Imports SCrawler.Plugin.Attributes Imports PersonalUtilities.Tools Imports PersonalUtilities.Functions.RegularExpressions -Imports SCrawler.API.Base Namespace API.Twitter Friend Class SiteSettings : Inherits SiteSettingsBase diff --git a/SCrawler/API/Twitter/UserData.vb b/SCrawler/API/Twitter/UserData.vb index f3a0c09..8bc984d 100644 --- a/SCrawler/API/Twitter/UserData.vb +++ b/SCrawler/API/Twitter/UserData.vb @@ -176,7 +176,8 @@ Namespace API.Twitter 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 + Return P4K + 'If LargeContained Then Return "large" Else Return P4K Else Return l(0).Data End If diff --git a/SCrawler/API/UserDataBind.vb b/SCrawler/API/UserDataBind.vb index a0b2a7e..7acfed4 100644 --- a/SCrawler/API/UserDataBind.vb +++ b/SCrawler/API/UserDataBind.vb @@ -267,6 +267,7 @@ Namespace API End Property #End Region #End Region +#Region "Initializers" Friend Sub New() _IsCollection = True Collections = New List(Of IUserData) @@ -276,6 +277,8 @@ Namespace API Me.New CollectionName = _Name End Sub +#End Region +#Region "Load, Update" Friend Overrides Sub LoadUserInformation() If Count > 0 Then Collections.ForEach(Sub(c) c.LoadUserInformation()) End Sub @@ -287,6 +290,8 @@ Namespace API End Sub Protected Overrides Sub LoadUserInformation_OptionalFields(ByRef Container As XmlFile, ByVal Loading As Boolean) End Sub +#End Region +#Region "Download" Friend Overrides Property DownloadTopCount As Integer? Get If Count > 0 Then @@ -312,8 +317,10 @@ Namespace API Return 0 End Function Private Sub User_OnUserUpdated(ByVal User As IUserData) - RaiseEvent_OnUserUpdated() + OnUserUpdated() End Sub +#End Region +#Region "Open site, folder" Friend Overrides Sub OpenSite(Optional ByVal e As ErrorsDescriber = Nothing) If Not e.Exists Then e = New ErrorsDescriber(EDP.SendInLog) If Count > 0 Then Collections.ForEach(Sub(c) c.OpenSite(e)) @@ -324,6 +331,7 @@ Namespace API Catch ex As Exception End Try End Sub +#End Region #Region "ICollection Support" Default Friend ReadOnly Property Item(ByVal Index As Integer) As IUserData Implements IMyEnumerator(Of IUserData).MyEnumeratorObject Get @@ -353,7 +361,7 @@ Namespace API End If ImageHandler(_Item, False) AddRemoveBttDeleteHandler(.Self, True) - AddHandler .Self.OnUserUpdated, AddressOf User_OnUserUpdated + AddHandler .Self.UserUpdated, AddressOf User_OnUserUpdated End With Else Throw New InvalidOperationException("User data was not moved to the collection folder") @@ -367,7 +375,7 @@ Namespace API With Collections.Last If _CollectionName.IsEmptyString Then _CollectionName = .CollectionName AddRemoveBttDeleteHandler(.Self, True) - AddHandler .OnUserUpdated, AddressOf User_OnUserUpdated + AddHandler .UserUpdated, AddressOf User_OnUserUpdated End With Else Collections.RemoveAt(Count - 1) diff --git a/SCrawler/Channels/ChannelViewForm.Designer.vb b/SCrawler/Channels/ChannelViewForm.Designer.vb index f2a31ba..bbf55c6 100644 --- a/SCrawler/Channels/ChannelViewForm.Designer.vb +++ b/SCrawler/Channels/ChannelViewForm.Designer.vb @@ -15,8 +15,6 @@ Partial Friend Class ChannelViewForm : Inherits System.Windows.Forms.Form Private Sub InitializeComponent() Me.components = New System.ComponentModel.Container() Dim SEP_1 As System.Windows.Forms.ToolStripSeparator - Dim SEP_2 As System.Windows.Forms.ToolStripSeparator - Dim SEP_3 As System.Windows.Forms.ToolStripSeparator Dim CONTEXT_SEP_1 As System.Windows.Forms.ToolStripSeparator Dim CONTEXT_SEP_2 As System.Windows.Forms.ToolStripSeparator Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(ChannelViewForm)) @@ -34,11 +32,9 @@ Partial Friend Class ChannelViewForm : Inherits System.Windows.Forms.Form Me.BTT_C_OPEN_POST = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_C_OPEN_PICTURE = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_C_OPEN_FOLDER = New System.Windows.Forms.ToolStripMenuItem() - Me.BTT_C_ADD_TO_BLACKLIST = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_C_REMOVE_FROM_SELECTED = New System.Windows.Forms.ToolStripMenuItem() + Me.BTT_C_ADD_TO_BLACKLIST = New System.Windows.Forms.ToolStripMenuItem() SEP_1 = New System.Windows.Forms.ToolStripSeparator() - SEP_2 = New System.Windows.Forms.ToolStripSeparator() - SEP_3 = New System.Windows.Forms.ToolStripSeparator() CONTEXT_SEP_1 = New System.Windows.Forms.ToolStripSeparator() CONTEXT_SEP_2 = New System.Windows.Forms.ToolStripSeparator() Me.ToolbarTOP.SuspendLayout() @@ -51,25 +47,20 @@ Partial Friend Class ChannelViewForm : Inherits System.Windows.Forms.Form SEP_1.Name = "SEP_1" SEP_1.Size = New System.Drawing.Size(6, 25) ' - 'SEP_2 - ' - SEP_2.Name = "SEP_2" - SEP_2.Size = New System.Drawing.Size(6, 25) - ' - 'SEP_3 - ' - SEP_3.Name = "SEP_3" - SEP_3.Size = New System.Drawing.Size(6, 25) - ' 'CONTEXT_SEP_1 ' CONTEXT_SEP_1.Name = "CONTEXT_SEP_1" CONTEXT_SEP_1.Size = New System.Drawing.Size(302, 6) ' + 'CONTEXT_SEP_2 + ' + CONTEXT_SEP_2.Name = "CONTEXT_SEP_2" + CONTEXT_SEP_2.Size = New System.Drawing.Size(302, 6) + ' 'ToolbarTOP ' Me.ToolbarTOP.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden - Me.ToolbarTOP.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_DOWNLOAD, Me.BTT_STOP, SEP_1, Me.BTT_ADD_USERS, SEP_2, SEP_3}) + Me.ToolbarTOP.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_DOWNLOAD, Me.BTT_STOP, SEP_1, Me.BTT_ADD_USERS}) Me.ToolbarTOP.Location = New System.Drawing.Point(0, 0) Me.ToolbarTOP.Name = "ToolbarTOP" Me.ToolbarTOP.Size = New System.Drawing.Size(744, 25) @@ -138,7 +129,7 @@ Partial Friend Class ChannelViewForm : Inherits System.Windows.Forms.Form ' Me.LCONTEXT.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_C_OPEN_USER, Me.BTT_C_OPEN_POST, Me.BTT_C_OPEN_PICTURE, Me.BTT_C_OPEN_FOLDER, CONTEXT_SEP_1, Me.BTT_C_REMOVE_FROM_SELECTED, CONTEXT_SEP_2, Me.BTT_C_ADD_TO_BLACKLIST}) Me.LCONTEXT.Name = "LCONTEXT" - Me.LCONTEXT.Size = New System.Drawing.Size(306, 170) + Me.LCONTEXT.Size = New System.Drawing.Size(306, 148) ' 'BTT_C_OPEN_USER ' @@ -164,17 +155,6 @@ Partial Friend Class ChannelViewForm : Inherits System.Windows.Forms.Form Me.BTT_C_OPEN_FOLDER.Size = New System.Drawing.Size(305, 22) Me.BTT_C_OPEN_FOLDER.Text = "Open folder" ' - 'BTT_C_ADD_TO_BLACKLIST - ' - Me.BTT_C_ADD_TO_BLACKLIST.Name = "BTT_C_ADD_TO_BLACKLIST" - Me.BTT_C_ADD_TO_BLACKLIST.Size = New System.Drawing.Size(305, 22) - Me.BTT_C_ADD_TO_BLACKLIST.Text = "Add/Remove this user to/from the BlackList" - ' - 'CONTEXT_SEP_2 - ' - CONTEXT_SEP_2.Name = "CONTEXT_SEP_2" - CONTEXT_SEP_2.Size = New System.Drawing.Size(302, 6) - ' 'BTT_C_REMOVE_FROM_SELECTED ' Me.BTT_C_REMOVE_FROM_SELECTED.AutoToolTip = True @@ -183,6 +163,12 @@ Partial Friend Class ChannelViewForm : Inherits System.Windows.Forms.Form Me.BTT_C_REMOVE_FROM_SELECTED.Text = "Remove user from selected" Me.BTT_C_REMOVE_FROM_SELECTED.ToolTipText = "Remove this user from selected users if user was added to" ' + 'BTT_C_ADD_TO_BLACKLIST + ' + Me.BTT_C_ADD_TO_BLACKLIST.Name = "BTT_C_ADD_TO_BLACKLIST" + Me.BTT_C_ADD_TO_BLACKLIST.Size = New System.Drawing.Size(305, 22) + Me.BTT_C_ADD_TO_BLACKLIST.Text = "Add/Remove this user to/from the BlackList" + ' 'ChannelViewForm ' Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!) diff --git a/SCrawler/Channels/ChannelViewForm.resx b/SCrawler/Channels/ChannelViewForm.resx index 0eaaeec..814e7af 100644 --- a/SCrawler/Channels/ChannelViewForm.resx +++ b/SCrawler/Channels/ChannelViewForm.resx @@ -120,15 +120,12 @@ False - - False - - - False - False + + False + 241, 17 @@ -141,9 +138,6 @@ 342, 17 - - False - diff --git a/SCrawler/Channels/ChannelViewForm.vb b/SCrawler/Channels/ChannelViewForm.vb index e3b568f..a59155e 100644 --- a/SCrawler/Channels/ChannelViewForm.vb +++ b/SCrawler/Channels/ChannelViewForm.vb @@ -16,8 +16,8 @@ Imports System.Threading Imports SCrawler.API.Base Imports SCrawler.API.Reddit Imports SCrawler.Plugin.Hosts -Imports CmbDefaultButtons = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons -Imports RButton = PersonalUtilities.Tools.RangeSwitcherButton.Types +Imports ADB = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons +Imports RButton = PersonalUtilities.Forms.Toolbars.RangeSwitcherToolbar.ControlItem Friend Class ChannelViewForm : Implements IChannelLimits Friend Event OnUsersAdded(ByVal StartIndex As Integer) Friend Event OnDownloadDone As NotificationEventHandler @@ -49,7 +49,7 @@ Friend Class ChannelViewForm : Implements IChannelLimits End Structure #End Region #Region "Declarations" - Private ReadOnly MyDefs As DefaultFormProps + Private ReadOnly MyDefs As DefaultFormOptions #Region "Controls" Private WithEvents CMB_CHANNELS As ComboBoxExtended Private WithEvents CH_HIDE_EXISTS_USERS As CheckBox @@ -125,7 +125,7 @@ Friend Class ChannelViewForm : Implements IChannelLimits Private ReadOnly HOST As SettingsHost Private ReadOnly PendingUsers As List(Of PendingUser) Private ReadOnly LNC As New ListAddParams(LAP.NotContainsOnly) - Private WithEvents MyRange As RangeSwitcher(Of UserPost) + Private WithEvents MyRange As RangeSwitcherToolbar(Of UserPost) Private ReadOnly SelectorExpression As Predicate(Of UserPost) = Function(ByVal Post As UserPost) As Boolean If Post.UserID.ToLower = "[deleted]" Or Settings.BlackList.Contains(Post.UserID) Then Return False @@ -141,7 +141,7 @@ Friend Class ChannelViewForm : Implements IChannelLimits #Region "Initializer and form methods" Friend Sub New() InitializeComponent() - MyDefs = New DefaultFormProps + MyDefs = New DefaultFormOptions CProgress = New MyProgress(ToolbarBOTTOM, PR_CN, LBL_STATUS, "Downloading data") With {.PerformMod = 10, .DropCurrentProgressOnTotalChange = False} CProvider = New ANumbers With {.FormatOptions = ANumbers.Options.GroupIntegral} LimitProvider = New ADateTime("dd.MM.yyyy HH:mm") @@ -157,10 +157,10 @@ Friend Class ChannelViewForm : Implements IChannelLimits .ListMaxDropDownItems = 15, .CaptionPadding = New Padding(0, 3, 0, 0) } - CMB_CHANNELS.Buttons.AddRange({CmbDefaultButtons.Refresh, CmbDefaultButtons.Add, CmbDefaultButtons.Delete, - New ActionButton(CmbDefaultButtons.Up) With {.ToolTipText = "Previous item (F1)"}, - New ActionButton(CmbDefaultButtons.Down) With {.ToolTipText = "Next item (F4)"}, - CmbDefaultButtons.Edit, CmbDefaultButtons.Info}) + CMB_CHANNELS.Buttons.AddRange({ADB.Refresh, ADB.Add, ADB.Delete, + New ActionButton(ADB.Up) With {.ToolTipText = "Previous item (F1)"}, + New ActionButton(ADB.Down) With {.ToolTipText = "Next item (F4)"}, + ADB.Edit, ADB.Info}) TXT_LIMIT = New TextBoxExtended With { .CaptionText = "Limit", .Margin = New Padding(2), @@ -186,6 +186,16 @@ Friend Class ChannelViewForm : Implements IChannelLimits TT_MAIN.SetToolTip(CH_HIDE_EXISTS_USERS, "Hide users which already exists in collection") TT_MAIN.SetToolTip(OPT_LIMITS_COUNT, "Total posts count limit") TT_MAIN.SetToolTip(OPT_LIMITS_POST, "Looking limit till post(-s) (comma separated)") + MyRange = New RangeSwitcherToolbar(Of UserPost)(ToolbarTOP) + With MyRange + .Switcher = New RangeSwitcher(Of UserPost) With {.Selector = SelectorExpression} + .Buttons = {RButton.First, RButton.Previous, RButton.Label, RButton.Next, RButton.Last, RButton.Separator} + .AutoToolTip = True + .ButtonKey(RButton.Previous) = Keys.F2 + .ButtonKey(RButton.Next) = Keys.F3 + .LabelNumbersProvider = CProvider + .AddThisToolbar() + End With ToolbarTOP.Items.AddRange({CMB_CHANNELS.GetControlHost, New ToolStripSeparator, LBL_LIMITS, @@ -198,17 +208,6 @@ Friend Class ChannelViewForm : Implements IChannelLimits New ToolStripSeparator, New ToolStripControlHost(CH_HIDE_EXISTS_USERS), BTT_SHOW_STATS}) - MyRange = New RangeSwitcher(Of UserPost) With {.Selector = SelectorExpression} - With MyRange - .Limit = ImagesInRow * ImagesRows - .InsertButtons(ToolbarTOP,, 5) - .SetButtonKey(RButton.Previous, Keys.F2) - .SetButtonKey(RButton.Next, Keys.F3) - .BindForm(Me) - .LabelNumbersProvider = CProvider - .LabelShowAbsolutIndexes = False - .UpdateControls() - End With AddHandler Settings.ChannelsImagesColumns.OnValueChanged, AddressOf ImagesCountChanged AddHandler Settings.ChannelsImagesRows.OnValueChanged, AddressOf ImagesCountChanged End Sub @@ -344,8 +343,7 @@ Friend Class ChannelViewForm : Implements IChannelLimits CH_HIDE_EXISTS_USERS.Enabled = False CMB_CHANNELS.Enabled(True) = False BTT_SHOW_STATS.Enabled = False - MyRange.EnableButton(RButton.Previous, False) - MyRange.EnableButton(RButton.Next, False) + MyRange.Enabled = False End If End Sub Dim c As Channel @@ -374,7 +372,7 @@ Friend Class ChannelViewForm : Implements IChannelLimits End If If Not c Is Nothing Then SetLimitsByChannel(c) - MyRange.ChangeSource(c) + MyRange.Source = c End If Else MsgBoxE("No one channels detected", MsgBoxStyle.Exclamation) @@ -403,10 +401,8 @@ Friend Class ChannelViewForm : Implements IChannelLimits CMB_CHANNELS.Enabled(True) = True BTT_SHOW_STATS.Enabled = True CMB_CHANNELS_ActionOnCheckedChange(CMB_CHANNELS.Checked) - With MyRange - .EnableButton(RButton.Previous, .Count > 0 AndAlso .CurrentIndex > 0) - .EnableButton(RButton.Next, .Count > 0 AndAlso .CurrentIndex < .Max) - End With + MyRange.Enabled = True + MyRange.UpdateControls() End If End Try End Sub @@ -573,14 +569,14 @@ Friend Class ChannelViewForm : Implements IChannelLimits Private Sub CMB_CHANNELS_ActionSelectedItemChanged(ByVal _Item As ListViewItem) Handles CMB_CHANNELS.ActionSelectedItemChanged SetLimitsByChannel() Dim c As Channel = GetCurrentChannel() - If Not c Is Nothing Then MyRange.ChangeSource(c, EDP.SendInLog) + If Not c Is Nothing Then MyRange.Source = c End Sub Private Sub CMB_CHANNELS_ActionOnButtonClick(ByVal Sender As ActionButton) Handles CMB_CHANNELS.ActionOnButtonClick Dim c As Channel Select Case Sender.DefaultButton - Case CmbDefaultButtons.Refresh : RefillChannels() - Case CmbDefaultButtons.Add : AddNewChannel() - Case CmbDefaultButtons.Delete + Case ADB.Refresh : RefillChannels() + Case ADB.Add : AddNewChannel() + Case ADB.Delete Try c = GetCurrentChannel() If Not c Is Nothing AndAlso MsgBoxE($"Do you really want to delete channel [{c}]?", MsgBoxStyle.Exclamation + MsgBoxStyle.YesNo) = 0 Then @@ -590,9 +586,9 @@ Friend Class ChannelViewForm : Implements IChannelLimits Catch ex As Exception ErrorsDescriber.Execute(EDP.LogMessageValue, ex, "Error on trying to delete channel") End Try - Case CmbDefaultButtons.Up : ChangeComboIndex(-1) - Case CmbDefaultButtons.Down : ChangeComboIndex(1) - Case CmbDefaultButtons.Edit + Case ADB.Up : ChangeComboIndex(-1) + Case ADB.Down : ChangeComboIndex(1) + Case ADB.Edit Try c = GetCurrentChannel() If Not c Is Nothing Then @@ -604,7 +600,7 @@ Friend Class ChannelViewForm : Implements IChannelLimits Catch ex As Exception ErrorsDescriber.Execute(EDP.LogMessageValue, ex, "Error on trying to edit channel") End Try - Case CmbDefaultButtons.Info + Case ADB.Info Try c = GetCurrentChannel() If Not c Is Nothing Then MsgBoxE({c.GetChannelStats(True), "Channel statistics"}) @@ -621,8 +617,8 @@ Friend Class ChannelViewForm : Implements IChannelLimits LBL_LIMIT_TEXT.Text = String.Empty ChangeComboIndex(0) Else - CMB_CHANNELS.Button(ActionButton.BTT_UP_NAME).Enabled = False - CMB_CHANNELS.Button(ActionButton.BTT_DOWN_NAME).Enabled = False + CMB_CHANNELS.Button(ADB.Up).Enabled = False + CMB_CHANNELS.Button(ADB.Down).Enabled = False SetLimitsByChannel() End If End Sub @@ -661,8 +657,8 @@ Friend Class ChannelViewForm : Implements IChannelLimits _ComboUpEnabled = i > 0 And c > 0 _ComboDownEnabled = i < c And c > 0 End If - CMB_CHANNELS.Button(ActionButton.BTT_UP_NAME).Enabled = _ComboUpEnabled - CMB_CHANNELS.Button(ActionButton.BTT_DOWN_NAME).Enabled = _ComboDownEnabled + CMB_CHANNELS.Button(ADB.Up).Enabled = _ComboUpEnabled + CMB_CHANNELS.Button(ADB.Down).Enabled = _ComboDownEnabled Catch ex As Exception ErrorsDescriber.Execute(EDP.LogMessageValue, ex, "ComboBox index changing") End Try @@ -799,10 +795,10 @@ Friend Class ChannelViewForm : Implements IChannelLimits #Region "MyRange" Private Sub ImagesCountChanged(ByVal Sender As Object, ByVal _Name As String, ByVal _Value As Object) AppendPendingUsers() - MyRange.Update(ImagesInRow * ImagesRows) - MyRange.GoTo(0, EDP.SendInLog) + MyRange.Limit = ImagesInRow * ImagesRows + MyRange.GoTo(0) End Sub - Private Sub MyRange_IndexChanged(ByVal Index As Integer) Handles MyRange.IndexChanged + Private Sub MyRange_IndexChanged(ByVal Sender As IRangeSwitcherProvider, ByVal Index As Integer) Handles MyRange.IndexChanged Try If MyDefs.Initializing Then Exit Sub AppendPendingUsers() @@ -832,8 +828,8 @@ Friend Class ChannelViewForm : Implements IChannelLimits ErrorsDescriber.Execute(EDP.LogMessageValue, ex) End Try End Sub - Private Sub MyRange_RangesChanged(ByVal Sender As RangeSwitcher(Of UserPost)) Handles MyRange.RangesChanged - If Sender.Count > 0 Then MyRange_IndexChanged(0) + Private Sub MyRange_RangesChanged(ByVal Sender As IRangeSwitcherProvider, ByVal Index As Integer) Handles MyRange.RangesChanged + If Sender.Count > 0 Then MyRange_IndexChanged(Nothing, 0) End Sub #End Region End Class \ No newline at end of file diff --git a/SCrawler/Channels/ChannelsStatsForm.Designer.vb b/SCrawler/Channels/ChannelsStatsForm.Designer.vb index 22fa9a2..5293d85 100644 --- a/SCrawler/Channels/ChannelsStatsForm.Designer.vb +++ b/SCrawler/Channels/ChannelsStatsForm.Designer.vb @@ -55,15 +55,12 @@ Partial Friend Class ChannelsStatsForm : Inherits System.Windows.Forms.Form 'CMB_CHANNELS ' ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image) - ActionButton1.Index = 0 - ActionButton1.Name = "BTT_COMBOBOX_ARROW" - ActionButton1.Visible = False + ActionButton1.Name = "Clear" ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image) - ActionButton2.Index = 1 - ActionButton2.Name = "BTT_CLEAR" + ActionButton2.Name = "Delete" ActionButton3.BackgroundImage = CType(resources.GetObject("ActionButton3.BackgroundImage"), System.Drawing.Image) - ActionButton3.Index = 2 - ActionButton3.Name = "BTT_DELETE" + ActionButton3.Name = "ArrowDown" + ActionButton3.Visible = False Me.CMB_CHANNELS.Buttons.Add(ActionButton1) Me.CMB_CHANNELS.Buttons.Add(ActionButton2) Me.CMB_CHANNELS.Buttons.Add(ActionButton3) diff --git a/SCrawler/Channels/ChannelsStatsForm.resx b/SCrawler/Channels/ChannelsStatsForm.resx index 1e95d2e..f45e744 100644 --- a/SCrawler/Channels/ChannelsStatsForm.resx +++ b/SCrawler/Channels/ChannelsStatsForm.resx @@ -122,6 +122,43 @@ + + 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 @@ -209,43 +246,6 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6LEtW/4flgYiLD1qeX0A AAAASUVORK5CYII= - - - - - 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 diff --git a/SCrawler/Channels/ChannelsStatsForm.vb b/SCrawler/Channels/ChannelsStatsForm.vb index a5db274..7126fb0 100644 --- a/SCrawler/Channels/ChannelsStatsForm.vb +++ b/SCrawler/Channels/ChannelsStatsForm.vb @@ -11,11 +11,11 @@ Imports PersonalUtilities.Forms Imports PersonalUtilities.Forms.Controls.Base Imports PersonalUtilities.Forms.Toolbars Friend Class ChannelsStatsForm : Implements IOkCancelDeleteToolbar - Private ReadOnly MyDefs As DefaultFormProps + Private ReadOnly MyDefs As DefaultFormOptions Friend Property DeletedChannels As Integer = 0 Friend Sub New() InitializeComponent() - MyDefs = New DefaultFormProps + MyDefs = New DefaultFormOptions End Sub Private Sub ChannelsStatsForm_Load(sender As Object, e As EventArgs) Handles Me.Load Try diff --git a/SCrawler/Download/ActiveDownloadingProgress.Designer.vb b/SCrawler/Download/ActiveDownloadingProgress.Designer.vb index f4482f5..c82c577 100644 --- a/SCrawler/Download/ActiveDownloadingProgress.Designer.vb +++ b/SCrawler/Download/ActiveDownloadingProgress.Designer.vb @@ -36,8 +36,8 @@ Namespace DownloadObjects Me.TP_MAIN.Location = New System.Drawing.Point(0, 0) Me.TP_MAIN.Name = "TP_MAIN" Me.TP_MAIN.RowCount = 1 - Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 62.0!)) - Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 62.0!)) + Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 64.0!)) + Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 64.0!)) Me.TP_MAIN.Size = New System.Drawing.Size(434, 61) Me.TP_MAIN.TabIndex = 0 ' diff --git a/SCrawler/Download/AutoDownloader.vb b/SCrawler/Download/AutoDownloader.vb index a3c0480..a21875b 100644 --- a/SCrawler/Download/AutoDownloader.vb +++ b/SCrawler/Download/AutoDownloader.vb @@ -8,12 +8,13 @@ ' but WITHOUT ANY WARRANTY Imports System.Threading Imports PersonalUtilities.Functions.XML +Imports PersonalUtilities.Functions.XML.Base Imports PersonalUtilities.Tools.Notifications Imports SCrawler.DownloadObjects.Groups Imports SCrawler.API Imports SCrawler.API.Base Namespace DownloadObjects - Friend Class AutoDownloader : Inherits GroupParameters + Friend Class AutoDownloader : Inherits GroupParameters : Implements IEContainerProvider Friend Event UserFind(ByVal Key As String, ByVal Activate As Boolean) Friend Enum Modes As Integer None = 0 @@ -31,6 +32,7 @@ Namespace DownloadObjects Private ReadOnly UserKeys As List(Of NotifiedUser) Private Class NotifiedUser : Implements IDisposable Private ReadOnly Property User As IUserData + Friend ReadOnly Property IUserDataKey As String Private ReadOnly Property Key As String Private ReadOnly Property KeyFolder As String Private ReadOnly Property KeySite As String @@ -49,6 +51,7 @@ Namespace DownloadObjects Friend Sub New(ByVal _Key As String, ByRef _User As IUserData) Me.New(_Key) User = _User + IUserDataKey = _User.Key End Sub Public Shared Widening Operator CType(ByVal Key As String) As NotifiedUser Return New NotifiedUser(Key) @@ -138,10 +141,12 @@ Namespace DownloadObjects Private Const Name_Groups As String = "Groups" Private Const Name_Labels As String = "Labels" Private Const Name_Timer As String = "Timer" + Private Const Name_StartupDelay As String = "StartupDelay" Private Const Name_LastDownloadDate As String = "LastDownloadDate" Private Const Name_ShowNotifications As String = "Notify" #End Region #Region "Declarations" + Friend Property Source As Scheduler Private _Mode As Modes = Modes.None Friend Property Mode As Modes Get @@ -154,36 +159,99 @@ Namespace DownloadObjects End Property Friend ReadOnly Property Groups As List(Of String) Friend Property Timer As Integer = DefaultTimer + Friend Property StartupDelay As Integer = 0 Friend Property ShowNotifications As Boolean = True - Friend Property LastDownloadDate As Date = Now.AddYears(-1) +#Region "Date" + Private ReadOnly LastDownloadDateXML As Date? = Nothing + Private _LastDownloadDate As Date = Now.AddYears(-1) + Private _LastDownloadDateChanged As Boolean = False + Friend Property LastDownloadDate As Date + Get + Return _LastDownloadDate + End Get + Set(ByVal d As Date) + _LastDownloadDate = d + If Not Initialization Then _LastDownloadDateChanged = True + End Set + End Property Private ReadOnly DateProvider As New ADateTime(ADateTime.Formats.BaseDateTime) + Private Function GetLastDateString() As String + If LastDownloadDateXML.HasValue Or _LastDownloadDateChanged Then + Return LastDownloadDate.ToStringDate(ADateTime.Formats.BaseDateTime) + Else + Return "never" + End If + End Function + Private Function GetNextDateString() As String + If _LastDownloadDateChanged Then + Return LastDownloadDate.AddMinutes(Timer).ToStringDate(ADateTime.Formats.BaseDateTime) + Else + Return _StartTime.AddMinutes(StartupDelay).ToStringDate(ADateTime.Formats.BaseDateTime) + End If + End Function +#End Region Friend ReadOnly Property Information As String Get - Return $"Last download date: {LastDownloadDate.ToStringDate(ADateTime.Formats.BaseDateTime)} " & - $"({IIf(Working, "working", "stopped")}{IIf(Working And Pause, ", paused", String.Empty)})" + Return $"Last download date: {GetLastDateString()} ({GetWorkingState()})" End Get End Property + Private Function GetWorkingState() As String + Dim OutStr$ + If Working Then + If StartupDelay > 0 And _StartTime.AddMinutes(StartupDelay) > Now Then + OutStr = $"delayed until {_StartTime.AddMinutes(StartupDelay).ToStringDate(ADateTime.Formats.BaseDateTime)}" + ElseIf _StopRequested Then + OutStr = "stopping" + Else + OutStr = "working" + End If + If Pause Then OutStr &= ", paused" + Else + OutStr = "stopped" + End If + Return OutStr + End Function + Public Overrides Function ToString() As String + Return $"{Name} ({GetWorkingState()}): last download date: {GetLastDateString()}; next run: {GetNextDateString()}" + End Function Private File As SFile = $"Settings\AutoDownload.xml" Private AThread As Thread #End Region #Region "Initializer" - Friend Sub New() + Private ReadOnly Initialization As Boolean = True + Private _IsNewPlan As Boolean = False + Friend ReadOnly Property IsNewPlan As Boolean + Get + Return _IsNewPlan + End Get + End Property + Friend Sub New(Optional ByVal IsNewPlan As Boolean = False) Groups = New List(Of String) UserKeys = New List(Of NotifiedUser) - If File.Exists Then - Using x As New XmlFile(File) - Mode = x.Value(Name_Mode).FromXML(Of Integer)(Modes.None) - Groups.ListAddList(x.Value(Name_Groups).StringToList(Of String)("|"), LAP.NotContainsOnly) - Labels.ListAddList(x.Value(Name_Labels).StringToList(Of String)("|"), LAP.NotContainsOnly) - Temporary = x.Value(Name_Temporary).FromXML(Of Integer)(CheckState.Indeterminate) - Favorite = x.Value(Name_Favorite).FromXML(Of Integer)(CheckState.Indeterminate) - ReadyForDownload = x.Value(Name_ReadyForDownload).FromXML(Of Boolean)(True) - ReadyForDownloadIgnore = x.Value(Name_ReadyForDownloadIgnore).FromXML(Of Boolean)(False) - Timer = x.Value(Name_Timer).FromXML(Of Integer)(DefaultTimer) - ShowNotifications = x.Value(Name_ShowNotifications).FromXML(Of Boolean)(True) - LastDownloadDate = AConvert(Of Date)(x.Value(Name_LastDownloadDate), DateProvider, Now.AddYears(-1)) - End Using + _IsNewPlan = IsNewPlan + End Sub + Friend Sub New(ByVal x As EContainer) + Me.New + Name = x.Value(Name_Name).FromXML(Of String)("Default") + Mode = x.Value(Name_Mode).FromXML(Of Integer)(Modes.None) + Groups.ListAddList(x.Value(Name_Groups).StringToList(Of String)("|"), LAP.NotContainsOnly) + Labels.ListAddList(x.Value(Name_Labels).StringToList(Of String)("|"), LAP.NotContainsOnly) + Temporary = x.Value(Name_Temporary).FromXML(Of Integer)(CheckState.Indeterminate) + Favorite = x.Value(Name_Favorite).FromXML(Of Integer)(CheckState.Indeterminate) + ReadyForDownload = x.Value(Name_ReadyForDownload).FromXML(Of Boolean)(True) + ReadyForDownloadIgnore = x.Value(Name_ReadyForDownloadIgnore).FromXML(Of Boolean)(False) + Timer = x.Value(Name_Timer).FromXML(Of Integer)(DefaultTimer) + If Timer <= 0 Then Timer = DefaultTimer + StartupDelay = x.Value(Name_StartupDelay).FromXML(Of Integer)(0) + If StartupDelay < 0 Then StartupDelay = 0 + ShowNotifications = x.Value(Name_ShowNotifications).FromXML(Of Boolean)(True) + LastDownloadDateXML = AConvert(Of Date)(x.Value(Name_LastDownloadDate), DateProvider, Nothing) + If LastDownloadDateXML.HasValue Then + LastDownloadDate = LastDownloadDateXML.Value + Else + LastDownloadDate = Now.AddYears(-1) End If + Initialization = False End Sub #End Region #Region "Groups Support" @@ -202,33 +270,37 @@ Namespace DownloadObjects #End Region #Region "Update" Friend Sub Update() - Try - Using x As New XmlFile With {.Name = "Settings"} - x.Add(Name_Mode, CInt(Mode)) - x.Add(Name_Groups, Groups.ListToString("|")) - x.Add(Name_Labels, Labels.ListToString("|")) - x.Add(Name_Temporary, CInt(Temporary)) - x.Add(Name_Favorite, CInt(Favorite)) - x.Add(Name_ReadyForDownload, ReadyForDownload.BoolToInteger) - x.Add(Name_ReadyForDownloadIgnore, ReadyForDownloadIgnore.BoolToInteger) - x.Add(Name_Timer, Timer) - x.Add(Name_ShowNotifications, ShowNotifications.BoolToInteger) - x.Add(Name_LastDownloadDate, CStr(AConvert(Of String)(LastDownloadDate, DateProvider, String.Empty))) - x.Save(File) - End Using - Catch ex As Exception - ErrorsDescriber.Execute(EDP.SendInLog, ex, "[AutoDownloader.Update]") - End Try + If Not Source Is Nothing Then Source.Update() End Sub + Private Function ToEContainer(Optional ByVal e As ErrorsDescriber = Nothing) As EContainer Implements IEContainerProvider.ToEContainer + Return New EContainer(Scheduler.Name_Plan, String.Empty) From { + New EContainer(Name_Name, Name), + New EContainer(Name_Mode, CInt(Mode)), + New EContainer(Name_Groups, Groups.ListToString("|")), + New EContainer(Name_Labels, Labels.ListToString("|")), + New EContainer(Name_Temporary, CInt(Temporary)), + New EContainer(Name_Favorite, CInt(Favorite)), + New EContainer(Name_ReadyForDownload, ReadyForDownload.BoolToInteger), + New EContainer(Name_ReadyForDownloadIgnore, ReadyForDownloadIgnore.BoolToInteger), + New EContainer(Name_Timer, Timer), + New EContainer(Name_StartupDelay, StartupDelay), + New EContainer(Name_ShowNotifications, ShowNotifications.BoolToInteger), + New EContainer(Name_LastDownloadDate, CStr(AConvert(Of String)(If(LastDownloadDateXML.HasValue Or _LastDownloadDateChanged, + CObj(LastDownloadDate), Nothing), DateProvider, String.Empty))) + } + End Function #End Region #Region "Execution" - Private ReadOnly Property Working As Boolean + Friend ReadOnly Property Working As Boolean Get Return If(AThread?.IsAlive, False) End Get End Property - Friend Sub Start() - If Not If(AThread?.IsAlive, False) And Not Mode = Modes.None Then + Private _StartTime As Date = Now + Friend Sub Start(ByVal Init As Boolean) + If Init Then _StartTime = Now + _IsNewPlan = False + If Not Working And Not Mode = Modes.None Then AThread = New Thread(New ThreadStart(AddressOf Checker)) AThread.SetApartmentState(ApartmentState.MTA) AThread.Start() @@ -239,10 +311,18 @@ Namespace DownloadObjects Friend Sub [Stop]() If Working Then _StopRequested = True End Sub + Friend Sub Skip() + If LastDownloadDate.AddMinutes(Timer) <= Now Then + LastDownloadDate = Now.AddMinutes(Timer) + Else + LastDownloadDate = LastDownloadDate.AddMinutes(Timer) + End If + End Sub Private Sub Checker() Try - While Not _StopRequested Or Downloader.Working - If LastDownloadDate.AddMinutes(Timer) < Now And Not Downloader.Working And Not Pause And Not _StopRequested Then Download() + While (Not _StopRequested Or Downloader.Working) And Not Mode = Modes.None + If LastDownloadDate.AddMinutes(Timer) < Now And _StartTime.AddMinutes(StartupDelay) < Now And + Not Downloader.Working And Not Pause And Not _StopRequested And Not Mode = Modes.None Then Download() Thread.Sleep(500) End While Catch ex As Exception @@ -251,7 +331,14 @@ Namespace DownloadObjects _StopRequested = False End Try End Sub + Private _Downloading As Boolean = False + Friend ReadOnly Property Downloading As Boolean + Get + Return _Downloading + End Get + End Property Private Sub Download() + _Downloading = True Dim Keys As New List(Of String) Try Dim users As New List(Of IUserData) @@ -299,7 +386,6 @@ Namespace DownloadObjects .AutoDownloaderWorking = True If .Downloaded.Count > 0 Then .Downloaded.RemoveAll(Function(u) Keys.Contains(u.Key)) : .InvokeDownloadsChangeEvent() .AddRange(users) - .DisableOpenForms = False While .Working Or .Count > 0 : notify.Invoke() : Thread.Sleep(200) : End While .AutoDownloaderWorking = False notify.Invoke @@ -311,21 +397,23 @@ Namespace DownloadObjects Keys.Clear() LastDownloadDate = Now Update() + _Downloading = False End Try End Sub Private Sub ShowNotification(ByVal u As IUserData) - Dim i% = UserKeys.IndexOf(u.Key) + Dim k$ = $"{Name}_{u.Key}" + Dim i% = UserKeys.IndexOf(k) If i >= 0 Then UserKeys(i).ShowNotification() Else - UserKeys.Add(New NotifiedUser(u.Key, TDownloader.GetUserFromMainCollection(u))) + UserKeys.Add(New NotifiedUser(k, TDownloader.GetUserFromMainCollection(u))) UserKeys.Last.ShowNotification() End If End Sub Friend Function NotificationClicked(ByVal Key As String) As Boolean Dim i% = UserKeys.IndexOf(Key) If i >= 0 Then - RaiseEvent UserFind(Key, UserKeys(i).Open(Key)) + RaiseEvent UserFind(UserKeys(i).IUserDataKey, UserKeys(i).Open(Key)) Return True Else Return False diff --git a/SCrawler/Download/AutoDownloaderEditorForm.Designer.vb b/SCrawler/Download/AutoDownloaderEditorForm.Designer.vb index de7e4c7..27fa31f 100644 --- a/SCrawler/Download/AutoDownloaderEditorForm.Designer.vb +++ b/SCrawler/Download/AutoDownloaderEditorForm.Designer.vb @@ -29,6 +29,7 @@ Namespace DownloadObjects Dim ActionButton2 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Dim TP_MODE As System.Windows.Forms.TableLayoutPanel Dim ActionButton3 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() + Dim ActionButton4 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Dim TT_MAIN As System.Windows.Forms.ToolTip Me.DEF_GROUP = New SCrawler.DownloadObjects.Groups.GroupDefaults() Me.TXT_GROUPS = New PersonalUtilities.Forms.Controls.TextBoxExtended() @@ -40,6 +41,7 @@ Namespace DownloadObjects Me.CH_NOTIFY = New System.Windows.Forms.CheckBox() Me.TXT_TIMER = New PersonalUtilities.Forms.Controls.TextBoxExtended() Me.LBL_LAST_TIME_UP = New System.Windows.Forms.Label() + Me.NUM_DELAY = New PersonalUtilities.Forms.Controls.TextBoxExtended() CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer() TP_MODE = New System.Windows.Forms.TableLayoutPanel() TT_MAIN = New System.Windows.Forms.ToolTip(Me.components) @@ -49,6 +51,7 @@ Namespace DownloadObjects CType(Me.TXT_GROUPS, System.ComponentModel.ISupportInitialize).BeginInit() TP_MODE.SuspendLayout() CType(Me.TXT_TIMER, System.ComponentModel.ISupportInitialize).BeginInit() + CType(Me.NUM_DELAY, System.ComponentModel.ISupportInitialize).BeginInit() Me.SuspendLayout() ' 'CONTAINER_MAIN @@ -57,13 +60,13 @@ Namespace DownloadObjects 'CONTAINER_MAIN.ContentPanel ' CONTAINER_MAIN.ContentPanel.Controls.Add(Me.DEF_GROUP) - CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(476, 242) + CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(476, 301) 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, 242) + CONTAINER_MAIN.Size = New System.Drawing.Size(476, 301) CONTAINER_MAIN.TabIndex = 0 CONTAINER_MAIN.TopToolStripPanelVisible = False ' @@ -72,44 +75,45 @@ Namespace DownloadObjects Me.DEF_GROUP.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single] Me.DEF_GROUP.ColumnCount = 1 Me.DEF_GROUP.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) - Me.DEF_GROUP.Controls.Add(Me.TXT_GROUPS, 0, 4) + Me.DEF_GROUP.Controls.Add(Me.TXT_GROUPS, 0, 5) Me.DEF_GROUP.Controls.Add(TP_MODE, 0, 0) - Me.DEF_GROUP.Controls.Add(Me.CH_NOTIFY, 0, 5) - Me.DEF_GROUP.Controls.Add(Me.TXT_TIMER, 0, 6) - Me.DEF_GROUP.Controls.Add(Me.LBL_LAST_TIME_UP, 0, 7) + Me.DEF_GROUP.Controls.Add(Me.CH_NOTIFY, 0, 6) + Me.DEF_GROUP.Controls.Add(Me.TXT_TIMER, 0, 7) + Me.DEF_GROUP.Controls.Add(Me.LBL_LAST_TIME_UP, 0, 9) + Me.DEF_GROUP.Controls.Add(Me.NUM_DELAY, 0, 8) Me.DEF_GROUP.Dock = System.Windows.Forms.DockStyle.Fill Me.DEF_GROUP.Location = New System.Drawing.Point(0, 0) Me.DEF_GROUP.Name = "DEF_GROUP" - Me.DEF_GROUP.RowCount = 9 + Me.DEF_GROUP.RowCount = 11 Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) + Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) + Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) - Me.DEF_GROUP.Size = New System.Drawing.Size(476, 242) + Me.DEF_GROUP.Size = New System.Drawing.Size(476, 301) Me.DEF_GROUP.TabIndex = 0 ' 'TXT_GROUPS ' ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image) - ActionButton1.Index = 0 - ActionButton1.Name = "BTT_EDIT" + ActionButton1.Name = "Edit" ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image) - ActionButton2.Index = 1 - ActionButton2.Name = "BTT_CLEAR" + ActionButton2.Name = "Clear" Me.TXT_GROUPS.Buttons.Add(ActionButton1) Me.TXT_GROUPS.Buttons.Add(ActionButton2) Me.TXT_GROUPS.CaptionText = "Groups" Me.TXT_GROUPS.CaptionWidth = 50.0R Me.TXT_GROUPS.Dock = System.Windows.Forms.DockStyle.Fill - Me.TXT_GROUPS.Location = New System.Drawing.Point(4, 111) + Me.TXT_GROUPS.Location = New System.Drawing.Point(4, 140) Me.TXT_GROUPS.Name = "TXT_GROUPS" Me.TXT_GROUPS.Size = New System.Drawing.Size(468, 22) - Me.TXT_GROUPS.TabIndex = 4 + Me.TXT_GROUPS.TabIndex = 2 ' 'TP_MODE ' @@ -132,7 +136,7 @@ Namespace DownloadObjects TP_MODE.RowCount = 1 TP_MODE.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) TP_MODE.Size = New System.Drawing.Size(474, 25) - TP_MODE.TabIndex = 8 + TP_MODE.TabIndex = 1 ' 'OPT_ALL ' @@ -203,52 +207,71 @@ Namespace DownloadObjects ' Me.CH_NOTIFY.AutoSize = True Me.CH_NOTIFY.Dock = System.Windows.Forms.DockStyle.Fill - Me.CH_NOTIFY.Location = New System.Drawing.Point(4, 140) + Me.CH_NOTIFY.Location = New System.Drawing.Point(4, 169) Me.CH_NOTIFY.Name = "CH_NOTIFY" Me.CH_NOTIFY.Size = New System.Drawing.Size(468, 19) - Me.CH_NOTIFY.TabIndex = 12 + Me.CH_NOTIFY.TabIndex = 3 Me.CH_NOTIFY.Text = "Show notifications" Me.CH_NOTIFY.UseVisualStyleBackColor = True ' 'TXT_TIMER ' ActionButton3.BackgroundImage = CType(resources.GetObject("ActionButton3.BackgroundImage"), System.Drawing.Image) - ActionButton3.Index = 0 - ActionButton3.Name = "BTT_REFRESH" + ActionButton3.Name = "Refresh" Me.TXT_TIMER.Buttons.Add(ActionButton3) Me.TXT_TIMER.CaptionText = "Timer" Me.TXT_TIMER.CaptionWidth = 50.0R Me.TXT_TIMER.Dock = System.Windows.Forms.DockStyle.Fill - Me.TXT_TIMER.Location = New System.Drawing.Point(4, 166) + Me.TXT_TIMER.Location = New System.Drawing.Point(4, 195) Me.TXT_TIMER.Name = "TXT_TIMER" Me.TXT_TIMER.Size = New System.Drawing.Size(468, 22) - Me.TXT_TIMER.TabIndex = 16 + Me.TXT_TIMER.TabIndex = 4 ' 'LBL_LAST_TIME_UP ' Me.LBL_LAST_TIME_UP.AutoSize = True Me.LBL_LAST_TIME_UP.Dock = System.Windows.Forms.DockStyle.Fill Me.LBL_LAST_TIME_UP.Font = New System.Drawing.Font("Microsoft Sans Serif", 8.25!, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Point, CType(204, Byte)) - Me.LBL_LAST_TIME_UP.Location = New System.Drawing.Point(4, 192) + Me.LBL_LAST_TIME_UP.Location = New System.Drawing.Point(4, 250) Me.LBL_LAST_TIME_UP.Name = "LBL_LAST_TIME_UP" Me.LBL_LAST_TIME_UP.Size = New System.Drawing.Size(468, 25) - Me.LBL_LAST_TIME_UP.TabIndex = 20 + Me.LBL_LAST_TIME_UP.TabIndex = 6 Me.LBL_LAST_TIME_UP.Text = "Last download date: " Me.LBL_LAST_TIME_UP.TextAlign = System.Drawing.ContentAlignment.TopCenter ' + 'NUM_DELAY + ' + ActionButton4.BackgroundImage = CType(resources.GetObject("ActionButton4.BackgroundImage"), System.Drawing.Image) + ActionButton4.Name = "Refresh" + Me.NUM_DELAY.Buttons.Add(ActionButton4) + Me.NUM_DELAY.CaptionText = "Delay" + Me.NUM_DELAY.CaptionToolTipEnabled = True + Me.NUM_DELAY.CaptionToolTipText = "Startup delay" + Me.NUM_DELAY.CaptionWidth = 50.0R + Me.NUM_DELAY.ClearTextByButtonClear = False + Me.NUM_DELAY.ControlMode = PersonalUtilities.Forms.Controls.TextBoxExtended.ControlModes.NumericUpDown + Me.NUM_DELAY.Dock = System.Windows.Forms.DockStyle.Fill + Me.NUM_DELAY.Location = New System.Drawing.Point(4, 224) + Me.NUM_DELAY.Name = "NUM_DELAY" + Me.NUM_DELAY.NumberMaximum = New Decimal(New Integer() {1440, 0, 0, 0}) + Me.NUM_DELAY.NumberUpDownAlign = System.Windows.Forms.LeftRightAlignment.Left + Me.NUM_DELAY.Size = New System.Drawing.Size(468, 22) + Me.NUM_DELAY.TabIndex = 5 + Me.NUM_DELAY.Text = "0" + ' 'AutoDownloaderEditorForm ' Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!) Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font - Me.ClientSize = New System.Drawing.Size(476, 242) + Me.ClientSize = New System.Drawing.Size(476, 301) Me.Controls.Add(CONTAINER_MAIN) Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle Me.Icon = CType(resources.GetObject("$this.Icon"), System.Drawing.Icon) Me.KeyPreview = True Me.MaximizeBox = False - Me.MaximumSize = New System.Drawing.Size(492, 281) + Me.MaximumSize = New System.Drawing.Size(492, 340) Me.MinimizeBox = False - Me.MinimumSize = New System.Drawing.Size(492, 281) + Me.MinimumSize = New System.Drawing.Size(492, 340) Me.Name = "AutoDownloaderEditorForm" Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide Me.Text = "AutoDownloader settings" @@ -261,6 +284,7 @@ Namespace DownloadObjects TP_MODE.ResumeLayout(False) TP_MODE.PerformLayout() CType(Me.TXT_TIMER, System.ComponentModel.ISupportInitialize).EndInit() + CType(Me.NUM_DELAY, System.ComponentModel.ISupportInitialize).EndInit() Me.ResumeLayout(False) End Sub @@ -274,5 +298,6 @@ Namespace DownloadObjects Friend WithEvents TXT_TIMER As PersonalUtilities.Forms.Controls.TextBoxExtended Private WithEvents OPT_GROUP As RadioButton Private WithEvents LBL_LAST_TIME_UP As Label + Private WithEvents NUM_DELAY As PersonalUtilities.Forms.Controls.TextBoxExtended End Class End Namespace \ No newline at end of file diff --git a/SCrawler/Download/AutoDownloaderEditorForm.resx b/SCrawler/Download/AutoDownloaderEditorForm.resx index 2a0eae1..2bd6ddd 100644 --- a/SCrawler/Download/AutoDownloaderEditorForm.resx +++ b/SCrawler/Download/AutoDownloaderEditorForm.resx @@ -210,6 +210,22 @@ HhQDmFjYeHVKFp7WX/Xuv9Kq9/+Vd/z7r7rv/3+l7f//y676DEwDN/9L+BVvYkKLCTgDhNkkVUyVlr74 qbbz73/VOTc/qsy89kWx+9h7qbQpJwS1bbOAscGGrB6EUTggLOqf16C55ft/HlnNAFZOXgVWdi4FRgYG VnR1MIwhwMTCyqEQ37qEmZVDFF0OE/9nAACtFF4Ey6OP+wAAAABJRU5ErkJggg== + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6 + JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsTAAALEwEAmpwYAAACOElE + QVQ4T2P4//8/QczOJyyqHpzfiE0OQwAZC8iqszAzs7CJ69o4BR768V/W2jcGXQ0KB4aFNS3dDQtnrbCb + ePCK48wTN1wXXXzge/jXf/clV55zC4hIIatF0cjIyMikElzc57z0wX+XHd/+2+//99/ywP//xlu//tdb + +eK/4Zp3/1WTOhYzARViNUAluKjTdf37/0ZTTn9TbdhwXblhwwW1/qOP1Ja9+K8w+95/6cm3/6v2Xvkv + qKjniGGAoIqRpW3/4e8S9uGdzFz82gwMDFxAzCxm4ZegtuLDf+VJ1/8rZM25IqLvnM/CximCYYCic1QN + v7x2JIwPwyrJ3XNUylddE9G2TWNmZOBDl4czmJiZMSRBmFdSyYyJgUEQmxwIYxWEYXZBCUls4sgYq6CA + prWNbtG8nXKeaVPR5XiVjSxEzf0yYXy4BBMLO6eQjoOXZvrkbbazrv53Xf/2v4CSbjBMXkhBl1/CMyNZ + qWnvGy5pNQ+YONwAfjXzAOupl/47LLr333L50/96q9/8l23YdES6cO5KuYqVW+R7Tj6SnfP0v4hryjyY + HhQDmFjYeHVKFp7WX/Xuv9Kq9/+Vd/z7r7rv/3+l7f//y676DEwDN/9L+BVvYkKLCTgDhNkkVUyVlr74 + qbbz73/VOTc/qsy89kWx+9h7qbQpJwS1bbOAscGGrB6EUTggLOqf16C55ft/HlnNAFZOXgVWdi4FRgYG + VnR1MIwhwMTCyqEQ37qEmZVDFF0OE/9nAACtFF4Ey6OP+wAAAABJRU5ErkJggg== diff --git a/SCrawler/Download/AutoDownloaderEditorForm.vb b/SCrawler/Download/AutoDownloaderEditorForm.vb index 4ee05fa..2ab4c45 100644 --- a/SCrawler/Download/AutoDownloaderEditorForm.vb +++ b/SCrawler/Download/AutoDownloaderEditorForm.vb @@ -12,15 +12,16 @@ Imports PersonalUtilities.Forms.Toolbars Imports DModes = SCrawler.DownloadObjects.AutoDownloader.Modes Namespace DownloadObjects Friend Class AutoDownloaderEditorForm : Implements IOkCancelToolbar - Private ReadOnly MyDefs As DefaultFormProps + Private ReadOnly MyDefs As DefaultFormOptions Private ReadOnly MyGroups As List(Of String) - Friend Property IsControlForm As Boolean = False - Friend Sub New() + Private ReadOnly Property Plan As AutoDownloader + Friend Sub New(ByRef _Plan As AutoDownloader) InitializeComponent() - MyDefs = New DefaultFormProps - MyGroups.ListAddList(Settings.Automation.Groups, LAP.NotContainsOnly) + Plan = _Plan + MyDefs = New DefaultFormOptions + MyGroups.ListAddList(Plan.Groups, LAP.NotContainsOnly) End Sub - Friend Class AutomationTimerChecker : Implements IFieldsCheckerProvider + Private Class AutomationTimerChecker : Implements IFieldsCheckerProvider Private Property ErrorMessage As String = "The timer value must be greater than 0" Implements IFieldsCheckerProvider.ErrorMessage Private Property Name As String Implements IFieldsCheckerProvider.Name Private Property TypeError As Boolean Implements IFieldsCheckerProvider.TypeError @@ -36,18 +37,11 @@ Namespace DownloadObjects Throw New NotImplementedException() End Function End Class - Private _Loaded As Boolean = False - Friend Shadows Sub Show() - MyBase.Show() - If Not _Loaded And IsControlForm Then AutoDownloaderEditorForm_Load(Nothing, EventArgs.Empty) - End Sub Private Sub AutoDownloaderEditorForm_Load(sender As Object, e As EventArgs) Handles Me.Load With MyDefs - If Not IsControlForm Then - .MyViewInitialize(Me, Settings.Design, True) - .AddOkCancelToolbar() - End If - With Settings.Automation + .MyViewInitialize(Me, Settings.Design, True) + .AddOkCancelToolbar() + With Plan Select Case .Mode Case DModes.None : OPT_DISABLED.Checked = True Case DModes.All : OPT_ALL.Checked = True @@ -56,30 +50,30 @@ Namespace DownloadObjects Case DModes.Groups : OPT_GROUP.Checked = True End Select ChangeEnabled() - DEF_GROUP.Set(Settings.Automation) + DEF_GROUP.Set(Plan) If MyGroups.Count > 0 Then TXT_GROUPS.Text = MyGroups.ListToString If Settings.Groups.Count = 0 Then TXT_GROUPS.Clear() : TXT_GROUPS.Enabled = False CH_NOTIFY.Checked = .ShowNotifications TXT_TIMER.Text = .Timer + NUM_DELAY.Value = .StartupDelay LBL_LAST_TIME_UP.Text = .Information End With - If Not IsControlForm Then - .MyFieldsChecker = New FieldsChecker - With DirectCast(.MyFieldsChecker, FieldsChecker) - .AddControl(Of Integer)(TXT_TIMER, TXT_TIMER.CaptionText,, New AutomationTimerChecker) - .EndLoaderOperations() - End With + .MyFieldsChecker = New FieldsChecker + With .MyFieldsCheckerE + .AddControl(Of String)(DEF_GROUP.TXT_NAME, DEF_GROUP.TXT_NAME.CaptionText,, + New Groups.GroupEditorForm.NameChecker(Plan.Name, Settings.Automation, "Plan")) + .AddControl(Of Integer)(TXT_TIMER, TXT_TIMER.CaptionText,, New AutomationTimerChecker) .EndLoaderOperations() - End If + End With + .EndLoaderOperations() End With - _Loaded = True End Sub Private Sub AutoDownloaderEditorForm_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed MyGroups.Clear() End Sub - Friend Sub SaveSettings() Implements IOkCancelToolbar.OK + Private Sub OK() Implements IOkCancelToolbar.OK If If(MyDefs.MyFieldsChecker?.AllParamsOK, True) Then - With Settings.Automation + With Plan Select Case True Case OPT_DISABLED.Checked : .Mode = DModes.None Case OPT_ALL.Checked : .Mode = DModes.All @@ -87,13 +81,14 @@ Namespace DownloadObjects Case OPT_SPEC.Checked : .Mode = DModes.Specified Case OPT_GROUP.Checked : .Mode = DModes.Groups End Select - DEF_GROUP.Get(Settings.Automation) + DEF_GROUP.Get(Plan) .Groups.Clear() .Groups.ListAddList(MyGroups) .Timer = AConvert(Of Integer)(TXT_TIMER.Text, AutoDownloader.DefaultTimer) + .StartupDelay = NUM_DELAY.Value .Update() End With - If Not IsControlForm Then MyDefs.CloseForm() + MyDefs.CloseForm() End If End Sub Private Sub Cancel() Implements IOkCancelToolbar.Cancel @@ -128,7 +123,11 @@ Namespace DownloadObjects DEF_GROUP.Enabled = OPT_SPEC.Checked TXT_GROUPS.Enabled = OPT_GROUP.Checked TXT_TIMER.Enabled = Not OPT_DISABLED.Checked + NUM_DELAY.Enabled = Not OPT_DISABLED.Checked CH_NOTIFY.Enabled = Not OPT_DISABLED.Checked End Sub + Private Sub NUM_DELAY_ActionOnButtonClick(ByVal Sender As ActionButton) Handles NUM_DELAY.ActionOnButtonClick + If Sender.DefaultButton = ActionButton.DefaultButtons.Clear Then NUM_DELAY.Value = 0 + End Sub End Class End Namespace \ No newline at end of file diff --git a/SCrawler/Download/DownloadedInfoForm.Designer.vb b/SCrawler/Download/DownloadedInfoForm.Designer.vb index 793cf83..056af62 100644 --- a/SCrawler/Download/DownloadedInfoForm.Designer.vb +++ b/SCrawler/Download/DownloadedInfoForm.Designer.vb @@ -152,10 +152,10 @@ Me.Controls.Add(Me.LIST_DOWN) Me.Controls.Add(Me.ToolbarBOTTOM) Me.Controls.Add(Me.ToolbarTOP) + Me.Icon = CType(resources.GetObject("$this.Icon"), System.Drawing.Icon) Me.KeyPreview = True Me.MinimumSize = New System.Drawing.Size(570, 450) Me.Name = "DownloadedInfoForm" - Me.ShowIcon = False Me.Text = "Downloaded items" Me.ToolbarTOP.ResumeLayout(False) Me.ToolbarTOP.PerformLayout() diff --git a/SCrawler/Download/DownloadedInfoForm.resx b/SCrawler/Download/DownloadedInfoForm.resx index 9e3ed28..50397e1 100644 --- a/SCrawler/Download/DownloadedInfoForm.resx +++ b/SCrawler/Download/DownloadedInfoForm.resx @@ -198,4 +198,507 @@ 133, 17 + + + AAABAAwAMDAQAAEABABoBgAAxgAAACAgEAABAAQA6AIAAC4HAAAYGBAAAQAEAOgBAAAWCgAAEBAQAAEA + BAAoAQAA/gsAADAwAAABAAgAqA4AACYNAAAgIAAAAQAIAKgIAADOGwAAGBgAAAEACADIBgAAdiQAABAQ + AAABAAgAaAUAAD4rAAAwMAAAAQAgAKglAACmMAAAICAAAAEAIACoEAAATlYAABgYAAABACAAiAkAAPZm + AAAQEAAAAQAgAGgEAAB+cAAAKAAAADAAAABgAAAAAQAEAAAAAACABAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAIAAAIAAAACAgACAAAAAgACAAICAAACAgIAAwMDAAAAA/wAA/wAAAP//AP8AAAD/AP8A//8AAP// + /wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4YAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjsjgAAAAAAAAAAAA + AAAAAAAAAAAAAAAIbOh4AAAAAAAAAAAAAAAAAAAAAAAAAAAH5mfsgAAAAAAAAAAAAAAAAAAAAAAAAAB+ + xs54YAAAAAAAAAAAAAAAAAAAAAAAAAfsbmxo5wAAAAAAAAAAAAAAAAAAAAAAAIbObObOeMAAAAAAAAAA + AAAAAAAAAAAACG5+zmzsaOgAAAAAAAAAAAAAAAAAAAAABn7ObOZmbneAAAAAAAAAAAAAAAAAAAAAfs5s + 5+zs7I7AAAAAAAAAAAAAAAAAAAAH7Ofm7G7GbGiOAAAAAAAAAAAAAAAAAAB+fs7Ofs5+zmzngAAAAAAA + AAAAAAAAAAhn7Ojs5uzm7OZ4yAAAAAAAAAAAAAAAAAaOfm7Obsfsbs7OjnAAAAAAAAAAAAAAAH7Ojs7n + 7O7ObOZs54AAAAAAAAAAAAAABn6Ozuduzn5uznzmyOcAAAAAAAAAAAAAfn7I6M7s5+zn7Obs5oyAAAAA + AAAAAAAIZ+jujuzo7Obs5uxubOjnAAAAAAAAAAAG586M5+js7n7OfOfs5s54cAAAAAAAAABnzo7o5+zu + fs5+5uzmzmzowAAAAAAAAAdujn5+fu7Ozuzs7Ofs5+bI6AAAAAAAAHzn7OjOjI5+5+jufs5uzs5ueOAA + AAAAAG6M6O6O7n7Ofs7Ozo7Ofmzs53gAAAAAB+zo7IznyOzuzufufs6Ofo6Ofn4AAAAACEdsZ2Z87o5+ + js7O7O5cjHx8jIgAAAAAAAAAAAAAfOfs7Ojs6OfgAAAAAAAAAAAAAAAAAAAAbo7O6O7O7OfAAAAAAAAA + AAAAAAAAAAAAfsjm7Obo7s6AAAAAAAAAAAAAAAAAAAAAaO5+zo7OyO5wAAAAAAAAAAAAAAAAAAAAzn7O + js7n7sjAAAAAAAAAAAAAAAAAAAAAaM6Ozuzuzu5wAAAAAAAAAAAAAAAAAAAAbn7Obn5+jshgAAAAAAAA + AAAAAAAAAAAAbOjn7Ozs7O5wAAAAAAAAAAAAAAAAAAAAfnzn5+bn7n7AAAAAAAAAAAAAAAAAAAAAbOjs + 7OzuzshgAAAAAAAAAAAAAAAAAAAAaOyOfn7I5+5wAAAAAAAAAAAAAAAAAAAAbOfs7Ozm7OfAAAAAAAAA + AAAAAAAAAAAAbnzn5+bs5u5wAAAAAAAAAAAAAAAAAAAAfOfsjOx+zn7AAAAAAAAAAAAAAAAAAAAAbnzn + 5o7OfshgAAAAAAAAAAAAAAAAAAAAx+Z+zs5uzm5gAAAAAAAAAAAAAAAAAAAAbs7H5+fObsjAAAAAAAAA + AAAAAAAAAAAAZ2js585s7O5wAAAAAAAAAAAAAAAAAAAAjOyH5+jn53aAAAAAAAAAAAAAAAAAAAAACGZs + bHxsfGgAAAAAAAAAAAD///////8AAP///////wAA////////AAD///j///8AAP//8H///wAA///gP/// + AAD//+Af//8AAP//wB///wAA//+AD///AAD//wAH//8AAP/+AAP//wAA//4AAf//AAD//AAB//8AAP/4 + AAD//wAA//AAAH//AAD/4AAAP/8AAP/gAAAf/wAA/8AAAB//AAD/gAAAD/8AAP8AAAAH/wAA/gAAAAP/ + AAD+AAAAAf8AAPwAAAAB/wAA+AAAAAD/AADwAAAAAH8AAPAAAAAAPwAA4AAAAAA/AADgAAAAAD8AAP/8 + AAH//wAA//wAAf//AAD//AAB//8AAP/8AAH//wAA//wAAf//AAD//AAB//8AAP/8AAH//wAA//wAAf// + AAD//AAB//8AAP/8AAH//wAA//wAAf//AAD//AAB//8AAP/8AAH//wAA//wAAf//AAD//AAB//8AAP/8 + AAH//wAA//wAAf//AAD//AAB//8AAP/8AAH//wAA//4AA///AAAoAAAAIAAAAEAAAAABAAQAAAAAAAAC + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAgAAAAICAAIAAAACAAIAAgIAAAICAgADAwMAAAAD/AAD/ + AAAA//8A/wAAAP8A/wD//wAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5+AAAAAAAAAAAAAAAAAA + BoyHAAAAAAAAAAAAAAAAAOfn7AAAAAAAAAAAAAAAAAjIzn6AAAAAAAAAAAAAAAAO5uxo7AAAAAAAAAAA + AAAAaM7ObI6AAAAAAAAAAAAADn5ubOboyAAAAAAAAAAAAH7Ozs5sbo4AAAAAAAAAAAjI5+fn7saM4AAA + AAAAAAAO7n7Ozsbs6OcAAAAAAAAAaH7O5+bn5s6MgAAAAAAABo7o5+zs7Ozm6OAAAAAAAH7I7Ozufn5u + zsfsAAAAAAjOjn6Ofs7s5+bsjnAAAAAG6Ozo7O7n5+zs5ujnAAAAaOyOjo587Ozo6I7IjIAAAGxmxsZ+ + 7o7uzsbG7O4AAAAAAAAM587OyOhgAAAAAAAAAAAABo7n5+7OYAAAAAAAAAAAAAzozuzujsAAAAAAAAAA + AAAGjufuzs5wAAAAAAAAAAAADOfOyOfowAAAAAAAAAAAAAaOfm7O7mAAAAAAAAAAAAAM7Ofs5sjAAAAA + AAAAAAAABn585+7oYAAAAAAAAAAAAAyM6Oxs58AAAAAAAAAAAAAG5+zm5+5gAAAAAAAAAAAABOx+fs7I + wAAAAAAAAAAAAAZ+Z8hs7kAAAAAAAAAAAAAMjOjm52fAAAAAAAAAAAAAAGbExsbOAAAAAAAA///////8 + f///+D////A////gH///4A///8AH//+AA///AAP//gAB//4AAP/8AAB/+AAAf/AAAD/gAAAf4AAAD8AA + AAfAAAAP/4AH//+AB///gAf//4AH//+AB///gAf//4AH//+AB///gAf//4AH//+AB///gAf//4AH///A + D/8oAAAAGAAAADAAAAABAAQAAAAAACABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAgAAAAICAAIAA + AACAAIAAgIAAAICAgADAwMAAAAD/AAD/AAAA//8A/wAAAP8A/wD//wAA////AAAAAAAAAAAAAAAAAAAA + AAAABgAAAAAAAAAAAAAAeOAAAAAAAAAAAAAG7IcAAAAAAAAAAAB+fujgAAAAAAAAAAbs7OyHAAAAAAAA + AGjufm7oYAAAAAAABo7OzsfOhwAAAAAAaO5+5+7s6GAAAAAG5+zs7Ozn7PYAAABo6Ojo7n6IjojgAAAM + bGzs7OyOx+wAAAAAAAfo7o7nAAAAAAAAAAaM7OyGAAAAAAAAAAbufu6MAAAAAAAAAAd+zn6GAAAAAAAA + AAzn7OznAAAAAAAAAAaOzuiGAAAAAAAAAAbn587sAAAAAAAAAAZ87m6GAAAAAAAAAAzozs6MAAAAAAAA + AAaOh+eGAAAAAAAAAABsbGxgAAAAAAAAAAAAAAAAAAAAAP///wD/7/8A/8f/AP+D/wD/Af8A/gD/APwA + fwD4AD8A8AAfAOAADwDAAAcA4AAPAP4A/wD+AP8A/gD/AP4A/wD+AP8A/gD/AP4A/wD+AP8A/gD/AP4A + /wD/Af8A////ACgAAAAQAAAAIAAAAAEABAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAACA + AAAAgIAAgAAAAIAAgACAgAAAgICAAMDAwAAAAP8AAP8AAAD//wD/AAAA/wD/AP//AAD///8AAAAABgAA + AAAAAABoYAAAAAAABo6MAAAAAABozshgAAAABo5uboYAAABo7OfOeGAABo5+fn6OhgB2xs7O6MfHgAAA + aOfIYAAAAABuzujgAAAAAGjn6MAAAAAAzs5+cAAAAABo5+jAAAAAAG7OyOAAAAAAaI6OcAAAAAAMbGYA + AAD+/wAA/H8AAPg/AADwHwAA4A8AAMAHAACAAwAAAAEAAPAfAADwHwAA8B8AAPAfAADwHwAA8B8AAPAf + AAD4PwAAKAAAADAAAABgAAAAAQAIAAAAAAAACQAAAAAAAAAAAAAAAQAAAAEAAAAAAACjaB0ApmsgAKlt + IwCrcCYArXMqALF1LACzeC4ArHYwALR6MQC4fTQAt385AMh1AADJdwQAy3gAAM17AADOfQEAy3oHAM5/ + CQDMfA0A0H4BAMt/GQC7gDcAvoI6ALmBPADRgAIA0oIEANSDBADVhQUA1ogGANaMBwDZiQYA3I0GANKE + CgDWhwkA0YIMANaMCwDZiggA2o0JANyOCQDbkgsA3pAKAN6UCwDekg0A3ZQNAM+EGgDRhhUA1YkSANiN + EgDajhcA2pISANqSHgDalh4A3ZgaAOGUCgDgkg0A4ZUOAOSWDgDhmA4A5ZgPAOicDgDklxAA45cVAOGY + EADlmRAA5ZwRAOSdFwDonRIA550YAOmfGwDpoBIA6qEUAO2iFADrpBQA7qUWAO6mGADvqBgA8KUXAPCm + GADxqRgA9KsZAPKsGgD0rBoA9a0cAPiuGgD1sBsA+bEbAPixHADOhycAzo0lAMqKKwDRjCIA0Y8lANSP + JgDTji0A05ImANiRIwDdnScA1JQpANmVKwDXmCoA25stAMGJNQDAhj0A0I84AM2VPwDTmTYA3JwyANKR + OQDSlDgA2Js6AOGeIADknS8A3qAxANyiPwDopCAA7qogAOKiLQDtqykA8asjAPOxJwD6syAA+LMkAPq1 + JwD2tSoA+rYsAPq4LgDiozEA6qUzAOepNQDpqTEA66wyAOmrNwDtqjUA6qw2AO2vNQDjpjoA6aw4AOir + PwDwrDgA67A3AO2xOQDssT8A8rIwAPazMwD2tzEA8bE2APq7NgDytDoA+Lc6APW5PAD5uToA+bw7APi7 + PQD5vD0A/L49APzAPgCxgEMAv4VAALaFSAC5h0sAvJZmALyacgC5mnYAxYlBAMOLRgDHi0QAyY1GAMaO + SgDJj0oAyZBEAMyQSgDPlEkAypFNAM6TTADNlE4A0pVHANebQwDUnUUA0JRNANaaSgDDkVUAzpZWAM2X + WwDOmVsAzZpdANGZVgDUmlcA0ppaANOcWwDQnF4A16BHANqiSADapUkA3adLAN2lTQDbo1QA1KFeANql + WwDgpkMA4KtOAO6sSwDxrUYA8rdAAPGxRQD1uUAA+r1AAPSySADirl0Ax5ljAMOYZgDFmWUAz51gAM+f + ZADBnG4AxJ1uANGeYgDQnmUA0aBjANalYwDVoWQA2KRgAN+sYwDbqWYA3aplAN2sZwDRo2sA1KdrANWl + bADZqmoA3q5qAMWhcgDNpHMAzKV1AMmmeQDUqXAA1Kp5ANuwcADhrWAA569jAOCvaQDismgA5LRoAOGy + bADitGwA+8BDALGchQCxnokAxa2OAMqwkQDPs5MA1LiXAN3AngDjwJYAAAAAAP///wAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + 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 + AAC/YQAAvGgNALllFwC5Zx8AtWUpAMJkAADFaAAAyGsAAMxuAgDOcQYA0nYJANR5DQDFdREAz34aANd8 + EADafxMA0IAGANSDBQDThAYA1YUFANiJBwDThg8A2YoIANqNCQDcjQoA25AKAN2QCgDekQ0A35UNAN2A + FgDXjxAA2Y4UAN6DGQDWjBsA3ZEQAN6UFgDdmBgA4JMKAOCSDQDhlQ4A5ZcPAOSZDgDghhsA44geAOSW + EADjmxEA5ZoQAOScEQDnnxQA6Z0SAOWcGgDpoBIA6aEUAO2iFADtpBYA5qAZAO+oGgDwphcA8acYAPGp + GAD0qxkA86waAPSsGgD1rhwA9rAbAPawHAD4sBoA+LEcAMyAIADXhSMA0IUnAN+NKgDRkScA2pYhAN2b + IwDcmyUA05MoANWWKQDali8A2ZksANucLQDcnS4A3Z0xAN2TOwDblT8A1po7ANKYPADVmj0A154+AOaO + JADjkCoA5ZIuAOqTKgDtkysA7ZQrAOiTLQDulSwA4pIxAOmWMQDrlzUA6J02AOOaOQDgnTwA6pw5APCa + NADynj0A36AvAN6hMADdoDgA2aE/AOSgIQDioSYA7KchAO2oJgDgoCkA6agrAPewIAD5tCIA+bQnAPOx + KAD5tigA+bcvAOOmMgDjpjQA5KU0AOepNQDnrD8A6Ko4AOyvOADprj8A86A/AO+zOgDysjAA8LE3APe4 + NgD7ujEA8rY7APCzPQDytj4A9Lg6APW6PQD7vDoA+b0+AMWARADPkEUA3ZlEANmbTQDPnF8A0phUAOqe + QgDdoEEA2aJGAN2kRADep0kA3aVOANuiUADdplQA4ahGAO2qRwDooEgA4alKAOOtTQDzoUAA869EAPap + TgDsskAA77JGAOewTgDusUoA6rBMAPC1QwD0ukUA9rxGAPm9QQDwskkA8rVNAPe+SAD1uk8A+L5IAPWp + UADyqlQA6rRRAO22UgDuuFQA47BbAPCyUQD0vFAA8r5WAPC2XAD4sV0AyZ5nAMSlfwDfr3MA2K19AOWt + YgDltmcA67NgAOm5YQDsu2oA77ptAPW+awDwvm0A+bhpAOizcQDiu34A7Lt9APS9cAD7wEIA+8FGAPnA + SAD4wk4A+MNZAPnEWgD6w2AA/ctkAMOnhQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAABta58AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbc2/a8oAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAKpvpabIawAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADWcqgdHaa/awAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAG2JLR8dIM6tXgAAAAAAAAAAAAAAAAAAAAAAAAAAAABlsT0xIx8dLNJzngAAAAAA + AAAAAAAAAAAAAAAAAAAAUq58PDMxIyMdWdVr4gAAAAAAAAAAAAAAAAAAAAAAAJypj0REMzMxJSMdochr + AAAAAAAAAAAAAAAAAAAAAADLcN9KRURERDMxJSMjw69lAAAAAAAAAAAAAAAAAAAAAFDhuH9KSkQzRDMx + JSMq0o1fAAAAAAAAAAAAAAAAAAAY4Nu4gUdHQ0VEM0QlJSNU2XPJAAAAAAAAAAAAAAAAT8TcuNuSTUpK + R0REMzsxJSNd1WsAAAAAAAAAAAAAAJtw3bi425hNTUpKSkRERDMzMSOryGsAAAAAAAAAAADMUd2Vl7i4 + mIFNTU1KSkRERDMzMSXQr2wAAAAAAAAAABfBsJOXmLi4g01NTU1KSkRERDk5MS3ZdJ0AAAAAAAAMz7S0 + urrFxbiETYFNTU1KSo+xlbq6tMfTa9gAAAAAAJoGBgYGCQkL35FLTU2BTU1KthkZKys1NmSgAAAAAAAA + AAAAAAAAAAnfl0pLTU1NgU29FgAAAAAAAAAAAAAAAAAAAAAAAAAABt2VgkpNgU1NTdwVAAAAAAAAAAAA + AAAAAAAAAAAAAAAGxrGPSkpKTU2B2xQAAAAAAAAAAAAAAAAAAAAAAAAAAAbCi5BDREpLTU3cEwAAAAAA + AAAAAAAAAAAAAAAAAAAABMGIi3xAR0pLTdwTAAAAAAAAAAAAAAAAAAAAAAAAAAADsoWKjzlEQ0pL3BEA + AAAAAAAAAAAAAAAAAAAAAAAAAAOrhYWFOztEREq7EQAAAAAAAAAAAAAAAAAAAAAAAAAAA6tdXIV5OTtE + Q7YLAAAAAAAAAAAAAAAAAAAAAAAAAAABpVxcdn0nMztEtgkAAAAAAAAAAAAAAAAAAAAAAAAAAAGhWFpd + di8nMzu1CQAAAAAAAAAAAAAAAAAAAAAAAAAAAaVTWFxdViUnJ7EGAAAAAAAAAAAAAAAAAAAAAAAAAAAB + YFNYWFhcKSQnsAYAAAAAAAAAAAAAAAAAAAAAAAAAAA/XYWBjoaF3VFZWDQAAAAAAAAAAAAAAAAAAAAAA + AAAAAA8BAQEBAQEEBA4AAAAAAAAAAAAAAAD///////x////4P///8D///+Af///gD///wAf//4AD//8A + A//+AAH//gAA//wAAH/4AAB/8AAAP+AAAB/gAAAPwAAAB8AAAA//gAf//4AH//+AB///gAf//4AH//+A + B///gAf//4AH//+AB///gAf//4AH//+AB///gAf//8AP/ygAAAAYAAAAMAAAAAEACAAAAAAAQAIAAAAA + AAAAAAAAAAEAAAABAAAAAAAApWYWAKhpGQCqbBsAqm0dAKxuHgCucCEAsHMjALJ2JgC2eioAuH4uALyC + MgC9gzQAvoU1AN+YEwDklw8A5ZkQAOmdEgDooBIA6aEUAO2hFQDtpRYA8KYXAPGqFwDxpxgA8qoZAPSr + GgD0rRoA86wcAPauHAD3sBoA97AcAPmwGgD4sRwAwIY3AMGJOQDDizwAxIs8AMWNPgDjnSUA5J4nAN6g + MADnoyAA5aAnAOSjKQDgoi8A7awpAPCsIwD6syIA+rcrAOKlMwDqqzIA6Kk3AOSpOgDpqz0A+rozAPq6 + NADytjsA97s+APe8PAD5uzgA36VCAN+sVADgqUQA5axHAOmuQADkrUoA6bNKAO63TgDws0EA9btDAPS6 + RQD6vkEA9LxMAPm+SADhrlUA5LJZAPK7UAD7wEMA+8NOAPbBUAD6xFIA+8VUAPDDaQD0xmwA9shtAPjK + bgD6zW8A8cmCAPPMhAD0zoYA99CHAPDPmQDw0JkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmAAAAAAAA + AAAAAAAAAAAAAAAAAAAAACZcJgAAAAAAAAAAAAAAAAAAAAAAAAAAJjYnXSYAAAAAAAAAAAAAAAAAAAAA + AAAiRREPJ10mAAAAAAAAAAAAAAAAAAAAAAtHFhYQECddJgAAAAAAAAAAAAAAAAAACkobGxYRERAnXSYA + AAAAAAAAAAAAAAAJUjAbGxgbFhEQKF0mAAAAAAAAAAAAAAhSTjEgGxsbFhYRECtdJgAAAAAAAAAABjpI + SDggICAbGBgWERAnXSYAAAAAAAAFOVBSUk84IDAgGxtUW1paWlwmAAAAAAAABQUGBgg8IDAgMBtWCwsL + IiIAAAAAAAAAAAAAAAY6HiAgMCBXCgAAAAAAAAAAAAAAAAAAAAVHGx4wICBXCgAAAAAAAAAAAAAAAAAA + AAVJGxseMCBXCQAAAAAAAAAAAAAAAAAAAAVJLxsbHjBXCAAAAAAAAAAAAAAAAAAAAAFELhYcGx5XCAAA + AAAAAAAAAAAAAAAAAAFDMxMVGxtXBgAAAAAAAAAAAAAAAAAAAAFANCsWFhxVBgAAAAAAAAAAAAAAAAAA + AAE/MisOEBZVBQAAAAAAAAAAAAAAAAAAAAE9KS0OEBNUAwAAAAAAAAAAAAAAAAAAAAE+S0xAND9TAwAA + AAAAAAAAAAAAAAAAAAABAQEBAwEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP/v + /wD/x/8A/4P/AP8B/wD+AP8A/AB/APgAPwDwAB8A4AAPAMAABwDgAA8A/gD/AP4A/wD+AP8A/gD/AP4A + /wD+AP8A/gD/AP4A/wD+AP8A/gD/AP8B/wD///8AKAAAABAAAAAgAAAAAQAIAAAAAAAAAQAAAAAAAAAA + AAAAAQAAAAEAAAAAAAClZhYAsnYmALN4KQC4fi8A1Y0XANWOGADXkBkA2pUbANuVHADclhwA3poeAOCc + HwDgmyAA46EiAOaiIwDmpiMA56cnAOilIwDppiUA66omAO2rJwDuricA46YsAOyrKADurikA7q4sAPCv + KQDvsS4A8LAqAO2vMQDkpjgA5q8+AOqwOADwszIA4qtBAOi0TwDyvEoA7LlSAOSyXADnt18Aw5ljAMui + bQDqumEA5LhoAOa7cADpv3MA78FlAPDFdgDyyXkA88x6APXNegD20IAA6MeQAOnIkQDpyZcAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAP///wAAAAAAAAAAAwAAAAAAAAAAAAAAAAAAAzcCAAAAAAAAAAAAAAAAAycFNQIAAAAA + AAAAAAAAAysLCAY1BAAAAAAAAAAAAy8SDg0IBjUEAAAAAAAAAzMaFBIODQgINQQAAAAAAzQlIhQaEg4f + Li01BAAAKQEBAQEbGhQUMAQEBAQqAAAAAAABGxsbFDMEAAAAAAAAAAAAARwbGxszBAAAAAAAAAAAAAEe + FBsbMwQAAAAAAAAAAAABIRQcHDMEAAAAAAAAAAAAASARFBQzBAAAAAAAAAAAAAEjFw4WMwQAAAAAAAAA + AAABLCgkJjMDAAAAAAAAAAAAAAEBAQEBAAAAAAAA/v8AAPx/AAD4PwAA8B8AAOAPAADABwAAgAMAAAAB + AADwHwAA8B8AAPAfAADwHwAA8B8AAPAfAADwHwAA+D8AACgAAAAwAAAAYAAAAAEAIAAAAAAAgCUAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAADAAAABgAAAAgAAAAGAAAAAwAA + AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAMAAAAFgAA + ABsAAAAWAAAACwAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAA + AAwAAAAfAAAAMwAAADwAAAAyAAAAHQAAAAsAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAACAAAACSccDyHPllLiypFQ4M2UUesdFQtZAAAANQAAABoAAAAJAAAAAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAEAAAAHAAAAF8aOTb/RlU3z0pVH/82UU/K/iUvcAAAAUAAAADAAAAAWAAAABgAA + AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + 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 + Q//6tiz/+K4a//auG//1rRr/9Ksa//KpGf/wpxj/76MX/+2hFP/pnxP/6JwS/+WYD//hlQ//35IN/92O + Cv/aiwn/14gH/9SEBf/ViRP/4rJo/8+cXfS4hEjVAAAATQAAAC0AAAAUAAAABgAAAAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAUAAAASjl8jgq91LPfjpjr/+Ls///q+ + Qf/7v0H/+79B//vAQ//7vDb/+bEc//iwHP/2rhz/9a0b//SrGv/yqhn/8agY/++kF//toRT/6p8T/+ic + Ev/lmRD/45YO/9+TDf/djwv/2owI/9eJB//UhQT/2JEj/+Gya/zRmVf5mm48sQAAAEYAAAAnAAAAEAAA + AAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAA5zTBtTrXIp+NOY + NPzytz3/+bw+//q9QP/6vkH/+79B//u/Qf/7vj7/+rMg//mxHP/4sBz/9q4c//WsG//0rBr/86oZ//Go + GP/vpBf/7aEV/+qfE//onRH/5ZkQ/+OWD//gkw7/3Y8J/9uMCP/XiQf/1YQG/9uaNv/armz30phU+nJR + LI0AAABAAAAAIgAAAAwAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAACzom + DSyobyXxv4Ut9e2wOv/1ujz/+Ls9//m8QP/6vUD/+r5B//u/Qf/7v0L/+rUn//mxG//5sR3/+LAc//au + HP/1rRv/9Kwa//OqGf/xqBj/76QX/+6iFf/roBP/6JwS/+aZEP/klg//4JMN/96OC//bjQn/2YkI/9WF + Bv/fpkz/06Zp8s2TUPY/LRhtAAAAOQAAABwAAAAJAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAEGRAFFKRqI9mwdibx56o3//G0Ov/ztjv/9bo8//a7Pv/5vED/+r1A//q+Qf/7wEP/+rgu//mx + G//5sh3/+bId//ixHP/2sBz/9a0b//SrGv/yqhn/8agY//CmF//uoxX/6qAT/+mdEf/mmRD/5JYP/+CT + Dv/ejwr/3IwK/9mJB//Whwn/4q5d/9GiZ+7Hj0znEg0HSAAAACcAAAAPAAAAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAGoGcgpaluIvLdoDP/6q03/++yOf/xtDr/87Y7//S4PP/2uz3/+bw+//m9 + QP/6vkL/+rs3//myHP/5sh3/+bId//myHf/5sR3/+LAc//WtHP/0rRv/9KsZ//KpGP/wphf/7qMV/+ug + E//onhL/55oR/+SXD//hlA3/3pAL/9yNCf/Zigf/2I0S/+S0aP/ToGPwvolJxAAAACcAAAARAAAABQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACiaB9ppmsg9dKVL//nqjX/67A3/+6yOP/wtDr/87Y7//W4 + PP/4uz3/+b0+//m9QP/5vUD/+rw7//myHv/5sh3/+bId//myHf/5sh3/+LEd//iwHP/2rhv/9awb//Or + Gv/xqBn/8KYY/+6jFf/roBP/6p4Q/+icDv/llw3/4ZQK/9+QCf/cjQb/2okF/9mRHf/ismj40ZVQ9MGK + SogAAAALAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACmaR7PyYgn+uSdL//loDD/56Iy/+qk + M//rpjT/7qk3//CrOP/xrTn/8a05//CxOP/4vD7/+bxA//izJP/4sRz/+bId//myHf/5sh3/+bId//mx + Hf/4sBz/9q4c//WsG//zqxr/8qkY//GrI//xsDr/8bFF//W0Sf/2s0n/9LJI//OwSP/yr0f/8a1G//Cs + R//urEv/5ahV6dGVT+AAAAAEAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACkaR2XpGoe/6Vq + H/+mayD/pmwh/6hsIv+pbSP/qW4k/6twJf+scCf/rXIn/65zKf/6vDz/+LxA//a1Kv/2sBr/+bEd//my + Hf/5sh3/+bId//myHf/5sR3/+LAc//auHP/1rRv/9Ksa//a3Ov/EiED/xYlB/8aKQ//Hi0T/yY1G/8qO + R//Lj0n/zJBK/82RS//Ok0z/0JRN/9GVTpcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK1yJ//5uzv/9rs+//a3 + Mf/1rhr/9rAc//iyHf/5sh3/+bId//myHf/5sh3/+bEd//iwHP/2rhz/9a0b//m5Ov/Chj//AAAAKwAA + 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 + + \ No newline at end of file diff --git a/SCrawler/Download/DownloadedInfoForm.vb b/SCrawler/Download/DownloadedInfoForm.vb index 8450451..4f85983 100644 --- a/SCrawler/Download/DownloadedInfoForm.vb +++ b/SCrawler/Download/DownloadedInfoForm.vb @@ -161,7 +161,7 @@ Namespace DownloadObjects End Sub Private Sub LIST_DOWN_MouseDoubleClick(sender As Object, e As MouseEventArgs) Handles LIST_DOWN.MouseDoubleClick Try - If _LatestSelected >= 0 AndAlso _LatestSelected <= _TempUsersList.Count - 1 AndAlso + If _LatestSelected.ValueBetween(0, _TempUsersList.Count - 1) AndAlso Not DirectCast(_TempUsersList(_LatestSelected), UserDataBase).Disposed Then _TempUsersList(_LatestSelected).OpenFolder() Catch ex As Exception End Try diff --git a/SCrawler/Download/Groups/DownloadGroup.vb b/SCrawler/Download/Groups/DownloadGroup.vb index 0c0d9d6..05eb3c9 100644 --- a/SCrawler/Download/Groups/DownloadGroup.vb +++ b/SCrawler/Download/Groups/DownloadGroup.vb @@ -15,9 +15,6 @@ Namespace DownloadObjects.Groups 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" -#End Region Private WithEvents BTT_EDIT As ToolStripMenuItem Private WithEvents BTT_DELETE As ToolStripMenuItem Private WithEvents BTT_DOWNLOAD As ToolStripMenuItem @@ -25,7 +22,6 @@ Namespace DownloadObjects.Groups Private ReadOnly SEP_1 As ToolStripSeparator Private WithEvents BTT_MENU As ToolStripMenuItem Friend Property NameBefore As String = String.Empty - Friend Property Name As String Private _Key As String = String.Empty Friend ReadOnly Property Key As String Get diff --git a/SCrawler/Download/Groups/GroupDefaults.vb b/SCrawler/Download/Groups/GroupDefaults.vb index bf61391..5717270 100644 --- a/SCrawler/Download/Groups/GroupDefaults.vb +++ b/SCrawler/Download/Groups/GroupDefaults.vb @@ -18,6 +18,7 @@ Namespace DownloadObjects.Groups Private ReadOnly CH_READY_FOR_DOWN As CheckBox Private ReadOnly CH_READY_FOR_DOWN_IGNORE As CheckBox Private WithEvents TXT_LABELS As TextBoxExtended + Friend WithEvents TXT_NAME As TextBoxExtended Private ReadOnly Labels As List(Of String) Public Sub New() Labels = New List(Of String) @@ -30,6 +31,15 @@ Namespace DownloadObjects.Groups .Dock = DockStyle.Fill .EndInit() End With + TXT_NAME = New TextBoxExtended + With TXT_NAME + .BeginInit() + .Buttons.Add(ADB.Clear) + .CaptionText = "Name" + .CaptionWidth = 50 + .Dock = DockStyle.Fill + .EndInit() + End With CH_TEMPORARY = New CheckBox With {.Text = "Temporary", .Name = "CH_TEMPORARY", .ThreeState = True, .CheckState = CheckState.Indeterminate, .Dock = DockStyle.Fill} CH_FAV = New CheckBox With {.Text = "Favorite", .Name = "CH_FAV", .ThreeState = True, .CheckState = CheckState.Indeterminate, .Dock = DockStyle.Fill} CH_READY_FOR_DOWN = New CheckBox With {.Text = "Ready for download", .Name = "CH_READY_FOR_DOWN", .Checked = True, .Dock = DockStyle.Fill} @@ -77,16 +87,18 @@ Namespace DownloadObjects.Groups CellBorderStyle = TableLayoutPanelCellBorderStyle.Single ColumnCount = 1 ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 100)) - RowCount = 5 + RowCount = 6 RowStyles.Add(New RowStyle(SizeType.Absolute, 25)) + RowStyles.Add(New RowStyle(SizeType.Absolute, 28)) RowStyles.Add(New RowStyle(SizeType.Absolute, 25)) RowStyles.Add(New RowStyle(SizeType.Absolute, 25)) RowStyles.Add(New RowStyle(SizeType.Absolute, 28)) RowStyles.Add(New RowStyle(SizeType.Percent, 100)) End If - Controls.Add(TP_1, 0, 1) - Controls.Add(TP_2, 0, 2) - Controls.Add(TXT_LABELS, 0, 3) + Controls.Add(TXT_NAME, 0, 1) + Controls.Add(TP_1, 0, 2) + Controls.Add(TP_2, 0, 3) + Controls.Add(TXT_LABELS, 0, 4) End Sub Private Sub TXT_LABELS_ActionOnButtonClick(ByVal Sender As ActionButton) Handles TXT_LABELS.ActionOnButtonClick Select Case Sender.DefaultButton @@ -105,6 +117,7 @@ Namespace DownloadObjects.Groups Friend Sub [Get](ByRef Instance As IGroup) If Not Instance Is Nothing Then With Instance + .Name = TXT_NAME.Text .Temporary = CH_TEMPORARY.CheckState .Favorite = CH_FAV.CheckState .ReadyForDownload = CH_READY_FOR_DOWN.Checked @@ -117,6 +130,7 @@ Namespace DownloadObjects.Groups Friend Sub [Set](ByVal Instance As IGroup) If Not Instance Is Nothing Then With Instance + TXT_NAME.Text = .Name CH_TEMPORARY.CheckState = .Temporary CH_FAV.CheckState = .Favorite CH_READY_FOR_DOWN.Checked = .ReadyForDownload diff --git a/SCrawler/Download/Groups/GroupEditorForm.Designer.vb b/SCrawler/Download/Groups/GroupEditorForm.Designer.vb index a468937..5906b0b 100644 --- a/SCrawler/Download/Groups/GroupEditorForm.Designer.vb +++ b/SCrawler/Download/Groups/GroupEditorForm.Designer.vb @@ -23,15 +23,10 @@ Namespace DownloadObjects.Groups Private Sub InitializeComponent() Dim CONTAINER_MAIN As System.Windows.Forms.ToolStripContainer - Dim ActionButton1 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() - Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(GroupEditorForm)) Me.DEFS_GROUP = New SCrawler.DownloadObjects.Groups.GroupDefaults() - Me.TXT_NAME = New PersonalUtilities.Forms.Controls.TextBoxExtended() CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer() CONTAINER_MAIN.ContentPanel.SuspendLayout() CONTAINER_MAIN.SuspendLayout() - Me.DEFS_GROUP.SuspendLayout() - CType(Me.TXT_NAME, System.ComponentModel.ISupportInitialize).BeginInit() Me.SuspendLayout() ' 'CONTAINER_MAIN @@ -40,7 +35,7 @@ Namespace DownloadObjects.Groups 'CONTAINER_MAIN.ContentPanel ' CONTAINER_MAIN.ContentPanel.Controls.Add(Me.DEFS_GROUP) - CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(476, 134) + CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(476, 109) CONTAINER_MAIN.Dock = System.Windows.Forms.DockStyle.Fill CONTAINER_MAIN.LeftToolStripPanelVisible = False CONTAINER_MAIN.Location = New System.Drawing.Point(0, 0) @@ -55,35 +50,19 @@ Namespace DownloadObjects.Groups Me.DEFS_GROUP.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single] Me.DEFS_GROUP.ColumnCount = 1 Me.DEFS_GROUP.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) - Me.DEFS_GROUP.Controls.Add(Me.TXT_NAME, 0, 0) Me.DEFS_GROUP.Dock = System.Windows.Forms.DockStyle.Fill Me.DEFS_GROUP.Location = New System.Drawing.Point(0, 0) Me.DEFS_GROUP.Name = "DEFS_GROUP" - Me.DEFS_GROUP.RowCount = 5 - Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) + Me.DEFS_GROUP.RowCount = 6 + Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 0!)) + Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) - Me.DEFS_GROUP.Size = New System.Drawing.Size(476, 134) + Me.DEFS_GROUP.Size = New System.Drawing.Size(476, 109) Me.DEFS_GROUP.TabIndex = 1 ' - 'TXT_NAME - ' - ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image) - ActionButton1.Index = 0 - ActionButton1.Name = "BTT_CLEAR" - Me.TXT_NAME.Buttons.Add(ActionButton1) - 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 - ' 'GroupEditorForm ' Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!) @@ -104,12 +83,9 @@ Namespace DownloadObjects.Groups CONTAINER_MAIN.ContentPanel.ResumeLayout(False) CONTAINER_MAIN.ResumeLayout(False) CONTAINER_MAIN.PerformLayout() - Me.DEFS_GROUP.ResumeLayout(False) - CType(Me.TXT_NAME, System.ComponentModel.ISupportInitialize).EndInit() Me.ResumeLayout(False) End Sub - Private WithEvents TXT_NAME As PersonalUtilities.Forms.Controls.TextBoxExtended Private WithEvents DEFS_GROUP As GroupDefaults End Class End Namespace \ No newline at end of file diff --git a/SCrawler/Download/Groups/GroupEditorForm.resx b/SCrawler/Download/Groups/GroupEditorForm.resx index 7e5ab0d..56d6ce4 100644 --- a/SCrawler/Download/Groups/GroupEditorForm.resx +++ b/SCrawler/Download/Groups/GroupEditorForm.resx @@ -120,13 +120,4 @@ False - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go - tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX - AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC - - \ No newline at end of file diff --git a/SCrawler/Download/Groups/GroupEditorForm.vb b/SCrawler/Download/Groups/GroupEditorForm.vb index 17591d6..269623d 100644 --- a/SCrawler/Download/Groups/GroupEditorForm.vb +++ b/SCrawler/Download/Groups/GroupEditorForm.vb @@ -10,29 +10,33 @@ Imports PersonalUtilities.Forms Imports PersonalUtilities.Forms.Toolbars Namespace DownloadObjects.Groups Friend Class GroupEditorForm : Implements IOkCancelToolbar - Private ReadOnly MyDefs As DefaultFormProps + Private ReadOnly MyDefs As DefaultFormOptions Friend Property MyGroup As DownloadGroup Friend Sub New(ByRef g As DownloadGroup) InitializeComponent() MyGroup = g - MyDefs = New DefaultFormProps + MyDefs = New DefaultFormOptions End Sub - Private Class NameChecker : Implements IFieldsCheckerProvider + Friend 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) + Private ReadOnly Property Source As IEnumerable(Of IGroup) + Private ReadOnly ParamName As String + Friend Sub New(ByVal _ExistingGroupName As String, ByRef _Source As IEnumerable(Of IGroup), ByVal Param As String) ExistingGroupName = _ExistingGroupName + Source = _Source + ParamName = Param 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" + ErrorMessage = $"{ParamName} 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" + ElseIf Source.Count > 0 AndAlso Source.LongCount(Function(g) g.Name = CStr(Value)) > 0 Then + ErrorMessage = $"A {ParamName.ToLower} with the same name already exists" Else Return Value End If @@ -48,7 +52,6 @@ Namespace DownloadObjects.Groups .AddOkCancelToolbar() If Not MyGroup Is Nothing Then With MyGroup - TXT_NAME.Text = .Name DEFS_GROUP.Set(MyGroup) Text &= $" { .Name}" End With @@ -56,7 +59,8 @@ Namespace DownloadObjects.Groups 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))) + DirectCast(.MyFieldsChecker, FieldsChecker).AddControl(Of String)(DEFS_GROUP.TXT_NAME, DEFS_GROUP.TXT_NAME.CaptionText,, + New NameChecker(If(MyGroup?.Name, String.Empty), Settings.Groups, "Group")) .MyFieldsChecker.EndLoaderOperations() .EndLoaderOperations() End With @@ -66,7 +70,6 @@ Namespace DownloadObjects.Groups If MyGroup Is Nothing Then MyGroup = New DownloadGroup With MyGroup .NameBefore = .Name - .Name = TXT_NAME.Text DEFS_GROUP.Get(MyGroup) End With MyDefs.CloseForm() diff --git a/SCrawler/Download/Groups/GroupParameters.vb b/SCrawler/Download/Groups/GroupParameters.vb index 71a62eb..6de8edc 100644 --- a/SCrawler/Download/Groups/GroupParameters.vb +++ b/SCrawler/Download/Groups/GroupParameters.vb @@ -8,6 +8,7 @@ ' but WITHOUT ANY WARRANTY Namespace DownloadObjects.Groups Friend Interface IGroup + Property Name As String ReadOnly Property Labels As List(Of String) Property Temporary As CheckState Property Favorite As CheckState @@ -15,10 +16,12 @@ Namespace DownloadObjects.Groups Property ReadyForDownloadIgnore As Boolean End Interface Friend Class GroupParameters : Implements IGroup, IDisposable + Protected Const Name_Name As String = "Name" Protected Const Name_Temporary As String = "Temporary" Protected Const Name_Favorite As String = "Favorite" Protected Const Name_ReadyForDownload As String = "RFD" Protected Const Name_ReadyForDownloadIgnore As String = "RFDI" + Friend Property Name As String Implements IGroup.Name Friend ReadOnly Property Labels As List(Of String) Implements IGroup.Labels Friend Property Temporary As CheckState = CheckState.Indeterminate Implements IGroup.Temporary Friend Property Favorite As CheckState = CheckState.Indeterminate Implements IGroup.Favorite diff --git a/SCrawler/Download/Scheduler.vb b/SCrawler/Download/Scheduler.vb new file mode 100644 index 0000000..0132acb --- /dev/null +++ b/SCrawler/Download/Scheduler.vb @@ -0,0 +1,149 @@ +' 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 +Imports SCrawler.DownloadObjects.Groups +Imports System.Threading +Namespace DownloadObjects + Friend Class Scheduler : Implements IEnumerable(Of AutoDownloader), IMyEnumerator(Of AutoDownloader), IDisposable + Friend Const Name_Plan As String = "Plan" + Friend Event UserFind As AutoDownloader.UserFindEventHandler + Private Sub OnUserFind(ByVal Key As String, ByVal Activate As Boolean) + RaiseEvent UserFind(Key, Activate) + End Sub + Private ReadOnly Plans As List(Of AutoDownloader) + Private ReadOnly File As SFile = $"Settings\AutoDownload.xml" + Private ReadOnly PlanWorking As Predicate(Of AutoDownloader) = Function(Plan) Plan.Working + Private ReadOnly PlanDownloading As Predicate(Of AutoDownloader) = Function(Plan) Plan.Downloading + Private ReadOnly PlansWaiter As Action(Of Predicate(Of AutoDownloader)) = Sub(ByVal Predicate As Predicate(Of AutoDownloader)) + While Plans.Exists(Predicate) : Thread.Sleep(200) : End While + End Sub + Friend Sub New() + Plans = New List(Of AutoDownloader) + If File.Exists Then + Using x As New XmlFile(File,, False) With {.AllowSameNames = True} + x.LoadData() + If x.Contains(Name_Plan) Then + For Each e In x : Plans.Add(New AutoDownloader(e)) : Next + Else + Plans.Add(New AutoDownloader(x)) + End If + End Using + End If + If Plans.Count > 0 Then Plans.ForEach(Sub(p) + p.Source = Me + AddHandler p.UserFind, AddressOf OnUserFind + End Sub) + End Sub + Default Friend ReadOnly Property Item(ByVal Index As Integer) As AutoDownloader Implements IMyEnumerator(Of AutoDownloader).MyEnumeratorObject + Get + Return Plans(Index) + End Get + End Property + Friend ReadOnly Property Count As Integer Implements IMyEnumerator(Of AutoDownloader).MyEnumeratorCount + Get + 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)) + End Function + Friend Sub Add(ByVal Plan As AutoDownloader) + Plan.Source = Me + AddHandler Plan.UserFind, AddressOf OnUserFind + Plans.Add(Plan) + Update() + End Sub + Friend Async Function RemoveAt(ByVal Index As Integer) As Task + If Index.ValueBetween(0, Count - 1) Then + With Plans(Index) + .Stop() + If .Working Then + Await Task.Run(Sub() + While .Working : Thread.Sleep(510) : End While + End Sub) + End If + .Dispose() + End With + Plans.RemoveAt(Index) + Update() + End If + End Function + Private _UpdateRequired As Boolean = False + Friend Sub Update() + _UpdateRequired = True + Try + If Plans.Count > 0 Then + Using x As New XmlFile With {.Name = "Scheduler", .AllowSameNames = True} : x.AddRange(Plans) : x.Save(File) : End Using + Else + File.Delete() + End If + _UpdateRequired = False + Catch + End Try + End Sub +#Region "Groups Support" + Friend Sub GROUPS_Updated(ByVal Sender As DownloadGroup) + If Count > 0 Then Plans.ForEach(Sub(p) p.GROUPS_Updated(Sender)) + End Sub + Friend Sub GROUPS_Deleted(ByVal Sender As DownloadGroup) + If Count > 0 Then Plans.ForEach(Sub(p) p.GROUPS_Deleted(Sender)) + End Sub +#End Region +#Region "Execution" + Friend Async Sub Start(ByVal Init As Boolean) + If Count > 0 Then + If Plans.Exists(PlanDownloading) Then Await Task.Run(Sub() PlansWaiter(PlanDownloading)) + For Each Plan In Plans : Plan.Start(Init) : Thread.Sleep(200) : Next + End If + End Sub + Friend Sub [Stop]() + If Count > 0 Then Plans.ForEach(Sub(p) p.Stop()) + End Sub + Friend Property Pause As Boolean + Get + If Count > 0 Then Return Plans(0).Pause Else Return False + End Get + Set(ByVal p As Boolean) + If Count > 0 Then Plans.ForEach(Sub(pp) pp.Pause = p) + End Set + End Property +#End Region +#Region "IEnumerable Support" + Private Function GetEnumerator() As IEnumerator(Of AutoDownloader) Implements IEnumerable(Of AutoDownloader).GetEnumerator + Return New MyEnumerator(Of AutoDownloader)(Me) + End Function + Private Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator + Return GetEnumerator() + 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 + [Stop]() + If Plans.Exists(PlanWorking) Then Task.WaitAll(Task.Run(Sub() PlansWaiter(PlanWorking))) + If _UpdateRequired Then Update() + Plans.ListClearDispose + 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/SchedulerEditorForm.Designer.vb b/SCrawler/Download/SchedulerEditorForm.Designer.vb new file mode 100644 index 0000000..ce94c6d --- /dev/null +++ b/SCrawler/Download/SchedulerEditorForm.Designer.vb @@ -0,0 +1,77 @@ +' 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 + + Partial Friend Class SchedulerEditorForm : 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() + Me.CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer() + Me.LIST_PLANS = New System.Windows.Forms.ListBox() + Me.CONTAINER_MAIN.ContentPanel.SuspendLayout() + Me.CONTAINER_MAIN.SuspendLayout() + Me.SuspendLayout() + ' + 'CONTAINER_MAIN + ' + Me.CONTAINER_MAIN.BottomToolStripPanelVisible = False + ' + 'CONTAINER_MAIN.ContentPanel + ' + Me.CONTAINER_MAIN.ContentPanel.Controls.Add(Me.LIST_PLANS) + Me.CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(414, 316) + Me.CONTAINER_MAIN.Dock = System.Windows.Forms.DockStyle.Fill + Me.CONTAINER_MAIN.LeftToolStripPanelVisible = False + Me.CONTAINER_MAIN.Location = New System.Drawing.Point(0, 0) + Me.CONTAINER_MAIN.Name = "CONTAINER_MAIN" + Me.CONTAINER_MAIN.RightToolStripPanelVisible = False + Me.CONTAINER_MAIN.Size = New System.Drawing.Size(414, 341) + Me.CONTAINER_MAIN.TabIndex = 0 + ' + 'LIST_PLANS + ' + Me.LIST_PLANS.Dock = System.Windows.Forms.DockStyle.Fill + Me.LIST_PLANS.FormattingEnabled = True + Me.LIST_PLANS.Location = New System.Drawing.Point(0, 0) + Me.LIST_PLANS.Name = "LIST_PLANS" + Me.LIST_PLANS.Size = New System.Drawing.Size(414, 316) + Me.LIST_PLANS.TabIndex = 0 + ' + 'SchedulerEditorForm + ' + Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!) + Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font + Me.ClientSize = New System.Drawing.Size(414, 341) + Me.Controls.Add(Me.CONTAINER_MAIN) + Me.KeyPreview = True + Me.MinimumSize = New System.Drawing.Size(430, 380) + Me.Name = "SchedulerEditorForm" + Me.ShowIcon = False + Me.Text = "Scheduler" + Me.CONTAINER_MAIN.ContentPanel.ResumeLayout(False) + Me.CONTAINER_MAIN.ResumeLayout(False) + Me.CONTAINER_MAIN.PerformLayout() + Me.ResumeLayout(False) + + End Sub + + Private WithEvents CONTAINER_MAIN As ToolStripContainer + Private WithEvents LIST_PLANS As ListBox + End Class +End Namespace \ No newline at end of file diff --git a/SCrawler/Download/SchedulerEditorForm.resx b/SCrawler/Download/SchedulerEditorForm.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/SCrawler/Download/SchedulerEditorForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + \ No newline at end of file diff --git a/SCrawler/Download/SchedulerEditorForm.vb b/SCrawler/Download/SchedulerEditorForm.vb new file mode 100644 index 0000000..745efc0 --- /dev/null +++ b/SCrawler/Download/SchedulerEditorForm.vb @@ -0,0 +1,117 @@ +' 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.Toolbars +Namespace DownloadObjects + Friend Class SchedulerEditorForm : Implements IEditToolbar + Private ReadOnly MyDefs As DefaultFormOptions + Private WithEvents BTT_SKIP As ToolStripButton + Private WithEvents BTT_START As ToolStripButton + Friend Sub New() + InitializeComponent() + MyDefs = New DefaultFormOptions + End Sub + Private Sub SchedulerEditorForm_Load(sender As Object, e As EventArgs) Handles Me.Load + With MyDefs + .MyViewInitialize(Me, Settings.Design) + .AddEditToolbar() + BTT_SKIP = New ToolStripButton With { + .Text = "Skip", + .ToolTipText = "Skip next run", + .AutoToolTip = True, + .DisplayStyle = ToolStripItemDisplayStyle.Text + } + BTT_START = New ToolStripButton With { + .Text = "Start", + .Image = My.Resources.StartPic_01_Green_16, + .ToolTipText = "Run selected plan", + .AutoToolTip = True + } + .MyEditToolbar.ToolStrip.Items.AddRange({BTT_START, BTT_SKIP}) + Refill() + .EndLoaderOperations(False) + End With + End Sub + Private Sub SchedulerEditorForm_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed + BTT_SKIP.Dispose() + End Sub + Private Sub SchedulerEditorForm_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown + If e.KeyCode = Keys.Escape Then Close() + End Sub + Private Sub Refill() Implements IEditToolbar.Update + Try + LIST_PLANS.Items.Clear() + If Settings.Automation.Count > 0 Then + LIST_PLANS.Items.AddRange(Settings.Automation.Select(Function(a) a.ToString()).Cast(Of Object).ToArray) + If _LatestSelected.ValueBetween(0, LIST_PLANS.Items.Count - 1) Then LIST_PLANS.SelectedIndex = _LatestSelected + Else + _LatestSelected = -1 + End If + Catch ex As Exception + ErrorsDescriber.Execute(EDP.SendInLog, ex) + End Try + End Sub + Private Sub Add() Implements IEditToolbar.Add + Dim a As New AutoDownloader(True) + Using f As New AutoDownloaderEditorForm(a) + f.ShowDialog() + If f.DialogResult = DialogResult.OK Then + Settings.Automation.Add(a) + Refill() + Else + a.Dispose() + End If + End Using + End Sub + Private Sub Edit() Implements IEditToolbar.Edit + If _LatestSelected.ValueBetween(0, LIST_PLANS.Items.Count - 1) Then + Using f As New AutoDownloaderEditorForm(Settings.Automation(_LatestSelected)) : f.ShowDialog() : End Using + Refill() + Else + MsgBoxE("You have not selected a plan to edit.", vbExclamation) + End If + End Sub + Private _DeleteInProgress As Boolean = False + Private Async Sub Delete() Implements IEditToolbar.Delete + If Not _DeleteInProgress Then + If _LatestSelected.ValueBetween(0, LIST_PLANS.Items.Count - 1) Then + _DeleteInProgress = True + Dim n$ = Settings.Automation(_LatestSelected).Name + Await Settings.Automation.RemoveAt(_LatestSelected) + Refill() + MsgBoxE($"Plan [{n}] deleted") + _DeleteInProgress = False + Else + MsgBoxE("You have not selected a plan to delete.", vbExclamation) + End If + Else + MsgBoxE({"One of the plans is currently in progress. Wait until this plan is stopped and deleted.", "Deleting a plan"}, vbExclamation) + End If + End Sub + Private _LatestSelected As Integer = -1 + Private Sub LIST_PLANS_SelectedIndexChanged(sender As Object, e As EventArgs) Handles LIST_PLANS.SelectedIndexChanged + _LatestSelected = LIST_PLANS.SelectedIndex + End Sub + Private Sub LIST_PLANS_MouseDoubleClick(sender As Object, e As MouseEventArgs) Handles LIST_PLANS.MouseDoubleClick + Edit() + End Sub + Private Sub BTT_START_Click(sender As Object, e As EventArgs) Handles BTT_START.Click + If _LatestSelected.ValueBetween(0, LIST_PLANS.Items.Count - 1) Then + With Settings.Automation(_LatestSelected) : .Start(.IsNewPlan) : End With + Refill() + End If + End Sub + Private Sub BTT_SKIP_Click(sender As Object, e As EventArgs) Handles BTT_SKIP.Click + If _LatestSelected.ValueBetween(0, LIST_PLANS.Items.Count - 1) Then + Settings.Automation(_LatestSelected).Skip() + Refill() + End If + 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 038a54f..0565f67 100644 --- a/SCrawler/Download/TDownloader.vb +++ b/SCrawler/Download/TDownloader.vb @@ -39,14 +39,13 @@ Namespace DownloadObjects End Property #End Region #Region "Automation Support" - Friend Property DisableOpenForms As Boolean = False - Private _DisableCompleteNotification As Boolean = False - Private _AutoDownloaderWorking As Boolean = False - Friend WriteOnly Property AutoDownloaderWorking As Boolean + Private _AutoDownloaderTasks As Integer = 0 + Friend Property AutoDownloaderWorking As Boolean + Private Get + Return _AutoDownloaderTasks > 0 + End Get Set(ByVal adw As Boolean) - _AutoDownloaderWorking = adw - DisableOpenForms = adw - _DisableCompleteNotification = adw + _AutoDownloaderTasks += IIf(adw, 1, -1) End Set End Property Friend Sub InvokeDownloadsChangeEvent() @@ -70,6 +69,9 @@ Namespace DownloadObjects Return Items.Count End Get End Property + Friend Sub Clear() + Items.Clear() + End Sub Friend ReadOnly Property Working As Boolean Get Return _Working OrElse If(Thread?.IsAlive, False) @@ -237,16 +239,17 @@ Namespace DownloadObjects #Region "Thread" Private CheckerThread As Thread Private Sub [Start]() - If Not DisableOpenForms AndAlso MyProgressForm.ReadyToOpen AndAlso Pool.LongCount(Function(p) p.Count > 0) > 1 Then MyProgressForm.Show() : MainFrameObj.Focus() + If Not AutoDownloaderWorking AndAlso 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 Not DisableOpenForms AndAlso InfoForm.ReadyToOpen Then InfoForm.Show() : MainFrameObj.Focus() + If Not AutoDownloaderWorking AndAlso InfoForm.ReadyToOpen Then InfoForm.Show() : MainFrameObj.Focus() CheckerThread = New Thread(New ThreadStart(AddressOf JobsChecker)) CheckerThread.SetApartmentState(ApartmentState.MTA) CheckerThread.Start() End If End Sub Private Sub JobsChecker() + RaiseEvent OnDownloading(True) Try MainProgress.TotalCount = 0 MainProgress.CurrentCounter = 0 @@ -257,7 +260,7 @@ Namespace DownloadObjects Next Thread.Sleep(200) Loop - Catch ex As Exception + Catch Finally With MainProgress .TotalCount = 0 @@ -268,15 +271,16 @@ Namespace DownloadObjects 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) + UpdateJobsLabel() + RaiseEvent OnDownloading(False) End Try End Sub Private Sub StartDownloading(ByRef _Job As Job) - RaiseEvent OnDownloading(True) Dim isSeparated As Boolean = _Job.IsSeparated Dim n$ = _Job.Name Dim pt As Func(Of String, String) = Function(ByVal t As String) As String Dim _t$ = If(isSeparated, $"{n} {Left(t, 1).ToLower}{Right(t, t.Length - 1)}", t) - If Not _DisableCompleteNotification Then RaiseEvent SendNotification(_t) + If Not AutoDownloaderWorking Then RaiseEvent SendNotification(_t) Return _t End Function Try @@ -287,7 +291,7 @@ Namespace DownloadObjects Dim SiteChecked As Boolean = False Do While _Job.Count > 0 _Job.ThrowIfCancellationRequested() - If Not SiteChecked Then _Job.Available(_AutoDownloaderWorking) : SiteChecked = True : Continue Do + If Not SiteChecked Then _Job.Available(AutoDownloaderWorking) : SiteChecked = True : Continue Do UpdateJobsLabel() DownloadData(_Job, _Job.Token) _Job.ThrowIfCancellationRequested() @@ -300,17 +304,12 @@ Namespace DownloadObjects _Job.Progress.InformationTemporary = pt("Downloading error") ErrorsDescriber.Execute(EDP.SendInLog, ex, "TDownloader.Start") Finally + If _Job.Count > 0 Then _Job.Clear() _Job.Stopped() - UpdateJobsLabel() - RaiseEvent OnDownloading(False) End Try End Sub Friend Sub [Stop]() - If Pool.Count > 0 Then - For Each j As Job In Pool - If j.Working Then j.Stop() - Next - End If + If Pool.Count > 0 Then Pool.ForEach(Sub(j) If j.Working Then j.Stop()) End Sub Private Sub UpdateJobsLabel() RaiseEvent OnJobsChange(Count) diff --git a/SCrawler/Editors/CollectionEditorForm.Designer.vb b/SCrawler/Editors/CollectionEditorForm.Designer.vb index f7a9069..2b25ae0 100644 --- a/SCrawler/Editors/CollectionEditorForm.Designer.vb +++ b/SCrawler/Editors/CollectionEditorForm.Designer.vb @@ -44,13 +44,11 @@ 'CMB_COLLECTIONS ' ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image) - ActionButton1.Index = 0 - ActionButton1.Name = "BTT_COMBOBOX_ARROW" - ActionButton1.Visible = False + ActionButton1.Name = "Add" + ActionButton1.ToolTipText = "Add new collection" ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image) - ActionButton2.Index = 1 - ActionButton2.Name = "BTT_ADD" - ActionButton2.ToolTipText = "Add new collection" + ActionButton2.Name = "ArrowDown" + ActionButton2.Visible = False Me.CMB_COLLECTIONS.Buttons.Add(ActionButton1) Me.CMB_COLLECTIONS.Buttons.Add(ActionButton2) Me.CMB_COLLECTIONS.Dock = System.Windows.Forms.DockStyle.Fill diff --git a/SCrawler/Editors/CollectionEditorForm.resx b/SCrawler/Editors/CollectionEditorForm.resx index 06161e7..9512fa7 100644 --- a/SCrawler/Editors/CollectionEditorForm.resx +++ b/SCrawler/Editors/CollectionEditorForm.resx @@ -119,6 +119,28 @@ + + iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6 + JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsTAAALEwEAmpwYAAADmUlE + QVRIS62WWWxMURjHL220JW1HausmlFrDFKUhnUGH6bRFzJ2idImlC0Vp2mlji1A8iNhCPIjIRES8EU+W + h2oEtbSDTk3HNNM7S01VKsXjkb/vXBo3k1Ee7sMvmZzzzf//ne/+z50RAAxL1MUIG4G/YAv3HSVhF5Vw + IYNdz3LadVj9RgdTB+HQYYPHIJuE1ocSdlEJFzG+1bPRLQLinglIeCkg+XUkKvz56hnkOfQs/rmA8S9H + YEp7FDI64tAQtKhnsMapZ7zzNHsUFnbGY4VzIk70l6hnIH4wsDR7NBZ3apDrSqL5T8eFgUr1DLZ78lim + Q4N8VzK29MxEpZSBa4M16hnU+c3M9CEFpdJsVHsXos63DDcHrf9nQEXD5VymwW/5USLNwl5vJhp7dTgW + NML2pR7jbsUMS+KdMTa5Q8NQxinfBU4dRFcOyjy52OtbhwOBDTgZLKPPmTgY0ON4MBdNfSbYBupxY8Aq + G10dqMG5/nIc7ytGQ6CQRliAamkTN/g1Ai4e95Qy3iogpX0UtBRDnhRzdxq2SXOxz5eFQ70rScCEU335 + ssGxj0YS06HSm4GN3ekwdE2C1hGH1LZR0JDOJof5jwHvnIvzTa0jlooTYfktvt+fhcOBHDQFTWRgxJGP + ObAGsulZLMLWnjlY756K5c4JmNcRi6T2SGheCIihS2l5ozAo6NRhMolnUAcGV6IcwwqvFrX+JTjYuwKH + SfRAYDms/mzs9y1GFe2VSnOw1j0FejqpLN4WCX4ZufiIBwLMLxQGm12rsLQzgWKYgmLPLNTQw6ynpDSS + IBet8y+TqaVRVdFIeJrWuCcj+/0EzH43BomvIhBLI45uFiDcJ+6QwROFwa6+Amb9bGFNg6Xs9Ncd7Oy3 + Knb2eyU7/20nu9y/m136tIvEl6BC0qKoZwby3alo9JVhj7T5R7m/kJVIIityi8zyXmTiW+I10SqyIQNb + uIgNwYuuf25kFd75KPKkI49OmUWnrfYWyXv/wBb2cijhhVf6a9lGei65XclYRDd6mj0GWz2iLBJaH0rY + RSVc5Eywmhm7kuQXHX+bJlBStrh+zTi0PpSwi0q4yNFAOVvgiEcKJWUsxZn/NhT+znlofShhF5VwkRpv + MUtti4KGYjj6sYCIh5QSu4oG27stjItHU+cjeQzvkcFzFQ2KnSKLoc4FukDCXeI2GbSoaFD4ziyPxNxK + 0AUyNxOP1DOwcaG/8I+/LRB+At7psBnyDBG0AAAAAElFTkSuQmCC + + + iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABGdBTUEAALGPC/xhBQAAE65JREFUeF7t 3X2sJWddB/DdLi2lQG2hdOHuvfM887J7Cxca4ELTQMDWKigIFpBAEAgi9g+CJpJo9Q8NJhgBiYZIYspL @@ -206,28 +228,6 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6LEtW/4flgYiLD1qeX0A AAAASUVORK5CYII= - - - - - iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6 - JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsTAAALEwEAmpwYAAADmUlE - QVRIS62WWWxMURjHL220JW1HausmlFrDFKUhnUGH6bRFzJ2idImlC0Vp2mlji1A8iNhCPIjIRES8EU+W - h2oEtbSDTk3HNNM7S01VKsXjkb/vXBo3k1Ee7sMvmZzzzf//ne/+z50RAAxL1MUIG4G/YAv3HSVhF5Vw - IYNdz3LadVj9RgdTB+HQYYPHIJuE1ocSdlEJFzG+1bPRLQLinglIeCkg+XUkKvz56hnkOfQs/rmA8S9H - YEp7FDI64tAQtKhnsMapZ7zzNHsUFnbGY4VzIk70l6hnIH4wsDR7NBZ3apDrSqL5T8eFgUr1DLZ78lim - Q4N8VzK29MxEpZSBa4M16hnU+c3M9CEFpdJsVHsXos63DDcHrf9nQEXD5VymwW/5USLNwl5vJhp7dTgW - NML2pR7jbsUMS+KdMTa5Q8NQxinfBU4dRFcOyjy52OtbhwOBDTgZLKPPmTgY0ON4MBdNfSbYBupxY8Aq - G10dqMG5/nIc7ytGQ6CQRliAamkTN/g1Ai4e95Qy3iogpX0UtBRDnhRzdxq2SXOxz5eFQ70rScCEU335 - ssGxj0YS06HSm4GN3ekwdE2C1hGH1LZR0JDOJof5jwHvnIvzTa0jlooTYfktvt+fhcOBHDQFTWRgxJGP - ObAGsulZLMLWnjlY756K5c4JmNcRi6T2SGheCIihS2l5ozAo6NRhMolnUAcGV6IcwwqvFrX+JTjYuwKH - SfRAYDms/mzs9y1GFe2VSnOw1j0FejqpLN4WCX4ZufiIBwLMLxQGm12rsLQzgWKYgmLPLNTQw6ynpDSS - IBet8y+TqaVRVdFIeJrWuCcj+/0EzH43BomvIhBLI45uFiDcJ+6QwROFwa6+Amb9bGFNg6Xs9Ncd7Oy3 - Knb2eyU7/20nu9y/m136tIvEl6BC0qKoZwby3alo9JVhj7T5R7m/kJVIIityi8zyXmTiW+I10SqyIQNb - uIgNwYuuf25kFd75KPKkI49OmUWnrfYWyXv/wBb2cijhhVf6a9lGei65XclYRDd6mj0GWz2iLBJaH0rY - RSVc5Eywmhm7kuQXHX+bJlBStrh+zTi0PpSwi0q4yNFAOVvgiEcKJWUsxZn/NhT+znlofShhF5VwkRpv - MUtti4KGYjj6sYCIh5QSu4oG27stjItHU+cjeQzvkcFzFQ2KnSKLoc4FukDCXeI2GbSoaFD4ziyPxNxK - 0AUyNxOP1DOwcaG/8I+/LRB+At7psBnyDBG0AAAAAElFTkSuQmCC \ No newline at end of file diff --git a/SCrawler/Editors/CollectionEditorForm.vb b/SCrawler/Editors/CollectionEditorForm.vb index f7b81a7..a851413 100644 --- a/SCrawler/Editors/CollectionEditorForm.vb +++ b/SCrawler/Editors/CollectionEditorForm.vb @@ -11,12 +11,12 @@ Imports PersonalUtilities.Forms.Controls.Base Imports PersonalUtilities.Forms.Toolbars Namespace Editors Friend Class CollectionEditorForm : Implements IOkCancelToolbar - Private ReadOnly MyDefs As DefaultFormProps + Private ReadOnly MyDefs As DefaultFormOptions Private ReadOnly Collections As List(Of String) Friend Property [Collection] As String = String.Empty Friend Sub New() InitializeComponent() - MyDefs = New DefaultFormProps + MyDefs = New DefaultFormOptions Collections = New List(Of String) End Sub Friend Sub New(ByVal CollectionName As String) @@ -32,7 +32,7 @@ Namespace Editors If Collections.ListExists Then Collections.Sort() : CMB_COLLECTIONS.Items.AddRange(From c In Collections Select New ListItem(c)) If Not Collection.IsEmptyString And Collections.Contains(Collection) Then CMB_COLLECTIONS.SelectedIndex = Collections.IndexOf(Collection) .DelegateClosingChecker = False - .EndLoaderOperations(False) + .EndLoaderOperations() End With Catch ex As Exception MyDefs.InvokeLoaderError(ex) diff --git a/SCrawler/Editors/GlobalSettingsForm.Designer.vb b/SCrawler/Editors/GlobalSettingsForm.Designer.vb index db59fad..d50a3db 100644 --- a/SCrawler/Editors/GlobalSettingsForm.Designer.vb +++ b/SCrawler/Editors/GlobalSettingsForm.Designer.vb @@ -37,12 +37,13 @@ Dim TAB_BEHAVIOR As System.Windows.Forms.TabPage Dim TP_BEHAVIOR As System.Windows.Forms.TableLayoutPanel Dim ActionButton7 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() + Dim ActionButton8 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Dim TP_OPEN_INFO As System.Windows.Forms.TableLayoutPanel Dim TP_OPEN_PROGRESS As System.Windows.Forms.TableLayoutPanel Dim TAB_DOWN As System.Windows.Forms.TabPage 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 ActionButton10 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() 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() @@ -73,6 +74,7 @@ Me.CH_DOWN_OPEN_PROGRESS_SUSPEND = New System.Windows.Forms.CheckBox() Me.TXT_CHANNELS_ROWS = New PersonalUtilities.Forms.Controls.TextBoxExtended() Me.TXT_CHANNELS_COLUMNS = New PersonalUtilities.Forms.Controls.TextBoxExtended() + Me.CH_DOWN_IMAGES_NATIVE = New System.Windows.Forms.CheckBox() Me.TXT_CHANNEL_USER_POST_LIMIT = New PersonalUtilities.Forms.Controls.TextBoxExtended() Me.TXT_FOLDER_CMD = New PersonalUtilities.Forms.Controls.TextBoxExtended() Me.CH_EXIT_CONFIRM = New System.Windows.Forms.CheckBox() @@ -85,8 +87,6 @@ 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.TAB_AUTO = New System.Windows.Forms.TabPage() - Me.PANEL_AUTO = New System.Windows.Forms.Panel() Me.CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer() TP_BASIS = New System.Windows.Forms.TableLayoutPanel() TP_IMAGES = New System.Windows.Forms.TableLayoutPanel() @@ -137,7 +137,6 @@ CType(Me.TXT_SCRIPT, System.ComponentModel.ISupportInitialize).BeginInit() CType(Me.TXT_DOWN_COMPLETE_SCRIPT, System.ComponentModel.ISupportInitialize).BeginInit() Me.TAB_MAIN.SuspendLayout() - Me.TAB_AUTO.SuspendLayout() Me.CONTAINER_MAIN.ContentPanel.SuspendLayout() Me.CONTAINER_MAIN.SuspendLayout() Me.SuspendLayout() @@ -176,11 +175,9 @@ 'TXT_GLOBAL_PATH ' ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image) - ActionButton1.Index = 0 - ActionButton1.Name = "BTT_OPEN" + ActionButton1.Name = "Open" ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image) - ActionButton2.Index = 1 - ActionButton2.Name = "BTT_CLEAR" + ActionButton2.Name = "Clear" Me.TXT_GLOBAL_PATH.Buttons.Add(ActionButton1) Me.TXT_GLOBAL_PATH.Buttons.Add(ActionButton2) Me.TXT_GLOBAL_PATH.CaptionText = "Data Path" @@ -244,8 +241,7 @@ 'TXT_COLLECTIONS_PATH ' ActionButton3.BackgroundImage = CType(resources.GetObject("ActionButton3.BackgroundImage"), System.Drawing.Image) - ActionButton3.Index = 0 - ActionButton3.Name = "BTT_CLEAR" + ActionButton3.Name = "Clear" Me.TXT_COLLECTIONS_PATH.Buttons.Add(ActionButton3) Me.TXT_COLLECTIONS_PATH.CaptionText = "Collections folder" Me.TXT_COLLECTIONS_PATH.CaptionToolTipEnabled = True @@ -259,8 +255,7 @@ 'TXT_MAX_JOBS_USERS ' ActionButton4.BackgroundImage = CType(resources.GetObject("ActionButton4.BackgroundImage"), System.Drawing.Image) - ActionButton4.Index = 0 - ActionButton4.Name = "BTT_REFRESH" + ActionButton4.Name = "Refresh" ActionButton4.ToolTipText = "Set to default" Me.TXT_MAX_JOBS_USERS.Buttons.Add(ActionButton4) Me.TXT_MAX_JOBS_USERS.CaptionSizeType = System.Windows.Forms.SizeType.Percent @@ -279,8 +274,7 @@ 'TXT_MAX_JOBS_CHANNELS ' ActionButton5.BackgroundImage = CType(resources.GetObject("ActionButton5.BackgroundImage"), System.Drawing.Image) - ActionButton5.Index = 0 - ActionButton5.Name = "BTT_REFRESH" + ActionButton5.Name = "Refresh" ActionButton5.ToolTipText = "Set to default" Me.TXT_MAX_JOBS_CHANNELS.Buttons.Add(ActionButton5) Me.TXT_MAX_JOBS_CHANNELS.CaptionSizeType = System.Windows.Forms.SizeType.Percent @@ -310,8 +304,7 @@ 'TXT_IMGUR_CLIENT_ID ' ActionButton6.BackgroundImage = CType(resources.GetObject("ActionButton6.BackgroundImage"), System.Drawing.Image) - ActionButton6.Index = 0 - ActionButton6.Name = "BTT_CLEAR" + ActionButton6.Name = "Clear" Me.TXT_IMGUR_CLIENT_ID.Buttons.Add(ActionButton6) Me.TXT_IMGUR_CLIENT_ID.CaptionText = "Imgur Client ID" Me.TXT_IMGUR_CLIENT_ID.Dock = System.Windows.Forms.DockStyle.Fill @@ -687,19 +680,31 @@ TP_DEFS.Controls.Add(Me.CH_DOWN_VIDEOS, 0, 3) TP_DEFS.Controls.Add(Me.CH_DOWN_IMAGES, 0, 2) TP_DEFS.Controls.Add(Me.CH_DEF_TEMP, 0, 1) + TP_DEFS.Controls.Add(Me.CH_DOWN_IMAGES_NATIVE, 0, 4) TP_DEFS.Dock = System.Windows.Forms.DockStyle.Fill TP_DEFS.Location = New System.Drawing.Point(3, 3) TP_DEFS.Name = "TP_DEFS" - TP_DEFS.RowCount = 5 + TP_DEFS.RowCount = 6 + 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.Absolute, 25.0!)) 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.Absolute, 25.0!)) 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, 278) TP_DEFS.TabIndex = 0 ' + 'CH_DOWN_IMAGES_NATIVE + ' + Me.CH_DOWN_IMAGES_NATIVE.AutoSize = True + Me.CH_DOWN_IMAGES_NATIVE.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_DOWN_IMAGES_NATIVE.Location = New System.Drawing.Point(4, 108) + Me.CH_DOWN_IMAGES_NATIVE.Name = "CH_DOWN_IMAGES_NATIVE" + Me.CH_DOWN_IMAGES_NATIVE.Size = New System.Drawing.Size(562, 19) + Me.CH_DOWN_IMAGES_NATIVE.TabIndex = 4 + Me.CH_DOWN_IMAGES_NATIVE.Text = "Download 'jpg' instead of 'webp'" + Me.CH_DOWN_IMAGES_NATIVE.UseVisualStyleBackColor = True + ' 'TAB_DEFS_CHANNELS ' TAB_DEFS_CHANNELS.Controls.Add(TP_CHANNELS) @@ -799,8 +804,7 @@ Me.TXT_FOLDER_CMD.AutoShowClearButton = True ActionButton7.BackgroundImage = CType(resources.GetObject("ActionButton7.BackgroundImage"), System.Drawing.Image) ActionButton7.Enabled = False - ActionButton7.Index = 0 - ActionButton7.Name = "BTT_CLEAR" + ActionButton7.Name = "Clear" ActionButton7.Visible = False Me.TXT_FOLDER_CMD.Buttons.Add(ActionButton7) Me.TXT_FOLDER_CMD.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.CheckBox @@ -851,11 +855,18 @@ ' 'TXT_CLOSE_SCRIPT ' + Me.TXT_CLOSE_SCRIPT.AutoShowClearButton = True + ActionButton8.BackgroundImage = CType(resources.GetObject("ActionButton8.BackgroundImage"), System.Drawing.Image) + ActionButton8.Enabled = False + ActionButton8.Name = "Clear" + ActionButton8.Visible = False + Me.TXT_CLOSE_SCRIPT.Buttons.Add(ActionButton8) 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.LeaveDefaultButtons = True 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 @@ -966,14 +977,12 @@ ' 'TXT_SCRIPT ' - ActionButton8.BackgroundImage = CType(resources.GetObject("ActionButton8.BackgroundImage"), System.Drawing.Image) - ActionButton8.Index = 0 - ActionButton8.Name = "BTT_OPEN" ActionButton9.BackgroundImage = CType(resources.GetObject("ActionButton9.BackgroundImage"), System.Drawing.Image) - ActionButton9.Index = 1 - ActionButton9.Name = "BTT_CLEAR" - Me.TXT_SCRIPT.Buttons.Add(ActionButton8) + ActionButton9.Name = "Open" + ActionButton10.BackgroundImage = CType(resources.GetObject("ActionButton10.BackgroundImage"), System.Drawing.Image) + ActionButton10.Name = "Clear" Me.TXT_SCRIPT.Buttons.Add(ActionButton9) + Me.TXT_SCRIPT.Buttons.Add(ActionButton10) Me.TXT_SCRIPT.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.CheckBox Me.TXT_SCRIPT.CaptionText = "Script" Me.TXT_SCRIPT.CaptionToolTipEnabled = True @@ -1009,7 +1018,6 @@ Me.TAB_MAIN.Controls.Add(TAB_BEHAVIOR) Me.TAB_MAIN.Controls.Add(TAB_DEFAULTS) Me.TAB_MAIN.Controls.Add(TAB_DOWN) - Me.TAB_MAIN.Controls.Add(Me.TAB_AUTO) Me.TAB_MAIN.Controls.Add(TAB_DEFS_CHANNELS) Me.TAB_MAIN.Dock = System.Windows.Forms.DockStyle.Fill Me.TAB_MAIN.Location = New System.Drawing.Point(0, 0) @@ -1018,24 +1026,6 @@ Me.TAB_MAIN.Size = New System.Drawing.Size(584, 310) Me.TAB_MAIN.TabIndex = 1 ' - 'TAB_AUTO - ' - Me.TAB_AUTO.Controls.Add(Me.PANEL_AUTO) - Me.TAB_AUTO.Location = New System.Drawing.Point(4, 22) - Me.TAB_AUTO.Name = "TAB_AUTO" - Me.TAB_AUTO.Size = New System.Drawing.Size(576, 284) - Me.TAB_AUTO.TabIndex = 7 - Me.TAB_AUTO.Text = "Automation" - ' - 'PANEL_AUTO - ' - Me.PANEL_AUTO.AutoSize = True - Me.PANEL_AUTO.Dock = System.Windows.Forms.DockStyle.Fill - Me.PANEL_AUTO.Location = New System.Drawing.Point(0, 0) - Me.PANEL_AUTO.Name = "PANEL_AUTO" - Me.PANEL_AUTO.Size = New System.Drawing.Size(576, 284) - Me.PANEL_AUTO.TabIndex = 0 - ' 'CONTAINER_MAIN ' ' @@ -1109,8 +1099,6 @@ CType(Me.TXT_SCRIPT, System.ComponentModel.ISupportInitialize).EndInit() CType(Me.TXT_DOWN_COMPLETE_SCRIPT, System.ComponentModel.ISupportInitialize).EndInit() Me.TAB_MAIN.ResumeLayout(False) - Me.TAB_AUTO.ResumeLayout(False) - Me.TAB_AUTO.PerformLayout() Me.CONTAINER_MAIN.ContentPanel.ResumeLayout(False) Me.CONTAINER_MAIN.ResumeLayout(False) Me.CONTAINER_MAIN.PerformLayout() @@ -1161,7 +1149,6 @@ 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 - Private WithEvents TAB_AUTO As TabPage - Private WithEvents PANEL_AUTO As Panel + Private WithEvents CH_DOWN_IMAGES_NATIVE 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 f236247..6055126 100644 --- a/SCrawler/Editors/GlobalSettingsForm.resx +++ b/SCrawler/Editors/GlobalSettingsForm.resx @@ -241,6 +241,14 @@ If checked, videos will be stored in separate folder; otherwise, videos will be xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go + tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX + AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC @@ -255,7 +263,7 @@ If checked, videos will be stored in separate folder; otherwise, videos will be False - + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO wwAADsMBx2+oZAAAAR5JREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbGujg3ZATZPKYdC6FQhPwlAMkg3dP @@ -266,7 +274,7 @@ If checked, videos will be stored in separate folder; otherwise, videos will be cMaRN0UdBBkAAAAASUVORK5CYII= - + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go diff --git a/SCrawler/Editors/GlobalSettingsForm.vb b/SCrawler/Editors/GlobalSettingsForm.vb index 17f20fb..0d8ca19 100644 --- a/SCrawler/Editors/GlobalSettingsForm.vb +++ b/SCrawler/Editors/GlobalSettingsForm.vb @@ -11,19 +11,10 @@ Imports PersonalUtilities.Forms.Controls.Base Imports PersonalUtilities.Forms.Toolbars Namespace Editors Friend Class GlobalSettingsForm : Implements IOkCancelToolbar - Private ReadOnly MyDefs As DefaultFormProps - Private ReadOnly Automation As DownloadObjects.AutoDownloaderEditorForm + Private ReadOnly MyDefs As DefaultFormOptions Friend Sub New() InitializeComponent() - MyDefs = New DefaultFormProps - Automation = New DownloadObjects.AutoDownloaderEditorForm With { - .MaximumSize = New Size(0, 0), - .MinimumSize = New Size(0, 0), - .Dock = DockStyle.Fill, - .FormBorderStyle = FormBorderStyle.None, - .TopLevel = False, - .IsControlForm = True - } + MyDefs = New DefaultFormOptions End Sub Private Sub GlobalSettingsForm_Load(sender As Object, e As EventArgs) Handles Me.Load Try @@ -61,6 +52,7 @@ Namespace Editors CH_DEF_TEMP.Checked = .DefaultTemporary CH_DOWN_IMAGES.Checked = .DefaultDownloadImages CH_DOWN_VIDEOS.Checked = .DefaultDownloadVideos + CH_DOWN_IMAGES_NATIVE.Checked = .DownloadNativeImageFormat 'Downloading CH_UDESCR_UP.Checked = .UpdateUserDescriptionEveryTime TXT_SCRIPT.Checked = .ScriptData.Attribute @@ -85,14 +77,10 @@ Namespace Editors CH_COPY_CHANNEL_USER_IMAGE_ALL.Enabled = CH_COPY_CHANNEL_USER_IMAGE.Checked CH_CHANNELS_USERS_TEMP.Checked = .ChannelsDefaultTemporary End With - PANEL_AUTO.Controls.Add(Automation) - Automation.Show() .MyFieldsChecker = New FieldsChecker With DirectCast(.MyFieldsChecker, FieldsChecker) .AddControl(Of String)(TXT_GLOBAL_PATH, TXT_GLOBAL_PATH.CaptionText) .AddControl(Of String)(TXT_COLLECTIONS_PATH, TXT_COLLECTIONS_PATH.CaptionText) - .AddControl(Of Integer)(Automation.TXT_TIMER, Automation.TXT_TIMER.CaptionText,, - New DownloadObjects.AutoDownloaderEditorForm.AutomationTimerChecker) .EndLoaderOperations() End With .EndLoaderOperations() @@ -102,9 +90,6 @@ Namespace Editors MyDefs.InvokeLoaderError(ex) End Try End Sub - Private Sub GlobalSettingsForm_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed - Automation.Dispose() - End Sub Private Sub OK() Implements IOkCancelToolbar.OK If MyDefs.MyFieldsChecker.AllParamsOK Then With Settings @@ -167,6 +152,7 @@ Namespace Editors .DefaultTemporary.Value = CH_DEF_TEMP.Checked .DefaultDownloadImages.Value = CH_DOWN_IMAGES.Checked .DefaultDownloadVideos.Value = CH_DOWN_VIDEOS.Checked + .DownloadNativeImageFormat.Value = CH_DOWN_IMAGES_NATIVE.Checked 'Downloading .UpdateUserDescriptionEveryTime.Value = CH_UDESCR_UP.Checked .ScriptData.Value = TXT_SCRIPT.Text @@ -193,8 +179,6 @@ Namespace Editors .ChannelsAddUserImagesFromAllChannels.Value = CH_COPY_CHANNEL_USER_IMAGE_ALL.Checked .ChannelsDefaultTemporary.Value = CH_CHANNELS_USERS_TEMP.Checked - Automation.SaveSettings() - .EndUpdate() End With MyDefs.CloseForm() diff --git a/SCrawler/Editors/LabelsForm.Designer.vb b/SCrawler/Editors/LabelsForm.Designer.vb index d0a572e..bdda142 100644 --- a/SCrawler/Editors/LabelsForm.Designer.vb +++ b/SCrawler/Editors/LabelsForm.Designer.vb @@ -43,17 +43,14 @@ Partial Friend Class LabelsForm : Inherits System.Windows.Forms.Form 'CMB_LABELS ' ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image) - ActionButton1.Index = 0 - ActionButton1.Name = "BTT_COMBOBOX_ARROW" - ActionButton1.Visible = False + ActionButton1.Name = "Add" + ActionButton1.ToolTipText = "Add new label (Insert)" ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image) - ActionButton2.Index = 1 - ActionButton2.Name = "BTT_ADD" - ActionButton2.ToolTipText = "Add new label (Insert)" + ActionButton2.Name = "Clear" + ActionButton2.ToolTipText = "Clear checked labels" ActionButton3.BackgroundImage = CType(resources.GetObject("ActionButton3.BackgroundImage"), System.Drawing.Image) - ActionButton3.Index = 2 - ActionButton3.Name = "BTT_CLEAR" - ActionButton3.ToolTipText = "Clear checked labels" + ActionButton3.Name = "ArrowDown" + ActionButton3.Visible = False Me.CMB_LABELS.Buttons.Add(ActionButton1) Me.CMB_LABELS.Buttons.Add(ActionButton2) Me.CMB_LABELS.Buttons.Add(ActionButton3) diff --git a/SCrawler/Editors/LabelsForm.resx b/SCrawler/Editors/LabelsForm.resx index 22fe23b..6ab9463 100644 --- a/SCrawler/Editors/LabelsForm.resx +++ b/SCrawler/Editors/LabelsForm.resx @@ -119,6 +119,36 @@ + + iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6 + JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsTAAALEwEAmpwYAAADmUlE + QVRIS62WWWxMURjHL220JW1HausmlFrDFKUhnUGH6bRFzJ2idImlC0Vp2mlji1A8iNhCPIjIRES8EU+W + h2oEtbSDTk3HNNM7S01VKsXjkb/vXBo3k1Ee7sMvmZzzzf//ne/+z50RAAxL1MUIG4G/YAv3HSVhF5Vw + IYNdz3LadVj9RgdTB+HQYYPHIJuE1ocSdlEJFzG+1bPRLQLinglIeCkg+XUkKvz56hnkOfQs/rmA8S9H + YEp7FDI64tAQtKhnsMapZ7zzNHsUFnbGY4VzIk70l6hnIH4wsDR7NBZ3apDrSqL5T8eFgUr1DLZ78lim + Q4N8VzK29MxEpZSBa4M16hnU+c3M9CEFpdJsVHsXos63DDcHrf9nQEXD5VymwW/5USLNwl5vJhp7dTgW + NML2pR7jbsUMS+KdMTa5Q8NQxinfBU4dRFcOyjy52OtbhwOBDTgZLKPPmTgY0ON4MBdNfSbYBupxY8Aq + G10dqMG5/nIc7ytGQ6CQRliAamkTN/g1Ai4e95Qy3iogpX0UtBRDnhRzdxq2SXOxz5eFQ70rScCEU335 + ssGxj0YS06HSm4GN3ekwdE2C1hGH1LZR0JDOJof5jwHvnIvzTa0jlooTYfktvt+fhcOBHDQFTWRgxJGP + ObAGsulZLMLWnjlY756K5c4JmNcRi6T2SGheCIihS2l5ozAo6NRhMolnUAcGV6IcwwqvFrX+JTjYuwKH + SfRAYDms/mzs9y1GFe2VSnOw1j0FejqpLN4WCX4ZufiIBwLMLxQGm12rsLQzgWKYgmLPLNTQw6ynpDSS + IBet8y+TqaVRVdFIeJrWuCcj+/0EzH43BomvIhBLI45uFiDcJ+6QwROFwa6+Amb9bGFNg6Xs9Ncd7Oy3 + Knb2eyU7/20nu9y/m136tIvEl6BC0qKoZwby3alo9JVhj7T5R7m/kJVIIityi8zyXmTiW+I10SqyIQNb + uIgNwYuuf25kFd75KPKkI49OmUWnrfYWyXv/wBb2cijhhVf6a9lGei65XclYRDd6mj0GWz2iLBJaH0rY + RSVc5Eywmhm7kuQXHX+bJlBStrh+zTi0PpSwi0q4yNFAOVvgiEcKJWUsxZn/NhT+znlofShhF5VwkRpv + MUtti4KGYjj6sYCIh5QSu4oG27stjItHU+cjeQzvkcFzFQ2KnSKLoc4FukDCXeI2GbSoaFD4ziyPxNxK + 0AUyNxOP1DOwcaG/8I+/LRB+At7psBnyDBG0AAAAAElFTkSuQmCC + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go + tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX + AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC + + + iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABGdBTUEAALGPC/xhBQAAE65JREFUeF7t 3X2sJWddB/DdLi2lQG2hdOHuvfM887J7Cxca4ELTQMDWKigIFpBAEAgi9g+CJpJo9Q8NJhgBiYZIYspL @@ -206,36 +236,6 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6LEtW/4flgYiLD1qeX0A AAAASUVORK5CYII= - - - - - iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6 - JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsTAAALEwEAmpwYAAADmUlE - QVRIS62WWWxMURjHL220JW1HausmlFrDFKUhnUGH6bRFzJ2idImlC0Vp2mlji1A8iNhCPIjIRES8EU+W - h2oEtbSDTk3HNNM7S01VKsXjkb/vXBo3k1Ee7sMvmZzzzf//ne/+z50RAAxL1MUIG4G/YAv3HSVhF5Vw - IYNdz3LadVj9RgdTB+HQYYPHIJuE1ocSdlEJFzG+1bPRLQLinglIeCkg+XUkKvz56hnkOfQs/rmA8S9H - YEp7FDI64tAQtKhnsMapZ7zzNHsUFnbGY4VzIk70l6hnIH4wsDR7NBZ3apDrSqL5T8eFgUr1DLZ78lim - Q4N8VzK29MxEpZSBa4M16hnU+c3M9CEFpdJsVHsXos63DDcHrf9nQEXD5VymwW/5USLNwl5vJhp7dTgW - NML2pR7jbsUMS+KdMTa5Q8NQxinfBU4dRFcOyjy52OtbhwOBDTgZLKPPmTgY0ON4MBdNfSbYBupxY8Aq - G10dqMG5/nIc7ytGQ6CQRliAamkTN/g1Ai4e95Qy3iogpX0UtBRDnhRzdxq2SXOxz5eFQ70rScCEU335 - ssGxj0YS06HSm4GN3ekwdE2C1hGH1LZR0JDOJof5jwHvnIvzTa0jlooTYfktvt+fhcOBHDQFTWRgxJGP - ObAGsulZLMLWnjlY756K5c4JmNcRi6T2SGheCIihS2l5ozAo6NRhMolnUAcGV6IcwwqvFrX+JTjYuwKH - SfRAYDms/mzs9y1GFe2VSnOw1j0FejqpLN4WCX4ZufiIBwLMLxQGm12rsLQzgWKYgmLPLNTQw6ynpDSS - IBet8y+TqaVRVdFIeJrWuCcj+/0EzH43BomvIhBLI45uFiDcJ+6QwROFwa6+Amb9bGFNg6Xs9Ncd7Oy3 - Knb2eyU7/20nu9y/m136tIvEl6BC0qKoZwby3alo9JVhj7T5R7m/kJVIIityi8zyXmTiW+I10SqyIQNb - uIgNwYuuf25kFd75KPKkI49OmUWnrfYWyXv/wBb2cijhhVf6a9lGei65XclYRDd6mj0GWz2iLBJaH0rY - RSVc5Eywmhm7kuQXHX+bJlBStrh+zTi0PpSwi0q4yNFAOVvgiEcKJWUsxZn/NhT+znlofShhF5VwkRpv - MUtti4KGYjj6sYCIh5QSu4oG27stjItHU+cjeQzvkcFzFQ2KnSKLoc4FukDCXeI2GbSoaFD4ziyPxNxK - 0AUyNxOP1DOwcaG/8I+/LRB+At7psBnyDBG0AAAAAElFTkSuQmCC - - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go - tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX - AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC \ No newline at end of file diff --git a/SCrawler/Editors/LabelsForm.vb b/SCrawler/Editors/LabelsForm.vb index e8b914b..df84c07 100644 --- a/SCrawler/Editors/LabelsForm.vb +++ b/SCrawler/Editors/LabelsForm.vb @@ -12,7 +12,7 @@ Imports PersonalUtilities.Forms.Controls Imports PersonalUtilities.Forms.Controls.Base Imports PersonalUtilities.Functions.Messaging Friend Class LabelsForm : Implements IOkCancelDeleteToolbar - Private ReadOnly MyDefs As DefaultFormProps + Private ReadOnly MyDefs As DefaultFormOptions Friend ReadOnly Property LabelsList As List(Of String) Private ReadOnly _Source As IEnumerable(Of String) = Nothing Private ReadOnly Property Source As IEnumerable(Of String) @@ -32,7 +32,7 @@ Friend Class LabelsForm : Implements IOkCancelDeleteToolbar InitializeComponent() LabelsList = New List(Of String) LabelsList.ListAddList(LabelsArr) - MyDefs = New DefaultFormProps + MyDefs = New DefaultFormOptions End Sub Friend Sub New(ByVal Current As IEnumerable(Of String), ByVal Source As IEnumerable(Of String)) Me.New(Current) diff --git a/SCrawler/Editors/SiteEditorForm.Designer.vb b/SCrawler/Editors/SiteEditorForm.Designer.vb index 411dbdb..8f58969 100644 --- a/SCrawler/Editors/SiteEditorForm.Designer.vb +++ b/SCrawler/Editors/SiteEditorForm.Designer.vb @@ -62,11 +62,9 @@ 'TXT_PATH ' ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image) - ActionButton1.Index = 0 - ActionButton1.Name = "BTT_OPEN" + ActionButton1.Name = "Open" ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image) - ActionButton2.Index = 1 - ActionButton2.Name = "BTT_CLEAR" + ActionButton2.Name = "Clear" Me.TXT_PATH.Buttons.Add(ActionButton1) Me.TXT_PATH.Buttons.Add(ActionButton2) Me.TXT_PATH.CaptionText = "Path" @@ -81,11 +79,9 @@ 'TXT_COOKIES ' ActionButton3.BackgroundImage = CType(resources.GetObject("ActionButton3.BackgroundImage"), System.Drawing.Image) - ActionButton3.Index = 0 - ActionButton3.Name = "BTT_EDIT" + ActionButton3.Name = "Edit" ActionButton4.BackgroundImage = CType(resources.GetObject("ActionButton4.BackgroundImage"), System.Drawing.Image) - ActionButton4.Index = 1 - ActionButton4.Name = "BTT_CLEAR" + ActionButton4.Name = "Clear" Me.TXT_COOKIES.Buttons.Add(ActionButton3) Me.TXT_COOKIES.Buttons.Add(ActionButton4) Me.TXT_COOKIES.CaptionText = "Cookies" @@ -117,11 +113,9 @@ 'TXT_PATH_SAVED_POSTS ' ActionButton5.BackgroundImage = CType(resources.GetObject("ActionButton5.BackgroundImage"), System.Drawing.Image) - ActionButton5.Index = 0 - ActionButton5.Name = "BTT_OPEN" + ActionButton5.Name = "Open" ActionButton6.BackgroundImage = CType(resources.GetObject("ActionButton6.BackgroundImage"), System.Drawing.Image) - ActionButton6.Index = 1 - ActionButton6.Name = "BTT_CLEAR" + ActionButton6.Name = "Clear" Me.TXT_PATH_SAVED_POSTS.Buttons.Add(ActionButton5) Me.TXT_PATH_SAVED_POSTS.Buttons.Add(ActionButton6) Me.TXT_PATH_SAVED_POSTS.CaptionText = "Saved posts path" diff --git a/SCrawler/Editors/SiteEditorForm.vb b/SCrawler/Editors/SiteEditorForm.vb index bddc7d1..5831e66 100644 --- a/SCrawler/Editors/SiteEditorForm.vb +++ b/SCrawler/Editors/SiteEditorForm.vb @@ -18,7 +18,7 @@ Namespace Editors Friend Class SiteEditorForm : Implements IOkCancelToolbar Private ReadOnly LBL_AUTH As Label Private ReadOnly LBL_OTHER As Label - Private ReadOnly MyDefs As DefaultFormProps + Private ReadOnly MyDefs As DefaultFormOptions Private WithEvents SpecialButton As Button #Region "Providers" Private Class SavedPostsChecker : Implements IFieldsCheckerProvider @@ -42,7 +42,7 @@ Namespace Editors Private ReadOnly Property Host As SettingsHost Friend Sub New(ByVal h As SettingsHost) InitializeComponent() - MyDefs = New DefaultFormProps + MyDefs = New DefaultFormOptions 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} diff --git a/SCrawler/Editors/SiteSelectionForm.Designer.vb b/SCrawler/Editors/SiteSelectionForm.Designer.vb index 4e03089..690e688 100644 --- a/SCrawler/Editors/SiteSelectionForm.Designer.vb +++ b/SCrawler/Editors/SiteSelectionForm.Designer.vb @@ -52,8 +52,7 @@ Namespace Editors 'CMB_SITES ' ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image) - ActionButton1.Index = 0 - ActionButton1.Name = "BTT_COMBOBOX_ARROW" + ActionButton1.Name = "ArrowDown" ActionButton1.Visible = False Me.CMB_SITES.Buttons.Add(ActionButton1) ListColumn1.DisplayMember = True diff --git a/SCrawler/Editors/SiteSelectionForm.vb b/SCrawler/Editors/SiteSelectionForm.vb index 0db5d19..071d3dc 100644 --- a/SCrawler/Editors/SiteSelectionForm.vb +++ b/SCrawler/Editors/SiteSelectionForm.vb @@ -11,13 +11,13 @@ Imports PersonalUtilities.Forms.Toolbars Imports PersonalUtilities.Forms.Controls.Base Namespace Editors Friend Class SiteSelectionForm : Implements IOkCancelToolbar - Private ReadOnly MyDefs As DefaultFormProps + Private ReadOnly MyDefs As DefaultFormOptions Friend ReadOnly Property SelectedSites As List(Of String) Friend Sub New(ByVal s As List(Of String)) InitializeComponent() SelectedSites.ListAddList(s) If SelectedSites Is Nothing Then SelectedSites = New List(Of String) - MyDefs = New DefaultFormProps + MyDefs = New DefaultFormOptions End Sub Private Sub SiteSelectionForm_Load(sender As Object, e As EventArgs) Handles Me.Load With MyDefs @@ -32,7 +32,7 @@ Namespace Editors CMB_SITES.EndUpdate() If l.Count > 0 Then CMB_SITES.ListCheckedIndexes = l : l.Clear() .DelegateClosingChecker = False - .EndLoaderOperations(False) + .EndLoaderOperations() .MyOkCancel.EnableOK = True End With End Sub diff --git a/SCrawler/Editors/UserCreatorForm.Designer.vb b/SCrawler/Editors/UserCreatorForm.Designer.vb index cf46304..1aafee9 100644 --- a/SCrawler/Editors/UserCreatorForm.Designer.vb +++ b/SCrawler/Editors/UserCreatorForm.Designer.vb @@ -125,7 +125,7 @@ TP_SITE.ColumnCount = 3 TP_SITE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 79.0!)) TP_SITE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) - TP_SITE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 96.0!)) + TP_SITE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 98.0!)) TP_SITE.Controls.Add(Me.CH_IS_CHANNEL, 0, 0) TP_SITE.Controls.Add(Me.CMB_SITE, 1, 0) TP_SITE.Controls.Add(Me.BTT_OTHER_SETTINGS, 2, 0) @@ -152,8 +152,7 @@ 'CMB_SITE ' ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image) - ActionButton1.Index = 0 - ActionButton1.Name = "BTT_COMBOBOX_ARROW" + ActionButton1.Name = "ArrowDown" Me.CMB_SITE.Buttons.Add(ActionButton1) ListColumn1.Name = "_COL_KEY" ListColumn1.Text = "Key" @@ -169,17 +168,17 @@ Me.CMB_SITE.Location = New System.Drawing.Point(84, 3) Me.CMB_SITE.Margin = New System.Windows.Forms.Padding(3, 2, 3, 3) Me.CMB_SITE.Name = "CMB_SITE" - Me.CMB_SITE.Size = New System.Drawing.Size(267, 22) + Me.CMB_SITE.Size = New System.Drawing.Size(265, 22) Me.CMB_SITE.TabIndex = 1 Me.CMB_SITE.TextBoxBorderStyle = System.Windows.Forms.BorderStyle.FixedSingle ' 'BTT_OTHER_SETTINGS ' Me.BTT_OTHER_SETTINGS.Dock = System.Windows.Forms.DockStyle.Fill - Me.BTT_OTHER_SETTINGS.Location = New System.Drawing.Point(356, 2) + Me.BTT_OTHER_SETTINGS.Location = New System.Drawing.Point(354, 2) Me.BTT_OTHER_SETTINGS.Margin = New System.Windows.Forms.Padding(1) Me.BTT_OTHER_SETTINGS.Name = "BTT_OTHER_SETTINGS" - Me.BTT_OTHER_SETTINGS.Size = New System.Drawing.Size(94, 24) + Me.BTT_OTHER_SETTINGS.Size = New System.Drawing.Size(96, 24) Me.BTT_OTHER_SETTINGS.TabIndex = 2 Me.BTT_OTHER_SETTINGS.Text = "Options (F2)" TT_MAIN.SetToolTip(Me.BTT_OTHER_SETTINGS, "Other settings") @@ -272,8 +271,7 @@ ' ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image) ActionButton2.Dock = System.Windows.Forms.DockStyle.Top - ActionButton2.Index = 0 - ActionButton2.Name = "BTT_CLEAR" + ActionButton2.Name = "Clear" Me.TXT_DESCR.Buttons.Add(ActionButton2) Me.TXT_DESCR.CaptionDock = System.Windows.Forms.DockStyle.Top Me.TXT_DESCR.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.None @@ -339,11 +337,9 @@ 'TXT_LABELS ' ActionButton3.BackgroundImage = CType(resources.GetObject("ActionButton3.BackgroundImage"), System.Drawing.Image) - ActionButton3.Index = 0 - ActionButton3.Name = "BTT_OPEN" + ActionButton3.Name = "Open" ActionButton4.BackgroundImage = CType(resources.GetObject("ActionButton4.BackgroundImage"), System.Drawing.Image) - ActionButton4.Index = 1 - ActionButton4.Name = "BTT_CLEAR" + ActionButton4.Name = "Clear" Me.TXT_LABELS.Buttons.Add(ActionButton3) Me.TXT_LABELS.Buttons.Add(ActionButton4) Me.TXT_LABELS.CaptionText = "Labels" @@ -399,12 +395,10 @@ 'TXT_SPEC_FOLDER ' ActionButton5.BackgroundImage = CType(resources.GetObject("ActionButton5.BackgroundImage"), System.Drawing.Image) - ActionButton5.Index = 0 - ActionButton5.Name = "BTT_OPEN" + ActionButton5.Name = "Open" ActionButton5.ToolTipText = "Select a new path in the folder selection dialog" ActionButton6.BackgroundImage = CType(resources.GetObject("ActionButton6.BackgroundImage"), System.Drawing.Image) - ActionButton6.Index = 1 - ActionButton6.Name = "BTT_CLEAR" + ActionButton6.Name = "Clear" ActionButton6.ToolTipText = "Clear" Me.TXT_SPEC_FOLDER.Buttons.Add(ActionButton5) Me.TXT_SPEC_FOLDER.Buttons.Add(ActionButton6) @@ -419,12 +413,10 @@ ' ActionButton7.BackgroundImage = CType(resources.GetObject("ActionButton7.BackgroundImage"), System.Drawing.Image) ActionButton7.Enabled = False - ActionButton7.Index = 0 - ActionButton7.Name = "BTT_OPEN" + ActionButton7.Name = "Open" ActionButton8.BackgroundImage = CType(resources.GetObject("ActionButton8.BackgroundImage"), System.Drawing.Image) ActionButton8.Enabled = False - ActionButton8.Index = 1 - ActionButton8.Name = "BTT_CLEAR" + ActionButton8.Name = "Clear" Me.TXT_SCRIPT.Buttons.Add(ActionButton7) Me.TXT_SCRIPT.Buttons.Add(ActionButton8) Me.TXT_SCRIPT.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.CheckBox diff --git a/SCrawler/Editors/UserCreatorForm.vb b/SCrawler/Editors/UserCreatorForm.vb index 48b3896..467564c 100644 --- a/SCrawler/Editors/UserCreatorForm.vb +++ b/SCrawler/Editors/UserCreatorForm.vb @@ -6,7 +6,6 @@ ' ' This program is distributed in the hope that it will be useful, ' but WITHOUT ANY WARRANTY -Imports System.ComponentModel Imports PersonalUtilities.Forms Imports PersonalUtilities.Forms.Controls Imports PersonalUtilities.Forms.Controls.Base @@ -18,10 +17,10 @@ Imports SCrawler.Plugin.Hosts Imports ADB = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons Namespace Editors Friend Class UserCreatorForm : Implements IOkCancelToolbar - - Private ReadOnly MyDef As DefaultFormProps + Private ReadOnly MyDef As DefaultFormOptions Friend Property User As UserInfo - Friend Property UserInstance As IUserData + Private Property UserInstance As IUserData +#Region "User options" Friend Property StartIndex As Integer = -1 Friend ReadOnly Property UserTemporary As Boolean Get @@ -77,6 +76,8 @@ Namespace Editors Return TXT_SCRIPT.Text End Get End Property +#End Region +#Region "Exchange, Path, Labels" Friend Property MyExchangeOptions As Object = Nothing Private ReadOnly _SpecPathPattern As RParams = RParams.DM("\w:\\.*", 0, EDP.ReturnValue) Private ReadOnly Property SpecialPath(ByVal s As SettingsHost) As SFile @@ -93,11 +94,13 @@ Namespace Editors End Get End Property Friend ReadOnly Property UserLabels As List(Of String) +#End Region +#Region "Initializers" ''' Create new user Friend Sub New() InitializeComponent() UserLabels = New List(Of String) - MyDef = New DefaultFormProps + MyDef = New DefaultFormOptions End Sub ''' Edit exist user Friend Sub New(ByVal _Instance As IUserData) @@ -107,6 +110,8 @@ Namespace Editors User = DirectCast(UserInstance, UserDataBase).User End If End Sub +#End Region +#Region "Form handlers" Private Sub UserCreatorForm_Load(sender As Object, e As EventArgs) Handles Me.Load Try With MyDef @@ -180,19 +185,11 @@ Namespace Editors End Select If b Then e.Handled = True End Sub - Private Sub UserCreatorForm_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing - If Not BeforeCloseChecker(MyDef.ChangesDetected) Then - e.Cancel = True - Else - MyDef.Dispose() - End If - End Sub Private Sub UserCreatorForm_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed UserLabels.Clear() End Sub - Private Function GetSiteByCheckers() As SettingsHost - Return If(CMB_SITE.SelectedIndex >= 0, Settings(CStr(CMB_SITE.Items(CMB_SITE.SelectedIndex).Value(0))), Nothing) - End Function +#End Region +#Region "Ok, Cancel" Private Sub OK() Implements IOkCancelToolbar.OK If Not CH_ADD_BY_LIST.Checked Then If MyDef.MyFieldsChecker.AllParamsOK Then @@ -256,6 +253,8 @@ CloseForm: Private Sub Cancel() Implements IOkCancelToolbar.Cancel MyDef.CloseForm(IIf(StartIndex >= 0, DialogResult.OK, DialogResult.Cancel)) End Sub +#End Region +#Region "Controls handlers" Private _TextChangeInvoked As Boolean = False Private Sub TXT_USER_ActionOnTextChange() Handles TXT_USER.ActionOnTextChange Try @@ -284,14 +283,6 @@ CloseForm: Catch ex As Exception End Try End Sub - Private Function GetSiteByText(ByRef TXT As String) As ExchangeOptions - Dim s As ExchangeOptions - For Each p As PluginHost In Settings.Plugins - s = p.Settings.IsMyUser(TXT) - If Not s.UserName.IsEmptyString Then Return s - Next - Return Nothing - End Function Private Sub CMB_SITE_ActionSelectedItemChanged(ByVal _Item As ListViewItem) Handles CMB_SITE.ActionSelectedItemChanged CH_IS_CHANNEL.Checked = False MyExchangeOptions = Nothing @@ -319,30 +310,6 @@ CloseForm: Private Sub CH_FAV_CheckedChanged(sender As Object, e As EventArgs) Handles CH_FAV.CheckedChanged If CH_FAV.Checked Then CH_TEMP.Checked = False End Sub - Private Sub SetParamsBySite() - Dim s As SettingsHost = GetSiteByCheckers() - If Not s Is Nothing Then - With s - CH_TEMP.Checked = .Temporary - CH_DOWN_IMAGES.Checked = .DownloadImages - CH_DOWN_VIDEOS.Checked = .DownloadVideos - CH_PARSE_USER_MEDIA.Checked = .GetUserMediaOnly.Value - CH_READY_FOR_DOWN.Checked = Not CH_TEMP.Checked - If s.HasSpecialOptions Then - BTT_OTHER_SETTINGS.Enabled = True - If UserInstance Is Nothing Then - s.Source.UserOptions(MyExchangeOptions, False) - Else - MyExchangeOptions = DirectCast(UserInstance, UserDataBase).ExchangeOptionsGet - End If - Else - BTT_OTHER_SETTINGS.Enabled = False - End If - End With - Else - BTT_OTHER_SETTINGS.Enabled = False - End If - End Sub Private Sub CH_ADD_BY_LIST_CheckedChanged(sender As Object, e As EventArgs) Handles CH_ADD_BY_LIST.CheckedChanged If CH_ADD_BY_LIST.Checked Then TXT_DESCR.GroupBoxText = "Users list" @@ -366,6 +333,20 @@ CloseForm: BTT_OTHER_SETTINGS.Enabled = True End If End Sub + Private Sub TXT_LABELS_ActionOnButtonClick(ByVal Sender As ActionButton) Handles TXT_LABELS.ActionOnButtonClick + Select Case Sender.DefaultButton + Case ADB.Open : ChangeLabels() + Case ADB.Clear : UserLabels.Clear() + End Select + End Sub + Private Sub TXT_SCRIPT_ActionOnButtonClick(ByVal Sender As ActionButton) Handles TXT_SCRIPT.ActionOnButtonClick + SettingsCLS.ScriptTextBoxButtonClick(TXT_SCRIPT, Sender) + End Sub +#End Region +#Region "Functions" + Private Function GetSiteByCheckers() As SettingsHost + Return If(CMB_SITE.SelectedIndex >= 0, Settings(CStr(CMB_SITE.Items(CMB_SITE.SelectedIndex).Value(0))), Nothing) + End Function Private Function CreateUsersByList() As Boolean Try If CH_ADD_BY_LIST.Checked Then @@ -471,11 +452,37 @@ CloseForm: Return ErrorsDescriber.Execute(EDP.LogMessageValue, ex, "Error on adding users by list", False) End Try End Function - Private Sub TXT_LABELS_ActionOnButtonClick(ByVal Sender As ActionButton) Handles TXT_LABELS.ActionOnButtonClick - Select Case Sender.DefaultButton - Case ADB.Open : ChangeLabels() - Case ADB.Clear : UserLabels.Clear() - End Select + Private Function GetSiteByText(ByRef TXT As String) As ExchangeOptions + Dim s As ExchangeOptions + For Each p As PluginHost In Settings.Plugins + s = p.Settings.IsMyUser(TXT) + If Not s.UserName.IsEmptyString Then Return s + Next + Return Nothing + End Function + Private Sub SetParamsBySite() + Dim s As SettingsHost = GetSiteByCheckers() + If Not s Is Nothing Then + With s + CH_TEMP.Checked = .Temporary + CH_DOWN_IMAGES.Checked = .DownloadImages + CH_DOWN_VIDEOS.Checked = .DownloadVideos + CH_PARSE_USER_MEDIA.Checked = .GetUserMediaOnly.Value + CH_READY_FOR_DOWN.Checked = Not CH_TEMP.Checked + If s.HasSpecialOptions Then + BTT_OTHER_SETTINGS.Enabled = True + If UserInstance Is Nothing Then + s.Source.UserOptions(MyExchangeOptions, False) + Else + MyExchangeOptions = DirectCast(UserInstance, UserDataBase).ExchangeOptionsGet + End If + Else + BTT_OTHER_SETTINGS.Enabled = False + End If + End With + Else + BTT_OTHER_SETTINGS.Enabled = False + End If End Sub Private Sub ChangeLabels() Using fl As New LabelsForm(UserLabels) @@ -490,8 +497,6 @@ CloseForm: End If End Using End Sub - Private Sub TXT_SCRIPT_ActionOnButtonClick(ByVal Sender As ActionButton) Handles TXT_SCRIPT.ActionOnButtonClick - SettingsCLS.ScriptTextBoxButtonClick(TXT_SCRIPT, Sender) - End Sub +#End Region End Class End Namespace \ No newline at end of file diff --git a/SCrawler/FDatePickerForm.vb b/SCrawler/FDatePickerForm.vb index b044b44..cc8177c 100644 --- a/SCrawler/FDatePickerForm.vb +++ b/SCrawler/FDatePickerForm.vb @@ -9,7 +9,7 @@ Imports PersonalUtilities.Forms Imports PersonalUtilities.Forms.Toolbars Friend Class FDatePickerForm : Implements IOkCancelDeleteToolbar - Private MyDefs As DefaultFormProps + Private MyDefs As DefaultFormOptions Friend ReadOnly Property SelectedDate As Date? Get If DT.Checked Then Return DT.Value.Date Else Return Nothing @@ -21,24 +21,20 @@ Friend Class FDatePickerForm : Implements IOkCancelDeleteToolbar _InitialValue = d End Sub Private Sub FDatePickerForm_Load(sender As Object, e As EventArgs) Handles Me.Load - Try - MyDefs = New DefaultFormProps - With MyDefs - .MyViewInitialize(Me, Settings.Design, True) - .AddOkCancelToolbar() - If _InitialValue.HasValue Then - DT.Checked = True - DT.Value = _InitialValue.Value.Date - Else - DT.Checked = False - End If - .DelegateClosingChecker = False - .EndLoaderOperations() - MyDefs.MyOkCancel.EnableOK = True - End With - Catch ex As Exception - MyDefs.InvokeLoaderError(ex) - End Try + MyDefs = New DefaultFormOptions + With MyDefs + .MyViewInitialize(Me, Settings.Design, True) + .AddOkCancelToolbar() + If _InitialValue.HasValue Then + DT.Checked = True + DT.Value = _InitialValue.Value.Date + Else + DT.Checked = False + End If + .DelegateClosingChecker = False + .EndLoaderOperations() + MyDefs.MyOkCancel.EnableOK = True + End With End Sub Private Sub OK() Implements IOkCancelToolbar.OK MyDefs.CloseForm() diff --git a/SCrawler/MainFrame.vb b/SCrawler/MainFrame.vb index 04c52f3..4e3683d 100644 --- a/SCrawler/MainFrame.vb +++ b/SCrawler/MainFrame.vb @@ -15,7 +15,6 @@ Imports SCrawler.API.Base Imports SCrawler.Editors Imports SCrawler.DownloadObjects Imports SCrawler.Plugin.Hosts -Imports PersonalUtilities.Functions.Messaging Public Class MainFrame Private MyView As FormsView Private ReadOnly _VideoDownloadingMode As Boolean = False @@ -95,12 +94,12 @@ Public Class MainFrame For Each ugroup As Groups.DownloadGroup In Settings.Groups : GROUPS_Added(ugroup) : Next End If End With - Settings.Automation = New AutoDownloader + 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.UserFind, AddressOf FocusUser _UFinit = False - Settings.Automation.Start() + Settings.Automation.Start(True) GoTo EndFunction FormClosingInvoker: Close() @@ -273,7 +272,6 @@ CloseResume: (Not sg = Settings.ShowGroups And .UseGrouping) Then RefillList() TrayIcon.Visible = .CloseToTray LIST_PROFILES.ShowGroups = .UseGrouping - If Not Settings.Automation.Mode = AutoDownloader.Modes.None Then Settings.Automation.Start() End If End Using End With @@ -426,10 +424,8 @@ CloseResume: End Sub #End Region Private Sub BTT_DOWN_AUTOMATION_Click(sender As Object, e As EventArgs) Handles BTT_DOWN_AUTOMATION.Click - Using f As New AutoDownloaderEditorForm - f.ShowDialog() - If f.DialogResult = DialogResult.OK AndAlso Not Settings.Automation.Mode = AutoDownloader.Modes.None Then Settings.Automation.Start() - End Using + Using f As New SchedulerEditorForm : f.ShowDialog() : End Using + Settings.Automation.Start(False) End Sub Private Sub BTT_DOWN_AUTOMATION_PAUSE_Click(sender As Object, e As EventArgs) Handles BTT_DOWN_AUTOMATION_PAUSE.Click Settings.Automation.Pause = Not Settings.Automation.Pause @@ -1198,7 +1194,7 @@ ResumeDownloadingOperation: End If End Sub Private Sub Downloader_OnDownloading(ByVal Value As Boolean) - Dim a As Action = Sub() BTT_DOWN_STOP.Enabled = Value + Dim a As Action = Sub() BTT_DOWN_STOP.Enabled = Value Or Downloader.Working If Toolbar_TOP.InvokeRequired Then Toolbar_TOP.Invoke(a) Else a.Invoke End Sub Private Sub NotificationMessage(ByVal Message As String) diff --git a/SCrawler/MainFrameObjects.vb b/SCrawler/MainFrameObjects.vb index 73182ed..96e7d26 100644 --- a/SCrawler/MainFrameObjects.vb +++ b/SCrawler/MainFrameObjects.vb @@ -23,9 +23,9 @@ Friend Class MainFrameObjects Friend Sub ImageHandler(ByVal User As IUserData, ByVal Add As Boolean) Try If Add Then - AddHandler User.OnUserUpdated, AddressOf MF.User_OnUserUpdated + AddHandler User.UserUpdated, AddressOf MF.User_OnUserUpdated Else - RemoveHandler User.OnUserUpdated, AddressOf MF.User_OnUserUpdated + RemoveHandler User.UserUpdated, AddressOf MF.User_OnUserUpdated End If Catch ex As Exception End Try diff --git a/SCrawler/My Project/AssemblyInfo.vb b/SCrawler/My Project/AssemblyInfo.vb index 28b0db7..df86a96 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/PluginsEnvironment/Hosts/PropertyValueHost.vb b/SCrawler/PluginsEnvironment/Hosts/PropertyValueHost.vb index 5ecece1..e2766fd 100644 --- a/SCrawler/PluginsEnvironment/Hosts/PropertyValueHost.vb +++ b/SCrawler/PluginsEnvironment/Hosts/PropertyValueHost.vb @@ -6,13 +6,13 @@ ' ' This program is distributed in the hope that it will be useful, ' but WITHOUT ANY WARRANTY +Imports System.Reflection +Imports SCrawler.Plugin.Attributes Imports PersonalUtilities.Functions.XML.Base Imports PersonalUtilities.Forms Imports PersonalUtilities.Forms.Controls Imports PersonalUtilities.Forms.Controls.Base Imports ADB = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons -Imports SCrawler.Plugin.Attributes -Imports System.Reflection Namespace Plugin.Hosts Friend Class PropertyValueHost : Implements IPropertyValue, IComparable(Of PropertyValueHost) Friend Const LeftOffsetDefault As Integer = 100 @@ -41,33 +41,43 @@ Namespace Plugin.Hosts End Property Friend Sub CreateControl(Optional ByVal TT As ToolTip = Nothing) With Options - If Type Is GetType(Boolean) Then - Control = New CheckBox - If Not .ControlToolTip.IsEmptyString And Not TT Is Nothing Then TT.SetToolTip(Control, .ControlToolTip) - DirectCast(Control, CheckBox).ThreeState = .ThreeStates - DirectCast(Control, CheckBox).Text = .ControlText - If .ThreeStates Then - DirectCast(Control, CheckBox).CheckState = CInt(AConvert(Of Integer)(Value, CInt(CheckState.Indeterminate))) - Else - DirectCast(Control, CheckBox).Checked = CBool(AConvert(Of Boolean)(Value, False)) - End If - Control.Padding = New PaddingE(Control.Padding) With {.Left = LeftOffset} - Else - Control = New TextBoxExtended - With DirectCast(Control, TextBoxExtended) - .CaptionText = Options.ControlText - .CaptionToolTipEnabled = Not Options.ControlToolTip.IsEmptyString - .CaptionWidth = LeftOffset - If Not Options.ControlToolTip.IsEmptyString Then .CaptionToolTipText = Options.ControlToolTip : .CaptionToolTipEnabled = True + If .IsInformationLabel Then + Control = New Label + With DirectCast(Control, Label) + .Padding = New PaddingE(Control.Padding) With {.Left = LeftOffset} .Text = CStr(AConvert(Of String)(Value, String.Empty)) - With .Buttons - .BeginInit() - If Not Source Is Nothing And Not UpdateMethod Is Nothing Then .Add(New ActionButton(ADB.Refresh)) - .Add(ADB.Clear) - .EndInit(True) - End With - AddHandler .ActionOnButtonClick, AddressOf TextBoxClick + .TextAlign = Options.LabelTextAlign End With + If Not .ControlToolTip.IsEmptyString And Not TT Is Nothing Then TT.SetToolTip(Control, .ControlToolTip) + Else + If Type Is GetType(Boolean) Then + Control = New CheckBox + If Not .ControlToolTip.IsEmptyString And Not TT Is Nothing Then TT.SetToolTip(Control, .ControlToolTip) + DirectCast(Control, CheckBox).ThreeState = .ThreeStates + DirectCast(Control, CheckBox).Text = .ControlText + If .ThreeStates Then + DirectCast(Control, CheckBox).CheckState = CInt(AConvert(Of Integer)(Value, CInt(CheckState.Indeterminate))) + Else + DirectCast(Control, CheckBox).Checked = CBool(AConvert(Of Boolean)(Value, False)) + End If + Control.Padding = New PaddingE(Control.Padding) With {.Left = LeftOffset} + Else + Control = New TextBoxExtended + With DirectCast(Control, TextBoxExtended) + .CaptionText = Options.ControlText + .CaptionToolTipEnabled = Not Options.ControlToolTip.IsEmptyString + .CaptionWidth = LeftOffset + If Not Options.ControlToolTip.IsEmptyString Then .CaptionToolTipText = Options.ControlToolTip : .CaptionToolTipEnabled = True + .Text = CStr(AConvert(Of String)(Value, String.Empty)) + With .Buttons + .BeginInit() + If Not Source Is Nothing And Not UpdateMethod Is Nothing Then .Add(New ActionButton(ADB.Refresh)) + .Add(ADB.Clear) + .EndInit(True) + End With + AddHandler .ActionOnButtonClick, AddressOf TextBoxClick + End With + End If End If Control.Tag = Name Control.Dock = DockStyle.Fill @@ -89,7 +99,7 @@ Namespace Plugin.Hosts End Try End Sub Friend Sub UpdateValueByControl() - If Not Control Is Nothing Then + If Not Control Is Nothing AndAlso Not TypeOf Control Is Label Then If TypeOf Control Is CheckBox Then With DirectCast(Control, CheckBox) If Options.ThreeStates Then Value = CInt(.CheckState) Else Value = .Checked diff --git a/SCrawler/SCrawler.vbproj b/SCrawler/SCrawler.vbproj index 45ceeb7..77c397f 100644 --- a/SCrawler/SCrawler.vbproj +++ b/SCrawler/SCrawler.vbproj @@ -138,9 +138,7 @@ - - OptionsForm.vb @@ -180,6 +178,13 @@ Form + + + SchedulerEditorForm.vb + + + Form + @@ -339,6 +344,9 @@ GroupEditorForm.vb + + SchedulerEditorForm.vb + CollectionEditorForm.vb diff --git a/SCrawler/SettingsCLS.vb b/SCrawler/SettingsCLS.vb index 0a53473..229b9a5 100644 --- a/SCrawler/SettingsCLS.vb +++ b/SCrawler/SettingsCLS.vb @@ -34,7 +34,7 @@ Friend Class SettingsCLS : Implements IDisposable Friend Property Channels As Reddit.ChannelsCollection Friend ReadOnly Property Labels As LabelsKeeper Friend ReadOnly Property Groups As Groups.DownloadGroupCollection - Friend Property Automation As AutoDownloader + Friend Property Automation As Scheduler Friend ReadOnly Property BlackList As List(Of UserBan) Private ReadOnly BlackListFile As SFile = $"{SettingsFolderName}\BlackList.txt" Private ReadOnly UsersSettingsFile As SFile = $"{SettingsFolderName}\Users.xml" @@ -62,6 +62,7 @@ Friend Class SettingsCLS : Implements IDisposable DefaultDownloadImages = New XMLValue(Of Boolean)("DownloadImages", True, MyXML, n) DefaultDownloadVideos = New XMLValue(Of Boolean)("DownloadVideos", True, MyXML, n) ChangeReadyForDownOnTempChange = New XMLValue(Of Boolean)("ChangeReadyForDownOnTempChange", True, MyXML, n) + DownloadNativeImageFormat = New XMLValue(Of Boolean)("DownloadNativeImageFormat", True, MyXML, n) Plugins.AddRange(PluginHost.GetMyHosts(MyXML, GlobalPath.Value, DefaultTemporary, DefaultDownloadImages, DefaultDownloadVideos)) Dim tmpPluginList As IEnumerable(Of PluginHost) = PluginHost.GetPluginsHosts(MyXML, GlobalPath.Value, DefaultTemporary, @@ -390,6 +391,7 @@ Friend Class SettingsCLS : Implements IDisposable Friend ReadOnly Property DefaultDownloadImages As XMLValue(Of Boolean) Friend ReadOnly Property DefaultDownloadVideos As XMLValue(Of Boolean) Friend ReadOnly Property ChangeReadyForDownOnTempChange As XMLValue(Of Boolean) + Friend ReadOnly Property DownloadNativeImageFormat As XMLValue(Of Boolean) #End Region #Region "User data" Friend ReadOnly Property FromChannelDownloadTop As XMLValue(Of Integer)