Compare commits

...

2 Commits

Author SHA1 Message Date
Andy
e6d5fc2b95 2026.1.17.0
UserDataBase: move GLD functions from 'Twitter'
Instagram: add 'Reposts' and 'Likes' to the 'Sections' enum
OnlyFans: update the regex in 'DynamicRulesEnv'; handling error 502
PornHub: fix videos aren't downloading
ThreadsNet: add user name and description extraction
TikTok: fix downloading new videos; add downloading 'Stories' and 'Reposts'
Twitter: move GLD functions to 'UserDataBase'
Xhamster: fix a bug when adding new users; fix incorrect cache location
Download groups: add excluded groups
MainFrame: fix the 'Feed' tooltip
2026-01-17 20:06:37 +03:00
Andy
6d4380ccac 2025.11.25.0
YT
YouTubeSettings: add property 'DefaultSubtitlesEmbed'
YouTubeMediaContainerBase: improve trim options; update command for 'DefaultSubtitlesEmbed'

SCrawler
TokenBatch, GDLBatch, YTDLPBatch: optimize code; add default encoding
UserMedia: add property 'IsPhotoType'
API.TikTok: optimize code; download descriptions
API.Twitter: optimize code; fix downloading of site name, description and avatar
API.Xhamster: add the properties 'UseYTDLPJSON', 'UseYTDLPDownload' and 'UseYTDLPForceDisableInternal'; add yt-dlp support; update parsing functions
Groups, automation: delete 'Modes'; add groups downloading among other options; optimize code
DownloadSavedPostsForm, DownloadProgress: add hotkey 'Esc'
MainFrame: update 'BTT_VIEW_FILTER_LOAD_Click' function
2025-11-25 12:57:37 +03:00
56 changed files with 1005 additions and 617 deletions

View File

@@ -2,11 +2,61 @@
- [ffmpeg](https://github.com/AAndyProgram/SCrawler/wiki/Settings#ffmpeg) - [ffmpeg](https://github.com/AAndyProgram/SCrawler/wiki/Settings#ffmpeg)
- x64 version - [release](https://github.com/GyanD/codexffmpeg/releases/tag/5.1.2); [zip](https://github.com/GyanD/codexffmpeg/releases/download/5.1.2/ffmpeg-5.1.2-full_build.zip); **version `5.1.2-full_build-www.gyan.dev`** - x64 version - [release](https://github.com/GyanD/codexffmpeg/releases/tag/5.1.2); [zip](https://github.com/GyanD/codexffmpeg/releases/download/5.1.2/ffmpeg-5.1.2-full_build.zip); **version `5.1.2-full_build-www.gyan.dev`**
- x86 version - [release](https://github.com/yt-dlp/FFmpeg-Builds/releases/tag/autobuild-2022-11-30-12-57); [zip](https://github.com/yt-dlp/FFmpeg-Builds/releases/download/autobuild-2022-11-30-12-57/ffmpeg-N-109274-gd7a5f068c2-win32-gpl.zip); **version `N-109457-geeb280f351-20221226`** - x86 version - [release](https://github.com/yt-dlp/FFmpeg-Builds/releases/tag/autobuild-2022-11-30-12-57); [zip](https://github.com/yt-dlp/FFmpeg-Builds/releases/download/autobuild-2022-11-30-12-57/ffmpeg-N-109274-gd7a5f068c2-win32-gpl.zip); **version `N-109457-geeb280f351-20221226`**
- [Gallery-dl](https://github.com/AAndyProgram/SCrawler/wiki/Settings#gallery-dl) - **1.30.9** - [Gallery-dl](https://github.com/AAndyProgram/SCrawler/wiki/Settings#gallery-dl) - **1.31.3**
- [YT-DLP](https://github.com/AAndyProgram/SCrawler/wiki/Settings#yt-dlp) - **2025.09.26** - [YT-DLP](https://github.com/AAndyProgram/SCrawler/wiki/Settings#yt-dlp) - **2025.12.08**
- [Deno](https://github.com/AAndyProgram/SCrawler/wiki/Settings#deno) - latest *(`2.0.0` or higher)*
- [OF-Scraper](https://github.com/AAndyProgram/SCrawler/wiki/Settings#of-scraper) - **3.12.9** ([release](https://github.com/datawhores/OF-Scraper/releases/tag/3.12.9)) - [OF-Scraper](https://github.com/AAndyProgram/SCrawler/wiki/Settings#of-scraper) - **3.12.9** ([release](https://github.com/datawhores/OF-Scraper/releases/tag/3.12.9))
# 2026
## 2026.1.17.0
*2026-01-17*
- Add
- Sites:
- OnlyFans: handling error `502`
- Threads: user name and description extraction
- TikTok: **downloading `Stories` and `Reposts`**
- Download groups: excluded groups
- Updated
- yt-dlp up to version **2025.12.08**
- gallery-dl up to version **1.31.3**
- Fixed
- Sites:
- PornHub: videos aren't downloading
- TikTok: new videos aren't downloading
- xHamster: new users aren't added in some cases
# 2025 # 2025
## 2025.11.25.0
*2025-11-25*
**ATTENTION!**
**An external JavaScript runtime is now required for full YouTube support**
yt-dlp now requires users to have an external JavaScript runtime ([Deno](https://github.com/AAndyProgram/SCrawler/wiki/Settings#deno)) installed in order to solve the JavaScript challenges presented by YouTube.
**xHamster is back.** 🥳🎉 xHamster's downloading algorithms now partially utilize yt-dlp, so yt-dlp is now required for this site.
- Added
- Sites:
- TikTok: **download descriptions**
- Download groups: groups downloading among other options (more [here](https://github.com/AAndyProgram/SCrawler/wiki/Settings#download-groups))
- Saved posts: hotkey `Esc` to close the form
- Minor improvements
- Updated
- yt-dlp up to version **2025.11.12**
- gallery-dl up to version **1.30.10**
- AutoDownloader: the modes are now removed. Now you can only enable/disable the auto download plan. All options can now be combined.
- Fixed
- Sites:
- Twitter: the site name, description and avatar are not downloading
- xHamster: **data is not downloading**
- Minor bugs
## 2025.10.4.0 ## 2025.10.4.0
*2025-10-04* *2025-10-04*
@@ -1736,7 +1786,7 @@ At the requests of some users, I added [screenshots](ProgramScreenshots) of the
- Wrong some Reddit videos parsing - Wrong some Reddit videos parsing
- Wrong some Reddit images parsing - Wrong some Reddit images parsing
# 1.0.0.0 ## 1.0.0.0
*2021-12-07* *2021-12-07*

View File

@@ -8,3 +8,4 @@ List of available plugins:
Tools: Tools:
- [image2post](https://github.com/unknown81311/SCrawler-image2post) by @unknown81311: **get reddit post URL from file.** - [image2post](https://github.com/unknown81311/SCrawler-image2post) by @unknown81311: **get reddit post URL from file.**
- [Update-SCrawler-Tools](https://github.com/cjb900/Update-SCrawler-Tools) by @cjb900: **a tool for updating third-party programs such as yt-dlp and gallery-dl**

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -1,5 +1,6 @@
<!--
# 🏳️‍🌈 Happy LGBT Pride Month 🎉 # 🏳️‍🌈 Happy LGBT Pride Month 🎉
-->
# 🏳️‍🌈 Social networks crawler 🏳️‍🌈 # 🏳️‍🌈 Social networks crawler 🏳️‍🌈
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/AAndyProgram/SCrawler)](https://github.com/AAndyProgram/SCrawler/releases/latest) [![GitHub release (latest by date)](https://img.shields.io/github/v/release/AAndyProgram/SCrawler)](https://github.com/AAndyProgram/SCrawler/releases/latest)

View File

@@ -501,6 +501,9 @@ Namespace API.YouTube.Base
TypeConverter(GetType(ValueCollectionConverter)), TypeConverter(GetType(ValueCollectionConverter)),
Description("Additional format for downloading subtitles. This means that all subtitles will be converted to the formats you choose and saved as separate files.")> Description("Additional format for downloading subtitles. This means that all subtitles will be converted to the formats you choose and saved as separate files.")>
Public ReadOnly Property DefaultSubtitlesFormatAddit As XMLValuesCollection(Of String) Public ReadOnly Property DefaultSubtitlesFormatAddit As XMLValuesCollection(Of String)
<Browsable(True), GridVisible, XMLVN({"DefaultsSubtitles"}), Category("Defaults Subtitles"), DisplayName("Embed subtitles"),
Description("Embed subtitles in the video (only for mp4, webm and mkv videos)")>
Public ReadOnly Property DefaultSubtitlesEmbed As XMLValue(Of Boolean)
#End Region #End Region
#Region "Trim" #Region "Trim"
<Browsable(True), GridVisible, XMLVN({"DefaultsTrim"}, False), Category("Defaults Trimming"), DisplayName("Delete original file"), <Browsable(True), GridVisible, XMLVN({"DefaultsTrim"}, False), Category("Defaults Trimming"), DisplayName("Delete original file"),

View File

@@ -13,7 +13,7 @@ Imports System.Runtime.InteropServices
<Assembly: AssemblyDescription("YouTube plugin environment")> <Assembly: AssemblyDescription("YouTube plugin environment")>
<Assembly: AssemblyCompany("AndyProgram")> <Assembly: AssemblyCompany("AndyProgram")>
<Assembly: AssemblyProduct("SCrawler.YouTube")> <Assembly: AssemblyProduct("SCrawler.YouTube")>
<Assembly: AssemblyCopyright("Copyright © 2025")> <Assembly: AssemblyCopyright("Copyright © 2026")>
<Assembly: AssemblyTrademark("AndyProgram")> <Assembly: AssemblyTrademark("AndyProgram")>
<Assembly: ComVisible(False)> <Assembly: ComVisible(False)>
@@ -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("2025.10.4.0")> <Assembly: AssemblyVersion("2025.11.25.0")>
<Assembly: AssemblyFileVersion("2025.10.4.0")> <Assembly: AssemblyFileVersion("2025.11.25.0")>
<Assembly: NeutralResourcesLanguage("en")> <Assembly: NeutralResourcesLanguage("en")>

View File

@@ -827,6 +827,7 @@ Namespace API.YouTube.Objects
subs = ListAddList(Nothing, Subtitles.Select(Function(s, i) If(SubtitlesSelectedIndexes.Contains(i), s.FullID, String.Empty)), subs = ListAddList(Nothing, Subtitles.Select(Function(s, i) If(SubtitlesSelectedIndexes.Contains(i), s.FullID, String.Empty)),
LAP.NotContainsOnly, EDP.ReturnValue).ListToString(",") LAP.NotContainsOnly, EDP.ReturnValue).ListToString(",")
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}"
If MyYouTubeSettings.DefaultSubtitlesEmbed Then subs = $"--write-auto-sub --embed-subs {subs}"
End If End If
If Not cmd.IsEmptyString Then If Not cmd.IsEmptyString Then
'2023.3.4 -> 2023.7.6 '2023.3.4 -> 2023.7.6
@@ -1458,8 +1459,10 @@ Namespace API.YouTube.Objects
Const trimCommand$ = "ffmpeg -i ""{0}"" -ss {1} -to {2} -c:v copy -c:a copy ""{3}""" Const trimCommand$ = "ffmpeg -i ""{0}"" -ss {1} -to {2} -c:v copy -c:a copy ""{3}"""
Dim trimFirstFile As SFile = Nothing Dim trimFirstFile As SFile = Nothing
Dim trimFirstAdded As Boolean = False Dim trimFirstAdded As Boolean = False
Dim processTrim As Action(Of TrimOption, SFile) = Dim trimSingleReplace As Boolean = TrimOptions.Count = 1 And TrimDeleteOriginalFile
Sub(ByVal opt As TrimOption, ByVal pFile As SFile) Dim audioReplace As New Dictionary(Of SFile, SFile)
Dim processTrim As Action(Of TrimOption, SFile, Boolean) =
Sub(ByVal opt As TrimOption, ByVal pFile As SFile, ByVal isAudio As Boolean)
Dim fNew As SFile = pFile Dim fNew As SFile = pFile
fNew.Name &= $"_{opt.Name}" fNew.Name &= $"_{opt.Name}"
If TrimSeparateFolder Then fNew = $"{fNew.PathNoSeparator}\{MyYouTubeSettings.TrimSeparateFolderName.Value.IfNullOrEmpty(YouTubeSettings.TrimSeparateFolderNameDefault)}\{fNew.File}" : fNew.Exists(SFO.Path) If TrimSeparateFolder Then fNew = $"{fNew.PathNoSeparator}\{MyYouTubeSettings.TrimSeparateFolderName.Value.IfNullOrEmpty(YouTubeSettings.TrimSeparateFolderNameDefault)}\{fNew.File}" : fNew.Exists(SFO.Path)
@@ -1471,22 +1474,46 @@ Namespace API.YouTube.Objects
fNew)) fNew))
If fNew.Exists Then If fNew.Exists Then
If trimFirstFile.IsEmptyString Then trimFirstFile = fNew If trimFirstFile.IsEmptyString Then trimFirstFile = fNew
AddFile(fNew) If Not trimSingleReplace Then AddFile(fNew)
If isAudio And trimSingleReplace And Not audioReplace.ContainsKey(pFile) Then audioReplace.Add(pFile, fNew)
If format = mp3 And MyYouTubeSettings.DefaultAudioEmbedThumbnail_ExtractedFiles Then _ If format = mp3 And MyYouTubeSettings.DefaultAudioEmbedThumbnail_ExtractedFiles Then _
embedThumbTo.Invoke(fNew) : mp3ThumbEmbedded = True embedThumbTo.Invoke(fNew) : mp3ThumbEmbedded = True
If (TrimAddTrimmedFilesToM3U8 Or (TrimDeleteOriginalFile And Not trimFirstAdded)) AndAlso If Not trimSingleReplace AndAlso
(TrimAddTrimmedFilesToM3U8 Or (TrimDeleteOriginalFile And Not trimFirstAdded)) AndAlso
(M3U8_PlaylistFiles.ListExists OrElse (M3U8_PlaylistFiles.ListExists OrElse
(format = mp3 AndAlso MyYouTubeSettings.VideoPlaylist_AddExtractedMP3.Value)) Then _ (format = mp3 AndAlso MyYouTubeSettings.VideoPlaylist_AddExtractedMP3.Value)) Then _
M3U8_Append(fNew) : trimFirstAdded = True M3U8_Append(fNew) : trimFirstAdded = True
End If End If
End Sub End Sub
For Each tr As TrimOption In TrimOptions For Each tr As TrimOption In TrimOptions
processTrim(tr, File) processTrim(tr, File, False)
If audioFiles.Count > 0 Then If audioFiles.Count > 0 Then
For Each f In audioFiles : processTrim(tr, f) : Next For Each f In audioFiles : processTrim(tr, f, True) : Next
End If End If
Next Next
If TrimDeleteOriginalFile Then File.Delete() : File = trimFirstFile If TrimDeleteOriginalFile Then
Dim silentEDP As New ErrorsDescriber(EDP.ReturnValue)
File.Delete(,, silentEDP)
If trimSingleReplace Then
File = SFile.Rename(trimFirstFile, File,, New ErrorsDescriber(False, False, False, trimFirstFile))
If audioReplace.Count > 0 Then
For Each kvf As KeyValuePair(Of SFile, SFile) In audioReplace
If kvf.Key.Exists And kvf.Value.Exists Then
kvf.Key.Delete(,, silentEDP)
SFile.Rename(kvf.Value, kvf.Key,, silentEDP)
End If
Next
audioReplace.Clear()
End If
Else
File = trimFirstFile
If audioFiles.Count > 0 Then
For Each f In audioFiles
If Not f = File Then f.Delete(,, silentEDP)
Next
End If
End If
End If
End If End If
End If End If

View File

@@ -13,7 +13,7 @@ Imports System.Runtime.InteropServices
<Assembly: AssemblyDescription("SCrawler YouTube downloader")> <Assembly: AssemblyDescription("SCrawler YouTube downloader")>
<Assembly: AssemblyCompany("AndyProgram")> <Assembly: AssemblyCompany("AndyProgram")>
<Assembly: AssemblyProduct("SCrawler.YouTubeDownloader")> <Assembly: AssemblyProduct("SCrawler.YouTubeDownloader")>
<Assembly: AssemblyCopyright("Copyright © 2025")> <Assembly: AssemblyCopyright("Copyright © 2026")>
<Assembly: AssemblyTrademark("AndyProgram")> <Assembly: AssemblyTrademark("AndyProgram")>
<Assembly: ComVisible(False)> <Assembly: ComVisible(False)>
@@ -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("2025.10.4.0")> <Assembly: AssemblyVersion("2025.11.25.0")>
<Assembly: AssemblyFileVersion("2025.10.4.0")> <Assembly: AssemblyFileVersion("2025.11.25.0")>
<Assembly: NeutralResourcesLanguage("en")> <Assembly: NeutralResourcesLanguage("en")>

View File

@@ -10,10 +10,8 @@ Namespace API.Base.GDL
Friend Class GDLBatch : Inherits TokenBatch Friend Class GDLBatch : Inherits TokenBatch
Friend Const UrlLibStart As String = "[urllib3.connectionpool][debug]" Friend Const UrlLibStart As String = "[urllib3.connectionpool][debug]"
Friend Const UrlTextStart As String = UrlLibStart & " https" Friend Const UrlTextStart As String = UrlLibStart & " https"
Friend Sub New(ByVal _Token As Threading.CancellationToken) Friend Sub New(ByVal _Token As Threading.CancellationToken, Optional ByVal __MainProcessName As String = Nothing, Optional ByVal WorkingDir As SFile = Nothing)
MyBase.New(_Token) MyBase.New(_Token, __MainProcessName.IfNullOrEmpty(Settings.GalleryDLFile.File.Name), WorkingDir.IfNullOrEmpty(Settings.GalleryDLFile.File))
MainProcessName = "gallery-dl"
ChangeDirectory(Settings.GalleryDLFile.File)
End Sub End Sub
Protected Overrides Async Sub OutputDataReceiver(ByVal Sender As Object, ByVal e As DataReceivedEventArgs) Protected Overrides Async Sub OutputDataReceiver(ByVal Sender As Object, ByVal e As DataReceivedEventArgs)
If Not ProcessKilled Then If Not ProcessKilled Then

View File

@@ -58,6 +58,11 @@ Namespace API.Base
Return Type = Types.Audio Or Type = Types.AudioPre Return Type = Types.Audio Or Type = Types.AudioPre
End Get End Get
End Property End Property
Friend ReadOnly Property IsPhotoType As Boolean
Get
Return Type = Types.Picture Or Type = Types.GIF
End Get
End Property
Friend URL_BASE As String Friend URL_BASE As String
Friend URL As String Friend URL As String
Friend MD5 As String Friend MD5 As String

View File

@@ -13,10 +13,16 @@ Namespace API.Base
Friend Property TempPostsList As List(Of String) Friend Property TempPostsList As List(Of String)
Protected ReadOnly Token As CancellationToken Protected ReadOnly Token As CancellationToken
Friend Property DebugMode As Boolean = False Friend Property DebugMode As Boolean = False
Friend Sub New(ByVal _Token As CancellationToken) Friend Sub New(ByVal _Token As CancellationToken, Optional ByVal _MainProcessName As String = Nothing, Optional ByVal WorkingDir As SFile = Nothing)
MyBase.New(True) MyBase.New(True)
Token = _Token Token = _Token
MainProcessName = _MainProcessName
If Not WorkingDir.IsEmptyString Then ChangeDirectory(WorkingDir)
End Sub End Sub
Protected Overrides Function Internal_Execute(ByVal Commands As IEnumerable(Of String), ByVal e As ErrorsDescriber) As Boolean
If Not Encoding.HasValue Then Encoding = UnicodeEncoding
Return MyBase.Internal_Execute(Commands, e)
End Function
Public Overrides Sub Create() Public Overrides Sub Create()
If TempPostsList Is Nothing Then TempPostsList = New List(Of String) If TempPostsList Is Nothing Then TempPostsList = New List(Of String)
MyBase.Create() MyBase.Create()

View File

@@ -1439,6 +1439,16 @@ BlockNullPicture:
Cache.Validate() Cache.Validate()
Return Cache Return Cache
End Function End Function
#Region "GDL File Names"
Protected GDLFileNameProvider As ANumbers = Nothing
Protected Sub GDLResetFileNameProvider(Optional ByVal GroupSize As Integer? = Nothing)
GDLFileNameProvider = New ANumbers With {.FormatOptions = ANumbers.Options.FormatNumberGroup + ANumbers.Options.Groups}
GDLFileNameProvider.GroupSize = If(GroupSize, 3)
End Sub
Protected Function GDLRenameFile(ByVal Input As SFile, ByVal i As Integer) As SFile
Return SFile.Rename(Input, $"{Input.PathWithSeparator}{i.NumToString(GDLFileNameProvider)}.{Input.Extension}",, EDP.ThrowException)
End Function
#End Region
#Region "DownloadSingleObject" #Region "DownloadSingleObject"
Protected IsSingleObjectDownload As Boolean = False Protected IsSingleObjectDownload As Boolean = False
Friend Overridable Sub DownloadSingleObject(ByVal Data As YouTube.Objects.IYouTubeMediaContainer, ByVal Token As CancellationToken) Implements IUserData.DownloadSingleObject Friend Overridable Sub DownloadSingleObject(ByVal Data As YouTube.Objects.IYouTubeMediaContainer, ByVal Token As CancellationToken) Implements IUserData.DownloadSingleObject
@@ -2453,6 +2463,7 @@ stxt:
_TempPostsList.Clear() _TempPostsList.Clear()
_MD5List.Clear() _MD5List.Clear()
TokenPersonal = Nothing TokenPersonal = Nothing
GDLFileNameProvider = Nothing
If Not ProgressPre Is Nothing Then ProgressPre.Reset() : ProgressPre.Dispose() If Not ProgressPre Is Nothing Then ProgressPre.Reset() : ProgressPre.Dispose()
If Not Responser Is Nothing Then Responser.Dispose() If Not Responser Is Nothing Then Responser.Dispose()
If Not BTT_CONTEXT_DOWN Is Nothing Then BTT_CONTEXT_DOWN.Dispose() If Not BTT_CONTEXT_DOWN Is Nothing Then BTT_CONTEXT_DOWN.Dispose()

View File

@@ -8,11 +8,8 @@
' but WITHOUT ANY WARRANTY ' but WITHOUT ANY WARRANTY
Namespace API.Base.YTDLP Namespace API.Base.YTDLP
Friend Class YTDLPBatch : Inherits GDL.GDLBatch Friend Class YTDLPBatch : Inherits GDL.GDLBatch
Friend Sub New(ByVal _Token As Threading.CancellationToken) Friend Sub New(ByVal _Token As Threading.CancellationToken, Optional ByVal __MainProcessName As String = Nothing, Optional ByVal WorkingDir As SFile = Nothing)
MyBase.New(_Token) MyBase.New(_Token, __MainProcessName.IfNullOrEmpty(Settings.YtdlpFile.File.Name), WorkingDir.IfNullOrEmpty(Settings.YtdlpFile.File))
Commands.Clear()
MainProcessName = Settings.YtdlpFile.File.Name '"yt-dlp"
ChangeDirectory(Settings.YtdlpFile.File)
End Sub End Sub
End Class End Class
End Namespace End Namespace

View File

@@ -525,7 +525,7 @@ Namespace API.Instagram
Protected Overrides Sub Responser_ResponseReceived(ByVal Sender As Object, ByVal e As EventArguments.WebDataResponse) Protected Overrides Sub Responser_ResponseReceived(ByVal Sender As Object, ByVal e As EventArguments.WebDataResponse)
Declarations.UpdateResponser(e, Responser, WwwClaimUpdate) Declarations.UpdateResponser(e, Responser, WwwClaimUpdate)
End Sub End Sub
Friend Enum Sections : Timeline : Reels : Tagged : Stories : UserStories : SavedPosts : End Enum Friend Enum Sections : Timeline : Reels : Tagged : Stories : UserStories : SavedPosts : Reposts : Likes : End Enum
Protected Const StoriesFolder As String = "Stories" Protected Const StoriesFolder As String = "Stories"
Private Const TaggedFolder As String = "Tagged" Private Const TaggedFolder As String = "Tagged"
#Region "429 bypass" #Region "429 bypass"

View File

@@ -219,12 +219,12 @@ Namespace API.OnlyFans
DynamicRulesXml.Extension = "xml" DynamicRulesXml.Extension = "xml"
ReplacePattern_RepoToRaw = New RParams("(.*github.com/([^/]+)/([^/]+)/blob/(.+))", Nothing, 0, ReplacePattern_RepoToRaw = New RParams("(.*github.com/([^/]+)/([^/]+)/blob/(.+))", Nothing, 0,
RegexReturn.ReplaceChangeListMatch, EDP.ReturnValue) With { RegexReturn.ReplaceChangeListMatch, EDP.ReturnValue) With {
.PatternReplacement = "https://raw.githubusercontent.com/{2}/{3}/{4}"} .PatternReplacement = "https://raw.githubusercontent.com/{2}/{3}/refs/heads/{4}"}
ReplacePattern_JsonInfo = ReplacePattern_RepoToRaw.Copy ReplacePattern_JsonInfo = ReplacePattern_RepoToRaw.Copy
ReplacePattern_JsonInfo.PatternReplacement = "https://github.com/{2}/{3}/latest-commit/{4}" ReplacePattern_JsonInfo.PatternReplacement = "https://github.com/{2}/{3}/latest-commit/{4}"
ReplacePattern_RawToRepo = ReplacePattern_RepoToRaw.Copy ReplacePattern_RawToRepo = ReplacePattern_RepoToRaw.Copy
ReplacePattern_RawToRepo.Pattern = "(.*raw.githubusercontent.com/([^/]+)/([^/]+)/([^/]+)/(.+))" ReplacePattern_RawToRepo.Pattern = "(.*raw.githubusercontent.com/([^/]+)/([^/]+)(/refs/heads)?/([^/]+)/(.+))"
ReplacePattern_RawToRepo.PatternReplacement = "https://github.com/{2}/{3}/blob/{4}/{5}" ReplacePattern_RawToRepo.PatternReplacement = "https://github.com/{2}/{3}/blob/{5}/{6}"
ConfigRulesExtract = RParams.DMS("DYNAMIC_RULE"":(\{.+?\}[\r\n]+)", 1, RegexOptions.Singleline, EDP.ReturnValue) ConfigRulesExtract = RParams.DMS("DYNAMIC_RULE"":(\{.+?\}[\r\n]+)", 1, RegexOptions.Singleline, EDP.ReturnValue)
OFLOG = New TextSaver($"LOGs\OF_{Now:yyyyMMdd_HHmmss}.txt") With {.LogMode = True, .AutoSave = True, .AutoClear = True} OFLOG = New TextSaver($"LOGs\OF_{Now:yyyyMMdd_HHmmss}.txt") With {.LogMode = True, .AutoSave = True, .AutoClear = True}
AddHandler OFLOG.TextSaved, AddressOf OFLOG_TextSaved AddHandler OFLOG.TextSaved, AddressOf OFLOG_TextSaved

View File

@@ -88,6 +88,7 @@ Namespace API.OnlyFans
Private _DownloadedPostsSession As Integer = 0 Private _DownloadedPostsSession As Integer = 0
Private FunctionErr As Integer = FunctionErrDef Private FunctionErr As Integer = FunctionErrDef
Private Const FunctionErrDef As Integer = -100 Private Const FunctionErrDef As Integer = -100
Private _TimelineDownloading As Boolean = False
Private Sub ValidateOFScraper() Private Sub ValidateOFScraper()
_OFScraperExists = ACheck(MySettings.OFScraperPath.Value) AndAlso CStr(MySettings.OFScraperPath.Value).CSFile.Exists _OFScraperExists = ACheck(MySettings.OFScraperPath.Value) AndAlso CStr(MySettings.OFScraperPath.Value).CSFile.Exists
End Sub End Sub
@@ -110,7 +111,9 @@ Namespace API.OnlyFans
If ID.IsEmptyString Then Throw New ArgumentNullException("ID", "Unable to get user ID") If ID.IsEmptyString Then Throw New ArgumentNullException("ID", "Unable to get user ID")
End If End If
_TimelineDownloading = True
If MediaDownloadTimeline Then DownloadTimeline(IIf(IsSavedPosts, 0, String.Empty), Token) If MediaDownloadTimeline Then DownloadTimeline(IIf(IsSavedPosts, 0, String.Empty), Token)
_TimelineDownloading = False
If Not IsSavedPosts Then If Not IsSavedPosts Then
If MediaDownloadStories And FunctionErr = FunctionErrDef Then DownloadStories(Token) If MediaDownloadStories And FunctionErr = FunctionErrDef Then DownloadStories(Token)
If MediaDownloadHighlights And FunctionErr = FunctionErrDef Then DownloadHighlights(Token) If MediaDownloadHighlights And FunctionErr = FunctionErrDef Then DownloadHighlights(Token)
@@ -827,6 +830,8 @@ Namespace API.OnlyFans
Return 3 Return 3
ElseIf Responser.StatusCode = Net.HttpStatusCode.InternalServerError Then '500 ElseIf Responser.StatusCode = Net.HttpStatusCode.InternalServerError Then '500
Return 3 Return 3
ElseIf Not _TimelineDownloading And Responser.StatusCode = Net.HttpStatusCode.BadGateway Then '502
Return 3
Else Else
Return 0 Return 0
End If End If

View File

@@ -385,7 +385,7 @@ Namespace API.PornHub
If PersonType = PersonTypeCannel Then If PersonType = PersonTypeCannel Then
l = l.ListTake(4, l.Count) l = l.ListTake(4, l.Count)
Else Else
l.RemoveAll(Function(uv) uv.UserRef.IsEmptyString OrElse Not uv.UserRef = usrRef) l.RemoveAll(Function(uv) Not uv.UserRef.IsEmptyString AndAlso Not uv.UserRef = usrRef)
End If End If
ElseIf Type = VideoTypes.Favorite Then ElseIf Type = VideoTypes.Favorite Then
l.RemoveAll(Function(uv) uv.Type = VideoTypes.Private) l.RemoveAll(Function(uv) uv.Type = VideoTypes.Private)

View File

@@ -0,0 +1,17 @@
' Copyright (C) Andy https://github.com/AAndyProgram
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY
Imports SCrawler.API.Base
Imports PersonalUtilities.Functions.RegularExpressions
Namespace API.ThreadsNet
Friend Module Declarations
Friend ReadOnly RegexUserID As RParams = RParams.DMS("""props"":\{[^\{\}]*?""user_id"":""(\d+)""", 1, EDP.ReturnValue)
Friend ReadOnly RegexUserName As RParams = RParams.DMS("\<meta property=""og:title"" content=""([^\>]+)""\s*/\>", 1, TitleHtmlConverter, EDP.ReturnValue)
Friend ReadOnly RegexUserDescr As RParams = RParams.DMS("\<meta property=""og:description"" content=""([^\>]+)""\s*/\>", 1, HtmlConverter, EDP.ReturnValue)
End Module
End Namespace

View File

@@ -388,8 +388,10 @@ Namespace API.ThreadsNet
Dim newID$ Dim newID$
Dim idStr$ = String.Empty Dim idStr$ = String.Empty
If Not r.IsEmptyString Then If Not r.IsEmptyString Then
UserSiteNameUpdate(RegexReplace(r, RegexUserName))
UserDescriptionUpdate(RegexReplace(r, RegexUserDescr))
ParseTokens(r, 0) ParseTokens(r, 0)
newID = RegexReplace(r, RParams.DMS("""props"":\{[^\{\}]*?""user_id"":""(\d+)""", 1, EDP.ReturnValue)) newID = RegexReplace(r, RegexUserID)
If ID.IsEmptyString OrElse ID = newID Then If ID.IsEmptyString OrElse ID = newID Then
_IdChanged = ID.IsEmptyString _IdChanged = ID.IsEmptyString
ID = newID ID = newID

View File

@@ -11,6 +11,7 @@ Imports PersonalUtilities.Functions.RegularExpressions
Namespace API.TikTok Namespace API.TikTok
Friend Module Declarations Friend Module Declarations
Friend ReadOnly SimpleDateConverter As New ADateTime("yyyyMMdd") Friend ReadOnly SimpleDateConverter As New ADateTime("yyyyMMdd")
Friend ReadOnly SimpleDateConverterWithTime As New ADateTime("yyyyMMdd_HHmmss")
Friend ReadOnly RegexTagsReplacer As RParams = RParams.DM("#\w+\s?", -1, RegexReturn.Replace, Friend ReadOnly RegexTagsReplacer As RParams = RParams.DM("#\w+\s?", -1, RegexReturn.Replace,
CType(Function(input$) String.Empty, Func(Of String, String)), EDP.ReturnValue) CType(Function(input$) String.Empty, Func(Of String, String)), EDP.ReturnValue)
Friend ReadOnly RegexPhotoJson As RParams = RParams.DMS("UNIVERSAL_DATA_FOR_REHYDRATION__"" type=""application/json""\>([^\<]+)\<", 1, Friend ReadOnly RegexPhotoJson As RParams = RParams.DMS("UNIVERSAL_DATA_FOR_REHYDRATION__"" type=""application/json""\>([^\<]+)\<", 1,

View File

@@ -10,11 +10,13 @@ Imports SCrawler.API.Base
Imports SCrawler.Plugin Imports SCrawler.Plugin
Imports SCrawler.Plugin.Attributes Imports SCrawler.Plugin.Attributes
Imports PersonalUtilities.Functions.RegularExpressions Imports PersonalUtilities.Functions.RegularExpressions
Imports DN = SCrawler.API.Base.DeclaredNames
Namespace API.TikTok Namespace API.TikTok
<Manifest("AndyProgram_TikTok"), SpecialForm(False), SeparatedTasks(1)> <Manifest("AndyProgram_TikTok"), SpecialForm(False), SeparatedTasks(1)>
Friend Class SiteSettings : Inherits SiteSettingsBase Friend Class SiteSettings : Inherits SiteSettingsBase
#Region "Categories" #Region "Categories"
Private Const CAT_DOWN As String = "Download" Private Const CAT_DOWN As String = "Download"
Private Const CAT_UserDefs_Title As String = DN.CAT_UserDefs & " (Title)"
#End Region #End Region
#Region "Download" #Region "Download"
<PropertyOption(ControlText:="Download videos", Category:=CAT_DOWN), PXML, PClonable> <PropertyOption(ControlText:="Download videos", Category:=CAT_DOWN), PXML, PClonable>
@@ -22,33 +24,47 @@ Namespace API.TikTok
<PropertyOption(ControlText:="Download photos", Category:=CAT_DOWN), PXML, PClonable> <PropertyOption(ControlText:="Download photos", Category:=CAT_DOWN), PXML, PClonable>
Friend ReadOnly Property DownloadTTPhotos As PropertyValue Friend ReadOnly Property DownloadTTPhotos As PropertyValue
#End Region #End Region
<PropertyOption(ControlText:="Remove tags from title"), PXML, PClonable> #Region "User defaults"
#Region "Sections"
<PropertyOption(ControlText:="Get Timeline", Category:=DN.CAT_UserDefs), PXML, PClonable>
Friend ReadOnly Property GetTimeline As PropertyValue
<PropertyOption(ControlText:="Get User Stories", Category:=DN.CAT_UserDefs), PXML, PClonable>
Friend ReadOnly Property GetStoriesUser As PropertyValue
<PropertyOption(ControlText:="Get Reposts", Category:=DN.CAT_UserDefs), PXML, PClonable>
Friend ReadOnly Property GetReposts As PropertyValue
#End Region
#Region "Title"
<PropertyOption(ControlText:="Remove tags from title", Category:=CAT_UserDefs_Title), PXML, PClonable>
Friend ReadOnly Property RemoveTagsFromTitle As PropertyValue Friend ReadOnly Property RemoveTagsFromTitle As PropertyValue
<PropertyOption(ControlText:="Use native title", ControlToolTip:="Use a user-created video title for the filename instead of the video ID."), PXML, PClonable> <PropertyOption(ControlText:="Use native title", ControlToolTip:="Use a user-created video title for the filename instead of the video ID.",
Category:=CAT_UserDefs_Title), PXML, PClonable>
Friend ReadOnly Property TitleUseNative As PropertyValue Friend ReadOnly Property TitleUseNative As PropertyValue
<PropertyOption(ControlText:="Use native title (standalone downloader)", <PropertyOption(ControlText:="Use native title (standalone downloader)",
ControlToolTip:="Use a user-created video title for the filename instead of the video ID."), PXML, PClonable> ControlToolTip:="Use a user-created video title for the filename instead of the video ID.", Category:=CAT_UserDefs_Title), PXML, PClonable>
Friend ReadOnly Property TitleUseNativeSTD As PropertyValue Friend ReadOnly Property TitleUseNativeSTD As PropertyValue
<PropertyOption(ControlText:="Add video ID to video title"), PXML, PClonable> <PropertyOption(ControlText:="Add video ID to video title", Category:=CAT_UserDefs_Title), PXML, PClonable>
Friend ReadOnly Property TitleAddVideoID As PropertyValue Friend ReadOnly Property TitleAddVideoID As PropertyValue
<PropertyOption(ControlText:="Add video ID to video title (standalone downloader)"), PXML, PClonable> <PropertyOption(ControlText:="Add video ID to video title (standalone downloader)", Category:=CAT_UserDefs_Title), PXML, PClonable>
Friend ReadOnly Property TitleAddVideoIDSTD As PropertyValue Friend ReadOnly Property TitleAddVideoIDSTD As PropertyValue
<PropertyOption(ControlText:="Use regex to clean video title"), PXML, PClonable> <PropertyOption(ControlText:="Use regex to clean video title", Category:=CAT_UserDefs_Title), PXML, PClonable>
Friend ReadOnly Property TitleUseRegexForTitle As PropertyValue Friend ReadOnly Property TitleUseRegexForTitle As PropertyValue
<PropertyOption(ControlText:="Title regex", ControlToolTip:="Regex to clean video title"), PXML, PClonable> <PropertyOption(ControlText:="Title regex", ControlToolTip:="Regex to clean video title", Category:=CAT_UserDefs_Title), PXML, PClonable>
Friend ReadOnly Property TitleUseRegexForTitle_Value As PropertyValue Friend ReadOnly Property TitleUseRegexForTitle_Value As PropertyValue
#End Region
#End Region
<PropertyOption(ControlText:="Use video date as file date", <PropertyOption(ControlText:="Use video date as file date",
ControlToolTip:="Set the file date to the date the video was added (website) (if available)."), PXML, PClonable> ControlToolTip:="Set the file date to the date the video was added (website) (if available)."), PXML, PClonable>
Friend ReadOnly Property UseParsedVideoDate As PropertyValue Friend ReadOnly Property UseParsedVideoDate As PropertyValue
<PropertyOption(ControlText:="Use video date as file date (standalone downloader)", <PropertyOption(ControlText:="Use video date as file date (standalone downloader)",
ControlToolTip:="Set the file date to the date the video was added (website) (if available)."), PXML, PClonable> ControlToolTip:="Set the file date to the date the video was added (website) (if available)."), PXML, PClonable>
Friend ReadOnly Property UseParsedVideoDateSTD As PropertyValue Friend ReadOnly Property UseParsedVideoDateSTD As PropertyValue
<DoNotUse> Friend Overrides Property DownloadText As PropertyValue
<DoNotUse> Friend Overrides Property DownloadTextPosts As PropertyValue
<DoNotUse> Friend Overrides Property DownloadTextSpecialFolder As PropertyValue
Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean) Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean)
MyBase.New("TikTok", "www.tiktok.com", AccName, Temp, My.Resources.SiteResources.TikTokIcon_32, My.Resources.SiteResources.TikTokPic_192) MyBase.New("TikTok", "www.tiktok.com", AccName, Temp, My.Resources.SiteResources.TikTokIcon_32, My.Resources.SiteResources.TikTokPic_192)
GetTimeline = New PropertyValue(True)
GetStoriesUser = New PropertyValue(False)
GetReposts = New PropertyValue(False)
DownloadTTVideos = New PropertyValue(True) DownloadTTVideos = New PropertyValue(True)
DownloadTTPhotos = New PropertyValue(True) DownloadTTPhotos = New PropertyValue(True)
@@ -79,5 +95,10 @@ Namespace API.TikTok
Using f As New InternalSettingsForm(Options, Me, False) : f.ShowDialog() : End Using Using f As New InternalSettingsForm(Options, Me, False) : f.ShowDialog() : End Using
End If End If
End Sub End Sub
Friend Overrides Function GetUserPostUrl(ByVal User As UserDataBase, ByVal Media As UserMedia) As String
Dim url$ = MyBase.GetUserPostUrl(User, Media)
If Not url.IsEmptyString AndAlso url.EndsWith(UserData.GDL_POSTFIX) Then url = url.Replace(UserData.GDL_POSTFIX, String.Empty)
Return url
End Function
End Class End Class
End Namespace End Namespace

View File

@@ -7,16 +7,21 @@
' This program is distributed in the hope that it will be useful, ' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY ' but WITHOUT ANY WARRANTY
Imports System.Threading Imports System.Threading
Imports SCrawler.API.Base
Imports SCrawler.API.YouTube.Objects
Imports PersonalUtilities.Functions.XML
Imports PersonalUtilities.Functions.RegularExpressions Imports PersonalUtilities.Functions.RegularExpressions
Imports PersonalUtilities.Functions.XML
Imports PersonalUtilities.Tools Imports PersonalUtilities.Tools
Imports PersonalUtilities.Tools.Web.Documents.JSON Imports PersonalUtilities.Tools.Web.Documents.JSON
Imports SCrawler.API.Base
Imports SCrawler.API.YouTube.Objects
Imports SCrawler.Plugin.Attributes
Imports Sections = SCrawler.API.Instagram.UserData.Sections
Imports UTypes = SCrawler.API.Base.UserMedia.Types Imports UTypes = SCrawler.API.Base.UserMedia.Types
Namespace API.TikTok Namespace API.TikTok
Friend Class UserData : Inherits UserDataBase Friend Class UserData : Inherits UserDataBase
#Region "XML names" #Region "XML names"
Private Const Name_GetTimeline As String = "GetTimeline"
Private Const Name_GetStoriesUser As String = "GetStoriesUser"
Private Const Name_GetReposts As String = "GetReposts"
Private Const Name_RemoveTagsFromTitle As String = "RemoveTagsFromTitle" Private Const Name_RemoveTagsFromTitle As String = "RemoveTagsFromTitle"
Private Const Name_TitleUseNative As String = "TitleUseNative" Private Const Name_TitleUseNative As String = "TitleUseNative"
Private Const Name_TitleAddVideoID As String = "TitleAddVideoID" Private Const Name_TitleAddVideoID As String = "TitleAddVideoID"
@@ -27,6 +32,7 @@ Namespace API.TikTok
Private Const Name_PhotosDownloaded As String = "PhotosDownloaded" Private Const Name_PhotosDownloaded As String = "PhotosDownloaded"
#End Region #End Region
#Region "Declarations" #Region "Declarations"
Friend Const GDL_POSTFIX As String = "--GDL"
Private ReadOnly Property MySettings As SiteSettings Private ReadOnly Property MySettings As SiteSettings
Get Get
Return HOST.Source Return HOST.Source
@@ -57,6 +63,9 @@ Namespace API.TikTok
End If End If
End Get End Get
End Property End Property
Friend Property GetTimeline As Boolean = True
Friend Property GetStoriesUser As Boolean = False
Friend Property GetReposts As Boolean = False
Friend Property RemoveTagsFromTitle As Boolean = False Friend Property RemoveTagsFromTitle As Boolean = False
Friend Property TitleUseNative As Boolean = True Friend Property TitleUseNative As Boolean = True
Friend Property TitleAddVideoID As Boolean = True Friend Property TitleAddVideoID As Boolean = True
@@ -73,6 +82,10 @@ Namespace API.TikTok
Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object) Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object)
If Not Obj Is Nothing AndAlso TypeOf Obj Is UserExchangeOptions Then If Not Obj Is Nothing AndAlso TypeOf Obj Is UserExchangeOptions Then
With DirectCast(Obj, UserExchangeOptions) With DirectCast(Obj, UserExchangeOptions)
.ApplyBase(Me)
GetTimeline = .GetTimeline
GetStoriesUser = .GetStoriesUser
GetReposts = .GetReposts
RemoveTagsFromTitle = .RemoveTagsFromTitle RemoveTagsFromTitle = .RemoveTagsFromTitle
TitleUseNative = .TitleUseNative TitleUseNative = .TitleUseNative
TitleAddVideoID = .TitleAddVideoID TitleAddVideoID = .TitleAddVideoID
@@ -87,6 +100,9 @@ Namespace API.TikTok
Protected Overrides Sub LoadUserInformation_OptionalFields(ByRef Container As XmlFile, ByVal Loading As Boolean) Protected Overrides Sub LoadUserInformation_OptionalFields(ByRef Container As XmlFile, ByVal Loading As Boolean)
With Container With Container
If Loading Then If Loading Then
GetTimeline = .Value(Name_GetTimeline).FromXML(Of Boolean)(True)
GetStoriesUser = .Value(Name_GetStoriesUser).FromXML(Of Boolean)(False)
GetReposts = .Value(Name_GetReposts).FromXML(Of Boolean)(False)
RemoveTagsFromTitle = .Value(Name_RemoveTagsFromTitle).FromXML(Of Boolean)(False) RemoveTagsFromTitle = .Value(Name_RemoveTagsFromTitle).FromXML(Of Boolean)(False)
TitleUseNative = .Value(Name_TitleUseNative).FromXML(Of Boolean)(True) TitleUseNative = .Value(Name_TitleUseNative).FromXML(Of Boolean)(True)
TitleAddVideoID = .Value(Name_TitleAddVideoID).FromXML(Of Boolean)(True) TitleAddVideoID = .Value(Name_TitleAddVideoID).FromXML(Of Boolean)(True)
@@ -97,6 +113,9 @@ Namespace API.TikTok
TitleUseGlobalRegexOptions = .Value(Name_TitleUseGlobalRegexOptions).FromXML(Of Boolean)(True) TitleUseGlobalRegexOptions = .Value(Name_TitleUseGlobalRegexOptions).FromXML(Of Boolean)(True)
PhotosDownloaded = .Value(Name_PhotosDownloaded).FromXML(Of Boolean)(False) PhotosDownloaded = .Value(Name_PhotosDownloaded).FromXML(Of Boolean)(False)
Else Else
.Add(Name_GetTimeline, GetTimeline.BoolToInteger)
.Add(Name_GetStoriesUser, GetStoriesUser.BoolToInteger)
.Add(Name_GetReposts, GetReposts.BoolToInteger)
.Add(Name_RemoveTagsFromTitle, RemoveTagsFromTitle.BoolToInteger) .Add(Name_RemoveTagsFromTitle, RemoveTagsFromTitle.BoolToInteger)
.Add(Name_TitleUseNative, TitleUseNative.BoolToInteger) .Add(Name_TitleUseNative, TitleUseNative.BoolToInteger)
.Add(Name_TitleAddVideoID, TitleAddVideoID.BoolToInteger) .Add(Name_TitleAddVideoID, TitleAddVideoID.BoolToInteger)
@@ -165,17 +184,25 @@ Namespace API.TikTok
Private Function GetPhotoNode() As Object() Private Function GetPhotoNode() As Object()
Return {"imageURL", "urlList", 0, 0} Return {"imageURL", "urlList", 0, 0}
End Function End Function
Private Sub ValidateCache()
If If(UserCache?.Disposed, True) Then UserCache = CreateCache()
End Sub
Friend Overrides Sub DownloadData(ByVal Token As CancellationToken) Friend Overrides Sub DownloadData(ByVal Token As CancellationToken)
MyBase.DownloadData(Token) MyBase.DownloadData(Token)
UserCache.DisposeIfReady(False) UserCache.DisposeIfReady(False)
UserCache = Nothing UserCache = Nothing
End Sub End Sub
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken) Protected Overloads Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
ValidateCache()
If GetTimeline Then DownloadDataF(Sections.Timeline, Token)
If GetStoriesUser Then DownloadDataF(Sections.UserStories, Token)
If GetReposts Then DownloadDataF(Sections.Reposts, Token)
End Sub
Protected Overloads Sub DownloadDataF(ByVal Section As Sections, ByVal Token As CancellationToken)
Dim URL$ = $"https://www.tiktok.com/@{NameTrue}" Dim URL$ = $"https://www.tiktok.com/@{NameTrue}"
UserCache = CreateCache()
Try Try
Const photoPrefix$ = "photo_" Const photoPrefix$ = "photo_"
Dim postID$, title$, postUrl$, newName$, t$, postID2$, imgUrl$ Dim postID$, title$, postUrl$, newName$, t$, tOrig$, postID2$, imgUrl$, pText$
Dim postDate As Date? Dim postDate As Date?
Dim dateAfterC As Date? = Nothing Dim dateAfterC As Date? = Nothing
Dim dateBefore As Date? = DownloadDateTo Dim dateBefore As Date? = DownloadDateTo
@@ -184,12 +211,24 @@ Namespace API.TikTok
Dim titleRegex As RParams = GetTitleRegex() Dim titleRegex As RParams = GetTitleRegex()
Dim vPath As SFile = Nothing, pPath As SFile = Nothing Dim vPath As SFile = Nothing, pPath As SFile = Nothing
Dim file As SFile Dim file As SFile
Dim j As EContainer, photo As EContainer Dim j As EContainer = Nothing, photo As EContainer, item As EContainer
Dim photoNode As Object() = GetPhotoNode() Dim photoNode As Object() = GetPhotoNode()
Dim c%, cc%, i% Dim c%, cc%, i%
Dim errDef As New ErrorsDescriber(EDP.ReturnValue) Dim errDef As New ErrorsDescriber(EDP.ReturnValue)
Dim infoParsed As Boolean = False Dim infoParsed As Boolean = False
Dim gdlTmpIDs As New Dictionary(Of String, Integer)
Dim gdlCmd$ = String.Empty
Dim gdlIsNativeJson As Boolean
Dim __specFolder$ = String.Empty
Dim __specFolder_Cr As Func(Of String, String) = Function(_sp$) String.Empty.StringAppend(__specFolder).StringAppend(_sp, "\") &
IIf(__specFolder.IsEmptyString, String.Empty, "*")
Select Case Section
Case Sections.UserStories : URL &= "/stories" : __specFolder = "Stories (user)" : gdlCmd = "-o videos -o photos"
Case Sections.Reposts : URL &= "/reposts" : __specFolder = "Reposts"
End Select
If _ContentList.Count > 0 Then If _ContentList.Count > 0 Then
With (From d In _ContentList Where d.Post.Date.HasValue Select d.Post.Date.Value) With (From d In _ContentList Where d.Post.Date.HasValue Select d.Post.Date.Value)
If .ListExists Then dateAfterC = .Min If .ListExists Then dateAfterC = .Min
@@ -214,19 +253,16 @@ Namespace API.TikTok
End If End If
End If End If
If DownloadVideos And Settings.YtdlpFile.Exists And CBool(MySettings.DownloadTTVideos.Value) Then If Section = Sections.Timeline And DownloadVideos And Settings.YtdlpFile.Exists And CBool(MySettings.DownloadTTVideos.Value) Then
With UserCache.NewInstance : .Validate() : vPath = .RootDirectory : End With With UserCache.NewInstance : .Validate() : vPath = .RootDirectory : End With
Using b As New YTDLP.YTDLPBatch(Token) With {.TempPostsList = _TempPostsList} Using b As New YTDLP.YTDLPBatch(Token,, vPath) With {.TempPostsList = _TempPostsList}
b.Commands.Clear()
b.ChangeDirectory(vPath)
b.Encoding = BatchExecutor.UnicodeEncoding
b.Execute(CreateYTCommand(vPath, URL, False, dateBefore, dateAfter)) b.Execute(CreateYTCommand(vPath, URL, False, dateBefore, dateAfter))
End Using End Using
End If End If
If DownloadImages And Settings.GalleryDLFile.Exists And CBool(MySettings.DownloadTTPhotos.Value) Then If DownloadImages And Settings.GalleryDLFile.Exists And CBool(MySettings.DownloadTTPhotos.Value) Then
With UserCache.NewInstance : .Validate() : pPath = .RootDirectory : End With With UserCache.NewInstance : .Validate() : pPath = .RootDirectory : End With
Using b As New GDL.GDLBatch(Token) Using b As New GDL.GDLBatch(Token,, pPath)
With b With b
If PhotosDownloaded And _TempPostsList.Count > 0 Then If PhotosDownloaded And _TempPostsList.Count > 0 Then
.TempPostsList = (From p As String In _TempPostsList .TempPostsList = (From p As String In _TempPostsList
@@ -235,9 +271,7 @@ Namespace API.TikTok
Else Else
.TempPostsList = New List(Of String) .TempPostsList = New List(Of String)
End If End If
.ChangeDirectory(pPath) .Execute(CreateGDLCommand(URL, gdlCmd))
.Encoding = BatchExecutor.UnicodeEncoding
.Execute(CreateGDLCommand(URL))
If Not PhotosDownloaded Then _ForceSaveUserInfo = True : _ForceSaveUserInfoOnException = True If Not PhotosDownloaded Then _ForceSaveUserInfo = True : _ForceSaveUserInfoOnException = True
PhotosDownloaded = True PhotosDownloaded = True
End With End With
@@ -247,6 +281,7 @@ Namespace API.TikTok
ThrowAny(Token) ThrowAny(Token)
Dim files As List(Of SFile) Dim files As List(Of SFile)
'YTDLP
If Not vPath.IsEmptyString AndAlso vPath.Exists(SFO.Path, False) Then If Not vPath.IsEmptyString AndAlso vPath.Exists(SFO.Path, False) Then
files = SFile.GetFiles(vPath, "*.json",, errDef) files = SFile.GetFiles(vPath, "*.json",, errDef)
If files.ListExists Then If files.ListExists Then
@@ -254,7 +289,7 @@ Namespace API.TikTok
j = JsonDocument.Parse(file.GetText, errDef) j = JsonDocument.Parse(file.GetText, errDef)
If j.ListExists Then If j.ListExists Then
If j.Value("_type").StringToLower = "video" Then If j.Value("_type").StringToLower = "video" Then
If Not baseDataObtained Then If Not baseDataObtained And Section = Sections.Timeline Then
baseDataObtained = True baseDataObtained = True
If ID.IsEmptyString Then ID = j.Value("uploader_id") If ID.IsEmptyString Then ID = j.Value("uploader_id")
newName = j.Value("uploader") newName = j.Value("uploader")
@@ -266,10 +301,13 @@ Namespace API.TikTok
If Not _TempPostsList.Contains(postID) Then If Not _TempPostsList.Contains(postID) Then
_TempPostsList.ListAddValue(postID, LNC) _TempPostsList.ListAddValue(postID, LNC)
Else Else
Exit For 'Exit Sub 'Exit For 'Exit Sub
Continue For
End If End If
title = GetNewFileName(j.Value("title").StringRemoveWinForbiddenSymbols, title = GetNewFileName(j.Value("title").StringRemoveWinForbiddenSymbols,
TitleUseNative, RemoveTagsFromTitle, TitleAddVideoID, postID, titleRegex) TitleUseNative, RemoveTagsFromTitle, TitleAddVideoID, postID, titleRegex)
pText = j.Value("title")
If Not j.Value("description").IsEmptyString Then pText &= vbCr & vbCr & j.Value("description")
postDate = AConvert(Of Date)(j.Value("timestamp"), UnixDate32Provider, Nothing) postDate = AConvert(Of Date)(j.Value("timestamp"), UnixDate32Provider, Nothing)
If Not postDate.HasValue Then postDate = AConvert(Of Date)(j.Value("upload_date"), SimpleDateConverter, Nothing) If Not postDate.HasValue Then postDate = AConvert(Of Date)(j.Value("upload_date"), SimpleDateConverter, Nothing)
Select Case CheckDatesLimit(postDate, SimpleDateConverter) Select Case CheckDatesLimit(postDate, SimpleDateConverter)
@@ -280,7 +318,13 @@ Namespace API.TikTok
postUrl = j.Value("webpage_url") postUrl = j.Value("webpage_url")
If postUrl.IsEmptyString Then postUrl = $"https://www.tiktok.com/@{Name}/video/{postID}" If postUrl.IsEmptyString Then postUrl = $"https://www.tiktok.com/@{Name}/video/{postID}"
_TempMediaList.Add(New UserMedia(postUrl, UTypes.Video) With { _TempMediaList.Add(New UserMedia(postUrl, UTypes.Video) With {
.File = $"{title}.mp4", .Post = New UserPost(postID, postDate)}) .File = $"{title}.mp4",
.SpecialFolder = __specFolder_Cr(String.Empty),
.Post = New UserPost(postID, postDate),
.PostText = pText,
.PostTextFileSpecialFolder = DownloadTextSpecialFolder,
.PostTextFile = $"{ .File.Name}.txt"
})
End If End If
j.Dispose() j.Dispose()
End If End If
@@ -288,70 +332,183 @@ Namespace API.TikTok
End If End If
End If End If
j.DisposeIfReady
'GDL
If Not pPath.IsEmptyString AndAlso pPath.Exists(SFO.Path, False) Then If Not pPath.IsEmptyString AndAlso pPath.Exists(SFO.Path, False) Then
files = SFile.GetFiles(pPath, "*.txt",, errDef) files = SFile.GetFiles(pPath, "*.txt",, errDef)
If files.ListExists Then If files.ListExists Then
If Not Section = Sections.Timeline Then
GDLResetFileNameProvider(Math.Max(files.Count.ToString.Length, 2))
For i = 0 To files.Count - 1 : files(i) = GDLRenameFile(files(i), i) : Next
End If
For Each file In files For Each file In files
t = file.GetText(errDef) t = file.GetText(errDef)
If Not t.IsEmptyString Then t = RegexReplace(t, RegexPhotoJson) tOrig = t
gdlIsNativeJson = False
If Not t.IsEmptyString And Not Section = Sections.UserStories Then
t = RegexReplace(t, RegexPhotoJson)
If t.IsEmptyString Then t = tOrig : gdlIsNativeJson = True
End If
If Not t.IsEmptyString Then If Not t.IsEmptyString Then
j = JsonDocument.Parse(t, errDef) j = JsonDocument.Parse(t, errDef)
If j.ListExists Then If j.ListExists Then
With j.ItemF({0, "webapp.video-detail", "itemInfo", "itemStruct"}) If Section = Sections.UserStories Then
If .ListExists Then With j("itemList")
postID = .Value("id") If .ListExists Then
postID2 = $"{photoPrefix}{postID}" For Each item In .Self
If Not _TempPostsList.Contains(postID2) Then _TempPostsList.ListAddValue(postID2, LNC) Else Exit For 'Exit Sub With item
postDate = AConvert(Of Date)(j.Value("createTime"), UnixDate32Provider, Nothing) postID = .Value("id")
Select Case CheckDatesLimit(postDate, SimpleDateConverter) postDate = AConvert(Of Date)(.Value("createTime"), UnixDate32Provider, Nothing)
Case DateResult.Skip : Continue For If Not _TempPostsList.Contains(postID) Then
Case DateResult.Exit : Exit For 'Exit Sub _TempPostsList.Add(postID)
End Select postUrl = $"https://www.tiktok.com/@{Name}/video/{postID}{GDL_POSTFIX}"
If postDate.HasValue Then
title = CStr(AConvert(Of String)(postDate.Value, SimpleDateConverterWithTime, String.Empty)).StringAppend(postID, " ")
Else
title = postID
End If
_TempMediaList.Add(New UserMedia(postUrl, UTypes.Video) With {
.URL_BASE = postUrl,
.SpecialFolder = __specFolder_Cr(String.Empty),
.File = $"{title}.mp4",
.Post = New UserPost(postID, postDate)
})
With .Item("video")
If .ListExists AndAlso Not .Value("cover").IsEmptyString Then _
_TempMediaList.Add(New UserMedia(.Value("cover"), UTypes.Picture) With {
.URL_BASE = postUrl,
.SpecialFolder = __specFolder_Cr("Photo"),
.File = $"{title}.jpg"
})
End With
Else
Continue For
End If
End With
Next
End If
End With
ElseIf Section = Sections.Reposts And gdlIsNativeJson Then
With j("itemList")
If .ListExists Then
For Each item In .Self
With item
postID = .Value("id")
postID2 = $"{photoPrefix}{postID}"
If Not _TempPostsList.Contains(postID) And Not _TempPostsList.Contains(postID2) Then
title = GetNewFileName(.Value("title").StringRemoveWinForbiddenSymbols,
TitleUseNative, RemoveTagsFromTitle, TitleAddVideoID, postID, titleRegex)
pText = .Value("title")
If Not .Value("desc").IsEmptyString Then
pText &= vbCr & vbCr & .Value("desc")
If title.IsEmptyString Then title = GetNewFileName(.Value("desc").StringRemoveWinForbiddenSymbols,
TitleUseNative, RemoveTagsFromTitle, TitleAddVideoID, postID, titleRegex)
End If
postDate = AConvert(Of Date)(j.Value("createTime"), UnixDate32Provider, Nothing)
If postDate.HasValue Then
Select Case CheckDatesLimit(postDate, SimpleDateConverter)
Case DateResult.Skip : Continue For
Case DateResult.Exit : Exit For 'Exit Sub
End Select
End If
If Not infoParsed Then postUrl = .Value({"author"}, "uniqueId")
With .Item("author") If Not postUrl.IsEmptyString Then
If .ListExists Then postUrl = $"https://www.tiktok.com/@{postUrl}/video/{postID}"
infoParsed = True _TempMediaList.Add(New UserMedia(postUrl, UTypes.Video) With {
SimpleDownloadAvatar(.Value("avatarLarger").IfNullOrEmpty(.Value("avatarMedium")).IfNullOrEmpty(.Value("avatarThumb")), .File = $"{title}.mp4",
Function(ByVal ____url As String) As SFile .SpecialFolder = __specFolder_Cr(String.Empty),
Dim ____f As SFile = CreateFileFromUrl(____url) .Post = New UserPost(postID, postDate),
If Not ____f.Name.IsEmptyString Then ____f.Name = ____f.Name.Replace(":", "_").Replace("~", "-") .PostText = pText,
If Not ____f.Extension.IsEmptyString Then .PostTextFileSpecialFolder = DownloadTextSpecialFolder,
If Not (____f.Extension = "jpg" Or ____f.Extension = "jpeg") Then .PostTextFile = $"{ .File.Name}.txt"
____f.Extension = RegexReplace(____f.Extension, RParams.DMS("(.+)\?", 1, EDP.ReturnValue)) })
If Not ____f.Extension.IsEmptyString AndAlso Not (____f.Extension = "jpg" Or ____f.Extension = "jpeg") Then ____f.Extension = String.Empty If Not gdlTmpIDs.ContainsKey(postID) Then gdlTmpIDs.Add(postID, _TempMediaList.Count - 1)
End If
Else
Continue For
End If
End With
Next
End If
End With
Else
With j.ItemF({0, "webapp.video-detail", "itemInfo", "itemStruct"})
If .ListExists Then
postID = .Value("id")
postID2 = $"{photoPrefix}{postID}"
'If Not _TempPostsList.Contains(postID2) Then _TempPostsList.ListAddValue(postID2, LNC) Else Exit For 'Exit Sub
postDate = AConvert(Of Date)(.Value("createTime"), UnixDate32Provider, Nothing)
If Not Section = Sections.UserStories Then
Select Case CheckDatesLimit(postDate, SimpleDateConverter)
Case DateResult.Skip : Continue For
Case DateResult.Exit : Exit For 'Exit Sub
End Select
End If
If Not infoParsed Then
With .Item("author")
If .ListExists Then
infoParsed = True
SimpleDownloadAvatar(.Value("avatarLarger").IfNullOrEmpty(.Value("avatarMedium")).IfNullOrEmpty(.Value("avatarThumb")),
Function(ByVal ____url As String) As SFile
Dim ____f As SFile = CreateFileFromUrl(____url)
If Not ____f.Name.IsEmptyString Then ____f.Name = ____f.Name.Replace(":", "_").Replace("~", "-")
If Not ____f.Extension.IsEmptyString Then
If Not (____f.Extension = "jpg" Or ____f.Extension = "jpeg") Then
____f.Extension = RegexReplace(____f.Extension, RParams.DMS("(.+)\?", 1, EDP.ReturnValue))
If Not ____f.Extension.IsEmptyString AndAlso Not (____f.Extension = "jpg" Or ____f.Extension = "jpeg") Then ____f.Extension = String.Empty
End If
End If End If
End If Return ____f
Return ____f End Function)
End Function) UserSiteNameUpdate(.Value("nickname"))
UserSiteNameUpdate(.Value("nickname")) UserDescriptionUpdate(.Value("signature"))
UserDescriptionUpdate(.Value("signature")) End If
End With
End If
title = GetNewFileName(.Value({"imagePost"}, "title").StringRemoveWinForbiddenSymbols,
TitleUseNative, RemoveTagsFromTitle, TitleAddVideoID, postID, titleRegex)
pText = .Value({"imagePost"}, "title")
If Not .Value("desc").IsEmptyString Then pText &= vbCr & vbCr & .Value("desc")
postUrl = $"https://www.tiktok.com/@{Name}/photo/{postID}"
With .Item({"imagePost", "images"})
If .ListExists Then
If Not _TempPostsList.Contains(postID2) Then
_TempPostsList.ListAddValue(postID2, LNC)
If gdlTmpIDs.ContainsKey(postID) Then
_TempMediaList.RemoveAt(gdlTmpIDs(postID))
gdlTmpIDs.Remove(postID)
End If
Else
Continue For 'Exit Sub
End If
i = 0
c = .Count
cc = Math.Max(c.ToString.Length, 3)
For Each photo In .Self
i += 1
imgUrl = photo.ItemF(photoNode).XmlIfNothingValue
If Not imgUrl.IsEmptyString Then _
_TempMediaList.Add(New UserMedia(imgUrl, UTypes.Picture) With {
.URL_BASE = postUrl,
.SpecialFolder = __specFolder_Cr("Photo"),
.File = $"{title}{IIf(c > 1, $"_{i.NumToString(ANumbers.Formats.NumberGroup, cc)}", String.Empty)}.jpg",
.Post = New UserPost(postID, postDate),
.PostText = pText,
.PostTextFileSpecialFolder = DownloadTextSpecialFolder,
.PostTextFile = $"{ .File.Name}.txt"
})
Next
End If End If
End With End With
End If End If
End With
title = GetNewFileName(j.Value({"imagePost"}, "title").StringRemoveWinForbiddenSymbols, End If
TitleUseNative, RemoveTagsFromTitle, TitleAddVideoID, postID, titleRegex)
postUrl = $"https://www.tiktok.com/@{Name}/photo/{postID}"
With .Item({"imagePost", "images"})
If .ListExists Then
i = 0
c = .Count
cc = Math.Max(c.ToString.Length, 3)
For Each photo In .Self
i += 1
imgUrl = photo.ItemF(photoNode).XmlIfNothingValue
If Not imgUrl.IsEmptyString Then _
_TempMediaList.Add(New UserMedia(imgUrl, UTypes.Picture) With {
.URL_BASE = postUrl,
.SpecialFolder = "Photo",
.File = $"{title}{IIf(c > 1, $"_{i.NumToString(ANumbers.Formats.NumberGroup, cc)}", String.Empty)}.jpg",
.Post = New UserPost(postID, postDate)})
Next
End If
End With
End If
End With
j.Dispose() j.Dispose()
End If End If
End If End If
@@ -359,6 +516,9 @@ Namespace API.TikTok
End If End If
End If End If
j.DisposeIfReady
_TempPostsList.ListAddList(gdlTmpIDs.Keys)
gdlTmpIDs.Clear()
If _TempMediaList.Count > 0 Then LastDownloadDate = Now If _TempMediaList.Count > 0 Then LastDownloadDate = Now
Catch ex As Exception Catch ex As Exception
ProcessException(ex, Token, $"data downloading error [{URL}]") ProcessException(ex, Token, $"data downloading error [{URL}]")
@@ -443,8 +603,17 @@ Namespace API.TikTok
End Function End Function
#End Region #End Region
#Region "GDL Support" #Region "GDL Support"
Private Function CreateGDLCommand(ByVal URL As String) As String Private Function CreateGDLCommand(ByVal URL As String, Optional ByVal SectionCommand As String = Nothing,
Return $"""{Settings.GalleryDLFile}"" --verbose --no-download --no-skip --write-pages {URL}" Optional ByVal IsDownload As Boolean = False, Optional ByVal Output As SFile = Nothing) As String
Dim command$ = $"""{Settings.GalleryDLFile}"" "
If Not IsDownload Then
command &= "--verbose --no-download --no-skip --write-pages "
Else
command &= $"--dest ""{Output.PathNoSeparator}"" "
End If
If Not CBool(If(IsSingleObjectDownload, MySettings.UseParsedVideoDateSTD, MySettings.UseParsedVideoDate).Value) Then command &= "--no-mtime "
command &= $"{SectionCommand} {URL}"
Return command
End Function End Function
#End Region #End Region
#Region "DownloadContent, DownloadFile" #Region "DownloadContent, DownloadFile"
@@ -456,8 +625,16 @@ Namespace API.TikTok
End Function End Function
Protected Overrides Function DownloadFile(ByVal URL As String, ByVal Media As UserMedia, ByVal DestinationFile As SFile, ByVal Token As CancellationToken) As SFile Protected Overrides Function DownloadFile(ByVal URL As String, ByVal Media As UserMedia, ByVal DestinationFile As SFile, ByVal Token As CancellationToken) As SFile
Using b As New TokenBatch(Token) With {.FileExchanger = RootCacheTikTok} Using b As New TokenBatch(Token) With {.FileExchanger = RootCacheTikTok}
b.Encoding = BatchExecutor.UnicodeEncoding If URL.EndsWith(GDL_POSTFIX) Then
b.Execute(CreateYTCommand(DestinationFile, URL, True)) ValidateCache()
Dim tmpPath As SFile
With UserCache.NewInstance : .Validate() : tmpPath = .RootDirectory : End With
b.Execute(CreateGDLCommand(URL.Replace(GDL_POSTFIX, String.Empty),, True, tmpPath))
tmpPath = SFile.GetFiles(tmpPath, "*.mp4", IO.SearchOption.AllDirectories, EDP.ReturnValue).FirstOrDefault
If Not tmpPath.IsEmptyString Then SFile.Move(tmpPath, DestinationFile)
Else
b.Execute(CreateYTCommand(DestinationFile, URL, True))
End If
End Using End Using
If DestinationFile.Exists Then Return DestinationFile Else Return Nothing If DestinationFile.Exists Then Return DestinationFile Else Return Nothing
End Function End Function
@@ -477,7 +654,6 @@ Namespace API.TikTok
t = UTypes.Video t = UTypes.Video
If CBool(MySettings.TitleUseNativeSTD.Value) Then If CBool(MySettings.TitleUseNativeSTD.Value) Then
Using b As New BatchExecutor(True) With { Using b As New BatchExecutor(True) With {
.Encoding = BatchExecutor.UnicodeEncoding,
.CleanAutomaticallyViaRegEx = True, .CleanAutomaticallyViaRegEx = True,
.CleanAutomaticallyViaRegExRemoveAllCommands = True .CleanAutomaticallyViaRegExRemoveAllCommands = True
} }
@@ -498,11 +674,7 @@ Namespace API.TikTok
Data.Title = defName Data.Title = defName
Dim dir As SFile Dim dir As SFile
With If(Cache, Settings.Cache).NewInstance() : .Validate() : dir = .RootDirectory : End With With If(Cache, Settings.Cache).NewInstance() : .Validate() : dir = .RootDirectory : End With
Using b As New GDL.GDLBatch(Token) Using b As New GDL.GDLBatch(Token,, dir) : b.Execute(CreateGDLCommand(Data.URL)) : End Using
b.ChangeDirectory(dir)
b.Encoding = BatchExecutor.UnicodeEncoding
b.Execute(CreateGDLCommand(Data.URL))
End Using
Dim file As SFile = SFile.GetFiles(dir, "*.txt",, EDP.ReturnValue).FirstOrDefault Dim file As SFile = SFile.GetFiles(dir, "*.txt",, EDP.ReturnValue).FirstOrDefault
If file.Exists Then If file.Exists Then
Dim r$ = file.GetText(EDP.ReturnValue) Dim r$ = file.GetText(EDP.ReturnValue)

View File

@@ -6,9 +6,16 @@
' '
' This program is distributed in the hope that it will be useful, ' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY ' but WITHOUT ANY WARRANTY
Imports SCrawler.Plugin
Imports SCrawler.Plugin.Attributes Imports SCrawler.Plugin.Attributes
Namespace API.TikTok Namespace API.TikTok
Friend Class UserExchangeOptions Friend Class UserExchangeOptions : Inherits Base.EditorExchangeOptionsBase
<PSetting(NameOf(SiteSettings.GetTimeline), NameOf(MySettings))>
Friend Property GetTimeline As Boolean
<PSetting(NameOf(SiteSettings.GetStoriesUser), NameOf(MySettings))>
Friend Property GetStoriesUser As Boolean
<PSetting(NameOf(SiteSettings.GetReposts), NameOf(MySettings))>
Friend Property GetReposts As Boolean
<PSetting(NameOf(SiteSettings.RemoveTagsFromTitle), NameOf(MySettings))> <PSetting(NameOf(SiteSettings.RemoveTagsFromTitle), NameOf(MySettings))>
Friend Property RemoveTagsFromTitle As Boolean Friend Property RemoveTagsFromTitle As Boolean
<PSetting(NameOf(SiteSettings.TitleUseNative), NameOf(MySettings))> <PSetting(NameOf(SiteSettings.TitleUseNative), NameOf(MySettings))>
@@ -21,9 +28,15 @@ Namespace API.TikTok
Friend Property TitleUseRegexForTitle_Value As String Friend Property TitleUseRegexForTitle_Value As String
<PSetting(Caption:="Use global regex", ToolTip:="Use the global regex from the site settings to clean the video title")> <PSetting(Caption:="Use global regex", ToolTip:="Use the global regex from the site settings to clean the video title")>
Friend Property TitleUseGlobalRegexOptions As Boolean = True Friend Property TitleUseGlobalRegexOptions As Boolean = True
<PSetting(Address:=SettingAddress.None)> Friend Overrides Property UserName As String
Private ReadOnly MySettings As SiteSettings Private ReadOnly MySettings As SiteSettings
Friend Sub New(ByVal u As UserData) Friend Sub New(ByVal u As UserData)
MyBase.New(u)
_ApplyBase_Name = False
MySettings = u.HOST.Source MySettings = u.HOST.Source
GetTimeline = u.GetTimeline
GetStoriesUser = u.GetStoriesUser
GetReposts = u.GetReposts
RemoveTagsFromTitle = u.RemoveTagsFromTitle RemoveTagsFromTitle = u.RemoveTagsFromTitle
TitleUseNative = u.TitleUseNative TitleUseNative = u.TitleUseNative
TitleAddVideoID = u.TitleAddVideoID TitleAddVideoID = u.TitleAddVideoID
@@ -32,7 +45,12 @@ Namespace API.TikTok
TitleUseGlobalRegexOptions = u.TitleUseGlobalRegexOptions TitleUseGlobalRegexOptions = u.TitleUseGlobalRegexOptions
End Sub End Sub
Friend Sub New(ByVal s As SiteSettings) Friend Sub New(ByVal s As SiteSettings)
MyBase.New(s)
_ApplyBase_Name = False
MySettings = s MySettings = s
GetTimeline = s.GetTimeline.Value
GetStoriesUser = s.GetStoriesUser.Value
GetReposts = s.GetReposts.Value
RemoveTagsFromTitle = s.RemoveTagsFromTitle.Value RemoveTagsFromTitle = s.RemoveTagsFromTitle.Value
TitleUseNative = s.TitleUseNative.Value TitleUseNative = s.TitleUseNative.Value
TitleAddVideoID = s.TitleAddVideoID.Value TitleAddVideoID = s.TitleAddVideoID.Value

View File

@@ -112,14 +112,6 @@ Namespace API.Twitter
Return HOST.Source Return HOST.Source
End Get End Get
End Property End Property
Private FileNameProvider As ANumbers = Nothing
Private Sub ResetFileNameProvider(Optional ByVal GroupSize As Integer? = Nothing)
FileNameProvider = New ANumbers With {.FormatOptions = ANumbers.Options.FormatNumberGroup + ANumbers.Options.Groups}
FileNameProvider.GroupSize = If(GroupSize, 3)
End Sub
Private Function RenameGdlFile(ByVal Input As SFile, ByVal i As Integer) As SFile
Return SFile.Rename(Input, $"{Input.PathWithSeparator}{i.NumToString(FileNameProvider)}.{Input.Extension}",, EDP.ThrowException)
End Function
Friend Function GetUserUrl() As String Friend Function GetUserUrl() As String
Return $"https://x.com{IIf(IsCommunity, SiteSettings.CommunitiesUser, String.Empty)}/{NameTrue}" Return $"https://x.com{IIf(IsCommunity, SiteSettings.CommunitiesUser, String.Empty)}/{NameTrue}"
End Function End Function
@@ -479,10 +471,10 @@ Namespace API.Twitter
ThrowAny(Token) ThrowAny(Token)
Dim timelineFiles As List(Of SFile) = SFile.GetFiles(dir, "*.txt",, EDP.ReturnValue) Dim timelineFiles As List(Of SFile) = SFile.GetFiles(dir, "*.txt",, EDP.ReturnValue)
If timelineFiles.ListExists Then If timelineFiles.ListExists Then
ResetFileNameProvider(Math.Max(timelineFiles.Count.ToString.Length, 2)) GDLResetFileNameProvider(Math.Max(timelineFiles.Count.ToString.Length, 2))
'rename files 'rename files
If Not DEBUG_PROFILE Then If Not DEBUG_PROFILE Then
For i = 0 To timelineFiles.Count - 1 : timelineFiles(i) = RenameGdlFile(timelineFiles(i), i) : Next For i = 0 To timelineFiles.Count - 1 : timelineFiles(i) = GDLRenameFile(timelineFiles(i), i) : Next
End If End If
'parse files 'parse files
For i = 0 To timelineFiles.Count - 1 For i = 0 To timelineFiles.Count - 1
@@ -533,16 +525,19 @@ Namespace API.Twitter
With j({"data", "user", "result"}) With j({"data", "user", "result"})
If .ListExists Then If .ListExists Then
If ID.IsEmptyString Then ID = .Value("rest_id") If ID.IsEmptyString Then ID = .Value("rest_id")
icon = .Value({"avatar"}, "image_url")
UserSiteNameUpdate(.Value({"core"}, "name"))
Dim tScreenName$ = .Value({"core"}, "screen_name")
With .Item({"legacy"}) With .Item({"legacy"})
If .ListExists Then If .ListExists Then
If .Value("screen_name").StringToLower = NameTrue.ToLower Then If .Value("screen_name").IfNullOrEmpty(tScreenName).StringToLower = NameTrue.ToLower Then
UserSiteNameUpdate(.Value("name")) UserSiteNameUpdate(.Value("name"))
UserDescriptionUpdate(.Value("description")) UserDescriptionUpdate(.Value("description"))
icon = .Value("profile_image_url_https") If icon.IsEmptyString Then icon = .Value("profile_image_url_https")
If Not icon.IsEmptyString Then icon = icon.Replace("_normal", String.Empty) If Not icon.IsEmptyString Then icon = icon.Replace("_normal", String.Empty)
If DownloadIconBanner Then If DownloadIconBanner Then
SimpleDownloadAvatar(.Value("profile_banner_url"), fileCrFunc) SimpleDownloadAvatar(.Value("profile_banner_url").IfNullOrEmpty(.Value({"legacy"}, "profile_banner_url")), fileCrFunc)
SimpleDownloadAvatar(icon, fileCrFunc) SimpleDownloadAvatar(icon, fileCrFunc)
End If End If
End If End If
@@ -678,14 +673,14 @@ nextpIndx:
Dim f As SFile = GetDataFromGalleryDL("https://x.com/i/bookmarks", Settings.Cache, True, Token) Dim f As SFile = GetDataFromGalleryDL("https://x.com/i/bookmarks", Settings.Cache, True, Token)
Dim files As List(Of SFile) = SFile.GetFiles(f, "*.txt") Dim files As List(Of SFile) = SFile.GetFiles(f, "*.txt")
If files.ListExists Then If files.ListExists Then
ResetFileNameProvider(Math.Max(files.Count.ToString.Length, 3)) GDLResetFileNameProvider(Math.Max(files.Count.ToString.Length, 3))
Dim id$ Dim id$
Dim nodes As List(Of String()) = GetContainerSubnodes() Dim nodes As List(Of String()) = GetContainerSubnodes()
Dim node$() Dim node$()
Dim j As EContainer, jj As EContainer Dim j As EContainer, jj As EContainer
Dim jErr As New ErrorsDescriber(EDP.ReturnValue) Dim jErr As New ErrorsDescriber(EDP.ReturnValue)
For i% = 0 To files.Count - 1 For i% = 0 To files.Count - 1
f = RenameGdlFile(files(i), i) f = GDLRenameFile(files(i), i)
j = JsonDocument.Parse(f.GetText, jErr) j = JsonDocument.Parse(f.GetText, jErr)
If Not j Is Nothing Then If Not j Is Nothing Then
With j.ItemF({"data", 0, "timeline", "instructions", 0, "entries"}) With j.ItemF({"data", 0, "timeline", "instructions", 0, "entries"})
@@ -852,9 +847,7 @@ nextpIndx:
Private ReadOnly KillOnLimit As Boolean Private ReadOnly KillOnLimit As Boolean
Friend LimitReached As Boolean = False Friend LimitReached As Boolean = False
Friend Sub New(ByVal Dir As SFile, ByVal _Token As CancellationToken, ByVal _KillOnLimit As Boolean) Friend Sub New(ByVal Dir As SFile, ByVal _Token As CancellationToken, ByVal _KillOnLimit As Boolean)
MyBase.New(_Token) MyBase.New(_Token,, Dir)
Commands.Clear()
If Not Dir.IsEmptyString Then ChangeDirectory(Dir)
KillOnLimit = _KillOnLimit KillOnLimit = _KillOnLimit
End Sub End Sub
Protected Overrides Async Function Validate(ByVal Value As String) As Task Protected Overrides Async Function Validate(ByVal Value As String) As Task
@@ -1139,7 +1132,7 @@ nextpIndx:
Dim files As List(Of SFile) Dim files As List(Of SFile)
Dim lim% Dim lim%
Dim specFolder$ = IIf(_ReparseLikes, "Likes", String.Empty) Dim specFolder$ = IIf(_ReparseLikes, "Likes", String.Empty)
ResetFileNameProvider() GDLResetFileNameProvider()
cache = If(IsSingleObjectDownload, Settings.Cache, CreateCache()) cache = If(IsSingleObjectDownload, Settings.Cache, CreateCache())
If _ReparseLikes Then lim = LikesPosts.Count Else lim = _ContentList.Count If _ReparseLikes Then lim = LikesPosts.Count Else lim = _ContentList.Count
ProgressPre.ChangeMax(lim) ProgressPre.ChangeMax(lim)
@@ -1165,7 +1158,7 @@ nextpIndx:
files = SFile.GetFiles(f, "*.txt") files = SFile.GetFiles(f, "*.txt")
If files.ListExists Then If files.ListExists Then
For ii = 0 To files.Count - 1 For ii = 0 To files.Count - 1
f = RenameGdlFile(files(ii), ii) f = GDLRenameFile(files(ii), ii)
j = JsonDocument.Parse(f.GetText) j = JsonDocument.Parse(f.GetText)
If Not j Is Nothing Then If Not j Is Nothing Then
With j.ItemF({"data", 0, "instructions", 0, "entries"}) With j.ItemF({"data", 0, "instructions", 0, "entries"})

View File

@@ -14,7 +14,11 @@ Imports PersonalUtilities.Functions.RegularExpressions
Namespace API.Xhamster Namespace API.Xhamster
<Manifest(XhamsterSiteKey), SavedPosts, SpecialForm(True), SpecialForm(False), TaskGroup(SettingsCLS.TaskStackNamePornSite)> <Manifest(XhamsterSiteKey), SavedPosts, SpecialForm(True), SpecialForm(False), TaskGroup(SettingsCLS.TaskStackNamePornSite)>
Friend Class SiteSettings : Inherits SiteSettingsBase Friend Class SiteSettings : Inherits SiteSettingsBase
#Region "Consts"
Friend Const GetMomentsCaption As String = "Get moments (short videos)"
#End Region
#Region "Declarations" #Region "Declarations"
Private Const CAT_YTDLP As String = "yt-dlp support"
<PXML("Domains"), PClonable> Private ReadOnly Property SiteDomains As PropertyValue <PXML("Domains"), PClonable> Private ReadOnly Property SiteDomains As PropertyValue
Private Shadows ReadOnly Property DefaultInstance As SiteSettings Private Shadows ReadOnly Property DefaultInstance As SiteSettings
Get Get
@@ -33,6 +37,19 @@ Namespace API.Xhamster
ControlToolTip:="If enabled and the video is downloaded in a non-native format, the video will be re-encoded." & vbCr & ControlToolTip:="If enabled and the video is downloaded in a non-native format, the video will be re-encoded." & vbCr &
"Attention! Enabling this setting results in maximum CPU usage."), PXML, PClonable> "Attention! Enabling this setting results in maximum CPU usage."), PXML, PClonable>
Friend ReadOnly Property ReencodeVideos As PropertyValue Friend ReadOnly Property ReencodeVideos As PropertyValue
<PropertyOption(ControlText:="Use yt-dlp to get file info", ControlToolTip:="If checked, yt-dlp will be used to get information about the file", Category:=CAT_YTDLP), PXML, PClonable, HiddenControl>
Friend ReadOnly Property UseYTDLPJSON As PropertyValue
<PropertyOption(ControlText:="Use yt-dlp to download the file", ControlToolTip:="If checked, yt-dlp will be used to download the file instead of the internal algorithm", Category:=CAT_YTDLP), PXML, PClonable, HiddenControl>
Friend ReadOnly Property UseYTDLPDownload As PropertyValue
Private ReadOnly Property UseYtDlp As Boolean
Get
Return CBool(UseYTDLPJSON.Value) Or CBool(UseYTDLPDownload.Value)
End Get
End Property
<PropertyOption(ControlText:="Disable internal algorithm", ControlToolTip:="If checked, the internal algorithm will be forcibly disabled and replaced with yt-dlp", Category:=CAT_YTDLP), PXML, PClonable, HiddenControl>
Friend ReadOnly Property UseYTDLPForceDisableInternal As PropertyValue
<PropertyOption(ControlText:=GetMomentsCaption, Category:=DeclaredNames.CAT_UserDefs), PXML, PClonable>
Friend ReadOnly Property GetMoments As PropertyValue
<DoNotUse> Friend Overrides Property DownloadText As PropertyValue <DoNotUse> Friend Overrides Property DownloadText As PropertyValue
<DoNotUse> Friend Overrides Property DownloadTextPosts As PropertyValue <DoNotUse> Friend Overrides Property DownloadTextPosts As PropertyValue
<DoNotUse> Friend Overrides Property DownloadTextSpecialFolder As PropertyValue <DoNotUse> Friend Overrides Property DownloadTextSpecialFolder As PropertyValue
@@ -46,12 +63,17 @@ Namespace API.Xhamster
Domains.DestinationProp = SiteDomains Domains.DestinationProp = SiteDomains
DownloadUHD = New PropertyValue(False) DownloadUHD = New PropertyValue(False)
ReencodeVideos = New PropertyValue(False) ReencodeVideos = New PropertyValue(False)
UseYTDLPJSON = New PropertyValue(True)
UseYTDLPDownload = New PropertyValue(True)
UseYTDLPForceDisableInternal = New PropertyValue(False)
GetMoments = New PropertyValue(True)
_SubscriptionsAllowed = True _SubscriptionsAllowed = True
UrlPatternUser = "https://xhamster.com/{0}/{1}" UrlPatternUser = "https://xhamster.com/{0}/{1}"
UserRegex = RParams.DMS($"/({UserOption}|{ChannelOption}|{P_Creators})/([^/]+)(\Z|.*)", 0, RegexReturn.ListByMatch) UserRegex = RParams.DMS($"/({UserOption}|{UserOption2}|{ChannelOption}|{P_Creators})/([^/]+)(\Z|.*)", 0, RegexReturn.ListByMatch)
ImageVideoContains = "xhamster" ImageVideoContains = "xhamster"
UserOptionsType = GetType(UserExchangeOptions) UserOptionsType = GetType(UserExchangeOptions)
UseNetscapeCookies = True
End Sub End Sub
Friend Overrides Sub EndInit() Friend Overrides Sub EndInit()
Domains.PopulateInitialDomains(SiteDomains.Value) Domains.PopulateInitialDomains(SiteDomains.Value)
@@ -75,9 +97,7 @@ Namespace API.Xhamster
Return New UserData Return New UserData
End Function End Function
Friend Overrides Function Available(ByVal What As ISiteSettings.Download, ByVal Silent As Boolean) As Boolean Friend Overrides Function Available(ByVal What As ISiteSettings.Download, ByVal Silent As Boolean) As Boolean
'TODELETE: xHamster disabled If (Not UseYtDlp Or (UseYtDlp And Settings.YtdlpFile.Exists)) AndAlso Settings.UseM3U8 AndAlso MyBase.Available(What, Silent) Then
Return False
If Settings.UseM3U8 AndAlso MyBase.Available(What, Silent) Then
If What = ISiteSettings.Download.SavedPosts Then If What = ISiteSettings.Download.SavedPosts Then
Return Responser.CookiesExists Return Responser.CookiesExists
Else Else
@@ -98,7 +118,8 @@ Namespace API.Xhamster
End Function End Function
#Region "IsMyUser, IsMyImageVideo" #Region "IsMyUser, IsMyImageVideo"
Friend Const ChannelOption As String = "channels" Friend Const ChannelOption As String = "channels"
Private Const UserOption As String = "users" Friend Const UserOption As String = "users/profiles"
Private Const UserOption2 As String = "users"
Friend Const P_Search As String = "search" Friend Const P_Search As String = "search"
Friend Const P_Tags As String = "tags" Friend Const P_Tags As String = "tags"
Friend Const P_Categories As String = "categories" Friend Const P_Categories As String = "categories"

View File

@@ -11,6 +11,7 @@ Imports System.Threading
Imports PersonalUtilities.Functions.RegularExpressions Imports PersonalUtilities.Functions.RegularExpressions
Imports PersonalUtilities.Functions.XML Imports PersonalUtilities.Functions.XML
Imports PersonalUtilities.Functions.XML.Base Imports PersonalUtilities.Functions.XML.Base
Imports PersonalUtilities.Tools
Imports PersonalUtilities.Tools.Web.Clients Imports PersonalUtilities.Tools.Web.Clients
Imports PersonalUtilities.Tools.Web.Documents.JSON Imports PersonalUtilities.Tools.Web.Documents.JSON
Imports SCrawler.API.Base Imports SCrawler.API.Base
@@ -176,10 +177,16 @@ Namespace API.Xhamster
Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object) Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object)
If Not Obj Is Nothing AndAlso TypeOf Obj Is UserExchangeOptions Then DirectCast(Obj, UserExchangeOptions).Apply(Me) If Not Obj Is Nothing AndAlso TypeOf Obj Is UserExchangeOptions Then DirectCast(Obj, UserExchangeOptions).Apply(Me)
End Sub End Sub
Private MyCache As CacheKeeper = Nothing
Private Sub ResetCache()
MyCache.DisposeIfReady(False)
MyCache = Nothing
End Sub
#End Region #End Region
#Region "Initializer" #Region "Initializer"
Friend Sub New() Friend Sub New()
UseInternalM3U8Function = True UseInternalM3U8Function = True
UseInternalDownloadFileFunction = True
UseClientTokens = True UseClientTokens = True
_TempPhotoData = New List(Of UserMedia) _TempPhotoData = New List(Of UserMedia)
SessionPosts = New List(Of String) SessionPosts = New List(Of String)
@@ -235,6 +242,9 @@ Namespace API.Xhamster
Private SearchPostsCount As Integer = 0 Private SearchPostsCount As Integer = 0
Private ReadOnly SessionPosts As List(Of String) Private ReadOnly SessionPosts As List(Of String)
Private _PageVideosRepeat As Integer = 0 Private _PageVideosRepeat As Integer = 0
Friend Overrides Sub DownloadData(Token As CancellationToken)
Try : MyBase.DownloadData(Token) : Finally : ResetCache() : End Try
End Sub
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken) Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
Try Try
_TempPhotoData.Clear() _TempPhotoData.Clear()
@@ -243,7 +253,7 @@ Namespace API.Xhamster
SessionPosts.Clear() SessionPosts.Clear()
Responser.CookiesAsHeader = True Responser.CookiesAsHeader = True
If DownloadVideos Then DownloadData(1, True, False, Token) If DownloadVideos Then DownloadData(1, True, False, Token)
If GetMoments Then DownloadData(1, True, True, Token) If DownloadVideos And GetMoments Then DownloadData(1, True, True, Token)
If Not IsChannel And Not IsCreator And DownloadImages And Not IsSubscription Then If Not IsChannel And Not IsCreator And DownloadImages And Not IsSubscription Then
DownloadData(1, False, False, Token) DownloadData(1, False, False, Token)
ReparsePhoto(Token) ReparsePhoto(Token)
@@ -302,7 +312,7 @@ Namespace API.Xhamster
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)
Else Else
URL = $"https://xhamster.com/users/{NameTrue}/{If(GetMoments, "moments", IIf(IsVideo, "videos", "photos"))}{IIf(Page = 1, String.Empty, $"/{Page}")}" URL = $"https://xhamster.com/{SiteSettings.UserOption}/{NameTrue}/{If(GetMoments, "moments", IIf(IsVideo, "videos", "photos"))}{IIf(Page = 1, String.Empty, $"/{Page}")}"
End If End If
ThrowAny(Token) ThrowAny(Token)
@@ -402,9 +412,9 @@ Namespace API.Xhamster
If _TempMediaList(i).Type = UTypes.VideoPre Then If _TempMediaList(i).Type = UTypes.VideoPre Then
m = _TempMediaList(i) m = _TempMediaList(i)
If Not m.URL_BASE.IsEmptyString Then If Not m.URL_BASE.IsEmptyString Then
m2 = Nothing m2 = m
ThrowAny(Token) ThrowAny(Token)
If GetM3U8(m2, m.URL_BASE, m.SpecialFolder) Then If GetM3U8_Init(m2, m.URL_BASE, m.SpecialFolder, i) Then
m2.URL_BASE = m.URL_BASE m2.URL_BASE = m.URL_BASE
_TempMediaList(i) = m2 _TempMediaList(i) = m2
Else Else
@@ -432,9 +442,9 @@ Namespace API.Xhamster
If Not DownloadTopCount.HasValue OrElse c <= DownloadTopCount.Value Then If Not DownloadTopCount.HasValue OrElse c <= DownloadTopCount.Value Then
m = _TempMediaList(i) m = _TempMediaList(i)
If Not m.URL_BASE.IsEmptyString Then If Not m.URL_BASE.IsEmptyString Then
m2 = Nothing m2 = m
ThrowAny(Token) ThrowAny(Token)
If GetM3U8(m2, m.URL_BASE, String.Empty) Then If GetM3U8_Init(m2, m.URL_BASE, String.Empty, i) Then
m2.URL_BASE = m.URL_BASE m2.URL_BASE = m.URL_BASE
_TempMediaList(i) = m2 _TempMediaList(i) = m2
c += 1 c += 1
@@ -473,7 +483,7 @@ Namespace API.Xhamster
If Not r.IsEmptyString Then If Not r.IsEmptyString Then
Using j As EContainer = JsonDocument.Parse(r).XmlIfNothing Using j As EContainer = JsonDocument.Parse(r).XmlIfNothing
If j.Count > 0 Then If j.Count > 0 Then
MaxPage = j.Value({"pagination"}, "maxPage").FromXML(Of Integer)(-1) MaxPage = j.Value({"pagination"}, "maxPage").IfNullOrEmpty(j.Value({"galleryPage", "paginationProps"}, "lastPageNumber")).FromXML(Of Integer)(-1)
With j({"photosGalleryModel"}, "photos") With j({"photosGalleryModel"}, "photos")
If .ListExists Then If .ListExists Then
For Each e In .Self For Each e In .Self
@@ -515,7 +525,7 @@ Namespace API.Xhamster
If m.State = UserMedia.States.Missing AndAlso Not m.URL_BASE.IsEmptyString Then If m.State = UserMedia.States.Missing AndAlso Not m.URL_BASE.IsEmptyString Then
ThrowAny(Token) ThrowAny(Token)
m2 = Nothing m2 = Nothing
If GetM3U8(m2, m.URL_BASE, m.SpecialFolder) Then If GetM3U8_Init(m2, m.URL_BASE, m.SpecialFolder, i) Then
m2.URL_BASE = m.URL_BASE m2.URL_BASE = m.URL_BASE
m2.State = UserMedia.States.Missing m2.State = UserMedia.States.Missing
m2.Attempts = m.Attempts m2.Attempts = m.Attempts
@@ -536,25 +546,85 @@ Namespace API.Xhamster
End Sub End Sub
#End Region #End Region
#Region "GetM3U8" #Region "GetM3U8"
Private Overloads Function GetM3U8(ByRef m As UserMedia, ByVal URL As String, ByVal SpecFolder As String) As Boolean Private Structure XMMediaInfo : Implements IComparable(Of XMMediaInfo)
Friend URL As String
Friend Type As UTypes
Friend IsInternal As Boolean
Friend Thumb As String
Friend FormatID As String
Friend Width As Integer
Friend Height As Integer
Friend Title As String
Private Function CompareTo(ByVal Other As XMMediaInfo) As Integer Implements IComparable(Of XMMediaInfo).CompareTo
Return Width.CompareTo(Other.Width) * -1
End Function
End Structure
Private Function GetM3U8_Init(ByRef m As UserMedia, ByVal URL As String, ByVal SpecFolder As String, ByVal n As Integer) As Boolean
Try Try
If Not URL.IsEmptyString Then If Not URL.IsEmptyString Then
Dim r$ = Responser.GetResponse(URL) Dim IsInternal As Boolean = False
If Not r.IsEmptyString Then r = RegexReplace(r, HtmlScript) Dim r$ = GetMediaInfo(URL, n, IsInternal)
If Not r.IsEmptyString Then If Not r.IsEmptyString Then
Using j As EContainer = JsonDocument.Parse(r) Using j As EContainer = JsonDocument.Parse(r)
If j.ListExists Then If j.ListExists Then
m = ExtractMedia(j("videoModel"), UTypes.VideoPre,,,, SpecFolder) If IsInternal AndAlso GetM3U8_Internal(m, URL, j, SpecFolder) Then
m.URL_BASE = URL Return True
If IsSubscription Then
With j("videoModel")
If .ListExists Then
m.URL = .Value("thumbURL").IfNullOrEmpty(.Value("previewThumbURL"))
Return Not m.URL.IsEmptyString
End If
End With
Else Else
Return GetM3U8(m, j, SpecFolder) Dim xmm As New XMMediaInfo
Dim __checkURL As Func(Of EContainer, XMMediaInfo, XMMediaInfo) =
Function(ByVal jj As EContainer, ByVal __xmm As XMMediaInfo) As XMMediaInfo
With jj.Value("url").StringToLower
If Not .IsEmptyString AndAlso .EndsWith(".m3u8") Or .EndsWith(".mp4") Then __xmm.URL = .Self
End With
Return __xmm
End Function
Dim __applyXMM As Func(Of EContainer, XMMediaInfo, XMMediaInfo) =
Function(ByVal jj As EContainer, ByVal __xmm As XMMediaInfo) As XMMediaInfo
With jj
__xmm.Type = IIf(__xmm.URL.ToLower.EndsWith(".m3u8"), UTypes.m3u8, UTypes.Video)
__xmm.Width = AConvert(Of Integer)(.Value("width"), 1, EDP.ReturnValue)
__xmm.Height = AConvert(Of Integer)(.Value("height"), 1, EDP.ReturnValue)
__xmm.FormatID = .Value("format_id")
End With
Return __xmm
End Function
xmm = __checkURL(j, xmm)
If Not xmm.URL.IsEmptyString Then
xmm = __applyXMM(j, xmm)
Else
With j("formats")
If .ListExists Then
Dim l As New List(Of XMMediaInfo)
Dim tmpXMM As XMMediaInfo
For Each format As EContainer In .Self
tmpXMM = New XMMediaInfo
tmpXMM = __checkURL(format, tmpXMM)
If Not tmpXMM.URL.IsEmptyString Then
tmpXMM = __applyXMM(format, tmpXMM)
l.Add(tmpXMM)
End If
Next
If l.Count > 0 Then
If Not CBool(MySettings.DownloadUHD.Value) AndAlso l.LongCount(Function(v) v.Height <= 1080) > 0 Then _
l.RemoveAll(Function(v) v.Height > 1080)
l.Sort()
xmm = l.First
l.Clear()
End If
End If
End With
End If
If Not xmm.URL.IsEmptyString Then
xmm.IsInternal = False
xmm.Thumb = j.Value("thumbnail")
xmm.Title = TitleHtmlConverter(j.Value("title").IfNullOrEmpty(j.Value("fulltitle")))
If Not xmm.Title.IsEmptyString Then m.File.Name = xmm.Title
m.Type = xmm.Type
m.URL = IIf(IsSubscription, xmm.Thumb, xmm.URL)
m.Object = xmm
m.SpecialFolder = SpecFolder
Return True
End If
End If End If
End If End If
End Using End Using
@@ -562,16 +632,74 @@ Namespace API.Xhamster
End If End If
Return False Return False
Catch ex As Exception Catch ex As Exception
Return ErrorsDescriber.Execute(EDP.ReturnValue, ex, $"[{ToStringForLog()}]: API.Xhamster.GetM3U8({URL})", False) Return ErrorsDescriber.Execute(EDP.ReturnValue, ex, $"[{ToStringForLog()}]: API.Xhamster.GetM3U8_Init({URL})", False)
End Try End Try
End Function End Function
Private Overloads Function GetM3U8(ByRef m As UserMedia, ByVal j As EContainer, ByVal SpecFolder As String, Optional ByVal r As Integer = 0) As Boolean Private Function GetMediaInfo(ByVal URL As String, ByVal n As Integer, ByRef IsInternal As Boolean) As String
Try
If Not URL.IsEmptyString Then
Dim r$ = String.Empty
Dim f As SFile
If IsSubscription Then
Try
If Not CBool(MySettings.UseYTDLPForceDisableInternal.Value) Then r = Responser.GetResponse(URL)
Catch exr As Exception
ErrorsDescriber.Execute(EDP.SendToLog, exr, $"[{ToStringForLog()}]: API.Xhamster.GetMediaInfo({URL})", False)
End Try
If Not r.IsEmptyString Then r = RegexReplace(r, HtmlScript)
If Not r.IsEmptyString Then
IsInternal = True
Return r
Else
f = YTDLPGetInfo(URL, n)
If f.Exists Then IsInternal = False : Return f.GetText
End If
Else
f = YTDLPGetInfo(URL, n)
If f.Exists Then IsInternal = False : Return f.GetText
End If
End If
Return String.Empty
Catch ex As Exception
Return ErrorsDescriber.Execute(EDP.SendToLog + EDP.ReturnValue, ex, $"[{ToStringForLog()}]: API.Xhamster.GetMediaInfo({URL})", String.Empty)
End Try
End Function
Private Function GetM3U8_Internal(ByRef m As UserMedia, ByVal URL As String, ByVal j As EContainer, ByVal SpecFolder As String) As Boolean
Try
If j.ListExists Then
m = ExtractMedia(j("videoModel"), UTypes.VideoPre,,,, SpecFolder)
m.URL_BASE = URL
m.SpecialFolder = SpecFolder
If IsSubscription Then
With j("videoModel")
If .ListExists Then
m.URL = .Value("thumbURL").IfNullOrEmpty(.Value("previewThumbURL"))
m.Object = New XMMediaInfo With {
.IsInternal = True,
.Thumb = m.URL,
.URL = URL,
.Type = UTypes.VideoPre
}
Return Not m.URL.IsEmptyString
End If
End With
Else
Return GetM3U8_Internal_GetURL(m, j)
End If
End If
Return False
Catch ex As Exception
Return ErrorsDescriber.Execute(EDP.ReturnValue, ex, $"[{ToStringForLog()}]: API.Xhamster.GetM3U8_Internal({URL})", False)
End Try
End Function
Private Function GetM3U8_Internal_GetURL(ByRef m As UserMedia, ByVal j As EContainer, Optional ByVal r As Integer = 0) As Boolean
Const urlNode$ = "url" Const urlNode$ = "url"
Dim node As EContainer = j({"xplayerSettings", "sources", If(r = 0, "hls", "standard")}) Dim node As EContainer = j({"xplayerSettings", "sources", If(r = 0, "hls", "standard")})
Dim t As UTypes = UTypes.Undefined
If node.ListExists Then If node.ListExists Then
Dim url$ 'node.GetNode({New NodeParams("url", True, True, True, True, 2)}).XmlIfNothingValue Dim url$ 'node.GetNode({New NodeParams("url", True, True, True, True, 2)}).XmlIfNothingValue
Dim jn As EContainer, jn2 As EContainer Dim jn As EContainer, jn2 As EContainer
Dim __getUrl As Func(Of EContainer, String) = Function(jj) If(jj.Contains(urlNode), Decipher_URL(jj.Value(urlNode)), String.Empty) Dim __getUrl As Func(Of EContainer, String) = Function(jj) If(jj.Contains(urlNode), jj.Value(urlNode), String.Empty)
url = __getUrl(node) url = __getUrl(node)
If url.IsEmptyString Then If url.IsEmptyString Then
For Each jn In node For Each jn In node
@@ -587,61 +715,47 @@ Namespace API.Xhamster
Next Next
End If End If
If Not url.IsEmptyString Then If Not url.IsEmptyString Then
m.URL = url If url.ToLower.EndsWith(".m3u8") Then
m.Type = UTypes.m3u8 t = UTypes.m3u8
Return True ElseIf url.ToLower.EndsWith(".mp4") Then
t = UTypes.Video
End If
If Not t = UTypes.Undefined Then
m.URL = url
m.Type = t
m.Object = New XMMediaInfo With {
.IsInternal = True,
.Type = t,
.URL = url,
.Thumb = j.Value({"videoModel"}, "thumbURL").IfNullOrEmpty(j.Value({"videoModel"}, "previewThumbURL"))
}
Return True
End If
End If End If
End If End If
If r = 0 Then Return GetM3U8(m, j, SpecFolder, r + 1) If r = 0 Then Return GetM3U8_Internal_GetURL(m, j, r + 1)
Return False Return False
End Function End Function
#End Region #End Region
#Region "Decipher" #Region "yt-dlp support"
'https://github.com/yt-dlp/yt-dlp/blob/5513036104ed9710f624c537fb3644b07a0680db/yt_dlp/extractor/xhamster.py#L146-L165 Private Function YTDLPGetInfo(ByVal URL As String, ByVal n As Integer) As SFile
Private Function Decipher_URL(ByVal Input As String) As String
If Input.IsEmptyString Then Return String.Empty
Dim _XOR_KEY As Byte() = Encoding.ASCII.GetBytes("xh7999")
Dim cipher_type$ = String.Empty
Dim ciphertext$ = String.Empty
Try Try
Dim decoded$ = Encoding.ASCII.GetString(Convert.FromBase64String(Input)) Dim cc As CacheKeeper
Dim parts$() = decoded.Split(New Char() {"_"c}, 2) If IsSingleObjectDownload Then
If parts.Length = 2 Then cipher_type = parts(0) : ciphertext = parts(1) cc = Settings.Cache
Catch
End Try
If cipher_type.IsEmptyString Or ciphertext.IsEmptyString Then Return String.Empty
If cipher_type = "xor" Then
Dim ciphertextBytes() As Byte = Encoding.ASCII.GetBytes(ciphertext)
Dim resultBytes(ciphertextBytes.Length - 1) As Byte
For i% = 0 To ciphertextBytes.Length - 1
resultBytes(i) = ciphertextBytes(i) Xor _XOR_KEY(i Mod _XOR_KEY.Length)
Next
Return Encoding.ASCII.GetString(resultBytes)
End If
If cipher_type = "rot13" Then Return Decipher_URL_Rot13(ciphertext)
Return String.Empty
End Function
Private Function Decipher_URL_Rot13(ByVal Input As String) As String
Dim result As New Text.StringBuilder(Input.Length)
For Each c As Char In Input
Dim offset%
If c >= "a"c AndAlso c <= "z"c Then
offset = Asc("a"c)
result.Append(ChrW((Asc(c) - offset + 13) Mod 26 + offset))
ElseIf c >= "A"c AndAlso c <= "Z"c Then
offset = Asc("A"c)
result.Append(ChrW((Asc(c) - offset + 13) Mod 26 + offset))
Else Else
result.Append(c) If MyCache Is Nothing Then MyCache = CreateCache() : MyCache.Validate()
cc = MyCache
End If End If
Next Dim path As SFile = cc.NewPath
Return result.ToString Dim c$ = If(MySettings.CookiesNetscapeFile.Exists, $" --no-cookies-from-browser --cookies ""{MySettings.CookiesNetscapeFile}""", String.Empty)
Dim cmd$ = $"{Settings.YtdlpFile} --write-info-json --skip-download{c} {URL} -o ""{path.PathWithSeparator}file"""
path.Exists()
Using ytdlp As New YTDLP.YTDLPBatch(TokenPersonal,, path) : ytdlp.Encoding = Settings.CMDEncoding : ytdlp.Execute(cmd) : End Using
Return SFile.GetFiles(path, "*.json",, EDP.ReturnValue).FirstOrDefault
Catch ex As Exception
Return ErrorsDescriber.Execute(EDP.SendToLog + EDP.ReturnValue, ex, $"API.Xhamster.UserData.YTDLPGetInfo({URL})", New SFile)
End Try
End Function End Function
#End Region #End Region
#Region "DownloadSingleObject" #Region "DownloadSingleObject"
@@ -654,9 +768,35 @@ Namespace API.Xhamster
Protected Overrides Sub DownloadContent(ByVal Token As CancellationToken) Protected Overrides Sub DownloadContent(ByVal Token As CancellationToken)
DownloadContentDefault(Token) DownloadContentDefault(Token)
End Sub End Sub
Private Function XMMObjectExists(ByVal Media As UserMedia) As Boolean
Return Not IsNothing(Media.Object) AndAlso TypeOf Media.Object Is XMMediaInfo
End Function
Protected Overrides Function DownloadM3U8(ByVal URL As String, ByVal Media As UserMedia, ByVal DestinationFile As SFile, ByVal Token As CancellationToken) As SFile Protected Overrides Function DownloadM3U8(ByVal URL As String, ByVal Media As UserMedia, ByVal DestinationFile As SFile, ByVal Token As CancellationToken) As SFile
Media.File = DestinationFile If CBool(MySettings.UseYTDLPDownload.Value) Then
Return M3U8.Download(Media, Responser, MySettings.DownloadUHD.Value, Token, Progress, Not IsSingleObjectDownload, MySettings.ReencodeVideos.Value) If XMMObjectExists(Media) Then Return YTDLPDownload(Media, DestinationFile, Token)
Return Nothing
Else
Media.File = DestinationFile
Return M3U8.Download(Media, Responser, MySettings.DownloadUHD.Value, Token, Progress, Not IsSingleObjectDownload, MySettings.ReencodeVideos.Value)
End If
End Function
Protected Overrides Function ValidateDownloadFile(ByVal URL As String, ByVal Media As UserMedia, ByRef Interrupt As Boolean) As Boolean
If Not Media.IsPhotoType AndAlso CBool(MySettings.UseYTDLPDownload.Value) Then
If Not Media.URL_BASE.IsEmptyString And XMMObjectExists(Media) AndAlso
Not DirectCast(Media.Object, XMMediaInfo).FormatID.IsEmptyString Then Return True
Interrupt = True
End If
Return False
End Function
Protected Overrides Function DownloadFile(ByVal URL As String, ByVal Media As UserMedia, ByVal DestinationFile As SFile, ByVal Token As CancellationToken) As SFile
Return YTDLPDownload(Media, DestinationFile, Token)
End Function
Private Function YTDLPDownload(ByVal Media As UserMedia, ByVal DestinationFile As SFile, ByVal Token As CancellationToken) As SFile
DestinationFile.Extension = "mp4"
Dim c$ = If(MySettings.CookiesNetscapeFile.Exists, $" --no-cookies-from-browser --cookies ""{MySettings.CookiesNetscapeFile}""", String.Empty)
Dim cmd$ = $"{Settings.YtdlpFile} --format {DirectCast(Media.Object, XMMediaInfo).FormatID}{c} {Media.URL_BASE} -o ""{DestinationFile}"""
Using ytdlp As New YTDLP.YTDLPBatch(TokenPersonal,, DestinationFile) : ytdlp.Encoding = Settings.CMDEncoding : ytdlp.Execute(cmd) : End Using
Return DestinationFile
End Function End Function
#End Region #End Region
#Region "Create media" #Region "Create media"
@@ -722,7 +862,7 @@ Namespace API.Xhamster
#End Region #End Region
#Region "IDisposable support" #Region "IDisposable support"
Protected Overrides Sub Dispose(ByVal disposing As Boolean) Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If Not disposedValue And disposing Then _TempPhotoData.Clear() : SessionPosts.Clear() If Not disposedValue And disposing Then _TempPhotoData.Clear() : SessionPosts.Clear() : ResetCache()
MyBase.Dispose(disposing) MyBase.Dispose(disposing)
End Sub End Sub
#End Region #End Region

View File

@@ -10,7 +10,7 @@ Imports SCrawler.API.Base
Imports SCrawler.Plugin.Attributes Imports SCrawler.Plugin.Attributes
Namespace API.Xhamster Namespace API.Xhamster
Friend NotInheritable Class UserExchangeOptions : Inherits API.Base.EditorExchangeOptionsBase_P Friend NotInheritable Class UserExchangeOptions : Inherits API.Base.EditorExchangeOptionsBase_P
<PSetting(Address:=SettingAddress.User, Caption:="Get moments")> <PSetting(Address:=SettingAddress.User, Caption:=SiteSettings.GetMomentsCaption)>
Friend Property GetMoments As Boolean = False Friend Property GetMoments As Boolean = False
Friend Sub New() Friend Sub New()
MyBase.New MyBase.New
@@ -19,6 +19,10 @@ Namespace API.Xhamster
MyBase.New(DirectCast(u, UserData)) MyBase.New(DirectCast(u, UserData))
GetMoments = DirectCast(u, UserData).GetMoments GetMoments = DirectCast(u, UserData).GetMoments
End Sub End Sub
Friend Sub New(ByVal s As SiteSettings)
MyBase.New(s)
GetMoments = s.GetMoments.Value
End Sub
Friend Overrides Sub Apply(ByRef u As IPSite) Friend Overrides Sub Apply(ByRef u As IPSite)
MyBase.Apply(u) MyBase.Apply(u)
DirectCast(u, UserData).GetMoments = GetMoments DirectCast(u, UserData).GetMoments = GetMoments

View File

@@ -17,11 +17,6 @@ Namespace DownloadObjects
Friend Class AutoDownloader : Inherits GroupParameters : Implements IIndexable, IEContainerProvider, IComparable(Of AutoDownloader) Friend Class AutoDownloader : Inherits GroupParameters : Implements IIndexable, IEContainerProvider, IComparable(Of AutoDownloader)
Friend Event PauseChanged(ByVal Value As PauseModes) Friend Event PauseChanged(ByVal Value As PauseModes)
Friend Event PlanChanged As Scheduler.PlanChangedEventHandler Friend Event PlanChanged As Scheduler.PlanChangedEventHandler
Friend Enum Modes As Integer
None = 0
Specified = 3
Groups = 4
End Enum
Friend Const NoPauseMode As Integer = -100 Friend Const NoPauseMode As Integer = -100
Friend Enum PauseModes As Integer Friend Enum PauseModes As Integer
Disabled = -2 Disabled = -2
@@ -188,8 +183,9 @@ Namespace DownloadObjects
End Class End Class
#End Region #End Region
#Region "XML Names" #Region "XML Names"
Private Const Name_Mode As String = "Mode" 'TODELETE: AutoDownloader.Modes
Private Const Name_Groups As String = "Groups" <Obsolete> Private Const Name_Mode As String = "Mode"
Private Const Name_Enabled As String = "Enabled"
Private Const Name_IsManual As String = "IsManual" Private Const Name_IsManual As String = "IsManual"
Private Const Name_Timer As String = "Timer" Private Const Name_Timer As String = "Timer"
Private Const Name_StartupDelay As String = "StartupDelay" Private Const Name_StartupDelay As String = "StartupDelay"
@@ -247,17 +243,16 @@ Namespace DownloadObjects
End Get End Get
End Property End Property
Friend Property Source As Scheduler Friend Property Source As Scheduler
Private _Mode As Modes = Modes.None Private _Enabled As Boolean = False
Friend Property Mode As Modes Friend Property Enabled As Boolean
Get Get
Return _Mode Return _Enabled
End Get End Get
Set(ByVal m As Modes) Set(ByVal e As Boolean)
_Mode = m _Enabled = e
If _Mode = Modes.None Then [Stop]() If Not _Enabled Then [Stop]()
End Set End Set
End Property End Property
Friend ReadOnly Property Groups As List(Of String)
Friend Property IsManual As Boolean = False Friend Property IsManual As Boolean = False
Friend Property Timer As Integer = DefaultTimer Friend Property Timer As Integer = DefaultTimer
Friend Property StartupDelay As Integer = 1 Friend Property StartupDelay As Integer = 1
@@ -371,7 +366,6 @@ Namespace DownloadObjects
End Get End Get
End Property End Property
Friend Sub New(Optional ByVal IsNewPlan As Boolean = False) Friend Sub New(Optional ByVal IsNewPlan As Boolean = False)
Groups = New List(Of String)
UserKeys = New List(Of NotifiedUser) UserKeys = New List(Of NotifiedUser)
_IsNewPlan = IsNewPlan _IsNewPlan = IsNewPlan
Initialization = False Initialization = False
@@ -379,10 +373,17 @@ Namespace DownloadObjects
Friend Sub New(ByVal x As EContainer) Friend Sub New(ByVal x As EContainer)
Me.New Me.New
Initialization = True Initialization = True
Mode = x.Value(Name_Mode).FromXML(Of Integer)(Modes.None)
Import(x) Import(x)
#Disable Warning BC40008
If x.Contains(Name_Mode) Then
Dim g% = x.Value(Name_Mode).FromXML(Of Integer)(0)
If g = 4 Then GroupsOnly = True
Enabled = g
Else
Enabled = x.Value(Name_Enabled).FromXML(Of Boolean)(False)
End If
#Enable Warning
If Name.IsEmptyString Then Name = "Default" If Name.IsEmptyString Then Name = "Default"
Groups.ListAddList(x.Value(Name_Groups).StringToList(Of String)("|"), LAP.NotContainsOnly)
IsManual = x.Value(Name_IsManual).FromXML(Of Boolean)(False) IsManual = x.Value(Name_IsManual).FromXML(Of Boolean)(False)
Timer = x.Value(Name_Timer).FromXML(Of Integer)(DefaultTimer) Timer = x.Value(Name_Timer).FromXML(Of Integer)(DefaultTimer)
@@ -408,8 +409,7 @@ Namespace DownloadObjects
newObj.Copy(Me) newObj.Copy(Me)
With newObj With newObj
.Name = String.Empty .Name = String.Empty
._Mode = _Mode .Enabled = Enabled
.Groups.ListAddList(Groups, LAP.ClearBeforeAdd)
.IsManual = IsManual .IsManual = IsManual
.Timer = Timer .Timer = Timer
.StartupDelay = StartupDelay .StartupDelay = StartupDelay
@@ -441,8 +441,7 @@ Namespace DownloadObjects
End Sub End Sub
Private Function ToEContainer(Optional ByVal e As ErrorsDescriber = Nothing) As EContainer Implements IEContainerProvider.ToEContainer Private Function ToEContainer(Optional ByVal e As ErrorsDescriber = Nothing) As EContainer Implements IEContainerProvider.ToEContainer
Return Export(New EContainer(Scheduler.Name_Plan, String.Empty) From { Return Export(New EContainer(Scheduler.Name_Plan, String.Empty) From {
New EContainer(Name_Mode, CInt(Mode)), New EContainer(Name_Enabled, Enabled.BoolToInteger),
New EContainer(Name_Groups, Groups.ListToString("|")),
New EContainer(Name_IsManual, IsManual.BoolToInteger), New EContainer(Name_IsManual, IsManual.BoolToInteger),
New EContainer(Name_Timer, Timer), New EContainer(Name_Timer, Timer),
New EContainer(Name_StartupDelay, StartupDelay), New EContainer(Name_StartupDelay, StartupDelay),
@@ -467,7 +466,7 @@ Namespace DownloadObjects
If Not IsManual Or Force Then If Not IsManual Or Force Then
If Init Then _StartTime = Now If Init Then _StartTime = Now
_IsNewPlan = False _IsNewPlan = False
If Not Working And Not Mode = Modes.None Then _Working = True If Not Working And Enabled Then _Working = True
RaiseEvent PlanChanged(Me) RaiseEvent PlanChanged(Me)
End If End If
End Sub End Sub
@@ -556,12 +555,12 @@ Namespace DownloadObjects
Get Get
If _StopRequested Then _Working = False If _StopRequested Then _Working = False
Return (Working Or IsManual) And ((IsManual And _ForceStartRequested) Or (Not IsManual And NextExecutionDate < Now And (Not IsPaused Or IgnorePause)) Or _ForceStartRequested) And Return (Working Or IsManual) And ((IsManual And _ForceStartRequested) Or (Not IsManual And NextExecutionDate < Now And (Not IsPaused Or IgnorePause)) Or _ForceStartRequested) And
Not _StopRequested And Not Mode = Modes.None And (Not Downloader.Working Or IgnoreDownloaderWorking) Not _StopRequested And Enabled And (Not Downloader.Working Or IgnoreDownloaderWorking)
End Get End Get
End Property End Property
Friend ReadOnly Property NextDate As Date? Friend ReadOnly Property NextDate As Date?
Get Get
If Not _StopRequested And Not Mode = Modes.None Then If Not _StopRequested And Enabled Then
If IsManual Or _ForceStartRequested Then If IsManual Or _ForceStartRequested Then
Return Now.AddYears(-10) Return Now.AddYears(-10)
ElseIf Not IsPaused And Not IsManual And Working Then ElseIf Not IsPaused And Not IsManual And Working Then
@@ -583,8 +582,6 @@ Namespace DownloadObjects
Dim Keys As New List(Of String) Dim Keys As New List(Of String)
Try Try
Dim users As New List(Of IUserData) Dim users As New List(Of IUserData)
Dim GName$
Dim i%
Dim doRound% = -1, doLim% = Settings.Plugins.Count Dim doRound% = -1, doLim% = Settings.Plugins.Count
Dim DownloadedUsersCount% = 0 Dim DownloadedUsersCount% = 0
Dim DownloadedSubscriptionsCount% = 0 Dim DownloadedSubscriptionsCount% = 0
@@ -614,16 +611,9 @@ Namespace DownloadObjects
Catch n_ex As Exception Catch n_ex As Exception
End Try End Try
End Sub End Sub
Select Case Mode
Case Modes.Specified : users.ListAddList(DownloadGroup.GetUsers(Me)) If Enabled Then users.ListAddList(DownloadGroup.GetUsers(Me))
Case Modes.Groups
If Groups.Count > 0 And Settings.Groups.Count > 0 Then
For Each GName In Groups
i = Settings.Groups.IndexOf(GName)
If i >= 0 Then users.ListAddList(Settings.Groups(i).GetUsers, LAP.IgnoreICopier, LAP.NotContainsOnly)
Next
End If
End Select
If users.Count > 0 Then If users.Count > 0 Then
Keys.ListAddList(users.Select(Function(u) u.Key)) Keys.ListAddList(users.Select(Function(u) u.Key))
With Downloader With Downloader
@@ -699,7 +689,6 @@ Namespace DownloadObjects
If Not disposedValue And disposing Then If Not disposedValue And disposing Then
[Stop]() [Stop]()
UserKeys.ListClearDispose() UserKeys.ListClearDispose()
Groups.Clear()
End If End If
MyBase.Dispose(disposing) MyBase.Dispose(disposing)
End Sub End Sub

View File

@@ -25,19 +25,14 @@ Namespace DownloadObjects
Me.components = New System.ComponentModel.Container() Me.components = New System.ComponentModel.Container()
Dim CONTAINER_MAIN As System.Windows.Forms.ToolStripContainer Dim CONTAINER_MAIN As System.Windows.Forms.ToolStripContainer
Dim TP_MODE As System.Windows.Forms.TableLayoutPanel Dim TP_MODE As System.Windows.Forms.TableLayoutPanel
Dim ActionButton1 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(AutoDownloaderEditorForm))
Dim ActionButton2 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim ActionButton3 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim TP_NOTIFY As System.Windows.Forms.TableLayoutPanel Dim TP_NOTIFY As System.Windows.Forms.TableLayoutPanel
Dim ActionButton4 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(AutoDownloaderEditorForm))
Dim ActionButton5 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Dim ActionButton1 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim ActionButton2 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
Dim TT_MAIN As System.Windows.Forms.ToolTip Dim TT_MAIN As System.Windows.Forms.ToolTip
Me.DEF_GROUP = New SCrawler.DownloadObjects.Groups.GroupDefaults() Me.DEF_GROUP = New SCrawler.DownloadObjects.Groups.GroupDefaults()
Me.OPT_SPEC = New System.Windows.Forms.RadioButton() Me.OPT_ENABLED = New System.Windows.Forms.RadioButton()
Me.OPT_DISABLED = New System.Windows.Forms.RadioButton() Me.OPT_DISABLED = New System.Windows.Forms.RadioButton()
Me.OPT_GROUP = New System.Windows.Forms.RadioButton()
Me.TXT_GROUPS = New PersonalUtilities.Forms.Controls.TextBoxExtended()
Me.CH_NOTIFY = New System.Windows.Forms.CheckBox() Me.CH_NOTIFY = New System.Windows.Forms.CheckBox()
Me.CH_SHOW_PIC = New System.Windows.Forms.CheckBox() Me.CH_SHOW_PIC = New System.Windows.Forms.CheckBox()
Me.CH_SHOW_PIC_USER = New System.Windows.Forms.CheckBox() Me.CH_SHOW_PIC_USER = New System.Windows.Forms.CheckBox()
@@ -54,7 +49,6 @@ Namespace DownloadObjects
CONTAINER_MAIN.SuspendLayout() CONTAINER_MAIN.SuspendLayout()
Me.DEF_GROUP.SuspendLayout() Me.DEF_GROUP.SuspendLayout()
TP_MODE.SuspendLayout() TP_MODE.SuspendLayout()
CType(Me.TXT_GROUPS, System.ComponentModel.ISupportInitialize).BeginInit()
TP_NOTIFY.SuspendLayout() TP_NOTIFY.SuspendLayout()
CType(Me.TXT_TIMER, System.ComponentModel.ISupportInitialize).BeginInit() CType(Me.TXT_TIMER, System.ComponentModel.ISupportInitialize).BeginInit()
CType(Me.NUM_DELAY, System.ComponentModel.ISupportInitialize).BeginInit() CType(Me.NUM_DELAY, System.ComponentModel.ISupportInitialize).BeginInit()
@@ -66,7 +60,7 @@ Namespace DownloadObjects
'CONTAINER_MAIN.ContentPanel 'CONTAINER_MAIN.ContentPanel
' '
CONTAINER_MAIN.ContentPanel.Controls.Add(Me.DEF_GROUP) CONTAINER_MAIN.ContentPanel.Controls.Add(Me.DEF_GROUP)
CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(476, 519) CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(476, 494)
CONTAINER_MAIN.Dock = System.Windows.Forms.DockStyle.Fill CONTAINER_MAIN.Dock = System.Windows.Forms.DockStyle.Fill
CONTAINER_MAIN.LeftToolStripPanelVisible = False CONTAINER_MAIN.LeftToolStripPanelVisible = False
CONTAINER_MAIN.Location = New System.Drawing.Point(0, 0) CONTAINER_MAIN.Location = New System.Drawing.Point(0, 0)
@@ -82,7 +76,6 @@ Namespace DownloadObjects
Me.DEF_GROUP.ColumnCount = 1 Me.DEF_GROUP.ColumnCount = 1
Me.DEF_GROUP.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) Me.DEF_GROUP.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
Me.DEF_GROUP.Controls.Add(TP_MODE, 0, 0) Me.DEF_GROUP.Controls.Add(TP_MODE, 0, 0)
Me.DEF_GROUP.Controls.Add(Me.TXT_GROUPS, 0, 12)
Me.DEF_GROUP.Controls.Add(TP_NOTIFY, 0, 13) Me.DEF_GROUP.Controls.Add(TP_NOTIFY, 0, 13)
Me.DEF_GROUP.Controls.Add(Me.TXT_TIMER, 0, 15) Me.DEF_GROUP.Controls.Add(Me.TXT_TIMER, 0, 15)
Me.DEF_GROUP.Controls.Add(Me.NUM_DELAY, 0, 16) Me.DEF_GROUP.Controls.Add(Me.NUM_DELAY, 0, 16)
@@ -111,21 +104,18 @@ Namespace DownloadObjects
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
Me.DEF_GROUP.Size = New System.Drawing.Size(476, 519) Me.DEF_GROUP.Size = New System.Drawing.Size(476, 494)
Me.DEF_GROUP.TabIndex = 0 Me.DEF_GROUP.TabIndex = 0
' '
'TP_MODE 'TP_MODE
' '
TP_MODE.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single] TP_MODE.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single]
TP_MODE.ColumnCount = 3 TP_MODE.ColumnCount = 2
TP_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333!)) TP_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
TP_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333!)) TP_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
TP_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333!))
TP_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20.0!)) TP_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20.0!))
TP_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20.0!)) TP_MODE.Controls.Add(Me.OPT_ENABLED, 1, 0)
TP_MODE.Controls.Add(Me.OPT_SPEC, 1, 0)
TP_MODE.Controls.Add(Me.OPT_DISABLED, 0, 0) TP_MODE.Controls.Add(Me.OPT_DISABLED, 0, 0)
TP_MODE.Controls.Add(Me.OPT_GROUP, 2, 0)
TP_MODE.Dock = System.Windows.Forms.DockStyle.Fill TP_MODE.Dock = System.Windows.Forms.DockStyle.Fill
TP_MODE.Location = New System.Drawing.Point(1, 1) TP_MODE.Location = New System.Drawing.Point(1, 1)
TP_MODE.Margin = New System.Windows.Forms.Padding(0) TP_MODE.Margin = New System.Windows.Forms.Padding(0)
@@ -135,18 +125,18 @@ Namespace DownloadObjects
TP_MODE.Size = New System.Drawing.Size(474, 25) TP_MODE.Size = New System.Drawing.Size(474, 25)
TP_MODE.TabIndex = 0 TP_MODE.TabIndex = 0
' '
'OPT_SPEC 'OPT_ENABLED
' '
Me.OPT_SPEC.AutoSize = True Me.OPT_ENABLED.AutoSize = True
Me.OPT_SPEC.Dock = System.Windows.Forms.DockStyle.Fill Me.OPT_ENABLED.Dock = System.Windows.Forms.DockStyle.Fill
Me.OPT_SPEC.Location = New System.Drawing.Point(161, 4) Me.OPT_ENABLED.Location = New System.Drawing.Point(240, 4)
Me.OPT_SPEC.Name = "OPT_SPEC" Me.OPT_ENABLED.Name = "OPT_ENABLED"
Me.OPT_SPEC.Size = New System.Drawing.Size(150, 17) Me.OPT_ENABLED.Size = New System.Drawing.Size(230, 17)
Me.OPT_SPEC.TabIndex = 3 Me.OPT_ENABLED.TabIndex = 3
Me.OPT_SPEC.TabStop = True Me.OPT_ENABLED.TabStop = True
Me.OPT_SPEC.Text = "Specified" Me.OPT_ENABLED.Text = "Enabled"
TT_MAIN.SetToolTip(Me.OPT_SPEC, "Select parameters") TT_MAIN.SetToolTip(Me.OPT_ENABLED, "Select parameters")
Me.OPT_SPEC.UseVisualStyleBackColor = True Me.OPT_ENABLED.UseVisualStyleBackColor = True
' '
'OPT_DISABLED 'OPT_DISABLED
' '
@@ -154,48 +144,13 @@ Namespace DownloadObjects
Me.OPT_DISABLED.Dock = System.Windows.Forms.DockStyle.Fill Me.OPT_DISABLED.Dock = System.Windows.Forms.DockStyle.Fill
Me.OPT_DISABLED.Location = New System.Drawing.Point(4, 4) Me.OPT_DISABLED.Location = New System.Drawing.Point(4, 4)
Me.OPT_DISABLED.Name = "OPT_DISABLED" Me.OPT_DISABLED.Name = "OPT_DISABLED"
Me.OPT_DISABLED.Size = New System.Drawing.Size(150, 17) Me.OPT_DISABLED.Size = New System.Drawing.Size(229, 17)
Me.OPT_DISABLED.TabIndex = 0 Me.OPT_DISABLED.TabIndex = 0
Me.OPT_DISABLED.TabStop = True Me.OPT_DISABLED.TabStop = True
Me.OPT_DISABLED.Text = "Disabled" Me.OPT_DISABLED.Text = "Disabled"
TT_MAIN.SetToolTip(Me.OPT_DISABLED, "Automation disabled") TT_MAIN.SetToolTip(Me.OPT_DISABLED, "Automation disabled")
Me.OPT_DISABLED.UseVisualStyleBackColor = True Me.OPT_DISABLED.UseVisualStyleBackColor = True
' '
'OPT_GROUP
'
Me.OPT_GROUP.AutoSize = True
Me.OPT_GROUP.Dock = System.Windows.Forms.DockStyle.Fill
Me.OPT_GROUP.Location = New System.Drawing.Point(318, 4)
Me.OPT_GROUP.Name = "OPT_GROUP"
Me.OPT_GROUP.Size = New System.Drawing.Size(152, 17)
Me.OPT_GROUP.TabIndex = 4
Me.OPT_GROUP.TabStop = True
Me.OPT_GROUP.Text = "Groups"
TT_MAIN.SetToolTip(Me.OPT_GROUP, "Download groups")
Me.OPT_GROUP.UseVisualStyleBackColor = True
'
'TXT_GROUPS
'
ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image)
ActionButton1.Name = "Edit"
ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image)
ActionButton2.Name = "Info"
ActionButton2.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Info
ActionButton2.ToolTipText = "Open group"
ActionButton3.BackgroundImage = CType(resources.GetObject("ActionButton3.BackgroundImage"), System.Drawing.Image)
ActionButton3.Name = "Clear"
Me.TXT_GROUPS.Buttons.Add(ActionButton1)
Me.TXT_GROUPS.Buttons.Add(ActionButton2)
Me.TXT_GROUPS.Buttons.Add(ActionButton3)
Me.TXT_GROUPS.CaptionText = "Groups"
Me.TXT_GROUPS.CaptionWidth = 50.0R
Me.TXT_GROUPS.Dock = System.Windows.Forms.DockStyle.Fill
Me.TXT_GROUPS.Location = New System.Drawing.Point(4, 331)
Me.TXT_GROUPS.Name = "TXT_GROUPS"
Me.TXT_GROUPS.Size = New System.Drawing.Size(468, 22)
Me.TXT_GROUPS.TabIndex = 1
Me.TXT_GROUPS.TextBoxReadOnly = True
'
'TP_NOTIFY 'TP_NOTIFY
' '
TP_NOTIFY.ColumnCount = 4 TP_NOTIFY.ColumnCount = 4
@@ -266,9 +221,9 @@ Namespace DownloadObjects
' '
'TXT_TIMER 'TXT_TIMER
' '
ActionButton4.BackgroundImage = CType(resources.GetObject("ActionButton4.BackgroundImage"), System.Drawing.Image) ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image)
ActionButton4.Name = "Refresh" ActionButton1.Name = "Refresh"
Me.TXT_TIMER.Buttons.Add(ActionButton4) Me.TXT_TIMER.Buttons.Add(ActionButton1)
Me.TXT_TIMER.CaptionText = "Timer" Me.TXT_TIMER.CaptionText = "Timer"
Me.TXT_TIMER.CaptionToolTipEnabled = True Me.TXT_TIMER.CaptionToolTipEnabled = True
Me.TXT_TIMER.CaptionToolTipText = "Timer (in minutes)" Me.TXT_TIMER.CaptionToolTipText = "Timer (in minutes)"
@@ -281,9 +236,9 @@ Namespace DownloadObjects
' '
'NUM_DELAY 'NUM_DELAY
' '
ActionButton5.BackgroundImage = CType(resources.GetObject("ActionButton5.BackgroundImage"), System.Drawing.Image) ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image)
ActionButton5.Name = "Refresh" ActionButton2.Name = "Refresh"
Me.NUM_DELAY.Buttons.Add(ActionButton5) Me.NUM_DELAY.Buttons.Add(ActionButton2)
Me.NUM_DELAY.CaptionText = "Delay" Me.NUM_DELAY.CaptionText = "Delay"
Me.NUM_DELAY.CaptionToolTipEnabled = True Me.NUM_DELAY.CaptionToolTipEnabled = True
Me.NUM_DELAY.CaptionToolTipText = "Startup delay" Me.NUM_DELAY.CaptionToolTipText = "Startup delay"
@@ -348,7 +303,6 @@ Namespace DownloadObjects
Me.DEF_GROUP.PerformLayout() Me.DEF_GROUP.PerformLayout()
TP_MODE.ResumeLayout(False) TP_MODE.ResumeLayout(False)
TP_MODE.PerformLayout() TP_MODE.PerformLayout()
CType(Me.TXT_GROUPS, System.ComponentModel.ISupportInitialize).EndInit()
TP_NOTIFY.ResumeLayout(False) TP_NOTIFY.ResumeLayout(False)
TP_NOTIFY.PerformLayout() TP_NOTIFY.PerformLayout()
CType(Me.TXT_TIMER, System.ComponentModel.ISupportInitialize).EndInit() CType(Me.TXT_TIMER, System.ComponentModel.ISupportInitialize).EndInit()
@@ -357,12 +311,10 @@ Namespace DownloadObjects
End Sub End Sub
Private WithEvents DEF_GROUP As DownloadObjects.Groups.GroupDefaults Private WithEvents DEF_GROUP As DownloadObjects.Groups.GroupDefaults
Private WithEvents TXT_GROUPS As PersonalUtilities.Forms.Controls.TextBoxExtended Private WithEvents OPT_ENABLED As RadioButton
Private WithEvents OPT_SPEC As RadioButton
Private WithEvents OPT_DISABLED As RadioButton Private WithEvents OPT_DISABLED As RadioButton
Private WithEvents CH_NOTIFY As CheckBox Private WithEvents CH_NOTIFY As CheckBox
Private WithEvents TXT_TIMER As PersonalUtilities.Forms.Controls.TextBoxExtended Private WithEvents TXT_TIMER As PersonalUtilities.Forms.Controls.TextBoxExtended
Private WithEvents OPT_GROUP As RadioButton
Private WithEvents LBL_LAST_TIME_UP As Label Private WithEvents LBL_LAST_TIME_UP As Label
Private WithEvents NUM_DELAY As PersonalUtilities.Forms.Controls.TextBoxExtended Private WithEvents NUM_DELAY As PersonalUtilities.Forms.Controls.TextBoxExtended
Private WithEvents CH_SHOW_PIC As CheckBox Private WithEvents CH_SHOW_PIC As CheckBox

View File

@@ -129,85 +129,6 @@
<metadata name="TT_MAIN.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <metadata name="TT_MAIN.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value> <value>17, 17</value>
</metadata> </metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="ActionButton1.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAACH
DwAAjA8AAP1SAACBQAAAfXkAAOmLAAA85QAAGcxzPIV3AAAKOWlDQ1BQaG90b3Nob3AgSUNDIHByb2Zp
bGUAAEjHnZZ3VFTXFofPvXd6oc0w0hl6ky4wgPQuIB0EURhmBhjKAMMMTWyIqEBEEREBRZCggAGjoUis
iGIhKKhgD0gQUGIwiqioZEbWSnx5ee/l5ffHvd/aZ+9z99l7n7UuACRPHy4vBZYCIJkn4Ad6ONNXhUfQ
sf0ABniAAaYAMFnpqb5B7sFAJC83F3q6yAn8i94MAUj8vmXo6U+ng/9P0qxUvgAAyF/E5mxOOkvE+SJO
yhSkiu0zIqbGJIoZRomZL0pQxHJijlvkpZ99FtlRzOxkHlvE4pxT2clsMfeIeHuGkCNixEfEBRlcTqaI
b4tYM0mYzBXxW3FsMoeZDgCKJLYLOKx4EZuImMQPDnQR8XIAcKS4LzjmCxZwsgTiQ7mkpGbzuXHxArou
S49uam3NoHtyMpM4AoGhP5OVyOSz6S4pyalMXjYAi2f+LBlxbemiIluaWltaGpoZmX5RqP+6+Dcl7u0i
vQr43DOI1veH7a/8UuoAYMyKarPrD1vMfgA6tgIgd/8Pm+YhACRFfWu/8cV5aOJ5iRcIUm2MjTMzM424
HJaRuKC/6386/A198T0j8Xa/l4fuyollCpMEdHHdWClJKUI+PT2VyeLQDf88xP848K/zWBrIieXwOTxR
RKhoyri8OFG7eWyugJvCo3N5/6mJ/zDsT1qca5Eo9Z8ANcoISN2gAuTnPoCiEAESeVDc9d/75oMPBeKb
F6Y6sTj3nwX9+65wifiRzo37HOcSGExnCfkZi2viawnQgAAkARXIAxWgAXSBITADVsAWOAI3sAL4gWAQ
DtYCFogHyYAPMkEu2AwKQBHYBfaCSlAD6kEjaAEnQAc4DS6Ay+A6uAnugAdgBIyD52AGvAHzEARhITJE
geQhVUgLMoDMIAZkD7lBPlAgFA5FQ3EQDxJCudAWqAgqhSqhWqgR+hY6BV2ArkID0D1oFJqCfoXewwhM
gqmwMqwNG8MM2An2hoPhNXAcnAbnwPnwTrgCroOPwe3wBfg6fAcegZ/DswhAiAgNUUMMEQbigvghEUgs
wkc2IIVIOVKHtCBdSC9yCxlBppF3KAyKgqKjDFG2KE9UCIqFSkNtQBWjKlFHUe2oHtQt1ChqBvUJTUYr
oQ3QNmgv9Cp0HDoTXYAuRzeg29CX0HfQ4+g3GAyGhtHBWGE8MeGYBMw6TDHmAKYVcx4zgBnDzGKxWHms
AdYO64dlYgXYAux+7DHsOewgdhz7FkfEqeLMcO64CBwPl4crxzXhzuIGcRO4ebwUXgtvg/fDs/HZ+BJ8
Pb4LfwM/jp8nSBN0CHaEYEICYTOhgtBCuER4SHhFJBLVidbEACKXuIlYQTxOvEIcJb4jyZD0SS6kSJKQ
tJN0hHSedI/0ikwma5MdyRFkAXknuZF8kfyY/FaCImEk4SXBltgoUSXRLjEo8UISL6kl6SS5VjJHslzy
pOQNyWkpvJS2lIsUU2qDVJXUKalhqVlpirSptJ90snSxdJP0VelJGayMtoybDFsmX+awzEWZMQpC0aC4
UFiULZR6yiXKOBVD1aF6UROoRdRvqP3UGVkZ2WWyobJZslWyZ2RHaAhNm+ZFS6KV0E7QhmjvlygvcVrC
WbJjScuSwSVzcopyjnIcuUK5Vrk7cu/l6fJu8onyu+U75B8poBT0FQIUMhUOKlxSmFakKtoqshQLFU8o
3leClfSVApXWKR1W6lOaVVZR9lBOVd6vfFF5WoWm4qiSoFKmclZlSpWiaq/KVS1TPaf6jC5Ld6In0Svo
PfQZNSU1TzWhWq1av9q8uo56iHqeeqv6Iw2CBkMjVqNMo1tjRlNV01czV7NZ874WXouhFa+1T6tXa05b
RztMe5t2h/akjpyOl06OTrPOQ12yroNumm6d7m09jB5DL1HvgN5NfVjfQj9ev0r/hgFsYGnANThgMLAU
vdR6KW9p3dJhQ5Khk2GGYbPhqBHNyMcoz6jD6IWxpnGE8W7jXuNPJhYmSSb1Jg9MZUxXmOaZdpn+aqZv
xjKrMrttTjZ3N99o3mn+cpnBMs6yg8vuWlAsfC22WXRbfLS0suRbtlhOWWlaRVtVWw0zqAx/RjHjijXa
2tl6o/Vp63c2ljYCmxM2v9ga2ibaNtlOLtdZzllev3zMTt2OaVdrN2JPt4+2P2Q/4qDmwHSoc3jiqOHI
dmxwnHDSc0pwOub0wtnEme/c5jznYuOy3uW8K+Lq4Vro2u8m4xbiVun22F3dPc692X3Gw8Jjncd5T7Sn
t+duz2EvZS+WV6PXzAqrFetX9HiTvIO8K72f+Oj78H26fGHfFb57fB+u1FrJW9nhB/y8/Pb4PfLX8U/z
/z4AE+AfUBXwNNA0MDewN4gSFBXUFPQm2Dm4JPhBiG6IMKQ7VDI0MrQxdC7MNaw0bGSV8ar1q66HK4Rz
wzsjsBGhEQ0Rs6vdVu9dPR5pEVkQObRGZ03WmqtrFdYmrT0TJRnFjDoZjY4Oi26K/sD0Y9YxZ2O8Yqpj
ZlgurH2s52xHdhl7imPHKeVMxNrFlsZOxtnF7YmbineIL4+f5rpwK7kvEzwTahLmEv0SjyQuJIUltSbj
kqOTT/FkeIm8nhSVlKyUgVSD1ILUkTSbtL1pM3xvfkM6lL4mvVNAFf1M9Ql1hVuFoxn2GVUZbzNDM09m
SWfxsvqy9bN3ZE/kuOd8vQ61jrWuO1ctd3Pu6Hqn9bUboA0xG7o3amzM3zi+yWPT0c2EzYmbf8gzySvN
e70lbEtXvnL+pvyxrR5bmwskCvgFw9tst9VsR23nbu/fYb5j/45PhezCa0UmReVFH4pZxde+Mv2q4quF
nbE7+0ssSw7uwuzi7Rra7bD7aKl0aU7p2B7fPe1l9LLCstd7o/ZeLV9WXrOPsE+4b6TCp6Jzv+b+Xfs/
VMZX3qlyrmqtVqreUT13gH1g8KDjwZYa5ZqimveHuIfu1nrUttdp15UfxhzOOPy0PrS+92vG140NCg1F
DR+P8I6MHA082tNo1djYpNRU0gw3C5unjkUeu/mN6zedLYYtta201qLj4Ljw+LNvo78dOuF9ovsk42TL
d1rfVbdR2grbofbs9pmO+I6RzvDOgVMrTnV32Xa1fW/0/ZHTaqerzsieKTlLOJt/duFczrnZ86nnpy/E
XRjrjup+cHHVxds9AT39l7wvXbnsfvlir1PvuSt2V05ftbl66hrjWsd1y+vtfRZ9bT9Y/NDWb9nffsPq
RudN65tdA8sHzg46DF645Xrr8m2v29fvrLwzMBQydHc4cnjkLvvu5L2key/vZ9yff7DpIfph4SOpR+WP
lR7X/aj3Y+uI5ciZUdfRvidBTx6Mscae/5T+04fx/Kfkp+UTqhONk2aTp6fcp24+W/1s/Hnq8/npgp+l
f65+ofviu18cf+mbWTUz/pL/cuHX4lfyr468Xva6e9Z/9vGb5Dfzc4Vv5d8efcd41/s+7P3EfOYH7IeK
j3ofuz55f3q4kLyw8Bv3hPP74uYdwgAAAAlwSFlzAAALEwAACxMBAJqcGAAAAahJREFUOE9j+P//P8l4
vaOjPYyNIYkPO1lZsa1wdNy42sHh3Hxb22KQGFaF2LC4qjjroUP7n97s6vx/Ny/3/ypn54+LbGwisSpG
x+aaouwZren/u5f2/3/18tX/qzNn/l/i4XGSgYFBFasGZKwjzcJ6YVnU152blvw3LHH53zCl/ufatWu+
T+1vDALJY9UEwxrijExHZgd+/Xy1Hcg98BNkCMglMM0gjKEJhuX5GVh2TvD+/O5c0///P9b///qo819P
lgmKZhBG0QTDMjwMzJs7XT+9OVHz///XFf+/PWj7j00zCKNwQFiah4FtXbPjp8d78////7bo/4/79Tg1
gzAKR1mUg3lOocXbe9uz/v9/M/H/1zuVeDWDMJwhJcDBvK4p4tb1DQn//r/u+f/zRh5BzSAMZyyrdVh9
c33B9//32159vZr2hxjNIAwm1GUE3e+ur/n9/+Ls/592Nf9fUun3khjNIMzAysTAv6g6+OT/E33/j09N
+zWpMuImsZpBmMHIQK9x19T8/03x1ufE+TkqsCnChxmUlFWuyEpJtAHTtT42BfjxfwYAtlm0ShMkSB4A
AAAASUVORK5CYII=
</value>
</data>
<data name="ActionButton2.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1
MAAA6mAAADqYAAAXb5JfxUYAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAFQSURBVFhH7ZfNDcIwFIMZoXcm
YBtGYRHECIgTR1ZhBsS9YoJgQ1Poi5sfqhIOWPqkqvV7dWlI0oVzriry5Dd5HSS0PFwasAEn0AJn4Dle
o6fpykaVHYDNwB7YG6ZgzWiQrABosAbqaXNh7bprN1AyAAp3b42msuva9ooGYIFpELA931D2FI+VxzAI
gTIdAEb+7KpBz+p4RclQyifoXwdKwgAwcMAl3/mEAOz9GJgokQGyR/sHr8CzlwFwgU+vCuagUQE4gSjz
HGxUAM5iyiyxUp4IJ5QEAYomHCvlidCiJAigjKNYKU8M6B/g9wJUH4TV/4ZFE5GV8kSQE1HRVGylPBHC
qbh0MbJSnhH0YtQFyFqOiZXyCOLLMQVDckNCrJRHEN+QeMGY3JJZKY8hb0vmxQLTYAplm1IvFNbblnuh
Qb0Pk3exGZjv06wW8uT3cIs7jQnSONrSxH0AAAAASUVORK5CYII=
</value>
</data>
<data name="ActionButton3.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
</value>
</data>
<metadata name="TP_NOTIFY.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <metadata name="TP_NOTIFY.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value> <value>False</value>
</metadata> </metadata>
@@ -216,36 +137,37 @@
This means that if any user data has been downloaded with the plan, a simple notification will be shown with the number of users downloaded. This means that if any user data has been downloaded with the plan, a simple notification will be shown with the number of users downloaded.
The 'Image' and 'User icon' parameters will be ignored.</value> The 'Image' and 'User icon' parameters will be ignored.</value>
</data> </data>
<data name="ActionButton4.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="ActionButton1.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value> <value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6 iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6
JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsTAAALEwEAmpwYAAACOElE JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsPAAALDwGS+QOlAAACM0lE
QVQ4T2P4//8/QczOJyyqHpzfiE0OQwAZC8iqszAzs7CJ69o4BR768V/W2jcGXQ0KB4aFNS3dDQtnrbCb QVQ4T2P4//8/AyHMzicsqh6c34guDsIYAshYQFadhZmZhU1c18Yp8NCP/7LWvjHoajA0gbCwpqW7YeGs
ePCK48wTN1wXXXzge/jXf/clV55zC4hIIatF0cjIyMikElzc57z0wX+XHd/+2+//99/ywP//xlu//tdb FXYTD15xnHnihuuiiw98D//6777kynNuAREpnAYwMjIyqQQX9zkvffDfZce3//b7//23PPD/v/HWr//1
+eK/4Zp3/1WTOhYzARViNUAluKjTdf37/0ZTTn9TbdhwXblhwwW1/qOP1Ja9+K8w+95/6cm3/6v2Xvkv Vr74b7jm3X/VpI7FTIyMjFgNUAku6nRd//6/0ZTT31QbNlxXbthwQa3/6CO1ZS/+K8y+91968u3/qr1X
qKjniGGAoIqRpW3/4e8S9uGdzFz82gwMDFxAzCxm4ZegtuLDf+VJ1/8rZM25IqLvnM/CximCYYCic1QN /gsq6jliGCCoYmRp23/4u4R9eCczF782AwMDFwMDA7OYhV+C2ooP/5UnXf+vkDXnioi+cz4LG6cIhgGK
v7x2JIwPwyrJ3XNUylddE9G2TWNmZOBDl4czmJiZMSRBmFdSyYyJgUEQmxwIYxWEYXZBCUls4sgYq6CA zlE1/PLakcguArsquXuOSvmqayLatmnMjAx86PJwBhMzM4YkCPNKKpkxMTAIootjGIANswtKSKKLoWMM
prWNbtG8nXKeaVPR5XiVjSxEzf0yYXy4BBMLO6eQjoOXZvrkbbazrv53Xf/2v4CSbjBMXkhBl1/CMyNZ ARAW0LS20S2at1POM20quhyvspGFqLlfJoYBTCzsnEI6Dl6a6ZO32c66+t91/dv/Akq6wTB5IQVdfgnP
qWnvGy5pNQ+YONwAfjXzAOupl/47LLr333L50/96q9/8l23YdES6cO5KuYqVW+R7Tj6SnfP0v4hryjyY jGSlpr1vuKTVPDAM4FczD7Ceeum/w6J7/y2XP/2vt/rNf9mGTUekC+eulKtYuUW+5+Qj2TlP/4u4psxD
HhQDmFjYeHVKFp7WX/Xuv9Kq9/+Vd/z7r7rv/3+l7f//y676DEwDN/9L+BVvYkKLCTgDhNkkVUyVlr74 dhGSC9h4dUoWntZf9e6/0qr3/5V3/Puvuu//f6Xt///Lrvr8X3ryzf8SfsWbmNBiAsV/bJIqpkpLX/xU
qbbz73/VOTc/qsy89kWx+9h7qbQpJwS1bbOAscGGrB6EUTggLOqf16C55ft/HlnNAFZOXgVWdi4FRgYG 2/n3v+qcmx9VZl77oth97L1U2pQTgtq2WUwMDGzI6jEMAGFR/7wGzS3f//PIagawcvIqsLJzKTAyMLCi
VnR1MIwhwMTCyqEQ37qEmZVDFF0OE/9nAACtFF4Ey6OP+wAAAABJRU5ErkJggg== q8NpABMLK4dCfOsSZlYOUXQ5bBgArRReBMoH61gAAAAASUVORK5CYII=
</value> </value>
</data> </data>
<data name="ActionButton5.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> <data name="ActionButton2.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value> <value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6 iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6
JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsTAAALEwEAmpwYAAACOElE JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsPAAALDwGS+QOlAAACM0lE
QVQ4T2P4//8/QczOJyyqHpzfiE0OQwAZC8iqszAzs7CJ69o4BR768V/W2jcGXQ0KB4aFNS3dDQtnrbCb QVQ4T2P4//8/AyHMzicsqh6c34guDsIYAshYQFadhZmZhU1c18Yp8NCP/7LWvjHoajA0gbCwpqW7YeGs
ePCK48wTN1wXXXzge/jXf/clV55zC4hIIatF0cjIyMikElzc57z0wX+XHd/+2+//99/ywP//xlu//tdb FXYTD15xnHnihuuiiw98D//6777kynNuAREpnAYwMjIyqQQX9zkvffDfZce3//b7//23PPD/v/HWr//1
+eK/4Zp3/1WTOhYzARViNUAluKjTdf37/0ZTTn9TbdhwXblhwwW1/qOP1Ja9+K8w+95/6cm3/6v2Xvkv Vr74b7jm3X/VpI7FTIyMjFgNUAku6nRd//6/0ZTT31QbNlxXbthwQa3/6CO1ZS/+K8y+91968u3/qr1X
qKjniGGAoIqRpW3/4e8S9uGdzFz82gwMDFxAzCxm4ZegtuLDf+VJ1/8rZM25IqLvnM/CximCYYCic1QN /gsq6jliGCCoYmRp23/4u4R9eCczF782AwMDFwMDA7OYhV+C2ooP/5UnXf+vkDXnioi+cz4LG6cIhgGK
v7x2JIwPwyrJ3XNUylddE9G2TWNmZOBDl4czmJiZMSRBmFdSyYyJgUEQmxwIYxWEYXZBCUls4sgYq6CA zlE1/PLakcguArsquXuOSvmqayLatmnMjAx86PJwBhMzM4YkCPNKKpkxMTAIootjGIANswtKSKKLoWMM
prWNbtG8nXKeaVPR5XiVjSxEzf0yYXy4BBMLO6eQjoOXZvrkbbazrv53Xf/2v4CSbjBMXkhBl1/CMyNZ ARAW0LS20S2at1POM20quhyvspGFqLlfJoYBTCzsnEI6Dl6a6ZO32c66+t91/dv/Akq6wTB5IQVdfgnP
qWnvGy5pNQ+YONwAfjXzAOupl/47LLr333L50/96q9/8l23YdES6cO5KuYqVW+R7Tj6SnfP0v4hryjyY jGSlpr1vuKTVPDAM4FczD7Ceeum/w6J7/y2XP/2vt/rNf9mGTUekC+eulKtYuUW+5+Qj2TlP/4u4psxD
HhQDmFjYeHVKFp7WX/Xuv9Kq9/+Vd/z7r7rv/3+l7f//y676DEwDN/9L+BVvYkKLCTgDhNkkVUyVlr74 dhGSC9h4dUoWntZf9e6/0qr3/5V3/Puvuu//f6Xt///Lrvr8X3ryzf8SfsWbmNBiAsV/bJIqpkpLX/xU
qbbz73/VOTc/qsy89kWx+9h7qbQpJwS1bbOAscGGrB6EUTggLOqf16C55ft/HlnNAFZOXgVWdi4FRgYG 2/n3v+qcmx9VZl77oth97L1U2pQTgtq2WUwMDGzI6jEMAGFR/7wGzS3f//PIagawcvIqsLJzKTAyMLCi
VnR1MIwhwMTCyqEQ37qEmZVDFF0OE/9nAACtFF4Ey6OP+wAAAABJRU5ErkJggg== q8NpABMLK4dCfOsSZlYOUXQ5bBgArRReBMoH61gAAAAASUVORK5CYII=
</value> </value>
</data> </data>
</root> </root>

View File

@@ -9,17 +9,14 @@
Imports SCrawler.DownloadObjects.Groups Imports SCrawler.DownloadObjects.Groups
Imports PersonalUtilities.Forms Imports PersonalUtilities.Forms
Imports PersonalUtilities.Forms.Controls.Base Imports PersonalUtilities.Forms.Controls.Base
Imports DModes = SCrawler.DownloadObjects.AutoDownloader.Modes
Namespace DownloadObjects Namespace DownloadObjects
Friend Class AutoDownloaderEditorForm Friend Class AutoDownloaderEditorForm
Private WithEvents MyDefs As DefaultFormOptions Private WithEvents MyDefs As DefaultFormOptions
Private ReadOnly MyGroups As List(Of String)
Private ReadOnly Property Plan As AutoDownloader Private ReadOnly Property Plan As AutoDownloader
Friend Sub New(ByRef _Plan As AutoDownloader) Friend Sub New(ByRef _Plan As AutoDownloader)
InitializeComponent() InitializeComponent()
Plan = _Plan Plan = _Plan
MyDefs = New DefaultFormOptions(Me, Settings.Design) MyDefs = New DefaultFormOptions(Me, Settings.Design)
MyGroups.ListAddList(Plan.Groups, LAP.NotContainsOnly)
End Sub End Sub
Private Class AutomationTimerChecker : Inherits FieldsCheckerProviderBase Private Class AutomationTimerChecker : Inherits FieldsCheckerProviderBase
Public Overrides Property ErrorMessage As String Public Overrides Property ErrorMessage As String
@@ -45,19 +42,12 @@ Namespace DownloadObjects
.MyViewInitialize(True) .MyViewInitialize(True)
.AddOkCancelToolbar() .AddOkCancelToolbar()
With Plan With Plan
Select Case .Mode If Enabled Then OPT_ENABLED.Checked = True Else OPT_DISABLED.Checked = True
Case DModes.None : OPT_DISABLED.Checked = True
Case DModes.Specified : OPT_SPEC.Checked = True
Case DModes.Groups : OPT_GROUP.Checked = True
End Select
TXT_GROUPS.CaptionWidth = GroupDefaults.CaptionWidthDefault
TXT_TIMER.CaptionWidth = GroupDefaults.CaptionWidthDefault TXT_TIMER.CaptionWidth = GroupDefaults.CaptionWidthDefault
NUM_DELAY.CaptionWidth = GroupDefaults.CaptionWidthDefault NUM_DELAY.CaptionWidth = GroupDefaults.CaptionWidthDefault
DEF_GROUP.Set(Plan) DEF_GROUP.Set(Plan)
If MyGroups.Count > 0 Then TXT_GROUPS.Text = MyGroups.ListToString
If Settings.Groups.Count = 0 Then TXT_GROUPS.Clear() : TXT_GROUPS.Enabled = False
CH_NOTIFY.Checked = .ShowNotifications CH_NOTIFY.Checked = .ShowNotifications
CH_NOTIFY_SIMPLE.Checked = .ShowSimpleNotification CH_NOTIFY_SIMPLE.Checked = .ShowSimpleNotification
CH_SHOW_PIC.Checked = .ShowPictureDownloaded CH_SHOW_PIC.Checked = .ShowPictureDownloaded
@@ -79,27 +69,14 @@ Namespace DownloadObjects
If DEF_GROUP.TXT_NAME.IsEmptyString And Settings.Automation.Count = 0 Then DEF_GROUP.TXT_NAME.Text = "Default" If DEF_GROUP.TXT_NAME.IsEmptyString And Settings.Automation.Count = 0 Then DEF_GROUP.TXT_NAME.Text = "Default"
End With End With
End Sub End Sub
Private Sub AutoDownloaderEditorForm_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed
MyGroups.Clear()
End Sub
Private Sub AutoDownloaderEditorForm_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown Private Sub AutoDownloaderEditorForm_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
Try Try
If e = ShowUsersButtonKey AndAlso Not OPT_DISABLED.Checked Then If e = ShowUsersButtonKey AndAlso Not OPT_DISABLED.Checked Then
Dim users As New List(Of API.Base.IUserData) Dim users As New List(Of API.Base.IUserData)
If OPT_GROUP.Checked Then Using g As New GroupParameters
If MyGroups.Count > 0 Then DEF_GROUP.Get(g)
Dim i% users.ListAddList(DownloadGroup.GetUsers(g), LAP.IgnoreICopier)
For Each groupName$ In MyGroups End Using
i = Settings.Groups.IndexOf(groupName)
If i >= 0 Then users.ListAddList(DownloadGroup.GetUsers(Settings.Groups(i)), LAP.NotContainsOnly, LAP.IgnoreICopier)
Next
End If
Else
Using g As New GroupParameters
DEF_GROUP.Get(g)
users.ListAddList(DownloadGroup.GetUsers(g))
End Using
End If
GroupUsersViewer.Show(users, $"S {DEF_GROUP.TXT_NAME.Text}") GroupUsersViewer.Show(users, $"S {DEF_GROUP.TXT_NAME.Text}")
users.Clear() users.Clear()
End If End If
@@ -110,14 +87,8 @@ Namespace DownloadObjects
Private Sub MyDefs_ButtonOkClick(ByVal Sender As Object, ByVal e As KeyHandleEventArgs) Handles MyDefs.ButtonOkClick Private Sub MyDefs_ButtonOkClick(ByVal Sender As Object, ByVal e As KeyHandleEventArgs) Handles MyDefs.ButtonOkClick
If MyDefs.MyFieldsChecker.AllParamsOK Then If MyDefs.MyFieldsChecker.AllParamsOK Then
With Plan With Plan
Select Case True .Enabled = OPT_ENABLED.Checked
Case OPT_DISABLED.Checked : .Mode = DModes.None
Case OPT_SPEC.Checked : .Mode = DModes.Specified
Case OPT_GROUP.Checked : .Mode = DModes.Groups
End Select
DEF_GROUP.Get(Plan) DEF_GROUP.Get(Plan)
.Groups.Clear()
.Groups.ListAddList(MyGroups)
.ShowNotifications = CH_NOTIFY.Checked .ShowNotifications = CH_NOTIFY.Checked
.ShowSimpleNotification = CH_NOTIFY_SIMPLE.Checked .ShowSimpleNotification = CH_NOTIFY_SIMPLE.Checked
.ShowPictureDownloaded = CH_SHOW_PIC.Checked .ShowPictureDownloaded = CH_SHOW_PIC.Checked
@@ -131,42 +102,20 @@ Namespace DownloadObjects
MyDefs.CloseForm() MyDefs.CloseForm()
End If End If
End Sub End Sub
Private Sub TXT_GROUPS_ActionOnButtonClick(ByVal Sender As ActionButton, ByVal e As EventArgs) Handles TXT_GROUPS.ActionOnButtonClick
Select Case Sender.DefaultButton
Case ActionButton.DefaultButtons.Edit
Using f As New LabelsForm(MyGroups, (From g As DownloadGroup In Settings.Groups Where Not g.IsViewFilter Select g.Name)) With {
.Text = "Groups (F3 to edit)",
.Icon = My.Resources.GroupByIcon_16,
.IsGroups = True
}
f.ShowDialog()
If f.DialogResult = DialogResult.OK Then MyGroups.ListAddList(f.LabelsList, LAP.ClearBeforeAdd) : TXT_GROUPS.Text = MyGroups.ListToString
End Using
Case ActionButton.DefaultButtons.Clear : MyGroups.Clear()
Case ActionButton.DefaultButtons.Info
Try
If MyGroups.Count > 0 Then
Dim i% = Settings.Groups.IndexOf(MyGroups(0))
If i >= 0 Then
Using gf As New GroupEditorForm(Settings.Groups(i)) : gf.ShowDialog() : End Using
End If
End If
Catch ex As Exception
ErrorsDescriber.Execute(EDP.LogMessageValue, ex, "Show group")
End Try
End Select
End Sub
Private Sub ChangeEnabled() Handles OPT_DISABLED.CheckedChanged, Private Sub ChangeEnabled() Handles OPT_DISABLED.CheckedChanged,
OPT_SPEC.CheckedChanged, OPT_GROUP.CheckedChanged, OPT_ENABLED.CheckedChanged,
CH_NOTIFY.CheckedChanged, CH_NOTIFY_SIMPLE.CheckedChanged CH_NOTIFY.CheckedChanged, CH_NOTIFY_SIMPLE.CheckedChanged
DEF_GROUP.Enabled = OPT_SPEC.Checked Dim __enabled As Boolean = Not OPT_DISABLED.Checked
TXT_GROUPS.Enabled = OPT_GROUP.Checked DEF_GROUP.Enabled = __enabled
TXT_TIMER.Enabled = Not OPT_DISABLED.Checked TXT_TIMER.Enabled = __enabled
NUM_DELAY.Enabled = Not OPT_DISABLED.Checked NUM_DELAY.Enabled = __enabled
CH_NOTIFY.Enabled = Not OPT_DISABLED.Checked CH_NOTIFY.Enabled = __enabled
CH_NOTIFY_SIMPLE.Enabled = CH_NOTIFY.Enabled And CH_NOTIFY.Checked CH_NOTIFY_SIMPLE.Enabled = CH_NOTIFY.Enabled And CH_NOTIFY.Checked
CH_SHOW_PIC.Enabled = CH_NOTIFY.Checked And Not OPT_DISABLED.Checked And Not CH_NOTIFY_SIMPLE.Checked CH_SHOW_PIC.Enabled = CH_NOTIFY.Checked And Not OPT_DISABLED.Checked And Not CH_NOTIFY_SIMPLE.Checked
CH_SHOW_PIC_USER.Enabled = CH_NOTIFY.Checked And Not OPT_DISABLED.Checked And Not CH_NOTIFY_SIMPLE.Checked CH_SHOW_PIC_USER.Enabled = CH_NOTIFY.Checked And Not OPT_DISABLED.Checked And Not CH_NOTIFY_SIMPLE.Checked
If Settings.Labels.Count = 0 Then DEF_GROUP.LabelsEnabled = False
If Settings.Groups.Count = 0 Then DEF_GROUP.GroupsEnabled = False
End Sub End Sub
Private Sub NUM_DELAY_ActionOnButtonClick(ByVal Sender As ActionButton, ByVal e As EventArgs) Handles NUM_DELAY.ActionOnButtonClick Private Sub NUM_DELAY_ActionOnButtonClick(ByVal Sender As ActionButton, ByVal e As EventArgs) Handles NUM_DELAY.ActionOnButtonClick
If Sender.DefaultButton = ActionButton.DefaultButtons.Clear Then NUM_DELAY.Value = 0 If Sender.DefaultButton = ActionButton.DefaultButtons.Clear Then NUM_DELAY.Value = 0

View File

@@ -144,7 +144,7 @@ Namespace DownloadObjects
If UpdateBase Then UpdateBaseButton(Not p = PauseModes.Disabled) If UpdateBase Then UpdateBaseButton(Not p = PauseModes.Disabled)
If Not VerifyAll OrElse Settings.Automation.All(Function(ByVal plan As AutoDownloader) As Boolean If Not VerifyAll OrElse Settings.Automation.All(Function(ByVal plan As AutoDownloader) As Boolean
If plan.Mode = AutoDownloader.Modes.None Then If Not plan.Enabled Then
Return True Return True
Else Else
Return plan.Pause = p Return plan.Pause = p

View File

@@ -507,24 +507,7 @@ Namespace DownloadObjects
Private Sub ShowPlanUsers() Private Sub ShowPlanUsers()
Try Try
If _LatestSelected.ValueBetween(0, Settings.Automation.Count - 1) Then If _LatestSelected.ValueBetween(0, Settings.Automation.Count - 1) Then
With Settings.Automation(_LatestSelected) With Settings.Automation(_LatestSelected) : Groups.GroupUsersViewer.Show(Groups.DownloadGroup.GetUsers(.Self), $"S { .Name}") : End With
Dim users As New List(Of API.Base.IUserData)
If Not .Mode = AutoDownloader.Modes.None Then
If .Mode = AutoDownloader.Modes.Groups Then
If .Groups.Count > 0 Then
Dim i%
For Each groupName$ In .Groups
i = Settings.Groups.IndexOf(groupName)
If i >= 0 Then users.ListAddList(Groups.DownloadGroup.GetUsers(Settings.Groups(i)), LAP.NotContainsOnly, LAP.IgnoreICopier)
Next
End If
Else
users.ListAddList(Groups.DownloadGroup.GetUsers(.Self))
End If
End If
Groups.GroupUsersViewer.Show(users, $"S { .Name}")
users.Clear()
End With
End If End If
Catch ex As Exception Catch ex As Exception
ErrorsDescriber.Execute(EDP.LogMessageValue, ex, "Show plan users") ErrorsDescriber.Execute(EDP.LogMessageValue, ex, "Show plan users")

View File

@@ -16,6 +16,7 @@ Namespace DownloadObjects
Friend Event DownloadDone As NotificationEventHandler Friend Event DownloadDone As NotificationEventHandler
Friend Event ProgressChanged(ByVal Main As Boolean, ByVal IsMaxValue As Boolean, ByVal IsDone As Boolean) Friend Event ProgressChanged(ByVal Main As Boolean, ByVal IsMaxValue As Boolean, ByVal IsDone As Boolean)
Friend Event FeedFilesChanged As TDownloader.FeedFilesChangedEventHandler Friend Event FeedFilesChanged As TDownloader.FeedFilesChangedEventHandler
Friend Event KeyDown As KeyEventHandler
#End Region #End Region
#Region "Declarations" #Region "Declarations"
#Region "Controls" #Region "Controls"
@@ -126,6 +127,10 @@ Namespace DownloadObjects
TP_MAIN.Controls.Add(LBL_INFO, 0, 1) TP_MAIN.Controls.Add(LBL_INFO, 0, 1)
End If End If
For Each btt As Button In {BTT_OPEN, BTT_START, BTT_STOP}
If Not btt Is Nothing Then AddHandler btt.KeyDown, AddressOf BTT_KeyDown
Next
With Job With Job
.Progress = New MyProgressExt(PR_MAIN, PR_PRE, LBL_INFO) With {.ResetProgressOnMaximumChanges = False} .Progress = New MyProgressExt(PR_MAIN, PR_PRE, LBL_INFO) With {.ResetProgressOnMaximumChanges = False}
With DirectCast(.Progress, MyProgressExt) With DirectCast(.Progress, MyProgressExt)
@@ -149,6 +154,9 @@ Namespace DownloadObjects
.Dock = DockStyle.Fill .Dock = DockStyle.Fill
} }
End Sub End Sub
Private Sub BTT_KeyDown(ByVal Sender As Object, ByVal e As KeyEventArgs)
RaiseEvent KeyDown(Sender, e)
End Sub
#End Region #End Region
Friend Function [Get]() As TableLayoutPanel Friend Function [Get]() As TableLayoutPanel
Return TP_MAIN Return TP_MAIN

View File

@@ -43,6 +43,7 @@ Friend Class DownloadSavedPostsForm
For Each j As DownloadProgress In JobsList For Each j As DownloadProgress In JobsList
AddHandler j.DownloadDone, AddressOf Jobs_DownloadDone AddHandler j.DownloadDone, AddressOf Jobs_DownloadDone
AddHandler j.FeedFilesChanged, AddressOf Jobs_FeedFilesChanged AddHandler j.FeedFilesChanged, AddressOf Jobs_FeedFilesChanged
AddHandler j.KeyDown, AddressOf DownloadSavedPostsForm_KeyDown
TP_MAIN.RowStyles.Add(New RowStyle(SizeType.Absolute, 60)) TP_MAIN.RowStyles.Add(New RowStyle(SizeType.Absolute, 60))
TP_MAIN.RowCount += 1 TP_MAIN.RowCount += 1
TP_MAIN.Controls.Add(j.Get, 0, TP_MAIN.RowStyles.Count - 1) TP_MAIN.Controls.Add(j.Get, 0, TP_MAIN.RowStyles.Count - 1)
@@ -54,6 +55,9 @@ Friend Class DownloadSavedPostsForm
MaximumSize = s MaximumSize = s
End If End If
End Sub End Sub
Private Sub DownloadSavedPostsForm_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown, BTT_DOWN_ALL.KeyDown, BTT_STOP_ALL.KeyDown
If e.KeyCode = Keys.Escape Then Close()
End Sub
Private Sub DownloadSavedPostsForm_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing Private Sub DownloadSavedPostsForm_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
e.Cancel = True e.Cancel = True
Hide() Hide()

View File

@@ -245,7 +245,7 @@ Namespace DownloadObjects.Groups
If Not Settings.Automation Is Nothing AndAlso Settings.Automation.Count > 0 Then If Not Settings.Automation Is Nothing AndAlso Settings.Automation.Count > 0 Then
Dim aIncl As New List(Of String) Dim aIncl As New List(Of String)
For Each plan As AutoDownloader In Settings.Automation For Each plan As AutoDownloader In Settings.Automation
If plan.Mode = AutoDownloader.Modes.Groups AndAlso plan.Groups.Count > 0 AndAlso plan.Groups.Contains(Name) Then aIncl.Add(plan.Name) If plan.Groups.Count > 0 AndAlso plan.Groups.Contains(Name) Then aIncl.Add(plan.Name)
Next Next
If aIncl.Count > 0 Then If aIncl.Count > 0 Then
MsgBoxE({$"The '{Name}' group cannot be deleted because it is included in the following scheduler plans:{vbCr}{vbCr}" & MsgBoxE({$"The '{Name}' group cannot be deleted because it is included in the following scheduler plans:{vbCr}{vbCr}" &
@@ -285,6 +285,7 @@ Namespace DownloadObjects.Groups
Try Try
If Settings.Users.Count > 0 Then If Settings.Users.Count > 0 Then
With Instance With Instance
If TypeOf .Self Is AutoDownloader AndAlso Not DirectCast(.Self, AutoDownloader).Enabled Then Return Nothing
Dim downDate As Date? = Nothing Dim downDate As Date? = Nothing
If .DaysNumber > 0 Then If .DaysNumber > 0 Then
With Now.AddDays(- .DaysNumber) : downDate = New Date(.Year, .Month, .Day, 0, 0, 0) : End With With Now.AddDays(- .DaysNumber) : downDate = New Date(.Year, .Month, .Day, 0, 0, 0) : End With
@@ -363,10 +364,32 @@ Namespace DownloadObjects.Groups
Dim CheckSites As Predicate(Of IUserData) = Function(user) _ Dim CheckSites As Predicate(Of IUserData) = Function(user) _
(.Sites.Count = 0 OrElse .Sites.Contains(user.Site)) AndAlso (.Sites.Count = 0 OrElse .Sites.Contains(user.Site)) AndAlso
(.SitesExcluded.Count = 0 OrElse Not .SitesExcluded.Contains(user.Site)) (.SitesExcluded.Count = 0 OrElse Not .SitesExcluded.Contains(user.Site))
Dim users As IEnumerable(Of IUserData) = Dim users As New List(Of IUserData)
Settings.GetUsers(Function(user) CheckLabels.Invoke(user) AndAlso CheckSites.Invoke(user) AndAlso Dim l As New ListAddParams(LAP.IgnoreICopier)
CheckParams.Invoke(user) AndAlso CheckSubscription.Invoke(user) AndAlso If Not .GroupsOnly Or (.GroupsOnly And .Groups.Count = 0) Then
CheckDays.Invoke(user) AndAlso CheckDateRange.Invoke(user)) users.ListAddList(Settings.GetUsers(Function(user) CheckLabels.Invoke(user) AndAlso CheckSites.Invoke(user) AndAlso
CheckParams.Invoke(user) AndAlso CheckSubscription.Invoke(user) AndAlso
CheckDays.Invoke(user) AndAlso CheckDateRange.Invoke(user)), l)
End If
If Settings.Groups.Count > 0 Then
Dim i%
Dim groupName$
l.NotContainsOnly = True
If .Groups.Count > 0 Then
For Each groupName In .Groups
i = Settings.Groups.IndexOf(groupName)
If i >= 0 Then users.ListAddList(Settings.Groups(i).GetUsers, l)
Next
End If
l.DisableDispose = True
If .GroupsExcluded.Count > 0 Then
For Each groupName In .GroupsExcluded
i = Settings.Groups.IndexOf(groupName)
If i >= 0 Then users.ListDisposeRemove(Settings.Groups(i).GetUsers, l)
Next
End If
End If
If .UsersCount <> 0 And users.ListExists Then If .UsersCount <> 0 And users.ListExists Then
users = users.ListTake(If(.UsersCount > 0, -1, -2), Math.Abs(.UsersCount)) users = users.ListTake(If(.UsersCount > 0, -1, -2), Math.Abs(.UsersCount))
If .UsersCount < 0 Then users = users.ListReverse If .UsersCount < 0 Then users = users.ListReverse

View File

@@ -10,10 +10,11 @@ Imports PersonalUtilities.Forms
Imports PersonalUtilities.Forms.Controls Imports PersonalUtilities.Forms.Controls
Imports PersonalUtilities.Forms.Controls.Base Imports PersonalUtilities.Forms.Controls.Base
Imports ADB = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons Imports ADB = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons
Imports CaptionModes = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes
Namespace DownloadObjects.Groups Namespace DownloadObjects.Groups
Public Class GroupDefaults : Inherits TableLayoutPanel Public Class GroupDefaults : Inherits TableLayoutPanel
#Region "Constants" #Region "Constants"
Friend Const CaptionWidthDefault As Integer = 55 Friend Const CaptionWidthDefault As Integer = 60 '55
#End Region #End Region
#Region "Declarations" #Region "Declarations"
Private ReadOnly TP_1 As TableLayoutPanel 'CH_REGULAR, CH_TEMPORARY, CH_FAV Private ReadOnly TP_1 As TableLayoutPanel 'CH_REGULAR, CH_TEMPORARY, CH_FAV
@@ -49,13 +50,21 @@ Namespace DownloadObjects.Groups
Private WithEvents TXT_LABELS As TextBoxExtended Private WithEvents TXT_LABELS As TextBoxExtended
Private WithEvents TXT_SITES As TextBoxExtended Private WithEvents TXT_SITES As TextBoxExtended
Private WithEvents TXT_GROUPS As TextBoxExtended
Friend WithEvents TXT_NAME As TextBoxExtended Friend WithEvents TXT_NAME As TextBoxExtended
Private ReadOnly Labels As List(Of String) Private ReadOnly Labels As List(Of String)
Private ReadOnly LabelsExcluded As List(Of String) Private ReadOnly LabelsExcluded As List(Of String)
Private ReadOnly Sites As List(Of String) Private ReadOnly Sites As List(Of String)
Private ReadOnly SitesExcluded As List(Of String) Private ReadOnly SitesExcluded As List(Of String)
Private ReadOnly Groups As List(Of String)
Private ReadOnly GroupsExcluded As List(Of String)
Private ReadOnly TT_MAIN As ToolTip Private ReadOnly TT_MAIN As ToolTip
Friend ReadOnly Property GroupsOnly As Boolean
Get
Return TXT_GROUPS.Checked
End Get
End Property
#End Region #End Region
#Region "Initializer" #Region "Initializer"
Public Sub New() Public Sub New()
@@ -63,6 +72,8 @@ Namespace DownloadObjects.Groups
LabelsExcluded = New List(Of String) LabelsExcluded = New List(Of String)
Sites = New List(Of String) Sites = New List(Of String)
SitesExcluded = New List(Of String) SitesExcluded = New List(Of String)
Groups = New List(Of String)
GroupsExcluded = New List(Of String)
TT_MAIN = New ToolTip TT_MAIN = New ToolTip
InitTextBox(TXT_LABELS, "Labels", {New ActionButton(ADB.Edit) With {.ToolTipText = "Edit selected labels"}, InitTextBox(TXT_LABELS, "Labels", {New ActionButton(ADB.Edit) With {.ToolTipText = "Edit selected labels"},
@@ -73,6 +84,17 @@ Namespace DownloadObjects.Groups
New ActionButton(ADB.Delete) With {.ToolTipText = "Edit excluded sites"}, ADB.Clear}) New ActionButton(ADB.Delete) With {.ToolTipText = "Edit excluded sites"}, ADB.Clear})
TXT_SITES.TextBoxReadOnly = True TXT_SITES.TextBoxReadOnly = True
InitTextBox(TXT_GROUPS, "Groups", {New ActionButton(ADB.Edit) With {.ToolTipText = "Edit selected groups"},
New ActionButton(ADB.Delete) With {.ToolTipText = "Edit excluded groups"}, ADB.Clear}, CaptionModes.CheckBox)
With TXT_GROUPS
.TextBoxReadOnly = True
.CaptionCheckAlign = ContentAlignment.MiddleLeft
.ChangeControlsEnableOnCheckedChange = False
.CaptionToolTipText = "If checked, only the selected groups will be downloaded. All other options will be ignored."
.CaptionToolTipEnabled = True
.EndInit()
End With
InitTextBox(TXT_NAME, "Name", {ADB.Clear}) InitTextBox(TXT_NAME, "Name", {ADB.Clear})
CH_REGULAR = New CheckBox With {.Text = "Regular", .Name = "CH_REGULAR", .Checked = True, .Dock = DockStyle.Fill} CH_REGULAR = New CheckBox With {.Text = "Regular", .Name = "CH_REGULAR", .Checked = True, .Dock = DockStyle.Fill}
@@ -209,12 +231,14 @@ Namespace DownloadObjects.Groups
.EndInit() .EndInit()
End With End With
End Sub End Sub
Private Sub InitTextBox(ByRef TXT As TextBoxExtended, ByVal Caption As String, ByVal Buttons As ActionButton()) Private Sub InitTextBox(ByRef TXT As TextBoxExtended, ByVal Caption As String, ByVal Buttons As ActionButton(),
Optional ByVal CaptionMode As CaptionModes = CaptionModes.Label)
TXT = New TextBoxExtended TXT = New TextBoxExtended
With TXT With TXT
.BeginInit() .BeginInit()
.Buttons.AddRange(Buttons) .Buttons.AddRange(Buttons)
.CaptionText = Caption .CaptionText = Caption
.CaptionMode = CaptionMode
.CaptionWidth = CaptionWidthDefault .CaptionWidth = CaptionWidthDefault
.Dock = DockStyle.Fill .Dock = DockStyle.Fill
.EndInit() .EndInit()
@@ -240,7 +264,7 @@ Namespace DownloadObjects.Groups
CellBorderStyle = TableLayoutPanelCellBorderStyle.Single CellBorderStyle = TableLayoutPanelCellBorderStyle.Single
ColumnCount = 1 ColumnCount = 1
ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 100)) ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 100))
RowCount = 13 RowCount = 14
RowStyles.Add(New RowStyle(SizeType.Absolute, 25)) RowStyles.Add(New RowStyle(SizeType.Absolute, 25))
RowStyles.Add(New RowStyle(SizeType.Absolute, 28)) RowStyles.Add(New RowStyle(SizeType.Absolute, 28))
RowStyles.Add(New RowStyle(SizeType.Absolute, 25)) RowStyles.Add(New RowStyle(SizeType.Absolute, 25))
@@ -253,6 +277,7 @@ Namespace DownloadObjects.Groups
RowStyles.Add(New RowStyle(SizeType.Absolute, 25)) RowStyles.Add(New RowStyle(SizeType.Absolute, 25))
RowStyles.Add(New RowStyle(SizeType.Absolute, 28)) RowStyles.Add(New RowStyle(SizeType.Absolute, 28))
RowStyles.Add(New RowStyle(SizeType.Absolute, 28)) RowStyles.Add(New RowStyle(SizeType.Absolute, 28))
RowStyles.Add(New RowStyle(SizeType.Absolute, 28))
RowStyles.Add(New RowStyle(SizeType.Percent, 100)) RowStyles.Add(New RowStyle(SizeType.Percent, 100))
End If End If
Controls.Add(TXT_NAME, 0, 1) Controls.Add(TXT_NAME, 0, 1)
@@ -269,6 +294,7 @@ Namespace DownloadObjects.Groups
Controls.Add(TXT_LABELS, 0, 10) Controls.Add(TXT_LABELS, 0, 10)
Controls.Add(TXT_SITES, 0, 11) Controls.Add(TXT_SITES, 0, 11)
Controls.Add(TXT_GROUPS, 0, 12)
End Sub End Sub
#End Region #End Region
#Region "Control handlers" #Region "Control handlers"
@@ -277,6 +303,8 @@ Namespace DownloadObjects.Groups
LabelsExcluded.Clear() LabelsExcluded.Clear()
Sites.Clear() Sites.Clear()
SitesExcluded.Clear() SitesExcluded.Clear()
Groups.Clear()
GroupsExcluded.Clear()
CH_REGULAR.Dispose() CH_REGULAR.Dispose()
CH_TEMPORARY.Dispose() CH_TEMPORARY.Dispose()
CH_FAV.Dispose() CH_FAV.Dispose()
@@ -296,6 +324,7 @@ Namespace DownloadObjects.Groups
NUM_DAYS.Dispose() NUM_DAYS.Dispose()
TXT_LABELS.Dispose() TXT_LABELS.Dispose()
TXT_SITES.Dispose() TXT_SITES.Dispose()
TXT_GROUPS.Dispose()
TXT_NAME.Dispose() TXT_NAME.Dispose()
TT_MAIN.Dispose() TT_MAIN.Dispose()
ClearTP(TP_1) ClearTP(TP_1)
@@ -338,7 +367,7 @@ Namespace DownloadObjects.Groups
End If End If
End Using End Using
End With End With
Case ADB.Clear : Labels.Clear() : LabelsExcluded.Clear() : TXT_LABELS.Clear() : UpdateLabelsText() Case ADB.Clear : Labels.Clear() : LabelsExcluded.Clear() : UpdateLabelsText()
End Select End Select
End Sub End Sub
Private Sub TXT_SITES_ActionOnButtonClick(ByVal Sender As ActionButton, ByVal e As ActionButtonEventArgs) Handles TXT_SITES.ActionOnButtonClick Private Sub TXT_SITES_ActionOnButtonClick(ByVal Sender As ActionButton, ByVal e As ActionButtonEventArgs) Handles TXT_SITES.ActionOnButtonClick
@@ -354,18 +383,38 @@ Namespace DownloadObjects.Groups
End If End If
End Using End Using
End With End With
Case ADB.Clear : Sites.Clear() : SitesExcluded.Clear() : TXT_SITES.Clear() : UpdateSitesText() Case ADB.Clear : Sites.Clear() : SitesExcluded.Clear() : UpdateSitesText()
End Select
End Sub
Private Sub TXT_GROUPS_ActionOnButtonClick(ByVal Sender As ActionButton, ByVal e As ActionButtonEventArgs) Handles TXT_GROUPS.ActionOnButtonClick
Select Case Sender.DefaultButton
Case ADB.Edit, ADB.Delete
With If(Sender.DefaultButton = ADB.Edit, Groups, GroupsExcluded)
Using f As New LabelsForm(.Self, (From g As DownloadGroup In Settings.Groups Where Not g.IsViewFilter Select g.Name)) With {
.Text = $"Groups {IIf(Sender.DefaultButton = ADB.Delete, "excluded ", String.Empty)}(F3 to edit)",
.Icon = My.Resources.GroupByIcon_16,
.IsGroups = True
}
f.ShowDialog()
If f.DialogResult = DialogResult.OK Then .ListAddList(f.LabelsList, LAP.ClearBeforeAdd) : UpdateGroupsText()
End Using
End With
Case ADB.Clear : Groups.Clear() : GroupsExcluded.Clear() : UpdateGroupsText()
End Select End Select
End Sub End Sub
Private Sub UpdateLabelsText() Private Sub UpdateLabelsText()
TXT_LABELS.Clear() __UpdateTextImpl(TXT_LABELS, Labels, LabelsExcluded)
If Not _JustExcludeOptions Then TXT_LABELS.Text = Labels.ListToString
If LabelsExcluded.Count > 0 Then TXT_LABELS.Text.StringAppend($"EXCLUDED: {LabelsExcluded.ListToString}", "; ")
End Sub End Sub
Private Sub UpdateSitesText() Private Sub UpdateSitesText()
TXT_SITES.Clear() __UpdateTextImpl(TXT_SITES, Sites, SitesExcluded)
If Not _JustExcludeOptions Then TXT_SITES.Text = Sites.ListToString End Sub
If SitesExcluded.Count > 0 Then TXT_SITES.Text.StringAppend($"EXCLUDED: {SitesExcluded.ListToString}", "; ") Private Sub UpdateGroupsText()
__UpdateTextImpl(TXT_GROUPS, Groups, GroupsExcluded)
End Sub
Private Sub __UpdateTextImpl(ByRef txt As TextBoxExtended, ByVal filter As List(Of String), ByVal excluded As List(Of String))
txt.Clear()
txt.Text = filter.ListToString
If excluded.Count > 0 Then txt.Text.StringAppend($"EXCLUDED: {excluded.ListToString}", "; ")
End Sub End Sub
#End Region #End Region
#Region "Get/set" #Region "Get/set"
@@ -410,6 +459,10 @@ Namespace DownloadObjects.Groups
.Sites.ListAddList(Sites) .Sites.ListAddList(Sites)
.SitesExcluded.Clear() .SitesExcluded.Clear()
.SitesExcluded.ListAddList(SitesExcluded) .SitesExcluded.ListAddList(SitesExcluded)
.Groups.Clear()
.Groups.ListAddList(Groups)
.GroupsExcluded.ListAddList(GroupsExcluded)
.GroupsOnly = GroupsOnly
End With End With
End If End If
End Sub End Sub
@@ -457,20 +510,23 @@ Namespace DownloadObjects.Groups
Sites.ListAddList(.Sites) Sites.ListAddList(.Sites)
SitesExcluded.ListAddList(.SitesExcluded) SitesExcluded.ListAddList(.SitesExcluded)
UpdateSitesText() UpdateSitesText()
Groups.ListAddList(.Groups)
GroupsExcluded.ListAddList(.GroupsExcluded)
TXT_GROUPS.Checked = .GroupsOnly
UpdateGroupsText()
End With End With
End If End If
End Sub End Sub
#End Region #End Region
#Region "Enabled" #Region "Enabled"
Private _Enabled As Boolean = True Private _Enabled As Boolean = True
Private _JustExcludeOptions As Boolean = False
Friend Overloads Property Enabled() As Boolean Friend Overloads Property Enabled() As Boolean
Get Get
Return _Enabled Return _Enabled
End Get End Get
Set(ByVal e As Boolean) Set(ByVal e As Boolean)
_Enabled = e _Enabled = e
_JustExcludeOptions = False
TP_1.Enabled = e TP_1.Enabled = e
TP_2.Enabled = e TP_2.Enabled = e
TP_3.Enabled = e TP_3.Enabled = e
@@ -481,8 +537,26 @@ Namespace DownloadObjects.Groups
NUM_DAYS.Enabled = e NUM_DAYS.Enabled = e
TXT_LABELS.Enabled = e TXT_LABELS.Enabled = e
TXT_SITES.Enabled = e TXT_SITES.Enabled = e
TXT_GROUPS.Enabled = e
UpdateLabelsText() UpdateLabelsText()
UpdateSitesText() UpdateSitesText()
UpdateGroupsText()
End Set
End Property
Friend Property GroupsEnabled As Boolean
Get
Return TXT_GROUPS.Enabled
End Get
Set(ByVal e As Boolean)
TXT_GROUPS.Enabled = e
End Set
End Property
Friend Property LabelsEnabled As Boolean
Get
Return TXT_LABELS.Enabled
End Get
Set(ByVal e As Boolean)
TXT_LABELS.Enabled = e
End Set End Set
End Property End Property
#End Region #End Region

View File

@@ -35,13 +35,13 @@ Namespace DownloadObjects.Groups
'CONTAINER_MAIN.ContentPanel 'CONTAINER_MAIN.ContentPanel
' '
CONTAINER_MAIN.ContentPanel.Controls.Add(Me.DEFS_GROUP) CONTAINER_MAIN.ContentPanel.Controls.Add(Me.DEFS_GROUP)
CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(476, 328) CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(476, 331)
CONTAINER_MAIN.Dock = System.Windows.Forms.DockStyle.Fill CONTAINER_MAIN.Dock = System.Windows.Forms.DockStyle.Fill
CONTAINER_MAIN.LeftToolStripPanelVisible = False CONTAINER_MAIN.LeftToolStripPanelVisible = False
CONTAINER_MAIN.Location = New System.Drawing.Point(0, 0) CONTAINER_MAIN.Location = New System.Drawing.Point(0, 0)
CONTAINER_MAIN.Name = "CONTAINER_MAIN" CONTAINER_MAIN.Name = "CONTAINER_MAIN"
CONTAINER_MAIN.RightToolStripPanelVisible = False CONTAINER_MAIN.RightToolStripPanelVisible = False
CONTAINER_MAIN.Size = New System.Drawing.Size(476, 328) CONTAINER_MAIN.Size = New System.Drawing.Size(476, 356)
CONTAINER_MAIN.TabIndex = 0 CONTAINER_MAIN.TabIndex = 0
CONTAINER_MAIN.TopToolStripPanelVisible = False CONTAINER_MAIN.TopToolStripPanelVisible = False
' '
@@ -53,7 +53,7 @@ Namespace DownloadObjects.Groups
Me.DEFS_GROUP.Dock = System.Windows.Forms.DockStyle.Fill Me.DEFS_GROUP.Dock = System.Windows.Forms.DockStyle.Fill
Me.DEFS_GROUP.Location = New System.Drawing.Point(0, 0) Me.DEFS_GROUP.Location = New System.Drawing.Point(0, 0)
Me.DEFS_GROUP.Name = "DEFS_GROUP" Me.DEFS_GROUP.Name = "DEFS_GROUP"
Me.DEFS_GROUP.RowCount = 13 Me.DEFS_GROUP.RowCount = 14
Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 0!)) Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 0!))
Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
@@ -66,23 +66,24 @@ Namespace DownloadObjects.Groups
Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
Me.DEFS_GROUP.Size = New System.Drawing.Size(476, 328) Me.DEFS_GROUP.Size = New System.Drawing.Size(476, 331)
Me.DEFS_GROUP.TabIndex = 0 Me.DEFS_GROUP.TabIndex = 0
' '
'GroupEditorForm 'GroupEditorForm
' '
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!) Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(476, 328) Me.ClientSize = New System.Drawing.Size(476, 356)
Me.Controls.Add(CONTAINER_MAIN) Me.Controls.Add(CONTAINER_MAIN)
Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle
Me.Icon = Global.SCrawler.My.Resources.Resources.GroupByIcon_16 Me.Icon = Global.SCrawler.My.Resources.Resources.GroupByIcon_16
Me.KeyPreview = True Me.KeyPreview = True
Me.MaximizeBox = False Me.MaximizeBox = False
Me.MaximumSize = New System.Drawing.Size(492, 367) Me.MaximumSize = New System.Drawing.Size(492, 395)
Me.MinimizeBox = False Me.MinimizeBox = False
Me.MinimumSize = New System.Drawing.Size(492, 367) Me.MinimumSize = New System.Drawing.Size(492, 395)
Me.Name = "GroupEditorForm" Me.Name = "GroupEditorForm"
Me.ShowInTaskbar = False Me.ShowInTaskbar = False
Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide

View File

@@ -78,6 +78,8 @@ Namespace DownloadObjects.Groups
.MyFieldsChecker.EndLoaderOperations() .MyFieldsChecker.EndLoaderOperations()
.EndLoaderOperations() .EndLoaderOperations()
.MyOkCancel.EnableOK = True .MyOkCancel.EnableOK = True
If Settings.Labels.Count = 0 Then DEFS_GROUP.LabelsEnabled = False
If Settings.Groups.Count = 0 Then DEFS_GROUP.GroupsEnabled = False
End With End With
End Sub End Sub
Private Sub GroupEditorForm_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown Private Sub GroupEditorForm_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown

View File

@@ -311,28 +311,15 @@ Namespace DownloadObjects.Groups
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))) : n = $"F {Settings.Groups(i).Name}" If i >= 0 Then users.ListAddList(DownloadGroup.GetUsers(Settings.Groups(i)), LAP.IgnoreICopier) : 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)
users.ListAddList(DownloadGroup.GetUsers(.Self), LAP.IgnoreICopier)
n = .Name
If TypeOf .Self Is AutoDownloader Then If TypeOf .Self Is AutoDownloader Then
With DirectCast(.Self, AutoDownloader) n = $"S {n}"
If Not .Mode = AutoDownloader.Modes.None Then
If .Mode = AutoDownloader.Modes.Groups Then
If .Groups.Count > 0 Then
For Each groupName$ In .Groups
i = Settings.Groups.IndexOf(groupName)
If i >= 0 Then users.ListAddList(DownloadGroup.GetUsers(Settings.Groups(i)), LAP.NotContainsOnly, LAP.IgnoreICopier)
Next
End If
Else
users.ListAddList(DownloadGroup.GetUsers(.Self))
End If
End If
n = $"S { .Name}"
End With
ElseIf TypeOf .Self Is DownloadGroup Then ElseIf TypeOf .Self Is DownloadGroup Then
i = Settings.Groups.IndexOf(.Name, .IsViewFilter) n = $"G {n}"
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

View File

@@ -16,6 +16,9 @@ Namespace DownloadObjects.Groups
Property LabelsExcludedIgnore As Boolean Property LabelsExcludedIgnore As Boolean
ReadOnly Property Sites As List(Of String) ReadOnly Property Sites As List(Of String)
ReadOnly Property SitesExcluded As List(Of String) ReadOnly Property SitesExcluded As List(Of String)
ReadOnly Property Groups As List(Of String)
ReadOnly Property GroupsExcluded As List(Of String)
Property GroupsOnly As Boolean
Property Regular As Boolean Property Regular As Boolean
Property Temporary As Boolean Property Temporary As Boolean
Property Favorite As Boolean Property Favorite As Boolean
@@ -56,6 +59,9 @@ Namespace DownloadObjects.Groups
Protected Const Name_LabelsExcludedIgnore As String = "LabelsExcludedIgnore" Protected Const Name_LabelsExcludedIgnore As String = "LabelsExcludedIgnore"
Protected Const Name_Sites As String = "Sites" Protected Const Name_Sites As String = "Sites"
Protected Const Name_Sites_Excluded As String = "SitesExcluded" Protected Const Name_Sites_Excluded As String = "SitesExcluded"
Protected Const Name_Groups As String = "Groups"
Protected Const Name_GroupsExcluded As String = "GroupsExcluded"
Protected Const Name_GroupsOnly As String = "GroupsOnly"
Protected Const Name_DaysNumber As String = "DaysNumber" Protected Const Name_DaysNumber As String = "DaysNumber"
Protected Const Name_DaysIsDownloaded As String = "DaysIsDownloaded" Protected Const Name_DaysIsDownloaded As String = "DaysIsDownloaded"
Protected Const Name_UserDeleted As String = "UserDeleted" Protected Const Name_UserDeleted As String = "UserDeleted"
@@ -74,6 +80,9 @@ Namespace DownloadObjects.Groups
Friend Property LabelsExcludedIgnore As Boolean = False Implements IGroup.LabelsExcludedIgnore Friend Property LabelsExcludedIgnore As Boolean = False Implements IGroup.LabelsExcludedIgnore
Friend ReadOnly Property Sites As List(Of String) Implements IGroup.Sites Friend ReadOnly Property Sites As List(Of String) Implements IGroup.Sites
Friend ReadOnly Property SitesExcluded As List(Of String) Implements IGroup.SitesExcluded Friend ReadOnly Property SitesExcluded As List(Of String) Implements IGroup.SitesExcluded
Friend ReadOnly Property Groups As List(Of String) Implements IGroup.Groups
Friend ReadOnly Property GroupsExcluded As List(Of String) Implements IGroup.GroupsExcluded
Friend Property GroupsOnly As Boolean = False Implements IGroup.GroupsOnly
Friend Property Regular As Boolean = True Implements IGroup.Regular Friend Property Regular As Boolean = True Implements IGroup.Regular
Friend Property Temporary As Boolean = True Implements IGroup.Temporary Friend Property Temporary As Boolean = True Implements IGroup.Temporary
Friend Property Favorite As Boolean = True Implements IGroup.Favorite Friend Property Favorite As Boolean = True Implements IGroup.Favorite
@@ -98,6 +107,8 @@ Namespace DownloadObjects.Groups
LabelsExcluded = New List(Of String) LabelsExcluded = New List(Of String)
Sites = New List(Of String) Sites = New List(Of String)
SitesExcluded = New List(Of String) SitesExcluded = New List(Of String)
Groups = New List(Of String)
GroupsExcluded = New List(Of String)
End Sub End Sub
#End Region #End Region
#Region "Base functions" #Region "Base functions"
@@ -121,6 +132,9 @@ Namespace DownloadObjects.Groups
LabelsExcludedIgnore = .LabelsExcludedIgnore LabelsExcludedIgnore = .LabelsExcludedIgnore
Sites.ListAddList(.Sites, LAP.ClearBeforeAdd) Sites.ListAddList(.Sites, LAP.ClearBeforeAdd)
SitesExcluded.ListAddList(.SitesExcluded, LAP.ClearBeforeAdd) SitesExcluded.ListAddList(.SitesExcluded, LAP.ClearBeforeAdd)
Groups.ListAddList(.Groups, LAP.ClearBeforeAdd)
GroupsExcluded.ListAddList(.GroupsExcluded, LAP.ClearBeforeAdd)
GroupsOnly = .GroupsOnly
Regular = .Regular Regular = .Regular
Temporary = .Temporary Temporary = .Temporary
Favorite = .Favorite Favorite = .Favorite
@@ -153,6 +167,9 @@ Namespace DownloadObjects.Groups
LabelsExcludedIgnore = e.Value(Name_LabelsExcludedIgnore).FromXML(Of Boolean)(False) LabelsExcludedIgnore = e.Value(Name_LabelsExcludedIgnore).FromXML(Of Boolean)(False)
If Not e.Value(Name_Sites).IsEmptyString Then Sites.ListAddList(e.Value(Name_Sites).Split("|"), l) If Not e.Value(Name_Sites).IsEmptyString Then Sites.ListAddList(e.Value(Name_Sites).Split("|"), l)
If Not e.Value(Name_Sites_Excluded).IsEmptyString Then SitesExcluded.ListAddList(e.Value(Name_Sites_Excluded).Split("|"), l) If Not e.Value(Name_Sites_Excluded).IsEmptyString Then SitesExcluded.ListAddList(e.Value(Name_Sites_Excluded).Split("|"), l)
If Not e.Value(Name_Groups).IsEmptyString Then Groups.ListAddList(e.Value(Name_Groups).Split("|"), l)
If Not e.Value(Name_GroupsExcluded).IsEmptyString Then GroupsExcluded.ListAddList(e.Value(Name_GroupsExcluded).Split("|"), l)
GroupsOnly = e.Value(Name_GroupsOnly).FromXML(Of Boolean)(False)
Regular = e.Value(Name_Regular).FromXML(Of Boolean)(True) Regular = e.Value(Name_Regular).FromXML(Of Boolean)(True)
Temporary = e.Value(Name_Temporary).FromXML(Of Boolean)(True) Temporary = e.Value(Name_Temporary).FromXML(Of Boolean)(True)
@@ -190,6 +207,9 @@ Namespace DownloadObjects.Groups
New EContainer(Name_LabelsExcludedIgnore, LabelsExcludedIgnore.BoolToInteger), New EContainer(Name_LabelsExcludedIgnore, LabelsExcludedIgnore.BoolToInteger),
New EContainer(Name_Sites, Sites.ListToString("|")), New EContainer(Name_Sites, Sites.ListToString("|")),
New EContainer(Name_Sites_Excluded, SitesExcluded.ListToString("|")), New EContainer(Name_Sites_Excluded, SitesExcluded.ListToString("|")),
New EContainer(Name_Groups, Groups.ListToString("|")),
New EContainer(Name_GroupsExcluded, GroupsExcluded.ListToString("|")),
New EContainer(Name_GroupsOnly, GroupsOnly.BoolToInteger),
New EContainer(Name_Regular, Regular.BoolToInteger), New EContainer(Name_Regular, Regular.BoolToInteger),
New EContainer(Name_Temporary, Temporary.BoolToInteger), New EContainer(Name_Temporary, Temporary.BoolToInteger),
New EContainer(Name_Favorite, Favorite.BoolToInteger), New EContainer(Name_Favorite, Favorite.BoolToInteger),
@@ -219,6 +239,8 @@ Namespace DownloadObjects.Groups
LabelsExcluded.Clear() LabelsExcluded.Clear()
Sites.Clear() Sites.Clear()
SitesExcluded.Clear() SitesExcluded.Clear()
Groups.Clear()
GroupsExcluded.Clear()
End If End If
disposedValue = True disposedValue = True
End If End If

View File

@@ -368,7 +368,7 @@ Partial Public Class MainFrame : Inherits System.Windows.Forms.Form
Me.BTT_FEED.Name = "BTT_FEED" Me.BTT_FEED.Name = "BTT_FEED"
Me.BTT_FEED.Size = New System.Drawing.Size(52, 22) Me.BTT_FEED.Size = New System.Drawing.Size(52, 22)
Me.BTT_FEED.Text = "Feed" Me.BTT_FEED.Text = "Feed"
Me.BTT_FEED.ToolTipText = "Feed of recently downloaded data (Ctrl+F)" Me.BTT_FEED.ToolTipText = "Feed of recently downloaded data (Alt+F)"
' '
'BTT_CHANNELS 'BTT_CHANNELS
' '

View File

@@ -184,36 +184,37 @@
<data name="MENU_VIEW.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> <data name="MENU_VIEW.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value> <value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABkSURBVDhPY6AKyO86WFDQfeg/iIYKkQZAmkNbnvyXta76 YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABkSURBVDhPY2CgBsjvOlhQ0H3oP4hGlyMKgDSHtjz5L2td
DxViYGFi+Y8PQ5VBAMhmkGYgJs8FAw9GA5EKILFiWUFixfL/IBoqRBoAafYsOvpf0jiTvEAE2QzSLGmU 9R8mxsLE8h8fRjEAZDNIs6x1FXkuGHgwGohUAIkVywoSK5b/B9HockQBkGbPoqP/JY0zyQtEkM0gzZJG
MeQCkYEBAD3tUdo+/cEPAAAAAElFTkSuQmCC GeS5YEABAD3tUdqXHMg6AAAAAElFTkSuQmCC
</value> </value>
</data> </data>
<data name="BTT_LOG.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> <data name="BTT_LOG.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value> <value>
iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFmSURBVFhH1dc/K4VhHMbxJ5EFEQbFiERKCotIrMJIiYEi YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGTSURBVFhH1ZfPK21RGIaf5GaCCAPF0JVISWEiElNhSIkB
pbwCZcOqJC9AikUWiqRkJYtSRDbESMT3V07dna7zHHru+9T51me+Ts//E+V7LRjFFAZRiZzUhDVc4/vX RUr5C5QZpkryB0gxkQlFUjKlO1HKjcwQQyJatdXp7TtnH3t/Z+CpZ7be7z3tH2uvA7+cFmAUmAIGgSpd
B47Rh6D14Aqp4XQ36ECQ2nALNezaQjG8Vo5DqMF0bxiA1+bwCTWoLMFbNTiDGsrkABXw0jDsKldDmdyj UCiagDXgCviMfAOOgT5d7E0P8C+jWL0GOjTkRRtwY5SqW0CJhtNSARwaZZYvwIAOSMsc8G6UZXNJB6Sh
HokrwCrUSBz7wXbRJs4eLkdQI9m0I3ENeIAaiGN3QjMSZ4fxv+ffnKIKibOnmhqI84V5eMleOHY41VAm FjgzSnJ5AFTqoKQMR0+5luTyFmjQQUkoAlaNgjjDDw4PbWrC5nJkFORjuw5Lwl/gzhgeZ3gTmnVYEsJl
9k7wdgtW4wRqSHlCP7y2AjWmbMB7Y7DzqgZdz2iF9zrxCDXq2oU9uLz31+tgAcHahhp1DSFY9pGhRl29 /On9D54C1TosCWFX0+FxfgDzOigp4YMTLqeW5DJ8E9xewRrgxCjJ5gPQr0PSsmIUZXNDwx6MRfdVy9RH
CFYXxrMoQ7BmsZfFPkoRpHWow+56hX26BWkRatR1gRIEaQLvUMMpOyhCkBpxBzWcMoOgLUMNm0vUIWj2 oFXDHnQC90ahuhttXO7k+xwsaNCTbaNQHdKQJ+GQoYVqr4Y86QLGYyzXkCezwF6M+0CZBr1YNy65+hwd
ebaJF7jj5+hGTiqE/f+bxDRGUIt8LIp+AC/GHt3tQnwvAAAAAElFTkSuQmCC 3QrColGoXgClGvRiAng1SjPdAf5o0ItG4L9RmumMhrxZNkq/vQTqNeBNOJ5tAk9Sfg506+JCURz9/5sE
poERoE4X/Rq+AC/GHt09Rk0KAAAAAElFTkSuQmCC
</value> </value>
</data> </data>
<data name="BTT_BUG_REPORT.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> <data name="BTT_BUG_REPORT.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value> <value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIFSURBVDhPpZLtS1NhGMbPPxJmmlYSgqHiKzGU1EDxg4iK
YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9 YKyG2WBogqMYJQOtCEVRFBGdTBCJfRnkS4VaaWNT5sqx1BUxRXxDHYxAJLvkusEeBaPAB+5z4Jzn+t3X
0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw /aLhnEfjo8m+dCoa+7/C3O2Hqe0zDC+8KG+cRZHZhdzaaWTVTCLDMIY0vfM04Nfh77/G/sEhwpEDbO3t
bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc I7TxE8urEVy99fT/AL5gWDLrTB/hnF4XsW0khCu5ln8DmJliT2AXrcNBsU1gj/MH4nMeKwBrPktM28xM
VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9 cX79DFKrHHD5d9D26hvicx4pABt2lpg10zYzU0zr7+e3xXGcrkEB2O2TNec9nJFwB3alZn5jZorfeDZh
c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32 6Q3g8s06BeCoKF4MRURoH1+BY2oNCbeb0TIclIYxOhzf8frTOuo7FxCbbVIAzpni0iceEc8vhzEwGkJD
Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo lx83ymxifejdKjRNk/8PWnyIyTQqAJek0jqHwfEVscu31baIu8+90sTE4nY025dQ2/5FIPpnXlzKuK8A
mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ HBUzHot52djqQ6HZhfR7IwK4mKpHtvEDMqvfCiQ6zaAAXM8x94aIWTNrLLG4kVUzgaTSPlzLtyJOZxbb
kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D 1wtfyg4Q+AfA3aZlButjSfxGcUJBk4g5tuP3haQKRKXcUQDOmbvNTpPOJeFFjordZmbWTNvMTHFUcpUC
TgDQASA1MVpwzwAAAABJRU5ErkJggg== nOccAdABIDXXE1nzAAAAAElFTkSuQmCC
</value> </value>
</data> </data>
<metadata name="Toolbar_BOTTOM.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <metadata name="Toolbar_BOTTOM.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">

View File

@@ -801,29 +801,6 @@ CloseResume:
f.ShowDialog() f.ShowDialog()
If f.DialogResult = DialogResult.OK Then If f.DialogResult = DialogResult.OK Then
Dim filter As GroupParameters = f.FilterSelected Dim filter As GroupParameters = f.FilterSelected
If Not filter Is Nothing AndAlso TypeOf filter Is AutoDownloader Then
With DirectCast(filter, AutoDownloader)
If .Mode = AutoDownloader.Modes.Groups Then
If .Groups.Count = 0 Then
MsgBoxE({"The scheduler plan you select doesn't contain any group!", msgTitle}, vbCritical)
Exit Sub
ElseIf .Groups.Count > 1 Then
MsgBoxE({"The scheduler plan you select contains more than one group." & vbCr &
"You need to choose a plan with one group or without groups!", msgTitle}, vbCritical)
Exit Sub
Else
Dim i% = Settings.Groups.IndexOf(.Groups(0))
If i >= 0 Then
filter = Settings.Groups(i).Copy
Else
MsgBoxE({$"A group named '{ .Groups(0)}' cannot be found in existing groups.", msgTitle}, vbCritical)
filter = Nothing
Exit Sub
End If
End If
End If
End With
End If
If Not filter Is Nothing Then If Not filter Is Nothing Then
If filter.IsViewFilter Then If filter.IsViewFilter Then
With DirectCast(filter, DownloadGroup) With DirectCast(filter, DownloadGroup)

View File

@@ -13,7 +13,7 @@ Imports System.Runtime.InteropServices
<Assembly: AssemblyDescription("Social networks media downloader")> <Assembly: AssemblyDescription("Social networks media downloader")>
<Assembly: AssemblyCompany("AndyProgram")> <Assembly: AssemblyCompany("AndyProgram")>
<Assembly: AssemblyProduct("SCrawler")> <Assembly: AssemblyProduct("SCrawler")>
<Assembly: AssemblyCopyright("Copyright © 2025")> <Assembly: AssemblyCopyright("Copyright © 2026")>
<Assembly: AssemblyTrademark("AndyProgram")> <Assembly: AssemblyTrademark("AndyProgram")>
<Assembly: ComVisible(False)> <Assembly: ComVisible(False)>
@@ -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("2025.10.4.0")> <Assembly: AssemblyVersion("2026.1.17.0")>
<Assembly: AssemblyFileVersion("2025.10.4.0")> <Assembly: AssemblyFileVersion("2026.1.17.0")>
<Assembly: NeutralResourcesLanguage("en")> <Assembly: NeutralResourcesLanguage("en")>

View File

@@ -255,6 +255,7 @@
<Compile Include="API\ThisVid\SiteSettings.vb" /> <Compile Include="API\ThisVid\SiteSettings.vb" />
<Compile Include="API\ThisVid\UserData.vb" /> <Compile Include="API\ThisVid\UserData.vb" />
<Compile Include="API\ThisVid\UserExchangeOptions.vb" /> <Compile Include="API\ThisVid\UserExchangeOptions.vb" />
<Compile Include="API\ThreadsNet\Declarations.vb" />
<Compile Include="API\ThreadsNet\SiteSettings.vb" /> <Compile Include="API\ThreadsNet\SiteSettings.vb" />
<Compile Include="API\ThreadsNet\UserData.vb" /> <Compile Include="API\ThreadsNet\UserData.vb" />
<Compile Include="API\TikTok\Declarations.vb" /> <Compile Include="API\TikTok\Declarations.vb" />