From 0ea2156ada4a5d32d2c702c6bcc92b3a4c4148b3 Mon Sep 17 00:00:00 2001 From: Andy <88590076+AAndyProgram@users.noreply.github.com> Date: Sun, 18 Feb 2024 00:10:39 +0300 Subject: [PATCH] 2024.2.17.0 YT Add the ability to edit playlist items Add 'Open file' to the context menu Add the ability to embed thumbnail in the audio/video as cover art VideoOptionsForm: audio codec does not change when changing audio/video in the video options form SCrawler DownloadFeedForm: add ability to merge multiple special feeds into one AutoDownloader: fix bug when users are added during pool reconfiguration Scheduler: add the ability to move tasks FeedMedia: fix image rendering bug Feed: add select all/none; add the ability to add to a special feed(s) with removal from the current one; add loaded feed name to the title; refresh the loaded feed using the 'Refresh' button FeedSpecialCollection: add 'Add' button to feed chooser; fixed a bug in the 'Delete' function SettingsHostCollection, PluginHost: add 'IDisposable' support API.UserDataBase: add Responser handler options API.OnlyFans: handle 500 error API.Threads: extract 'csrftoken' from cookies; simplify 500 error when updating tokens API.Instagram: update handling of JSON parsing error when downloading reels; fix error downloading single post API.Facebook: simplify token update errors API.Twitter: update handling of JSON parsing error --- SCrawler.YouTube/Base/YouTubeSettings.vb | 6 + SCrawler.YouTube/Controls/VideoOptionsForm.vb | 63 ++- .../Downloader/MediaItem.Designer.vb | 59 ++- SCrawler.YouTube/Downloader/MediaItem.resx | 132 ++++++ SCrawler.YouTube/Downloader/MediaItem.vb | 43 +- .../Objects/YouTubeMediaContainerBase.vb | 111 +++-- SCrawler/API/Base/UserDataBase.vb | 26 +- SCrawler/API/Facebook/UserData.vb | 34 +- SCrawler/API/Instagram/UserData.vb | 16 +- SCrawler/API/JustForFans/UserData.vb | 5 +- SCrawler/API/OnlyFans/UserData.vb | 55 ++- SCrawler/API/ThisVid/SiteSettings.vb | 3 +- SCrawler/API/ThisVid/UserData.vb | 48 ++- SCrawler/API/ThreadsNet/SiteSettings.vb | 11 +- SCrawler/API/ThreadsNet/UserData.vb | 12 +- SCrawler/API/Twitter/UserData.vb | 7 +- .../Download/Automation/AutoDownloader.vb | 12 +- SCrawler/Download/Automation/Scheduler.vb | 19 + .../Automation/SchedulerEditorForm.vb | 24 ++ .../Feed/DownloadFeedForm.Designer.vb | 105 +++-- SCrawler/Download/Feed/DownloadFeedForm.resx | 6 + SCrawler/Download/Feed/DownloadFeedForm.vb | 390 ++++++++++++++---- SCrawler/Download/Feed/FeedMedia.Designer.vb | 124 +++--- SCrawler/Download/Feed/FeedMedia.vb | 43 +- .../Download/Feed/FeedSpecialCollection.vb | 60 ++- .../PluginsEnvironment/Hosts/PluginHost.vb | 19 +- .../Hosts/SettingsHostCollection.vb | 29 +- SCrawler/SettingsCLS.vb | 2 +- 28 files changed, 1120 insertions(+), 344 deletions(-) diff --git a/SCrawler.YouTube/Base/YouTubeSettings.vb b/SCrawler.YouTube/Base/YouTubeSettings.vb index 191659e..608b701 100644 --- a/SCrawler.YouTube/Base/YouTubeSettings.vb +++ b/SCrawler.YouTube/Base/YouTubeSettings.vb @@ -273,6 +273,9 @@ Namespace API.YouTube.Base Public ReadOnly Property DefaultVideoDefinition As XMLValue(Of Integer) + + Public ReadOnly Property DefaultVideoEmbedThumbnail As XMLValue(Of Boolean) Public ReadOnly Property DefaultVideoIncludeNullSize As XMLValue(Of Boolean) @@ -360,6 +363,9 @@ Namespace API.YouTube.Base TypeConverter(GetType(ValueCollectionConverter)), Description("Additional audio format for downloading videos. This means that the audio will be extracted and saved as a separate file in these formats.")> Public ReadOnly Property DefaultAudioCodecAddit As XMLValuesCollection(Of String) + + Public ReadOnly Property DefaultAudioEmbedThumbnail As XMLValue(Of Boolean) #End Region #Region "Defaults Subtitles" diff --git a/SCrawler.YouTube/Controls/VideoOptionsForm.vb b/SCrawler.YouTube/Controls/VideoOptionsForm.vb index bbffbcd..3bff34d 100644 --- a/SCrawler.YouTube/Controls/VideoOptionsForm.vb +++ b/SCrawler.YouTube/Controls/VideoOptionsForm.vb @@ -30,7 +30,7 @@ Namespace API.YouTube.Controls Private ReadOnly Property CNT_PROCESSOR As TableControlsProcessor Friend Property MyContainer As YouTubeMediaContainerBase Private Initialization As Boolean = True - Private ReadOnly IsSavedObject As Boolean + Private ReadOnly InheritsFromContainer As Boolean Private Class FpsFieldChecker : Inherits FieldsCheckerProviderBase Private ReadOnly MyProvider As ANumbers = YouTubeSettings.FpsFormatProvider.MyProviderDefault Public Overrides Property ErrorMessage As String @@ -52,11 +52,11 @@ Namespace API.YouTube.Controls End Class #End Region #Region "Initializers" - Friend Sub New(ByVal Container As YouTubeMediaContainerBase, Optional ByVal IsSavedObject As Boolean = False) + Friend Sub New(ByVal Container As YouTubeMediaContainerBase, Optional ByVal InheritsFromContainer As Boolean = False) InitializeComponent() MyContainer = Container CNT_PROCESSOR = New TableControlsProcessor(TP_CONTROLS) - Me.IsSavedObject = IsSavedObject + Me.InheritsFromContainer = InheritsFromContainer MyFieldsChecker = New FieldsChecker End Sub #End Region @@ -89,8 +89,8 @@ Namespace API.YouTube.Controls If Not .PlaylistTitle.IsEmptyString Or Not .Title.IsEmptyString Then Text &= $" - { .PlaylistTitle.IfNullOrEmpty(.Title)}" TP_MAIN.Controls.Remove(TP_HEADER_BASE) TP_MAIN.RowStyles(0).Height = 0 - Dim def% = If(IsSavedObject, .ArrayMaxResolution, MyYouTubeSettings.DefaultVideoDefinition.Value) - If IsSavedObject Then + Dim def% = If(InheritsFromContainer, .ArrayMaxResolution, MyYouTubeSettings.DefaultVideoDefinition.Value) + If InheritsFromContainer Then __audioOnly = def = -2 If def <= 0 Then def = MyYouTubeSettings.DefaultVideoDefinition Else @@ -119,7 +119,7 @@ Namespace API.YouTube.Controls LBL_URL.Text = .URL End If - If .IsMusic Or __audioOnly Then + If .IsMusic Or __audioOnly Or (InheritsFromContainer And .IsAudioSelected) Then OPT_AUDIO.Checked = True Else OPT_VIDEO.Checked = True @@ -128,7 +128,7 @@ Namespace API.YouTube.Controls arr = AvailableVideoFormats CMB_FORMAT.Items.AddRange(arr) - If IsSavedObject Then + If InheritsFromContainer Then __optionValue = .OutputVideoExtension.IfNullOrEmpty(MyYouTubeSettings.DefaultVideoFormat.Value) Else __optionValue = MyYouTubeSettings.DefaultVideoFormat.Value @@ -137,7 +137,7 @@ Namespace API.YouTube.Controls arr = AvailableAudioFormats CMB_AUDIO_CODEC.Items.AddRange(arr) - If IsSavedObject Then + If InheritsFromContainer Then __optionValue = .OutputAudioCodec.IfNullOrEmpty(IIf(.IsMusic, MyYouTubeSettings.DefaultAudioCodecMusic.Value, MyYouTubeSettings.DefaultAudioCodec.Value)) Else __optionValue = IIf(.IsMusic, MyYouTubeSettings.DefaultAudioCodecMusic.Value, MyYouTubeSettings.DefaultAudioCodec.Value) @@ -146,14 +146,18 @@ Namespace API.YouTube.Controls arr = AvailableSubtitlesFormats CMB_SUBS_FORMAT.Items.AddRange(arr) - If IsSavedObject Then + If InheritsFromContainer Then __optionValue = .OutputSubtitlesFormat.IfNullOrEmpty(IIf(.IsMusic, "LRC", MyYouTubeSettings.DefaultSubtitlesFormat.Value)) Else __optionValue = IIf(.IsMusic, "LRC", MyYouTubeSettings.DefaultSubtitlesFormat.Value) End If setDef(CMB_SUBS_FORMAT, __optionValue) - If MyYouTubeSettings.DefaultVideoFPS > 0 Then TXT_FPS.Text = MyYouTubeSettings.DefaultVideoFPS + If InheritsFromContainer Then + If .OutputVideoFPS > 0 Then TXT_FPS.Text = .OutputVideoFPS + Else + If MyYouTubeSettings.DefaultVideoFPS > 0 Then TXT_FPS.Text = MyYouTubeSettings.DefaultVideoFPS + End If MyFieldsChecker.AddControl(Of Double)(TXT_FPS, TXT_FPS.CaptionText, True, New FpsFieldChecker) MyFieldsChecker.EndLoaderOperations() TP_SUBS.Enabled = .Subtitles.Count > 0 @@ -208,7 +212,7 @@ Namespace API.YouTube.Controls Dim data As IEnumerable(Of Control) If .HasElements Then - data = .Elements.Select(Function(ee) New MediaItem(ee) With {.Dock = DockStyle.Fill, .Checked = ee.Checked, .IgnoreDownloadState = True}) + data = .Elements.Select(Function(ee) New MediaItem(ee, True) With {.Dock = DockStyle.Fill, .Checked = ee.Checked}) Else data = (From m As MediaObject In .Self.MediaObjects Where m.Type = __contentType @@ -229,6 +233,8 @@ Namespace API.YouTube.Controls If MyContainer.HasElements Then With DirectCast(d, MediaItem) AddHandler .CheckedChanged, AddressOf MediaItem_CheckedChanged + AddHandler .BeforeOpenEditor, AddressOf MediaItem_BeforeOpenEditor + AddHandler .BeforeOpenEditorFull, AddressOf MediaItem_BeforeOpenEditorFull AddHandler .Click, AddressOf CNT_PROCESSOR.MediaItem_Click AddHandler .KeyDown, AddressOf CNT_PROCESSOR.MediaItem_KeyDown End With @@ -296,6 +302,28 @@ Namespace API.YouTube.Controls Private Sub MediaItem_CheckedChanged(ByVal Sender As MediaItem, ByVal Container As IYouTubeMediaContainer) ControlInvokeFast(TP_CONTROLS, Sub() Container.Checked = Sender.Checked, EDP.None) End Sub + Private Sub MediaItem_BeforeOpenEditor(ByVal Sender As MediaItem, ByVal Container As IYouTubeMediaContainer) + MediaItem_BeforeOpenEditorImpl(Sender, Container, False) + End Sub + Private Sub MediaItem_BeforeOpenEditorFull(ByVal Sender As MediaItem, ByVal Container As IYouTubeMediaContainer) + MediaItem_BeforeOpenEditorImpl(Sender, Container, True) + End Sub + Private Sub MediaItem_BeforeOpenEditorImpl(ByVal Sender As MediaItem, ByVal Container As IYouTubeMediaContainer, ByVal Full As Boolean) + If MyContainer.HasElements Then + ControlInvokeFast(TP_CONTROLS, Sub() + With DirectCast(Container, YouTubeMediaContainerBase) + .File = $"{TXT_FILE.Text.CSFilePS}{ .File.File}" + If Full Then + .OutputVideoExtension = CMB_FORMAT.Text.StringToLower + .OutputVideoFPS = AConvert(Of Double)(TXT_FPS.Text, YouTubeSettings.FpsFormatProvider.MyProviderDefault, -1) + .OutputAudioCodec = CMB_AUDIO_CODEC.Text.StringToLower + .OutputSubtitlesFormat = CMB_SUBS_FORMAT.Text.StringToLower + .IsAudioSelected = OPT_AUDIO.Checked + End If + End With + End Sub, EDP.None) + End If + End Sub #End Region #Region "OK, Cancel" Private Sub BTT_DOWN_Click(sender As Object, e As EventArgs) Handles BTT_DOWN.Click @@ -373,6 +401,19 @@ Namespace API.YouTube.Controls Private Sub OPT_VIDEO_AUDIO_CheckedChanged(sender As Object, e As EventArgs) Handles OPT_VIDEO.CheckedChanged, OPT_AUDIO.CheckedChanged If Not Initialization Then CMB_FORMAT.Enabled = OPT_VIDEO.Checked + Dim upFormat As Action(Of String) = Sub(ByVal format As String) + If Not format.IsEmptyString Then + format = format.ToLower + Dim fIndex% = CMB_AUDIO_CODEC.Items.Cast(Of String).ListIndexOf(Function(f) f.ToLower = format) + If fIndex >= 0 Then CMB_AUDIO_CODEC.SelectedIndex = fIndex + End If + End Sub + If OPT_VIDEO.Checked Then + upFormat(MyYouTubeSettings.DefaultAudioCodec) + Else + upFormat(MyYouTubeSettings.DefaultAudioCodecMusic) + End If + If MyContainer.HasElements Then NUM_RES.Enabled = OPT_VIDEO.Checked Else diff --git a/SCrawler.YouTube/Downloader/MediaItem.Designer.vb b/SCrawler.YouTube/Downloader/MediaItem.Designer.vb index 59365af..ba70a23 100644 --- a/SCrawler.YouTube/Downloader/MediaItem.Designer.vb +++ b/SCrawler.YouTube/Downloader/MediaItem.Designer.vb @@ -30,11 +30,16 @@ Namespace DownloadObjects.STDownloader Me.BTT_DOWN = New System.Windows.Forms.ToolStripMenuItem() Me.SEP_DOWN = New System.Windows.Forms.ToolStripSeparator() Me.BTT_OPEN_FOLDER = New System.Windows.Forms.ToolStripMenuItem() + Me.BTT_OPEN_FILE = New System.Windows.Forms.ToolStripMenuItem() Me.SEP_FOLDER = New System.Windows.Forms.ToolStripSeparator() + Me.BTT_PLS_ITEM_EDIT = New System.Windows.Forms.ToolStripMenuItem() + Me.BTT_PLS_ITEM_EDIT_FULL = New System.Windows.Forms.ToolStripMenuItem() + Me.SEP_PLS_ITEM_EDIT = New System.Windows.Forms.ToolStripSeparator() Me.BTT_COPY_LINK = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_OPEN_IN_BROWSER = New System.Windows.Forms.ToolStripMenuItem() Me.SEP_DOWN_AGAIN = New System.Windows.Forms.ToolStripSeparator() Me.BTT_DOWN_AGAIN = New System.Windows.Forms.ToolStripMenuItem() + Me.BTT_VIEW_SETTINGS = New System.Windows.Forms.ToolStripMenuItem() Me.SEP_DEL = New System.Windows.Forms.ToolStripSeparator() Me.BTT_REMOVE_FROM_LIST = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_DELETE_FILE = New System.Windows.Forms.ToolStripMenuItem() @@ -42,7 +47,6 @@ Namespace DownloadObjects.STDownloader Me.TP_CHECKED_TITLE = New System.Windows.Forms.TableLayoutPanel() Me.LBL_TITLE = New System.Windows.Forms.Label() Me.CH_CHECKED = New System.Windows.Forms.CheckBox() - Me.BTT_VIEW_SETTINGS = New System.Windows.Forms.ToolStripMenuItem() TP_MAIN = New System.Windows.Forms.TableLayoutPanel() TP_MAIN.SuspendLayout() CType(Me.ICON_VIDEO, System.ComponentModel.ISupportInitialize).BeginInit() @@ -83,10 +87,10 @@ Namespace DownloadObjects.STDownloader ' 'CONTEXT_MAIN ' - Me.CONTEXT_MAIN.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_DOWN, Me.SEP_DOWN, Me.BTT_OPEN_FOLDER, Me.SEP_FOLDER, Me.BTT_COPY_LINK, Me.BTT_OPEN_IN_BROWSER, Me.SEP_DOWN_AGAIN, Me.BTT_DOWN_AGAIN, Me.BTT_VIEW_SETTINGS, Me.SEP_DEL, Me.BTT_REMOVE_FROM_LIST, Me.BTT_DELETE_FILE}) + Me.CONTEXT_MAIN.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_DOWN, Me.SEP_DOWN, Me.BTT_OPEN_FOLDER, Me.BTT_OPEN_FILE, Me.SEP_FOLDER, Me.BTT_PLS_ITEM_EDIT, Me.BTT_PLS_ITEM_EDIT_FULL, Me.SEP_PLS_ITEM_EDIT, Me.BTT_COPY_LINK, Me.BTT_OPEN_IN_BROWSER, Me.SEP_DOWN_AGAIN, Me.BTT_DOWN_AGAIN, Me.BTT_VIEW_SETTINGS, Me.SEP_DEL, Me.BTT_REMOVE_FROM_LIST, Me.BTT_DELETE_FILE}) Me.CONTEXT_MAIN.Name = "CONTEXT_MAIN" Me.CONTEXT_MAIN.ShowItemToolTips = False - Me.CONTEXT_MAIN.Size = New System.Drawing.Size(185, 226) + Me.CONTEXT_MAIN.Size = New System.Drawing.Size(185, 298) ' 'BTT_DOWN ' @@ -107,11 +111,42 @@ Namespace DownloadObjects.STDownloader Me.BTT_OPEN_FOLDER.Size = New System.Drawing.Size(184, 22) Me.BTT_OPEN_FOLDER.Text = "Open folder" ' + 'BTT_OPEN_FILE + ' + Me.BTT_OPEN_FILE.Image = CType(resources.GetObject("BTT_OPEN_FILE.Image"), System.Drawing.Image) + Me.BTT_OPEN_FILE.Name = "BTT_OPEN_FILE" + Me.BTT_OPEN_FILE.Size = New System.Drawing.Size(184, 22) + Me.BTT_OPEN_FILE.Text = "Open file" + ' 'SEP_FOLDER ' Me.SEP_FOLDER.Name = "SEP_FOLDER" Me.SEP_FOLDER.Size = New System.Drawing.Size(181, 6) ' + 'BTT_PLS_ITEM_EDIT + ' + Me.BTT_PLS_ITEM_EDIT.Image = CType(resources.GetObject("BTT_PLS_ITEM_EDIT.Image"), System.Drawing.Image) + Me.BTT_PLS_ITEM_EDIT.Name = "BTT_PLS_ITEM_EDIT" + Me.BTT_PLS_ITEM_EDIT.Size = New System.Drawing.Size(184, 22) + Me.BTT_PLS_ITEM_EDIT.Text = "Edit" + Me.BTT_PLS_ITEM_EDIT.Visible = False + ' + 'BTT_PLS_ITEM_EDIT_FULL + ' + Me.BTT_PLS_ITEM_EDIT_FULL.AutoToolTip = True + Me.BTT_PLS_ITEM_EDIT_FULL.Image = CType(resources.GetObject("BTT_PLS_ITEM_EDIT_FULL.Image"), System.Drawing.Image) + Me.BTT_PLS_ITEM_EDIT_FULL.Name = "BTT_PLS_ITEM_EDIT_FULL" + Me.BTT_PLS_ITEM_EDIT_FULL.Size = New System.Drawing.Size(184, 22) + Me.BTT_PLS_ITEM_EDIT_FULL.Text = "Edit (inherit settings)" + Me.BTT_PLS_ITEM_EDIT_FULL.ToolTipText = "Inherit settings selected in the form" + Me.BTT_PLS_ITEM_EDIT_FULL.Visible = False + ' + 'SEP_PLS_ITEM_EDIT + ' + Me.SEP_PLS_ITEM_EDIT.Name = "SEP_PLS_ITEM_EDIT" + Me.SEP_PLS_ITEM_EDIT.Size = New System.Drawing.Size(181, 6) + Me.SEP_PLS_ITEM_EDIT.Visible = False + ' 'BTT_COPY_LINK ' Me.BTT_COPY_LINK.Image = Global.SCrawler.My.Resources.Resources.LinkPic_32 @@ -138,6 +173,13 @@ Namespace DownloadObjects.STDownloader Me.BTT_DOWN_AGAIN.Size = New System.Drawing.Size(184, 22) Me.BTT_DOWN_AGAIN.Text = "Download again" ' + 'BTT_VIEW_SETTINGS + ' + Me.BTT_VIEW_SETTINGS.Image = Global.SCrawler.My.Resources.Resources.SettingsPic_16 + Me.BTT_VIEW_SETTINGS.Name = "BTT_VIEW_SETTINGS" + Me.BTT_VIEW_SETTINGS.Size = New System.Drawing.Size(184, 22) + Me.BTT_VIEW_SETTINGS.Text = "View settings" + ' 'SEP_DEL ' Me.SEP_DEL.Name = "SEP_DEL" @@ -212,13 +254,6 @@ Namespace DownloadObjects.STDownloader Me.CH_CHECKED.TabIndex = 0 Me.CH_CHECKED.UseVisualStyleBackColor = True ' - 'BTT_VIEW_SETTINGS - ' - Me.BTT_VIEW_SETTINGS.Image = Global.SCrawler.My.Resources.Resources.SettingsPic_16 - Me.BTT_VIEW_SETTINGS.Name = "BTT_VIEW_SETTINGS" - Me.BTT_VIEW_SETTINGS.Size = New System.Drawing.Size(184, 22) - Me.BTT_VIEW_SETTINGS.Text = "View settings" - ' 'MediaItem ' Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!) @@ -253,5 +288,9 @@ Namespace DownloadObjects.STDownloader Private WithEvents SEP_DOWN_AGAIN As ToolStripSeparator Private WithEvents SEP_DEL As ToolStripSeparator Private WithEvents BTT_VIEW_SETTINGS As ToolStripMenuItem + Private WithEvents BTT_OPEN_FILE As ToolStripMenuItem + Private WithEvents BTT_PLS_ITEM_EDIT As ToolStripMenuItem + Private WithEvents SEP_PLS_ITEM_EDIT As ToolStripSeparator + Private WithEvents BTT_PLS_ITEM_EDIT_FULL As ToolStripMenuItem End Class End Namespace \ No newline at end of file diff --git a/SCrawler.YouTube/Downloader/MediaItem.resx b/SCrawler.YouTube/Downloader/MediaItem.resx index e269219..6ea6a0b 100644 --- a/SCrawler.YouTube/Downloader/MediaItem.resx +++ b/SCrawler.YouTube/Downloader/MediaItem.resx @@ -138,6 +138,138 @@ PNWfb/GWbyQQ2Z/pgjaJ9XsI91sIjr1H+fgUVeYh/KVrFs8Itp6O1B2RR+fAdhzupEHDXnw3U3GVpuAq +w/y3l2wnHCNxMrhGIGMcp2WpkyYWeqcC30Co5OYu0gvwZIRtc4b606cpoUYtF9y3BgvNkFSmhcSO25a TGCkk99shOQwl9bXawAAAABJRU5ErkJggg== + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + wwAADsMBx2+oZAAAAk9JREFUOE+Nk0tIVGEUgKcWZlZWEK1aZEmZUlmpEQUtrF1Q0WNfUUgtCqKZLMXQ + UPJRmuY4TYYKmbPJcVSCAkuFQislzCx7rSo3Oc5T7zzu17njdZosxMXH/bn/+b97zn/ONfBjAJoPQctR + sB2bH1rsw8OEvnVj0BbUbdNJ19HW2+fmbgZO4wIR2MRm3irIQcsO2RA0Qe3mf9EOajGRuEycuXEiaDky + vdlXTfjrc0Kfu1BfVkJjtqR68G80cfRDIrgSL4Km/fCinFC/GU9JEs7CTUy25hAafYIy8hhl2IEy2Iwy + 0IzacRaq1kNNClizdEHjPhiw4nFcRClKFLukWZvG1PWVuI0GPMVr8LYb8XZcRvX/gqEH0HZSskmPEbyu + w9N+CaV41bS9/Qx86oQPdhh1EOwuwesw4bGdY7LvPoHhNgIlq5nIS5gl0DLoyIF3LfgbDjBhFap348uL + Q5EDyrVEgvZT+Htv4ytYiit/WYzAfh6lIgl1bBB/xQYmi1YQqkomVJmMapbLswhN2ajfX+ErW8dU+Vpc + eUtiBRcIPDpBoKcU99V4uJf1p2Va+2q3QE8hSvcN3PkJUL9r5g6kXW8sUoKRqSE7vlupBCUTrJl6u3SB + PNWfb/GWbyQQ2Z/pgjaJ9XsI91sIjr1H+fgUVeYh/KVrFs8Itp6O1B2RR+fAdhzupEHDXnw3U3GVpuAq + +w/y3l2wnHCNxMrhGIGMcp2WpkyYWeqcC30Co5OYu0gvwZIRtc4b606cpoUYtF9y3BgvNkFSmhcSO25a + TGCkk99shOQwl9bXawAAAABJRU5ErkJggg== + + + + + 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 + AAAASUVORK5CYII= + + + + + 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 + AAAASUVORK5CYII= diff --git a/SCrawler.YouTube/Downloader/MediaItem.vb b/SCrawler.YouTube/Downloader/MediaItem.vb index e39be8f..17eed97 100644 --- a/SCrawler.YouTube/Downloader/MediaItem.vb +++ b/SCrawler.YouTube/Downloader/MediaItem.vb @@ -23,6 +23,8 @@ Namespace DownloadObjects.STDownloader Public Event DownloadAgain As MediaItemEventHandler Public Event DownloadRequested As MediaItemEventHandler Public Event CheckedChanged As MediaItemEventHandler + Public Event BeforeOpenEditor As MediaItemEventHandler + Public Event BeforeOpenEditorFull As MediaItemEventHandler #End Region #Region "Declarations" #Region "Controls" @@ -51,8 +53,8 @@ Namespace DownloadObjects.STDownloader ControlInvokeFast(CH_CHECKED, Sub() CH_CHECKED.Checked = _Checked, EDP.None) End Set End Property - Public Property IgnoreDownloadState As Boolean = False Private ReadOnly FileOption As SFO = SFO.File + Private ReadOnly ContainerHasElements As Boolean = False #End Region #Region "Initializers" Public Sub New() @@ -111,16 +113,18 @@ Namespace DownloadObjects.STDownloader .ContextMenuStrip = CONTEXT_MAIN } End Sub - Public Sub New(ByVal Container As IYouTubeMediaContainer) + Public Sub New(ByVal Container As IYouTubeMediaContainer, Optional ByVal HasElements As Boolean = False) Me.New Const d$ = " " & ChrW(183) & " " MyContainer = Container + ContainerHasElements = HasElements With MyContainer .Progress = MyProgress + If HasElements Then BTT_PLS_ITEM_EDIT.Visible = True : BTT_PLS_ITEM_EDIT_FULL.Visible = True : SEP_PLS_ITEM_EDIT.Visible = True If .HasElements Then FileOption = SFO.Path Else FileOption = SFO.File If .DownloadState = Plugin.UserMediaStates.Downloaded AndAlso (.ObjectType = Base.YouTubeMediaType.Channel Or .ObjectType = Base.YouTubeMediaType.PlayList) AndAlso FileOption = SFO.File AndAlso - Not .File.Exists AndAlso .File.Exists(SFO.Path, False) Then FileOption = SFO.Path + Not .File.Exists AndAlso .File.Exists(SFO.Path, False) Then FileOption = SFO.Path : BTT_OPEN_FILE.Visible = False If Not .SiteKey = YouTubeSiteKey Then BTT_DOWN_AGAIN.Visible = False SEP_DOWN_AGAIN.Visible = False @@ -224,11 +228,17 @@ Namespace DownloadObjects.STDownloader .Controls.Clear() .ColumnStyles.Clear() .ColumnCount = 0 - If IgnoreDownloadState Or MyContainer.MediaState = Plugin.UserMediaStates.Downloaded Then + If ContainerHasElements Or MyContainer.MediaState = Plugin.UserMediaStates.Downloaded Then If Not MyContainer.SiteKey = YouTubeSiteKey Then UpdateMediaIcon() - If IgnoreDownloadState Then + If ContainerHasElements Then BTT_OPEN_FOLDER.Visible = False + BTT_OPEN_FILE.Visible = False SEP_FOLDER.Visible = False + If Not ContainerHasElements Then + BTT_PLS_ITEM_EDIT.Visible = False + BTT_PLS_ITEM_EDIT_FULL.Visible = False + SEP_PLS_ITEM_EDIT.Visible = False + End If BTT_DOWN_AGAIN.Visible = False SEP_DOWN_AGAIN.Visible = False BTT_REMOVE_FROM_LIST.Visible = False @@ -369,7 +379,7 @@ Namespace DownloadObjects.STDownloader ICON_WHAT.DoubleClick, LBL_TIME.DoubleClick, ICON_SIZE.DoubleClick, LBL_INFO.DoubleClick, LBL_PROGRESS.DoubleClick, PR_MAIN.DoubleClick Controls_Click(sender, e) - If Not IgnoreDownloadState AndAlso Not MyDownloaderSettings.OnItemDoubleClick = DoubleClickBehavior.None Then + If Not ContainerHasElements AndAlso Not MyDownloaderSettings.OnItemDoubleClick = DoubleClickBehavior.None Then Dim m As New MMessage("The specified path was not found.", "Open file/folder",, vbExclamation) If MyDownloaderSettings.OnItemDoubleClick = DoubleClickBehavior.File Then If FileOption = SFO.File And MyContainer.File.Exists(SFO.File, False) Then @@ -405,6 +415,27 @@ Namespace DownloadObjects.STDownloader Private Sub BTT_OPEN_FOLDER_Click(sender As Object, e As EventArgs) Handles BTT_OPEN_FOLDER.Click If MyContainer.File.Exists(FileOption, False) Then GlobalOpenPath(MyContainer.File) End Sub + Private Sub BTT_OPEN_FILE_Click(sender As Object, e As EventArgs) Handles BTT_OPEN_FILE.Click + If MyContainer.File.Exists(SFO.File) Then MyContainer.File.Open(,, EDP.ShowAllMsg) + End Sub + Private Sub BTT_PLS_ITEM_EDIT_Click(sender As Object, e As EventArgs) Handles BTT_PLS_ITEM_EDIT.Click, BTT_PLS_ITEM_EDIT_FULL.Click + If ContainerHasElements Then + With DirectCast(MyContainer, YouTubeMediaContainerBase) + Dim initProtected As Boolean = .Protected + Dim isFull As Boolean = sender Is BTT_PLS_ITEM_EDIT_FULL + .Protected = False + If isFull Then + RaiseEvent BeforeOpenEditorFull(Me, MyContainer) + Else + RaiseEvent BeforeOpenEditor(Me, MyContainer) + End If + Using f As New VideoOptionsForm(MyContainer, initProtected Or isFull) + f.ShowDialog() + .Protected = IIf(f.DialogResult = DialogResult.OK, True, initProtected) + End Using + End With + End If + End Sub Private Sub BTT_COPY_LINK_Click(sender As Object, e As EventArgs) Handles BTT_COPY_LINK.Click If Not MyContainer.URL.IsEmptyString Then BufferText = MyContainer.URL diff --git a/SCrawler.YouTube/Objects/YouTubeMediaContainerBase.vb b/SCrawler.YouTube/Objects/YouTubeMediaContainerBase.vb index 0f12868..d644b52 100644 --- a/SCrawler.YouTube/Objects/YouTubeMediaContainerBase.vb +++ b/SCrawler.YouTube/Objects/YouTubeMediaContainerBase.vb @@ -139,22 +139,26 @@ Namespace API.YouTube.Objects #End Region #Region "Data info" Friend ReadOnly Property MediaObjects As List(Of MediaObject) Implements IYouTubeMediaContainer.MediaObjects + Friend Property [Protected] As Boolean = False + Friend Property IsAudioSelected As Boolean = False #Region "Array" ''' [-10] = disabled; [-1] = max; [-2] = audio only Friend Property ArrayMaxResolution As Integer = -10 ''' [-1] = max; [-2] = audio only Friend Sub SetMaxResolution(ByVal Value As Integer) - ArrayMaxResolution = Value - SelectedVideoIndex = -1 - If MediaObjects.Count > 0 And Value <> -2 Then - If Value = -1 Then - SelectedVideoIndex = MediaObjects.FindIndex(Function(mo) mo.Type = UMTypes.Video) - Else - SelectedVideoIndex = MediaObjects.FindIndex(Function(mo) mo.Type = UMTypes.Video And mo.Height <= Value) - If SelectedVideoIndex = -1 Then SelectedVideoIndex = MediaObjects.FindIndex(Function(mo) mo.Type = UMTypes.Video) + If Not [Protected] Then + ArrayMaxResolution = Value + SelectedVideoIndex = -1 + If MediaObjects.Count > 0 And Value <> -2 Then + If Value = -1 Then + SelectedVideoIndex = MediaObjects.FindIndex(Function(mo) mo.Type = UMTypes.Video) + Else + SelectedVideoIndex = MediaObjects.FindIndex(Function(mo) mo.Type = UMTypes.Video And mo.Height <= Value) + If SelectedVideoIndex = -1 Then SelectedVideoIndex = MediaObjects.FindIndex(Function(mo) mo.Type = UMTypes.Video) + End If End If + If HasElements Then Elements.ForEach(Sub(e As YouTubeMediaContainerBase) e.SetMaxResolution(Value)) End If - If HasElements Then Elements.ForEach(Sub(e As YouTubeMediaContainerBase) e.SetMaxResolution(Value)) End Sub #End Region #Region "Thumbnails" @@ -213,8 +217,10 @@ Namespace API.YouTube.Objects Return _OutputVideoExtension End Get Set(ByVal _OutputVideoExtension As String) - Me._OutputVideoExtension = _OutputVideoExtension - If HasElements Then Elements.ForEach(Sub(e) e.OutputVideoExtension = _OutputVideoExtension) + If Not [Protected] Then + Me._OutputVideoExtension = _OutputVideoExtension + If HasElements Then Elements.ForEach(Sub(e) e.OutputVideoExtension = _OutputVideoExtension) + End If End Set End Property Protected _OutputVideoFPS As Double = -1 @@ -223,8 +229,10 @@ Namespace API.YouTube.Objects Return _OutputVideoFPS End Get Set(ByVal fps As Double) - _OutputVideoFPS = fps - If HasElements Then Elements.ForEach(Sub(elem) DirectCast(elem, YouTubeMediaContainerBase).OutputVideoFPS = fps) + If Not [Protected] Then + _OutputVideoFPS = fps + If HasElements Then Elements.ForEach(Sub(elem) DirectCast(elem, YouTubeMediaContainerBase).OutputVideoFPS = fps) + End If End Set End Property #End Region @@ -241,8 +249,10 @@ Namespace API.YouTube.Objects Return _OutputAudioCodec End Get Set(ByVal _OutputAudioCodec As String) - Me._OutputAudioCodec = _OutputAudioCodec - If HasElements Then Elements.ForEach(Sub(e) e.OutputAudioCodec = _OutputAudioCodec) + If Not [Protected] Then + Me._OutputAudioCodec = _OutputAudioCodec + If HasElements Then Elements.ForEach(Sub(e) e.OutputAudioCodec = _OutputAudioCodec) + End If End Set End Property @@ -282,8 +292,10 @@ Namespace API.YouTube.Objects Return _OutputSubtitlesFormat End Get Set(ByVal _OutputSubtitlesFormat As String) - Me._OutputSubtitlesFormat = _OutputSubtitlesFormat - If HasElements Then Elements.ForEach(Sub(e) e.OutputSubtitlesFormat = _OutputSubtitlesFormat) + If Not [Protected] Then + Me._OutputSubtitlesFormat = _OutputSubtitlesFormat + If HasElements Then Elements.ForEach(Sub(e) e.OutputSubtitlesFormat = _OutputSubtitlesFormat) + End If End Set End Property @@ -565,8 +577,10 @@ Namespace API.YouTube.Objects Return _AbsolutePath End Get Set(ByVal ap As Boolean) - _AbsolutePath = ap - If Elements.Count > 0 Then Elements.ForEach(Sub(e As YouTubeMediaContainerBase) e.AbsolutePath = ap) + If Not [Protected] Then + _AbsolutePath = ap + If Elements.Count > 0 Then Elements.ForEach(Sub(e As YouTubeMediaContainerBase) e.AbsolutePath = ap) + End If End Set End Property Public Overridable Property File As SFile Implements IYouTubeMediaContainer.File @@ -574,28 +588,30 @@ Namespace API.YouTube.Objects Return _File End Get Set(ByVal f As SFile) - Select Case ObjectType - Case YouTubeMediaType.Channel : _File = f.Path - Case YouTubeMediaType.PlayList - If AbsolutePath Then - _File.Path = f.Path - Else - _File.Path = $"{f.PathWithSeparator}{GetPlayListTitle()}" - End If - Case YouTubeMediaType.Single - If PlaylistCount > 0 And Not FileIgnorePlaylist Then - _File.Path = f.Path - Dim pls$ = If(AbsolutePath, String.Empty, GetPlayListTitle()) - If Not _File.Path.Contains(pls) Then _File.Path = $"{_File.PathWithSeparator(Not pls.IsEmptyString)}{pls}" - ElseIf Not f.Name.IsEmptyString Then - _File = f - Else - _File.Path = f.Path - End If - Case Else : _File = f - End Select - GenerateFileName() - If HasElements Then Elements.ForEach(Sub(e) e.File = _File) + If Not [Protected] Then + Select Case ObjectType + Case YouTubeMediaType.Channel : _File = f.Path + Case YouTubeMediaType.PlayList + If AbsolutePath Then + _File.Path = f.Path + Else + _File.Path = $"{f.PathWithSeparator}{GetPlayListTitle()}" + End If + Case YouTubeMediaType.Single + If PlaylistCount > 0 And Not FileIgnorePlaylist Then + _File.Path = f.Path + Dim pls$ = If(AbsolutePath, String.Empty, GetPlayListTitle()) + If Not _File.Path.Contains(pls) Then _File.Path = $"{_File.PathWithSeparator(Not pls.IsEmptyString)}{pls}" + ElseIf Not f.Name.IsEmptyString Then + _File = f + Else + _File.Path = f.Path + End If + Case Else : _File = f + End Select + GenerateFileName() + If HasElements Then Elements.ForEach(Sub(e) e.File = _File) + End If End Set End Property Public Property FileSettings As SFile @@ -624,6 +640,7 @@ Namespace API.YouTube.Objects If Not File.IsEmptyString Then If File.Exists Then File = SFile.IndexReindex(File) Dim cmd$ = String.Empty, formats$ = String.Empty, subs$ = String.Empty, remux$ = String.Empty + Dim embedThumbArgAdded As Boolean = False _Size = 0 Height = 0 Bitrate = 0 @@ -636,6 +653,10 @@ Namespace API.YouTube.Objects _MediaType = UMTypes.Video Height = SelectedVideo.Height _File.Extension = OutputVideoExtension + If Not embedThumbArgAdded And MyYouTubeSettings.DefaultVideoEmbedThumbnail Then + formats.StringAppend("--embed-thumbnail", " ") + embedThumbArgAdded = True + End If Else formats.StringAppend("--extract-audio", " ") _MediaType = UMTypes.Audio @@ -653,7 +674,13 @@ Namespace API.YouTube.Objects formats.StringAppend($"--audio-format {OutputAudioCodec.StringToLower}", " ") atCodec = OutputAudioCodec.StringToLower End If - If SelectedVideoIndex = -1 Then formats.StringAppend("--add-metadata", " ") + If SelectedVideoIndex = -1 Then + formats.StringAppend("--add-metadata", " ") + If Not embedThumbArgAdded And MyYouTubeSettings.DefaultAudioEmbedThumbnail Then + formats.StringAppend("--embed-thumbnail", " ") + embedThumbArgAdded = True + End If + End If _Size += SelectedAudio.Size If _MediaType = UMTypes.Undefined Then _MediaType = UMTypes.Audio Bitrate = SelectedAudio.Bitrate diff --git a/SCrawler/API/Base/UserDataBase.vb b/SCrawler/API/Base/UserDataBase.vb index 01aa977..64244d4 100644 --- a/SCrawler/API/Base/UserDataBase.vb +++ b/SCrawler/API/Base/UserDataBase.vb @@ -23,6 +23,7 @@ Imports PersonalUtilities.Tools.Web.Clients Imports PersonalUtilities.Tools.ImageRenderer Imports UStates = SCrawler.API.Base.UserMedia.States Imports UTypes = SCrawler.API.Base.UserMedia.Types +Imports CookieUpdateModes = PersonalUtilities.Tools.Web.Cookies.CookieKeeper.UpdateModes Namespace API.Base Friend MustInherit Class UserDataBase : Implements IUserData, IPluginContentProvider, IThrower Friend Const UserFileAppender As String = "User" @@ -1150,6 +1151,8 @@ BlockNullPicture: Private _EnvirChanged As Boolean = False Private _PictureExists As Boolean Private _EnvirInvokeUserUpdated As Boolean = False + Protected _ResponserAutoUpdateCookies As Boolean = False + Protected _ResponserAddResponseReceivedHandler As Boolean = False Protected Sub EnvirDownloadSet() TokenPersonal = Nothing ProgressPre.Reset() @@ -1191,7 +1194,14 @@ BlockNullPicture: If Not Responser Is Nothing Then Responser.Dispose() Responser = New Responser If Not HOST.Responser Is Nothing Then Responser.Copy(HOST.Responser) - + If Not Responser Is Nothing And _ResponserAutoUpdateCookies Then + If _ResponserAutoUpdateCookies Then + Responser.CookiesUpdateMode = CookieUpdateModes.ReplaceByNameAll + Responser.CookiesExtractMode = Responser.CookiesExtractModes.Any + Responser.CookiesExtractedAutoSave = False + End If + If _ResponserAddResponseReceivedHandler Then AddHandler Responser.ResponseReceived, AddressOf Responser_ResponseReceived + End If Responser.DecodersError = New ErrorsDescriber(EDP.SendToLog + EDP.ReturnValue) With { .DeclaredMessage = New MMessage($"SymbolsConverter error: [{ToStringForLog()}]", ToStringForLog())} @@ -1284,9 +1294,9 @@ BlockNullPicture: Catch exit_ex As ExitException If Not exit_ex.Silent Then If exit_ex.SimpleLogLine Then - MyMainLOG = $"{ToStringForLog()}: downloading canceled (exit) ({exit_ex.Message})" + MyMainLOG = $"{ToStringForLog()}: downloading interrupted (exit) ({exit_ex.Message})" Else - ErrorsDescriber.Execute(EDP.SendToLog, exit_ex, $"{ToStringForLog()}: downloading canceled (exit)") + ErrorsDescriber.Execute(EDP.SendToLog, exit_ex, $"{ToStringForLog()}: downloading interrupted (exit)") End If End If Canceled = True @@ -1311,6 +1321,7 @@ BlockNullPicture: ProgressPre.Done() __DOWNLOAD_IN_PROGRESS = False OnUserDownloadStateChanged(False) + If _ResponserAddResponseReceivedHandler Then Responser_ResponseReceived_RemoveHandler() End Try End Sub Protected Sub UpdateDataFiles() @@ -1333,6 +1344,13 @@ BlockNullPicture: End If End Sub Protected MustOverride Sub DownloadDataF(ByVal Token As CancellationToken) + Protected Overridable Sub Responser_ResponseReceived(ByVal Sender As Object, ByVal e As EventArguments.WebDataResponse) + End Sub + Protected Sub Responser_ResponseReceived_RemoveHandler() + If Not Responser Is Nothing And _ResponserAddResponseReceivedHandler And Not Disposed Then + Try : RemoveHandler Responser.ResponseReceived, AddressOf Responser_ResponseReceived : Catch : End Try + End If + End Sub Protected Function CreateCache() As CacheKeeper Dim Cache As New CacheKeeper($"{DownloadContentDefault_GetRootDir()}\_tCache\") Cache.CacheDeleteError = CacheDeletionError(Cache) @@ -2057,7 +2075,7 @@ BlockNullPicture: End Function Private Class FilesCopyingException : Inherits ErrorsDescriberException Friend Sub New(ByVal User As IUserData, ByVal Msg As String, ByVal Path As SFile) - SendInLogOnlyMessage = True + SendToLogOnlyMessage = True If User.IncludedInCollection Then _MainMessage = $"[{User.CollectionName}] - " _MainMessage &= $"[{User.Site}] - [{User.Name}]. {Msg}: {Path.Path}." End Sub diff --git a/SCrawler/API/Facebook/UserData.vb b/SCrawler/API/Facebook/UserData.vb index 1fce06c..290c03e 100644 --- a/SCrawler/API/Facebook/UserData.vb +++ b/SCrawler/API/Facebook/UserData.vb @@ -107,7 +107,23 @@ Namespace API.Facebook End With End Sub #End Region +#Region "Initializer" + Friend Sub New() + _ResponserAutoUpdateCookies = True + End Sub +#End Region #Region "Download functions" + Private Class TokensException : Inherits Plugin.ExitException + Friend ReadOnly Property BasicTokens As Boolean + Public Sub New(ByVal Message As String, ByVal _BasicTokens As Boolean) + MyBase.New(Message) + BasicTokens = _BasicTokens + End Sub + Friend Shared Sub SendToLog(ByVal Source As UserData, ByVal ex As TokensException, ByVal f As String) + ErrorsDescriber.Execute(EDP.SendToLog, New ErrorsDescriberException($"{Source.ToStringForLog()} ({f}): {ex.Message}",,, ex) With { + .SendToLogOnlyMessage = True, .ReplaceMainMessage = True}) + End Sub + End Class Private Token_dtsg As String = String.Empty Private Token_lsd As String = String.Empty Private Token_Photosby As String = String.Empty @@ -149,7 +165,7 @@ Namespace API.Facebook Dim pid As PostKV ValidateBaseTokens() - If Token_Photosby.IsEmptyString Then Throw New ArgumentNullException("Token_Photosby", "Unable to obtain token") + If Token_Photosby.IsEmptyString Then Throw New TokensException("Unable to obtain token 'Token_Photosby'", False) URL = String.Format(Graphql_UrlPattern, Token_lsd, DocID_Photo, Header_fb_fr_name_Photo, SymbolsConverter.ASCII.EncodeSymbolsOnly(Token_dtsg), @@ -199,6 +215,8 @@ Namespace API.Facebook End If If newPostsDetected And Not nextCursor.IsEmptyString Then DownloadData_Photo(nextCursor, Token) + Catch tex As TokensException When Not tex.BasicTokens + TokensException.SendToLog(Me, tex, "data (photo)") Catch ex As Exception ProcessException(ex, Token, $"data (photo) downloading error [{URL}]",, Responser) End Try @@ -212,7 +230,7 @@ Namespace API.Facebook Dim pid As PostKV If VideoPageID.IsEmptyString Then GetVideoPageID(Token) - If VideoPageID.IsEmptyString Then Throw New ArgumentNullException("VideoPageID", "Unable to obtain VideoPageID") + If VideoPageID.IsEmptyString Then Throw New TokensException("Unable to obtain 'VideoPageID'", False) ValidateBaseTokens() URL = String.Format(Graphql_UrlPattern, Token_lsd, DocID_Video, Header_fb_fr_name_Video, @@ -252,6 +270,8 @@ Namespace API.Facebook End If If newPostsDetected And Not nextCursor.IsEmptyString Then DownloadData_Video(nextCursor, Token) + Catch tex As TokensException When Not tex.BasicTokens + TokensException.SendToLog(Me, tex, "data (video)") Catch ex As Exception ProcessException(ex, Token, $"data (video) downloading error [{URL}]",, Responser) End Try @@ -266,7 +286,7 @@ Namespace API.Facebook Dim postDate As Date? ValidateBaseTokens() - If StoryBucket.IsEmptyString Then Throw New ArgumentNullException("StoryBucket", "Unable to obtain StoryBucket") + If StoryBucket.IsEmptyString Then Throw New TokensException("Unable to obtain 'StoryBucket'", False) URL = String.Format(Graphql_UrlPattern, Token_lsd, DocID_Stories, Header_fb_fr_name_Stories, SymbolsConverter.ASCII.EncodeSymbolsOnly(Token_dtsg), @@ -320,6 +340,8 @@ Namespace API.Facebook End If End Using End If + Catch tex As TokensException When Not tex.BasicTokens + TokensException.SendToLog(Me, tex, "data (stories)") Catch ex As Exception ProcessException(ex, Token, $"data (stories) downloading error [{URL}]",, Responser) End Try @@ -467,8 +489,10 @@ Namespace API.Facebook #Region "ValidateBaseTokens, GetVideoPageID, GetUserTokens" ''' Private Sub ValidateBaseTokens() - If Token_dtsg.IsEmptyString Then Throw New ArgumentNullException("Token_dtsg", "Unable to obtain token") - If Token_lsd.IsEmptyString Then Throw New ArgumentNullException("Token_lsd", "Unable to obtain token") + Dim tokens$ = String.Empty + If Token_dtsg.IsEmptyString Then tokens.StringAppend("Token_dtsg") + If Token_lsd.IsEmptyString Then tokens.StringAppend("Token_lsd") + If Not tokens.IsEmptyString Then Throw New TokensException($"Unable to obtain token(s) ({tokens}){vbCr}Your credentials may have expired.", True) End Sub Private Sub GetVideoPageID(ByVal Token As CancellationToken) Dim URL$ = $"{GetProfileUrl()}\videos" diff --git a/SCrawler/API/Instagram/UserData.vb b/SCrawler/API/Instagram/UserData.vb index 5a98a87..a3f748d 100644 --- a/SCrawler/API/Instagram/UserData.vb +++ b/SCrawler/API/Instagram/UserData.vb @@ -139,6 +139,7 @@ Namespace API.Instagram Friend Sub New() PostsKVIDs = New List(Of PostKV) PostsToReparse = New List(Of PostKV) + _ResponserAutoUpdateCookies = True End Sub #End Region #Region "Download data" @@ -313,13 +314,13 @@ Namespace API.Instagram Try If _DownloadingInProgress AndAlso Not Responser Is Nothing AndAlso Not Responser.Disposed Then _DownloadingInProgress = False - RemoveHandler Responser.ResponseReceived, AddressOf Responser_ResponseReceived + Responser_ResponseReceived_RemoveHandler() Declarations.UpdateResponser(Responser, MySiteSettings.Responser) End If Catch End Try End Sub - Protected Overridable Sub Responser_ResponseReceived(ByVal Sender As Object, ByVal e As EventArguments.WebDataResponse) + Protected Overrides Sub Responser_ResponseReceived(ByVal Sender As Object, ByVal e As EventArguments.WebDataResponse) Declarations.UpdateResponser(e, Responser) End Sub Protected Enum Sections : Timeline : Reels : Tagged : Stories : UserStories : SavedPosts : End Enum @@ -454,7 +455,6 @@ Namespace API.Instagram Dim StoriesList As List(Of String) = Nothing Dim StoriesRequested As Boolean = False Dim dValue% = 1 - Dim jsonArgs As New WebDocumentEventArgs With {.DeclaredError = EDP.ThrowException} LastCursor = Cursor Try Do While dValue = 1 @@ -529,7 +529,7 @@ Namespace API.Instagram 'Parsing If Not r.IsEmptyString Then - Using j As EContainer = JsonDocument.Parse(r, jsonArgs).XmlIfNothing + Using j As EContainer = JsonDocument.Parse(r).XmlIfNothing n = If(ENode Is Nothing, j, j.ItemF(ENode)).XmlIfNothing If n.Count > 0 Then Select Case Section @@ -610,7 +610,7 @@ Namespace API.Instagram End If dValue = 0 If HasNextPage And Not EndCursor.IsEmptyString Then DownloadData(EndCursor, Section, Token) - Catch jsonNull As ArgumentNullException When jsonArgs.State = WebDocumentEventArgs.States.Error And Section = Sections.Reels + Catch jsonNull As JsonDocumentException When jsonNull.State = WebDocumentEventArgs.States.Error And Section = Sections.Reels Throw jsonNull Catch eex As ExitException Throw eex @@ -618,7 +618,7 @@ Namespace API.Instagram dValue = ProcessException(ex, Token, $"data downloading error [{URL}]",, Section, False) End Try Loop - Catch jsonNull2 As ArgumentNullException When jsonArgs.State = WebDocumentEventArgs.States.Error And Section = Sections.Reels + Catch jsonNull2 As JsonDocumentException When jsonNull2.State = WebDocumentEventArgs.States.Error And Section = Sections.Reels Catch eex2 As ExitException If eex2.Is560 Then Throw New Plugin.ExitException With {.Silent = True} @@ -629,8 +629,6 @@ Namespace API.Instagram If oex2.HelpLink = InstAborted Then HasError = True Catch DoEx As Exception ProcessException(DoEx, Token, $"data downloading error [{URL}]",, Section) - Finally - jsonArgs.DisposeIfReady End Try End Sub Private Sub DownloadPosts(ByVal Token As CancellationToken, Optional ByVal IsTagged As Boolean = False) @@ -1245,7 +1243,7 @@ Namespace API.Instagram #End Region #Region "Standalone downloader" Protected Overrides Sub DownloadSingleObject_GetPosts(ByVal Data As IYouTubeMediaContainer, ByVal Token As CancellationToken) - Dim PID$ = RegexReplace(Data.URL, RParams.DMS(".*?instagram.com/p/([_\w\d]+)", 1)) + Dim PID$ = RegexReplace(Data.URL, RParams.DMS(String.Format(UserRegexDefaultPattern, "instagram.com/p/"), 1)) If Not PID.IsEmptyString AndAlso Not ACheck(Of Long)(PID) Then PID = CodeToID(PID) If Not PID.IsEmptyString Then PostsToReparse.Add(New PostKV With {.ID = PID}) diff --git a/SCrawler/API/JustForFans/UserData.vb b/SCrawler/API/JustForFans/UserData.vb index 282b19d..2041caf 100644 --- a/SCrawler/API/JustForFans/UserData.vb +++ b/SCrawler/API/JustForFans/UserData.vb @@ -168,6 +168,7 @@ Namespace API.JustForFans #Region "Initializer" Friend Sub New() UseInternalM3U8Function = True + _ResponserAutoUpdateCookies = True End Sub #End Region #Region "Download functions" @@ -191,11 +192,11 @@ Namespace API.JustForFans DownloadData(0, Token) Finally If DownloadTopCount.HasValue Then DownloadTopCount = Nothing - Try : RemoveHandler Responser.ResponseReceived, AddressOf Responser_ResponseReceived : Catch : End Try + Responser_ResponseReceived_RemoveHandler() MySettings.UpdateResponser(Responser) End Try End Sub - Private Sub Responser_ResponseReceived(ByVal Source As Object, ByVal e As EventArguments.WebDataResponse) + Protected Overrides Sub Responser_ResponseReceived(ByVal Source As Object, ByVal e As EventArguments.WebDataResponse) If e.CookiesExists Then Dim hv$ = If(e.Cookies.FirstOrDefault(Function(cc) cc.Name.StringToLower = SiteSettings.UserHash4_CookieName)?.Value, String.Empty) If Not hv.IsEmptyString And Not _UserHash4 = hv Then _UserHash4 = hv diff --git a/SCrawler/API/OnlyFans/UserData.vb b/SCrawler/API/OnlyFans/UserData.vb index 8bf09b5..00b8a84 100644 --- a/SCrawler/API/OnlyFans/UserData.vb +++ b/SCrawler/API/OnlyFans/UserData.vb @@ -74,26 +74,33 @@ Namespace API.OnlyFans Private _OFScraperExists As Boolean = False Private OFSCache As CacheKeeper = Nothing Private _AbsMediaIndex As Integer = 0 + Private FunctionErr As Integer = FunctionErrDef + Private Const FunctionErrDef As Integer = -100 Private Sub ValidateOFScraper() _OFScraperExists = ACheck(MySettings.OFScraperPath.Value) AndAlso CStr(MySettings.OFScraperPath.Value).CSFile.Exists End Sub Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken) - If Not MySettings.SessionAborted Then - ValidateOFScraper() - _AbsMediaIndex = 0 - If Not CCookie Is Nothing Then CCookie.Dispose() - CCookie = Responser.Cookies.Copy - Responser.Cookies.Clear() - AddHandler Responser.ResponseReceived, AddressOf OnResponseReceived - UpdateCookieHeader() - DownloadTimeline(IIf(IsSavedPosts, 0, String.Empty), Token) - If Not IsSavedPosts Then - If MediaDownloadHighlights Then DownloadHighlights(Token) - If MediaDownloadChatMedia Then DownloadChatMedia(0, Token) + Try + If Not MySettings.SessionAborted Then + ValidateOFScraper() + _AbsMediaIndex = 0 + FunctionErr = FunctionErrDef + If Not CCookie Is Nothing Then CCookie.Dispose() + CCookie = Responser.Cookies.Copy + Responser.Cookies.Clear() + AddHandler Responser.ResponseReceived, AddressOf Responser_ResponseReceived + UpdateCookieHeader() + DownloadTimeline(IIf(IsSavedPosts, 0, String.Empty), Token) + If Not IsSavedPosts Then + If MediaDownloadHighlights And FunctionErr = FunctionErrDef Then DownloadHighlights(Token) + If MediaDownloadChatMedia And FunctionErr = FunctionErrDef Then DownloadChatMedia(0, Token) + End If End If - End If + Finally + Responser_ResponseReceived_RemoveHandler() + End Try End Sub - Private Sub OnResponseReceived(ByVal Sender As Object, ByVal e As WebDataResponse) + Protected Overrides Sub Responser_ResponseReceived(ByVal Sender As Object, ByVal e As WebDataResponse) If e.CookiesExists Then CCookie.Update(e.Cookies, CookieKeeper.UpdateModes.ReplaceByNameAll,, EDP.ReturnValue) UpdateCookieHeader() @@ -102,6 +109,10 @@ Namespace API.OnlyFans Private Sub UpdateCookieHeader() Responser.Headers.Add("Cookie", CCookie.ToString(False)) End Sub + Private Function ProcessFunctionErrComplete(ByVal ErrValue As Integer) As Boolean + If ErrValue <= 0 Or (ErrValue > 0 And ErrValue <> 2) Then FunctionErr = ErrValue + Return ErrValue <> 2 + End Function Friend Const A_HIGHLIGHT As String = "HL" Friend Const A_MESSAGE As String = "MSG" Private Const BaseUrlPattern As String = "https://onlyfans.com{0}" @@ -180,7 +191,7 @@ Namespace API.OnlyFans DownloadTimeline(tmpCursor, Token) End If Catch ex As Exception - _complete = Not ProcessException(ex, Token, $"data downloading error [{url}]") = 2 + _complete = ProcessFunctionErrComplete(ProcessException(ex, Token, $"data downloading error [{url}]")) End Try Loop While Not _complete End Sub @@ -219,7 +230,7 @@ Namespace API.OnlyFans End If If hasMore Then DownloadHighlights(Cursor + 5, Token) Catch ex As Exception - _complete = Not ProcessException(ex, Token, $"highlights downloading error [{url}]") = 2 + _complete = ProcessFunctionErrComplete(ProcessException(ex, Token, $"highlights downloading error [{url}]")) End Try Loop While Not _complete End Sub @@ -264,7 +275,7 @@ Namespace API.OnlyFans End If End If Catch ex As Exception - _complete = Not ProcessException(ex, Token, $"highlights downloading error [{url}]") = 2 + _complete = ProcessFunctionErrComplete(ProcessException(ex, Token, $"highlights downloading error [{url}]")) End Try Loop While Not _complete End Sub @@ -311,7 +322,7 @@ Namespace API.OnlyFans End If If hasMore Then DownloadChatMedia(Cursor + 20, Token) Catch ex As Exception - _complete = Not ProcessException(ex, Token, $"chats downloading error [{url}]") = 2 + _complete = ProcessFunctionErrComplete(ProcessException(ex, Token, $"chats downloading error [{url}]")) End Try Loop While Not _complete End Sub @@ -709,15 +720,17 @@ Namespace API.OnlyFans End If ElseIf Responser.StatusCode = Net.HttpStatusCode.NotFound Then '404 UserExists = False - Return 1 + Return 3 ElseIf Responser.StatusCode = Net.HttpStatusCode.GatewayTimeout Or Responser.StatusCode = 429 Then '504, 429 If Responser.StatusCode = 429 Then MyMainLOG = $"[429] OnlyFans too many requests ({ToStringForLog()})" MySettings.SessionAborted = True - Return 1 + Return 3 ElseIf Responser.StatusCode = Net.HttpStatusCode.Unauthorized Then '401 MySettings.SessionAborted = True MyMainLOG = $"{ToStringForLog()} [{CInt(Responser.StatusCode)}]: OnlyFans credentials expired" - Return 1 + Return 3 + ElseIf Responser.StatusCode = Net.HttpStatusCode.InternalServerError Then '500 + Return 3 Else Return 0 End If diff --git a/SCrawler/API/ThisVid/SiteSettings.vb b/SCrawler/API/ThisVid/SiteSettings.vb index 90f20f9..b5010ed 100644 --- a/SCrawler/API/ThisVid/SiteSettings.vb +++ b/SCrawler/API/ThisVid/SiteSettings.vb @@ -55,8 +55,7 @@ Namespace API.ThisVid #End Region #Region "UpdateCookies" Friend Sub UpdateCookies(ByVal Source As Responser) - Responser.Cookies.Clear() - Responser.Cookies.AddRange(Source.Cookies) + Responser.Cookies.Update(Source.Cookies) Update_SaveCookiesNetscape(True) End Sub #End Region diff --git a/SCrawler/API/ThisVid/UserData.vb b/SCrawler/API/ThisVid/UserData.vb index 83f06ce..5afa933 100644 --- a/SCrawler/API/ThisVid/UserData.vb +++ b/SCrawler/API/ThisVid/UserData.vb @@ -178,6 +178,7 @@ Namespace API.ThisVid Friend Sub New() UseClientTokens = True SessionPosts = New List(Of String) + _ResponserAutoUpdateCookies = True End Sub #End Region #Region "Validation" @@ -225,31 +226,34 @@ Namespace API.ThisVid Private AddedCount As Integer = 0 Private _PageVideosRepeat As Integer = 0 Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken) - SessionPosts.Clear() - AddedCount = 0 - _PageVideosRepeat = 0 - SessionPosts.Clear() - Responser.Cookies.ChangedAllowInternalDrop = False - Responser.Cookies.Changed = False - If ID.IsEmptyString Then ID = Name - If Not IsUser OrElse IsValid() Then - If IsSavedPosts Then - DownloadData(1, 0, Token) - DownloadData_Images(Token) - Else - If IsUser Then - If DownloadVideos Then - If DownloadPublic Then DownloadData(1, 0, Token) - If DownloadPrivate Then DownloadData(1, 1, Token) - If DownloadFavourite Then DownloadData(1, 2, Token) - End If - If DownloadImages And Not IsSubscription Then DownloadData_Images(Token) - Else + Try + SessionPosts.Clear() + AddedCount = 0 + _PageVideosRepeat = 0 + SessionPosts.Clear() + Responser.Cookies.ChangedAllowInternalDrop = False + Responser.Cookies.Changed = False + If ID.IsEmptyString Then ID = Name + If Not IsUser OrElse IsValid() Then + If IsSavedPosts Then DownloadData(1, 0, Token) + DownloadData_Images(Token) + Else + If IsUser Then + If DownloadVideos Then + If DownloadPublic Then DownloadData(1, 0, Token) + If DownloadPrivate Then DownloadData(1, 1, Token) + If DownloadFavourite Then DownloadData(1, 2, Token) + End If + If DownloadImages And Not IsSubscription Then DownloadData_Images(Token) + Else + DownloadData(1, 0, Token) + End If End If End If - End If - If Responser.Cookies.Changed Then MySettings.UpdateCookies(Responser) : Responser.Cookies.Changed = False + Finally + If Responser.Cookies.Changed Then MySettings.UpdateCookies(Responser) : Responser.Cookies.Changed = False + End Try End Sub Friend Function GetNonUserUrl(ByVal Page As Integer) As String Dim url$ = String.Empty diff --git a/SCrawler/API/ThreadsNet/SiteSettings.vb b/SCrawler/API/ThreadsNet/SiteSettings.vb index 8393147..bbe24c5 100644 --- a/SCrawler/API/ThreadsNet/SiteSettings.vb +++ b/SCrawler/API/ThreadsNet/SiteSettings.vb @@ -19,7 +19,7 @@ Namespace API.ThreadsNet #Region "Declarations" #Region "Authorization" Protected ReadOnly __HH_CSRF_TOKEN As PropertyValue - + Friend Overridable ReadOnly Property HH_CSRF_TOKEN As PropertyValue Get Return __HH_CSRF_TOKEN @@ -165,6 +165,15 @@ Namespace API.ThreadsNet Return ErrorsDescriber.Execute(EDP.SendToLog, ex, "Can't open user's post", String.Empty) End Try End Function +#End Region +#Region "Update" + Friend Overrides Sub Update() + If _SiteEditorFormOpened And Responser.CookiesExists Then + Dim csrf$ = If(Responser.Cookies.FirstOrDefault(Function(c) c.Name.StringToLower = IG.Header_CSRF_TOKEN_COOKIE)?.Value, String.Empty) + If Not csrf.IsEmptyString Then HH_CSRF_TOKEN.Value = csrf + End If + MyBase.Update() + End Sub #End Region End Class End Namespace \ No newline at end of file diff --git a/SCrawler/API/ThreadsNet/UserData.vb b/SCrawler/API/ThreadsNet/UserData.vb index 4e324d6..b170f10 100644 --- a/SCrawler/API/ThreadsNet/UserData.vb +++ b/SCrawler/API/ThreadsNet/UserData.vb @@ -49,6 +49,8 @@ Namespace API.ThreadsNet ObtainMedia_AllowAbstract = True DefaultParser_ElemNode = DefaultParser_ElemNode_Default DefaultParser_PostUrlCreator = Function(post) $"https://www.threads.net/@{NameTrue}/post/{post.Code}" + _ResponserAutoUpdateCookies = True + _ResponserAddResponseReceivedHandler = True End Sub #End Region #Region "Download functions" @@ -56,7 +58,6 @@ Namespace API.ThreadsNet Dim errorFound As Boolean = False Try Responser.Method = "POST" - AddHandler Responser.ResponseReceived, AddressOf Responser_ResponseReceived LoadSavePostsKV(True) OPT_LSD = String.Empty OPT_FB_DTSG = String.Empty @@ -154,7 +155,7 @@ Namespace API.ThreadsNet Responser.Method = "GET" Responser.Referer = URL Responser.Headers.Remove(Header_FB_LSD) - Dim r$ = Responser.GetResponse(URL,, EDP.SendToLog + EDP.ThrowException) + Dim r$ = Responser.GetResponse(URL,, EDP.ThrowException) Dim rr As RParams Dim tt$, ttVal$ If Not r.IsEmptyString Then @@ -189,7 +190,12 @@ Namespace API.ThreadsNet If OPT_FB_DTSG.IsEmptyString Then notFound.StringAppend(Header_FB_LSD) If OPT_LSD.IsEmptyString Then notFound.StringAppend("lsd") If ID.IsEmptyString Then notFound.StringAppend("User ID") - LogError(ex, $"failed to update some{IIf(notFound.IsEmptyString, String.Empty, $" ({notFound})")} credentials", e) + Dim eex As New ErrorsDescriberException($"{ToStringForLog()}: failed to update some{IIf(notFound.IsEmptyString, String.Empty, $" ({notFound})")} credentials",,, ex) With { + .ReplaceMainMessage = True, + .SendToLogOnlyMessage = Responser.StatusCode = Net.HttpStatusCode.InternalServerError And Responser.Status = Net.WebExceptionStatus.ProtocolError + } + 'LogError(ex, $"failed to update some{IIf(notFound.IsEmptyString, String.Empty, $" ({notFound})")} credentials", e) + LogError(eex, String.Empty, e) Return False End Try End Function diff --git a/SCrawler/API/Twitter/UserData.vb b/SCrawler/API/Twitter/UserData.vb index b37ea53..a439655 100644 --- a/SCrawler/API/Twitter/UserData.vb +++ b/SCrawler/API/Twitter/UserData.vb @@ -157,7 +157,6 @@ Namespace API.Twitter Private Sub DownloadData_Timeline(ByVal Token As CancellationToken) Dim URL$ = String.Empty Dim tCache As CacheKeeper = Nothing - Dim jsonArgs As New WebDocumentEventArgs With {.DeclaredError = EDP.ThrowException} Try Const entry$ = "entry" Dim PostID$ = String.Empty @@ -237,8 +236,7 @@ Namespace API.Twitter For i = 0 To timelineFiles.Count - 1 : timelineFiles(i) = RenameGdlFile(timelineFiles(i), i) : Next 'parse files For i = 0 To timelineFiles.Count - 1 - j = JsonDocument.Parse(timelineFiles(i).GetText, jsonArgs) - jsonArgs.Reset() + j = JsonDocument.Parse(timelineFiles(i).GetText) If Not j Is Nothing Then If i = 0 Then If Not userInfoParsed Then @@ -363,7 +361,7 @@ Namespace API.Twitter End If DownloadModelForceApply = False FirstDownloadComplete = True - Catch jsonNull_ex As ArgumentNullException When jsonArgs.State = WebDocumentEventArgs.States.Error + Catch jsonNull_ex As JsonDocumentException When jsonNull_ex.State = WebDocumentEventArgs.States.Error Throw New Plugin.ExitException("No deserialized data found") Catch limit_ex As TwitterLimitException Throw limit_ex @@ -371,7 +369,6 @@ Namespace API.Twitter ProcessException(ex, Token, $"data downloading error [{URL}]") Finally If Not tCache Is Nothing Then tCache.Dispose() - jsonArgs.DisposeIfReady If _TempPostsList.Count > 0 Then _TempPostsList.Sort() End Try End Sub diff --git a/SCrawler/Download/Automation/AutoDownloader.vb b/SCrawler/Download/Automation/AutoDownloader.vb index 29ee151..1a2236c 100644 --- a/SCrawler/Download/Automation/AutoDownloader.vb +++ b/SCrawler/Download/Automation/AutoDownloader.vb @@ -14,7 +14,7 @@ Imports PersonalUtilities.Functions.XML.Base Imports PersonalUtilities.Tools Imports PersonalUtilities.Tools.Notifications Namespace DownloadObjects - Friend Class AutoDownloader : Inherits GroupParameters : Implements IIndexable, IEContainerProvider + Friend Class AutoDownloader : Inherits GroupParameters : Implements IIndexable, IEContainerProvider, IComparable(Of AutoDownloader) Friend Event PauseChanged(ByVal Value As PauseModes) Friend Enum Modes As Integer None = 0 @@ -219,7 +219,7 @@ Namespace DownloadObjects Friend Property ShowPictureDownloaded As Boolean = True Friend Property ShowPictureUser As Boolean = True Friend Property ShowSimpleNotification As Boolean = False - Private Property Index As Integer = -1 Implements IIndexable.Index + Friend Property Index As Integer = -1 Implements IIndexable.Index Private Function SetIndex(ByVal Obj As Object, ByVal Index As Integer) As Object Implements IIndexable.SetIndex DirectCast(Obj, AutoDownloader).Index = Index Return Obj @@ -525,6 +525,7 @@ Namespace DownloadObjects Dim users As New List(Of IUserData) Dim GName$ Dim i% + Dim doRound% = -1, doLim% = Settings.Plugins.Count Dim DownloadedUsersCount% = 0 Dim DownloadedSubscriptionsCount% = 0 Dim simple As Boolean = ShowSimpleNotification And ShowNotifications @@ -600,7 +601,7 @@ Namespace DownloadObjects With Downloader .AutoDownloaderWorking = True If .Downloaded.Count > 0 Then .Downloaded.RemoveAll(Function(u) Keys.Contains(u.Key)) : .InvokeDownloadsChangeEvent() - .AddRange(users, True) + Do : Try : doRound += 1 : .AddRange(users, True) : Exit Do : Catch iex As IndexOutOfRangeException : Thread.Sleep(200) : End Try : Loop While doRound < doLim While .Working Or .Count > 0 : notify.Invoke() : Thread.Sleep(200) : End While .AutoDownloaderWorking = False notify.Invoke @@ -646,6 +647,11 @@ Namespace DownloadObjects End If End Function #End Region +#Region "IComparable Support" + Private Function CompareTo(ByVal Other As AutoDownloader) As Integer Implements IComparable(Of AutoDownloader).CompareTo + Return Index.CompareTo(Other.Index) + End Function +#End Region #Region "IDisposable Support" Protected Overrides Sub Dispose(ByVal disposing As Boolean) If Not disposedValue And disposing Then diff --git a/SCrawler/Download/Automation/Scheduler.vb b/SCrawler/Download/Automation/Scheduler.vb index ca71d88..bbe757b 100644 --- a/SCrawler/Download/Automation/Scheduler.vb +++ b/SCrawler/Download/Automation/Scheduler.vb @@ -129,6 +129,25 @@ Namespace DownloadObjects End If Return True End Function + Friend Function Move(ByVal Index As Integer, ByVal Up As Boolean) As Integer + Try + If Index.ValueBetween(0, Count - 1) Then + Plans.ListReindex + Dim v% = IIf(Up, -1, 1) + Dim newIndx% + Item(Index).Index += v + newIndx = Item(Index).Index + If newIndx.ValueBetween(0, Count - 1) Then Item(newIndx).Index += v * -1 + Plans.Sort() + Plans.ListReindex + Update() + Return newIndx + End If + Catch ex As Exception + ErrorsDescriber.Execute(EDP.SendToLog, ex, "[Scheduler.Move]") + End Try + Return -1 + End Function #Region "Groups Support" Friend Sub GROUPS_Updated(ByVal Sender As DownloadGroup) If Count > 0 Then Plans.ForEach(Sub(p) p.GROUPS_Updated(Sender)) diff --git a/SCrawler/Download/Automation/SchedulerEditorForm.vb b/SCrawler/Download/Automation/SchedulerEditorForm.vb index d11ee0c..89e8c13 100644 --- a/SCrawler/Download/Automation/SchedulerEditorForm.vb +++ b/SCrawler/Download/Automation/SchedulerEditorForm.vb @@ -27,6 +27,8 @@ Namespace DownloadObjects Private WithEvents BTT_START_FORCE As ToolStripButton Private WithEvents BTT_PAUSE As ToolStripDropDownButton Private WithEvents PauseArr As AutoDownloaderPauseButtons + Private WithEvents BTT_MOVE_UP As ToolStripButton + Private WithEvents BTT_MOVE_DOWN As ToolStripButton #End Region #Region "Initializer" Friend Sub New() @@ -98,6 +100,18 @@ Namespace DownloadObjects .ToolTipText = "Pause task", .AutoToolTip = True } + BTT_MOVE_UP = New ToolStripButton With { + .Text = String.Empty, + .Image = PersonalUtilities.My.Resources.ArrowUpPic_Blue_32, + .ToolTipText = "Move the selected task higher in the list", + .AutoToolTip = True + } + BTT_MOVE_DOWN = New ToolStripButton With { + .Text = String.Empty, + .Image = PersonalUtilities.My.Resources.ArrowDownPic_Blue_32, + .ToolTipText = "Move the selected task lower in the list", + .AutoToolTip = True + } PauseArr = New AutoDownloaderPauseButtons(AutoDownloaderPauseButtons.ButtonsPlace.Scheduler) With { .MainFrameButtonsInstance = MainFrameObj.PauseButtons} Icon = ImageRenderer.GetIcon(My.Resources.ScriptPic_32, EDP.ReturnValue) @@ -108,6 +122,7 @@ Namespace DownloadObjects With MyDefs .MyViewInitialize() .AddEditToolbar({BTT_SETTINGS, ECI.Separator, ECI.Add, BTT_CLONE, ECI.Edit, ECI.Delete, ECI.Update, ECI.Separator, + BTT_MOVE_UP, BTT_MOVE_DOWN, ECI.Separator, BTT_START, BTT_START_FORCE, MENU_SKIP, BTT_PAUSE}) PauseArr.AddButtons(BTT_PAUSE, .MyEditToolbar.ToolStrip) Refill() @@ -332,6 +347,15 @@ Namespace DownloadObjects Private Sub PauseArr_Updating() Handles PauseArr.Updating Refill() End Sub +#End Region +#Region "Move" + Private Sub BTT_MOVE_UP_DOWN_Click(sender As Object, e As EventArgs) Handles BTT_MOVE_UP.Click, BTT_MOVE_DOWN.Click + If _LatestSelected.ValueBetween(0, LIST_PLANS.Items.Count - 1) Then + Dim v% = Settings.Automation.Move(_LatestSelected, sender Is BTT_MOVE_UP) + If v >= 0 Then _LatestSelected = v + Refill() + End If + End Sub #End Region End Class End Namespace \ No newline at end of file diff --git a/SCrawler/Download/Feed/DownloadFeedForm.Designer.vb b/SCrawler/Download/Feed/DownloadFeedForm.Designer.vb index 32ff230..c2f9d93 100644 --- a/SCrawler/Download/Feed/DownloadFeedForm.Designer.vb +++ b/SCrawler/Download/Feed/DownloadFeedForm.Designer.vb @@ -31,6 +31,8 @@ Namespace DownloadObjects Dim MENU_LOAD_SEP_3 As System.Windows.Forms.ToolStripSeparator Dim MENU_LOAD_SEP_4 As System.Windows.Forms.ToolStripSeparator Dim MENU_LOAD_SEP_5 As System.Windows.Forms.ToolStripSeparator + Dim MENU_LOAD_SEP_6 As System.Windows.Forms.ToolStripSeparator + Dim MENU_LOAD_SEP_7 As System.Windows.Forms.ToolStripSeparator Me.OPT_DEFAULT = New System.Windows.Forms.ToolStripMenuItem() Me.OPT_SUBSCRIPTIONS = New System.Windows.Forms.ToolStripMenuItem() Me.ToolbarTOP = New System.Windows.Forms.ToolStrip() @@ -41,8 +43,10 @@ Namespace DownloadObjects Me.BTT_LOAD_FAV = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_LOAD_SPEC = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_FEED_ADD_FAV = New System.Windows.Forms.ToolStripMenuItem() + Me.BTT_FEED_ADD_FAV_REMOVE = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_FEED_REMOVE_FAV = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_FEED_ADD_SPEC = New System.Windows.Forms.ToolStripMenuItem() + Me.BTT_FEED_ADD_SPEC_REMOVE = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_FEED_REMOVE_SPEC = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_FEED_CLEAR_FAV = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_FEED_CLEAR_SPEC = New System.Windows.Forms.ToolStripMenuItem() @@ -51,6 +55,9 @@ Namespace DownloadObjects Me.BTT_FEED_DELETE_DAILY_DATE = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_MERGE_SESSIONS = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_CLEAR_DAILY = New System.Windows.Forms.ToolStripMenuItem() + Me.BTT_MERGE_FEEDS = New System.Windows.Forms.ToolStripMenuItem() + Me.BTT_CHECK_ALL = New System.Windows.Forms.ToolStripMenuItem() + Me.BTT_CHECK_NONE = New System.Windows.Forms.ToolStripMenuItem() Me.SEP_0 = New System.Windows.Forms.ToolStripSeparator() Me.MENU_DOWN = New System.Windows.Forms.ToolStripDropDownButton() Me.BTT_DOWN_ALL = New System.Windows.Forms.ToolStripMenuItem() @@ -65,6 +72,8 @@ Namespace DownloadObjects MENU_LOAD_SEP_3 = New System.Windows.Forms.ToolStripSeparator() MENU_LOAD_SEP_4 = New System.Windows.Forms.ToolStripSeparator() MENU_LOAD_SEP_5 = New System.Windows.Forms.ToolStripSeparator() + MENU_LOAD_SEP_6 = New System.Windows.Forms.ToolStripSeparator() + MENU_LOAD_SEP_7 = New System.Windows.Forms.ToolStripSeparator() Me.ToolbarTOP.SuspendLayout() Me.SuspendLayout() ' @@ -103,27 +112,37 @@ Namespace DownloadObjects 'MENU_LOAD_SEP_1 ' MENU_LOAD_SEP_1.Name = "MENU_LOAD_SEP_1" - MENU_LOAD_SEP_1.Size = New System.Drawing.Size(264, 6) + MENU_LOAD_SEP_1.Size = New System.Drawing.Size(349, 6) ' 'MENU_LOAD_SEP_2 ' MENU_LOAD_SEP_2.Name = "MENU_LOAD_SEP_2" - MENU_LOAD_SEP_2.Size = New System.Drawing.Size(264, 6) + MENU_LOAD_SEP_2.Size = New System.Drawing.Size(349, 6) ' 'MENU_LOAD_SEP_3 ' MENU_LOAD_SEP_3.Name = "MENU_LOAD_SEP_3" - MENU_LOAD_SEP_3.Size = New System.Drawing.Size(264, 6) + MENU_LOAD_SEP_3.Size = New System.Drawing.Size(349, 6) ' 'MENU_LOAD_SEP_4 ' MENU_LOAD_SEP_4.Name = "MENU_LOAD_SEP_4" - MENU_LOAD_SEP_4.Size = New System.Drawing.Size(264, 6) + MENU_LOAD_SEP_4.Size = New System.Drawing.Size(349, 6) ' 'MENU_LOAD_SEP_5 ' MENU_LOAD_SEP_5.Name = "MENU_LOAD_SEP_5" - MENU_LOAD_SEP_5.Size = New System.Drawing.Size(264, 6) + MENU_LOAD_SEP_5.Size = New System.Drawing.Size(349, 6) + ' + 'MENU_LOAD_SEP_6 + ' + MENU_LOAD_SEP_6.Name = "MENU_LOAD_SEP_6" + MENU_LOAD_SEP_6.Size = New System.Drawing.Size(349, 6) + ' + 'MENU_LOAD_SEP_7 + ' + MENU_LOAD_SEP_7.Name = "MENU_LOAD_SEP_7" + MENU_LOAD_SEP_7.Size = New System.Drawing.Size(349, 6) ' 'ToolbarTOP ' @@ -137,7 +156,7 @@ Namespace DownloadObjects 'MENU_LOAD_SESSION ' Me.MENU_LOAD_SESSION.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image - Me.MENU_LOAD_SESSION.DropDownItems.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_LOAD_SESSION_CURRENT, Me.BTT_LOAD_SESSION_LAST, Me.BTT_LOAD_SESSION_CHOOSE, MENU_LOAD_SEP_1, Me.BTT_LOAD_FAV, Me.BTT_LOAD_SPEC, MENU_LOAD_SEP_2, Me.BTT_FEED_ADD_FAV, Me.BTT_FEED_REMOVE_FAV, MENU_LOAD_SEP_3, Me.BTT_FEED_ADD_SPEC, Me.BTT_FEED_REMOVE_SPEC, MENU_LOAD_SEP_4, Me.BTT_FEED_CLEAR_FAV, Me.BTT_FEED_CLEAR_SPEC, Me.BTT_FEED_DELETE_SPEC, Me.BTT_FEED_DELETE_DAILY_LIST, Me.BTT_FEED_DELETE_DAILY_DATE, MENU_LOAD_SEP_5, Me.BTT_MERGE_SESSIONS, Me.BTT_CLEAR_DAILY}) + Me.MENU_LOAD_SESSION.DropDownItems.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_LOAD_SESSION_CURRENT, Me.BTT_LOAD_SESSION_LAST, Me.BTT_LOAD_SESSION_CHOOSE, MENU_LOAD_SEP_1, Me.BTT_LOAD_FAV, Me.BTT_LOAD_SPEC, MENU_LOAD_SEP_2, Me.BTT_FEED_ADD_FAV, Me.BTT_FEED_ADD_FAV_REMOVE, Me.BTT_FEED_REMOVE_FAV, MENU_LOAD_SEP_3, Me.BTT_FEED_ADD_SPEC, Me.BTT_FEED_ADD_SPEC_REMOVE, Me.BTT_FEED_REMOVE_SPEC, MENU_LOAD_SEP_4, Me.BTT_FEED_CLEAR_FAV, Me.BTT_FEED_CLEAR_SPEC, Me.BTT_FEED_DELETE_SPEC, Me.BTT_FEED_DELETE_DAILY_LIST, Me.BTT_FEED_DELETE_DAILY_DATE, MENU_LOAD_SEP_5, Me.BTT_MERGE_SESSIONS, Me.BTT_CLEAR_DAILY, MENU_LOAD_SEP_6, Me.BTT_MERGE_FEEDS, MENU_LOAD_SEP_7, Me.BTT_CHECK_ALL, Me.BTT_CHECK_NONE}) Me.MENU_LOAD_SESSION.Image = Global.SCrawler.My.Resources.Resources.ArrowDownPic_Blue_24 Me.MENU_LOAD_SESSION.ImageTransparentColor = System.Drawing.Color.Magenta Me.MENU_LOAD_SESSION.Name = "MENU_LOAD_SESSION" @@ -148,98 +167,112 @@ Namespace DownloadObjects ' Me.BTT_LOAD_SESSION_CURRENT.Image = Global.SCrawler.My.Resources.Resources.ArrowDownPic_Blue_24 Me.BTT_LOAD_SESSION_CURRENT.Name = "BTT_LOAD_SESSION_CURRENT" - Me.BTT_LOAD_SESSION_CURRENT.Size = New System.Drawing.Size(267, 22) + Me.BTT_LOAD_SESSION_CURRENT.Size = New System.Drawing.Size(352, 22) Me.BTT_LOAD_SESSION_CURRENT.Text = "Load current session" ' 'BTT_LOAD_SESSION_LAST ' Me.BTT_LOAD_SESSION_LAST.Image = Global.SCrawler.My.Resources.Resources.ArrowDownPic_Blue_24 Me.BTT_LOAD_SESSION_LAST.Name = "BTT_LOAD_SESSION_LAST" - Me.BTT_LOAD_SESSION_LAST.Size = New System.Drawing.Size(267, 22) + Me.BTT_LOAD_SESSION_LAST.Size = New System.Drawing.Size(352, 22) Me.BTT_LOAD_SESSION_LAST.Text = "Load last session" ' 'BTT_LOAD_SESSION_CHOOSE ' Me.BTT_LOAD_SESSION_CHOOSE.Image = Global.SCrawler.My.Resources.Resources.ArrowDownPic_Blue_24 Me.BTT_LOAD_SESSION_CHOOSE.Name = "BTT_LOAD_SESSION_CHOOSE" - Me.BTT_LOAD_SESSION_CHOOSE.Size = New System.Drawing.Size(267, 22) + Me.BTT_LOAD_SESSION_CHOOSE.Size = New System.Drawing.Size(352, 22) Me.BTT_LOAD_SESSION_CHOOSE.Text = "Select loading session" ' 'BTT_LOAD_FAV ' Me.BTT_LOAD_FAV.Image = Global.SCrawler.My.Resources.Resources.HeartPic_32 Me.BTT_LOAD_FAV.Name = "BTT_LOAD_FAV" - Me.BTT_LOAD_FAV.Size = New System.Drawing.Size(267, 22) + Me.BTT_LOAD_FAV.Size = New System.Drawing.Size(352, 22) Me.BTT_LOAD_FAV.Text = "Load Favorite" ' 'BTT_LOAD_SPEC ' Me.BTT_LOAD_SPEC.Image = Global.SCrawler.My.Resources.Resources.RSSPic_512 Me.BTT_LOAD_SPEC.Name = "BTT_LOAD_SPEC" - Me.BTT_LOAD_SPEC.Size = New System.Drawing.Size(267, 22) + Me.BTT_LOAD_SPEC.Size = New System.Drawing.Size(352, 22) Me.BTT_LOAD_SPEC.Text = "Load special feed" ' 'BTT_FEED_ADD_FAV ' Me.BTT_FEED_ADD_FAV.Image = Global.SCrawler.My.Resources.Resources.HeartPic_32 Me.BTT_FEED_ADD_FAV.Name = "BTT_FEED_ADD_FAV" - Me.BTT_FEED_ADD_FAV.Size = New System.Drawing.Size(267, 22) + Me.BTT_FEED_ADD_FAV.Size = New System.Drawing.Size(352, 22) Me.BTT_FEED_ADD_FAV.Text = "Add checked to Favorite" ' + 'BTT_FEED_ADD_FAV_REMOVE + ' + Me.BTT_FEED_ADD_FAV_REMOVE.Image = Global.SCrawler.My.Resources.Resources.HeartPic_32 + Me.BTT_FEED_ADD_FAV_REMOVE.Name = "BTT_FEED_ADD_FAV_REMOVE" + Me.BTT_FEED_ADD_FAV_REMOVE.Size = New System.Drawing.Size(352, 22) + Me.BTT_FEED_ADD_FAV_REMOVE.Text = "Add checked to Favorite (remove from current)" + ' 'BTT_FEED_REMOVE_FAV ' Me.BTT_FEED_REMOVE_FAV.Image = Global.SCrawler.My.Resources.Resources.DeletePic_24 Me.BTT_FEED_REMOVE_FAV.Name = "BTT_FEED_REMOVE_FAV" - Me.BTT_FEED_REMOVE_FAV.Size = New System.Drawing.Size(267, 22) + Me.BTT_FEED_REMOVE_FAV.Size = New System.Drawing.Size(352, 22) Me.BTT_FEED_REMOVE_FAV.Text = "Remove checked from Favorite" ' 'BTT_FEED_ADD_SPEC ' Me.BTT_FEED_ADD_SPEC.Image = Global.SCrawler.My.Resources.Resources.RSSPic_512 Me.BTT_FEED_ADD_SPEC.Name = "BTT_FEED_ADD_SPEC" - Me.BTT_FEED_ADD_SPEC.Size = New System.Drawing.Size(267, 22) + Me.BTT_FEED_ADD_SPEC.Size = New System.Drawing.Size(352, 22) Me.BTT_FEED_ADD_SPEC.Text = "Add checked to special feed..." ' + 'BTT_FEED_ADD_SPEC_REMOVE + ' + Me.BTT_FEED_ADD_SPEC_REMOVE.Image = Global.SCrawler.My.Resources.Resources.RSSPic_512 + Me.BTT_FEED_ADD_SPEC_REMOVE.Name = "BTT_FEED_ADD_SPEC_REMOVE" + Me.BTT_FEED_ADD_SPEC_REMOVE.Size = New System.Drawing.Size(352, 22) + Me.BTT_FEED_ADD_SPEC_REMOVE.Text = "Add checked to special feed (remove from current)..." + ' 'BTT_FEED_REMOVE_SPEC ' Me.BTT_FEED_REMOVE_SPEC.Image = Global.SCrawler.My.Resources.Resources.DeletePic_24 Me.BTT_FEED_REMOVE_SPEC.Name = "BTT_FEED_REMOVE_SPEC" - Me.BTT_FEED_REMOVE_SPEC.Size = New System.Drawing.Size(267, 22) + Me.BTT_FEED_REMOVE_SPEC.Size = New System.Drawing.Size(352, 22) Me.BTT_FEED_REMOVE_SPEC.Text = "Remove checked from special feed..." ' 'BTT_FEED_CLEAR_FAV ' Me.BTT_FEED_CLEAR_FAV.Image = Global.SCrawler.My.Resources.Resources.BrushToolPic_16 Me.BTT_FEED_CLEAR_FAV.Name = "BTT_FEED_CLEAR_FAV" - Me.BTT_FEED_CLEAR_FAV.Size = New System.Drawing.Size(267, 22) + Me.BTT_FEED_CLEAR_FAV.Size = New System.Drawing.Size(352, 22) Me.BTT_FEED_CLEAR_FAV.Text = "Clear Favorite" ' 'BTT_FEED_CLEAR_SPEC ' Me.BTT_FEED_CLEAR_SPEC.Image = Global.SCrawler.My.Resources.Resources.BrushToolPic_16 Me.BTT_FEED_CLEAR_SPEC.Name = "BTT_FEED_CLEAR_SPEC" - Me.BTT_FEED_CLEAR_SPEC.Size = New System.Drawing.Size(267, 22) + Me.BTT_FEED_CLEAR_SPEC.Size = New System.Drawing.Size(352, 22) Me.BTT_FEED_CLEAR_SPEC.Text = "Clear special feed..." ' 'BTT_FEED_DELETE_SPEC ' Me.BTT_FEED_DELETE_SPEC.Image = Global.SCrawler.My.Resources.Resources.DeletePic_24 Me.BTT_FEED_DELETE_SPEC.Name = "BTT_FEED_DELETE_SPEC" - Me.BTT_FEED_DELETE_SPEC.Size = New System.Drawing.Size(267, 22) + Me.BTT_FEED_DELETE_SPEC.Size = New System.Drawing.Size(352, 22) Me.BTT_FEED_DELETE_SPEC.Text = "Delete special feed..." ' 'BTT_FEED_DELETE_DAILY_LIST ' Me.BTT_FEED_DELETE_DAILY_LIST.Image = Global.SCrawler.My.Resources.Resources.DeletePic_24 Me.BTT_FEED_DELETE_DAILY_LIST.Name = "BTT_FEED_DELETE_DAILY_LIST" - Me.BTT_FEED_DELETE_DAILY_LIST.Size = New System.Drawing.Size(267, 22) + Me.BTT_FEED_DELETE_DAILY_LIST.Size = New System.Drawing.Size(352, 22) Me.BTT_FEED_DELETE_DAILY_LIST.Text = "Delete daily feed (by list)" ' 'BTT_FEED_DELETE_DAILY_DATE ' Me.BTT_FEED_DELETE_DAILY_DATE.Image = Global.SCrawler.My.Resources.Resources.DeletePic_24 Me.BTT_FEED_DELETE_DAILY_DATE.Name = "BTT_FEED_DELETE_DAILY_DATE" - Me.BTT_FEED_DELETE_DAILY_DATE.Size = New System.Drawing.Size(267, 22) + Me.BTT_FEED_DELETE_DAILY_DATE.Size = New System.Drawing.Size(352, 22) Me.BTT_FEED_DELETE_DAILY_DATE.Text = "Delete daily feed (by date)" ' 'BTT_MERGE_SESSIONS @@ -247,7 +280,7 @@ Namespace DownloadObjects Me.BTT_MERGE_SESSIONS.AutoToolTip = True Me.BTT_MERGE_SESSIONS.Image = Global.SCrawler.My.Resources.Resources.DBPic_32 Me.BTT_MERGE_SESSIONS.Name = "BTT_MERGE_SESSIONS" - Me.BTT_MERGE_SESSIONS.Size = New System.Drawing.Size(267, 22) + Me.BTT_MERGE_SESSIONS.Size = New System.Drawing.Size(352, 22) Me.BTT_MERGE_SESSIONS.Text = "Merge sessions" Me.BTT_MERGE_SESSIONS.ToolTipText = "Merge multiple session feeds into one" ' @@ -256,10 +289,31 @@ Namespace DownloadObjects Me.BTT_CLEAR_DAILY.Image = Global.SCrawler.My.Resources.Resources.DeletePic_24 Me.BTT_CLEAR_DAILY.ImageTransparentColor = System.Drawing.Color.Magenta Me.BTT_CLEAR_DAILY.Name = "BTT_CLEAR_DAILY" - Me.BTT_CLEAR_DAILY.Size = New System.Drawing.Size(267, 22) + Me.BTT_CLEAR_DAILY.Size = New System.Drawing.Size(352, 22) Me.BTT_CLEAR_DAILY.Text = "Clear session" Me.BTT_CLEAR_DAILY.ToolTipText = "Clear data list (session)" ' + 'BTT_MERGE_FEEDS + ' + Me.BTT_MERGE_FEEDS.AutoToolTip = True + Me.BTT_MERGE_FEEDS.Image = Global.SCrawler.My.Resources.Resources.DBPic_32 + Me.BTT_MERGE_FEEDS.Name = "BTT_MERGE_FEEDS" + Me.BTT_MERGE_FEEDS.Size = New System.Drawing.Size(352, 22) + Me.BTT_MERGE_FEEDS.Text = "Merge special feeds" + Me.BTT_MERGE_FEEDS.ToolTipText = "Merge multiple special feeds into one" + ' + 'BTT_CHECK_ALL + ' + Me.BTT_CHECK_ALL.Name = "BTT_CHECK_ALL" + Me.BTT_CHECK_ALL.Size = New System.Drawing.Size(352, 22) + Me.BTT_CHECK_ALL.Text = "Select all" + ' + 'BTT_CHECK_NONE + ' + Me.BTT_CHECK_NONE.Name = "BTT_CHECK_NONE" + Me.BTT_CHECK_NONE.Size = New System.Drawing.Size(352, 22) + Me.BTT_CHECK_NONE.Text = "Select none" + ' 'SEP_0 ' Me.SEP_0.Name = "SEP_0" @@ -339,7 +393,7 @@ Namespace DownloadObjects Me.KeyPreview = True Me.MinimumSize = New System.Drawing.Size(300, 300) Me.Name = "DownloadFeedForm" - Me.Text = "Download Feed" + Me.Text = "Feed" Me.ToolbarTOP.ResumeLayout(False) Me.ToolbarTOP.PerformLayout() Me.ResumeLayout(False) @@ -372,5 +426,10 @@ Namespace DownloadObjects Private WithEvents BTT_FEED_DELETE_DAILY_LIST As ToolStripMenuItem Private WithEvents BTT_FEED_DELETE_DAILY_DATE As ToolStripMenuItem Private WithEvents BTT_MERGE_SESSIONS As ToolStripMenuItem + Private WithEvents BTT_MERGE_FEEDS As ToolStripMenuItem + Private WithEvents BTT_FEED_ADD_FAV_REMOVE As ToolStripMenuItem + Private WithEvents BTT_FEED_ADD_SPEC_REMOVE As ToolStripMenuItem + Private WithEvents BTT_CHECK_ALL As ToolStripMenuItem + Private WithEvents BTT_CHECK_NONE As ToolStripMenuItem End Class End Namespace \ No newline at end of file diff --git a/SCrawler/Download/Feed/DownloadFeedForm.resx b/SCrawler/Download/Feed/DownloadFeedForm.resx index d829379..6b14342 100644 --- a/SCrawler/Download/Feed/DownloadFeedForm.resx +++ b/SCrawler/Download/Feed/DownloadFeedForm.resx @@ -150,6 +150,12 @@ False + + False + + + False + 17, 17 diff --git a/SCrawler/Download/Feed/DownloadFeedForm.vb b/SCrawler/Download/Feed/DownloadFeedForm.vb index 65119be..4c65d2b 100644 --- a/SCrawler/Download/Feed/DownloadFeedForm.vb +++ b/SCrawler/Download/Feed/DownloadFeedForm.vb @@ -17,6 +17,7 @@ Imports DTSModes = PersonalUtilities.Forms.DateTimeSelectionForm.Modes Namespace DownloadObjects Friend Class DownloadFeedForm #Region "Declarations" + Private Const FeedTitleDefault As String = "Feed" Private WithEvents MyDefs As DefaultFormOptions Private WithEvents MyRange As RangeSwitcherToolbar(Of UserMediaD) Private ReadOnly DataList As List(Of UserMediaD) @@ -37,7 +38,71 @@ Namespace DownloadObjects Return OPT_SUBSCRIPTIONS.Checked End Get End Property - Private IsSession As Boolean = True +#Region "Feeds options" + Private Enum FeedModes : Current : Saved : Special : End Enum + Private FeedMode As FeedModes = FeedModes.Current + Private ReadOnly Property IsSession As Boolean + Get + Return FeedMode = FeedModes.Current Or FeedMode = FeedModes.Saved + End Get + End Property + Private ReadOnly LoadedFeedNames As List(Of String) + Private Sub FeedChangeMode(ByVal Mode As FeedModes, Optional ByVal fNames As IEnumerable(Of String) = Nothing) + FeedMode = Mode + LoadedFeedNames.Clear() + If fNames.ListExists Then LoadedFeedNames.AddRange(fNames) + Try : ControlInvokeFast(Me, Sub() + Select Case FeedMode + Case FeedModes.Current : Text = $"{FeedTitleDefault}: current session" + Case FeedModes.Saved : Text = $"{FeedTitleDefault}: saved session(s)" + Case FeedModes.Special : Text = $"{FeedTitleDefault}: {IIf(LoadedFeedNames.Count > 1, "multiple special feeds", LoadedFeedNames.FirstOrDefault.IfNullOrEmpty("?"))}" + Case Else : Text = FeedTitleDefault + End Select + End Sub, EDP.None) : Catch : End Try + End Sub + Private Sub FeedRemoveCheckedMedia(ByVal MediaList As IEnumerable(Of UserMediaD), Optional ByVal OverriddenNames As List(Of String) = Nothing, + Optional ByVal RemoveChecked As Boolean = True, Optional ByVal ExcludingNames As IEnumerable(Of String) = Nothing, + Optional ByVal RemoveFromDataListOnly As Boolean = False) + Try + If FeedMode = FeedModes.Special Then + If LoadedFeedNames.Count > 0 Then + Dim dataRemoved As Boolean = False + If OverriddenNames.ListExists And Not LoadedFeedNames.ListContains(OverriddenNames) Then Exit Sub + If Not RemoveFromDataListOnly Then + Dim eNames As IEnumerable(Of String) = If(ExcludingNames, New String() {}) + With If(OverriddenNames, LoadedFeedNames) + .ForEach(Sub(ByVal feedName As String) + If Not eNames.Contains(feedName) Then + Dim indx% = Settings.Feeds.IndexOf(feedName) + If indx >= 0 Then + If Settings.Feeds(indx).Remove(MediaList) > 0 Then dataRemoved = True + End If + End If + End Sub) + End With + End If + If RemoveFromDataListOnly Then + RefillSpecialFeedsData() + ElseIf dataRemoved Then + DataList.ListDisposeRemove(MediaList) + If RemoveChecked Then + If RemoveCheckedMedia(False) Then RefillAfterDelete() + Else + RefillSpecialFeedsData() + End If + End If + End If + ElseIf FeedMode = FeedModes.Current Then + If OverriddenNames Is Nothing AndAlso Downloader.Files.ListDisposeRemove(MediaList) > 0 AndAlso RemoveCheckedMedia(False) Then + DataList.ListDisposeRemove(MediaList) + RefillAfterDelete() + End If + End If + Catch ex As Exception + ErrorsDescriber.Execute(EDP.SendToLog, ex, "[DownloadFeedForm.FeedRemoveCheckedMedia]") + End Try + End Sub +#End Region #End Region #Region "Initializer" Friend Sub New() @@ -45,6 +110,7 @@ Namespace DownloadObjects MyDefs = New DefaultFormOptions(Me, Settings.Design) MyRange = New RangeSwitcherToolbar(Of UserMediaD)(ToolbarTOP) DataList = New List(Of UserMediaD) + LoadedFeedNames = New List(Of String) BTT_DELETE_SELECTED = New ToolStripButton With { .Text = "Delete selected", .AutoToolTip = True, @@ -79,6 +145,7 @@ Namespace DownloadObjects If Not feed.IsFavorite Then AddNewFeedItem(BTT_LOAD_SPEC, feed, My.Resources.RSSPic_512, AddressOf Feed_SPEC_LOAD) AddNewFeedItem(BTT_FEED_ADD_SPEC, feed, My.Resources.RSSPic_512, AddressOf Feed_SPEC_ADD) + AddNewFeedItem(BTT_FEED_ADD_SPEC_REMOVE, feed, My.Resources.RSSPic_512, AddressOf Feed_SPEC_ADD_REMOVE) AddNewFeedItem(BTT_FEED_REMOVE_SPEC, feed, My.Resources.RSSPic_512, AddressOf Feed_SPEC_REMOVE) AddNewFeedItem(BTT_FEED_DELETE_SPEC, feed, My.Resources.DeletePic_24, AddressOf Feed_SPEC_DELETE) AddNewFeedItem(BTT_FEED_CLEAR_SPEC, feed, My.Resources.BrushToolPic_16, AddressOf Feed_SPEC_CLEAR) @@ -95,7 +162,8 @@ Namespace DownloadObjects End With MENU_DOWN.Visible = OPT_SUBSCRIPTIONS.Checked UpdateSettings() - RefillList() + FeedChangeMode(FeedModes.Current) + RefillList(True, False) .EndLoaderOperations(False) End With End Sub @@ -106,11 +174,12 @@ Namespace DownloadObjects Private Sub DownloadFeedForm_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed ClearTable() MyRange.Dispose() + LoadedFeedNames.Clear() BTT_CLEAR_DAILY.Dispose() DataList.Clear() End Sub Private Sub DownloadFeedForm_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown - If e.KeyCode = Keys.F5 Then RefillList() : e.Handled = True + If e.KeyCode = Keys.F5 Then RefillList0() : e.Handled = True End Sub #End Region #Region "Feeds handlers" @@ -135,6 +204,7 @@ Namespace DownloadObjects Private Sub Feed_FeedAdded(ByVal Source As FeedSpecialCollection, ByVal Feed As FeedSpecial) AddNewFeedItem(BTT_LOAD_SPEC, Feed, My.Resources.RSSPic_512, AddressOf Feed_SPEC_LOAD, True) AddNewFeedItem(BTT_FEED_ADD_SPEC, Feed, My.Resources.RSSPic_512, AddressOf Feed_SPEC_ADD, True) + AddNewFeedItem(BTT_FEED_ADD_SPEC_REMOVE, Feed, My.Resources.RSSPic_512, AddressOf Feed_SPEC_ADD_REMOVE, True) AddNewFeedItem(BTT_FEED_REMOVE_SPEC, Feed, My.Resources.RSSPic_512, AddressOf Feed_SPEC_REMOVE, True) AddNewFeedItem(BTT_FEED_DELETE_SPEC, Feed, My.Resources.DeletePic_24, AddressOf Feed_SPEC_DELETE, True) AddNewFeedItem(BTT_FEED_CLEAR_SPEC, Feed, My.Resources.BrushToolPic_16, AddressOf Feed_SPEC_CLEAR, True) @@ -160,7 +230,6 @@ Namespace DownloadObjects item = .DropDownItems(i) If TypeOf item Is ToolStripMenuItem AndAlso Feed.Equals(DirectCast(item, ToolStripMenuItem).Tag) Then With DirectCast(item, ToolStripMenuItem) : .Tag = Nothing : .Dispose() : End With - '.DropDownItems.RemoveAt(i) End If Next End If @@ -172,33 +241,53 @@ Namespace DownloadObjects End Try End Sub Private Sub Feed_SPEC_LOAD(ByVal Source As ToolStripMenuItem, ByVal e As EventArgs) - IsSession = False Dim f As FeedSpecial = Source.Tag If Not f Is Nothing AndAlso Not f.Disposed Then - DataList.Clear() - If f.Count > 0 Then DataList.ListAddList(f) : CleanDataList() - RefillList(False) + FeedChangeMode(FeedModes.Special, {f.Name}) + RefillSpecialFeedsData(False) End If End Sub Private Sub Feed_SPEC_ADD(ByVal Source As ToolStripMenuItem, ByVal e As EventArgs) Dim f As FeedSpecial = Source.Tag If Not f Is Nothing AndAlso Not f.Disposed Then f.Add(GetCheckedMedia()) End Sub + Private Sub Feed_SPEC_ADD_REMOVE(ByVal Source As ToolStripMenuItem, ByVal e As EventArgs) + Dim f As FeedSpecial = Source.Tag + If Not f Is Nothing AndAlso Not f.Disposed Then + Dim c As IEnumerable(Of UserMediaD) = GetCheckedMedia() + If c.ListExists Then + f.Add(c) + FeedRemoveCheckedMedia(c,,, {f.Name}) + End If + End If + End Sub Private Sub Feed_SPEC_CLEAR(ByVal Source As ToolStripMenuItem, ByVal e As EventArgs) Dim f As FeedSpecial = Source.Tag If Not f Is Nothing AndAlso Not f.Disposed Then - If MsgBoxE({$"Are you sure you want to clear the '{f.Name}' feed?", "Clear feed"}, vbExclamation,,, {"Process", "Cancel"}) = 0 Then f.Clear() + If MsgBoxE({$"Are you sure you want to clear the '{f.Name}' feed?", "Clear feed"}, vbExclamation,,, {"Process", "Cancel"}) = 0 Then + f.Clear() + If FeedMode = FeedModes.Special Then RefillSpecialFeedsData() + End If End If End Sub Private Sub Feed_SPEC_REMOVE(ByVal Source As ToolStripMenuItem, ByVal e As EventArgs) Dim f As FeedSpecial = Source.Tag - If Not f Is Nothing AndAlso Not f.Disposed Then f.Remove(GetCheckedMedia()) + If Not f Is Nothing AndAlso Not f.Disposed Then + Dim m As IEnumerable(Of UserMediaD) = GetCheckedMedia() + If m.ListExists Then + f.Remove(m) + FeedRemoveCheckedMedia(m, {f.Name}.ToList) + End If + End If End Sub Private Sub Feed_SPEC_DELETE(ByVal Source As ToolStripMenuItem, ByVal e As EventArgs) Dim f As FeedSpecial = Source.Tag If Not f Is Nothing AndAlso Not f.Disposed Then - If MsgBoxE({$"Are you sure you want to delete the '{f.Name}' feed?", "Delete feed"}, vbExclamation,,, {"Process", "Cancel"}) = 0 AndAlso - f.Delete() Then Feed_FeedRemoved(Settings.Feeds, f) + Dim name$ = f.Name + If MsgBoxE({$"Are you sure you want to delete the '{name}' feed?", "Delete feed"}, vbExclamation,,, {"Process", "Cancel"}) = 0 AndAlso f.Delete() Then + Feed_FeedRemoved(Settings.Feeds, f) + If LoadedFeedNames.Count > 0 AndAlso LoadedFeedNames.Contains(name) Then LoadedFeedNames.Remove(name) : RefillSpecialFeedsData() + End If End If End Sub #End Region @@ -255,13 +344,22 @@ Namespace DownloadObjects MyRange.HandlersSuspended = True MyRange.Limit = c MyRange.HandlersSuspended = False - If Not MyDefs.Initializing Then RefillList(False) + If Not MyDefs.Initializing Then RefillList0() End With End Sub #End Region #Region "Refill" - Private Sub RefillList(Optional ByVal RefillDataList As Boolean = True) + Private Sub RefillList0(Optional ByVal RememberPosition As Boolean? = Nothing) + If IsSession Then + RefillList(FeedMode = FeedModes.Current, If(RememberPosition, True)) + Else + RefillSpecialFeedsData() + End If + End Sub + Private Sub RefillList(Optional ByVal RefillDataList As Boolean = True, Optional ByVal RememberPosition As Boolean = False) DataPopulated = False + Dim rIndx% = -1 + If RememberPosition Then rIndx = MyRange.CurrentIndex If RefillDataList Then If Not IsSubscription Then Try : Downloader.Files.RemoveAll(FileNotExist) : Catch : End Try @@ -270,6 +368,10 @@ Namespace DownloadObjects 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 @@ -293,19 +395,18 @@ Namespace DownloadObjects #Region "Feed" #Region "Load" Private Sub BTT_LOAD_SESSION_CURRENT_Click(sender As Object, e As EventArgs) Handles BTT_LOAD_SESSION_CURRENT.Click - IsSession = True - RefillList() + FeedChangeMode(FeedModes.Current) + RefillList(True, False) End Sub Private Sub BTT_LOAD_SESSION_LAST_Click(sender As Object, e As EventArgs) Handles BTT_LOAD_SESSION_LAST.Click - IsSession = True - SessionChooser(True) + SessionChooser(True,,, FeedModes.Saved) End Sub Private Sub BTT_LOAD_SESSION_CHOOSE_Click(sender As Object, e As EventArgs) Handles BTT_LOAD_SESSION_CHOOSE.Click - IsSession = True - SessionChooser(False) + SessionChooser(False,,, FeedModes.Saved) End Sub Private Sub SessionChooser(ByVal GetLast As Boolean, Optional ByVal GetFilesOnly As Boolean = False, - Optional ByRef ResultFilesList As List(Of SFile) = Nothing) + Optional ByRef ResultFilesList As List(Of SFile) = Nothing, + Optional ByVal SelectedMode As FeedModes = -1) Try Downloader.ClearSessions() Dim f As SFile = TDownloader.SessionsPath.CSFileP @@ -341,6 +442,7 @@ Namespace DownloadObjects ResultFilesList.AddRange(fList) Else DataList.Clear() + If SelectedMode >= 0 Then FeedChangeMode(SelectedMode) For Each f In fList x = New XmlFile(f,, False) With {.AllowSameNames = True, .XmlReadOnly = True} x.LoadData() @@ -348,7 +450,7 @@ Namespace DownloadObjects x.Dispose() Next CleanDataList() - RefillList(False) + RefillList(False, False) End If Else MsgBoxE(m) @@ -368,12 +470,14 @@ Namespace DownloadObjects f = Downloader.FilesSessionActual(False) End If If f.Exists Then + If SelectedMode >= 0 Then FeedChangeMode(SelectedMode) + DataList.Clear() x = New XmlFile(f,, False) With {.AllowSameNames = True, .XmlReadOnly = True} x.LoadData() - If x.Count > 0 Then DataList.Clear() : DataList.ListAddList(x, lcr) + If x.Count > 0 Then DataList.ListAddList(x, lcr) x.Dispose() CleanDataList() - RefillList(False) + RefillList(False, False) End If Else m.Text = "Saved sessions not found" @@ -387,43 +491,68 @@ Namespace DownloadObjects #End Region #Region "Load fav, spec" Private Sub BTT_LOAD_FAV_Click(sender As Object, e As EventArgs) Handles BTT_LOAD_FAV.Click - IsSession = False - DataList.Clear() - With Settings.Feeds.Favorite - .RemoveNotExist(FileNotExist) - If .Count > 0 Then DataList.AddRange(.Self) : CleanDataList() : RefillList(False) - End With + FeedChangeMode(FeedModes.Special, {FeedSpecial.FavoriteName}) + RefillSpecialFeedsData(False) End Sub Private Sub BTT_LOAD_SPEC_Click(sender As Object, e As EventArgs) Handles BTT_LOAD_SPEC.Click - IsSession = False With FeedSpecialCollection.ChooseFeeds(False) If .ListExists Then - DataList.Clear() - Dim d As New List(Of UserMediaD) - .ForEach(Sub(ByVal f As FeedSpecial) - f.RemoveNotExist(FileNotExist) - If f.Count > 0 Then d.AddRange(f) - End Sub) - If d.Count > 0 Then DataList.ListAddList(d.Distinct) - CleanDataList() - RefillList(False) + FeedChangeMode(FeedModes.Special, .Select(Function(f) f.Name)) + RefillSpecialFeedsData(False) End If End With End Sub + Private Sub RefillSpecialFeedsData(Optional ByVal RememberPosition As Boolean = True) + If LoadedFeedNames.Count > 0 Then + Dim d As New List(Of UserMediaD) + Dim lp As New ListAddParams(LAP.NotContainsOnly) + LoadedFeedNames.ForEach(Sub(ByVal fName As String) + Dim indx% = Settings.Feeds.IndexOf(fName) + If indx >= 0 Then + With Settings.Feeds(indx) + .RemoveNotExist(FileNotExist) + d.ListAddList(.Self, lp) + End With + End If + End Sub) + DataList.Clear() + If d.Count > 0 Then + d.Sort(New FeedSpecial.SEComparer) + DataList.AddRange(d) + CleanDataList() + d.Clear() + End If + RefillList(False, RememberPosition) + End If + End Sub #End Region #Region "Add remove fav spec" - Private Sub BTT_FEED_ADD_FAV_Click(sender As Object, e As EventArgs) Handles BTT_FEED_ADD_FAV.Click - Settings.Feeds.Favorite.Add(GetCheckedMedia()) + Private Sub BTT_FEED_ADD_FAV_Click(sender As Object, e As EventArgs) Handles BTT_FEED_ADD_FAV.Click, BTT_FEED_ADD_FAV_REMOVE.Click + Dim m As IEnumerable(Of UserMediaD) = GetCheckedMedia() + If m.ListExists Then + Settings.Feeds.Favorite.Add(m) + If sender Is BTT_FEED_ADD_FAV_REMOVE Then FeedRemoveCheckedMedia(m,,, {FeedSpecial.FavoriteName}) + End If End Sub Private Sub BTT_FEED_REMOVE_FAV_Click(sender As Object, e As EventArgs) Handles BTT_FEED_REMOVE_FAV.Click - Settings.Feeds.Favorite.Remove(GetCheckedMedia()) + Dim m As IEnumerable(Of UserMediaD) = GetCheckedMedia() + If m.ListExists Then + Settings.Feeds.Favorite.Remove(m) + If FeedMode = FeedModes.Special Then FeedRemoveCheckedMedia(m, {FeedSpecial.FavoriteName}.ToList) + End If End Sub - Private Sub BTT_FEED_ADD_SPEC_Click(sender As Object, e As EventArgs) Handles BTT_FEED_ADD_SPEC.Click + Private Sub BTT_FEED_ADD_SPEC_Click(sender As Object, e As EventArgs) Handles BTT_FEED_ADD_SPEC.Click, BTT_FEED_ADD_SPEC_REMOVE.Click Dim c As IEnumerable(Of UserMediaD) = GetCheckedMedia() If c.ListExists Then + Dim names As New List(Of String) With FeedSpecialCollection.ChooseFeeds(True) - If .ListExists Then .ForEach(Sub(f) f.Add(c)) + If .ListExists Then .ForEach(Sub(ByVal f As FeedSpecial) + names.Add(f.Name) + f.Add(c) + End Sub) End With + If sender Is BTT_FEED_ADD_SPEC_REMOVE Then FeedRemoveCheckedMedia(c,,, names) + names.Clear() Else MsgBoxE({"You haven't selected media to add to your feed(s)", "Add to feed(s)"}, vbExclamation) End If @@ -431,9 +560,14 @@ Namespace DownloadObjects Private Sub BTT_FEED_REMOVE_SPEC_Click(sender As Object, e As EventArgs) Handles BTT_FEED_REMOVE_SPEC.Click Dim c As IEnumerable(Of UserMediaD) = GetCheckedMedia() If c.ListExists Then + Dim names As New List(Of String) With FeedSpecialCollection.ChooseFeeds(False) - If .ListExists Then .ForEach(Sub(f) f.Remove(c)) + If .ListExists Then .ForEach(Sub(ByVal f As FeedSpecial) + names.Add(f.Name) + f.Remove(c) + End Sub) End With + If FeedMode = FeedModes.Special Then FeedRemoveCheckedMedia(c, names) Else MsgBoxE({"You haven't selected media to remove from your feed(s)", "Remove from feed(s)"}, vbExclamation) End If @@ -457,16 +591,28 @@ Namespace DownloadObjects Private Sub BTT_FEED_CLEAR_SPEC_Click(sender As Object, e As EventArgs) Handles BTT_FEED_CLEAR_SPEC.Click With FeedSpecialCollection.ChooseFeeds(False) If .ListExists Then - If MsgBoxE({$"Are you sure you want to clear the following feeds?{vbCr}{vbCr}{ .ListToString(vbCr)}", "Clear feed"}, vbExclamation,,, - {"Process", "Cancel"}) = 0 Then .ForEach(Sub(f) f.Clear()) + If MsgBoxE({$"Are you sure you want to clear the following feeds?{vbCr}{vbCr}{ .ListToString(vbCr)}", "Clear feed"}, vbExclamation,,, {"Process", "Cancel"}) = 0 Then + Dim names As IEnumerable(Of String) = .Select(Function(f) f.Name) + .ForEach(Sub(f) f.Clear()) + If FeedMode = FeedModes.Special Then + LoadedFeedNames.ListDisposeRemove(names) + RefillSpecialFeedsData() + End If + End If End If End With End Sub Private Sub BTT_FEED_DELETE_SPEC_Click(sender As Object, e As EventArgs) Handles BTT_FEED_DELETE_SPEC.Click With FeedSpecialCollection.ChooseFeeds(False) If .ListExists Then - If MsgBoxE({$"Are you sure you want to delete the following feeds?{vbCr}{vbCr}{ .ListToString(vbCr)}", "Delete feed"}, vbExclamation,,, - {"Process", "Cancel"}) = 0 Then .ForEach(Sub(f) f.Delete()) + If MsgBoxE({$"Are you sure you want to delete the following feeds?{vbCr}{vbCr}{ .ListToString(vbCr)}", "Delete feed"}, vbExclamation,,, {"Process", "Cancel"}) = 0 Then + Dim names As IEnumerable(Of String) = .Select(Function(f) f.Name) + .ForEach(Sub(f) f.Delete()) + If FeedMode = FeedModes.Special Then + LoadedFeedNames.ListDisposeRemove(names) + RefillSpecialFeedsData() + End If + End If End If End With End Sub @@ -530,12 +676,12 @@ Namespace DownloadObjects If MsgBoxE({"Are you sure you want to clear this session data?", "Clear session"}, vbExclamation,,, {"Process", "Cancel"}) = 0 Then Downloader.Files.Clear() ClearTable() - RefillList() + RefillList0() End If End Sub #End Region #Region "Merge feeds" - Private Sub MergeFeeds() Handles BTT_MERGE_SESSIONS.Click + Private Sub BTT_MERGE_SESSIONS_Click(sender As Object, e As EventArgs) Handles BTT_MERGE_SESSIONS.Click Try Const msgTitle$ = "Merge feeds" Dim files As New List(Of SFile) @@ -591,11 +737,62 @@ Namespace DownloadObjects Else MsgBoxE({"You haven't selected any feeds", msgTitle}, vbExclamation) End If + Catch ex As Exception + ErrorsDescriber.Execute(EDP.SendToLog, ex, "[DownloadFeedForm.MergeSessions]") + End Try + End Sub + Private Sub BTT_MERGE_FEEDS_Click(sender As Object, e As EventArgs) Handles BTT_MERGE_FEEDS.Click + Try + Const msgTitle$ = "Merge feeds" + If Settings.Feeds.Count > 1 Then + Dim mFrom As List(Of FeedSpecial) = FeedSpecialCollection.ChooseFeeds(False, "[SOURCE]", True) + Dim mTo As FeedSpecial + If mFrom.ListExists(2) Then + mTo = FeedSpecialCollection.ChooseFeeds(True, "[DESTINATION]", True).FirstOrDefault + If Not mTo Is Nothing Then + Dim names$() = mFrom.Select(Function(f) f.Name).ToArray + If MsgBoxE({$"Are you sure you want to merge the following feeds into '{mTo.Name}'?{vbCr}{vbCr}" & + names.ListToString(vbCr), msgTitle}, vbQuestion + vbYesNo) = vbYes Then + mFrom.ForEach(Sub(f) mTo.Add(f, False)) + mTo.Save() + mFrom.ForEach(Sub(f) If Not f.Equals(mTo) Then Settings.Feeds.Delete(f)) + MsgBoxE({$"Feeds' data was combined into '{mTo.Name}'.{vbCr}It is highly recommended to restart SCrawler!{vbCr}{vbCr}" & + names.ListToStringE(vbCr), msgTitle}) + Else + ShowOperationCanceledMsg(msgTitle) + End If + mFrom.Clear() + Else + MsgBoxE({"No destination selected", msgTitle}, vbExclamation) + End If + ElseIf mfrom.ListExists(1) Then + MsgBoxE({"You must select two or more files to merge feeds", msgTitle}, vbExclamation) + Else + MsgBoxE({"You haven't selected any feeds", msgTitle}, vbExclamation) + End If + ElseIf Settings.Feeds.Count = 1 Then + MsgBoxE({"You must have two or more files to merge feeds", msgTitle}, vbExclamation) + Else + MsgBoxE({"No feeds found", msgTitle}, vbExclamation) + End If Catch ex As Exception ErrorsDescriber.Execute(EDP.SendToLog, ex, "[DownloadFeedForm.MergeFeeds]") End Try End Sub #End Region + Private Sub BTT_CHECK_ALL_NONE_Click(sender As Object, e As EventArgs) Handles BTT_CHECK_ALL.Click, BTT_CHECK_NONE.Click + Try + Dim checked As Boolean = sender Is BTT_CHECK_ALL + ControlInvokeFast(TP_DATA, Sub() + With TP_DATA + If .Controls.Count > 0 Then + For Each cnt As FeedMedia In .Controls : cnt.Checked = checked : Next + End If + End With + End Sub, EDP.None) + Catch + End Try + End Sub #End Region #Region "View modes" Private Sub OPT_Click(ByVal Sender As ToolStripMenuItem, ByVal e As EventArgs) Handles OPT_DEFAULT.Click, OPT_SUBSCRIPTIONS.Click @@ -614,7 +811,7 @@ Namespace DownloadObjects Settings.FeedLastModeSubscriptions.Value = OPT_SUBSCRIPTIONS.Checked MENU_DOWN.Visible = OPT_SUBSCRIPTIONS.Checked End Sub, EDP.None) - If __refill Then RefillList() + If __refill Then RefillList0() End Sub #End Region Friend Sub Downloader_FilesChanged(ByVal Added As Boolean) @@ -622,11 +819,18 @@ Namespace DownloadObjects BTT_REFRESH.ControlChangeColor(ToolbarTOP, Added, False) End Sub Private Sub BTT_REFRESH_Click(sender As Object, e As EventArgs) Handles BTT_REFRESH.Click - IsSession = True - RefillList() + RefillList0() End Sub #End Region -#Region "Download" +#Region "FeedMedia handlers" + Private Sub FeedMedia_MediaDeleted(ByVal Sender As FeedMedia) + Try + ControlInvoke(TP_DATA, Sub() TPRemoveControl(Sender, True)) + DataList.RemoveAll(Function(dd) dd.Data.File = Sender.File) + RefillAfterDelete() + Catch + End Try + End Sub Private Sub FeedMedia_Download(ByVal Sender As Object, ByVal e As EventArgs) Handles BTT_DOWN_ALL.Click, BTT_DOWN_SELECTED.Click Try Dim urls As New List(Of String) @@ -650,38 +854,19 @@ Namespace DownloadObjects ErrorsDescriber.Execute(EDP.LogMessageValue, ex, "Download subscription media") End Try End Sub + Private Sub FeedMedia_FeedAddWithRemove(ByVal Sender As FeedMedia, ByVal Feeds As IEnumerable(Of String), ByVal Media As UserMediaD, ByVal RemoveOperation As Boolean) + FeedRemoveCheckedMedia({Media},, False, Feeds, RemoveOperation) + End Sub #End Region -#Region "Delete" +#Region "Delete / Remove" Private Sub BTT_DELETE_SELECTED_Click(sender As Object, e As EventArgs) Handles BTT_DELETE_SELECTED.Click Const MsgTitle$ = "Deleting marked files" Try - Dim c As IEnumerable(Of FeedMedia) = ControlInvoke(TP_DATA, Function() If(TP_DATA.Controls.Count > 0, TP_DATA.Controls.ToObjectsList.Cast(Of FeedMedia)().Where(Function(f) f.Checked), New FeedMedia() {})) + Dim c As IEnumerable(Of FeedMedia) = GetCheckedMediaControls() If c.ListExists Then If MsgBoxE({$"Are you sure you want to delete {c.Count} file(s)?", MsgTitle}, vbExclamation,,, {"Process", "Cancel"}) = 0 Then Dim indx% = MyRange.CurrentIndex - Dim d% = 0 - ControlInvoke(TP_DATA, Sub() - With TP_DATA - .SuspendLayout() - LatestScrollValueDisabled = True - For Each fm As FeedMedia In c - If fm.DeleteFile(True) Then - d += 1 - DataList.RemoveAll(Function(dd) dd.Data.File = fm.File) - TPRemoveControl(fm, False) - End If - Next - If d = 0 Then LatestScrollValueDisabled = False - .ResumeLayout(d = 0) - If d > 0 Then - .AutoScroll = False - .AutoScroll = True - SetScrollValue(False) - .PerformLayout() - LatestScrollValueDisabled = False - End If - End With - End Sub) + Dim d% = RemoveCheckedMedia(True, c) If d > 0 Then RefillAfterDelete() MsgBoxE({$"{d}/{c.Count} file(s) deleted", MsgTitle}) Else @@ -694,14 +879,42 @@ Namespace DownloadObjects ErrorsDescriber.Execute(EDP.LogMessageValue, ex, MsgTitle) End Try End Sub - Private Sub FeedMedia_MediaDeleted(ByVal Sender As FeedMedia) + Private Function GetCheckedMediaControls() As IEnumerable(Of FeedMedia) + Return ControlInvoke(TP_DATA, Function() If(TP_DATA.Controls.Count > 0, TP_DATA.Controls.ToObjectsList.Cast(Of FeedMedia)().Where(Function(f) f.Checked), New FeedMedia() {})) + End Function + Private Function RemoveCheckedMedia(ByVal DeleteFiles As Boolean, Optional ByVal Controls As IEnumerable(Of FeedMedia) = Nothing) As Integer Try - ControlInvoke(TP_DATA, Sub() TPRemoveControl(Sender, True)) - DataList.RemoveAll(Function(dd) dd.Data.File = Sender.File) - RefillAfterDelete() - Catch + Dim d% = 0 + If Not Controls.ListExists Then Controls = GetCheckedMediaControls() + If Controls.ListExists Then + ControlInvoke(TP_DATA, Sub() + With TP_DATA + .SuspendLayout() + LatestScrollValueDisabled = True + For Each fm As FeedMedia In Controls + If Not DeleteFiles OrElse fm.DeleteFile(True) Then + d += 1 + DataList.RemoveAll(Function(dd) dd.Data.File = fm.File) + TPRemoveControl(fm, False) + End If + Next + If d = 0 Then LatestScrollValueDisabled = False + .ResumeLayout(d = 0) + If d > 0 Then + .AutoScroll = False + .AutoScroll = True + SetScrollValue(False) + .PerformLayout() + LatestScrollValueDisabled = False + End If + End With + End Sub) + End If + Return d + Catch ex As Exception + Return ErrorsDescriber.Execute(EDP.SendToLog, ex, "[DownloadFeedForm.RemoveCheckedMedia]", 0) End Try - End Sub + End Function Private Sub TPRemoveControl(ByVal CNT As FeedMedia, ByVal Suspend As Boolean) Dim HeightChanged As Boolean = False Try @@ -811,7 +1024,7 @@ Namespace DownloadObjects If d.ListExists AndAlso Not IsSubscription AndAlso d.All(FileNotExist) Then i = Sender.CurrentIndex Sender.HandlersSuspended = True - RefillList() + RefillList0(False) If Sender.Count > 0 Then If i.ValueBetween(0, Sender.Count - 1) Then Sender.CurrentIndex = i Sender.HandlersSuspended = False @@ -837,6 +1050,7 @@ Namespace DownloadObjects With fmList.Last AddHandler .MediaDeleted, AddressOf FeedMedia_MediaDeleted AddHandler .MediaDownload, AddressOf FeedMedia_Download + AddHandler .FeedAddWithRemove, AddressOf FeedMedia_FeedAddWithRemove End With End Sub) If fmList.Count > 0 Then fmList.ListDisposeRemoveAll(Function(fm) fm Is Nothing OrElse fm.HasError) diff --git a/SCrawler/Download/Feed/FeedMedia.Designer.vb b/SCrawler/Download/Feed/FeedMedia.Designer.vb index 0e54a09..200bf40 100644 --- a/SCrawler/Download/Feed/FeedMedia.Designer.vb +++ b/SCrawler/Download/Feed/FeedMedia.Designer.vb @@ -35,18 +35,20 @@ Namespace DownloadObjects Me.BTT_CONTEXT_OPEN_USER = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_CONTEXT_OPEN_USER_URL = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_CONTEXT_OPEN_USER_POST = New System.Windows.Forms.ToolStripMenuItem() - Me.BTT_CONTEXT_FIND_USER = New System.Windows.Forms.ToolStripMenuItem() - Me.BTT_CONTEXT_INFO = New System.Windows.Forms.ToolStripMenuItem() - Me.CONTEXT_SEP_3 = New System.Windows.Forms.ToolStripSeparator() - Me.BTT_CONTEXT_DELETE = New System.Windows.Forms.ToolStripMenuItem() - Me.ICON_SITE = New System.Windows.Forms.PictureBox() - Me.TP_MAIN = New System.Windows.Forms.TableLayoutPanel() - Me.LBL_TITLE = New System.Windows.Forms.Label() - Me.CONTEXT_SEP_4 = New System.Windows.Forms.ToolStripSeparator() Me.BTT_FEED_ADD_FAV = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_FEED_ADD_SPEC = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_FEED_REMOVE_FAV = New System.Windows.Forms.ToolStripMenuItem() Me.BTT_FEED_REMOVE_SPEC = New System.Windows.Forms.ToolStripMenuItem() + Me.CONTEXT_SEP_3 = New System.Windows.Forms.ToolStripSeparator() + Me.BTT_CONTEXT_FIND_USER = New System.Windows.Forms.ToolStripMenuItem() + Me.BTT_CONTEXT_INFO = New System.Windows.Forms.ToolStripMenuItem() + Me.CONTEXT_SEP_4 = New System.Windows.Forms.ToolStripSeparator() + Me.BTT_CONTEXT_DELETE = New System.Windows.Forms.ToolStripMenuItem() + Me.ICON_SITE = New System.Windows.Forms.PictureBox() + Me.TP_MAIN = New System.Windows.Forms.TableLayoutPanel() + Me.LBL_TITLE = New System.Windows.Forms.Label() + Me.BTT_FEED_ADD_FAV_REMOVE = New System.Windows.Forms.ToolStripMenuItem() + Me.BTT_FEED_ADD_SPEC_REMOVE = New System.Windows.Forms.ToolStripMenuItem() CONTEXT_SEP_1 = New System.Windows.Forms.ToolStripSeparator() CONTEXT_SEP_2 = New System.Windows.Forms.ToolStripSeparator() TP_LBL = New System.Windows.Forms.TableLayoutPanel() @@ -59,12 +61,12 @@ Namespace DownloadObjects 'CONTEXT_SEP_1 ' CONTEXT_SEP_1.Name = "CONTEXT_SEP_1" - CONTEXT_SEP_1.Size = New System.Drawing.Size(217, 6) + CONTEXT_SEP_1.Size = New System.Drawing.Size(302, 6) ' 'CONTEXT_SEP_2 ' CONTEXT_SEP_2.Name = "CONTEXT_SEP_2" - CONTEXT_SEP_2.Size = New System.Drawing.Size(217, 6) + CONTEXT_SEP_2.Size = New System.Drawing.Size(302, 6) ' 'TP_LBL ' @@ -108,76 +110,109 @@ Namespace DownloadObjects ' 'CONTEXT_DATA ' - Me.CONTEXT_DATA.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_CONTEXT_DOWN, Me.CONTEXT_SEP_0, Me.BTT_CONTEXT_OPEN_MEDIA, Me.BTT_CONTEXT_OPEN_USER, CONTEXT_SEP_1, Me.BTT_CONTEXT_OPEN_USER_URL, Me.BTT_CONTEXT_OPEN_USER_POST, CONTEXT_SEP_2, Me.BTT_FEED_ADD_FAV, Me.BTT_FEED_ADD_SPEC, Me.BTT_FEED_REMOVE_FAV, Me.BTT_FEED_REMOVE_SPEC, Me.CONTEXT_SEP_3, Me.BTT_CONTEXT_FIND_USER, Me.BTT_CONTEXT_INFO, Me.CONTEXT_SEP_4, Me.BTT_CONTEXT_DELETE}) + Me.CONTEXT_DATA.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_CONTEXT_DOWN, Me.CONTEXT_SEP_0, Me.BTT_CONTEXT_OPEN_MEDIA, Me.BTT_CONTEXT_OPEN_USER, CONTEXT_SEP_1, Me.BTT_CONTEXT_OPEN_USER_URL, Me.BTT_CONTEXT_OPEN_USER_POST, CONTEXT_SEP_2, Me.BTT_FEED_ADD_FAV, Me.BTT_FEED_ADD_FAV_REMOVE, Me.BTT_FEED_ADD_SPEC, Me.BTT_FEED_ADD_SPEC_REMOVE, Me.BTT_FEED_REMOVE_FAV, Me.BTT_FEED_REMOVE_SPEC, Me.CONTEXT_SEP_3, Me.BTT_CONTEXT_FIND_USER, Me.BTT_CONTEXT_INFO, Me.CONTEXT_SEP_4, Me.BTT_CONTEXT_DELETE}) Me.CONTEXT_DATA.Name = "CONTEXT_PIC" - Me.CONTEXT_DATA.Size = New System.Drawing.Size(221, 320) + Me.CONTEXT_DATA.Size = New System.Drawing.Size(306, 364) ' 'BTT_CONTEXT_DOWN ' Me.BTT_CONTEXT_DOWN.Image = Global.SCrawler.My.Resources.Resources.StartPic_Green_16 Me.BTT_CONTEXT_DOWN.Name = "BTT_CONTEXT_DOWN" - Me.BTT_CONTEXT_DOWN.Size = New System.Drawing.Size(220, 22) + Me.BTT_CONTEXT_DOWN.Size = New System.Drawing.Size(305, 22) Me.BTT_CONTEXT_DOWN.Text = "Download" Me.BTT_CONTEXT_DOWN.Visible = False ' 'CONTEXT_SEP_0 ' Me.CONTEXT_SEP_0.Name = "CONTEXT_SEP_0" - Me.CONTEXT_SEP_0.Size = New System.Drawing.Size(217, 6) + Me.CONTEXT_SEP_0.Size = New System.Drawing.Size(302, 6) Me.CONTEXT_SEP_0.Visible = False ' 'BTT_CONTEXT_OPEN_MEDIA ' Me.BTT_CONTEXT_OPEN_MEDIA.Image = Global.SCrawler.My.Resources.Resources.FolderPic_32 Me.BTT_CONTEXT_OPEN_MEDIA.Name = "BTT_CONTEXT_OPEN_MEDIA" - Me.BTT_CONTEXT_OPEN_MEDIA.Size = New System.Drawing.Size(220, 22) + Me.BTT_CONTEXT_OPEN_MEDIA.Size = New System.Drawing.Size(305, 22) Me.BTT_CONTEXT_OPEN_MEDIA.Text = "Open" ' 'BTT_CONTEXT_OPEN_USER ' Me.BTT_CONTEXT_OPEN_USER.Image = Global.SCrawler.My.Resources.Resources.FolderPic_32 Me.BTT_CONTEXT_OPEN_USER.Name = "BTT_CONTEXT_OPEN_USER" - Me.BTT_CONTEXT_OPEN_USER.Size = New System.Drawing.Size(220, 22) + Me.BTT_CONTEXT_OPEN_USER.Size = New System.Drawing.Size(305, 22) Me.BTT_CONTEXT_OPEN_USER.Text = "Open user" ' 'BTT_CONTEXT_OPEN_USER_URL ' Me.BTT_CONTEXT_OPEN_USER_URL.Image = Global.SCrawler.My.Resources.Resources.GlobePic_32 Me.BTT_CONTEXT_OPEN_USER_URL.Name = "BTT_CONTEXT_OPEN_USER_URL" - Me.BTT_CONTEXT_OPEN_USER_URL.Size = New System.Drawing.Size(220, 22) + Me.BTT_CONTEXT_OPEN_USER_URL.Size = New System.Drawing.Size(305, 22) Me.BTT_CONTEXT_OPEN_USER_URL.Text = "Open user" ' 'BTT_CONTEXT_OPEN_USER_POST ' Me.BTT_CONTEXT_OPEN_USER_POST.Image = Global.SCrawler.My.Resources.Resources.GlobePic_32 Me.BTT_CONTEXT_OPEN_USER_POST.Name = "BTT_CONTEXT_OPEN_USER_POST" - Me.BTT_CONTEXT_OPEN_USER_POST.Size = New System.Drawing.Size(220, 22) + Me.BTT_CONTEXT_OPEN_USER_POST.Size = New System.Drawing.Size(305, 22) Me.BTT_CONTEXT_OPEN_USER_POST.Text = "Open post" ' + 'BTT_FEED_ADD_FAV + ' + Me.BTT_FEED_ADD_FAV.Image = Global.SCrawler.My.Resources.Resources.HeartPic_32 + Me.BTT_FEED_ADD_FAV.Name = "BTT_FEED_ADD_FAV" + Me.BTT_FEED_ADD_FAV.Size = New System.Drawing.Size(305, 22) + Me.BTT_FEED_ADD_FAV.Text = "Add to Favorite" + ' + 'BTT_FEED_ADD_SPEC + ' + Me.BTT_FEED_ADD_SPEC.Image = Global.SCrawler.My.Resources.Resources.RSSPic_512 + Me.BTT_FEED_ADD_SPEC.Name = "BTT_FEED_ADD_SPEC" + Me.BTT_FEED_ADD_SPEC.Size = New System.Drawing.Size(305, 22) + Me.BTT_FEED_ADD_SPEC.Text = "Add to special feed..." + ' + 'BTT_FEED_REMOVE_FAV + ' + Me.BTT_FEED_REMOVE_FAV.Image = Global.SCrawler.My.Resources.Resources.DeletePic_24 + Me.BTT_FEED_REMOVE_FAV.Name = "BTT_FEED_REMOVE_FAV" + Me.BTT_FEED_REMOVE_FAV.Size = New System.Drawing.Size(305, 22) + Me.BTT_FEED_REMOVE_FAV.Text = "Remove from Favorite" + ' + 'BTT_FEED_REMOVE_SPEC + ' + Me.BTT_FEED_REMOVE_SPEC.Image = Global.SCrawler.My.Resources.Resources.DeletePic_24 + Me.BTT_FEED_REMOVE_SPEC.Name = "BTT_FEED_REMOVE_SPEC" + Me.BTT_FEED_REMOVE_SPEC.Size = New System.Drawing.Size(305, 22) + Me.BTT_FEED_REMOVE_SPEC.Text = "Remove from special feed..." + ' + 'CONTEXT_SEP_3 + ' + Me.CONTEXT_SEP_3.Name = "CONTEXT_SEP_3" + Me.CONTEXT_SEP_3.Size = New System.Drawing.Size(302, 6) + ' 'BTT_CONTEXT_FIND_USER ' Me.BTT_CONTEXT_FIND_USER.Image = Global.SCrawler.My.Resources.Resources.InfoPic_32 Me.BTT_CONTEXT_FIND_USER.Name = "BTT_CONTEXT_FIND_USER" - Me.BTT_CONTEXT_FIND_USER.Size = New System.Drawing.Size(220, 22) + Me.BTT_CONTEXT_FIND_USER.Size = New System.Drawing.Size(305, 22) Me.BTT_CONTEXT_FIND_USER.Text = "Find user" ' 'BTT_CONTEXT_INFO ' Me.BTT_CONTEXT_INFO.Image = Global.SCrawler.My.Resources.Resources.InfoPic_32 Me.BTT_CONTEXT_INFO.Name = "BTT_CONTEXT_INFO" - Me.BTT_CONTEXT_INFO.Size = New System.Drawing.Size(220, 22) + Me.BTT_CONTEXT_INFO.Size = New System.Drawing.Size(305, 22) Me.BTT_CONTEXT_INFO.Text = "Information" ' - 'CONTEXT_SEP_3 + 'CONTEXT_SEP_4 ' - Me.CONTEXT_SEP_3.Name = "CONTEXT_SEP_3" - Me.CONTEXT_SEP_3.Size = New System.Drawing.Size(217, 6) + Me.CONTEXT_SEP_4.Name = "CONTEXT_SEP_4" + Me.CONTEXT_SEP_4.Size = New System.Drawing.Size(302, 6) ' 'BTT_CONTEXT_DELETE ' Me.BTT_CONTEXT_DELETE.Image = Global.SCrawler.My.Resources.Resources.DeletePic_24 Me.BTT_CONTEXT_DELETE.Name = "BTT_CONTEXT_DELETE" - Me.BTT_CONTEXT_DELETE.Size = New System.Drawing.Size(220, 22) + Me.BTT_CONTEXT_DELETE.Size = New System.Drawing.Size(305, 22) Me.BTT_CONTEXT_DELETE.Text = "Delete" ' 'ICON_SITE @@ -217,38 +252,19 @@ Namespace DownloadObjects Me.LBL_TITLE.Size = New System.Drawing.Size(140, 25) Me.LBL_TITLE.TabIndex = 1 ' - 'CONTEXT_SEP_4 + 'BTT_FEED_ADD_FAV_REMOVE ' - Me.CONTEXT_SEP_4.Name = "CONTEXT_SEP_4" - Me.CONTEXT_SEP_4.Size = New System.Drawing.Size(217, 6) + Me.BTT_FEED_ADD_FAV_REMOVE.Image = Global.SCrawler.My.Resources.Resources.HeartPic_32 + Me.BTT_FEED_ADD_FAV_REMOVE.Name = "BTT_FEED_ADD_FAV_REMOVE" + Me.BTT_FEED_ADD_FAV_REMOVE.Size = New System.Drawing.Size(305, 22) + Me.BTT_FEED_ADD_FAV_REMOVE.Text = "Add to Favorite (remove from current)" ' - 'BTT_FEED_ADD_FAV + 'BTT_FEED_ADD_SPEC_REMOVE ' - Me.BTT_FEED_ADD_FAV.Image = Global.SCrawler.My.Resources.Resources.HeartPic_32 - Me.BTT_FEED_ADD_FAV.Name = "BTT_FEED_ADD_FAV" - Me.BTT_FEED_ADD_FAV.Size = New System.Drawing.Size(220, 22) - Me.BTT_FEED_ADD_FAV.Text = "Add to Favorite" - ' - 'BTT_FEED_ADD_SPEC - ' - Me.BTT_FEED_ADD_SPEC.Image = Global.SCrawler.My.Resources.Resources.RSSPic_512 - Me.BTT_FEED_ADD_SPEC.Name = "BTT_FEED_ADD_SPEC" - Me.BTT_FEED_ADD_SPEC.Size = New System.Drawing.Size(220, 22) - Me.BTT_FEED_ADD_SPEC.Text = "Add to special feed..." - ' - 'BTT_FEED_REMOVE_FAV - ' - Me.BTT_FEED_REMOVE_FAV.Image = Global.SCrawler.My.Resources.Resources.DeletePic_24 - Me.BTT_FEED_REMOVE_FAV.Name = "BTT_FEED_REMOVE_FAV" - Me.BTT_FEED_REMOVE_FAV.Size = New System.Drawing.Size(220, 22) - Me.BTT_FEED_REMOVE_FAV.Text = "Remove from Favorite" - ' - 'BTT_FEED_REMOVE_SPEC - ' - Me.BTT_FEED_REMOVE_SPEC.Image = Global.SCrawler.My.Resources.Resources.DeletePic_24 - Me.BTT_FEED_REMOVE_SPEC.Name = "BTT_FEED_REMOVE_SPEC" - Me.BTT_FEED_REMOVE_SPEC.Size = New System.Drawing.Size(220, 22) - Me.BTT_FEED_REMOVE_SPEC.Text = "Remove from special feed..." + Me.BTT_FEED_ADD_SPEC_REMOVE.Image = Global.SCrawler.My.Resources.Resources.RSSPic_512 + Me.BTT_FEED_ADD_SPEC_REMOVE.Name = "BTT_FEED_ADD_SPEC_REMOVE" + Me.BTT_FEED_ADD_SPEC_REMOVE.Size = New System.Drawing.Size(305, 22) + Me.BTT_FEED_ADD_SPEC_REMOVE.Text = "Add to special feed (remove from current)..." ' 'FeedMedia ' @@ -292,5 +308,7 @@ Namespace DownloadObjects Private WithEvents BTT_FEED_REMOVE_FAV As ToolStripMenuItem Private WithEvents BTT_FEED_REMOVE_SPEC As ToolStripMenuItem Private WithEvents CONTEXT_SEP_4 As ToolStripSeparator + Private WithEvents BTT_FEED_ADD_FAV_REMOVE As ToolStripMenuItem + Private WithEvents BTT_FEED_ADD_SPEC_REMOVE As ToolStripMenuItem 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 fecb676..f1665a6 100644 --- a/SCrawler/Download/Feed/FeedMedia.vb +++ b/SCrawler/Download/Feed/FeedMedia.vb @@ -17,6 +17,7 @@ Namespace DownloadObjects #Region "Events" Friend Event MediaDeleted(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) #End Region #Region "Declarations" Private Const VideoHeight As Integer = 450 @@ -74,7 +75,7 @@ Namespace DownloadObjects Private ReadOnly Property IsSubscription As Boolean = False Private Function GetImageResize(ByVal Width As Integer, ByVal Height As Integer) As Size If Height > 0 Then - Dim h% = Height = ObjectsPaddingHeight + Dim h% = Height - ObjectsPaddingHeight If h <= 0 Then h = Height Dim s As Size = MyImage.FitToHeightF(h) s = MyImage.FitToWidthF(s, Width, False) @@ -191,8 +192,7 @@ Namespace DownloadObjects End With If Not imgFile.Exists Then Settings.Cache.Validate() - GetWebFile(Media.Data.URL, imgFile, EDP.None) - If imgFile.Exists Then File = ConvertWebp(imgFile) + If GetWebFile(Media.Data.URL, imgFile, EDP.None) AndAlso imgFile.Exists Then File = ConvertWebp(imgFile) Else File = imgFile End If @@ -228,7 +228,12 @@ Namespace DownloadObjects Case UserMedia.Types.Picture, UserMedia.Types.GIF Dim tmpMediaFile As SFile = ConvertWebp(File, True) If tmpMediaFile.IsEmptyString Then Throw New ArgumentNullException With {.HelpLink = 1} - MyImage = New ImageRenderer(tmpMediaFile) + Try + MyImage = New ImageRenderer(tmpMediaFile, EDP.ThrowException) + Catch + MyImage.DisposeIfReady + MyImage = New ImageRenderer(New Bitmap(10, 10)) + End Try Dim a As AnchorStyles = AnchorStyles.Top + If(Height > 0, 0, AnchorStyles.Left) s = GetImageResize(Width, Height) h = s.Height @@ -314,6 +319,7 @@ Namespace DownloadObjects For Each fItem As FeedSpecial In .Self If Not fItem.IsFavorite Then DownloadFeedForm.AddNewFeedItem(BTT_FEED_ADD_SPEC, CONTEXT_DATA, fItem, Nothing, AddressOf Feed_SPEC_ADD) + DownloadFeedForm.AddNewFeedItem(BTT_FEED_ADD_SPEC_REMOVE, CONTEXT_DATA, fItem, Nothing, AddressOf Feed_SPEC_ADD_REMOVE) DownloadFeedForm.AddNewFeedItem(BTT_FEED_REMOVE_SPEC, CONTEXT_DATA, fItem, Nothing, AddressOf Feed_SPEC_REMOVE) End If Next @@ -333,6 +339,7 @@ Namespace DownloadObjects #Region "Feed handlers" Private Sub Feed_FeedAdded(ByVal Source As FeedSpecialCollection, ByVal Feed As FeedSpecial) DownloadFeedForm.AddNewFeedItem(BTT_FEED_ADD_SPEC, CONTEXT_DATA, Feed, My.Resources.RSSPic_512, AddressOf Feed_SPEC_ADD, True) + DownloadFeedForm.AddNewFeedItem(BTT_FEED_ADD_SPEC_REMOVE, CONTEXT_DATA, Feed, My.Resources.RSSPic_512, AddressOf Feed_SPEC_ADD_REMOVE, True) DownloadFeedForm.AddNewFeedItem(BTT_FEED_REMOVE_SPEC, CONTEXT_DATA, Feed, My.Resources.RSSPic_512, AddressOf Feed_SPEC_REMOVE, True) End Sub Private Sub Feed_FeedRemoved(ByVal Source As FeedSpecialCollection, ByVal Feed As FeedSpecial) @@ -340,12 +347,20 @@ Namespace DownloadObjects DownloadFeedForm.Feed_FeedRemoved(BTT_FEED_REMOVE_SPEC, CONTEXT_DATA, Feed) End Sub Private Sub Feed_SPEC_ADD(ByVal Source As ToolStripMenuItem, ByVal e As EventArgs) + Feed_SPEC_ADD_Impl(Source) + End Sub + Private Function Feed_SPEC_ADD_Impl(ByVal Source As ToolStripMenuItem) As FeedSpecial Dim f As FeedSpecial = Source.Tag - If Not f Is Nothing AndAlso Not f.Disposed Then f.Add(Media) + If Not f Is Nothing AndAlso Not f.Disposed Then f.Add(Media) : Return f + Return Nothing + End Function + Private Sub Feed_SPEC_ADD_REMOVE(ByVal Source As ToolStripMenuItem, ByVal e As EventArgs) + Dim f As FeedSpecial = Feed_SPEC_ADD_Impl(Source) + If Not f Is Nothing Then RaiseEvent FeedAddWithRemove(Me, {f.Name}, Media, False) End Sub Private Sub Feed_SPEC_REMOVE(ByVal Source As ToolStripMenuItem, ByVal e As EventArgs) Dim f As FeedSpecial = Source.Tag - If Not f Is Nothing AndAlso Not f.Disposed Then f.Remove(Media) + If Not f Is Nothing AndAlso Not f.Disposed Then f.Remove(Media) : RaiseEvent FeedAddWithRemove(Me, {f.Name}, Media, True) End Sub #End Region #Region "Dispose" @@ -464,26 +479,34 @@ Namespace DownloadObjects End Sub #End Region #Region "Feed" - Private Sub BTT_FEED_ADD_FAV_Click(sender As Object, e As EventArgs) Handles BTT_FEED_ADD_FAV.Click + Private Sub BTT_FEED_ADD_FAV_Click(sender As Object, e As EventArgs) Handles BTT_FEED_ADD_FAV.Click, BTT_FEED_ADD_FAV_REMOVE.Click With Settings.Feeds.Favorite If Not .Contains(Media) Then .Add(Media) BTT_FEED_ADD_FAV.ControlChangeColor(True, False) + If sender Is BTT_FEED_ADD_FAV_REMOVE Then RaiseEvent FeedAddWithRemove(Me, {FeedSpecial.FavoriteName}, Media, False) End With End Sub - Private Sub BTT_FEED_ADD_SPEC_Click(sender As Object, e As EventArgs) Handles BTT_FEED_ADD_SPEC.Click + Private Sub BTT_FEED_ADD_SPEC_Click(sender As Object, e As EventArgs) Handles BTT_FEED_ADD_SPEC.Click, BTT_FEED_ADD_SPEC_REMOVE.Click With FeedSpecialCollection.ChooseFeeds(True) - If .ListExists Then .ForEach(Sub(f) f.Add(Media)) + If .ListExists Then + .ForEach(Sub(f) f.Add(Media)) + If sender Is BTT_FEED_ADD_SPEC_REMOVE Then RaiseEvent FeedAddWithRemove(Me, .Select(Function(f) f.Name), Media, False) + End If End With End Sub Private Sub BTT_FEED_REMOVE_FAV_Click(sender As Object, e As EventArgs) Handles BTT_FEED_REMOVE_FAV.Click With Settings.Feeds.Favorite If .Contains(Media) Then .Remove(Media) BTT_FEED_ADD_FAV.ControlChangeColor(True) + RaiseEvent FeedAddWithRemove(Me, {FeedSpecial.FavoriteName}, Media, True) End With End Sub Private Sub BTT_FEED_REMOVE_SPEC_Click(sender As Object, e As EventArgs) Handles BTT_FEED_REMOVE_SPEC.Click With FeedSpecialCollection.ChooseFeeds(False) - If .ListExists Then .ForEach(Sub(f) f.Remove(Media)) + If .ListExists Then + .ForEach(Sub(f) f.Remove(Media)) + RaiseEvent FeedAddWithRemove(Me, .Select(Function(f) f.Name), Media, True) + End If End With End Sub #End Region diff --git a/SCrawler/Download/Feed/FeedSpecialCollection.vb b/SCrawler/Download/Feed/FeedSpecialCollection.vb index 74e750e..5bc122b 100644 --- a/SCrawler/Download/Feed/FeedSpecialCollection.vb +++ b/SCrawler/Download/Feed/FeedSpecialCollection.vb @@ -8,6 +8,7 @@ ' but WITHOUT ANY WARRANTY Imports PersonalUtilities.Tools Imports PersonalUtilities.Forms +Imports ADB = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons Namespace DownloadObjects Friend Class FeedSpecialCollection : Implements IEnumerable(Of FeedSpecial), IMyEnumerator(Of FeedSpecial) #Region "Events" @@ -115,33 +116,41 @@ Namespace DownloadObjects End Sub Private Sub Feeds_FeedDeleted(ByVal Source As FeedSpecialCollection, ByVal Feed As FeedSpecial) RaiseEvent FeedRemoved(Me, Feed) - If Count > 0 Then Feeds.Remove(Feed) + If Count > 0 And Not Feed Is Nothing Then Feeds.Remove(Feed) End Sub #End Region #Region "ChooseFeeds" - Friend Shared Function ChooseFeeds(ByVal AllowAdd As Boolean) As List(Of FeedSpecial) + Friend Shared Function ChooseFeeds(ByVal AllowAdd As Boolean, Optional ByVal AdditText As String = Nothing, + Optional ByVal ReplaceOriginalText As Boolean = False) As List(Of FeedSpecial) Try Dim newFeed$ = String.Empty + If Not AdditText.IsEmptyString And Not ReplaceOriginalText Then AdditText = $" {AdditText}" Using f As New SimpleListForm(Of String)(Settings.Feeds.Select(Function(ff) ff.Name), Settings.Design) With { .DesignXMLNodeName = "FeedsChooserForm", .Icon = My.Resources.RSSIcon_32, - .FormText = "Feeds" + .FormText = $"{IIf(ReplaceOriginalText, String.Empty, "Feeds")}{AdditText}" } - If AllowAdd Then f.AddFunction = Sub(ByVal sender As Object, ByVal e As SimpleListFormEventArgs) - If newFeed.IsEmptyString Then - Dim nf$ = InputBoxE("Enter a new feed name:", "New feed") - If Not nf.IsEmptyString Then - If Settings.Feeds.ListExists(Function(ff) ff.Name.StringToLower = nf.ToLower) Then - MsgBoxE({$"A feed named '{nf}' already exists", "New feed"}, vbCritical) - Else - newFeed = nf - e.Item = nf - End If - Else - MsgBoxE({"You can only create one feed at a time", "New feed"}, vbCritical) - End If - End If - End Sub + If AllowAdd Then + f.Buttons = {ADB.Add, ADB.Clear} + f.AddFunction = Sub(ByVal sender As Object, ByVal e As SimpleListFormEventArgs) + If newFeed.IsEmptyString Then + Dim nf$ = InputBoxE("Enter a new feed name:", "New feed") + If Not nf.IsEmptyString Then + If Settings.Feeds.ListExists(Function(ff) ff.Name.StringToLower = nf.ToLower) Then + MsgBoxE({$"A feed named '{nf}' already exists", "New feed"}, vbCritical) + e.Result = False + Else + newFeed = nf + e.Item = nf + End If + Else + e.Result = False + End If + Else + MsgBoxE({"You can only create one feed at a time", "New feed"}, vbCritical) + End If + End Sub + End If If f.ShowDialog = DialogResult.OK AndAlso f.DataResult.Count > 0 Then If Not newFeed.IsEmptyString AndAlso f.DataResult.Contains(newFeed) Then Settings.Feeds.Add(newFeed) Return Settings.Feeds.Where(Function(ff) f.DataResult.Contains(ff.Name)).ToList @@ -174,7 +183,7 @@ Namespace DownloadObjects Feeds.Last.Save() i = Count - 1 Else - i = Feeds.FindIndex(Function(f) f.Name = Name) + i = IndexOf(Name) If i = -1 Then Feeds.Add(FeedSpecial.CreateSpecial(Name)) Feeds.Last.Save() @@ -184,7 +193,7 @@ Namespace DownloadObjects End If If i >= 0 Then Feeds.Sort(ComparerFeeds) - i = Feeds.FindIndex(Function(f) f.Name = Name) + i = IndexOf(Name) If i >= 0 Then RaiseEvent FeedAdded(Me, Feeds(i)) End If Return i @@ -194,11 +203,14 @@ Namespace DownloadObjects Dim i% = Feeds.IndexOf(Item) If i >= 0 Then With Feeds(i) + Dim name$ = .Name If .IsFavorite Then result = .Clear Else result = .Delete - If result Then + i = -1 + If Feeds.Count > 0 Then i = Feeds.FindIndex(Function(f) f.Name = name And Not f.IsFavorite) + If result And i >= 0 Then .Dispose() Feeds.RemoveAt(i) End If @@ -208,6 +220,12 @@ Namespace DownloadObjects Return result End Function #End Region +#Region "IndexOf" + Friend Function IndexOf(ByVal Name As String) As Integer + If Feeds.Count > 0 Then Return Feeds.FindIndex(Function(f) f.Name = Name) + Return -1 + End Function +#End Region #Region "UpdateUsers" Friend Sub UpdateUsers(ByVal InitialUser As UserInfo, ByVal NewUser As UserInfo) Try diff --git a/SCrawler/PluginsEnvironment/Hosts/PluginHost.vb b/SCrawler/PluginsEnvironment/Hosts/PluginHost.vb index 011a8b1..1f56337 100644 --- a/SCrawler/PluginsEnvironment/Hosts/PluginHost.vb +++ b/SCrawler/PluginsEnvironment/Hosts/PluginHost.vb @@ -12,7 +12,7 @@ Imports PersonalUtilities.Functions.XML Imports PersonalUtilities.Functions.XML.Objects Imports PersonalUtilities.Tools.WEB.GitHub Namespace Plugin.Hosts - Friend Class PluginHost + Friend Class PluginHost : Implements IDisposable Friend Const PluginsPath As String = "Plugins\" Friend ReadOnly Property Settings As SettingsHostCollection Friend ReadOnly Property Name As String @@ -123,5 +123,22 @@ Namespace Plugin.Hosts Return Nothing End Try End Function +#Region "IDisposable Support" + Private disposedValue As Boolean = False + Protected Overridable Overloads Sub Dispose(ByVal disposing As Boolean) + If Not disposedValue Then + If disposing Then Settings.Dispose() + disposedValue = True + End If + End Sub + Protected Overrides Sub Finalize() + Dispose(False) + MyBase.Finalize() + End Sub + Friend Overloads Sub Dispose() Implements IDisposable.Dispose + Dispose(True) + GC.SuppressFinalize(Me) + End Sub +#End Region End Class End Namespace \ No newline at end of file diff --git a/SCrawler/PluginsEnvironment/Hosts/SettingsHostCollection.vb b/SCrawler/PluginsEnvironment/Hosts/SettingsHostCollection.vb index a9dee00..38c0668 100644 --- a/SCrawler/PluginsEnvironment/Hosts/SettingsHostCollection.vb +++ b/SCrawler/PluginsEnvironment/Hosts/SettingsHostCollection.vb @@ -17,7 +17,7 @@ Imports Download = SCrawler.Plugin.ISiteSettings.Download Imports PauseModes = SCrawler.DownloadObjects.AutoDownloader.PauseModes Imports MsgBoxButton = PersonalUtilities.Functions.Messaging.MsgBoxButton Namespace Plugin.Hosts - Friend Class SettingsHostCollection : Implements IEnumerable(Of SettingsHost), IMyEnumerator(Of SettingsHost) + Friend Class SettingsHostCollection : Implements IEnumerable(Of SettingsHost), IMyEnumerator(Of SettingsHost), IDisposable #Region "Declarations" Private Const FileNamePrefix As String = "Host_" Private Const FileNamePattern As String = FileNamePrefix & "{0}_{1}_" @@ -437,6 +437,33 @@ Namespace Plugin.Hosts Private Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator Return GetEnumerator() End Function +#End Region +#Region "IDisposable Support" + Private disposedValue As Boolean = False + Protected Overridable Overloads Sub Dispose(ByVal disposing As Boolean) + If Not disposedValue Then + If disposing Then + Hosts.ListClearDispose(, False, EDP.SendToLog) + HostsUnavailableIndexes.Clear() + HostsXml.ListClearDispose(, False, EDP.SendToLog) + BTT_SETTINGS.DisposeIfReady + BTT_SETTINGS_SEP_1.DisposeIfReady + BTT_SETTINGS_ACTIONS_ADD.DisposeIfReady + End If + BTT_SETTINGS = Nothing + BTT_SETTINGS_SEP_1 = Nothing + BTT_SETTINGS_ACTIONS_ADD = Nothing + disposedValue = True + End If + End Sub + Protected Overrides Sub Finalize() + Dispose(False) + MyBase.Finalize() + End Sub + Friend Overloads Sub Dispose() Implements IDisposable.Dispose + Dispose(True) + GC.SuppressFinalize(Me) + End Sub #End Region End Class End Namespace \ No newline at end of file diff --git a/SCrawler/SettingsCLS.vb b/SCrawler/SettingsCLS.vb index c1fe436..842c2e2 100644 --- a/SCrawler/SettingsCLS.vb +++ b/SCrawler/SettingsCLS.vb @@ -217,7 +217,7 @@ Friend Class SettingsCLS : Implements IDownloaderSettings, IDisposable tplIndx = Plugins.FindIndex(Function(pl) pl.Key.StringToLower = tpl.Replacer.PluginKey.StringToLower Or pl.Name.StringToLower = tpl.Replacer.SiteName.StringToLower) If tplIndx >= 0 Then - Plugins(tplIndx).Settings.ListClearDispose + Plugins(tplIndx).Dispose() Plugins.RemoveAt(tplIndx) If Plugins.Count = 0 Then Exit For End If