From 82ef4f44104055cdcb2b56cfef594b6e45ab12fc Mon Sep 17 00:00:00 2001 From: Andy <88590076+AAndyProgram@users.noreply.github.com> Date: Mon, 19 Jun 2023 06:05:28 +0300 Subject: [PATCH] 2023.6.19.0 YT.Progress: make the playlists parsing progress more informative; change form display method YT.YouTubeMediaContainerBase: fix sort algo YT.Tray: add 'Add' button; add 'Ctrl+Click' on tray icon to add download YT.Settings: add setting 'Download on click in tray: show form' LPSG: some files didn't download (encoding) Twitter: hide cache deletion errors Mastogon: fixed bug in 'ReparseMissing' function Reddit: downloaded gifs are static XHamster: videos are not downloading or downloading incorrectly Progress: fix bugs; minor improvements --- Changelog.md | 20 + ProgramScreenshots/SavedPosts.png | Bin 30747 -> 34313 bytes ProgramScreenshots/SettingsSiteOnlyFans.png | Bin 0 -> 20623 bytes ProgramsComparison.md | 2 +- README.md | 5 +- SCrawler.YouTube/Base/YouTubeSettings.vb | 3 + .../Controls/ParsingProgressForm.Designer.vb | 1 - .../Controls/ParsingProgressForm.vb | 22 +- SCrawler.YouTube/Downloader/VideoListForm.vb | 22 +- SCrawler.YouTube/My Project/AssemblyInfo.vb | 4 +- .../Objects/YouTubeMediaContainerBase.vb | 11 +- .../MainFrame.Designer.vb | 23 +- SCrawler.YouTubeDownloader/MainFrame.resx | 3 + SCrawler.YouTubeDownloader/MainFrame.vb | 10 + .../My Project/AssemblyInfo.vb | 4 +- SCrawler/API/LPSG/Declarations.vb | 8 +- SCrawler/API/Mastodon/UserData.vb | 3 +- SCrawler/API/OnlyFans/Declarations.vb | 15 + SCrawler/API/OnlyFans/SiteSettings.vb | 165 ++++++++ SCrawler/API/OnlyFans/UserData.vb | 362 ++++++++++++++++++ SCrawler/API/Reddit/UserData.vb | 32 +- SCrawler/API/Twitter/UserData.vb | 3 +- SCrawler/API/Xhamster/UserData.vb | 8 +- .../Icons/SiteIcons/OnlyFansIcon_32.ico | Bin 0 -> 15086 bytes .../Pictures/SitePictures/OnlyFansPic_32.png | Bin 0 -> 1361 bytes .../Download/ActiveDownloadingProgress.vb | 21 +- SCrawler/Download/DownloadProgress.vb | 25 +- SCrawler/My Project/AssemblyInfo.vb | 4 +- SCrawler/MyProgressExt.vb | 71 ++-- .../PluginsEnvironment/Hosts/PluginHost.vb | 3 +- SCrawler/SCrawler.vbproj | 9 + SCrawler/SiteResources.Designer.vb | 20 + SCrawler/SiteResources.resx | 6 + 33 files changed, 780 insertions(+), 105 deletions(-) create mode 100644 ProgramScreenshots/SettingsSiteOnlyFans.png create mode 100644 SCrawler/API/OnlyFans/Declarations.vb create mode 100644 SCrawler/API/OnlyFans/SiteSettings.vb create mode 100644 SCrawler/API/OnlyFans/UserData.vb create mode 100644 SCrawler/Content/Icons/SiteIcons/OnlyFansIcon_32.ico create mode 100644 SCrawler/Content/Pictures/SitePictures/OnlyFansPic_32.png diff --git a/Changelog.md b/Changelog.md index 3d97a09..247c90a 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,23 @@ +# 2023.6.19.0 + +*2023-06-19* + +- Added + - **OnlyFans** + - YouTube: make the playlists parsing progress more informative + - YouTube: add `Add` button to tray + - YouTube: add `Ctrl+Click` on tray icon to add download + - YouTube: add setting `Download on click in tray: show form` + - Minor improvements to progress bars + - Other improvements +- Fixed + - YouTube: incorrect sorting algorithm + - LPSG: some files didn't download + - Reddit: downloaded gifs are static (Issue #141) + - xHamster: videos are not downloading or downloading incorrectly (Issue #144) + - Progress bar bugs + - Minor bugs + # 2023.6.9.0 *2023-06-09* diff --git a/ProgramScreenshots/SavedPosts.png b/ProgramScreenshots/SavedPosts.png index a86a4885c0099d6dbd158e70de0c30a604a678ca..6f2e61f6676f019db7ec3888bdaf991027626c82 100644 GIT binary patch literal 34313 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 literal 30747 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 G?*9QKhl|Dl diff --git a/ProgramScreenshots/SettingsSiteOnlyFans.png b/ProgramScreenshots/SettingsSiteOnlyFans.png new file mode 100644 index 0000000000000000000000000000000000000000..6603b68c8267f1d4f78d8a55cdd24b0bd9f4c8c5 GIT binary patch literal 20623 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 f%4aDtyX;+dv5eno+`vx`Qc)?%t0VJdZ$JJ&2D; Public ReadOnly Property ExitConfirm As XMLValue(Of Boolean) + + Public ReadOnly Property ShowFormDownTrayClick As XMLValue(Of Boolean) #End Region #Region "Defaults Video" 1 Then + Return $"{MainMsg} [{CountCurrent - 1}/{CountMax}]" + Else + Return MainMsg + End If + End Get + End Property + Public Sub New(Optional ByVal _Count As Integer = 1) InitializeComponent() - MyProgress = New MyProgress(PR_MAIN, LBL_MAIN, "Data parsing in progress") With {.ResetProgressOnMaximumChanges = False} + CountMax = _Count + MyProgress = New MyProgress(PR_MAIN, LBL_MAIN, InfoStr) With {.ResetProgressOnMaximumChanges = False} TokenSource = New CancellationTokenSource End Sub Public Sub SetInitialValues(ByVal Count As Integer, ByVal Info As String) diff --git a/SCrawler.YouTube/Downloader/VideoListForm.vb b/SCrawler.YouTube/Downloader/VideoListForm.vb index 7548a32..c25aec2 100644 --- a/SCrawler.YouTube/Downloader/VideoListForm.vb +++ b/SCrawler.YouTube/Downloader/VideoListForm.vb @@ -237,6 +237,7 @@ Namespace DownloadObjects.STDownloader Dim pForm As ParsingProgressForm = Nothing Try Dim useCookies As Boolean = MyYouTubeSettings.DefaultUseCookies + Dim sTag$ = If(Sender?.Tag, String.Empty) Dim disableDown As Boolean = e.Shift If e.Control Then useCookies = True Dim useCookiesParse As Boolean? = Nothing @@ -247,21 +248,28 @@ Namespace DownloadObjects.STDownloader Dim GetDefault As Boolean = True Dim GetShorts As Boolean = True - If Sender.Tag = "pls" Then + If sTag = "pls" Then Using pf As New PlaylistArrayForm With {.DesignXML = DesignXML} pf.ShowDialog() If pf.DialogResult = DialogResult.OK Then With pf.URLs If .Count > 0 Then - pForm = New ParsingProgressForm - pForm.Show() + pForm = New ParsingProgressForm(.Count) + pForm.Show(Me) pForm.SetInitialValues(.Count, "Parsing playlists...") Dim containers As New List(Of IYouTubeMediaContainer) - For Each u$ In .Self : containers.Add(YouTubeFunctions.Parse(u, useCookiesParse, pForm.Token, pForm.MyProgress, True, False)) : pForm.MyProgress.Perform() : Next + For Each u$ In .Self + containers.Add(YouTubeFunctions.Parse(u, useCookiesParse, pForm.Token, pForm.MyProgress, True, False)) + pForm.NextPlaylist() + pForm.MyProgress.Perform() + Next pForm.Dispose() If containers.Count > 0 Then containers.ListDisposeRemoveAll(Function(cc) cc.HasError Or Not cc.Exists) If containers.Count > 0 Then - c = New Channel With {.UserTitle = IIf(pf.IsOneArtist, containers(0).UserTitle, "Playlists")} + c = New Channel With { + .UserTitle = IIf(pf.IsOneArtist, containers(0).UserTitle, "Playlists"), + .IsMusic = containers.Any(Function(cc) cc.IsMusic) + } c.Elements.AddRange(containers) End If End If @@ -269,7 +277,7 @@ Namespace DownloadObjects.STDownloader End If End Using Else - Select Case CStr(Sender.Tag) + Select Case sTag Case "ans" : GetShorts = False Case "as" : GetDefault = False : GetShorts = True End Select @@ -280,7 +288,7 @@ Namespace DownloadObjects.STDownloader If Not c Is Nothing OrElse YouTubeFunctions.IsMyUrl(url) Then If c Is Nothing Then pForm = New ParsingProgressForm - pForm.Show() + pForm.Show(Me) pForm.SetInitialValues(1, "Parsing data...") c = YouTubeFunctions.Parse(url, useCookiesParse, pForm.Token, pForm.MyProgress, GetDefault, GetShorts) pForm.Dispose() diff --git a/SCrawler.YouTube/My Project/AssemblyInfo.vb b/SCrawler.YouTube/My Project/AssemblyInfo.vb index c74fed3..ed53f87 100644 --- a/SCrawler.YouTube/My Project/AssemblyInfo.vb +++ b/SCrawler.YouTube/My Project/AssemblyInfo.vb @@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices ' by using the '*' as shown below: ' - - + + diff --git a/SCrawler.YouTube/Objects/YouTubeMediaContainerBase.vb b/SCrawler.YouTube/Objects/YouTubeMediaContainerBase.vb index ac3ba3c..c63bed4 100644 --- a/SCrawler.YouTube/Objects/YouTubeMediaContainerBase.vb +++ b/SCrawler.YouTube/Objects/YouTubeMediaContainerBase.vb @@ -22,17 +22,8 @@ Imports UMStates = SCrawler.Plugin.UserMediaStates Imports CollectionModes = PersonalUtilities.Functions.XML.Objects.IXMLValuesCollection.Modes Namespace API.YouTube.Objects Public Class ContainerDateComparer : Implements IComparer(Of IYouTubeMediaContainer) - Private ReadOnly NullDateValue As New Date Public Function Compare(ByVal x As IYouTubeMediaContainer, ByVal y As IYouTubeMediaContainer) As Integer Implements IComparer(Of IYouTubeMediaContainer).Compare - If x.DateDownloaded = NullDateValue And y.DateDownloaded = NullDateValue Then - Return x.DateCreated.CompareTo(y.DateCreated) * -1 - ElseIf x.DateDownloaded = NullDateValue Then - Return -1 - ElseIf y.DateDownloaded = NullDateValue Then - Return 1 - Else - Return x.DateDownloaded.CompareTo(y.DateDownloaded) * -1 - End If + Return x.DateCreated.CompareTo(y.DateCreated) * -1 End Function End Class Public MustInherit Class YouTubeMediaContainerBase : Implements IYouTubeMediaContainer diff --git a/SCrawler.YouTubeDownloader/MainFrame.Designer.vb b/SCrawler.YouTubeDownloader/MainFrame.Designer.vb index bc7fecb..7393dae 100644 --- a/SCrawler.YouTubeDownloader/MainFrame.Designer.vb +++ b/SCrawler.YouTubeDownloader/MainFrame.Designer.vb @@ -20,9 +20,12 @@ Partial Public Class MainFrame : Inherits SCrawler.DownloadObjects.STDownloader. Private Sub InitializeComponent() Me.components = New System.ComponentModel.Container() Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(MainFrame)) + Dim CONTEXT_SEP_1 As System.Windows.Forms.ToolStripSeparator Me.TRAY_ICON = New System.Windows.Forms.NotifyIcon(Me.components) Me.TRAY_CONTEXT = New System.Windows.Forms.ContextMenuStrip(Me.components) Me.BTT_TRAY_CLOSE = New System.Windows.Forms.ToolStripMenuItem() + Me.CONTEXT_BTT_ADD = New PersonalUtilities.Forms.Controls.KeyClick.ToolStripMenuItemKeyClick() + CONTEXT_SEP_1 = New System.Windows.Forms.ToolStripSeparator() Me.TRAY_CONTEXT.SuspendLayout() Me.SuspendLayout() ' @@ -32,13 +35,13 @@ Partial Public Class MainFrame : Inherits SCrawler.DownloadObjects.STDownloader. Me.TRAY_ICON.BalloonTipTitle = "YouTube Downloader" Me.TRAY_ICON.ContextMenuStrip = Me.TRAY_CONTEXT Me.TRAY_ICON.Icon = CType(resources.GetObject("TRAY_ICON.Icon"), System.Drawing.Icon) - Me.TRAY_ICON.Text = "YouTube Downloader" + Me.TRAY_ICON.Text = "YouTube Downloader" & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Ctrl+Click to add download" ' 'TRAY_CONTEXT ' - Me.TRAY_CONTEXT.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_TRAY_CLOSE}) + Me.TRAY_CONTEXT.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.CONTEXT_BTT_ADD, CONTEXT_SEP_1, Me.BTT_TRAY_CLOSE}) Me.TRAY_CONTEXT.Name = "ContextMenuStrip1" - Me.TRAY_CONTEXT.Size = New System.Drawing.Size(181, 48) + Me.TRAY_CONTEXT.Size = New System.Drawing.Size(181, 76) ' 'BTT_TRAY_CLOSE ' @@ -47,11 +50,24 @@ Partial Public Class MainFrame : Inherits SCrawler.DownloadObjects.STDownloader. Me.BTT_TRAY_CLOSE.Size = New System.Drawing.Size(180, 22) Me.BTT_TRAY_CLOSE.Text = "Close" ' + 'CONTEXT_BTT_ADD + ' + Me.CONTEXT_BTT_ADD.Name = "CONTEXT_BTT_ADD" + Me.CONTEXT_BTT_ADD.Size = New System.Drawing.Size(180, 22) + Me.CONTEXT_BTT_ADD.Text = "Add" + Me.CONTEXT_BTT_ADD.Image = Global.PersonalUtilities.My.Resources.PlusPic_Green_24 + ' + 'CONTEXT_SEP_1 + ' + CONTEXT_SEP_1.Name = "CONTEXT_SEP_1" + CONTEXT_SEP_1.Size = New System.Drawing.Size(177, 6) + ' 'MainFrame ' Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!) Me.ClientSize = New System.Drawing.Size(1008, 729) Me.Name = "MainFrame" + Me.Text = "SCrawler: Happy LGBT Pride Month! :-)" Me.TRAY_CONTEXT.ResumeLayout(False) Me.ResumeLayout(False) Me.PerformLayout() @@ -61,4 +77,5 @@ Partial Public Class MainFrame : Inherits SCrawler.DownloadObjects.STDownloader. Private WithEvents TRAY_ICON As NotifyIcon Private WithEvents TRAY_CONTEXT As ContextMenuStrip Private WithEvents BTT_TRAY_CLOSE As ToolStripMenuItem + Private WithEvents CONTEXT_BTT_ADD As PersonalUtilities.Forms.Controls.KeyClick.ToolStripMenuItemKeyClick End Class \ No newline at end of file diff --git a/SCrawler.YouTubeDownloader/MainFrame.resx b/SCrawler.YouTubeDownloader/MainFrame.resx index cbd1fc6..9d327fb 100644 --- a/SCrawler.YouTubeDownloader/MainFrame.resx +++ b/SCrawler.YouTubeDownloader/MainFrame.resx @@ -123,6 +123,9 @@ 425, 17 + + False + diff --git a/SCrawler.YouTubeDownloader/MainFrame.vb b/SCrawler.YouTubeDownloader/MainFrame.vb index edd400e..07de683 100644 --- a/SCrawler.YouTubeDownloader/MainFrame.vb +++ b/SCrawler.YouTubeDownloader/MainFrame.vb @@ -9,6 +9,7 @@ Imports System.ComponentModel Imports SCrawler.API.YouTube Imports PersonalUtilities.Forms +Imports PersonalUtilities.Forms.Controls.KeyClick Public Class MainFrame Private WithEvents MyActivator As FormActivator Public Sub New() @@ -66,6 +67,12 @@ CloseResume: Private Sub BTT_TRAY_CLOSE_Click(sender As Object, e As EventArgs) Handles BTT_TRAY_CLOSE.Click If CheckForClose(False) Then _IgnoreCloseConfirm = True : _IgnoreTrayOptions = True : Close() End Sub + Private Sub MyActivator_TrayIconClick(ByVal Sender As Object, ByVal e As KeyClickEventArgs) Handles MyActivator.TrayIconClick + If e.MouseButton = MouseButtons.Left And e.Control Then + BTT_ADD_KeyClick(Nothing, New KeyClickEventArgs) + e.Handled = Not MyYouTubeSettings.ShowFormDownTrayClick + End If + End Sub Private Function CheckForClose(ByVal _Ignore As Boolean) As Boolean If MyYouTubeSettings.ExitConfirm And Not _Ignore Then Return MsgBoxE({"Do you want to close the program?", "Closing the program"}, MsgBoxStyle.YesNo) = MsgBoxResult.Yes @@ -77,6 +84,9 @@ CloseResume: MyBase.BTT_SETTINGS_Click(sender, e) TRAY_ICON.Visible = MyYouTubeSettings.CloseToTray End Sub + Protected Overrides Sub BTT_ADD_KeyClick(ByVal Sender As ToolStripMenuItemKeyClick, ByVal e As KeyClickEventArgs) Handles CONTEXT_BTT_ADD.KeyClick + MyBase.BTT_ADD_KeyClick(Sender, e) + End Sub Protected Overrides Sub MyJob_Started(ByVal Sender As Object, ByVal e As EventArgs) TRAY_ICON.Icon = My.Resources.ArrowDownIcon_Orange_24 End Sub diff --git a/SCrawler.YouTubeDownloader/My Project/AssemblyInfo.vb b/SCrawler.YouTubeDownloader/My Project/AssemblyInfo.vb index 5ebb707..3ff188f 100644 --- a/SCrawler.YouTubeDownloader/My Project/AssemblyInfo.vb +++ b/SCrawler.YouTubeDownloader/My Project/AssemblyInfo.vb @@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices ' by using the '*' as shown below: ' - - + + diff --git a/SCrawler/API/LPSG/Declarations.vb b/SCrawler/API/LPSG/Declarations.vb index 1c5a36c..99f9541 100644 --- a/SCrawler/API/LPSG/Declarations.vb +++ b/SCrawler/API/LPSG/Declarations.vb @@ -19,7 +19,10 @@ Namespace API.LPSG Friend ReadOnly Property NextPageRegex As RParams = RParams.DMS(" + Friend Class SiteSettings : Inherits SiteSettingsBase +#Region "Icon" + Friend Overrides ReadOnly Property Icon As Icon + Get + Return My.Resources.SiteResources.OnlyFansIcon_32 + End Get + End Property + Friend Overrides ReadOnly Property Image As Image + Get + Return My.Resources.SiteResources.OnlyFansPic_32 + End Get + End Property +#End Region +#Region "Declarations" + Private Const HeaderBrowser As String = "sec-ch-ua" + Private Const HeaderUserID As String = "User-Id" + Private Const HeaderXBC As String = "X-Bc" + Private Const HeaderAppToken As String = "App-Token" + + Friend ReadOnly Property HH_USER_ID As PropertyValue + + Private ReadOnly Property HH_X_BC As PropertyValue + + Private ReadOnly Property HH_APP_TOKEN As PropertyValue + + Private ReadOnly Property HH_BROWSER As PropertyValue + + Private ReadOnly Property UserAgent As PropertyValue + Private Sub UpdateHeader(ByVal PropertyName As String, ByVal Value As String) + Dim hName$ = String.Empty + Dim isUserAgent As Boolean = False + Select Case PropertyName + Case NameOf(HH_USER_ID) : hName = HeaderUserID + Case NameOf(HH_X_BC) : hName = HeaderXBC + Case NameOf(HH_APP_TOKEN) : hName = HeaderAppToken + Case NameOf(HH_BROWSER) : hName = HeaderBrowser + Case NameOf(UserAgent) : isUserAgent = True + End Select + If Not hName.IsEmptyString Then + Responser.Headers.Add(hName, Value) + ElseIf isUserAgent Then + Responser.UserAgent = Value + End If + End Sub + Private ReadOnly Property LastDateUpdated_XML As PropertyValue + Friend Property LastDateUpdated As Date + Get + Return LastDateUpdated_XML.Value + End Get + Set(ByVal d As Date) + LastDateUpdated_XML.Value = d + End Set + End Property + + Friend ReadOnly Property UseOldAuthRules As PropertyValue + + Friend ReadOnly Property DynamicRulesUpdateInterval As PropertyValue + + Private ReadOnly Property DynamicRulesUpdateIntervalProvider As IFormatProvider + + Friend ReadOnly Property DynamicRules As PropertyValue +#End Region +#Region "Initializer" + Friend Sub New() + MyBase.New("OnlyFans", ".onlyfans.com") + + With Responser + .Accept = "application/json, text/plain, */*" + .AutomaticDecompression = Net.DecompressionMethods.GZip + .CookiesExtractMode = Responser.CookiesExtractModes.Any + .CookiesExtractedAutoSave = False + .CookiesUpdateMode = CookieKeeper.UpdateModes.Disabled + .Cookies.ChangedAllowInternalDrop = False + .Cookies.Changed = False + With .Headers + .Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecChUaPlatform)) + .Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecChUaMobile)) + .Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecFetchDest)) + .Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecFetchMode)) + .Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecFetchSite)) + .Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.DHT)) + .Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.Authority, "onlyfans.com")) + .Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.AcceptEncoding)) + HH_USER_ID = New PropertyValue(.Value(HeaderUserID), GetType(String), Sub(v) UpdateHeader(NameOf(HH_USER_ID), v)) + HH_X_BC = New PropertyValue(.Value(HeaderXBC), GetType(String), Sub(v) UpdateHeader(NameOf(HH_X_BC), v)) + HH_APP_TOKEN = New PropertyValue(.Value(HeaderAppToken), GetType(String), Sub(v) UpdateHeader(NameOf(HH_APP_TOKEN), v)) + HH_BROWSER = New PropertyValue(.Value(HeaderBrowser), GetType(String), Sub(v) UpdateHeader(NameOf(HH_BROWSER), v)) + End With + UserAgent = New PropertyValue(IIf(.UserAgentExists, .UserAgent, String.Empty), GetType(String), Sub(v) UpdateHeader(NameOf(UserAgent), v)) + End With + + LastDateUpdated_XML = New PropertyValue(Now.AddYears(-1), GetType(Date)) + UseOldAuthRules = New PropertyValue(False) + DynamicRulesUpdateInterval = New PropertyValue(60 * 24) + DynamicRulesUpdateIntervalProvider = New FieldsCheckerProviderSimple(Function(v) IIf(AConvert(Of Integer)(v, 0) > 0, v, Nothing), + "The value of [{0}] field must be greater than 0") + DynamicRules = New PropertyValue(String.Empty, GetType(String)) + UserRegex = RParams.DMS("onlyfans.com/(\w+)", 1, EDP.ReturnValue) + UrlPatternUser = "https://onlyfans.com/{0}" + ImageVideoContains = "onlyfans.com" + End Sub +#End Region +#Region "GetInstance" + Friend Overrides Function GetInstance(ByVal What As ISiteSettings.Download) As IPluginContentProvider + Return New UserData + End Function +#End Region +#Region "Update" + Friend Overrides Sub Update() + If _SiteEditorFormOpened Then Responser.Cookies.Changed = False + MyBase.Update() + End Sub +#End Region +#Region "Download" + Friend Overrides Function BaseAuthExists() As Boolean + Return Responser.CookiesExists And {HH_USER_ID, HH_X_BC, HH_APP_TOKEN, HH_BROWSER, UserAgent}.All(Function(v) ACheck(v.Value)) + End Function + Friend Overrides Function ReadyToDownload(ByVal What As ISiteSettings.Download) As Boolean + Return BaseAuthExists() And Not SessionAborted + End Function + Friend Property SessionAborted As Boolean = False + Friend Overrides Sub AfterDownload(ByVal User As Object, ByVal What As ISiteSettings.Download) + Responser.Cookies.Update(DirectCast(User, UserData).CCookie) + End Sub + Friend Overrides Sub DownloadDone(ByVal What As ISiteSettings.Download) + MyBase.DownloadDone(What) + SessionAborted = False + If Responser.Cookies.Changed Then Responser.SaveCookies() : Responser.Cookies.Changed = False + End Sub +#End Region +#Region "GetUserUrl, GetUserPostUrl" + Friend Overrides Function GetUserUrl(ByVal User As IPluginContentProvider) As String + Return String.Format(UrlPatternUser, If(User.ID.IsEmptyString, User.Name, $"u{User.ID}")) + End Function + Friend Overrides Function GetUserPostUrl(ByVal User As UserDataBase, ByVal Media As UserMedia) As String + If Not Media.Post.ID.IsEmptyString Then + Return String.Format("https://onlyfans.com/{0}/{1}", Media.Post.ID, If(User.ID.IsEmptyString, User.Name, $"u{User.ID}")) + Else + Return String.Empty + End If + End Function +#End Region + End Class +End Namespace \ No newline at end of file diff --git a/SCrawler/API/OnlyFans/UserData.vb b/SCrawler/API/OnlyFans/UserData.vb new file mode 100644 index 0000000..e5c6dc8 --- /dev/null +++ b/SCrawler/API/OnlyFans/UserData.vb @@ -0,0 +1,362 @@ +' Copyright (C) 2023 Andy https://github.com/AAndyProgram +' This program is free software: you can redistribute it and/or modify +' it under the terms of the GNU General Public License as published by +' the Free Software Foundation, either version 3 of the License, or +' (at your option) any later version. +' +' This program is distributed in the hope that it will be useful, +' but WITHOUT ANY WARRANTY +Imports System.Threading +Imports SCrawler.API.Base +Imports SCrawler.API.YouTube.Objects +Imports PersonalUtilities.Functions.XML +Imports PersonalUtilities.Functions.RegularExpressions +Imports PersonalUtilities.Tools.Web.Clients +Imports PersonalUtilities.Tools.Web.Clients.EventArguments +Imports PersonalUtilities.Tools.Web.Cookies +Imports PersonalUtilities.Tools.Web.Documents.JSON +Imports UTypes = SCrawler.API.Base.UserMedia.Types +Imports UStates = SCrawler.API.Base.UserMedia.States +Namespace API.OnlyFans + Friend Class UserData : Inherits UserDataBase +#Region "Declarations" + Friend Property CCookie As CookieKeeper = Nothing + Private Const HeaderSign As String = "Sign" + Private Const HeaderTime As String = "Time" + Private ReadOnly Property MySettings As SiteSettings + Get + Return HOST.Source + End Get + End Property + Protected Overrides Sub LoadUserInformation_OptionalFields(ByRef Container As XmlFile, ByVal Loading As Boolean) + End Sub +#End Region +#Region "Download functions" + Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken) + If Not CCookie Is Nothing Then CCookie.Dispose() + CCookie = Responser.Cookies.Copy + Responser.Cookies.Clear() + AddHandler Responser.ResponseReceived, AddressOf OnResponseReceived + UpdateCookieHeader() + DownloadData(IIf(IsSavedPosts, 0, String.Empty), Token) + End Sub + Private Sub OnResponseReceived(ByVal Sender As Object, ByVal e As WebDataResponse) + If e.CookiesExists Then + CCookie.Update(e.Cookies, CookieKeeper.UpdateModes.ReplaceByNameAll,, EDP.ReturnValue) + UpdateCookieHeader() + End If + End Sub + Private Sub UpdateCookieHeader() + Responser.Headers.Add("Cookie", CCookie.ToString(False)) + End Sub + Private Const BaseUrlPattern As String = "https://onlyfans.com{0}" + Private Overloads Sub DownloadData(ByVal Cursor As String, ByVal Token As CancellationToken) + + Dim url$ = String.Empty + Dim _complete As Boolean = True + Do + Try + Dim tmpCursor$ = String.Empty + Dim hasMore As Boolean = False + Dim path$ = String.Empty + Dim postDate$, postID$ + Dim n As EContainer + Dim mediaList As List(Of UserMedia) + Dim mediaResult As Boolean + + If IsSavedPosts Then + path = $"/api2/v2/posts/bookmarks/all/?format=infinite&limit=10&offset={Cursor}" + Else + If ID.IsEmptyString Then GetUserID() + If ID.IsEmptyString Then Throw New ArgumentNullException("ID", "Unable to get user ID") + + path = $"/api2/v2/users/{ID}/posts/medias?limit=50&order=publish_date_desc&skip_users=all&format=infinite&counters=1" + If Not Cursor.IsEmptyString Then path &= $"&counters=0&beforePublishTime={Cursor}" Else path &= "&counters=1" + End If + + If UpdateSignature(path) Then + url = String.Format(BaseUrlPattern, path) + ThrowAny(Token) + + Dim r$ = Responser.GetResponse(url) + If Not r.IsEmptyString Then + Using j As EContainer = JsonDocument.Parse(r) + If j.ListExists Then + If IsSavedPosts Then + hasMore = j.Value("hasMore").FromXML(Of Boolean)(False) + Else + tmpCursor = j.Value("tailMarker") + hasMore = Not tmpCursor.IsEmptyString + End If + With j("list") + If .ListExists Then + ProgressPre.ChangeMax(.Count) + For Each n In .Self + ProgressPre.Perform() + postID = n.Value("id") + postDate = n.Value("postedAt") + + If Not _TempPostsList.Contains(postID) Then + _TempPostsList.Add(postID) + Else + Exit Sub + End If + + Select Case MyBase.CheckDatesLimit(postDate, DateProvider) + Case DateResult.Skip : Continue For + Case DateResult.Exit : Exit Sub + End Select + + mediaResult = False + mediaList = TryCreateMedia(n, postID, postDate, mediaResult) + If mediaResult Then _TempMediaList.ListAddList(mediaList, LNC) + Next + Else + hasMore = False + End If + End With + End If + End Using + End If + End If + + If hasMore Then + If IsSavedPosts Then tmpCursor = CInt(Cursor.IfNullOrEmpty(0)) + 10 + DownloadData(tmpCursor, Token) + End If + Catch ex As Exception + If ProcessException(ex, Token, $"data downloading error [{url}]") = 2 Then _complete = False + End Try + Loop While Not _complete + End Sub + Private Function TryCreateMedia(ByVal n As EContainer, ByVal PostID As String, Optional ByVal PostDate As String = Nothing, + Optional ByRef Result As Boolean = False) As List(Of UserMedia) + Dim postUrl$, ext$ + Dim t As UTypes + Dim mList As New List(Of UserMedia) + Result = False + With n("media") + If .ListExists Then + For Each m In .Self + postUrl = m.Value({"source"}, "source").IfNullOrEmpty(m.Value("full")) + Select Case m.Value("type") + Case "photo" : t = UTypes.Picture : ext = "jpg" + Case "video" : t = UTypes.Video : ext = "mp4" + Case Else : t = UTypes.Undefined : ext = String.Empty + End Select + If Not t = UTypes.Undefined And Not postUrl.IsEmptyString Then + Dim media As New UserMedia(postUrl, t) With { + .Post = New UserPost(PostID, AConvert(Of Date)(PostDate, DateProvider, Nothing))} + media.File.Extension = ext + Result = True + mList.Add(media) + End If + Next + End If + End With + Return mList + End Function + Private Sub GetUserID() + Dim path$ = $"/api2/v2/users/{Name}" + Dim url$ = String.Format(BaseUrlPattern, path) + Try + If ID.IsEmptyString AndAlso UpdateSignature(path) Then + Dim r$ = Responser.GetResponse(url) + If Not r.IsEmptyString Then + Using j As EContainer = JsonDocument.Parse(r) + If j.ListExists Then + ID = j.Value("id") + If Not ID.IsEmptyString Then _ForceSaveUserInfo = True + UserSiteNameUpdate(j.Value("name")) + UserDescriptionUpdate(j.Value("about")) + Dim a As Action(Of String) = Sub(ByVal address As String) + If Not address.IsEmptyString Then + Dim f As SFile = address + f.Separator = "\" + f.Path = DownloadContentDefault_GetRootDir() + If Not f.Exists Then GetWebFile(address, f, EDP.None) + End If + End Sub + a.Invoke(j.Value("avatar")) + a.Invoke(j.Value("header")) + End If + End Using + End If + End If + Catch ex As Exception + ProcessException(ex, Nothing, $"user info parsing error [{url}]") + End Try + End Sub + Protected Overrides Sub ReparseMissing(ByVal Token As CancellationToken) + Const PathPattern$ = "/api2/v2/posts/{0}?skip_users=all" + Dim rList As New List(Of Integer) + Dim URL$ = String.Empty + Try + If ContentMissingExists Then + Dim m As UserMedia + Dim mList As List(Of UserMedia) + Dim mediaResult As Boolean + Dim r$, path$, postDate$ + Dim j As EContainer + ProgressPre.ChangeMax(_ContentList.Count) + For i% = 0 To _ContentList.Count - 1 + ProgressPre.Perform() + If _ContentList(i).State = UStates.Missing Then + m = _ContentList(i) + If Not m.Post.ID.IsEmptyString Then + ThrowAny(Token) + path = String.Format(PathPattern, m.Post.ID) + If UpdateSignature(path) Then + URL = String.Format(BaseUrlPattern, path) + r = Responser.GetResponse(URL,, EDP.ReturnValue) + If Not r.IsEmptyString Then + j = JsonDocument.Parse(r) + If Not j Is Nothing Then + postDate = j.Value("postedAt") + mediaResult = False + mList = TryCreateMedia(j, m.Post.ID, postDate, mediaResult) + If mediaResult Then + _TempMediaList.ListAddList(mList, LNC) + rList.Add(i) + mList.Clear() + End If + j.Dispose() + End If + End If + End If + End If + End If + Next + End If + Catch ex As Exception + ProcessException(ex, Token, $"ReparseMissing error [{URL}]") + Finally + If rList.Count > 0 Then + For i% = rList.Count - 1 To 0 Step -1 : _ContentList.RemoveAt(i) : Next + rList.Clear() + End If + End Try + End Sub +#End Region +#Region "DownloadSingleObject" + Protected Overrides Sub DownloadSingleObject_GetPosts(ByVal Data As IYouTubeMediaContainer, ByVal Token As CancellationToken) + Dim postID$ = RegexReplace(Data.URL, RegExPostID) + If Not postID.IsEmptyString Then _ContentList.Add(New UserMedia With {.Post = postID, .State = UStates.Missing}) : ReparseMissing(Token) + End Sub +#End Region +#Region "Auth" + Private ReadOnly Property AuthFile As SFile + Get + Dim f As SFile = MySettings.Responser.File + f.Name &= "_Auth" + f.Extension = "json" + Return f + End Get + End Property + Private Function UpdateSignature(ByVal Path As String, Optional ByVal ForceUpdateAuth As Boolean = False) As Boolean + Try + If UpdateAuthFile(ForceUpdateAuth) Then + Const nullMsg$ = "The auth parameter is null" + Dim j As EContainer = JsonDocument.Parse(AuthFile.GetText) + Dim pattern$ = j.Value("format") + If pattern.IsEmptyString Then Throw New ArgumentNullException("format", nullMsg) + pattern = pattern.Replace("{}", "{0}").Replace("{:x}", "{1:x}") + + Dim li%() = j("checksum_indexes").Select(Function(e) CInt(e(0).Value)).ToArray + + If Not li.ListExists Then Throw New ArgumentNullException("checksum_indexes", nullMsg) + If j.Value("static_param").IsEmptyString Then Throw New ArgumentNullException("static_param", nullMsg) + If j.Value("checksum_constant").IsEmptyString Then Throw New ArgumentNullException("checksum_constant", nullMsg) + + Dim t$ = ADateTime.ConvertToUnix64(Now.ToUniversalTime).ToString + Dim h$ = String.Join(vbLf, j.Value("static_param"), t, Path, MySettings.HH_USER_ID.Value.ToString) + + Dim hash$ = GetHashSha1(h) + Dim hashBytes() As Byte = System.Text.Encoding.ASCII.GetBytes(hash) + Dim hashSum% = li.Sum(Function(i) hashBytes(i)) + CInt(j.Value("checksum_constant")) + Dim sign$ = String.Format(pattern, hash, Math.Abs(hashSum)) + + '#If DEBUG Then + 'Debug.WriteLine(sign) + 'Debug.WriteLine(t) + '#End If + + Responser.Headers.Add(HeaderSign, sign) + Responser.Headers.Add(HeaderTime, t) + + j.Dispose() + Return True + Else + Return False + End If + Catch ex As Exception + Return ErrorsDescriber.Execute(EDP.SendToLog + EDP.ReturnValue, ex, $"{ToStringForLog()}: UpdateSignature", False) + End Try + End Function + Private Function UpdateAuthFile(ByVal Force As Boolean) As Boolean + Const urlOld$ = "https://raw.githubusercontent.com/DATAHOARDERS/dynamic-rules/main/onlyfans.json" + Const urlNew$ = "https://raw.githubusercontent.com/DIGITALCRIMINALS/dynamic-rules/main/onlyfans.json" + Try + If MySettings.LastDateUpdated.AddMinutes(CInt(MySettings.DynamicRulesUpdateInterval.Value)) < Now Or Not AuthFile.Exists Or Force Then + Dim r$ = GetWebString(If(ACheck(Of String)(MySettings.DynamicRules.Value), + CStr(MySettings.DynamicRules.Value), + IIf(MySettings.UseOldAuthRules.Value, urlOld, urlNew)),, EDP.ReturnValue) + If Not r.IsEmptyString Then + Using j As EContainer = JsonDocument.Parse(r, EDP.ReturnValue) + If j.ListExists Then + If Not j.Value("format").IsEmptyString And j("checksum_indexes").ListExists And + Not j.Value("static_param").IsEmptyString And Not j.Value("checksum_constant").IsEmptyString Then _ + TextSaver.SaveTextToFile(r, AuthFile, True, False, EDP.ThrowException) : MySettings.LastDateUpdated = Now + End If + End Using + End If + End If + Return AuthFile.Exists + Catch ex As Exception + Return ErrorsDescriber.Execute(EDP.SendToLog + EDP.ReturnValue, ex, $"{ToStringForLog()}: UpdateAuthFile", False) + End Try + End Function + Private Function GetHashSha1(ByVal Input As String) As String + Dim s As New Security.Cryptography.SHA1CryptoServiceProvider + Dim inputBytes() As Byte = System.Text.Encoding.UTF8.GetBytes(Input) + Dim hashBytes() As Byte = s.ComputeHash(inputBytes) + s.Dispose() + Dim result As String = String.Empty + For Each b As Byte In hashBytes : result &= b.ToString("x2") : Next + Return result + End Function +#End Region +#Region "DownloadContent" + Protected Overrides Sub DownloadContent(ByVal Token As CancellationToken) + DownloadContentDefault(Token) + End Sub +#End Region +#Region "DownloadingException" + Private _DownloadingException_AuthFileUpdate As Boolean = False + Protected Overrides Function DownloadingException(ByVal ex As Exception, ByVal Message As String, Optional ByVal FromPE As Boolean = False, + Optional ByVal EObj As Object = Nothing) As Integer + If Responser.StatusCode = Net.HttpStatusCode.BadRequest Then + If Not _DownloadingException_AuthFileUpdate AndAlso UpdateAuthFile(True) Then + _DownloadingException_AuthFileUpdate = True + Return 2 + Else + MySettings.SessionAborted = True + MyMainLOG = $"{ToStringForLog()}: OnlyFans credentials expired" + Return 1 + End If + ElseIf Responser.StatusCode = Net.HttpStatusCode.NotFound Then + UserExists = False + Return 1 + Else + Return 0 + End If + End Function +#End Region +#Region "IDisposable Support" + Protected Overrides Sub Dispose(ByVal disposing As Boolean) + If Not disposedValue And disposing Then CCookie.DisposeIfReady(False) : CCookie = Nothing + MyBase.Dispose(disposing) + End Sub +#End Region + End Class +End Namespace \ No newline at end of file diff --git a/SCrawler/API/Reddit/UserData.vb b/SCrawler/API/Reddit/UserData.vb index 37d8c64..e8d78c8 100644 --- a/SCrawler/API/Reddit/UserData.vb +++ b/SCrawler/API/Reddit/UserData.vb @@ -585,12 +585,32 @@ Namespace API.Reddit End If End If If Not added And e.Contains("preview") Then - tmpUrl = If(e.ItemF({"preview", "images", eCount, "source", "url"})?.Value, String.Empty) - If Not tmpUrl.IsEmptyString Then - _TempMediaList.ListAddValue(MediaFromData(UTypes.Picture, tmpUrl, PostID, PostDate, UserID), LNC) - _TotalPostsDownloaded += 1 - added = True - End If + With e.ItemF({"preview", "images", eCount}) + If .ListExists Then + tmpType = UTypes.Undefined + tmpUrl = String.Empty + Dim sv$ = .Value({"source"}, "url") + If Not sv.IsEmptyString AndAlso sv.Contains(".gif") Then + tmpUrl = .Value({"variants", "gif", "source"}, "url") + If Not tmpUrl.IsEmptyString Then tmpType = UTypes.GIF + End If + If tmpUrl.IsEmptyString Then + tmpUrl = .Value({"variants", "mp4", "source"}, "url") + If Not tmpUrl.IsEmptyString Then tmpType = UTypes.Video + End If + If tmpUrl.IsEmptyString Then + tmpUrl = .Value({"source"}, "url") + If Not tmpUrl.IsEmptyString Then tmpType = UTypes.Picture + End If + If Not tmpUrl.IsEmptyString And Not tmpType = UTypes.Undefined Then + Dim m As UserMedia = MediaFromData(tmpType, tmpUrl, PostID, PostDate, UserID) + If tmpType = UTypes.Video Then m.File.Extension = "mp4" + _TempMediaList.ListAddValue(m, LNC) + _TotalPostsDownloaded += 1 + added = True + End If + End If + End With End If End If End If diff --git a/SCrawler/API/Twitter/UserData.vb b/SCrawler/API/Twitter/UserData.vb index e7588ea..c5f295d 100644 --- a/SCrawler/API/Twitter/UserData.vb +++ b/SCrawler/API/Twitter/UserData.vb @@ -186,7 +186,8 @@ Namespace API.Twitter Return True End Function - tCache = New CacheKeeper($"{DownloadContentDefault_GetRootDir()}\_tCache\") + tCache = New CacheKeeper($"{DownloadContentDefault_GetRootDir()}\_tCache\") With { + .CacheDeleteError = New ErrorsDescriber(EDP.None) With {.Action = Sub(ee, eex, msg, obj) Settings.Cache.AddPath(tCache)}} If tCache.RootDirectory.Exists(SFO.Path, False) Then tCache.RootDirectory.Delete(SFO.Path, SFODelete.DeletePermanently, EDP.ReturnValue) tCache.Validate() diff --git a/SCrawler/API/Xhamster/UserData.vb b/SCrawler/API/Xhamster/UserData.vb index b794546..d5c8b5a 100644 --- a/SCrawler/API/Xhamster/UserData.vb +++ b/SCrawler/API/Xhamster/UserData.vb @@ -10,6 +10,7 @@ Imports System.Threading Imports SCrawler.API.Base Imports SCrawler.API.YouTube.Objects Imports PersonalUtilities.Functions.XML +Imports PersonalUtilities.Functions.XML.Base Imports PersonalUtilities.Functions.RegularExpressions Imports PersonalUtilities.Tools.Web.Clients Imports PersonalUtilities.Tools.Web.Documents.JSON @@ -287,8 +288,11 @@ Namespace API.Xhamster End Try End Function Private Overloads Function GetM3U8(ByRef m As UserMedia, ByVal j As EContainer) As Boolean - Dim url$ = j.Value({"xplayerSettings", "sources", "hls"}, "url") - If Not url.IsEmptyString Then m.URL = url : m.Type = UTypes.m3u8 : Return True + Dim node As EContainer = j({"xplayerSettings", "sources", "hls"}) + If node.ListExists Then + Dim url$ = node.GetNode({New NodeParams("url", True, True, True, True, 2)}) + If Not url.IsEmptyString Then m.URL = url : m.Type = UTypes.m3u8 : Return True + End If Return False End Function #End Region diff --git a/SCrawler/Content/Icons/SiteIcons/OnlyFansIcon_32.ico b/SCrawler/Content/Icons/SiteIcons/OnlyFansIcon_32.ico new file mode 100644 index 0000000000000000000000000000000000000000..138c096974cf814ba85de73a0afde8739465d394 GIT binary patch literal 15086 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 xIE7hxbBMy}8&^&oIdeqj2>a;_sfD_8&k literal 0 HcmV?d00001 diff --git a/SCrawler/Download/ActiveDownloadingProgress.vb b/SCrawler/Download/ActiveDownloadingProgress.vb index 0fc4489..870c5d4 100644 --- a/SCrawler/Download/ActiveDownloadingProgress.vb +++ b/SCrawler/Download/ActiveDownloadingProgress.vb @@ -62,8 +62,7 @@ Namespace DownloadObjects .RowStyles.Add(New RowStyle(SizeType.Absolute, RowHeight)) .RowCount += 1 JobsList.Add(New DownloadProgress(j)) - AddHandler JobsList.Last.ProgressMaximumChanged, AddressOf Jobs_ProgressMaximumChanged - AddHandler JobsList.Last.ProgressMaximum0Changed, AddressOf Jobs_ProgressMaximum0Changed + AddHandler JobsList.Last.ProgressChanged, AddressOf Jobs_ProgressChanged .Controls.Add(JobsList.Last.Get, 0, .RowStyles.Count - 1) End With Next @@ -84,16 +83,18 @@ Namespace DownloadObjects End Sub If TP_MAIN.InvokeRequired Then TP_MAIN.Invoke(a) Else a.Invoke End Sub - Private Sub Jobs_ProgressMaximumChanged() + Private Sub Jobs_ProgressChanged(ByVal Main As Boolean, ByVal IsMaxValue As Boolean, ByVal IsDone As Boolean) If JobsList.Count > 0 And Not DisableProgressChange Then - MainProgress.Maximum = JobsList.Sum(Function(j) CLng(j.Job.Progress.Maximum)) - MainProgress.Value = Math.Max(JobsList.Sum(Function(j) CLng(j.Job.Progress.Value)) - 1, 0) - If MainProgress.Value > 0 Then MainProgress.Perform() + If Main Then + MainProgress.Maximum = JobsList.Sum(Function(j) CLng(j.Job.Progress.Maximum)) + MainProgress.Value = Math.Max(JobsList.Sum(Function(j) CLng(j.Job.Progress.Value)) - 1, 0) + If MainProgress.Value > 0 Then MainProgress.Perform() + Else + MainProgress.Maximum0 = JobsList.Sum(Function(j) CLng(DirectCast(j.Job.Progress, MyProgressExt).Maximum0)) + MainProgress.Value0 = Math.Max(JobsList.Sum(Function(j) CLng(DirectCast(j.Job.Progress, MyProgressExt).Value0)) - 1, 0) + If MainProgress.Value0 > 0 Then MainProgress.Perform0() + End If End If End Sub - Private Sub Jobs_ProgressMaximum0Changed() - If JobsList.Count > 0 And Not DisableProgressChange Then _ - MainProgress.Maximum0 = JobsList.Sum(Function(j) CLng(DirectCast(j.Job.Progress, MyProgressExt).Maximum0)) - End Sub End Class End Namespace \ No newline at end of file diff --git a/SCrawler/Download/DownloadProgress.vb b/SCrawler/Download/DownloadProgress.vb index c768980..04f53f8 100644 --- a/SCrawler/Download/DownloadProgress.vb +++ b/SCrawler/Download/DownloadProgress.vb @@ -13,8 +13,7 @@ Namespace DownloadObjects Friend Class DownloadProgress : Implements IDisposable #Region "Events" Friend Event DownloadDone As NotificationEventHandler - Friend Event ProgressMaximumChanged() - Friend Event ProgressMaximum0Changed() + Friend Event ProgressChanged(ByVal Main As Boolean, ByVal IsMaxValue As Boolean, ByVal IsDone As Boolean) #End Region #Region "Declarations" #Region "Controls" @@ -127,6 +126,8 @@ Namespace DownloadObjects AddHandler .MaximumChanged, AddressOf JobProgress_MaximumChanged AddHandler .Maximum0Changed, AddressOf JobProgress_Maximum0Changed AddHandler .Progress0Changed, AddressOf JobProgress_Progress0Changed + AddHandler .ProgressCompleted, AddressOf JobProgress_Done + AddHandler .Progress0Completed, AddressOf JobProgress_Done0 End With End With @@ -190,22 +191,22 @@ Namespace DownloadObjects #End Region #Region "Progress, Jobs count" Private Sub JobProgress_MaximumChanged(ByVal Sender As Object, ByVal e As ProgressEventArgs) - RaiseEvent ProgressMaximumChanged() + If Not Job.Type = Download.SavedPosts Then RaiseEvent ProgressChanged(True, True, False) End Sub Private Sub JobProgress_Maximum0Changed(ByVal Sender As Object, ByVal e As ProgressEventArgs) - RaiseEvent ProgressMaximum0Changed() + If Not Job.Type = Download.SavedPosts Then RaiseEvent ProgressChanged(False, True, False) End Sub Private Sub JobProgress_ProgressChanged(ByVal Sender As Object, ByVal e As ProgressEventArgs) - If Not Job.Type = Download.SavedPosts Then - MainProgress.Value = DirectCast(Sender, MyProgressExt).Value - MainProgress.Perform(0) - End If + If Not Job.Type = Download.SavedPosts Then MainProgress.Perform() End Sub Private Sub JobProgress_Progress0Changed(ByVal Sender As Object, ByVal e As ProgressEventArgs) - If Not Job.Type = Download.SavedPosts Then - MainProgress.Value0 = DirectCast(Job.Progress, MyProgressExt).Value0 - MainProgress.Perform0(0) - End If + If Not Job.Type = Download.SavedPosts Then MainProgress.Perform0() + End Sub + Private Sub JobProgress_Done(ByVal Sender As Object, ByVal e As ProgressEventArgs) + If Not Job.Type = Download.SavedPosts Then RaiseEvent ProgressChanged(True, False, True) + End Sub + Private Sub JobProgress_Done0(ByVal Sender As Object, ByVal e As ProgressEventArgs) + If Not Job.Type = Download.SavedPosts Then RaiseEvent ProgressChanged(False, False, True) End Sub #End Region #Region "IDisposable Support" diff --git a/SCrawler/My Project/AssemblyInfo.vb b/SCrawler/My Project/AssemblyInfo.vb index e6f9587..a6c5e50 100644 --- a/SCrawler/My Project/AssemblyInfo.vb +++ b/SCrawler/My Project/AssemblyInfo.vb @@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices ' by using the '*' as shown below: ' - - + + diff --git a/SCrawler/MyProgressExt.vb b/SCrawler/MyProgressExt.vb index 59602e1..b57a71a 100644 --- a/SCrawler/MyProgressExt.vb +++ b/SCrawler/MyProgressExt.vb @@ -21,41 +21,23 @@ Friend Class PreProgress : Implements IDisposable ProgressExists = True End If End Sub - Private _Maximum As Integer = 0 Friend Sub ChangeMax(ByVal Value As Integer, Optional ByVal Add As Boolean = True) If Ready Then If Add Then - _Maximum += Value If Value > 0 Then Progress.Maximum0 += Value Else - _Maximum = Value Progress.Maximum0 = Value End If End If End Sub - Private CumulVal As Integer = 0 Friend Sub Perform(Optional ByVal Value As Integer = 1) - If Ready Then - CumulVal += Value - Progress.Perform0(Value) - End If + If Ready Then Progress.Perform0(Value) End Sub Friend Sub Reset() - _Maximum = 0 - CumulVal = 0 + If Ready Then Progress.Reset0() End Sub Friend Sub Done() - If Ready Then - Dim v# = _Maximum - CumulVal - If v > 0 Then - With Progress - If v + .Value0 > .Maximum0 Then v = .Maximum0 - .Value0 - If v < 0 Then v = 0 - .Perform0(v) - Reset() - End With - End If - End If + If Ready Then Progress.Done0() End Sub #Region "IDisposable Support" Private disposedValue As Boolean = False @@ -85,14 +67,7 @@ Friend Class MyProgressExt : Inherits MyProgress _Progress0ChangedEventHandlers.Remove(h) End RemoveHandler RaiseEvent(ByVal Sender As Object, ByVal e As ProgressEventArgs) - If _Progress0ChangedEventHandlers.Count > 0 Then - Try - For i% = 0 To _Progress0ChangedEventHandlers.Count - 1 - Try : _Progress0ChangedEventHandlers(i).Invoke(Sender, e) : Catch : End Try - Next - Catch - End Try - End If + InvokeHandlers(_Progress0ChangedEventHandlers, Sender, e) End RaiseEvent End Event Private ReadOnly _Maximum0ChangedEventHandlers As List(Of EventHandler(Of ProgressEventArgs)) @@ -104,14 +79,19 @@ Friend Class MyProgressExt : Inherits MyProgress _Maximum0ChangedEventHandlers.Remove(h) End RemoveHandler RaiseEvent(ByVal Sender As Object, ByVal e As ProgressEventArgs) - If _Maximum0ChangedEventHandlers.Count > 0 Then - Try - For i% = 0 To _Maximum0ChangedEventHandlers.Count - 1 - Try : _Maximum0ChangedEventHandlers(i).Invoke(Sender, e) : Catch : End Try - Next - Catch - End Try - End If + InvokeHandlers(_Maximum0ChangedEventHandlers, Sender, e) + End RaiseEvent + End Event + Private ReadOnly _Progress0CompletedEventHandlers As List(Of EventHandler(Of ProgressEventArgs)) + Friend Custom Event Progress0Completed As EventHandler(Of ProgressEventArgs) + AddHandler(ByVal h As EventHandler(Of ProgressEventArgs)) + If Not _Progress0CompletedEventHandlers.Contains(h) Then _Progress0CompletedEventHandlers.Add(h) + End AddHandler + RemoveHandler(ByVal h As EventHandler(Of ProgressEventArgs)) + _Progress0CompletedEventHandlers.Remove(h) + End RemoveHandler + RaiseEvent(ByVal Sender As Object, ByVal e As ProgressEventArgs) + InvokeHandlers(_Progress0CompletedEventHandlers, Sender, e) End RaiseEvent End Event Private WithEvents PR_PRE As MyProgress @@ -121,9 +101,13 @@ Friend Class MyProgressExt : Inherits MyProgress Private Sub PR_PRE_MaximumChanged(ByVal Sender As Object, ByVal e As ProgressEventArgs) Handles PR_PRE.MaximumChanged RaiseEvent Maximum0Changed(Sender, e) End Sub + Private Sub PR_PRE_ProgressCompleted(ByVal Sender As Object, ByVal e As ProgressEventArgs) Handles PR_PRE.ProgressCompleted + RaiseEvent Progress0Completed(Sender, e) + End Sub Friend Sub New() _Progress0ChangedEventHandlers = New List(Of EventHandler(Of ProgressEventArgs)) _Maximum0ChangedEventHandlers = New List(Of EventHandler(Of ProgressEventArgs)) + _Progress0CompletedEventHandlers = New List(Of EventHandler(Of ProgressEventArgs)) End Sub Friend Sub New(ByRef StatusStrip As StatusStrip, ByRef ProgressBar As ToolStripProgressBar, ByRef ProgressBarPre As ToolStripProgressBar, ByRef Label As ToolStripStatusLabel, Optional ByVal Information As String = Nothing) @@ -131,12 +115,14 @@ Friend Class MyProgressExt : Inherits MyProgress PR_PRE = New MyProgress(StatusStrip, ProgressBarPre, Nothing) With {.PerformMod = 10, .ResetProgressOnMaximumChanges = False} _Progress0ChangedEventHandlers = New List(Of EventHandler(Of ProgressEventArgs)) _Maximum0ChangedEventHandlers = New List(Of EventHandler(Of ProgressEventArgs)) + _Progress0CompletedEventHandlers = New List(Of EventHandler(Of ProgressEventArgs)) End Sub Friend Sub New(ByRef ProgressBar As ProgressBar, ByRef ProgressBarPre As ProgressBar, ByRef Label As Label, Optional ByVal Information As String = Nothing) MyBase.New(ProgressBar, Label, Information) PR_PRE = New MyProgress(ProgressBarPre, Nothing) With {.PerformMod = 10, .ResetProgressOnMaximumChanges = False} _Progress0ChangedEventHandlers = New List(Of EventHandler(Of ProgressEventArgs)) _Maximum0ChangedEventHandlers = New List(Of EventHandler(Of ProgressEventArgs)) + _Progress0CompletedEventHandlers = New List(Of EventHandler(Of ProgressEventArgs)) End Sub Friend Property Maximum0 As Double Get @@ -161,10 +147,16 @@ Friend Class MyProgressExt : Inherits MyProgress PR_PRE.Done() MyBase.Done() End Sub - Public Overrides Sub Reset() - MyBase.Reset() + Friend Sub Done0() PR_PRE.Done() End Sub + Public Overrides Sub Reset() + PR_PRE.Reset() + MyBase.Reset() + End Sub + Friend Sub Reset0() + PR_PRE.Reset() + End Sub Public Overrides Property Visible(Optional ByVal ProgressBar As Boolean = True, Optional ByVal Label As Boolean = True) As Boolean Get Return MyBase.Visible(ProgressBar, Label) @@ -178,6 +170,7 @@ Friend Class MyProgressExt : Inherits MyProgress If Not disposedValue And disposing Then _Progress0ChangedEventHandlers.Clear() _Maximum0ChangedEventHandlers.Clear() + _Progress0CompletedEventHandlers.Clear() PR_PRE.Dispose() End If MyBase.Dispose(disposing) diff --git a/SCrawler/PluginsEnvironment/Hosts/PluginHost.vb b/SCrawler/PluginsEnvironment/Hosts/PluginHost.vb index 5fd87a9..6dca8a7 100644 --- a/SCrawler/PluginsEnvironment/Hosts/PluginHost.vb +++ b/SCrawler/PluginsEnvironment/Hosts/PluginHost.vb @@ -88,7 +88,8 @@ Namespace Plugin.Hosts New PluginHost(New API.Xhamster.SiteSettings, _XML, GlobalPath, _Temp, _Imgs, _Vids), New PluginHost(New API.XVIDEOS.SiteSettings, _XML, GlobalPath, _Temp, _Imgs, _Vids), New PluginHost(New API.ThisVid.SiteSettings, _XML, GlobalPath, _Temp, _Imgs, _Vids), - New PluginHost(New API.PathPlugin.SiteSettings, _XML, GlobalPath, _Temp, _Imgs, _Vids)} + New PluginHost(New API.PathPlugin.SiteSettings, _XML, GlobalPath, _Temp, _Imgs, _Vids), + New PluginHost(New API.OnlyFans.SiteSettings, _XML, GlobalPath, _Temp, _Imgs, _Vids)} End Function Friend Shared Function GetPluginsHosts(ByRef _XML As XmlFile, ByVal GlobalPath As SFile, ByRef _Temp As XMLValue(Of Boolean), ByRef _Imgs As XMLValue(Of Boolean), diff --git a/SCrawler/SCrawler.vbproj b/SCrawler/SCrawler.vbproj index 39dd0d8..ba8e50d 100644 --- a/SCrawler/SCrawler.vbproj +++ b/SCrawler/SCrawler.vbproj @@ -188,6 +188,9 @@ + + + @@ -661,6 +664,12 @@ + + + + + + diff --git a/SCrawler/SiteResources.Designer.vb b/SCrawler/SiteResources.Designer.vb index 0b94ad4..dff6ac0 100644 --- a/SCrawler/SiteResources.Designer.vb +++ b/SCrawler/SiteResources.Designer.vb @@ -124,6 +124,26 @@ Namespace My.Resources End Get End Property + ''' + ''' Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + ''' + Friend Shared ReadOnly Property OnlyFansIcon_32() As System.Drawing.Icon + Get + Dim obj As Object = ResourceManager.GetObject("OnlyFansIcon_32", resourceCulture) + Return CType(obj,System.Drawing.Icon) + End Get + End Property + + ''' + ''' Looks up a localized resource of type System.Drawing.Bitmap. + ''' + Friend Shared ReadOnly Property OnlyFansPic_32() As System.Drawing.Bitmap + Get + Dim obj As Object = ResourceManager.GetObject("OnlyFansPic_32", resourceCulture) + Return CType(obj,System.Drawing.Bitmap) + End Get + End Property + ''' ''' Looks up a localized resource of type System.Drawing.Icon similar to (Icon). ''' diff --git a/SCrawler/SiteResources.resx b/SCrawler/SiteResources.resx index a8fa6a0..fc91260 100644 --- a/SCrawler/SiteResources.resx +++ b/SCrawler/SiteResources.resx @@ -136,6 +136,12 @@ Content\Pictures\SitePictures\MastodonPic_48.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + Content\Icons\SiteIcons\OnlyFansIcon_32.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Content\Pictures\SitePictures\OnlyFansPic_32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + Content\Icons\SiteIcons\PinterestIcon_32.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a