diff --git a/Changelog.md b/Changelog.md index 353eb58..85798f3 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,17 @@ +# 2023.1.27.0 + +*2023-01-27* + +- Added + - Advanced Twitter options for GIFs + - Changing the icon of the user creation form based on the selected site +- Fixed + - Pinned Instagram posts reload every time +- Plugins + - Added + - `Interaction` option to the `Provider` attribute + - `IPropertyProvider` interface + # 2023.1.24.1 *2023-01-24* diff --git a/ProgramScreenshots/SettingsSiteTwitter.png b/ProgramScreenshots/SettingsSiteTwitter.png index fa55583..224880c 100644 Binary files a/ProgramScreenshots/SettingsSiteTwitter.png and b/ProgramScreenshots/SettingsSiteTwitter.png differ diff --git a/SCrawler.PluginProvider/Attributes/Attributes.vb b/SCrawler.PluginProvider/Attributes/Attributes.vb index f7d33c0..0dd2c6a 100644 --- a/SCrawler.PluginProvider/Attributes/Attributes.vb +++ b/SCrawler.PluginProvider/Attributes/Attributes.vb @@ -100,6 +100,8 @@ Namespace Plugin.Attributes ''' - only for conversion ''' Public FieldsChecker As Boolean = False + ''' Interaction with changing text field. Default: + Public Interaction As Boolean = False ''' Initialize a new Provider attribute. is only allowed ''' The name of the property for which this provider is used Public Sub New(ByVal PropertyName As String) diff --git a/SCrawler.PluginProvider/Interfaces/IPropertyProvider.vb b/SCrawler.PluginProvider/Interfaces/IPropertyProvider.vb new file mode 100644 index 0000000..85508bb --- /dev/null +++ b/SCrawler.PluginProvider/Interfaces/IPropertyProvider.vb @@ -0,0 +1,13 @@ +' Copyright (C) 2023 Andy https://github.com/AAndyProgram +' This program is free software: you can redistribute it and/or modify +' it under the terms of the GNU General Public License as published by +' the Free Software Foundation, either version 3 of the License, or +' (at your option) any later version. +' +' This program is distributed in the hope that it will be useful, +' but WITHOUT ANY WARRANTY +Namespace Plugin + Public Interface IPropertyProvider : Inherits IFormatProvider + Property PropertyName As String + End Interface +End Namespace \ No newline at end of file diff --git a/SCrawler.PluginProvider/My Project/AssemblyInfo.vb b/SCrawler.PluginProvider/My Project/AssemblyInfo.vb index b9fd8cd..5ad7254 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.PluginProvider/SCrawler.PluginProvider.vbproj b/SCrawler.PluginProvider/SCrawler.PluginProvider.vbproj index 3bd708f..c5a6ecd 100644 --- a/SCrawler.PluginProvider/SCrawler.PluginProvider.vbproj +++ b/SCrawler.PluginProvider/SCrawler.PluginProvider.vbproj @@ -102,6 +102,7 @@ + diff --git a/SCrawler/API/Base/UserDataBase.vb b/SCrawler/API/Base/UserDataBase.vb index d833c12..5693be4 100644 --- a/SCrawler/API/Base/UserDataBase.vb +++ b/SCrawler/API/Base/UserDataBase.vb @@ -1023,12 +1023,14 @@ BlockNullPicture: End If If Not v.SpecialFolder.IsEmptyString Then - f.Path = $"{f.PathWithSeparator}{v.SpecialFolder}\".CSFileP.Path + f.Path = $"{f.PathWithSeparator}{v.SpecialFolder.StringTrimEnd("*")}\".CSFileP.Path f.Exists(SFO.Path) End If If __isVideo And vsf Then - f.Path = $"{f.PathWithSeparator}Video" - If Not v.SpecialFolder.IsEmptyString Then f.Exists(SFO.Path) + If v.SpecialFolder.IsEmptyString OrElse Not v.SpecialFolder.EndsWith("*") Then + f.Path = $"{f.PathWithSeparator}Video" + If Not v.SpecialFolder.IsEmptyString Then f.Exists(SFO.Path) + End If End If If v.Type = UTypes.m3u8 And UseInternalM3U8Function Then diff --git a/SCrawler/API/Instagram/UserData.vb b/SCrawler/API/Instagram/UserData.vb index c16c2e0..4f49608 100644 --- a/SCrawler/API/Instagram/UserData.vb +++ b/SCrawler/API/Instagram/UserData.vb @@ -613,17 +613,20 @@ Namespace API.Instagram With nn PostIDKV = New PostKV(.Value("code"), .Value("id"), Section) Pinned = .Contains("timeline_pinned_user_ids") - If PostKvExists(PostIDKV) And Not Pinned Then Return False - _TempPostsList.Add(PostIDKV.ID) - PostsKVIDs.ListAddValue(PostIDKV, LAP.NotContainsOnly) - PostDate = .Value("taken_at") - If Not IsSavedPosts Then - Select Case CheckDatesLimit(PostDate, DateProvider) - Case DateResult.Skip : Continue For - Case DateResult.Exit : If Not Pinned Then Return False - End Select + If PostKvExists(PostIDKV) Then + If Not Pinned Then Return False + Else + _TempPostsList.Add(PostIDKV.ID) + PostsKVIDs.ListAddValue(PostIDKV, LNC) + PostDate = .Value("taken_at") + If Not IsSavedPosts Then + Select Case CheckDatesLimit(PostDate, DateProvider) + Case DateResult.Skip : Continue For + Case DateResult.Exit : If Not Pinned Then Return False + End Select + End If + ObtainMedia(.Self, PostIDKV.ID, SpecFolder, PostDate) End If - ObtainMedia(.Self, PostIDKV.ID, SpecFolder, PostDate) End With Next Return True diff --git a/SCrawler/API/Twitter/Declarations.vb b/SCrawler/API/Twitter/Declarations.vb index a1a055c..1073ac4 100644 --- a/SCrawler/API/Twitter/Declarations.vb +++ b/SCrawler/API/Twitter/Declarations.vb @@ -12,6 +12,7 @@ Imports PersonalUtilities.Functions.RegularExpressions Namespace API.Twitter Friend Module Declarations Friend Const TwitterSite As String = "Twitter" + Friend Const TwitterSiteKey As String = "AndyProgram_Twitter" Friend ReadOnly DateProvider As ADateTime = GetDateProvider() Friend ReadOnly VideoNode As NodeParams() = {New NodeParams("video_info", True, True, True, True, 10)} Friend ReadOnly VideoSizeRegEx As RParams = RParams.DMS("\d+x(\d+)", 1, EDP.ReturnValue) diff --git a/SCrawler/API/Twitter/EditorExchangeOptions.vb b/SCrawler/API/Twitter/EditorExchangeOptions.vb new file mode 100644 index 0000000..dddbf05 --- /dev/null +++ b/SCrawler/API/Twitter/EditorExchangeOptions.vb @@ -0,0 +1,27 @@ +' Copyright (C) 2023 Andy https://github.com/AAndyProgram +' This program is free software: you can redistribute it and/or modify +' it under the terms of the GNU General Public License as published by +' the Free Software Foundation, either version 3 of the License, or +' (at your option) any later version. +' +' This program is distributed in the hope that it will be useful, +' but WITHOUT ANY WARRANTY +Namespace API.Twitter + Friend Class EditorExchangeOptions + Friend Property GifsDownload As Boolean + Friend Property GifsSpecialFolder As String + Friend Property GifsPrefix As String + Friend Sub New() + End Sub + Friend Sub New(ByVal s As SiteSettings) + GifsDownload = s.GifsDownload.Value + GifsSpecialFolder = s.GifsSpecialFolder.Value + GifsPrefix = s.GifsPrefix.Value + End Sub + Friend Sub New(ByVal u As UserData) + GifsDownload = u.GifsDownload + GifsSpecialFolder = u.GifsSpecialFolder + GifsPrefix = u.GifsPrefix + End Sub + End Class +End Namespace \ No newline at end of file diff --git a/SCrawler/API/Twitter/OptionsForm.Designer.vb b/SCrawler/API/Twitter/OptionsForm.Designer.vb new file mode 100644 index 0000000..3330cfa --- /dev/null +++ b/SCrawler/API/Twitter/OptionsForm.Designer.vb @@ -0,0 +1,148 @@ +' Copyright (C) 2023 Andy https://github.com/AAndyProgram +' This program is free software: you can redistribute it and/or modify +' it under the terms of the GNU General Public License as published by +' the Free Software Foundation, either version 3 of the License, or +' (at your option) any later version. +' +' This program is distributed in the hope that it will be useful, +' but WITHOUT ANY WARRANTY +Namespace API.Twitter + + Partial Friend Class OptionsForm : Inherits System.Windows.Forms.Form + + Protected Overrides Sub Dispose(ByVal disposing As Boolean) + Try + If disposing AndAlso components IsNot Nothing Then + components.Dispose() + End If + Finally + MyBase.Dispose(disposing) + End Try + End Sub + Private components As System.ComponentModel.IContainer + + Private Sub InitializeComponent() + Dim CONTAINER_MAIN As System.Windows.Forms.ToolStripContainer + Dim TP_MAIN As System.Windows.Forms.TableLayoutPanel + Dim ActionButton1 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() + Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(OptionsForm)) + Dim ActionButton2 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() + Me.CH_DOWN_GIFS = New System.Windows.Forms.CheckBox() + Me.TXT_GIF_FOLDER = New PersonalUtilities.Forms.Controls.TextBoxExtended() + Me.TXT_GIF_PREFIX = New PersonalUtilities.Forms.Controls.TextBoxExtended() + CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer() + TP_MAIN = New System.Windows.Forms.TableLayoutPanel() + CONTAINER_MAIN.ContentPanel.SuspendLayout() + CONTAINER_MAIN.SuspendLayout() + TP_MAIN.SuspendLayout() + CType(Me.TXT_GIF_FOLDER, System.ComponentModel.ISupportInitialize).BeginInit() + CType(Me.TXT_GIF_PREFIX, System.ComponentModel.ISupportInitialize).BeginInit() + Me.SuspendLayout() + ' + 'CONTAINER_MAIN + ' + ' + 'CONTAINER_MAIN.ContentPanel + ' + CONTAINER_MAIN.ContentPanel.Controls.Add(TP_MAIN) + CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(304, 84) + 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(304, 109) + CONTAINER_MAIN.TabIndex = 0 + CONTAINER_MAIN.TopToolStripPanelVisible = False + ' + 'TP_MAIN + ' + TP_MAIN.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single] + TP_MAIN.ColumnCount = 1 + TP_MAIN.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + TP_MAIN.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20.0!)) + TP_MAIN.Controls.Add(Me.CH_DOWN_GIFS, 0, 0) + TP_MAIN.Controls.Add(Me.TXT_GIF_FOLDER, 0, 1) + TP_MAIN.Controls.Add(Me.TXT_GIF_PREFIX, 0, 2) + TP_MAIN.Dock = System.Windows.Forms.DockStyle.Fill + TP_MAIN.Location = New System.Drawing.Point(0, 0) + TP_MAIN.Name = "TP_MAIN" + TP_MAIN.RowCount = 4 + TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) + TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) + TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) + TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + TP_MAIN.Size = New System.Drawing.Size(304, 84) + TP_MAIN.TabIndex = 0 + ' + 'CH_DOWN_GIFS + ' + Me.CH_DOWN_GIFS.AutoSize = True + Me.CH_DOWN_GIFS.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_DOWN_GIFS.Location = New System.Drawing.Point(4, 4) + Me.CH_DOWN_GIFS.Name = "CH_DOWN_GIFS" + Me.CH_DOWN_GIFS.Padding = New System.Windows.Forms.Padding(100, 0, 0, 0) + Me.CH_DOWN_GIFS.Size = New System.Drawing.Size(296, 19) + Me.CH_DOWN_GIFS.TabIndex = 0 + Me.CH_DOWN_GIFS.Text = "Download GIFs" + Me.CH_DOWN_GIFS.UseVisualStyleBackColor = True + ' + 'TXT_GIF_FOLDER + ' + ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image) + ActionButton1.Name = "Clear" + ActionButton1.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear + Me.TXT_GIF_FOLDER.Buttons.Add(ActionButton1) + Me.TXT_GIF_FOLDER.CaptionText = "GIFs special folder" + Me.TXT_GIF_FOLDER.CaptionToolTipText = "Put the GIFs in a special folder" + Me.TXT_GIF_FOLDER.Dock = System.Windows.Forms.DockStyle.Fill + Me.TXT_GIF_FOLDER.Location = New System.Drawing.Point(4, 30) + Me.TXT_GIF_FOLDER.Name = "TXT_GIF_FOLDER" + Me.TXT_GIF_FOLDER.Size = New System.Drawing.Size(296, 22) + Me.TXT_GIF_FOLDER.TabIndex = 1 + ' + 'TXT_GIF_PREFIX + ' + ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image) + ActionButton2.Name = "Clear" + ActionButton2.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear + Me.TXT_GIF_PREFIX.Buttons.Add(ActionButton2) + Me.TXT_GIF_PREFIX.CaptionText = "GIF prefix" + Me.TXT_GIF_PREFIX.CaptionToolTipText = "This prefix will be added to the beginning of the filename" + Me.TXT_GIF_PREFIX.Dock = System.Windows.Forms.DockStyle.Fill + Me.TXT_GIF_PREFIX.Location = New System.Drawing.Point(4, 59) + Me.TXT_GIF_PREFIX.Name = "TXT_GIF_PREFIX" + Me.TXT_GIF_PREFIX.Size = New System.Drawing.Size(296, 22) + Me.TXT_GIF_PREFIX.TabIndex = 2 + ' + 'OptionsForm + ' + Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!) + Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font + Me.ClientSize = New System.Drawing.Size(304, 109) + Me.Controls.Add(CONTAINER_MAIN) + Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle + Me.Icon = Global.SCrawler.My.Resources.SiteResources.TwitterIcon_32 + Me.MaximizeBox = False + Me.MaximumSize = New System.Drawing.Size(320, 148) + Me.MinimizeBox = False + Me.MinimumSize = New System.Drawing.Size(320, 148) + Me.Name = "OptionsForm" + Me.ShowInTaskbar = False + Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide + Me.Text = "Options" + CONTAINER_MAIN.ContentPanel.ResumeLayout(False) + CONTAINER_MAIN.ResumeLayout(False) + CONTAINER_MAIN.PerformLayout() + TP_MAIN.ResumeLayout(False) + TP_MAIN.PerformLayout() + CType(Me.TXT_GIF_FOLDER, System.ComponentModel.ISupportInitialize).EndInit() + CType(Me.TXT_GIF_PREFIX, System.ComponentModel.ISupportInitialize).EndInit() + Me.ResumeLayout(False) + + End Sub + Private WithEvents CH_DOWN_GIFS As CheckBox + Private WithEvents TXT_GIF_FOLDER As PersonalUtilities.Forms.Controls.TextBoxExtended + Private WithEvents TXT_GIF_PREFIX As PersonalUtilities.Forms.Controls.TextBoxExtended + End Class +End Namespace \ No newline at end of file diff --git a/SCrawler/API/Twitter/OptionsForm.resx b/SCrawler/API/Twitter/OptionsForm.resx new file mode 100644 index 0000000..27f385b --- /dev/null +++ b/SCrawler/API/Twitter/OptionsForm.resx @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + False + + + False + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go + tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX + AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go + tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX + AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC + + + \ No newline at end of file diff --git a/SCrawler/API/Twitter/OptionsForm.vb b/SCrawler/API/Twitter/OptionsForm.vb new file mode 100644 index 0000000..e7f74be --- /dev/null +++ b/SCrawler/API/Twitter/OptionsForm.vb @@ -0,0 +1,78 @@ +' Copyright (C) 2023 Andy https://github.com/AAndyProgram +' This program is free software: you can redistribute it and/or modify +' it under the terms of the GNU General Public License as published by +' the Free Software Foundation, either version 3 of the License, or +' (at your option) any later version. +' +' This program is distributed in the hope that it will be useful, +' but WITHOUT ANY WARRANTY +Imports System.Reflection +Imports SCrawler.Plugin.Attributes +Imports PersonalUtilities.Forms +Imports PersonalUtilities.Forms.Controls +Namespace API.Twitter + Friend Class OptionsForm + Private WithEvents MyDefs As DefaultFormOptions + Private ReadOnly Property MyExchangeOptions As EditorExchangeOptions + Private ReadOnly MyGifTextProvider As SiteSettings.GifStringProvider + Friend Sub New(ByRef ExchangeOptions As EditorExchangeOptions) + InitializeComponent() + MyExchangeOptions = ExchangeOptions + MyGifTextProvider = New SiteSettings.GifStringProvider + MyDefs = New DefaultFormOptions(Me, Settings.Design) + End Sub + Private Sub OptionsForm_Load(sender As Object, e As EventArgs) Handles Me.Load + With MyDefs + .MyViewInitialize(True) + .AddOkCancelToolbar() + With MyExchangeOptions + CH_DOWN_GIFS.Checked = .GifsDownload + TXT_GIF_FOLDER.Text = .GifsSpecialFolder + TXT_GIF_FOLDER.Tag = NameOf(SiteSettings.GifsSpecialFolder) + TXT_GIF_PREFIX.Text = .GifsPrefix + TXT_GIF_PREFIX.Tag = NameOf(SiteSettings.GifsPrefix) + + Try + Dim p As PropertyOption + With Settings(TwitterSiteKey) + p = .PropList.Find(Function(pp) pp.Name = TXT_GIF_FOLDER.Tag).Options + If Not p Is Nothing Then + TXT_GIF_FOLDER.CaptionText = p.ControlText + TXT_GIF_FOLDER.CaptionToolTipText = p.ControlToolTip + TXT_GIF_FOLDER.CaptionToolTipEnabled = Not TXT_GIF_FOLDER.CaptionToolTipText.IsEmptyString + End If + + p = .PropList.Find(Function(pp) pp.Name = TXT_GIF_PREFIX.Tag).Options + If Not p Is Nothing Then + TXT_GIF_PREFIX.CaptionText = p.ControlText + TXT_GIF_PREFIX.CaptionToolTipText = p.ControlToolTip + TXT_GIF_PREFIX.CaptionToolTipEnabled = Not TXT_GIF_PREFIX.CaptionToolTipText.IsEmptyString + End If + End With + Catch + End Try + End With + .EndLoaderOperations() + End With + End Sub + Private Sub MyDefs_ButtonOkClick(ByVal Sender As Object, ByVal e As KeyHandleEventArgs) Handles MyDefs.ButtonOkClick + With MyExchangeOptions + .GifsDownload = CH_DOWN_GIFS.Checked + .GifsSpecialFolder = TXT_GIF_FOLDER.Text + .GifsPrefix = TXT_GIF_PREFIX.Text + End With + MyDefs.CloseForm() + End Sub + Private Sub TXT_ActionOnTextChanged(ByVal Sender As TextBoxExtended, ByVal e As EventArgs) Handles TXT_GIF_FOLDER.ActionOnTextChanged, + TXT_GIF_PREFIX.ActionOnTextChanged + If Not MyDefs.Initializing Then + With Sender + MyGifTextProvider.PropertyName = .Tag + Dim s% = .SelectionStart + Dim t$ = AConvert(Of String)(.Text, String.Empty, MyGifTextProvider) + If Not .Text = t Then .Text = t : .Select(s, 0) + End With + End If + End Sub + End Class +End Namespace \ No newline at end of file diff --git a/SCrawler/API/Twitter/SiteSettings.vb b/SCrawler/API/Twitter/SiteSettings.vb index 66f2fb7..e34ca4b 100644 --- a/SCrawler/API/Twitter/SiteSettings.vb +++ b/SCrawler/API/Twitter/SiteSettings.vb @@ -13,10 +13,11 @@ Imports PersonalUtilities.Functions.RegularExpressions Imports PersonalUtilities.Tools.Web.Clients Imports PersonalUtilities.Tools.Web.Cookies Namespace API.Twitter - + Friend Class SiteSettings : Inherits SiteSettingsBase Friend Const Header_Authorization As String = "authorization" Friend Const Header_Token As String = "x-csrf-token" +#Region "Declarations" Friend Overrides ReadOnly Property Icon As Icon Get Return My.Resources.SiteResources.TwitterIcon_32 @@ -27,14 +28,50 @@ Namespace API.Twitter Return My.Resources.SiteResources.TwitterPic_400 End Get End Property - Private ReadOnly Property Auth As PropertyValue - + Private ReadOnly Property Token As PropertyValue - + Friend ReadOnly Property SavedPostsUserName As PropertyValue +#End Region +#Region "Other properties" + + Friend ReadOnly Property GifsDownload As PropertyValue + + Friend ReadOnly Property GifsSpecialFolder As PropertyValue + + Friend ReadOnly Property GifsPrefix As PropertyValue + + Private ReadOnly Property GifStringChecker As IFormatProvider + Friend Class GifStringProvider : Implements ICustomProvider, IPropertyProvider + Friend Property PropertyName As String Implements IPropertyProvider.PropertyName + 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 + Dim v$ = AConvert(Of String)(Value, String.Empty) + If Not v.IsEmptyString Then + If PropertyName = NameOf(GifsPrefix) Then + v = v.StringRemoveWinForbiddenSymbols + Else + v = v.StringReplaceSymbols(GetWinForbiddenSymbols.ToList.ListWithRemove("\").ToArray, String.Empty, EDP.ReturnValue) + v = v.StringTrim("\") + End If + End If + Return v + End Function + Private Function GetFormat(ByVal FormatType As Type) As Object Implements IFormatProvider.GetFormat + Throw New NotImplementedException("[GetFormat] is not available in the context of [TimersChecker]") + End Function + End Class +#End Region Friend Overrides ReadOnly Property Responser As Responser +#End Region Friend Sub New() MyBase.New(TwitterSite) Responser = New Responser($"{SettingsFolderName}\Responser_{Site}.xml") @@ -72,6 +109,11 @@ Namespace API.Twitter Token = New PropertyValue(t, GetType(String), Sub(v) ChangeResponserFields(NameOf(Token), v)) SavedPostsUserName = New PropertyValue(String.Empty, GetType(String)) + GifsDownload = New PropertyValue(True) + GifsSpecialFolder = New PropertyValue(String.Empty, GetType(String)) + GifsPrefix = New PropertyValue("GIF_") + GifStringChecker = New GifStringProvider + UserRegex = RParams.DMS("[htps:/]{7,8}.*?twitter.com/([^/]+)", 1) UrlPatternUser = "https://twitter.com/{0}" ImageVideoContains = "twitter" @@ -106,5 +148,11 @@ Namespace API.Twitter Friend Overrides Function BaseAuthExists() As Boolean Return If(Responser.Cookies?.Count, 0) > 0 And ACheck(Token.Value) And ACheck(Auth.Value) End Function + Friend Overrides Sub UserOptions(ByRef Options As Object, ByVal OpenForm As Boolean) + If Options Is Nothing OrElse Not TypeOf Options Is EditorExchangeOptions Then Options = New EditorExchangeOptions(Me) + If OpenForm Then + Using f As New OptionsForm(Options) : f.ShowDialog() : End Using + End If + End Sub End Class End Namespace \ No newline at end of file diff --git a/SCrawler/API/Twitter/UserData.vb b/SCrawler/API/Twitter/UserData.vb index f23319f..392ae7a 100644 --- a/SCrawler/API/Twitter/UserData.vb +++ b/SCrawler/API/Twitter/UserData.vb @@ -17,15 +17,50 @@ Imports UStates = SCrawler.API.Base.UserMedia.States Namespace API.Twitter Friend Class UserData : Inherits UserDataBase Private Const SinglePostUrl As String = "https://api.twitter.com/1.1/statuses/show.json?id={0}&tweet_mode=extended" +#Region "XML names" + Private Const Name_GifsDownload As String = "GifsDownload" + Private Const Name_GifsSpecialFolder As String = "GifsSpecialFolder" + Private Const Name_GifsPrefix As String = "GifsPrefix" +#End Region #Region "Declarations" + Friend Property GifsDownload As Boolean + Friend Property GifsSpecialFolder As String + Friend Property GifsPrefix As String Private ReadOnly _DataNames As List(Of String) - Protected Overrides Sub LoadUserInformation_OptionalFields(ByRef Container As XmlFile, ByVal Loading As Boolean) +#End Region +#Region "Exchange options" + Friend Overrides Function ExchangeOptionsGet() As Object + Return New EditorExchangeOptions(Me) + End Function + Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object) + If Not Obj Is Nothing AndAlso TypeOf Obj Is EditorExchangeOptions Then + With DirectCast(Obj, EditorExchangeOptions) + GifsDownload = .GifsDownload + GifsSpecialFolder = .GifsSpecialFolder + GifsPrefix = .GifsPrefix + End With + End If End Sub #End Region -#Region "Initializer" +#Region "Initializer, loader" Friend Sub New() _DataNames = New List(Of String) End Sub + Protected Overrides Sub LoadUserInformation_OptionalFields(ByRef Container As XmlFile, ByVal Loading As Boolean) + If Loading Then + GifsDownload = Container.Value(Name_GifsDownload).FromXML(Of Boolean)(True) + GifsSpecialFolder = Container.Value(Name_GifsSpecialFolder) + If Not Container.Contains(Name_GifsPrefix) Then + GifsPrefix = "GIF_" + Else + GifsPrefix = Container.Value(Name_GifsPrefix) + End If + Else + Container.Add(Name_GifsDownload, GifsDownload.BoolToInteger) + Container.Add(Name_GifsSpecialFolder, GifsSpecialFolder) + Container.Add(Name_GifsPrefix, GifsPrefix) + End If + End Sub #End Region #Region "Download functions" Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken) @@ -182,10 +217,11 @@ Namespace API.Twitter url = .Value("url") ff = UrlFile(url) If Not ff.IsEmptyString Then - If Not _DataNames.Contains(ff) Then + If GifsDownload And Not _DataNames.Contains(ff) Then m = MediaFromData(url, PostID, PostDate,, State) f = m.File - If Not f.IsEmptyString Then f.Name = $"GIF_{f.Name}" : m.File = f + If Not f.IsEmptyString And Not GifsPrefix.IsEmptyString Then f.Name = $"{GifsPrefix}{f.Name}" : m.File = f + If Not GifsSpecialFolder.IsEmptyString Then m.SpecialFolder = $"{GifsSpecialFolder}*" _TempMediaList.ListAddValue(m, LNC) End If Return True diff --git a/SCrawler/Editors/UserCreatorForm.vb b/SCrawler/Editors/UserCreatorForm.vb index 6260ae8..ae0d63a 100644 --- a/SCrawler/Editors/UserCreatorForm.vb +++ b/SCrawler/Editors/UserCreatorForm.vb @@ -397,6 +397,7 @@ CloseForm: CMB_SITE.SelectedIndex = -1 CMB_SITE.Clear(ComboBoxExtended.ClearMode.Text) CH_IS_CHANNEL.Checked = False + If Not UserIsCollection Then Icon = My.Resources.UsersIcon_32 End If End If _TextChangeInvoked = False @@ -412,6 +413,9 @@ CloseForm: MyExchangeOptions = Nothing SetParamsBySite() End Sub + Private Sub CMB_SITE_ActionOnTextChanged(sender As Object, e As EventArgs) Handles CMB_SITE.ActionOnTextChanged + If CMB_SITE.Text.IsEmptyString And Not UserIsCollection Then CMB_SITE.SelectedIndex = -1 : Icon = My.Resources.UsersIcon_32 + End Sub Private Sub BTT_OTHER_SETTINGS_Click(sender As Object, e As EventArgs) Handles BTT_OTHER_SETTINGS.Click Dim s As SettingsHost = GetSiteByCheckers() If Not s Is Nothing Then @@ -604,9 +608,17 @@ CloseForm: Else BTT_OTHER_SETTINGS.Enabled = False End If + If Not UserIsCollection Then + If Not s.Source.Icon Is Nothing Then + Icon = s.Source.Icon + ElseIf Not s.Source.Image Is Nothing Then + Icon = ImageRenderer.GetIcon(s.Source.Image, New ErrorsDescriber(False, False, False, My.Resources.UsersIcon_32)) + End If + End If End With Else BTT_OTHER_SETTINGS.Enabled = False + If Not UserIsCollection Then Icon = My.Resources.UsersIcon_32 End If End Sub Private Sub ChangeLabels() diff --git a/SCrawler/My Project/AssemblyInfo.vb b/SCrawler/My Project/AssemblyInfo.vb index c020c8e..43195ea 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 d4393c4..0fc4edc 100644 --- a/SCrawler/PluginsEnvironment/Hosts/PropertyValueHost.vb +++ b/SCrawler/PluginsEnvironment/Hosts/PropertyValueHost.vb @@ -76,6 +76,7 @@ Namespace Plugin.Hosts .EndInit(True) End With AddHandler .ActionOnButtonClick, AddressOf TextBoxClick + If Not ProviderValue Is Nothing AndAlso ProviderValueInteraction Then AddHandler .ActionOnTextChanged, AddressOf TextBoxTextChanged End With End If End If @@ -98,6 +99,14 @@ Namespace Plugin.Hosts ErrorsDescriber.Execute(EDP.LogMessageValue, ex, $"Updating [{Name}] property") End Try End Sub + Private Sub TextBoxTextChanged(ByVal Sender As Object, ByVal e As EventArgs) + UpdateProviderPropertyName() + With DirectCast(Sender, TextBoxExtended) + Dim s% = .SelectionStart + Dim t$ = AConvert(Of String)(.Text, ProviderValue, String.Empty) + If Not t = .Text Then .Text = t : .Select(s, 0) + End With + End Sub Friend Sub UpdateValueByControl() If Not Control Is Nothing AndAlso Not TypeOf Control Is Label Then If TypeOf Control Is CheckBox Then @@ -105,6 +114,7 @@ Namespace Plugin.Hosts If Options.ThreeStates Then Value = CInt(.CheckState) Else Value = .Checked End With Else + UpdateProviderPropertyName() Value = AConvert(DirectCast(Control, TextBoxExtended).Text, AModes.Var, [Type],,,, ProviderValue) End If End If @@ -116,12 +126,16 @@ Namespace Plugin.Hosts If Options.ThreeStates Then Return CInt(.CheckState) Else Return .Checked End With Else + UpdateProviderPropertyName() Return AConvert(DirectCast(Control, TextBoxExtended).Text, AModes.Var, [Type],,,, ProviderValue) End If Else Return Nothing End If End Function + Private Sub UpdateProviderPropertyName() + If ProviderValueIsPropertyProvider Then DirectCast(ProviderValue, IPropertyProvider).PropertyName = Name + End Sub #End Region #Region "Compatibility" Private ReadOnly Source As Object @@ -143,9 +157,17 @@ Namespace Plugin.Hosts End Property #Region "Providers" Friend Property ProviderFieldsChecker As IFormatProvider - Friend Property ProviderValue As IFormatProvider - Friend Sub SetProvider(ByVal Provider As IFormatProvider, ByVal FC As Boolean) - If FC Then ProviderFieldsChecker = Provider Else ProviderValue = Provider + Private Property ProviderValue As IFormatProvider + Private Property ProviderValueInteraction As Boolean = False + Private Property ProviderValueIsPropertyProvider As Boolean = False + Friend Sub SetProvider(ByVal Provider As IFormatProvider, ByVal Instance As Provider) + If Instance.FieldsChecker Then + ProviderFieldsChecker = Provider + Else + ProviderValue = Provider + ProviderValueIsPropertyProvider = TypeOf ProviderValue Is IPropertyProvider + ProviderValueInteraction = Instance.Interaction + End If End Sub #End Region Friend PropertiesChecking As String() diff --git a/SCrawler/PluginsEnvironment/Hosts/SettingsHost.vb b/SCrawler/PluginsEnvironment/Hosts/SettingsHost.vb index f0dec10..0bd7ce8 100644 --- a/SCrawler/PluginsEnvironment/Hosts/SettingsHost.vb +++ b/SCrawler/PluginsEnvironment/Hosts/SettingsHost.vb @@ -204,7 +204,7 @@ Namespace Plugin.Hosts End If Next ElseIf m.MemberType = MemberTypes.Property Then - If Not m.GetCustomAttribute(Of Provider)() Is Nothing Then Providers.Add(m) + If m.GetCustomAttributes(Of Provider)().ListExists Then Providers.Add(m) End If End If End With @@ -220,13 +220,15 @@ Namespace Plugin.Hosts Updaters.Clear() End If If Providers.Count > 0 Then - Dim prov As Provider + Dim prov As IEnumerable(Of Provider) + Dim _prov As Provider For Each m In Providers - prov = m.GetCustomAttribute(Of Provider)() - i = PropList.FindIndex(Function(p) p.Name = prov.Name) - If i >= 0 Then - PropList(i).SetProvider(DirectCast(DirectCast(m, PropertyInfo).GetValue(Source), IFormatProvider), - m.GetCustomAttribute(Of Provider)().FieldsChecker) + prov = m.GetCustomAttributes(Of Provider)() + If prov.ListExists Then + For Each _prov In prov + i = PropList.FindIndex(Function(p) p.Name = _prov.Name) + If i >= 0 Then PropList(i).SetProvider(DirectCast(DirectCast(m, PropertyInfo).GetValue(Source), IFormatProvider), _prov) + Next End If Next Providers.Clear() diff --git a/SCrawler/SCrawler.vbproj b/SCrawler/SCrawler.vbproj index 8859e76..f0fe311 100644 --- a/SCrawler/SCrawler.vbproj +++ b/SCrawler/SCrawler.vbproj @@ -196,6 +196,13 @@ + + + OptionsForm.vb + + + Form + @@ -416,6 +423,9 @@ RedditViewSettingsForm.vb + + OptionsForm.vb + ChannelsStatsForm.vb diff --git a/SCrawler/UserSearchForm.vb b/SCrawler/UserSearchForm.vb index 00bc05a..3e6f935 100644 --- a/SCrawler/UserSearchForm.vb +++ b/SCrawler/UserSearchForm.vb @@ -94,56 +94,49 @@ Friend Class UserSearchForm LIST_SEARCH.BeginUpdate() ControlInvokeFast(LIST_SEARCH, Sub() LIST_SEARCH.Items.Clear()) Results.Clear() - Dim t$ = TXT_SEARCH.Text.Trim + Dim t$ = TXT_SEARCH.Text.StringTrim.StringToLower With Settings If Not t.IsEmptyString And .Users.Count > 0 Then Dim i% Dim s As Plugin.ExchangeOptions = Nothing - Dim cu As Boolean = False Dim __descr As Boolean = CH_SEARCH_IN_DESCR.Checked Dim __name As Boolean = CH_SEARCH_IN_NAME.Checked Dim __lbl As Boolean = CH_SEARCH_IN_LABEL.Checked - Dim _CheckUrl As Action(Of IUserData) = Sub(ByVal u As IUserData) - If cu AndAlso ((u.Site = s.SiteName Or u.HOST.Key = s.HostKey) And u.Name.ToLower = s.UserName) Then _ - Results.ListAddValue(New SearchResult(u, SearchResult.Modes.URL), RLP) - End Sub - Dim _CheckDescr As Action(Of IUserData) = Sub(ByVal u As IUserData) - If __descr AndAlso Not u.Description.IsEmptyString AndAlso - u.Description.Contains(t) Then _ - Results.ListAddValue(New SearchResult(u, SearchResult.Modes.Description), RLP) - End Sub - Dim _LabelPredicate As Predicate(Of String) = Function(l) l.ToLower.Contains(t) - Dim _CheckLabels As Action(Of IUserData) = Sub(ByVal u As IUserData) - If __lbl AndAlso u.Labels.ListExists AndAlso u.Labels.Exists(_LabelPredicate) Then _ - Results.ListAddValue(New SearchResult(u, SearchResult.Modes.Label), RLP) - End Sub + Dim __isUrl As Boolean = t.StartsWith("http") + Dim __urlFound As Boolean = False + Dim _p_url As Predicate(Of IUserData) = Function(u) __urlFound AndAlso ((u.Site = s.SiteName Or u.HOST.Key = s.HostKey) And u.Name.ToLower = s.UserName.ToLower) + Dim _p_descr As Predicate(Of IUserData) = Function(u) __descr AndAlso Not u.Description.IsEmptyString AndAlso u.Description.ToLower.Contains(t) + Dim _p_labels_p As Predicate(Of String) = Function(l) l.ToLower.Contains(t) + Dim _p_labels As Predicate(Of IUserData) = Function(u) __lbl AndAlso u.Labels.ListExists AndAlso u.Labels.Exists(_p_labels_p) + Dim _addValue As Action(Of IUserData, SearchResult.Modes, Predicate(Of IUserData)) = Sub(u, m, p) If p.Invoke(u) Then Results.ListAddValue(New SearchResult(u, m), RLP) - If t.Length >= 4 AndAlso t.StartsWith("http") Then + If __isUrl Then For Each p In Settings.Plugins s = p.Settings.IsMyUser(t) If Not s.UserName.IsEmptyString Then Exit For Next + __urlFound = Not s.UserName.IsEmptyString End If - cu = Not s.UserName.IsEmptyString - t = t.ToLower For Each user As IUserData In .Users - If __name AndAlso user.Name.ToLower.Contains(t) Then Results.ListAddValue(New SearchResult(user, SearchResult.Modes.Name), RLP) + If Not __isUrl AndAlso __name AndAlso user.Name.ToLower.Contains(t) Then Results.ListAddValue(New SearchResult(user, SearchResult.Modes.Name), RLP) If user.IsCollection Then With DirectCast(user, UserDataBind) If .Count > 0 Then For i = 0 To .Count - 1 - If __name AndAlso .Item(i).Name.ToLower = t Then Results.ListAddValue(New SearchResult(.Item(i), SearchResult.Modes.Name), RLP) - _CheckUrl(.Item(i)) - _CheckDescr(.Item(i)) - _CheckLabels(.Item(i)) + With .Item(i) + If Not __isUrl AndAlso __name AndAlso .Self.Name.ToLower = t Then Results.ListAddValue(New SearchResult(.Self, SearchResult.Modes.Name), RLP) + _addValue(.Self, SearchResult.Modes.URL, _p_url) + _addValue(.Self, SearchResult.Modes.Description, _p_descr) + _addValue(.Self, SearchResult.Modes.Label, _p_labels) + End With Next End If End With Else - _CheckUrl(user) - _CheckDescr(user) - _CheckLabels(user) + _addValue(user, SearchResult.Modes.URL, _p_url) + _addValue(user, SearchResult.Modes.Description, _p_descr) + _addValue(user, SearchResult.Modes.Label, _p_labels) End If Next If Results.Count > 0 Then