2023.12.13.0

YT
Structures: add 'YouTubeChannelTab' enum
YouTubeFunctions: add 'StandardizeURL_Channel' function; update 'Info_GetUrlType', 'Parse' and 'Parse_Internal' functions (YouTubeChannelTab)
YouTubeSettings: add 'ChannelsDownload' property and 'YouTubeChannelTabConverter' converter for grid
Add 'ChannelTabsChooserForm'
VideoListForm: remove buttons 'BTT_ADD_NO_SHORTS' and 'BTT_ADD_SHORTS_ONLY'; update 'BTT_ADD_KeyClick' function

SCrawler
API.M3U8Base: add 'M3U8URL' structure; update 'Download' function with 'OnlyDownload' arg
API.ProfileSaved: add sorting of feed files
API.Xhamster: update M3U8 parser and 'Download' function for additional downloading ways; add 'ReencodeVideos' property (to the 'SiteSettings')
API.YouTube: update to updated 'Parse' function
This commit is contained in:
Andy
2023-12-13 19:48:50 +03:00
parent 64d6e6b28c
commit 1455a31879
23 changed files with 882 additions and 332 deletions

View File

@@ -1,3 +1,15 @@
# 2023.12.13.0
*2023-12-13*
- Added
- YouTube (standalone app): additional options for downloading channels
- Updated
- gallery-dl up to version 1.26.4
- Fixed
- Feed: saved posts are added to the end of the feed
- xHamster: some videos won't download
# 2023.12.10.0
*2023-12-10*

View File

@@ -62,6 +62,14 @@ Namespace API.YouTube.Base
Channel = 2
PlayList = 3
End Enum
<Editor(GetType(EnumDropDownEditor), GetType(UITypeEditor)), Flags>
Public Enum YouTubeChannelTab As Integer
<EnumValue(IsNullValue:=True)>
All = 0
Videos = 1
Shorts = 3
Playlists = 10
End Enum
<Editor(GetType(EnumDropDownEditor), GetType(UITypeEditor))>
Public Enum Protocols As Integer
<EnumValue(ExcludeFromList:=True)>

View File

@@ -43,11 +43,35 @@ Namespace API.YouTube.Base
Return URL
End Try
End Function
Public Shared Function StandardizeURL_Channel(ByVal URL As String, Optional ByVal Process As Boolean = True) As String
Try
Dim ct As YouTubeChannelTab = YouTubeChannelTab.All
Dim isMusic As Boolean = False
If Process AndAlso Info_GetUrlType(URL, isMusic,,,, ct) = YouTubeMediaType.Channel AndAlso Not isMusic Then
If Not ct = YouTubeChannelTab.All Then
Dim rValue$ = String.Empty
Select Case ct
Case YouTubeChannelTab.Videos : rValue = "/videos"
Case YouTubeChannelTab.Shorts : rValue = "/shorts"
Case YouTubeChannelTab.Playlists : rValue = "/playlists"
End Select
If Not rValue.IsEmptyString Then
Dim startIndx% = InStr(URL, rValue)
If startIndx > 0 Then URL = URL.Remove(startIndx - 1)
End If
End If
End If
Return URL
Catch ex As Exception
Return URL
End Try
End Function
Public Shared Function IsMyUrl(ByVal URL As String) As Boolean
Return Not Info_GetUrlType(URL) = YouTubeMediaType.Undefined
End Function
Public Shared Function Info_GetUrlType(ByVal URL As String, Optional ByRef IsMusic As Boolean = False, Optional ByRef IsShorts As Boolean = False,
Optional ByRef IsChannelUser As Boolean = False, Optional ByRef Id As String = Nothing) As YouTubeMediaType
Optional ByRef IsChannelUser As Boolean = False, Optional ByRef Id As String = Nothing,
Optional ByRef ChannelOptions As YouTubeChannelTab = YouTubeChannelTab.All) As YouTubeMediaType
If Not URL.IsEmptyString Then
IsMusic = URL.Contains("music.youtube.com")
IsChannelUser = False
@@ -60,7 +84,17 @@ Namespace API.YouTube.Base
Case "watch" : Return YouTubeMediaType.Single
Case "shorts" : IsShorts = True : Return YouTubeMediaType.Single
Case "playlist" : Return YouTubeMediaType.PlayList
Case UserChannelOption, "@" : IsChannelUser = data(2).ToLower = UserChannelOption : Return YouTubeMediaType.Channel
Case UserChannelOption, "@"
IsChannelUser = data(2).ToLower = UserChannelOption
If data.Count > 6 Then
Select Case data(6).StringToLower.StringTrimStart("/")
Case "videos" : ChannelOptions = YouTubeChannelTab.Videos
Case "shorts" : ChannelOptions = YouTubeChannelTab.Shorts
Case "playlists" : ChannelOptions = YouTubeChannelTab.Playlists
Case Else : ChannelOptions = YouTubeChannelTab.All
End Select
End If
Return YouTubeMediaType.Channel
End Select
End If
End If
@@ -82,27 +116,25 @@ Namespace API.YouTube.Base
''' <exception cref="InvalidOperationException"></exception>
Public Shared Function Parse(ByVal URL As String, Optional ByVal UseCookies As Boolean? = Nothing,
Optional ByVal Token As Threading.CancellationToken = Nothing, Optional ByVal Progress As IMyProgress = Nothing,
Optional ByVal GetDefault As Boolean? = Nothing, Optional ByVal GetShorts As Boolean? = Nothing,
Optional ByVal DateAfter As Date? = Nothing, Optional ByVal DateBefore As Date? = Nothing) As IYouTubeMediaContainer
Optional ByVal DateAfter As Date? = Nothing, Optional ByVal DateBefore As Date? = Nothing,
Optional ByVal ChannelOption As YouTubeChannelTab? = Nothing, Optional ByVal UrlAsIs As Boolean = False) As IYouTubeMediaContainer
If URL.IsEmptyString Then Throw New ArgumentNullException("URL", "URL cannot be null")
If Not MyYouTubeSettings.YTDLP.Value.Exists Then Throw New IO.FileNotFoundException("Path to 'yt-dlp.exe' not set or program not found at destination", MyYouTubeSettings.YTDLP.Value.ToString)
Dim urlOrig$ = URL
URL = RegexReplace(URL, TrueUrlRegEx)
If URL.IsEmptyString Then Throw New ArgumentNullException("URL", $"Can't get true URL from [{urlOrig}]")
Dim isMusic As Boolean = False, isShorts As Boolean = False
Dim objType As YouTubeMediaType = Info_GetUrlType(URL, isMusic, isShorts)
Dim channelTab As YouTubeChannelTab = YouTubeChannelTab.All
Dim objType As YouTubeMediaType = Info_GetUrlType(URL, isMusic, isShorts,,, channelTab)
If ChannelOption.HasValue Then channelTab = ChannelOption.Value
If Not objType = YouTubeMediaType.Undefined Then
Dim __GetDefault As Boolean = If(GetDefault, True)
Dim __GetShorts As Boolean = If(GetShorts, True)
If isMusic Then __GetShorts = False
Dim container As IYouTubeMediaContainer
Dim pattern$ = "%(channel_id)s_%(id)s_%(playlist_index)s"
Select Case objType
Case YouTubeMediaType.Single
__GetShorts = False
If isMusic Then container = New Track Else container = New Video
Case YouTubeMediaType.PlayList : container = New PlayList : pattern = "%(playlist_index)s_%(id)s" : __GetShorts = False
Case YouTubeMediaType.PlayList : container = New PlayList : pattern = "%(playlist_index)s_%(id)s"
Case YouTubeMediaType.Channel
container = New Channel
If isMusic Then pattern = "%(playlist_id)s/%(channel_id)s_%(id)s_%(playlist_index)s"
@@ -121,11 +153,11 @@ Namespace API.YouTube.Base
Dim useCookiesForce As Boolean = UseCookies.HasValue AndAlso UseCookies.Value AndAlso cookiesExists
If UseCookies.HasValue AndAlso UseCookies.Value Then
withCookieRequested = True
result = Parse_Internal(URL, pattern, _CachePathDefault, True, YouTubeCookieNetscapeFile, DateAfter, DateBefore, __GetDefault, __GetShorts)
result = Parse_Internal(URL, pattern, _CachePathDefault, True, YouTubeCookieNetscapeFile, DateAfter, DateBefore, objType, channelTab, isMusic, UrlAsIs)
End If
If Not result And Not withCookieRequested Then
If Not UseCookies.HasValue OrElse Not UseCookies.Value Then result = Parse_Internal(URL, pattern, _CachePathDefault, False, YouTubeCookieNetscapeFile, DateAfter, DateBefore, __GetDefault, __GetShorts)
If Not result And Not UseCookies.HasValue And cookiesExists Then result = Parse_Internal(URL, pattern, _CachePathDefault, True, YouTubeCookieNetscapeFile, DateAfter, DateBefore, __GetDefault, __GetShorts)
If Not UseCookies.HasValue OrElse Not UseCookies.Value Then result = Parse_Internal(URL, pattern, _CachePathDefault, False, YouTubeCookieNetscapeFile, DateAfter, DateBefore, objType, channelTab, isMusic, UrlAsIs)
If Not result And Not UseCookies.HasValue And cookiesExists Then result = Parse_Internal(URL, pattern, _CachePathDefault, True, YouTubeCookieNetscapeFile, DateAfter, DateBefore, objType, channelTab, isMusic, UrlAsIs)
End If
If result Then
@@ -139,21 +171,40 @@ Namespace API.YouTube.Base
Private Shared Function Parse_Internal(ByVal URL As String, ByVal OutputPattern As String, ByVal OutputPath As SFile,
ByVal UseCookies As Boolean, ByVal CookiesFile As SFile,
ByVal DateAfter As Date?, ByVal DateBefore As Date?,
ByVal GetDefault As Boolean, ByVal GetShorts As Boolean) As Boolean
ByVal ObjType As YouTubeMediaType, ByVal ChannelTab As YouTubeChannelTab,
ByVal IsMusic As Boolean, ByVal UrlAsIs As Boolean) As Boolean
Try
Dim command$ = "yt-dlp --write-info-json --skip-download"
command.StringAppend(GetCookiesCommand(UseCookies, CookiesFile), " ")
If DateAfter.HasValue Then command.StringAppend($"--dateafter {DateAfter.Value:yyyyMMdd}", " ")
If DateBefore.HasValue Then command.StringAppend($"--datebefore {DateBefore.Value:yyyyMMdd}", " ")
command.StringAppend("{0}" & $" -o ""{OutputPattern}""", " ")
'#If DEBUG Then
'Debug.WriteLine(String.Format(command, URL))
'#End If
Dim debugString As Func(Of String, String) = Function(ByVal input As String) As String
#If DEBUG Then
Debug.WriteLine(String.Format(command, URL))
Debug.WriteLine(input)
#End If
Return input
End Function
Using batch As New BatchExecutor(True)
With batch
.CommandPermanent = BatchExecutor.GetDirectoryCommand(MyYouTubeSettings.YTDLP.Value)
If GetDefault Then .Execute(String.Format(command, URL))
If GetShorts Then .Execute(String.Format(command, $"{URL.StringTrimEnd("/")}/shorts"))
If ObjType = YouTubeMediaType.Channel And Not IsMusic And Not UrlAsIs Then
Dim ct As List(Of YouTubeChannelTab) = EnumExtract(Of YouTubeChannelTab)(ChannelTab,, True).ListIfNothing
If ct.Count = 0 Then
.Execute(debugString(String.Format(command, $"{URL.StringTrimEnd("/")}/videos")))
.Execute(debugString(String.Format(command, $"{URL.StringTrimEnd("/")}/shorts")))
.Execute(debugString(String.Format(command, $"{URL.StringTrimEnd("/")}/playlists")))
Else
If ct.Contains(YouTubeChannelTab.Videos) Then .Execute(debugString(String.Format(command, $"{URL.StringTrimEnd("/")}/videos")))
If ct.Contains(YouTubeChannelTab.Shorts) Then .Execute(debugString(String.Format(command, $"{URL.StringTrimEnd("/")}/shorts")))
If ct.Contains(YouTubeChannelTab.Playlists) Then .Execute(debugString(String.Format(command, $"{URL.StringTrimEnd("/")}/playlists")))
End If
Else
.Execute(debugString(String.Format(command, URL)))
End If
End With
End Using
Return SFile.GetFiles(OutputPath,, IO.SearchOption.AllDirectories, EDP.ReturnValue).Count > 0

View File

@@ -223,6 +223,38 @@ Namespace API.YouTube.Base
Description("Add some additional info to the program info if you need")>
Friend ReadOnly Property ProgramDescription As XMLValue(Of String)
#End Region
#Region "Defaults ChannelsDownload"
<Browsable(True), GridVisible, XMLVN({"Defaults", "Channels"}), Category("Defaults"), DisplayName("Default download tabs for channels"),
Description("Default download tabs for downloading channels"), TypeConverter(GetType(YouTubeChannelTabConverter))>
Public ReadOnly Property ChannelsDownload As XMLValue(Of YouTubeChannelTab)
Private Class YouTubeChannelTabConverter : Inherits TypeConverter
Public Overrides Function ConvertTo(ByVal Context As ITypeDescriptorContext, ByVal Culture As CultureInfo, ByVal Value As Object,
ByVal DestinationType As Type) As Object
If Not DestinationType Is Nothing Then
If DestinationType Is GetType(String) Then
If IsNothing(Value) Then
Return YouTubeChannelTab.All.ToString
Else
Dim v As List(Of YouTubeChannelTab) = EnumExtract(Of YouTubeChannelTab)(Value,,, EDP.ReturnValue).ListIfNothing
If v.ListExists Then
v.Sort()
Return v.ListToStringE(, New ANumbers.EnumToStringProvider(GetType(YouTubeChannelTab)))
Else
Return YouTubeChannelTab.All.ToString
End If
End If
Else
If IsNothing(Value) Then
Return YouTubeChannelTab.All
Else
Return Value
End If
End If
End If
Return MyBase.ConvertTo(Context, Culture, Value, DestinationType)
End Function
End Class
#End Region
#Region "Defaults Video"
<Browsable(True), GridVisible, XMLVN({"DefaultsVideo"}, "MKV"), Category("Defaults Video"), DisplayName("Default format"),
TypeConverter(GetType(FieldsTypeConverter)), GridStandardValuesProvider(NameOf(AvailableVideoFormats_Impl)),

View File

@@ -0,0 +1,179 @@
' Copyright (C) Andy https://github.com/AAndyProgram
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY
Namespace API.YouTube.Controls
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()>
Partial Friend Class ChannelTabsChooserForm : Inherits System.Windows.Forms.Form
<System.Diagnostics.DebuggerNonUserCode()>
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
Try
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
Finally
MyBase.Dispose(disposing)
End Try
End Sub
Private components As System.ComponentModel.IContainer
<System.Diagnostics.DebuggerStepThrough()>
Private Sub InitializeComponent()
Dim CONTAINER_MAIN As System.Windows.Forms.ToolStripContainer
Dim TP_MAIN As System.Windows.Forms.TableLayoutPanel
Me.CH_ALL = New System.Windows.Forms.CheckBox()
Me.CH_VIDEOS = New System.Windows.Forms.CheckBox()
Me.CH_SHORTS = New System.Windows.Forms.CheckBox()
Me.CH_PLS = New System.Windows.Forms.CheckBox()
Me.TXT_URL = New PersonalUtilities.Forms.Controls.TextBoxExtended()
Me.CH_URL_ASIS = New System.Windows.Forms.CheckBox()
CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer()
TP_MAIN = New System.Windows.Forms.TableLayoutPanel()
CONTAINER_MAIN.ContentPanel.SuspendLayout()
CONTAINER_MAIN.SuspendLayout()
TP_MAIN.SuspendLayout()
CType(Me.TXT_URL, System.ComponentModel.ISupportInitialize).BeginInit()
Me.SuspendLayout()
'
'CONTAINER_MAIN
'
'
'CONTAINER_MAIN.ContentPanel
'
CONTAINER_MAIN.ContentPanel.Controls.Add(TP_MAIN)
CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(474, 159)
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(474, 184)
CONTAINER_MAIN.TabIndex = 0
CONTAINER_MAIN.TopToolStripPanelVisible = False
'
'TP_MAIN
'
TP_MAIN.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single]
TP_MAIN.ColumnCount = 1
TP_MAIN.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_MAIN.Controls.Add(Me.CH_ALL, 0, 2)
TP_MAIN.Controls.Add(Me.CH_VIDEOS, 0, 3)
TP_MAIN.Controls.Add(Me.CH_SHORTS, 0, 4)
TP_MAIN.Controls.Add(Me.CH_PLS, 0, 5)
TP_MAIN.Controls.Add(Me.TXT_URL, 0, 0)
TP_MAIN.Controls.Add(Me.CH_URL_ASIS, 0, 1)
TP_MAIN.Dock = System.Windows.Forms.DockStyle.Fill
TP_MAIN.Location = New System.Drawing.Point(0, 0)
TP_MAIN.Name = "TP_MAIN"
TP_MAIN.RowCount = 7
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
TP_MAIN.Size = New System.Drawing.Size(474, 159)
TP_MAIN.TabIndex = 0
'
'CH_ALL
'
Me.CH_ALL.AutoSize = True
Me.CH_ALL.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_ALL.Location = New System.Drawing.Point(4, 59)
Me.CH_ALL.Name = "CH_ALL"
Me.CH_ALL.Size = New System.Drawing.Size(466, 19)
Me.CH_ALL.TabIndex = 2
Me.CH_ALL.Text = "ALL"
Me.CH_ALL.UseVisualStyleBackColor = True
'
'CH_VIDEOS
'
Me.CH_VIDEOS.AutoSize = True
Me.CH_VIDEOS.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_VIDEOS.Location = New System.Drawing.Point(4, 85)
Me.CH_VIDEOS.Name = "CH_VIDEOS"
Me.CH_VIDEOS.Size = New System.Drawing.Size(466, 19)
Me.CH_VIDEOS.TabIndex = 3
Me.CH_VIDEOS.Text = "Videos"
Me.CH_VIDEOS.UseVisualStyleBackColor = True
'
'CH_SHORTS
'
Me.CH_SHORTS.AutoSize = True
Me.CH_SHORTS.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_SHORTS.Location = New System.Drawing.Point(4, 111)
Me.CH_SHORTS.Name = "CH_SHORTS"
Me.CH_SHORTS.Size = New System.Drawing.Size(466, 19)
Me.CH_SHORTS.TabIndex = 4
Me.CH_SHORTS.Text = "Shorts"
Me.CH_SHORTS.UseVisualStyleBackColor = True
'
'CH_PLS
'
Me.CH_PLS.AutoSize = True
Me.CH_PLS.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_PLS.Location = New System.Drawing.Point(4, 137)
Me.CH_PLS.Name = "CH_PLS"
Me.CH_PLS.Size = New System.Drawing.Size(466, 19)
Me.CH_PLS.TabIndex = 5
Me.CH_PLS.Text = "Playlists"
Me.CH_PLS.UseVisualStyleBackColor = True
'
'TXT_URL
'
Me.TXT_URL.CaptionText = "Channel URL"
Me.TXT_URL.CaptionWidth = 80.0R
Me.TXT_URL.Dock = System.Windows.Forms.DockStyle.Fill
Me.TXT_URL.Location = New System.Drawing.Point(4, 4)
Me.TXT_URL.Name = "TXT_URL"
Me.TXT_URL.Size = New System.Drawing.Size(466, 22)
Me.TXT_URL.TabIndex = 0
'
'CH_URL_ASIS
'
Me.CH_URL_ASIS.AutoSize = True
Me.CH_URL_ASIS.Dock = System.Windows.Forms.DockStyle.Fill
Me.CH_URL_ASIS.Location = New System.Drawing.Point(4, 33)
Me.CH_URL_ASIS.Name = "CH_URL_ASIS"
Me.CH_URL_ASIS.Size = New System.Drawing.Size(466, 19)
Me.CH_URL_ASIS.TabIndex = 1
Me.CH_URL_ASIS.Text = "Download URL as is"
Me.CH_URL_ASIS.UseVisualStyleBackColor = True
'
'ChannelTabsChooserForm
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(474, 184)
Me.Controls.Add(CONTAINER_MAIN)
Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle
Me.Icon = Global.SCrawler.My.Resources.SiteYouTube.YouTubeIcon_32
Me.MaximizeBox = False
Me.MaximumSize = New System.Drawing.Size(490, 223)
Me.MinimizeBox = False
Me.MinimumSize = New System.Drawing.Size(490, 223)
Me.Name = "ChannelTabsChooserForm"
Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide
Me.Text = "Tabs"
CONTAINER_MAIN.ContentPanel.ResumeLayout(False)
CONTAINER_MAIN.ResumeLayout(False)
CONTAINER_MAIN.PerformLayout()
TP_MAIN.ResumeLayout(False)
TP_MAIN.PerformLayout()
CType(Me.TXT_URL, System.ComponentModel.ISupportInitialize).EndInit()
Me.ResumeLayout(False)
End Sub
Private WithEvents CH_ALL As CheckBox
Private WithEvents CH_VIDEOS As CheckBox
Private WithEvents CH_SHORTS As CheckBox
Private WithEvents CH_PLS As CheckBox
Private WithEvents TXT_URL As PersonalUtilities.Forms.Controls.TextBoxExtended
Private WithEvents CH_URL_ASIS As CheckBox
End Class
End Namespace

View File

@@ -0,0 +1,126 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="CONTAINER_MAIN.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="TP_MAIN.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
</root>

View File

@@ -0,0 +1,85 @@
' Copyright (C) Andy https://github.com/AAndyProgram
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY
Imports PersonalUtilities.Forms
Imports PersonalUtilities.Functions.XML
Imports PersonalUtilities.Functions.XML.Base
Imports SCrawler.API.YouTube.Base
Namespace API.YouTube.Controls
Friend Class ChannelTabsChooserForm : Implements IDesignXMLContainer
Private WithEvents MyDefs As DefaultFormOptions
Friend Property DesignXML As EContainer Implements IDesignXMLContainer.DesignXML
Private Property DesignXMLNodes As String() Implements IDesignXMLContainer.DesignXMLNodes
Private Property DesignXMLNodeName As String Implements IDesignXMLContainer.DesignXMLNodeName
Private _Result As YouTubeChannelTab = YouTubeChannelTab.All
Friend ReadOnly Property Result As YouTubeChannelTab
Get
Return _Result
End Get
End Property
Friend ReadOnly Property URL As String
Get
Return TXT_URL.Text
End Get
End Property
Friend ReadOnly Property MyUrlAsIs As Boolean
Get
Return CH_URL_ASIS.Checked
End Get
End Property
Friend Sub New(ByVal InitVal As YouTubeChannelTab, ByVal _URL As String)
InitializeComponent()
MyDefs = New DefaultFormOptions(Me)
_Result = InitVal
TXT_URL.Text = _URL
End Sub
Private Sub ChannelTabsChooserForm_Load(sender As Object, e As EventArgs) Handles Me.Load
Try
With MyDefs
MyDefs.MyXML = DesignXML
If Not DesignXML Is Nothing Then .MyViewInitialize(True)
.AddOkCancelToolbar()
If _Result = YouTubeChannelTab.All And Not MyYouTubeSettings Is Nothing Then _Result = MyYouTubeSettings.ChannelsDownload
Dim r() As YouTubeChannelTab = _Result.EnumExtract(Of YouTubeChannelTab)
If r.ListExists Then
For Each value As YouTubeChannelTab In r
Select Case value
Case YouTubeChannelTab.All : CH_ALL.Checked = True
Case YouTubeChannelTab.Videos : CH_VIDEOS.Checked = True
Case YouTubeChannelTab.Shorts : CH_SHORTS.Checked = True
Case YouTubeChannelTab.Playlists : CH_PLS.Checked = True
End Select
Next
Else
CH_ALL.Checked = True
End If
UpdateCheckBoxes()
.EndLoaderOperations()
.MyOkCancel.EnableOK = True
End With
Catch ex As Exception
MyDefs.InvokeLoaderError(ex)
End Try
End Sub
Private Sub MyDefs_ButtonOkClick(ByVal Sender As Object, ByVal e As KeyHandleEventArgs) Handles MyDefs.ButtonOkClick
_Result = YouTubeChannelTab.All
If Not CH_ALL.Checked And {CH_VIDEOS, CH_SHORTS, CH_PLS}.Any(Function(c) c.Checked) Then
If CH_VIDEOS.Checked Then _Result += YouTubeChannelTab.Videos
If CH_SHORTS.Checked Then _Result += YouTubeChannelTab.Shorts
If CH_PLS.Checked Then _Result += YouTubeChannelTab.Playlists
End If
MyDefs.CloseForm()
End Sub
Private Sub UpdateCheckBoxes() Handles CH_ALL.CheckedChanged, CH_URL_ASIS.CheckedChanged
Dim e As Boolean = Not CH_ALL.Checked And Not CH_URL_ASIS.Checked
CH_VIDEOS.Enabled = e
CH_SHORTS.Enabled = e
CH_PLS.Enabled = e
End Sub
End Class
End Namespace

View File

@@ -24,7 +24,6 @@ Namespace DownloadObjects.STDownloader
Private Sub InitializeComponent()
Dim SEP_2 As System.Windows.Forms.ToolStripSeparator
Dim SEP_3 As System.Windows.Forms.ToolStripSeparator
Dim MENU_ADD_SEP_1 As System.Windows.Forms.ToolStripSeparator
Dim MENU_DEL_CLEAR As System.Windows.Forms.ToolStripDropDownButton
Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(VideoListForm))
Dim MENU_DEL_SEP_1 As System.Windows.Forms.ToolStripSeparator
@@ -40,10 +39,6 @@ Namespace DownloadObjects.STDownloader
Me.BTT_SETTINGS = New System.Windows.Forms.ToolStripButton()
Me.SEP_1 = New System.Windows.Forms.ToolStripSeparator()
Me.MENU_ADD = New System.Windows.Forms.ToolStripDropDownButton()
Me.BTT_ADD = New PersonalUtilities.Forms.Controls.KeyClick.ToolStripMenuItemKeyClick()
Me.BTT_ADD_PLS_ARR = New PersonalUtilities.Forms.Controls.KeyClick.ToolStripMenuItemKeyClick()
Me.BTT_ADD_NO_SHORTS = New PersonalUtilities.Forms.Controls.KeyClick.ToolStripMenuItemKeyClick()
Me.BTT_ADD_SHORTS_ONLY = New PersonalUtilities.Forms.Controls.KeyClick.ToolStripMenuItemKeyClick()
Me.BTT_DOWN = New System.Windows.Forms.ToolStripButton()
Me.BTT_STOP = New System.Windows.Forms.ToolStripButton()
Me.SEP_LOG = New System.Windows.Forms.ToolStripSeparator()
@@ -51,9 +46,10 @@ Namespace DownloadObjects.STDownloader
Me.BTT_INFO = New System.Windows.Forms.ToolStripButton()
Me.BTT_DONATE = New System.Windows.Forms.ToolStripButton()
Me.BTT_BUG_REPORT = New System.Windows.Forms.ToolStripButton()
Me.BTT_ADD = New PersonalUtilities.Forms.Controls.KeyClick.ToolStripMenuItemKeyClick()
Me.BTT_ADD_PLS_ARR = New PersonalUtilities.Forms.Controls.KeyClick.ToolStripMenuItemKeyClick()
SEP_2 = New System.Windows.Forms.ToolStripSeparator()
SEP_3 = New System.Windows.Forms.ToolStripSeparator()
MENU_ADD_SEP_1 = New System.Windows.Forms.ToolStripSeparator()
MENU_DEL_CLEAR = New System.Windows.Forms.ToolStripDropDownButton()
MENU_DEL_SEP_1 = New System.Windows.Forms.ToolStripSeparator()
Me.TOOLBAR_BOTTOM.SuspendLayout()
@@ -70,11 +66,6 @@ Namespace DownloadObjects.STDownloader
SEP_3.Name = "SEP_3"
SEP_3.Size = New System.Drawing.Size(6, 25)
'
'MENU_ADD_SEP_1
'
MENU_ADD_SEP_1.Name = "MENU_ADD_SEP_1"
MENU_ADD_SEP_1.Size = New System.Drawing.Size(181, 6)
'
'MENU_DEL_CLEAR
'
MENU_DEL_CLEAR.AutoToolTip = False
@@ -186,60 +177,12 @@ Namespace DownloadObjects.STDownloader
'MENU_ADD
'
Me.MENU_ADD.AutoToolTip = False
Me.MENU_ADD.DropDownItems.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_ADD, Me.BTT_ADD_PLS_ARR, MENU_ADD_SEP_1, Me.BTT_ADD_NO_SHORTS, Me.BTT_ADD_SHORTS_ONLY})
Me.MENU_ADD.DropDownItems.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_ADD, Me.BTT_ADD_PLS_ARR})
Me.MENU_ADD.Image = CType(resources.GetObject("MENU_ADD.Image"), System.Drawing.Image)
Me.MENU_ADD.ImageTransparentColor = System.Drawing.Color.Magenta
Me.MENU_ADD.Name = "MENU_ADD"
Me.MENU_ADD.Size = New System.Drawing.Size(84, 22)
Me.MENU_ADD.Text = "Add (Ins)"
'
'BTT_ADD
'
Me.BTT_ADD.AutoToolTip = True
Me.BTT_ADD.Image = CType(resources.GetObject("BTT_ADD.Image"), System.Drawing.Image)
Me.BTT_ADD.ImageTransparentColor = System.Drawing.Color.Magenta
Me.BTT_ADD.Name = "BTT_ADD"
Me.BTT_ADD.Size = New System.Drawing.Size(184, 22)
Me.BTT_ADD.Tag = "a"
Me.BTT_ADD.Text = "Add (Ins)"
Me.BTT_ADD.ToolTipText = "Click to add." & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Ctrl+click to use cookies for download (if supported)." & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Shift to a" &
"dd without downloading."
'
'BTT_ADD_PLS_ARR
'
Me.BTT_ADD_PLS_ARR.AutoToolTip = True
Me.BTT_ADD_PLS_ARR.Image = CType(resources.GetObject("BTT_ADD_PLS_ARR.Image"), System.Drawing.Image)
Me.BTT_ADD_PLS_ARR.ImageTransparentColor = System.Drawing.Color.Magenta
Me.BTT_ADD_PLS_ARR.Name = "BTT_ADD_PLS_ARR"
Me.BTT_ADD_PLS_ARR.Size = New System.Drawing.Size(184, 22)
Me.BTT_ADD_PLS_ARR.Tag = "pls"
Me.BTT_ADD_PLS_ARR.Text = "Add playlist array"
Me.BTT_ADD_PLS_ARR.ToolTipText = "Click to add." & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Ctrl+click to use cookies for download (if supported)." & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Shift to a" &
"dd without downloading."
'
'BTT_ADD_NO_SHORTS
'
Me.BTT_ADD_NO_SHORTS.AutoToolTip = True
Me.BTT_ADD_NO_SHORTS.Image = CType(resources.GetObject("BTT_ADD_NO_SHORTS.Image"), System.Drawing.Image)
Me.BTT_ADD_NO_SHORTS.ImageTransparentColor = System.Drawing.Color.Magenta
Me.BTT_ADD_NO_SHORTS.Name = "BTT_ADD_NO_SHORTS"
Me.BTT_ADD_NO_SHORTS.Size = New System.Drawing.Size(184, 22)
Me.BTT_ADD_NO_SHORTS.Tag = "ans"
Me.BTT_ADD_NO_SHORTS.Text = "Add (without Shorts)"
Me.BTT_ADD_NO_SHORTS.ToolTipText = "Download all videos except 'Shorts'." & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Click to add." & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Ctrl+click to use cookies fo" &
"r download (if supported)." & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Shift to add without downloading."
'
'BTT_ADD_SHORTS_ONLY
'
Me.BTT_ADD_SHORTS_ONLY.AutoToolTip = True
Me.BTT_ADD_SHORTS_ONLY.Image = CType(resources.GetObject("BTT_ADD_SHORTS_ONLY.Image"), System.Drawing.Image)
Me.BTT_ADD_SHORTS_ONLY.ImageTransparentColor = System.Drawing.Color.Magenta
Me.BTT_ADD_SHORTS_ONLY.Name = "BTT_ADD_SHORTS_ONLY"
Me.BTT_ADD_SHORTS_ONLY.Size = New System.Drawing.Size(184, 22)
Me.BTT_ADD_SHORTS_ONLY.Tag = "as"
Me.BTT_ADD_SHORTS_ONLY.Text = "Add (Shorts only)"
Me.BTT_ADD_SHORTS_ONLY.ToolTipText = "Download only 'Shorts' videos." & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Click to add." & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Ctrl+click to use cookies for down" &
"load (if supported)." & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Shift to add without downloading."
'
'BTT_DOWN
'
@@ -303,6 +246,30 @@ Namespace DownloadObjects.STDownloader
Me.BTT_BUG_REPORT.Name = "BTT_BUG_REPORT"
Me.BTT_BUG_REPORT.Size = New System.Drawing.Size(23, 22)
Me.BTT_BUG_REPORT.Text = "Bug report"
'
'BTT_ADD
'
Me.BTT_ADD.AutoToolTip = True
Me.BTT_ADD.Image = CType(resources.GetObject("BTT_ADD.Image"), System.Drawing.Image)
Me.BTT_ADD.ImageTransparentColor = System.Drawing.Color.Magenta
Me.BTT_ADD.Name = "BTT_ADD"
Me.BTT_ADD.Size = New System.Drawing.Size(180, 22)
Me.BTT_ADD.Tag = "a"
Me.BTT_ADD.Text = "Add (Ins)"
Me.BTT_ADD.ToolTipText = "Click to add." & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Ctrl+click to use cookies for download (if supported)." & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Shift to a" &
"dd without downloading."
'
'BTT_ADD_PLS_ARR
'
Me.BTT_ADD_PLS_ARR.AutoToolTip = True
Me.BTT_ADD_PLS_ARR.Image = CType(resources.GetObject("BTT_ADD_PLS_ARR.Image"), System.Drawing.Image)
Me.BTT_ADD_PLS_ARR.ImageTransparentColor = System.Drawing.Color.Magenta
Me.BTT_ADD_PLS_ARR.Name = "BTT_ADD_PLS_ARR"
Me.BTT_ADD_PLS_ARR.Size = New System.Drawing.Size(180, 22)
Me.BTT_ADD_PLS_ARR.Tag = "pls"
Me.BTT_ADD_PLS_ARR.Text = "Add URL array"
Me.BTT_ADD_PLS_ARR.ToolTipText = "Click to add." & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Ctrl+click to use cookies for download (if supported)." & Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10) & "Shift to a" &
"dd without downloading."
'
'VideoListForm
'
@@ -343,8 +310,6 @@ Namespace DownloadObjects.STDownloader
Private WithEvents BTT_DONATE As ToolStripButton
Protected WithEvents BTT_ADD As PersonalUtilities.Forms.Controls.KeyClick.ToolStripMenuItemKeyClick
Protected WithEvents BTT_ADD_PLS_ARR As PersonalUtilities.Forms.Controls.KeyClick.ToolStripMenuItemKeyClick
Protected WithEvents BTT_ADD_NO_SHORTS As PersonalUtilities.Forms.Controls.KeyClick.ToolStripMenuItemKeyClick
Protected WithEvents BTT_ADD_SHORTS_ONLY As PersonalUtilities.Forms.Controls.KeyClick.ToolStripMenuItemKeyClick
Protected WithEvents MENU_ADD As ToolStripDropDownButton
Protected WithEvents BTT_DOWN As ToolStripButton
Private WithEvents BTT_BUG_REPORT As ToolStripButton

View File

@@ -123,9 +123,6 @@
<metadata name="SEP_3.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="MENU_ADD_SEP_1.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="MENU_DEL_CLEAR.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
@@ -133,30 +130,30 @@
<data name="BTT_DELETE.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAVDSURBVEhLjZVtTFNXGMcLQmdHO6AdarLSOcTxXqC3lls3
FceLFC3YUkHHiJpRcQXFF5QoRmM00fiSLNmH7cP2YctMZtwyXZaNCaNsTsAJAzdcENBhLaXvhctekkV6
9j+l1RnLxpP8cnvPec7/+fc5597LozFQVBRjTkp6v3PJkpGrMtl766XSFzAcFZj8nxhWqdjfZLJro4sX
919OTjZgKAZEBCZpDJpMwptFRZ8ONzeTsfPnyXdNTf6rLNuRJxItx3T0bFb4GGKYV21bttznzpwh0+fO
kZHKSs87qan1stjYeEzPFulYtuzdO/v2kXvHj5OxY8eIFcmWgwdJK8tek4tELyMlbJFRtfo1iFu4s2cJ
h7VcSwuZPnqU3NFqvV9IpW8jRQyieJ0SiZWK32tqIvcPHyZWJE2cOkW6m5v9V1WqH7JEohQkPlEEbSm2
VVVZqXMqPg1x7sABMg1jvpoaYk5IuI00Foh47YmJF0Zqa8kYCliA9dAhYsMCx8mT5Aba1c6y3ZlCYSqS
A0WGFYriicpK69Tp04SDmWmY4rBueu9eMrlzJ2lVqVxbJZJLSC0FYp5+6dIXW5XKa53bt/sfIGkcTMCN
A3viRsuc+/eTThTJFQrTfmKYonGDwTZ14kSgJRwcc2gv19hIpiBuzs31pAgEH0HYCOSAbjgvmpFIUlGk
27J1K7Ht2kXsDQ3EsWcPcaGYF0K9DQ3+HrX61t3ycit35EjAMYc5Drlcff0j8TSB4AL0akFGUDwSBIKf
KxanfaNQdHVVV/vtdXXECdwmE/FAwIdivt27yRTcTlFh3HO4D4ijvV1KpVcuFFJx6jwdLASPj2ow+Cqx
OL09O7vbtmkTcW7bRtzAazQSHxxOouAkNnCyvJz41q4lPrWaeEBXXp4vRyS6iPU7AHUuAE+Jh4K/Ij4+
o10u7x7MyXno2byZuDUa4mYY4pJKiUskIq7oaOJasID0CoX+tqQkLxsXRze0DmSCZ8Gc4qEItOumXD4w
AUE7xBzACahwgKgo0p+d/ZchNfUr5L8FssC8xANhq6kx2dRqi10geFoc0LHB5OSHZq32blpiYjmWxIL5
ifuMxv2uggKXHe7nEh8H94ElI4P063S3X1+5MgdL//O1Egi30djiXLfObY+JeUrcid7TdlHxMTASGUkG
QXtOjn+gouJXA8vSNs1dxLtjx2FHSYknnHOnREIelJT8fSMlxU/Fh4PifaALmBlmZoD+k7mK4Ci22AsK
vHahMCD8RFsWLSJDpaW/n1i9uqdvw4YJS1oa+QWiveA6+J4WoKxYMfOjwXCrQC6nL8jHr3pPbW0zFXeE
E09IIENr1vxRzzDtSG0oycx843ZZ2d0h9D4k3gHaQCstolLN9FRU9H2o1dKN54MInmfjRqsjLi68c4jX
KRRtSDQBupHiPfn5r/Tr9aO3srIeiX8NvgRXwEB6+sNevf4OcpcCPs+u0w15ZLKwzk0M8y2S6oPioS8V
f29hIdtfUTF6OSvL/2/xzyIiSC8KmDWaceQVgXheT3X1lgmNxu2GaMj5YHHxn7vCi4eC35ifn4eNHbmZ
nU0uB8XNeXkzn2g0D0qXL/8AObMFEAvbKiuPWMvKvH0s66fOG5XKDozPJR4KvnHVKgVtx+dYZ1arZy7B
+XMCwTnM6cBsixARTFJSbJ9e//G9sjLnxcJCnL7IRowzQEjnadIcwb9SVfXmzzrd+HWt1lWSkkK/BXog
BfS4PlpLf8QBJVgfvM738X8G0KNJT84G8BII+8AtANQx/VjTK72fT1AT9P3/fBBaMGiMx/sHXLrYtE2a
9iQAAAAASUVORK5CYII=
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAVDSURBVEhLjZVtTFNXGMcLQmdHO6AdarLSOcTx2gK9tbRu
Ko4XKVqwpYKOETWj4gqKLyhRjMZoolFMluzD9mH7sGUmM2qiy7KhIDVDAV8YuOGCgA5rKX0vXPaSLNKz
/ymtzlg2nuSX23vOc/7Pv885914Ojf7CwhhzUtLn1xctGr4qkXy2Vix+A8NRgcn/iSGlUvWbRNI5snBh
36XkZAOGYkBEYJLGgMnEv1NYeGGoqYmMnjlDOhob/VdVqo5cgWAppqNnssLHIMO8a9u06TF76hSZamkh
wxUVnk9SU+sksbHxmJ4p0rFkyacP9uwhj44eJaNHjhArki3795NWlapTJhC8jZSwRUbU6vcgbmFPnyYs
1rLNzWTq8GHyQKv1fisWf4wUIYjiXBeJrFT8UWMjeXzwILEiafzECXKjqcl/Vam8IRUIUpD4QhG0pchW
WWmlzqn4FMTZffvIFIz5qquJOSHhPtJUQMBpT0w8O1xTQ0ZRwAKsBw4QGxY4jh8nXWhXu0rVncnnpyI5
UGRILi8ar6iwTp48SViYmYIpFuumdu8mE9u3k1al0rVZJDqP1BIg5OgXL36zVaHovLZ1q/8JksbAONw4
sCdutMy5dy+5jiI5fH7aTwxTOGYw2CaPHQu0hIVjFu1lGxrIJMTNOTmeFB7vKwgbgQzQDedEMyJRKop0
WzZvJrYdO4i9vp44du0iLhTzQuhWfb2/R62+97CszMoeOhRwzGKORS5bV/dMPI3HOwu9GpARFI8EgeDm
CIVpV+Tyrs6qKr+9tpY4gdtkIh4I+FDMt3MnmYTbSSqMexb3AXG0t0uh8Mr4fCpOnaeD+eD5UQ0GVykU
prdnZXXbNmwgzi1biBt4jUbig8MJFJzABk6UlRHf6tXEp1YTD+jKzfVlCwTnsH4boM554CXxUHCXxcdn
tMtk3QNS6VPPxo3ErdEQN8MQl1hMXAIBcUVHE9e8eeQWn+9vS0ryquLi6IbWgkzwKphVPBSBdt2RyfrH
IWiHmAM4ARUOEBVF+rKy/jKkpn6P/I+AFMxJPBC26mqTTa222Hm8l8UBHRtITn5q1mofpiUmlmFJLJib
uM9o3OvKz3fZ4X428THwGFgyMkifTnf//eXLs7H0P18rgXAbjc3ONWvc9piYl8Sd6D1tFxUfBcORkWQA
XMnO9veXl/9qUKlom2Yv4t227aCjuNgTzrlTJCJPiov/7kpJ8VPxoaB4L+gCZoaZ7qf/ZLYiOIrN9vx8
r53PDwi/0JYFC8hgScnvx1au7Oldt27ckpZGfoHoXXAT/EgLUJYtm75tMNzLl8noC/L5q95TU9NExR3h
xBMSyOCqVX/UMUw7UuuLMzM/uF9a+nAQvQ+Jd4A20EqLKJXTPeXlvV9qtXTjuSCC41m/3uqIiwvvHOK1
cnkbEk2AbqRwV17eO316/cg9qfSZ+A/gO3AZ9KenP72r1z9A7mLA5dh1ukGPRBLWuYlhriGpLige+lJx
dxcUqPrKy0cuSqX+f4tfjIggd1HArNGMIa8QxHN6qqo2jWs0bjdEQ84Hior+3BFePBTchry8XGzs8J2s
LHIpKG7OzZ3+RqN5UrJ06RfImSmAmN9WUXHIWlrqva1S+anzBoWiA+OziYeCa1yxQk7bcQHrzGr19Hk4
f43Ha8GcDsy0CBHBJCXF9ur1Xz8qLXWeKyjA6YtswDgD+HSeJs0S3MuVlR/+rNON3dRqXcUpKfRboAdi
QI/rs7X0RxxQgLXB61wf/1cAPZr05KwDb4GwD9w8QB3TjzW90vu5BDVB3/+vB6EFg8Y4nH8AgWzYiqo5
SH4AAAAASUVORK5CYII=
</value>
</data>
<metadata name="MENU_DEL_SEP_1.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
@@ -194,88 +191,88 @@
<data name="BTT_CLEAR_DONE.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAVDSURBVEhLjZVtTFNXGMcLQmdHO6AdarLSOcTxXqC3lls3
FceLFC3YUkHHiJpRcQXFF5QoRmM00fiSLNmH7cP2YctMZtwyXZaNCaNsTsAJAzdcENBhLaXvhctekkV6
9j+l1RnLxpP8cnvPec7/+fc5597LozFQVBRjTkp6v3PJkpGrMtl766XSFzAcFZj8nxhWqdjfZLJro4sX
919OTjZgKAZEBCZpDJpMwptFRZ8ONzeTsfPnyXdNTf6rLNuRJxItx3T0bFb4GGKYV21bttznzpwh0+fO
kZHKSs87qan1stjYeEzPFulYtuzdO/v2kXvHj5OxY8eIFcmWgwdJK8tek4tELyMlbJFRtfo1iFu4s2cJ
h7VcSwuZPnqU3NFqvV9IpW8jRQyieJ0SiZWK32tqIvcPHyZWJE2cOkW6m5v9V1WqH7JEohQkPlEEbSm2
VVVZqXMqPg1x7sABMg1jvpoaYk5IuI00Foh47YmJF0Zqa8kYCliA9dAhYsMCx8mT5Aba1c6y3ZlCYSqS
A0WGFYriicpK69Tp04SDmWmY4rBueu9eMrlzJ2lVqVxbJZJLSC0FYp5+6dIXW5XKa53bt/sfIGkcTMCN
A3viRsuc+/eTThTJFQrTfmKYonGDwTZ14kSgJRwcc2gv19hIpiBuzs31pAgEH0HYCOSAbjgvmpFIUlGk
27J1K7Ht2kXsDQ3EsWcPcaGYF0K9DQ3+HrX61t3ycit35EjAMYc5Drlcff0j8TSB4AL0akFGUDwSBIKf
KxanfaNQdHVVV/vtdXXECdwmE/FAwIdivt27yRTcTlFh3HO4D4ijvV1KpVcuFFJx6jwdLASPj2ow+Cqx
OL09O7vbtmkTcW7bRtzAazQSHxxOouAkNnCyvJz41q4lPrWaeEBXXp4vRyS6iPU7AHUuAE+Jh4K/Ij4+
o10u7x7MyXno2byZuDUa4mYY4pJKiUskIq7oaOJasID0CoX+tqQkLxsXRze0DmSCZ8Gc4qEItOumXD4w
AUE7xBzACahwgKgo0p+d/ZchNfUr5L8FssC8xANhq6kx2dRqi10geFoc0LHB5OSHZq32blpiYjmWxIL5
ifuMxv2uggKXHe7nEh8H94ElI4P063S3X1+5MgdL//O1Egi30djiXLfObY+JeUrcid7TdlHxMTASGUkG
QXtOjn+gouJXA8vSNs1dxLtjx2FHSYknnHOnREIelJT8fSMlxU/Fh4PifaALmBlmZoD+k7mK4Ci22AsK
vHahMCD8RFsWLSJDpaW/n1i9uqdvw4YJS1oa+QWiveA6+J4WoKxYMfOjwXCrQC6nL8jHr3pPbW0zFXeE
E09IIENr1vxRzzDtSG0oycx843ZZ2d0h9D4k3gHaQCstolLN9FRU9H2o1dKN54MInmfjRqsjLi68c4jX
KRRtSDQBupHiPfn5r/Tr9aO3srIeiX8NvgRXwEB6+sNevf4OcpcCPs+u0w15ZLKwzk0M8y2S6oPioS8V
f29hIdtfUTF6OSvL/2/xzyIiSC8KmDWaceQVgXheT3X1lgmNxu2GaMj5YHHxn7vCi4eC35ifn4eNHbmZ
nU0uB8XNeXkzn2g0D0qXL/8AObMFEAvbKiuPWMvKvH0s66fOG5XKDozPJR4KvnHVKgVtx+dYZ1arZy7B
+XMCwTnM6cBsixARTFJSbJ9e//G9sjLnxcJCnL7IRowzQEjnadIcwb9SVfXmzzrd+HWt1lWSkkK/BXog
BfS4PlpLf8QBJVgfvM738X8G0KNJT84G8BII+8AtANQx/VjTK72fT1AT9P3/fBBaMGiMx/sHXLrYtE2a
9iQAAAAASUVORK5CYII=
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAVDSURBVEhLjZVtTFNXGMcLQmdHO6AdarLSOcTx2gK9tbRu
Ko4XKVqwpYKOETWj4gqKLyhRjMZoolFMluzD9mH7sGUmM2qiy7KhIDVDAV8YuOGCgA5rKX0vXPaSLNKz
/ymtzlg2nuSX23vOc/7Pv885914Ojf7CwhhzUtLn1xctGr4qkXy2Vix+A8NRgcn/iSGlUvWbRNI5snBh
36XkZAOGYkBEYJLGgMnEv1NYeGGoqYmMnjlDOhob/VdVqo5cgWAppqNnssLHIMO8a9u06TF76hSZamkh
wxUVnk9SU+sksbHxmJ4p0rFkyacP9uwhj44eJaNHjhArki3795NWlapTJhC8jZSwRUbU6vcgbmFPnyYs
1rLNzWTq8GHyQKv1fisWf4wUIYjiXBeJrFT8UWMjeXzwILEiafzECXKjqcl/Vam8IRUIUpD4QhG0pchW
WWmlzqn4FMTZffvIFIz5qquJOSHhPtJUQMBpT0w8O1xTQ0ZRwAKsBw4QGxY4jh8nXWhXu0rVncnnpyI5
UGRILi8ar6iwTp48SViYmYIpFuumdu8mE9u3k1al0rVZJDqP1BIg5OgXL36zVaHovLZ1q/8JksbAONw4
sCdutMy5dy+5jiI5fH7aTwxTOGYw2CaPHQu0hIVjFu1lGxrIJMTNOTmeFB7vKwgbgQzQDedEMyJRKop0
WzZvJrYdO4i9vp44du0iLhTzQuhWfb2/R62+97CszMoeOhRwzGKORS5bV/dMPI3HOwu9GpARFI8EgeDm
CIVpV+Tyrs6qKr+9tpY4gdtkIh4I+FDMt3MnmYTbSSqMexb3AXG0t0uh8Mr4fCpOnaeD+eD5UQ0GVykU
prdnZXXbNmwgzi1biBt4jUbig8MJFJzABk6UlRHf6tXEp1YTD+jKzfVlCwTnsH4boM554CXxUHCXxcdn
tMtk3QNS6VPPxo3ErdEQN8MQl1hMXAIBcUVHE9e8eeQWn+9vS0ryquLi6IbWgkzwKphVPBSBdt2RyfrH
IWiHmAM4ARUOEBVF+rKy/jKkpn6P/I+AFMxJPBC26mqTTa222Hm8l8UBHRtITn5q1mofpiUmlmFJLJib
uM9o3OvKz3fZ4X428THwGFgyMkifTnf//eXLs7H0P18rgXAbjc3ONWvc9piYl8Sd6D1tFxUfBcORkWQA
XMnO9veXl/9qUKlom2Yv4t227aCjuNgTzrlTJCJPiov/7kpJ8VPxoaB4L+gCZoaZ7qf/ZLYiOIrN9vx8
r53PDwi/0JYFC8hgScnvx1au7Oldt27ckpZGfoHoXXAT/EgLUJYtm75tMNzLl8noC/L5q95TU9NExR3h
xBMSyOCqVX/UMUw7UuuLMzM/uF9a+nAQvQ+Jd4A20EqLKJXTPeXlvV9qtXTjuSCC41m/3uqIiwvvHOK1
cnkbEk2AbqRwV17eO316/cg9qfSZ+A/gO3AZ9KenP72r1z9A7mLA5dh1ukGPRBLWuYlhriGpLige+lJx
dxcUqPrKy0cuSqX+f4tfjIggd1HArNGMIa8QxHN6qqo2jWs0bjdEQ84Hior+3BFePBTchry8XGzs8J2s
LHIpKG7OzZ3+RqN5UrJ06RfImSmAmN9WUXHIWlrqva1S+anzBoWiA+OziYeCa1yxQk7bcQHrzGr19Hk4
f43Ha8GcDsy0CBHBJCXF9ur1Xz8qLXWeKyjA6YtswDgD+HSeJs0S3MuVlR/+rNON3dRqXcUpKfRboAdi
QI/rs7X0RxxQgLXB61wf/1cAPZr05KwDb4GwD9w8QB3TjzW90vu5BDVB3/+vB6EFg8Y4nH8AgWzYiqo5
SH4AAAAASUVORK5CYII=
</value>
</data>
<data name="BTT_CLEAR_ALL.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAVDSURBVEhLjZVtTFNXGMcLQmdHO6AdarLSOcTxXqC3lls3
FceLFC3YUkHHiJpRcQXFF5QoRmM00fiSLNmH7cP2YctMZtwyXZaNCaNsTsAJAzdcENBhLaXvhctekkV6
9j+l1RnLxpP8cnvPec7/+fc5597LozFQVBRjTkp6v3PJkpGrMtl766XSFzAcFZj8nxhWqdjfZLJro4sX
919OTjZgKAZEBCZpDJpMwptFRZ8ONzeTsfPnyXdNTf6rLNuRJxItx3T0bFb4GGKYV21bttznzpwh0+fO
kZHKSs87qan1stjYeEzPFulYtuzdO/v2kXvHj5OxY8eIFcmWgwdJK8tek4tELyMlbJFRtfo1iFu4s2cJ
h7VcSwuZPnqU3NFqvV9IpW8jRQyieJ0SiZWK32tqIvcPHyZWJE2cOkW6m5v9V1WqH7JEohQkPlEEbSm2
VVVZqXMqPg1x7sABMg1jvpoaYk5IuI00Foh47YmJF0Zqa8kYCliA9dAhYsMCx8mT5Aba1c6y3ZlCYSqS
A0WGFYriicpK69Tp04SDmWmY4rBueu9eMrlzJ2lVqVxbJZJLSC0FYp5+6dIXW5XKa53bt/sfIGkcTMCN
A3viRsuc+/eTThTJFQrTfmKYonGDwTZ14kSgJRwcc2gv19hIpiBuzs31pAgEH0HYCOSAbjgvmpFIUlGk
27J1K7Ht2kXsDQ3EsWcPcaGYF0K9DQ3+HrX61t3ycit35EjAMYc5Drlcff0j8TSB4AL0akFGUDwSBIKf
KxanfaNQdHVVV/vtdXXECdwmE/FAwIdivt27yRTcTlFh3HO4D4ijvV1KpVcuFFJx6jwdLASPj2ow+Cqx
OL09O7vbtmkTcW7bRtzAazQSHxxOouAkNnCyvJz41q4lPrWaeEBXXp4vRyS6iPU7AHUuAE+Jh4K/Ij4+
o10u7x7MyXno2byZuDUa4mYY4pJKiUskIq7oaOJasID0CoX+tqQkLxsXRze0DmSCZ8Gc4qEItOumXD4w
AUE7xBzACahwgKgo0p+d/ZchNfUr5L8FssC8xANhq6kx2dRqi10geFoc0LHB5OSHZq32blpiYjmWxIL5
ifuMxv2uggKXHe7nEh8H94ElI4P063S3X1+5MgdL//O1Egi30djiXLfObY+JeUrcid7TdlHxMTASGUkG
QXtOjn+gouJXA8vSNs1dxLtjx2FHSYknnHOnREIelJT8fSMlxU/Fh4PifaALmBlmZoD+k7mK4Ci22AsK
vHahMCD8RFsWLSJDpaW/n1i9uqdvw4YJS1oa+QWiveA6+J4WoKxYMfOjwXCrQC6nL8jHr3pPbW0zFXeE
E09IIENr1vxRzzDtSG0oycx843ZZ2d0h9D4k3gHaQCstolLN9FRU9H2o1dKN54MInmfjRqsjLi68c4jX
KRRtSDQBupHiPfn5r/Tr9aO3srIeiX8NvgRXwEB6+sNevf4OcpcCPs+u0w15ZLKwzk0M8y2S6oPioS8V
f29hIdtfUTF6OSvL/2/xzyIiSC8KmDWaceQVgXheT3X1lgmNxu2GaMj5YHHxn7vCi4eC35ifn4eNHbmZ
nU0uB8XNeXkzn2g0D0qXL/8AObMFEAvbKiuPWMvKvH0s66fOG5XKDozPJR4KvnHVKgVtx+dYZ1arZy7B
+XMCwTnM6cBsixARTFJSbJ9e//G9sjLnxcJCnL7IRowzQEjnadIcwb9SVfXmzzrd+HWt1lWSkkK/BXog
BfS4PlpLf8QBJVgfvM738X8G0KNJT84G8BII+8AtANQx/VjTK72fT1AT9P3/fBBaMGiMx/sHXLrYtE2a
9iQAAAAASUVORK5CYII=
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAVDSURBVEhLjZVtTFNXGMcLQmdHO6AdarLSOcTx2gK9tbRu
Ko4XKVqwpYKOETWj4gqKLyhRjMZoolFMluzD9mH7sGUmM2qiy7KhIDVDAV8YuOGCgA5rKX0vXPaSLNKz
/ymtzlg2nuSX23vOc/7Pv885914Ojf7CwhhzUtLn1xctGr4qkXy2Vix+A8NRgcn/iSGlUvWbRNI5snBh
36XkZAOGYkBEYJLGgMnEv1NYeGGoqYmMnjlDOhob/VdVqo5cgWAppqNnssLHIMO8a9u06TF76hSZamkh
wxUVnk9SU+sksbHxmJ4p0rFkyacP9uwhj44eJaNHjhArki3795NWlapTJhC8jZSwRUbU6vcgbmFPnyYs
1rLNzWTq8GHyQKv1fisWf4wUIYjiXBeJrFT8UWMjeXzwILEiafzECXKjqcl/Vam8IRUIUpD4QhG0pchW
WWmlzqn4FMTZffvIFIz5qquJOSHhPtJUQMBpT0w8O1xTQ0ZRwAKsBw4QGxY4jh8nXWhXu0rVncnnpyI5
UGRILi8ar6iwTp48SViYmYIpFuumdu8mE9u3k1al0rVZJDqP1BIg5OgXL36zVaHovLZ1q/8JksbAONw4
sCdutMy5dy+5jiI5fH7aTwxTOGYw2CaPHQu0hIVjFu1lGxrIJMTNOTmeFB7vKwgbgQzQDedEMyJRKop0
WzZvJrYdO4i9vp44du0iLhTzQuhWfb2/R62+97CszMoeOhRwzGKORS5bV/dMPI3HOwu9GpARFI8EgeDm
CIVpV+Tyrs6qKr+9tpY4gdtkIh4I+FDMt3MnmYTbSSqMexb3AXG0t0uh8Mr4fCpOnaeD+eD5UQ0GVykU
prdnZXXbNmwgzi1biBt4jUbig8MJFJzABk6UlRHf6tXEp1YTD+jKzfVlCwTnsH4boM554CXxUHCXxcdn
tMtk3QNS6VPPxo3ErdEQN8MQl1hMXAIBcUVHE9e8eeQWn+9vS0ryquLi6IbWgkzwKphVPBSBdt2RyfrH
IWiHmAM4ARUOEBVF+rKy/jKkpn6P/I+AFMxJPBC26mqTTa222Hm8l8UBHRtITn5q1mofpiUmlmFJLJib
uM9o3OvKz3fZ4X428THwGFgyMkifTnf//eXLs7H0P18rgXAbjc3ONWvc9piYl8Sd6D1tFxUfBcORkWQA
XMnO9veXl/9qUKlom2Yv4t227aCjuNgTzrlTJCJPiov/7kpJ8VPxoaB4L+gCZoaZ7qf/ZLYiOIrN9vx8
r53PDwi/0JYFC8hgScnvx1au7Oldt27ckpZGfoHoXXAT/EgLUJYtm75tMNzLl8noC/L5q95TU9NExR3h
xBMSyOCqVX/UMUw7UuuLMzM/uF9a+nAQvQ+Jd4A20EqLKJXTPeXlvV9qtXTjuSCC41m/3uqIiwvvHOK1
cnkbEk2AbqRwV17eO316/cg9qfSZ+A/gO3AZ9KenP72r1z9A7mLA5dh1ukGPRBLWuYlhriGpLige+lJx
dxcUqPrKy0cuSqX+f4tfjIggd1HArNGMIa8QxHN6qqo2jWs0bjdEQ84Hior+3BFePBTchry8XGzs8J2s
LHIpKG7OzZ3+RqN5UrJ06RfImSmAmN9WUXHIWlrqva1S+anzBoWiA+OziYeCa1yxQk7bcQHrzGr19Hk4
f43Ha8GcDsy0CBHBJCXF9ur1Xz8qLXWeKyjA6YtswDgD+HSeJs0S3MuVlR/+rNON3dRqXcUpKfRboAdi
QI/rs7X0RxxQgLXB61wf/1cAPZr05KwDb4GwD9w8QB3TjzW90vu5BDVB3/+vB6EFg8Y4nH8AgWzYiqo5
SH4AAAAASUVORK5CYII=
</value>
</data>
<data name="MENU_DEL_CLEAR.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAVHSURBVEhLjZVrTJNXGMcLQmdHO6AdarLCHOIAgQJ9a2nx
EpwgLbVWSgWVETWj4gqKF5QoRmM00SgmS/Zh+7B92DKTGbdEl2VzwsDMC0REYJMNARFK6f0CL3NLFujZ
/5TiJZaNJ/mlfc95zv/55znnPS+HRndBQVRrYuJnN5csGbiRkPCpRix+C8MRgcn/iX65XPEkIeHW4OLF
XVeTkgwYigJhgUkaD00mfkdBwTf99fVk+OJFMlhX57+hULTkCATLMR05kxU6+hhmtXXbthH2/Hky2dhI
hkpLPR+npFQnREfHYnqmSMuyZZ88OniQDJ06RYZPniQWJJuPHCHXFYpbEoHgXaSELDKoVL4HcTN74QJh
sZZtaCCTJ06QR1qt9zux+COkCEEE56ZIZKHiQ3V1ZOTYMWJBku3sWWKur/ffkMtvZwgEyUh8qQjassFa
Vmahzqn4JMTZw4fJJIz5KipIa1xcL9IUQMBpjo+/NFBZSYZRwAwsR48SKxY4zpwhFrSrWaFoS+fzU5Ac
KNIvlW6wlZZaJs6dIyzMTMIUi3WTBw6Q8T17SLNc7tohEl1BahEQcvRLl759XSa7NbBrl38USWPABjcO
7IkbLXMeOkRuokg2n5/6gGEKxgwG68Tp04GWsHDMor1sbS2ZgHirTOZJ5vG+hLARSADdcE4kIxKloEib
eccOYt27l9hraohj/37iQjEvhGw1Nf52pbLniU5nYY8fDzhmMccil62unhGXSj2pPN4l6FWCtKB4OAgE
N1soTP1JKr07Ul7ut1dVESdwm0zEAwEfivn27SMTcDtBhfHM4jkgjvbezcnxSvh8Kk6drwALwfOjGgyu
XChc0ZyZ2WbdsoU4d+4kbuA1GokPDsdRcBwbOK7TEd+6dcSnVBIPgLgvSyC4jPW7AXXOA6+IzwZ3ZWxs
WrNE0jaq0Ux5tm4lbrWauBmGuMRi4hIIiCsykrgWLCA2Pt/flJjoVcTE0A2tAungdTCn+GwE2tUhkXTb
IGiHmAM4ARUOEBFBerOz/zakpPyA/A9BBpiXeCCsFRUma26u2c7jvSoO6Jg5KWmqVat9nBofr8OSaDA/
cZ/ReMi1fr3LDvdziY+BEWBOSyNdxcW923Nzs7D0P6+VQLiNxgZnYaHbHhX1irgTvaftouLDYCA8nDwE
f2Rl+btLSn43KBS0TXMX8e7efcyhUnlCOXeKRGRUpfrHkpzsp+L9QfFOcBf0MMx0t17fu32uIjiKDY7C
Qq+dzw8Iv9SWRYtIX1HRn6fXrm3v3LjRZk5NJb9B9D64A34BreDBypXT9wyGnvUSCb0gn1/1nsrKejj3
OkKJx8WRPrX6aTXDNCO1RpWe/n6vTve4D72fFW8BTeA6uCeXT7eXlHR+odXSjeeCMI5n82aLIyYmtHOI
V0mlTUg0AbqRwv15eau69PrBnoyMZ+I/gu/BNdC9evXUfb3+EXKXAi7Hrtf3eRISQjo3MczPSKoOis9+
qbgH8vMVXSUlgx0ZGf4Xxb8NCyP3V62aatVoxpBXAGI57eXl22wajdsN0Rec/7U3tPhscGvz8nKwsQMd
mZnkalD8dk7O9Ndq9WjR8uWfI2emAGJhU2npccumTV67QuHvU6me1spkLRifS3w2uMY1a6S0Hfewrk2p
nL6iVo+9weM1Yq4YzLQIEcYkJkZ36vVfDel0zsv5+Th94bUYZwCfztOkOYJ7razsg1+Li8fuaLUuVXIy
/RbogRjQ4/psLf0TA2RAE/yd7+v/GqBHk56cjeAdEPKFWwCoY/qxpr/0eT5BTdD7/80gtGDQGIfzL+FH
22tl8CvUAAAAAElFTkSuQmCC
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAVGSURBVEhLjZVtTFNXGMcLQmdHO6AdarLSOcQBAgXaWm7d
NDgptmjBlgo6RtSMiisovqBEMRqjicaXZMk+bB+2D1tmMuOW6LJsKgzcVCBDBjpZyosItZS+Fy5zSxbo
2f+UVmcsG0/yy+095zn/59/nnHsvh0avWh3XlpLy6c0lSwZvSCSfbBCLX8NwTHDyf2JAqWQeSSS3hhYv
7rmSmmrEUByICk7SeGA287vU6q8HGhvJyIULpL+hIXCDYVrzBYLlmI6dzYocFrn8bfvWraPs2bNk6vx5
Mlhe7v0oPb1WEh+fiOnZIq3Lln3cv38/GT5xgowcP05sSLYeOkSuMcwtqUDwJlIiFhlSqd6BuJU9d46w
WMs2NZGpY8dIv07n+1Ys/hApQhDDuSkS2aj4cEMDGT1yhNiQNH76NHnU2Bi4oVTezhYI0pD4XBG0pche
UWGjzqn4FMTZgwfJFIz5q6pIW1JSH9IYIOC0JCdfHKyuJiMoYAW2w4eJHQucp06RUbSrhWE6svj8dCQH
iwzIZEXj5eW2yTNnCAszUzDFYt3Uvn1kYtcucl2pdG8TiS4jtRgIOYalS1+/plDcsuzYEXiMpDEwDjdO
7IkHLXMdOEBuokgen5/xq1yuHjMa7ZMnTwZbwsIxi/ay9fVkEuJteXneNB7vCwibgBTQDefEykWidBTp
sG7bRuy7dxNHXR1x7t1L3Cjmg5Ctri7QqVLde1haamOPHg06ZjHHIpetrX0qnsHjXYReNcgMiUeDYHDz
hMKM6zJZ+3BlZcBRU0NcwGM2Ey8E/Cjm37OHTMLtJBXGPYv7oDja265Q+KR8PhWnzleAheDZUQ0FVykU
rmjJyemwb95MXNu3Ew/wmUzED4cTKDiBDZwoLSX+tWuJX6UiXtCen+/PFQguYf1OQJ3zwAvi4eCuTEzM
bJFKO0Y0mmnvli3Eo9USj1xO3GIxcQsExB0bS9wLFhAbnx9oTknxMQkJdENrQBZ4GcwpHo5gu7qk0t5x
CDog5gQuQIWDxMSQ+zk5fxnT079H/gcgG8xLPBj2qiqzXaWyOni8F8UBHXuUmjrdptM9zEhOLsWSeDA/
cb/JdMC9bp3bAfdziY+BUWDNzCQ9en3fu6tW5WLpf75WguExmZpc69d7HHFxL4i70HvaLio+Agajo8kD
Sm5uoLes7Hcjw9A2zV3Et3PnEadG443k3CUSkccazd+jaWkBKj4QEu8G7QAP4Ewv/SdzFcFRbHIUFvoc
fH5Q+Lm2LFpELMXFf5xcs6aze+PGcWtGBvkNonfBHfAzaANdK1fO/GI03lsnldIX5LNXvbe6utGhVvuc
kcSTkoilqOhJrVzegtQ6TVbWe30lJQ8t6H1YvBU0g2ugQ6mc6Swr6/5cp6MbzwVRHO+mTTZnQkJk5xCv
kcmakWgGdCOFewsK3uoxGIbuZWc/Ff8BfAeugl6VavquwdCP3KWAy3Ho9RavRBLRuVku/xFJtSHx8JeK
u6+wkOkpKxvqzM4O/Fv8m6gocpdhptu02jHkqUEip7Oycuu4VuvxQDTsvK+o6M/dkcXDwa0vKMjHxg52
5eSQKyHxn/LzZ77Sah8XL1/+GXJmCyAWNpeXH7WVlPjGGCZgUauf1CsUrRifSzwcXNPq1TLajg6su61S
zVyG81d4vPOY04PZFiGi5Ckp8d0Gw5fDJSWuS4WFOH3R9RiXAz6dp0lzBPdqRcX79/X6sTs6nVuTlka/
BQYgBvS4Pl1LfyQABdgQus738X8J0KNJT85G8AaI+MAtANQx/VjTK72fT1AT9P3/aghaMGSMw/kHSsza
wAU0N/QAAAAASUVORK5CYII=
</value>
</data>
<metadata name="TOOLBAR_BOTTOM.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
@@ -287,135 +284,93 @@
<data name="BTT_ADD.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANxSURBVEhLrZVJTFNRFIYfQhgD1OBUpiCKQwkUoUA0FBAU
KqixAlpliAODYEQJFAJiCKBujcadcUGMMW4MxpXDAoeoOEDR1woVUjph0QTD/pLfcx8lsiBg8J3kT9vc
k/+797z/vgorlf9N376AW75YSnzN27b64kYqk4rlDWuxf0QLnUgya1Fmy5cg3rbVlwT4omLBrwSEvRMQ
8VFA1Gc/1LiK5AMkiioW/l7A+o8+iBsOQIoYhlZPiXyAZALwncebApBqCUfu6EZc/VUhH0BDgHhTINIt
ChRaI2n+W3FzplY+wBkxkWnMChRZo3Bycjtq7Sm4O9soH6BZTGO679GotO9EgyMVzc49uD9r/DfAcjlf
kOFtzlyFfQcuODRom9Ki21OAvt8tWPcgaFkpH4X0STvMX8g45bt4VIuj1jxU2QpxwXkY7e4yXPNU0XcN
OtzZ6PEUondah76ZFtybMUqgOzONuPGrGj3T5Wh1l9IIi9FgPw5lfwgkADcPe0sZHxQQPewPNcWQJ0U/
EY/T9kRcdGbi8tReMtDh+nSRBOj+UUBmWtQ6UnBsIgH5Y5ugNochZsgfCvI5btb/BfCdc3O+qDaHUrMS
JV7zS65MdLrz0OvREaAAV37kwejOomeRhlOTKhwZ34yc0Q1IEkMROewHxQcBQXQpS0YWAYotWsSSeQrt
IN+qlGJY41CjyZWBjqlcdJJpuzsHRlcWLjnTUUdrlXYVDo3HIZtOKpkP+YFfRm7u80yA/sMiwAnrPuy2
RFAMo1Fu24FGepgtlJQ2MuSmza49kppoVHU0Ep6mg+OxyPq2ATu/hkD5yRehNOLAAQHCU1I/Ad4sAtSL
ScwoprMusZJ0lnWZ61iXpZY+z9Hv8+z2z3oyz0CNXQ3D5DYUjcegzVmFw69z5qrFDFYhapiBlE7SfCF9
Jg1qmATgMV0qYgviTd1iG6txJMNgS8ABOmUmnbbBYZDWlhWP6UrFG7vEJnaMnkvhWBTS6EZvMQXhlO2o
ZOJtW33NAxpYwVik9KLjb9MISspJq3fG/1vzgGq2yxyOaErKWooz/28oXcj5/xY3aRTLWcxQABQUw+CX
AnyfU0pMMgLOUMK4eSDtfA2P4RMCvJcRUE7xC6KdC3SBhMekhwR4JSOg9KteGol+kEQXSD9AeiEXgLLM
jZbUijkXhD9w0a0SO8Tg+AAAAABJRU5ErkJggg==
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANqSURBVEhLrZVbSJNhGMe/mjhN1IWdpjPMssOitqklidPS
cksrmufyQAcPZWSKzqEZUla3UXQXXYyI6CaMrjpcmEV5KF31zXQt5k42Cxbdf/Hveb8meSEa+j3wh8H7
8v897/P+32/cQhV+U2aV35JhLrG10LbFFzNS29RC7qgeBz7oYeRJdj1KXXkiJLRt8SUCPqqFFf0cYt5y
iBvmkPA+DHW+AgkBvFqIHeCwengZkkbl0PIxaA8USwfYTgDWebJNjtSxWOwdX4urP6qkA+gIkGyLwK4x
BQyOeJr/JtwM1ksHOEWAdLsCBY4EHJ/cgnq3Fnd/NUkHaOW1gvGLCtXubWj0pKLVm4n7v8z/B5gv5zMq
fZXzu8q9Fec96bBM6XE5kA/rzzasehA5r5SPoqxih3kzGad8F47rUeTIRY3LgPPeI+jwl+JaoIZ+p6PT
n40rAQN6po2wBttwL2gWQXeCTbjxoxZXpivR7i+hERai0V0OZW8URAAzj3lDGR/koBoNh4ZiyJJi+pqM
k+7tuODNwMWpfWRgxPXpAhFw+Vs+melR79Gi7GsK8ibWQWOPQeJIOBTkU243/QOwzpk5W9TYo2mzEsUh
82ZfBrr8uegJGAmQj0vfcmH2Z9FdpOHEpBpHnRuQM74GO/hoxI+GQTHEIZIeZfGHWYDCMT3Wk7mWOshz
KMUY1nk0aPHtRufUXnSRaYc/B2ZfFpq9u9BAa9VuNQ47k5BNJxXNR8LAHiMzX/aMg2loFuCYYz/2jMVR
DFWodG1FE11mGyXFQobMtNWXKaqFRtVAI2FpOuRcj6zPa7DtUxSU72SIphFH9HHgnpJ6CfB6FuAs5dzM
pwrdfDXpNKmBVE86Qzon3P5+lsx3o86tQcXkZhQ4E2Hx1qCwL+d3LZ8mVPE6oYKUStJ9JL0nDeoEEcBi
OlfEZsQ2dfMWoc6zExWuFBykU2bQaRs9FeLavGIxXajYxm6+RSijezFMJCCNXvRGWyROuIpEk9C2xddf
QKOQPxEvfujY1zSOknLcEZrxUusvoFbQ2WOhoqSspDiz/4aSmZwvtZhJE18pJI7IoaAYrnjJQfacUmKT
EHCKEsbMI6jz5SyGTwgwICGgkuIXSZ1z9IC4x6SHBOiXEFDyySSOxDRIogdk6iO9kApAWWZGc2rBnHPc
H0WkrMjY2947AAAAAElFTkSuQmCC
</value>
</data>
<data name="BTT_ADD_PLS_ARR.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAN0SURBVEhLrZVJTFNRFIafQhgD1KBoGYzihDXYqtCqoYKg
UEENFUSkQFApKEaUQCVOaQR1azTujAtijHFjNK4cFmocGASKvFaokNIJiiYY99f8nvsskQUBg+8kf9rk
3vzfuef99z1hvgq7FdIRfjsEs4mvBbctvLiRyqZiuf167B3QwyCS7HocduVJkOC2hZcE+KxiUW8FxH4U
EN8jIKk3FGZfoXyAdFHF4joFLOtZhFX94dCIsTgfKJEPoCEA7zzVFo6tjjjkDC3Hte+V8gG0BEi1RSDT
oUCBM5Hmvxa3purkAxwX01mGXYFCZxIqxjagzq3BvZ+N8gGaxUxm+JqMKvdGNHi2otm7Ew9+Wv4NMFfO
p1XRmf2r0p2GM54MtI7rcTWQj44fLVj6MHJOKR9Hd0gd5k1nnPJdNKTHIWcuql0FOOM9iAv+w7geqKb/
Gbjo34W2QAHaJw3omGrB/SmLBLo71Yib32vRNmnCeX8pjbAIDe4jUD6JhgTg5rEfKONdApL7w6CmGPKk
GEdTccy9CWe9Olwa300GBtyYLJQAVyfyyUyPOo8GZaPrkDe8Amp7LFL6wqAgnyN2418A75yb80W1PYY2
K1ESND/n0+GyPxftAQMB8nFlIhcWfxY9i22oGVOheGQ1socS6K7EILE/FIpuAZF0KUsGZgCKHHqsJHMN
dZDnVEoxNHvUaPJpcXE8B5fJ9II/GxZfFs55M1FPa1VuFQ6MrMIuOqlk3hcKfhm5+aIXAozdMwBHnXuw
wxFPMUyGyZWGRnqYLZSUVjLkps2+nZKaaFT1NBKepv0jK5H1JQEbB6Oh/BSCGBpxxGsBwnPSEwK8mwE4
JaqZRdQxq72KWR0nmPVLPbMO1dHvSWYVT7M7306RuRZmtxrlY+tROJKCVm81it9n/6oVt7NKUcvKSTqS
9jOpl9SlZRKAx3S2iE2Lb2oXW5nZsxnlrnXYR6fU0WkbPOXS2pziMZ2v+Ear2MTK6LkUDCdhG93oNbZI
1LgOSSbBbQuvP4AGlj+cKL3o+Ns0npJS4QzO+H/rD6CWbbHHIZmSsoTizL8NpdM5/9/iJo2iiaX0hUNB
MYx6IyDkJaXEJiPgOCWMm0dQ54t5DJ8RoFNGgIniF0mdC3SBhKekRwR4KyOgdNAojcTYRaILZHxNeiUX
gLLMjWbVvDkXhN9lPK1NCDBSGgAAAABJRU5ErkJggg==
</value>
</data>
<data name="BTT_ADD_NO_SHORTS.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAN6SURBVEhLrZVJTFNRFIYfQhgkQA1OZTCKoqLBVgRRpEpb
hQpqrAwiBYJIQTCiBCpxSuO41GjcGRfEGOPGYFw5LJAYFQco8opQIKUTFEkw7K/5PfelRBYEDL6T/GmT
e/N/55733/eEhSr0XnBb2P1gzCW+Fti2+OJGabZUpuvR4ECvBgaRZNeg2KmXIIFtiy9ukvE9lS3tFBD9
UUDsFwHx30Jg9ubLB9glprKYTwJWfAnC2p4wqMVoXPAXygfYQwDeeZItDGn9McgZWIWbk+XyAbRiGkuy
hSOjX4E8RxzNfwPuTdXKB6gWd7F0uwL5jniUjW5CrUuNR9ON8gGaxRxmGEpAhSsFDe40NHuy8GTa8m+A
+XI+I3Of7ne5azPOutPROqbBNX8u2n61YPnTiHmlfB7ZJnWon8k45btgQINjDh0qnXk46zmCi75i3PJX
0v90XPLtxXV/Hm5MGNA21YLHUxYJ9HCqEXcna3B9woQLviIaYQEaXMehbI+EBODm0R8o410CEnpCoaIY
8qQYR5Jw0rUV5zyZuDymJQMDbk/kS4Br47lkpkGtW42SkWToB1dDZY9GYncoFORz3G78C+Cdc3O+qLJH
0WYlCgPm572ZuOLT4YbfQIBcXB3XweLLpmexA1WjW3B0eB32DaxEqhiFuJ4QKD4LiKBLWdg7C1DQr8Ea
MldTB3qHUoqh2a1Ck3cnLo3l4AqZXvTtg8WbjfOeDNTRWoVrCw4Pr8VeOqlk3h0Cfhm5edBrAcbPswAn
HPuxuz+WYpgAk3MzGulhtlBSWsmQmzZ7syQ10ajqaCQ8TYeG1yD7x0qk9EVC+TUYUTTi8A4BwitSOwHe
zwLUD2Qxy5COWUcrmNV1ilnddczqqaXf0+ym4wx78LOezHfC7FKhdHQj8ocT0eqphMlm+F0j6lm5qGWl
JB1J+530jdSlZRKAx3SuiM2Ib7oz1MrM7m0odSbjIJ0yk07b4C6V1uYVj+lCxTfedjSxEnoueYPx2EE3
er0tAlXOY5JJYNvii5tYfzSw3ME46UXH36axlJQyR2DG/1sSQKxh2+0xSKCkLKM4829D0UzO/7e4SaNo
YondYVBQDJe+ExD8hlJikxFQLeoYNw+nzpfwGL4kwCcZASaKXwR1LtAFEl6QnhGgU0ZAUZ9RGomxi0QX
yNhBeisXgLLMjebUgjkXhD+4Jq73JQ87ogAAAABJRU5ErkJggg==
</value>
</data>
<data name="BTT_ADD_SHORTS_ONLY.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
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
mnOO+wP8Kqz2voJYygAAAABJRU5ErkJggg==
</value>
</data>
<data name="MENU_ADD.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
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
</value>
</data>
<data name="BTT_STOP.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAVCSURBVEhLjZVtTFNXGMcLQmdHO1461GSlc4jjvUBvLbdu
Ko4XKVqwpYKOETWj4gqKLyhRjMZoovElWbIP24ftw5aZzLgluiyTCaNmKrApAltZENBhLaXvhctekkV6
9j+l1RnLxpP8cnvPec7/+fc5597Lo9FfXBxjSk7++PqSJSPXpNKP1kskr2A4KjD5PzGsVLK/SaU3Rhcv
7ruckqLHUAyICEzSMBuNwtvFxV8Ot7SQsfPnyY/Nzf5rLNuZLxItx3T0bFb4GGKYN21btjzkzpwh0+fO
kZGqKs8HaWkN0tjYeEzPFulctuzDe/v2kQfHj5OxY8eIFcmWgwdJG8vekIlEryMlbJFRleotiFu4s2cJ
h7VcayuZPnqU3NNovF9LJO8jJQFE8a6LxVYq/qC5mTw8fJhYkTRx6hTpa2nxX1Mqb2aLRKlIfKYI2lJi
q662UudUfBri3IEDZBrGfLW1xJSYOIg0Foh4HUlJF0bq6sgYCliA9dAhYsMCx8mTZADt6mDZ7iyhMA3J
gSLDcnnJRFWVder0acLBzDRMcVg3vXcvmdy5k7Qpla6tYvElpJaBBJ5u6dJX2xSKGz3bt/sfIWkcTMCN
A3viRsuc+/eT6yiSJxSm32WY4nG93jZ14kSgJRwcc2gv19REpiBuysvzpAoEn0HYAGSAbjgvmhGL01Ck
27J1K7Ht2kXsjY3EsWcPcaGYF0LmxkZ/j0o1cL+iwsodORJwzGGOQy7X0PBEPF0guAC9OpAZFI8EgeDn
JSSkfyeXd92tqfHb6+uJE7iNRuKBgA/FfLt3kym4naLCuOdwHxBHe7sUCq9MKKTi1HkGWAieHtVg8JUJ
CRkdOTndtk2biHPbNuIGXoOB+OBwEgUnsYGTFRXEt3Yt8alUxAO68vN9uSLRRazfAahzAXhOPBT8FfHx
mR0yWbeZZR97Nm8mbrWauBmGuCQS4hKJiCs6mrgWLCBmodDfnpzsZePi6IbWgyzwIphTPBSBdt2Wyfon
IGiHmAM4ARUOEBVF+nJy/tKnpX2L/PdANpiXeCBstbVGm0plsQsEz4sDOmZOSXls0mjupyclVWBJLJif
uM9g2O8qLHTZ4X4u8XHwEFgyM0mfVjv49sqVuVj6n6+VQLgNhlbnunVue0zMc+JO9J62i4qPgZHISGIG
N3Nz/f2Vlb/qWZa2ae4i3h07DjtKSz3hnDvFYvKotPTvgdRUPxUfDor3gi5gYpiZfvpP5iqCo9hqLyz0
2oXCgPAzbVm0iAyVlf1+YvXqnt4NGyYs6enkF4jeAbfAD7QAZcWKmZ/0+oFCmYy+IJ++6j11dS1U3BFO
PDGRDK1Z80cDw3QgtbE0K+udwfLy+0PofUi8E7SDNlpEqZzpqazs/VSjoRvPBxE8z8aNVkdcXHjnEK+X
y9uRaAR0IxP2FBS80afTjQ5kZz8Rvwq+AVdAf0bG4zs63T3kLgV8nl2rHfJIpWGdGxnmeyQ1BMVDXyr+
3qIitq+ycrQtO9v/b/GvIiLIHRQwqdXjyCsG8byempotE2q12w3RkHNzScmfu8KLh4LfVFCQj40duZ2T
Qy4HxU35+TNfqNWPypYv/wQ5swUQC9urqo5Yy8u9gyzrp86bFIpOjM8lHgq+YdUqOW3HVawzqVQzl+D8
JYHgHOa0YLZFiAgmOTm2V6f7/EF5ufNiURFOX2QTxhkgpPM0aY7gX6mufvdnrXb8lkbjKk1Npd8CHZAA
elyfrKU/4oACrA9e5/v4vwDo0aQnZwN4DYR94BYA6ph+rOmV3s8nqAn6/n85CC0YNMbj/QOlgNkkdPGc
ugAAAABJRU5ErkJggg==
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAVDSURBVEhLjZVtTFNXGMcLQmdHO6AdarLSOcTxXqC3lFs3
FceLFC3YgqBjRM2ouILiC0oUozGauPiSLNmH7cP2YctMZtwSXdzGhFE3J5ABAg4XBHRYS+l74bKXZJGe
/U9pdcay8SS/3N5znvN//n3OuffyaAwUFkaZEhI+ur5s2eg1mezDDVLpSxiO8E/+T4yoVOxvMtmNsaVL
+y8nJlZgKAqE+SdpDBmNwp7Cwi9GmpvJ+PnzpLOpyXeNZTtyRaKVmI6cywodwwzzunXr1gfcmTNk5tw5
MlpZ6X4/ObleFh0di+m5Ih0rVnxwd/9+cv/ECTJ+/DixINl86BBpZdkbcpHoVaSELDKmVr8BcTN39izh
sJZraSEzx46Ru1qt5yup9D2kiEEE77pEYqHi95uayIMjR4gFSZOnT5Pe5mbfNZXqpwyRKAmJTxVBW4qs
VVUW6pyKz0CcO3iQzMCYt6aGmOLi7iCNBSJee3z8hdHaWjKOAmZgOXyYWLHAfuoUuYV2tbNsV7pQmIxk
f5ERhaJosrLSMv3uu4SDmRmY4rBuZt8+MrVrF2lVqZzbJJJLSC0BYp5++fKXW5XKGzd37PA9RNIEmIQb
O/bEhZY5Dhwg11EkWyhMucUwhRMVFdbpkyf9LeHgmEN7ucZGMg1xU3a2O0kg+BTCBiAHdMN5kYxEkowi
XeZt24h1925ia2gg9r17iRPFPBAabGjwdavVg/fKyizc0aN+xxzmOORy9fWPxVMEggvQqwVpAfFw4A9+
tlic8p1C0dlTXe2z1dURB3AZjcQNAS+KeffsIdNwO02Fcc/h3i+O9nYqlR65UEjFqfNUsBg8OaqB4KvE
4tT2zMwu6+bNxLF9O3EBj8FAvHA4hYJT2MCpsjLiXbeOeNVq4gadubneLJHoItbvBNS5ADwjHgx+Tmxs
Wrtc3jWUk/PIvWULcWk0xMUwxCmVEqdIRJyRkcS5aBEZFAp9bQkJHjYmhm5oHUgHz4N5xYPhb1ePXD4w
CUEbxOzAAaiwn4gI0p+Z+VdFcvI3yH8HZIAFifvDWlNjtKrVZptA8Kw4oGNDiYmPTFrtvZT4+DIsiQYL
E/caDAec+flOG9zPJz4BHgBzWhrp1+nuvLlqVRaW/udrxR8ug6HFsX69yxYV9Yy4A72n7aLi42A0PJwM
gR+ysnwD5eW/VrAsbdP8RTw7dx6xFxe7Qzl3SCTkYXHx37eSknxUfCQg3gc6gYlhZgfoP5mvCI5iiy0/
32MTCv3CT7VlyRIyXFLy+8k1a7r7Nm6cNKekkF8g2gtugh9pAUpOzuzPFRWD+XI5fUE+edW7a2ubqbg9
lHhcHBleu/aPeoZpR2pDcXr6W3dKS+8No/dB8Q7QBlppEZVqtru8vO8TrZZuPB+E8dybNlnsMTGhnUO8
TqFoQ6IR0I0U783Le61frx8bzMh4LP4tuAqugIHU1Ee9ev1d5C4HfJ5Npxt2y2QhnRsZ5nsk1QfEg18q
/r6CAra/vHzs64wM37/FvwwLI70oYNJoJpBXCGJ53dXVWyc1GpcLokHnQ0VFf+4OLR4MfmNeXi42drQn
M5NcDoibcnNnP9doHpasXPkxcuYKIBa3VVYetZSWem6zrI86b1QqOzA+n3gw+IbVqxW0HVexzqRWz16C
8xcEgnOY04G5FiHCmISE6D69/rP7paWOiwUFOH3hjRhngJDO06R5gn+lqurt2zrdxE2t1lmclES/BXog
BfS4Pl5Lf8QAJdgQuC708X8O0KNJT85G8AoI+cAtAtQx/VjTK71fSFAT9P3/YgBaMGCMx/sHyjLY+hqD
P/QAAAAASUVORK5CYII=
</value>
</data>
<data name="BTT_LOG.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">

View File

@@ -237,8 +237,7 @@ Namespace DownloadObjects.STDownloader
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
Protected Overridable Sub BTT_ADD_KeyClick(ByVal Sender As ToolStripMenuItemKeyClick, ByVal e As KeyClickEventArgs) Handles BTT_ADD.KeyClick, BTT_ADD_PLS_ARR.KeyClick
Dim pForm As ParsingProgressForm = Nothing
Try
Dim useCookies As Boolean = MyYouTubeSettings.DefaultUseCookies
@@ -252,8 +251,6 @@ Namespace DownloadObjects.STDownloader
Dim c As IYouTubeMediaContainer = Nothing
Dim url$ = String.Empty
Dim GetDefault As Boolean = True
Dim GetShorts As Boolean = True
If sTag = "pls" Then
Using pf As New PlaylistArrayForm With {.DesignXML = DesignXML}
@@ -266,7 +263,7 @@ Namespace DownloadObjects.STDownloader
pForm.SetInitialValues(.Count, "Parsing playlists...")
Dim containers As New List(Of IYouTubeMediaContainer)
For Each u$ In .Self
containers.Add(YouTubeFunctions.Parse(standardize(u), useCookiesParse, pForm.Token, pForm.MyProgress, True, False))
containers.Add(YouTubeFunctions.Parse(standardize(u), useCookiesParse, pForm.Token, pForm.MyProgress))
pForm.NextPlaylist()
pForm.MyProgress.Perform()
Next
@@ -295,20 +292,36 @@ Namespace DownloadObjects.STDownloader
End If
End Using
Else
Select Case sTag
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
Dim downAsIs As Boolean = False
Dim channelTab As YouTubeChannelTab? = Nothing
Dim __channelTab As YouTubeChannelTab = YouTubeChannelTab.All
Dim oType As YouTubeMediaType = YouTubeFunctions.Info_GetUrlType(url,,,,, __channelTab)
If oType = YouTubeMediaType.Channel Then
channelTab = __channelTab
Using channelTabForm As New ChannelTabsChooserForm(__channelTab, url)
With channelTabForm
.ShowDialog()
If .DialogResult = DialogResult.OK Then
channelTab = .Result
downAsIs = .MyUrlAsIs
url = YouTubeFunctions.StandardizeURL_Channel(.URL, Not downAsIs)
Else
Exit Sub
End If
End With
End Using
End If
pForm = New ParsingProgressForm
pForm.Show(Me)
pForm.SetInitialValues(1, "Parsing data...")
c = YouTubeFunctions.Parse(standardize(url), useCookiesParse, pForm.Token, pForm.MyProgress, GetDefault, GetShorts)
c = YouTubeFunctions.Parse(standardize(url), useCookiesParse, pForm.Token, pForm.MyProgress,,, channelTab,
oType <> YouTubeMediaType.Channel Or downAsIs)
pForm.Dispose()
End If
If Not c Is Nothing Then

View File

@@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices
' by using the '*' as shown below:
' <Assembly: AssemblyVersion("1.0.*")>
<Assembly: AssemblyVersion("2023.12.10.0")>
<Assembly: AssemblyFileVersion("2023.12.10.0")>
<Assembly: AssemblyVersion("2023.12.13.0")>
<Assembly: AssemblyFileVersion("2023.12.13.0")>
<Assembly: NeutralResourcesLanguage("en")>

View File

@@ -115,6 +115,12 @@
<ItemGroup>
<Compile Include="Attributes\GridVisibleAttribute.vb" />
<Compile Include="Base\TableControlsProcessor.vb" />
<Compile Include="Controls\ChannelTabsChooserForm.Designer.vb">
<DependentUpon>ChannelTabsChooserForm.vb</DependentUpon>
</Compile>
<Compile Include="Controls\ChannelTabsChooserForm.vb">
<SubType>Form</SubType>
</Compile>
<Compile Include="Controls\PlayListParserForm.Designer.vb">
<DependentUpon>PlayListParserForm.vb</DependentUpon>
</Compile>
@@ -208,6 +214,9 @@
<Compile Include="Base\YouTubeSettings.vb" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Controls\ChannelTabsChooserForm.resx">
<DependentUpon>ChannelTabsChooserForm.vb</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Controls\PlayListParserForm.resx">
<DependentUpon>PlayListParserForm.vb</DependentUpon>
</EmbeddedResource>

View File

@@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices
' by using the '*' as shown below:
' <Assembly: AssemblyVersion("1.0.*")>
<Assembly: AssemblyVersion("2023.12.10.0")>
<Assembly: AssemblyFileVersion("2023.12.10.0")>
<Assembly: AssemblyVersion("2023.12.13.0")>
<Assembly: AssemblyFileVersion("2023.12.13.0")>
<Assembly: NeutralResourcesLanguage("en")>

View File

@@ -18,8 +18,30 @@ Namespace API.Base
Friend ReadOnly TsFilesRegEx As RParams = RParams.DM(".+?\.ts[^\r\n]*", 0, RegexReturn.List)
End Module
End Namespace
Friend Structure M3U8URL
Friend URL As String
Friend Extension As String
Friend Sub New(ByVal _URL As String, Optional ByVal _Extension As String = Nothing)
URL = _URL
Extension = _Extension
End Sub
Public Shared Widening Operator CType(ByVal URL As String) As M3U8URL
Return New M3U8URL(URL)
End Operator
Public Overrides Function Equals(ByVal Obj As Object) As Boolean
If Not IsNothing(Obj) Then
If TypeOf Obj Is M3U8URL Then
Return CType(Obj, M3U8URL).URL = URL
Else
Return CStr(Obj) = URL
End If
End If
Return False
End Function
End Structure
Friend NotInheritable Class M3U8Base
Friend Const TempCacheFolderName As String = "tmpCache"
Friend Const TempFilePrefix As String = "ConPart_"
Private Sub New()
End Sub
Friend Shared Function CreateUrl(ByVal Appender As String, ByVal File As String) As String
@@ -32,9 +54,17 @@ Namespace API.Base
Return $"{Appender.StringTrimEnd("/")}/{File}"
End If
End Function
Friend Shared Function Download(ByVal URLs As List(Of String), ByVal DestinationFile As SFile, Optional ByVal Responser As Responser = Nothing,
Optional ByVal Token As CancellationToken = Nothing, Optional ByVal Progress As MyProgress = Nothing,
Optional ByVal UsePreProgress As Boolean = True, Optional ByVal ExistingCache As CacheKeeper = Nothing) As SFile
Friend Overloads Shared Function Download(ByVal URLs As List(Of String), ByVal DestinationFile As SFile, Optional ByVal Responser As Responser = Nothing,
Optional ByVal Token As CancellationToken = Nothing, Optional ByVal Progress As MyProgress = Nothing,
Optional ByVal UsePreProgress As Boolean = True, Optional ByVal ExistingCache As CacheKeeper = Nothing,
Optional ByVal OnlyDownload As Boolean = False) As SFile
Return Download(URLs.ListCast(Of M3U8URL), DestinationFile, Responser, Token, Progress, UsePreProgress, ExistingCache, OnlyDownload)
End Function
Friend Overloads Shared Function Download(ByVal URLs As List(Of M3U8URL), ByVal DestinationFile As SFile, Optional ByVal Responser As Responser = Nothing,
Optional ByVal Token As CancellationToken = Nothing, Optional ByVal Progress As MyProgress = Nothing,
Optional ByVal UsePreProgress As Boolean = True, Optional ByVal ExistingCache As CacheKeeper = Nothing,
Optional ByVal OnlyDownload As Boolean = False) As SFile
Const defaultExtension$ = "ts"
Dim Cache As CacheKeeper = Nothing
Using tmpPr As New PreProgress(Progress)
Try
@@ -59,10 +89,13 @@ Namespace API.Base
End If
End If
Dim p As SFileNumbers = SFileNumbers.Default(ConcatFile.Name)
Dim pNum As ANumbers = SFileNumbers.NumberProviderDefault
p.NumberProvider = pNum
DirectCast(p.NumberProvider, ANumbers).GroupSize = {URLs.Count.ToString.Length, 3}.Max
ConcatFile = SFile.IndexReindex(ConcatFile,,, p, EDP.ReturnValue)
Dim i%
Dim dFile As SFile = cache2.RootDirectory
dFile.Extension = "ts"
dFile.Extension = defaultExtension
Using w As New DownloadObjects.WebClient2(Responser)
For i = 0 To URLs.Count - 1
If progressExists Then
@@ -73,12 +106,14 @@ Namespace API.Base
End If
End If
Token.ThrowIfCancellationRequested()
dFile.Name = $"ConPart_{i}"
w.DownloadFile(URLs(i), dFile)
dFile.Name = $"{TempFilePrefix}{i.NumToString(pNum)}"
dFile.Extension = URLs(i).Extension.IfNullOrEmpty(defaultExtension)
w.DownloadFile(URLs(i).URL, dFile)
cache2.AddFile(dFile, True)
Next
End Using
DestinationFile = FFMPEG.ConcatenateFiles(cache2, Settings.FfmpegFile.File, ConcatFile, Settings.CMDEncoding, p, EDP.ThrowException)
If Not OnlyDownload Then _
DestinationFile = FFMPEG.ConcatenateFiles(cache2, Settings.FfmpegFile.File, ConcatFile, Settings.CMDEncoding, p, EDP.ThrowException)
Return DestinationFile
End If
End If

View File

@@ -47,6 +47,7 @@ Namespace API.Base
Progress.InformationTemporary = $"{HOST.Name} ({c - s}/{c}) Images: {_TotalImages}; Videos: {_TotalVideos}"
End If
End If
If _FeedDataExists Then Downloader.Files.Sort()
End Sub
Private Overloads Sub Download(ByVal Host As SettingsHost, ByVal Number As Integer, ByVal Count As Integer,
ByVal Token As CancellationToken, ByVal Multiple As Boolean)

View File

@@ -14,5 +14,6 @@ Namespace API.Xhamster
Friend ReadOnly HtmlScript As RParams = RParams.DMS("\<script id='initials-script'\>window.initials=(\{.+?\});\</script\>", 1, EDP.ReturnValue,
CType(Function(Input$) Input.StringTrim, Func(Of String, String)))
Friend ReadOnly FirstM3U8FileRegEx As RParams = RParams.DM("RESOLUTION=\d+x(\d+).*?[\r\n]+?([^#]*?\.m3u8.*)", 0, RegexReturn.List)
Friend ReadOnly SecondM3U8FileRegEx As RParams = RParams.DM("(#EXT-X-MAP.URI=""([^""]+((?<=\.)([^\?\.]{2,5})(?=(\?|\Z|"")))(.+|))""|#EXTINF[^\r\n]*[\r\n]+(([^\r\n]+((?<=\.)([^\?\.\r\n]{2,5})(?=(\?[^\r\n]+|[\r\n]+)))([^\r\n]+|))([\r\n]+|\Z)))", 0, RegexReturn.List)
End Module
End Namespace

View File

@@ -10,6 +10,7 @@ Imports System.Threading
Imports SCrawler.API.Base
Imports SCrawler.API.Base.M3U8Declarations
Imports PersonalUtilities.Forms.Toolbars
Imports PersonalUtilities.Tools
Imports PersonalUtilities.Tools.Web.Clients
Imports PersonalUtilities.Functions.RegularExpressions
Namespace API.Xhamster
@@ -40,18 +41,40 @@ Namespace API.Xhamster
Next
Return String.Empty
End Function
Private Shared Function ParseSecondM3U8(ByVal URL As String, ByVal Responser As Responser, ByVal Appender As String) As List(Of String)
Private Shared Function ParseSecondM3U8(ByVal URL As String, ByVal Responser As Responser, ByVal Appender As String) As List(Of M3U8URL)
Dim r$
Dim l As List(Of String)
Dim ll As List(Of M3U8URL) = Nothing
Dim u As M3U8URL
Dim rmsF As Func(Of RegexMatchStruct, M3U8URL) =
Function(ByVal rms As RegexMatchStruct) As M3U8URL
With rms
If .Arr(0).IsEmptyString Then
Return New M3U8URL(.Arr(3).IfNullOrEmpty(.Arr(4)), .Arr(5).IfNullOrEmpty(.Arr(6)))
Else
Return New M3U8URL(.Arr(0), .Arr(1).IfNullOrEmpty(.Arr(2)))
End If
End With
End Function
For i% = 0 To 1
Try
Responser.UseGZipStream = i
r = Responser.GetResponse(URL)
If Not r.IsEmptyString Then
l = RegexReplace(r, TsFilesRegEx)
If l.ListExists Then
For indx% = 0 To l.Count - 1 : l(indx) = M3U8Base.CreateUrl(Appender, l(indx)) : Next
Return l
If Not l.ListExists Then
With RegexFields(Of RegexMatchStruct)(r, {SecondM3U8FileRegEx}, {2, 4, 3, 8, 7, 10, 9}, EDP.ReturnValue)
If .ListExists Then ll = .Select(rmsF).ListWithRemove(Function(v) v.URL.IsEmptyString)
End With
End If
If Not ll.ListExists And l.ListExists Then ll = l.ListCast(Of M3U8URL)
If ll.ListExists Then
For indx% = 0 To ll.Count - 1
u = ll(indx)
u.URL = M3U8Base.CreateUrl(Appender, u.URL)
ll(indx) = u
Next
Return ll
End If
End If
Catch
@@ -59,14 +82,14 @@ Namespace API.Xhamster
Next
Return Nothing
End Function
Private Shared Function ObtainUrls(ByVal URL As String, ByVal Responser As Responser, ByVal UHD As Boolean) As List(Of String)
Private Shared Function ObtainUrls(ByVal URL As String, ByVal Responser As Responser, ByVal UHD As Boolean) As List(Of M3U8URL)
Try
Dim file$ = ParseFirstM3U8(URL, Responser, UHD)
If Not file.IsEmptyString Then
Responser.UseGZipStream = False
Dim appender$ = URL.Replace(URL.Split("/").LastOrDefault, String.Empty)
URL = M3U8Base.CreateUrl(appender, file)
Dim l As List(Of String) = ParseSecondM3U8(URL, Responser, appender)
Dim l As List(Of M3U8URL) = ParseSecondM3U8(URL, Responser, appender)
If l.ListExists Then Return l
End If
Return Nothing
@@ -75,8 +98,57 @@ Namespace API.Xhamster
End Try
End Function
Friend Shared Function Download(ByVal Media As UserMedia, ByVal Responser As Responser, ByVal UHD As Boolean,
ByVal Token As CancellationToken, ByVal Progress As MyProgress, ByVal UsePreProgress As Boolean) As SFile
Return M3U8Base.Download(ObtainUrls(Media.URL, Responser, UHD), Media.File, Responser, Token, Progress, UsePreProgress)
ByVal Token As CancellationToken, ByVal Progress As MyProgress, ByVal UsePreProgress As Boolean,
ByVal ReencodeVideos As Boolean) As SFile
'Return M3U8Base.Download(ObtainUrls(Media.URL, Responser, UHD), Media.File, Responser, Token, Progress, UsePreProgress)
Dim Cache As CacheKeeper = Nothing
Try
Dim urls As List(Of M3U8URL) = ObtainUrls(Media.URL, Responser, UHD)
If urls.ListExists Then
Cache = New CacheKeeper($"{Media.File.PathWithSeparator}_{M3U8Base.TempCacheFolderName}\") With {.DisposeSuspended = True}
Cache.CacheDeleteError = CacheDeletionError(Cache)
Dim isNewWay As Boolean = Not urls(0).Extension.IsEmptyString AndAlso urls(0).Extension = "mp4" AndAlso urls.Count > 1 AndAlso
urls.Exists(Function(u) Not u.Extension = urls(0).Extension)
Dim f As SFile = M3U8Base.Download(urls, Media.File, Responser, Token, Progress, UsePreProgress, Cache, isNewWay)
If isNewWay Then
f = Media.File
With DirectCast(Cache.CurrentInstance, CacheKeeper)
If .Count > 0 Then
Using batch As New BatchExecutor With {.Encoding = Settings.CMDEncoding}
batch.ChangeDirectory(.Self.RootDirectory)
Using bat As New TextSaver($"{ .RootDirectory.PathWithSeparator}Merge.bat")
Dim tmpFile As SFile
Dim tmpFileStr$
If ReencodeVideos Then
tmpFile = $"{ .Self.RootDirectory.PathWithSeparator}NewVideo.{urls(1).Extension}"
tmpFileStr = tmpFile.File
.AddFile(tmpFile)
Else
tmpFile = Media.File
tmpFileStr = $"""{tmpFile}"""
End If
bat.AppendLine($"copy /b { .First.File} + {M3U8Base.TempFilePrefix}*.{urls(1).Extension} {tmpFileStr}")
If ReencodeVideos Then bat.AppendLine($"""{Settings.FfmpegFile}"" -i ""{tmpFile}"" ""{Media.File}""")
bat.Save()
.AddFile(bat.File)
batch.Execute($"""{bat.File}""")
If f.Exists Then Return f
End Using
End Using
End If
End With
ElseIf f.Exists Then
Return f
End If
End If
Return Nothing
Finally
Cache.DisposeIfReady(False)
End Try
End Function
End Class
End Namespace

View File

@@ -28,7 +28,11 @@ Namespace API.Xhamster
End Get
End Property
<PropertyOption(ControlText:="Download UHD", ControlToolTip:="Download UHD (4K) content"), PXML, PClonable>
Friend Property DownloadUHD As PropertyValue
Friend ReadOnly Property DownloadUHD As PropertyValue
<PropertyOption(ControlText:="Re-encode downloaded videos if necessary",
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
#End Region
#Region "Initializer"
Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean)
@@ -38,6 +42,7 @@ Namespace API.Xhamster
SiteDomains = New PropertyValue(Domains.DomainsDefault, GetType(String))
Domains.DestinationProp = SiteDomains
DownloadUHD = New PropertyValue(False)
ReencodeVideos = New PropertyValue(False)
_SubscriptionsAllowed = True
UrlPatternUser = "https://xhamster.com/{0}/{1}"

View File

@@ -537,7 +537,7 @@ Namespace API.Xhamster
Private Overloads Function GetM3U8(ByRef m As UserMedia, ByVal j As EContainer) As Boolean
Dim node As EContainer = j({"xplayerSettings", "sources", "hls"})
If node.ListExists Then
Dim url$ = node.GetNode({New NodeParams("url", True, True, True, True, 2)})
Dim url$ = node.GetNode({New NodeParams("url", True, True, True, True, 2)}).XmlIfNothingValue
If Not url.IsEmptyString Then m.URL = url : m.Type = UTypes.m3u8 : Return True
End If
Return False
@@ -555,7 +555,7 @@ Namespace API.Xhamster
End Sub
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)
Return M3U8.Download(Media, Responser, MySettings.DownloadUHD.Value, Token, Progress, Not IsSingleObjectDownload, MySettings.ReencodeVideos.Value)
End Function
#End Region
#Region "Create media"

View File

@@ -175,7 +175,7 @@ Namespace API.YouTube
maxDate = Nothing
LastDownloadDatePlaylist = nDate(LastDownloadDatePlaylist)
url = $"https://{IIf(IsMusic, "music", "www")}.youtube.com/playlist?list={ID}"
container = YouTubeFunctions.Parse(url, YTUseCookies, Token, pr, True, False,, LastDownloadDatePlaylist)
container = YouTubeFunctions.Parse(url, YTUseCookies, Token, pr,, LastDownloadDatePlaylist,, True)
applySpecFolder.Invoke(String.Empty, False)
If fillList.Invoke(LastDownloadDatePlaylist) Then LastDownloadDatePlaylist = If(maxDate, Now)
ElseIf YTMediaType = YouTubeMediaType.Channel Then
@@ -183,7 +183,7 @@ Namespace API.YouTube
maxDate = Nothing
LastDownloadDateVideos = nDate(LastDownloadDateVideos)
url = $"https://{IIf(IsMusic, "music", "www")}.youtube.com/{IIf(IsMusic Or IsChannelUser, $"{YouTubeFunctions.UserChannelOption}/", "@")}{ID}"
container = YouTubeFunctions.Parse(url, YTUseCookies, Token, pr, True, False,, LastDownloadDateVideos)
container = YouTubeFunctions.Parse(url, YTUseCookies, Token, pr,, LastDownloadDateVideos,, True)
applySpecFolder.Invoke(IIf(IsMusic, String.Empty, "Videos"), False)
If fillList.Invoke(LastDownloadDateVideos) Then LastDownloadDateVideos = If(maxDate, Now)
End If
@@ -191,7 +191,7 @@ Namespace API.YouTube
maxDate = Nothing
LastDownloadDateShorts = nDate(LastDownloadDateShorts)
url = $"https://www.youtube.com/{IIf(IsChannelUser, $"{YouTubeFunctions.UserChannelOption}/", "@")}{ID}/shorts"
container = YouTubeFunctions.Parse(url, YTUseCookies, Token, pr, True, False,, LastDownloadDateShorts)
container = YouTubeFunctions.Parse(url, YTUseCookies, Token, pr,, LastDownloadDateShorts,, True)
applySpecFolder.Invoke("Shorts", False)
If fillList.Invoke(LastDownloadDateShorts) Then LastDownloadDateShorts = If(maxDate, Now)
End If
@@ -199,7 +199,7 @@ Namespace API.YouTube
maxDate = Nothing
LastDownloadDatePlaylist = nDate(LastDownloadDatePlaylist)
url = $"https://www.youtube.com/{IIf(IsChannelUser, $"{YouTubeFunctions.UserChannelOption}/", "@")}{ID}/playlists"
container = YouTubeFunctions.Parse(url, YTUseCookies, Token, pr, True, False,, LastDownloadDatePlaylist)
container = YouTubeFunctions.Parse(url, YTUseCookies, Token, pr,, LastDownloadDatePlaylist,, True)
applySpecFolder.Invoke("Playlists", True)
If fillList.Invoke(LastDownloadDatePlaylist) Then LastDownloadDatePlaylist = If(maxDate, Now)
End If

View File

@@ -25,8 +25,6 @@ Namespace DownloadObjects.STDownloader
AppMode = False
Icon = My.Resources.ArrowDownIcon_Blue_24
BTT_ADD_PLS_ARR.Text = $"YouTube: {BTT_ADD_PLS_ARR.Text}"
BTT_ADD_NO_SHORTS.Text = $"YouTube: {BTT_ADD_NO_SHORTS.Text}"
BTT_ADD_SHORTS_ONLY.Text = $"YouTube: {BTT_ADD_SHORTS_ONLY.Text}"
BTT_ADD_URLS_ARR = New ToolStripMenuItemKeyClick("Add an array of URLs", PersonalUtilities.My.Resources.PlusPic_Green_24) With {.Tag = UrlsArrTag}
BTT_ADD_URLS_EXTERNAL = New ToolStripMenuItemKeyClick With {.Tag = TAG_EXTERNAL}
MENU_ADD.DropDownItems.Insert(1, BTT_ADD_URLS_ARR)

View File

@@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices
' by using the '*' as shown below:
' <Assembly: AssemblyVersion("1.0.*")>
<Assembly: AssemblyVersion("2023.12.10.0")>
<Assembly: AssemblyFileVersion("2023.12.10.0")>
<Assembly: AssemblyVersion("2023.12.13.0")>
<Assembly: AssemblyFileVersion("2023.12.13.0")>
<Assembly: NeutralResourcesLanguage("en")>

View File

@@ -70,6 +70,9 @@ Friend Class SettingsCLS : Implements IDownloaderSettings, IDisposable
Public Shared Widening Operator CType(ByVal f As ProgramFile) As SFile
Return f.File
End Operator
Public Shared Narrowing Operator CType(ByVal f As ProgramFile) As String
Return f.ToString
End Operator
Public Overrides Function ToString() As String
Return File.ToString
End Function