2023.4.28.0

Plugins
IPluginContentProvider: added DownloadSingleObject function; added tokens to GetMedia and Download functions; removed GetSpecialData function
Add IDownloadableMedia interface
Removed 'Channel' option from all functions and enums
ISiteSettings: added GetSingleMediaInstance function
ExchangeOptions: removed 'IsChannel'
UserMediaTypes: added Audio and AudioPre enums
IUserMedia, PluginUserMedia: changed ContentType and DownloadState from integers to their enums

SCrawler
Add YouTube standalone downloader
Add gallery-dl & yt-dlp support
Remove 'UserInfo' requirement from 'ProfilesSaved'
Update 'SiteSettingsBase' to use domains and Netscape cookies
UserDataBase: remove channels; remove old 'Merge' const; standardize SavedPosts file naming; move 'ValidateMD5' function from Twitter to UserDataBase to use it in other UserData classes; add 'DownloadSingleObject' environment for single posts; add validating file extension for m3u8 during download; add reindex of video file during download

Rewritten DomainsContainer
Create a universal settings form and PSettingsArttribute
Gfycat, Imgur: turn these classes into IUserData to download a single object

All plugins: update 'GetInstance' function for saved posts; update domains where implemented; remove 'OptionForm' where it exists; update options where they exist; update unix date providers; reconfigure channels where they exist

LPSG: fix attachments; update converters and regex
Add sites: ThisVid, Mastodon, Pinterest, YouTube, YouTube music
Reddit: standardize container parsing for all data types; new channel environment; fix 'ReparseMissing' function; redirect data downloading to the base download function, saved crossposts support
Twitter: fixed gif path bug; fixed downloading saved posts
PornHub: hide unnecessary errors; photo galleries bug
RedGifs: add 'UserAgent' option

Added icons to download progress

Rename some objects
Completely redesigned standalone downloader form and rewritten its environment
WebClient2: update to use tokens

Labels: update label form (save labels to file only when OK button is clicked); change removing labels.txt from recycle bin to permanent; disable storing label 'NoParsedUser'

UserCreatorForm: remove the 'Channel' checkbox and related functions; ability to extract the user's URL from the buffer and apply parameters if found
Remove temporary 'EncryptCookies' module

MainFrame: added simplified way to create new users (Ctrl+Insert to create a new user with default parameters from clipboard URL); removed SCrawler command line argument "-v" (remove the ability to run SCrawler as video downloader)
PropertyValueHost: update for option forms compatibility
SettingsHost: removed 'GetSpecialData' fork; added 'GetSingleMediaInstance' fork
UserDataHost: update functions with tokens; update events; add 'DownloadSingleObject' function
Settings: add the ability to get environment from 4 destinations; add the ability to set the program environment manually; add CMDEncoding; add cache; remove the old function 'RemoveUnusedPlugins'; add 'STDownloader' properties; add YT compatibility; add new notification options; add deleting user settings file when 'SettingsCLS.Dispose()' if where are no users in SCrawler
UserFinder: remove old 'Merge' const; remove channel option
UserInfo: remove channel option
This commit is contained in:
Andy
2023-04-28 10:13:46 +03:00
parent db9e2cfb88
commit b2a9b22478
270 changed files with 18120 additions and 3332 deletions

View File

@@ -0,0 +1,499 @@
' Copyright (C) 2023 Andy https://github.com/AAndyProgram
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY
Imports System.ComponentModel
Imports PersonalUtilities.Tools
Imports PersonalUtilities.Forms
Imports PersonalUtilities.Forms.Toolbars
Imports PersonalUtilities.Forms.Controls.KeyClick
Imports PersonalUtilities.Functions.XML
Imports PersonalUtilities.Functions.XML.Base
Imports PersonalUtilities.Functions.Messaging
Imports SCrawler.API.YouTube
Imports SCrawler.API.YouTube.Base
Imports SCrawler.API.YouTube.Controls
Imports SCrawler.API.YouTube.Objects
Namespace DownloadObjects.STDownloader
Public Class VideoListForm : Implements IDesignXMLContainer
#Region "Declarations"
Private ReadOnly MyView As FormView
Private ReadOnly MyProgress As MyProgress
Protected WithEvents MyJob As JobThread(Of MediaItem)
Public Property DesignXML As EContainer Implements IDesignXMLContainer.DesignXML
Public Property DesignXMLNodes As String() Implements IDesignXMLContainer.DesignXMLNodes
Public Property DesignXMLNodeName As String Implements IDesignXMLContainer.DesignXMLNodeName
Private ReadOnly ControlsDownloaded As New FPredicate(Of MediaItem)(Function(i) i.MyContainer.MediaState = Plugin.UserMediaStates.Downloaded)
Private ReadOnly ControlsChecked As Predicate(Of MediaItem) = Function(i) i.Checked
Private ReadOnly CNT_PROCESSOR As TableControlsProcessor
Protected AppMode As Boolean = True
#End Region
#Region "Initializer"
Public Sub New()
InitializeComponent()
CNT_PROCESSOR = New TableControlsProcessor(TP_CONTROLS)
MyView = New FormView(Me)
MyProgress = New MyProgress(TOOLBAR_BOTTOM, PR_MAIN, LBL_INFO)
MyJob = New JobThread(Of MediaItem)
End Sub
#End Region
#Region "Form handlers"
Protected Overridable Sub VideoListForm_Load(sender As Object, e As EventArgs) Handles Me.Load
If Not LicenseManager.UsageMode = LicenseUsageMode.Designtime Then
If MyYouTubeSettings Is Nothing Then MyYouTubeSettings = New YouTubeSettings
DesignXML = MyYouTubeSettings.DesignXml
If MyCache Is Nothing Then MyCache = New CacheKeeper(YouTubeFunctions.YouTubeCachePathRoot)
End If
If AppMode Then
If Now.Month.ValueBetween(6, 8) Then Text = "SCrawler: Happy LGBT Pride Month! :-)"
MyNotificator = New YTNotificator(Me)
MyDownloaderSettings = MyYouTubeSettings
End If
With MyView : .Import() : .SetFormSize() : End With
BTT_DELETE.Enabled = False
If Not AppMode Then
BTT_SETTINGS.Visible = False
SEP_1.Visible = False
SEP_LOG.Visible = False
BTT_LOG.Visible = False
BTT_INFO.Visible = False
BTT_DONATE.Visible = False
End If
MyProgress.Visible = False
LoadData()
End Sub
Protected Overridable Sub VideoListForm_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
If Not AppMode Then e.Cancel = True : Hide()
End Sub
Protected Overridable Sub VideoListForm_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed
MyView.Dispose()
MyCache.DisposeIfReady()
If AppMode Then
MyNotificator.Clear()
If Not MyMainLOG.IsEmptyString Then SaveLogToFile()
End If
If Not MyYouTubeSettings Is Nothing Then MyYouTubeSettings.Close()
End Sub
Private Sub VideoListForm_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
If e.KeyCode = Keys.Insert Then BTT_ADD.PerformClick() : e.Handled = True
End Sub
#End Region
#Region "Refill, save list"
Protected Sub LoadData()
Dim c As List(Of IYouTubeMediaContainer) = LoadData_GetFiles()
If c.ListExists Then
c.Sort(New ContainerDateComparer)
SuspendLayout()
For i% = c.Count - 1 To 0 Step -1 : ControlCreateAndAdd(c(i), True, i = 0) : Next
ResumeLayout(False)
PerformLayout()
End If
End Sub
Protected Overridable Function LoadData_GetFiles() As List(Of IYouTubeMediaContainer)
Try
Dim l As New List(Of IYouTubeMediaContainer)
Dim path As SFile = DownloaderDataFolderYouTube
If path.Exists(SFO.Path, False) Then
Dim files As List(Of SFile) = SFile.GetFiles(path, "*.xml",, EDP.ReturnValue)
If files.Count > 0 Then files.ForEach(Sub(f) l.Add(YouTubeFunctions.CreateContainer(f)))
End If
If l.Count > 0 Then l.RemoveAll(Function(c) c Is Nothing)
If l.Count > 0 Then l.ListDisposeRemoveAll(Function(c) Not c.Exists)
Return l
Catch ex As Exception
Dim e As EDP = EDP.LogMessageValue
If Not ex.HelpLink.IsEmptyString AndAlso ex.HelpLink = NameOf(YouTubeFunctions.CreateContainer) Then e = EDP.SendToLog + EDP.ReturnValue
Return ErrorsDescriber.Execute(e, ex, "VideoListForm.LoadData_GetFiles", New List(Of IYouTubeMediaContainer))
End Try
End Function
#End Region
#Region "Controls"
Protected Sub ControlCreateAndAdd(ByVal Container As IYouTubeMediaContainer, Optional ByVal DisableDownload As Boolean = False,
Optional ByVal PerformClick As Boolean = True)
ControlInvokeFast(TP_CONTROLS, Sub()
With TP_CONTROLS
.SuspendLayout()
If DisableDownload Or Not MyDownloaderSettings.DownloadAutomatically Then Container.Save()
'.AutoScroll = True
'.HorizontalScroll.Visible = False
.RowStyles.Insert(0, New RowStyle(SizeType.Absolute, 60))
.RowCount = .RowStyles.Count
OffsetControls(0, True)
Dim cnt As New MediaItem(Container) With {.Dock = DockStyle.Fill, .Margin = New Padding(0)}
AddHandler cnt.FileDownloaded, AddressOf MediaControl_FileDownloaded
AddHandler cnt.Removal, AddressOf MediaControl_Removal
AddHandler cnt.DownloadAgain, AddressOf MediaControl_DownloadAgain
AddHandler cnt.DownloadRequested, AddressOf MediaControl_DownloadRequested
AddHandler cnt.CheckedChanged, AddressOf MediaControl_CheckedChanged
AddHandler cnt.Click, AddressOf CNT_PROCESSOR.MediaItem_Click
AddHandler cnt.KeyDown, AddressOf CNT_PROCESSOR.MediaItem_KeyDown
.Controls.Add(cnt, 0, 0)
.Controls.Cast(Of ISupportInitialize).ToList.ForEach(Sub(_cnt) _cnt.EndInit())
.ScrollControlIntoView(cnt)
cnt.Select()
RefillColors()
'.AutoScroll = False
'.AutoScroll = True
.ResumeLayout()
.PerformLayout()
UpdateScrolls(Me, Nothing)
If PerformClick Then cnt.PerformClick()
If Not DisableDownload And MyDownloaderSettings.DownloadAutomatically Then AddToDownload(cnt, True)
End With
End Sub, EDP.None)
End Sub
#Region "Controls rendering"
Private Overloads Sub OffsetControls()
Try
With TP_CONTROLS
If .Controls.Count > 0 Then
Dim i%, ri%
Dim cntIndx% = -1
Dim cnt As Control
For i = .Controls.Count - 1 To 0 Step -1
cnt = .Controls(i)
If Not cnt Is Nothing Then cntIndx += 1 : .SetCellPosition(cnt, New TableLayoutPanelCellPosition(0, cntIndx))
Next
For i = .RowStyles.Count - 1 To 0 Step -1
If Not .GetControlFromPosition(0, i) Is Nothing Then
If i + 1 < .RowStyles.Count - 1 Then
For ri = .RowStyles.Count - 1 To i + 1 Step -1 : .RowStyles.RemoveAt(i) : Next
.RowStyles.Add(New RowStyle(SizeType.AutoSize))
.RowCount = .RowStyles.Count
End If
Exit For
End If
Next
Else
.RowStyles.Clear()
.RowCount = 0
.RowStyles.Add(New RowStyle(SizeType.AutoSize))
.RowCount = .RowStyles.Count
End If
End With
Catch
End Try
End Sub
Private Overloads Sub OffsetControls(ByVal ReflectedRow As Integer, ByVal Add As Boolean)
ControlInvokeFast(TP_CONTROLS, Sub()
Dim offset% = IIf(Add, 1, -1)
Dim cnt As Control
With TP_CONTROLS
If .RowStyles.Count > 1 Then
For i% = .RowStyles.Count - 1 To ReflectedRow Step -1
cnt = .GetControlFromPosition(0, i)
If Not cnt Is Nothing Then .SetCellPosition(cnt, New TableLayoutPanelCellPosition(0, i + offset))
Next
End If
End With
End Sub, EDP.None)
End Sub
Private Sub RefillColors()
ControlInvokeFast(TP_CONTROLS, Sub()
With TP_CONTROLS
If .Controls.Count > 0 Then
Dim i% = 0
Dim c As Color
For Each cnt As MediaItem In .Controls
i += 1
If (i Mod 2) = 0 Then c = SystemColors.ControlLight Else c = SystemColors.Window
cnt.BackColor = c
Next
End If
End With
End Sub, EDP.None)
End Sub
Private Sub UpdateScrolls(sender As Object, e As EventArgs) Handles TP_CONTROLS.StyleChanged, Me.ResizeEnd, Me.SizeChanged
ControlInvokeFast(TP_CONTROLS, Sub()
With TP_CONTROLS
.SuspendLayout()
.Padding = New Padding(0, 0, .VerticalScroll.Visible.BoolToInteger * 3, 0)
.HorizontalScroll.Visible = False
.HorizontalScroll.Enabled = False
.ResumeLayout()
.PerformLayout()
End With
End Sub, EDP.None)
End Sub
#End Region
#Region "Toolbar controls handlers"
Protected Overridable Sub BTT_SETTINGS_Click(sender As Object, e As EventArgs) Handles BTT_SETTINGS.Click
MyYouTubeSettings.ShowForm(AppMode)
End Sub
Protected Overridable Sub BTT_ADD_KeyClick(ByVal Sender As ToolStripMenuItemKeyClick, ByVal e As KeyClickEventArgs) Handles BTT_ADD.KeyClick, BTT_ADD_PLS_ARR.KeyClick,
BTT_ADD_NO_SHORTS.KeyClick, BTT_ADD_SHORTS_ONLY.KeyClick
Dim pForm As ParsingProgressForm = Nothing
Try
Dim canProcess As Boolean = True
If TP_CONTROLS.Controls.Count >= MyYouTubeSettings.ItemsListLimit Then canProcess = TP_CONTROLS.Controls.Cast(Of MediaItem).ListExists(ControlsDownloaded)
If canProcess Then
Dim useCookies As Boolean = MyYouTubeSettings.DefaultUseCookies
If e.Control Then useCookies = True
Dim useCookiesParse As Boolean? = Nothing
If useCookies Then useCookiesParse = True
Dim c As IYouTubeMediaContainer = Nothing
Dim url$ = String.Empty
Dim GetDefault As Boolean = True
Dim GetShorts As Boolean = True
If Sender.Tag = "pls" Then
Using pf As New PlaylistArrayForm With {.DesignXML = DesignXML}
pf.ShowDialog()
If pf.DialogResult = DialogResult.OK Then
With pf.URLs
If .Count > 0 Then
pForm = New ParsingProgressForm
pForm.Show()
pForm.SetInitialValues(.Count, "Parsing playlists...")
Dim containers As New List(Of IYouTubeMediaContainer)
For Each u$ In .Self : containers.Add(YouTubeFunctions.Parse(u, useCookiesParse, pForm.Token, pForm.MyProgress, True, False)) : pForm.MyProgress.Perform() : Next
pForm.Dispose()
If containers.Count > 0 Then containers.ListDisposeRemoveAll(Function(cc) cc.HasError Or Not cc.Exists)
If containers.Count > 0 Then
c = New Channel With {.UserTitle = IIf(pf.IsOneArtist, containers(0).UserTitle, "Playlists")}
c.Elements.AddRange(containers)
End If
End If
End With
End If
End Using
Else
Select Case CStr(Sender.Tag)
Case "ans" : GetShorts = False
Case "as" : GetDefault = False : GetShorts = True
End Select
url = BufferText
If url.IsEmptyString OrElse Not YouTubeFunctions.IsMyUrl(url) Then url = InputBoxE("Enter a valid URL to the YouTube video:", "YouTube link")
End If
If Not c Is Nothing OrElse YouTubeFunctions.IsMyUrl(url) Then
If c Is Nothing Then
pForm = New ParsingProgressForm
pForm.Show()
pForm.SetInitialValues(1, "Parsing data...")
c = YouTubeFunctions.Parse(url, useCookiesParse, pForm.Token, pForm.MyProgress, GetDefault, GetShorts)
pForm.Dispose()
End If
If Not c Is Nothing Then
Dim f As Form
Select Case c.ObjectType
Case YouTubeMediaType.Single : f = New VideoOptionsForm(c)
Case YouTubeMediaType.Channel, YouTubeMediaType.PlayList
If c.IsMusic Then
f = New MusicPlaylistsForm(c)
Else
f = New VideoOptionsForm(c)
End If
Case Else : c.Dispose() : Throw New ArgumentException($"Object type {c.ObjectType} not implemented", "IYouTubeMediaContainer.ObjectType")
End Select
If Not f Is Nothing Then
If TypeOf f Is IDesignXMLContainer Then DirectCast(f, IDesignXMLContainer).DesignXML = DesignXML
f.ShowDialog()
If f.DialogResult = DialogResult.OK Then
If TP_CONTROLS.Controls.Count >= MyYouTubeSettings.ItemsListLimit Then _
RemoveControls(TP_CONTROLS.Controls.Cast(Of MediaItem).LastOrDefault(ControlsDownloaded))
ControlCreateAndAdd(c)
End If
f.Dispose()
End If
End If
End If
Else
MsgBoxE({$"Number of items to download exceeded!{vbCr}Reduce the number of items or increase the limit.", "New download"}, vbCritical)
End If
Catch oex As OperationCanceledException
Catch dex As ObjectDisposedException
Catch ex As Exception
ErrorsDescriber.Execute(EDP.LogMessageValue, ex, "VideoListForm.Add")
UpdateLogButton()
Finally
If Not pForm Is Nothing Then pForm.Dispose()
End Try
End Sub
Private Sub BTT_DOWN_Click(sender As Object, e As EventArgs) Handles BTT_DOWN.Click
With TP_CONTROLS
If .Controls.Count > 0 Then
For Each cnt As MediaItem In .Controls
If Not cnt.MyContainer.MediaState = Plugin.UserMediaStates.Downloaded And Not cnt.Pending Then AddToDownload(cnt, False)
Next
End If
End With
StartDownloading()
End Sub
Private Sub BTT_STOP_Click(sender As Object, e As EventArgs) Handles BTT_STOP.Click
ControlInvoke(TOOLBAR_TOP, BTT_STOP, Sub() BTT_STOP.Enabled = False, EDP.SendToLog)
MyJob.Cancel()
End Sub
Private Sub BTT_DELETE_Click(sender As Object, e As EventArgs) Handles BTT_DELETE.Click
RemoveControls(ControlsChecked)
End Sub
Protected Overridable Sub BTT_CLEAR_DONE_Click(sender As Object, e As EventArgs) Handles BTT_CLEAR_DONE.Click
RemoveControls(ControlsDownloaded)
End Sub
Protected Overridable Sub BTT_CLEAR_ALL_Click(sender As Object, e As EventArgs) Handles BTT_CLEAR_ALL.Click
RemoveControls()
End Sub
Private Sub BTT_LOG_Click(sender As Object, e As EventArgs) Handles BTT_LOG.Click
MyMainLOG_ShowForm(DesignXML,,,, AddressOf UpdateLogButton)
End Sub
Friend Sub UpdateLogButton()
If AppMode Then MyMainLOG_UpdateLogButton(BTT_LOG, TOOLBAR_TOP)
End Sub
Private Sub BTT_DONATE_Click(sender As Object, e As EventArgs) Handles BTT_DONATE.Click
Try : Process.Start("https://github.com/AAndyProgram/SCrawler/blob/main/HowToSupport.md") : Catch : End Try
End Sub
Private Sub BTT_INFO_Click(sender As Object, e As EventArgs) Handles BTT_INFO.Click
Try
MsgBoxE({$"YouTube Downloader v{My.Application.Info.Version}" & vbCr &
$"Address: https://github.com/AAndyProgram/SCrawler" & vbCr &
"Created by Greek LGBT person Andy (Gay)",
"Program information"},,,,
{"OK", New MsgBoxButton("Go to site") With {.CallBack = Sub(r, n, b) Process.Start("https://github.com/AAndyProgram/SCrawler/releases")}})
Catch
End Try
End Sub
Protected Overloads Sub RemoveControls(Optional ByVal Predicate As Predicate(Of MediaItem) = Nothing)
ControlInvokeFast(TP_CONTROLS, Sub()
With TP_CONTROLS
If .Controls.Count > 0 Then
Dim i%
Dim rCnt As New List(Of Integer)
Dim predicateExists As Boolean = Not Predicate Is Nothing
For i = 0 To .Controls.Count - 1
If Not predicateExists OrElse Predicate.Invoke(.Controls(i)) Then rCnt.Add(i)
Next
If rCnt.Count > 0 Then
Dim cnt As MediaItem
For i = rCnt.Count - 1 To 0 Step -1
cnt = .Controls(rCnt(i))
.Controls.RemoveAt(rCnt(i))
If Not cnt.MyContainer Is Nothing Then cnt.MyContainer.Delete(False)
cnt.Dispose()
Next
End If
End If
If .Controls.Count > 0 Then
OffsetControls()
Else
.RowStyles.Clear()
.RowStyles.Add(New RowStyle(SizeType.AutoSize))
.RowCount = 1
End If
End With
UpdateScrolls(Nothing, Nothing)
End Sub, EDP.None)
End Sub
Private Overloads Sub RemoveControls(ByVal CNT As MediaItem)
ControlInvokeFast(TP_CONTROLS, Sub()
If Not CNT Is Nothing Then TP_CONTROLS.Controls.Remove(CNT) : OffsetControls()
End Sub, EDP.None)
End Sub
#End Region
#Region "Media controls' handlers"
Private Sub MediaControl_FileDownloaded(ByVal Sender As MediaItem, ByVal Container As IYouTubeMediaContainer)
If MyDownloaderSettings.ShowNotifications Then MyNotificator.ShowNotification(Container.ToString(), Container.ThumbnailFile)
If MyDownloaderSettings.RemoveDownloadedAutomatically Then RemoveControls(Sender)
End Sub
Private Sub MediaControl_Removal(ByVal Sender As MediaItem, ByVal Container As IYouTubeMediaContainer)
RemoveControls(Sender)
End Sub
Private Sub MediaControl_DownloadAgain(ByVal Sender As MediaItem, ByVal Container As IYouTubeMediaContainer)
If Not Container.URL.IsEmptyString Then BufferText = Container.URL : BTT_ADD.PerformClick()
End Sub
Private Sub MediaControl_DownloadRequested(ByVal Sender As MediaItem, ByVal Container As IYouTubeMediaContainer)
AddToDownload(Sender, True)
End Sub
Private Sub MediaControl_CheckedChanged(ByVal Sender As MediaItem, ByVal Container As IYouTubeMediaContainer)
With TP_CONTROLS.Controls
ControlInvokeFast(TOOLBAR_TOP, BTT_DELETE,
Sub() BTT_DELETE.Enabled = .Count > 0 AndAlso .Cast(Of MediaItem).ListExists(Function(cnt) cnt.Checked), EDP.None)
End With
End Sub
#End Region
#End Region
#Region "Downloading"
Protected Overridable Sub MyJob_Started(ByVal Sender As Object, ByVal e As EventArgs) Handles MyJob.Started
End Sub
Protected Overridable Sub MyJob_Finished(ByVal Sender As Object, ByVal e As EventArgs) Handles MyJob.Finished
UpdateLogButton()
End Sub
Protected Sub AddToDownload(ByRef Item As MediaItem, ByVal RunThread As Boolean)
If MyJob.Count = 0 OrElse Not MyJob.Items.Exists(Function(i) i.MyContainer.GetHashCode) Then
Item.Pending = True
MyJob.Add(Item)
Item.AddToQueue()
If RunThread Then StartDownloading()
End If
End Sub
Private Sub StartDownloading()
If Not MyJob.Working And MyJob.Count > 0 Then
EnableDownloadButtons(True)
MyJob.StartThread(AddressOf DownloadData)
End If
End Sub
Private Sub EnableDownloadButtons(ByVal Downloading As Boolean)
ControlInvoke(TOOLBAR_TOP, BTT_DOWN, Sub()
BTT_DOWN.Enabled = Not Downloading
BTT_STOP.Enabled = Downloading
End Sub, EDP.SendToLog)
End Sub
Private ReadOnly PNumProv As New ANumbers With {.FormatOptions = ANumbers.Options.GroupIntegral}
Private Sub DownloadData()
Try
MyJob.Start()
Const nf As ANumbers.Formats = ANumbers.Formats.Number
Dim t As New List(Of Task)
Dim i%
Dim __item As MediaItem
Dim Indexes As New List(Of Integer)
Dim maxJobCount% = MyDownloaderSettings.MaxJobsCount
If maxJobCount <= 0 Then maxJobCount = 1
MyProgress.Visible = True
MyProgress.Maximum = MyJob.Count
Do While MyJob.Count > 0 And Not MyJob.IsCancellationRequested
i = -1
Indexes.Clear()
For Each __item In MyJob.Items
i += 1
If i <= maxJobCount - 1 Then
Indexes.Add(i)
t.Add(Task.Run(Sub() __item.Download(MyJob.Token)))
Else
Exit For
End If
Next
If t.Count > 0 Then
MyProgress.Information = $"Downloading {t.Count.NumToString(nf, PNumProv)}/{MyJob.Count.NumToString(nf, PNumProv)}"
MyProgress.InformationTemporary = MyProgress.Information
Task.WaitAll(t.ToArray)
MyProgress.Perform(t.Count)
If Indexes.Count > 0 Then
For i = Indexes.Count - 1 To 0 Step -1 : MyJob.Items.RemoveAt(Indexes(i)) : Next
End If
t.Clear()
End If
Loop
Indexes.Clear()
MyProgress.Done()
MyProgress.InformationTemporary = "Download completed"
Catch aoex As ArgumentOutOfRangeException
Catch oex As OperationCanceledException
MyProgress.InformationTemporary = "Download canceled"
Catch ex As Exception
MyProgress.InformationTemporary = "Download error"
ErrorsDescriber.Execute(EDP.SendToLog, ex, "[VideoListForm.DownloadData]")
Finally
MyJob.Finish()
EnableDownloadButtons(False)
End Try
End Sub
#End Region
End Class
End Namespace