Compare commits

...

2 Commits

Author SHA1 Message Date
Andy
5b5857e31d 2024.4.14.0
Delete old notes and comments
API.Facebook: add app-id extraction from page; remove app-id from site requirements; update tokens parsing; update tokens regex
API.Instagram: add default function to parse tokens
2024-04-14 07:44:05 +03:00
Andy
46372ec9fb 2024.4.13.0
YT
Add subtitles to information about downloaded files

PluginProvider
IPluginContentProvider: add 'ResetHistoryData' function

SCrawler
UserDataBase: call 'UpdateUsersList' when 'UpdateUserInformation' with argument 'OnlyDiff'; implement 'ResetHistoryData' function; set 'LastUpdated' to null and 'UpdateUserInformation' when erasing history data
API.Instagram: set 'FirstLoadingDone' to false when erasing history data; fix broken saved posts downloading
API.TikTok: set 'LastDownloadDate' to null when erasing history data
API.YouTube: set last download dates to null when erasing history data
GroupUsersViewer: add the number of users, object type and object name to the form title; add 'F1' to help hint; add '(Alt+)F3' to edit user
AutoDownloaderEditorForm, SchedulerEditorForm, GroupEditorForm, GroupListForm: update to 'GroupUsersViewer'
MainFrame: make 'EditSelectedUser' friend
UserDataHost: implement 'ResetHistoryData' function
SettingsCLS: add 'OnlyDiff' to the 'UpdateUsersList' function
UserInfo: add 'ExactEquals' shared function
2024-04-13 10:10:27 +03:00
30 changed files with 213 additions and 136 deletions

View File

@@ -1,3 +1,24 @@
# 2024.4.14.0
*2024-04-14*
- Fixed
- Facebook: can't get tokens
# 2024.4.13.0
*2024-04-13*
- Added
- Minor improvements
- PluginProvider
- IPluginContentProvider: added `ResetHistoryData` function
- Fixed
- Sites
- TikTok: remove last download date when erasing history data
- YouTube: remove last download date when erasing history data
- Instagram: **saved posts aren't downloading**
# 2024.4.10.0 # 2024.4.10.0
*2024-04-10* *2024-04-10*

View File

@@ -40,5 +40,6 @@ Namespace Plugin
Sub GetMedia(ByVal Token As Threading.CancellationToken) Sub GetMedia(ByVal Token As Threading.CancellationToken)
Sub Download(ByVal Token As Threading.CancellationToken) Sub Download(ByVal Token As Threading.CancellationToken)
Sub DownloadSingleObject(ByVal Data As IDownloadableMedia, ByVal Token As Threading.CancellationToken) Sub DownloadSingleObject(ByVal Data As IDownloadableMedia, ByVal Token As Threading.CancellationToken)
Sub ResetHistoryData()
End Interface End Interface
End Namespace End Namespace

View File

@@ -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("2024.4.10.0")> <Assembly: AssemblyVersion("2024.4.13.0")>
<Assembly: AssemblyFileVersion("2024.4.10.0")> <Assembly: AssemblyFileVersion("2024.4.13.0")>
<Assembly: NeutralResourcesLanguage("en")> <Assembly: NeutralResourcesLanguage("en")>

View File

@@ -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("2024.4.10.0")> <Assembly: AssemblyVersion("2024.4.14.0")>
<Assembly: AssemblyFileVersion("2024.4.10.0")> <Assembly: AssemblyFileVersion("2024.4.14.0")>
<Assembly: NeutralResourcesLanguage("en")> <Assembly: NeutralResourcesLanguage("en")>

View File

@@ -709,7 +709,7 @@ Namespace API.YouTube.Objects
Bitrate = 0 Bitrate = 0
_MediaType = UMTypes.Undefined _MediaType = UMTypes.Undefined
If SelectedVideoIndex >= 0 Then If SelectedVideoIndex >= 0 Then
'URGENT: 2023.3.4 -> 2023.7.6 '2023.3.4 -> 2023.7.6
'cmd.StringAppend($"bv*[format_id={SelectedVideo.ID}]") 'cmd.StringAppend($"bv*[format_id={SelectedVideo.ID}]")
cmd.StringAppend(SelectedVideo.ID) cmd.StringAppend(SelectedVideo.ID)
_Size = SelectedVideo.Size _Size = SelectedVideo.Size
@@ -726,7 +726,7 @@ Namespace API.YouTube.Objects
End If End If
If SelectedAudioIndex >= 0 Then If SelectedAudioIndex >= 0 Then
Dim atCodec$ Dim atCodec$
'URGENT: 2023.3.4 -> 2023.7.6 '2023.3.4 -> 2023.7.6
'cmd.StringAppend($"ba*[format_id={SelectedAudio.ID}]", "+") 'cmd.StringAppend($"ba*[format_id={SelectedAudio.ID}]", "+")
cmd.StringAppend(SelectedAudio.ID, "+") cmd.StringAppend(SelectedAudio.ID, "+")
If OutputAudioCodec.StringToLower = ac3 Then If OutputAudioCodec.StringToLower = ac3 Then
@@ -769,7 +769,7 @@ Namespace API.YouTube.Objects
subs = $"--write-subs --write-auto-subs --sub-format {OutputSubtitlesFormat.StringToLower} --sub-langs ""{subs}"" --convert-subs {OutputSubtitlesFormat.StringToLower}" subs = $"--write-subs --write-auto-subs --sub-format {OutputSubtitlesFormat.StringToLower} --sub-langs ""{subs}"" --convert-subs {OutputSubtitlesFormat.StringToLower}"
End If End If
If Not cmd.IsEmptyString Then If Not cmd.IsEmptyString Then
'URGENT: 2023.3.4 -> 2023.7.6 '2023.3.4 -> 2023.7.6
'cmd = $"yt-dlp -f ""{cmd}""" 'cmd = $"yt-dlp -f ""{cmd}"""
'cmd = $"yt-dlp -f {cmd}" 'cmd = $"yt-dlp -f {cmd}"
cmd = $"{YTDLP_NAME} -f {cmd}" cmd = $"{YTDLP_NAME} -f {cmd}"
@@ -1219,19 +1219,21 @@ Namespace API.YouTube.Objects
'Subtitles 'Subtitles
ThrowAny(Token) ThrowAny(Token)
If PostProcessing_OutputSubtitlesFormats.Count > 0 Then If SubtitlesSelectedIndexes.Count > 0 And Not OutputSubtitlesFormat.IsEmptyString Then
files = SFile.GetFiles(File, String.Format(fPatternFiles, OutputSubtitlesFormat.StringToLower),, EDP.ReturnValue) files = SFile.GetFiles(File, String.Format(fPatternFiles, OutputSubtitlesFormat.StringToLower),, EDP.ReturnValue)
AddFile(files)
If files.ListExists Then If files.ListExists Then
For Each f In files AddFile(files)
For Each format In PostProcessing_OutputSubtitlesFormats If PostProcessing_OutputSubtitlesFormats.Count > 0 Then
format = format.StringToLower For Each f In files
commandFile = $"{f.PathWithSeparator}{f.Name}.{format}" For Each format In PostProcessing_OutputSubtitlesFormats
AddFile(commandFile) format = format.StringToLower
ThrowAny(Token) commandFile = $"{f.PathWithSeparator}{f.Name}.{format}"
.Execute($"ffmpeg -i ""{f}"" ""{commandFile}""") AddFile(commandFile)
ThrowAny(Token)
.Execute($"ffmpeg -i ""{f}"" ""{commandFile}""")
Next
Next Next
Next End If
End If End If
End If End If

View File

@@ -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("2024.4.10.0")> <Assembly: AssemblyVersion("2024.4.14.0")>
<Assembly: AssemblyFileVersion("2024.4.10.0")> <Assembly: AssemblyFileVersion("2024.4.14.0")>
<Assembly: NeutralResourcesLanguage("en")> <Assembly: NeutralResourcesLanguage("en")>

View File

@@ -1001,7 +1001,7 @@ BlockNullPicture:
x.Save(MyFileSettings) x.Save(MyFileSettings)
End Using End Using
If Not IsSavedPosts Then Settings.UpdateUsersList(User) If Not IsSavedPosts Then Settings.UpdateUsersList(User, True)
Catch ex As Exception Catch ex As Exception
LogError(ex, "user information saving error") LogError(ex, "user information saving error")
End Try End Try
@@ -1894,7 +1894,9 @@ BlockNullPicture:
If m.Contains(IUserData.EraseMode.History) Then If m.Contains(IUserData.EraseMode.History) Then
If MyFilePosts.Delete(SFO.File, SFODelete.DeleteToRecycleBin, e) Then result = True If MyFilePosts.Delete(SFO.File, SFODelete.DeleteToRecycleBin, e) Then result = True
If MyFileData.Delete(SFO.File, SFODelete.DeleteToRecycleBin, e) Then result = True If MyFileData.Delete(SFO.File, SFODelete.DeleteToRecycleBin, e) Then result = True
LastUpdated = Nothing
EraseData_AdditionalDataFiles() EraseData_AdditionalDataFiles()
UpdateUserInformation()
End If End If
If m.Contains(IUserData.EraseMode.Data) Then If m.Contains(IUserData.EraseMode.Data) Then
Dim files As List(Of SFile) = SFile.GetFiles(DownloadContentDefault_GetRootDir.CSFileP,, SearchOption.AllDirectories, e) Dim files As List(Of SFile) = SFile.GetFiles(DownloadContentDefault_GetRootDir.CSFileP,, SearchOption.AllDirectories, e)
@@ -1916,7 +1918,7 @@ BlockNullPicture:
Return ErrorsDescriber.Execute(EDP.SendToLog + EDP.ReturnValue, ex, $"EraseData({CInt(Mode)}): {ToStringForLog()}", False) Return ErrorsDescriber.Execute(EDP.SendToLog + EDP.ReturnValue, ex, $"EraseData({CInt(Mode)}): {ToStringForLog()}", False)
End Try End Try
End Function End Function
Protected Overridable Sub EraseData_AdditionalDataFiles() Protected Overridable Sub EraseData_AdditionalDataFiles() Implements IPluginContentProvider.ResetHistoryData
End Sub End Sub
Friend Overridable Function Delete(Optional ByVal Multiple As Boolean = False, Optional ByVal CollectionValue As Integer = -1) As Integer Implements IUserData.Delete Friend Overridable Function Delete(Optional ByVal Multiple As Boolean = False, Optional ByVal CollectionValue As Integer = -1) As Integer Implements IUserData.Delete
Dim f As SFile = SFile.GetPath(MyFile.CutPath.Path) Dim f As SFile = SFile.GetPath(MyFile.CutPath.Path)

View File

@@ -11,9 +11,8 @@ Imports PersonalUtilities.Functions.XML.Base
Imports PersonalUtilities.Functions.RegularExpressions Imports PersonalUtilities.Functions.RegularExpressions
Namespace API.Facebook Namespace API.Facebook
Friend Module Declarations Friend Module Declarations
Friend ReadOnly Regex_UserToken_dtsg As RParams = RParams.DMS("DTSGInitialData.:.?{\s*.token.:\s*""([^""]+)", 1, EDP.ReturnValue)
Friend ReadOnly Regex_UserToken_lsd As RParams = RParams.DMS("LSD.:.?{\s*.token.:\s*""([^""]+)", 1, EDP.ReturnValue)
Friend ReadOnly Regex_UserID As RParams = RParams.DMS("userid.:.(\d+)", 1, RegexOptions.IgnoreCase, EDP.ReturnValue) Friend ReadOnly Regex_UserID As RParams = RParams.DMS("userid.:.(\d+)", 1, RegexOptions.IgnoreCase, EDP.ReturnValue)
Friend ReadOnly Regex_AppID As RParams = RParams.DMS("APP_ID.:.(\d+)", 1, RegexOptions.IgnoreCase, EDP.ReturnValue)
Friend ReadOnly Regex_Photos_by As RParams = RParams.DMS("photos_by"",""id"":""([^""]+)", 1, EDP.ReturnValue) Friend ReadOnly Regex_Photos_by As RParams = RParams.DMS("photos_by"",""id"":""([^""]+)", 1, EDP.ReturnValue)
Friend ReadOnly Regex_FileName As RParams = RParams.DM("([^/\?]+\..{3,4})(?=(\?|\Z))", 0, EDP.ReturnValue) Friend ReadOnly Regex_FileName As RParams = RParams.DM("([^/\?]+\..{3,4})(?=(\?|\Z))", 0, EDP.ReturnValue)

View File

@@ -18,7 +18,7 @@ Namespace API.Facebook
#Region "Auth" #Region "Auth"
<PropertyOption(AllowNull:=False, ControlText:="Accept", ControlToolTip:="Header 'Accept'", IsAuth:=True), ControlNumber(21), PXML, PClonable> <PropertyOption(AllowNull:=False, ControlText:="Accept", ControlToolTip:="Header 'Accept'", IsAuth:=True), ControlNumber(21), PXML, PClonable>
Friend ReadOnly Property Header_Accept As PropertyValue Friend ReadOnly Property Header_Accept As PropertyValue
<PropertyOption(ControlText:="x-ig-app-id", AllowNull:=True, IsAuth:=True)> <PropertyOption(ControlText:="x-ig-app-id", AllowNull:=True, IsAuth:=True), HiddenControl>
Friend Overrides ReadOnly Property HH_IG_APP_ID As PropertyValue Friend Overrides ReadOnly Property HH_IG_APP_ID As PropertyValue
Get Get
Return __HH_IG_APP_ID Return __HH_IG_APP_ID
@@ -74,7 +74,7 @@ Namespace API.Facebook
#End Region #End Region
#Region "BaseAuthExists, GetUserUrl, GetUserPostUrl, IsMyUser, IsMyImageVideo" #Region "BaseAuthExists, GetUserUrl, GetUserPostUrl, IsMyUser, IsMyImageVideo"
Friend Overrides Function BaseAuthExists() As Boolean Friend Overrides Function BaseAuthExists() As Boolean
Return Responser.CookiesExists And ACheck(HH_IG_APP_ID.Value) And CBool(DownloadData_Impl.Value) Return Responser.CookiesExists And CBool(DownloadData_Impl.Value) 'And ACheck(HH_IG_APP_ID.Value)
End Function End Function
Friend Overrides Function GetUserUrl(ByVal User As IPluginContentProvider) As String Friend Overrides Function GetUserUrl(ByVal User As IPluginContentProvider) As String
Return DirectCast(User, UserData).GetProfileUrl Return DirectCast(User, UserData).GetProfileUrl

View File

@@ -136,6 +136,7 @@ Namespace API.Facebook
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken) Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
If CBool(MySettings.DownloadData_Impl.Value) Then If CBool(MySettings.DownloadData_Impl.Value) Then
Try Try
If Responser.Headers.Value(IG.Header_IG_APP_ID).IsEmptyString Then Responser.Headers.Remove(IG.Header_IG_APP_ID)
ResetBaseTokens() ResetBaseTokens()
GetUserTokens(Token) GetUserTokens(Token)
LoadSavePostsKV(True) LoadSavePostsKV(True)
@@ -529,8 +530,14 @@ Namespace API.Facebook
Dim r$ = resp.GetResponse(URL) Dim r$ = resp.GetResponse(URL)
If Not r.IsEmptyString Then If Not r.IsEmptyString Then
If Responser.CookiesExists Then Responser.Cookies.Update(resp.Cookies) If Responser.CookiesExists Then Responser.Cookies.Update(resp.Cookies)
Token_dtsg = RegexReplace(r, Regex_UserToken_dtsg) ParseTokens(r, 0)
Token_lsd = RegexReplace(r, Regex_UserToken_lsd) Dim app_id$ = RegexReplace(r, Regex_AppID)
If Not app_id.IsEmptyString Then
If Not AEquals(Of String)(MySettings.HH_IG_APP_ID.Value, app_id) Then
MySettings.HH_IG_APP_ID.Value = app_id
Responser.Headers.Add(IG.Header_IG_APP_ID, app_id)
End If
End If
Token_Photosby = RegexReplace(r, Regex_Photos_by) Token_Photosby = RegexReplace(r, Regex_Photos_by)
If StoryBucket.IsEmptyString Then StoryBucket = RegexReplace(r, Regex_StoryBucket) If StoryBucket.IsEmptyString Then StoryBucket = RegexReplace(r, Regex_StoryBucket)
If ID.IsEmptyString Then If ID.IsEmptyString Then
@@ -568,14 +575,14 @@ Namespace API.Facebook
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecFetchSite, "none")) .Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecFetchSite, "none"))
.Add("Sec-Fetch-User", "?1") .Add("Sec-Fetch-User", "?1")
.Add("Upgrade-Insecure-Requests", 1) .Add("Upgrade-Insecure-Requests", 1)
Dim h$ = Responser.Headers.Value(IG.Header_Browser) Dim cloneHeader As Action(Of String) = Sub(ByVal hName As String)
If Not h.IsEmptyString Then .Add(IG.Header_Browser, h) Dim hValue$ = Responser.Headers.Value(hName)
h = Responser.Headers.Value(IG.Header_BrowserExt) If Not hValue.IsEmptyString Then .Add(hName, hValue)
If Not h.IsEmptyString Then .Add(IG.Header_BrowserExt, h) End Sub
h = Responser.Headers.Value(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecChUaPlatform)) cloneHeader.Invoke(IG.Header_Browser)
If Not h.IsEmptyString Then .Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecChUaPlatform, h)) cloneHeader.Invoke(IG.Header_BrowserExt)
h = Responser.Headers.Value(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecChUaPlatformVersion)) cloneHeader.Invoke(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecChUaPlatform).Name)
If Not h.IsEmptyString Then .Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecChUaPlatformVersion, h)) cloneHeader.Invoke(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecChUaPlatformVersion).Name)
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecChUaMobile, "?0")) .Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecChUaMobile, "?0"))
.Add("Sec-Ch-Ua-Model", "") .Add("Sec-Ch-Ua-Model", "")
End With End With

View File

@@ -18,6 +18,8 @@ Namespace API.Instagram
Friend ReadOnly ObtainMedia_SizeFuncPic_RegexP As RParams = RParams.DMS("_p(\d+)x(\d+)", 1, EDP.ReturnValue) Friend ReadOnly ObtainMedia_SizeFuncPic_RegexP As RParams = RParams.DMS("_p(\d+)x(\d+)", 1, EDP.ReturnValue)
Friend ReadOnly ObtainMedia_SizeFuncPic_RegexS As RParams = RParams.DMS("_s(\d+)x(\d+)", 1, EDP.ReturnValue) Friend ReadOnly ObtainMedia_SizeFuncPic_RegexS As RParams = RParams.DMS("_s(\d+)x(\d+)", 1, EDP.ReturnValue)
Friend Const PageTokenRegexPatternDefault As String = "\[\],{""token"":""(.*?)""},\d+\]" Friend Const PageTokenRegexPatternDefault As String = "\[\],{""token"":""(.*?)""},\d+\]"
Friend ReadOnly Regex_UserToken_dtsg As RParams = RParams.DMS("DTSGInitialData["":,.\[\]]*?{\s*.token.:\s*""([^""]+)", 1, EDP.ReturnValue)
Friend ReadOnly Regex_UserToken_lsd As RParams = RParams.DMS("LSD["":,.\[\]]*?{\s*.token.:\s*""([^""]+)", 1, EDP.ReturnValue)
Friend Sub UpdateResponser(ByVal Source As IResponse, ByRef Destination As Responser, ByVal UpdateWwwClaim As Boolean) Friend Sub UpdateResponser(ByVal Source As IResponse, ByRef Destination As Responser, ByVal UpdateWwwClaim As Boolean)
Const r_wwwClaimName$ = "x-ig-set-www-claim" Const r_wwwClaimName$ = "x-ig-set-www-claim"
Const r_tokenName$ = SiteSettings.Header_CSRF_TOKEN_COOKIE Const r_tokenName$ = SiteSettings.Header_CSRF_TOKEN_COOKIE

View File

@@ -297,37 +297,51 @@ Namespace API.Instagram
End With End With
End With End With
Dim r$ = Responser.GetResponse(MySiteSettings.GetUserUrl(Me)) Dim r$ = Responser.GetResponse(MySiteSettings.GetUserUrl(Me))
If Not r.IsEmptyString Then ParseTokens(r, 0)
Dim rr As RParams = RParams.DM(PageTokenRegexPatternDefault, 0, RegexReturn.List, EDP.ReturnValue)
Dim tokens As List(Of String) = RegexReplace(r, rr)
Dim tt$, ttVal$
If tokens.ListExists Then
With rr
.Match = Nothing
.MatchSub = 1
.WhatGet = RegexReturn.Value
End With
For Each tt In tokens
If Not Token_lsd.IsEmptyString And Not Token_dtsg.IsEmptyString Then
Exit For
Else
ttVal = RegexReplace(tt, rr)
If Not ttVal.IsEmptyString Then
If ttVal.Contains(":") Then
If Token_dtsg.IsEmptyString Then Token_dtsg = ttVal
Else
If Token_lsd.IsEmptyString Then Token_lsd = ttVal
End If
End If
End If
Next
End If
End If
Catch ex As Exception Catch ex As Exception
Finally Finally
ChangeResponserMode(_UseGQL, Not _UseGQL) ChangeResponserMode(_UseGQL, Not _UseGQL)
End Try End Try
End Sub End Sub
Protected Sub ParseTokens(ByVal r As String, ByVal Attempt As Integer)
Try
If Not r.IsEmptyString Then
ResetBaseTokens()
Select Case Attempt
Case 0
Dim rr As RParams = RParams.DM(PageTokenRegexPatternDefault, 0, RegexReturn.List, EDP.ReturnValue)
Dim tokens As List(Of String) = RegexReplace(r, rr)
Dim tt$, ttVal$
If tokens.ListExists Then
With rr
.Match = Nothing
.MatchSub = 1
.WhatGet = RegexReturn.Value
End With
For Each tt In tokens
If Not Token_lsd.IsEmptyString And Not Token_dtsg.IsEmptyString Then
Exit For
Else
ttVal = RegexReplace(tt, rr)
If Not ttVal.IsEmptyString Then
If ttVal.Contains(":") Then
If Token_dtsg.IsEmptyString Then Token_dtsg = ttVal
Else
If Token_lsd.IsEmptyString Then Token_lsd = ttVal
End If
End If
End If
Next
End If
Case 1
Token_dtsg = RegexReplace(r, Regex_UserToken_dtsg)
Token_lsd = RegexReplace(r, Regex_UserToken_lsd)
End Select
If Not ValidateBaseTokens() And Attempt = 0 Then ParseTokens(r, Attempt + 1)
End If
Catch
End Try
End Sub
#End Region #End Region
End Class End Class
End Namespace End Namespace

View File

@@ -886,8 +886,8 @@ NextPageBlock:
PostIDKV = New PostKV(.Value("code"), .Value("id"), Section) PostIDKV = New PostKV(.Value("code"), .Value("id"), Section)
PostOriginUrl = DefaultParser_PostUrlCreator(PostIDKV) PostOriginUrl = DefaultParser_PostUrlCreator(PostIDKV)
Pinned = .Contains("timeline_pinned_user_ids") Pinned = .Contains("timeline_pinned_user_ids")
If (Section = Sections.Timeline And Not DefaultParser_IgnorePass) AndAlso PostKvExists(PostIDKV) Then If Not DefaultParser_IgnorePass AndAlso PostKvExists(PostIDKV) Then
If Not Pinned Then Return False If Not Section = Sections.Timeline OrElse Not Pinned Then Return False
Else Else
_TempPostsList.Add(PostIDKV.ID) _TempPostsList.Add(PostIDKV.ID)
PostsKVIDs.ListAddValue(PostIDKV, LNC) PostsKVIDs.ListAddValue(PostIDKV, LNC)
@@ -1233,6 +1233,7 @@ NextPageBlock:
Protected Overrides Sub EraseData_AdditionalDataFiles() Protected Overrides Sub EraseData_AdditionalDataFiles()
Dim f As SFile = MyFilePostsKV Dim f As SFile = MyFilePostsKV
If f.Exists Then f.Delete(SFO.File, SFODelete.DeleteToRecycleBin, EDP.ReturnValue) If f.Exists Then f.Delete(SFO.File, SFODelete.DeleteToRecycleBin, EDP.ReturnValue)
FirstLoadingDone = False
End Sub End Sub
#End Region #End Region
#Region "Exceptions" #Region "Exceptions"

View File

@@ -29,7 +29,6 @@ Namespace API.PornHub
Private Const Name_DownloadFavorite As String = "DownloadFavorite" Private Const Name_DownloadFavorite As String = "DownloadFavorite"
Private Const Name_DownloadGifs As String = "DownloadGifs" Private Const Name_DownloadGifs As String = "DownloadGifs"
Private Const Name_DownloadPhotoOnlyFromModelHub As String = "DownloadPhotoOnlyFromModelHub" Private Const Name_DownloadPhotoOnlyFromModelHub As String = "DownloadPhotoOnlyFromModelHub"
<Obsolete> Private Const Name_IsUser As String = "IsUser"
#End Region #End Region
#Region "Structures" #Region "Structures"
Private Structure FlashVar : Implements IRegExCreator Private Structure FlashVar : Implements IRegExCreator
@@ -254,14 +253,7 @@ Namespace API.PornHub
DownloadFavorite = .Value(Name_DownloadFavorite).FromXML(Of Boolean)(False) DownloadFavorite = .Value(Name_DownloadFavorite).FromXML(Of Boolean)(False)
DownloadGifs = .Value(Name_DownloadGifs).FromXML(Of Integer)(False) DownloadGifs = .Value(Name_DownloadGifs).FromXML(Of Integer)(False)
DownloadPhotoOnlyFromModelHub = .Value(Name_DownloadPhotoOnlyFromModelHub).FromXML(Of Boolean)(True) DownloadPhotoOnlyFromModelHub = .Value(Name_DownloadPhotoOnlyFromModelHub).FromXML(Of Boolean)(True)
If .Contains(Name_SiteMode) Then SiteMode = .Value(Name_SiteMode).FromXML(Of Integer)(SiteModes.User)
SiteMode = .Value(Name_SiteMode).FromXML(Of Integer)(SiteModes.User)
Else
'TODELETE: PornHub 'IsUser' 20231113
#Disable Warning BC40008
SiteMode = IIf(.Value(Name_IsUser).FromXML(Of Boolean)(True), SiteModes.User, SiteModes.Search)
#Enable Warning
End If
UpdateUserOptions() UpdateUserOptions()
Else Else
If UpdateUserOptions() Then .Value(Name_LabelsName) = LabelsString If UpdateUserOptions() Then .Value(Name_LabelsName) = LabelsString
@@ -404,7 +396,6 @@ Namespace API.PornHub
Dim r$ = Responser.GetResponse(URL) Dim r$ = Responser.GetResponse(URL)
If Not r.IsEmptyString Then If Not r.IsEmptyString Then
Dim l As List(Of UserVideo) = RegexFields(Of UserVideo)(r, {RegexUserVideos}, {6, 7, 3, 10}) Dim l As List(Of UserVideo) = RegexFields(Of UserVideo)(r, {RegexUserVideos}, {6, 7, 3, 10})
'URGENT: PornHub: changed list trimming
'If l.ListExists And Not SiteMode = SiteModes.Playlists Then l = l.ListTake(3, l.Count).ToList 'If l.ListExists And Not SiteMode = SiteModes.Playlists Then l = l.ListTake(3, l.Count).ToList
If l.ListExists And Not SiteMode = SiteModes.Playlists Then l = l.ListTake(1, l.Count).ToList If l.ListExists And Not SiteMode = SiteModes.Playlists Then l = l.ListTake(1, l.Count).ToList
If l.ListExists Then If l.ListExists Then

View File

@@ -103,8 +103,6 @@ Namespace API.ThreadsNet
With Responser With Responser
.Accept = "*/*" .Accept = "*/*"
'URGENT: remove after debug
.DeclaredError = EDP.SendToLog + EDP.ThrowException
If .UserAgentExists Then useragent = .UserAgent If .UserAgentExists Then useragent = .UserAgent
With .Headers With .Headers
If .Count > 0 Then If .Count > 0 Then
@@ -125,6 +123,8 @@ Namespace API.ThreadsNet
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecFetchMode, "cors")) .Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecFetchMode, "cors"))
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecFetchSite, "same-origin")) .Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecFetchSite, "same-origin"))
.Add("Sec-Fetch-User", "?1") .Add("Sec-Fetch-User", "?1")
.Add("dht", 1)
.Add("drp", 1)
.Add(Instagram.UserData.GQL_HEADER_FB_FRINDLY_NAME, "BarcelonaProfileThreadsTabRefetchableQuery") .Add(Instagram.UserData.GQL_HEADER_FB_FRINDLY_NAME, "BarcelonaProfileThreadsTabRefetchableQuery")
End With End With
.CookiesExtractMode = Responser.CookiesExtractModes.Any .CookiesExtractMode = Responser.CookiesExtractModes.Any

View File

@@ -157,38 +157,22 @@ Namespace API.ThreadsNet
Private Function UpdateCredentials(Optional ByVal e As ErrorsDescriber = Nothing) As Boolean Private Function UpdateCredentials(Optional ByVal e As ErrorsDescriber = Nothing) As Boolean
Dim URL$ = $"https://www.threads.net/@{NameTrue}" Dim URL$ = $"https://www.threads.net/@{NameTrue}"
ResetBaseTokens() ResetBaseTokens()
Dim headers As New HttpHeaderCollection
headers.AddRange(Responser.Headers)
Try Try
Responser.Method = "GET" With Responser
Responser.Referer = URL .Method = "GET"
Responser.Headers.Remove(GQL_HEADER_FB_LSD) .Referer = URL
With .Headers
.Remove(GQL_HEADER_FB_LSD)
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecFetchDest, "document"))
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecFetchMode, "navigate"))
End With
End With
WaitTimer() WaitTimer()
Dim r$ = Responser.GetResponse(URL,, EDP.ThrowException) Dim r$ = Responser.GetResponse(URL,, EDP.ThrowException)
Dim rr As RParams
Dim tt$, ttVal$
If Not r.IsEmptyString Then If Not r.IsEmptyString Then
rr = RParams.DM(Instagram.PageTokenRegexPatternDefault, 0, RegexReturn.List, EDP.ReturnValue) ParseTokens(r, 0)
Dim tokens As List(Of String) = RegexReplace(r, rr)
If tokens.ListExists Then
With rr
.Match = Nothing
.MatchSub = 1
.WhatGet = RegexReturn.Value
End With
For Each tt In tokens
If Not Token_dtsg.IsEmptyString And Not Token_lsd.IsEmptyString Then
Exit For
Else
ttVal = RegexReplace(tt, rr)
If Not ttVal.IsEmptyString Then
If ttVal.Contains(":") Then
If Token_dtsg.IsEmptyString Then Token_dtsg = ttVal
Else
If Token_lsd.IsEmptyString Then Token_lsd = ttVal
End If
End If
End If
Next
End If
If ID.IsEmptyString Then ID = RegexReplace(r, RParams.DMS("""props"":\{""user_id"":""(\d+)""\},", 1, EDP.ReturnValue)) If ID.IsEmptyString Then ID = RegexReplace(r, RParams.DMS("""props"":\{""user_id"":""(\d+)""\},", 1, EDP.ReturnValue))
End If End If
Return Valid Return Valid
@@ -204,6 +188,12 @@ Namespace API.ThreadsNet
'LogError(ex, $"failed to update some{IIf(notFound.IsEmptyString, String.Empty, $" ({notFound})")} credentials", e) 'LogError(ex, $"failed to update some{IIf(notFound.IsEmptyString, String.Empty, $" ({notFound})")} credentials", e)
LogError(eex, String.Empty, e) LogError(eex, String.Empty, e)
Return False Return False
Finally
If headers.ListExists Then
Responser.Headers.Clear()
Responser.Headers.AddRange(headers)
headers.Dispose()
End If
End Try End Try
End Function End Function
#End Region #End Region

View File

@@ -359,6 +359,11 @@ Namespace API.TikTok
_TempMediaList.Add(m) _TempMediaList.Add(m)
End Sub End Sub
#End Region #End Region
#Region "EraseData"
Protected Overrides Sub EraseData_AdditionalDataFiles()
LastDownloadDate = Nothing
End Sub
#End Region
#Region "Exception" #Region "Exception"
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

View File

@@ -280,32 +280,18 @@ Namespace API.Xhamster
End If End If
End If End If
'TODELETE: xHamster remove old container nodes attachments
If IsSavedPosts Then If IsSavedPosts Then
URL = $"https://xhamster.com/my/favorites/{IIf(IsVideo, "videos", "photos-and-galleries")}{IIf(Page = 1, String.Empty, $"/{Page}")}" URL = $"https://xhamster.com/my/favorites/{IIf(IsVideo, "videos", "photos-and-galleries")}{IIf(Page = 1, String.Empty, $"/{Page}")}"
containerNodes.Add(If(IsVideo, {"favoriteVideoListComponent", "models"}, {"favoritesGalleriesAndPhotosCollection"})) containerNodes.Add(If(IsVideo, {"favoriteVideoListComponent", "models"}, {"favoritesGalleriesAndPhotosCollection"}))
ElseIf IsChannel Then ElseIf IsChannel Then
URL = $"https://xhamster.com/channels/{TrueName}/newest{IIf(Page = 1, String.Empty, $"/{Page}")}" URL = $"https://xhamster.com/channels/{TrueName}/newest{IIf(Page = 1, String.Empty, $"/{Page}")}"
'containerNodes.Add({"trendingVideoListComponent", "models"})
'containerNodes.Add({"pagesCategoryComponent", "trendingVideoListProps", "models"})
ElseIf SiteMode = SiteModes.Search Then ElseIf SiteMode = SiteModes.Search Then
URL = GetNonUserUrl(Page) URL = GetNonUserUrl(Page)
containerNodes.Add({"searchResult", "models"}) containerNodes.Add({"searchResult", "models"})
ElseIf IsCreator Or SiteMode = SiteModes.Tags Or SiteMode = SiteModes.Categories Or SiteMode = SiteModes.Pornstars Then ElseIf IsCreator Or SiteMode = SiteModes.Tags Or SiteMode = SiteModes.Categories Or SiteMode = SiteModes.Pornstars Then
URL = GetNonUserUrl(Page) URL = GetNonUserUrl(Page)
'If SiteMode = SiteModes.Pornstars Then
' containerNodes.Add({"trendingVideoListComponent", "models"})
' containerNodes.Add({"pagesCategoryComponent", "trendingVideoListProps", "models"})
'Else
' containerNodes.Add({"pagesCategoryComponent", "trendingVideoListProps", "models"})
' containerNodes.Add({"trendingVideoListComponent", "models"})
'End If
'containerNodes.Add({"trendingVideoSectionComponent", "videoModels"})
Else Else
URL = $"https://xhamster.com/users/{TrueName}/{IIf(IsVideo, "videos", "photos")}{IIf(Page = 1, String.Empty, $"/{Page}")}" URL = $"https://xhamster.com/users/{TrueName}/{IIf(IsVideo, "videos", "photos")}{IIf(Page = 1, String.Empty, $"/{Page}")}"
'containerNodes.Add({If(IsVideo, "userVideoCollection", "userGalleriesCollection")})
'containerNodes.Add(If(IsVideo, {"videoListComponent", "models"}, {"userGalleriesCollection"}))
End If End If
ThrowAny(Token) ThrowAny(Token)

View File

@@ -467,6 +467,13 @@ Namespace API.YouTube
_TempMediaList.Add(New UserMedia(Data)) _TempMediaList.Add(New UserMedia(Data))
End Sub End Sub
#End Region #End Region
#Region "EraseData"
Protected Overrides Sub EraseData_AdditionalDataFiles()
LastDownloadDateVideos = Nothing
LastDownloadDateShorts = Nothing
LastDownloadDatePlaylist = Nothing
End Sub
#End Region
#Region "DownloadingException" #Region "DownloadingException"
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

View File

@@ -100,7 +100,7 @@ Namespace DownloadObjects
users.ListAddList(DownloadGroup.GetUsers(g)) users.ListAddList(DownloadGroup.GetUsers(g))
End Using End Using
End If End If
GroupUsersViewer.Show(users) GroupUsersViewer.Show(users, $"S {DEF_GROUP.TXT_NAME.Text}")
users.Clear() users.Clear()
End If End If
Catch ex As Exception Catch ex As Exception

View File

@@ -381,7 +381,7 @@ Namespace DownloadObjects
users.ListAddList(Groups.DownloadGroup.GetUsers(.Self)) users.ListAddList(Groups.DownloadGroup.GetUsers(.Self))
End If End If
End If End If
Groups.GroupUsersViewer.Show(users) Groups.GroupUsersViewer.Show(users, $"S { .Name}")
users.Clear() users.Clear()
End With End With
End If End If

View File

@@ -85,7 +85,7 @@ Namespace DownloadObjects.Groups
If e = ShowUsersButtonKey Then If e = ShowUsersButtonKey Then
Using g As New GroupParameters Using g As New GroupParameters
DEFS_GROUP.Get(g) DEFS_GROUP.Get(g)
GroupUsersViewer.Show(DownloadGroup.GetUsers(g)) GroupUsersViewer.Show(DownloadGroup.GetUsers(g), $"{IIf(FilterMode, "F", "G")} {g.Name}")
End Using End Using
End If End If
Catch ex As Exception Catch ex As Exception

View File

@@ -305,10 +305,11 @@ Namespace DownloadObjects.Groups
Try Try
If _LatestSelected.ValueBetween(0, MyGroups.Count - 1) Then If _LatestSelected.ValueBetween(0, MyGroups.Count - 1) Then
Dim i% Dim i%
Dim n$ = String.Empty
Dim users As New List(Of API.Base.IUserData) Dim users As New List(Of API.Base.IUserData)
If Not IsViewFilter Then If Not IsViewFilter Then
i = Settings.Groups.IndexOf(MyGroups(_LatestSelected)) i = Settings.Groups.IndexOf(MyGroups(_LatestSelected))
If i >= 0 Then users.ListAddList(DownloadGroup.GetUsers(Settings.Groups(i))) If i >= 0 Then users.ListAddList(DownloadGroup.GetUsers(Settings.Groups(i))) : n = $"F {Settings.Groups(i).Name}"
ElseIf _LatestSelected.ValueBetween(0, MyGroupParams.Count - 1) Then ElseIf _LatestSelected.ValueBetween(0, MyGroupParams.Count - 1) Then
With MyGroupParams(_LatestSelected) With MyGroupParams(_LatestSelected)
If TypeOf .Self Is AutoDownloader Then If TypeOf .Self Is AutoDownloader Then
@@ -325,14 +326,15 @@ Namespace DownloadObjects.Groups
users.ListAddList(DownloadGroup.GetUsers(.Self)) users.ListAddList(DownloadGroup.GetUsers(.Self))
End If End If
End If End If
n = $"S { .Name}"
End With End With
ElseIf TypeOf .Self Is DownloadGroup Then ElseIf TypeOf .Self Is DownloadGroup Then
i = Settings.Groups.IndexOf(.Name, .IsViewFilter) i = Settings.Groups.IndexOf(.Name, .IsViewFilter)
If i >= 0 Then users.ListAddList(DownloadGroup.GetUsers(Settings.Groups(i))) If i >= 0 Then users.ListAddList(DownloadGroup.GetUsers(Settings.Groups(i))) : n = $"G {Settings.Groups(i).Name}"
End If End If
End With End With
End If End If
GroupUsersViewer.Show(users) GroupUsersViewer.Show(users, n)
users.Clear() users.Clear()
End If End If
Catch ex As Exception Catch ex As Exception

View File

@@ -10,11 +10,16 @@ Imports SCrawler.API.Base
Imports PersonalUtilities.Forms Imports PersonalUtilities.Forms
Namespace DownloadObjects.Groups Namespace DownloadObjects.Groups
Friend Class GroupUsersViewer : Inherits SimpleListForm(Of IUserData) Friend Class GroupUsersViewer : Inherits SimpleListForm(Of IUserData)
Friend Sub New(ByVal Users As IEnumerable(Of IUserData)) Friend Sub New(ByVal Users As IEnumerable(Of IUserData), ByVal AdditText As String)
MyBase.New(Users, Settings.Design) MyBase.New(Users, Settings.Design)
DesignXMLNodeName = "GroupUsersViewer" DesignXMLNodeName = "GroupUsersViewer"
Provider = New CustomProvider(Function(u As UserDataBase) u.ToStringForLog) Provider = New CustomProvider(Function(u As UserDataBase) u.ToStringForLog)
FormText = "Users" FormText = $"Users ({If(Users?.Count, 0)})"
If Not AdditText.IsEmptyString Then
Dim a$ = AdditText.Trim.Take(100).ListToStringE(String.Empty,,, " ", EDP.ReturnValue)
If Not a = AdditText Then AdditText &= "..."
FormText &= $" [{a}]"
End If
Icon = My.Resources.UsersIcon_32 Icon = My.Resources.UsersIcon_32
MyDefs.DelegateClosingChecker = False MyDefs.DelegateClosingChecker = False
Mode = SimpleListFormModes.SelectedItems Mode = SimpleListFormModes.SelectedItems
@@ -23,18 +28,26 @@ Namespace DownloadObjects.Groups
End Sub End Sub
Protected Overrides Sub MyForm_KeyDown(sender As Object, e As KeyEventArgs) Protected Overrides Sub MyForm_KeyDown(sender As Object, e As KeyEventArgs)
Try Try
Dim b As Boolean = True
If e.KeyCode = Keys.F And e.Control Then If e.KeyCode = Keys.F And e.Control Then
e.Handled = True
FocusUser() FocusUser()
ElseIf e.KeyCode = Keys.F3 Then
EditUser(e.Alt)
ElseIf e = ShowUsersButtonKey Then ElseIf e = ShowUsersButtonKey Then
MsgBoxE(New MMessage(DataSourceCollection.ListToStringE(vbCr, Provider,,, EDP.LogMessageValue), "User list") With {.Editable = True}) MsgBoxE(New MMessage(DataSourceCollection.ListToStringE(vbCr, Provider,,, EDP.LogMessageValue), "User list") With {.Editable = True})
ElseIf e.KeyCode = Keys.F1 And Not e.Alt And Not e.Control Then
MsgBoxE({$"Hotkeys:{vbCr}Alt+F1 - show user list{vbCr}Ctrl+F - find the selected user in the main window{vbCr}" &
$"F3 - edit selected user{vbCr}Alt+F3 - edit selected collection", "Hotkeys"})
Else
b = False
End If End If
If b Then e.Handled = True
Catch Catch
End Try End Try
End Sub End Sub
Friend Overloads Shared Sub Show(ByVal Users As IEnumerable(Of IUserData)) Friend Overloads Shared Sub Show(ByVal Users As IEnumerable(Of IUserData), ByVal AdditText As String)
If Users.ListExists Then If Users.ListExists Then
MainFrameObj.OpenedGroupUsersForms.Add(New GroupUsersViewer(Users)) MainFrameObj.OpenedGroupUsersForms.Add(New GroupUsersViewer(Users, AdditText))
MainFrameObj.OpenedGroupUsersForms.Last.Show() MainFrameObj.OpenedGroupUsersForms.Last.Show()
Else Else
MsgBoxE({"No users were found based on the selected parameters", "Show group users"}, vbExclamation) MsgBoxE({"No users were found based on the selected parameters", "Show group users"}, vbExclamation)
@@ -49,6 +62,15 @@ Namespace DownloadObjects.Groups
Catch Catch
End Try End Try
End Sub End Sub
Private Sub EditUser(ByVal EditCollection As Boolean)
Try
If _LatestSelected.ValueBetween(0, DataSourceCollection.Count - 1) Then
Dim u As IUserData = Settings.GetUser(DataSourceCollection(_LatestSelected).Key, EditCollection)
If Not u Is Nothing Then ControlInvokeFast(MainFrameObj.MF, Sub() MainFrameObj.MF.EditSelectedUser(u), EDP.None)
End If
Catch
End Try
End Sub
Friend Overloads Sub Show() Friend Overloads Sub Show()
MyForm.Show() MyForm.Show()
End Sub End Sub

View File

@@ -1706,9 +1706,9 @@ ResumeDownloadingOperation:
End If End If
End If End If
End Sub End Sub
Private Sub EditSelectedUser() Friend Sub EditSelectedUser(Optional ByVal CUser As IUserData = Nothing)
Const MsgTitle$ = "User update" Const MsgTitle$ = "User update"
Dim user As IUserData = GetSelectedUser() Dim user As IUserData = If(CUser, GetSelectedUser())
If Not user Is Nothing Then If Not user Is Nothing Then
On Error Resume Next On Error Resume Next
If Not user.IsCollection OrElse DirectCast(user, UserDataBind).Count > 0 Then If Not user.IsCollection OrElse DirectCast(user, UserDataBind).Count > 0 Then

View File

@@ -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("2024.4.10.0")> <Assembly: AssemblyVersion("2024.4.14.0")>
<Assembly: AssemblyFileVersion("2024.4.10.0")> <Assembly: AssemblyFileVersion("2024.4.14.0")>
<Assembly: NeutralResourcesLanguage("en")> <Assembly: NeutralResourcesLanguage("en")>

View File

@@ -104,6 +104,9 @@ Namespace Plugin.Hosts
End With End With
End If End If
End Sub End Sub
Protected Overrides Sub EraseData_AdditionalDataFiles()
ExternalPlugin.ResetHistoryData()
End Sub
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
LogError(ex, Message) LogError(ex, Message)

View File

@@ -825,14 +825,19 @@ Friend Class SettingsCLS : Implements IDownloaderSettings, IDisposable
Return _UserListUpdateRequired Return _UserListUpdateRequired
End Get End Get
End Property End Property
Friend Overloads Sub UpdateUsersList(ByVal u As UserInfo) Friend Overloads Sub UpdateUsersList(ByVal u As UserInfo, Optional ByVal OnlyDiff As Boolean = False)
Dim result As Boolean = True
Dim i% = UsersList.IndexOf(u) Dim i% = UsersList.IndexOf(u)
If i >= 0 Then If i >= 0 Then
UsersList(i) = u If Not OnlyDiff OrElse Not UserInfo.ExactEquals(UsersList(i), u) Then
UsersList(i) = u
Else
result = False
End If
Else Else
UsersList.Add(u) UsersList.Add(u)
End If End If
UpdateUsersList() If result Then UpdateUsersList()
End Sub End Sub
Friend Overloads Sub UpdateUsersList() Friend Overloads Sub UpdateUsersList()
Try Try

View File

@@ -182,6 +182,22 @@ Partial Friend Module MainMod
End Function End Function
#End Region #End Region
#Region "IEquatable Support" #Region "IEquatable Support"
Friend Shared Function ExactEquals(ByVal x As UserInfo, ByVal y As UserInfo) As Boolean
Return x.Name = y.Name And
x.Site = y.Site And
x.Plugin = y.Plugin And
x.AccountName = y.AccountName And
x.File = y.File And
x.IsSubscription = y.IsSubscription And
x.SpecialPath = y.SpecialPath And
x.SpecialCollectionPath = y.SpecialCollectionPath And
x.Merged = y.Merged And
x.UserModel = y.UserModel And
x.CollectionName = y.CollectionName And
x.CollectionModel = y.CollectionModel And
x.[Protected] = y.[Protected] And
AEquals(Of Date)(x.LastSeen, y.LastSeen)
End Function
Friend Overloads Function Equals(ByVal Other As UserInfo) As Boolean Implements IEquatable(Of UserInfo).Equals Friend Overloads Function Equals(ByVal Other As UserInfo) As Boolean Implements IEquatable(Of UserInfo).Equals
Return Site.StringToLower = Other.Site.StringToLower And Name.StringToLower = Other.Name.StringToLower And Return Site.StringToLower = Other.Site.StringToLower And Name.StringToLower = Other.Name.StringToLower And
IsSubscription = Other.IsSubscription And (Not Plugin = PathPlugin.PluginKey Or SpecialPath = Other.SpecialPath) IsSubscription = Other.IsSubscription And (Not Plugin = PathPlugin.PluginKey Or SpecialPath = Other.SpecialPath)

View File

@@ -1,4 +1,5 @@
$arr=Get-ChildItem -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\|Select-Object Name try{Set-ExecutionPolicy Unrestricted CurrentUser -ErrorAction SilentlyContinue}catch{}
$arr=Get-ChildItem -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\|Select-Object Name
$mv=0 $mv=0
$found=0 $found=0
foreach($v in $arr){if($v.Name -match "v4.0."){$mv=$v.Name}} foreach($v in $arr){if($v.Name -match "v4.0."){$mv=$v.Name}}