diff --git a/Changelog.md b/Changelog.md index d9b20fc..0e8875a 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,11 +2,40 @@ - [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`** - 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** -- [YT-DLP](https://github.com/AAndyProgram/SCrawler/wiki/Settings#yt-dlp) - **2025.09.26** +- [Gallery-dl](https://github.com/AAndyProgram/SCrawler/wiki/Settings#gallery-dl) - **1.30.10** +- [YT-DLP](https://github.com/AAndyProgram/SCrawler/wiki/Settings#yt-dlp) - **2025.11.12** +- [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)) # 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-04* diff --git a/Plugins.md b/Plugins.md index 07d3320..1181bb0 100644 --- a/Plugins.md +++ b/Plugins.md @@ -7,4 +7,5 @@ If you've created a plugin, you can create a [new issue](https://github.com/AAnd List of available plugins: Tools: -- [image2post](https://github.com/unknown81311/SCrawler-image2post) by @unknown81311: **get reddit post URL from file.** \ No newline at end of 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** \ No newline at end of file diff --git a/ProgramScreenshots/FeedWindowSessionContext.png b/ProgramScreenshots/FeedWindowSessionContext.png index b2264f1..5f0e851 100644 Binary files a/ProgramScreenshots/FeedWindowSessionContext.png and b/ProgramScreenshots/FeedWindowSessionContext.png differ diff --git a/ProgramScreenshots/GroupCreating.png b/ProgramScreenshots/GroupCreating.png index 27d36aa..6363f76 100644 Binary files a/ProgramScreenshots/GroupCreating.png and b/ProgramScreenshots/GroupCreating.png differ diff --git a/ProgramScreenshots/SavedPosts.png b/ProgramScreenshots/SavedPosts.png index 1bf4df2..2eb81ad 100644 Binary files a/ProgramScreenshots/SavedPosts.png and b/ProgramScreenshots/SavedPosts.png differ diff --git a/ProgramScreenshots/SettingsAutoDownloader.png b/ProgramScreenshots/SettingsAutoDownloader.png index 462634f..24e5dab 100644 Binary files a/ProgramScreenshots/SettingsAutoDownloader.png and b/ProgramScreenshots/SettingsAutoDownloader.png differ diff --git a/ProgramScreenshots/SettingsSiteBluesky.png b/ProgramScreenshots/SettingsSiteBluesky.png index 283ac2f..4bbf136 100644 Binary files a/ProgramScreenshots/SettingsSiteBluesky.png and b/ProgramScreenshots/SettingsSiteBluesky.png differ diff --git a/ProgramScreenshots/SettingsSiteOnlyFans.png b/ProgramScreenshots/SettingsSiteOnlyFans.png index e6fb3b5..743a58d 100644 Binary files a/ProgramScreenshots/SettingsSiteOnlyFans.png and b/ProgramScreenshots/SettingsSiteOnlyFans.png differ diff --git a/ProgramScreenshots/SettingsSiteReddit.png b/ProgramScreenshots/SettingsSiteReddit.png index e4fb7bc..8bdc714 100644 Binary files a/ProgramScreenshots/SettingsSiteReddit.png and b/ProgramScreenshots/SettingsSiteReddit.png differ diff --git a/ProgramScreenshots/SettingsSiteThreads.png b/ProgramScreenshots/SettingsSiteThreads.png index 773bd60..26ead59 100644 Binary files a/ProgramScreenshots/SettingsSiteThreads.png and b/ProgramScreenshots/SettingsSiteThreads.png differ diff --git a/ProgramScreenshots/SettingsSiteTikTok.png b/ProgramScreenshots/SettingsSiteTikTok.png index 3aa48b6..f3b96e5 100644 Binary files a/ProgramScreenshots/SettingsSiteTikTok.png and b/ProgramScreenshots/SettingsSiteTikTok.png differ diff --git a/ProgramScreenshots/SettingsSiteTwitter.png b/ProgramScreenshots/SettingsSiteTwitter.png index 2a62595..98d1fa5 100644 Binary files a/ProgramScreenshots/SettingsSiteTwitter.png and b/ProgramScreenshots/SettingsSiteTwitter.png differ diff --git a/ProgramScreenshots/SettingsTwitterUser.png b/ProgramScreenshots/SettingsTwitterUser.png index d6c770d..d6814fe 100644 Binary files a/ProgramScreenshots/SettingsTwitterUser.png and b/ProgramScreenshots/SettingsTwitterUser.png differ diff --git a/README.md b/README.md index e63eae8..c606baf 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ + # 🏳️‍🌈 Social networks crawler 🏳️‍🌈 [![GitHub release (latest by date)](https://img.shields.io/github/v/release/AAndyProgram/SCrawler)](https://github.com/AAndyProgram/SCrawler/releases/latest) diff --git a/SCrawler.YouTube/Base/YouTubeSettings.vb b/SCrawler.YouTube/Base/YouTubeSettings.vb index 87d17a1..5096951 100644 --- a/SCrawler.YouTube/Base/YouTubeSettings.vb +++ b/SCrawler.YouTube/Base/YouTubeSettings.vb @@ -501,6 +501,9 @@ Namespace API.YouTube.Base 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.")> Public ReadOnly Property DefaultSubtitlesFormatAddit As XMLValuesCollection(Of String) + + Public ReadOnly Property DefaultSubtitlesEmbed As XMLValue(Of Boolean) #End Region #Region "Trim" - + @@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices ' by using the '*' as shown below: ' - - + + diff --git a/SCrawler.YouTube/Objects/YouTubeMediaContainerBase.vb b/SCrawler.YouTube/Objects/YouTubeMediaContainerBase.vb index 392077b..fe54719 100644 --- a/SCrawler.YouTube/Objects/YouTubeMediaContainerBase.vb +++ b/SCrawler.YouTube/Objects/YouTubeMediaContainerBase.vb @@ -827,6 +827,7 @@ Namespace API.YouTube.Objects subs = ListAddList(Nothing, Subtitles.Select(Function(s, i) If(SubtitlesSelectedIndexes.Contains(i), s.FullID, String.Empty)), LAP.NotContainsOnly, EDP.ReturnValue).ListToString(",") 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 If Not cmd.IsEmptyString Then '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}""" Dim trimFirstFile As SFile = Nothing Dim trimFirstAdded As Boolean = False - Dim processTrim As Action(Of TrimOption, SFile) = - Sub(ByVal opt As TrimOption, ByVal pFile As SFile) + Dim trimSingleReplace As Boolean = TrimOptions.Count = 1 And TrimDeleteOriginalFile + 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 fNew.Name &= $"_{opt.Name}" 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)) If fNew.Exists Then 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 _ 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 (format = mp3 AndAlso MyYouTubeSettings.VideoPlaylist_AddExtractedMP3.Value)) Then _ M3U8_Append(fNew) : trimFirstAdded = True End If End Sub For Each tr As TrimOption In TrimOptions - processTrim(tr, File) + processTrim(tr, File, False) 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 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 diff --git a/SCrawler.YouTubeDownloader/My Project/AssemblyInfo.vb b/SCrawler.YouTubeDownloader/My Project/AssemblyInfo.vb index 11d7297..7e74c66 100644 --- a/SCrawler.YouTubeDownloader/My Project/AssemblyInfo.vb +++ b/SCrawler.YouTubeDownloader/My Project/AssemblyInfo.vb @@ -13,7 +13,7 @@ Imports System.Runtime.InteropServices - + @@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices ' by using the '*' as shown below: ' - - + + diff --git a/SCrawler/API/Base/GDL.vb b/SCrawler/API/Base/GDL.vb index 0fbf7eb..698b9aa 100644 --- a/SCrawler/API/Base/GDL.vb +++ b/SCrawler/API/Base/GDL.vb @@ -10,10 +10,8 @@ Namespace API.Base.GDL Friend Class GDLBatch : Inherits TokenBatch Friend Const UrlLibStart As String = "[urllib3.connectionpool][debug]" Friend Const UrlTextStart As String = UrlLibStart & " https" - Friend Sub New(ByVal _Token As Threading.CancellationToken) - MyBase.New(_Token) - MainProcessName = "gallery-dl" - ChangeDirectory(Settings.GalleryDLFile.File) + Friend Sub New(ByVal _Token As Threading.CancellationToken, Optional ByVal __MainProcessName As String = Nothing, Optional ByVal WorkingDir As SFile = Nothing) + MyBase.New(_Token, __MainProcessName.IfNullOrEmpty(Settings.GalleryDLFile.File.Name), WorkingDir.IfNullOrEmpty(Settings.GalleryDLFile.File)) End Sub Protected Overrides Async Sub OutputDataReceiver(ByVal Sender As Object, ByVal e As DataReceivedEventArgs) If Not ProcessKilled Then diff --git a/SCrawler/API/Base/Structures.vb b/SCrawler/API/Base/Structures.vb index c8257e5..02525df 100644 --- a/SCrawler/API/Base/Structures.vb +++ b/SCrawler/API/Base/Structures.vb @@ -58,6 +58,11 @@ Namespace API.Base Return Type = Types.Audio Or Type = Types.AudioPre End Get 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 As String Friend MD5 As String diff --git a/SCrawler/API/Base/TokenBatch.vb b/SCrawler/API/Base/TokenBatch.vb index dac7090..9cf0332 100644 --- a/SCrawler/API/Base/TokenBatch.vb +++ b/SCrawler/API/Base/TokenBatch.vb @@ -13,10 +13,16 @@ Namespace API.Base Friend Property TempPostsList As List(Of String) Protected ReadOnly Token As CancellationToken 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) Token = _Token + MainProcessName = _MainProcessName + If Not WorkingDir.IsEmptyString Then ChangeDirectory(WorkingDir) 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() If TempPostsList Is Nothing Then TempPostsList = New List(Of String) MyBase.Create() diff --git a/SCrawler/API/Base/YTDLP.vb b/SCrawler/API/Base/YTDLP.vb index de95702..36bae23 100644 --- a/SCrawler/API/Base/YTDLP.vb +++ b/SCrawler/API/Base/YTDLP.vb @@ -8,11 +8,8 @@ ' but WITHOUT ANY WARRANTY Namespace API.Base.YTDLP Friend Class YTDLPBatch : Inherits GDL.GDLBatch - Friend Sub New(ByVal _Token As Threading.CancellationToken) - MyBase.New(_Token) - Commands.Clear() - MainProcessName = Settings.YtdlpFile.File.Name '"yt-dlp" - ChangeDirectory(Settings.YtdlpFile.File) + Friend Sub New(ByVal _Token As Threading.CancellationToken, Optional ByVal __MainProcessName As String = Nothing, Optional ByVal WorkingDir As SFile = Nothing) + MyBase.New(_Token, __MainProcessName.IfNullOrEmpty(Settings.YtdlpFile.File.Name), WorkingDir.IfNullOrEmpty(Settings.YtdlpFile.File)) End Sub End Class End Namespace \ No newline at end of file diff --git a/SCrawler/API/TikTok/SiteSettings.vb b/SCrawler/API/TikTok/SiteSettings.vb index f09c111..29fef64 100644 --- a/SCrawler/API/TikTok/SiteSettings.vb +++ b/SCrawler/API/TikTok/SiteSettings.vb @@ -43,9 +43,6 @@ Namespace API.TikTok Friend ReadOnly Property UseParsedVideoDateSTD As PropertyValue - Friend Overrides Property DownloadText As PropertyValue - Friend Overrides Property DownloadTextPosts As PropertyValue - Friend Overrides Property DownloadTextSpecialFolder As PropertyValue 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) diff --git a/SCrawler/API/TikTok/UserData.vb b/SCrawler/API/TikTok/UserData.vb index 4fffeba..65bd2db 100644 --- a/SCrawler/API/TikTok/UserData.vb +++ b/SCrawler/API/TikTok/UserData.vb @@ -73,6 +73,7 @@ Namespace API.TikTok Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object) If Not Obj Is Nothing AndAlso TypeOf Obj Is UserExchangeOptions Then With DirectCast(Obj, UserExchangeOptions) + .ApplyBase(Me) RemoveTagsFromTitle = .RemoveTagsFromTitle TitleUseNative = .TitleUseNative TitleAddVideoID = .TitleAddVideoID @@ -175,7 +176,7 @@ Namespace API.TikTok UserCache = CreateCache() Try Const photoPrefix$ = "photo_" - Dim postID$, title$, postUrl$, newName$, t$, postID2$, imgUrl$ + Dim postID$, title$, postUrl$, newName$, t$, postID2$, imgUrl$, pText$ Dim postDate As Date? Dim dateAfterC As Date? = Nothing Dim dateBefore As Date? = DownloadDateTo @@ -216,17 +217,14 @@ Namespace API.TikTok If DownloadVideos And Settings.YtdlpFile.Exists And CBool(MySettings.DownloadTTVideos.Value) Then With UserCache.NewInstance : .Validate() : vPath = .RootDirectory : End With - Using b As New YTDLP.YTDLPBatch(Token) With {.TempPostsList = _TempPostsList} - b.Commands.Clear() - b.ChangeDirectory(vPath) - b.Encoding = BatchExecutor.UnicodeEncoding + Using b As New YTDLP.YTDLPBatch(Token,, vPath) With {.TempPostsList = _TempPostsList} b.Execute(CreateYTCommand(vPath, URL, False, dateBefore, dateAfter)) End Using End If If DownloadImages And Settings.GalleryDLFile.Exists And CBool(MySettings.DownloadTTPhotos.Value) Then 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 If PhotosDownloaded And _TempPostsList.Count > 0 Then .TempPostsList = (From p As String In _TempPostsList @@ -235,8 +233,6 @@ Namespace API.TikTok Else .TempPostsList = New List(Of String) End If - .ChangeDirectory(pPath) - .Encoding = BatchExecutor.UnicodeEncoding .Execute(CreateGDLCommand(URL)) If Not PhotosDownloaded Then _ForceSaveUserInfo = True : _ForceSaveUserInfoOnException = True PhotosDownloaded = True @@ -270,6 +266,8 @@ Namespace API.TikTok End If title = GetNewFileName(j.Value("title").StringRemoveWinForbiddenSymbols, 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) If Not postDate.HasValue Then postDate = AConvert(Of Date)(j.Value("upload_date"), SimpleDateConverter, Nothing) Select Case CheckDatesLimit(postDate, SimpleDateConverter) @@ -280,7 +278,12 @@ Namespace API.TikTok postUrl = j.Value("webpage_url") If postUrl.IsEmptyString Then postUrl = $"https://www.tiktok.com/@{Name}/video/{postID}" _TempMediaList.Add(New UserMedia(postUrl, UTypes.Video) With { - .File = $"{title}.mp4", .Post = New UserPost(postID, postDate)}) + .File = $"{title}.mp4", + .Post = New UserPost(postID, postDate), + .PostText = pText, + .PostTextFileSpecialFolder = DownloadTextSpecialFolder, + .PostTextFile = $"{ .File.Name}.txt" + }) End If j.Dispose() End If @@ -302,7 +305,7 @@ Namespace API.TikTok 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)(j.Value("createTime"), UnixDate32Provider, Nothing) + postDate = AConvert(Of Date)(.Value("createTime"), UnixDate32Provider, Nothing) Select Case CheckDatesLimit(postDate, SimpleDateConverter) Case DateResult.Skip : Continue For Case DateResult.Exit : Exit For 'Exit Sub @@ -330,8 +333,10 @@ Namespace API.TikTok End With End If - title = GetNewFileName(j.Value({"imagePost"}, "title").StringRemoveWinForbiddenSymbols, + 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 @@ -346,7 +351,11 @@ Namespace API.TikTok .URL_BASE = postUrl, .SpecialFolder = "Photo", .File = $"{title}{IIf(c > 1, $"_{i.NumToString(ANumbers.Formats.NumberGroup, cc)}", String.Empty)}.jpg", - .Post = New UserPost(postID, postDate)}) + .Post = New UserPost(postID, postDate), + .PostText = pText, + .PostTextFileSpecialFolder = DownloadTextSpecialFolder, + .PostTextFile = $"{ .File.Name}.txt" + }) Next End If End With @@ -456,7 +465,6 @@ Namespace API.TikTok End Function 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} - b.Encoding = BatchExecutor.UnicodeEncoding b.Execute(CreateYTCommand(DestinationFile, URL, True)) End Using If DestinationFile.Exists Then Return DestinationFile Else Return Nothing @@ -477,7 +485,6 @@ Namespace API.TikTok t = UTypes.Video If CBool(MySettings.TitleUseNativeSTD.Value) Then Using b As New BatchExecutor(True) With { - .Encoding = BatchExecutor.UnicodeEncoding, .CleanAutomaticallyViaRegEx = True, .CleanAutomaticallyViaRegExRemoveAllCommands = True } @@ -498,11 +505,7 @@ Namespace API.TikTok Data.Title = defName Dim dir As SFile With If(Cache, Settings.Cache).NewInstance() : .Validate() : dir = .RootDirectory : End With - Using b As New GDL.GDLBatch(Token) - b.ChangeDirectory(dir) - b.Encoding = BatchExecutor.UnicodeEncoding - b.Execute(CreateGDLCommand(Data.URL)) - End Using + Using b As New GDL.GDLBatch(Token,, dir) : b.Execute(CreateGDLCommand(Data.URL)) : End Using Dim file As SFile = SFile.GetFiles(dir, "*.txt",, EDP.ReturnValue).FirstOrDefault If file.Exists Then Dim r$ = file.GetText(EDP.ReturnValue) diff --git a/SCrawler/API/TikTok/UserExchangeOptions.vb b/SCrawler/API/TikTok/UserExchangeOptions.vb index 456d0bc..5ec2154 100644 --- a/SCrawler/API/TikTok/UserExchangeOptions.vb +++ b/SCrawler/API/TikTok/UserExchangeOptions.vb @@ -8,7 +8,7 @@ ' but WITHOUT ANY WARRANTY Imports SCrawler.Plugin.Attributes Namespace API.TikTok - Friend Class UserExchangeOptions + Friend Class UserExchangeOptions : Inherits Base.EditorExchangeOptionsBase Friend Property RemoveTagsFromTitle As Boolean @@ -21,8 +21,11 @@ Namespace API.TikTok Friend Property TitleUseRegexForTitle_Value As String Friend Property TitleUseGlobalRegexOptions As Boolean = True + Friend Overrides Property UserName As String Private ReadOnly MySettings As SiteSettings Friend Sub New(ByVal u As UserData) + MyBase.New(u) + _ApplyBase_Name = False MySettings = u.HOST.Source RemoveTagsFromTitle = u.RemoveTagsFromTitle TitleUseNative = u.TitleUseNative @@ -32,6 +35,8 @@ Namespace API.TikTok TitleUseGlobalRegexOptions = u.TitleUseGlobalRegexOptions End Sub Friend Sub New(ByVal s As SiteSettings) + MyBase.New(s) + _ApplyBase_Name = False MySettings = s RemoveTagsFromTitle = s.RemoveTagsFromTitle.Value TitleUseNative = s.TitleUseNative.Value diff --git a/SCrawler/API/Twitter/UserData.vb b/SCrawler/API/Twitter/UserData.vb index 329cae0..aa4387a 100644 --- a/SCrawler/API/Twitter/UserData.vb +++ b/SCrawler/API/Twitter/UserData.vb @@ -533,16 +533,19 @@ Namespace API.Twitter With j({"data", "user", "result"}) If .ListExists Then 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"}) If .ListExists Then - If .Value("screen_name").StringToLower = NameTrue.ToLower Then + If .Value("screen_name").IfNullOrEmpty(tScreenName).StringToLower = NameTrue.ToLower Then UserSiteNameUpdate(.Value("name")) 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 DownloadIconBanner Then - SimpleDownloadAvatar(.Value("profile_banner_url"), fileCrFunc) + SimpleDownloadAvatar(.Value("profile_banner_url").IfNullOrEmpty(.Value({"legacy"}, "profile_banner_url")), fileCrFunc) SimpleDownloadAvatar(icon, fileCrFunc) End If End If @@ -852,9 +855,7 @@ nextpIndx: Private ReadOnly KillOnLimit As Boolean Friend LimitReached As Boolean = False Friend Sub New(ByVal Dir As SFile, ByVal _Token As CancellationToken, ByVal _KillOnLimit As Boolean) - MyBase.New(_Token) - Commands.Clear() - If Not Dir.IsEmptyString Then ChangeDirectory(Dir) + MyBase.New(_Token,, Dir) KillOnLimit = _KillOnLimit End Sub Protected Overrides Async Function Validate(ByVal Value As String) As Task diff --git a/SCrawler/API/Xhamster/SiteSettings.vb b/SCrawler/API/Xhamster/SiteSettings.vb index c54c21e..0eac1f2 100644 --- a/SCrawler/API/Xhamster/SiteSettings.vb +++ b/SCrawler/API/Xhamster/SiteSettings.vb @@ -15,6 +15,7 @@ Namespace API.Xhamster Friend Class SiteSettings : Inherits SiteSettingsBase #Region "Declarations" + Private Const CAT_YTDLP As String = "yt-dlp support" Private ReadOnly Property SiteDomains As PropertyValue Private Shadows ReadOnly Property DefaultInstance As SiteSettings Get @@ -33,6 +34,17 @@ Namespace API.Xhamster 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> Friend ReadOnly Property ReencodeVideos As PropertyValue + + Friend ReadOnly Property UseYTDLPJSON As PropertyValue + + 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 + + Friend ReadOnly Property UseYTDLPForceDisableInternal As PropertyValue Friend Overrides Property DownloadText As PropertyValue Friend Overrides Property DownloadTextPosts As PropertyValue Friend Overrides Property DownloadTextSpecialFolder As PropertyValue @@ -46,12 +58,16 @@ Namespace API.Xhamster Domains.DestinationProp = SiteDomains DownloadUHD = New PropertyValue(False) ReencodeVideos = New PropertyValue(False) + UseYTDLPJSON = New PropertyValue(True) + UseYTDLPDownload = New PropertyValue(True) + UseYTDLPForceDisableInternal = New PropertyValue(False) _SubscriptionsAllowed = True UrlPatternUser = "https://xhamster.com/{0}/{1}" UserRegex = RParams.DMS($"/({UserOption}|{ChannelOption}|{P_Creators})/([^/]+)(\Z|.*)", 0, RegexReturn.ListByMatch) ImageVideoContains = "xhamster" UserOptionsType = GetType(UserExchangeOptions) + UseNetscapeCookies = True End Sub Friend Overrides Sub EndInit() Domains.PopulateInitialDomains(SiteDomains.Value) @@ -75,9 +91,7 @@ Namespace API.Xhamster Return New UserData End Function Friend Overrides Function Available(ByVal What As ISiteSettings.Download, ByVal Silent As Boolean) As Boolean - 'TODELETE: xHamster disabled - Return False - If Settings.UseM3U8 AndAlso MyBase.Available(What, Silent) Then + If (Not UseYtDlp Or (UseYtDlp And Settings.YtdlpFile.Exists)) AndAlso Settings.UseM3U8 AndAlso MyBase.Available(What, Silent) Then If What = ISiteSettings.Download.SavedPosts Then Return Responser.CookiesExists Else @@ -98,7 +112,7 @@ Namespace API.Xhamster End Function #Region "IsMyUser, IsMyImageVideo" Friend Const ChannelOption As String = "channels" - Private Const UserOption As String = "users" + Friend Const UserOption As String = "users/profiles" Friend Const P_Search As String = "search" Friend Const P_Tags As String = "tags" Friend Const P_Categories As String = "categories" diff --git a/SCrawler/API/Xhamster/UserData.vb b/SCrawler/API/Xhamster/UserData.vb index 1bf5601..9ebc33b 100644 --- a/SCrawler/API/Xhamster/UserData.vb +++ b/SCrawler/API/Xhamster/UserData.vb @@ -11,6 +11,7 @@ Imports System.Threading Imports PersonalUtilities.Functions.RegularExpressions Imports PersonalUtilities.Functions.XML Imports PersonalUtilities.Functions.XML.Base +Imports PersonalUtilities.Tools Imports PersonalUtilities.Tools.Web.Clients Imports PersonalUtilities.Tools.Web.Documents.JSON Imports SCrawler.API.Base @@ -176,10 +177,16 @@ Namespace API.Xhamster Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object) If Not Obj Is Nothing AndAlso TypeOf Obj Is UserExchangeOptions Then DirectCast(Obj, UserExchangeOptions).Apply(Me) End Sub + Private MyCache As CacheKeeper = Nothing + Private Sub ResetCache() + MyCache.DisposeIfReady(False) + MyCache = Nothing + End Sub #End Region #Region "Initializer" Friend Sub New() UseInternalM3U8Function = True + UseInternalDownloadFileFunction = True UseClientTokens = True _TempPhotoData = New List(Of UserMedia) SessionPosts = New List(Of String) @@ -235,6 +242,9 @@ Namespace API.Xhamster Private SearchPostsCount As Integer = 0 Private ReadOnly SessionPosts As List(Of String) 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) Try _TempPhotoData.Clear() @@ -243,7 +253,7 @@ Namespace API.Xhamster SessionPosts.Clear() Responser.CookiesAsHeader = True 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 DownloadData(1, False, False, 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 URL = GetNonUserUrl(Page) 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 ThrowAny(Token) @@ -402,9 +412,9 @@ Namespace API.Xhamster If _TempMediaList(i).Type = UTypes.VideoPre Then m = _TempMediaList(i) If Not m.URL_BASE.IsEmptyString Then - m2 = Nothing + m2 = m 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 _TempMediaList(i) = m2 Else @@ -432,9 +442,9 @@ Namespace API.Xhamster If Not DownloadTopCount.HasValue OrElse c <= DownloadTopCount.Value Then m = _TempMediaList(i) If Not m.URL_BASE.IsEmptyString Then - m2 = Nothing + m2 = m 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 _TempMediaList(i) = m2 c += 1 @@ -473,7 +483,7 @@ Namespace API.Xhamster If Not r.IsEmptyString Then Using j As EContainer = JsonDocument.Parse(r).XmlIfNothing 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") If .ListExists Then 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 ThrowAny(Token) 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.State = UserMedia.States.Missing m2.Attempts = m.Attempts @@ -536,25 +546,85 @@ Namespace API.Xhamster End Sub #End Region #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 If Not URL.IsEmptyString Then - Dim r$ = Responser.GetResponse(URL) - If Not r.IsEmptyString Then r = RegexReplace(r, HtmlScript) + Dim IsInternal As Boolean = False + Dim r$ = GetMediaInfo(URL, n, IsInternal) If Not r.IsEmptyString Then Using j As EContainer = JsonDocument.Parse(r) If j.ListExists Then - m = ExtractMedia(j("videoModel"), UTypes.VideoPre,,,, SpecFolder) - m.URL_BASE = URL - 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 + If IsInternal AndAlso GetM3U8_Internal(m, URL, j, SpecFolder) Then + Return True 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 Using @@ -562,16 +632,74 @@ Namespace API.Xhamster End If Return False 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 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" Dim node As EContainer = j({"xplayerSettings", "sources", If(r = 0, "hls", "standard")}) + Dim t As UTypes = UTypes.Undefined If node.ListExists Then Dim url$ 'node.GetNode({New NodeParams("url", True, True, True, True, 2)}).XmlIfNothingValue 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) If url.IsEmptyString Then For Each jn In node @@ -587,61 +715,40 @@ Namespace API.Xhamster Next End If If Not url.IsEmptyString Then - m.URL = url - m.Type = UTypes.m3u8 - Return True + If url.ToLower.EndsWith(".m3u8") Then + t = UTypes.m3u8 + 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 - 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 End Function #End Region -#Region "Decipher" - 'https://github.com/yt-dlp/yt-dlp/blob/5513036104ed9710f624c537fb3644b07a0680db/yt_dlp/extractor/xhamster.py#L146-L165 - 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 - +#Region "yt-dlp support" + Private Function YTDLPGetInfo(ByVal URL As String, ByVal n As Integer) As SFile Try - Dim decoded$ = Encoding.ASCII.GetString(Convert.FromBase64String(Input)) - Dim parts$() = decoded.Split(New Char() {"_"c}, 2) - If parts.Length = 2 Then cipher_type = parts(0) : ciphertext = parts(1) - Catch + If MyCache Is Nothing Then MyCache = CreateCache() : MyCache.Validate() + Dim path As SFile = MyCache.NewPath + 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""" + 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 - - 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 - result.Append(c) - End If - Next - Return result.ToString End Function #End Region #Region "DownloadSingleObject" @@ -654,9 +761,35 @@ Namespace API.Xhamster Protected Overrides Sub DownloadContent(ByVal Token As CancellationToken) DownloadContentDefault(Token) 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 - Media.File = DestinationFile - Return M3U8.Download(Media, Responser, MySettings.DownloadUHD.Value, Token, Progress, Not IsSingleObjectDownload, MySettings.ReencodeVideos.Value) + If CBool(MySettings.UseYTDLPDownload.Value) Then + 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 Region #Region "Create media" @@ -722,7 +855,7 @@ Namespace API.Xhamster #End Region #Region "IDisposable support" 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) End Sub #End Region diff --git a/SCrawler/Download/Automation/AutoDownloader.vb b/SCrawler/Download/Automation/AutoDownloader.vb index 8585259..865096b 100644 --- a/SCrawler/Download/Automation/AutoDownloader.vb +++ b/SCrawler/Download/Automation/AutoDownloader.vb @@ -17,11 +17,6 @@ Namespace DownloadObjects Friend Class AutoDownloader : Inherits GroupParameters : Implements IIndexable, IEContainerProvider, IComparable(Of AutoDownloader) Friend Event PauseChanged(ByVal Value As PauseModes) 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 Enum PauseModes As Integer Disabled = -2 @@ -188,8 +183,9 @@ Namespace DownloadObjects End Class #End Region #Region "XML Names" - Private Const Name_Mode As String = "Mode" - Private Const Name_Groups As String = "Groups" + 'TODELETE: AutoDownloader.Modes + Private Const Name_Mode As String = "Mode" + Private Const Name_Enabled As String = "Enabled" Private Const Name_IsManual As String = "IsManual" Private Const Name_Timer As String = "Timer" Private Const Name_StartupDelay As String = "StartupDelay" @@ -247,17 +243,16 @@ Namespace DownloadObjects End Get End Property Friend Property Source As Scheduler - Private _Mode As Modes = Modes.None - Friend Property Mode As Modes + Private _Enabled As Boolean = False + Friend Property Enabled As Boolean Get - Return _Mode + Return _Enabled End Get - Set(ByVal m As Modes) - _Mode = m - If _Mode = Modes.None Then [Stop]() + Set(ByVal e As Boolean) + _Enabled = e + If Not _Enabled Then [Stop]() End Set End Property - Friend ReadOnly Property Groups As List(Of String) Friend Property IsManual As Boolean = False Friend Property Timer As Integer = DefaultTimer Friend Property StartupDelay As Integer = 1 @@ -371,7 +366,6 @@ Namespace DownloadObjects End Get End Property Friend Sub New(Optional ByVal IsNewPlan As Boolean = False) - Groups = New List(Of String) UserKeys = New List(Of NotifiedUser) _IsNewPlan = IsNewPlan Initialization = False @@ -379,10 +373,17 @@ Namespace DownloadObjects Friend Sub New(ByVal x As EContainer) Me.New Initialization = True - Mode = x.Value(Name_Mode).FromXML(Of Integer)(Modes.None) 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" - Groups.ListAddList(x.Value(Name_Groups).StringToList(Of String)("|"), LAP.NotContainsOnly) IsManual = x.Value(Name_IsManual).FromXML(Of Boolean)(False) Timer = x.Value(Name_Timer).FromXML(Of Integer)(DefaultTimer) @@ -408,7 +409,7 @@ Namespace DownloadObjects newObj.Copy(Me) With newObj .Name = String.Empty - ._Mode = _Mode + .Enabled = Enabled .Groups.ListAddList(Groups, LAP.ClearBeforeAdd) .IsManual = IsManual .Timer = Timer @@ -441,8 +442,7 @@ Namespace DownloadObjects End Sub Private Function ToEContainer(Optional ByVal e As ErrorsDescriber = Nothing) As EContainer Implements IEContainerProvider.ToEContainer Return Export(New EContainer(Scheduler.Name_Plan, String.Empty) From { - New EContainer(Name_Mode, CInt(Mode)), - New EContainer(Name_Groups, Groups.ListToString("|")), + New EContainer(Name_Enabled, Enabled.BoolToInteger), New EContainer(Name_IsManual, IsManual.BoolToInteger), New EContainer(Name_Timer, Timer), New EContainer(Name_StartupDelay, StartupDelay), @@ -467,7 +467,7 @@ Namespace DownloadObjects If Not IsManual Or Force Then If Init Then _StartTime = Now _IsNewPlan = False - If Not Working And Not Mode = Modes.None Then _Working = True + If Not Working And Enabled Then _Working = True RaiseEvent PlanChanged(Me) End If End Sub @@ -556,12 +556,12 @@ Namespace DownloadObjects Get 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 - 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 Property Friend ReadOnly Property NextDate As Date? Get - If Not _StopRequested And Not Mode = Modes.None Then + If Not _StopRequested And Enabled Then If IsManual Or _ForceStartRequested Then Return Now.AddYears(-10) ElseIf Not IsPaused And Not IsManual And Working Then @@ -583,8 +583,6 @@ Namespace DownloadObjects Dim Keys As New List(Of String) Try Dim users As New List(Of IUserData) - Dim GName$ - Dim i% Dim doRound% = -1, doLim% = Settings.Plugins.Count Dim DownloadedUsersCount% = 0 Dim DownloadedSubscriptionsCount% = 0 @@ -614,16 +612,9 @@ Namespace DownloadObjects Catch n_ex As Exception End Try End Sub - Select Case Mode - Case Modes.Specified : 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 Enabled Then users.ListAddList(DownloadGroup.GetUsers(Me)) + If users.Count > 0 Then Keys.ListAddList(users.Select(Function(u) u.Key)) With Downloader diff --git a/SCrawler/Download/Automation/AutoDownloaderEditorForm.Designer.vb b/SCrawler/Download/Automation/AutoDownloaderEditorForm.Designer.vb index 430c934..73d7787 100644 --- a/SCrawler/Download/Automation/AutoDownloaderEditorForm.Designer.vb +++ b/SCrawler/Download/Automation/AutoDownloaderEditorForm.Designer.vb @@ -25,19 +25,14 @@ Namespace DownloadObjects Me.components = New System.ComponentModel.Container() Dim CONTAINER_MAIN As System.Windows.Forms.ToolStripContainer 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 ActionButton4 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() - Dim ActionButton5 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 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 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_GROUP = New System.Windows.Forms.RadioButton() - Me.TXT_GROUPS = New PersonalUtilities.Forms.Controls.TextBoxExtended() Me.CH_NOTIFY = New System.Windows.Forms.CheckBox() Me.CH_SHOW_PIC = New System.Windows.Forms.CheckBox() Me.CH_SHOW_PIC_USER = New System.Windows.Forms.CheckBox() @@ -54,7 +49,6 @@ Namespace DownloadObjects CONTAINER_MAIN.SuspendLayout() Me.DEF_GROUP.SuspendLayout() TP_MODE.SuspendLayout() - CType(Me.TXT_GROUPS, System.ComponentModel.ISupportInitialize).BeginInit() TP_NOTIFY.SuspendLayout() CType(Me.TXT_TIMER, System.ComponentModel.ISupportInitialize).BeginInit() CType(Me.NUM_DELAY, System.ComponentModel.ISupportInitialize).BeginInit() @@ -66,7 +60,7 @@ Namespace DownloadObjects 'CONTAINER_MAIN.ContentPanel ' 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.LeftToolStripPanelVisible = False CONTAINER_MAIN.Location = New System.Drawing.Point(0, 0) @@ -82,7 +76,6 @@ Namespace DownloadObjects 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.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(Me.TXT_TIMER, 0, 15) 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, 25.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 ' 'TP_MODE ' TP_MODE.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single] - TP_MODE.ColumnCount = 3 - 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, 33.33333!)) - TP_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333!)) + TP_MODE.ColumnCount = 2 + 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, 50.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_SPEC, 1, 0) + TP_MODE.Controls.Add(Me.OPT_ENABLED, 1, 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.Location = New System.Drawing.Point(1, 1) 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.TabIndex = 0 ' - 'OPT_SPEC + 'OPT_ENABLED ' - Me.OPT_SPEC.AutoSize = True - Me.OPT_SPEC.Dock = System.Windows.Forms.DockStyle.Fill - Me.OPT_SPEC.Location = New System.Drawing.Point(161, 4) - Me.OPT_SPEC.Name = "OPT_SPEC" - Me.OPT_SPEC.Size = New System.Drawing.Size(150, 17) - Me.OPT_SPEC.TabIndex = 3 - Me.OPT_SPEC.TabStop = True - Me.OPT_SPEC.Text = "Specified" - TT_MAIN.SetToolTip(Me.OPT_SPEC, "Select parameters") - Me.OPT_SPEC.UseVisualStyleBackColor = True + Me.OPT_ENABLED.AutoSize = True + Me.OPT_ENABLED.Dock = System.Windows.Forms.DockStyle.Fill + Me.OPT_ENABLED.Location = New System.Drawing.Point(240, 4) + Me.OPT_ENABLED.Name = "OPT_ENABLED" + Me.OPT_ENABLED.Size = New System.Drawing.Size(230, 17) + Me.OPT_ENABLED.TabIndex = 3 + Me.OPT_ENABLED.TabStop = True + Me.OPT_ENABLED.Text = "Enabled" + TT_MAIN.SetToolTip(Me.OPT_ENABLED, "Select parameters") + Me.OPT_ENABLED.UseVisualStyleBackColor = True ' 'OPT_DISABLED ' @@ -154,48 +144,13 @@ Namespace DownloadObjects Me.OPT_DISABLED.Dock = System.Windows.Forms.DockStyle.Fill Me.OPT_DISABLED.Location = New System.Drawing.Point(4, 4) 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.TabStop = True Me.OPT_DISABLED.Text = "Disabled" TT_MAIN.SetToolTip(Me.OPT_DISABLED, "Automation disabled") 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.ColumnCount = 4 @@ -266,9 +221,9 @@ Namespace DownloadObjects ' 'TXT_TIMER ' - ActionButton4.BackgroundImage = CType(resources.GetObject("ActionButton4.BackgroundImage"), System.Drawing.Image) - ActionButton4.Name = "Refresh" - Me.TXT_TIMER.Buttons.Add(ActionButton4) + ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image) + ActionButton1.Name = "Refresh" + Me.TXT_TIMER.Buttons.Add(ActionButton1) Me.TXT_TIMER.CaptionText = "Timer" Me.TXT_TIMER.CaptionToolTipEnabled = True Me.TXT_TIMER.CaptionToolTipText = "Timer (in minutes)" @@ -281,9 +236,9 @@ Namespace DownloadObjects ' 'NUM_DELAY ' - ActionButton5.BackgroundImage = CType(resources.GetObject("ActionButton5.BackgroundImage"), System.Drawing.Image) - ActionButton5.Name = "Refresh" - Me.NUM_DELAY.Buttons.Add(ActionButton5) + ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image) + ActionButton2.Name = "Refresh" + Me.NUM_DELAY.Buttons.Add(ActionButton2) Me.NUM_DELAY.CaptionText = "Delay" Me.NUM_DELAY.CaptionToolTipEnabled = True Me.NUM_DELAY.CaptionToolTipText = "Startup delay" @@ -348,7 +303,6 @@ Namespace DownloadObjects Me.DEF_GROUP.PerformLayout() TP_MODE.ResumeLayout(False) TP_MODE.PerformLayout() - CType(Me.TXT_GROUPS, System.ComponentModel.ISupportInitialize).EndInit() TP_NOTIFY.ResumeLayout(False) TP_NOTIFY.PerformLayout() CType(Me.TXT_TIMER, System.ComponentModel.ISupportInitialize).EndInit() @@ -357,12 +311,10 @@ Namespace DownloadObjects End Sub Private WithEvents DEF_GROUP As DownloadObjects.Groups.GroupDefaults - Private WithEvents TXT_GROUPS As PersonalUtilities.Forms.Controls.TextBoxExtended - Private WithEvents OPT_SPEC As RadioButton + Private WithEvents OPT_ENABLED As RadioButton Private WithEvents OPT_DISABLED As RadioButton Private WithEvents CH_NOTIFY As CheckBox 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 NUM_DELAY As PersonalUtilities.Forms.Controls.TextBoxExtended Private WithEvents CH_SHOW_PIC As CheckBox diff --git a/SCrawler/Download/Automation/AutoDownloaderEditorForm.resx b/SCrawler/Download/Automation/AutoDownloaderEditorForm.resx index e2ab359..5c76c46 100644 --- a/SCrawler/Download/Automation/AutoDownloaderEditorForm.resx +++ b/SCrawler/Download/Automation/AutoDownloaderEditorForm.resx @@ -129,85 +129,6 @@ 17, 17 - - - - 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 - AAAASUVORK5CYII= - - - - - iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1 - MAAA6mAAADqYAAAXb5JfxUYAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAFQSURBVFhH7ZfNDcIwFIMZoXcm - YBtGYRHECIgTR1ZhBsS9YoJgQ1Poi5sfqhIOWPqkqvV7dWlI0oVzriry5Dd5HSS0PFwasAEn0AJn4Dle - o6fpykaVHYDNwB7YG6ZgzWiQrABosAbqaXNh7bprN1AyAAp3b42msuva9ooGYIFpELA931D2FI+VxzAI - gTIdAEb+7KpBz+p4RclQyifoXwdKwgAwcMAl3/mEAOz9GJgokQGyR/sHr8CzlwFwgU+vCuagUQE4gSjz - HGxUAM5iyiyxUp4IJ5QEAYomHCvlidCiJAigjKNYKU8M6B/g9wJUH4TV/4ZFE5GV8kSQE1HRVGylPBHC - qbh0MbJSnhH0YtQFyFqOiZXyCOLLMQVDckNCrJRHEN+QeMGY3JJZKY8hb0vmxQLTYAplm1IvFNbblnuh - Qb0Pk3exGZjv06wW8uT3cIs7jQnSONrSxH0AAAAASUVORK5CYII= - - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go - tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX - AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC - - False @@ -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. The 'Image' and 'User icon' parameters will be ignored. - + + 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 \ No newline at end of file diff --git a/SCrawler/Download/Automation/AutoDownloaderEditorForm.vb b/SCrawler/Download/Automation/AutoDownloaderEditorForm.vb index 0a8390c..7da4a00 100644 --- a/SCrawler/Download/Automation/AutoDownloaderEditorForm.vb +++ b/SCrawler/Download/Automation/AutoDownloaderEditorForm.vb @@ -9,17 +9,14 @@ Imports SCrawler.DownloadObjects.Groups Imports PersonalUtilities.Forms Imports PersonalUtilities.Forms.Controls.Base -Imports DModes = SCrawler.DownloadObjects.AutoDownloader.Modes Namespace DownloadObjects Friend Class AutoDownloaderEditorForm Private WithEvents MyDefs As DefaultFormOptions - Private ReadOnly MyGroups As List(Of String) Private ReadOnly Property Plan As AutoDownloader Friend Sub New(ByRef _Plan As AutoDownloader) InitializeComponent() Plan = _Plan MyDefs = New DefaultFormOptions(Me, Settings.Design) - MyGroups.ListAddList(Plan.Groups, LAP.NotContainsOnly) End Sub Private Class AutomationTimerChecker : Inherits FieldsCheckerProviderBase Public Overrides Property ErrorMessage As String @@ -45,19 +42,12 @@ Namespace DownloadObjects .MyViewInitialize(True) .AddOkCancelToolbar() With Plan - Select Case .Mode - Case DModes.None : OPT_DISABLED.Checked = True - Case DModes.Specified : OPT_SPEC.Checked = True - Case DModes.Groups : OPT_GROUP.Checked = True - End Select + If Enabled Then OPT_ENABLED.Checked = True Else OPT_DISABLED.Checked = True - TXT_GROUPS.CaptionWidth = GroupDefaults.CaptionWidthDefault TXT_TIMER.CaptionWidth = GroupDefaults.CaptionWidthDefault NUM_DELAY.CaptionWidth = GroupDefaults.CaptionWidthDefault 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_SIMPLE.Checked = .ShowSimpleNotification 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" End With 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 Try If e = ShowUsersButtonKey AndAlso Not OPT_DISABLED.Checked Then Dim users As New List(Of API.Base.IUserData) - If OPT_GROUP.Checked Then - If MyGroups.Count > 0 Then - Dim i% - For Each groupName$ In MyGroups - 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 + Using g As New GroupParameters + DEF_GROUP.Get(g) + users.ListAddList(DownloadGroup.GetUsers(g), LAP.IgnoreICopier) + End Using GroupUsersViewer.Show(users, $"S {DEF_GROUP.TXT_NAME.Text}") users.Clear() End If @@ -110,14 +87,8 @@ Namespace DownloadObjects Private Sub MyDefs_ButtonOkClick(ByVal Sender As Object, ByVal e As KeyHandleEventArgs) Handles MyDefs.ButtonOkClick If MyDefs.MyFieldsChecker.AllParamsOK Then With Plan - Select Case True - Case OPT_DISABLED.Checked : .Mode = DModes.None - Case OPT_SPEC.Checked : .Mode = DModes.Specified - Case OPT_GROUP.Checked : .Mode = DModes.Groups - End Select + .Enabled = OPT_ENABLED.Checked DEF_GROUP.Get(Plan) - .Groups.Clear() - .Groups.ListAddList(MyGroups) .ShowNotifications = CH_NOTIFY.Checked .ShowSimpleNotification = CH_NOTIFY_SIMPLE.Checked .ShowPictureDownloaded = CH_SHOW_PIC.Checked @@ -131,42 +102,20 @@ Namespace DownloadObjects MyDefs.CloseForm() End If 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, - OPT_SPEC.CheckedChanged, OPT_GROUP.CheckedChanged, + OPT_ENABLED.CheckedChanged, CH_NOTIFY.CheckedChanged, CH_NOTIFY_SIMPLE.CheckedChanged - DEF_GROUP.Enabled = OPT_SPEC.Checked - TXT_GROUPS.Enabled = OPT_GROUP.Checked - TXT_TIMER.Enabled = Not OPT_DISABLED.Checked - NUM_DELAY.Enabled = Not OPT_DISABLED.Checked - CH_NOTIFY.Enabled = Not OPT_DISABLED.Checked + Dim __enabled As Boolean = Not OPT_DISABLED.Checked + DEF_GROUP.Enabled = __enabled + TXT_TIMER.Enabled = __enabled + NUM_DELAY.Enabled = __enabled + CH_NOTIFY.Enabled = __enabled 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_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 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 diff --git a/SCrawler/Download/Automation/AutoDownloaderPauseButtons.vb b/SCrawler/Download/Automation/AutoDownloaderPauseButtons.vb index 3510840..adf8365 100644 --- a/SCrawler/Download/Automation/AutoDownloaderPauseButtons.vb +++ b/SCrawler/Download/Automation/AutoDownloaderPauseButtons.vb @@ -144,7 +144,7 @@ Namespace DownloadObjects If UpdateBase Then UpdateBaseButton(Not p = PauseModes.Disabled) 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 Else Return plan.Pause = p diff --git a/SCrawler/Download/Automation/SchedulerEditorForm.vb b/SCrawler/Download/Automation/SchedulerEditorForm.vb index 8538a55..1c5bc7e 100644 --- a/SCrawler/Download/Automation/SchedulerEditorForm.vb +++ b/SCrawler/Download/Automation/SchedulerEditorForm.vb @@ -507,24 +507,7 @@ Namespace DownloadObjects Private Sub ShowPlanUsers() Try If _LatestSelected.ValueBetween(0, Settings.Automation.Count - 1) Then - With Settings.Automation(_LatestSelected) - 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 + With Settings.Automation(_LatestSelected) : Groups.GroupUsersViewer.Show(Groups.DownloadGroup.GetUsers(.Self), $"S { .Name}") : End With End If Catch ex As Exception ErrorsDescriber.Execute(EDP.LogMessageValue, ex, "Show plan users") diff --git a/SCrawler/Download/DownloadProgress.vb b/SCrawler/Download/DownloadProgress.vb index 9d05837..3fa830c 100644 --- a/SCrawler/Download/DownloadProgress.vb +++ b/SCrawler/Download/DownloadProgress.vb @@ -16,6 +16,7 @@ Namespace DownloadObjects Friend Event DownloadDone As NotificationEventHandler Friend Event ProgressChanged(ByVal Main As Boolean, ByVal IsMaxValue As Boolean, ByVal IsDone As Boolean) Friend Event FeedFilesChanged As TDownloader.FeedFilesChangedEventHandler + Friend Event KeyDown As KeyEventHandler #End Region #Region "Declarations" #Region "Controls" @@ -126,6 +127,10 @@ Namespace DownloadObjects TP_MAIN.Controls.Add(LBL_INFO, 0, 1) 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 .Progress = New MyProgressExt(PR_MAIN, PR_PRE, LBL_INFO) With {.ResetProgressOnMaximumChanges = False} With DirectCast(.Progress, MyProgressExt) @@ -149,6 +154,9 @@ Namespace DownloadObjects .Dock = DockStyle.Fill } End Sub + Private Sub BTT_KeyDown(ByVal Sender As Object, ByVal e As KeyEventArgs) + RaiseEvent KeyDown(Sender, e) + End Sub #End Region Friend Function [Get]() As TableLayoutPanel Return TP_MAIN diff --git a/SCrawler/Download/DownloadSavedPostsForm.vb b/SCrawler/Download/DownloadSavedPostsForm.vb index 0ae4abc..f3b4300 100644 --- a/SCrawler/Download/DownloadSavedPostsForm.vb +++ b/SCrawler/Download/DownloadSavedPostsForm.vb @@ -43,6 +43,7 @@ Friend Class DownloadSavedPostsForm For Each j As DownloadProgress In JobsList AddHandler j.DownloadDone, AddressOf Jobs_DownloadDone AddHandler j.FeedFilesChanged, AddressOf Jobs_FeedFilesChanged + AddHandler j.KeyDown, AddressOf DownloadSavedPostsForm_KeyDown TP_MAIN.RowStyles.Add(New RowStyle(SizeType.Absolute, 60)) TP_MAIN.RowCount += 1 TP_MAIN.Controls.Add(j.Get, 0, TP_MAIN.RowStyles.Count - 1) @@ -54,6 +55,9 @@ Friend Class DownloadSavedPostsForm MaximumSize = s End If 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 e.Cancel = True Hide() diff --git a/SCrawler/Download/Groups/DownloadGroup.vb b/SCrawler/Download/Groups/DownloadGroup.vb index 914f25e..50a0bf8 100644 --- a/SCrawler/Download/Groups/DownloadGroup.vb +++ b/SCrawler/Download/Groups/DownloadGroup.vb @@ -245,7 +245,7 @@ Namespace DownloadObjects.Groups If Not Settings.Automation Is Nothing AndAlso Settings.Automation.Count > 0 Then Dim aIncl As New List(Of String) 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 If aIncl.Count > 0 Then 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 If Settings.Users.Count > 0 Then With Instance + If TypeOf .Self Is AutoDownloader AndAlso Not DirectCast(.Self, AutoDownloader).Enabled Then Return Nothing Dim downDate As Date? = Nothing If .DaysNumber > 0 Then With Now.AddDays(- .DaysNumber) : downDate = New Date(.Year, .Month, .Day, 0, 0, 0) : End With @@ -363,10 +364,20 @@ Namespace DownloadObjects.Groups Dim CheckSites As Predicate(Of IUserData) = Function(user) _ (.Sites.Count = 0 OrElse .Sites.Contains(user.Site)) AndAlso (.SitesExcluded.Count = 0 OrElse Not .SitesExcluded.Contains(user.Site)) - Dim users As IEnumerable(Of IUserData) = - 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)) + Dim users As New List(Of IUserData) + If Not .GroupsOnly Or (.GroupsOnly And .Groups.Count = 0) Then + 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)), LAP.IgnoreICopier) + End If + If .Groups.Count > 0 And Settings.Groups.Count > 0 Then + Dim i% + For Each groupName$ In .Groups + i = Settings.Groups.IndexOf(groupName) + If i >= 0 Then users.ListAddList(Settings.Groups(i).GetUsers, LAP.NotContainsOnly, LAP.IgnoreICopier) + Next + End If + If .UsersCount <> 0 And users.ListExists Then users = users.ListTake(If(.UsersCount > 0, -1, -2), Math.Abs(.UsersCount)) If .UsersCount < 0 Then users = users.ListReverse diff --git a/SCrawler/Download/Groups/GroupDefaults.vb b/SCrawler/Download/Groups/GroupDefaults.vb index 9936d35..03ed13b 100644 --- a/SCrawler/Download/Groups/GroupDefaults.vb +++ b/SCrawler/Download/Groups/GroupDefaults.vb @@ -10,10 +10,11 @@ Imports PersonalUtilities.Forms Imports PersonalUtilities.Forms.Controls Imports PersonalUtilities.Forms.Controls.Base Imports ADB = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons +Imports CaptionModes = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes Namespace DownloadObjects.Groups Public Class GroupDefaults : Inherits TableLayoutPanel #Region "Constants" - Friend Const CaptionWidthDefault As Integer = 55 + Friend Const CaptionWidthDefault As Integer = 60 '55 #End Region #Region "Declarations" Private ReadOnly TP_1 As TableLayoutPanel 'CH_REGULAR, CH_TEMPORARY, CH_FAV @@ -49,13 +50,20 @@ Namespace DownloadObjects.Groups Private WithEvents TXT_LABELS As TextBoxExtended Private WithEvents TXT_SITES As TextBoxExtended + Private WithEvents TXT_GROUPS As TextBoxExtended Friend WithEvents TXT_NAME As TextBoxExtended Private ReadOnly Labels As List(Of String) Private ReadOnly LabelsExcluded As List(Of String) Private ReadOnly Sites As List(Of String) Private ReadOnly SitesExcluded As List(Of String) + Private ReadOnly Groups As List(Of String) Private ReadOnly TT_MAIN As ToolTip + Friend ReadOnly Property GroupsOnly As Boolean + Get + Return TXT_GROUPS.Checked + End Get + End Property #End Region #Region "Initializer" Public Sub New() @@ -63,6 +71,7 @@ Namespace DownloadObjects.Groups LabelsExcluded = New List(Of String) Sites = New List(Of String) SitesExcluded = New List(Of String) + Groups = New List(Of String) TT_MAIN = New ToolTip InitTextBox(TXT_LABELS, "Labels", {New ActionButton(ADB.Edit) With {.ToolTipText = "Edit selected labels"}, @@ -73,6 +82,16 @@ Namespace DownloadObjects.Groups New ActionButton(ADB.Delete) With {.ToolTipText = "Edit excluded sites"}, ADB.Clear}) TXT_SITES.TextBoxReadOnly = True + InitTextBox(TXT_GROUPS, "Groups", {New ActionButton(ADB.Edit) With {.ToolTipText = "Edit selected 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}) CH_REGULAR = New CheckBox With {.Text = "Regular", .Name = "CH_REGULAR", .Checked = True, .Dock = DockStyle.Fill} @@ -209,12 +228,14 @@ Namespace DownloadObjects.Groups .EndInit() End With 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 With TXT .BeginInit() .Buttons.AddRange(Buttons) .CaptionText = Caption + .CaptionMode = CaptionMode .CaptionWidth = CaptionWidthDefault .Dock = DockStyle.Fill .EndInit() @@ -240,7 +261,7 @@ Namespace DownloadObjects.Groups CellBorderStyle = TableLayoutPanelCellBorderStyle.Single ColumnCount = 1 ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 100)) - RowCount = 13 + RowCount = 14 RowStyles.Add(New RowStyle(SizeType.Absolute, 25)) RowStyles.Add(New RowStyle(SizeType.Absolute, 28)) RowStyles.Add(New RowStyle(SizeType.Absolute, 25)) @@ -253,6 +274,7 @@ Namespace DownloadObjects.Groups 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.Percent, 100)) End If Controls.Add(TXT_NAME, 0, 1) @@ -269,6 +291,7 @@ Namespace DownloadObjects.Groups Controls.Add(TXT_LABELS, 0, 10) Controls.Add(TXT_SITES, 0, 11) + Controls.Add(TXT_GROUPS, 0, 12) End Sub #End Region #Region "Control handlers" @@ -277,6 +300,7 @@ Namespace DownloadObjects.Groups LabelsExcluded.Clear() Sites.Clear() SitesExcluded.Clear() + Groups.Clear() CH_REGULAR.Dispose() CH_TEMPORARY.Dispose() CH_FAV.Dispose() @@ -296,6 +320,7 @@ Namespace DownloadObjects.Groups NUM_DAYS.Dispose() TXT_LABELS.Dispose() TXT_SITES.Dispose() + TXT_GROUPS.Dispose() TXT_NAME.Dispose() TT_MAIN.Dispose() ClearTP(TP_1) @@ -357,6 +382,20 @@ Namespace DownloadObjects.Groups Case ADB.Clear : Sites.Clear() : SitesExcluded.Clear() : TXT_SITES.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 + Using f As New LabelsForm(Groups, (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 Groups.ListAddList(f.LabelsList, LAP.ClearBeforeAdd) : UpdateGroupsText() + End Using + Case ADB.Clear : Groups.Clear() : TXT_GROUPS.Clear() : UpdateGroupsText() + End Select + End Sub Private Sub UpdateLabelsText() TXT_LABELS.Clear() If Not _JustExcludeOptions Then TXT_LABELS.Text = Labels.ListToString @@ -367,6 +406,10 @@ Namespace DownloadObjects.Groups If Not _JustExcludeOptions Then TXT_SITES.Text = Sites.ListToString If SitesExcluded.Count > 0 Then TXT_SITES.Text.StringAppend($"EXCLUDED: {SitesExcluded.ListToString}", "; ") End Sub + Private Sub UpdateGroupsText() + TXT_GROUPS.Clear() + TXT_GROUPS.Text = Groups.ListToString + End Sub #End Region #Region "Get/set" Friend Sub [Get](ByRef Instance As IGroup) @@ -410,6 +453,9 @@ Namespace DownloadObjects.Groups .Sites.ListAddList(Sites) .SitesExcluded.Clear() .SitesExcluded.ListAddList(SitesExcluded) + .Groups.Clear() + .Groups.ListAddList(Groups) + .GroupsOnly = GroupsOnly End With End If End Sub @@ -457,6 +503,10 @@ Namespace DownloadObjects.Groups Sites.ListAddList(.Sites) SitesExcluded.ListAddList(.SitesExcluded) UpdateSitesText() + + Groups.ListAddList(.Groups) + TXT_GROUPS.Checked = .GroupsOnly + UpdateGroupsText() End With End If End Sub @@ -481,8 +531,26 @@ Namespace DownloadObjects.Groups NUM_DAYS.Enabled = e TXT_LABELS.Enabled = e TXT_SITES.Enabled = e + TXT_GROUPS.Enabled = e UpdateLabelsText() 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 Property #End Region diff --git a/SCrawler/Download/Groups/GroupEditorForm.Designer.vb b/SCrawler/Download/Groups/GroupEditorForm.Designer.vb index d0a524d..af1fa07 100644 --- a/SCrawler/Download/Groups/GroupEditorForm.Designer.vb +++ b/SCrawler/Download/Groups/GroupEditorForm.Designer.vb @@ -35,13 +35,13 @@ Namespace DownloadObjects.Groups 'CONTAINER_MAIN.ContentPanel ' 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.LeftToolStripPanelVisible = False CONTAINER_MAIN.Location = New System.Drawing.Point(0, 0) CONTAINER_MAIN.Name = "CONTAINER_MAIN" 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.TopToolStripPanelVisible = False ' @@ -53,7 +53,7 @@ Namespace DownloadObjects.Groups Me.DEFS_GROUP.Dock = System.Windows.Forms.DockStyle.Fill Me.DEFS_GROUP.Location = New System.Drawing.Point(0, 0) 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, 28.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, 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.Size = New System.Drawing.Size(476, 328) + Me.DEFS_GROUP.Size = New System.Drawing.Size(476, 331) Me.DEFS_GROUP.TabIndex = 0 ' 'GroupEditorForm ' Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!) 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.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle Me.Icon = Global.SCrawler.My.Resources.Resources.GroupByIcon_16 Me.KeyPreview = True Me.MaximizeBox = False - Me.MaximumSize = New System.Drawing.Size(492, 367) + Me.MaximumSize = New System.Drawing.Size(492, 395) Me.MinimizeBox = False - Me.MinimumSize = New System.Drawing.Size(492, 367) + Me.MinimumSize = New System.Drawing.Size(492, 395) Me.Name = "GroupEditorForm" Me.ShowInTaskbar = False Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide diff --git a/SCrawler/Download/Groups/GroupEditorForm.vb b/SCrawler/Download/Groups/GroupEditorForm.vb index 7912561..079a62a 100644 --- a/SCrawler/Download/Groups/GroupEditorForm.vb +++ b/SCrawler/Download/Groups/GroupEditorForm.vb @@ -78,6 +78,8 @@ Namespace DownloadObjects.Groups .MyFieldsChecker.EndLoaderOperations() .EndLoaderOperations() .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 Sub Private Sub GroupEditorForm_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown diff --git a/SCrawler/Download/Groups/GroupListForm.vb b/SCrawler/Download/Groups/GroupListForm.vb index bb5e32d..6673d27 100644 --- a/SCrawler/Download/Groups/GroupListForm.vb +++ b/SCrawler/Download/Groups/GroupListForm.vb @@ -311,28 +311,15 @@ Namespace DownloadObjects.Groups Dim users As New List(Of API.Base.IUserData) If Not IsViewFilter Then 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 With MyGroupParams(_LatestSelected) + users.ListAddList(DownloadGroup.GetUsers(.Self), LAP.IgnoreICopier) + n = .Name If TypeOf .Self Is AutoDownloader Then - With DirectCast(.Self, AutoDownloader) - 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 + n = $"S {n}" ElseIf TypeOf .Self Is DownloadGroup Then - i = Settings.Groups.IndexOf(.Name, .IsViewFilter) - If i >= 0 Then users.ListAddList(DownloadGroup.GetUsers(Settings.Groups(i))) : n = $"G {Settings.Groups(i).Name}" + n = $"G {n}" End If End With End If diff --git a/SCrawler/Download/Groups/GroupParameters.vb b/SCrawler/Download/Groups/GroupParameters.vb index cd5f733..72fc735 100644 --- a/SCrawler/Download/Groups/GroupParameters.vb +++ b/SCrawler/Download/Groups/GroupParameters.vb @@ -16,6 +16,8 @@ Namespace DownloadObjects.Groups Property LabelsExcludedIgnore As Boolean ReadOnly Property Sites As List(Of String) ReadOnly Property SitesExcluded As List(Of String) + ReadOnly Property Groups As List(Of String) + Property GroupsOnly As Boolean Property Regular As Boolean Property Temporary As Boolean Property Favorite As Boolean @@ -56,6 +58,8 @@ Namespace DownloadObjects.Groups Protected Const Name_LabelsExcludedIgnore As String = "LabelsExcludedIgnore" Protected Const Name_Sites As String = "Sites" Protected Const Name_Sites_Excluded As String = "SitesExcluded" + Protected Const Name_Groups As String = "Groups" + Protected Const Name_GroupsOnly As String = "GroupsOnly" Protected Const Name_DaysNumber As String = "DaysNumber" Protected Const Name_DaysIsDownloaded As String = "DaysIsDownloaded" Protected Const Name_UserDeleted As String = "UserDeleted" @@ -74,6 +78,8 @@ Namespace DownloadObjects.Groups Friend Property LabelsExcludedIgnore As Boolean = False Implements IGroup.LabelsExcludedIgnore 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 Groups As List(Of String) Implements IGroup.Groups + Friend Property GroupsOnly As Boolean = False Implements IGroup.GroupsOnly Friend Property Regular As Boolean = True Implements IGroup.Regular Friend Property Temporary As Boolean = True Implements IGroup.Temporary Friend Property Favorite As Boolean = True Implements IGroup.Favorite @@ -98,6 +104,7 @@ Namespace DownloadObjects.Groups LabelsExcluded = New List(Of String) Sites = New List(Of String) SitesExcluded = New List(Of String) + Groups = New List(Of String) End Sub #End Region #Region "Base functions" @@ -121,6 +128,8 @@ Namespace DownloadObjects.Groups LabelsExcludedIgnore = .LabelsExcludedIgnore Sites.ListAddList(.Sites, LAP.ClearBeforeAdd) SitesExcluded.ListAddList(.SitesExcluded, LAP.ClearBeforeAdd) + Groups.ListAddList(.Groups, LAP.ClearBeforeAdd) + GroupsOnly = .GroupsOnly Regular = .Regular Temporary = .Temporary Favorite = .Favorite @@ -153,6 +162,8 @@ Namespace DownloadObjects.Groups 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_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) + GroupsOnly = e.Value(Name_GroupsOnly).FromXML(Of Boolean)(False) Regular = e.Value(Name_Regular).FromXML(Of Boolean)(True) Temporary = e.Value(Name_Temporary).FromXML(Of Boolean)(True) @@ -190,6 +201,8 @@ Namespace DownloadObjects.Groups New EContainer(Name_LabelsExcludedIgnore, LabelsExcludedIgnore.BoolToInteger), New EContainer(Name_Sites, Sites.ListToString("|")), New EContainer(Name_Sites_Excluded, SitesExcluded.ListToString("|")), + New EContainer(Name_Groups, Groups.ListToString("|")), + New EContainer(Name_GroupsOnly, GroupsOnly.BoolToInteger), New EContainer(Name_Regular, Regular.BoolToInteger), New EContainer(Name_Temporary, Temporary.BoolToInteger), New EContainer(Name_Favorite, Favorite.BoolToInteger), @@ -219,6 +232,7 @@ Namespace DownloadObjects.Groups LabelsExcluded.Clear() Sites.Clear() SitesExcluded.Clear() + Groups.Clear() End If disposedValue = True End If diff --git a/SCrawler/MainFrame.vb b/SCrawler/MainFrame.vb index d6ca5c9..4d7f0c2 100644 --- a/SCrawler/MainFrame.vb +++ b/SCrawler/MainFrame.vb @@ -801,29 +801,6 @@ CloseResume: f.ShowDialog() If f.DialogResult = DialogResult.OK Then 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 filter.IsViewFilter Then With DirectCast(filter, DownloadGroup) diff --git a/SCrawler/My Project/AssemblyInfo.vb b/SCrawler/My Project/AssemblyInfo.vb index e9b53f8..d816d67 100644 --- a/SCrawler/My Project/AssemblyInfo.vb +++ b/SCrawler/My Project/AssemblyInfo.vb @@ -13,7 +13,7 @@ Imports System.Runtime.InteropServices - + @@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices ' by using the '*' as shown below: ' - - + +