mirror of
https://github.com/AAndyProgram/SCrawler.git
synced 2026-03-14 15:52:18 +00:00
2023.11.24.0
Scheduler: handle scheduler change error (collection was modified) SchedulerEditorForm: add scheduler name to form title DownloadProgress: fix disposing error when some objects are already null API.Reddit: add special notification for error 429 API.Twitter: handle JSON deserialization error Porn sites: fix incorrect parsing of search queries YouTube: path not set when adding array to download
This commit is contained in:
24
Changelog.md
24
Changelog.md
@@ -1,3 +1,27 @@
|
|||||||
|
# 2023.11.24.0
|
||||||
|
|
||||||
|
*2023-11-24*
|
||||||
|
|
||||||
|
For those of you who use TikTok, I recommend updating [TikTok plugin](https://github.com/bashonly/yt-dlp-TTUser) to the latest version using [these instructions](https://github.com/AAndyProgram/SCrawler/wiki/Settings#how-to-install-yt-dlp-ttuser-plugin).
|
||||||
|
|
||||||
|
- Added
|
||||||
|
- Automation: manual task option
|
||||||
|
- Scheduler: add scheduler name to form title
|
||||||
|
- Feeds: update when users' location and/or basic information changes
|
||||||
|
- Reddit: special notification for error 429
|
||||||
|
- TikTok: ID, username and friendly name extraction from data
|
||||||
|
- TikTok: new option `Use video date as file date`
|
||||||
|
- YouTube: absolute path for a single playlist
|
||||||
|
- Updated
|
||||||
|
- yt-dlp up to version 2023.11.16
|
||||||
|
- Fixed
|
||||||
|
- Scheduler: scheduler change error
|
||||||
|
- Twitter: JSON deserialization error
|
||||||
|
- xHamster, XVideos, PornHub, ThisVid: incorrect parsing of search queries
|
||||||
|
- YouTube: the file name is not changed manually
|
||||||
|
- YouTube: path not set when adding array to download
|
||||||
|
- Minor bugs
|
||||||
|
|
||||||
# 2023.11.17.0
|
# 2023.11.17.0
|
||||||
|
|
||||||
*2023-11-17*
|
*2023-11-17*
|
||||||
|
|||||||
@@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices
|
|||||||
' by using the '*' as shown below:
|
' by using the '*' as shown below:
|
||||||
' <Assembly: AssemblyVersion("1.0.*")>
|
' <Assembly: AssemblyVersion("1.0.*")>
|
||||||
|
|
||||||
<Assembly: AssemblyVersion("2023.11.17.0")>
|
<Assembly: AssemblyVersion("2023.11.24.0")>
|
||||||
<Assembly: AssemblyFileVersion("2023.11.17.0")>
|
<Assembly: AssemblyFileVersion("2023.11.24.0")>
|
||||||
<Assembly: NeutralResourcesLanguage("en")>
|
<Assembly: NeutralResourcesLanguage("en")>
|
||||||
|
|||||||
@@ -278,6 +278,17 @@ Namespace DownloadObjects.STDownloader
|
|||||||
.IsMusic = containers.Any(Function(cc) cc.IsMusic)
|
.IsMusic = containers.Any(Function(cc) cc.IsMusic)
|
||||||
}
|
}
|
||||||
c.Elements.AddRange(containers)
|
c.Elements.AddRange(containers)
|
||||||
|
Dim path$ = c.Elements(0).File.PathWithSeparator
|
||||||
|
For Each list As List(Of String) In {
|
||||||
|
c.Elements.Select(Function(cc) cc.UserTitle).ListWithRemove(Function(cc) cc.IsEmptyString).ListIfNothing,
|
||||||
|
c.Elements.Select(Function(cc) cc.PlaylistTitle).ListWithRemove(Function(cc) cc.IsEmptyString).ListIfNothing
|
||||||
|
}
|
||||||
|
If list.Count > 0 AndAlso
|
||||||
|
(list.Count = 1 OrElse
|
||||||
|
ListAddList(Nothing, list, LAP.NotContainsOnly, EDP.ReturnValue).ListIfNothing.Count = 1) Then _
|
||||||
|
path &= $"{list(0)}\"
|
||||||
|
Next
|
||||||
|
c.File = path
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
End With
|
End With
|
||||||
@@ -450,12 +461,16 @@ Namespace DownloadObjects.STDownloader
|
|||||||
UpdateLogButton()
|
UpdateLogButton()
|
||||||
End Sub
|
End Sub
|
||||||
Protected Sub AddToDownload(ByRef Item As MediaItem, ByVal RunThread As Boolean)
|
Protected Sub AddToDownload(ByRef Item As MediaItem, ByVal RunThread As Boolean)
|
||||||
|
Try
|
||||||
Dim hc% = Item.MyContainer.GetHashCode
|
Dim hc% = Item.MyContainer.GetHashCode
|
||||||
If MyJob.Count = 0 OrElse Not MyJob.Items.Exists(Function(i) i.MyContainer.GetHashCode = hc) Then
|
If MyJob.Count = 0 OrElse Not MyJob.Items.Exists(Function(i) i.MyContainer.GetHashCode = hc) Then
|
||||||
MyJob.Add(Item)
|
MyJob.Add(Item)
|
||||||
Item.AddToQueue()
|
Item.AddToQueue()
|
||||||
If RunThread Then StartDownloading()
|
If RunThread Then StartDownloading()
|
||||||
End If
|
End If
|
||||||
|
Catch ex As Exception
|
||||||
|
ErrorsDescriber.Execute(EDP.SendToLog, ex, "[VideoListForm.AddToDownload]")
|
||||||
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
Private Sub StartDownloading()
|
Private Sub StartDownloading()
|
||||||
If Not MyJob.Working And MyJob.Count > 0 Then
|
If Not MyJob.Working And MyJob.Count > 0 Then
|
||||||
|
|||||||
@@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices
|
|||||||
' by using the '*' as shown below:
|
' by using the '*' as shown below:
|
||||||
' <Assembly: AssemblyVersion("1.0.*")>
|
' <Assembly: AssemblyVersion("1.0.*")>
|
||||||
|
|
||||||
<Assembly: AssemblyVersion("2023.11.17.0")>
|
<Assembly: AssemblyVersion("2023.11.24.0")>
|
||||||
<Assembly: AssemblyFileVersion("2023.11.17.0")>
|
<Assembly: AssemblyFileVersion("2023.11.24.0")>
|
||||||
<Assembly: NeutralResourcesLanguage("en")>
|
<Assembly: NeutralResourcesLanguage("en")>
|
||||||
|
|||||||
@@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices
|
|||||||
' by using the '*' as shown below:
|
' by using the '*' as shown below:
|
||||||
' <Assembly: AssemblyVersion("1.0.*")>
|
' <Assembly: AssemblyVersion("1.0.*")>
|
||||||
|
|
||||||
<Assembly: AssemblyVersion("2023.11.17.0")>
|
<Assembly: AssemblyVersion("2023.11.24.0")>
|
||||||
<Assembly: AssemblyFileVersion("2023.11.17.0")>
|
<Assembly: AssemblyFileVersion("2023.11.24.0")>
|
||||||
<Assembly: NeutralResourcesLanguage("en")>
|
<Assembly: NeutralResourcesLanguage("en")>
|
||||||
|
|||||||
@@ -1729,8 +1729,6 @@ BlockNullPicture:
|
|||||||
DownloadContentDefault_PostProcessing(v, f, Token)
|
DownloadContentDefault_PostProcessing(v, f, Token)
|
||||||
dCount += 1
|
dCount += 1
|
||||||
Catch woex As OperationCanceledException When Token.IsCancellationRequested
|
Catch woex As OperationCanceledException When Token.IsCancellationRequested
|
||||||
'TODELETE: UserDataBase.DownloadContentDefault: remove file when 'OperationCanceledException'
|
|
||||||
'If f.Exists Then f.Delete(,, EDP.SendToLog)
|
|
||||||
__deleteFile.Invoke(f, v.URL_BASE)
|
__deleteFile.Invoke(f, v.URL_BASE)
|
||||||
v.State = UStates.Missing
|
v.State = UStates.Missing
|
||||||
v.Attempts += 1
|
v.Attempts += 1
|
||||||
|
|||||||
@@ -126,70 +126,6 @@ Namespace API.JustForFans
|
|||||||
$"API.JustForFans.M3U8.GetFiles({IIf(IsAudio, "audio", "video")}):{vbCr}URL: {URL}{vbCr}File: {File}")
|
$"API.JustForFans.M3U8.GetFiles({IIf(IsAudio, "audio", "video")}):{vbCr}URL: {URL}{vbCr}File: {File}")
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
'TODELETE: JFF.M3U8.GetFiles_OLD 20231008
|
|
||||||
'Private Sub GetFiles_OLD(ByVal URL As String, ByRef File As SFile, ByVal IsAudio As Boolean)
|
|
||||||
' Try
|
|
||||||
' Dim r$ = Responser.GetResponse(URL)
|
|
||||||
' If Not r.IsEmptyString Then
|
|
||||||
' Dim data As List(Of RegexMatchStruct) = RegexFields(Of RegexMatchStruct)(r, {REGEX_PLS_FILES}, {1, 2}, EDP.ReturnValue)
|
|
||||||
' If data.ListExists Then
|
|
||||||
' Dim appender$ = URL.Replace(URL.Split("/").LastOrDefault, String.Empty)
|
|
||||||
' With (From d As RegexMatchStruct In data
|
|
||||||
' Where Not d.Arr(0).IfNullOrEmpty(d.Arr(1)).IsEmptyString
|
|
||||||
' Select M3U8Base.CreateUrl(appender, d.Arr(0).IfNullOrEmpty(d.Arr(1)).Trim)).ToList
|
|
||||||
' If .ListExists Then
|
|
||||||
' File = $"{Cache.RootDirectory.PathWithSeparator}{IIf(IsAudio, "AUDIO.aac", "VIDEO.mp4")}"
|
|
||||||
' Dim tmpCache As CacheKeeper = Cache.NewInstance
|
|
||||||
' Dim tmpFile As SFile = .Item(0)
|
|
||||||
' If tmpFile.Extension.IsEmptyString Then tmpFile.Extension = "ts"
|
|
||||||
' tmpFile.Path = tmpCache.RootDirectory.Path
|
|
||||||
' tmpFile.Separator = "\"
|
|
||||||
|
|
||||||
' Dim cFile As SFile = tmpFile
|
|
||||||
' cFile.Name = "all"
|
|
||||||
|
|
||||||
' tmpCache.Validate()
|
|
||||||
|
|
||||||
' Using bat As New TextSaver
|
|
||||||
' Using b As New BatchExecutor(True) With {.Encoding = Settings.CMDEncoding}
|
|
||||||
' AddHandler b.OutputDataReceived, AddressOf Batch_OutputDataReceived
|
|
||||||
' bat.AppendLine($"chcp {BatchExecutor.UnicodeEncoding}")
|
|
||||||
' bat.AppendLine(BatchExecutor.GetDirectoryCommand(tmpCache))
|
|
||||||
' ProgressChangeMax(.Count * 2 + 1)
|
|
||||||
' Using w As New WebClient
|
|
||||||
' For i = 0 To .Count - 1
|
|
||||||
' tmpFile.Name = $"ConPart_{i}"
|
|
||||||
' Thrower.ThrowAny()
|
|
||||||
' 'Responser.DownloadFile(.Item(i), tmpFile)
|
|
||||||
' w.DownloadFile(.Item(i), tmpFile)
|
|
||||||
' ProgressPerform()
|
|
||||||
' tmpCache.AddFile(tmpFile, True)
|
|
||||||
' bat.AppendLine($"type {tmpFile.File} >> {cFile.File}")
|
|
||||||
' Next
|
|
||||||
' End Using
|
|
||||||
|
|
||||||
' bat.AppendLine($"""{Settings.FfmpegFile}"" -i {cFile.File} -c copy ""{File}""")
|
|
||||||
|
|
||||||
' Dim batFile As SFile = bat.SaveAs($"{tmpCache.RootDirectory.PathWithSeparator}command.bat")
|
|
||||||
|
|
||||||
' b.Execute($"""{batFile}""")
|
|
||||||
|
|
||||||
' If Not File.Exists Then File = Nothing
|
|
||||||
' End Using
|
|
||||||
' End Using
|
|
||||||
' End If
|
|
||||||
' End With
|
|
||||||
' End If
|
|
||||||
' End If
|
|
||||||
' Catch oex As OperationCanceledException
|
|
||||||
' Throw oex
|
|
||||||
' Catch dex As ObjectDisposedException
|
|
||||||
' Throw dex
|
|
||||||
' Catch ex As Exception
|
|
||||||
' ErrorsDescriber.Execute(EDP.SendToLog + EDP.ThrowException, ex,
|
|
||||||
' $"API.JustForFans.M3U8.GetFiles({IIf(IsAudio, "audio", "video")}):{vbCr}URL: {URL}{vbCr}File: {File}")
|
|
||||||
' End Try
|
|
||||||
'End Sub
|
|
||||||
Private Async Sub Batch_OutputDataReceived(ByVal Sender As Object, ByVal e As DataReceivedEventArgs)
|
Private Async Sub Batch_OutputDataReceived(ByVal Sender As Object, ByVal e As DataReceivedEventArgs)
|
||||||
Await Task.Run(Sub() If Not e.Data.IsEmptyString AndAlso e.Data.Contains("] Opening") Then ProgressPerform())
|
Await Task.Run(Sub() If Not e.Data.IsEmptyString AndAlso e.Data.Contains("] Opening") Then ProgressPerform())
|
||||||
End Sub
|
End Sub
|
||||||
|
|||||||
@@ -168,8 +168,6 @@ Namespace API.JustForFans
|
|||||||
#Region "Initializer"
|
#Region "Initializer"
|
||||||
Friend Sub New()
|
Friend Sub New()
|
||||||
UseInternalM3U8Function = True
|
UseInternalM3U8Function = True
|
||||||
'TODELETE: UseResponserClient 20231008
|
|
||||||
'UseResponserClient = True
|
|
||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Download functions"
|
#Region "Download functions"
|
||||||
|
|||||||
@@ -423,30 +423,28 @@ Namespace API.PornHub
|
|||||||
newLastPageIDs.Add(uv.ID)
|
newLastPageIDs.Add(uv.ID)
|
||||||
If Not _TempPostsList.Contains(uv.ID) Then
|
If Not _TempPostsList.Contains(uv.ID) Then
|
||||||
_TempPostsList.Add(uv.ID)
|
_TempPostsList.Add(uv.ID)
|
||||||
|
newPostsFound = True
|
||||||
Return False
|
Return False
|
||||||
ElseIf SessionPosts.Count > 0 AndAlso SessionPosts.Contains(uv.id) Then
|
ElseIf SessionPosts.Count > 0 AndAlso SessionPosts.Contains(uv.id) Then
|
||||||
prevPostsFound = True
|
prevPostsFound = True
|
||||||
If pageRepeatSet Then pageRepeatSet = False : _PageVideosRepeat -= 1
|
|
||||||
Return True
|
Return True
|
||||||
Else
|
Else
|
||||||
'TODELETE: PornHub old validating
|
|
||||||
'If Not SessionPosts.Contains(uv.ID) Then nonLastPageDetected = True
|
|
||||||
If Not pageRepeatSet And Not newPostsFound Then pageRepeatSet = True : _PageVideosRepeat += 1
|
If Not pageRepeatSet And Not newPostsFound Then pageRepeatSet = True : _PageVideosRepeat += 1
|
||||||
'Debug.WriteLine($"[REMOVED]: {uv.Title}")
|
'Debug.WriteLine($"[REMOVED]: {uv.Title}")
|
||||||
Return True
|
Return True
|
||||||
End If
|
End If
|
||||||
End Function)
|
End Function)
|
||||||
'Debug.WriteLineIf(l.Count > 0, l.Select(Function(ll) ll.Title).ListToString(vbNewLine))
|
'Debug.WriteLineIf(l.Count > 0, l.Select(Function(ll) ll.Title).ListToString(vbNewLine))
|
||||||
|
If prevPostsFound And Not pageRepeatSet And Not newPostsFound Then pageRepeatSet = True : _PageVideosRepeat += 1
|
||||||
|
If prevPostsFound And newPostsFound And pageRepeatSet Then _PageVideosRepeat -= 1
|
||||||
If l.Count > 0 Then _TempMediaList.ListAddList(l.Select(Function(uv) uv.ToUserMedia(specFolder)))
|
If l.Count > 0 Then _TempMediaList.ListAddList(l.Select(Function(uv) uv.ToUserMedia(specFolder)))
|
||||||
SessionPosts.ListAddList(newLastPageIDs, LNC)
|
SessionPosts.ListAddList(newLastPageIDs, LNC)
|
||||||
newLastPageIDs.Clear()
|
newLastPageIDs.Clear()
|
||||||
'TODELETE: PornHub old validating
|
|
||||||
'If l.Count > 0 AndAlso (l.Count = lBefore Or Not nonLastPageDetected) AndAlso
|
|
||||||
' Not (limit > 0 And _TempMediaList.Count >= limit) Then tryNextPage = True
|
|
||||||
|
|
||||||
If limit > 0 And _TempMediaList.Count >= limit Then Exit Sub
|
If limit > 0 And _TempMediaList.Count >= limit Then Exit Sub
|
||||||
If (Not IsUser And prevPostsFound And Not newPostsFound And Page < 1000) Or
|
If _PageVideosRepeat < 2 And
|
||||||
(Not cBefore = _TempMediaList.Count And (IsUser Or Page < 1000)) Then tryNextPage = True
|
((Not IsUser And prevPostsFound And Not newPostsFound And Page < 1000) Or
|
||||||
|
(Not cBefore = _TempMediaList.Count And (IsUser Or Page < 1000))) Then tryNextPage = True
|
||||||
|
|
||||||
l.Clear()
|
l.Clear()
|
||||||
End If
|
End If
|
||||||
|
|||||||
@@ -50,6 +50,12 @@ Namespace API.Reddit
|
|||||||
Friend ReadOnly Property UseCookiesForTimelines As PropertyValue
|
Friend ReadOnly Property UseCookiesForTimelines As PropertyValue
|
||||||
<PropertyOption(ControlText:=DeclaredNames.SavedPostsUserNameCaption, ControlToolTip:=DeclaredNames.SavedPostsUserNameToolTip, IsAuth:=True), PXML, PClonable(Clone:=False)>
|
<PropertyOption(ControlText:=DeclaredNames.SavedPostsUserNameCaption, ControlToolTip:=DeclaredNames.SavedPostsUserNameToolTip, IsAuth:=True), PXML, PClonable(Clone:=False)>
|
||||||
Friend ReadOnly Property SavedPostsUserName As PropertyValue
|
Friend ReadOnly Property SavedPostsUserName As PropertyValue
|
||||||
|
Friend ReadOnly Property CredentialsExists As Boolean
|
||||||
|
Get
|
||||||
|
Return {AuthUserName.Value, AuthPassword.Value, ApiClientID.Value, ApiClientSecret.Value}.All(Function(v$) Not v.IsEmptyString)
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Other"
|
#Region "Other"
|
||||||
<PropertyOption(ControlText:="Use M3U8", ControlToolTip:="Use M3U8 or mp4 for Reddit videos", IsAuth:=False), PXML, PClonable>
|
<PropertyOption(ControlText:="Use M3U8", ControlToolTip:="Use M3U8 or mp4 for Reddit videos", IsAuth:=False), PXML, PClonable>
|
||||||
@@ -238,8 +244,7 @@ Namespace API.Reddit
|
|||||||
Return False
|
Return False
|
||||||
End Function
|
End Function
|
||||||
Private Function UpdateTokenIfRequired() As Boolean
|
Private Function UpdateTokenIfRequired() As Boolean
|
||||||
If (CBool(UseTokenForTimelines.Value) Or CBool(UseTokenForSavedPosts.Value)) AndAlso
|
If (CBool(UseTokenForTimelines.Value) Or CBool(UseTokenForSavedPosts.Value)) AndAlso CredentialsExists Then
|
||||||
{AuthUserName.Value, AuthPassword.Value, ApiClientID.Value, ApiClientSecret.Value}.All(Function(v$) Not v.IsEmptyString) Then
|
|
||||||
If CDate(BearerTokenDateUpdate.Value).AddMinutes(TokenUpdateInterval.Value) <= Now Then Return UpdateToken()
|
If CDate(BearerTokenDateUpdate.Value).AddMinutes(TokenUpdateInterval.Value) <= Now Then Return UpdateToken()
|
||||||
End If
|
End If
|
||||||
Return True
|
Return True
|
||||||
|
|||||||
@@ -1037,22 +1037,29 @@ Namespace API.Reddit
|
|||||||
Protected Overrides Function DownloadingException(ByVal ex As Exception, ByVal Message As String, Optional ByVal FromPE 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
|
Optional ByVal EObj As Object = Nothing) As Integer
|
||||||
With Responser
|
With Responser
|
||||||
If .StatusCode = HttpStatusCode.NotFound Then
|
If .StatusCode = HttpStatusCode.NotFound Then '404
|
||||||
UserExists = False
|
UserExists = False
|
||||||
ElseIf .StatusCode = HttpStatusCode.Forbidden Then
|
ElseIf .StatusCode = HttpStatusCode.Forbidden Then '403
|
||||||
UserSuspended = True
|
UserSuspended = True
|
||||||
ElseIf .StatusCode = HttpStatusCode.BadGateway Or .StatusCode = HttpStatusCode.ServiceUnavailable Then
|
ElseIf .StatusCode = HttpStatusCode.BadGateway Or .StatusCode = HttpStatusCode.ServiceUnavailable Then '502, 503
|
||||||
MyMainLOG = $"[{CInt(Responser.StatusCode)}] Reddit is currently unavailable ({ToString()})"
|
MyMainLOG = $"{ToStringForLog()}: [{CInt(Responser.StatusCode)}] Reddit is currently unavailable"
|
||||||
Throw New Plugin.ExitException With {.Silent = True}
|
Throw New Plugin.ExitException With {.Silent = True}
|
||||||
ElseIf .StatusCode = HttpStatusCode.GatewayTimeout Then
|
ElseIf .StatusCode = HttpStatusCode.GatewayTimeout Then '504
|
||||||
Return 1
|
Return 1
|
||||||
ElseIf .StatusCode = HttpStatusCode.Unauthorized Then
|
ElseIf .StatusCode = HttpStatusCode.Unauthorized Then '401
|
||||||
MyMainLOG = $"[{CInt(Responser.StatusCode)}] Reddit credentials expired ({ToString()})"
|
MyMainLOG = $"{ToStringForLog()}: [{CInt(Responser.StatusCode)}] Reddit credentials expired"
|
||||||
MySiteSettings.SessionInterrupted = True
|
MySiteSettings.SessionInterrupted = True
|
||||||
Throw New Plugin.ExitException With {.Silent = True}
|
Throw New Plugin.ExitException With {.Silent = True}
|
||||||
ElseIf .StatusCode = HttpStatusCode.InternalServerError Then
|
ElseIf .StatusCode = HttpStatusCode.InternalServerError Then '500
|
||||||
If Not IsNothing(EObj) AndAlso IsNumeric(EObj) AndAlso CInt(EObj) = HttpStatusCode.InternalServerError Then Return 1
|
If Not IsNothing(EObj) AndAlso IsNumeric(EObj) AndAlso CInt(EObj) = HttpStatusCode.InternalServerError Then Return 1
|
||||||
Return HttpStatusCode.InternalServerError
|
Return HttpStatusCode.InternalServerError
|
||||||
|
ElseIf .StatusCode = 429 AndAlso
|
||||||
|
((Not IsSavedPosts And CBool(MySiteSettings.UseTokenForTimelines.Value)) Or (IsSavedPosts And MySiteSettings.UseTokenForSavedPosts.Value)) AndAlso
|
||||||
|
Not MySiteSettings.CredentialsExists Then '429
|
||||||
|
MyMainLOG = $"{ToStringForLog()}: [{CInt(Responser.StatusCode)}] You should use OAuth authorization or disable " &
|
||||||
|
IIf(IsSavedPosts, "token usage for downloading saved posts", "the use of token and cookies for downloading timelines")
|
||||||
|
MySiteSettings.SessionInterrupted = True
|
||||||
|
Throw New Plugin.ExitException With {.Silent = True}
|
||||||
Else
|
Else
|
||||||
If Not FromPE Then LogError(ex, Message) : HasError = True
|
If Not FromPE Then LogError(ex, Message) : HasError = True
|
||||||
Return 0
|
Return 0
|
||||||
|
|||||||
@@ -304,14 +304,12 @@ Namespace API.ThisVid
|
|||||||
_TempMediaList.Add(New UserMedia(u) With {.Type = UserMedia.Types.VideoPre, .SpecialFolder = __SpecialFolder})
|
_TempMediaList.Add(New UserMedia(u) With {.Type = UserMedia.Types.VideoPre, .SpecialFolder = __SpecialFolder})
|
||||||
AddedCount += 1
|
AddedCount += 1
|
||||||
newPostsFound = True
|
newPostsFound = True
|
||||||
If pageRepeatSet Then pageRepeatSet = False : _PageVideosRepeat -= 1
|
|
||||||
If limit > 0 And AddedCount >= limit Then Exit Sub
|
If limit > 0 And AddedCount >= limit Then Exit Sub
|
||||||
ElseIf SessionPosts.Count > 0 AndAlso SessionPosts.Contains(u) Then
|
ElseIf SessionPosts.Count > 0 AndAlso SessionPosts.Contains(u) Then
|
||||||
prevPostsFound = True
|
prevPostsFound = True
|
||||||
If pageRepeatSet Then pageRepeatSet = False : _PageVideosRepeat -= 1
|
|
||||||
Continue For
|
Continue For
|
||||||
Else
|
Else
|
||||||
If _PageVideosRepeat > 2 Then
|
If _PageVideosRepeat >= 2 Then
|
||||||
Exit Sub
|
Exit Sub
|
||||||
ElseIf Not pageRepeatSet And Not newPostsFound Then
|
ElseIf Not pageRepeatSet And Not newPostsFound Then
|
||||||
pageRepeatSet = True
|
pageRepeatSet = True
|
||||||
@@ -320,12 +318,15 @@ Namespace API.ThisVid
|
|||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
Next
|
Next
|
||||||
|
If prevPostsFound And Not pageRepeatSet And Not newPostsFound Then pageRepeatSet = True : _PageVideosRepeat += 1
|
||||||
|
If prevPostsFound And newPostsFound And pageRepeatSet Then _PageVideosRepeat -= 1
|
||||||
SessionPosts.ListAddList(l, LNC)
|
SessionPosts.ListAddList(l, LNC)
|
||||||
l.Clear()
|
l.Clear()
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
If (Not IsUser And prevPostsFound And Not newPostsFound And Page < 1000) Or
|
If _PageVideosRepeat < 2 And
|
||||||
(Not cBefore = _TempMediaList.Count And (IsUser Or Page < 1000)) Then DownloadData(Page + 1, Model, Token)
|
((Not IsUser And prevPostsFound And Not newPostsFound And Page < 1000) Or
|
||||||
|
(Not cBefore = _TempMediaList.Count And (IsUser Or Page < 1000))) Then DownloadData(Page + 1, Model, Token)
|
||||||
Catch aex As ArgumentNullException When aex.HelpLink = 1
|
Catch aex As ArgumentNullException When aex.HelpLink = 1
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
ProcessException(ex, Token, $"videos downloading error [{URL}]")
|
ProcessException(ex, Token, $"videos downloading error [{URL}]")
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ Imports SCrawler.API.YouTube.Objects
|
|||||||
Imports PersonalUtilities.Functions.XML
|
Imports PersonalUtilities.Functions.XML
|
||||||
Imports PersonalUtilities.Functions.RegularExpressions
|
Imports PersonalUtilities.Functions.RegularExpressions
|
||||||
Imports PersonalUtilities.Tools
|
Imports PersonalUtilities.Tools
|
||||||
|
Imports PersonalUtilities.Tools.Web.Documents
|
||||||
Imports PersonalUtilities.Tools.Web.Documents.JSON
|
Imports PersonalUtilities.Tools.Web.Documents.JSON
|
||||||
Imports UStates = SCrawler.API.Base.UserMedia.States
|
Imports UStates = SCrawler.API.Base.UserMedia.States
|
||||||
Imports UTypes = SCrawler.API.Base.UserMedia.Types
|
Imports UTypes = SCrawler.API.Base.UserMedia.Types
|
||||||
@@ -154,6 +155,7 @@ Namespace API.Twitter
|
|||||||
Private Sub DownloadData_Timeline(ByVal Token As CancellationToken)
|
Private Sub DownloadData_Timeline(ByVal Token As CancellationToken)
|
||||||
Dim URL$ = String.Empty
|
Dim URL$ = String.Empty
|
||||||
Dim tCache As CacheKeeper = Nothing
|
Dim tCache As CacheKeeper = Nothing
|
||||||
|
Dim jsonArgs As New WebDocumentEventArgs With {.DeclaredError = EDP.ThrowException}
|
||||||
Try
|
Try
|
||||||
Const entry$ = "entry"
|
Const entry$ = "entry"
|
||||||
Dim PostID$ = String.Empty
|
Dim PostID$ = String.Empty
|
||||||
@@ -231,7 +233,8 @@ Namespace API.Twitter
|
|||||||
For i = 0 To timelineFiles.Count - 1 : timelineFiles(i) = RenameGdlFile(timelineFiles(i), i) : Next
|
For i = 0 To timelineFiles.Count - 1 : timelineFiles(i) = RenameGdlFile(timelineFiles(i), i) : Next
|
||||||
'parse files
|
'parse files
|
||||||
For i = 0 To timelineFiles.Count - 1
|
For i = 0 To timelineFiles.Count - 1
|
||||||
j = JsonDocument.Parse(timelineFiles(i).GetText)
|
j = JsonDocument.Parse(timelineFiles(i).GetText, jsonArgs)
|
||||||
|
jsonArgs.Reset()
|
||||||
If Not j Is Nothing Then
|
If Not j Is Nothing Then
|
||||||
If i = 0 Then
|
If i = 0 Then
|
||||||
If Not userInfoParsed Then
|
If Not userInfoParsed Then
|
||||||
@@ -339,12 +342,15 @@ Namespace API.Twitter
|
|||||||
End If
|
End If
|
||||||
DownloadModelForceApply = False
|
DownloadModelForceApply = False
|
||||||
FirstDownloadComplete = True
|
FirstDownloadComplete = True
|
||||||
|
Catch jsonNull_ex As ArgumentNullException When jsonArgs.State = WebDocumentEventArgs.States.Error
|
||||||
|
Throw New Plugin.ExitException($"{ToStringForLog()}: No deserialized data found")
|
||||||
Catch limit_ex As TwitterLimitException
|
Catch limit_ex As TwitterLimitException
|
||||||
Throw limit_ex
|
Throw limit_ex
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
ProcessException(ex, Token, $"data downloading error [{URL}]")
|
ProcessException(ex, Token, $"data downloading error [{URL}]")
|
||||||
Finally
|
Finally
|
||||||
If Not tCache Is Nothing Then tCache.Dispose()
|
If Not tCache Is Nothing Then tCache.Dispose()
|
||||||
|
jsonArgs.DisposeIfReady
|
||||||
If _TempPostsList.Count > 0 Then _TempPostsList.Sort()
|
If _TempPostsList.Count > 0 Then _TempPostsList.Sort()
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
|
|||||||
@@ -375,9 +375,9 @@ Namespace API.XVIDEOS
|
|||||||
_TempMediaList.ListAddList(data.Select(Function(d) d.ToUserMedia()), LNC)
|
_TempMediaList.ListAddList(data.Select(Function(d) d.ToUserMedia()), LNC)
|
||||||
newPostsFound = cBefore <> _TempMediaList.Count
|
newPostsFound = cBefore <> _TempMediaList.Count
|
||||||
ElseIf sessionPosts.Count > 0 AndAlso sessionPosts.ListContains(pids) Then
|
ElseIf sessionPosts.Count > 0 AndAlso sessionPosts.ListContains(pids) Then
|
||||||
If pageRepeatSet Then pageRepeatSet = False : pageVideosRepeat -= 1
|
prevPostsFound = True
|
||||||
Else
|
Else
|
||||||
If pageVideosRepeat > 2 Then
|
If pageVideosRepeat >= 2 Then
|
||||||
Exit Do
|
Exit Do
|
||||||
ElseIf Not pageRepeatSet And Not newPostsFound Then
|
ElseIf Not pageRepeatSet And Not newPostsFound Then
|
||||||
pageRepeatSet = True
|
pageRepeatSet = True
|
||||||
@@ -388,8 +388,10 @@ Namespace API.XVIDEOS
|
|||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
If limit > 0 And _TempMediaList.Count >= limit Then Exit Do
|
If limit > 0 And _TempMediaList.Count >= limit Then Exit Do
|
||||||
|
If prevPostsFound And Not pageRepeatSet And Not newPostsFound Then pageRepeatSet = True : pageVideosRepeat += 1
|
||||||
|
If prevPostsFound And newPostsFound And pageRepeatSet Then pageVideosRepeat -= 1
|
||||||
If IsSearch Then
|
If IsSearch Then
|
||||||
__continue = NextPage < 1000 And (newPostsFound Or (prevPostsFound And Not newPostsFound))
|
__continue = pageVideosRepeat < 2 And NextPage < 1000 And (newPostsFound Or (prevPostsFound And Not newPostsFound))
|
||||||
ElseIf __continue Then
|
ElseIf __continue Then
|
||||||
__continue = Not cBefore = _TempMediaList.Count
|
__continue = Not cBefore = _TempMediaList.Count
|
||||||
End If
|
End If
|
||||||
|
|||||||
@@ -308,7 +308,6 @@ Namespace API.Xhamster
|
|||||||
_TempMediaList.ListAddValue(m, LNC)
|
_TempMediaList.ListAddValue(m, LNC)
|
||||||
SearchPostsCount += 1
|
SearchPostsCount += 1
|
||||||
newPostsFound = True
|
newPostsFound = True
|
||||||
If pageRepeatSet Then pageRepeatSet = False : _PageVideosRepeat -= 1
|
|
||||||
If checkLimit.Invoke Then Exit Sub
|
If checkLimit.Invoke Then Exit Sub
|
||||||
ElseIf Not IsVideo Then
|
ElseIf Not IsVideo Then
|
||||||
If DirectCast(m.Object, ExchObj).IsPhoto Then
|
If DirectCast(m.Object, ExchObj).IsPhoto Then
|
||||||
@@ -322,9 +321,8 @@ Namespace API.Xhamster
|
|||||||
ElseIf IsVideo And _TempPostsList.Contains(m.Post.ID) Then
|
ElseIf IsVideo And _TempPostsList.Contains(m.Post.ID) Then
|
||||||
If SessionPosts.Count > 0 AndAlso SessionPosts.Contains(m.Post.ID) Then
|
If SessionPosts.Count > 0 AndAlso SessionPosts.Contains(m.Post.ID) Then
|
||||||
prevPostsFound = True
|
prevPostsFound = True
|
||||||
If pageRepeatSet Then pageRepeatSet = False : _PageVideosRepeat -= 1
|
|
||||||
Continue For
|
Continue For
|
||||||
ElseIf _PageVideosRepeat > 2 Then
|
ElseIf _PageVideosRepeat >= 2 Then
|
||||||
Exit Sub
|
Exit Sub
|
||||||
ElseIf Not pageRepeatSet And Not newPostsFound Then
|
ElseIf Not pageRepeatSet And Not newPostsFound Then
|
||||||
pageRepeatSet = True
|
pageRepeatSet = True
|
||||||
@@ -335,6 +333,8 @@ Namespace API.Xhamster
|
|||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
Next
|
Next
|
||||||
|
If prevPostsFound And Not pageRepeatSet And Not newPostsFound Then pageRepeatSet = True : _PageVideosRepeat += 1
|
||||||
|
If prevPostsFound And newPostsFound And pageRepeatSet Then _PageVideosRepeat -= 1
|
||||||
SessionPosts.ListAddList(pids, LNC)
|
SessionPosts.ListAddList(pids, LNC)
|
||||||
pids.Clear()
|
pids.Clear()
|
||||||
Exit For
|
Exit For
|
||||||
@@ -347,11 +347,11 @@ Namespace API.Xhamster
|
|||||||
|
|
||||||
containerNodes.Clear()
|
containerNodes.Clear()
|
||||||
|
|
||||||
If (
|
If _PageVideosRepeat < 2 And ((
|
||||||
(MaxPage = -1 Or Page < MaxPage) And
|
(MaxPage = -1 Or Page < MaxPage) And
|
||||||
((Not _TempMediaList.Count = cBefore Or skipped) And (IsUser Or Page < 1000))
|
((Not _TempMediaList.Count = cBefore Or skipped) And (IsUser Or Page < 1000))
|
||||||
) Or
|
) Or
|
||||||
(IsChannel Or (Not IsUser And Page < 1000 And prevPostsFound And Not newPostsFound)) Then DownloadData(Page + 1, IsVideo, Token)
|
(IsChannel Or (Not IsUser And Page < 1000 And prevPostsFound And Not newPostsFound))) Then DownloadData(Page + 1, IsVideo, Token)
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
ProcessException(ex, Token, $"data downloading error [{URL}]")
|
ProcessException(ex, Token, $"data downloading error [{URL}]")
|
||||||
End Try
|
End Try
|
||||||
|
|||||||
@@ -27,6 +27,15 @@ Namespace DownloadObjects
|
|||||||
Private ReadOnly PlansWaiter As Action(Of Predicate(Of AutoDownloader)) = Sub(ByVal Predicate As Predicate(Of AutoDownloader))
|
Private ReadOnly PlansWaiter As Action(Of Predicate(Of AutoDownloader)) = Sub(ByVal Predicate As Predicate(Of AutoDownloader))
|
||||||
While Plans.Exists(Predicate) : Thread.Sleep(200) : End While
|
While Plans.Exists(Predicate) : Thread.Sleep(200) : End While
|
||||||
End Sub
|
End Sub
|
||||||
|
Friend ReadOnly Property Name As String
|
||||||
|
Get
|
||||||
|
If Not File.Name.IsEmptyString AndAlso Not File.Name = FileNameDefault Then
|
||||||
|
Return File.Name.Replace(FileNameDefault, String.Empty).StringTrimStart("_").IfNullOrEmpty("Default")
|
||||||
|
Else
|
||||||
|
Return "Default"
|
||||||
|
End If
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
Friend Sub New()
|
Friend Sub New()
|
||||||
Plans = New List(Of AutoDownloader)
|
Plans = New List(Of AutoDownloader)
|
||||||
File = Settings.AutomationFile.Value.IfNullOrEmpty(FileDefault)
|
File = Settings.AutomationFile.Value.IfNullOrEmpty(FileDefault)
|
||||||
@@ -132,6 +141,10 @@ Namespace DownloadObjects
|
|||||||
Friend Async Function Start(ByVal Init As Boolean) As Task
|
Friend Async Function Start(ByVal Init As Boolean) As Task
|
||||||
Try
|
Try
|
||||||
Await Task.Run(Sub()
|
Await Task.Run(Sub()
|
||||||
|
Dim r% = 0
|
||||||
|
Do
|
||||||
|
r += 1
|
||||||
|
Try
|
||||||
If Count > 0 Then
|
If Count > 0 Then
|
||||||
If Plans.Exists(PlanDownloading) Then PlansWaiter(PlanDownloading)
|
If Plans.Exists(PlanDownloading) Then PlansWaiter(PlanDownloading)
|
||||||
For Each Plan In Plans
|
For Each Plan In Plans
|
||||||
@@ -140,6 +153,10 @@ Namespace DownloadObjects
|
|||||||
Thread.Sleep(1000)
|
Thread.Sleep(1000)
|
||||||
Next
|
Next
|
||||||
End If
|
End If
|
||||||
|
Exit Do
|
||||||
|
Catch io_ex As InvalidOperationException 'Collection was modified; enumeration operation may not execute
|
||||||
|
End Try
|
||||||
|
Loop While r < 10
|
||||||
End Sub)
|
End Sub)
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
If Init Then
|
If Init Then
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ Imports ADB = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons
|
|||||||
Namespace DownloadObjects
|
Namespace DownloadObjects
|
||||||
Friend Class SchedulerEditorForm
|
Friend Class SchedulerEditorForm
|
||||||
#Region "Declarations"
|
#Region "Declarations"
|
||||||
|
Private Const TitleDefault As String = "Scheduler"
|
||||||
Private WithEvents MyDefs As DefaultFormOptions
|
Private WithEvents MyDefs As DefaultFormOptions
|
||||||
Private WithEvents BTT_SETTINGS As ToolStripButton
|
Private WithEvents BTT_SETTINGS As ToolStripButton
|
||||||
Private WithEvents BTT_CLONE As ToolStripButton
|
Private WithEvents BTT_CLONE As ToolStripButton
|
||||||
@@ -110,6 +111,7 @@ Namespace DownloadObjects
|
|||||||
BTT_START, BTT_START_FORCE, MENU_SKIP, BTT_PAUSE})
|
BTT_START, BTT_START_FORCE, MENU_SKIP, BTT_PAUSE})
|
||||||
PauseArr.AddButtons(BTT_PAUSE, .MyEditToolbar.ToolStrip)
|
PauseArr.AddButtons(BTT_PAUSE, .MyEditToolbar.ToolStrip)
|
||||||
Refill()
|
Refill()
|
||||||
|
SetTitle()
|
||||||
.EndLoaderOperations(False)
|
.EndLoaderOperations(False)
|
||||||
End With
|
End With
|
||||||
End Sub
|
End Sub
|
||||||
@@ -138,6 +140,17 @@ Namespace DownloadObjects
|
|||||||
ErrorsDescriber.Execute(EDP.SendToLog, ex, "[DownloadObjects.SchedulerEditorForm.Refill]")
|
ErrorsDescriber.Execute(EDP.SendToLog, ex, "[DownloadObjects.SchedulerEditorForm.Refill]")
|
||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
|
Private Sub SetTitle()
|
||||||
|
Try
|
||||||
|
If GetSchedulerFiles.ListExists(2) Then
|
||||||
|
Text = $"{TitleDefault} [{Settings.Automation.Name}]"
|
||||||
|
Else
|
||||||
|
Text = TitleDefault
|
||||||
|
End If
|
||||||
|
Catch ex As Exception
|
||||||
|
ErrorsDescriber.Execute(EDP.SendToLog, ex, "[SchedulerEditorForm.SetTitle]")
|
||||||
|
End Try
|
||||||
|
End Sub
|
||||||
#Region "Add, Edit, Delete"
|
#Region "Add, Edit, Delete"
|
||||||
Private Sub MyDefs_ButtonAddClick(ByVal Sender As Object, ByVal e As EventArgs) Handles MyDefs.ButtonAddClick, BTT_CLONE.Click
|
Private Sub MyDefs_ButtonAddClick(ByVal Sender As Object, ByVal e As EventArgs) Handles MyDefs.ButtonAddClick, BTT_CLONE.Click
|
||||||
Dim a As AutoDownloader = Nothing
|
Dim a As AutoDownloader = Nothing
|
||||||
@@ -199,12 +212,15 @@ Namespace DownloadObjects
|
|||||||
End Sub
|
End Sub
|
||||||
#End Region
|
#End Region
|
||||||
#Region "Settings, Start, Skip, Pause"
|
#Region "Settings, Start, Skip, Pause"
|
||||||
|
Private Function GetSchedulerFiles() As List(Of SFile)
|
||||||
|
Return SFile.GetFiles(SettingsFolderName.CSFileP, $"{Scheduler.FileNameDefault}*.xml",, EDP.ReturnValue)
|
||||||
|
End Function
|
||||||
Private Sub BTT_SETTINGS_Click(sender As Object, e As EventArgs) Handles BTT_SETTINGS.Click
|
Private Sub BTT_SETTINGS_Click(sender As Object, e As EventArgs) Handles BTT_SETTINGS.Click
|
||||||
Const msgTitle$ = "Change scheduler"
|
Const msgTitle$ = "Change scheduler"
|
||||||
Try
|
Try
|
||||||
Const defName$ = "Default"
|
Const defName$ = "Default"
|
||||||
Dim l As New Dictionary(Of SFile, String)
|
Dim l As New Dictionary(Of SFile, String)
|
||||||
With SFile.GetFiles(SettingsFolderName.CSFileP, $"{Scheduler.FileNameDefault}*.xml",, EDP.ReturnValue)
|
With GetSchedulerFiles()
|
||||||
If .ListExists Then .ForEach(Sub(ff) l.Add(ff, ff.Name.Replace(Scheduler.FileNameDefault, String.Empty).StringTrimStart("_").IfNullOrEmpty(defName)))
|
If .ListExists Then .ForEach(Sub(ff) l.Add(ff, ff.Name.Replace(Scheduler.FileNameDefault, String.Empty).StringTrimStart("_").IfNullOrEmpty(defName)))
|
||||||
End With
|
End With
|
||||||
If l.Count > 0 Then
|
If l.Count > 0 Then
|
||||||
@@ -260,6 +276,7 @@ Namespace DownloadObjects
|
|||||||
Next
|
Next
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
|
SetTitle()
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
End With
|
End With
|
||||||
|
|||||||
@@ -218,13 +218,17 @@ Namespace DownloadObjects
|
|||||||
If Not BTT_STOP Is Nothing Then BTT_STOP.Dispose()
|
If Not BTT_STOP Is Nothing Then BTT_STOP.Dispose()
|
||||||
If Not BTT_OPEN Is Nothing Then BTT_OPEN.Dispose()
|
If Not BTT_OPEN Is Nothing Then BTT_OPEN.Dispose()
|
||||||
If Not Icon Is Nothing Then Icon.Dispose()
|
If Not Icon Is Nothing Then Icon.Dispose()
|
||||||
PR_MAIN.Dispose()
|
PR_MAIN.DisposeIfReady()
|
||||||
LBL_INFO.Dispose()
|
LBL_INFO.DisposeIfReady()
|
||||||
|
If Not TP_CONTROLS Is Nothing Then
|
||||||
TP_CONTROLS.Controls.Clear()
|
TP_CONTROLS.Controls.Clear()
|
||||||
TP_CONTROLS.Dispose()
|
TP_CONTROLS.Dispose()
|
||||||
|
End If
|
||||||
|
If Not TP_MAIN Is Nothing Then
|
||||||
TP_MAIN.Controls.Clear()
|
TP_MAIN.Controls.Clear()
|
||||||
TP_MAIN.Dispose()
|
TP_MAIN.Dispose()
|
||||||
End If
|
End If
|
||||||
|
End If
|
||||||
disposedValue = True
|
disposedValue = True
|
||||||
End If
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
|
|||||||
@@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices
|
|||||||
' by using the '*' as shown below:
|
' by using the '*' as shown below:
|
||||||
' <Assembly: AssemblyVersion("1.0.*")>
|
' <Assembly: AssemblyVersion("1.0.*")>
|
||||||
|
|
||||||
<Assembly: AssemblyVersion("2023.11.17.0")>
|
<Assembly: AssemblyVersion("2023.11.24.0")>
|
||||||
<Assembly: AssemblyFileVersion("2023.11.17.0")>
|
<Assembly: AssemblyFileVersion("2023.11.24.0")>
|
||||||
<Assembly: NeutralResourcesLanguage("en")>
|
<Assembly: NeutralResourcesLanguage("en")>
|
||||||
|
|||||||
@@ -41,9 +41,7 @@ Friend Class UserSearchForm
|
|||||||
End If
|
End If
|
||||||
End Function
|
End Function
|
||||||
Public Overrides Function Equals(ByVal Obj As Object) As Boolean
|
Public Overrides Function Equals(ByVal Obj As Object) As Boolean
|
||||||
'TODO: [UserSearchForm]: updated equal function
|
|
||||||
With DirectCast(Obj, SearchResult) : Return Key = .Key : End With
|
With DirectCast(Obj, SearchResult) : Return Key = .Key : End With
|
||||||
'With DirectCast(Obj, SearchResult) : Return Key = .Key And Mode = .Mode : End With
|
|
||||||
End Function
|
End Function
|
||||||
End Structure
|
End Structure
|
||||||
Public Sub New()
|
Public Sub New()
|
||||||
|
|||||||
Reference in New Issue
Block a user