From ff0c4587eb31731b140c260999c3b60c13fe976c Mon Sep 17 00:00:00 2001 From: Andy <88590076+AAndyProgram@users.noreply.github.com> Date: Sun, 1 Jun 2025 19:01:26 +0300 Subject: [PATCH] 2025.6.1.0 PluginProvider IUserMedia, PluginUserMedia: add properties 'PostText', 'PostTextFile', 'PostTextFileSpecialFolder' YT YouTubeFunctions: update 'Info_GetUrlType' and 'StandardizeURL' functions: add youtu.be domain YouTubeSettings: add 'FILTER' property Add classes 'FilterForm', 'YTDataFilter' VideoListForm: add filters; update 'LoadData' and 'RemoveControls' functions; add hotkey 'Ctrl+F5' for refresh YouTubeMediaContainerBase: add support for new interface properties Minor bugs SCrawler DeclaredNames: add new names EditorExchangeOptionsBase, IUserData, SiteSettingsBase, UserMedia, UserDataBase: add support for text downloading Sites Bluesky, Instagram, OnlyFans, Reddit, ThreadsNet, Twitter: add support for text downloading Sites Facebook, JustForFans, LPSG, Mastodon, Pinterest, PornHub, Redgifs, ThisVid, TikTok, Xhamster, XVIDEOS, YouTube (STD): disable text downloading UserDataBase: add 'ToStringExt' functions API.Instagram: add 'SleepTimerRequestsNextProfile' property API.OnlyFans: update 'DynamicRules'; fix incorrect posts opening (update 'GetUserPostUrl' function); fix limited download ('DownloadTopCount') API.Reddit: fix post date provider; add 'Best' and 'Rising' view modes; fix request (data is not downloading); set 'BearerTokenUseCurl' to 'False' by default API.ThreadsNet: change domain from 'net' to 'com'; fix data downloading API.TikTok: add downloading of avatar, site name and description API.Twitter: fix JSON error; add debug options; fix downloading API.Xhamster: add folder 'Photo' for albums Feed: add filters; update move/copy algo; add the ability to show test posts; update table rendering; add new 'MediaItem' handlers FeedMedia: add text options; update 'DeleteFile' function FeedMoveCopyTo: add text option VideoDownloaderForm: disable filter button GlobalSettingsForm: add 'FeedShowTextPosts' and 'FeedShowTextPostsAlwaysMove' options SettingsCLS: add feed text properties UserImage: add 'CreateImageFromText' function UserInfo: update 'Equals' function Add classes: 'FeedFilter', 'FeedFilterCollection', 'FeedFilterForm' Minor bugs and improvements --- Changelog.md | 42 ++ .../My Project/AssemblyInfo.vb | 4 +- .../Objects/PluginUserMedia.vb | 6 + SCrawler.Shared/Content/Icons/FilterIcon.ico | Bin 0 -> 2862 bytes SCrawler.Shared/Content/Images/FilterPic.png | Bin 0 -> 320 bytes SCrawler.Shared/My Project/AssemblyInfo.vb | 4 +- .../My Project/Resources.Designer.vb | 26 +- SCrawler.Shared/My Project/Resources.resx | 20 +- SCrawler.Shared/SCrawler.Shared.vbproj | 7 +- SCrawler.YouTube/Base/YouTubeFunctions.vb | 5 + SCrawler.YouTube/Base/YouTubeSettings.vb | 2 + .../Controls/FilterForm.Designer.vb | 324 +++++++++++ SCrawler.YouTube/Controls/FilterForm.resx | 135 +++++ SCrawler.YouTube/Controls/FilterForm.vb | 181 ++++++ .../Controls/MusicPlaylistsForm.vb | 2 +- SCrawler.YouTube/Controls/YTDataFilter.vb | 122 ++++ .../Downloader/VideoListForm.Designer.vb | 30 +- .../Downloader/VideoListForm.resx | 421 +++++++------- SCrawler.YouTube/Downloader/VideoListForm.vb | 22 +- .../Editors/BugReporterForm.Designer.vb | 261 ++++----- SCrawler.YouTube/Editors/BugReporterForm.resx | 88 +-- SCrawler.YouTube/My Project/AssemblyInfo.vb | 4 +- .../Objects/YouTubeMediaContainerBase.vb | 4 +- SCrawler.YouTube/SCrawler.YouTube.vbproj | 10 + .../My Project/AssemblyInfo.vb | 4 +- SCrawler/API/Base/DeclaredNames.vb | 7 + .../API/Base/EditorExchangeOptionsBase.vb | 24 + SCrawler/API/Base/IUserData.vb | 1 + SCrawler/API/Base/SiteSettingsBase.vb | 12 + SCrawler/API/Base/Structures.vb | 54 +- SCrawler/API/Base/UserDataBase.vb | 112 +++- SCrawler/API/Bluesky/UserData.vb | 21 +- SCrawler/API/Facebook/SiteSettings.vb | 3 + .../API/Instagram/EditorExchangeOptions.vb | 1 + SCrawler/API/Instagram/SiteSettings.vb | 17 + SCrawler/API/Instagram/UserData.vb | 56 +- SCrawler/API/JustForFans/SiteSettings.vb | 3 + SCrawler/API/LPSG/SiteSettings.vb | 3 + SCrawler/API/Mastodon/SiteSettings.vb | 3 + SCrawler/API/OnlyFans/DynamicRules.txt | 1 - SCrawler/API/OnlyFans/DynamicRulesAll.txt | 4 +- SCrawler/API/OnlyFans/SiteSettings.vb | 24 +- SCrawler/API/OnlyFans/UserData.vb | 45 +- SCrawler/API/OnlyFans/UserExchangeOptions.vb | 9 +- SCrawler/API/Pinterest/SiteSettings.vb | 3 + SCrawler/API/PornHub/SiteSettings.vb | 3 + SCrawler/API/Reddit/Channel.vb | 16 +- SCrawler/API/Reddit/Declarations.vb | 2 +- SCrawler/API/Reddit/IRedditView.vb | 26 +- .../Reddit/RedditViewSettingsForm.Designer.vb | 154 ++++- .../API/Reddit/RedditViewSettingsForm.resx | 323 ++++++----- SCrawler/API/Reddit/RedditViewSettingsForm.vb | 13 +- SCrawler/API/Reddit/SiteSettings.vb | 7 +- SCrawler/API/Reddit/UserData.vb | 185 +++--- SCrawler/API/Redgifs/SiteSettings.vb | 3 + SCrawler/API/ThisVid/SiteSettings.vb | 3 + SCrawler/API/ThreadsNet/SiteSettings.vb | 14 +- SCrawler/API/ThreadsNet/UserData.vb | 22 +- SCrawler/API/TikTok/SiteSettings.vb | 3 + SCrawler/API/TikTok/UserData.vb | 24 + SCrawler/API/Twitter/EditorExchangeOptions.vb | 1 + SCrawler/API/Twitter/UserData.vb | 80 ++- SCrawler/API/XVIDEOS/SiteSettings.vb | 3 + SCrawler/API/Xhamster/SiteSettings.vb | 3 + SCrawler/API/Xhamster/UserData.vb | 2 +- SCrawler/API/YouTube/SiteSettings.vb | 3 + .../Feed/DownloadFeedForm.Designer.vb | 75 ++- SCrawler/Download/Feed/DownloadFeedForm.resx | 12 +- SCrawler/Download/Feed/DownloadFeedForm.vb | 314 ++++++++-- SCrawler/Download/Feed/FeedFilter.vb | 252 ++++++++ .../Download/Feed/FeedFilterForm.Designer.vb | 337 +++++++++++ SCrawler/Download/Feed/FeedFilterForm.resx | 206 +++++++ SCrawler/Download/Feed/FeedFilterForm.vb | 252 ++++++++ SCrawler/Download/Feed/FeedMedia.vb | 75 ++- SCrawler/Download/Feed/FeedMoveCopyTo.vb | 2 +- .../STDownloader/VideoDownloaderForm.vb | 2 + .../Editors/GlobalSettingsForm.Designer.vb | 283 ++++++--- SCrawler/Editors/GlobalSettingsForm.resx | 541 +++++++++--------- SCrawler/Editors/GlobalSettingsForm.vb | 4 + SCrawler/MainFrame.vb | 1 + SCrawler/MainMod.vb | 2 + SCrawler/My Project/AssemblyInfo.vb | 4 +- SCrawler/SCrawler.vbproj | 10 + SCrawler/SettingsCLS.vb | 17 + SCrawler/UserImage.vb | 3 + SCrawler/UserInfo.vb | 6 +- 86 files changed, 4219 insertions(+), 1196 deletions(-) create mode 100644 SCrawler.Shared/Content/Icons/FilterIcon.ico create mode 100644 SCrawler.Shared/Content/Images/FilterPic.png create mode 100644 SCrawler.YouTube/Controls/FilterForm.Designer.vb create mode 100644 SCrawler.YouTube/Controls/FilterForm.resx create mode 100644 SCrawler.YouTube/Controls/FilterForm.vb create mode 100644 SCrawler.YouTube/Controls/YTDataFilter.vb create mode 100644 SCrawler/Download/Feed/FeedFilter.vb create mode 100644 SCrawler/Download/Feed/FeedFilterForm.Designer.vb create mode 100644 SCrawler/Download/Feed/FeedFilterForm.resx create mode 100644 SCrawler/Download/Feed/FeedFilterForm.vb diff --git a/Changelog.md b/Changelog.md index 579a346..1865222 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,45 @@ +# 2025.6.1.0 + +*2025-06-01* + +- Added + - Sites: + - YouTube (standalone app): + - support for **youtu.be** domain + - **filters** + - hotkey `Ctrl+F5` for refresh + - **Bluesky, Instagram, OnlyFans, Reddit, Threads, Twitter: the ability to download text posts** + - OnlyFans: + - updated `DynamicRules` + - `backend` option *(`aio` & `httpx`)* + - Reddit: add `Best` and `Rising` view modes + - TikTok: downloading of avatar, site name and description + - Feed: + - **filters** + - add the ability to show test posts + - Minor improvements +- Updated + - yt-dlp up to version **2025.05.22** + - gallery-dl up to version **1.29.7** +- PluginProvider + - IUserMedia: properties `PostText`, `PostTextFile`, `PostTextFileSpecialFolder` +- Fixed + - Sites: + - OnlyFans: + - DRM videos are not downloading in some cases *(only if you can't download video try changing `backend` option to `httpx`)* + - incorrect open posts + - while limited downloading, the first time, the profile still loads completely + - Reddit: + - **data is not downloading** + - post date is incorrect + - Threads + - change domain from `net` to `com` + - data is not downloading + - Twitter + - fix JSON error + - data is not downloaded in some cases + - Minor bugs + # 2025.3.17.0 *2025-03-17* diff --git a/SCrawler.PluginProvider/My Project/AssemblyInfo.vb b/SCrawler.PluginProvider/My Project/AssemblyInfo.vb index a65597b..6381b0a 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/Objects/PluginUserMedia.vb b/SCrawler.PluginProvider/Objects/PluginUserMedia.vb index a16a893..25cd3b1 100644 --- a/SCrawler.PluginProvider/Objects/PluginUserMedia.vb +++ b/SCrawler.PluginProvider/Objects/PluginUserMedia.vb @@ -35,6 +35,9 @@ Namespace Plugin Public Property DownloadState As UserMediaStates Implements IUserMedia.DownloadState Public Property PostID As String Implements IUserMedia.PostID Public Property PostDate As Date? Implements IUserMedia.PostDate + Public Property PostText As String Implements IUserMedia.PostText + Public Property PostTextFile As String Implements IUserMedia.PostTextFile + Public Property PostTextFileSpecialFolder As Boolean Implements IUserMedia.PostTextFileSpecialFolder Public Property SpecialFolder As String Implements IUserMedia.SpecialFolder Public Property Attempts As Integer Implements IUserMedia.Attempts Public Property [Object] As Object Implements IUserMedia.Object @@ -48,6 +51,9 @@ Namespace Plugin Property DownloadState As UserMediaStates Property PostID As String Property PostDate As Date? + Property PostText As String + Property PostTextFile As String + Property PostTextFileSpecialFolder As Boolean Property SpecialFolder As String Property Attempts As Integer Property [Object] As Object diff --git a/SCrawler.Shared/Content/Icons/FilterIcon.ico b/SCrawler.Shared/Content/Icons/FilterIcon.ico new file mode 100644 index 0000000000000000000000000000000000000000..02996c12c2e0639649fe605be03b23f397ce28ec GIT binary patch literal 2862 zcmeHJJ8r^25Pgfy$29l`p`=WeHi(`pq@tiq=X9YWWsX6aE4Ye8l`FWX2o<=9`(QWZ^^; zyA~~sC^(tqf-6<>1aTZQkl8=7Od6R#xwMp%i>@E@oD$iIqNNhjD0-HBilPS!x@}-B z$qL-8XurGX$8euw}Vm6y$ zKA$5=5-b)AtX3U%BPK3i58q_W9h8 z6PEXnW$Awj&wj6YKW_V%F5fBNz`T(B#`|`QmoA@T-_>Bw3-9SI)}5hzidEqmzvuma zgmpC(Q%+G0`ultrWPC4_;uTYlat~|J_s(}lDc1F%9OV|^pF@<~KNRCr$Pmq7}HFcd^{gdU}5a4+-_+1s0lr^qeh5!~b!F0zSk zZD;YJFhwC>tAz|?75>bS_)yJdR5Z`?^2>GI0@m84s;VOvyjKgf*a#sURRG>nprrya z#@l;iKndsE-r?|+@Bvxon^H=5IijX%b_<7>_#(rsX_}@d3XJ2p)OD>6hX=gi32({S zD$!%Wd#^134+-zrQ~7y_80@+(HypEqUF3V;K81%|MFyIf`8@iE$q=EbKrTa!rW(0z z>Ct55)M7N1$gvb?>XB2TsYfmsO)5ah9sJ=!1?V+f3X}q+z*+wf=NI@l6} - - + + diff --git a/SCrawler.Shared/My Project/Resources.Designer.vb b/SCrawler.Shared/My Project/Resources.Designer.vb index 3d40d22..7d9c58f 100644 --- a/SCrawler.Shared/My Project/Resources.Designer.vb +++ b/SCrawler.Shared/My Project/Resources.Designer.vb @@ -26,7 +26,7 @@ Namespace My.Resources Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _ Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _ Global.Microsoft.VisualBasic.HideModuleNameAttribute()> _ - Friend Module Resources + Public Module Resources Private resourceMan As Global.System.Resources.ResourceManager @@ -36,7 +36,7 @@ Namespace My.Resources ''' Returns the cached ResourceManager instance used by this class. ''' _ - Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager + Public ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager Get If Object.ReferenceEquals(resourceMan, Nothing) Then Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("SCrawler.Resources", GetType(Resources).Assembly) @@ -51,7 +51,7 @@ Namespace My.Resources ''' resource lookups using this strongly typed resource class. ''' _ - Friend Property Culture() As Global.System.Globalization.CultureInfo + Public Property Culture() As Global.System.Globalization.CultureInfo Get Return resourceCulture End Get @@ -59,5 +59,25 @@ Namespace My.Resources resourceCulture = value End Set End Property + + ''' + ''' Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + ''' + Public ReadOnly Property FilterIcon() As System.Drawing.Icon + Get + Dim obj As Object = ResourceManager.GetObject("FilterIcon", resourceCulture) + Return CType(obj,System.Drawing.Icon) + End Get + End Property + + ''' + ''' Looks up a localized resource of type System.Drawing.Bitmap. + ''' + Public ReadOnly Property FilterPic() As System.Drawing.Bitmap + Get + Dim obj As Object = ResourceManager.GetObject("FilterPic", resourceCulture) + Return CType(obj,System.Drawing.Bitmap) + End Get + End Property End Module End Namespace diff --git a/SCrawler.Shared/My Project/Resources.resx b/SCrawler.Shared/My Project/Resources.resx index af7dbeb..42a6d72 100644 --- a/SCrawler.Shared/My Project/Resources.resx +++ b/SCrawler.Shared/My Project/Resources.resx @@ -46,7 +46,7 @@ mimetype: application/x-microsoft.net.object.binary.base64 value : The object must be serialized with - : System.Serialization.Formatters.Binary.BinaryFormatter + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter : and then encoded with base64 encoding. mimetype: application/x-microsoft.net.object.soap.base64 @@ -60,6 +60,7 @@ : and then encoded with base64 encoding. --> + @@ -68,9 +69,10 @@ - + + @@ -85,9 +87,10 @@ - + + @@ -109,9 +112,16 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\Content\Icons\FilterIcon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Content\Images\FilterPic.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/SCrawler.Shared/SCrawler.Shared.vbproj b/SCrawler.Shared/SCrawler.Shared.vbproj index 41ff721..8c5c4bf 100644 --- a/SCrawler.Shared/SCrawler.Shared.vbproj +++ b/SCrawler.Shared/SCrawler.Shared.vbproj @@ -82,6 +82,7 @@ + @@ -123,7 +124,7 @@ - VbMyResourcesResXFileCodeGenerator + PublicVbMyResourcesResXFileCodeGenerator Resources.Designer.vb My.Resources Designer @@ -147,5 +148,9 @@ PersonalUtilities + + + + \ No newline at end of file diff --git a/SCrawler.YouTube/Base/YouTubeFunctions.vb b/SCrawler.YouTube/Base/YouTubeFunctions.vb index 1568345..16b2c28 100644 --- a/SCrawler.YouTube/Base/YouTubeFunctions.vb +++ b/SCrawler.YouTube/Base/YouTubeFunctions.vb @@ -18,6 +18,7 @@ Namespace API.YouTube.Base Public Const TrueUrlPattern As String = "https?://[^/]*?youtube.com/[^\?/&]+((\??[^\?/&]+|/[^\?/&]+))" '2 - type; 5 - id Public Const UrlTypePattern As String = "(?<=https?://[^/]*?youtube.com/)((@|[^\?/&]+))([/\?]{0,1}(list=|v=|)([^\?/&]*))(?=(\S+|\Z|))" + Public Const UrlTypePattern_BE As String = "(?<=https?://[^/]*?youtu.be/)([^\?/&]+)" Private Sub New() End Sub Public Shared Function StandardizeURL(ByVal URL As String) As String @@ -36,6 +37,7 @@ Namespace API.YouTube.Base Next data.Clear() End If + If val.IsEmptyString Then val = RegexReplace(URL, RParams.DMS(UrlTypePattern_BE, 0, EDP.ReturnValue)) If Not val.IsEmptyString Then Return $"https://www.youtube.com/watch?v={val}" End If End If @@ -100,6 +102,9 @@ Namespace API.YouTube.Base Return YouTubeMediaType.Channel End Select End If + Else + Dim v$ = RegexReplace(URL, RParams.DMS(UrlTypePattern_BE, 0, EDP.ReturnValue)) + If Not v.IsEmptyString Then Return YouTubeMediaType.Single End If End If Return YouTubeMediaType.Undefined diff --git a/SCrawler.YouTube/Base/YouTubeSettings.vb b/SCrawler.YouTube/Base/YouTubeSettings.vb index d1fec59..82428e7 100644 --- a/SCrawler.YouTube/Base/YouTubeSettings.vb +++ b/SCrawler.YouTube/Base/YouTubeSettings.vb @@ -33,6 +33,7 @@ Namespace API.YouTube.Base #Region "Declarations" Private ReadOnly Property XML As XmlFile Implements IXMLValuesContainer.XML Friend ReadOnly Property DesignXml As XmlFile + Friend ReadOnly Property FILTER As Controls.YTDataFilter Private Property Mode As GridUpdateModes = GridUpdateModes.OnConfirm Implements IGridValuesContainer.Mode Friend ReadOnly Property PlaylistFormSplitterDistance As XMLValue(Of Integer) Friend ReadOnly Property DownloadLocations As DownloadLocationsCollection @@ -514,6 +515,7 @@ Namespace API.YouTube.Base XML.LoadData(EDP.None) DesignXml = New XmlFile("Settings\DesignDownloader.xml", Protector.Modes.All, False) DesignXml.LoadData(EDP.None) + FILTER = New Controls.YTDataFilter InitializeXMLValueProperties(Me) AddHandler ShowNotificationsEveryDownload.TempValueChanged, AddressOf ShowNotificationsEveryDownload_TempValueChanged Cookies = New CookieKeeper diff --git a/SCrawler.YouTube/Controls/FilterForm.Designer.vb b/SCrawler.YouTube/Controls/FilterForm.Designer.vb new file mode 100644 index 0000000..6814814 --- /dev/null +++ b/SCrawler.YouTube/Controls/FilterForm.Designer.vb @@ -0,0 +1,324 @@ +' Copyright (C) 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.YouTube.Controls + + Partial Friend Class FilterForm : 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 TP_TYPES As System.Windows.Forms.TableLayoutPanel + Dim TP_USERS As System.Windows.Forms.TableLayoutPanel + Dim TP_USERS_2 As System.Windows.Forms.TableLayoutPanel + Me.CH_FILTER_ALL = New System.Windows.Forms.CheckBox() + Me.CH_FILTER_SINGLE = New System.Windows.Forms.CheckBox() + Me.CH_FILTER_CHANNEL = New System.Windows.Forms.CheckBox() + Me.CH_FILTER_PLS = New System.Windows.Forms.CheckBox() + Me.TP_MUSIC = New System.Windows.Forms.TableLayoutPanel() + Me.CH_M_ALL = New System.Windows.Forms.CheckBox() + Me.CH_M_VIDEO = New System.Windows.Forms.CheckBox() + Me.CH_M_MUSIC = New System.Windows.Forms.CheckBox() + Me.LIST_USERS = New System.Windows.Forms.CheckedListBox() + Me.CH_USERS_USE = New System.Windows.Forms.CheckBox() + Me.BTT_SELECT_ALL = New System.Windows.Forms.Button() + Me.BTT_SELECT_NONE = New System.Windows.Forms.Button() + CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer() + TP_MAIN = New System.Windows.Forms.TableLayoutPanel() + TP_TYPES = New System.Windows.Forms.TableLayoutPanel() + TP_USERS = New System.Windows.Forms.TableLayoutPanel() + TP_USERS_2 = New System.Windows.Forms.TableLayoutPanel() + CONTAINER_MAIN.ContentPanel.SuspendLayout() + CONTAINER_MAIN.SuspendLayout() + TP_MAIN.SuspendLayout() + TP_TYPES.SuspendLayout() + Me.TP_MUSIC.SuspendLayout() + TP_USERS.SuspendLayout() + TP_USERS_2.SuspendLayout() + Me.SuspendLayout() + ' + 'CONTAINER_MAIN + ' + ' + 'CONTAINER_MAIN.ContentPanel + ' + CONTAINER_MAIN.ContentPanel.Controls.Add(TP_MAIN) + CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(384, 361) + CONTAINER_MAIN.Dock = System.Windows.Forms.DockStyle.Fill + CONTAINER_MAIN.LeftToolStripPanelVisible = False + CONTAINER_MAIN.Location = New System.Drawing.Point(0, 0) + CONTAINER_MAIN.Name = "CONTAINER_MAIN" + CONTAINER_MAIN.RightToolStripPanelVisible = False + CONTAINER_MAIN.Size = New System.Drawing.Size(384, 361) + CONTAINER_MAIN.TabIndex = 0 + CONTAINER_MAIN.TopToolStripPanelVisible = False + ' + 'TP_MAIN + ' + TP_MAIN.ColumnCount = 1 + TP_MAIN.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + TP_MAIN.Controls.Add(TP_TYPES, 0, 0) + TP_MAIN.Controls.Add(Me.TP_MUSIC, 0, 1) + TP_MAIN.Controls.Add(TP_USERS, 0, 2) + TP_MAIN.Dock = System.Windows.Forms.DockStyle.Fill + TP_MAIN.Location = New System.Drawing.Point(0, 0) + TP_MAIN.Name = "TP_MAIN" + TP_MAIN.RowCount = 3 + TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) + TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) + TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20.0!)) + TP_MAIN.Size = New System.Drawing.Size(384, 361) + TP_MAIN.TabIndex = 0 + ' + 'TP_TYPES + ' + TP_TYPES.ColumnCount = 4 + TP_TYPES.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25.0!)) + TP_TYPES.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25.0!)) + TP_TYPES.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25.0!)) + TP_TYPES.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25.0!)) + TP_TYPES.Controls.Add(Me.CH_FILTER_ALL, 0, 0) + TP_TYPES.Controls.Add(Me.CH_FILTER_SINGLE, 1, 0) + TP_TYPES.Controls.Add(Me.CH_FILTER_CHANNEL, 2, 0) + TP_TYPES.Controls.Add(Me.CH_FILTER_PLS, 3, 0) + TP_TYPES.Dock = System.Windows.Forms.DockStyle.Fill + TP_TYPES.Location = New System.Drawing.Point(0, 0) + TP_TYPES.Margin = New System.Windows.Forms.Padding(0) + TP_TYPES.Name = "TP_TYPES" + TP_TYPES.RowCount = 1 + TP_TYPES.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + TP_TYPES.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) + TP_TYPES.Size = New System.Drawing.Size(384, 25) + TP_TYPES.TabIndex = 0 + ' + 'CH_FILTER_ALL + ' + Me.CH_FILTER_ALL.AutoSize = True + Me.CH_FILTER_ALL.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_FILTER_ALL.Location = New System.Drawing.Point(3, 3) + Me.CH_FILTER_ALL.Name = "CH_FILTER_ALL" + Me.CH_FILTER_ALL.Size = New System.Drawing.Size(90, 19) + Me.CH_FILTER_ALL.TabIndex = 0 + Me.CH_FILTER_ALL.Text = "ALL" + Me.CH_FILTER_ALL.UseVisualStyleBackColor = True + ' + 'CH_FILTER_SINGLE + ' + Me.CH_FILTER_SINGLE.AutoSize = True + Me.CH_FILTER_SINGLE.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_FILTER_SINGLE.Location = New System.Drawing.Point(99, 3) + Me.CH_FILTER_SINGLE.Name = "CH_FILTER_SINGLE" + Me.CH_FILTER_SINGLE.Size = New System.Drawing.Size(90, 19) + Me.CH_FILTER_SINGLE.TabIndex = 1 + Me.CH_FILTER_SINGLE.Text = "Single" + Me.CH_FILTER_SINGLE.UseVisualStyleBackColor = True + ' + 'CH_FILTER_CHANNEL + ' + Me.CH_FILTER_CHANNEL.AutoSize = True + Me.CH_FILTER_CHANNEL.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_FILTER_CHANNEL.Location = New System.Drawing.Point(195, 3) + Me.CH_FILTER_CHANNEL.Name = "CH_FILTER_CHANNEL" + Me.CH_FILTER_CHANNEL.Size = New System.Drawing.Size(90, 19) + Me.CH_FILTER_CHANNEL.TabIndex = 2 + Me.CH_FILTER_CHANNEL.Text = "Channel" + Me.CH_FILTER_CHANNEL.UseVisualStyleBackColor = True + ' + 'CH_FILTER_PLS + ' + Me.CH_FILTER_PLS.AutoSize = True + Me.CH_FILTER_PLS.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_FILTER_PLS.Location = New System.Drawing.Point(291, 3) + Me.CH_FILTER_PLS.Name = "CH_FILTER_PLS" + Me.CH_FILTER_PLS.Size = New System.Drawing.Size(90, 19) + Me.CH_FILTER_PLS.TabIndex = 3 + Me.CH_FILTER_PLS.Text = "Playlist" + Me.CH_FILTER_PLS.UseVisualStyleBackColor = True + ' + 'TP_MUSIC + ' + Me.TP_MUSIC.ColumnCount = 3 + Me.TP_MUSIC.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333!)) + Me.TP_MUSIC.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333!)) + Me.TP_MUSIC.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333!)) + Me.TP_MUSIC.Controls.Add(Me.CH_M_ALL, 0, 0) + Me.TP_MUSIC.Controls.Add(Me.CH_M_VIDEO, 1, 0) + Me.TP_MUSIC.Controls.Add(Me.CH_M_MUSIC, 2, 0) + Me.TP_MUSIC.Dock = System.Windows.Forms.DockStyle.Fill + Me.TP_MUSIC.Location = New System.Drawing.Point(0, 25) + Me.TP_MUSIC.Margin = New System.Windows.Forms.Padding(0) + Me.TP_MUSIC.Name = "TP_MUSIC" + Me.TP_MUSIC.RowCount = 1 + Me.TP_MUSIC.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + Me.TP_MUSIC.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) + Me.TP_MUSIC.Size = New System.Drawing.Size(384, 25) + Me.TP_MUSIC.TabIndex = 1 + ' + 'CH_M_ALL + ' + Me.CH_M_ALL.AutoSize = True + Me.CH_M_ALL.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_M_ALL.Location = New System.Drawing.Point(3, 3) + Me.CH_M_ALL.Name = "CH_M_ALL" + Me.CH_M_ALL.Size = New System.Drawing.Size(122, 19) + Me.CH_M_ALL.TabIndex = 0 + Me.CH_M_ALL.Text = "ALL" + Me.CH_M_ALL.UseVisualStyleBackColor = True + ' + 'CH_M_VIDEO + ' + Me.CH_M_VIDEO.AutoSize = True + Me.CH_M_VIDEO.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_M_VIDEO.Location = New System.Drawing.Point(131, 3) + Me.CH_M_VIDEO.Name = "CH_M_VIDEO" + Me.CH_M_VIDEO.Size = New System.Drawing.Size(122, 19) + Me.CH_M_VIDEO.TabIndex = 1 + Me.CH_M_VIDEO.Text = "Video" + Me.CH_M_VIDEO.UseVisualStyleBackColor = True + ' + 'CH_M_MUSIC + ' + Me.CH_M_MUSIC.AutoSize = True + Me.CH_M_MUSIC.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_M_MUSIC.Location = New System.Drawing.Point(259, 3) + Me.CH_M_MUSIC.Name = "CH_M_MUSIC" + Me.CH_M_MUSIC.Size = New System.Drawing.Size(122, 19) + Me.CH_M_MUSIC.TabIndex = 2 + Me.CH_M_MUSIC.Text = "Music" + Me.CH_M_MUSIC.UseVisualStyleBackColor = True + ' + 'TP_USERS + ' + TP_USERS.ColumnCount = 1 + TP_USERS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + TP_USERS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20.0!)) + TP_USERS.Controls.Add(Me.LIST_USERS, 0, 1) + TP_USERS.Controls.Add(TP_USERS_2, 0, 0) + TP_USERS.Dock = System.Windows.Forms.DockStyle.Fill + TP_USERS.Location = New System.Drawing.Point(0, 50) + TP_USERS.Margin = New System.Windows.Forms.Padding(0) + TP_USERS.Name = "TP_USERS" + TP_USERS.RowCount = 2 + TP_USERS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) + TP_USERS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + TP_USERS.Size = New System.Drawing.Size(384, 311) + TP_USERS.TabIndex = 3 + ' + 'LIST_USERS + ' + Me.LIST_USERS.Dock = System.Windows.Forms.DockStyle.Fill + Me.LIST_USERS.FormattingEnabled = True + Me.LIST_USERS.Location = New System.Drawing.Point(3, 28) + Me.LIST_USERS.Name = "LIST_USERS" + Me.LIST_USERS.Size = New System.Drawing.Size(378, 280) + Me.LIST_USERS.TabIndex = 1 + ' + 'TP_USERS_2 + ' + TP_USERS_2.ColumnCount = 3 + TP_USERS_2.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333!)) + TP_USERS_2.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333!)) + TP_USERS_2.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333!)) + TP_USERS_2.Controls.Add(Me.CH_USERS_USE, 0, 0) + TP_USERS_2.Controls.Add(Me.BTT_SELECT_ALL, 1, 0) + TP_USERS_2.Controls.Add(Me.BTT_SELECT_NONE, 2, 0) + TP_USERS_2.Dock = System.Windows.Forms.DockStyle.Fill + TP_USERS_2.Location = New System.Drawing.Point(0, 0) + TP_USERS_2.Margin = New System.Windows.Forms.Padding(0) + TP_USERS_2.Name = "TP_USERS_2" + TP_USERS_2.RowCount = 1 + TP_USERS_2.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + TP_USERS_2.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) + TP_USERS_2.Size = New System.Drawing.Size(384, 25) + TP_USERS_2.TabIndex = 0 + ' + 'CH_USERS_USE + ' + Me.CH_USERS_USE.AutoSize = True + Me.CH_USERS_USE.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_USERS_USE.Location = New System.Drawing.Point(3, 3) + Me.CH_USERS_USE.Name = "CH_USERS_USE" + Me.CH_USERS_USE.Size = New System.Drawing.Size(122, 19) + Me.CH_USERS_USE.TabIndex = 0 + Me.CH_USERS_USE.Text = "Filter users" + Me.CH_USERS_USE.UseVisualStyleBackColor = True + ' + 'BTT_SELECT_ALL + ' + Me.BTT_SELECT_ALL.Dock = System.Windows.Forms.DockStyle.Fill + Me.BTT_SELECT_ALL.Location = New System.Drawing.Point(129, 1) + Me.BTT_SELECT_ALL.Margin = New System.Windows.Forms.Padding(1) + Me.BTT_SELECT_ALL.Name = "BTT_SELECT_ALL" + Me.BTT_SELECT_ALL.Size = New System.Drawing.Size(126, 23) + Me.BTT_SELECT_ALL.TabIndex = 1 + Me.BTT_SELECT_ALL.Text = "All" + Me.BTT_SELECT_ALL.UseVisualStyleBackColor = True + ' + 'BTT_SELECT_NONE + ' + Me.BTT_SELECT_NONE.Dock = System.Windows.Forms.DockStyle.Fill + Me.BTT_SELECT_NONE.Location = New System.Drawing.Point(257, 1) + Me.BTT_SELECT_NONE.Margin = New System.Windows.Forms.Padding(1) + Me.BTT_SELECT_NONE.Name = "BTT_SELECT_NONE" + Me.BTT_SELECT_NONE.Size = New System.Drawing.Size(126, 23) + Me.BTT_SELECT_NONE.TabIndex = 2 + Me.BTT_SELECT_NONE.Text = "None" + Me.BTT_SELECT_NONE.UseVisualStyleBackColor = True + ' + 'FilterForm + ' + Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!) + Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font + Me.ClientSize = New System.Drawing.Size(384, 361) + Me.Controls.Add(CONTAINER_MAIN) + Me.MinimizeBox = False + Me.MinimumSize = New System.Drawing.Size(400, 400) + Me.Name = "FilterForm" + Me.ShowInTaskbar = False + Me.Text = "Filter" + CONTAINER_MAIN.ContentPanel.ResumeLayout(False) + CONTAINER_MAIN.ResumeLayout(False) + CONTAINER_MAIN.PerformLayout() + TP_MAIN.ResumeLayout(False) + TP_TYPES.ResumeLayout(False) + TP_TYPES.PerformLayout() + Me.TP_MUSIC.ResumeLayout(False) + Me.TP_MUSIC.PerformLayout() + TP_USERS.ResumeLayout(False) + TP_USERS_2.ResumeLayout(False) + TP_USERS_2.PerformLayout() + Me.ResumeLayout(False) + + End Sub + + Private WithEvents CH_FILTER_ALL As CheckBox + Private WithEvents CH_FILTER_SINGLE As CheckBox + Private WithEvents CH_FILTER_CHANNEL As CheckBox + Private WithEvents CH_FILTER_PLS As CheckBox + Private WithEvents TP_MUSIC As TableLayoutPanel + Private WithEvents CH_M_ALL As CheckBox + Private WithEvents CH_M_VIDEO As CheckBox + Private WithEvents CH_M_MUSIC As CheckBox + Private WithEvents LIST_USERS As CheckedListBox + Private WithEvents CH_USERS_USE As CheckBox + Private WithEvents BTT_SELECT_ALL As Button + Private WithEvents BTT_SELECT_NONE As Button + End Class +End Namespace \ No newline at end of file diff --git a/SCrawler.YouTube/Controls/FilterForm.resx b/SCrawler.YouTube/Controls/FilterForm.resx new file mode 100644 index 0000000..05f27e3 --- /dev/null +++ b/SCrawler.YouTube/Controls/FilterForm.resx @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + False + + + False + + + False + + + False + + + False + + \ No newline at end of file diff --git a/SCrawler.YouTube/Controls/FilterForm.vb b/SCrawler.YouTube/Controls/FilterForm.vb new file mode 100644 index 0000000..39c907e --- /dev/null +++ b/SCrawler.YouTube/Controls/FilterForm.vb @@ -0,0 +1,181 @@ +' Copyright (C) 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 SCrawler.API.YouTube.Base +Imports SCrawler.API.YouTube.Objects +Imports PersonalUtilities.Forms +Imports SimpleUser = SCrawler.API.YouTube.Controls.YTDataFilter.SimpleUser +Namespace API.YouTube.Controls + Friend Class FilterForm + Private WithEvents MyDefs As DefaultFormOptions + Friend ReadOnly Property DATA As List(Of IYouTubeMediaContainer) + Private ReadOnly Property DataTMP As List(Of IYouTubeMediaContainer) + Private ReadOnly Property MyFilterTmp As YTDataFilter + Private ReadOnly Property MyTmpUsers As List(Of SimpleUser) + Friend Sub New(ByVal d As IEnumerable(Of IYouTubeMediaContainer)) + InitializeComponent() + MyDefs = New DefaultFormOptions(Me, MyYouTubeSettings.DesignXml) + DATA = New List(Of IYouTubeMediaContainer) + DATA.ListAddList(d) + DataTMP = New List(Of IYouTubeMediaContainer) + DataTMP.ListAddList(d) + MyFilterTmp = New YTDataFilter(MyYouTubeSettings.FILTER) + MyTmpUsers = New List(Of SimpleUser) + Icon = My.Resources.FilterIcon + End Sub + Private Sub FilterForm_Load(sender As Object, e As EventArgs) Handles Me.Load + Try + With MyDefs + .MyViewInitialize() + .AddOkCancelToolbar(True) + + With MyYouTubeSettings.FILTER + With .Types + If .Count = 0 Or (.Count = 1 AndAlso .Item(0) = YouTubeMediaType.Undefined) Then + CH_FILTER_ALL.Checked = True + Else + If .Contains(YouTubeMediaType.Single) Then CH_FILTER_SINGLE.Checked = True + If .Contains(YouTubeMediaType.Channel) Then CH_FILTER_CHANNEL.Checked = True + If .Contains(YouTubeMediaType.PlayList) Then CH_FILTER_PLS.Checked = True + End If + End With + If .IsMusic And .IsVideo Then + CH_M_ALL.Checked = True + Else + CH_M_MUSIC.Checked = .IsMusic + CH_M_VIDEO.Checked = .IsVideo + End If + + CH_USERS_USE.Checked = .UserList.Count > 0 + End With + + .EndLoaderOperations() + _RefillEnabled = True + RefillList(True) + CH_USERS_USE_CheckedChanged() + End With + Catch ex As Exception + MyDefs.InvokeLoaderError(ex) + End Try + End Sub + Private Sub FilterForm_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed + DATA.ListClearDispose + DataTMP.ListClearDispose + MyTmpUsers.ListClearDispose + End Sub + Private _RefillEnabled As Boolean = False + Private Sub RefillList(Optional ByVal Init As Boolean = False) + If Not MyDefs.Initializing And _RefillEnabled Then + ApplyFilter(MyFilterTmp, Init) + MyFilterTmp.Populate(DATA, DataTMP, CH_USERS_USE.Checked) + With DataTMP + If .Count > 0 Then + Dim tmpUsers As New List(Of SimpleUser) + tmpUsers.ListAddList(DataTMP, LAP.NotContainsOnly, CType(Function(obj As YouTubeMediaContainerBase) CType(obj, SimpleUser), Func(Of Object, Object))) + If tmpUsers.Count > 0 Then + tmpUsers.Sort() + LIST_USERS.BeginUpdate() + LIST_USERS.Items.Clear() + tmpUsers.ForEach(Sub(u) LIST_USERS.Items.Add(u, True)) + + If CH_USERS_USE.Checked And MyFilterTmp.UserList.Count > 0 Then + For i% = 0 To LIST_USERS.Items.Count - 1 + LIST_USERS.SetItemChecked(i, MyFilterTmp.UserList.Contains(LIST_USERS.Items(i))) + Next + End If + + LIST_USERS.EndUpdate() + End If + End If + End With + End If + End Sub + Private Sub ApplyFilter(ByRef Filter As YTDataFilter, ByVal Init As Boolean) + With Filter + .Reset(False, Not Init) + With .Types + If CH_FILTER_ALL.Checked Then + .Add(YouTubeMediaType.Undefined) + Else + If CH_FILTER_SINGLE.Checked Then .Add(YouTubeMediaType.Single) + If CH_FILTER_CHANNEL.Checked Then .Add(YouTubeMediaType.Channel) + If CH_FILTER_PLS.Checked Then .Add(YouTubeMediaType.PlayList) + End If + If .Count = 0 Then .Add(YouTubeMediaType.Undefined) + End With + If CH_M_ALL.Checked Then + .IsMusic = True + .IsVideo = True + Else + If CH_M_MUSIC.Checked Then .IsMusic = True + If CH_M_VIDEO.Checked Then .IsVideo = True + End If + If Not .IsVideo And Not .IsMusic Then .IsMusic = True : .IsVideo = True + + If CH_USERS_USE.Checked And Not Init Then + .UserList.Clear() + If LIST_USERS.CheckedItems.Count > 0 Then + For Each item In LIST_USERS.CheckedItems : .UserList.Add(item) : Next + End If + End If + End With + End Sub + Private Sub MyDefs_ButtonOkClick(ByVal Sender As Object, ByVal e As KeyHandleEventArgs) Handles MyDefs.ButtonOkClick + ApplyFilter(MyYouTubeSettings.FILTER, False) + MyYouTubeSettings.FILTER.RemoveAll(DATA) + MyYouTubeSettings.FILTER.Update() + MyDefs.CloseForm() + End Sub + Private Sub MyDefs_ButtonDeleteClickOC(ByVal Sender As Object, ByVal e As KeyHandleEventArgs) Handles MyDefs.ButtonDeleteClickOC + With MyYouTubeSettings.FILTER : .Reset() : .Update() : End With + MyDefs.CloseForm() + End Sub + Private Sub UpdateControlOptions(ByRef CNT As CheckBox, ByVal v As Boolean) + If v Then CNT.Checked = True + CNT.Enabled = Not v + End Sub + Private Sub CH_FILTER_ALL_CheckedChanged(sender As Object, e As EventArgs) Handles CH_FILTER_ALL.CheckedChanged + _RefillEnabled = False + Dim v As Boolean = CH_FILTER_ALL.Checked + UpdateControlOptions(CH_FILTER_SINGLE, v) + UpdateControlOptions(CH_FILTER_CHANNEL, v) + UpdateControlOptions(CH_FILTER_PLS, v) + _RefillEnabled = True + RefillList() + End Sub + Private Sub CH_FILTER_SINGLE_CHANNEL_PLS_CheckedChanged(sender As Object, e As EventArgs) Handles CH_FILTER_SINGLE.CheckedChanged, + CH_FILTER_CHANNEL.CheckedChanged, + CH_FILTER_PLS.CheckedChanged + RefillList() + End Sub + Private Sub CH_M_ALL_CheckedChanged(sender As Object, e As EventArgs) Handles CH_M_ALL.CheckedChanged + _RefillEnabled = False + Dim v As Boolean = CH_M_ALL.Checked + UpdateControlOptions(CH_M_VIDEO, v) + UpdateControlOptions(CH_M_MUSIC, v) + _RefillEnabled = True + RefillList() + End Sub + Private Sub CH_M_VIDEO_MUSIC_CheckedChanged(sender As Object, e As EventArgs) Handles CH_M_VIDEO.CheckedChanged, CH_M_MUSIC.CheckedChanged + RefillList() + End Sub + Private Sub CH_USERS_USE_CheckedChanged() Handles CH_USERS_USE.CheckedChanged + LIST_USERS.Enabled = CH_USERS_USE.Checked + BTT_SELECT_ALL.Enabled = CH_USERS_USE.Checked + BTT_SELECT_NONE.Enabled = CH_USERS_USE.Checked + End Sub + Private Sub BTT_SELECT_ALL_NONE_Click(sender As Object, e As EventArgs) Handles BTT_SELECT_ALL.Click, BTT_SELECT_NONE.Click + Dim checked As Boolean = sender Is BTT_SELECT_ALL + With LIST_USERS + If .Items.Count > 0 Then + For i% = 0 To .Items.Count - 1 : .SetItemChecked(i, checked) : Next + End If + End With + End Sub + End Class +End Namespace \ No newline at end of file diff --git a/SCrawler.YouTube/Controls/MusicPlaylistsForm.vb b/SCrawler.YouTube/Controls/MusicPlaylistsForm.vb index c509861..52d4d13 100644 --- a/SCrawler.YouTube/Controls/MusicPlaylistsForm.vb +++ b/SCrawler.YouTube/Controls/MusicPlaylistsForm.vb @@ -155,7 +155,7 @@ Namespace API.YouTube.Controls With DirectCast(MyContainer, YouTubeMediaContainerBase) Select Case Sender.DefaultButton Case ADB.Open - Using f As New SimpleListForm(Of String)(IIf(isLyrics, AvailableSubtitlesFormats, AvailableAudioFormats)) With { + Using f As New SimpleListForm(Of String)(If(isLyrics, AvailableSubtitlesFormats, AvailableAudioFormats)) With { .DesignXML = DesignXML, .DesignXMLNodeName = SimpleArraysFormNode, .FormText = DirectCast(e.AssociatedControl, TextBoxExtended).CaptionText, diff --git a/SCrawler.YouTube/Controls/YTDataFilter.vb b/SCrawler.YouTube/Controls/YTDataFilter.vb new file mode 100644 index 0000000..3ae096b --- /dev/null +++ b/SCrawler.YouTube/Controls/YTDataFilter.vb @@ -0,0 +1,122 @@ +' Copyright (C) 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 SCrawler.API.YouTube.Base +Imports SCrawler.API.YouTube.Objects +Imports PersonalUtilities.Functions.XML +Imports PersonalUtilities.Functions.XML.Base +Namespace API.YouTube.Controls + Friend Class YTDataFilter + Private Const Name_Types As String = "Types" + Private Const Name_IsMusic As String = "IsMusic" + Private Const Name_IsVideo As String = "IsVideo" + Private Const Name_UserList As String = "UserList" + Friend Structure SimpleUser : Implements IEContainerProvider, IComparable(Of SimpleUser) + Private Const Name_UID As String = "UID" + Friend Title As String + Friend ID As String + Friend Sub New(ByVal _Title As String, ByVal _ID As String) + Title = _Title + ID = _ID + End Sub + Private Sub New(ByVal u As YouTubeMediaContainerBase) + Title = u.Title + ID = u.ID + End Sub + Public Shared Widening Operator CType(ByVal u As YouTubeMediaContainerBase) As SimpleUser + Return New SimpleUser(u.UserTitle, u.UserID) + End Operator + Public Shared Widening Operator CType(ByVal e As EContainer) As SimpleUser + Return New SimpleUser(e.Value, e.Attribute(Name_UID).Value) + End Operator + Public Overrides Function ToString() As String + Return String.Format(CStr(Interaction.Switch(Title.IsEmptyString, "{1}", ID.IsEmptyString, "{0}", True, "{0} ({1})")), Title, ID) + End Function + Public Overrides Function Equals(ByVal Obj As Object) As Boolean + Return Not IsDBNull(Obj) AndAlso ToString() = DirectCast(Obj, SimpleUser).ToString + End Function + Private Function CompareTo(ByVal Other As SimpleUser) As Integer Implements IComparable(Of SimpleUser).CompareTo + Return ToString.CompareTo(Other.ToString) + End Function + Private Function ToEContainer(Optional ByVal e As ErrorsDescriber = Nothing) As EContainer Implements IEContainerProvider.ToEContainer + Return New EContainer("User", Title, {New EAttribute(Name_UID, ID)}) + End Function + End Structure + Friend ReadOnly Property Types As List(Of YouTubeMediaType) + Friend Property IsMusic As Boolean = True + Friend Property IsVideo As Boolean = True + Friend ReadOnly Property UserList As List(Of SimpleUser) + Private ReadOnly File As New SFile("Settings\YouTubeFilter.xml") + Friend Sub New(Optional ByVal LoadFromFile As Boolean = True) + Types = New List(Of YouTubeMediaType) From {YouTubeMediaType.Undefined} + UserList = New List(Of SimpleUser) + If LoadFromFile AndAlso File.Exists Then + Using e As New XmlFile(File, Protector.Modes.All, False) With {.AllowSameNames = True} + e.LoadData() + If e.Count > 0 Then + Types.Clear() + Types.ListAddList(e.Value(Name_Types).StringToList(Of Integer)(","), LAP.NotContainsOnly) + IsMusic = e.Value(Name_IsMusic).FromXML(Of Boolean)(True) + IsVideo = e.Value(Name_IsVideo).FromXML(Of Boolean)(True) + UserList.ListAddList(e(Name_UserList), LAP.IgnoreICopier) + End If + End Using + End If + End Sub + Friend Sub New(ByVal f As YTDataFilter) + Me.New(False) + With f + Types.ListAddList(.Types, LAP.NotContainsOnly) + IsMusic = .IsMusic + IsVideo = .IsVideo + UserList.ListAddList(.UserList) + End With + End Sub + Friend Sub Reset(Optional ByVal AddDefType As Boolean = True, Optional ByVal ClearUserList As Boolean = True) + Types.Clear() + If AddDefType Then Types.Add(YouTubeMediaType.Undefined) + IsMusic = True + IsVideo = True + If ClearUserList Then UserList.Clear() + End Sub + Friend Sub Update() + Using x As New XmlFile With {.AllowSameNames = True} + With x + .Add(Name_Types, Types.ListToStringE(",")) + .Add(Name_IsMusic, IsMusic.BoolToInteger) + .Add(Name_IsVideo, IsVideo.BoolToInteger) + .Add(Name_UserList, String.Empty) + .Self()(Name_UserList).AddRange(UserList) + .Name = "FILTER" + .Save(File) + End With + End Using + End Sub + Friend Function Ready(ByVal Item As YouTubeMediaContainerBase, Optional ByVal IgnoreUserList As Boolean = False) As Boolean + With Item + If Not IsMusic Or Not IsVideo Then + If .IsMusic And Not IsMusic Then Return False + If Not .IsMusic And Not IsVideo Then Return False + End If + If Not Types.Contains(YouTubeMediaType.Undefined) AndAlso Not Types.Contains(.ObjectType) Then Return False + If Not IgnoreUserList AndAlso UserList.Count > 0 AndAlso Not UserList.Contains(Item) Then Return False + End With + Return True + End Function + Friend Overloads Sub RemoveAll(ByRef Data As List(Of IYouTubeMediaContainer)) + Data.RemoveAll(Function(item) Not Ready(item)) + End Sub + Friend Overloads Sub RemoveAll(ByRef Data As List(Of YouTubeMediaContainerBase)) + Data.RemoveAll(Function(item) Not Ready(item)) + End Sub + Friend Sub Populate(ByVal InitList As List(Of IYouTubeMediaContainer), ByVal DestList As List(Of IYouTubeMediaContainer), ByVal IgnoreUserList As Boolean) + DestList.Clear() + If InitList.Count > 0 Then InitList.ForEach(Sub(item) If Ready(item, IgnoreUserList) Then DestList.ListAddValue(item)) + End Sub + End Class +End Namespace \ No newline at end of file diff --git a/SCrawler.YouTube/Downloader/VideoListForm.Designer.vb b/SCrawler.YouTube/Downloader/VideoListForm.Designer.vb index 78426d0..8c0b061 100644 --- a/SCrawler.YouTube/Downloader/VideoListForm.Designer.vb +++ b/SCrawler.YouTube/Downloader/VideoListForm.Designer.vb @@ -33,6 +33,7 @@ Namespace DownloadObjects.STDownloader Me.BTT_CLEAR_DONE = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_CLEAR_ALL = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_SELECT_ALL = New System.Windows.Forms.ToolStripMenuItem() + Me.BTT_SELECT_NONE = New System.Windows.Forms.ToolStripMenuItem() Me.TOOLBAR_BOTTOM = New System.Windows.Forms.StatusStrip() Me.PR_MAIN = New System.Windows.Forms.ToolStripProgressBar() Me.LBL_INFO = New System.Windows.Forms.ToolStripStatusLabel() @@ -43,6 +44,7 @@ Namespace DownloadObjects.STDownloader Me.MENU_ADD = New System.Windows.Forms.ToolStripDropDownButton() Me.BTT_ADD = New PersonalUtilities.Forms.Controls.KeyClick.ToolStripMenuItemKeyClick() Me.BTT_ADD_PLS_ARR = New PersonalUtilities.Forms.Controls.KeyClick.ToolStripMenuItemKeyClick() + Me.BTT_FILTER = New System.Windows.Forms.ToolStripButton() Me.BTT_DOWN = New System.Windows.Forms.ToolStripButton() Me.BTT_STOP = New System.Windows.Forms.ToolStripButton() Me.SEP_LOG = New System.Windows.Forms.ToolStripSeparator() @@ -50,7 +52,7 @@ Namespace DownloadObjects.STDownloader Me.BTT_INFO = New System.Windows.Forms.ToolStripButton() Me.BTT_DONATE = New System.Windows.Forms.ToolStripButton() Me.BTT_BUG_REPORT = New System.Windows.Forms.ToolStripButton() - Me.BTT_SELECT_NONE = New System.Windows.Forms.ToolStripMenuItem() + Me.SEP_FILTER = New System.Windows.Forms.ToolStripSeparator() SEP_2 = New System.Windows.Forms.ToolStripSeparator() SEP_3 = New System.Windows.Forms.ToolStripSeparator() MENU_DEL_CLEAR = New System.Windows.Forms.ToolStripDropDownButton() @@ -134,6 +136,12 @@ Namespace DownloadObjects.STDownloader Me.BTT_SELECT_ALL.Size = New System.Drawing.Size(185, 22) Me.BTT_SELECT_ALL.Text = "Select all" ' + 'BTT_SELECT_NONE + ' + Me.BTT_SELECT_NONE.Name = "BTT_SELECT_NONE" + Me.BTT_SELECT_NONE.Size = New System.Drawing.Size(185, 22) + Me.BTT_SELECT_NONE.Text = "Select none" + ' 'TOOLBAR_BOTTOM ' Me.TOOLBAR_BOTTOM.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.PR_MAIN, Me.LBL_INFO}) @@ -169,7 +177,7 @@ Namespace DownloadObjects.STDownloader 'TOOLBAR_TOP ' Me.TOOLBAR_TOP.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden - Me.TOOLBAR_TOP.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_SETTINGS, Me.SEP_1, Me.MENU_ADD, SEP_2, Me.BTT_DOWN, Me.BTT_STOP, SEP_3, MENU_DEL_CLEAR, Me.SEP_LOG, Me.BTT_LOG, Me.BTT_INFO, Me.BTT_DONATE, Me.BTT_BUG_REPORT}) + Me.TOOLBAR_TOP.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_SETTINGS, Me.SEP_1, Me.MENU_ADD, Me.SEP_FILTER, Me.BTT_FILTER, SEP_2, Me.BTT_DOWN, Me.BTT_STOP, SEP_3, MENU_DEL_CLEAR, Me.SEP_LOG, Me.BTT_LOG, Me.BTT_INFO, Me.BTT_DONATE, Me.BTT_BUG_REPORT}) Me.TOOLBAR_TOP.Location = New System.Drawing.Point(0, 0) Me.TOOLBAR_TOP.Name = "TOOLBAR_TOP" Me.TOOLBAR_TOP.Size = New System.Drawing.Size(584, 25) @@ -222,6 +230,15 @@ Namespace DownloadObjects.STDownloader Me.BTT_ADD_PLS_ARR.Text = "Add URL array" Me.BTT_ADD_PLS_ARR.ToolTipText = "Click to add." & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Ctrl+click to use cookies for download (if supported)." & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Shift to a" & "dd without downloading." + ' + 'BTT_FILTER + ' + Me.BTT_FILTER.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image + Me.BTT_FILTER.Image = CType(resources.GetObject("BTT_FILTER.Image"), System.Drawing.Image) + Me.BTT_FILTER.ImageTransparentColor = System.Drawing.Color.Magenta + Me.BTT_FILTER.Name = "BTT_FILTER" + Me.BTT_FILTER.Size = New System.Drawing.Size(23, 22) + Me.BTT_FILTER.Text = "Filter" ' 'BTT_DOWN ' @@ -286,11 +303,10 @@ Namespace DownloadObjects.STDownloader Me.BTT_BUG_REPORT.Size = New System.Drawing.Size(23, 22) Me.BTT_BUG_REPORT.Text = "Bug report" ' - 'BTT_SELECT_NONE + 'SEP_FILTER ' - Me.BTT_SELECT_NONE.Name = "BTT_SELECT_NONE" - Me.BTT_SELECT_NONE.Size = New System.Drawing.Size(185, 22) - Me.BTT_SELECT_NONE.Text = "Select none" + Me.SEP_FILTER.Name = "SEP_FILTER" + Me.SEP_FILTER.Size = New System.Drawing.Size(6, 25) ' 'VideoListForm ' @@ -337,5 +353,7 @@ Namespace DownloadObjects.STDownloader Private WithEvents BTT_CLEAR_SELECTED As ToolStripMenuItem Private WithEvents BTT_SELECT_ALL As ToolStripMenuItem Private WithEvents BTT_SELECT_NONE As ToolStripMenuItem + Public WithEvents BTT_FILTER As ToolStripButton + Public WithEvents SEP_FILTER As ToolStripSeparator End Class End Namespace \ No newline at end of file diff --git a/SCrawler.YouTube/Downloader/VideoListForm.resx b/SCrawler.YouTube/Downloader/VideoListForm.resx index 4b6b22f..7803415 100644 --- a/SCrawler.YouTube/Downloader/VideoListForm.resx +++ b/SCrawler.YouTube/Downloader/VideoListForm.resx @@ -130,30 +130,31 @@ iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAVDSURBVEhLjZVtTFNXGMcLQmdHO6AdarLSOcTxXqC3lls3 - FeVFihZsqaBjRM2ouILiC0oUozGaaBSTJfuwfdg+bJnJnFuiyzKZMOp8ATJl4IYLAjqspfS9cNlLskjP - /qe0OmPZeJJfbu85z/k//z7n3Ht5NPqLimLMSUkfXV20aPiKTPbhOqn0FQxHBSb/J4ZUKvY3mez6yMKF - fReTkw0YigERgUkaAyaT8FZR0ZdDzc1k9OxZ0tHU5L/Csp15ItFSTEfPZIWPQYZ507Z580Pu9Gky1dpK - hisrPe+nptbLYmPjMT1TpHPJkg/u7d1LHhw7RkaPHiVWJFsOHCBtLHtdLhK9jpSwRUbU6jUQt3BnzhAO - a7mWFjJ15Ai5p9V6v5ZK30OKGETxrkokVir+oKmJPDx0iFiRNH7yJLnW3Oy/olLdyBKJUpD4TBG0pdhW - VWWlzqn4FMS5/fvJFIz5amqIOSHhLtJYIOJ1JCaeG66tJaMoYAHWgweJDQscJ06QG2hXB8t2ZwqFqUgO - FBlSKIrHKyutk6dOEQ5mpmCKw7qpPXvIxI4dpE2lcm2RSC4gtRSIefrFi19tUyqvt2/b5n+EpDEwDjcO - 7IkbLXPu20euokiuUJj2E8MUjRkMtsnjxwMt4eCYQ3u5xkYyCXFzbq4nRSD4FMJGIAd0w3nRjESSiiLd - li1biG3nTmJvaCCO3buJC8W8EOpuaPD3qNV37peXW7nDhwOOOcxxyOXq65+IpwkE56BXCzKC4pEgEPxc - sTjtO4Wi64fqar+9ro44gdtkIh4I+FDMt2sXmYTbSSqMew73AXG0t0up9MqFQipOnaeD+eDpUQ0GXyUW - p3dkZ3fbNm4kzq1biRt4jUbig8MJFJzABk6UlxPf6tXEp1YTD+jKy/PliETnsX47oM4F4DnxUPCXxcdn - dMjl3QMZGY89mzYRt0ZD3AxDXFIpcYlExBUdTVzz5pFuodDfnpTkZePi6IbWgUzwIphVPBSBdt2Sy/vH - IWiHmAM4ARUOEBVF+rKz/zKkpn6L/HdBFpiTeCBsNTUmm1ptsQsEz4sDOjaQnPzYrNXeT0tMLMeSWDA3 - cZ/RuM9VUOCyw/1s4mPgIbBkZJA+ne7uW8uX52Dpf75WAuE2Gluca9e67TExz4k70XvaLio+CoYjI8kA - uJyT4++vqPjVwLK0TbMX8W7ffshRUuIJ59wpkZBHJSV/30hJ8VPxoaB4L+gCZoaZ7qf/ZLYiOIot9oIC - r10oDAg/05YFC8hgaenvx1eu7Oldv37ckpZGfoHobXATXKMFKMuWTf9oMNwpkMvpC/Lpq95TW9tMxR3h - xBMSyOCqVX/UM0wHUhtKMjPfvltWdn8QvQ+Jd4J20EaLqFTTPRUVvZ9otXTj+SCC59mwweqIiwvvHOJ1 - CkU7Ek2AbqR4d37+G316/cidrKwn4pfBN+AS6E9Pf3xbr7+H3MWAz7PrdIMemSyscxPDfI+k+qB46EvF - 31NYyPZVVIxcyMry/1v8q4gIchsFzBrNGPKKQDyvp7p687hG43ZDNOR8oLj4z53hxUPBb8zPz8PGDt/K - ziYXg+LmvLzpzzWaR6VLl36MnJkCiPntlZWHrWVl3h6W9VPnjUplJ8ZnEw8F37hihYK24wusM6vV0xfg - /CWBoBVzOjDTIkQEk5QU26vXf/agrMx5vrAQpy+yEeMMENJ5mjRL8C9VVb3zs043dlOrdZWkpNBvgR5I - AT2uT9bSH3FACdYFr3N9/F8A9GjSk7MevAbCPnDzAHVMP9b0Su/nEtQEff+/HIQWDBrj8f4B7zPYbtFn - HR8AAAAASUVORK5CYII= + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAV6SURBVEhLjZVrTFNnGMcfT4Wto2dcOtRkyBzigALlcmo5 + dVNwXKRowRYEGSNiRi3jXiwQqYEQTVxQkyX7sH3YPmyZicYt0WUXBEaJjkumDNxwQUCHWErpFQ5zSxbo + s7xd200Fxz95c9qcc37//3me9wIAAKOZmQGGiIiP+7ZsmewKD/9of1jYywCwkdz7P01Ipexv4eE3pjZv + HrkSGVkAAAEAsMH3wFhlpeBmZuYXE83NOH3+PHbpdK4ulu1NoekdAOD3GO0JjTPMG6bi4gdcRwcunTuH + k4WF9g+io6vCAwODfSa927d/eLehAe+3t+N0WxsaOzpwpqkJO1n2hpimX1vLZEome9NUXDzDnT2LXHs7 + cno9LrW24l2FwvFVWNj7ABDirkKfUGgk8Ps6HT5oaUFjayvOnTmDfc3Nri6p9Id4mo560mRCKs0yFRUZ + SXICX9LrkWtsxKWmJnSWlqIhNPQOALAAQEPP1q0XJsvLcVqnwxmdDo0nTqBJr8f506fxuk7n6mHZwTiB + INprMpGcnDVXWGhcfO895FpbcamlBTmdDpe0WlyoqMBOqdR6RCi8DAA57q9Qbdv2SqdEcuPa0aOuh1ot + zmq1ONfYiPPNzWhra0PL8ePYx7KDSQJBzE8MkzlbUGBaPHXKXRKuqQm5hgbk6upwsaICDUlJ9ig+/zMA + UAOA2NNw8GOEwuhOiWRw5sgRNNXUoLm6Gufr69Gq1aJDr8f+6mrXkEx2+15enpE7edKdmNNqkaupQa6q + ygeP4fMvAEA5AMR64JS3rP5JISEx15KTBwwlJS6zRoMWjQZtlZVor6pCZ309OmtrcbGhARcJuL4eudra + f+Dl5TggkTjEAgGBk+QiAHj+sanqNZGGhIh6EhIGTYcOoaWsDG1lZehQq9FZUYELGg0ulJbiQl4eOvfu + RadMhnaZDAdSUpyJNH0JAI55kvNXg3vlvzM4OLZHLB4cE4mW7YcPo00uRxvDoDUsDK00jVY/P7TyeNgv + ELi6IyIcbFAQaagGAOIA4IVnwb1yl+umWDw6R9No5vFwnsdDC4/nBrvHxo04kpDwZ0F09LcA8C4AxK8X + 7paptLTSJJPNmPn8p+Eew7HIyGWDQnEvZuvWPAAIXDfcqVYft6anW800vSZ8lsfDBzwezsTG4ohSeeet + XbsSn1yMq8qmVust+/bZzAEBT8Etfn7uchH4NI+HkxSFYxSF3yQmukbz838tYFlSprVNHMeOtcxnZ9tX + S24RCvFhdvZf16OiXAQ+4YEPUxQOUBQaGGZllHzJWiYOtVpvTk93mAUCN/ixsmzahOM5Ob+f2rNnaPjA + gbmZmBj8haLwFkVhP0XhdWJAxs6dKz8WFNxOF4vJBvnvVm8vL28m8PnV4KGhOJ6a+qiKYXoAoDo7Lu7t + O7m598ZjY33wXorCborCTmIila4M5ecPf6pQkMb7uxtvP3jQOB8U9DScJE9NfaRJTu4GgEoAII0MqU9L + e31EpZq6HR/vg39HUfg1ReFVisJRkWj5lkp1FwC2uU3MSuW4PTx81eSVDPM9AFR54N6Tyl+bkcGO5OdP + XYqPd/0X/uWGDXhLJFo2yOWzAJAJAMEwVFJSPCeX22yhob7kY1lZf9SsDvfKvy4tLWVUqZy8mZCAVzxw + Q0rKykW5/GHOjh2f+AzIxtRdWHjSmJvrGGBZF0leJ5H0PgPulb969+5kUo6LLOsyyGQrl+Xy2Rf5/HMA + oPSViLzMREQEDqtUn9/PzbVcysgYpiiqDgAYABCsAffK/2pR0Ts/K5Wz/QqFNTsqipwFKgAI80xX37vk + RxAASABgv+e63uX/HACQqUlmzgEAeHXVtQAAPE9icliTK/m/HpEQZP9/yTOIoS/Y32gy2FQGa9GfAAAA + AElFTkSuQmCC @@ -162,88 +163,91 @@ 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 - HR8AAAAASUVORK5CYII= + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAV6SURBVEhLjZVrTFNnGMcfT4Wto2dcOtRkyBzigALlcmo5 + dVNwXKRowRYEGSNiRi3jXiwQqYEQTVxQkyX7sH3YPmyZicYt0WUXBEaJjkumDNxwQUCHWErpFQ5zSxbo + s7xd200Fxz95c9qcc37//3me9wIAAKOZmQGGiIiP+7ZsmewKD/9of1jYywCwkdz7P01Ipexv4eE3pjZv + HrkSGVkAAAEAsMH3wFhlpeBmZuYXE83NOH3+PHbpdK4ulu1NoekdAOD3GO0JjTPMG6bi4gdcRwcunTuH + k4WF9g+io6vCAwODfSa927d/eLehAe+3t+N0WxsaOzpwpqkJO1n2hpimX1vLZEome9NUXDzDnT2LXHs7 + cno9LrW24l2FwvFVWNj7ABDirkKfUGgk8Ps6HT5oaUFjayvOnTmDfc3Nri6p9Id4mo560mRCKs0yFRUZ + SXICX9LrkWtsxKWmJnSWlqIhNPQOALAAQEPP1q0XJsvLcVqnwxmdDo0nTqBJr8f506fxuk7n6mHZwTiB + INprMpGcnDVXWGhcfO895FpbcamlBTmdDpe0WlyoqMBOqdR6RCi8DAA57q9Qbdv2SqdEcuPa0aOuh1ot + zmq1ONfYiPPNzWhra0PL8ePYx7KDSQJBzE8MkzlbUGBaPHXKXRKuqQm5hgbk6upwsaICDUlJ9ig+/zMA + UAOA2NNw8GOEwuhOiWRw5sgRNNXUoLm6Gufr69Gq1aJDr8f+6mrXkEx2+15enpE7edKdmNNqkaupQa6q + ygeP4fMvAEA5AMR64JS3rP5JISEx15KTBwwlJS6zRoMWjQZtlZVor6pCZ309OmtrcbGhARcJuL4eudra + f+Dl5TggkTjEAgGBk+QiAHj+sanqNZGGhIh6EhIGTYcOoaWsDG1lZehQq9FZUYELGg0ulJbiQl4eOvfu + RadMhnaZDAdSUpyJNH0JAI55kvNXg3vlvzM4OLZHLB4cE4mW7YcPo00uRxvDoDUsDK00jVY/P7TyeNgv + ELi6IyIcbFAQaagGAOIA4IVnwb1yl+umWDw6R9No5vFwnsdDC4/nBrvHxo04kpDwZ0F09LcA8C4AxK8X + 7paptLTSJJPNmPn8p+Eew7HIyGWDQnEvZuvWPAAIXDfcqVYft6anW800vSZ8lsfDBzwezsTG4ohSeeet + XbsSn1yMq8qmVust+/bZzAEBT8Etfn7uchH4NI+HkxSFYxSF3yQmukbz838tYFlSprVNHMeOtcxnZ9tX + S24RCvFhdvZf16OiXAQ+4YEPUxQOUBQaGGZllHzJWiYOtVpvTk93mAUCN/ixsmzahOM5Ob+f2rNnaPjA + gbmZmBj8haLwFkVhP0XhdWJAxs6dKz8WFNxOF4vJBvnvVm8vL28m8PnV4KGhOJ6a+qiKYXoAoDo7Lu7t + O7m598ZjY33wXorCborCTmIila4M5ecPf6pQkMb7uxtvP3jQOB8U9DScJE9NfaRJTu4GgEoAII0MqU9L + e31EpZq6HR/vg39HUfg1ReFVisJRkWj5lkp1FwC2uU3MSuW4PTx81eSVDPM9AFR54N6Tyl+bkcGO5OdP + XYqPd/0X/uWGDXhLJFo2yOWzAJAJAMEwVFJSPCeX22yhob7kY1lZf9SsDvfKvy4tLWVUqZy8mZCAVzxw + Q0rKykW5/GHOjh2f+AzIxtRdWHjSmJvrGGBZF0leJ5H0PgPulb969+5kUo6LLOsyyGQrl+Xy2Rf5/HMA + oPSViLzMREQEDqtUn9/PzbVcysgYpiiqDgAYABCsAffK/2pR0Ts/K5Wz/QqFNTsqipwFKgAI80xX37vk + RxAASABgv+e63uX/HACQqUlmzgEAeHXVtQAAPE9icliTK/m/HpEQZP9/yTOIoS/Y32gy2FQGa9GfAAAA + AElFTkSuQmCC iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAVDSURBVEhLjZVtTFNXGMcLQmdHO6AdarLSOcTxXqC3lls3 - FeVFihZsqaBjRM2ouILiC0oUozGaaBSTJfuwfdg+bJnJnFuiyzKZMOp8ATJl4IYLAjqspfS9cNlLskjP - /qe0OmPZeJJfbu85z/k//z7n3Ht5NPqLimLMSUkfXV20aPiKTPbhOqn0FQxHBSb/J4ZUKvY3mez6yMKF - fReTkw0YigERgUkaAyaT8FZR0ZdDzc1k9OxZ0tHU5L/Csp15ItFSTEfPZIWPQYZ507Z580Pu9Gky1dpK - hisrPe+nptbLYmPjMT1TpHPJkg/u7d1LHhw7RkaPHiVWJFsOHCBtLHtdLhK9jpSwRUbU6jUQt3BnzhAO - a7mWFjJ15Ai5p9V6v5ZK30OKGETxrkokVir+oKmJPDx0iFiRNH7yJLnW3Oy/olLdyBKJUpD4TBG0pdhW - VWWlzqn4FMS5/fvJFIz5amqIOSHhLtJYIOJ1JCaeG66tJaMoYAHWgweJDQscJ06QG2hXB8t2ZwqFqUgO - FBlSKIrHKyutk6dOEQ5mpmCKw7qpPXvIxI4dpE2lcm2RSC4gtRSIefrFi19tUyqvt2/b5n+EpDEwDjcO - 7IkbLXPu20euokiuUJj2E8MUjRkMtsnjxwMt4eCYQ3u5xkYyCXFzbq4nRSD4FMJGIAd0w3nRjESSiiLd - li1biG3nTmJvaCCO3buJC8W8EOpuaPD3qNV37peXW7nDhwOOOcxxyOXq65+IpwkE56BXCzKC4pEgEPxc - sTjtO4Wi64fqar+9ro44gdtkIh4I+FDMt2sXmYTbSSqMew73AXG0t0up9MqFQipOnaeD+eDpUQ0GXyUW - p3dkZ3fbNm4kzq1biRt4jUbig8MJFJzABk6UlxPf6tXEp1YTD+jKy/PliETnsX47oM4F4DnxUPCXxcdn - dMjl3QMZGY89mzYRt0ZD3AxDXFIpcYlExBUdTVzz5pFuodDfnpTkZePi6IbWgUzwIphVPBSBdt2Sy/vH - IWiHmAM4ARUOEBVF+rKz/zKkpn6L/HdBFpiTeCBsNTUmm1ptsQsEz4sDOjaQnPzYrNXeT0tMLMeSWDA3 - cZ/RuM9VUOCyw/1s4mPgIbBkZJA+ne7uW8uX52Dpf75WAuE2Gluca9e67TExz4k70XvaLio+CoYjI8kA - uJyT4++vqPjVwLK0TbMX8W7ffshRUuIJ59wpkZBHJSV/30hJ8VPxoaB4L+gCZoaZ7qf/ZLYiOIot9oIC - r10oDAg/05YFC8hgaenvx1eu7Oldv37ckpZGfoHobXATXKMFKMuWTf9oMNwpkMvpC/Lpq95TW9tMxR3h - xBMSyOCqVX/UM0wHUhtKMjPfvltWdn8QvQ+Jd4J20EaLqFTTPRUVvZ9otXTj+SCC59mwweqIiwvvHOJ1 - CkU7Ek2AbqR4d37+G316/cidrKwn4pfBN+AS6E9Pf3xbr7+H3MWAz7PrdIMemSyscxPDfI+k+qB46EvF - 31NYyPZVVIxcyMry/1v8q4gIchsFzBrNGPKKQDyvp7p687hG43ZDNOR8oLj4z53hxUPBb8zPz8PGDt/K - ziYXg+LmvLzpzzWaR6VLl36MnJkCiPntlZWHrWVl3h6W9VPnjUplJ8ZnEw8F37hihYK24wusM6vV0xfg - /CWBoBVzOjDTIkQEk5QU26vXf/agrMx5vrAQpy+yEeMMENJ5mjRL8C9VVb3zs043dlOrdZWkpNBvgR5I - AT2uT9bSH3FACdYFr3N9/F8A9GjSk7MevAbCPnDzAHVMP9b0Su/nEtQEff+/HIQWDBrj8f4B7zPYbtFn - HR8AAAAASUVORK5CYII= + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAV6SURBVEhLjZVrTFNnGMcfT4Wto2dcOtRkyBzigALlcmo5 + dVNwXKRowRYEGSNiRi3jXiwQqYEQTVxQkyX7sH3YPmyZicYt0WUXBEaJjkumDNxwQUCHWErpFQ5zSxbo + s7xd200Fxz95c9qcc37//3me9wIAAKOZmQGGiIiP+7ZsmewKD/9of1jYywCwkdz7P01Ipexv4eE3pjZv + HrkSGVkAAAEAsMH3wFhlpeBmZuYXE83NOH3+PHbpdK4ulu1NoekdAOD3GO0JjTPMG6bi4gdcRwcunTuH + k4WF9g+io6vCAwODfSa927d/eLehAe+3t+N0WxsaOzpwpqkJO1n2hpimX1vLZEome9NUXDzDnT2LXHs7 + cno9LrW24l2FwvFVWNj7ABDirkKfUGgk8Ps6HT5oaUFjayvOnTmDfc3Nri6p9Id4mo560mRCKs0yFRUZ + SXICX9LrkWtsxKWmJnSWlqIhNPQOALAAQEPP1q0XJsvLcVqnwxmdDo0nTqBJr8f506fxuk7n6mHZwTiB + INprMpGcnDVXWGhcfO895FpbcamlBTmdDpe0WlyoqMBOqdR6RCi8DAA57q9Qbdv2SqdEcuPa0aOuh1ot + zmq1ONfYiPPNzWhra0PL8ePYx7KDSQJBzE8MkzlbUGBaPHXKXRKuqQm5hgbk6upwsaICDUlJ9ig+/zMA + UAOA2NNw8GOEwuhOiWRw5sgRNNXUoLm6Gufr69Gq1aJDr8f+6mrXkEx2+15enpE7edKdmNNqkaupQa6q + ygeP4fMvAEA5AMR64JS3rP5JISEx15KTBwwlJS6zRoMWjQZtlZVor6pCZ309OmtrcbGhARcJuL4eudra + f+Dl5TggkTjEAgGBk+QiAHj+sanqNZGGhIh6EhIGTYcOoaWsDG1lZehQq9FZUYELGg0ulJbiQl4eOvfu + RadMhnaZDAdSUpyJNH0JAI55kvNXg3vlvzM4OLZHLB4cE4mW7YcPo00uRxvDoDUsDK00jVY/P7TyeNgv + ELi6IyIcbFAQaagGAOIA4IVnwb1yl+umWDw6R9No5vFwnsdDC4/nBrvHxo04kpDwZ0F09LcA8C4AxK8X + 7paptLTSJJPNmPn8p+Eew7HIyGWDQnEvZuvWPAAIXDfcqVYft6anW800vSZ8lsfDBzwezsTG4ohSeeet + XbsSn1yMq8qmVust+/bZzAEBT8Etfn7uchH4NI+HkxSFYxSF3yQmukbz838tYFlSprVNHMeOtcxnZ9tX + S24RCvFhdvZf16OiXAQ+4YEPUxQOUBQaGGZllHzJWiYOtVpvTk93mAUCN/ixsmzahOM5Ob+f2rNnaPjA + gbmZmBj8haLwFkVhP0XhdWJAxs6dKz8WFNxOF4vJBvnvVm8vL28m8PnV4KGhOJ6a+qiKYXoAoDo7Lu7t + O7m598ZjY33wXorCborCTmIila4M5ecPf6pQkMb7uxtvP3jQOB8U9DScJE9NfaRJTu4GgEoAII0MqU9L + e31EpZq6HR/vg39HUfg1ReFVisJRkWj5lkp1FwC2uU3MSuW4PTx81eSVDPM9AFR54N6Tyl+bkcGO5OdP + XYqPd/0X/uWGDXhLJFo2yOWzAJAJAMEwVFJSPCeX22yhob7kY1lZf9SsDvfKvy4tLWVUqZy8mZCAVzxw + Q0rKykW5/GHOjh2f+AzIxtRdWHjSmJvrGGBZF0leJ5H0PgPulb969+5kUo6LLOsyyGQrl+Xy2Rf5/HMA + oPSViLzMREQEDqtUn9/PzbVcysgYpiiqDgAYABCsAffK/2pR0Ts/K5Wz/QqFNTsqipwFKgAI80xX37vk + RxAASABgv+e63uX/HACQqUlmzgEAeHXVtQAAPE9icliTK/m/HpEQZP9/yTOIoS/Y32gy2FQGa9GfAAAA + AElFTkSuQmCC @@ -252,30 +256,31 @@ iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAVGSURBVEhLjZVtTFNXGMcLQmdHO6AdarLSOcQBAgV6a1/c - NGgBKVqwpYKOETWj4gqKLyhRjMZoovElWbIP24ftw5aZzLgluiwbE0aNjpdNGejUIW9iKaX0FS5zSxbo - 2f+UVmcsG0/yy+095zn/59/nnHsvh0ZPfn6MJSnpk+tLlvRfk0g+3iAWv4bhqMDk/0SfQqF6JJHcHFi8 - uPtKcrIRQzEgIjBJ457ZzL+Vn/9VX0MDGb5wgfxeX++/plK1KgWC5ZiOns0KH70M87Z969bH7NmzZOr8 - edJfVub5MDW1RhIbG4/p2SKty5Z99HD/fjJ04gQZPn6c2JBsPXSINKlUN6UCwZtICVtkQK1eB3Ere+4c - YbGWbWwkU8eOkYc6nfcbsfgDpAhBFOe6SGSj4kP19eTxkSPEhqSx06fJYEOD/5pC8VOmQJCCxOeKoC0F - 9vJyG3VOxacgzh48SKZgzFdZSSwJCfeRpgICTkti4sX+qioyjAJWYDt8mNixYPzUKfII7WpRqToy+PxU - JAeK9MlkBWNlZbbJM2cICzNTMMVi3dS+fWRi1y7SpFC4tolEl5FaBIQcw9KlrzfJ5Tcf7NjhH0HSKBiD - m3HsiRstcx44QK6jSA6fn/Yrw+SPGo32yZMnAy1h4ZhFe9m6OjIJcUtOjieFx/scwiYgBXTDOdGMSJSK - Ih3WbduIffdu4qitJeN79xIXinkhZK2t9Xeq1XcGS0ps7NGjAccs5ljksjU1T8XTeLyL0KsC6UHxSBAI - bo5QmPaDTNY+UFHhd1RXEydwm83EAwEfivn27CGTcDtJhXHP4j4gjva2y+VeKZ9PxanzFWAheHZUg8FV - CIUrWrKyOuybNxPn9u3EDbwmE/HB4QQKTmADJ0pKiG/tWuJTq4kHtCuVvmyB4BLW7wTUOQ+8IB4K7sr4 - +PQWqbRjqKBg2rNlC3FrtcTNMMQlFhOXQEBc0dHEtWABsfL5/uakJK8qLo5uaDXIAC+DOcVDEWjXLam0 - ZwyCDoiNAyegwgGiokhPVtZfxtTU75D/PsgE8xIPhL2y0mxXq60OHu9FcUDHBpOTpy063WBaYmIJlsSC - +Yn7TKYDLo3G5YD7ucRHwWNgTU8n3Xr9/XdWrcrG0v98rQTCbTI1OtevdztiYl4Qd6L3tF1UfBj0R0aS - e+Budra/p7T0gVGlom2au4h3584j44WFnnDOnSIRGSks/PtRSoqfivcFxbtAO7jNMDM99J/MVQRHsdGh - 0XgdfH5A+Lm2LFpEeouK/ji5Zk1n18aNY9a0NPIbFQVt4AawgJ9Xrpz5xWi8o5FK6Qvy2aveU1XVQMXH - w4knJJDevLwnNQzTgtTawoyMd+8XFw/2ovch8VbQDJpAm0Ix01la2vWZTkc3ngsiOJ5Nm2zjcXHhnUO8 - WiZrRqIZ0I0U7s3NfavbYBi4k5n5VPx78C24CnqUyunbBsND5C4FXI5Dr+/1SCRhnZsZ5kck1QTFQ18q - 7r68PFV3aelAe2am/9/iX0dEkNsKxbRFqx1FXj6I53RWVGwd02rdboiGnN8rKPhzd3jxUHDrcnOV2Nj+ - W1lZ5EpQ3KJUznyp1Y4ULV/+KXJmCyAWNpeVHbUVF3tHVCp/r0bzpE4ub8X4XOKh4JpWr5bRdrRh3Q21 - euYynL/C453HnB7MtggRwSQlxXYZDF8MFRc7L+Xl4fRF1mGcAXw6T5PmCO7V8vL37ur1o206naswJYV+ - CwxADOhxfbqW/ogDcrAheJ3v4/8SoEeTnpyN4A0Q9oFbAKhj+rGmV3o/n6Am6Pv/1SC0YNAYh/MPME3a - dCWdzmEAAAAASUVORK5CYII= + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAV8SURBVEhLjZVrTFNnGMcf3wpbR8+4dKjJgDnEAQLl0lJO + 3TTcpWjBFgQZI2JGLeNeLBCpgRBNNIjJkn3YPmwftsxkxi3RZdmYMCBDgagM3GBBLg6wlNIrlLklC/RZ + 3q7tpoLjn5ycNuec3///Ps97AQCA0YwMn97Q0I/7du2auhkS8tHhoKBXAWA7ffZ/mhSL2d9CQvqnd+4c + uR4Wlg8APgCwzfPCWEUF725GxpeTTU04e/kyjms0jpss25PEMHsBwOsJ2lOaEArf0hcVzdnb23G1owOn + CgosH0REVIb4+vp7THr27PnwQX09Pmxrw9nWVtS1t+N8YyN2smy/gGHe2MxkWiJJ1RcVzdsvXUJ7Wxva + tVpcbWnBBzKZ9eugoPcBIMBZhT4+X0fhDzUanGtuRl1LCy5euIBTTU2Om2LxrRiGCX/aZFIsztQXFupo + cgpf1WrR3tCAq42NaCspwd7AwHEAYAGAge7g4CtTZWU4q9HgvEaDujNnUK/V4tL58zij0Ti6WXYwmseL + cJtMJiRkLhYU6FYuXkR7SwuuNjejXaPBVbUal8vLsVMsNp3g868BQLZzFIrdu1/rFIn6x06edDxSq3FB + rcbFhgZcampCc2srGk+fxj6WHYzn8SJ/EgozFvLz9SvnzjlLYm9sRHt9Pdpra3GlvBx74+Mt4VzuZwCg + BACBq+HgJeTzIzpFosH5EydQX12NhqoqXKqrQ5NajVatFmerqhxDEsn9mdxcnf3sWWdiu1qN9upqtFdW + euCRXO4VACgDgCgXnLjL6h0fEBD5fULCwGRxscOgUqFRpUJzRQVaKivRVleHtpoaXKmvxxUKrqtDe03N + P/CyMhwQiawCHo/CafJ9APDiE1PVbSIOCNjXHRs7qD92DI2lpWguLUWrUom28nJcVqlwuaQEl3Nz0ZaS + gjaJBC0SCQ4kJdniGOYqAJxyJeduBHfLO9HfP6pbIBicTk9fsxw/jmapFM1CIZqCgtDEMGjy8kITh4Oz + PJ6jKzTUyvr50YaqACAaAF56HtwtZ7nuCgSjiwyDBg4HlzgcNHI4TrDz2r4dR2Jj/8yPiPgWAN4DgJit + wp3Sl5RU6CWSeQOX+yzcZTgVFrbWK5PNRAYH5wKA75bhNqXytCktzWRgmE3hCxwOznE4OB8VhSNy+fjb + +/fHPb0YN5RZqdQaDx0yG3x8noEbvbyc5aLwWToCQnCMEByNi3OM5uX9ms+ytEybm1hPnWpeysqybJTc + yOfjo6ysv2bCwx0UPumCDxOCA4TgHaFwfZSOZDMTq1KpNaSlWQ08nhP8RFl27MCJ7Ozfzx08ODR85Mji + fGQk/kII3iMEbxOCPxKCvYTgYGLi+p38/PtpAgHdIP/d6i1lZU0UvrQRPDAQJ1JTH1cKhd0AUJUVHf3O + eE7OzERUlAfeQwh2EYKdhGC/WLw+lJc3/KlMRhvv7Wy85ehR3ZKf37Nwmjw19bEqIaELACoAgDYyoC45 + +c0RhWL6fkyMB/4dIfgNIXiD9iQxce2eQvEAAHY7TQxy+YQlJGTD5BVC4Q8AUOmCu08qb3V6OjuSlzd9 + KybG8V/4V9u24T2RaK1XKl0AgAwA8Ieh4uKiRanUbA4M9CQfy8z8o3pjuFvetcnJSaNy+dTd2Fi87oL3 + JiWtfyGVPsreu/cTjwHdmLoKCs7qcnKscyzrmEhJeVwrEvU8B+6Wt/LAgQRajn6WdfRJJOvXpNKFl7nc + DgCQe0pEPxaGhvoOKxSfP8zJMV5NTx8mhNQCgBAAeJvA3fK+UVj47s9y+cJtmcyUFR5OzwIFAAS5pqvn + W/rDDwBEAHDYdd/q8n8BAOjUpDPnCAC8vuFaAACOKzE9rOmd/t+KaAi6/7/iuqihJ9jfOenaM1O34/0A + AAAASUVORK5CYII= @@ -287,105 +292,123 @@ iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANoSURBVEhLrZVrSFNhGMePTbwkzoVlzUuUZdkizzIvFE5r - K51a0bzU8kYXp2W4El1SGdL1axh9iz5IRPQljD51gUyitIvOOjNdytxNZ4Hh9xP/nvc0yQ+iYeeBPwze - l//veZ/3/55xi1VYh6Iz/LYC84mtBbctvZiRxq4R9QM67BvUwSiQHDqUuwwSJLht6SUBPmvE5T0clO84 - xH7gkPApFBZfkYwAQSPG9HJY9SEE6wbCoRWUOB8olRfAOk+2hyN9KAa7h1fj+o8q+QA8AZLtEcgcUqHA - GU/z34iO6Tr5ACcIkOFQociZgIrxzahza3FvxiofoFlIE43fElHt3oIGTzqavbvwYMb2b4CFcj6r0td5 - v6rcqWj0ZKB1QocrgXx0/mzByoeRC0r9OKpT6tAwm3HKd/GwDiVOPWpcBWj0HsQFfzluBGrodwYu+nNx - NVCAa1NGdE634P60TQLdnbbi1o9aXJ2qxHl/GY2wGA3uI1B3RUECMHPlW8p4H4fEgTC6VKWUFNNYMo67 - t+KsNxuXJvaQgRE3p4okwJXJfDLToc6jxeGxFBhG1oB3KJHUHwYV+RxxmP4CWOfMnC3yjmjarEZp0Pyc - Lxttfj2uBYwEyMflST1s/hy6ix04Nq7BodH1yBuOwzYhGvEDoVC95xBJj7J0cA6geEiHtWSupQ4MTrUU - Q4uHR5MvCxcndqONTC/482Dz5eCcNxP1tFbt1uDA6Drk0kkl8/5QsMfIzEOeczC9nwM46tyLnUOxFMNE - VLpSYaXLbKGktJIhM2327ZLURKOqp5GwNO0fXYucr3HY8iUK6o8KRNOII7o5cM9IXQR4MwdwmnJuE7Ri - u1BNOkmqJ9WRTpHOiHe+nybzLFjcPMzjm1A0moRWbw0KX+X9qhW2i1UCL5pJWhL/mfSJ1MeLEoDFdL6I - zYptahdaRYsnDWZXCgrplNl02gaPWVpbUCymixXb2C40iYfpXgpGErCDXvQGeySOuUokk+C2pdcfQIOY - PxIvfejY1zSWklLhDM74f+sPoFbc7ohBIiVlBcWZ/TeUzeb8f4uZWIVKMak/HCqK4fLXHBQvKCV2GQEn - KGHMPII6X8Zi+JQAvTICKil+kdQ5Rw+Ie0J6RIAeGQFlX0zSSEx9JHpApm7SS7kAlGVmNK8WzTnH/Qao - hKygM1JCJAAAAABJRU5ErkJggg== + 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 - H0WkrMjY2947AAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAOKSURBVEhLrZVfTFNXHMePg/DHhlLTqSsU41A3vUZPVZSM + cMW1G9SyLV4BZfIn6qBoF5gECtG5NOK218Vlb8seGrMsvhjMnuaWTMiiFLVUPbdChym9t4V2Jiy+H/M1 + 91Y2RhbUcL/J7+mcfD8nJ59zLyEvSN6lnGD+tzn4v9HWlu5/5WhFQkTgzgkR798T4WYi3LKIprhLhyzd + /8rRAfcFvnqUwHyLwHqboPRuLjqTHgMBTODFYwRrb6/Cxol8OJgZA+kGYwHaycsj+dgdLcaByfX48nGr + cQDKBF4eKcDeqAV1sRI0xTfj0rzXOMBJJvAK2QJPrBTHZt6GN+HAD096jAP0sZ3c/acdbYlt8Cm70adW + 4ccn/pcDLOf5wjSM1DxtTWxFt1KBwVkRF9K1CP7dj9d/Klx2bFdNQf2ErgXHZRH1kyIOx5xoj9ehW/0I + Z1NN+Crdjm61AudS+zGUrsPFjBvB+X5cnvfroO/ne/DN4w4MZVowkGqEN1EPX+IobMMm6ACt3HyTwBoi + sE/kgTKzbor0qBwnEtvxmVqJz2ffxVDGja8zHh1wYa4WAykRXsWBI4+2wDX1BqhsRlk4D5YQwVFZ+heg + nVwr1xapXATXlA0Nz8vPJCtxPuXExbQbQ5lafDHnhD9VDZ+yB8dnBByafhM1k+uwgxWhZCIXlnGCwlGC + hnuLAPVRERvCeXDIZrhiNl3DToWiN7kP52YP4PycE2dTNfAnq3FG3YsuhaItIeDD6Y3YP7k+Wx7OhfYY + tfJV1wmk8UWAj2Pv4Z2oFZ6YHS3xrehRKtCvVmEwWa2X9iWr9OlVK9GlOHSbPpjegOqH67DtgQm2Ozko + uklQcIOA/EJAhgmkPxYBTjOB+5mDB1gbD7BPeIB18QDz8gA7xQPsU/7dX6fRq+5DZ4KieeYteKbLMKi2 + 4+DvNU872C7eyihvZpQ7GOX0PuX0LuU0RLkO0DRdqtd/VBs2IcAGeaeyE83xLTgYs6MyaoVPadbXlh1N + 0xclC+jlR+KbUTdVij2yBZsihTgeP5y9gpUmC/Dx2qkS/UOnfU2t4wTHYs/veKXJAjr4LrkY9nAu1oQI + tH9D44LnK41W0sNaeFk4H5YxgtUjBDm/EkgRAwEnmYNr5QWjBK9pGv5MII0ZCGhhlBeOEJDrBOQaAblC + II0aCGh8IOlXIoUk/QFJNyRIvxkFuGoK/uP10nkJz58BqISsoFjBRioAAAAASUVORK5CYII= iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAN5SURBVEhLrZVJTFNRFIafljBIgBqcymAU54oWGSRCK1oU - KqixAoIyiMqgGBAChYCaOsed0bgzLogxxo3RuHJYqDEqKFD1tUItKZ2gaIJxf8nvuc8SWRAw8E7yp03u - zf+de95/3xNmquCbis6QWwpMJb4W2Db74kaJFjXT9+mw+7MOBpFk1aHImS1BAttmX9xE80XNFrwREPle - QPRHAbE9Qaj25skHSBbVLOqDgMUf52FFXwiSxEi0+gvkA6QRgHeeYAlBsi0KO/qX4srPMvkAmWIiS7CE - Is2mRK49hua/GjfHauQDHBeTWapViTx7LI4MrUONKwl3fzfIB2gWM5jhexzKXRtQ505GsycD93+b/g8w - Xc4ndLQna7zMtR717lS0Detw0Z+Dzl8tWPQgbFqpHoV3Sh1mT2Sc8p3fr8NBux4VzlzUe/aj3VeEq/4K - +p+KDt92XPLn4vKoAZ1jLbg3ZpJAd8YacONnFS6NlqLVV0gjzEedqxiqx+GQANw88h1lvEtAXF8wNBRD - nhTjYAKOuTbijCcdZ4d3koEB10bzJMDFkRwy06HGnYRDg2uQPbAMGmsk4nuDoSSfYqvxH4B3zs35osYa - QZtVKAiYN3rTcc6nx2W/gQA5OD+ih8mnpWeRgsohNQ44ViKrfwk2iRGI6QuCsltAGF3Kgs+TAPk2HZaT - eRJ1kG1XSTGsdmvQ5N2KjuEdOEem7b4smLxaNHrSUEtr5S419jlWYDudVDLvDQK/jNx83nMBxu5JgMP2 - Xdhmi6YYxqHUuR4N9DBbKCltZMhNm70ZkppoVLU0Ep6mvY7l0H5bgg1fw6H6pEAEjTj0lQDhGekxAd5O - ApwSU5nJqmVmezkzfz/BzI5aZh6sod+TzCyeZrd/nCLzrah2aVAytBZ5jni0eSpQ1K0frxJ1rEzMZCUk - LSnzC6mH1JXJJACP6VQRmxDfdN3axqrdm1HiXIM9dMp0Om2du0Ram1Y8pjMV33hBbGKH6LnkDsQihW70 - KksYKp0HJZPAttkXNzGLdSxnIEZ60fG3aTQl5Yg9MOO51l9AFdtijUIcJWUhxZl/Gwoncj7X4iYNYimL - 7w2BkmK44LUAxQtKiUVGwHFRy7h5KHU+n8fwKQE+yAgopfiFUecCXSDhCekhAd7ICCj8apRGYuwi0QUy - viK9lAtAWeZGU2rGnAvCHy5drfKWDYjrAAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAOUSURBVEhLrZVfTFtVHMfPhPBnDaWmulkoy8RNt5rZCmx4 + K3dgq1CLGu+ADcefzAnF1YAjUMjmTDOmezUzvi0+NMYYXxaMT04fNmImBVe67dza3rGU3ttC6xLM3s/y + NecyFIlhW+g3+T2dk+/n5ORz7iXkISm6UBAq/rIA/zd8bf3+xw4vskVtzDUn4o0bIjxUhEcW0ZF065D1 + +x87vGTfTRvbOkVg/I3APEtQeb0Q/Wlv/gAOamPl0wRPz27BzrliOKgRY9m2/AFqqY3xk1dHi1ETK0dT + fDs+u9udP4BAbaw6WoL9MRNalAp0JHfhwrIvf4Dj1MHqZBO8SiWOLrwAX8qBr+8N5Q8wQl9hnttW9KT2 + wq/WYERz4tt7gUcDbOT56vTMNt7vTu3BoFqH8UURZ7PNCP01iqe+K91wLJcMIf2E7lXHZRGtcRGHFBd6 + ky0Y1N7BqUwHPs/2YlCrw+nMQUxkW3Au50FoeRTfLAd00MXlIXxxtw8TuS6MZdrhS7XCnzoCy6QBOoCX + G68RmMME1rki2KlRN0W6U433Uy/iY60enyy+homcB+dzXh1wdqkZYxkRPtWBw3d2w514BnbZiKpIEUxh + giOy9C+An5yX80W7XAZ3woK2B+Un0/U4k3HhXNaDiVwzPl1yIZBpgF+txbEFG96dfxaN8W3YR8tQMVcI + 0wxB6RRB2401gNaYiB2RIjhkI9yKRdewX7VjOH0ApxebcGbJhVOZRgTSDTip7ceAakdPyoa353fiYHz7 + SnmkEPwx8vItlwmkmTWA95TXIcTM8CpWdCX3YEitw6jmxHi6QS8dSTv1GdbqMaA6dJvemt+Bhj+2Ye8t + Ayy/F6DsGkHJFQLyEwGZJJB+XQM4QWtYgDpZMN7DgokPWFAZYMHbPhZUPmRB+hH76s8TGNYOoD9lR+fC + 8/DOV2Fc60XbdNP9Pvoq66YC66QCc1KBCTcFJlwXmBAWmA7gmq7X6z+qTRpwno6zfvUldCZ3403FivqY + GX61U1/bcLimDwvfGKTD7HByF1oSlaiVTXguWopjyUMrV7DZrAD8rDlRoX/o+NfUPENwVHlwx5vNCqCP + vSyXwxopxJNhAv5vaF/1fLPhJUO0i1VFimGaJth6laDgZwIpmkfAcepkvLxkiuAJruGPBNJ0HgFdVGCl + VwnIZQLyAwH5nkCayiOg/ZakX4kUlvQHJF2RIP2SL8AlQ+gfr9fPI3j+N/WNrat6NXl+AAAAAElFTkSu + QmCC + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIFSURBVDhPpZLtS1NhGMbPPxJmmlYSgqHiKzGU1EDxg4iK + YKyG2WBogqMYJQOtCEVRFBGdTBCJfRnkS4VaaWNT5sqx1BUxRXxDHYxAJLvkusEeBaPAB+5z4Jzn+t3X + /aLhnEfjo8m+dCoa+7/C3O2Hqe0zDC+8KG+cRZHZhdzaaWTVTCLDMIY0vfM04Nfh77/G/sEhwpEDbO3t + I7TxE8urEVy99fT/AL5gWDLrTB/hnF4XsW0khCu5ln8DmJliT2AXrcNBsU1gj/MH4nMeKwBrPktM28xM + cX79DFKrHHD5d9D26hvicx4pABt2lpg10zYzU0zr7+e3xXGcrkEB2O2TNec9nJFwB3alZn5jZorfeDZh + 6Q3g8s06BeCoKF4MRURoH1+BY2oNCbeb0TIclIYxOhzf8frTOuo7FxCbbVIAzpni0iceEc8vhzEwGkJD + lx83ymxifejdKjRNk/8PWnyIyTQqAJek0jqHwfEVscu31baIu8+90sTE4nY025dQ2/5FIPpnXlzKuK8A + HBUzHot52djqQ6HZhfR7IwK4mKpHtvEDMqvfCiQ6zaAAXM8x94aIWTNrLLG4kVUzgaTSPlzLtyJOZxbb + 1wtfyg4Q+AfA3aZlButjSfxGcUJBk4g5tuP3haQKRKXcUQDOmbvNTpPOJeFFjordZmbWTNvMTHFUcpUC + nOccAdABIDXXE1nzAAAAAElFTkSuQmCC iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAVCSURBVEhLjZVtTFNXGMcLQmdHO6AdarLCHOJ4L9Bby62b - iuNFihZsqaBjRM2ouILiC0oUozGauPiSLNmH7cP2YctMZtwSdcvGhFEzFJjCihsuCOiwltL3wmUvySI9 - +5/S6oxl40l+ub3nPOf//Pucc+/l0RgoLo4xJSd/dG3JkpGrSUkfrpdKX8JwVGDyf2JYqWR/S0rqGl28 - 2HwpJUWPoRgQEZikMWg0Cm8VF38x3NJCxs6dI9ebm/1XWbYzXyRajuno2azwMcQwr9u2bHnAnT5Nps+e - JSNVVZ7309IakmJj4zE9W6Rz2bIP7u7bR+4fP07Gjh0jViRbDh4kbSzbJROJXkVK2CKjKtUbELdwZ84Q - Dmu51lYyffQouavReK9Ipe8hRQyieNckEisVv9/cTB4cPkysSJo4dYrcbGnxX1Uqr2eLRKlIfKoI2lJi - q662UudUfBri3IEDZBrGfLW1xJSQcAdpLBDxOhITz4/U1ZExFLAA66FDxIYFjpMnSR/a1cGyPVlCYRqS - A0WG5fKSiaoq69S77xIOZqZhisO66b17yeTOnaRNqXRtlUguIrUMiHm6pUtfblMourq2b/c/RNI4mIAb - B/bEjZY59+8n11AkTyhM/4lhisf1etvUiROBlnBwzKG9XFMTmYK4KS/PkyoQfAphA5ABuuG8aEYiSUOR - HsvWrcS2axexNzYSx549xIViXgiZGxv9vSrV7XsVFVbuyJGAYw5zHHK5hobH4ukCwXno1YHMoHgkCAQ/ - TyxO/04u7/6xpsZvr68nTuA2GokHAj4U8+3eTabgdooK457DfUAc7e1WKLwyoZCKU+cZYCF4clSDwVeK - xRkdOTk9tk2biHPbNuIGXoOB+OBwEgUnsYGTFRXEt3Yt8alUxAO68/N9uSLRBazfAahzAXhGPBT8FfHx - mR0yWc8gwzzybN5M3Go1cTMMcUmlxCUSEVd0NHEtWEDMQqG/PTnZy8bF0Q2tB1ngeTCneCgC7bolkw1M - QNAOMQdwAiocICqKmHNy/tKnpX2D/HdANpiXeCBstbVGm0plsQsEz4oDOjaYkvLIpNHcS09MrMCSWDA/ - cZ/BsN9VWOiyw/1c4uPgAbBkZhKzVnvnzZUrc7H0P18rgXAbDK3Odevc9piYZ8Sd6D1tFxUfAyORkWQQ - mHJz/QOVlb/qWZa2ae4i3h07DjtKSz3hnDslEvKwtPTvvtRUPxUfDor3g25ahGFmBug/masIjmKrvbDQ - axcKA8JPtWXRIjJUVvb7idWre/s3bJiwpKeTXyDaB26AH2gByooVMzf1+tuFMhl9QT551Xvq6lqouCOc - eEICGVqz5o8GhulAamNpVtZbd8rL7w2h9yHxTtAO2mgRpXKmt7Ky/xONhm48H0TwPBs3Wh1xceGdQ7xe - Lm9HohHQjRTvKSh4zazTjd7Ozn4s/i34GlwGAxkZj/p0urvIXQr4PLtWO+RJSgrr3Mgw3yOpISge+lLx - 9xYVsebKytGvsrP9/xb/MiKC9KGASa0eR14xiOf11tRsmVCr3W6IhpwPlpT8uSu8eCj4TQUF+djYkVs5 - OeRSUNyUnz/zuVr9sGz58o+RM1sAsbC9quqItbzcO8Cyfuq8SaHoxPhc4qHgG1atktN2XME6k0o1cxHO - XxAIzmJOC2ZbhIhgkpNj+3W6z+6XlzsvFBXh9EU2YZwBQjpPk+YI/uXq6rd/1mrHb2g0rtLUVPot0AEp - oMf18Vr6Iw4owPrgdb6P/3OAHk16cjaAV0DYB24BoI7px5pe6f18gpqg7/8Xg9CCQWM83j84CNjeVkuE - bAAAAABJRU5ErkJggg== + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAV6SURBVEhLjZVrTFNnGMcfzxG2jp5x6VCTIXOI414up5ZT + NwXHRYoWbEGQMSJm1DLuxQKRGgjRRIOaLNmH7cP2YctMZtwSXZaNCVKnE4iK4IYLAjrEUkqvcJhbskCf + 5e3abio4/smb0+ac8/v/z/O8FwAAGM7KCjBERHxyZcOG8Uvh4R/vDgt7FQDWknv/pzGplPstPPzaxPr1 + QxciIwsBIAAA1vgeGKmqEt7MyvpqrKUFJ8+cwas6nesSx/WmMswWAPB7gvaURln2LVNJyUO+sxMXTp/G + 8aIi+4fR0dXhgYHBPpPezZs/utfYiA86OnCyvR2NnZ041dyMXRx3Tcwwb6xkMiGTvW0qKZniT51CvqMD + eb0eF9ra8J5C4fgmLOwDAAhxV+GKSGQk8Ac6HT5sbUVjWxvOnDiBAy0trktS6U8JDBP1tMmYVJptKi42 + kuQEvqDXI9/UhAvNzegsK0NDaOhdAOAAgIGejRvPjldU4KROh1M6HRqPHEGTXo+zx4/jDZ3O1cNx/fFC + YbTXZCwlJXumqMg4f/Ik8m1tuNDairxOhwtaLc5VVmKXVGo9IBKdB4Bc91eoNm16rUsiufbjwYOuR1ot + Tmu1ONPUhLMtLWhrb0fL4cN4heP6k4XCmNssmzVdWGiaP3bMXRK+uRn5xkbk6+txvrISDcnJ9iiB4HMA + UAOA2NNw8GNFouguiaR/6sABNNXWormmBmcbGtCq1aJDr8fBmhrXgEx2535+vpE/etSdmNdqka+tRb66 + 2gePEQjOAkAFAMR54JS3rP7JISExP6Sk9PWXlrrMGg1aNBq0VVWhvboanQ0N6Kyrw/nGRpwn4IYG5Ovq + /oFXVGCfROIQC4UETpLHAsCLT0xVr4k0JCS2JzGx37RvH1rKy9FWXo4OtRqdlZU4p9HgXFkZzuXno3Pn + TnTKZGiXybAvNdWZxDDnAOCQJ7lgObhX/luDg+N6xOL+keTkRfv+/WiTy9HGsmgNC0Mrw6DVzw+tNI2D + QqGrOyLCwQUFkYZqACAeAF56Htwrd7luisXDMwyDZprGWZpGC027we6xdi0OJSb+WRgd/R0AvA8ACauF + u2UqK6syyWRTZoHgWbjHcCQyctGgUNyP2bgxHwACVw13qtWHrRkZVjPDrAifpml8SNM4FReHQ0rl3Xe2 + bUt6ejEuK5tarbfs2mUzBwQ8A7f4+bnLReCTNI3jFIUjFIWXk5JcwwUFvxZyHCnTyiaOQ4daZ3Ny7Msl + t4hE+Cgn568bUVEuAh/zwAcpCvsoCg0suzRMvmQlE4darTdnZDjMQqEb/ERZ1q3D0dzc34/t2DEwuGfP + zFRMDP5CUXiLovA6ReFVYkDG1q1LNwoL72SIxWSD/Hert1dUtBD47HLw0FAcTUt7XM2yPQBQkxMf/+7d + vLz7o3FxPngvRWE3RWEXMZFKlwYKCgY/UyhI4/3djbfv3WucDQp6Fk6Sp6U91qSkdANAFQCQRoY0pKe/ + OaRSTdxJSPDBv6co/Jai8CJF4XBs7OItleoeAGxym5iVylF7ePiyyatY9jIAVHvg3pPKX5uZyQ0VFExc + TEhw/Rf+9Zo1eCs2dtEgl08DQBYABMNAaWnJjFxus4WG+pKPZGf/Ubs83Cv/+vT01GGlcvxmYiJe8MAN + qalLX8rlj3K3bPnUZ0A2pu6ioqPGvDzHbY5zkeT1Eknvc+Be+au3b08h5bjAcS6DTLZ0Xi6fflkgOA0A + Sl+JyMtsRETgoEr1xYO8PMu5zMxBiqLqAYAFAOEKcK/8LxYXv/ezUjl9XaGw5kRFkbNABQBhnunqe5f8 + CAIACQDs9lxXu/xfAAAyNcnM2QMAry+7FgCA9iQmhzW5kv+rEQlB9v9XPIMY+oL9DaXP2MIw0VMVAAAA + AElFTkSuQmCC iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFmSURBVFhH1dc/K4VhHMbxJ5EFEQbFiERKCotIrMJIiYEi - pbwCZcOqJC9AikUWiqRkJYtSRDbESMT3V07dna7zHHru+9T51me+Ts//E+V7LRjFFAZRiZzUhDVc4/vX - B47Rh6D14Aqp4XQ36ECQ2nALNezaQjG8Vo5DqMF0bxiA1+bwCTWoLMFbNTiDGsrkABXw0jDsKldDmdyj - HokrwCrUSBz7wXbRJs4eLkdQI9m0I3ENeIAaiGN3QjMSZ4fxv+ffnKIKibOnmhqI84V5eMleOHY41VAm - 9k7wdgtW4wRqSHlCP7y2AjWmbMB7Y7DzqgZdz2iF9zrxCDXq2oU9uLz31+tgAcHahhp1DSFY9pGhRl29 - CFYXxrMoQ7BmsZfFPkoRpHWow+56hX26BWkRatR1gRIEaQLvUMMpOyhCkBpxBzWcMoOgLUMNm0vUIWj2 - ebaJF7jj5+hGTiqE/f+bxDRGUIt8LIp+AC/GHt3tQnwvAAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGTSURBVFhH1ZfPK21RGIaf5GaCCAPF0JVISWEiElNhSIkB + RUr5C5QZpkryB0gxkQlFUjKlO1HKjcwQQyJatdXp7TtnH3t/Z+CpZ7be7z3tH2uvA7+cFmAUmAIGgSpd + UCiagDXgCviMfAOOgT5d7E0P8C+jWL0GOjTkRRtwY5SqW0CJhtNSARwaZZYvwIAOSMsc8G6UZXNJB6Sh + FjgzSnJ5AFTqoKQMR0+5luTyFmjQQUkoAlaNgjjDDw4PbWrC5nJkFORjuw5Lwl/gzhgeZ3gTmnVYEsJl + /On9D54C1TosCWFX0+FxfgDzOigp4YMTLqeW5DJ8E9xewRrgxCjJ5gPQr0PSsmIUZXNDwx6MRfdVy9RH + oFXDHnQC90ahuhttXO7k+xwsaNCTbaNQHdKQJ+GQoYVqr4Y86QLGYyzXkCezwF6M+0CZBr1YNy65+hwd + 3QrColGoXgClGvRiAng1SjPdAf5o0ItG4L9RmumMhrxZNkq/vQTqNeBNOJ5tAk9Sfg506+JCURz9/5sE + poERoE4X/Rq+AC/GHt09Rk0KAAAAAElFTkSuQmCC \ No newline at end of file diff --git a/SCrawler.YouTube/Downloader/VideoListForm.vb b/SCrawler.YouTube/Downloader/VideoListForm.vb index 2547e83..8562360 100644 --- a/SCrawler.YouTube/Downloader/VideoListForm.vb +++ b/SCrawler.YouTube/Downloader/VideoListForm.vb @@ -39,6 +39,7 @@ Namespace DownloadObjects.STDownloader MyView = New FormView(Me) MyProgress = New MyProgress(TOOLBAR_BOTTOM, PR_MAIN, LBL_INFO) MyJob = New JobThread(Of MediaItem) + BTT_FILTER.Image = My.Resources.FilterPic End Sub #End Region #Region "Form handlers" @@ -95,15 +96,18 @@ Namespace DownloadObjects.STDownloader Dim b As Boolean = True Select Case e.KeyCode Case Keys.Insert : BTT_ADD.PerformClick() - Case Keys.F5 : BTT_DOWN.PerformClick() + Case Keys.F5 + If e.Control Then LoadData(True) Else BTT_DOWN.PerformClick() Case Else : b = False End Select If b Then e.Handled = True End Sub #End Region #Region "Refill, save list" - Protected Sub LoadData() + Protected Sub LoadData(Optional ByVal ClearTable As Boolean = False) + If ClearTable Then RemoveControls(,, False) Dim c As List(Of IYouTubeMediaContainer) = LoadData_GetFiles() + If c.ListExists Then MyYouTubeSettings.FILTER.RemoveAll(c) If c.ListExists Then c.Sort(New ContainerDateComparer) SuspendLayout() @@ -415,6 +419,12 @@ Namespace DownloadObjects.STDownloader Return ErrorsDescriber.Execute(EDP.SendToLog + EDP.ReturnValue, ex, "[VideoListForm.ValidateContainerURL]", True) End Try End Function + Private Sub BTT_FILTER_Click(sender As Object, e As EventArgs) Handles BTT_FILTER.Click + Using f As New FilterForm(LoadData_GetFiles) + f.ShowDialog() + If f.DialogResult = DialogResult.OK Or f.DialogResult = DialogResult.Abort Then LoadData(True) + End Using + End Sub Private Sub BTT_DOWN_Click(sender As Object, e As EventArgs) Handles BTT_DOWN.Click With TP_CONTROLS If .Controls.Count > 0 Then @@ -494,7 +504,8 @@ Namespace DownloadObjects.STDownloader Protected Sub CheckVersionImpl(ByVal Force As Boolean) CheckVersion(Force) End Sub - Protected Overloads Sub RemoveControls(Optional ByVal Predicate As Predicate(Of MediaItem) = Nothing, Optional ByVal RemoveFiles As Boolean = False) + Protected Overloads Sub RemoveControls(Optional ByVal Predicate As Predicate(Of MediaItem) = Nothing, Optional ByVal RemoveFiles As Boolean = False, + Optional ByVal ProcessDelete As Boolean = True) ControlInvokeFast(TP_CONTROLS, Sub() With TP_CONTROLS If .Controls.Count > 0 Then @@ -509,7 +520,10 @@ Namespace DownloadObjects.STDownloader For i = rCnt.Count - 1 To 0 Step -1 cnt = .Controls(rCnt(i)) .Controls.RemoveAt(rCnt(i)) - If Not cnt.MyContainer Is Nothing Then cnt.MyContainer.Delete(RemoveFiles) : cnt.MyContainer.Dispose() + If Not cnt.MyContainer Is Nothing Then + If ProcessDelete Then cnt.MyContainer.Delete(RemoveFiles) + cnt.MyContainer.Dispose() + End If cnt.Dispose() Next End If diff --git a/SCrawler.YouTube/Editors/BugReporterForm.Designer.vb b/SCrawler.YouTube/Editors/BugReporterForm.Designer.vb index 5d0fffb..03569c0 100644 --- a/SCrawler.YouTube/Editors/BugReporterForm.Designer.vb +++ b/SCrawler.YouTube/Editors/BugReporterForm.Designer.vb @@ -24,7 +24,6 @@ Namespace Editors Private Sub InitializeComponent() Me.components = New System.ComponentModel.Container() Dim TP_MAIN As System.Windows.Forms.TableLayoutPanel - Dim TP_BUTTONS As System.Windows.Forms.TableLayoutPanel Dim ActionButton1 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(BugReporterForm)) Dim ActionButton2 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() @@ -33,31 +32,32 @@ Namespace Editors Dim ActionButton5 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Dim ActionButton6 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Dim ActionButton7 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() + Dim TP_BUTTONS 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() - Me.BTT_EMAIL = New System.Windows.Forms.Button() - Me.BTT_GITHUB = New System.Windows.Forms.Button() - Me.BTT_COPY = New System.Windows.Forms.Button() - Me.BTT_CANCEL = New System.Windows.Forms.Button() - Me.BTT_ANON = New System.Windows.Forms.Button() - Me.TT_MAIN = New System.Windows.Forms.ToolTip(Me.components) Me.TXT_DESCR = New PersonalUtilities.Forms.Controls.TextBoxExtended() Me.TXT_URL_PROFILE = New PersonalUtilities.Forms.Controls.TextBoxExtended() Me.TXT_URL_POST = New PersonalUtilities.Forms.Controls.TextBoxExtended() Me.TXT_REPRODUCE = New PersonalUtilities.Forms.Controls.TextBoxExtended() Me.TXT_EXPECT = New PersonalUtilities.Forms.Controls.TextBoxExtended() Me.TXT_LOG = New PersonalUtilities.Forms.Controls.TextBoxExtended() + Me.BTT_EMAIL = New System.Windows.Forms.Button() + Me.BTT_GITHUB = New System.Windows.Forms.Button() + Me.BTT_COPY = New System.Windows.Forms.Button() + Me.BTT_CANCEL = New System.Windows.Forms.Button() + Me.BTT_ANON = New System.Windows.Forms.Button() Me.TXT_FILES = New PersonalUtilities.Forms.Controls.TextBoxExtended() + Me.TT_MAIN = New System.Windows.Forms.ToolTip(Me.components) TP_MAIN = New System.Windows.Forms.TableLayoutPanel() TP_BUTTONS = New System.Windows.Forms.TableLayoutPanel() TP_MAIN.SuspendLayout() - TP_BUTTONS.SuspendLayout() CType(Me.TXT_DESCR, System.ComponentModel.ISupportInitialize).BeginInit() CType(Me.TXT_URL_PROFILE, System.ComponentModel.ISupportInitialize).BeginInit() CType(Me.TXT_URL_POST, System.ComponentModel.ISupportInitialize).BeginInit() CType(Me.TXT_REPRODUCE, System.ComponentModel.ISupportInitialize).BeginInit() CType(Me.TXT_EXPECT, System.ComponentModel.ISupportInitialize).BeginInit() CType(Me.TXT_LOG, System.ComponentModel.ISupportInitialize).BeginInit() + TP_BUTTONS.SuspendLayout() CType(Me.TXT_FILES, System.ComponentModel.ISupportInitialize).BeginInit() Me.SuspendLayout() ' @@ -88,6 +88,123 @@ Namespace Editors TP_MAIN.Size = New System.Drawing.Size(584, 461) TP_MAIN.TabIndex = 0 ' + 'TXT_DESCR + ' + ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image) + ActionButton1.Dock = System.Windows.Forms.DockStyle.Top + ActionButton1.Name = "Clear" + ActionButton1.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear + Me.TXT_DESCR.Buttons.Add(ActionButton1) + Me.TXT_DESCR.CaptionDock = System.Windows.Forms.DockStyle.Top + Me.TXT_DESCR.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.None + Me.TXT_DESCR.CaptionVisible = False + Me.TXT_DESCR.Dock = System.Windows.Forms.DockStyle.Fill + Me.TXT_DESCR.GroupBoxed = True + Me.TXT_DESCR.GroupBoxText = "Describe the bug or write your message" + Me.TXT_DESCR.Location = New System.Drawing.Point(3, 3) + Me.TXT_DESCR.Multiline = True + Me.TXT_DESCR.Name = "TXT_DESCR" + Me.TXT_DESCR.Size = New System.Drawing.Size(578, 69) + Me.TXT_DESCR.TabIndex = 0 + Me.TXT_DESCR.TextToolTip = "A clear and concise description of what the bug is" + Me.TXT_DESCR.TextToolTipEnabled = True + ' + 'TXT_URL_PROFILE + ' + ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image) + ActionButton2.Name = "Clear" + ActionButton2.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear + Me.TXT_URL_PROFILE.Buttons.Add(ActionButton2) + Me.TXT_URL_PROFILE.CaptionText = "Profile URL" + Me.TXT_URL_PROFILE.CaptionWidth = 75.0R + Me.TXT_URL_PROFILE.Dock = System.Windows.Forms.DockStyle.Fill + Me.TXT_URL_PROFILE.Location = New System.Drawing.Point(3, 78) + Me.TXT_URL_PROFILE.Name = "TXT_URL_PROFILE" + Me.TXT_URL_PROFILE.Size = New System.Drawing.Size(578, 22) + Me.TXT_URL_PROFILE.TabIndex = 1 + ' + 'TXT_URL_POST + ' + ActionButton3.BackgroundImage = CType(resources.GetObject("ActionButton3.BackgroundImage"), System.Drawing.Image) + ActionButton3.Name = "Clear" + ActionButton3.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear + Me.TXT_URL_POST.Buttons.Add(ActionButton3) + Me.TXT_URL_POST.CaptionText = "Post URL" + Me.TXT_URL_POST.CaptionWidth = 75.0R + Me.TXT_URL_POST.Dock = System.Windows.Forms.DockStyle.Fill + Me.TXT_URL_POST.Location = New System.Drawing.Point(3, 106) + Me.TXT_URL_POST.Name = "TXT_URL_POST" + Me.TXT_URL_POST.Size = New System.Drawing.Size(578, 22) + Me.TXT_URL_POST.TabIndex = 2 + ' + 'TXT_REPRODUCE + ' + ActionButton4.BackgroundImage = CType(resources.GetObject("ActionButton4.BackgroundImage"), System.Drawing.Image) + ActionButton4.Dock = System.Windows.Forms.DockStyle.Top + ActionButton4.Name = "Clear" + ActionButton4.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear + Me.TXT_REPRODUCE.Buttons.Add(ActionButton4) + Me.TXT_REPRODUCE.CaptionDock = System.Windows.Forms.DockStyle.Top + Me.TXT_REPRODUCE.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.None + Me.TXT_REPRODUCE.CaptionVisible = False + Me.TXT_REPRODUCE.Dock = System.Windows.Forms.DockStyle.Fill + Me.TXT_REPRODUCE.GroupBoxed = True + Me.TXT_REPRODUCE.GroupBoxText = "Steps to reproduce" + Me.TXT_REPRODUCE.Location = New System.Drawing.Point(3, 134) + Me.TXT_REPRODUCE.Multiline = True + Me.TXT_REPRODUCE.Name = "TXT_REPRODUCE" + Me.TXT_REPRODUCE.Size = New System.Drawing.Size(578, 69) + Me.TXT_REPRODUCE.TabIndex = 3 + Me.TXT_REPRODUCE.TextToolTip = "Steps to reproduce the behavior:" & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "1. Do something" & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "2. See error" + Me.TXT_REPRODUCE.TextToolTipEnabled = True + ' + 'TXT_EXPECT + ' + ActionButton5.BackgroundImage = CType(resources.GetObject("ActionButton5.BackgroundImage"), System.Drawing.Image) + ActionButton5.Dock = System.Windows.Forms.DockStyle.Top + ActionButton5.Name = "Clear" + ActionButton5.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear + Me.TXT_EXPECT.Buttons.Add(ActionButton5) + Me.TXT_EXPECT.CaptionDock = System.Windows.Forms.DockStyle.Top + Me.TXT_EXPECT.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.None + Me.TXT_EXPECT.CaptionVisible = False + Me.TXT_EXPECT.Dock = System.Windows.Forms.DockStyle.Fill + Me.TXT_EXPECT.GroupBoxed = True + Me.TXT_EXPECT.GroupBoxText = "Expected behavior" + Me.TXT_EXPECT.Location = New System.Drawing.Point(3, 209) + Me.TXT_EXPECT.Multiline = True + Me.TXT_EXPECT.Name = "TXT_EXPECT" + Me.TXT_EXPECT.Size = New System.Drawing.Size(578, 69) + Me.TXT_EXPECT.TabIndex = 4 + Me.TXT_EXPECT.TextToolTip = "A clear and concise description of what you expected to happen." + Me.TXT_EXPECT.TextToolTipEnabled = True + ' + 'TXT_LOG + ' + ActionButton6.BackgroundImage = CType(resources.GetObject("ActionButton6.BackgroundImage"), System.Drawing.Image) + ActionButton6.Dock = System.Windows.Forms.DockStyle.Top + ActionButton6.Name = "Open" + ActionButton6.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Open + ActionButton6.ToolTipText = "Select log files to add their text to the message" + ActionButton7.BackgroundImage = CType(resources.GetObject("ActionButton7.BackgroundImage"), System.Drawing.Image) + ActionButton7.Dock = System.Windows.Forms.DockStyle.Top + ActionButton7.Name = "Clear" + ActionButton7.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear + ActionButton7.ToolTipText = "Empty" + Me.TXT_LOG.Buttons.Add(ActionButton6) + Me.TXT_LOG.Buttons.Add(ActionButton7) + Me.TXT_LOG.CaptionDock = System.Windows.Forms.DockStyle.Top + Me.TXT_LOG.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.None + Me.TXT_LOG.CaptionVisible = False + Me.TXT_LOG.Dock = System.Windows.Forms.DockStyle.Fill + Me.TXT_LOG.GroupBoxed = True + Me.TXT_LOG.GroupBoxText = "Log data" + Me.TXT_LOG.Location = New System.Drawing.Point(3, 284) + Me.TXT_LOG.Multiline = True + Me.TXT_LOG.Name = "TXT_LOG" + Me.TXT_LOG.Size = New System.Drawing.Size(578, 69) + Me.TXT_LOG.TabIndex = 5 + ' 'TP_BUTTONS ' TP_BUTTONS.ColumnCount = 6 @@ -119,7 +236,7 @@ Namespace Editors Me.BTT_EMAIL.Name = "BTT_EMAIL" Me.BTT_EMAIL.Size = New System.Drawing.Size(94, 24) Me.BTT_EMAIL.TabIndex = 1 - Me.BTT_EMAIL.Text = "email" + Me.BTT_EMAIL.Text = "Email" Me.TT_MAIN.SetToolTip(Me.BTT_EMAIL, "Create a message to send via email.") Me.BTT_EMAIL.UseVisualStyleBackColor = True ' @@ -167,129 +284,6 @@ Namespace Editors Me.TT_MAIN.SetToolTip(Me.BTT_ANON, resources.GetString("BTT_ANON.ToolTip")) Me.BTT_ANON.UseVisualStyleBackColor = True ' - 'TXT_DESCR - ' - ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image) - ActionButton1.Dock = System.Windows.Forms.DockStyle.Top - ActionButton1.Name = "Clear" - ActionButton1.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear - Me.TXT_DESCR.Buttons.Add(ActionButton1) - Me.TXT_DESCR.CaptionDock = System.Windows.Forms.DockStyle.Top - Me.TXT_DESCR.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.None - Me.TXT_DESCR.CaptionVisible = False - Me.TXT_DESCR.Dock = System.Windows.Forms.DockStyle.Fill - Me.TXT_DESCR.GroupBoxed = True - Me.TXT_DESCR.GroupBoxText = "Describe the bug or write your message" - Me.TXT_DESCR.Lines = New String(-1) {} - Me.TXT_DESCR.Location = New System.Drawing.Point(3, 3) - Me.TXT_DESCR.Multiline = True - Me.TXT_DESCR.Name = "TXT_DESCR" - Me.TXT_DESCR.Size = New System.Drawing.Size(578, 69) - Me.TXT_DESCR.TabIndex = 0 - Me.TXT_DESCR.TextToolTip = "A clear and concise description of what the bug is" - Me.TXT_DESCR.TextToolTipEnabled = True - ' - 'TXT_URL_PROFILE - ' - ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image) - ActionButton2.Name = "Clear" - ActionButton2.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear - Me.TXT_URL_PROFILE.Buttons.Add(ActionButton2) - Me.TXT_URL_PROFILE.CaptionText = "Profile URL" - Me.TXT_URL_PROFILE.CaptionWidth = 75.0R - Me.TXT_URL_PROFILE.Dock = System.Windows.Forms.DockStyle.Fill - Me.TXT_URL_PROFILE.Lines = New String(-1) {} - Me.TXT_URL_PROFILE.Location = New System.Drawing.Point(3, 78) - Me.TXT_URL_PROFILE.Name = "TXT_URL_PROFILE" - Me.TXT_URL_PROFILE.Size = New System.Drawing.Size(578, 22) - Me.TXT_URL_PROFILE.TabIndex = 1 - ' - 'TXT_URL_POST - ' - ActionButton3.BackgroundImage = CType(resources.GetObject("ActionButton3.BackgroundImage"), System.Drawing.Image) - ActionButton3.Name = "Clear" - ActionButton3.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear - Me.TXT_URL_POST.Buttons.Add(ActionButton3) - Me.TXT_URL_POST.CaptionText = "Post URL" - Me.TXT_URL_POST.CaptionWidth = 75.0R - Me.TXT_URL_POST.Dock = System.Windows.Forms.DockStyle.Fill - Me.TXT_URL_POST.Lines = New String(-1) {} - Me.TXT_URL_POST.Location = New System.Drawing.Point(3, 106) - Me.TXT_URL_POST.Name = "TXT_URL_POST" - Me.TXT_URL_POST.Size = New System.Drawing.Size(578, 22) - Me.TXT_URL_POST.TabIndex = 2 - ' - 'TXT_REPRODUCE - ' - ActionButton4.BackgroundImage = CType(resources.GetObject("ActionButton4.BackgroundImage"), System.Drawing.Image) - ActionButton4.Dock = System.Windows.Forms.DockStyle.Top - ActionButton4.Name = "Clear" - ActionButton4.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear - Me.TXT_REPRODUCE.Buttons.Add(ActionButton4) - Me.TXT_REPRODUCE.CaptionDock = System.Windows.Forms.DockStyle.Top - Me.TXT_REPRODUCE.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.None - Me.TXT_REPRODUCE.CaptionVisible = False - Me.TXT_REPRODUCE.Dock = System.Windows.Forms.DockStyle.Fill - Me.TXT_REPRODUCE.GroupBoxed = True - Me.TXT_REPRODUCE.GroupBoxText = "To Reproduce" - Me.TXT_REPRODUCE.Lines = New String(-1) {} - Me.TXT_REPRODUCE.Location = New System.Drawing.Point(3, 134) - Me.TXT_REPRODUCE.Multiline = True - Me.TXT_REPRODUCE.Name = "TXT_REPRODUCE" - Me.TXT_REPRODUCE.Size = New System.Drawing.Size(578, 69) - Me.TXT_REPRODUCE.TabIndex = 3 - Me.TXT_REPRODUCE.TextToolTip = "Steps to reproduce the behavior:" & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "1. Do something" & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "2. See error" - Me.TXT_REPRODUCE.TextToolTipEnabled = True - ' - 'TXT_EXPECT - ' - ActionButton5.BackgroundImage = CType(resources.GetObject("ActionButton5.BackgroundImage"), System.Drawing.Image) - ActionButton5.Dock = System.Windows.Forms.DockStyle.Top - ActionButton5.Name = "Clear" - ActionButton5.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear - Me.TXT_EXPECT.Buttons.Add(ActionButton5) - Me.TXT_EXPECT.CaptionDock = System.Windows.Forms.DockStyle.Top - Me.TXT_EXPECT.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.None - Me.TXT_EXPECT.CaptionVisible = False - Me.TXT_EXPECT.Dock = System.Windows.Forms.DockStyle.Fill - Me.TXT_EXPECT.GroupBoxed = True - Me.TXT_EXPECT.GroupBoxText = "Expected behavior" - Me.TXT_EXPECT.Lines = New String(-1) {} - Me.TXT_EXPECT.Location = New System.Drawing.Point(3, 209) - Me.TXT_EXPECT.Multiline = True - Me.TXT_EXPECT.Name = "TXT_EXPECT" - Me.TXT_EXPECT.Size = New System.Drawing.Size(578, 69) - Me.TXT_EXPECT.TabIndex = 4 - Me.TXT_EXPECT.TextToolTip = "A clear and concise description of what you expected to happen." - Me.TXT_EXPECT.TextToolTipEnabled = True - ' - 'TXT_LOG - ' - ActionButton6.BackgroundImage = CType(resources.GetObject("ActionButton6.BackgroundImage"), System.Drawing.Image) - ActionButton6.Dock = System.Windows.Forms.DockStyle.Top - ActionButton6.Name = "Open" - ActionButton6.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Open - ActionButton6.ToolTipText = "Select log files to add their text to the message" - ActionButton7.BackgroundImage = CType(resources.GetObject("ActionButton7.BackgroundImage"), System.Drawing.Image) - ActionButton7.Dock = System.Windows.Forms.DockStyle.Top - ActionButton7.Name = "Clear" - ActionButton7.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear - ActionButton7.ToolTipText = "Empty" - Me.TXT_LOG.Buttons.Add(ActionButton6) - Me.TXT_LOG.Buttons.Add(ActionButton7) - Me.TXT_LOG.CaptionDock = System.Windows.Forms.DockStyle.Top - Me.TXT_LOG.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.None - Me.TXT_LOG.CaptionVisible = False - Me.TXT_LOG.Dock = System.Windows.Forms.DockStyle.Fill - Me.TXT_LOG.GroupBoxed = True - Me.TXT_LOG.GroupBoxText = "Log data" - Me.TXT_LOG.Lines = New String(-1) {} - Me.TXT_LOG.Location = New System.Drawing.Point(3, 284) - Me.TXT_LOG.Multiline = True - Me.TXT_LOG.Name = "TXT_LOG" - Me.TXT_LOG.Size = New System.Drawing.Size(578, 69) - Me.TXT_LOG.TabIndex = 5 - ' 'TXT_FILES ' ActionButton8.BackgroundImage = CType(resources.GetObject("ActionButton8.BackgroundImage"), System.Drawing.Image) @@ -310,7 +304,6 @@ Namespace Editors Me.TXT_FILES.Dock = System.Windows.Forms.DockStyle.Fill Me.TXT_FILES.GroupBoxed = True Me.TXT_FILES.GroupBoxText = "Files" - Me.TXT_FILES.Lines = New String(-1) {} Me.TXT_FILES.Location = New System.Drawing.Point(3, 359) Me.TXT_FILES.Multiline = True Me.TXT_FILES.Name = "TXT_FILES" @@ -332,13 +325,13 @@ Namespace Editors Me.Name = "BugReporterForm" Me.Text = "New message" TP_MAIN.ResumeLayout(False) - TP_BUTTONS.ResumeLayout(False) CType(Me.TXT_DESCR, System.ComponentModel.ISupportInitialize).EndInit() CType(Me.TXT_URL_PROFILE, System.ComponentModel.ISupportInitialize).EndInit() CType(Me.TXT_URL_POST, System.ComponentModel.ISupportInitialize).EndInit() CType(Me.TXT_REPRODUCE, System.ComponentModel.ISupportInitialize).EndInit() CType(Me.TXT_EXPECT, System.ComponentModel.ISupportInitialize).EndInit() CType(Me.TXT_LOG, System.ComponentModel.ISupportInitialize).EndInit() + TP_BUTTONS.ResumeLayout(False) CType(Me.TXT_FILES, System.ComponentModel.ISupportInitialize).EndInit() Me.ResumeLayout(False) diff --git a/SCrawler.YouTube/Editors/BugReporterForm.resx b/SCrawler.YouTube/Editors/BugReporterForm.resx index 4702b2e..caaa442 100644 --- a/SCrawler.YouTube/Editors/BugReporterForm.resx +++ b/SCrawler.YouTube/Editors/BugReporterForm.resx @@ -124,60 +124,60 @@ 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 - cMaRN0UdBBkAAAAASUVORK5CYII= + wwAADsMBx2+oZAAAARlJREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbWujg3dATZPKYZC6BQhvw1AMkg3dP + XQyl7WIyJIEW5CbS0/jKE5GwpCghgg9s6/8/y5Kj6DA45zcAwAAAezB6rjNnB4XX244NHt8wGs7wblop + yRGxwZQBYKIfbn477EvqusY4jj2MgMpPiwav7l9UyYXmdrs9duzP4ApUmd72sfrxVsD33JQISyClvFUX + w9nJssvJFei9CJUtgQ7394Du3YKLJaCbLMuwqips21ZNuDve/35X8J7nuRcMsVwsbYEQYlSWpRcMMR5P + bAH9fU3TeMEQSZLYgsMpsDRNvXCIr89vWyCEeC6KwguGmL/ObYGU8oFOwA2ewwgYY9f6f7iUf3DGkTcu + khP7AAAAAElFTkSuQmCC iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go - tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX - AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC + xAAADsQBlSsOGwAAAHpJREFUOE+1kVEKgDAMQ3e2/e+MXqpn6W/HxM7SpkIVB4HxSMKiTUTaFwVQ1X25 + DjMfSxskHBYsAxHJkjUjHgrUNMY4peaMPxb03rcZMVhgn2oDKAwn+L0aROH/Cny4NAGFSx8x+10ZDwV2 + gt+LOCxQsw1nPBS8VQBVTTzyhrdZSUm7AAAAAElFTkSuQmCC @@ -195,31 +195,31 @@ If you would like a response from the developer, response, please add your conta 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 \ No newline at end of file diff --git a/SCrawler.YouTube/My Project/AssemblyInfo.vb b/SCrawler.YouTube/My Project/AssemblyInfo.vb index ce03b2e..734a5c0 100644 --- a/SCrawler.YouTube/My Project/AssemblyInfo.vb +++ b/SCrawler.YouTube/My Project/AssemblyInfo.vb @@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices ' by using the '*' as shown below: ' - - + + diff --git a/SCrawler.YouTube/Objects/YouTubeMediaContainerBase.vb b/SCrawler.YouTube/Objects/YouTubeMediaContainerBase.vb index 692f921..19ec98e 100644 --- a/SCrawler.YouTube/Objects/YouTubeMediaContainerBase.vb +++ b/SCrawler.YouTube/Objects/YouTubeMediaContainerBase.vb @@ -116,7 +116,9 @@ Namespace API.YouTube.Objects Public Property IsShorts As Boolean = False Implements IYouTubeMediaContainer.IsShorts Public Property ID As String Implements IYouTubeMediaContainer.ID, IUserMedia.PostID Public Property Title As String Implements IDownloadableMedia.Title - Public Property Description As String Implements IYouTubeMediaContainer.Description + Public Property Description As String Implements IYouTubeMediaContainer.Description, IUserMedia.PostText + Private Property IUserMedia_PostTextFile As String Implements IUserMedia.PostTextFile + Private Property IUserMedia_PostTextFileSpecialFolder As Boolean Implements IUserMedia.PostTextFileSpecialFolder Public Property PlaylistID As String Implements IYouTubeMediaContainer.PlaylistID Public Property PlaylistTitle As String Implements IYouTubeMediaContainer.PlaylistTitle Public Property UserID As String Implements IYouTubeMediaContainer.UserID diff --git a/SCrawler.YouTube/SCrawler.YouTube.vbproj b/SCrawler.YouTube/SCrawler.YouTube.vbproj index 75d3904..9bc194e 100644 --- a/SCrawler.YouTube/SCrawler.YouTube.vbproj +++ b/SCrawler.YouTube/SCrawler.YouTube.vbproj @@ -124,12 +124,19 @@ Form + + FilterForm.vb + + + Form + PlayListParserForm.vb Form + @@ -220,6 +227,9 @@ ChannelTabsChooserForm.vb + + FilterForm.vb + PlayListParserForm.vb diff --git a/SCrawler.YouTubeDownloader/My Project/AssemblyInfo.vb b/SCrawler.YouTubeDownloader/My Project/AssemblyInfo.vb index 0e9e1bc..479d8de 100644 --- a/SCrawler.YouTubeDownloader/My Project/AssemblyInfo.vb +++ b/SCrawler.YouTubeDownloader/My Project/AssemblyInfo.vb @@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices ' by using the '*' as shown below: ' - - + + diff --git a/SCrawler/API/Base/DeclaredNames.vb b/SCrawler/API/Base/DeclaredNames.vb index 456c42b..d057f03 100644 --- a/SCrawler/API/Base/DeclaredNames.vb +++ b/SCrawler/API/Base/DeclaredNames.vb @@ -30,6 +30,13 @@ Namespace API.Base Friend Const UseMD5ComparisonToolTip As String = "Each image will be checked for existence using MD5" Friend Const UserNameChangeCaption As String = "UserName" Friend Const UserNameChangeToolTip As String = "If the user has changed their UserName, you can set a new name here. Not required for new users." + + Friend Const DownloadTextCaption As String = "Download text" + Friend Const DownloadTextTip As String = "Download text (if available) for posts with image and video" & vbCr & "If this checkbox is checked, the post text will be downloaded along with the file and saved under the same name but with the 'txt' extension." + Friend Const DownloadTextPostsCaption As String = "Download text posts" + Friend Const DownloadTextPostsTip As String = "Download text (if available) for text posts (no image and video)" + Friend Const DownloadTextSpecialFolderCaption As String = "Text special folder" + Friend Const DownloadTextSpecialFolderTip As String = "If checked, text files will be saved to a separate folder" Private Sub New() End Sub End Class diff --git a/SCrawler/API/Base/EditorExchangeOptionsBase.vb b/SCrawler/API/Base/EditorExchangeOptionsBase.vb index 19cc411..257cc66 100644 --- a/SCrawler/API/Base/EditorExchangeOptionsBase.vb +++ b/SCrawler/API/Base/EditorExchangeOptionsBase.vb @@ -13,10 +13,34 @@ Namespace API.Base Friend Overridable Property SiteKey As String Friend Overridable Property UserName As String = String.Empty + + Friend Overridable Property DownloadText As Boolean = False + + Friend Overridable Property DownloadTextPosts As Boolean = False + + Friend Overridable Property DownloadTextSpecialFolder As Boolean = False Friend Sub New(ByVal u As UserDataBase) UserName = u.NameTrue(True) + DownloadText = u.DownloadText + DownloadTextPosts = u.DownloadTextPosts + DownloadTextSpecialFolder = u.DownloadTextSpecialFolder + End Sub + Friend Sub New(ByVal s As SiteSettingsBase) + DownloadText = s.DownloadText.Value + DownloadTextPosts = s.DownloadTextPosts.Value + DownloadTextSpecialFolder = s.DownloadTextSpecialFolder.Value End Sub Friend Sub New() End Sub + Protected _ApplyBase_Name As Boolean = True + Protected _ApplyBase_Text As Boolean = True + Friend Sub ApplyBase(ByRef u As UserDataBase) + If _ApplyBase_Name Then u.NameTrue = UserName + If _ApplyBase_Text Then + u.DownloadText = DownloadText + u.DownloadTextPosts = DownloadTextPosts + u.DownloadTextSpecialFolder = DownloadTextSpecialFolder + End If + End Sub End Class End Namespace \ No newline at end of file diff --git a/SCrawler/API/Base/IUserData.vb b/SCrawler/API/Base/IUserData.vb index e72e224..5ac497a 100644 --- a/SCrawler/API/Base/IUserData.vb +++ b/SCrawler/API/Base/IUserData.vb @@ -57,6 +57,7 @@ Namespace API.Base Property FileExists As Boolean Property DownloadedPictures(ByVal Total As Boolean) As Integer Property DownloadedVideos(ByVal Total As Boolean) As Integer + Property DownloadedTexts(ByVal Total As Boolean) As Integer ReadOnly Property DownloadedTotal(Optional ByVal Total As Boolean = True) As Integer ReadOnly Property DownloadedInformation As String Property HasError As Boolean diff --git a/SCrawler/API/Base/SiteSettingsBase.vb b/SCrawler/API/Base/SiteSettingsBase.vb index 56b2eaa..c058825 100644 --- a/SCrawler/API/Base/SiteSettingsBase.vb +++ b/SCrawler/API/Base/SiteSettingsBase.vb @@ -14,6 +14,7 @@ Imports PersonalUtilities.Tools.Web.Cookies Imports PersonalUtilities.Tools.Web.Clients Imports PersonalUtilities.Functions.RegularExpressions Imports Download = SCrawler.Plugin.ISiteSettings.Download +Imports DN = SCrawler.API.Base.DeclaredNames Namespace API.Base Friend MustInherit Class SiteSettingsBase : Implements ISiteSettings, IResponserContainer #Region "Declarations" @@ -69,6 +70,14 @@ Namespace API.Base _UserOptionsExists = Not t Is Nothing End Set End Property +#Region "New user defaults" + + Friend Overridable Property DownloadText As PropertyValue + + Friend Overridable Property DownloadTextPosts As PropertyValue + + Friend Overridable Property DownloadTextSpecialFolder As PropertyValue +#End Region #End Region #Region "EnvironmentPrograms" Private Property CMDEncoding As String Implements ISiteSettings.CMDEncoding @@ -124,6 +133,9 @@ Namespace API.Base _Image = __Image Responser = New Responser With {.DeclaredError = EDP.ThrowException} SettingsVersion = New PropertyValue(0) + DownloadText = New PropertyValue(False) + DownloadTextPosts = New PropertyValue(False) + DownloadTextSpecialFolder = New PropertyValue(True) UpdateResponserFile() End Sub Friend Sub New(ByVal SiteName As String, ByVal CookiesDomain As String, ByVal AccName As String, ByVal Temp As Boolean, diff --git a/SCrawler/API/Base/Structures.vb b/SCrawler/API/Base/Structures.vb index e8fdb6e..c8257e5 100644 --- a/SCrawler/API/Base/Structures.vb +++ b/SCrawler/API/Base/Structures.vb @@ -32,6 +32,8 @@ Namespace API.Base Private Const Name_MediaPostID As String = "ID" Private Const Name_MediaPostDate As String = "Date" Private Const Name_SpecialFolder As String = "SpecialFolder" + Private Const Name_PostTextFile As String = "PostTextFile" + Private Const Name_PostTextFileSpecialFolder As String = "PostTextFileSpecialFolder" #End Region Friend Enum Types As Integer Undefined = 0 @@ -46,12 +48,25 @@ Namespace API.Base End Enum Friend Enum States As Integer : Unknown = 0 : Tried = 1 : Downloaded = 2 : Skipped = 3 : Missing = 4 : End Enum Friend [Type] As Types + Friend ReadOnly Property IsVideoType As Boolean + Get + Return Type = Types.m3u8 Or Type = Types.Video Or Type = Types.VideoPre + End Get + End Property + Friend ReadOnly Property IsAudioType As Boolean + Get + Return Type = Types.Audio Or Type = Types.AudioPre + End Get + End Property Friend URL_BASE As String Friend URL As String Friend MD5 As String Friend [File] As SFile Friend Post As UserPost Friend PictureOption As String + Friend PostText As String + Friend PostTextFile As SFile + Friend PostTextFileSpecialFolder As Boolean Friend State As States Friend Attempts As Integer ''' @@ -125,6 +140,30 @@ Namespace API.Base Post = New UserPost(Post.ID, PostDate) End Set End Property + Private Property IUserMedia_PostText As String Implements IUserMedia.PostText + Get + Return PostText + End Get + Set(ByVal NewText As String) + PostText = NewText + End Set + End Property + Private Property IUserMedia_PostTextFile As String Implements IUserMedia.PostTextFile + Get + Return PostTextFile.ToString + End Get + Set(ByVal NewPostFile As String) + If Not NewPostFile.IsEmptyString Then PostTextFile = New SFile(NewPostFile) Else PostTextFile = Nothing + End Set + End Property + Private Property IUserMedia_PostTextFileSpecialFolder As Boolean Implements IUserMedia.PostTextFileSpecialFolder + Get + Return PostTextFileSpecialFolder + End Get + Set(ByVal IsSpecialFolder As Boolean) + PostTextFileSpecialFolder = IsSpecialFolder + End Set + End Property Private Property IUserMedia_SpecialFolder As String Implements IUserMedia.SpecialFolder Get Return SpecialFolder @@ -171,6 +210,9 @@ Namespace API.Base SpecialFolder = m.SpecialFolder Attempts = m.Attempts Me.Object = m.Object + PostText = m.PostText + PostTextFile = m.PostTextFile + PostTextFileSpecialFolder = m.PostTextFileSpecialFolder End Sub Friend Sub New(ByVal e As EContainer, ByVal UserInstance As IUserData) Type = e.Attribute(Name_MediaType).Value.FromXML(Of Integer)(CInt(Types.Undefined)) @@ -180,6 +222,8 @@ Namespace API.Base URL_BASE = e.Value MD5 = e.Attribute(Name_MediaHash).Value File = e.Attribute(Name_MediaFile).Value + PostTextFile = e.Attribute(Name_PostTextFile).Value + PostTextFileSpecialFolder = e.Attribute(Name_PostTextFileSpecialFolder).Value.FromXML(Of Boolean)(False) Dim vp As Boolean? = Nothing Dim upath$ = String.Empty @@ -194,7 +238,13 @@ Namespace API.Base SpecialFolder = e.Attribute(Name_SpecialFolder).Value If Not SpecialFolder.IsEmptyString Then upath &= $"{SpecialFolder}\" If vp.HasValue AndAlso vp.Value Then upath &= $"Video\" - If Not upath.IsEmptyString Then File = $"{upath.CSFilePS}{File.File}" + If Not upath.IsEmptyString Then + File = $"{upath.CSFilePS}{File.File}" + If Not PostTextFile.IsEmptyString Then + PostTextFile = $"{upath.CSFilePS}{IIf(PostTextFileSpecialFolder, $"{UserDataBase.PostTextSpecialFolderDefault}\", String.Empty)}{PostTextFile.File}" + If Type = Types.Text Then File = PostTextFile + End If + End If Post = New UserPost With { .ID = e.Attribute(Name_MediaPostID).Value, @@ -234,7 +284,9 @@ Namespace API.Base New EAttribute(Name_MediaURL, URL), New EAttribute(Name_MediaHash, MD5), New EAttribute(Name_MediaFile, File.File), + New EAttribute(Name_PostTextFile, PostTextFile.File), New EAttribute(Name_SpecialFolder, SpecialFolder), + New EAttribute(Name_PostTextFileSpecialFolder, PostTextFileSpecialFolder.BoolToInteger), New EAttribute(Name_MediaPostID, Post.ID), New EAttribute(Name_MediaPostDate, AConvert(Of String)(Post.Date, DateTimeDefaultProvider, String.Empty)) } diff --git a/SCrawler/API/Base/UserDataBase.vb b/SCrawler/API/Base/UserDataBase.vb index 1c00259..4664970 100644 --- a/SCrawler/API/Base/UserDataBase.vb +++ b/SCrawler/API/Base/UserDataBase.vb @@ -27,6 +27,7 @@ Imports CookieUpdateModes = PersonalUtilities.Tools.Web.Cookies.CookieKeeper.Upd Namespace API.Base Friend MustInherit Class UserDataBase : Implements IUserData, IPluginContentProvider, IThrower Friend Const UserFileAppender As String = "User" + Friend Const PostTextSpecialFolderDefault As String = "txt" #Region "Events" Private ReadOnly UserUpdatedEventHandlers As List(Of IUserData.UserUpdatedEventHandler) Friend Custom Event UserUpdated As IUserData.UserUpdatedEventHandler Implements IUserData.UserUpdated @@ -152,6 +153,9 @@ Namespace API.Base Private Const Name_IsSubscription As String = UserInfo.Name_IsSubscription Private Const Name_Temporary As String = "Temporary" Private Const Name_Favorite As String = "Favorite" + Private Const Name_DownloadText As String = "DownloadText" + Private Const Name_DownloadTextPosts As String = "DownloadTextPosts" + Private Const Name_DownloadTextSpecialFolder As String = "DownloadTextSpecialFolder" Private Const Name_BackColor As String = "BackColor" Private Const Name_ForeColor As String = "ForeColor" Private Const Name_CreatedByChannel As String = "CreatedByChannel" @@ -167,6 +171,7 @@ Namespace API.Base Private Const Name_VideoCount As String = "VideoCount" Private Const Name_PicturesCount As String = "PicturesCount" + Private Const Name_TextCount As String = "TextCount" Private Const Name_LastUpdated As String = "LastUpdated" Private Const Name_ScriptUse As String = "ScriptUse" @@ -639,6 +644,9 @@ BlockNullPicture: 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 + Friend Overridable Property DownloadText As Boolean = False + Friend Overridable Property DownloadTextPosts As Boolean = False + Friend Overridable Property DownloadTextSpecialFolder As Boolean = True Friend Property DownloadMissingOnly As Boolean = False Implements IUserData.DownloadMissingOnly Private _IconBannerDownloaded As Boolean = False Friend WriteOnly Property IconBannerDownloaded As Boolean @@ -750,9 +758,23 @@ BlockNullPicture: End If End Set End Property + Private _DownloadedTextsTotal As Integer = 0 + Private _DownloadedTextsSession As Integer = 0 + Friend Property DownloadedTexts(ByVal Total As Boolean) As Integer Implements IUserData.DownloadedTexts + Get + Return IIf(Total, _DownloadedTextsTotal, _DownloadedTextsSession) + End Get + Set(ByVal NewValue As Integer) + If Total Then + _DownloadedTextsTotal = NewValue + Else + _DownloadedTextsSession = NewValue + End If + End Set + End Property Friend Overridable ReadOnly Property DownloadedTotal(Optional ByVal Total As Boolean = True) As Integer Implements IUserData.DownloadedTotal Get - Return DownloadedPictures(Total) + DownloadedVideos(Total) + Return DownloadedPictures(Total) + DownloadedVideos(Total) + DownloadedTexts(Total) End Get End Property Friend ReadOnly Property DownloadedInformation As String Implements IUserData.DownloadedInformation @@ -963,9 +985,13 @@ BlockNullPicture: ReadyForDownload = x.Value(Name_ReadyForDownload).FromXML(Of Boolean)(True) DownloadImages = x.Value(Name_DownloadImages).FromXML(Of Boolean)(True) DownloadVideos = x.Value(Name_DownloadVideos).FromXML(Of Boolean)(True) + DownloadText = x.Value(Name_DownloadText).FromXML(Of Boolean)(False) + DownloadTextPosts = x.Value(Name_DownloadTextPosts).FromXML(Of Boolean)(False) + DownloadTextSpecialFolder = x.Value(Name_DownloadTextSpecialFolder).FromXML(Of Boolean)(True) _IconBannerDownloaded = x.Value(Name_IconBannerDownloaded).FromXML(Of Boolean)(False) DownloadedVideos(True) = x.Value(Name_VideoCount).FromXML(Of Integer)(0) DownloadedPictures(True) = x.Value(Name_PicturesCount).FromXML(Of Integer)(0) + DownloadedTexts(True) = x.Value(Name_TextCount).FromXML(Of Integer)(0) LastUpdated = AConvert(Of Date)(x.Value(Name_LastUpdated), ADateTime.Formats.BaseDateTime, Nothing) ScriptUse = x.Value(Name_ScriptUse).FromXML(Of Boolean)(False) ScriptData = x.Value(Name_ScriptData) @@ -1025,9 +1051,13 @@ BlockNullPicture: x.Add(Name_ReadyForDownload, ReadyForDownload.BoolToInteger) x.Add(Name_DownloadImages, DownloadImages.BoolToInteger) x.Add(Name_DownloadVideos, DownloadVideos.BoolToInteger) + x.Add(Name_DownloadText, DownloadText.BoolToInteger) + x.Add(Name_DownloadTextPosts, DownloadTextPosts.BoolToInteger) + x.Add(Name_DownloadTextSpecialFolder, DownloadTextSpecialFolder.BoolToInteger) x.Add(Name_IconBannerDownloaded, _IconBannerDownloaded.BoolToInteger) x.Add(Name_VideoCount, DownloadedVideos(True)) x.Add(Name_PicturesCount, DownloadedPictures(True)) + x.Add(Name_TextCount, DownloadedTexts(True)) x.Add(Name_LastUpdated, AConvert(Of String)(LastUpdated, ADateTime.Formats.BaseDateTime, String.Empty)) x.Add(Name_ScriptUse, ScriptUse.BoolToInteger) x.Add(Name_ScriptData, ScriptData) @@ -1246,6 +1276,7 @@ BlockNullPicture: If Not DownloadImages Then _TempMediaList.RemoveAll(Function(m) m.Type = UTypes.GIF Or m.Type = UTypes.Picture) If Not DownloadVideos Then _TempMediaList.RemoveAll(Function(m) m.Type = UTypes.Video Or m.Type = UTypes.VideoPre Or m.Type = UTypes.m3u8) + If Not DownloadTextPosts Then _TempMediaList.RemoveAll(Function(m) m.Type = UTypes.Text) If DownloadMissingOnly Then _TempMediaList.RemoveAll(Function(m) Not m.State = UStates.Missing) End If @@ -1659,7 +1690,8 @@ BlockNullPicture: Dim dCount% = 0, dTotal% = 0 ThrowAny(Token) If _ContentNew.Count > 0 Then - _ContentNew.RemoveAll(Function(c) c.URL.IsEmptyString) + _ContentNew.RemoveAll(Function(c) Not c.Type = UTypes.Text And c.URL.IsEmptyString) + If Not DownloadText Or Not DownloadTextPosts Then _ContentNew.RemoveAll(Function(c) c.Type = UTypes.Text) If _ContentNew.Count > 0 Then If UseMD5Comparison Then LoadMD5() MyFile.Exists(SFO.Path) @@ -1668,7 +1700,7 @@ BlockNullPicture: Dim vsf As Boolean = SeparateVideoFolderF Dim __isVideo As Boolean Dim __interrupt As Boolean - Dim f As SFile + Dim f As SFile, fTxt As SFile Dim v As UserMedia Dim __fileDeleted As Boolean Dim fileNumProvider As SFileNumbers = SFileNumbers.Default @@ -1682,18 +1714,20 @@ BlockNullPicture: ErrorsDescriber.Execute(EDP.SendToLog, file_del_ex) End Try End Sub - Dim updateDownCount As Action = Sub() - Dim __n% = IIf(__fileDeleted, -1, 1) - If __isVideo Then - v.Type = UTypes.Video - DownloadedVideos(False) += __n - ElseIf v.Type = UTypes.GIF Then - DownloadedPictures(False) += __n - Else - v.Type = UTypes.Picture - DownloadedPictures(False) += __n - End If - End Sub + Dim updateDownCount As Action(Of Boolean) = Sub(ByVal forceText As Boolean) + Dim __n% = IIf(__fileDeleted And Not forceText, -1, 1) + If v.Type = UTypes.Text Or forceText Then + DownloadedTexts(False) += __n + ElseIf __isVideo Then + v.Type = UTypes.Video + DownloadedVideos(False) += __n + ElseIf v.Type = UTypes.GIF Then + DownloadedPictures(False) += __n + Else + v.Type = UTypes.Picture + DownloadedPictures(False) += __n + End If + End Sub Using w As New OptionalWebClient(Me) If vsf Then CSFileP($"{MyDir}\{VideoFolderName}\").Exists(SFO.Path) @@ -1726,8 +1760,9 @@ BlockNullPicture: __fileDeleted = False - If Not f.IsEmptyString And Not v.URL.IsEmptyString Then + If (v.Type = UTypes.Text And DownloadText) Or (Not f.IsEmptyString And Not v.URL.IsEmptyString) Then Try + If v.Type = UTypes.Text Then GoTo stxt __isVideo = v.Type = UTypes.Video Or f.Extension = "mp4" Or v.Type = UTypes.m3u8 If f.Extension.IsEmptyString Then @@ -1770,7 +1805,7 @@ BlockNullPicture: End If End If - updateDownCount() + updateDownCount(False) v.File = ChangeFileNameByProvider(f, v) v.State = UStates.Downloaded @@ -1781,7 +1816,7 @@ BlockNullPicture: If Not v.MD5.IsEmptyString Then If _MD5List.Contains(v.MD5) Then __fileDeleted = v.File.Delete(SFO.File, SFODelete.DeletePermanently, EDP.ReturnValue) - If __fileDeleted Then dCount -= 1 : updateDownCount() + If __fileDeleted Then dCount -= 1 : updateDownCount(False) Else _MD5List.Add(v.MD5) End If @@ -1790,7 +1825,33 @@ BlockNullPicture: dCount -= 1 End If End If +stxt: + If DownloadText And Not v.PostText.IsEmptyString And (v.Type = UTypes.Text Or v.File.Exists) Then + fTxt = v.File + If fTxt.IsEmptyString Then + If DownloadTextPosts And Not f.IsEmptyString Then + fTxt = f + If v.Type = UTypes.Text Then fTxt.Name &= IIf(fTxt.Name.IsEmptyString, String.Empty, "_") & + v.Post.ID.StringRemoveWinForbiddenSymbols + If fTxt.IsEmptyString Then Throw New ArgumentNullException("Text", "Error downloading text") With {.HelpLink = 10} + Else + Continue For + End If + End If + v.PostTextFileSpecialFolder = DownloadTextSpecialFolder + If DownloadTextSpecialFolder Then fTxt.Path = $"{fTxt.Path.StringTrimEnd("\")}\{PostTextSpecialFolderDefault}" + fTxt.Extension = "txt" + v.PostTextFile = TextSaver.SaveTextToFile(v.PostText, fTxt,,, Settings.FeedShowTextPosts_LogErrors_E) + If Not v.PostTextFile.Exists Then Throw New ArgumentNullException("Text", "Error downloading text") With {.HelpLink = 10} + If v.Type = UTypes.Text Then v.File = v.PostTextFile + v.State = UStates.Downloaded + updateDownCount(Not v.Type = UTypes.Text) + If v.URL.IsEmptyString Then v.URL = v.PostTextFile.File + If v.URL_BASE.IsEmptyString Then v.URL_BASE = v.URL + End If dCount += 1 + Catch anex As ArgumentNullException When anex.HelpLink = 10 + LogError(anex, anex.Message, Settings.FeedShowTextPosts_LogErrors_E) Catch woex As OperationCanceledException When Token.IsCancellationRequested __deleteFile.Invoke(f, v.URL_BASE) v.State = UStates.Missing @@ -1798,7 +1859,7 @@ BlockNullPicture: _ContentNew(i) = v Throw woex Catch wex As Exception - If DownloadContentDefault_ProcessDownloadException() Then + If Not v.Type = UTypes.Text AndAlso DownloadContentDefault_ProcessDownloadException() Then v.Attempts += 1 v.State = UStates.Missing If MissingErrorsAdd Then ErrorDownloading(f, v.URL) @@ -1991,7 +2052,7 @@ BlockNullPicture: End If If m.Contains(IUserData.EraseMode.Data) Then Dim files As List(Of SFile) = SFile.GetFiles(DownloadContentDefault_GetRootDir.CSFileP,, SearchOption.AllDirectories, e) - If files.ListExists Then files.RemoveAll(Function(f) Not f.Extension.IsEmptyString AndAlso (f.Extension = "txt" Or f.Extension = "xml")) + If files.ListExists Then files.RemoveAll(Function(f) Not f.Extension.IsEmptyString AndAlso ((f.Path.EndsWith(SettingsFolderName) And f.Extension = "txt") Or f.Extension = "xml")) If files.ListExists Then files.ForEach(Sub(f) f.Delete(SFO.File, Settings.DeleteMode, e)) LatestData.Clear() result = True @@ -2234,6 +2295,17 @@ BlockNullPicture: Friend Function ToStringForLog() As String Return $"{IIf(IncludedInCollection, $"[{CollectionName}] - ", String.Empty)}[{Site}] - {Name}" End Function + Friend Overloads Function ToStringExt(ByVal UseFriendlyName As Boolean) As String + Return $"{IIf(IncludedInCollection, $"[{CollectionName}] - ", String.Empty)}[{Site}] - {String.Format(CStr(IIf(Not FriendlyName.IsEmptyString And + UseFriendlyName, "{1} ({0})", "{0}")), Name, FriendlyName)}" + End Function + Friend Overloads Shared Function ToStringExt(ByVal User As UserInfo) As String + If Not IsDBNull(User) Then + With User : Return $"{IIf(.IncludedInCollection, $"[{ .CollectionName}] - ", String.Empty)}[{ .Site}] - { .Name}" : End With + Else + Return String.Empty + End If + End Function Public Overrides Function ToString() As String If IsCollection Then Return CollectionName diff --git a/SCrawler/API/Bluesky/UserData.vb b/SCrawler/API/Bluesky/UserData.vb index 2fcc8c9..4da8013 100644 --- a/SCrawler/API/Bluesky/UserData.vb +++ b/SCrawler/API/Bluesky/UserData.vb @@ -36,7 +36,7 @@ Namespace API.Bluesky End Function Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object) If Not Obj Is Nothing AndAlso TypeOf Obj Is EditorExchangeOptionsBase AndAlso - DirectCast(Obj, EditorExchangeOptionsBase).SiteKey = BlueskySiteKey Then NameTrue = DirectCast(Obj, EditorExchangeOptionsBase).UserName + DirectCast(Obj, EditorExchangeOptionsBase).SiteKey = BlueskySiteKey Then DirectCast(Obj, EditorExchangeOptionsBase).ApplyBase(Me) End Sub #End Region #Region "Initializer" @@ -117,7 +117,7 @@ Namespace API.Bluesky Private Function DefaultParser(ByVal e As EContainer, Optional ByVal CheckDateLimits As Boolean = True, Optional ByRef NextCursor As String = Nothing, Optional ByVal CheckTempPosts As Boolean = True, Optional ByVal State As UStates = UStates.Unknown) As Integer Const exitReturn% = CInt(DateResult.Exit) * -1 - Dim postID$, postDate$, __url$, __urlBase$ + Dim postID$, postDate$, __url$, __urlBase$, __txt$ Dim updateUrl As Boolean Dim c% = 0 Dim m As UserMedia @@ -127,6 +127,7 @@ Namespace API.Bluesky postID = GetPostID(.Value("uri")) postDate = String.Empty __urlBase = String.Empty + __txt = String.Empty With .Item({"record"}) If .ListExists Then '2025-01-28T02:42:12.415Z @@ -152,13 +153,18 @@ Namespace API.Bluesky .URL_BASE = __urlBase, .File = CreateFileFromUrl(url, type), .Post = New UserPost(postID, If(AConvert(Of Date)(postDate, DateProvider, Nothing, EDP.ReturnValue), Nothing)), - .State = State + .State = State, + .PostText = __txt, + .PostTextFileSpecialFolder = DownloadTextSpecialFolder } + If type = UTypes.Text Then m.PostTextFile = $"{postID}.txt" _TempMediaList.ListAddValue(m, LNC) c += 1 Return m End Function + __txt = .Value({"record"}, "text").IfNullOrEmpty(__txt) + For Each SecondExtraction As Boolean In {False, True} With If(SecondExtraction, .Item({"record", "embed"}), .Item("embed")) If .ListExists Then @@ -177,8 +183,15 @@ Namespace API.Bluesky If Not .Value("playlist").IsEmptyString Then createMedia(.Value("playlist"), UTypes.m3u8) - If If(.Item("external")?.Count, 0) > 0 Then createMedia(.Value({"external"}, "uri"), UTypes.GIF) + If If(.Item("external")?.Count, 0) > 0 Then + __txt = .Value({"external"}, "title").IfNullOrEmpty(__txt) + createMedia(.Value({"external"}, "uri"), UTypes.GIF) + End If + If If(.Item({"media"}, "external")?.Count, 0) > 0 Then + __txt = .Value({"media", "external"}, "title").IfNullOrEmpty(__txt) + createMedia(.Value({"media", "external"}, "uri"), UTypes.GIF) + End If End If End With diff --git a/SCrawler/API/Facebook/SiteSettings.vb b/SCrawler/API/Facebook/SiteSettings.vb index b443cc0..796575d 100644 --- a/SCrawler/API/Facebook/SiteSettings.vb +++ b/SCrawler/API/Facebook/SiteSettings.vb @@ -40,6 +40,9 @@ Namespace API.Facebook Friend ReadOnly Property ParseReelsBlock As PropertyValue Friend ReadOnly Property ParseStoriesBlock As PropertyValue + Friend Overrides Property DownloadText As PropertyValue + Friend Overrides Property DownloadTextPosts As PropertyValue + Friend Overrides Property DownloadTextSpecialFolder As PropertyValue #End Region #End Region #Region "Initializer" diff --git a/SCrawler/API/Instagram/EditorExchangeOptions.vb b/SCrawler/API/Instagram/EditorExchangeOptions.vb index d9582bd..eaa4523 100644 --- a/SCrawler/API/Instagram/EditorExchangeOptions.vb +++ b/SCrawler/API/Instagram/EditorExchangeOptions.vb @@ -62,6 +62,7 @@ Namespace API.Instagram End With End Sub Friend Sub New(ByVal s As SiteSettings) + MyBase.New(s) With s GetTimeline = CBool(.GetTimeline.Value) GetReels = CBool(.GetReels.Value) diff --git a/SCrawler/API/Instagram/SiteSettings.vb b/SCrawler/API/Instagram/SiteSettings.vb index 4d79436..4b4c836 100644 --- a/SCrawler/API/Instagram/SiteSettings.vb +++ b/SCrawler/API/Instagram/SiteSettings.vb @@ -196,6 +196,18 @@ Namespace API.Instagram Friend ReadOnly Property SleepTimerOnPostsLimit As PropertyValue Private ReadOnly Property SleepTimerOnPostsLimitProvider As IFormatProvider + + Friend ReadOnly Property SleepTimerRequestsNextProfile As PropertyValue + Friend ReadOnly Property SleepTimerRequestsNextProfileMax As Integer + Get + Return {RequestsWaitTimer_Any, RequestsWaitTimer, SleepTimerOnPostsLimit}.Max(Function(obj) CInt(obj.Value)) + End Get + End Property + + Private ReadOnly Property SleepTimerRequestsNextProfileProvider As IFormatProvider #End Region #Region "New user defaults" @@ -493,6 +505,8 @@ Namespace API.Instagram RequestsWaitTimerTaskCountProvider = New TimersChecker(1) SleepTimerOnPostsLimit = New PropertyValue(60000) SleepTimerOnPostsLimitProvider = New TimersChecker(10000) + SleepTimerRequestsNextProfile = New PropertyValue(-2) + SleepTimerRequestsNextProfileProvider = New TimersChecker(-2) GetTimeline = New PropertyValue(True) GetTimeline_VideoPic = New PropertyValue(True) @@ -579,6 +593,7 @@ Namespace API.Instagram MDD.Reset() If ActiveSessionRequestsExists Then RefreshMyLastRequests(Now) ActiveSessionRequestsExists = False + ActiveSessionLastProfileRequests = False _NextWNM = UserData.WNM.Notify _NextTagged = True SkipUntilNextSession = False @@ -596,6 +611,7 @@ Namespace API.Instagram Private ActiveJobs As Integer = 0 Private ActiveSessionDate As Date Private ActiveSessionRequestsExists As Boolean = False + Friend ActiveSessionLastProfileRequests As Boolean = False Private _NextWNM As UserData.WNM = UserData.WNM.Notify Private _NextTagged As Boolean = True Friend Overrides Sub DownloadStarted(ByVal What As Download) @@ -632,6 +648,7 @@ Namespace API.Instagram _NextWNM = .WaitNotificationMode If _NextWNM = UserData.WNM.SkipTemp Or _NextWNM = UserData.WNM.SkipCurrent Then _NextWNM = UserData.WNM.Notify _NextTagged = .TaggedCheckSession + If MyLastRequestsCount <> .RequestsCountSession Then ActiveSessionLastProfileRequests = True MyLastRequestsCount = .RequestsCountSession If .RequestsCountSession > 0 Then ActiveSessionRequestsExists = True _FieldsChangerSuspended = True diff --git a/SCrawler/API/Instagram/UserData.vb b/SCrawler/API/Instagram/UserData.vb index 8200210..6a6575b 100644 --- a/SCrawler/API/Instagram/UserData.vb +++ b/SCrawler/API/Instagram/UserData.vb @@ -164,6 +164,7 @@ Namespace API.Instagram Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object) If Not Obj Is Nothing AndAlso TypeOf Obj Is EditorExchangeOptions Then With DirectCast(Obj, EditorExchangeOptions) + .ApplyBase(Me) GetTimeline = .GetTimeline GetReels = .GetReels GetStories = .GetStories @@ -178,7 +179,6 @@ Namespace API.Instagram PutImageVideoFolder = .PutImageVideoFolder - NameTrue = .UserName ForceUpdateUserName = .ForceUpdateUserName ForceUpdateUserInfo = .ForceUpdateUserInfo End With @@ -385,6 +385,20 @@ Namespace API.Instagram Dim s As Sections = Sections.Timeline Dim errorFound As Boolean = False + Dim firstWait As Boolean = False + Dim __firstWait As Action = Sub() + With MySiteSettings + If Not firstWait And .ActiveSessionLastProfileRequests And CInt(.SleepTimerRequestsNextProfile.Value) <> -1 Then + Dim ____v% = 0 + If CInt(.SleepTimerRequestsNextProfile.Value) = -2 Then + ____v = .SleepTimerRequestsNextProfileMax + Else + ____v = CInt(.SleepTimerRequestsNextProfile.Value) + End If + If ____v > 0 Then firstWait = True : Thread.Sleep(____v) + End If + End With + End Sub Try Err5xx = -1 ErrHandling = -1 @@ -401,6 +415,7 @@ Namespace API.Instagram If dt.Invoke And Not LastCursor.IsEmptyString Then s = IIf(IsSavedPosts, Sections.SavedPosts, Sections.Timeline) upClaimRequest.Invoke + __firstWait.Invoke DownloadData(LastCursor, s, Token) ProgressPre.Done() ThrowAny(Token) @@ -410,6 +425,7 @@ Namespace API.Instagram s = IIf(IsSavedPosts, Sections.SavedPosts, Sections.Timeline) upClaimRequest.Invoke ChangeResponserMode(_UseGQL) + __firstWait.Invoke DownloadData(String.Empty, s, Token) ProgressPre.Done() ThrowAny(Token) @@ -425,6 +441,7 @@ Namespace API.Instagram DefaultParser_ElemNode = {"node", "media"} upClaimRequest.Invoke ChangeResponserMode(True) + __firstWait.Invoke DownloadData(String.Empty, s, Token) GetReelsGQL_SetEnvir = False ProgressPre.Done() @@ -434,6 +451,7 @@ Namespace API.Instagram If CBool(MySiteSettings.DownloadStories.Value) And GetStories Then s = Sections.Stories upClaimRequest.Invoke + __firstWait.Invoke DownloadData(String.Empty, s, Token) ProgressPre.Done() End If @@ -442,6 +460,7 @@ Namespace API.Instagram If CBool(MySiteSettings.DownloadStoriesUser.Value) And GetStoriesUser Then s = Sections.UserStories upClaimRequest.Invoke + __firstWait.Invoke DownloadData(String.Empty, s, Token) ProgressPre.Done() End If @@ -450,6 +469,7 @@ Namespace API.Instagram If CBool(MySiteSettings.DownloadTagged.Value) And GetTaggedData Then s = Sections.Tagged upClaimRequest.Invoke + __firstWait.Invoke DownloadData(String.Empty, s, Token) ProgressPre.Done() DefaultParser_ElemNode = Nothing @@ -968,10 +988,12 @@ NextPageBlock: Dim PostIDKV As PostKV Dim Pinned As Boolean Dim PostDate$, PostOriginUrl$ + Dim PostText$ = String.Empty Dim i%, before% Dim usePinFunc As Boolean = Not DefaultParser_Pinned Is Nothing Dim skipPostFuncExists As Boolean = Not DefaultParser_SkipPost Is Nothing Dim nn As EContainer + Dim textMedia As UserMedia If SpecFolder.IsEmptyString Then Select Case Section Case Sections.Tagged : SpecFolder = TaggedFolder @@ -1006,9 +1028,17 @@ NextPageBlock: Case DateResult.Exit : If Not Pinned Then Return False End Select End If + If DownloadTextPosts Then PostText = DefaultParser_GetCaption(.Self) before = _TempMediaList.Count - ObtainMedia(.Self, PostIDKV.ID, SpecFolder, PostDate,, PostOriginUrl, State, Attempts,, Section) - If Not before = _TempMediaList.Count Then _TotalPostsParsed += 1 + ObtainMedia(.Self, PostIDKV.ID, SpecFolder, PostDate,, PostOriginUrl, State, Attempts,, Section, PostText) + If Not before = _TempMediaList.Count Then + _TotalPostsParsed += 1 + ElseIf DownloadTextPosts And DownloadText And Not PostText.IsEmptyString Then + textMedia = MediaFromData(UTypes.Text, PostIDKV.ID, PostIDKV.ID, PostDate, SpecFolder, PostOriginUrl, State, Attempts, PostText) + textMedia.URL = PostIDKV.ID + textMedia.PostTextFile = $"{PostIDKV.ID}.txt" + _TempMediaList.ListAddValue(textMedia, LNC) + End If If _Limit > 0 And _TotalPostsParsed >= _Limit Then Return False End If Else @@ -1021,6 +1051,9 @@ NextPageBlock: Return False End If End Function + Protected Overridable Function DefaultParser_GetCaption(ByVal e As EContainer) As String + Return e.Value({"caption"}, "text") + End Function #End Region #Region "Code ID converters" Protected Function CodeToID(ByVal Code As String) As String @@ -1069,7 +1102,8 @@ NextPageBlock: Optional ByVal PostOriginUrl As String = Nothing, Optional ByVal State As UStates = UStates.Unknown, Optional ByVal Attempts As Integer = 0, Optional ByVal TryExtractImage As Boolean = False, - Optional ByVal Section As Sections = ObtainMedia_NoSection) + Optional ByVal Section As Sections = ObtainMedia_NoSection, + Optional ByVal Text As String = Nothing) Try Dim maxSize As Func(Of EContainer, Integer) = Function(ByVal _ss As EContainer) As Integer Dim w% = AConvert(Of Integer)(_ss.Value("width"), 0) @@ -1104,6 +1138,7 @@ NextPageBlock: End Function If Not ObtainMedia_SizeFuncVid Is Nothing Then ssVid = ObtainMedia_SizeFuncVid If Not ObtainMedia_SizeFuncPic Is Nothing Then ssPic = ObtainMedia_SizeFuncPic + If DownloadTextPosts And Text.IsEmptyString Then Text = DefaultParser_GetCaption(n) If n.Count > 0 Then Dim l As New List(Of Sizes) Dim d As EContainer @@ -1145,7 +1180,7 @@ NextPageBlock: If l.Count > 0 Then l.RemoveAll(wrongData) If l.Count > 0 Then l.Sort() - _TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, l.First.Data, PostID, DateObj, SpecialFolder, PostOriginUrl, State, Attempts), LNC) + _TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, l.First.Data, PostID, DateObj, SpecialFolder, PostOriginUrl, State, Attempts, Text), LNC) l.Clear() End If End If @@ -1162,19 +1197,19 @@ NextPageBlock: If l.Count > 0 Then l.RemoveAll(wrongData) If l.Count > 0 Then l.Sort() - _TempMediaList.ListAddValue(MediaFromData(UTypes.Video, l.First.Data, PostID, DateObj, SpecialFolder, PostOriginUrl, State, Attempts), LNC) + _TempMediaList.ListAddValue(MediaFromData(UTypes.Video, l.First.Data, PostID, DateObj, SpecialFolder, PostOriginUrl, State, Attempts, Text), LNC) l.Clear() End If End If End With End If If Not TryExtractImage And Not Section = ObtainMedia_NoSection And ExtractImageFrom(Section) Then _ - ObtainMedia(n, PostID, SpecialFolder, DateObj, InitialType, PostOriginUrl, State, Attempts, True, Section) + ObtainMedia(n, PostID, SpecialFolder, DateObj, InitialType, PostOriginUrl, State, Attempts, True, Section, Text) Case 8 'gallery DateObj = mDate(n) With n("carousel_media").XmlIfNothing If .Count > 0 Then - For Each d In .Self : ObtainMedia(d, PostID, SpecialFolder, DateObj, 8, PostOriginUrl) : Next + For Each d In .Self : ObtainMedia(d, PostID, SpecialFolder, DateObj, 8, PostOriginUrl,,,,, Text) : Next End If End With End Select @@ -1438,13 +1473,16 @@ NextPageBlock: #Region "Create media" Private Function MediaFromData(ByVal t As UTypes, ByVal _URL As String, ByVal PostID As String, ByVal PostDate As String, Optional ByVal SpecialFolder As String = Nothing, Optional ByVal PostOriginUrl As String = Nothing, - Optional ByVal State As UStates = UStates.Unknown, Optional ByVal Attempts As Integer = 0) As UserMedia + Optional ByVal State As UStates = UStates.Unknown, Optional ByVal Attempts As Integer = 0, + Optional ByVal Text As String = Nothing) As UserMedia _URL = LinkFormatterSecure(RegexReplace(_URL.Replace("\", String.Empty), LinkPattern)) Dim m As New UserMedia(_URL, t) With {.URL_BASE = PostOriginUrl.IfNullOrEmpty(_URL), .Post = New UserPost With {.ID = PostID}} If Not m.URL.IsEmptyString Then m.File = CStr(RegexReplace(m.URL, FilesPattern)) If Not PostDate.IsEmptyString Then m.Post.Date = AConvert(Of Date)(PostDate, UnixDate32Provider, Nothing) Else m.Post.Date = Nothing m.SpecialFolder = SpecialFolder If State = UStates.Missing Then m.State = UStates.Missing : m.Attempts = Attempts + m.PostText = Text + m.PostTextFileSpecialFolder = DownloadTextSpecialFolder Return m End Function #End Region diff --git a/SCrawler/API/JustForFans/SiteSettings.vb b/SCrawler/API/JustForFans/SiteSettings.vb index db408cf..6e96207 100644 --- a/SCrawler/API/JustForFans/SiteSettings.vb +++ b/SCrawler/API/JustForFans/SiteSettings.vb @@ -34,6 +34,9 @@ Namespace API.JustForFans Case NameOf(UserAgent) : If Not HeaderValue.IsEmptyString Then Responser.UserAgent = HeaderValue End Select End Sub + Friend Overrides Property DownloadText As PropertyValue + Friend Overrides Property DownloadTextPosts As PropertyValue + Friend Overrides Property DownloadTextSpecialFolder As PropertyValue Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean) MyBase.New("JustForFans", "justfor.fans", AccName, Temp, My.Resources.SiteResources.JFFIcon_64, My.Resources.SiteResources.JFFPic_76) diff --git a/SCrawler/API/LPSG/SiteSettings.vb b/SCrawler/API/LPSG/SiteSettings.vb index d4a3e7c..dc2bab9 100644 --- a/SCrawler/API/LPSG/SiteSettings.vb +++ b/SCrawler/API/LPSG/SiteSettings.vb @@ -12,6 +12,9 @@ Imports PersonalUtilities.Functions.RegularExpressions Namespace API.LPSG Friend Class SiteSettings : Inherits Base.SiteSettingsBase + Friend Overrides Property DownloadText As PropertyValue + Friend Overrides Property DownloadTextPosts As PropertyValue + Friend Overrides Property DownloadTextSpecialFolder As PropertyValue Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean) MyBase.New("LPSG", "www.lpsg.com", AccName, Temp, My.Resources.SiteResources.LPSGIcon_48, My.Resources.SiteResources.LPSGPic_32) UrlPatternUser = "https://www.lpsg.com/threads/{0}/" diff --git a/SCrawler/API/Mastodon/SiteSettings.vb b/SCrawler/API/Mastodon/SiteSettings.vb index d267dfa..7251281 100644 --- a/SCrawler/API/Mastodon/SiteSettings.vb +++ b/SCrawler/API/Mastodon/SiteSettings.vb @@ -76,6 +76,9 @@ Namespace API.Mastodon Friend ReadOnly Property UserRelatedToMyDomain As PropertyValue + Friend Overrides Property DownloadText As PropertyValue + Friend Overrides Property DownloadTextPosts As PropertyValue + Friend Overrides Property DownloadTextSpecialFolder As PropertyValue #End Region #End Region #Region "Initializer" diff --git a/SCrawler/API/OnlyFans/DynamicRules.txt b/SCrawler/API/OnlyFans/DynamicRules.txt index f787f35..8327fd0 100644 --- a/SCrawler/API/OnlyFans/DynamicRules.txt +++ b/SCrawler/API/OnlyFans/DynamicRules.txt @@ -3,5 +3,4 @@ https://github.com/riley-access-labs/onlyfans-dynamic-rules-1/blob/main/dynamicR https://github.com/riley-access-labs/onlyfans-dynamic-rules-1/blob/patch-1/dynamicRules.json https://github.com/DATAHOARDERS/dynamic-rules/blob/main/onlyfans.json https://github.com/DIGITALCRIMINAL/dynamic-rules/blob/main/onlyfans.json -https://github.com/deviint/onlyfans-dynamic-rules/blob/main/dynamicRules.json https://github.com/rafa-9/dynamic-rules/blob/main/rules.json \ No newline at end of file diff --git a/SCrawler/API/OnlyFans/DynamicRulesAll.txt b/SCrawler/API/OnlyFans/DynamicRulesAll.txt index ee9a5f4..19b3a36 100644 --- a/SCrawler/API/OnlyFans/DynamicRulesAll.txt +++ b/SCrawler/API/OnlyFans/DynamicRulesAll.txt @@ -4,8 +4,8 @@ https://github.com/riley-access-labs/onlyfans-dynamic-rules-1/blob/main/dynamicR https://github.com/riley-access-labs/onlyfans-dynamic-rules-1/blob/patch-1/dynamicRules.json https://github.com/DATAHOARDERS/dynamic-rules/blob/main/onlyfans.json https://github.com/DIGITALCRIMINAL/dynamic-rules/blob/main/onlyfans.json -https://github.com/deviint/onlyfans-dynamic-rules/blob/main/dynamicRules.json https://github.com/rafa-9/dynamic-rules/blob/main/rules.json https://github.com/SneakyOvis/onlyfans-dynamic-rules/blob/main/rules.json -https://github.com/Growik/onlyfans-dynamic-rules/blob/main/rules.json \ No newline at end of file +https://github.com/Growik/onlyfans-dynamic-rules/blob/main/rules.json +https://github.com/deviint/onlyfans-dynamic-rules/blob/main/dynamicRules.json \ No newline at end of file diff --git a/SCrawler/API/OnlyFans/SiteSettings.vb b/SCrawler/API/OnlyFans/SiteSettings.vb index e1ae7bc..4b665b5 100644 --- a/SCrawler/API/OnlyFans/SiteSettings.vb +++ b/SCrawler/API/OnlyFans/SiteSettings.vb @@ -37,6 +37,8 @@ Namespace API.OnlyFans Friend Const HeaderXBC As String = "X-Bc" Friend Const HeaderAppToken As String = "App-Token" Private Const AppTokenDefault As String = "33d57ade8c02dbc5a333db99ff9ae26a" + Private Const BackendDefault As String = "aio" + Private Const Backendhttpx As String = "httpx" Friend ReadOnly Property HH_USER_ID As PropertyValue @@ -199,6 +201,24 @@ Namespace API.OnlyFans End If Return False End Function + Private ReadOnly Property OFS_BACKEND_XML As PropertyValue + + Friend ReadOnly Property OFS_BACKEND As PropertyValue + Get + If Not DefaultInstance Is Nothing Then + Return DirectCast(DefaultInstance, SiteSettings).OFS_BACKEND_XML + Else + Return OFS_BACKEND_XML + End If + End Get + End Property + + Private Function OFS_BACKEND_Update() As Boolean + DirectCast(If(DefaultInstance, Me), SiteSettings).OFS_BACKEND_XML.Value = + CStr(IIf(MsgBoxE({"Select a value for the 'backend' option", "'backend' value"}, vbQuestion,,, {BackendDefault, Backendhttpx}) = 0, BackendDefault, Backendhttpx)) + Return True + End Function #End Region #End Region #Region "Initializer" @@ -261,6 +281,7 @@ Namespace API.OnlyFans Keydb_Api_XML = New PropertyValue(String.Empty, GetType(String)) OFS_KEYS_Key_XML = New PropertyValue(String.Empty, GetType(String)) OFS_KEYS_ClientID_XML = New PropertyValue(String.Empty, GetType(String)) + OFS_BACKEND_XML = New PropertyValue(BackendDefault) UpdateRules401_XML = New PropertyValue(False) @@ -343,7 +364,8 @@ Namespace API.OnlyFans If p.IsEmptyString Then Return GetUserUrl(User) Else - Return String.Format(UserPostPattern, p, If(User.ID.IsEmptyString, User.Name, $"u{User.ID}")) + 'Return String.Format(UserPostPattern, p, If(User.ID.IsEmptyString, User.Name, $"u{User.ID}")) + Return String.Format(UserPostPattern, p, User.NameTrue) End If Else Return String.Empty diff --git a/SCrawler/API/OnlyFans/UserData.vb b/SCrawler/API/OnlyFans/UserData.vb index b843028..2aaa383 100644 --- a/SCrawler/API/OnlyFans/UserData.vb +++ b/SCrawler/API/OnlyFans/UserData.vb @@ -66,6 +66,7 @@ Namespace API.OnlyFans Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object) If Not Obj Is Nothing AndAlso TypeOf Obj Is UserExchangeOptions Then With DirectCast(Obj, UserExchangeOptions) + .ApplyBase(Me) MediaDownloadTimeline = .DownloadTimeline MediaDownloadStories = .DownloadStories MediaDownloadHighlights = .DownloadHighlights @@ -84,6 +85,7 @@ Namespace API.OnlyFans Private _OFScraperExists As Boolean = False Private OFSCache As CacheKeeper = Nothing Private _AbsMediaIndex As Integer = 0 + Private _DownloadedPostsSession As Integer = 0 Private FunctionErr As Integer = FunctionErrDef Private Const FunctionErrDef As Integer = -100 Private Sub ValidateOFScraper() @@ -95,6 +97,7 @@ Namespace API.OnlyFans If Not MySettings.SessionAborted Then ValidateOFScraper() _AbsMediaIndex = 0 + _DownloadedPostsSession = 0 FunctionErr = FunctionErrDef If Not CCookie Is Nothing Then CCookie.Dispose() CCookie = Responser.Cookies.Copy @@ -144,7 +147,7 @@ Namespace API.OnlyFans Dim tmpCursor$ = String.Empty Dim hasMore As Boolean = False Dim path$ = String.Empty - Dim postDate$, postID$ + Dim postDate$, postID$, txt$ Dim n As EContainer Dim mediaList As List(Of UserMedia) Dim mediaResult As Boolean @@ -189,9 +192,21 @@ Namespace API.OnlyFans Case DateResult.Exit : Exit Sub End Select + txt = n.Value("text") + mediaResult = False - mediaList = TryCreateMedia(n, postID, postDate, mediaResult) - If mediaResult Then _TempMediaList.ListAddList(mediaList, LNC) + mediaList = TryCreateMedia(n, postID, postDate, mediaResult,,,,, txt) + If mediaResult Then + _TempMediaList.ListAddList(mediaList, LNC) + _DownloadedPostsSession += 1 + ElseIf Not txt.IsEmptyString Then + _TempMediaList.ListAddValue(New UserMedia(postID, UTypes.Text) With { + .Post = New UserPost(postID, AConvert(Of Date)(postDate, DateProvider, Nothing)), + .PostText = txt, + .PostTextFileSpecialFolder = DownloadTextSpecialFolder, + .PostTextFile = $"{postID}.txt" + }, LNC) + End If Next Else hasMore = False @@ -202,7 +217,10 @@ Namespace API.OnlyFans End If End If - If hasMore Then + If DownloadTopCount.HasValue AndAlso DownloadTopCount.Value <= _DownloadedPostsSession Then + _complete = True + Exit Sub + ElseIf hasMore Then If IsSavedPosts Then tmpCursor = CInt(Cursor.IfNullOrEmpty(0)) + 10 DownloadTimeline(tmpCursor, Token) End If @@ -405,7 +423,7 @@ Namespace API.OnlyFans Private Function TryCreateMedia(ByVal n As EContainer, ByVal PostID As String, Optional ByVal PostDate As String = Nothing, Optional ByRef Result As Boolean = False, Optional ByVal IsHL As Boolean = False, Optional ByVal SpecFolder As String = Nothing, Optional ByVal PostUserID As String = Nothing, - Optional ByVal TryUseOFS As Boolean = True) As List(Of UserMedia) + Optional ByVal TryUseOFS As Boolean = True, Optional ByVal PostText As String = Nothing) As List(Of UserMedia) Dim postUrl$, postUrlBase$, ext$ Dim t As UTypes Dim mList As New List(Of UserMedia) @@ -438,7 +456,9 @@ Namespace API.OnlyFans If Not t = UTypes.Undefined And (Not postUrl.IsEmptyString Or t = UTypes.VideoPre) Then Dim media As New UserMedia(postUrl.IfNullOrEmpty(IIf(t = UTypes.VideoPre, $"{t}{_AbsMediaIndex}", String.Empty)), t) With { .Post = New UserPost(PostID, AConvert(Of Date)(PostDate, DateProvider, Nothing)), - .SpecialFolder = SpecFolder + .SpecialFolder = SpecFolder, + .PostText = PostText, + .PostTextFileSpecialFolder = DownloadTextSpecialFolder } If postUrlBase.IsEmptyString And Not IsSingleObjectDownload Then postUrlBase = GetPostUrl(Me, media) If Not postUrlBase.IsEmptyString Then media.URL_BASE = postUrlBase @@ -451,16 +471,20 @@ Namespace API.OnlyFans End With Return mList End Function - Private Sub GetUserID() + Private _NameUpdated As Boolean = False + Private Sub GetUserID(Optional ByVal UpdateNameOnly As Boolean = False) Const brTag$ = "
" - Dim path$ = $"/api2/v2/users/{Name}" + Dim path$ = $"/api2/v2/users/{IIf(UpdateNameOnly, $"u{ID}", Name)}" Dim url$ = String.Format(BaseUrlPattern, path) Try - If ID.IsEmptyString AndAlso UpdateSignature(path) Then + If (ID.IsEmptyString Or UpdateNameOnly) AndAlso UpdateSignature(path) Then Dim r$ = Responser.GetResponse(url) If Not r.IsEmptyString Then Using j As EContainer = JsonDocument.Parse(r) If j.ListExists Then + NameTrue = j.Value("username") + _NameUpdated = True + If UpdateNameOnly Then Exit Sub ID = j.Value("id") If Not ID.IsEmptyString Then _ForceSaveUserInfo = True UserSiteNameUpdate(j.Value("name")) @@ -600,6 +624,7 @@ Namespace API.OnlyFans Const requestPattern$ = """{0}"" manual --config ""{1}"" --url {2}" Dim conf As SFile = OFS_CreateConfig() If conf.Exists Then + If Not _NameUpdated Then GetUserID(True) Dim command$ = String.Format(requestPattern, MySettings.OFScraperPath.Value, conf, URL) '#If DEBUG Then 'Debug.WriteLine(command) @@ -657,6 +682,7 @@ Namespace API.OnlyFans updateConf("key-mode-default", CStr(MySettings.KeyModeDefault.Value).IfNullOrEmpty(SiteSettings.KeyModeDefault_Default), m1) updateConf("keydb_api", CStr(MySettings.Keydb_Api.Value), m1) + updateConf("backend", CStr(MySettings.OFS_BACKEND.Value), m1) If Not CStr(MySettings.OFS_KEYS_Key.Value).IsEmptyString And Not CStr(MySettings.OFS_KEYS_ClientID.Value).IsEmptyString Then updateConf("private-key", CStr(MySettings.OFS_KEYS_Key.Value).Replace("\", "/"), m3) @@ -730,6 +756,7 @@ Namespace API.OnlyFans If IsSingleObjectDownload Then URL = Media.URL_BASE Else + If Not _NameUpdated Then GetUserID(True) URL = GetPostUrl(Me, Media) End If If Not URL.IsEmptyString Then diff --git a/SCrawler/API/OnlyFans/UserExchangeOptions.vb b/SCrawler/API/OnlyFans/UserExchangeOptions.vb index 0a8752d..08016df 100644 --- a/SCrawler/API/OnlyFans/UserExchangeOptions.vb +++ b/SCrawler/API/OnlyFans/UserExchangeOptions.vb @@ -8,7 +8,7 @@ ' but WITHOUT ANY WARRANTY Imports SCrawler.Plugin.Attributes Namespace API.OnlyFans - Friend Class UserExchangeOptions + Friend Class UserExchangeOptions : Inherits Base.EditorExchangeOptionsBase Friend Property DownloadTimeline As Boolean @@ -18,7 +18,12 @@ Namespace API.OnlyFans Friend Property DownloadChatMedia As Boolean Private ReadOnly MySettings As SiteSettings + Friend Overrides Property UserName As String + Private Sub New() + End Sub Friend Sub New(ByVal u As UserData) + MyBase.New(u) + _ApplyBase_Name = False DownloadTimeline = u.MediaDownloadTimeline DownloadStories = u.MediaDownloadStories DownloadHighlights = u.MediaDownloadHighlights @@ -26,6 +31,8 @@ Namespace API.OnlyFans MySettings = u.HOST.Source End Sub Friend Sub New(ByVal s As SiteSettings) + MyBase.New(s) + _ApplyBase_Name = False DownloadTimeline = s.DownloadTimeline.Value DownloadStories = s.DownloadStories.Value DownloadHighlights = s.DownloadHighlights.Value diff --git a/SCrawler/API/Pinterest/SiteSettings.vb b/SCrawler/API/Pinterest/SiteSettings.vb index f2d8a67..65fe9f5 100644 --- a/SCrawler/API/Pinterest/SiteSettings.vb +++ b/SCrawler/API/Pinterest/SiteSettings.vb @@ -21,6 +21,9 @@ Namespace API.Pinterest Private ReadOnly Property MyConcurrentDownloadsProvider As IFormatProvider Friend ReadOnly Property SavedPostsUserName As PropertyValue + Friend Overrides Property DownloadText As PropertyValue + Friend Overrides Property DownloadTextPosts As PropertyValue + Friend Overrides Property DownloadTextSpecialFolder As PropertyValue #End Region #Region "Initializer" Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean) diff --git a/SCrawler/API/PornHub/SiteSettings.vb b/SCrawler/API/PornHub/SiteSettings.vb index e230503..0404fe3 100644 --- a/SCrawler/API/PornHub/SiteSettings.vb +++ b/SCrawler/API/PornHub/SiteSettings.vb @@ -31,6 +31,9 @@ Namespace API.PornHub Friend ReadOnly Property DownloadGifsAsMp4 As PropertyValue Friend ReadOnly Property SavedPostsUserName As PropertyValue + Friend Overrides Property DownloadText As PropertyValue + Friend Overrides Property DownloadTextPosts As PropertyValue + Friend Overrides Property DownloadTextSpecialFolder As PropertyValue #End Region #Region "Initializer" Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean) diff --git a/SCrawler/API/Reddit/Channel.vb b/SCrawler/API/Reddit/Channel.vb index f1fa0b4..7ea305a 100644 --- a/SCrawler/API/Reddit/Channel.vb +++ b/SCrawler/API/Reddit/Channel.vb @@ -88,14 +88,22 @@ Namespace API.Reddit End Property Friend Property ViewMode As View = View.New Implements IRedditView.ViewMode Friend Property ViewPeriod As Period = Period.All Implements IRedditView.ViewPeriod + Friend Property DownloadText As Boolean = False Implements IRedditView.DownloadText + Friend Property DownloadTextPosts As Boolean = False Implements IRedditView.DownloadTextPosts + Friend Property DownloadTextSpecialFolder As Boolean = False Implements IRedditView.DownloadTextSpecialFolder Friend Property RedGifsAccount As String = String.Empty Implements IRedditView.RedGifsAccount Friend Property RedditAccount As String = String.Empty Implements IRedditView.RedditAccount Friend Sub SetView(ByVal Options As IRedditView) Implements IRedditView.SetView If Not Options Is Nothing Then - ViewMode = Options.ViewMode - ViewPeriod = Options.ViewPeriod - RedditAccount = Options.RedditAccount - RedGifsAccount = Options.RedGifsAccount + With Options + ViewMode = .ViewMode + ViewPeriod = .ViewPeriod + DownloadText = .DownloadText + DownloadTextPosts = .DownloadTextPosts + DownloadTextSpecialFolder = .DownloadTextSpecialFolder + RedditAccount = .RedditAccount + RedGifsAccount = .RedGifsAccount + End With End If End Sub #Region "Statistics support" diff --git a/SCrawler/API/Reddit/Declarations.vb b/SCrawler/API/Reddit/Declarations.vb index ad04dfd..5b16901 100644 --- a/SCrawler/API/Reddit/Declarations.vb +++ b/SCrawler/API/Reddit/Declarations.vb @@ -21,6 +21,6 @@ Namespace API.Reddit Friend ReadOnly UrlBasePattern As RParams = RParams.DM("(?<=/)([^/]+?\.[\w]{3,4})(?=(\?|\Z))", 0) Friend ReadOnly VideoRegEx As RParams = RParams.DM("http.{0,1}://[^" & Chr(34) & "]+?mp4", 0) Private ReadOnly EUR_PROVIDER As New ANumbers(ANumbers.Cultures.EUR) - Friend ReadOnly UnixDate32ProviderReddit As New CustomProvider(Function(v, d, p, n, e) ADateTime.ParseUnix32(AConvert(Of Double)(v, EUR_PROVIDER, v), n, e)) + Friend ReadOnly UnixDate32ProviderReddit As New CustomProvider(Function(v, d, p, n, e) ADateTime.ParseUnix32(AConvert(Of Double)(v, EUR_PROVIDER, v), n, e)) End Module End Namespace \ No newline at end of file diff --git a/SCrawler/API/Reddit/IRedditView.vb b/SCrawler/API/Reddit/IRedditView.vb index 7f0bbfe..2148fb9 100644 --- a/SCrawler/API/Reddit/IRedditView.vb +++ b/SCrawler/API/Reddit/IRedditView.vb @@ -12,6 +12,8 @@ Namespace API.Reddit [New] = 0 Hot = 1 Top = 2 + Best = 3 + Rising = 4 End Enum Enum Period As Integer All = 0 @@ -23,6 +25,9 @@ Namespace API.Reddit End Enum Property ViewMode As View Property ViewPeriod As Period + Property DownloadText As Boolean + Property DownloadTextPosts As Boolean + Property DownloadTextSpecialFolder As Boolean Property RedGifsAccount As String Property RedditAccount As String Sub SetView(ByVal Options As IRedditView) @@ -34,14 +39,27 @@ Namespace API.Reddit Friend Const Name_RedditAccount As String = "RedditAccount" Friend Property ViewMode As IRedditView.View Implements IRedditView.ViewMode Friend Property ViewPeriod As IRedditView.Period Implements IRedditView.ViewPeriod + Friend Property DownloadText As Boolean Implements IRedditView.DownloadText + Friend Property DownloadTextPosts As Boolean Implements IRedditView.DownloadTextPosts + Friend Property DownloadTextSpecialFolder As Boolean Implements IRedditView.DownloadTextSpecialFolder Friend Property RedGifsAccount As String Implements IRedditView.RedGifsAccount Friend Property RedditAccount As String Implements IRedditView.RedditAccount + Friend Sub New() + End Sub + Friend Sub New(ByVal Options As IRedditView) + SetView(Options) + End Sub Friend Sub SetView(ByVal Options As IRedditView) Implements IRedditView.SetView If Not Options Is Nothing Then - ViewMode = Options.ViewMode - ViewPeriod = Options.ViewPeriod - RedGifsAccount = Options.RedGifsAccount - RedditAccount = Options.RedditAccount + With Options + ViewMode = .ViewMode + ViewPeriod = .ViewPeriod + DownloadText = .DownloadText + DownloadTextPosts = .DownloadTextPosts + DownloadTextSpecialFolder = .DownloadTextSpecialFolder + RedGifsAccount = .RedGifsAccount + RedditAccount = .RedditAccount + End With End If End Sub End Class diff --git a/SCrawler/API/Reddit/RedditViewSettingsForm.Designer.vb b/SCrawler/API/Reddit/RedditViewSettingsForm.Designer.vb index d4659b8..8493196 100644 --- a/SCrawler/API/Reddit/RedditViewSettingsForm.Designer.vb +++ b/SCrawler/API/Reddit/RedditViewSettingsForm.Designer.vb @@ -22,17 +22,21 @@ Namespace API.Reddit Private components As System.ComponentModel.IContainer Private Sub InitializeComponent() + Me.components = New System.ComponentModel.Container() Dim CONTAINER_MAIN As System.Windows.Forms.ToolStripContainer Dim TP_VIEW_MODE As System.Windows.Forms.TableLayoutPanel Dim LBL_VIEW_MODE As System.Windows.Forms.Label Dim LBL_PERIOD As System.Windows.Forms.Label - Dim ActionButton1 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() + Dim ActionButton3 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(RedditViewSettingsForm)) - Dim ActionButton2 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 TP_TEXT As System.Windows.Forms.TableLayoutPanel Me.TP_MAIN = New System.Windows.Forms.TableLayoutPanel() Me.OPT_VIEW_MODE_NEW = New System.Windows.Forms.RadioButton() Me.OPT_VIEW_MODE_HOT = New System.Windows.Forms.RadioButton() Me.OPT_VIEW_MODE_TOP = New System.Windows.Forms.RadioButton() + Me.OPT_VIEW_MODE_BEST = New System.Windows.Forms.RadioButton() + Me.OPT_VIEW_MODE_RISING = New System.Windows.Forms.RadioButton() Me.TP_PERIOD = New System.Windows.Forms.TableLayoutPanel() Me.OPT_PERIOD_ALL = New System.Windows.Forms.RadioButton() Me.OPT_PERIOD_HOUR = New System.Windows.Forms.RadioButton() @@ -42,10 +46,15 @@ Namespace API.Reddit Me.OPT_PERIOD_YEAR = New System.Windows.Forms.RadioButton() Me.CMB_REDGIFS_ACC = New PersonalUtilities.Forms.Controls.ComboBoxExtended() Me.CMB_REDDIT_ACC = New PersonalUtilities.Forms.Controls.ComboBoxExtended() + Me.CH_TXT_DOWN_TXT = New System.Windows.Forms.CheckBox() + Me.CH_TXT_DOWN_POSTS = New System.Windows.Forms.CheckBox() + Me.TT_MAIN = New System.Windows.Forms.ToolTip(Me.components) + Me.CH_TXT_DOWN_SPEC_FOLDER = New System.Windows.Forms.CheckBox() CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer() TP_VIEW_MODE = New System.Windows.Forms.TableLayoutPanel() LBL_VIEW_MODE = New System.Windows.Forms.Label() LBL_PERIOD = New System.Windows.Forms.Label() + TP_TEXT = New System.Windows.Forms.TableLayoutPanel() CONTAINER_MAIN.ContentPanel.SuspendLayout() CONTAINER_MAIN.SuspendLayout() Me.TP_MAIN.SuspendLayout() @@ -53,6 +62,7 @@ Namespace API.Reddit Me.TP_PERIOD.SuspendLayout() CType(Me.CMB_REDGIFS_ACC, System.ComponentModel.ISupportInitialize).BeginInit() CType(Me.CMB_REDDIT_ACC, System.ComponentModel.ISupportInitialize).BeginInit() + TP_TEXT.SuspendLayout() Me.SuspendLayout() ' 'CONTAINER_MAIN @@ -61,13 +71,13 @@ Namespace API.Reddit 'CONTAINER_MAIN.ContentPanel ' CONTAINER_MAIN.ContentPanel.Controls.Add(Me.TP_MAIN) - CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(477, 169) + CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(477, 222) 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(477, 169) + CONTAINER_MAIN.Size = New System.Drawing.Size(477, 222) CONTAINER_MAIN.TabIndex = 0 CONTAINER_MAIN.TopToolStripPanelVisible = False ' @@ -78,18 +88,20 @@ Namespace API.Reddit Me.TP_MAIN.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) Me.TP_MAIN.Controls.Add(TP_VIEW_MODE, 0, 0) Me.TP_MAIN.Controls.Add(Me.TP_PERIOD, 0, 1) - Me.TP_MAIN.Controls.Add(Me.CMB_REDGIFS_ACC, 0, 3) - Me.TP_MAIN.Controls.Add(Me.CMB_REDDIT_ACC, 0, 2) + Me.TP_MAIN.Controls.Add(Me.CMB_REDGIFS_ACC, 0, 4) + Me.TP_MAIN.Controls.Add(Me.CMB_REDDIT_ACC, 0, 3) + Me.TP_MAIN.Controls.Add(TP_TEXT, 0, 2) Me.TP_MAIN.Dock = System.Windows.Forms.DockStyle.Fill Me.TP_MAIN.Location = New System.Drawing.Point(0, 0) Me.TP_MAIN.Name = "TP_MAIN" - Me.TP_MAIN.RowCount = 5 - Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) + Me.TP_MAIN.RowCount = 6 Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 56.0!)) + Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 56.0!)) + Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) - Me.TP_MAIN.Size = New System.Drawing.Size(477, 169) + Me.TP_MAIN.Size = New System.Drawing.Size(477, 222) Me.TP_MAIN.TabIndex = 0 ' 'TP_VIEW_MODE @@ -103,14 +115,16 @@ Namespace API.Reddit TP_VIEW_MODE.Controls.Add(Me.OPT_VIEW_MODE_NEW, 1, 0) TP_VIEW_MODE.Controls.Add(Me.OPT_VIEW_MODE_HOT, 2, 0) TP_VIEW_MODE.Controls.Add(Me.OPT_VIEW_MODE_TOP, 3, 0) + TP_VIEW_MODE.Controls.Add(Me.OPT_VIEW_MODE_BEST, 1, 1) + TP_VIEW_MODE.Controls.Add(Me.OPT_VIEW_MODE_RISING, 2, 1) TP_VIEW_MODE.Dock = System.Windows.Forms.DockStyle.Fill TP_VIEW_MODE.Location = New System.Drawing.Point(1, 1) TP_VIEW_MODE.Margin = New System.Windows.Forms.Padding(0) TP_VIEW_MODE.Name = "TP_VIEW_MODE" - TP_VIEW_MODE.RowCount = 1 - TP_VIEW_MODE.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) - TP_VIEW_MODE.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) - TP_VIEW_MODE.Size = New System.Drawing.Size(475, 28) + TP_VIEW_MODE.RowCount = 2 + TP_VIEW_MODE.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50.0!)) + TP_VIEW_MODE.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50.0!)) + TP_VIEW_MODE.Size = New System.Drawing.Size(475, 56) TP_VIEW_MODE.TabIndex = 0 ' 'LBL_VIEW_MODE @@ -160,6 +174,30 @@ Namespace API.Reddit Me.OPT_VIEW_MODE_TOP.Text = "Top" Me.OPT_VIEW_MODE_TOP.UseVisualStyleBackColor = True ' + 'OPT_VIEW_MODE_BEST + ' + Me.OPT_VIEW_MODE_BEST.AutoSize = True + Me.OPT_VIEW_MODE_BEST.Dock = System.Windows.Forms.DockStyle.Fill + Me.OPT_VIEW_MODE_BEST.Location = New System.Drawing.Point(121, 31) + Me.OPT_VIEW_MODE_BEST.Name = "OPT_VIEW_MODE_BEST" + Me.OPT_VIEW_MODE_BEST.Size = New System.Drawing.Size(112, 22) + Me.OPT_VIEW_MODE_BEST.TabIndex = 4 + Me.OPT_VIEW_MODE_BEST.TabStop = True + Me.OPT_VIEW_MODE_BEST.Text = "Best" + Me.OPT_VIEW_MODE_BEST.UseVisualStyleBackColor = True + ' + 'OPT_VIEW_MODE_RISING + ' + Me.OPT_VIEW_MODE_RISING.AutoSize = True + Me.OPT_VIEW_MODE_RISING.Dock = System.Windows.Forms.DockStyle.Fill + Me.OPT_VIEW_MODE_RISING.Location = New System.Drawing.Point(239, 31) + Me.OPT_VIEW_MODE_RISING.Name = "OPT_VIEW_MODE_RISING" + Me.OPT_VIEW_MODE_RISING.Size = New System.Drawing.Size(112, 22) + Me.OPT_VIEW_MODE_RISING.TabIndex = 5 + Me.OPT_VIEW_MODE_RISING.TabStop = True + Me.OPT_VIEW_MODE_RISING.Text = "Rising" + Me.OPT_VIEW_MODE_RISING.UseVisualStyleBackColor = True + ' 'TP_PERIOD ' Me.TP_PERIOD.ColumnCount = 4 @@ -175,7 +213,7 @@ Namespace API.Reddit Me.TP_PERIOD.Controls.Add(Me.OPT_PERIOD_MONTH, 2, 1) Me.TP_PERIOD.Controls.Add(Me.OPT_PERIOD_YEAR, 3, 1) Me.TP_PERIOD.Dock = System.Windows.Forms.DockStyle.Fill - Me.TP_PERIOD.Location = New System.Drawing.Point(1, 30) + Me.TP_PERIOD.Location = New System.Drawing.Point(1, 58) Me.TP_PERIOD.Margin = New System.Windows.Forms.Padding(0) Me.TP_PERIOD.Name = "TP_PERIOD" Me.TP_PERIOD.RowCount = 2 @@ -269,17 +307,17 @@ Namespace API.Reddit ' 'CMB_REDGIFS_ACC ' - ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image) - ActionButton1.Name = "ArrowDown" - ActionButton1.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.ArrowDown - Me.CMB_REDGIFS_ACC.Buttons.Add(ActionButton1) + ActionButton3.BackgroundImage = CType(resources.GetObject("ActionButton3.BackgroundImage"), System.Drawing.Image) + ActionButton3.Name = "ArrowDown" + ActionButton3.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.ArrowDown + Me.CMB_REDGIFS_ACC.Buttons.Add(ActionButton3) Me.CMB_REDGIFS_ACC.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.Label Me.CMB_REDGIFS_ACC.CaptionSizeType = System.Windows.Forms.SizeType.Percent Me.CMB_REDGIFS_ACC.CaptionText = "RedGifs account" Me.CMB_REDGIFS_ACC.CaptionVisible = True Me.CMB_REDGIFS_ACC.CaptionWidth = 26.0R Me.CMB_REDGIFS_ACC.Dock = System.Windows.Forms.DockStyle.Fill - Me.CMB_REDGIFS_ACC.Location = New System.Drawing.Point(4, 119) + Me.CMB_REDGIFS_ACC.Location = New System.Drawing.Point(4, 173) Me.CMB_REDGIFS_ACC.Name = "CMB_REDGIFS_ACC" Me.CMB_REDGIFS_ACC.Size = New System.Drawing.Size(469, 22) Me.CMB_REDGIFS_ACC.TabIndex = 4 @@ -287,35 +325,89 @@ Namespace API.Reddit ' 'CMB_REDDIT_ACC ' - ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image) - ActionButton2.Name = "ArrowDown" - ActionButton2.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.ArrowDown - Me.CMB_REDDIT_ACC.Buttons.Add(ActionButton2) + ActionButton4.BackgroundImage = CType(resources.GetObject("ActionButton4.BackgroundImage"), System.Drawing.Image) + ActionButton4.Name = "ArrowDown" + ActionButton4.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.ArrowDown + Me.CMB_REDDIT_ACC.Buttons.Add(ActionButton4) Me.CMB_REDDIT_ACC.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.Label Me.CMB_REDDIT_ACC.CaptionSizeType = System.Windows.Forms.SizeType.Percent Me.CMB_REDDIT_ACC.CaptionText = "Reddit account" Me.CMB_REDDIT_ACC.CaptionVisible = True Me.CMB_REDDIT_ACC.CaptionWidth = 26.0R Me.CMB_REDDIT_ACC.Dock = System.Windows.Forms.DockStyle.Fill - Me.CMB_REDDIT_ACC.Location = New System.Drawing.Point(4, 90) + Me.CMB_REDDIT_ACC.Location = New System.Drawing.Point(4, 144) Me.CMB_REDDIT_ACC.Name = "CMB_REDDIT_ACC" Me.CMB_REDDIT_ACC.Size = New System.Drawing.Size(469, 22) Me.CMB_REDDIT_ACC.TabIndex = 3 Me.CMB_REDDIT_ACC.TextBoxBorderStyle = System.Windows.Forms.BorderStyle.FixedSingle ' + 'TP_TEXT + ' + TP_TEXT.ColumnCount = 3 + TP_TEXT.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333!)) + TP_TEXT.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333!)) + TP_TEXT.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333!)) + TP_TEXT.Controls.Add(Me.CH_TXT_DOWN_TXT, 0, 0) + TP_TEXT.Controls.Add(Me.CH_TXT_DOWN_POSTS, 1, 0) + TP_TEXT.Controls.Add(Me.CH_TXT_DOWN_SPEC_FOLDER, 2, 0) + TP_TEXT.Dock = System.Windows.Forms.DockStyle.Fill + TP_TEXT.Location = New System.Drawing.Point(1, 115) + TP_TEXT.Margin = New System.Windows.Forms.Padding(0) + TP_TEXT.Name = "TP_TEXT" + TP_TEXT.RowCount = 1 + TP_TEXT.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + TP_TEXT.Size = New System.Drawing.Size(475, 25) + TP_TEXT.TabIndex = 5 + ' + 'CH_TXT_DOWN_TXT + ' + Me.CH_TXT_DOWN_TXT.AutoSize = True + Me.CH_TXT_DOWN_TXT.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_TXT_DOWN_TXT.Location = New System.Drawing.Point(3, 3) + Me.CH_TXT_DOWN_TXT.Name = "CH_TXT_DOWN_TXT" + Me.CH_TXT_DOWN_TXT.Size = New System.Drawing.Size(152, 19) + Me.CH_TXT_DOWN_TXT.TabIndex = 0 + Me.CH_TXT_DOWN_TXT.Text = "Download text" + Me.TT_MAIN.SetToolTip(Me.CH_TXT_DOWN_TXT, "Download text (if available) for posts with image and video") + Me.CH_TXT_DOWN_TXT.UseVisualStyleBackColor = True + ' + 'CH_TXT_DOWN_POSTS + ' + Me.CH_TXT_DOWN_POSTS.AutoSize = True + Me.CH_TXT_DOWN_POSTS.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_TXT_DOWN_POSTS.Location = New System.Drawing.Point(161, 3) + Me.CH_TXT_DOWN_POSTS.Name = "CH_TXT_DOWN_POSTS" + Me.CH_TXT_DOWN_POSTS.Size = New System.Drawing.Size(152, 19) + Me.CH_TXT_DOWN_POSTS.TabIndex = 1 + Me.CH_TXT_DOWN_POSTS.Text = "Download text posts" + Me.TT_MAIN.SetToolTip(Me.CH_TXT_DOWN_POSTS, "Download text (if available) for text posts (no image and video)") + Me.CH_TXT_DOWN_POSTS.UseVisualStyleBackColor = True + ' + 'CH_TXT_DOWN_SPEC_FOLDER + ' + Me.CH_TXT_DOWN_SPEC_FOLDER.AutoSize = True + Me.CH_TXT_DOWN_SPEC_FOLDER.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_TXT_DOWN_SPEC_FOLDER.Location = New System.Drawing.Point(319, 3) + Me.CH_TXT_DOWN_SPEC_FOLDER.Name = "CH_TXT_DOWN_SPEC_FOLDER" + Me.CH_TXT_DOWN_SPEC_FOLDER.Size = New System.Drawing.Size(153, 19) + Me.CH_TXT_DOWN_SPEC_FOLDER.TabIndex = 2 + Me.CH_TXT_DOWN_SPEC_FOLDER.Text = "Text special folder" + Me.TT_MAIN.SetToolTip(Me.CH_TXT_DOWN_SPEC_FOLDER, "If checked, text files will be saved to a separate folder") + Me.CH_TXT_DOWN_SPEC_FOLDER.UseVisualStyleBackColor = True + ' 'RedditViewSettingsForm ' Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!) Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font - Me.ClientSize = New System.Drawing.Size(477, 169) + Me.ClientSize = New System.Drawing.Size(477, 222) Me.Controls.Add(CONTAINER_MAIN) Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle Me.Icon = Global.SCrawler.My.Resources.SiteResources.RedditIcon_128 Me.KeyPreview = True Me.MaximizeBox = False - Me.MaximumSize = New System.Drawing.Size(493, 208) + Me.MaximumSize = New System.Drawing.Size(493, 261) Me.MinimizeBox = False - Me.MinimumSize = New System.Drawing.Size(493, 208) + Me.MinimumSize = New System.Drawing.Size(493, 261) Me.Name = "RedditViewSettingsForm" Me.ShowInTaskbar = False Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide @@ -330,6 +422,8 @@ Namespace API.Reddit Me.TP_PERIOD.PerformLayout() CType(Me.CMB_REDGIFS_ACC, System.ComponentModel.ISupportInitialize).EndInit() CType(Me.CMB_REDDIT_ACC, System.ComponentModel.ISupportInitialize).EndInit() + TP_TEXT.ResumeLayout(False) + TP_TEXT.PerformLayout() Me.ResumeLayout(False) End Sub @@ -346,5 +440,11 @@ Namespace API.Reddit Private WithEvents CMB_REDGIFS_ACC As PersonalUtilities.Forms.Controls.ComboBoxExtended Private WithEvents CMB_REDDIT_ACC As PersonalUtilities.Forms.Controls.ComboBoxExtended Private WithEvents TP_MAIN As TableLayoutPanel + Private WithEvents OPT_VIEW_MODE_BEST As RadioButton + Private WithEvents OPT_VIEW_MODE_RISING As RadioButton + Private WithEvents CH_TXT_DOWN_TXT As CheckBox + Private WithEvents TT_MAIN As ToolTip + Private WithEvents CH_TXT_DOWN_POSTS As CheckBox + Private WithEvents CH_TXT_DOWN_SPEC_FOLDER As CheckBox End Class End Namespace \ No newline at end of file diff --git a/SCrawler/API/Reddit/RedditViewSettingsForm.resx b/SCrawler/API/Reddit/RedditViewSettingsForm.resx index 1050e12..435ba91 100644 --- a/SCrawler/API/Reddit/RedditViewSettingsForm.resx +++ b/SCrawler/API/Reddit/RedditViewSettingsForm.resx @@ -130,184 +130,195 @@ False - + - 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 + U1wTEVFuCACwydqqfmZO8Z3yxXrc6T7f73o/AEyQiDgtp/QXG/EpgTbFF3JKv1D+TABgQnQfx2ur+POc + 4kflC/kx5u6c4l+blF7YXWoofw4AMIG6W/G2i/Wzckp/lVP896EX9PJFvkh3M5/6o03E7+acF8vvCQBM + mQO/EFTVctfezxEXtlX9vLaqX9z9s6mqC5YWF+fLrwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6LEtW/4flgYiLD1qeX0A - AAAASUVORK5CYII= + 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 - AAAASUVORK5CYII= + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAYIj+H5YGIizEb/aEAAAAAElFTkSuQmCC + + False + + + 17, 17 + + + 17, 17 + + + False + + + False + \ No newline at end of file diff --git a/SCrawler/API/Reddit/RedditViewSettingsForm.vb b/SCrawler/API/Reddit/RedditViewSettingsForm.vb index 0f7a1a3..c5b34d6 100644 --- a/SCrawler/API/Reddit/RedditViewSettingsForm.vb +++ b/SCrawler/API/Reddit/RedditViewSettingsForm.vb @@ -38,6 +38,8 @@ Namespace API.Reddit Select Case MyOptions.ViewMode Case CView.Hot : OPT_VIEW_MODE_HOT.Checked = True Case CView.Top : OPT_VIEW_MODE_TOP.Checked = True + Case CView.Best : OPT_VIEW_MODE_BEST.Checked = True + Case CView.Rising : OPT_VIEW_MODE_RISING.Checked = True Case Else : OPT_VIEW_MODE_NEW.Checked = True End Select Select Case MyOptions.ViewPeriod @@ -50,11 +52,15 @@ Namespace API.Reddit End Select ChangePeriodEnabled() + CH_TXT_DOWN_TXT.Checked = MyOptions.DownloadText + CH_TXT_DOWN_POSTS.Checked = MyOptions.DownloadTextPosts + CH_TXT_DOWN_SPEC_FOLDER.Checked = MyOptions.DownloadTextSpecialFolder + PopulateCMB(Settings(RedditSiteKey), CMB_REDDIT_ACC, MyOptions.RedditAccount) PopulateCMB(Settings(RedGifs.RedGifsSiteKey), CMB_REDGIFS_ACC, MyOptions.RedGifsAccount) If IsUserSettings Then TP_MAIN.Controls.Remove(CMB_REDDIT_ACC) - TP_MAIN.RowStyles(2).Height = 0 + TP_MAIN.RowStyles(3).Height = 0 TP_MAIN.Refresh() Dim s As Size = Size s.Height -= 28 @@ -100,6 +106,8 @@ Namespace API.Reddit Select Case True Case OPT_VIEW_MODE_HOT.Checked : .ViewMode = CView.Hot Case OPT_VIEW_MODE_TOP.Checked : .ViewMode = CView.Top + Case OPT_VIEW_MODE_BEST.Checked : .ViewMode = CView.Best + Case OPT_VIEW_MODE_RISING.Checked : .ViewMode = CView.Rising Case Else : .ViewMode = CView.New End Select Select Case True @@ -110,6 +118,9 @@ Namespace API.Reddit Case OPT_PERIOD_YEAR.Checked : .ViewPeriod = CPeriod.Year Case Else : .ViewPeriod = CPeriod.All End Select + .DownloadText = CH_TXT_DOWN_TXT.Checked + .DownloadTextPosts = CH_TXT_DOWN_POSTS.Checked + .DownloadTextSpecialFolder = CH_TXT_DOWN_SPEC_FOLDER.Checked .RedGifsAccount = CMB_REDGIFS_ACC.Text If Not IsUserSettings Then .RedditAccount = CMB_REDDIT_ACC.Text End With diff --git a/SCrawler/API/Reddit/SiteSettings.vb b/SCrawler/API/Reddit/SiteSettings.vb index bf67c48..03242b5 100644 --- a/SCrawler/API/Reddit/SiteSettings.vb +++ b/SCrawler/API/Reddit/SiteSettings.vb @@ -96,6 +96,7 @@ Namespace API.Reddit With Responser Dim d% = .Decoders.Count .Decoders.ListAddList({SymbolsConverter.Converters.Unicode, SymbolsConverter.Converters.HTML}, LAP.NotContainsOnly) + .Accept = "application/json" token = .Headers.Value(DeclaredNames.Header_Authorization) End With @@ -104,7 +105,7 @@ Namespace API.Reddit ApiClientID = New PropertyValue(String.Empty, GetType(String)) ApiClientSecret = New PropertyValue(String.Empty, GetType(String)) BearerToken = New PropertyValue(token, GetType(String), Sub(v) Responser.Headers.Add(DeclaredNames.Header_Authorization, v)) - BearerTokenUseCurl = New PropertyValue(True) + BearerTokenUseCurl = New PropertyValue(False) TokenUpdateInterval = New PropertyValue(360) TokenUpdateIntervalProvider = New TokenRefreshIntervalProvider BearerTokenDateUpdate = New PropertyValue(Now.AddYears(-1)) @@ -123,11 +124,11 @@ Namespace API.Reddit ImageVideoContains = "reddit.com" UserRegex = RParams.DM("[htps:/]{7,8}.*?reddit.com/([user]{1,4})/([^/\?&]+)", 0, RegexReturn.ListByMatch, EDP.ReturnValue) End Sub - Private Const SettingsVersionCurrent As Integer = 1 + Private Const SettingsVersionCurrent As Integer = 2 Friend Overrides Sub EndInit() If CInt(SettingsVersion.Value) < SettingsVersionCurrent Then SettingsVersion.Value = SettingsVersionCurrent - TokenUpdateInterval.Value = 360 + BearerTokenUseCurl.Value = False End If MyBase.EndInit() End Sub diff --git a/SCrawler/API/Reddit/UserData.vb b/SCrawler/API/Reddit/UserData.vb index eccc1b8..9558129 100644 --- a/SCrawler/API/Reddit/UserData.vb +++ b/SCrawler/API/Reddit/UserData.vb @@ -33,7 +33,8 @@ Namespace API.Reddit End Property Private ReadOnly Property DateTrueProvider(ByVal IsChannel As Boolean) As IFormatProvider Get - Return If(IsChannel, UnixDate32ProviderReddit, UnixDate64Provider) + Return UnixDate32Provider + 'Return If(IsChannel, UnixDate32ProviderReddit, UnixDate64Provider) End Get End Property Private ReadOnly Property UseM3U8 As Boolean @@ -126,10 +127,15 @@ Namespace API.Reddit Friend Property ViewPeriod As CPeriod Implements IRedditView.ViewPeriod Friend Sub SetView(ByVal Options As IRedditView) Implements IRedditView.SetView If Not Options Is Nothing Then - ViewMode = Options.ViewMode - ViewPeriod = Options.ViewPeriod - RedGifsAccount = Options.RedGifsAccount - RedditAccount = Options.RedditAccount + With Options + ViewMode = .ViewMode + ViewPeriod = .ViewPeriod + DownloadText = .DownloadText + DownloadTextPosts = .DownloadTextPosts + DownloadTextSpecialFolder = .DownloadTextSpecialFolder + RedGifsAccount = .RedGifsAccount + RedditAccount = .RedditAccount + End With End If End Sub Private ReadOnly Property View As String @@ -137,6 +143,8 @@ Namespace API.Reddit Select Case ViewMode Case CView.Hot : Return "hot" Case CView.Top : Return "top" + Case CView.Best : Return "best" + Case CView.Rising : Return "rising" Case Else : Return "new" End Select End Get @@ -157,6 +165,9 @@ Namespace API.Reddit End If End Get End Property + Friend Overrides Property DownloadText As Boolean Implements IRedditView.DownloadText + Friend Overrides Property DownloadTextPosts As Boolean Implements IRedditView.DownloadTextPosts + Friend Overrides Property DownloadTextSpecialFolder As Boolean Implements IRedditView.DownloadTextSpecialFolder #End Region #Region "Initializer" Friend Sub New() @@ -215,7 +226,7 @@ Namespace API.Reddit End With End Sub Friend Overrides Function ExchangeOptionsGet() As Object - Return New RedditViewExchange With {.ViewMode = ViewMode, .ViewPeriod = ViewPeriod, .RedGifsAccount = RedGifsAccount, .RedditAccount = RedditAccount} + Return New RedditViewExchange(Me) End Function Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object) If Not Obj Is Nothing AndAlso TypeOf Obj Is IRedditView Then SetView(DirectCast(Obj, IRedditView)) @@ -274,8 +285,13 @@ Namespace API.Reddit Else GetUserInfo() End If - If SaveToCache AndAlso Not Responser.Decoders.Contains(SymbolsConverter.Converters.HTML) Then _ - Responser.Decoders.Add(SymbolsConverter.Converters.HTML) + If SaveToCache Then + DownloadText = False + DownloadTextPosts = False + DownloadTextSpecialFolder = False + If Not Responser.Decoders.Contains(SymbolsConverter.Converters.HTML) Then _ + Responser.Decoders.Add(SymbolsConverter.Converters.HTML) + End If DownloadDataChannel(String.Empty, Token) If ChannelInfo Is Nothing Then _TempPostsList.ListAddList(_TempMediaList.Select(Function(m) m.Post.ID), LNC) Else @@ -311,52 +327,56 @@ Namespace API.Reddit Dim CheckNode As Predicate(Of EContainer) = Function(e) Not ParseUserMediaOnly OrElse If(e("author")?.Value, "/").ToLower.Equals(NameTrue.StringToLower) Dim _PostID As Func(Of String) = Function() PostTmp.IfNullOrEmpty(PostID) - URL = $"https://gateway.reddit.com/desktopapi/v1/user/{NameTrue}/posts?rtj=only&allow_quarantined=true&allow_over18=1&include=identity&after={POST}&dist=25&sort={View}&t={Period}&layout=classic" + 'URL = $"https://gateway.reddit.com/desktopapi/v1/user/{NameTrue}/posts?rtj=only&allow_quarantined=true&allow_over18=1&include=identity&after={POST}&dist=25&sort={View}&t={Period}&layout=classic" + URL = $"https://oauth.reddit.com/user/{NameTrue}/submitted.json?rtj=only&allow_quarantined=true&allow_over18=1&include=identity&after={POST}&dist=25&sort={View}&t={Period}&layout=classic" ThrowAny(Token) Dim r$ = Responser.GetResponse(URL) If Not r.IsEmptyString Then Using w As EContainer = JsonDocument.Parse(r).XmlIfNothing If w.Count > 0 Then - n = w.GetNode(JsonNodesJson) - If Not n Is Nothing AndAlso n.Count > 0 Then + 'n = w.GetNode(JsonNodesJson) + n = w.GetNode(ChannelJsonNodes) + If n.ListExists Then ProgressPre.ChangeMax(n.Count) For Each nn In n ProgressPre.Perform() ThrowAny(Token) - If nn.Count > 0 Then - If CheckNode(nn) Then + With nn("data") + If .ListExists Then + If CheckNode(.Self) Then - 'Obtain post ID - PostTmp = nn.Name - If PostTmp.IsEmptyString Then PostTmp = nn.Value("id") - If PostTmp.IsEmptyString Then Continue For - 'Check for CrossPost - If IsCrossPost(nn) Then - _CrossPosts.ListAddList({nn.Value(Node_CrosspostRootId), - nn.Value(Node_CrosspostParentId), - nn.Value(Node_CrosspostParent)}, LNC) - Continue For - Else - If Not _CrossPosts.Contains(PostTmp) Then PostID = PostTmp : PostTmp = String.Empty + 'Obtain post ID + PostTmp = .Value("name") '.Name + If PostTmp.IsEmptyString Then PostTmp = .Value("id") + If PostTmp.IsEmptyString Then Continue For + 'Check for CrossPost + If IsCrossPost(.Self) Then + _CrossPosts.ListAddList({ .Value(Node_CrosspostRootId), + .Value(Node_CrosspostParentId), + .Value(Node_CrosspostParent)}, LNC) + Continue For + Else + If Not _CrossPosts.Contains(PostTmp) Then PostID = PostTmp : PostTmp = String.Empty + End If + + 'Download decision + If Not _TempPostsList.Contains(_PostID()) Then + NewPostDetected = True + _TempPostsList.Add(_PostID()) + Else + If Not _CrossPosts.Contains(_PostID()) Then ExistsDetected = True + Continue For + End If + PostDate = If(.Item("created")?.Value, String.Empty) + Select Case CheckDatesLimit(PostDate, DateTrueProvider(IsChannel)) + Case DateResult.Skip : Continue For + Case DateResult.Exit : Exit Sub + End Select + + ParseContainer(.Self, _PostID(), PostDate,,, GetTextDocument(.Self)) End If - - 'Download decision - If Not _TempPostsList.Contains(_PostID()) Then - NewPostDetected = True - _TempPostsList.Add(_PostID()) - Else - If Not _CrossPosts.Contains(_PostID()) Then ExistsDetected = True - Continue For - End If - If nn.Contains("created") Then PostDate = nn("created").Value Else PostDate = String.Empty - Select Case CheckDatesLimit(PostDate, DateTrueProvider(IsChannel)) - Case DateResult.Skip : Continue For - Case DateResult.Exit : Exit Sub - End Select - - ParseContainer(nn, _PostID(), PostDate) End If - End If + End With Next End If End If @@ -450,7 +470,7 @@ Namespace API.Reddit Continue For End If - ParseContainer(s, PostID, PostDate, _UserID) + ParseContainer(s, PostID, PostDate, _UserID,, If(Not SaveToCache, GetTextDocument(s), String.Empty)) End If Next End If @@ -503,7 +523,7 @@ Namespace API.Reddit #End Region #Region "ParseContainer" Private Function ParseContainer(ByVal e As EContainer, ByVal PostID As String, ByVal PostDate As String, Optional ByVal UserID As String = Nothing, - Optional ByVal AllowReparse As Boolean = True) As Boolean + Optional ByVal AllowReparse As Boolean = True, Optional ByVal PostText As String = Nothing) As Boolean If Not e Is Nothing Then Dim UPicType As Func(Of String, UTypes) = Function(input) IIf(input = "image", UTypes.Picture, UTypes.GIF) Dim eCount As Predicate(Of EContainer) = Function(item) item.Count > 0 @@ -513,24 +533,24 @@ Namespace API.Reddit If SaveToCache Then tmpUrl = e.Value({"media", "oembed"}, "thumbnail_url") If Not tmpUrl.IsEmptyString Then - _TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, tmpUrl, PostID, PostDate, UserID), LNC) + _TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, tmpUrl, PostID, PostDate, UserID,, PostText), LNC) _TotalPostsDownloaded += 1 Else added = False End If Else - _TempMediaList.ListAddValue(MediaFromData(UTypes.VideoPre, tmpUrl, PostID, PostDate, UserID), LNC) + _TempMediaList.ListAddValue(MediaFromData(UTypes.VideoPre, tmpUrl, PostID, PostDate, UserID,, PostText), LNC) _TotalPostsDownloaded += 1 End If - ElseIf CreateImgurMedia(tmpUrl, PostID, PostDate, UserID, IsChannel) Then + ElseIf CreateImgurMedia(tmpUrl, PostID, PostDate, UserID, IsChannel, PostText) Then _TotalPostsDownloaded += 1 - ElseIf DownloadGallery(e, PostID, PostDate, UserID, SaveToCache) Then + ElseIf DownloadGallery(e, PostID, PostDate, UserID, SaveToCache, PostText) Then _TotalPostsDownloaded += 1 ElseIf Not If(e({"media"}, "type")?.Value, String.Empty).IsEmptyString Then With e("media") Dim t$ = .Item("type").Value Select Case t - Case "gallery" : If DownloadGallery(.Self, PostID, PostDate) Then _TotalPostsDownloaded += 1 Else added = False + Case "gallery" : If DownloadGallery(.Self, PostID, PostDate,,, PostText) Then _TotalPostsDownloaded += 1 Else added = False Case "image", "gifvideo" Dim resolution As Sizes = Nothing @@ -565,17 +585,17 @@ Namespace API.Reddit End If If Not chosenVal.IsEmptyString Then - _TempMediaList.ListAddValue(MediaFromData(UPicType(t), chosenVal, PostID, PostDate, UserID), LNC) + _TempMediaList.ListAddValue(MediaFromData(UPicType(t), chosenVal, PostID, PostDate, UserID,, PostText), LNC) _TotalPostsDownloaded += 1 Else added = False End If Case "video" If UseM3U8 AndAlso .Item("hlsUrl").XmlIfNothingValue("/").ToLower.Contains("m3u8") Then - _TempMediaList.ListAddValue(MediaFromData(UTypes.m3u8, .Value("hlsUrl"), PostID, PostDate, UserID), LNC) + _TempMediaList.ListAddValue(MediaFromData(UTypes.m3u8, .Value("hlsUrl"), PostID, PostDate, UserID,, PostText), LNC) _TotalPostsDownloaded += 1 ElseIf Not UseM3U8 AndAlso .Item("fallback_url").XmlIfNothingValue("/").ToLower.Contains("mp4") Then - _TempMediaList.ListAddValue(MediaFromData(UTypes.Video, .Value("fallback_url"), PostID, PostDate, UserID), LNC) + _TempMediaList.ListAddValue(MediaFromData(UTypes.Video, .Value("fallback_url"), PostID, PostDate, UserID,, PostText), LNC) _TotalPostsDownloaded += 1 Else added = False @@ -588,16 +608,16 @@ Namespace API.Reddit If SaveToCache Then tmpUrl = GetVideoRedditPreview(e) If Not tmpUrl.IsEmptyString Then - _TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, tmpUrl, PostID, PostDate, UserID, False), LNC) + _TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, tmpUrl, PostID, PostDate, UserID, False, PostText), LNC) _TotalPostsDownloaded += 1 Else added = False End If ElseIf UseM3U8 AndAlso Not If(e({"media", "reddit_video"}, "hls_url")?.Value, String.Empty).IsEmptyString Then - _TempMediaList.ListAddValue(MediaFromData(UTypes.m3u8, e.Value({"media", "reddit_video"}, "hls_url"), PostID, PostDate, UserID), LNC) + _TempMediaList.ListAddValue(MediaFromData(UTypes.m3u8, e.Value({"media", "reddit_video"}, "hls_url"), PostID, PostDate, UserID,, PostText), LNC) _TotalPostsDownloaded += 1 Else - _TempMediaList.ListAddValue(MediaFromData(UTypes.Video, tmpUrl, PostID, PostDate, UserID), LNC) + _TempMediaList.ListAddValue(MediaFromData(UTypes.Video, tmpUrl, PostID, PostDate, UserID,, PostText), LNC) _TotalPostsDownloaded += 1 End If Else @@ -606,7 +626,7 @@ Namespace API.Reddit If Not added Then If AllowReparse Then If If(e.ItemF({"crosspost_parent_list", 0})?.Count, 0) > 0 Then - added = ParseContainer(e.ItemF({"crosspost_parent_list", 0}), PostID, PostDate, UserID, True) + added = ParseContainer(e.ItemF({"crosspost_parent_list", 0}), PostID, PostDate, UserID, True, PostText) Else Dim tPostId$ = e.Value(Node_CrosspostParent).IfNullOrEmpty(e.Value(Node_CrosspostParentId)).IfNullOrEmpty(e.Value(Node_CrosspostRootId)) If Not PostID.IsEmptyString Then @@ -615,7 +635,7 @@ Namespace API.Reddit Using j As EContainer = JsonDocument.Parse(r, EDP.ReturnValue) If j.ListExists Then With j.ItemF({0, "data", "children", 0, "data"}) - If .ListExists Then added = ParseContainer(.Self, PostID, PostDate, UserID, False) + If .ListExists Then added = ParseContainer(.Self, PostID, PostDate, UserID, False, PostText) End With End If End Using @@ -637,7 +657,7 @@ Namespace API.Reddit End Select End With If Not tmpType = UTypes.Undefined Then - _TempMediaList.ListAddValue(MediaFromData(tmpType, node.Value, PostID, PostDate, UserID), LNC) + _TempMediaList.ListAddValue(MediaFromData(tmpType, node.Value, PostID, PostDate, UserID,, PostText), LNC) added = True End If End If @@ -660,7 +680,7 @@ Namespace API.Reddit If Not tmpUrl.IsEmptyString Then tmpType = UTypes.Picture End If If Not tmpUrl.IsEmptyString And Not tmpType = UTypes.Undefined Then - Dim m As UserMedia = MediaFromData(tmpType, tmpUrl, PostID, PostDate, UserID) + Dim m As UserMedia = MediaFromData(tmpType, tmpUrl, PostID, PostDate, UserID,, PostText) If tmpType = UTypes.Video Then m.File.Extension = "mp4" _TempMediaList.ListAddValue(m, LNC) _TotalPostsDownloaded += 1 @@ -671,6 +691,7 @@ Namespace API.Reddit End If End If End If + If Not added And Not PostText.IsEmptyString Then _TempMediaList.ListAddValue(MediaFromData(UTypes.Text, String.Empty, PostID, PostDate, UserID,, PostText)) Return added Else Return False @@ -693,28 +714,45 @@ Namespace API.Reddit Return False End Try End Function + Private Function GetTextDocument(ByVal e As EContainer) As String + Dim t$ = String.Empty + Try + t = e.Value("title") + With e({"rtjson", "document"}) + If .ListExists Then + For Each tt As EContainer In .Self + t.StringAppendLine(vbCrLf,, False) + t.StringAppendLine(If(tt.ItemF({"c", 0, "t"})?.Value, String.Empty)) + Next + End If + End With + Catch + End Try + Return t + End Function #End Region #Region "Download Base Functions" Private Function CreateImgurMedia(ByVal _URL As String, ByVal PostID As String, ByVal PostDate As String, - Optional ByVal _UserID As String = "", Optional ByVal IsChannel As Boolean = False) As Boolean + Optional ByVal _UserID As String = "", Optional ByVal IsChannel As Boolean = False, + Optional ByVal PostText As String = Nothing) As Boolean If Not _URL.IsEmptyString AndAlso _URL.Contains("imgur") Then If _URL.StringContains({".jpg", ".png", ".jpeg"}) Then - _TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, _URL, PostID, PostDate, _UserID), LNC) + _TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, _URL, PostID, PostDate, _UserID,, PostText), LNC) ElseIf _URL.Contains(".gifv") Then If SaveToCache Then - _TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, _URL.Replace(".gifv", ".gif"), PostID, PostDate, _UserID), LNC) + _TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, _URL.Replace(".gifv", ".gif"), PostID, PostDate, _UserID,, PostText), LNC) Else - _TempMediaList.ListAddValue(MediaFromData(UTypes.Video, _URL.Replace(".gifv", ".mp4"), PostID, PostDate, _UserID), LNC) + _TempMediaList.ListAddValue(MediaFromData(UTypes.Video, _URL.Replace(".gifv", ".mp4"), PostID, PostDate, _UserID,, PostText), LNC) End If ElseIf _URL.Contains(".mp4") Then - _TempMediaList.ListAddValue(MediaFromData(UTypes.Video, _URL, PostID, PostDate, _UserID), LNC) + _TempMediaList.ListAddValue(MediaFromData(UTypes.Video, _URL, PostID, PostDate, _UserID,, PostText), LNC) ElseIf _URL.Contains(".gif") Then - _TempMediaList.ListAddValue(MediaFromData(UTypes.GIF, _URL, PostID, PostDate, _UserID), LNC) + _TempMediaList.ListAddValue(MediaFromData(UTypes.GIF, _URL, PostID, PostDate, _UserID,, PostText), LNC) Else Dim obj As IEnumerable(Of UserMedia) = Imgur.Envir.GetVideoInfo(_URL, EDP.ReturnValue) If Not obj.ListExists Then If Not TryFile(_URL) Then _URL &= ".jpg" - _TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, _URL, PostID, PostDate, _UserID), LNC) + _TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, _URL, PostID, PostDate, _UserID,, PostText), LNC) Else Dim ut As UTypes Dim m As UserMedia @@ -729,7 +767,7 @@ Namespace API.Reddit Case "gif" : ut = UTypes.GIF Case Else : ut = UTypes.Picture : .File.Extension = "jpg" End Select - m = MediaFromData(ut, _URL, PostID, PostDate, _UserID) + m = MediaFromData(ut, _URL, PostID, PostDate, _UserID,, PostText) m.URL = .URL m.File = .File.File _TempMediaList.ListAddValue(m, LNC) @@ -745,7 +783,8 @@ Namespace API.Reddit End If End Function Private Function DownloadGallery(ByVal e As EContainer, ByVal PostID As String, ByVal PostDate As String, - Optional ByVal _UserID As String = Nothing, Optional ByVal FirstOnly As Boolean = False) As Boolean + Optional ByVal _UserID As String = Nothing, Optional ByVal FirstOnly As Boolean = False, + Optional ByVal PostText As String = Nothing) As Boolean Try Dim added As Boolean = False Dim node As EContainer = Nothing @@ -759,7 +798,7 @@ Namespace API.Reddit For Each n As EContainer In node t = n.ItemF({"s", "u"}) If Not t Is Nothing AndAlso Not t.Value.IsEmptyString Then - _TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, t.Value, PostID, PostDate, _UserID), LNC) + _TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, t.Value, PostID, PostDate, _UserID,, PostText), LNC) added = True If FirstOnly Then Exit For End If @@ -876,7 +915,7 @@ Namespace API.Reddit If Not r.IsEmptyString Then v = RegexReplace(r, VideoRegEx) If Not v.IsEmptyString Then - _TempMediaList(i) = New UserMedia With {.Type = UTypes.Video, .URL = v, .File = v, .Post = m.Post} + _TempMediaList(i) = New UserMedia With {.Type = UTypes.Video, .URL = v, .File = v, .Post = m.Post, .PostText = m.PostText, .PostTextFile = m.PostTextFile} Else _TempMediaList.RemoveAt(i) End If @@ -924,7 +963,7 @@ Namespace API.Reddit If j.Count > 0 Then lastCount = _TempMediaList.Count With j.GetNode(SingleJsonNodes) - If .ListExists AndAlso ParseContainer(.Self, m.Post.ID, String.Empty) Then + If .ListExists AndAlso ParseContainer(.Self, m.Post.ID, String.Empty,,, GetTextDocument(.Self)) Then If lastCount <> _TempMediaList.Count Then For li = IIf(lastCount < 0, 0, lastCount) To _TempMediaList.Count - 1 m2 = _TempMediaList(i) @@ -971,13 +1010,15 @@ Namespace API.Reddit #End Region #Region "Structure creator" Private Function MediaFromData(ByVal t As UTypes, ByVal _URL As String, ByVal PostID As String, ByVal PostDate As String, - Optional ByVal _UserID As String = "", Optional ByVal ReplacePreview As Boolean = True) As UserMedia + Optional ByVal _UserID As String = "", Optional ByVal ReplacePreview As Boolean = True, + Optional ByVal PostText As String = Nothing) As UserMedia If _URL.IsEmptyString And t = UTypes.Picture Then Return Nothing _URL = LinkFormatterSecure(RegexReplace(_URL.Replace("\", String.Empty), LinkPattern)) Dim m As New UserMedia(_URL, t) With {.Post = New UserPost With {.ID = PostID, .UserID = _UserID}} If t = UTypes.Picture Or t = UTypes.GIF Then m.File = CreateFileFromUrl(m.URL) Else m.File = Nothing If ReplacePreview And m.URL.Contains("preview") And Not t = UTypes.Picture Then m.URL = $"https://i.redd.it/{m.File.File}" If Not PostDate.IsEmptyString Then m.Post.Date = AConvert(Of Date)(PostDate, DateTrueProvider(IsChannel Or IsSavedPosts), Nothing) Else m.Post.Date = Nothing + If Not PostText.IsEmptyString Then m.PostText = PostText Return m End Function Private Function TryFile(ByVal URL As String) As Boolean diff --git a/SCrawler/API/Redgifs/SiteSettings.vb b/SCrawler/API/Redgifs/SiteSettings.vb index 798f76b..3fafd25 100644 --- a/SCrawler/API/Redgifs/SiteSettings.vb +++ b/SCrawler/API/Redgifs/SiteSettings.vb @@ -31,6 +31,9 @@ Namespace API.RedGifs Private ReadOnly Property TokenUpdateIntervalProvider As IFormatProvider #End Region + Friend Overrides Property DownloadText As PropertyValue + Friend Overrides Property DownloadTextPosts As PropertyValue + Friend Overrides Property DownloadTextSpecialFolder As PropertyValue #End Region #Region "Initializer" Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean) diff --git a/SCrawler/API/ThisVid/SiteSettings.vb b/SCrawler/API/ThisVid/SiteSettings.vb index b5010ed..bf2df65 100644 --- a/SCrawler/API/ThisVid/SiteSettings.vb +++ b/SCrawler/API/ThisVid/SiteSettings.vb @@ -27,6 +27,9 @@ Namespace API.ThisVid "If true, then public videos will be stored in the 'Public' folder, private - in the 'Private' folder." & vbCr & "If false, all videos will be stored in the 'Video' folder."), PClonable> Friend ReadOnly Property DifferentFolders As PropertyValue + Friend Overrides Property DownloadText As PropertyValue + Friend Overrides Property DownloadTextPosts As PropertyValue + Friend Overrides Property DownloadTextSpecialFolder As PropertyValue #End Region #Region "Initializer" Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean) diff --git a/SCrawler/API/ThreadsNet/SiteSettings.vb b/SCrawler/API/ThreadsNet/SiteSettings.vb index 954d570..2030bf8 100644 --- a/SCrawler/API/ThreadsNet/SiteSettings.vb +++ b/SCrawler/API/ThreadsNet/SiteSettings.vb @@ -89,7 +89,7 @@ Namespace API.ThreadsNet #End Region #Region "Initializer" Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean) - Me.New("Threads", "threads.net", AccName, Temp, My.Resources.SiteResources.ThreadsIcon_192, My.Resources.SiteResources.ThreadsIcon_192.ToBitmap) + Me.New("Threads", "threads.com", AccName, Temp, My.Resources.SiteResources.ThreadsIcon_192, My.Resources.SiteResources.ThreadsIcon_192.ToBitmap) End Sub Protected Sub New(ByVal SiteName As String, ByVal CookiesDomain As String, ByVal AccName As String, ByVal Temp As Boolean, Optional ByVal __Icon As Icon = Nothing, Optional ByVal __Image As Image = Nothing) @@ -118,8 +118,8 @@ Namespace API.ThreadsNet browserExt = .Value(IG.Header_BrowserExt) platform = .Value(IG.Header_Platform_Verion) End If - .Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.Authority, "www.threads.net")) - .Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.Origin, "https://www.threads.net")) + .Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.Authority, "www.threads.com")) + .Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.Origin, "https://www.threads.com")) .Add("Upgrade-Insecure-Requests", 1) .Add("Sec-Ch-Ua-Model", "") .Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecChUaMobile, "?0")) @@ -152,9 +152,9 @@ Namespace API.ThreadsNet RequestsWaitTimer_AnyProvider = New IG.TimersChecker(0) DownloadData_Impl = New PropertyValue(True) - UrlPatternUser = "https://www.threads.net/@{0}" - UserRegex = RParams.DMS(String.Format(UserRegexDefaultPattern, "threads.net/@"), 1) - ImageVideoContains = "threads.net" + UrlPatternUser = "https://www.threads.com/@{0}" + UserRegex = RParams.DMS(String.Format(UserRegexDefaultPattern, "threads.(net|com)/@"), 2) + ImageVideoContains = "threads.com" UserOptionsType = GetType(EditorExchangeOptionsBase) End Sub #End Region @@ -185,7 +185,7 @@ Namespace API.ThreadsNet Try Dim code$ = DirectCast(User, UserData).GetPostCodeById(Media.Post.ID) Dim name$ = DirectCast(User, UserData).NameTrue - If Not code.IsEmptyString Then Return $"https://www.threads.net/@{name}/post/{code}/" Else Return String.Empty + If Not code.IsEmptyString Then Return $"https://www.threads.com/@{name}/post/{code}/" Else Return String.Empty Catch ex As Exception Return ErrorsDescriber.Execute(EDP.SendToLog, ex, "Can't open user's post", String.Empty) End Try diff --git a/SCrawler/API/ThreadsNet/UserData.vb b/SCrawler/API/ThreadsNet/UserData.vb index a0328c0..e1f125a 100644 --- a/SCrawler/API/ThreadsNet/UserData.vb +++ b/SCrawler/API/ThreadsNet/UserData.vb @@ -55,7 +55,7 @@ Namespace API.ThreadsNet Return New EditorExchangeOptionsBase(Me) End Function Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object) - If Not Obj Is Nothing AndAlso TypeOf Obj Is EditorExchangeOptionsBase Then NameTrue = DirectCast(Obj, EditorExchangeOptionsBase).UserName + If Not Obj Is Nothing AndAlso TypeOf Obj Is EditorExchangeOptionsBase Then DirectCast(Obj, EditorExchangeOptionsBase).ApplyBase(Me) End Sub #End Region #Region "Initializer" @@ -63,7 +63,7 @@ Namespace API.ThreadsNet ObtainMedia_SetReelsFunc() ObtainMedia_AllowAbstract = True DefaultParser_ElemNode = DefaultParser_ElemNode_Default - DefaultParser_PostUrlCreator = Function(post) $"https://www.threads.net/@{NameTrue}/post/{post.Code}" + DefaultParser_PostUrlCreator = Function(post) $"https://www.threads.com/@{NameTrue}/post/{post.Code}" _ResponserAutoUpdateCookies = True _ResponserAddResponseReceivedHandler = True DefaultParser_Pinned = AddressOf IsPinnedPost @@ -157,8 +157,8 @@ Namespace API.ThreadsNet Responser.Headers.Add(IGS.Header_CSRF_TOKEN, csrf) End If End Sub - 'Private Const GQL_Q As String = "https://www.threads.net/api/graphql?lsd={0}&fb_dtsg={1}&doc_id={2}&fb_api_req_friendly_name={3}&server_timestamps=true&variables={4}" - Private Const GQL_Q2 As String = "https://www.threads.net/graphql/query" + 'Private Const GQL_Q As String = "https://www.threads.com/api/graphql?lsd={0}&fb_dtsg={1}&doc_id={2}&fb_api_req_friendly_name={3}&server_timestamps=true&variables={4}" + Private Const GQL_Q2 As String = "https://www.threads.com/graphql/query" Private Const PayloadData As String = "lsd={0}&fb_dtsg={1}&doc_id={2}&fb_api_req_friendly_name={3}&server_timestamps=true&variables={4}" Private Const GQL_P_DOC_ID As String = "9039187972876777" '"8779269398849532" '"6371597506283707" Private Const GQL_P_NAME As String = "BarcelonaProfileThreadsTabRefetchableDirectQuery" '"BarcelonaProfileThreadsTabRefetchableQuery" @@ -223,7 +223,7 @@ Namespace API.ThreadsNet With Responser .Method = "POST" - .Referer = $"https://www.threads.net/@{NameTrue}" + .Referer = $"https://www.threads.com/@{NameTrue}" .ContentType = "application/x-www-form-urlencoded" With .Headers .Add(GQL_HEADER_FB_LSD, Token_lsd) @@ -286,7 +286,7 @@ Namespace API.ThreadsNet With Responser .Method = "POST" - .Referer = "https://www.threads.net/" + .Referer = "https://www.threads.com/" .ContentType = "application/x-www-form-urlencoded" With .Headers .Add(GQL_HEADER_FB_LSD, Token_lsd) @@ -358,7 +358,7 @@ Namespace API.ThreadsNet End Function Private _IdChanged As Boolean = False Private Function UpdateCredentials(Optional ByVal e As ErrorsDescriber = Nothing) As Boolean - Dim URL$ = If(IsSavedPosts, "https://www.threads.net/", $"https://www.threads.net/@{NameTrue}") + Dim URL$ = If(IsSavedPosts, "https://www.threads.com/", $"https://www.threads.com/@{NameTrue}") ResetBaseTokens() Dim headers As New HttpHeaderCollection headers.AddRange(Responser.Headers) @@ -369,8 +369,8 @@ Namespace API.ThreadsNet With .Headers .Clear() .Add("dnt", 1) - .Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.Authority, "www.threads.net")) - .Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.Origin, "https://www.threads.net")) + .Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.Authority, "www.threads.com")) + .Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.Origin, "https://www.threads.com")) .Add("Sec-Ch-Ua-Model", "") .Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecChUaMobile, "?0")) .Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecChUaPlatform, """Windows""")) @@ -432,7 +432,7 @@ Namespace API.ThreadsNet 'Const varsPattern$ = """postID"":""{0}"",""userID"":""{1}"",""__relay_internal__pv__BarcelonaIsLoggedInrelayprovider"":true,""__relay_internal__pv__BarcelonaIsFeedbackHubEnabledrelayprovider"":false" Const varsPattern$ = """postID"":""{0}"",""__relay_internal__pv__BarcelonaIsLoggedInrelayprovider"":true,""__relay_internal__pv__BarcelonaShouldShowFediverseM1Featuresrelayprovider"":true,""__relay_internal__pv__BarcelonaShareableListsrelayprovider"":true,""__relay_internal__pv__BarcelonaIsSearchDiscoveryEnabledrelayprovider"":false,""__relay_internal__pv__BarcelonaOptionalCookiesEnabledrelayprovider"":true,""__relay_internal__pv__BarcelonaQuotedPostUFIEnabledrelayprovider"":false,""__relay_internal__pv__BarcelonaIsCrawlerrelayprovider"":false,""__relay_internal__pv__BarcelonaHasDisplayNamesrelayprovider"":false,""__relay_internal__pv__BarcelonaCanSeeSponsoredContentrelayprovider"":false,""__relay_internal__pv__BarcelonaShouldShowFediverseM075Featuresrelayprovider"":true,""__relay_internal__pv__BarcelonaShouldShowTagRedesignrelayprovider"":false,""__relay_internal__pv__BarcelonaIsInternalUserrelayprovider"":false,""__relay_internal__pv__BarcelonaInlineComposerEnabledrelayprovider"":false" 'Const varsPattern$ = "{""postID"":""{0}"",""__relay_internal__pv__BarcelonaIsLoggedInrelayprovider"":true,""__relay_internal__pv__BarcelonaIsFeedbackHubEnabledrelayprovider"":false}" - 'Const urlPattern$ = "https://www.threads.net/api/graphql?lsd={0}&variables={1}&fb_api_req_friendly_name=BarcelonaPostPageQuery&server_timestamps=true&fb_dtsg={2}&doc_id=25460088156920903" + 'Const urlPattern$ = "https://www.threads.com/api/graphql?lsd={0}&variables={1}&fb_api_req_friendly_name=BarcelonaPostPageQuery&server_timestamps=true&fb_dtsg={2}&doc_id=25460088156920903" Dim rList As New List(Of Integer) DefaultParser_ElemNode = Nothing DefaultParser_IgnorePass = True @@ -440,7 +440,7 @@ Namespace API.ThreadsNet If ContentMissingExists Then Responser.Method = "POST" Responser.ContentType = "application/x-www-form-urlencoded" - Responser.Referer = $"https://www.threads.net/@{NameTrue}" + Responser.Referer = $"https://www.threads.com/@{NameTrue}" If Not IsSingleObjectDownload AndAlso Not UpdateCredentials() Then Throw New Exception("Failed to update credentials") Dim m As UserMedia Dim vars$ diff --git a/SCrawler/API/TikTok/SiteSettings.vb b/SCrawler/API/TikTok/SiteSettings.vb index 29fef64..f09c111 100644 --- a/SCrawler/API/TikTok/SiteSettings.vb +++ b/SCrawler/API/TikTok/SiteSettings.vb @@ -43,6 +43,9 @@ Namespace API.TikTok Friend ReadOnly Property UseParsedVideoDateSTD As PropertyValue + Friend Overrides Property DownloadText As PropertyValue + Friend Overrides Property DownloadTextPosts As PropertyValue + Friend Overrides Property DownloadTextSpecialFolder As PropertyValue Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean) MyBase.New("TikTok", "www.tiktok.com", AccName, Temp, My.Resources.SiteResources.TikTokIcon_32, My.Resources.SiteResources.TikTokPic_192) diff --git a/SCrawler/API/TikTok/UserData.vb b/SCrawler/API/TikTok/UserData.vb index 2308d6f..eab10b2 100644 --- a/SCrawler/API/TikTok/UserData.vb +++ b/SCrawler/API/TikTok/UserData.vb @@ -188,6 +188,7 @@ Namespace API.TikTok Dim photoNode As Object() = GetPhotoNode() Dim c%, cc%, i% Dim errDef As New ErrorsDescriber(EDP.ReturnValue) + Dim infoParsed As Boolean = False If _ContentList.Count > 0 Then With (From d In _ContentList Where d.Post.Date.HasValue Select d.Post.Date.Value) @@ -309,6 +310,29 @@ Namespace API.TikTok Case DateResult.Skip : Continue For Case DateResult.Exit : Exit For 'Exit Sub End Select + + If Not infoParsed Then + With .Item("author") + If .ListExists Then + infoParsed = True + SimpleDownloadAvatar(.Value("avatarLarger").IfNullOrEmpty(.Value("avatarMedium")).IfNullOrEmpty(.Value("avatarThumb")), + Function(ByVal ____url As String) As SFile + Dim ____f As SFile = CreateFileFromUrl(____url) + If Not ____f.Name.IsEmptyString Then ____f.Name = ____f.Name.Replace(":", "_").Replace("~", "-") + If Not ____f.Extension.IsEmptyString Then + If Not (____f.Extension = "jpg" Or ____f.Extension = "jpeg") Then + ____f.Extension = RegexReplace(____f.Extension, RParams.DMS("(.+)\?", 1, EDP.ReturnValue)) + If Not ____f.Extension.IsEmptyString AndAlso Not (____f.Extension = "jpg" Or ____f.Extension = "jpeg") Then ____f.Extension = String.Empty + End If + End If + Return ____f + End Function) + UserSiteNameUpdate(.Value("nickname")) + UserDescriptionUpdate(.Value("signature")) + End If + End With + End If + title = GetNewFileName(j.Value({"imagePost"}, "title").StringRemoveWinForbiddenSymbols, TitleUseNative, RemoveTagsFromTitle, TitleAddVideoID, postID, titleRegex) postUrl = $"https://www.tiktok.com/@{Name}/photo/{postID}" diff --git a/SCrawler/API/Twitter/EditorExchangeOptions.vb b/SCrawler/API/Twitter/EditorExchangeOptions.vb index 66da405..8dd7a89 100644 --- a/SCrawler/API/Twitter/EditorExchangeOptions.vb +++ b/SCrawler/API/Twitter/EditorExchangeOptions.vb @@ -52,6 +52,7 @@ Namespace API.Twitter Friend Overridable Property DownloadModelForceApply As Boolean = False Private ReadOnly Property MySettings As Object Friend Sub New(ByVal s As SiteSettings) + MyBase.New(s) GifsDownload = s.GifsDownload.Value GifsSpecialFolder = s.GifsSpecialFolder.Value GifsPrefix = s.GifsPrefix.Value diff --git a/SCrawler/API/Twitter/UserData.vb b/SCrawler/API/Twitter/UserData.vb index a537665..0752db2 100644 --- a/SCrawler/API/Twitter/UserData.vb +++ b/SCrawler/API/Twitter/UserData.vb @@ -89,6 +89,7 @@ Namespace API.Twitter Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object) If Not Obj Is Nothing AndAlso TypeOf Obj Is EditorExchangeOptions Then With DirectCast(Obj, EditorExchangeOptions) + .ApplyBase(Me) GifsDownload = .GifsDownload GifsSpecialFolder = .GifsSpecialFolder GifsPrefix = .GifsPrefix @@ -105,7 +106,6 @@ Namespace API.Twitter If .DownloadModelSearch Then DownloadModel += DownloadModels.Search If .DownloadModelLikes Then DownloadModel += DownloadModels.Likes If Not dModel = DownloadModel Then DownloadModelChanged = True - NameTrue = .UserName End With End If End Sub @@ -257,9 +257,13 @@ Namespace API.Twitter Return result End Function Friend Property GDL_REQUESTS_COUNT As Integer = 0 + Private Const DEBUG_PROFILE As Boolean = False + Private Const DEBUG_LEAVE_CACHE As Boolean = False + Private JsonNullErr As Boolean = False Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken) Try GDL_REQUESTS_COUNT = 0 + JsonNullErr = False If MySettings.LIMIT_ABORT Then Throw New TwitterLimitException(Me) Else @@ -277,6 +281,7 @@ Namespace API.Twitter LikesPosts.Clear() If _ContentList.Count > 0 Then _DataNames.ListAddList(_ContentList.Select(Function(c) c.File.File), LAP.ClearBeforeAdd, LAP.NotContainsOnly) DownloadData_Timeline(Token) + If _TempMediaList.Count = 0 And LikesPosts.Count = 0 And JsonNullErr Then Throw New Plugin.ExitException("No deserialized data found") LoadSavePostsKV(False) If LikesPosts.Count > 0 Then _ReparseLikes = True @@ -289,10 +294,20 @@ Namespace API.Twitter _ReparseLikes = False End Try End Sub + Private Class WebDocumentEventArgsT : Inherits WebDocumentEventArgs + Public Overloads Overrides Sub Reset() + State = States.None + End Sub + Public Overloads Sub Reset(ByVal Token As CancellationToken) + Reset() + Me.Token = Token + End Sub + End Class Private Sub DownloadData_Timeline(ByVal Token As CancellationToken) Dim URL$ = String.Empty Dim tCache As CacheKeeper = Nothing Dim likesDetected As Boolean = False + Dim jsonArgs As New WebDocumentEventArgsT With {.DeclaredError = New ErrorsDescriber(EDP.ReturnValue)} Try Const entry$ = "entry" Dim PostID$ = String.Empty @@ -340,6 +355,8 @@ Namespace API.Twitter ElseIf dirIndx = 3 Then ElseIf isPins Then Return False + ElseIf Not FirstDownloadComplete Then + Return True Else ExistsDetected = Not multiMode Return multiMode @@ -379,13 +396,24 @@ Namespace API.Twitter Return True End Function - tCache = CreateCache() + If Not DEBUG_PROFILE Then tCache = CreateCache() '0 - media '1 - profile '2 - search '3 - likes - Dim dirs As List(Of SFile) = GetTimelineFromGalleryDL(tCache, Token) + Dim dirs As List(Of SFile) + If Not DEBUG_PROFILE Then + dirs = GetTimelineFromGalleryDL(tCache, Token) + Else + dirs = SFile.GetDirectories($"{DownloadContentDefault_GetRootDir()}\_tCache\".CSFileP) + If dirs.ListExists(2) Then + dirs = SFile.GetDirectories(dirs(1)) + Else + dirs = New List(Of SFile) + End If + End If + If dirs.ListExists Then For Each dir As SFile In dirs dirIndx += 1 @@ -408,12 +436,18 @@ Namespace API.Twitter If timelineFiles.ListExists Then ResetFileNameProvider(Math.Max(timelineFiles.Count.ToString.Length, 2)) 'rename files - For i = 0 To timelineFiles.Count - 1 : timelineFiles(i) = RenameGdlFile(timelineFiles(i), i) : Next + If Not DEBUG_PROFILE Then + For i = 0 To timelineFiles.Count - 1 : timelineFiles(i) = RenameGdlFile(timelineFiles(i), i) : Next + End If 'parse files For i = 0 To timelineFiles.Count - 1 - j = JsonDocument.Parse(timelineFiles(i).GetText) + j = JsonDocument.Parse(timelineFiles(i).GetText, jsonArgs) + If jsonArgs.State = WebDocumentEventArgs.States.Error Then + jsonArgs.Reset(Token) + Continue For + End If If Not j Is Nothing Then - If i = 0 And Not indxChanged Then + If Not userInfoParsed Or (i = 0 And Not indxChanged) Then If Not userInfoParsed Then userInfoParsed = True Dim resValue$ = j.Value({"data", IIf(IsCommunity, "communityResults", "user"), "result"}, "__typename").StringTrim.StringToLower @@ -498,6 +532,8 @@ Namespace API.Twitter Select Case dirIndx Case 0, 1, 3 rootNode = j({"data", "user", "result", "timeline_v2", "timeline", "instructions"}) + If Not rootNode.ListExists Then rootNode = j({"data", "user", "result", "timeline", "timeline", "instructions"}) + If Not rootNode.ListExists Then rootNode = j({"data", "search_by_raw_query", "search_timeline", "timeline", "instructions"}) If rootNode.ListExists Then If dirIndx = 3 Then p = entriesNode @@ -589,8 +625,9 @@ nextpIndx: Catch ex As Exception ProcessException(ex, Token, $"data downloading error [{URL}]") Finally - If Not tCache Is Nothing Then tCache.Dispose() + If Not tCache Is Nothing And Not DEBUG_PROFILE And Not DEBUG_LEAVE_CACHE Then tCache.Dispose() If _TempPostsList.Count > 0 And Not likesDetected Then _TempPostsList.Sort() + jsonArgs.DisposeIfReady(False) End Try End Sub Private Sub DownloadData_SavedPosts(ByVal Token As CancellationToken) @@ -642,30 +679,42 @@ nextpIndx: Dim s As EContainer = e({"extended_entities", "media"}) If If(s?.Count, 0) = 0 Then s = e({"retweeted_status", "extended_entities", "media"}) If If(s?.Count, 0) = 0 Then s = e({"retweeted_status_result", "result", "legacy", "extended_entities", "media"}) + Dim txt$ = If(DownloadText, e.Value("full_text"), String.Empty) + Dim mUrl$ + Dim media As UserMedia + Dim setMediaDef As Action = Sub() + If Not SpecialFolder.IsEmptyString Then media.SpecialFolder = SpecialFolder + media.PostText = txt + media.PostTextFileSpecialFolder = DownloadTextSpecialFolder + End Sub If If(s?.Count, 0) > 0 Then - Dim mUrl$ - Dim media As UserMedia For Each m As EContainer In s - If Not CheckVideoNode(m, PostID, PostDate, State, SpecialFolder) Then + If Not CheckVideoNode(m, PostID, PostDate, State, SpecialFolder, txt) Then mUrl = m.Value("media_url").IfNullOrEmpty(m.Value("media_url_https")) If Not mUrl.IsEmptyString Then Dim dName$ = UrlFile(mUrl) If Not dName.IsEmptyString AndAlso Not _DataNames.Contains(dName) Then _DataNames.Add(dName) media = MediaFromData(mUrl, PostID, PostDate, GetPictureOption(m), State, UTypes.Picture, Attempts) - If Not SpecialFolder.IsEmptyString Then media.SpecialFolder = SpecialFolder + setMediaDef() _TempMediaList.ListAddValue(media, LNC) End If End If End If Next + ElseIf Not txt.IsEmptyString And DownloadTextPosts Then + media = MediaFromData(PostID, PostID, PostDate, String.Empty, State, UTypes.Text, Attempts) + setMediaDef() + media.PostTextFile = $"{PostID}.txt" + _TempMediaList.ListAddValue(media, LNC) End If End Sub Private Function CheckVideoNode(ByVal w As EContainer, ByVal PostID As String, ByVal PostDate As String, - Optional ByVal State As UStates = UStates.Unknown, Optional ByVal SpecialFolder As String = Nothing) As Boolean + Optional ByVal State As UStates = UStates.Unknown, Optional ByVal SpecialFolder As String = Nothing, + Optional ByVal PostText As String = Nothing) As Boolean Try - If CheckForGif(w, PostID, PostDate, State, SpecialFolder) Then Return True + If CheckForGif(w, PostID, PostDate, State, SpecialFolder, PostText) Then Return True Dim URL$ = GetVideoNodeURL(w) If Not URL.IsEmptyString Then Dim f$ = UrlFile(URL) @@ -673,6 +722,7 @@ nextpIndx: _DataNames.Add(f) Dim m As UserMedia = MediaFromData(URL, PostID, PostDate,, State, UTypes.Video) If Not SpecialFolder.IsEmptyString Then m.SpecialFolder = SpecialFolder + m.PostText = PostText _TempMediaList.ListAddValue(m, LNC) End If Return True @@ -684,7 +734,8 @@ nextpIndx: End Try End Function Private Function CheckForGif(ByVal w As EContainer, ByVal PostID As String, ByVal PostDate As String, - Optional ByVal State As UStates = UStates.Unknown, Optional ByVal SpecialFolder As String = Nothing) As Boolean + Optional ByVal State As UStates = UStates.Unknown, Optional ByVal SpecialFolder As String = Nothing, + Optional ByVal PostText As String = Nothing) As Boolean Try Dim gifUrl As Predicate(Of EContainer) = Function(e) Not e.Value("content_type").IsEmptyString AndAlso e.Value("content_type").Contains("mp4") AndAlso @@ -710,6 +761,7 @@ nextpIndx: If Not m.SpecialFolder.IsEmptyString Then m.SpecialFolder &= "\" m.SpecialFolder &= $"{GifsSpecialFolder}*" End If + m.PostText = PostText _TempMediaList.ListAddValue(m, LNC) End If Return True diff --git a/SCrawler/API/XVIDEOS/SiteSettings.vb b/SCrawler/API/XVIDEOS/SiteSettings.vb index fa47c26..0e59f69 100644 --- a/SCrawler/API/XVIDEOS/SiteSettings.vb +++ b/SCrawler/API/XVIDEOS/SiteSettings.vb @@ -35,6 +35,9 @@ Namespace API.XVIDEOS "This playlist must be entered by pattern: https://www.xvideos.com/favorite/01234567/playlistname.", LeftOffset:=130), PXML, PClonable(Clone:=False)> Friend ReadOnly Property SavedVideosPlaylist As PropertyValue + Friend Overrides Property DownloadText As PropertyValue + Friend Overrides Property DownloadTextPosts As PropertyValue + Friend Overrides Property DownloadTextSpecialFolder As PropertyValue #End Region #Region "Initializer" Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean) diff --git a/SCrawler/API/Xhamster/SiteSettings.vb b/SCrawler/API/Xhamster/SiteSettings.vb index f59c45c..2dc4d78 100644 --- a/SCrawler/API/Xhamster/SiteSettings.vb +++ b/SCrawler/API/Xhamster/SiteSettings.vb @@ -33,6 +33,9 @@ Namespace API.Xhamster ControlToolTip:="If enabled and the video is downloaded in a non-native format, the video will be re-encoded." & vbCr & "Attention! Enabling this setting results in maximum CPU usage."), PXML, PClonable> Friend ReadOnly Property ReencodeVideos As PropertyValue + Friend Overrides Property DownloadText As PropertyValue + Friend Overrides Property DownloadTextPosts As PropertyValue + Friend Overrides Property DownloadTextSpecialFolder As PropertyValue #End Region #Region "Initializer" Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean) diff --git a/SCrawler/API/Xhamster/UserData.vb b/SCrawler/API/Xhamster/UserData.vb index 421af09..e0d6d8b 100644 --- a/SCrawler/API/Xhamster/UserData.vb +++ b/SCrawler/API/Xhamster/UserData.vb @@ -615,7 +615,7 @@ Namespace API.Xhamster If m.Post.ID.IsEmptyString Then m.Post.ID = m.URL.Split("/").LastOrDefault If m.PictureOption.IsEmptyString Then m.PictureOption = TitleHtmlConverter(j.Value("titleLocalized")) If m.PictureOption.IsEmptyString Then m.PictureOption = m.Post.ID - If setSpecialFolder Then m.SpecialFolder = m.PictureOption + If setSpecialFolder Then m.SpecialFolder = IIf(t = UTypes.Picture, "Photo\", String.Empty) & m.PictureOption If processFile Then If Not m.PictureOption.IsEmptyString Then diff --git a/SCrawler/API/YouTube/SiteSettings.vb b/SCrawler/API/YouTube/SiteSettings.vb index d916867..93dd1ad 100644 --- a/SCrawler/API/YouTube/SiteSettings.vb +++ b/SCrawler/API/YouTube/SiteSettings.vb @@ -31,6 +31,9 @@ Namespace API.YouTube Friend ReadOnly Property DownloadCommunityImages As PropertyValue Friend ReadOnly Property DownloadCommunityVideos As PropertyValue + Friend Overrides Property DownloadText As PropertyValue + Friend Overrides Property DownloadTextPosts As PropertyValue + Friend Overrides Property DownloadTextSpecialFolder As PropertyValue #End Region #Region "Communities" iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABkSURBVDhPY6AKyO86WFDQfeg/iIYKkQZAmkNbnvyXta76 - DxViYGFi+Y8PQ5VBAMhmkGYgJs8FAw9GA5EKILFiWUFixfL/IBoqRBoAafYsOvpf0jiTvEAE2QzSLGmU - MeQCkYEBAD3tUdo+/cEPAAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABkSURBVDhPY2CgBsjvOlhQ0H3oP4hGlyMKgDSHtjz5L2td + 9R8mxsLE8h8fRjEAZDNIs6x1FXkuGHgwGohUAIkVywoSK5b/B9HockQBkGbPoqP/JY0zyQtEkM0gzZJG + GeS5YEABAD3tUdqXHMg6AAAAAElFTkSuQmCC @@ -165,6 +165,12 @@ False + + False + + + False + 17, 17 diff --git a/SCrawler/Download/Feed/DownloadFeedForm.vb b/SCrawler/Download/Feed/DownloadFeedForm.vb index 78a58bd..7e5421c 100644 --- a/SCrawler/Download/Feed/DownloadFeedForm.vb +++ b/SCrawler/Download/Feed/DownloadFeedForm.vb @@ -12,8 +12,10 @@ Imports PersonalUtilities.Forms Imports PersonalUtilities.Forms.Toolbars Imports PersonalUtilities.Tools Imports RCI = PersonalUtilities.Forms.Toolbars.RangeSwitcherToolbar.ControlItem +Imports UTypes = SCrawler.API.Base.UserMedia.Types Imports UserMediaD = SCrawler.DownloadObjects.TDownloader.UserMediaD Imports DTSModes = PersonalUtilities.Forms.DateTimeSelectionForm.Modes +Imports ETC = PersonalUtilities.Forms.Toolbars.EditToolbar.ControlItem Namespace DownloadObjects Friend Class DownloadFeedForm #Region "Events" @@ -42,6 +44,36 @@ Namespace DownloadObjects Return OPT_SUBSCRIPTIONS.Checked End Get End Property +#Region "Filter options" + Friend ReadOnly Property FILTERS As FeedFilterCollection + Private ReadOnly Property CurrentFilter As FeedFilter + Get + Return FILTERS.Current + End Get + End Property + Private ReadOnly FilterTypesConversion As Func(Of UTypes, UserMediaD, Boolean) = Function(ByVal t As UTypes, ByVal d As UserMediaD) As Boolean + Select Case t + Case UTypes.Video : Return d.Data.IsVideoType + Case UTypes.Picture : Return d.Data.Type = UTypes.Picture + Case UTypes.GIF : Return d.Data.Type = UTypes.GIF + Case UTypes.Text : Return d.Data.Type = UTypes.Text + Case Else : Return False + End Select + End Function + Private ReadOnly DataFilterPredicate As New FPredicate(Of UserMediaD)( + Function(ByVal d As UserMediaD) As Boolean + If Not CurrentFilter Is Nothing Then + With CurrentFilter + If .Types.Count > 0 AndAlso Not .Types.Any(Function(t) FilterTypesConversion(t, d)) Then Return False +#Disable Warning BC42109 + If .Users.Count > 0 AndAlso Not .Users.Contains(d.UserInfo) Then Return False +#Enable Warning + End With + End If + Return True + End Function) + Private ReadOnly DataFilterPredicateInv As New FPredicate(Of UserMediaD)(Function(d) Not DataFilterPredicate.Invoke(d)) +#End Region #Region "Feeds options" Private Enum FeedModes : Current : Saved : Special : End Enum Private FeedMode As FeedModes = FeedModes.Current @@ -112,6 +144,7 @@ Namespace DownloadObjects #Region "Initializer" Friend Sub New() InitializeComponent() + FormFont = ControlInvokeFast(Of Font)(Me, Function() Font.Clone, Nothing) MyDefs = New DefaultFormOptions(Me, Settings.Design) MyRange = New RangeSwitcherToolbar(Of UserMediaD)(ToolbarTOP) DataList = New List(Of UserMediaD) @@ -123,6 +156,10 @@ Namespace DownloadObjects .Image = My.Resources.DeletePic_24, .DisplayStyle = ToolStripItemDisplayStyle.ImageAndText } + FILTERS = New FeedFilterCollection + BTT_FILTER.Image = My.Resources.FilterPic + BTT_FILTER_SIMPLE.Image = My.Resources.FilterPic + BTT_FILTER_SAVE.Image = PersonalUtilities.My.Resources.SaveAsPic_Black_16 End Sub #End Region #Region "Form handlers" @@ -383,6 +420,8 @@ Namespace DownloadObjects End Sub #End Region #Region "Refill" + Private _RefillListProcessTable As Boolean = True + Private _RefillListIgnoreFilter As Boolean = False Private Overloads Sub RefillList(Optional ByVal RememberPosition As Boolean? = Nothing) If IsSession Then RefillList(FeedMode = FeedModes.Current, If(RememberPosition, True)) @@ -391,6 +430,7 @@ Namespace DownloadObjects End If End Sub Private Overloads Sub RefillList(ByVal RefillDataList As Boolean, ByVal RememberPosition As Boolean) + UpdateFilterControls() DataPopulated = False Dim rIndx% = -1 If RememberPosition Then rIndx = MyRange.CurrentIndex @@ -401,17 +441,20 @@ Namespace DownloadObjects DataList.Clear() DataList.ListAddList(Downloader.Files.Where(If(IsSubscription, FilterSubscriptions, FilterUsers)), LAP.NotContainsOnly) End If - MyRange.Source = DataList - If rIndx >= 0 Then - If Not rIndx.ValueBetween(0, MyRange.Count - 1) Then rIndx -= 1 - If rIndx.ValueBetween(0, MyRange.Count - 1) Then MyRange.CurrentIndex = rIndx - End If - ControlInvokeFast(ToolbarTOP, BTT_REFRESH, Sub() BTT_REFRESH.ToolTipText = BttRefreshToolTipText) - BTT_REFRESH.ControlDropColor(ToolbarTOP) - If DataList.Count = 0 Then - ClearTable() - ElseIf Not DataPopulated Then - MyRange_IndexChanged(MyRange, Nothing) + If Not _RefillListIgnoreFilter And Not CurrentFilter Is Nothing And DataList.Count > 0 Then DataList.RemoveAll(DataFilterPredicateInv) + If _RefillListProcessTable Then + MyRange.Source = DataList + If rIndx >= 0 Then + If Not rIndx.ValueBetween(0, MyRange.Count - 1) Then rIndx -= 1 + If rIndx.ValueBetween(0, MyRange.Count - 1) Then MyRange.CurrentIndex = rIndx + End If + ControlInvokeFast(ToolbarTOP, BTT_REFRESH, Sub() BTT_REFRESH.ToolTipText = BttRefreshToolTipText) + BTT_REFRESH.ControlDropColor(ToolbarTOP) + If DataList.Count = 0 Then + ClearTable() + ElseIf Not DataPopulated Then + MyRange_IndexChanged(MyRange, Nothing) + End If End If End Sub Private Sub CleanDataList() @@ -555,7 +598,7 @@ Namespace DownloadObjects Try Dim isCopy As Boolean = Not Sender Is Nothing AndAlso (Sender Is BTT_COPY_TO OrElse Sender Is BTT_COPY_SPEC_TO) Dim moveOptions As FeedMoveCopyTo = Nothing - Dim ff As SFile = Nothing, df As SFile + Dim ff As SFile = Nothing, ffInit As SFile = Nothing, df As SFile = Nothing Dim data As IEnumerable(Of UserMediaD) = Nothing Dim dd As UserMediaD Dim __user As UserInfo @@ -565,10 +608,11 @@ Namespace DownloadObjects Dim mm As UserMediaD Dim mm_data As API.Base.UserMedia Dim indx% + Dim indxR As Byte Dim renameExisting As Boolean = False Dim downloaderFilesUpdated As Boolean = False Dim eFiles As IEnumerable(Of SFile) - Dim finder As Predicate(Of UserMediaD) = Function(media) media.Data.File = ff + Dim finder As Predicate(Of UserMediaD) = Function(media) media.Data.File = ffInit Dim x As XmlFile Dim sessionData As New List(Of UserMediaD) Dim sesFile As SFile @@ -671,39 +715,57 @@ Namespace DownloadObjects End If For Each dd In data - If Not dd.Data.File.IsEmptyString Then - ff = dd.Data.File - df = ff - df.Path = moveOptions.DestinationTrue(dd).Path - If isCopy Then - If ff.Copy(df) Then new_files.Add(df) : result = True - Else - If df.Exists And renameExisting Then df = SFile.IndexReindex(df,,,, New ErrorsDescriber(False, False, False, df)) - If SFile.Move(ff, df) Then - new_files.Add(df) - result = True - If updateFileLocations Then - filesReplace.Add(New KeyValuePair(Of SFile, SFile)(ff, df)) - indx = Downloader.Files.FindIndex(finder) - If indx >= 0 Then - mm = Downloader.Files(indx) - __user = mm.UserInfo - mm_data = mm.Data - mm_data.File = df - __isSavedPosts = mm.IsSavedPosts And moveOptions.ReplaceUserProfile_Profile Is Nothing - postUrl = mm.PostUrl(True) - mm = New UserMediaD(mm_data, If(moveOptions.ReplaceUserProfile_Profile, mm.User), mm.Session, mm.Date) With { - .IsSavedPosts = __isSavedPosts, - .PostUrl = postUrl - } - If __isSavedPosts Then mm.UserInfo = __user - Downloader.Files(indx) = mm - downloaderFilesUpdated = True + For indxR = 0 To 1 + ff = If(indxR = 0, dd.Data.File, dd.Data.PostTextFile) + If Not ff.IsEmptyString AndAlso ff.Exists Then + If indxR = 0 Then + ffInit = ff + df = ff + df.Path = moveOptions.DestinationTrue(dd).Path + ElseIf Not Settings.FeedShowTextPosts Or Settings.FeedShowTextPostsAlwaysMove Then + df.Name = ff.Name + df.Extension = ff.Extension + Else + Exit For + End If + If isCopy Then + If ff.Copy(df) Then new_files.Add(df) : result = True + Else + If df.Exists And renameExisting Then df = SFile.IndexReindex(df,,,, New ErrorsDescriber(False, False, False, df)) + If SFile.Move(ff, df) Then + If indxR = 0 Then + new_files.Add(df) + result = True + End If + If updateFileLocations Then + If indxR = 0 Then filesReplace.Add(New KeyValuePair(Of SFile, SFile)(ff, df)) + indx = Downloader.Files.FindIndex(finder) + If indx >= 0 Then + mm = Downloader.Files(indx) + __user = mm.UserInfo + mm_data = mm.Data + If indxR = 0 Then + mm_data.File = df + ffInit = df + Else + mm_data.PostTextFile = df + mm_data.PostTextFileSpecialFolder = False + End If + __isSavedPosts = mm.IsSavedPosts And moveOptions.ReplaceUserProfile_Profile Is Nothing + postUrl = mm.PostUrl(True) + mm = New UserMediaD(mm_data, If(moveOptions.ReplaceUserProfile_Profile, mm.User), mm.Session, mm.Date) With { + .IsSavedPosts = __isSavedPosts, + .PostUrl = postUrl + } + If __isSavedPosts Then mm.UserInfo = __user + Downloader.Files(indx) = mm + downloaderFilesUpdated = True + End If End If End If End If End If - End If + Next Next If Not isCopy And updateFileLocations Then If downloaderFilesUpdated Then Downloader.FilesSave() @@ -718,6 +780,7 @@ Namespace DownloadObjects If sessionData.Count > 0 Then For Each rfile As KeyValuePair(Of SFile, SFile) In filesReplace ff = rfile.Key + ffInit = ff df = rfile.Value indx = sessionData.FindIndex(finder) If indx >= 0 Then @@ -771,6 +834,130 @@ Namespace DownloadObjects End Try End Function #End Region +#Region "Filters" + Private Sub BTT_FILTER_Click(sender As Object, e As EventArgs) Handles BTT_FILTER.Click, BTT_FILTER_SIMPLE.Click + Dim changer As Action(Of Boolean) = Sub(ByVal start As Boolean) + _RefillListIgnoreFilter = start + _RefillListProcessTable = Not start + End Sub + Try + changer.Invoke(True) + RefillList(True) + Using f As New FeedFilterForm(CurrentFilter, DataList, True) + f.ShowDialog() + If f.DialogResult = DialogResult.OK Then + FILTERS.TEMP = f.MyFilter.Copy + ElseIf f.DialogResult = DialogResult.Abort Then + FILTERS.TEMP = Nothing + FILTERS.Disable(False, Not FILTERS.Current(False, False) Is Nothing AndAlso + MsgBoxE({$"Want to apply the '{FILTERS.Current(False, False).Name}' filter?", "Apply saved filter"}, + vbExclamation + vbYesNo) = vbYes, True) + Else + Exit Sub + End If + changer.Invoke(False) + RefillList(True) + End Using + Catch + Finally + changer.Invoke(False) + End Try + End Sub + Private Sub BTT_FILTER_DISABLE_Click(sender As Object, e As EventArgs) Handles BTT_FILTER_DISABLE.Click + If Not CurrentFilter Is Nothing Then FILTERS.Disable() : RefillList(False) + End Sub + Private Sub BTT_FILTER_SAVE_Click(sender As Object, e As EventArgs) Handles BTT_FILTER_SAVE.Click + If CurrentFilter Is Nothing Then + MsgBoxE({"No filters to save", "Save filter"}, vbCritical) + Else + Dim names As New List(Of String) + Dim n$ = String.Empty + If FILTERS.Count > 0 Then names.AddRange(FILTERS.Select(Function(ff) ff.Name)) + Do + n = InputBoxE("Enter a new filter name here:", "Filter name", n) + If n.IsEmptyString Then + ShowOperationCanceledMsg() + Exit Sub + ElseIf names.Count > 0 AndAlso names.Contains(n) Then + If MsgBoxE({"You have entered a name that already exists", "Incorrect name"}, vbCritical,,, {"Try again", "Cancel"}) = 1 Then _ + ShowOperationCanceledMsg() : Exit Sub + Else + Exit Do + End If + Loop + If Not n.IsEmptyString Then + Dim f As FeedFilter = CurrentFilter.Copy + f.Name = n + FILTERS.Add(f, True) + RefillList(True) + End If + End If + End Sub + Private Sub BTT_FILTER_MANAGE_Click(sender As Object, e As EventArgs) Handles BTT_FILTER_MANAGE.Click + Try + Using f As New SimpleListForm(Of FeedFilter)(FILTERS, Settings.Design, True) With { + .DesignXMLNodeName = "FeedFilters", + .MultiSelect = False, + .Mode = SimpleListFormModes.SelectedItems, + .FormText = "Filters", + .Icon = My.Resources.FilterIcon + } + Dim updateSource As Action = Sub() + f.Clear() + f.DataSource = FILTERS + f.Update() + End Sub + Dim __edit As EventHandler(Of SimpleListFormEventArgs) = Sub(ByVal __sender As Object, ByVal __e As SimpleListFormEventArgs) + If Not __e.Item Is Nothing Then + Using ff As New FeedFilterForm(__e.Item) With {.ShowAllUsers = True} + ff.ShowDialog() + If ff.DialogResult = DialogResult.OK AndAlso FILTERS.Update(ff.MyFilter) Then updateSource() + End Using + End If + __e.Result = False + End Sub + Dim __delete As EventHandler(Of SimpleListFormEventArgs) = Sub(ByVal __sender As Object, ByVal __e As SimpleListFormEventArgs) + If Not __e.Item Is Nothing Then + If MsgBoxE({$"Are you sure you want to delete the '{DirectCast(__e.Item, FeedFilter).Name}' filter", "Delete filter"}, vbCritical + vbYesNo) = vbYes AndAlso + FILTERS.Delete(__e.Item) Then updateSource() + End If + __e.Result = False + End Sub + Dim __clone As EventHandler = Sub(ByVal __sender As Object, ByVal __e As EventArgs) + If f.CMB_DATA.SelectedIndex >= 0 Then + Using ff As New FeedFilterForm(FILTERS(f.CMB_DATA.SelectedIndex).Copy) With {.ShowAllUsers = True, .AllowNameEdit = True} + ff.ShowDialog() + If ff.DialogResult = DialogResult.OK AndAlso FILTERS.Add(ff.MyFilter.Copy) >= 0 Then updateSource() + End Using + End If + End Sub + Dim bClone As New ToolStripButton("Clone", My.Resources.PlusPic_24, __clone) + With f + .Buttons = {ETC.Edit, ETC.Delete, New ToolStripSeparator, bClone} + AddHandler .EditClick, __edit + AddHandler .DeleteClick, __delete + f.ShowDialog() + If f.DialogResult = DialogResult.OK AndAlso f.DataResult.Count > 0 Then _ + FILTERS.CurrentFilterName = f.DataResult.First.Name : RefillList(False) + End With + bClone.Dispose() + End Using + Catch ex As Exception + ErrorsDescriber.Execute(EDP.SendToLog, ex, "[DownloadFeedForm.BTT_FILTER_MANAGE_Click]") + End Try + End Sub + Private Sub UpdateFilterControls() + Const fStr$ = " (filtered)" + ControlInvokeFast(ToolbarTOP, BTT_FILTER, Sub() BTT_FILTER.ControlChangeColor(True, CurrentFilter Is Nothing), EDP.None) + Try : ControlInvokeFast(Me, Sub() + If CurrentFilter Is Nothing Then + If Text.Contains(fStr) Then Text = Text.Replace(fStr, String.Empty) + Else + If Not Text.Contains(fStr) Then Text &= fStr + End If + End Sub, EDP.None) : Catch : End Try + End Sub +#End Region #Region "Load fav, spec" Private Sub BTT_LOAD_FAV_Click(sender As Object, e As EventArgs) Handles BTT_LOAD_FAV.Click FeedChangeMode(FeedModes.Special, {FeedSpecial.FavoriteName}) @@ -1181,10 +1368,19 @@ Namespace DownloadObjects Private Sub FeedMedia_MediaMove(ByVal Sender As FeedMedia, ByVal MCTOptions As FeedMoveCopyTo, ByRef Result As Boolean) Result = MoveCopyFiles(False, Nothing, MCTOptions, Sender) End Sub + Private Sub FeedMedia_MediaCopy(ByVal Sender As FeedMedia, ByVal MCTOptions As FeedMoveCopyTo, ByRef Result As Boolean) + Result = MoveCopyFiles(False, BTT_COPY_TO, MCTOptions, Sender) + End Sub Private Sub FeedMedia_MediaDeleted(ByVal Sender As FeedMedia) + FeedMedia_MediaDeleted_F(Sender, True) + End Sub + Private Sub FeedMedia_MediaDeletedText(ByVal Sender As FeedMedia) + FeedMedia_MediaDeleted_F(Sender, False) + End Sub + Private Sub FeedMedia_MediaDeleted_F(ByVal Sender As FeedMedia, ByVal MainFile As Boolean) Try ControlInvoke(TP_DATA, Sub() TPRemoveControl(Sender, True)) - DataList.RemoveAll(Function(dd) dd.Data.File = Sender.File) + If MainFile Then DataList.RemoveAll(Function(dd) dd.Data.File = Sender.File) RefillAfterDelete() Catch End Try @@ -1406,20 +1602,36 @@ Namespace DownloadObjects Dim w% = GetWidth() Dim h% = GetHeight() Dim p As New TPCELL(DataRows, DataColumns) + Dim eText As Byte + Dim eTextLim As Byte = IIf(Settings.FeedShowTextPosts, 1, 0) Dim fmList As New List(Of FeedMedia) + TextImageWidth = w d.ForEach(Sub(ByVal de As UserMediaD) - fmList.Add(New FeedMedia(de, w, h, IsSession)) - With fmList.Last - AddHandler .MediaDeleted, AddressOf FeedMedia_MediaDeleted - AddHandler .MediaDownload, AddressOf FeedMedia_Download - AddHandler .MediaMove, AddressOf FeedMedia_MediaMove - AddHandler .FeedAddWithRemove, AddressOf FeedMedia_FeedAddWithRemove - End With + If Not de.Data.Type = UTypes.Text Or eTextLim = 1 Then + For eText = 0 To eTextLim + fmList.Add(New FeedMedia(de, w, h, IsSession, eText)) + With fmList.Last + AddHandler .MediaDeleted, AddressOf FeedMedia_MediaDeleted + AddHandler .MediaDeletedText, AddressOf FeedMedia_MediaDeletedText + AddHandler .MediaDownload, AddressOf FeedMedia_Download + AddHandler .MediaMove, AddressOf FeedMedia_MediaMove + AddHandler .MediaCopy, AddressOf FeedMedia_MediaCopy + AddHandler .FeedAddWithRemove, AddressOf FeedMedia_FeedAddWithRemove + End With + If de.Data.Type = UTypes.Text OrElse de.Data.PostTextFile.IsEmptyString Then Exit For + Next + End If End Sub) If fmList.Count > 0 Then fmList.ListDisposeRemoveAll(Function(fm) fm Is Nothing OrElse fm.HasError) If fmList.Count > 0 Then For i = 0 To fmList.Count - 1 - ControlInvoke(TP_DATA, Sub() TP_DATA.Controls.Add(fmList(i), p.Column, p.Row)) + ControlInvoke(TP_DATA, Sub() + If p.Row > TP_DATA.RowStyles.Count - 1 And p.Column = 0 Then + TP_DATA.RowStyles.Add(New RowStyle(SizeType.Absolute, 0)) + TP_DATA.RowCount += 1 + End If + TP_DATA.Controls.Add(fmList(i), p.Column, p.Row) + End Sub) p = p.Next Next End If diff --git a/SCrawler/Download/Feed/FeedFilter.vb b/SCrawler/Download/Feed/FeedFilter.vb new file mode 100644 index 0000000..7f18d83 --- /dev/null +++ b/SCrawler/Download/Feed/FeedFilter.vb @@ -0,0 +1,252 @@ +' Copyright (C) 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 PersonalUtilities.Tools +Imports PersonalUtilities.Functions.XML +Imports PersonalUtilities.Functions.XML.Base +Imports SCrawler.API.Base +Imports UTypes = SCrawler.API.Base.UserMedia.Types +Namespace DownloadObjects + Friend Class FeedFilter : Implements IEContainerProvider, IComparable, ICopier +#Region "XML" + Private Const Name_Name As String = "Name" + Private Const Name_Types As String = "Types" + Private Const Name_Users As String = "Users" + Private Const Name_Sites As String = "Sites" +#End Region +#Region "Properties" + Friend Property Name As String + Friend ReadOnly Property Types As List(Of UTypes) + Friend ReadOnly Property Users As List(Of UserInfo) + Friend ReadOnly Property Sites As List(Of String) +#End Region +#Region "Initializers" + Friend Sub New() + Types = New List(Of UTypes) + Users = New List(Of UserInfo) + Sites = New List(Of String) + End Sub + Friend Sub New(ByVal e As EContainer) + Me.New + Name = e.Value(Name_Name) + Types.ListAddList(e.Value(Name_Types).StringToList(Of Integer)(",")) + Sites.ListAddList(e.Value(Name_Sites).StringToList(Of String)("|")) + If If(e(Name_Users)?.Count, 0) > 0 Then + Users.ListAddList(e(Name_Users), LAP.IgnoreICopier) + Users.RemoveAll(Function(u) Not u.File.Exists) + End If + End Sub + Public Shared Widening Operator CType(ByVal e As EContainer) As FeedFilter + Return New FeedFilter(e) + End Operator + Public Shared Widening Operator CType(ByVal f As FeedFilter) As String + Return f.ToString + End Operator +#End Region +#Region "Base overrides" + Public Overrides Function ToString() As String + Return Name + End Function + Public Overrides Function Equals(ByVal Obj As Object) As Boolean + If Not Obj Is Nothing AndAlso Not IsDBNull(Obj) Then + Return DirectCast(Obj, FeedFilter).Name = Name + Else + Return False + End If + End Function +#End Region +#Region "IComparable Support" + Private Function CompareTo(ByVal Obj As Object) As Integer Implements IComparable.CompareTo + If Not Obj Is Nothing AndAlso Not IsDBNull(Obj) Then + Return Name.CompareTo(DirectCast(Obj, FeedFilter).Name) + Else + Return 0 + End If + End Function +#End Region +#Region "IEContainerProvider Support" + Private Function ToEContainer(Optional ByVal e As ErrorsDescriber = Nothing) As EContainer Implements IEContainerProvider.ToEContainer + Dim ee As New EContainer("User") With {.AllowSameNames = True} + ee.Add(New EContainer(Name_Name, Name)) + ee.Add(New EContainer(Name_Types, Types.ListToString(","))) + ee.Add(New EContainer(Name_Sites, Sites.ListToString("|"))) + If Users.Count > 0 Then + ee.Add(New EContainer(Name_Users, String.Empty)) + ee(Name_Users).AddRange(Users) + End If + Return ee + End Function +#End Region +#Region "ICopier Support" + Friend Overloads Function Copy() As Object Implements ICopier.Copy + Return (New FeedFilter).Copy(Me) + End Function + Friend Overloads Function Copy(ByVal Source As Object) As Object Implements ICopier.Copy + With DirectCast(Source, FeedFilter) + Name = .Name + Types.Clear() + Types.ListAddList(.Types, LAP.NotContainsOnly) + Users.Clear() + Users.ListAddList(.Users, LAP.NotContainsOnly) + Sites.Clear() + Sites.ListAddList(.Sites, LAP.NotContainsOnly) + End With + Return Me + End Function +#End Region + End Class + Friend Class FeedFilterCollection : Implements IEnumerable(Of FeedFilter), IMyEnumerator(Of FeedFilter) +#Region "XML" + Private Const Name_CurrentFilterName As String = "CurrentFilterName" + Private Const Name_FiltersNode As String = "Filters" +#End Region +#Region "Declarations" + Private ReadOnly MyFilters As List(Of FeedFilter) +#Region "Filters: current, temp" + Private _CurrentFilterName As String = String.Empty + Private _CurrentFilterNameLast As String = String.Empty + Friend Property CurrentFilterName As String + Get + Return _CurrentFilterName + End Get + Set(ByVal NewName As String) + If Not _CurrentFilterName = NewName Then _CurrentFilterNameLast = _CurrentFilterName + _CurrentFilterName = NewName + End Set + End Property + Private _TEMP As FeedFilter = Nothing + Friend Property TEMP As FeedFilter + Get + Return _TEMP + End Get + Set(ByVal f As FeedFilter) + _TEMP = f + If _TEMP Is Nothing And _CurrentFilterName.IsEmptyString And Not _CurrentFilterNameLast.IsEmptyString Then _ + _CurrentFilterName = _CurrentFilterNameLast + End Set + End Property + Friend ReadOnly Property Current(Optional ByVal Any As Boolean = True, Optional ByVal GetTemp As Boolean = True) As FeedFilter + Get + If Any Then + If CurrentFilterName.IsEmptyString Then + Return TEMP + Else + Return Item(CurrentFilterName) + End If + ElseIf GetTemp Then + Return TEMP + ElseIf Not CurrentFilterName.IsEmptyString Then + Return Item(CurrentFilterName) + Else + Return Nothing + End If + End Get + End Property + Friend ReadOnly Property Exists As Boolean + Get + Return Not Current Is Nothing + End Get + End Property + Friend Sub Disable(Optional ByVal All As Boolean = True, Optional ByVal Saved As Boolean = True, Optional ByVal Temp As Boolean = True) + If All Or Saved Then + _CurrentFilterName = String.Empty + _CurrentFilterNameLast = String.Empty + Update() + End If + If All Or Temp Then _TEMP = Nothing + End Sub +#End Region + Private ReadOnly File As New SFile($"{SettingsFolderName}\FeedDataFilters.xml") + Friend ReadOnly UsersToStringProvider As New CustomProvider(Function(ByVal v As UserInfo) As Object + Dim u As UserDataBase = Settings.GetUser(v) + Return If(u?.ToStringExt(True), UserDataBase.ToStringExt(v)) + End Function) +#End Region +#Region "Initializers" + Friend Sub New() + MyFilters = New List(Of FeedFilter) + If File.Exists Then + Using x As New XmlFile(File, Protector.Modes.All, False) With {.AllowSameNames = True} + x.LoadData() + If x.Count > 0 Then + CurrentFilterName = x.Value(Name_CurrentFilterName) + MyFilters.ListAddList(x(Name_FiltersNode), LAP.IgnoreICopier) + End If + End Using + End If + End Sub +#End Region +#Region "Count" + Friend ReadOnly Property Count As Integer Implements IMyEnumerator(Of FeedFilter).MyEnumeratorCount + Get + Return MyFilters.Count + End Get + End Property +#End Region +#Region "Defaults: Item" + Default Friend ReadOnly Property Item(ByVal Index As Integer) As FeedFilter Implements IMyEnumerator(Of FeedFilter).MyEnumeratorObject + Get + Return MyFilters(Index) + End Get + End Property + Default Friend ReadOnly Property Item(ByVal Name As String) As FeedFilter + Get + Return MyFilters.Find(Function(ff) ff.Name = Name) + End Get + End Property +#End Region +#Region "Collection functions" + Friend Function Add(ByVal f As FeedFilter, Optional ByVal SetAsCurrent As Boolean = False) As Integer + If Not MyFilters.Contains(f) Then + MyFilters.Add(f) + MyFilters.Sort() + Update() + End If + Dim i% = MyFilters.IndexOf(f) + If i >= 0 And SetAsCurrent Then CurrentFilterName = Item(i).Name : _TEMP = Nothing + Return i + End Function + Friend Function Delete(ByVal f As FeedFilter) As Boolean + Dim i% = MyFilters.IndexOf(f) + If i >= 0 Then + MyFilters.RemoveAt(i) + Update() + Return True + Else + Return False + End If + End Function + Friend Overloads Function Update(ByVal f As FeedFilter) As Integer + Dim i% = MyFilters.IndexOf(f) + If i >= 0 Then MyFilters(i) = f : Update() + Return i + End Function + Friend Overloads Sub Update() + If MyFilters.Count > 0 Then + Using x As New XmlFile With {.AllowSameNames = True} + x.Add(Name_CurrentFilterName, CurrentFilterName) + x.Add(Name_FiltersNode, String.Empty) + x(Name_FiltersNode).AddRange(MyFilters) + x.Name = "MyFilters" + x.Save(File) + End Using + Else + File.Delete(SFO.File, Settings.DeleteMode, EDP.ReturnValue) + End If + End Sub +#End Region +#Region "IEnumerable Support" + Private Function GetEnumerator() As IEnumerator(Of FeedFilter) Implements IEnumerable(Of FeedFilter).GetEnumerator + Return New MyEnumerator(Of FeedFilter)(Me) + End Function + Private Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator + Return GetEnumerator() + End Function +#End Region + End Class +End Namespace \ No newline at end of file diff --git a/SCrawler/Download/Feed/FeedFilterForm.Designer.vb b/SCrawler/Download/Feed/FeedFilterForm.Designer.vb new file mode 100644 index 0000000..86f6169 --- /dev/null +++ b/SCrawler/Download/Feed/FeedFilterForm.Designer.vb @@ -0,0 +1,337 @@ +' Copyright (C) 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 DownloadObjects + + Partial Friend Class FeedFilterForm : 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_TYPES As System.Windows.Forms.TableLayoutPanel + Dim TP_USERS As System.Windows.Forms.TableLayoutPanel + Dim TP_USERS_2 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(FeedFilterForm)) + Dim ActionButton2 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() + Dim ActionButton3 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() + Me.TP_MAIN = New System.Windows.Forms.TableLayoutPanel() + Me.CH_T_ALL = New System.Windows.Forms.CheckBox() + Me.CH_T_IMG = New System.Windows.Forms.CheckBox() + Me.CH_T_VID = New System.Windows.Forms.CheckBox() + Me.CH_T_GIF = New System.Windows.Forms.CheckBox() + Me.CH_T_TXT = New System.Windows.Forms.CheckBox() + Me.CH_U_USE = New System.Windows.Forms.CheckBox() + Me.CH_U_SHOW_ALL = New System.Windows.Forms.CheckBox() + Me.BTT_ALL = New System.Windows.Forms.Button() + Me.BTT_NONE = New System.Windows.Forms.Button() + Me.LIST_USERS = New System.Windows.Forms.CheckedListBox() + Me.TXT_NAME = New PersonalUtilities.Forms.Controls.TextBoxExtended() + Me.TXT_SITE = New PersonalUtilities.Forms.Controls.TextBoxExtended() + CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer() + TP_TYPES = New System.Windows.Forms.TableLayoutPanel() + TP_USERS = New System.Windows.Forms.TableLayoutPanel() + TP_USERS_2 = New System.Windows.Forms.TableLayoutPanel() + CONTAINER_MAIN.ContentPanel.SuspendLayout() + CONTAINER_MAIN.SuspendLayout() + Me.TP_MAIN.SuspendLayout() + TP_TYPES.SuspendLayout() + TP_USERS.SuspendLayout() + TP_USERS_2.SuspendLayout() + CType(Me.TXT_NAME, System.ComponentModel.ISupportInitialize).BeginInit() + CType(Me.TXT_SITE, System.ComponentModel.ISupportInitialize).BeginInit() + Me.SuspendLayout() + ' + 'CONTAINER_MAIN + ' + ' + 'CONTAINER_MAIN.ContentPanel + ' + CONTAINER_MAIN.ContentPanel.Controls.Add(Me.TP_MAIN) + CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(522, 336) + 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(522, 336) + CONTAINER_MAIN.TabIndex = 0 + CONTAINER_MAIN.TopToolStripPanelVisible = False + ' + 'TP_MAIN + ' + Me.TP_MAIN.ColumnCount = 1 + Me.TP_MAIN.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + Me.TP_MAIN.Controls.Add(TP_TYPES, 0, 1) + Me.TP_MAIN.Controls.Add(TP_USERS, 0, 3) + Me.TP_MAIN.Controls.Add(Me.TXT_NAME, 0, 0) + Me.TP_MAIN.Controls.Add(Me.TXT_SITE, 0, 2) + Me.TP_MAIN.Dock = System.Windows.Forms.DockStyle.Fill + Me.TP_MAIN.Location = New System.Drawing.Point(0, 0) + Me.TP_MAIN.Name = "TP_MAIN" + Me.TP_MAIN.RowCount = 4 + Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) + Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) + Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) + Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + Me.TP_MAIN.Size = New System.Drawing.Size(522, 336) + Me.TP_MAIN.TabIndex = 0 + ' + 'TP_TYPES + ' + TP_TYPES.ColumnCount = 5 + TP_TYPES.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 20.0!)) + TP_TYPES.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 20.0!)) + TP_TYPES.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 20.0!)) + TP_TYPES.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 20.0!)) + TP_TYPES.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 20.0!)) + TP_TYPES.Controls.Add(Me.CH_T_ALL, 0, 0) + TP_TYPES.Controls.Add(Me.CH_T_IMG, 1, 0) + TP_TYPES.Controls.Add(Me.CH_T_VID, 2, 0) + TP_TYPES.Controls.Add(Me.CH_T_GIF, 3, 0) + TP_TYPES.Controls.Add(Me.CH_T_TXT, 4, 0) + TP_TYPES.Dock = System.Windows.Forms.DockStyle.Fill + TP_TYPES.Location = New System.Drawing.Point(0, 28) + TP_TYPES.Margin = New System.Windows.Forms.Padding(0) + TP_TYPES.Name = "TP_TYPES" + TP_TYPES.RowCount = 1 + TP_TYPES.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + TP_TYPES.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) + TP_TYPES.Size = New System.Drawing.Size(522, 25) + TP_TYPES.TabIndex = 1 + ' + 'CH_T_ALL + ' + Me.CH_T_ALL.AutoSize = True + Me.CH_T_ALL.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_T_ALL.Location = New System.Drawing.Point(3, 3) + Me.CH_T_ALL.Name = "CH_T_ALL" + Me.CH_T_ALL.Size = New System.Drawing.Size(98, 19) + Me.CH_T_ALL.TabIndex = 0 + Me.CH_T_ALL.Text = "ALL" + Me.CH_T_ALL.UseVisualStyleBackColor = True + ' + 'CH_T_IMG + ' + Me.CH_T_IMG.AutoSize = True + Me.CH_T_IMG.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_T_IMG.Location = New System.Drawing.Point(107, 3) + Me.CH_T_IMG.Name = "CH_T_IMG" + Me.CH_T_IMG.Size = New System.Drawing.Size(98, 19) + Me.CH_T_IMG.TabIndex = 1 + Me.CH_T_IMG.Text = "Image" + Me.CH_T_IMG.UseVisualStyleBackColor = True + ' + 'CH_T_VID + ' + Me.CH_T_VID.AutoSize = True + Me.CH_T_VID.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_T_VID.Location = New System.Drawing.Point(211, 3) + Me.CH_T_VID.Name = "CH_T_VID" + Me.CH_T_VID.Size = New System.Drawing.Size(98, 19) + Me.CH_T_VID.TabIndex = 2 + Me.CH_T_VID.Text = "Video" + Me.CH_T_VID.UseVisualStyleBackColor = True + ' + 'CH_T_GIF + ' + Me.CH_T_GIF.AutoSize = True + Me.CH_T_GIF.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_T_GIF.Location = New System.Drawing.Point(315, 3) + Me.CH_T_GIF.Name = "CH_T_GIF" + Me.CH_T_GIF.Size = New System.Drawing.Size(98, 19) + Me.CH_T_GIF.TabIndex = 3 + Me.CH_T_GIF.Text = "GIF" + Me.CH_T_GIF.UseVisualStyleBackColor = True + ' + 'CH_T_TXT + ' + Me.CH_T_TXT.AutoSize = True + Me.CH_T_TXT.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_T_TXT.Location = New System.Drawing.Point(419, 3) + Me.CH_T_TXT.Name = "CH_T_TXT" + Me.CH_T_TXT.Size = New System.Drawing.Size(100, 19) + Me.CH_T_TXT.TabIndex = 4 + Me.CH_T_TXT.Text = "Text" + Me.CH_T_TXT.UseVisualStyleBackColor = True + ' + 'TP_USERS + ' + TP_USERS.ColumnCount = 1 + TP_USERS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + TP_USERS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20.0!)) + TP_USERS.Controls.Add(TP_USERS_2, 0, 0) + TP_USERS.Controls.Add(Me.LIST_USERS, 0, 1) + TP_USERS.Dock = System.Windows.Forms.DockStyle.Fill + TP_USERS.Location = New System.Drawing.Point(0, 81) + TP_USERS.Margin = New System.Windows.Forms.Padding(0) + TP_USERS.Name = "TP_USERS" + TP_USERS.RowCount = 2 + TP_USERS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) + TP_USERS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + TP_USERS.Size = New System.Drawing.Size(522, 255) + TP_USERS.TabIndex = 3 + ' + 'TP_USERS_2 + ' + TP_USERS_2.ColumnCount = 4 + TP_USERS_2.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25.0!)) + TP_USERS_2.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25.0!)) + TP_USERS_2.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25.0!)) + TP_USERS_2.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25.0!)) + TP_USERS_2.Controls.Add(Me.CH_U_USE, 0, 0) + TP_USERS_2.Controls.Add(Me.CH_U_SHOW_ALL, 1, 0) + TP_USERS_2.Controls.Add(Me.BTT_ALL, 2, 0) + TP_USERS_2.Controls.Add(Me.BTT_NONE, 3, 0) + TP_USERS_2.Dock = System.Windows.Forms.DockStyle.Fill + TP_USERS_2.Location = New System.Drawing.Point(0, 0) + TP_USERS_2.Margin = New System.Windows.Forms.Padding(0) + TP_USERS_2.Name = "TP_USERS_2" + TP_USERS_2.RowCount = 1 + TP_USERS_2.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + TP_USERS_2.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) + TP_USERS_2.Size = New System.Drawing.Size(522, 25) + TP_USERS_2.TabIndex = 0 + ' + 'CH_U_USE + ' + Me.CH_U_USE.AutoSize = True + Me.CH_U_USE.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_U_USE.Location = New System.Drawing.Point(3, 3) + Me.CH_U_USE.Name = "CH_U_USE" + Me.CH_U_USE.Size = New System.Drawing.Size(124, 19) + Me.CH_U_USE.TabIndex = 0 + Me.CH_U_USE.Text = "Filter users" + Me.CH_U_USE.UseVisualStyleBackColor = True + ' + 'CH_U_SHOW_ALL + ' + Me.CH_U_SHOW_ALL.AutoSize = True + Me.CH_U_SHOW_ALL.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_U_SHOW_ALL.Location = New System.Drawing.Point(133, 3) + Me.CH_U_SHOW_ALL.Name = "CH_U_SHOW_ALL" + Me.CH_U_SHOW_ALL.Size = New System.Drawing.Size(124, 19) + Me.CH_U_SHOW_ALL.TabIndex = 1 + Me.CH_U_SHOW_ALL.Text = "Show all users" + Me.CH_U_SHOW_ALL.UseVisualStyleBackColor = True + ' + 'BTT_ALL + ' + Me.BTT_ALL.Dock = System.Windows.Forms.DockStyle.Fill + Me.BTT_ALL.Location = New System.Drawing.Point(261, 1) + Me.BTT_ALL.Margin = New System.Windows.Forms.Padding(1) + Me.BTT_ALL.Name = "BTT_ALL" + Me.BTT_ALL.Size = New System.Drawing.Size(128, 23) + Me.BTT_ALL.TabIndex = 2 + Me.BTT_ALL.Text = "All" + Me.BTT_ALL.UseVisualStyleBackColor = True + ' + 'BTT_NONE + ' + Me.BTT_NONE.Dock = System.Windows.Forms.DockStyle.Fill + Me.BTT_NONE.Location = New System.Drawing.Point(391, 1) + Me.BTT_NONE.Margin = New System.Windows.Forms.Padding(1) + Me.BTT_NONE.Name = "BTT_NONE" + Me.BTT_NONE.Size = New System.Drawing.Size(130, 23) + Me.BTT_NONE.TabIndex = 3 + Me.BTT_NONE.Text = "None" + Me.BTT_NONE.UseVisualStyleBackColor = True + ' + 'LIST_USERS + ' + Me.LIST_USERS.Dock = System.Windows.Forms.DockStyle.Fill + Me.LIST_USERS.FormattingEnabled = True + Me.LIST_USERS.Location = New System.Drawing.Point(3, 28) + Me.LIST_USERS.Name = "LIST_USERS" + Me.LIST_USERS.Size = New System.Drawing.Size(516, 224) + Me.LIST_USERS.TabIndex = 1 + ' + 'TXT_NAME + ' + ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image) + ActionButton1.Name = "Clear" + ActionButton1.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear + Me.TXT_NAME.Buttons.Add(ActionButton1) + Me.TXT_NAME.CaptionText = "Filter name" + Me.TXT_NAME.CaptionWidth = 80.0R + Me.TXT_NAME.Dock = System.Windows.Forms.DockStyle.Fill + Me.TXT_NAME.Location = New System.Drawing.Point(3, 3) + Me.TXT_NAME.Name = "TXT_NAME" + Me.TXT_NAME.PlaceholderEnabled = True + Me.TXT_NAME.PlaceholderText = "Enter filter name here..." + Me.TXT_NAME.Size = New System.Drawing.Size(516, 22) + Me.TXT_NAME.TabIndex = 0 + ' + 'TXT_SITE + ' + ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image) + ActionButton2.Name = "Edit" + ActionButton2.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Edit + ActionButton2.ToolTipText = "Edit sites" + ActionButton3.BackgroundImage = CType(resources.GetObject("ActionButton3.BackgroundImage"), System.Drawing.Image) + ActionButton3.Name = "Clear" + ActionButton3.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear + ActionButton3.ToolTipText = "Delete all sites" + Me.TXT_SITE.Buttons.Add(ActionButton2) + Me.TXT_SITE.Buttons.Add(ActionButton3) + Me.TXT_SITE.CaptionText = "Sites" + Me.TXT_SITE.CaptionWidth = 40.0R + Me.TXT_SITE.Dock = System.Windows.Forms.DockStyle.Fill + Me.TXT_SITE.Location = New System.Drawing.Point(3, 56) + Me.TXT_SITE.Name = "TXT_SITE" + Me.TXT_SITE.Size = New System.Drawing.Size(516, 22) + Me.TXT_SITE.TabIndex = 2 + Me.TXT_SITE.TextBoxReadOnly = True + ' + 'FeedFilterForm + ' + Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!) + Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font + Me.ClientSize = New System.Drawing.Size(522, 336) + Me.Controls.Add(CONTAINER_MAIN) + Me.Name = "FeedFilterForm" + Me.Text = "Filter" + CONTAINER_MAIN.ContentPanel.ResumeLayout(False) + CONTAINER_MAIN.ResumeLayout(False) + CONTAINER_MAIN.PerformLayout() + Me.TP_MAIN.ResumeLayout(False) + TP_TYPES.ResumeLayout(False) + TP_TYPES.PerformLayout() + TP_USERS.ResumeLayout(False) + TP_USERS_2.ResumeLayout(False) + TP_USERS_2.PerformLayout() + CType(Me.TXT_NAME, System.ComponentModel.ISupportInitialize).EndInit() + CType(Me.TXT_SITE, System.ComponentModel.ISupportInitialize).EndInit() + Me.ResumeLayout(False) + + End Sub + Private WithEvents CH_T_ALL As CheckBox + Private WithEvents CH_T_IMG As CheckBox + Private WithEvents CH_T_VID As CheckBox + Private WithEvents CH_T_GIF As CheckBox + Private WithEvents CH_T_TXT As CheckBox + Private WithEvents CH_U_USE As CheckBox + Private WithEvents CH_U_SHOW_ALL As CheckBox + Private WithEvents BTT_ALL As Button + Private WithEvents BTT_NONE As Button + Private WithEvents LIST_USERS As CheckedListBox + Private WithEvents TXT_NAME As PersonalUtilities.Forms.Controls.TextBoxExtended + Private WithEvents TP_MAIN As TableLayoutPanel + Private WithEvents TXT_SITE As PersonalUtilities.Forms.Controls.TextBoxExtended + End Class +End Namespace \ No newline at end of file diff --git a/SCrawler/Download/Feed/FeedFilterForm.resx b/SCrawler/Download/Feed/FeedFilterForm.resx new file mode 100644 index 0000000..3586f1a --- /dev/null +++ b/SCrawler/Download/Feed/FeedFilterForm.resx @@ -0,0 +1,206 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + False + + + False + + + False + + + False + + + + + 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 + + + \ No newline at end of file diff --git a/SCrawler/Download/Feed/FeedFilterForm.vb b/SCrawler/Download/Feed/FeedFilterForm.vb new file mode 100644 index 0000000..a454820 --- /dev/null +++ b/SCrawler/Download/Feed/FeedFilterForm.vb @@ -0,0 +1,252 @@ +' Copyright (C) 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 PersonalUtilities.Forms +Imports PersonalUtilities.Forms.Controls.Base +Imports UTypes = SCrawler.API.Base.UserMedia.Types +Imports UserMediaD = SCrawler.DownloadObjects.TDownloader.UserMediaD +Namespace DownloadObjects + Friend Class FeedFilterForm +#Region "Declarations" + Private WithEvents MyDefs As DefaultFormOptions + Friend ReadOnly Property MyFilter As FeedFilter = Nothing + Private ReadOnly IsTempFilter As Boolean + Private ReadOnly MyData As List(Of UserMediaD) + Friend Property ShowAllUsers As Boolean? = Nothing + Friend Property AllowNameEdit As Boolean = False + Private Class NameChecker : Inherits FieldsCheckerProviderBase + Public Overrides Property ErrorMessage As String + Get + Return MyBase.ErrorMessage + End Get + Set(ByVal m As String) + MyBase.ErrorMessage = m + HasError = True + End Set + End Property + Public Overrides Sub Reset() + MyBase.Reset() + MyBase.ErrorMessage = String.Empty + End Sub + Friend ReadOnly Property ENames As List(Of String) + Friend Sub New() + ENames = New List(Of String)(MainFrameObj.MF.MyFeed.FILTERS.Select(Function(f) f.Name)) + End Sub + Public Overrides 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 + Dim v$ = AConvert(Of String)(Value, String.Empty) + If Not v.IsEmptyString Then + If ENames.Count = 0 OrElse Not ENames.Contains(v) Then + Return Value + Else + ErrorMessage = $"The '{v}' filter already exists!" + End If + End If + Return Nothing + End Function + End Class + Private ReadOnly Property MyNameChecker As NameChecker +#End Region +#Region "Initializer" + Friend Sub New(Optional ByVal f As FeedFilter = Nothing, Optional ByVal Data As IEnumerable(Of UserMediaD) = Nothing, + Optional ByVal IsTempFilter As Boolean = False) + InitializeComponent() + MyDefs = New DefaultFormOptions(Me, Settings.Design) + Me.IsTempFilter = IsTempFilter + MyFilter = f?.Copy + If MyFilter Is Nothing Then MyFilter = New FeedFilter + MyData = New List(Of UserMediaD) + If Data.ListExists Then MyData.ListAddList(Data) + Icon = My.Resources.FilterIcon + MyNameChecker = New NameChecker + End Sub +#End Region +#Region "Form handlers" + Private Sub MyForm_Load(sender As Object, e As EventArgs) Handles Me.Load + Try + With MyDefs + .MyViewInitialize() + .AddOkCancelToolbar(IsTempFilter) + + If IsTempFilter Then + TXT_NAME.Visible = False + TP_MAIN.RowStyles(0).Height = 0 + .MyOkCancel.BTT_DELETE.Text = "Disable" + .MyOkCancel.ToolTipDelete = "Disable filter" + End If + + With MyFilter + If Not .Name.IsEmptyString Then + Text &= $" [{ .Name}]" + TXT_NAME.Text = .Name + If Not AllowNameEdit Then TXT_NAME.Enabled = False + End If + If .Types.Count = 0 Then + CH_T_ALL.Checked = True + Else + If .Types.Contains(UTypes.Picture) Then CH_T_IMG.Checked = True + If .Types.Contains(UTypes.Video) Then CH_T_VID.Checked = True + If .Types.Contains(UTypes.GIF) Then CH_T_GIF.Checked = True + If .Types.Contains(UTypes.Text) Then CH_T_TXT.Checked = True + End If + CH_U_USE.Checked = .Users.Count > 0 + CH_U_SHOW_ALL.Checked = If(ShowAllUsers, False) + End With + + If Not IsTempFilter And (MyFilter.Name.IsEmptyString Or AllowNameEdit) Then + .MyFieldsCheckerE = New FieldsChecker + .MyFieldsCheckerE.AddControl(Of String)(TXT_NAME, TXT_NAME.CaptionText,, MyNameChecker) + .MyFieldsCheckerE.EndLoaderOperations() + End If + + UpdateSitesText() + + .EndLoaderOperations() + RefillList(True) + End With + Catch ex As Exception + MyDefs.InvokeLoaderError(ex) + End Try + End Sub + Private Sub FeedFilterForm_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed + MyData.ListClearDispose + End Sub +#End Region +#Region "Refill" + Private Structure DataUserTmp : Implements IComparable(Of DataUserTmp) + Friend UserInfo As UserInfo + Public Shared Widening Operator CType(ByVal u As UserInfo) As DataUserTmp + Return New DataUserTmp With {.UserInfo = u} + End Operator + Public Shared Widening Operator CType(ByVal d As DataUserTmp) As UserInfo + Return d.UserInfo + End Operator + Public Overrides Function ToString() As String + Return AConvert(Of String)(UserInfo, MainFrameObj.MF.MyFeed.FILTERS.UsersToStringProvider, String.Empty) + End Function + Public Overrides Function Equals(ByVal Obj As Object) As Boolean + If Not IsDBNull(Obj) Then + Return UserInfo.Equals(DirectCast(Obj, DataUserTmp).UserInfo) + Else + Return False + End If + End Function + Private Function CompareTo(ByVal Other As DataUserTmp) As Integer Implements IComparable(Of DataUserTmp).CompareTo + Return ToString.CompareTo(Other.ToString) + End Function + Friend Shared Function GetItem(ByVal Obj As Object) As UserInfo + Return DirectCast(Obj, DataUserTmp).UserInfo + End Function + End Structure + Private Sub RefillList(Optional ByVal Init As Boolean = False) + If Not MyDefs.Initializing Then + If Not Init Then ApplyFilter() + LIST_USERS.Items.Clear() + Dim dataUsers As New List(Of DataUserTmp) + If CH_U_SHOW_ALL.Checked Or MyData.Count = 0 Then + dataUsers.ListAddList(Settings.UsersList) + Else + dataUsers.ListAddList(MyData.Select(Function(d) d.UserInfo), LAP.NotContainsOnly) + End If + Dim i% + If dataUsers.Count > 0 Then + dataUsers.Sort() + With MyFilter + If .Sites.Count > 0 Then dataUsers.RemoveAll(Function(d) Not .Sites.Contains(d.UserInfo.Site)) + If dataUsers.Count > 0 Then + dataUsers.ForEach(Sub(d) LIST_USERS.Items.Add(d, True)) + If .Users.Count > 0 Then + For i = 0 To LIST_USERS.Items.Count - 1 : LIST_USERS.SetItemChecked(i, .Users.Contains(DataUserTmp.GetItem(LIST_USERS.Items(i)))) : Next + End If + End If + End With + End If + End If + End Sub +#End Region +#Region "ApplyFilter" + Private Sub ApplyFilter() + With MyFilter + .Name = TXT_NAME.Text + .Types.Clear() + If Not CH_T_ALL.Checked Then + If CH_T_IMG.Checked Then .Types.Add(UTypes.Picture) + If CH_T_VID.Checked Then .Types.Add(UTypes.Video) + If CH_T_GIF.Checked Then .Types.Add(UTypes.GIF) + If CH_T_TXT.Checked Then .Types.Add(UTypes.Text) + End If + .Users.Clear() + If CH_U_USE.Checked Then + If LIST_USERS.CheckedItems.Count > 0 Then + For Each item As Object In LIST_USERS.CheckedItems : .Users.Add(DataUserTmp.GetItem(item)) : Next + End If + End If + End With + End Sub +#End Region +#Region "OK" + Private Sub MyDefs_ButtonOkClick(ByVal Sender As Object, ByVal e As KeyHandleEventArgs) Handles MyDefs.ButtonOkClick + If MyDefs.MyFieldsChecker Is Nothing OrElse MyDefs.MyFieldsChecker.AllParamsOK Then + ApplyFilter() + MyDefs.CloseForm() + End If + End Sub +#End Region +#Region "Form controls" + Private Sub UpdateControlOptions(ByRef CNT As CheckBox, ByVal v As Boolean) + If v Then CNT.Checked = True + CNT.Enabled = Not v + End Sub + Private Sub CH_T_ALL_CheckedChanged(sender As Object, e As EventArgs) Handles CH_T_ALL.CheckedChanged + Dim v As Boolean = CH_T_ALL.Checked + UpdateControlOptions(CH_T_IMG, v) + UpdateControlOptions(CH_T_VID, v) + UpdateControlOptions(CH_T_GIF, v) + UpdateControlOptions(CH_T_TXT, v) + End Sub + Private Sub CH_U_USE_CheckedChanged(sender As Object, e As EventArgs) Handles CH_U_USE.CheckedChanged + Dim v As Boolean = CH_U_USE.Checked + CH_U_SHOW_ALL.Enabled = v + BTT_ALL.Enabled = v + BTT_NONE.Enabled = v + LIST_USERS.Enabled = v + End Sub + Private Sub CH_U_SHOW_ALL_CheckedChanged(sender As Object, e As EventArgs) Handles CH_U_SHOW_ALL.CheckedChanged + RefillList() + End Sub + Private Sub BTT_ALL_NONE_Click(sender As Object, e As EventArgs) Handles BTT_ALL.Click, BTT_NONE.Click + Dim checked As Boolean = sender Is BTT_ALL + With LIST_USERS + If .Items.Count > 0 Then + For i% = 0 To .Items.Count - 1 : .SetItemChecked(i, checked) : Next + End If + End With + End Sub + Private Sub TXT_SITE_ActionOnButtonClick(ByVal Sender As Object, ByVal e As ActionButtonEventArgs) Handles TXT_SITE.ActionOnButtonClick + Dim refill As Boolean = False + Select Case e.DefaultButton + Case ActionButton.DefaultButtons.Edit + Using f As New Editors.SiteSelectionForm(MyFilter.Sites) + f.ShowDialog() + If f.DialogResult = DialogResult.OK Then + refill = Not MyFilter.Sites.ListEquals(f.SelectedSites) + MyFilter.Sites.ListAddList(f.SelectedSites, LAP.NotContainsOnly, LAP.ClearBeforeAdd) + UpdateSitesText() + End If + End Using + Case ActionButton.DefaultButtons.Clear : refill = MyFilter.Sites.Count > 0 : MyFilter.Sites.Clear() : UpdateSitesText() + End Select + If refill Then RefillList() + End Sub + Private Sub UpdateSitesText() + TXT_SITE.Clear() + TXT_SITE.Text = MyFilter.Sites.ListToString + End Sub +#End Region + End Class +End Namespace \ No newline at end of file diff --git a/SCrawler/Download/Feed/FeedMedia.vb b/SCrawler/Download/Feed/FeedMedia.vb index edfdde0..812294c 100644 --- a/SCrawler/Download/Feed/FeedMedia.vb +++ b/SCrawler/Download/Feed/FeedMedia.vb @@ -15,10 +15,13 @@ Namespace DownloadObjects Public Class FeedMedia #Region "Events" + Friend Delegate Sub MediaMoveCopyEventHandler(ByVal Sender As FeedMedia, ByVal MCTOptions As FeedMoveCopyTo, ByRef Result As Boolean) Friend Event MediaDeleted(ByVal Sender As Object) + Friend Event MediaDeletedText(ByVal Sender As Object) Friend Event MediaDownload As EventHandler Friend Event FeedAddWithRemove(ByVal Sender As FeedMedia, ByVal Feeds As IEnumerable(Of String), ByVal Media As UserMediaD, ByVal RemoveOperation As Boolean) - Friend Event MediaMove(ByVal Sender As FeedMedia, ByVal MCTOptions As FeedMoveCopyTo, ByRef Result As Boolean) + Friend Event MediaMove As MediaMoveCopyEventHandler + Friend Event MediaCopy As MediaMoveCopyEventHandler #End Region #Region "Declarations" Private Const VideoHeight As Integer = 450 @@ -32,6 +35,7 @@ Namespace DownloadObjects End Property Friend ReadOnly Property HasError As Boolean Friend ReadOnly File As SFile + Private ReadOnly IsText As Boolean = False Public Shadows Property Width(Optional ByVal UpdateImage As Boolean = True) As Integer Get Return MyBase.Width @@ -158,10 +162,19 @@ Namespace DownloadObjects End Function #End Region #Region "Initializers" + Private Sub FileCheckSpecialFolders(ByRef f As SFile, ByVal ExtractText As Boolean) + If Not File.Exists Then + If ExtractText Then + f.Path = $"{File.Path.CSFilePS}{UserDataBase.PostTextSpecialFolderDefault}" + ElseIf Media.Data.Type = UserMedia.Types.Video Then + f.Path = $"{File.Path.CSFilePS}Video" + End If + End If + End Sub Public Sub New() InitializeComponent() End Sub - Friend Sub New(ByVal Media As UserMediaD, ByVal Width As Integer, ByVal Height As Integer, ByVal IsSession As Boolean) + Friend Sub New(ByVal Media As UserMediaD, ByVal Width As Integer, ByVal Height As Integer, ByVal IsSession As Boolean, ByVal ExtractText As Boolean) Try InitializeComponent() Me.Media = Media @@ -207,32 +220,47 @@ Namespace DownloadObjects TP_MAIN.Controls.Remove(LBL_TITLE) LBL_TITLE.Dispose() TP_MAIN.RowStyles(1).Height = 0 - File = Media.Data.File - If Not File.Exists And Media.Data.Type = UserMedia.Types.Video Then File.Path = $"{File.Path.CSFilePS}Video" + File = If(ExtractText, Media.Data.PostTextFile, Media.Data.File) + FileCheckSpecialFolders(File, ExtractText) End If If Not File.Exists And Not IsSubscription Then If Not Media.Data.SpecialFolder.IsEmptyString Then + File = If(ExtractText, Media.Data.PostTextFile, Media.Data.File) File.Path = $"{File.Path.CSFilePS}{Media.Data.SpecialFolder}".CSFileP - If Not File.Exists And Media.Data.Type = UserMedia.Types.Video Then File.Path = $"{File.Path.CSFilePS}Video" + FileCheckSpecialFolders(File, ExtractText) End If End If If File.Exists Then - Information = $"Type: {Media.Data.Type}" + Information = $"Type: {IIf(ExtractText, UserMedia.Types.Text.ToString, Media.Data.Type.ToString)}" Information.StringAppendLine($"File: {File.File}") Information.StringAppendLine($"Address: {File}") Information.StringAppendLine($"Downloaded: {Media.Date.ToStringDateDef}") If Media.Data.Post.Date.HasValue Then Information.StringAppendLine($"Post date: {Media.Data.Post.Date.Value.ToStringDateDef}") Dim infoType As UserMedia.Types = If(IsSubscription, UserMedia.Types.Picture, Media.Data.Type) + If ExtractText Then infoType = UserMedia.Types.Text Dim h% Dim s As Size Post = Media.Data Select Case infoType - Case UserMedia.Types.Picture, UserMedia.Types.GIF - Dim tmpMediaFile As SFile = ConvertWebp(File, True) + Case UserMedia.Types.Picture, UserMedia.Types.GIF, UserMedia.Types.Text + Dim tmpMediaFile As SFile = File + If infoType = UserMedia.Types.Text Or ExtractText Then + IsText = True + tmpMediaFile = $"{Settings.Cache.RootDirectory.PathWithSeparator}Text\{File.GetHashCode}.png" + If Not tmpMediaFile.Exists Then tmpMediaFile.Exists(SFO.Path) : UserImage.CreateImageFromText(File.GetText, tmpMediaFile) + If Not tmpMediaFile.Exists Then + If Settings.FeedShowTextPosts_LogErrors Then + Throw New Exception($"Unable to create an image preview for text [{File}]") + Else + Throw New ArgumentNullException("TextImage", $"Unable to create an image preview for text [{File}]") With {.HelpLink = 1} + End If + End If + End If + tmpMediaFile = ConvertWebp(tmpMediaFile, True) If tmpMediaFile.IsEmptyString Then Throw New ArgumentNullException With {.HelpLink = 1} Try MyImage = New ImageRenderer(tmpMediaFile, EDP.ThrowException) @@ -258,8 +286,9 @@ Namespace DownloadObjects .ContextMenuStrip = CONTEXT_DATA } TP_MAIN.Controls.Add(MyPicture, 0, 2) - BTT_CONTEXT_OPEN_MEDIA.Text &= " picture" - BTT_CONTEXT_DELETE.Text &= " picture" + Dim openWhat$ = IIf(infoType = UserMedia.Types.Text Or ExtractText, " text", " picture") + BTT_CONTEXT_OPEN_MEDIA.Text &= openWhat + BTT_CONTEXT_DELETE.Text &= openWhat Case UserMedia.Types.Video, UserMedia.Types.m3u8 infoType = UserMedia.Types.Video MyVideo = New FeedVideo(File) With {.Tag = File, .Dock = DockStyle.Fill, .ContextMenuStrip = CONTEXT_DATA} @@ -293,6 +322,12 @@ Namespace DownloadObjects End With End If + If Media.Data.Type = UserMedia.Types.Text Or ExtractText Then + Information.StringAppendLine(String.Empty,, False) + Information.StringAppendLine("Text:") + Information.StringAppendLine(If(ExtractText, Media.Data.PostTextFile, Media.Data.File).GetText) + End If + If Settings.FeedAddSessionToCaption And IsSession Then info = $"[{Media.Session}] {info}" If Settings.FeedAddDateToCaption Then info &= $" ({Media.Date.ToStringDate(ADateTime.Formats.BaseDateTime)})" LBL_INFO.Text = info @@ -511,7 +546,8 @@ Namespace DownloadObjects If Not moveOptions.Destination.IsEmptyString Then ff.Path = moveOptions.DestinationTrue(Media).Path If isCopy Then - result = File.Copy(ff) + 'result = File.Copy(ff) + RaiseEvent MediaCopy(Me, moveOptions, result) Else RaiseEvent MediaMove(Me, moveOptions, result) End If @@ -573,8 +609,21 @@ Namespace DownloadObjects Try If Silent OrElse MsgBoxE({$"Are you sure you want to delete the [{File.File}] file?{vbCr}{File}", msgTitle}, vbExclamation,,, {"Process", "Cancel"}) = 0 Then If Not MyVideo Is Nothing Then MyVideo.Stop() - If File.Delete(SFO.File, Settings.DeleteMode, EDP.ThrowException) Then - If Not Silent Then RaiseEvent MediaDeleted(Me) : MsgBoxE({"File deleted", msgTitle}) + Dim process As Boolean = False + Dim deletedMainFile As Boolean = False + If Not IsText Or Media.Data.Type = UserMedia.Types.Text Then + process = File.Delete(SFO.File, Settings.DeleteMode, EDP.ThrowException) + deletedMainFile = True + Else + process = Media.Data.PostTextFile.Delete(SFO.File, Settings.DeleteMode, EDP.ReturnValue) + End If + If process Then + If deletedMainFile And (Not Settings.FeedShowTextPosts Or Settings.FeedShowTextPostsAlwaysMove) And Not Media.Data.PostTextFile.IsEmptyString Then _ + Media.Data.PostTextFile.Delete(SFO.File, Settings.DeleteMode, EDP.ReturnValue) + If Not Silent Then + If deletedMainFile Then RaiseEvent MediaDeleted(Me) Else RaiseEvent MediaDeletedText(Me) + MsgBoxE({"File deleted", msgTitle}) + End If LBL_INFO.Height = 0 Height = 0 Return True diff --git a/SCrawler/Download/Feed/FeedMoveCopyTo.vb b/SCrawler/Download/Feed/FeedMoveCopyTo.vb index 90da6dc..76b5511 100644 --- a/SCrawler/Download/Feed/FeedMoveCopyTo.vb +++ b/SCrawler/Download/Feed/FeedMoveCopyTo.vb @@ -19,7 +19,7 @@ Namespace DownloadObjects If SeparateVideoFolder Then Dim f$ = Destination.PathWithSeparator With Media.Data - If Not (.Type = UTypes.Picture Or .Type = UTypes.GIF) Then f &= "Video\" + If Not (.Type = UTypes.Picture Or .Type = UTypes.GIF Or .Type = UTypes.Text) Then f &= "Video\" End With Return f Else diff --git a/SCrawler/Download/STDownloader/VideoDownloaderForm.vb b/SCrawler/Download/STDownloader/VideoDownloaderForm.vb index ff18c12..b29efb7 100644 --- a/SCrawler/Download/STDownloader/VideoDownloaderForm.vb +++ b/SCrawler/Download/STDownloader/VideoDownloaderForm.vb @@ -29,6 +29,8 @@ Namespace DownloadObjects.STDownloader BTT_ADD_URLS_EXTERNAL = New ToolStripMenuItemKeyClick With {.Tag = TAG_EXTERNAL} MENU_ADD.DropDownItems.Insert(1, BTT_ADD_URLS_ARR) Text = "Video downloader" + SEP_FILTER.Visible = False + BTT_FILTER.Visible = False End Sub Protected Overrides Sub VideoListForm_Disposed(sender As Object, e As EventArgs) ExternalUrlsTemp.Clear() diff --git a/SCrawler/Editors/GlobalSettingsForm.Designer.vb b/SCrawler/Editors/GlobalSettingsForm.Designer.vb index 9f27f1e..8feff4b 100644 --- a/SCrawler/Editors/GlobalSettingsForm.Designer.vb +++ b/SCrawler/Editors/GlobalSettingsForm.Designer.vb @@ -61,6 +61,8 @@ Namespace Editors Dim ActionButton11 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Dim ActionButton12 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Dim TP_FEED_SPEC_SEARCH As System.Windows.Forms.TableLayoutPanel + Dim TP_FEED_1 As System.Windows.Forms.TableLayoutPanel + Dim TP_FEED_2 As System.Windows.Forms.TableLayoutPanel Dim TAB_NOTIFY As System.Windows.Forms.TabPage Dim TP_NOTIFY_MAIN As System.Windows.Forms.TableLayoutPanel Dim TP_ENVIR As System.Windows.Forms.TableLayoutPanel @@ -96,6 +98,7 @@ Namespace Editors Dim ActionButton35 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Dim ActionButton36 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Dim TAB_HEADERS As System.Windows.Forms.TabPage + Dim TP_FEED_3 As System.Windows.Forms.TableLayoutPanel Me.TXT_GLOBAL_PATH = New PersonalUtilities.Forms.Controls.TextBoxExtended() Me.TXT_IMAGE_LARGE = New PersonalUtilities.Forms.Controls.TextBoxExtended() Me.TXT_IMAGE_SMALL = New PersonalUtilities.Forms.Controls.TextBoxExtended() @@ -151,6 +154,7 @@ Namespace Editors Me.CH_FEED_SPEC_SEARCH = New System.Windows.Forms.CheckBox() Me.CH_FEED_SPEC_SEARCH_DEEP = New System.Windows.Forms.CheckBox() Me.CH_FEED_OPEN_CTRLF = New System.Windows.Forms.CheckBox() + Me.CH_FEED_TEXT = 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() @@ -174,17 +178,17 @@ Namespace Editors Me.TXT_FEED_ROWS = New PersonalUtilities.Forms.Controls.TextBoxExtended() Me.TXT_FEED_COLUMNS = New PersonalUtilities.Forms.Controls.TextBoxExtended() Me.CH_FEED_ENDLESS = New System.Windows.Forms.CheckBox() - Me.CH_FEED_ADD_SESSION = New System.Windows.Forms.CheckBox() - Me.CH_FEED_ADD_DATE = New System.Windows.Forms.CheckBox() Me.TXT_FEED_CENTER_IMAGE = New PersonalUtilities.Forms.Controls.TextBoxExtended() Me.COLORS_FEED = New SCrawler.Editors.ColorPicker() Me.CH_FEED_SHOW_FRIENDLY = New System.Windows.Forms.CheckBox() Me.CH_FEED_SHOW_SPEC_MEDIAITEM = New System.Windows.Forms.CheckBox() Me.NUM_FEED_STORE_SESSION_DATA = New PersonalUtilities.Forms.Controls.TextBoxExtended() Me.NUM_FEED_SES_CURR_LOAD_LAST = New PersonalUtilities.Forms.Controls.TextBoxExtended() + Me.CH_FEED_ESC_TO_CLOSE = New System.Windows.Forms.CheckBox() + Me.CH_FEED_ADD_SESSION = New System.Windows.Forms.CheckBox() Me.CH_FEED_ADD_SITE = New System.Windows.Forms.CheckBox() Me.CH_FEED_ADD_TYPE = New System.Windows.Forms.CheckBox() - Me.CH_FEED_ESC_TO_CLOSE = New System.Windows.Forms.CheckBox() + Me.CH_FEED_ADD_DATE = New System.Windows.Forms.CheckBox() Me.TXT_YTDLP = New PersonalUtilities.Forms.Controls.TextBoxExtended() Me.TXT_FFMPEG = New PersonalUtilities.Forms.Controls.TextBoxExtended() Me.TXT_CURL = New PersonalUtilities.Forms.Controls.TextBoxExtended() @@ -210,6 +214,7 @@ Namespace Editors Me.TAB_MAIN = New System.Windows.Forms.TabControl() Me.TAB_ENVIR = New System.Windows.Forms.TabPage() Me.CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer() + Me.CH_FEED_TEXT_ALWAYS_MOVE = New System.Windows.Forms.CheckBox() TP_BASIS = New System.Windows.Forms.TableLayoutPanel() TP_IMAGES = New System.Windows.Forms.TableLayoutPanel() TP_FILE_NAME = New System.Windows.Forms.TableLayoutPanel() @@ -235,6 +240,8 @@ Namespace Editors TP_FEED_IMG_COUNT = New System.Windows.Forms.TableLayoutPanel() TP_FEED_SES = New System.Windows.Forms.TableLayoutPanel() TP_FEED_SPEC_SEARCH = New System.Windows.Forms.TableLayoutPanel() + TP_FEED_1 = New System.Windows.Forms.TableLayoutPanel() + TP_FEED_2 = New System.Windows.Forms.TableLayoutPanel() TAB_NOTIFY = New System.Windows.Forms.TabPage() TP_NOTIFY_MAIN = New System.Windows.Forms.TableLayoutPanel() TP_ENVIR = New System.Windows.Forms.TableLayoutPanel() @@ -244,6 +251,7 @@ Namespace Editors TP_DESIGN = New System.Windows.Forms.TableLayoutPanel() TP_HEADERS_DEF = New System.Windows.Forms.TableLayoutPanel() TAB_HEADERS = New System.Windows.Forms.TabPage() + TP_FEED_3 = New System.Windows.Forms.TableLayoutPanel() TP_BASIS.SuspendLayout() CType(Me.TXT_GLOBAL_PATH, System.ComponentModel.ISupportInitialize).BeginInit() TP_IMAGES.SuspendLayout() @@ -288,6 +296,8 @@ Namespace Editors CType(Me.NUM_FEED_STORE_SESSION_DATA, System.ComponentModel.ISupportInitialize).BeginInit() CType(Me.NUM_FEED_SES_CURR_LOAD_LAST, System.ComponentModel.ISupportInitialize).BeginInit() TP_FEED_SPEC_SEARCH.SuspendLayout() + TP_FEED_1.SuspendLayout() + TP_FEED_2.SuspendLayout() TAB_NOTIFY.SuspendLayout() TP_NOTIFY_MAIN.SuspendLayout() TP_ENVIR.SuspendLayout() @@ -316,6 +326,7 @@ Namespace Editors Me.TAB_ENVIR.SuspendLayout() Me.CONTAINER_MAIN.ContentPanel.SuspendLayout() Me.CONTAINER_MAIN.SuspendLayout() + TP_FEED_3.SuspendLayout() Me.SuspendLayout() ' 'TP_BASIS @@ -343,7 +354,7 @@ Namespace Editors TP_BASIS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) TP_BASIS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) TP_BASIS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20.0!)) - TP_BASIS.Size = New System.Drawing.Size(615, 418) + TP_BASIS.Size = New System.Drawing.Size(615, 393) TP_BASIS.TabIndex = 0 ' 'TXT_GLOBAL_PATH @@ -935,7 +946,7 @@ Namespace Editors ' Me.CH_FEED_OPEN_LAST_MODE.AutoSize = True Me.CH_FEED_OPEN_LAST_MODE.Dock = System.Windows.Forms.DockStyle.Fill - Me.CH_FEED_OPEN_LAST_MODE.Location = New System.Drawing.Point(4, 247) + Me.CH_FEED_OPEN_LAST_MODE.Location = New System.Drawing.Point(4, 221) Me.CH_FEED_OPEN_LAST_MODE.Name = "CH_FEED_OPEN_LAST_MODE" Me.CH_FEED_OPEN_LAST_MODE.Size = New System.Drawing.Size(613, 19) Me.CH_FEED_OPEN_LAST_MODE.TabIndex = 9 @@ -1048,7 +1059,7 @@ Namespace Editors ' Me.CH_FEED_UP_FILE_LOC_MOVE.AutoSize = True Me.CH_FEED_UP_FILE_LOC_MOVE.Dock = System.Windows.Forms.DockStyle.Fill - Me.CH_FEED_UP_FILE_LOC_MOVE.Location = New System.Drawing.Point(4, 325) + Me.CH_FEED_UP_FILE_LOC_MOVE.Location = New System.Drawing.Point(4, 299) Me.CH_FEED_UP_FILE_LOC_MOVE.Name = "CH_FEED_UP_FILE_LOC_MOVE" Me.CH_FEED_UP_FILE_LOC_MOVE.Size = New System.Drawing.Size(613, 19) Me.CH_FEED_UP_FILE_LOC_MOVE.TabIndex = 12 @@ -1118,6 +1129,18 @@ Namespace Editors "ed.") Me.CH_FEED_OPEN_CTRLF.UseVisualStyleBackColor = True ' + 'CH_FEED_TEXT + ' + Me.CH_FEED_TEXT.AutoSize = True + Me.CH_FEED_TEXT.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_FEED_TEXT.Location = New System.Drawing.Point(3, 3) + Me.CH_FEED_TEXT.Name = "CH_FEED_TEXT" + Me.CH_FEED_TEXT.Size = New System.Drawing.Size(303, 19) + Me.CH_FEED_TEXT.TabIndex = 0 + Me.CH_FEED_TEXT.Text = "Show text posts" + TT_MAIN.SetToolTip(Me.CH_FEED_TEXT, "If checked, downloaded text posts will be displayed in the feed (as an image)") + Me.CH_FEED_TEXT.UseVisualStyleBackColor = True + ' 'TP_CHANNELS_IMGS ' TP_CHANNELS_IMGS.ColumnCount = 2 @@ -1169,7 +1192,7 @@ Namespace Editors TAB_BASIS.Location = New System.Drawing.Point(4, 22) TAB_BASIS.Name = "TAB_BASIS" TAB_BASIS.Padding = New System.Windows.Forms.Padding(3) - TAB_BASIS.Size = New System.Drawing.Size(621, 424) + TAB_BASIS.Size = New System.Drawing.Size(621, 399) TAB_BASIS.TabIndex = 0 TAB_BASIS.Text = "Basis" ' @@ -1179,7 +1202,7 @@ Namespace Editors TAB_DEFAULTS.Location = New System.Drawing.Point(4, 22) TAB_DEFAULTS.Name = "TAB_DEFAULTS" TAB_DEFAULTS.Padding = New System.Windows.Forms.Padding(3) - TAB_DEFAULTS.Size = New System.Drawing.Size(621, 424) + TAB_DEFAULTS.Size = New System.Drawing.Size(621, 399) TAB_DEFAULTS.TabIndex = 1 TAB_DEFAULTS.Text = "Defaults" ' @@ -1205,7 +1228,7 @@ Namespace Editors 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.Size = New System.Drawing.Size(615, 418) + TP_DEFS.Size = New System.Drawing.Size(615, 393) TP_DEFS.TabIndex = 0 ' 'CH_DOWN_IMAGES_NATIVE @@ -1225,7 +1248,7 @@ Namespace Editors TAB_DEFS_CHANNELS.Location = New System.Drawing.Point(4, 22) TAB_DEFS_CHANNELS.Name = "TAB_DEFS_CHANNELS" TAB_DEFS_CHANNELS.Padding = New System.Windows.Forms.Padding(3) - TAB_DEFS_CHANNELS.Size = New System.Drawing.Size(621, 424) + TAB_DEFS_CHANNELS.Size = New System.Drawing.Size(621, 399) TAB_DEFS_CHANNELS.TabIndex = 4 TAB_DEFS_CHANNELS.Text = "Channels" ' @@ -1251,7 +1274,7 @@ Namespace Editors TP_CHANNELS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) TP_CHANNELS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) TP_CHANNELS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) - TP_CHANNELS.Size = New System.Drawing.Size(615, 418) + TP_CHANNELS.Size = New System.Drawing.Size(615, 393) TP_CHANNELS.TabIndex = 0 ' 'TXT_CHANNEL_USER_POST_LIMIT @@ -1290,7 +1313,7 @@ Namespace Editors TAB_BEHAVIOR.Controls.Add(TP_BEHAVIOR) TAB_BEHAVIOR.Location = New System.Drawing.Point(4, 22) TAB_BEHAVIOR.Name = "TAB_BEHAVIOR" - TAB_BEHAVIOR.Size = New System.Drawing.Size(621, 424) + TAB_BEHAVIOR.Size = New System.Drawing.Size(621, 399) TAB_BEHAVIOR.TabIndex = 5 TAB_BEHAVIOR.Text = "Behavior" ' @@ -1328,7 +1351,7 @@ Namespace Editors TP_BEHAVIOR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) TP_BEHAVIOR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) TP_BEHAVIOR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) - TP_BEHAVIOR.Size = New System.Drawing.Size(621, 424) + TP_BEHAVIOR.Size = New System.Drawing.Size(621, 399) TP_BEHAVIOR.TabIndex = 0 ' 'TXT_FOLDER_CMD @@ -1524,7 +1547,7 @@ Namespace Editors TAB_DOWN.Controls.Add(TP_DOWNLOADING) TAB_DOWN.Location = New System.Drawing.Point(4, 22) TAB_DOWN.Name = "TAB_DOWN" - TAB_DOWN.Size = New System.Drawing.Size(621, 424) + TAB_DOWN.Size = New System.Drawing.Size(621, 399) TAB_DOWN.TabIndex = 6 TAB_DOWN.Text = "Downloading" ' @@ -1560,7 +1583,7 @@ Namespace Editors TP_DOWNLOADING.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) TP_DOWNLOADING.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) TP_DOWNLOADING.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) - TP_DOWNLOADING.Size = New System.Drawing.Size(621, 424) + TP_DOWNLOADING.Size = New System.Drawing.Size(621, 399) TP_DOWNLOADING.TabIndex = 1 ' 'TXT_SCRIPT @@ -1664,7 +1687,7 @@ Namespace Editors TAB_FEED.Controls.Add(TP_FEED) TAB_FEED.Location = New System.Drawing.Point(4, 22) TAB_FEED.Name = "TAB_FEED" - TAB_FEED.Size = New System.Drawing.Size(621, 424) + TAB_FEED.Size = New System.Drawing.Size(621, 399) TAB_FEED.TabIndex = 7 TAB_FEED.Text = "Feed" ' @@ -1675,23 +1698,22 @@ Namespace Editors TP_FEED.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) TP_FEED.Controls.Add(TP_FEED_IMG_COUNT, 0, 0) TP_FEED.Controls.Add(Me.CH_FEED_ENDLESS, 0, 3) - TP_FEED.Controls.Add(Me.CH_FEED_ADD_SESSION, 0, 4) - TP_FEED.Controls.Add(Me.CH_FEED_ADD_DATE, 0, 7) TP_FEED.Controls.Add(Me.TXT_FEED_CENTER_IMAGE, 0, 1) TP_FEED.Controls.Add(Me.COLORS_FEED, 0, 2) - TP_FEED.Controls.Add(Me.CH_FEED_OPEN_LAST_MODE, 0, 9) - TP_FEED.Controls.Add(Me.CH_FEED_SHOW_FRIENDLY, 0, 10) - TP_FEED.Controls.Add(Me.CH_FEED_SHOW_SPEC_MEDIAITEM, 0, 11) - TP_FEED.Controls.Add(Me.CH_FEED_UP_FILE_LOC_MOVE, 0, 12) - TP_FEED.Controls.Add(TP_FEED_SES, 0, 8) - TP_FEED.Controls.Add(Me.CH_FEED_ADD_SITE, 0, 5) - TP_FEED.Controls.Add(Me.CH_FEED_ADD_TYPE, 0, 6) - TP_FEED.Controls.Add(Me.CH_FEED_ESC_TO_CLOSE, 0, 13) - TP_FEED.Controls.Add(TP_FEED_SPEC_SEARCH, 0, 14) + TP_FEED.Controls.Add(Me.CH_FEED_OPEN_LAST_MODE, 0, 8) + TP_FEED.Controls.Add(Me.CH_FEED_SHOW_FRIENDLY, 0, 9) + TP_FEED.Controls.Add(Me.CH_FEED_SHOW_SPEC_MEDIAITEM, 0, 10) + TP_FEED.Controls.Add(Me.CH_FEED_UP_FILE_LOC_MOVE, 0, 11) + TP_FEED.Controls.Add(TP_FEED_SES, 0, 7) + TP_FEED.Controls.Add(Me.CH_FEED_ESC_TO_CLOSE, 0, 12) + TP_FEED.Controls.Add(TP_FEED_SPEC_SEARCH, 0, 13) + TP_FEED.Controls.Add(TP_FEED_1, 0, 4) + TP_FEED.Controls.Add(TP_FEED_2, 0, 5) + TP_FEED.Controls.Add(TP_FEED_3, 0, 6) TP_FEED.Dock = System.Windows.Forms.DockStyle.Fill TP_FEED.Location = New System.Drawing.Point(0, 0) TP_FEED.Name = "TP_FEED" - TP_FEED.RowCount = 16 + TP_FEED.RowCount = 15 TP_FEED.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) TP_FEED.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) TP_FEED.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) @@ -1699,7 +1721,6 @@ Namespace Editors TP_FEED.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) TP_FEED.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) TP_FEED.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) - TP_FEED.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) TP_FEED.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) TP_FEED.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) TP_FEED.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) @@ -1709,7 +1730,8 @@ Namespace Editors TP_FEED.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) TP_FEED.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) TP_FEED.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20.0!)) - TP_FEED.Size = New System.Drawing.Size(621, 424) + TP_FEED.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20.0!)) + TP_FEED.Size = New System.Drawing.Size(621, 399) TP_FEED.TabIndex = 0 ' 'TP_FEED_IMG_COUNT @@ -1772,28 +1794,6 @@ Namespace Editors Me.CH_FEED_ENDLESS.Text = "Endless feed" Me.CH_FEED_ENDLESS.UseVisualStyleBackColor = True ' - 'CH_FEED_ADD_SESSION - ' - Me.CH_FEED_ADD_SESSION.AutoSize = True - Me.CH_FEED_ADD_SESSION.Dock = System.Windows.Forms.DockStyle.Fill - Me.CH_FEED_ADD_SESSION.Location = New System.Drawing.Point(4, 114) - Me.CH_FEED_ADD_SESSION.Name = "CH_FEED_ADD_SESSION" - Me.CH_FEED_ADD_SESSION.Size = New System.Drawing.Size(613, 19) - Me.CH_FEED_ADD_SESSION.TabIndex = 4 - Me.CH_FEED_ADD_SESSION.Text = "Add the session number to the post title" - Me.CH_FEED_ADD_SESSION.UseVisualStyleBackColor = True - ' - 'CH_FEED_ADD_DATE - ' - Me.CH_FEED_ADD_DATE.AutoSize = True - Me.CH_FEED_ADD_DATE.Dock = System.Windows.Forms.DockStyle.Fill - Me.CH_FEED_ADD_DATE.Location = New System.Drawing.Point(4, 192) - Me.CH_FEED_ADD_DATE.Name = "CH_FEED_ADD_DATE" - Me.CH_FEED_ADD_DATE.Size = New System.Drawing.Size(613, 19) - Me.CH_FEED_ADD_DATE.TabIndex = 7 - Me.CH_FEED_ADD_DATE.Text = "Add the date to the post title" - Me.CH_FEED_ADD_DATE.UseVisualStyleBackColor = True - ' 'TXT_FEED_CENTER_IMAGE ' Me.TXT_FEED_CENTER_IMAGE.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.CheckBox @@ -1830,7 +1830,7 @@ Namespace Editors ' Me.CH_FEED_SHOW_FRIENDLY.AutoSize = True Me.CH_FEED_SHOW_FRIENDLY.Dock = System.Windows.Forms.DockStyle.Fill - Me.CH_FEED_SHOW_FRIENDLY.Location = New System.Drawing.Point(4, 273) + Me.CH_FEED_SHOW_FRIENDLY.Location = New System.Drawing.Point(4, 247) Me.CH_FEED_SHOW_FRIENDLY.Name = "CH_FEED_SHOW_FRIENDLY" Me.CH_FEED_SHOW_FRIENDLY.Size = New System.Drawing.Size(613, 19) Me.CH_FEED_SHOW_FRIENDLY.TabIndex = 10 @@ -1841,7 +1841,7 @@ Namespace Editors ' Me.CH_FEED_SHOW_SPEC_MEDIAITEM.AutoSize = True Me.CH_FEED_SHOW_SPEC_MEDIAITEM.Dock = System.Windows.Forms.DockStyle.Fill - Me.CH_FEED_SHOW_SPEC_MEDIAITEM.Location = New System.Drawing.Point(4, 299) + Me.CH_FEED_SHOW_SPEC_MEDIAITEM.Location = New System.Drawing.Point(4, 273) Me.CH_FEED_SHOW_SPEC_MEDIAITEM.Name = "CH_FEED_SHOW_SPEC_MEDIAITEM" Me.CH_FEED_SHOW_SPEC_MEDIAITEM.Size = New System.Drawing.Size(613, 19) Me.CH_FEED_SHOW_SPEC_MEDIAITEM.TabIndex = 11 @@ -1856,7 +1856,7 @@ Namespace Editors TP_FEED_SES.Controls.Add(Me.NUM_FEED_STORE_SESSION_DATA, 0, 0) TP_FEED_SES.Controls.Add(Me.NUM_FEED_SES_CURR_LOAD_LAST, 1, 0) TP_FEED_SES.Dock = System.Windows.Forms.DockStyle.Fill - TP_FEED_SES.Location = New System.Drawing.Point(1, 215) + TP_FEED_SES.Location = New System.Drawing.Point(1, 189) TP_FEED_SES.Margin = New System.Windows.Forms.Padding(0) TP_FEED_SES.Name = "TP_FEED_SES" TP_FEED_SES.RowCount = 1 @@ -1912,33 +1912,11 @@ Namespace Editors Me.NUM_FEED_SES_CURR_LOAD_LAST.TabIndex = 1 Me.NUM_FEED_SES_CURR_LOAD_LAST.Text = "0" ' - 'CH_FEED_ADD_SITE - ' - Me.CH_FEED_ADD_SITE.AutoSize = True - Me.CH_FEED_ADD_SITE.Dock = System.Windows.Forms.DockStyle.Fill - Me.CH_FEED_ADD_SITE.Location = New System.Drawing.Point(4, 140) - Me.CH_FEED_ADD_SITE.Name = "CH_FEED_ADD_SITE" - Me.CH_FEED_ADD_SITE.Size = New System.Drawing.Size(613, 19) - Me.CH_FEED_ADD_SITE.TabIndex = 5 - Me.CH_FEED_ADD_SITE.Text = "Add the site name to the post title" - Me.CH_FEED_ADD_SITE.UseVisualStyleBackColor = True - ' - 'CH_FEED_ADD_TYPE - ' - Me.CH_FEED_ADD_TYPE.AutoSize = True - Me.CH_FEED_ADD_TYPE.Dock = System.Windows.Forms.DockStyle.Fill - Me.CH_FEED_ADD_TYPE.Location = New System.Drawing.Point(4, 166) - Me.CH_FEED_ADD_TYPE.Name = "CH_FEED_ADD_TYPE" - Me.CH_FEED_ADD_TYPE.Size = New System.Drawing.Size(613, 19) - Me.CH_FEED_ADD_TYPE.TabIndex = 6 - Me.CH_FEED_ADD_TYPE.Text = "Add the file type to the post title" - Me.CH_FEED_ADD_TYPE.UseVisualStyleBackColor = True - ' 'CH_FEED_ESC_TO_CLOSE ' Me.CH_FEED_ESC_TO_CLOSE.AutoSize = True Me.CH_FEED_ESC_TO_CLOSE.Dock = System.Windows.Forms.DockStyle.Fill - Me.CH_FEED_ESC_TO_CLOSE.Location = New System.Drawing.Point(4, 351) + Me.CH_FEED_ESC_TO_CLOSE.Location = New System.Drawing.Point(4, 325) Me.CH_FEED_ESC_TO_CLOSE.Name = "CH_FEED_ESC_TO_CLOSE" Me.CH_FEED_ESC_TO_CLOSE.Size = New System.Drawing.Size(613, 19) Me.CH_FEED_ESC_TO_CLOSE.TabIndex = 13 @@ -1953,7 +1931,7 @@ Namespace Editors TP_FEED_SPEC_SEARCH.Controls.Add(Me.CH_FEED_SPEC_SEARCH, 0, 0) TP_FEED_SPEC_SEARCH.Controls.Add(Me.CH_FEED_SPEC_SEARCH_DEEP, 1, 0) TP_FEED_SPEC_SEARCH.Dock = System.Windows.Forms.DockStyle.Fill - TP_FEED_SPEC_SEARCH.Location = New System.Drawing.Point(1, 374) + TP_FEED_SPEC_SEARCH.Location = New System.Drawing.Point(1, 348) TP_FEED_SPEC_SEARCH.Margin = New System.Windows.Forms.Padding(0) TP_FEED_SPEC_SEARCH.Name = "TP_FEED_SPEC_SEARCH" TP_FEED_SPEC_SEARCH.RowCount = 1 @@ -1962,12 +1940,90 @@ Namespace Editors TP_FEED_SPEC_SEARCH.Size = New System.Drawing.Size(619, 25) TP_FEED_SPEC_SEARCH.TabIndex = 14 ' + 'TP_FEED_1 + ' + TP_FEED_1.ColumnCount = 2 + TP_FEED_1.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!)) + TP_FEED_1.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!)) + TP_FEED_1.Controls.Add(Me.CH_FEED_ADD_SESSION, 0, 0) + TP_FEED_1.Controls.Add(Me.CH_FEED_ADD_SITE, 1, 0) + TP_FEED_1.Dock = System.Windows.Forms.DockStyle.Fill + TP_FEED_1.Location = New System.Drawing.Point(1, 111) + TP_FEED_1.Margin = New System.Windows.Forms.Padding(0) + TP_FEED_1.Name = "TP_FEED_1" + TP_FEED_1.RowCount = 1 + TP_FEED_1.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + TP_FEED_1.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) + TP_FEED_1.Size = New System.Drawing.Size(619, 25) + TP_FEED_1.TabIndex = 4 + ' + 'CH_FEED_ADD_SESSION + ' + Me.CH_FEED_ADD_SESSION.AutoSize = True + Me.CH_FEED_ADD_SESSION.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_FEED_ADD_SESSION.Location = New System.Drawing.Point(3, 3) + Me.CH_FEED_ADD_SESSION.Name = "CH_FEED_ADD_SESSION" + Me.CH_FEED_ADD_SESSION.Size = New System.Drawing.Size(303, 19) + Me.CH_FEED_ADD_SESSION.TabIndex = 0 + Me.CH_FEED_ADD_SESSION.Text = "Add the session number to the post title" + Me.CH_FEED_ADD_SESSION.UseVisualStyleBackColor = True + ' + 'CH_FEED_ADD_SITE + ' + Me.CH_FEED_ADD_SITE.AutoSize = True + Me.CH_FEED_ADD_SITE.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_FEED_ADD_SITE.Location = New System.Drawing.Point(312, 3) + Me.CH_FEED_ADD_SITE.Name = "CH_FEED_ADD_SITE" + Me.CH_FEED_ADD_SITE.Size = New System.Drawing.Size(304, 19) + Me.CH_FEED_ADD_SITE.TabIndex = 1 + Me.CH_FEED_ADD_SITE.Text = "Add the site name to the post title" + Me.CH_FEED_ADD_SITE.UseVisualStyleBackColor = True + ' + 'TP_FEED_2 + ' + TP_FEED_2.ColumnCount = 2 + TP_FEED_2.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!)) + TP_FEED_2.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!)) + TP_FEED_2.Controls.Add(Me.CH_FEED_ADD_TYPE, 0, 0) + TP_FEED_2.Controls.Add(Me.CH_FEED_ADD_DATE, 1, 0) + TP_FEED_2.Dock = System.Windows.Forms.DockStyle.Fill + TP_FEED_2.Location = New System.Drawing.Point(1, 137) + TP_FEED_2.Margin = New System.Windows.Forms.Padding(0) + TP_FEED_2.Name = "TP_FEED_2" + TP_FEED_2.RowCount = 1 + TP_FEED_2.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + TP_FEED_2.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) + TP_FEED_2.Size = New System.Drawing.Size(619, 25) + TP_FEED_2.TabIndex = 5 + ' + 'CH_FEED_ADD_TYPE + ' + Me.CH_FEED_ADD_TYPE.AutoSize = True + Me.CH_FEED_ADD_TYPE.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_FEED_ADD_TYPE.Location = New System.Drawing.Point(3, 3) + Me.CH_FEED_ADD_TYPE.Name = "CH_FEED_ADD_TYPE" + Me.CH_FEED_ADD_TYPE.Size = New System.Drawing.Size(303, 19) + Me.CH_FEED_ADD_TYPE.TabIndex = 0 + Me.CH_FEED_ADD_TYPE.Text = "Add the file type to the post title" + Me.CH_FEED_ADD_TYPE.UseVisualStyleBackColor = True + ' + 'CH_FEED_ADD_DATE + ' + Me.CH_FEED_ADD_DATE.AutoSize = True + Me.CH_FEED_ADD_DATE.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_FEED_ADD_DATE.Location = New System.Drawing.Point(312, 3) + Me.CH_FEED_ADD_DATE.Name = "CH_FEED_ADD_DATE" + Me.CH_FEED_ADD_DATE.Size = New System.Drawing.Size(304, 19) + Me.CH_FEED_ADD_DATE.TabIndex = 1 + Me.CH_FEED_ADD_DATE.Text = "Add the date to the post title" + Me.CH_FEED_ADD_DATE.UseVisualStyleBackColor = True + ' 'TAB_NOTIFY ' TAB_NOTIFY.Controls.Add(TP_NOTIFY_MAIN) TAB_NOTIFY.Location = New System.Drawing.Point(4, 22) TAB_NOTIFY.Name = "TAB_NOTIFY" - TAB_NOTIFY.Size = New System.Drawing.Size(621, 424) + TAB_NOTIFY.Size = New System.Drawing.Size(621, 399) TAB_NOTIFY.TabIndex = 8 TAB_NOTIFY.Text = "Notifications" ' @@ -1999,7 +2055,7 @@ Namespace Editors TP_NOTIFY_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) TP_NOTIFY_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) TP_NOTIFY_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) - TP_NOTIFY_MAIN.Size = New System.Drawing.Size(621, 424) + TP_NOTIFY_MAIN.Size = New System.Drawing.Size(621, 399) TP_NOTIFY_MAIN.TabIndex = 0 ' 'TP_ENVIR @@ -2022,7 +2078,7 @@ Namespace Editors TP_ENVIR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) TP_ENVIR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) TP_ENVIR.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) - TP_ENVIR.Size = New System.Drawing.Size(621, 424) + TP_ENVIR.Size = New System.Drawing.Size(621, 399) TP_ENVIR.TabIndex = 0 ' 'TXT_YTDLP @@ -2153,7 +2209,7 @@ Namespace Editors TAB_STD.Controls.Add(TP_STD) TAB_STD.Location = New System.Drawing.Point(4, 22) TAB_STD.Name = "TAB_STD" - TAB_STD.Size = New System.Drawing.Size(621, 424) + TAB_STD.Size = New System.Drawing.Size(621, 399) TAB_STD.TabIndex = 10 TAB_STD.Text = "Downloader" ' @@ -2195,7 +2251,7 @@ Namespace Editors TP_STD.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) TP_STD.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) TP_STD.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) - TP_STD.Size = New System.Drawing.Size(621, 424) + TP_STD.Size = New System.Drawing.Size(621, 399) TP_STD.TabIndex = 0 ' 'TXT_STD_MAX_JOBS_COUNT @@ -2294,7 +2350,7 @@ Namespace Editors TAB_DESIGN.Controls.Add(TP_DESIGN) TAB_DESIGN.Location = New System.Drawing.Point(4, 22) TAB_DESIGN.Name = "TAB_DESIGN" - TAB_DESIGN.Size = New System.Drawing.Size(621, 424) + TAB_DESIGN.Size = New System.Drawing.Size(621, 399) TAB_DESIGN.TabIndex = 11 TAB_DESIGN.Text = "Design" ' @@ -2320,7 +2376,7 @@ Namespace Editors TP_DESIGN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) TP_DESIGN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) TP_DESIGN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) - TP_DESIGN.Size = New System.Drawing.Size(621, 424) + TP_DESIGN.Size = New System.Drawing.Size(621, 399) TP_DESIGN.TabIndex = 0 ' 'TXT_PRG_TITLE @@ -2431,7 +2487,7 @@ Namespace Editors TP_HEADERS_DEF.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) TP_HEADERS_DEF.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) TP_HEADERS_DEF.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20.0!)) - TP_HEADERS_DEF.Size = New System.Drawing.Size(621, 424) + TP_HEADERS_DEF.Size = New System.Drawing.Size(621, 399) TP_HEADERS_DEF.TabIndex = 0 ' 'TXT_H_DEF_UserAgent @@ -2509,7 +2565,7 @@ Namespace Editors TAB_HEADERS.Controls.Add(TP_HEADERS_DEF) TAB_HEADERS.Location = New System.Drawing.Point(4, 22) TAB_HEADERS.Name = "TAB_HEADERS" - TAB_HEADERS.Size = New System.Drawing.Size(621, 424) + TAB_HEADERS.Size = New System.Drawing.Size(621, 399) TAB_HEADERS.TabIndex = 12 TAB_HEADERS.Text = "Headers" ' @@ -2530,7 +2586,7 @@ Namespace Editors Me.TAB_MAIN.Location = New System.Drawing.Point(0, 0) Me.TAB_MAIN.Name = "TAB_MAIN" Me.TAB_MAIN.SelectedIndex = 0 - Me.TAB_MAIN.Size = New System.Drawing.Size(629, 450) + Me.TAB_MAIN.Size = New System.Drawing.Size(629, 425) Me.TAB_MAIN.TabIndex = 1 ' 'TAB_ENVIR @@ -2538,7 +2594,7 @@ Namespace Editors Me.TAB_ENVIR.Controls.Add(TP_ENVIR) Me.TAB_ENVIR.Location = New System.Drawing.Point(4, 22) Me.TAB_ENVIR.Name = "TAB_ENVIR" - Me.TAB_ENVIR.Size = New System.Drawing.Size(621, 424) + Me.TAB_ENVIR.Size = New System.Drawing.Size(621, 399) Me.TAB_ENVIR.TabIndex = 9 Me.TAB_ENVIR.Text = "Environment" ' @@ -2548,29 +2604,58 @@ Namespace Editors 'CONTAINER_MAIN.ContentPanel ' Me.CONTAINER_MAIN.ContentPanel.Controls.Add(Me.TAB_MAIN) - Me.CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(629, 450) + Me.CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(629, 425) 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(629, 450) + Me.CONTAINER_MAIN.Size = New System.Drawing.Size(629, 425) Me.CONTAINER_MAIN.TabIndex = 0 Me.CONTAINER_MAIN.TopToolStripPanelVisible = False ' + 'TP_FEED_3 + ' + TP_FEED_3.ColumnCount = 2 + TP_FEED_3.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!)) + TP_FEED_3.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!)) + TP_FEED_3.Controls.Add(Me.CH_FEED_TEXT, 0, 0) + TP_FEED_3.Controls.Add(Me.CH_FEED_TEXT_ALWAYS_MOVE, 1, 0) + TP_FEED_3.Dock = System.Windows.Forms.DockStyle.Fill + TP_FEED_3.Location = New System.Drawing.Point(1, 163) + TP_FEED_3.Margin = New System.Windows.Forms.Padding(0) + TP_FEED_3.Name = "TP_FEED_3" + TP_FEED_3.RowCount = 1 + TP_FEED_3.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + TP_FEED_3.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20.0!)) + TP_FEED_3.Size = New System.Drawing.Size(619, 25) + TP_FEED_3.TabIndex = 6 + ' + 'CH_FEED_TEXT_ALWAYS_MOVE + ' + Me.CH_FEED_TEXT_ALWAYS_MOVE.AutoSize = True + Me.CH_FEED_TEXT_ALWAYS_MOVE.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_FEED_TEXT_ALWAYS_MOVE.Location = New System.Drawing.Point(312, 3) + Me.CH_FEED_TEXT_ALWAYS_MOVE.Name = "CH_FEED_TEXT_ALWAYS_MOVE" + Me.CH_FEED_TEXT_ALWAYS_MOVE.Size = New System.Drawing.Size(304, 19) + Me.CH_FEED_TEXT_ALWAYS_MOVE.TabIndex = 1 + Me.CH_FEED_TEXT_ALWAYS_MOVE.Text = "Auto-move linked text" + TT_MAIN.SetToolTip(Me.CH_FEED_TEXT_ALWAYS_MOVE, "Always move the linked text file along with the original file") + Me.CH_FEED_TEXT_ALWAYS_MOVE.UseVisualStyleBackColor = True + ' 'GlobalSettingsForm ' Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!) Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font - Me.ClientSize = New System.Drawing.Size(629, 450) + Me.ClientSize = New System.Drawing.Size(629, 425) Me.Controls.Add(Me.CONTAINER_MAIN) Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle Me.Icon = Global.SCrawler.My.Resources.Resources.SettingsIcon_48 Me.KeyPreview = True Me.MaximizeBox = False - Me.MaximumSize = New System.Drawing.Size(645, 489) + Me.MaximumSize = New System.Drawing.Size(645, 464) Me.MinimizeBox = False - Me.MinimumSize = New System.Drawing.Size(645, 489) + Me.MinimumSize = New System.Drawing.Size(645, 464) Me.Name = "GlobalSettingsForm" Me.ShowInTaskbar = False Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide @@ -2632,6 +2717,10 @@ Namespace Editors CType(Me.NUM_FEED_SES_CURR_LOAD_LAST, System.ComponentModel.ISupportInitialize).EndInit() TP_FEED_SPEC_SEARCH.ResumeLayout(False) TP_FEED_SPEC_SEARCH.PerformLayout() + TP_FEED_1.ResumeLayout(False) + TP_FEED_1.PerformLayout() + TP_FEED_2.ResumeLayout(False) + TP_FEED_2.PerformLayout() TAB_NOTIFY.ResumeLayout(False) TP_NOTIFY_MAIN.ResumeLayout(False) TP_NOTIFY_MAIN.PerformLayout() @@ -2663,6 +2752,8 @@ Namespace Editors Me.CONTAINER_MAIN.ContentPanel.ResumeLayout(False) Me.CONTAINER_MAIN.ResumeLayout(False) Me.CONTAINER_MAIN.PerformLayout() + TP_FEED_3.ResumeLayout(False) + TP_FEED_3.PerformLayout() Me.ResumeLayout(False) End Sub @@ -2780,5 +2871,7 @@ Namespace Editors Private WithEvents CH_FEED_SPEC_SEARCH As CheckBox Private WithEvents CH_FEED_SPEC_SEARCH_DEEP As CheckBox Private WithEvents CH_FEED_OPEN_CTRLF As CheckBox + Private WithEvents CH_FEED_TEXT As CheckBox + Private WithEvents CH_FEED_TEXT_ALWAYS_MOVE 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 64d18d1..c53f391 100644 --- a/SCrawler/Editors/GlobalSettingsForm.resx +++ b/SCrawler/Editors/GlobalSettingsForm.resx @@ -124,20 +124,20 @@ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - wwAADsMBx2+oZAAAAR5JREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbGujg3ZATZPKYdC6FQhPwlAMkg3dP - WQwhyWIyJIUW5NqyPb7oCVtIlhVTwYf8nv7/t2zJagel9KmqKsIACYL9RjI8UHz5zshougZr/AEvbxEP - aZCDBY3VslixaJvX3wzkkDiOwbZtDRGA5vdNAg+TL27qgmt5XkBG/gTdAG7Gt+3PP9oOaEGFCVEC6rp+ - 5g9MfM/c5e4OsEZMZkQEtGL5H2DdZ5JRArDwPA+iKII0TfkC9vroC9j5vq8JTWw3WzWgLMtZGIaa0MR8 - vlAD8PYlSaIJTTiOowY0p0Bc19XEJo6HE59FAPuMzyAINKGJ1XLFZxHALtMrnkBXOIQIIIQ8YvF/KrgB - cMaRN0UdBBkAAAAASUVORK5CYII= + wwAADsMBx2+oZAAAARlJREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbWujg3dATZPKYZC6BQhvw1AMkg3dP + XQyl7WIyJIEW5CbS0/jKE5GwpCghgg9s6/8/y5Kj6DA45zcAwAAAezB6rjNnB4XX244NHt8wGs7wblop + yRGxwZQBYKIfbn477EvqusY4jj2MgMpPiwav7l9UyYXmdrs9duzP4ApUmd72sfrxVsD33JQISyClvFUX + w9nJssvJFei9CJUtgQ7394Du3YKLJaCbLMuwqips21ZNuDve/35X8J7nuRcMsVwsbYEQYlSWpRcMMR5P + bAH9fU3TeMEQSZLYgsMpsDRNvXCIr89vWyCEeC6KwguGmL/ObYGU8oFOwA2ewwgYY9f6f7iUf3DGkTcu + khP7AAAAAElFTkSuQmCC iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go - tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX - AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC + xAAADsQBlSsOGwAAAHpJREFUOE+1kVEKgDAMQ3e2/e+MXqpn6W/HxM7SpkIVB4HxSMKiTUTaFwVQ1X25 + DjMfSxskHBYsAxHJkjUjHgrUNMY4peaMPxb03rcZMVhgn2oDKAwn+L0aROH/Cny4NAGFSx8x+10ZDwV2 + gt+LOCxQsw1nPBS8VQBVTTzyhrdZSUm7AAAAAElFTkSuQmCC @@ -146,49 +146,49 @@ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go - tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX - AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC + xAAADsQBlSsOGwAAAHpJREFUOE+1kVEKgDAMQ3e2/e+MXqpn6W/HxM7SpkIVB4HxSMKiTUTaFwVQ1X25 + DjMfSxskHBYsAxHJkjUjHgrUNMY4peaMPxb03rcZMVhgn2oDKAwn+L0aROH/Cny4NAGFSx8x+10ZDwV2 + gt+LOCxQsw1nPBS8VQBVTTzyhrdZSUm7AAAAAElFTkSuQmCC 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== + JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsTAAALEwEAmpwYAAACM0lE + QVQ4T2P4//8/AyHMzicsqh6c34guDsIYAshYQFadhZmZhU1c18Yp8NCP/7LWvjHoajA0gbCwpqW7YeGs + FXYTD15xnHnihuuiiw98D//6777kynNuAREpnAYwMjIyqQQX9zkvffDfZce3//b7//23PPD/v/HWr//1 + Vr74b7jm3X/VpI7FTIyMjFgNUAku6nRd//6/0ZTT31QbNlxXbthwQa3/6CO1ZS/+K8y+91968u3/qr1X + /gsq6jliGCCoYmRp23/4u4R9eCczF782AwMDFwMDA7OYhV+C2ooP/5UnXf+vkDXnioi+cz4LG6cIhgGK + zlE1/PLakcguArsquXuOSvmqayLatmnMjAx86PJwBhMzM4YkCPNKKpkxMTAIootjGIANswtKSKKLoWMM + ARAW0LS20S2at1POM20quhyvspGFqLlfJoYBTCzsnEI6Dl6a6ZO32c66+t91/dv/Akq6wTB5IQVdfgnP + jGSlpr1vuKTVPDAM4FczD7Ceeum/w6J7/y2XP/2vt/rNf9mGTUekC+eulKtYuUW+5+Qj2TlP/4u4psxD + dhGSC9h4dUoWntZf9e6/0qr3/5V3/Puvuu//f6Xt///Lrvr8X3ryzf8SfsWbmNBiAsV/bJIqpkpLX/xU + 2/n3v+qcmx9VZl77oth97L1U2pQTgtq2WUwMDGzI6jEMAGFR/7wGzS3f//PIagawcvIqsLJzKTAyMLCi + q8NpABMLK4dCfOsSZlYOUXQ5bBgArRReBMoH61gAAAAASUVORK5CYII= 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== + JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsTAAALEwEAmpwYAAACM0lE + QVQ4T2P4//8/AyHMzicsqh6c34guDsIYAshYQFadhZmZhU1c18Yp8NCP/7LWvjHoajA0gbCwpqW7YeGs + FXYTD15xnHnihuuiiw98D//6777kynNuAREpnAYwMjIyqQQX9zkvffDfZce3//b7//23PPD/v/HWr//1 + Vr74b7jm3X/VpI7FTIyMjFgNUAku6nRd//6/0ZTT31QbNlxXbthwQa3/6CO1ZS/+K8y+91968u3/qr1X + /gsq6jliGCCoYmRp23/4u4R9eCczF782AwMDFwMDA7OYhV+C2ooP/5UnXf+vkDXnioi+cz4LG6cIhgGK + zlE1/PLakcguArsquXuOSvmqayLatmnMjAx86PJwBhMzM4YkCPNKKpkxMTAIootjGIANswtKSKKLoWMM + ARAW0LS20S2at1POM20quhyvspGFqLlfJoYBTCzsnEI6Dl6a6ZO32c66+t91/dv/Akq6wTB5IQVdfgnP + jGSlpr1vuKTVPDAM4FczD7Ceeum/w6J7/y2XP/2vt/rNf9mGTUekC+eulKtYuUW+5+Qj2TlP/4u4psxD + dhGSC9h4dUoWntZf9e6/0qr3/5V3/Puvuu//f6Xt///Lrvr8X3ryzf8SfsWbmNBiAsV/bJIqpkpLX/xU + 2/n3v+qcmx9VZl77oth97L1U2pQTgtq2WUwMDGzI6jEMAGFR/7wGzS3f//PIagawcvIqsLJzKTAyMLCi + q8NpABMLK4dCfOsSZlYOUXQ5bBgArRReBMoH61gAAAAASUVORK5CYII= iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go - tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX - AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC + xAAADsQBlSsOGwAAAHpJREFUOE+1kVEKgDAMQ3e2/e+MXqpn6W/HxM7SpkIVB4HxSMKiTUTaFwVQ1X25 + DjMfSxskHBYsAxHJkjUjHgrUNMY4peaMPxb03rcZMVhgn2oDKAwn+L0aROH/Cny4NAGFSx8x+10ZDwV2 + gt+LOCxQsw1nPBS8VQBVTTzyhrdZSUm7AAAAAElFTkSuQmCC @@ -248,17 +248,17 @@ You can find more detailed information about the missing posts in the form that iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go - tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX - AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC + xAAADsQBlSsOGwAAAHpJREFUOE+1kVEKgDAMQ3e2/e+MXqpn6W/HxM7SpkIVB4HxSMKiTUTaFwVQ1X25 + DjMfSxskHBYsAxHJkjUjHgrUNMY4peaMPxb03rcZMVhgn2oDKAwn+L0aROH/Cny4NAGFSx8x+10ZDwV2 + gt+LOCxQsw1nPBS8VQBVTTzyhrdZSUm7AAAAAElFTkSuQmCC iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go - tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX - AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC + xAAADsQBlSsOGwAAAHpJREFUOE+1kVEKgDAMQ3e2/e+MXqpn6W/HxM7SpkIVB4HxSMKiTUTaFwVQ1X25 + DjMfSxskHBYsAxHJkjUjHgrUNMY4peaMPxb03rcZMVhgn2oDKAwn+L0aROH/Cny4NAGFSx8x+10ZDwV2 + gt+LOCxQsw1nPBS8VQBVTTzyhrdZSUm7AAAAAElFTkSuQmCC @@ -279,20 +279,20 @@ You can find more detailed information about the missing posts in the form that iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - wwAADsMBx2+oZAAAAR5JREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbGujg3ZATZPKYdC6FQhPwlAMkg3dP - WQwhyWIyJIUW5NqyPb7oCVtIlhVTwYf8nv7/t2zJagel9KmqKsIACYL9RjI8UHz5zshougZr/AEvbxEP - aZCDBY3VslixaJvX3wzkkDiOwbZtDRGA5vdNAg+TL27qgmt5XkBG/gTdAG7Gt+3PP9oOaEGFCVEC6rp+ - 5g9MfM/c5e4OsEZMZkQEtGL5H2DdZ5JRArDwPA+iKII0TfkC9vroC9j5vq8JTWw3WzWgLMtZGIaa0MR8 - vlAD8PYlSaIJTTiOowY0p0Bc19XEJo6HE59FAPuMzyAINKGJ1XLFZxHALtMrnkBXOIQIIIQ8YvF/KrgB - cMaRN0UdBBkAAAAASUVORK5CYII= + wwAADsMBx2+oZAAAARlJREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbWujg3dATZPKYZC6BQhvw1AMkg3dP + XQyl7WIyJIEW5CbS0/jKE5GwpCghgg9s6/8/y5Kj6DA45zcAwAAAezB6rjNnB4XX244NHt8wGs7wblop + yRGxwZQBYKIfbn477EvqusY4jj2MgMpPiwav7l9UyYXmdrs9duzP4ApUmd72sfrxVsD33JQISyClvFUX + w9nJssvJFei9CJUtgQ7394Du3YKLJaCbLMuwqips21ZNuDve/35X8J7nuRcMsVwsbYEQYlSWpRcMMR5P + bAH9fU3TeMEQSZLYgsMpsDRNvXCIr89vWyCEeC6KwguGmL/ObYGU8oFOwA2ewwgYY9f6f7iUf3DGkTcu + khP7AAAAAElFTkSuQmCC iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go - tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX - AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC + xAAADsQBlSsOGwAAAHpJREFUOE+1kVEKgDAMQ3e2/e+MXqpn6W/HxM7SpkIVB4HxSMKiTUTaFwVQ1X25 + DjMfSxskHBYsAxHJkjUjHgrUNMY4peaMPxb03rcZMVhgn2oDKAwn+L0aROH/Cny4NAGFSx8x+10ZDwV2 + gt+LOCxQsw1nPBS8VQBVTTzyhrdZSUm7AAAAAElFTkSuQmCC @@ -313,25 +313,25 @@ You can find more detailed information about the missing posts in the form that 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 @@ -343,6 +343,15 @@ You can find more detailed information about the missing posts in the form that False + + False + + + False + + + False + False @@ -355,165 +364,165 @@ You can find more detailed information about the missing posts in the form that iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - wwAADsMBx2+oZAAAAR5JREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbGujg3ZATZPKYdC6FQhPwlAMkg3dP - WQwhyWIyJIUW5NqyPb7oCVtIlhVTwYf8nv7/t2zJagel9KmqKsIACYL9RjI8UHz5zshougZr/AEvbxEP - aZCDBY3VslixaJvX3wzkkDiOwbZtDRGA5vdNAg+TL27qgmt5XkBG/gTdAG7Gt+3PP9oOaEGFCVEC6rp+ - 5g9MfM/c5e4OsEZMZkQEtGL5H2DdZ5JRArDwPA+iKII0TfkC9vroC9j5vq8JTWw3WzWgLMtZGIaa0MR8 - vlAD8PYlSaIJTTiOowY0p0Bc19XEJo6HE59FAPuMzyAINKGJ1XLFZxHALtMrnkBXOIQIIIQ8YvF/KrgB - cMaRN0UdBBkAAAAASUVORK5CYII= + wwAADsMBx2+oZAAAARlJREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbWujg3dATZPKYZC6BQhvw1AMkg3dP + XQyl7WIyJIEW5CbS0/jKE5GwpCghgg9s6/8/y5Kj6DA45zcAwAAAezB6rjNnB4XX244NHt8wGs7wblop + yRGxwZQBYKIfbn477EvqusY4jj2MgMpPiwav7l9UyYXmdrs9duzP4ApUmd72sfrxVsD33JQISyClvFUX + w9nJssvJFei9CJUtgQ7394Du3YKLJaCbLMuwqips21ZNuDve/35X8J7nuRcMsVwsbYEQYlSWpRcMMR5P + bAH9fU3TeMEQSZLYgsMpsDRNvXCIr89vWyCEeC6KwguGmL/ObYGU8oFOwA2ewwgYY9f6f7iUf3DGkTcu + khP7AAAAAElFTkSuQmCC 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 - cMaRN0UdBBkAAAAASUVORK5CYII= + wwAADsMBx2+oZAAAARlJREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbWujg3dATZPKYZC6BQhvw1AMkg3dP + XQyl7WIyJIEW5CbS0/jKE5GwpCghgg9s6/8/y5Kj6DA45zcAwAAAezB6rjNnB4XX244NHt8wGs7wblop + yRGxwZQBYKIfbn477EvqusY4jj2MgMpPiwav7l9UyYXmdrs9duzP4ApUmd72sfrxVsD33JQISyClvFUX + w9nJssvJFei9CJUtgQ7394Du3YKLJaCbLMuwqips21ZNuDve/35X8J7nuRcMsVwsbYEQYlSWpRcMMR5P + bAH9fU3TeMEQSZLYgsMpsDRNvXCIr89vWyCEeC6KwguGmL/ObYGU8oFOwA2ewwgYY9f6f7iUf3DGkTcu + khP7AAAAAElFTkSuQmCC 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 - cMaRN0UdBBkAAAAASUVORK5CYII= + wwAADsMBx2+oZAAAARlJREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbWujg3dATZPKYZC6BQhvw1AMkg3dP + XQyl7WIyJIEW5CbS0/jKE5GwpCghgg9s6/8/y5Kj6DA45zcAwAAAezB6rjNnB4XX244NHt8wGs7wblop + yRGxwZQBYKIfbn477EvqusY4jj2MgMpPiwav7l9UyYXmdrs9duzP4ApUmd72sfrxVsD33JQISyClvFUX + w9nJssvJFei9CJUtgQ7394Du3YKLJaCbLMuwqips21ZNuDve/35X8J7nuRcMsVwsbYEQYlSWpRcMMR5P + bAH9fU3TeMEQSZLYgsMpsDRNvXCIr89vWyCEeC6KwguGmL/ObYGU8oFOwA2ewwgYY9f6f7iUf3DGkTcu + khP7AAAAAElFTkSuQmCC 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 - cMaRN0UdBBkAAAAASUVORK5CYII= + wwAADsMBx2+oZAAAARlJREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbWujg3dATZPKYZC6BQhvw1AMkg3dP + XQyl7WIyJIEW5CbS0/jKE5GwpCghgg9s6/8/y5Kj6DA45zcAwAAAezB6rjNnB4XX244NHt8wGs7wblop + yRGxwZQBYKIfbn477EvqusY4jj2MgMpPiwav7l9UyYXmdrs9duzP4ApUmd72sfrxVsD33JQISyClvFUX + w9nJssvJFei9CJUtgQ7394Du3YKLJaCbLMuwqips21ZNuDve/35X8J7nuRcMsVwsbYEQYlSWpRcMMR5P + bAH9fU3TeMEQSZLYgsMpsDRNvXCIr89vWyCEeC6KwguGmL/ObYGU8oFOwA2ewwgYY9f6f7iUf3DGkTcu + khP7AAAAAElFTkSuQmCC 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 @@ -524,92 +533,90 @@ You can find more detailed information about the missing posts in the form that - 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 + U1wTEVFuCACwydqqfmZO8Z3yxXrc6T7f73o/AEyQiDgtp/QXG/EpgTbFF3JKv1D+TABgQnQfx2ur+POc + 4kflC/kx5u6c4l+blF7YXWoofw4AMIG6W/G2i/Wzckp/lVP896EX9PJFvkh3M5/6o03E7+acF8vvCQBM + mQO/EFTVctfezxEXtlX9vLaqX9z9s6mqC5YWF+fLrwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6LEtW/4flgYiLD1qeX0A - AAAASUVORK5CYII= + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAYIj+H5YGIizEb/aEAAAAAElFTkSuQmCC @@ -621,36 +628,36 @@ You can find more detailed information about the missing posts in the form that iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go - tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX - AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC + xAAADsQBlSsOGwAAAHpJREFUOE+1kVEKgDAMQ3e2/e+MXqpn6W/HxM7SpkIVB4HxSMKiTUTaFwVQ1X25 + DjMfSxskHBYsAxHJkjUjHgrUNMY4peaMPxb03rcZMVhgn2oDKAwn+L0aROH/Cny4NAGFSx8x+10ZDwV2 + gt+LOCxQsw1nPBS8VQBVTTzyhrdZSUm7AAAAAElFTkSuQmCC iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go - tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX - AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC + xAAADsQBlSsOGwAAAHpJREFUOE+1kVEKgDAMQ3e2/e+MXqpn6W/HxM7SpkIVB4HxSMKiTUTaFwVQ1X25 + DjMfSxskHBYsAxHJkjUjHgrUNMY4peaMPxb03rcZMVhgn2oDKAwn+L0aROH/Cny4NAGFSx8x+10ZDwV2 + gt+LOCxQsw1nPBS8VQBVTTzyhrdZSUm7AAAAAElFTkSuQmCC iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - wwAADsMBx2+oZAAAAR5JREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbGujg3ZATZPKYdC6FQhPwlAMkg3dP - WQwhyWIyJIUW5NqyPb7oCVtIlhVTwYf8nv7/t2zJagel9KmqKsIACYL9RjI8UHz5zshougZr/AEvbxEP - aZCDBY3VslixaJvX3wzkkDiOwbZtDRGA5vdNAg+TL27qgmt5XkBG/gTdAG7Gt+3PP9oOaEGFCVEC6rp+ - 5g9MfM/c5e4OsEZMZkQEtGL5H2DdZ5JRArDwPA+iKII0TfkC9vroC9j5vq8JTWw3WzWgLMtZGIaa0MR8 - vlAD8PYlSaIJTTiOowY0p0Bc19XEJo6HE59FAPuMzyAINKGJ1XLFZxHALtMrnkBXOIQIIIQ8YvF/KrgB - cMaRN0UdBBkAAAAASUVORK5CYII= + wwAADsMBx2+oZAAAARlJREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbWujg3dATZPKYZC6BQhvw1AMkg3dP + XQyl7WIyJIEW5CbS0/jKE5GwpCghgg9s6/8/y5Kj6DA45zcAwAAAezB6rjNnB4XX244NHt8wGs7wblop + yRGxwZQBYKIfbn477EvqusY4jj2MgMpPiwav7l9UyYXmdrs9duzP4ApUmd72sfrxVsD33JQISyClvFUX + w9nJssvJFei9CJUtgQ7394Du3YKLJaCbLMuwqips21ZNuDve/35X8J7nuRcMsVwsbYEQYlSWpRcMMR5P + bAH9fU3TeMEQSZLYgsMpsDRNvXCIr89vWyCEeC6KwguGmL/ObYGU8oFOwA2ewwgYY9f6f7iUf3DGkTcu + khP7AAAAAElFTkSuQmCC iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go - tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX - AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC + xAAADsQBlSsOGwAAAHpJREFUOE+1kVEKgDAMQ3e2/e+MXqpn6W/HxM7SpkIVB4HxSMKiTUTaFwVQ1X25 + DjMfSxskHBYsAxHJkjUjHgrUNMY4peaMPxb03rcZMVhgn2oDKAwn+L0aROH/Cny4NAGFSx8x+10ZDwV2 + gt+LOCxQsw1nPBS8VQBVTTzyhrdZSUm7AAAAAElFTkSuQmCC @@ -659,41 +666,41 @@ You can find more detailed information about the missing posts in the form that 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 diff --git a/SCrawler/Editors/GlobalSettingsForm.vb b/SCrawler/Editors/GlobalSettingsForm.vb index 450431a..8170215 100644 --- a/SCrawler/Editors/GlobalSettingsForm.vb +++ b/SCrawler/Editors/GlobalSettingsForm.vb @@ -157,6 +157,8 @@ Namespace Editors CH_FEED_ADD_SITE.Checked = .FeedAddSiteToCaption CH_FEED_ADD_TYPE.Checked = .FeedAddTypeToCaption CH_FEED_ADD_DATE.Checked = .FeedAddDateToCaption + CH_FEED_TEXT.Checked = .FeedShowTextPosts + CH_FEED_TEXT_ALWAYS_MOVE.Checked = .FeedShowTextPostsAlwaysMove NUM_FEED_STORE_SESSION_DATA.Checked = .FeedStoreSessionsData NUM_FEED_STORE_SESSION_DATA.Value = .FeedStoredSessionsNumber.Value NUM_FEED_SES_CURR_LOAD_LAST.Value = .FeedCurrentTryLoadLastSession.Value @@ -375,6 +377,8 @@ Namespace Editors .FeedAddSiteToCaption.Value = CH_FEED_ADD_SITE.Checked .FeedAddTypeToCaption.Value = CH_FEED_ADD_TYPE.Checked .FeedAddDateToCaption.Value = CH_FEED_ADD_DATE.Checked + .FeedShowTextPosts.Value = CH_FEED_TEXT.Checked + .FeedShowTextPostsAlwaysMove.Value = CH_FEED_TEXT_ALWAYS_MOVE.Checked .FeedStoreSessionsData.Value = NUM_FEED_STORE_SESSION_DATA.Checked .FeedStoredSessionsNumber.Value = NUM_FEED_STORE_SESSION_DATA.Value .FeedCurrentTryLoadLastSession.Value = NUM_FEED_SES_CURR_LOAD_LAST.Value diff --git a/SCrawler/MainFrame.vb b/SCrawler/MainFrame.vb index 3cda4f1..d6ca5c9 100644 --- a/SCrawler/MainFrame.vb +++ b/SCrawler/MainFrame.vb @@ -39,6 +39,7 @@ Public Class MainFrame #Region "Initializer" Public Sub New() InitializeComponent() + FormFont = Font Settings = New SettingsCLS With Settings.Plugins If .Count > 0 Then diff --git a/SCrawler/MainMod.vb b/SCrawler/MainMod.vb index ba5972a..db58c5c 100644 --- a/SCrawler/MainMod.vb +++ b/SCrawler/MainMod.vb @@ -74,6 +74,8 @@ Friend Module MainMod Friend UserListLoader As ListImagesLoader Friend MyProgressForm As ActiveDownloadingProgress Friend MainFrameObj As MainFrameObjects + Friend FormFont As Font = Nothing + Friend TextImageWidth As Integer = 300 ''' Alt+F1 Friend ReadOnly ShowUsersButtonKey As New PersonalUtilities.Forms.ButtonKey(Keys.F1,, True) Friend ReadOnly DateTimeDefaultProvider As New ADateTime(ADateTime.Formats.BaseDateTime) diff --git a/SCrawler/My Project/AssemblyInfo.vb b/SCrawler/My Project/AssemblyInfo.vb index b9f5a37..9b25891 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/SCrawler.vbproj b/SCrawler/SCrawler.vbproj index ed461d2..c3df7fd 100644 --- a/SCrawler/SCrawler.vbproj +++ b/SCrawler/SCrawler.vbproj @@ -300,6 +300,13 @@ Form + + + FeedFilterForm.vb + + + Form + FeedMedia.vb @@ -585,6 +592,9 @@ FeedCopyToForm.vb + + FeedFilterForm.vb + FeedMedia.vb diff --git a/SCrawler/SettingsCLS.vb b/SCrawler/SettingsCLS.vb index fc4d8bf..84b1545 100644 --- a/SCrawler/SettingsCLS.vb +++ b/SCrawler/SettingsCLS.vb @@ -422,6 +422,11 @@ Friend Class SettingsCLS : Implements IDownloaderSettings, IDisposable FeedEscToClose = New XMLValue(Of Boolean)("EscToClose", True, MyXML, n) FeedSpecialSearchForMissing = New XMLValue(Of Boolean)("FeedSpecialSearchForMissing", True, MyXML, n) FeedSpecialSearchForMissing_Deep = New XMLValue(Of Boolean)("FeedSpecialSearchForMissing_Deep", False, MyXML, n) + FeedShowTextPosts = New XMLValue(Of Boolean)("FeedShowTextPosts", True, MyXML, n) + FeedShowTextPostsAlwaysMove = New XMLValue(Of Boolean)("FeedShowTextPostsAlwaysMove", True, MyXML, n) + FeedShowTextPosts_LogErrors = New XMLValue(Of Boolean)("FeedShowTextPosts_LogErrors", False, MyXML, n) + AddHandler FeedShowTextPosts_LogErrors.ValueChanged, AddressOf FeedShowTextPosts_LogErrors_ValueChanged + FeedShowTextPosts_LogErrors_ValueChanged(Nothing, Nothing) n = {"Feed", "MoveCopy"} FeedMoveCopyLastLocation = New XMLValue(Of SFile)("LastLocation",, MyXML, n) FeedMoveCopyUpdateFileLocationOnMove = New XMLValue(Of Boolean)("UpdateFileLocationOnMove", True, MyXML, n) @@ -1137,6 +1142,18 @@ Friend Class SettingsCLS : Implements IDownloaderSettings, IDisposable Friend ReadOnly Property FeedEscToClose As XMLValue(Of Boolean) Friend ReadOnly Property FeedSpecialSearchForMissing As XMLValue(Of Boolean) Friend ReadOnly Property FeedSpecialSearchForMissing_Deep As XMLValue(Of Boolean) + Friend ReadOnly Property FeedShowTextPosts As XMLValue(Of Boolean) + Friend ReadOnly Property FeedShowTextPostsAlwaysMove As XMLValue(Of Boolean) + Friend ReadOnly Property FeedShowTextPosts_LogErrors As XMLValue(Of Boolean) + Private _FeedShowTextPosts_LogErrors_E As ErrorsDescriber + Friend ReadOnly Property FeedShowTextPosts_LogErrors_E As ErrorsDescriber + Get + Return _FeedShowTextPosts_LogErrors_E + End Get + End Property + Private Sub FeedShowTextPosts_LogErrors_ValueChanged(ByVal Sender As Object, ByVal e As EventArgs) + _FeedShowTextPosts_LogErrors_E = New ErrorsDescriber(If(FeedShowTextPosts_LogErrors, EDP.SendToLog, EDP.None) + EDP.ReturnValue) + End Sub #Region "MoveCopy" Friend ReadOnly Property FeedMoveCopyLastLocation As XMLValue(Of SFile) Friend ReadOnly Property FeedMoveCopyUpdateFileLocationOnMove As XMLValue(Of Boolean) diff --git a/SCrawler/UserImage.vb b/SCrawler/UserImage.vb index b115e4e..58bdbb0 100644 --- a/SCrawler/UserImage.vb +++ b/SCrawler/UserImage.vb @@ -94,4 +94,7 @@ Friend Class UserImage : Inherits ImageRenderer Small.Save(_SmallAddress) Large.Save(_LargeAddress) End Sub + Friend Overloads Shared Function CreateImageFromText(ByVal Text As String, ByVal File As SFile) As Boolean + Return CreateImageFromText(Text, FormFont, Color.Black, TextImageWidth, File, Color.White,, EDP.ThrowException) + End Function End Class \ No newline at end of file diff --git a/SCrawler/UserInfo.vb b/SCrawler/UserInfo.vb index 1cc1401..0a34f17 100644 --- a/SCrawler/UserInfo.vb +++ b/SCrawler/UserInfo.vb @@ -203,7 +203,11 @@ Partial Friend Module MainMod IsSubscription = Other.IsSubscription And (Not Plugin = PathPlugin.PluginKey Or SpecialPath = Other.SpecialPath) End Function Public Overloads Overrides Function Equals(ByVal Obj As Object) As Boolean - Return Equals(DirectCast(Obj, UserInfo)) + If Not IsDBNull(Obj) Then + Return Equals(DirectCast(Obj, UserInfo)) + Else + Return False + End If End Function #End Region End Structure