' 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.Globalization Imports System.Drawing.Design Imports System.ComponentModel Imports SCrawler.API.YouTube.Attributes Imports SCrawler.DownloadObjects.STDownloader Imports PersonalUtilities.Forms Imports PersonalUtilities.Functions.XML Imports PersonalUtilities.Functions.XML.Base Imports PersonalUtilities.Functions.XML.Objects Imports PersonalUtilities.Functions.XML.Attributes Imports PersonalUtilities.Functions.XML.Attributes.Specialized Imports PersonalUtilities.Tools Imports PersonalUtilities.Tools.Grid.Base Imports PersonalUtilities.Tools.Grid.Attributes Imports PersonalUtilities.Tools.Grid.Collections Imports PersonalUtilities.Tools.Grid.Specialized Imports PersonalUtilities.Tools.Web.Cookies Namespace API.YouTube.Base Public Class YouTubeSettings : Implements IXMLValuesContainer, IGridValuesContainer, IDownloaderSettings #Region "Events" Private Event OnBeginUpdate As EventHandler Implements IXMLValuesContainer.OnBeginUpdate Private Event OnEndUpdate As EventHandler Implements IXMLValuesContainer.OnEndUpdate #End Region #Region "Declarations" Private ReadOnly Property XML As XmlFile Implements IXMLValuesContainer.XML Friend ReadOnly Property DesignXml As XmlFile Friend ReadOnly Property FILTER As Controls.YTDataFilter Private Property Mode As GridUpdateModes = GridUpdateModes.OnConfirm Implements IGridValuesContainer.Mode Friend ReadOnly Property PlaylistFormSplitterDistance As XMLValue(Of Integer) Friend ReadOnly Property DownloadLocations As DownloadLocationsCollection Friend ReadOnly Property PlaylistsLocations As DownloadLocationsCollection Public Overridable Property AccountName As String Private ReadOnly Property SettingsVersion As XMLValue(Of Integer) #Region "Environment" #Region "Programs" Public ReadOnly Property YTDLP As XMLValue(Of SFile) Public ReadOnly Property FFMPEG As XMLValue(Of SFile) Private ReadOnly Property ENVIR_FFMPEG As SFile Implements IDownloaderSettings.ENVIR_FFMPEG Get Return FFMPEG End Get End Property Private ReadOnly Property ENVIR_YTDLP As SFile Implements IDownloaderSettings.ENVIR_YTDLP Get Return YTDLP End Get End Property Private ReadOnly Property ENVIR_GDL As SFile Implements IDownloaderSettings.ENVIR_GDL Get Return Nothing End Get End Property Private ReadOnly Property ENVIR_CURL As SFile Implements IDownloaderSettings.ENVIR_CURL Get Return Nothing End Get End Property #End Region Public ReadOnly Property Cookies As CookieKeeper Private Function ShouldSerializeCookies() As Boolean Return Cookies.Count > 0 End Function Private Sub ResetCookies() Cookies.Clear() End Sub Private Class CookieListForm2 : Inherits CookieListForm Public Sub New() ShowGrid = False End Sub End Class Public ReadOnly Property OutputPath As XMLValue(Of SFile) Public ReadOnly Property LatestPlaylistFile As XMLValue(Of SFile) Private Class GridSFileTypeEditor_M3U8 : Inherits GridSFileTypeEditor Public Overrides Function EditValue(ByVal Context As ITypeDescriptorContext, ByVal Provider As IServiceProvider, ByVal Value As Object) As Object Dim f As SFile = SFile.SelectFiles(New SFile(CStr(AConvert(Of String)(Value, AModes.Var, String.Empty))), False, "Select playlist file", "Playlists|*.m3u;*.m3u8|All files|*.*", EDP.ReturnValue).FirstOrDefault() If Not f.IsEmptyString() Then Value = f Return Value End Function End Class Public ReadOnly Property OutputPathAutoChange As XMLValue(Of Boolean) Public ReadOnly Property OutputPathAskForName As XMLValue(Of Boolean) Private ReadOnly Property IDownloaderSettings_OutputPathAskForName As Boolean Implements IDownloaderSettings.OutputPathAskForName Get Return OutputPathAskForName End Get End Property Public ReadOnly Property OutputPathAutoAddPaths As XMLValue(Of Boolean) Private ReadOnly Property IDownloaderSettings_OutputPathAutoAddPaths As Boolean Implements IDownloaderSettings.OutputPathAutoAddPaths Get Return OutputPathAutoAddPaths End Get End Property Public ReadOnly Property OnItemDoubleClick As XMLValue(Of DoubleClickBehavior) Private ReadOnly Property IDownloaderSettings_OnItemDoubleClick As DoubleClickBehavior Implements IDownloaderSettings.OnItemDoubleClick Get Return OnItemDoubleClick End Get End Property Public ReadOnly Property OpenFolderInOtherProgram As XMLValueUse(Of String) Private Property IDownloaderSettings_OpenFolderInOtherProgram As Boolean Implements IDownloaderSettings.OpenFolderInOtherProgram Get Return OpenFolderInOtherProgram.Attribute.ValueTemp End Get Set(ByVal use As Boolean) OpenFolderInOtherProgram.Attribute.ValueTemp = use End Set End Property Private Function ShouldSerializeIDownloaderSettings_OpenFolderInOtherProgram() As Boolean Return DirectCast(OpenFolderInOtherProgram.Attribute, IGridValue).ShouldSerializeValue End Function Private Property IDownloaderSettings_OpenFolderInOtherProgram_Command As String Implements IDownloaderSettings.OpenFolderInOtherProgram_Command Get Return OpenFolderInOtherProgram.ValueTemp End Get Set(ByVal command As String) OpenFolderInOtherProgram.ValueTemp = command End Set End Property Private Function ShouldSerializeIDownloaderSettings_OpenFolderInOtherProgram_Command() As Boolean Return DirectCast(OpenFolderInOtherProgram, IGridValue).ShouldSerializeValue End Function Friend ReadOnly Property CheckUpdatesAtStart As XMLValue(Of Boolean) #End Region #Region "Info" Public ReadOnly Property CreateUrlFiles As XMLValue(Of Boolean) Private ReadOnly Property IDownloaderSettings_CreateUrlFiles As Boolean Implements IDownloaderSettings.CreateUrlFiles Get Return CreateUrlFiles End Get End Property Public ReadOnly Property CreateDescriptionFiles As XMLValue(Of Boolean) Public ReadOnly Property CreateDescriptionFiles_CreateWithNoDescription As XMLValue(Of Boolean) Public ReadOnly Property CreateThumbnails_Video As XMLValue(Of Boolean) Public ReadOnly Property CreateThumbnails_Music As XMLValue(Of Boolean) #End Region #Region "Defaults" Public ReadOnly Property StandardizeURLs As XMLValue(Of Boolean) Public ReadOnly Property ReplaceModificationDate As XMLValue(Of Boolean) Public ReadOnly Property DefaultUseCookies As XMLValue(Of Boolean) Public ReadOnly Property DefaultProtocol As XMLValue(Of Protocols) Public ReadOnly Property RemoveDownloadedAutomatically As XMLValue(Of Boolean) Private ReadOnly Property IDownloaderSettings_RemoveDownloadedAutomatically As Boolean Implements IDownloaderSettings.RemoveDownloadedAutomatically Get Return RemoveDownloadedAutomatically End Get End Property Public ReadOnly Property DownloadAutomatically As XMLValue(Of Boolean) Private ReadOnly Property IDownloaderSettings_DownloadAutomatically As Boolean Implements IDownloaderSettings.DownloadAutomatically Get Return DownloadAutomatically End Get End Property Public ReadOnly Property MaxJobsCount As XMLValue(Of Integer) Private ReadOnly Property IDownloaderSettings_MaxJobsCount As Integer Implements IDownloaderSettings.MaxJobsCount Get Return MaxJobsCount End Get End Property Public ReadOnly Property ShowNotifications As XMLValue(Of Boolean) Private ReadOnly Property IDownloaderSettings_ShowNotifications As Boolean Implements IDownloaderSettings.ShowNotifications Get Return ShowNotifications End Get End Property Public ReadOnly Property ShowNotificationsEveryDownload As XMLValue(Of Boolean) Private ReadOnly Property IDownloaderSettings_ShowNotificationsEveryDownload As Boolean Implements IDownloaderSettings.ShowNotificationsEveryDownload Get Return ShowNotifications And ShowNotificationsEveryDownload End Get End Property Private Sub ShowNotificationsEveryDownload_TempValueChanged(ByVal Sender As Object, ByVal e As EventArgs) If ShowNotificationsEveryDownload.ValueTemp Then ShowNotifications.ValueTemp = True End Sub Public ReadOnly Property CloseToTray As XMLValue(Of Boolean) Public ReadOnly Property ExitConfirm As XMLValue(Of Boolean) Public ReadOnly Property ShowFormDownTrayClick As XMLValue(Of Boolean) Friend ReadOnly Property ProgramText As XMLValue(Of String) Friend ReadOnly Property ProgramDescription As XMLValue(Of String) Public ReadOnly Property FileRemoveCharacters As XMLValue(Of String) Public ReadOnly Property FileAddDateToFileName As XMLValue(Of FileDateMode) Public ReadOnly Property FileAddDateToFileName_VideoForm As XMLValue(Of Boolean) Public ReadOnly Property FileAddDateToFileName_VideoList As XMLValue(Of Boolean) Public ReadOnly Property FileAddChannelToFileName As XMLValue(Of FileDateMode) Public ReadOnly Property ParseLongUserTitle As XMLValue(Of Boolean) #End Region #Region "Defaults ChannelsDownload" 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" Public ReadOnly Property DefaultVideoFormat As XMLValue(Of String) Private Function AvailableVideoFormats_Impl() As String() Return AvailableVideoFormats End Function Public ReadOnly Property DefaultVideoDefinition As XMLValue(Of Integer) Public ReadOnly Property DefaultVideoAllowWebm As XMLValue(Of Boolean) Public ReadOnly Property DefaultVideoConvertNonAVC As XMLValue(Of Boolean) Public ReadOnly Property DefaultVideoEmbedThumbnail As XMLValue(Of Boolean) Public ReadOnly Property DefaultVideoEmbedChapters As XMLValue(Of Boolean) Public ReadOnly Property DefaultVideoIncludeNullSize As XMLValue(Of Boolean) Private ReadOnly Property DefaultVideoFPS_XML As XMLValue(Of Double) Public Property DefaultVideoFPS As Double Get Return DefaultVideoFPS_XML End Get Set(ByVal fps As Double) DefaultVideoFPS_XML.Value = fps End Set End Property Private Function ShouldSerializeDefaultVideoFPS() As Boolean Return DefaultVideoFPS <> DefaultVideoFPS_XML.Value End Function Private Sub ResetDefaultVideoFPS() DefaultVideoFPS = -1 End Sub Friend Class FpsFormatProvider : Implements IGridConversionProvider Private Property Converter As TypeConverter Implements IGridConversionProvider.Converter Private Property Context As ITypeDescriptorContext Implements IGridConversionProvider.Context Private Property DataType As Type Implements IGridConversionProvider.DataType Private Property Instance As Object Implements IGridConversionProvider.Instance Friend Shared ReadOnly Property MyProviderDefault As ANumbers Get Return New ANumbers(ANumbers.Cultures.Primitive) With {.DecimalDigits = 5, .TrimDecimalDigits = True} End Get End Property Friend Const ErrorMessageDefault As String = "The fps value must be a number" Private ReadOnly MyProvider As ANumbers = MyProviderDefault Friend Function ToObject(ByVal Context As ITypeDescriptorContext, ByVal Culture As CultureInfo, ByVal Value As Object) As Object Implements IGridConversionProvider.ToObject Return AConvert(Of Double)(Value, MyProvider, -1) End Function Friend Overloads Function ToString(ByVal Context As ITypeDescriptorContext, ByVal Culture As CultureInfo, ByVal Value As Object, ByVal DestinationType As Type) As Object Implements IGridConversionProvider.ToString If ACheck(Of Double)(Value, AModes.Var, MyProvider) Then Return Value.ToString Else Return -1 End If End Function Friend Function CreateInstance(ByVal Context As ITypeDescriptorContext, ByVal NewValue As Object, ByRef RefreshGrid As Boolean) As Object Implements IGridConversionProvider.CreateInstance If ACheck(Of Double)(NewValue, AModes.Var, MyProvider) Then Return NewValue Else RefreshGrid = True Return -1 End If End Function Friend Function Convert(ByVal Value As Object, ByVal DestinationType As Type, ByVal Provider As IFormatProvider, Optional ByVal NothingArg As Object = Nothing, Optional ByVal e As ErrorsDescriber = Nothing) As Object Implements ICustomProvider.Convert Return AConvert(Value, AModes.Var, DestinationType,, True, -1, MyProvider, EDP.ReturnValue) End Function Friend Function IsValid(ByVal Context As ITypeDescriptorContext, ByVal Value As Object, ByVal DestinationType As Type) As Boolean Implements IGridValidator.IsValid If ACheck(Of Double)(Value, AModes.Var, MyProvider) Then Return True Else Throw New FormatException(ErrorMessageDefault) End If End Function Private Function GetFormat(ByVal FormatType As Type) As Object Implements IFormatProvider.GetFormat Throw New NotImplementedException("'GetFormat' is not available in 'FpsFormatProvider'") End Function End Class Public ReadOnly Property DefaultVideoHighlightFPS_H As XMLValue(Of Integer) Public ReadOnly Property DefaultVideoHighlightFPS_L As XMLValue(Of Integer) Public ReadOnly Property VideoPlaylist_AddExtractedMP3 As XMLValue(Of Boolean) #End Region #Region "Defaults Audio" Public ReadOnly Property DefaultAudioCodec As XMLValue(Of String) Private Function AvailableAudioFormats_Impl() As String() Return AvailableAudioFormats End Function Public ReadOnly Property DefaultAudioCodecMusic As XMLValue(Of String) Public ReadOnly Property DefaultAudioCodecAddit As XMLValuesCollection(Of String) Public ReadOnly Property DefaultAudioEmbedThumbnail As XMLValue(Of Boolean) Public ReadOnly Property DefaultAudioEmbedThumbnail_Cover As XMLValue(Of Boolean) Public ReadOnly Property DefaultAudioEmbedThumbnail_ExtractedFiles As XMLValue(Of Boolean) Public ReadOnly Property DefaultAudioBitrate As XMLValue(Of Integer) Public ReadOnly Property DefaultAudioBitrate_crf As XMLValue(Of Integer) #Region "Music" Public ReadOnly Property MusicPlaylistCreate_M3U8 As XMLValue(Of Boolean) Public ReadOnly Property MusicPlaylistCreate_M3U As XMLValue(Of Boolean) Public ReadOnly Property MusicPlaylistCreate_M3U8_AppendArtist As XMLValue(Of Boolean) Public ReadOnly Property MusicPlaylistCreate_M3U8_AppendExt As XMLValue(Of Boolean) Public ReadOnly Property MusicPlaylistCreate_M3U8_AppendNumber As XMLValue(Of Boolean) Public ReadOnly Property MusicPlaylistCreate_CreationMode As XMLValue(Of M3U8CreationMode) #End Region #End Region #Region "Defaults Subtitles" Public ReadOnly Property DefaultSubtitles As XMLValuesCollection(Of String) Private Property DefaultSubtitles_Impl As String Get If DefaultSubtitles.ValueTemp.Count > 0 Then Return DefaultSubtitles.ValueTemp.ListToString(",") Else Return String.Empty End If End Get Set(ByVal s As String) If s.IsEmptyString Then DefaultSubtitles.ValueTemp = Nothing Else DefaultSubtitles.ValueTemp = ListAddList(Nothing, s.Split(","), LAP.NotContainsOnly, CType(Function(Input$) Input.StringTrim, Func(Of Object, Object))) End If End Set End Property Private Function ShouldSerializeDefaultSubtitles_Impl() As Boolean Return DirectCast(DefaultSubtitles, IGridValue).ShouldSerializeValue End Function Private Sub ResetDefaultSubtitles_Impl() DirectCast(DefaultSubtitles, IGridValue).ResetValue() End Sub Public ReadOnly Property DefaultSubtitlesFormat As XMLValue(Of String) Private Function AvailableSubtitlesFormats_Impl() As String() Return AvailableSubtitlesFormats End Function Public ReadOnly Property DefaultSubtitlesFormatAddit As XMLValuesCollection(Of String) Public ReadOnly Property DefaultSubtitlesEmbed As XMLValue(Of Boolean) #End Region #Region "Trim" Public ReadOnly Property TrimDeleteOriginalFile As XMLValue(Of Boolean) Public ReadOnly Property TrimAddTrimmedFilesToM3U8 As XMLValue(Of Boolean) Public ReadOnly Property TrimSeparateFolder As XMLValue(Of Boolean) Friend Const TrimSeparateFolderNameDefault As String = "Trim" Public ReadOnly Property TrimSeparateFolderName As XMLValue(Of String) #End Region #Region "Errors" Public ReadOnly Property ErrorsIgnore As XMLValue(Of Boolean) #End Region #End Region #Region "Initializer" Public Sub New() Me.New(String.Empty) End Sub Public Sub New(ByVal AccountName As String) Me.AccountName = AccountName DownloadLocations = New DownloadLocationsCollection PlaylistsLocations = New DownloadLocationsCollection DownloadLocations.Load(False, True) PlaylistsLocations.Load(True, True, $"{XmlFile.SettingsFolder}\DownloadLocations_Playlists.xml") Dim acc$ = String.Empty If Not AccountName.IsEmptyString Then acc = $"_{AccountName}" Dim f As SFile = YouTubeSettingsFile f.Name &= acc XML = New XmlFile(f,, False) With {.AutoUpdateFile = True} XML.LoadData(EDP.None) DesignXml = New XmlFile("Settings\DesignDownloader.xml", Protector.Modes.All, False) DesignXml.LoadData(EDP.None) FILTER = New Controls.YTDataFilter InitializeXMLValueProperties(Me) AddHandler ShowNotificationsEveryDownload.TempValueChanged, AddressOf ShowNotificationsEveryDownload_TempValueChanged Cookies = New CookieKeeper Grid.Abstract.DesignerXmlSource.Add(New Grid.Abstract.DesignerXmlData(GetType(CookieListForm2), DesignXml, "CookiesListForm")) f = YouTubeCookieNetscapeFile f.Name &= acc If f.Exists Then Cookies.AddRange(CookieKeeper.ParseNetscapeText(f.GetText(EDP.ReturnValue), EDP.None),, EDP.None) If Not YTDLP.Value.Exists Then YTDLP.Value = ProgramPath("yt-dlp.exe") If Not FFMPEG.Value.Exists Then FFMPEG.Value = ProgramPath("ffmpeg.exe") If Not OutputPath.Value.Exists(SFO.Path, False) Then OutputPath.Value = YouTubeDownloadPathDefault If XML.ChangesDetected Then XML.UpdateData() End Sub Private Function ProgramPath(ByVal Program As String) As SFile If Program.CSFile.Exists Then Return Program.CSFile ElseIf $"Environment\{Program}".CSFile.Exists Then Return $"Environment\{Program}" Else Return SystemEnvironment.FindFileInPaths(Program).ListIfNothing.FirstOrDefault End If End Function #End Region #Region "Edit, Update" Protected Overridable Sub BeginUpdate() Implements IXMLValuesContainer.BeginUpdate, IGridValuesContainer.BeginUpdate XML.BeginUpdate() End Sub Protected Overridable Sub EndUpdate() Implements IXMLValuesContainer.EndUpdate, IGridValuesContainer.EndUpdate XML.EndUpdate() If XML.ChangesDetected Then XML.UpdateData() End Sub Protected Overridable Sub Apply() Implements IGridValuesContainer.Apply XMLValuesApply(Me) ApplyCookies() End Sub Protected Sub ApplyCookies() If Cookies.Count > 0 Then Cookies.SaveNetscapeFile(YouTubeCookieNetscapeFile) Else YouTubeCookieNetscapeFile.Delete(,, EDP.None) End Sub Private Sub BeginEdit() Implements IGridValuesContainer.BeginEdit XMLValuesBeginEdit(Me) End Sub Protected Overridable Sub EndEdit() Implements IGridValuesContainer.EndEdit XMLValuesEndEdit(Me) Cookies.Clear() If YouTubeCookieNetscapeFile.Exists Then Cookies.AddRange(CookieKeeper.ParseNetscapeText(YouTubeCookieNetscapeFile.GetText(EDP.ReturnValue), EDP.None),, EDP.None) End Sub Public Sub ShowForm(ByVal AppMode As Boolean) Using f As New SimpleGridForm(Me) With { .GridShowToolbar = False, .InitialOkValue = True, .ShowIcon = True, .Icon = My.Resources.SiteYouTube.YouTubeIcon_32, .Text = "YouTube Settings", .DesignXML = DesignXml, .DesignXMLNodeName = "YouTubeSettingsForm" } f.GridBrowsableAttributes = New AttributeCollection(New BrowsableAttribute(True), New GridVisibleAttribute(Not AppMode)) f.ShowDialog() End Using End Sub #End Region #Region "Close" Friend Sub Close() DesignXml.Dispose() XML.Dispose() Cookies.Dispose() End Sub #End Region #Region "Grid Support" Private Class ValueCollectionConverter : 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 TypeOf Value Is IEnumerable Then Return DirectCast(Value, IEnumerable).ToObjectsList(Of String).ListToString Else Return String.Empty End If End Function End Class Private Class ValueCollectionEditor : Inherits GridStructureCollectionEditor Public Overrides Function EditValue(ByVal Context As ITypeDescriptorContext, ByVal Provider As IServiceProvider, ByVal Value As Object) As Object Dim eObj As IEnumerable(Of String) = Nothing Select Case Context.PropertyDescriptor.Name Case NameOf(DefaultSubtitlesFormatAddit) : eObj = AvailableSubtitlesFormats Case NameOf(DefaultAudioCodecAddit) : eObj = AvailableAudioFormats End Select Using f As New SimpleListForm(Of String)(eObj) With { .Mode = SimpleListFormModes.CheckedItems, .DesignXML = MyYouTubeSettings.DesignXml, .DesignXMLNodeName = "YouTubeSettingsFormList", .FormText = DirectCast(Context.PropertyDescriptor.Attributes.Cast(Of Attribute).First(Function(a) a.GetType Is GetType(DisplayNameAttribute)), DisplayNameAttribute).DisplayName, .Icon = My.Resources.SiteYouTube.YouTubeIcon_32 } f.DataSelected.ListAddList(Value) If f.ShowDialog() = DialogResult.OK Then eObj = f.DataResult.ToList With DirectCast(Value, List(Of String)) : .Clear() : .ListAddList(eObj) : End With End If End Using Return Value End Function End Class #End Region End Class End Namespace