From 3f38803643956592c4696067d980bdd8039f10ce Mon Sep 17 00:00:00 2001 From: Andy <88590076+AAndyProgram@users.noreply.github.com> Date: Mon, 4 Mar 2024 21:09:38 +0300 Subject: [PATCH] 2024.3.4.0 YT Add the ability to add downloaded item(s) to a playlist Add the ability to create a playlist from downloaded music SCrawler Fix resetting of 'Available' indexes when the exiting a job --- SCrawler.YouTube/Base/YouTubeSettings.vb | 21 ++ .../Controls/MusicPlaylistsForm.Designer.vb | 65 +++++- .../Controls/MusicPlaylistsForm.resx | 131 ++++++++++++ .../Controls/MusicPlaylistsForm.vb | 27 +++ .../Controls/VideoOptionsForm.Designer.vb | 200 ++++++++++++------ .../Controls/VideoOptionsForm.resx | 185 ++++++++++++---- SCrawler.YouTube/Controls/VideoOptionsForm.vb | 26 +++ .../Downloader/DownloadLocationsCollection.vb | 16 +- .../Objects/YouTubeMediaContainerBase.vb | 81 ++++++- SCrawler/Download/TDownloader.vb | 1 + .../Hosts/SettingsHostCollection.vb | 3 + 11 files changed, 629 insertions(+), 127 deletions(-) diff --git a/SCrawler.YouTube/Base/YouTubeSettings.vb b/SCrawler.YouTube/Base/YouTubeSettings.vb index 608b701..4c55c54 100644 --- a/SCrawler.YouTube/Base/YouTubeSettings.vb +++ b/SCrawler.YouTube/Base/YouTubeSettings.vb @@ -36,6 +36,7 @@ Namespace API.YouTube.Base 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 #Region "Environment" #Region "Programs" @@ -229,6 +230,7 @@ Namespace API.YouTube.Base Friend ReadOnly Property ProgramDescription As XMLValue(Of String) + Friend ReadOnly Property LatestPlaylistFile As XMLValue(Of String) #End Region #Region "Defaults ChannelsDownload" Public ReadOnly Property DefaultAudioEmbedThumbnail As XMLValue(Of Boolean) +#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) +#End Region #End Region #Region "Defaults Subtitles" @@ -418,7 +437,9 @@ Namespace API.YouTube.Base 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 diff --git a/SCrawler.YouTube/Controls/MusicPlaylistsForm.Designer.vb b/SCrawler.YouTube/Controls/MusicPlaylistsForm.Designer.vb index 58e40dd..b8965df 100644 --- a/SCrawler.YouTube/Controls/MusicPlaylistsForm.Designer.vb +++ b/SCrawler.YouTube/Controls/MusicPlaylistsForm.Designer.vb @@ -45,6 +45,10 @@ Namespace API.YouTube.Controls Dim ActionButton10 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Dim ListColumn1 As PersonalUtilities.Forms.Controls.Base.ListColumn = New PersonalUtilities.Forms.Controls.Base.ListColumn() Dim ListColumn2 As PersonalUtilities.Forms.Controls.Base.ListColumn = New PersonalUtilities.Forms.Controls.Base.ListColumn() + Dim ActionButton11 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() + Dim ActionButton12 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() + Dim ActionButton13 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() + Dim ActionButton14 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Dim TT_MAIN As System.Windows.Forms.ToolTip Me.BTT_DOWN = New System.Windows.Forms.Button() Me.BTT_CANCEL = New System.Windows.Forms.Button() @@ -58,6 +62,7 @@ Namespace API.YouTube.Controls Me.TXT_SUBS = New PersonalUtilities.Forms.Controls.TextBoxExtended() Me.CH_DOWN_LYRICS = New System.Windows.Forms.CheckBox() Me.TXT_OUTPUT_PATH = New PersonalUtilities.Forms.Controls.ComboBoxExtended() + Me.CMB_PLS = New PersonalUtilities.Forms.Controls.ComboBoxExtended() TP_MAIN = New System.Windows.Forms.TableLayoutPanel() TP_BUTTONS = New System.Windows.Forms.TableLayoutPanel() TP_PLS = New System.Windows.Forms.TableLayoutPanel() @@ -83,6 +88,7 @@ Namespace API.YouTube.Controls TP_LYRICS.SuspendLayout() CType(Me.TXT_SUBS, System.ComponentModel.ISupportInitialize).BeginInit() CType(Me.TXT_OUTPUT_PATH, System.ComponentModel.ISupportInitialize).BeginInit() + CType(Me.CMB_PLS, System.ComponentModel.ISupportInitialize).BeginInit() Me.SuspendLayout() ' 'TP_MAIN @@ -97,10 +103,10 @@ Namespace API.YouTube.Controls TP_MAIN.Margin = New System.Windows.Forms.Padding(0) TP_MAIN.Name = "TP_MAIN" TP_MAIN.RowCount = 3 - TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 84.0!)) + TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 112.0!)) TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) - TP_MAIN.Size = New System.Drawing.Size(434, 261) + TP_MAIN.Size = New System.Drawing.Size(434, 289) TP_MAIN.TabIndex = 0 ' 'TP_BUTTONS @@ -112,7 +118,7 @@ Namespace API.YouTube.Controls TP_BUTTONS.Controls.Add(Me.BTT_DOWN, 1, 0) TP_BUTTONS.Controls.Add(Me.BTT_CANCEL, 2, 0) TP_BUTTONS.Dock = System.Windows.Forms.DockStyle.Fill - TP_BUTTONS.Location = New System.Drawing.Point(0, 236) + TP_BUTTONS.Location = New System.Drawing.Point(0, 264) TP_BUTTONS.Margin = New System.Windows.Forms.Padding(0) TP_BUTTONS.Name = "TP_BUTTONS" TP_BUTTONS.RowCount = 1 @@ -147,7 +153,7 @@ Namespace API.YouTube.Controls 'SPLITTER_MAIN ' Me.SPLITTER_MAIN.Dock = System.Windows.Forms.DockStyle.Fill - Me.SPLITTER_MAIN.Location = New System.Drawing.Point(3, 87) + Me.SPLITTER_MAIN.Location = New System.Drawing.Point(3, 115) Me.SPLITTER_MAIN.Name = "SPLITTER_MAIN" ' 'SPLITTER_MAIN.Panel1 @@ -264,15 +270,17 @@ Namespace API.YouTube.Controls TP_SETTINGS.Controls.Add(TP_FORMATS, 0, 1) TP_SETTINGS.Controls.Add(TP_LYRICS, 0, 0) TP_SETTINGS.Controls.Add(Me.TXT_OUTPUT_PATH, 0, 2) + TP_SETTINGS.Controls.Add(Me.CMB_PLS, 0, 3) TP_SETTINGS.Dock = System.Windows.Forms.DockStyle.Fill TP_SETTINGS.Location = New System.Drawing.Point(0, 0) TP_SETTINGS.Margin = New System.Windows.Forms.Padding(0) TP_SETTINGS.Name = "TP_SETTINGS" - TP_SETTINGS.RowCount = 3 - TP_SETTINGS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333!)) - TP_SETTINGS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333!)) - TP_SETTINGS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333!)) - TP_SETTINGS.Size = New System.Drawing.Size(434, 84) + TP_SETTINGS.RowCount = 4 + TP_SETTINGS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25.0!)) + TP_SETTINGS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25.0!)) + TP_SETTINGS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25.0!)) + TP_SETTINGS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25.0!)) + TP_SETTINGS.Size = New System.Drawing.Size(434, 112) TP_SETTINGS.TabIndex = 1 ' 'TP_FORMATS @@ -452,17 +460,50 @@ Namespace API.YouTube.Controls Me.TXT_OUTPUT_PATH.TabIndex = 2 Me.TXT_OUTPUT_PATH.TextBoxBorderStyle = System.Windows.Forms.BorderStyle.FixedSingle ' + 'CMB_PLS + ' + ActionButton11.BackgroundImage = CType(resources.GetObject("ActionButton11.BackgroundImage"), System.Drawing.Image) + ActionButton11.Name = "Open" + ActionButton11.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Open + ActionButton11.ToolTipText = "Choose an output file" + ActionButton12.BackgroundImage = CType(resources.GetObject("ActionButton12.BackgroundImage"), System.Drawing.Image) + ActionButton12.Name = "Add" + ActionButton12.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Add + ActionButton12.ToolTipText = "Choose an output file (add a new location to the list)" + ActionButton13.BackgroundImage = CType(resources.GetObject("ActionButton13.BackgroundImage"), System.Drawing.Image) + ActionButton13.Name = "Clear" + ActionButton13.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear + ActionButton14.BackgroundImage = CType(resources.GetObject("ActionButton14.BackgroundImage"), System.Drawing.Image) + ActionButton14.Name = "ArrowDown" + ActionButton14.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.ArrowDown + Me.CMB_PLS.Buttons.Add(ActionButton11) + Me.CMB_PLS.Buttons.Add(ActionButton12) + Me.CMB_PLS.Buttons.Add(ActionButton13) + Me.CMB_PLS.Buttons.Add(ActionButton14) + Me.CMB_PLS.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.Label + Me.CMB_PLS.CaptionText = "Playlist" + Me.CMB_PLS.CaptionToolTipEnabled = True + Me.CMB_PLS.CaptionToolTipText = "Add downloaded item(s) to playlist" + Me.CMB_PLS.CaptionVisible = True + Me.CMB_PLS.CaptionWidth = 50.0R + Me.CMB_PLS.Dock = System.Windows.Forms.DockStyle.Fill + Me.CMB_PLS.Location = New System.Drawing.Point(3, 87) + Me.CMB_PLS.Name = "CMB_PLS" + Me.CMB_PLS.Size = New System.Drawing.Size(428, 22) + Me.CMB_PLS.TabIndex = 3 + Me.CMB_PLS.TextBoxBorderStyle = System.Windows.Forms.BorderStyle.FixedSingle + ' 'MusicPlaylistsForm ' Me.AcceptButton = Me.BTT_DOWN Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!) Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font Me.CancelButton = Me.BTT_CANCEL - Me.ClientSize = New System.Drawing.Size(434, 261) + Me.ClientSize = New System.Drawing.Size(434, 289) Me.Controls.Add(TP_MAIN) Me.Icon = Global.SCrawler.My.Resources.SiteYouTube.YouTubeMusicIcon_32 Me.KeyPreview = True - Me.MinimumSize = New System.Drawing.Size(450, 300) + Me.MinimumSize = New System.Drawing.Size(450, 328) Me.Name = "MusicPlaylistsForm" Me.Text = "Albums" TP_MAIN.ResumeLayout(False) @@ -481,6 +522,7 @@ Namespace API.YouTube.Controls TP_LYRICS.PerformLayout() CType(Me.TXT_SUBS, System.ComponentModel.ISupportInitialize).EndInit() CType(Me.TXT_OUTPUT_PATH, System.ComponentModel.ISupportInitialize).EndInit() + CType(Me.CMB_PLS, System.ComponentModel.ISupportInitialize).EndInit() Me.ResumeLayout(False) End Sub @@ -496,5 +538,6 @@ Namespace API.YouTube.Controls Private WithEvents SPLITTER_MAIN As SplitContainer Private WithEvents CH_DOWN_LYRICS As CheckBox Private WithEvents TXT_OUTPUT_PATH As PersonalUtilities.Forms.Controls.ComboBoxExtended + Private WithEvents CMB_PLS As PersonalUtilities.Forms.Controls.ComboBoxExtended End Class End Namespace \ No newline at end of file diff --git a/SCrawler.YouTube/Controls/MusicPlaylistsForm.resx b/SCrawler.YouTube/Controls/MusicPlaylistsForm.resx index cd7aef0..8bf8028 100644 --- a/SCrawler.YouTube/Controls/MusicPlaylistsForm.resx +++ b/SCrawler.YouTube/Controls/MusicPlaylistsForm.resx @@ -350,6 +350,137 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6LEtW/4flgYiLD1qeX0A AAAASUVORK5CYII= + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + wwAADsMBx2+oZAAAAR5JREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbGujg3ZATZPKYdC6FQhPwlAMkg3dP + WQwhyWIyJIUW5NqyPb7oCVtIlhVTwYf8nv7/t2zJagel9KmqKsIACYL9RjI8UHz5zshougZr/AEvbxEP + aZCDBY3VslixaJvX3wzkkDiOwbZtDRGA5vdNAg+TL27qgmt5XkBG/gTdAG7Gt+3PP9oOaEGFCVEC6rp+ + 5g9MfM/c5e4OsEZMZkQEtGL5H2DdZ5JRArDwPA+iKII0TfkC9vroC9j5vq8JTWw3WzWgLMtZGIaa0MR8 + vlAD8PYlSaIJTTiOowY0p0Bc19XEJo6HE59FAPuMzyAINKGJ1XLFZxHALtMrnkBXOIQIIIQ8YvF/KrgB + cMaRN0UdBBkAAAAASUVORK5CYII= + + + + + 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 + AAAASUVORK5CYII= \ No newline at end of file diff --git a/SCrawler.YouTube/Controls/MusicPlaylistsForm.vb b/SCrawler.YouTube/Controls/MusicPlaylistsForm.vb index ce8e38a..58a02d2 100644 --- a/SCrawler.YouTube/Controls/MusicPlaylistsForm.vb +++ b/SCrawler.YouTube/Controls/MusicPlaylistsForm.vb @@ -52,6 +52,8 @@ Namespace API.YouTube.Controls End If MyYouTubeSettings.DownloadLocations.PopulateComboBox(TXT_OUTPUT_PATH) + MyYouTubeSettings.PlaylistsLocations.PopulateComboBox(CMB_PLS,, True) + CMB_PLS.Text = MyYouTubeSettings.LatestPlaylistFile.Value CMB_FORMATS.Items.AddRange(AvailableAudioFormats) If MyYouTubeSettings.PlaylistFormSplitterDistance > 0 Then SPLITTER_MAIN.SplitterDistancePercentageSet(MyYouTubeSettings.PlaylistFormSplitterDistance) @@ -184,6 +186,28 @@ Namespace API.YouTube.Controls If Sender.DefaultButton = ADB.Open Or Sender.DefaultButton = ADB.Add Then _ MyYouTubeSettings.DownloadLocations.ChooseNewLocation(TXT_OUTPUT_PATH, Sender.DefaultButton = ADB.Add, MyDownloaderSettings.OutputPathAskForName) End Sub + Private Sub CMB_PLS_ActionOnButtonClick(ByVal Sender As ActionButton, ByVal e As ActionButtonEventArgs) Handles CMB_PLS.ActionOnButtonClick + Try + If Sender.DefaultButton = ADB.Add Or Sender.DefaultButton = ADB.Open Then + Dim f As SFile = Nothing + If Not CMB_PLS.Text.IsEmptyString Then + f = CMB_PLS.Text + ElseIf Not TXT_OUTPUT_PATH.Text.IsEmptyString Then + f = TXT_OUTPUT_PATH.Text + End If + f = SFile.SelectFiles(f, False, "Select a playlist...", "Playlists|*.m3u;*.m3u8|All files|*.*", EDP.ReturnValue).FirstOrDefault + If Not f.IsEmptyString Then + If Sender.DefaultButton = ADB.Add Then + MyYouTubeSettings.PlaylistsLocations.Add(f.ToString, True, True) + MyYouTubeSettings.PlaylistsLocations.PopulateComboBox(CMB_PLS, f, True) + End If + CMB_PLS.Text = f + End If + End If + Catch ex As Exception + ErrorsDescriber.Execute(EDP.SendToLog, ex, "[API.YouTube.Controls.MusicPlaylistsForm.SelectPlaylist]") + End Try + End Sub #End Region #Region "Lists' handlers" Private _LatestSelected As Integer = -1 @@ -276,8 +300,11 @@ Namespace API.YouTube.Controls If Not TXT_FORMATS_ADDIT.Checked Then .PostProcessing_OutputAudioFormats.Clear() .AbsolutePath = TXT_OUTPUT_PATH.Checked .File = TXT_OUTPUT_PATH.Text.CSFileP + .M3U8_PlaylistFile = CMB_PLS.Text If MyYouTubeSettings.OutputPathAutoChange Then MyYouTubeSettings.OutputPath.Value = .File If MyDownloaderSettings.OutputPathAutoAddPaths Then MyYouTubeSettings.DownloadLocations.Add(.File, False) + If Not CMB_PLS.Text.IsEmptyString Then MyYouTubeSettings.PlaylistsLocations.Add(CMB_PLS.Text, False, True) + MyYouTubeSettings.LatestPlaylistFile.Value = CMB_PLS.Text End With DialogResult = DialogResult.OK Close() diff --git a/SCrawler.YouTube/Controls/VideoOptionsForm.Designer.vb b/SCrawler.YouTube/Controls/VideoOptionsForm.Designer.vb index e3da4b4..9e8c4eb 100644 --- a/SCrawler.YouTube/Controls/VideoOptionsForm.Designer.vb +++ b/SCrawler.YouTube/Controls/VideoOptionsForm.Designer.vb @@ -34,6 +34,9 @@ Namespace API.YouTube.Controls Dim ListColumn1 As PersonalUtilities.Forms.Controls.Base.ListColumn = New PersonalUtilities.Forms.Controls.Base.ListColumn() Dim ListColumn2 As PersonalUtilities.Forms.Controls.Base.ListColumn = New PersonalUtilities.Forms.Controls.Base.ListColumn() Dim TP_OK_CANCEL As System.Windows.Forms.TableLayoutPanel + Dim TP_PLS As System.Windows.Forms.TableLayoutPanel + Dim ActionButton2 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() + Dim ActionButton3 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Dim LB_SEP_1 As System.Windows.Forms.Label Dim LB_SEP_2 As System.Windows.Forms.Label Dim TP_WHAT As System.Windows.Forms.TableLayoutPanel @@ -41,8 +44,6 @@ Namespace API.YouTube.Controls Dim LBL_FORMAT As System.Windows.Forms.Label Dim LBL_SUBS_FORMAT As System.Windows.Forms.Label Dim TT_MAIN As System.Windows.Forms.ToolTip - Dim ActionButton2 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() - Dim ActionButton3 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Dim ActionButton4 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Dim ActionButton5 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Dim ActionButton6 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() @@ -51,6 +52,8 @@ Namespace API.YouTube.Controls Dim ActionButton9 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Dim ActionButton10 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Dim ActionButton11 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() + Dim ActionButton12 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() + Dim ActionButton13 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() Me.ICON_VIDEO = New System.Windows.Forms.PictureBox() Me.LBL_TITLE = New System.Windows.Forms.Label() Me.TP_HEADER_INFO_2 = New System.Windows.Forms.TableLayoutPanel() @@ -60,6 +63,8 @@ Namespace API.YouTube.Controls Me.BTT_BROWSE = New System.Windows.Forms.Button() Me.BTT_DOWN = New System.Windows.Forms.Button() Me.BTT_CANCEL = New System.Windows.Forms.Button() + Me.CMB_PLS = New PersonalUtilities.Forms.Controls.ComboBoxExtended() + Me.BTT_PLS_BROWSE = New System.Windows.Forms.Button() Me.OPT_VIDEO = New System.Windows.Forms.RadioButton() Me.OPT_AUDIO = New System.Windows.Forms.RadioButton() Me.LBL_AUDIO_CODEC = New System.Windows.Forms.Label() @@ -83,6 +88,7 @@ Namespace API.YouTube.Controls TP_FOOTER = New System.Windows.Forms.TableLayoutPanel() TP_DESTINATION = New System.Windows.Forms.TableLayoutPanel() TP_OK_CANCEL = New System.Windows.Forms.TableLayoutPanel() + TP_PLS = New System.Windows.Forms.TableLayoutPanel() LB_SEP_1 = New System.Windows.Forms.Label() LB_SEP_2 = New System.Windows.Forms.Label() TP_WHAT = New System.Windows.Forms.TableLayoutPanel() @@ -100,6 +106,8 @@ Namespace API.YouTube.Controls TP_DESTINATION.SuspendLayout() CType(Me.TXT_FILE, System.ComponentModel.ISupportInitialize).BeginInit() TP_OK_CANCEL.SuspendLayout() + TP_PLS.SuspendLayout() + CType(Me.CMB_PLS, System.ComponentModel.ISupportInitialize).BeginInit() TP_WHAT.SuspendLayout() Me.TP_HEADER_BASE.SuspendLayout() Me.TP_SUBS.SuspendLayout() @@ -243,17 +251,18 @@ Namespace API.YouTube.Controls ' TP_FOOTER.ColumnCount = 1 TP_FOOTER.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) - TP_FOOTER.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20.0!)) - TP_FOOTER.Controls.Add(TP_DESTINATION, 0, 0) - TP_FOOTER.Controls.Add(TP_OK_CANCEL, 0, 1) + TP_FOOTER.Controls.Add(TP_DESTINATION, 0, 1) + TP_FOOTER.Controls.Add(TP_OK_CANCEL, 0, 2) + TP_FOOTER.Controls.Add(TP_PLS, 0, 0) TP_FOOTER.Dock = System.Windows.Forms.DockStyle.Fill TP_FOOTER.Location = New System.Drawing.Point(6, 215) TP_FOOTER.Margin = New System.Windows.Forms.Padding(6, 3, 6, 3) TP_FOOTER.Name = "TP_FOOTER" - TP_FOOTER.RowCount = 2 - TP_FOOTER.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50.0!)) - TP_FOOTER.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50.0!)) - TP_FOOTER.Size = New System.Drawing.Size(709, 52) + TP_FOOTER.RowCount = 3 + TP_FOOTER.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333!)) + TP_FOOTER.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333!)) + TP_FOOTER.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333!)) + TP_FOOTER.Size = New System.Drawing.Size(709, 81) TP_FOOTER.TabIndex = 5 ' 'TP_DESTINATION @@ -264,12 +273,12 @@ Namespace API.YouTube.Controls TP_DESTINATION.Controls.Add(Me.TXT_FILE, 0, 0) TP_DESTINATION.Controls.Add(Me.BTT_BROWSE, 1, 0) TP_DESTINATION.Dock = System.Windows.Forms.DockStyle.Fill - TP_DESTINATION.Location = New System.Drawing.Point(0, 0) + TP_DESTINATION.Location = New System.Drawing.Point(0, 27) TP_DESTINATION.Margin = New System.Windows.Forms.Padding(0) TP_DESTINATION.Name = "TP_DESTINATION" TP_DESTINATION.RowCount = 1 TP_DESTINATION.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) - TP_DESTINATION.Size = New System.Drawing.Size(709, 26) + TP_DESTINATION.Size = New System.Drawing.Size(709, 27) TP_DESTINATION.TabIndex = 0 ' 'TXT_FILE @@ -303,7 +312,7 @@ Namespace API.YouTube.Controls Me.BTT_BROWSE.Location = New System.Drawing.Point(632, 2) Me.BTT_BROWSE.Margin = New System.Windows.Forms.Padding(3, 2, 3, 2) Me.BTT_BROWSE.Name = "BTT_BROWSE" - Me.BTT_BROWSE.Size = New System.Drawing.Size(74, 22) + Me.BTT_BROWSE.Size = New System.Drawing.Size(74, 23) Me.BTT_BROWSE.TabIndex = 1 Me.BTT_BROWSE.Text = "Browse" TT_MAIN.SetToolTip(Me.BTT_BROWSE, "Choose an output file (Right click for add a new location to the list)") @@ -318,13 +327,13 @@ Namespace API.YouTube.Controls TP_OK_CANCEL.Controls.Add(Me.BTT_DOWN, 1, 0) TP_OK_CANCEL.Controls.Add(Me.BTT_CANCEL, 2, 0) TP_OK_CANCEL.Dock = System.Windows.Forms.DockStyle.Fill - TP_OK_CANCEL.Location = New System.Drawing.Point(0, 26) + TP_OK_CANCEL.Location = New System.Drawing.Point(0, 54) TP_OK_CANCEL.Margin = New System.Windows.Forms.Padding(0) TP_OK_CANCEL.Name = "TP_OK_CANCEL" TP_OK_CANCEL.RowCount = 1 TP_OK_CANCEL.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) - TP_OK_CANCEL.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 26.0!)) - TP_OK_CANCEL.Size = New System.Drawing.Size(709, 26) + TP_OK_CANCEL.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 27.0!)) + TP_OK_CANCEL.Size = New System.Drawing.Size(709, 27) TP_OK_CANCEL.TabIndex = 1 ' 'BTT_DOWN @@ -333,7 +342,7 @@ Namespace API.YouTube.Controls Me.BTT_DOWN.Location = New System.Drawing.Point(552, 2) Me.BTT_DOWN.Margin = New System.Windows.Forms.Padding(3, 2, 3, 2) Me.BTT_DOWN.Name = "BTT_DOWN" - Me.BTT_DOWN.Size = New System.Drawing.Size(74, 22) + Me.BTT_DOWN.Size = New System.Drawing.Size(74, 23) Me.BTT_DOWN.TabIndex = 0 Me.BTT_DOWN.Text = "Download" Me.BTT_DOWN.UseVisualStyleBackColor = True @@ -345,11 +354,64 @@ Namespace API.YouTube.Controls Me.BTT_CANCEL.Location = New System.Drawing.Point(632, 2) Me.BTT_CANCEL.Margin = New System.Windows.Forms.Padding(3, 2, 3, 2) Me.BTT_CANCEL.Name = "BTT_CANCEL" - Me.BTT_CANCEL.Size = New System.Drawing.Size(74, 22) + Me.BTT_CANCEL.Size = New System.Drawing.Size(74, 23) Me.BTT_CANCEL.TabIndex = 1 Me.BTT_CANCEL.Text = "Cancel" Me.BTT_CANCEL.UseVisualStyleBackColor = True ' + 'TP_PLS + ' + TP_PLS.ColumnCount = 2 + TP_PLS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + TP_PLS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 80.0!)) + TP_PLS.Controls.Add(Me.CMB_PLS, 0, 0) + TP_PLS.Controls.Add(Me.BTT_PLS_BROWSE, 1, 0) + TP_PLS.Dock = System.Windows.Forms.DockStyle.Fill + TP_PLS.Location = New System.Drawing.Point(0, 0) + TP_PLS.Margin = New System.Windows.Forms.Padding(0) + TP_PLS.Name = "TP_PLS" + TP_PLS.RowCount = 1 + TP_PLS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + TP_PLS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 27.0!)) + TP_PLS.Size = New System.Drawing.Size(709, 27) + TP_PLS.TabIndex = 2 + ' + 'CMB_PLS + ' + ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image) + ActionButton2.Name = "Clear" + ActionButton2.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear + ActionButton3.BackgroundImage = CType(resources.GetObject("ActionButton3.BackgroundImage"), System.Drawing.Image) + ActionButton3.Name = "ArrowDown" + ActionButton3.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.ArrowDown + Me.CMB_PLS.Buttons.Add(ActionButton2) + Me.CMB_PLS.Buttons.Add(ActionButton3) + Me.CMB_PLS.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.Label + Me.CMB_PLS.CaptionText = "Playlist" + Me.CMB_PLS.CaptionToolTipEnabled = True + Me.CMB_PLS.CaptionToolTipText = "Add downloaded item(s) to playlist" + Me.CMB_PLS.CaptionVisible = True + Me.CMB_PLS.CaptionWidth = 50.0R + Me.CMB_PLS.Dock = System.Windows.Forms.DockStyle.Fill + Me.CMB_PLS.Location = New System.Drawing.Point(1, 1) + Me.CMB_PLS.Margin = New System.Windows.Forms.Padding(1) + Me.CMB_PLS.Name = "CMB_PLS" + Me.CMB_PLS.Size = New System.Drawing.Size(627, 22) + Me.CMB_PLS.TabIndex = 0 + Me.CMB_PLS.TextBoxBorderStyle = System.Windows.Forms.BorderStyle.FixedSingle + ' + 'BTT_PLS_BROWSE + ' + Me.BTT_PLS_BROWSE.Dock = System.Windows.Forms.DockStyle.Fill + Me.BTT_PLS_BROWSE.Location = New System.Drawing.Point(632, 2) + Me.BTT_PLS_BROWSE.Margin = New System.Windows.Forms.Padding(3, 2, 3, 2) + Me.BTT_PLS_BROWSE.Name = "BTT_PLS_BROWSE" + Me.BTT_PLS_BROWSE.Size = New System.Drawing.Size(74, 23) + Me.BTT_PLS_BROWSE.TabIndex = 1 + Me.BTT_PLS_BROWSE.Text = "Browse" + TT_MAIN.SetToolTip(Me.BTT_PLS_BROWSE, "Choose an output file (Right click for add a new location to the list)") + Me.BTT_PLS_BROWSE.UseVisualStyleBackColor = True + ' 'LB_SEP_1 ' LB_SEP_1.Anchor = CType((System.Windows.Forms.AnchorStyles.Left Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles) @@ -496,21 +558,21 @@ Namespace API.YouTube.Controls ' 'TXT_SUBS ' - ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image) - ActionButton2.Name = "Open" - ActionButton2.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Open - ActionButton2.ToolTipText = "Choose subtitles" - ActionButton3.BackgroundImage = CType(resources.GetObject("ActionButton3.BackgroundImage"), System.Drawing.Image) - ActionButton3.Name = "Refresh" - ActionButton3.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Refresh - ActionButton3.ToolTipText = "Reset subtitles to initial selected" ActionButton4.BackgroundImage = CType(resources.GetObject("ActionButton4.BackgroundImage"), System.Drawing.Image) - ActionButton4.Name = "Clear" - ActionButton4.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear - ActionButton4.ToolTipText = "Clear subtitles selection (don't download subtitles)" - Me.TXT_SUBS.Buttons.Add(ActionButton2) - Me.TXT_SUBS.Buttons.Add(ActionButton3) + ActionButton4.Name = "Open" + ActionButton4.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Open + ActionButton4.ToolTipText = "Choose subtitles" + ActionButton5.BackgroundImage = CType(resources.GetObject("ActionButton5.BackgroundImage"), System.Drawing.Image) + ActionButton5.Name = "Refresh" + ActionButton5.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Refresh + ActionButton5.ToolTipText = "Reset subtitles to initial selected" + ActionButton6.BackgroundImage = CType(resources.GetObject("ActionButton6.BackgroundImage"), System.Drawing.Image) + ActionButton6.Name = "Clear" + ActionButton6.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear + ActionButton6.ToolTipText = "Clear subtitles selection (don't download subtitles)" Me.TXT_SUBS.Buttons.Add(ActionButton4) + Me.TXT_SUBS.Buttons.Add(ActionButton5) + Me.TXT_SUBS.Buttons.Add(ActionButton6) Me.TXT_SUBS.CaptionText = "Subtitles" Me.TXT_SUBS.CaptionToolTipEnabled = True Me.TXT_SUBS.CaptionToolTipText = "The selected subtitles will also be downloaded" @@ -558,9 +620,9 @@ Namespace API.YouTube.Controls Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 5.0!)) Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 5.0!)) - Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 58.0!)) + Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 87.0!)) Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle()) - Me.TP_MAIN.Size = New System.Drawing.Size(721, 271) + Me.TP_MAIN.Size = New System.Drawing.Size(721, 300) Me.TP_MAIN.TabIndex = 0 ' 'TP_OPTIONS @@ -623,10 +685,10 @@ Namespace API.YouTube.Controls ' 'TXT_FPS ' - ActionButton5.BackgroundImage = CType(resources.GetObject("ActionButton5.BackgroundImage"), System.Drawing.Image) - ActionButton5.Name = "Clear" - ActionButton5.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear - Me.TXT_FPS.Buttons.Add(ActionButton5) + ActionButton7.BackgroundImage = CType(resources.GetObject("ActionButton7.BackgroundImage"), System.Drawing.Image) + ActionButton7.Name = "Clear" + ActionButton7.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear + Me.TXT_FPS.Buttons.Add(ActionButton7) Me.TXT_FPS.CaptionText = "FPS" Me.TXT_FPS.CaptionToolTipEnabled = True Me.TXT_FPS.CaptionToolTipText = "You can reduce the video FPS by setting the FPS value in this field." @@ -654,24 +716,24 @@ Namespace API.YouTube.Controls ' 'TXT_SUBS_ADDIT ' - ActionButton6.BackgroundImage = CType(resources.GetObject("ActionButton6.BackgroundImage"), System.Drawing.Image) - ActionButton6.Enabled = False - ActionButton6.Name = "Open" - ActionButton6.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Open - ActionButton6.ToolTipText = "Choose additional formats" - ActionButton7.BackgroundImage = CType(resources.GetObject("ActionButton7.BackgroundImage"), System.Drawing.Image) - ActionButton7.Enabled = False - ActionButton7.Name = "Refresh" - ActionButton7.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Refresh - ActionButton7.ToolTipText = "Fill in additional formats from the defaults" ActionButton8.BackgroundImage = CType(resources.GetObject("ActionButton8.BackgroundImage"), System.Drawing.Image) ActionButton8.Enabled = False - ActionButton8.Name = "Clear" - ActionButton8.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear - ActionButton8.ToolTipText = "Remove all additional formats" - Me.TXT_SUBS_ADDIT.Buttons.Add(ActionButton6) - Me.TXT_SUBS_ADDIT.Buttons.Add(ActionButton7) + ActionButton8.Name = "Open" + ActionButton8.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Open + ActionButton8.ToolTipText = "Choose additional formats" + ActionButton9.BackgroundImage = CType(resources.GetObject("ActionButton9.BackgroundImage"), System.Drawing.Image) + ActionButton9.Enabled = False + ActionButton9.Name = "Refresh" + ActionButton9.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Refresh + ActionButton9.ToolTipText = "Fill in additional formats from the defaults" + ActionButton10.BackgroundImage = CType(resources.GetObject("ActionButton10.BackgroundImage"), System.Drawing.Image) + ActionButton10.Enabled = False + ActionButton10.Name = "Clear" + ActionButton10.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear + ActionButton10.ToolTipText = "Remove all additional formats" Me.TXT_SUBS_ADDIT.Buttons.Add(ActionButton8) + Me.TXT_SUBS_ADDIT.Buttons.Add(ActionButton9) + Me.TXT_SUBS_ADDIT.Buttons.Add(ActionButton10) Me.TXT_SUBS_ADDIT.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.CheckBox Me.TXT_SUBS_ADDIT.CaptionText = "Additional subtitle formats" Me.TXT_SUBS_ADDIT.CaptionToolTipEnabled = True @@ -689,24 +751,24 @@ Namespace API.YouTube.Controls ' 'TXT_EXTRA_AUDIO_FORMATS ' - ActionButton9.BackgroundImage = CType(resources.GetObject("ActionButton9.BackgroundImage"), System.Drawing.Image) - ActionButton9.Enabled = False - ActionButton9.Name = "Open" - ActionButton9.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Open - ActionButton9.ToolTipText = "Choose additional formats" - ActionButton10.BackgroundImage = CType(resources.GetObject("ActionButton10.BackgroundImage"), System.Drawing.Image) - ActionButton10.Enabled = False - ActionButton10.Name = "Refresh" - ActionButton10.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Refresh - ActionButton10.ToolTipText = "Fill in additional formats from the defaults" ActionButton11.BackgroundImage = CType(resources.GetObject("ActionButton11.BackgroundImage"), System.Drawing.Image) ActionButton11.Enabled = False - ActionButton11.Name = "Clear" - ActionButton11.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear + ActionButton11.Name = "Open" + ActionButton11.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Open ActionButton11.ToolTipText = "Choose additional formats" - Me.TXT_EXTRA_AUDIO_FORMATS.Buttons.Add(ActionButton9) - Me.TXT_EXTRA_AUDIO_FORMATS.Buttons.Add(ActionButton10) + ActionButton12.BackgroundImage = CType(resources.GetObject("ActionButton12.BackgroundImage"), System.Drawing.Image) + ActionButton12.Enabled = False + ActionButton12.Name = "Refresh" + ActionButton12.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Refresh + ActionButton12.ToolTipText = "Fill in additional formats from the defaults" + ActionButton13.BackgroundImage = CType(resources.GetObject("ActionButton13.BackgroundImage"), System.Drawing.Image) + ActionButton13.Enabled = False + ActionButton13.Name = "Clear" + ActionButton13.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear + ActionButton13.ToolTipText = "Choose additional formats" Me.TXT_EXTRA_AUDIO_FORMATS.Buttons.Add(ActionButton11) + Me.TXT_EXTRA_AUDIO_FORMATS.Buttons.Add(ActionButton12) + Me.TXT_EXTRA_AUDIO_FORMATS.Buttons.Add(ActionButton13) Me.TXT_EXTRA_AUDIO_FORMATS.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.CheckBox Me.TXT_EXTRA_AUDIO_FORMATS.CaptionText = "Additional audio formats" Me.TXT_EXTRA_AUDIO_FORMATS.CaptionToolTipEnabled = True @@ -727,14 +789,14 @@ Namespace API.YouTube.Controls Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!) Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font Me.CancelButton = Me.BTT_CANCEL - Me.ClientSize = New System.Drawing.Size(721, 271) + Me.ClientSize = New System.Drawing.Size(721, 300) Me.Controls.Add(Me.TP_MAIN) Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle Me.Icon = Global.SCrawler.My.Resources.SiteYouTube.YouTubeIcon_32 Me.KeyPreview = True Me.MaximizeBox = False Me.MinimizeBox = False - Me.MinimumSize = New System.Drawing.Size(737, 310) + Me.MinimumSize = New System.Drawing.Size(737, 339) Me.Name = "VideoOptionsForm" Me.ShowInTaskbar = False Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide @@ -750,6 +812,8 @@ Namespace API.YouTube.Controls TP_DESTINATION.ResumeLayout(False) CType(Me.TXT_FILE, System.ComponentModel.ISupportInitialize).EndInit() TP_OK_CANCEL.ResumeLayout(False) + TP_PLS.ResumeLayout(False) + CType(Me.CMB_PLS, System.ComponentModel.ISupportInitialize).EndInit() TP_WHAT.ResumeLayout(False) TP_WHAT.PerformLayout() Me.TP_HEADER_BASE.ResumeLayout(False) @@ -791,5 +855,7 @@ Namespace API.YouTube.Controls Private WithEvents BTT_CANCEL As Button Private WithEvents TP_HEADER_INFO_2 As TableLayoutPanel Private WithEvents TXT_FPS As PersonalUtilities.Forms.Controls.TextBoxExtended + Private WithEvents CMB_PLS As PersonalUtilities.Forms.Controls.ComboBoxExtended + Private WithEvents BTT_PLS_BROWSE As Button End Class End Namespace \ No newline at end of file diff --git a/SCrawler.YouTube/Controls/VideoOptionsForm.resx b/SCrawler.YouTube/Controls/VideoOptionsForm.resx index b290494..e894896 100644 --- a/SCrawler.YouTube/Controls/VideoOptionsForm.resx +++ b/SCrawler.YouTube/Controls/VideoOptionsForm.resx @@ -235,6 +235,107 @@ False + + False + + + + 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 + AAAASUVORK5CYII= + + False @@ -253,7 +354,7 @@ False - + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO wwAADsMBx2+oZAAAAR5JREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbGujg3ZATZPKYdC6FQhPwlAMkg3dP @@ -264,7 +365,7 @@ cMaRN0UdBBkAAAAASUVORK5CYII= - + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6 JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsTAAALEwEAmpwYAAACOElE @@ -278,52 +379,17 @@ HhQDmFjYeHVKFp7WX/Xuv9Kq9/+Vd/z7r7rv/3+l7f//y676DEwDN/9L+BVvYkKLCTgDhNkkVUyVlr74 qbbz73/VOTc/qsy89kWx+9h7qbQpJwS1bbOAscGGrB6EUTggLOqf16C55ft/HlnNAFZOXgVWdi4FRgYG VnR1MIwhwMTCyqEQ37qEmZVDFF0OE/9nAACtFF4Ey6OP+wAAAABJRU5ErkJggg== - - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go - tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX - AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC - - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go - tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX - AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - wwAADsMBx2+oZAAAAR5JREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbGujg3ZATZPKYdC6FQhPwlAMkg3dP - WQwhyWIyJIUW5NqyPb7oCVtIlhVTwYf8nv7/t2zJagel9KmqKsIACYL9RjI8UHz5zshougZr/AEvbxEP - aZCDBY3VslixaJvX3wzkkDiOwbZtDRGA5vdNAg+TL27qgmt5XkBG/gTdAG7Gt+3PP9oOaEGFCVEC6rp+ - 5g9MfM/c5e4OsEZMZkQEtGL5H2DdZ5JRArDwPA+iKII0TfkC9vroC9j5vq8JTWw3WzWgLMtZGIaa0MR8 - vlAD8PYlSaIJTTiOowY0p0Bc19XEJo6HE59FAPuMzyAINKGJ1XLFZxHALtMrnkBXOIQIIIQ8YvF/KrgB - cMaRN0UdBBkAAAAASUVORK5CYII= + xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go + tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX + AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6 - JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsTAAALEwEAmpwYAAACOElE - QVQ4T2P4//8/QczOJyyqHpzfiE0OQwAZC8iqszAzs7CJ69o4BR768V/W2jcGXQ0KB4aFNS3dDQtnrbCb - ePCK48wTN1wXXXzge/jXf/clV55zC4hIIatF0cjIyMikElzc57z0wX+XHd/+2+//99/ywP//xlu//tdb - +eK/4Zp3/1WTOhYzARViNUAluKjTdf37/0ZTTn9TbdhwXblhwwW1/qOP1Ja9+K8w+95/6cm3/6v2Xvkv - qKjniGGAoIqRpW3/4e8S9uGdzFz82gwMDFxAzCxm4ZegtuLDf+VJ1/8rZM25IqLvnM/CximCYYCic1QN - v7x2JIwPwyrJ3XNUylddE9G2TWNmZOBDl4czmJiZMSRBmFdSyYyJgUEQmxwIYxWEYXZBCUls4sgYq6CA - prWNbtG8nXKeaVPR5XiVjSxEzf0yYXy4BBMLO6eQjoOXZvrkbbazrv53Xf/2v4CSbjBMXkhBl1/CMyNZ - qWnvGy5pNQ+YONwAfjXzAOupl/47LLr333L50/96q9/8l23YdES6cO5KuYqVW+R7Tj6SnfP0v4hryjyY - HhQDmFjYeHVKFp7WX/Xuv9Kq9/+Vd/z7r7rv/3+l7f//y676DEwDN/9L+BVvYkKLCTgDhNkkVUyVlr74 - qbbz73/VOTc/qsy89kWx+9h7qbQpJwS1bbOAscGGrB6EUTggLOqf16C55ft/HlnNAFZOXgVWdi4FRgYG - VnR1MIwhwMTCyqEQ37qEmZVDFF0OE/9nAACtFF4Ey6OP+wAAAABJRU5ErkJggg== - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go @@ -331,7 +397,7 @@ AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC - + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO wwAADsMBx2+oZAAAAR5JREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbGujg3ZATZPKYdC6FQhPwlAMkg3dP @@ -342,7 +408,7 @@ cMaRN0UdBBkAAAAASUVORK5CYII= - + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6 JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsTAAALEwEAmpwYAAACOElE @@ -356,9 +422,44 @@ HhQDmFjYeHVKFp7WX/Xuv9Kq9/+Vd/z7r7rv/3+l7f//y676DEwDN/9L+BVvYkKLCTgDhNkkVUyVlr74 qbbz73/VOTc/qsy89kWx+9h7qbQpJwS1bbOAscGGrB6EUTggLOqf16C55ft/HlnNAFZOXgVWdi4FRgYG VnR1MIwhwMTCyqEQ37qEmZVDFF0OE/9nAACtFF4Ey6OP+wAAAABJRU5ErkJggg== + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go + tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX + AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + wwAADsMBx2+oZAAAAR5JREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbGujg3ZATZPKYdC6FQhPwlAMkg3dP + WQwhyWIyJIUW5NqyPb7oCVtIlhVTwYf8nv7/t2zJagel9KmqKsIACYL9RjI8UHz5zshougZr/AEvbxEP + aZCDBY3VslixaJvX3wzkkDiOwbZtDRGA5vdNAg+TL27qgmt5XkBG/gTdAG7Gt+3PP9oOaEGFCVEC6rp+ + 5g9MfM/c5e4OsEZMZkQEtGL5H2DdZ5JRArDwPA+iKII0TfkC9vroC9j5vq8JTWw3WzWgLMtZGIaa0MR8 + vlAD8PYlSaIJTTiOowY0p0Bc19XEJo6HE59FAPuMzyAINKGJ1XLFZxHALtMrnkBXOIQIIIQ8YvF/KrgB + cMaRN0UdBBkAAAAASUVORK5CYII= + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6 + JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsTAAALEwEAmpwYAAACOElE + QVQ4T2P4//8/QczOJyyqHpzfiE0OQwAZC8iqszAzs7CJ69o4BR768V/W2jcGXQ0KB4aFNS3dDQtnrbCb + ePCK48wTN1wXXXzge/jXf/clV55zC4hIIatF0cjIyMikElzc57z0wX+XHd/+2+//99/ywP//xlu//tdb + +eK/4Zp3/1WTOhYzARViNUAluKjTdf37/0ZTTn9TbdhwXblhwwW1/qOP1Ja9+K8w+95/6cm3/6v2Xvkv + qKjniGGAoIqRpW3/4e8S9uGdzFz82gwMDFxAzCxm4ZegtuLDf+VJ1/8rZM25IqLvnM/CximCYYCic1QN + v7x2JIwPwyrJ3XNUylddE9G2TWNmZOBDl4czmJiZMSRBmFdSyYyJgUEQmxwIYxWEYXZBCUls4sgYq6CA + prWNbtG8nXKeaVPR5XiVjSxEzf0yYXy4BBMLO6eQjoOXZvrkbbazrv53Xf/2v4CSbjBMXkhBl1/CMyNZ + qWnvGy5pNQ+YONwAfjXzAOupl/47LLr333L50/96q9/8l23YdES6cO5KuYqVW+R7Tj6SnfP0v4hryjyY + HhQDmFjYeHVKFp7WX/Xuv9Kq9/+Vd/z7r7rv/3+l7f//y676DEwDN/9L+BVvYkKLCTgDhNkkVUyVlr74 + qbbz73/VOTc/qsy89kWx+9h7qbQpJwS1bbOAscGGrB6EUTggLOqf16C55ft/HlnNAFZOXgVWdi4FRgYG + VnR1MIwhwMTCyqEQ37qEmZVDFF0OE/9nAACtFF4Ey6OP+wAAAABJRU5ErkJggg== + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go diff --git a/SCrawler.YouTube/Controls/VideoOptionsForm.vb b/SCrawler.YouTube/Controls/VideoOptionsForm.vb index 3bff34d..6df1f54 100644 --- a/SCrawler.YouTube/Controls/VideoOptionsForm.vb +++ b/SCrawler.YouTube/Controls/VideoOptionsForm.vb @@ -69,6 +69,8 @@ Namespace API.YouTube.Controls End If MyYouTubeSettings.DownloadLocations.PopulateComboBox(TXT_FILE) + MyYouTubeSettings.PlaylistsLocations.PopulateComboBox(CMB_PLS,, True) + CMB_PLS.Text = MyYouTubeSettings.LatestPlaylistFile.Value If Not MyContainer Is Nothing Then With MyContainer @@ -313,6 +315,7 @@ Namespace API.YouTube.Controls ControlInvokeFast(TP_CONTROLS, Sub() With DirectCast(Container, YouTubeMediaContainerBase) .File = $"{TXT_FILE.Text.CSFilePS}{ .File.File}" + .M3U8_PlaylistFile = CMB_PLS.Text If Full Then .OutputVideoExtension = CMB_FORMAT.Text.StringToLower .OutputVideoFPS = AConvert(Of Double)(TXT_FPS.Text, YouTubeSettings.FpsFormatProvider.MyProviderDefault, -1) @@ -341,6 +344,7 @@ Namespace API.YouTube.Controls .OutputVideoFPS = AConvert(Of Double)(TXT_FPS.Text, YouTubeSettings.FpsFormatProvider.MyProviderDefault, -1) .OutputAudioCodec = CMB_AUDIO_CODEC.Text.StringToLower .OutputSubtitlesFormat = CMB_SUBS_FORMAT.Text.StringToLower + .M3U8_PlaylistFile = CMB_PLS.Text If Not .HasElements Then Dim cntIndex% = -1 @@ -377,6 +381,8 @@ Namespace API.YouTube.Controls If MyYouTubeSettings.OutputPathAutoChange Then MyYouTubeSettings.OutputPath.Value = f If MyDownloaderSettings.OutputPathAutoAddPaths Then MyYouTubeSettings.DownloadLocations.Add(f, False) + If Not CMB_PLS.Text.IsEmptyString Then MyYouTubeSettings.PlaylistsLocations.Add(CMB_PLS.Text, False, True) + MyYouTubeSettings.LatestPlaylistFile.Value = CMB_PLS.Text DialogResult = DialogResult.OK Close() @@ -508,6 +514,26 @@ Namespace API.YouTube.Controls End Sub #End Region #Region "Footer" + Private Sub BTT_PLS_BROWSE_MouseDown(sender As Object, e As MouseEventArgs) Handles BTT_PLS_BROWSE.MouseDown + Try + Dim f As SFile = Nothing + If Not CMB_PLS.Text.IsEmptyString Then + f = CMB_PLS.Text + ElseIf Not TXT_FILE.Text.IsEmptyString Then + f = TXT_FILE.Text + End If + f = SFile.SelectFiles(f, False, "Select a playlist...", "Playlists|*.m3u;*.m3u8|All files|*.*", EDP.ReturnValue).FirstOrDefault + If Not f.IsEmptyString Then + If e.Button = MouseButtons.Right Then + MyYouTubeSettings.PlaylistsLocations.Add(f.ToString, True, True) + MyYouTubeSettings.PlaylistsLocations.PopulateComboBox(CMB_PLS, f, True) + End If + CMB_PLS.Text = f + End If + Catch ex As Exception + ErrorsDescriber.Execute(EDP.SendToLog, ex, "[API.YouTube.Controls.VideoOptionsForm.SelectPlaylist]") + End Try + End Sub Private _FilePathBeforeItemChange As SFile = Nothing Private Sub TXT_FILE_ActionSelectedItemBeforeChanged(ByVal Sender As Object, ByVal e As EventArgs, ByVal Item As ListViewItem) Handles TXT_FILE.ActionSelectedItemBeforeChanged If Not TXT_FILE.Text.IsEmptyString Then _FilePathBeforeItemChange = TXT_FILE.Text Else _FilePathBeforeItemChange = Nothing diff --git a/SCrawler.YouTube/Downloader/DownloadLocationsCollection.vb b/SCrawler.YouTube/Downloader/DownloadLocationsCollection.vb index ba15afd..2a2b9c8 100644 --- a/SCrawler.YouTube/Downloader/DownloadLocationsCollection.vb +++ b/SCrawler.YouTube/Downloader/DownloadLocationsCollection.vb @@ -103,7 +103,7 @@ Namespace DownloadObjects.STDownloader If UseUpdate Then .EndUpdate(True) End With End Sub - Public Sub PopulateComboBox(ByRef CMB As ComboBoxExtended, Optional ByVal Current As SFile = Nothing) + Public Sub PopulateComboBox(ByRef CMB As ComboBoxExtended, Optional ByVal Current As SFile = Nothing, Optional ByVal IsFile As Boolean = False) Locations.Sort() With CMB .BeginUpdate() @@ -124,7 +124,7 @@ Namespace DownloadObjects.STDownloader .EndUpdate() If Not Current.IsEmptyString And Locations.Count > 0 Then - Dim i% = IndexOf(Current.PathWithSeparator) + Dim i% = IndexOf(If(IsFile, Current.ToString, Current.PathWithSeparator),, IsFile) If i.ValueBetween(0, .Items.Count - 1) Then .SelectedIndex = i If Current.File.IsEmptyString Then CMB.Text = Current.PathWithSeparator Else CMB.Text = Current End If @@ -158,9 +158,9 @@ Namespace DownloadObjects.STDownloader Public Overloads Sub Add(ByVal Item As DownloadLocation) Implements ICollection(Of DownloadLocation).Add Add(Item, True) End Sub - Public Overloads Sub Add(ByVal Item As DownloadLocation, ByVal AskForName As Boolean) + Public Overloads Sub Add(ByVal Item As DownloadLocation, ByVal AskForName As Boolean, Optional ByVal IsFile As Boolean = False) If Not Item.Path.IsEmptyString Then - Dim i% = IndexOf(Item) + Dim i% = IndexOf(Item,, IsFile) Dim processUpdate As Boolean = True If i >= 0 Then If Locations(i).Model = Item.Model Then @@ -183,8 +183,12 @@ Namespace DownloadObjects.STDownloader Public Function Contains(ByVal Item As DownloadLocation) As Boolean Implements ICollection(Of DownloadLocation).Contains Return Not Item.Path.IsEmptyString AndAlso Locations.Contains(Item) End Function - Public Function IndexOf(ByVal Item As DownloadLocation, Optional ByVal IgnoreModel As Boolean = False) As Integer - Return Locations.FindIndex(Function(d) d.Path = Item.Path And (d.Model = Item.Model Or IgnoreModel)) + Public Function IndexOf(ByVal Item As DownloadLocation, Optional ByVal IgnoreModel As Boolean = False, Optional ByVal IsFile As Boolean = False) As Integer + If Not IsFile Then + Return Locations.FindIndex(Function(d) d.Path = Item.Path And (d.Model = Item.Model Or IgnoreModel)) + Else + Return Locations.FindIndex(Function(d) d.Path = Item.Path) + End If End Function Public Function Remove(ByVal Item As DownloadLocation) As Boolean Implements ICollection(Of DownloadLocation).Remove If Locations.Remove(Item) Then diff --git a/SCrawler.YouTube/Objects/YouTubeMediaContainerBase.vb b/SCrawler.YouTube/Objects/YouTubeMediaContainerBase.vb index d644b52..33e9617 100644 --- a/SCrawler.YouTube/Objects/YouTubeMediaContainerBase.vb +++ b/SCrawler.YouTube/Objects/YouTubeMediaContainerBase.vb @@ -628,6 +628,18 @@ Namespace API.YouTube.Objects If HasElements And Not IsMusic Then urls.ListAddList(Elements.SelectMany(Function(elem As YouTubeMediaContainerBase) elem.GetFiles()), LAP.NotContainsOnly) Return urls End Function + Private _M3U8_PlaylistFile As SFile = Nothing + Friend Property M3U8_PlaylistFile As SFile + Get + Return _M3U8_PlaylistFile + End Get + Set(ByVal f As SFile) + If Not [Protected] Then + _M3U8_PlaylistFile = f + If HasElements Then Elements.ForEach(Sub(e As YouTubeMediaContainerBase) e.M3U8_PlaylistFile = f) + End If + End Set + End Property #End Region #Region "Command" Public Property UseCookies As Boolean = MyYouTubeSettings.DefaultUseCookies Implements IYouTubeMediaContainer.UseCookies @@ -788,6 +800,23 @@ Namespace API.YouTube.Objects Return Nothing End Try End Function + Private Function GetPlaylistRow(ByVal Element As YouTubeMediaContainerBase, Optional ByVal __file As SFile = Nothing) As String + Const m3u8DataRow$ = "#EXTINF:{0},{1}" & vbCrLf & "{2}" + With Element + Dim f As SFile = __file.IfNullOrEmpty(.File) + Dim fName$ = .Title.IfNullOrEmpty(f.Name) + If MyYouTubeSettings.MusicPlaylistCreate_M3U8_AppendNumber Then fName = $"{ .PlaylistIndex}. {fName}" + If Not .UserTitle.IsEmptyString Then + fName = $"{ .UserTitle} - {fName}" + If MyYouTubeSettings.MusicPlaylistCreate_M3U8_AppendArtist Then fName = $"{ .UserTitle} - {fName}" + End If + If MyYouTubeSettings.MusicPlaylistCreate_M3U8_AppendExt Then fName &= $".{f.Extension}" + Return String.Format(m3u8DataRow, + CInt(.Duration.TotalSeconds), + fName, + $"file:///{SymbolsConverter.ASCII.EncodeSymbolsOnly(f)}") + End With + End Function Private ReadOnly DownloadProgressPattern As RParams = RParams.DMS("\[download\]\s*([\d\.,]+)", 1, EDP.ReturnValue) Public Property Progress As MyProgress Implements IYouTubeMediaContainer.Progress Private Property IDownloadableMedia_Progress As Object Implements IDownloadableMedia.Progress @@ -822,6 +851,27 @@ Namespace API.YouTube.Objects DownloadCommand(UseCookies, Token) Else DownloadCommandArray(UseCookies, Token) + If HasElements AndAlso Elements(0).ObjectType = YouTubeMediaType.Single AndAlso Elements(0).IsMusic Then + Dim t As TextSaver = Nothing + Try + If MyYouTubeSettings.MusicPlaylistCreate_M3U8 Then + t = New TextSaver + t.AppendLine("#EXTM3U") + Elements.ForEach(Sub(e) t.AppendLine(GetPlaylistRow(e))) + t.SaveAs($"{Elements(0).File.PathWithSeparator}Playlist.m3u8", EDP.SendToLog) + t.Dispose() + End If + If MyYouTubeSettings.MusicPlaylistCreate_M3U Then + t = New TextSaver + Elements.ForEach(Sub(e) t.AppendLine(e.File)) + t.SaveAs($"{Elements(0).File.PathWithSeparator}Playlist.m3u", EDP.SendToLog) + t.Dispose() + End If + Catch ex As Exception + ErrorsDescriber.Execute(EDP.SendToLog, ex, "[YouTubeMediaContainerBase.Download.CreatePlaylist]") + End Try + t.DisposeIfReady + End If End If RaiseEvent DataDownloaded(Me, Nothing) End Sub @@ -971,6 +1021,8 @@ Namespace API.YouTube.Objects If Not File.Exists Then _File.Name = File.File If File.Exists Then + M3U8_Append() + If DownloadObjects.STDownloader.MyDownloaderSettings.CreateUrlFiles Then Dim fileUrl As SFile = File fileUrl.Extension = "url" @@ -1042,7 +1094,11 @@ Namespace API.YouTube.Objects format = format.StringToLower f = String.Format(fPattern, format) Me.Files.Add(f) - If Not format = ac3 Or Not f.Exists Then ThrowAny(Token) : .Execute($"ffmpeg -i ""{fAacAudio}"" -f {format} ""{f}""") + If Not format = ac3 Or Not f.Exists Then + ThrowAny(Token) + .Execute($"ffmpeg -i ""{fAacAudio}"" -f {format} ""{f}""") + If Not M3U8_PlaylistFile.IsEmptyString AndAlso f.Exists Then M3U8_Append(f) + End If Next End If End If @@ -1092,6 +1148,29 @@ Namespace API.YouTube.Objects End If End Try End Sub + Private Sub M3U8_Append(Optional ByVal __file As SFile = Nothing) + If Not M3U8_PlaylistFile.IsEmptyString Then + Dim m3u8Row$ = String.Empty + If Not M3U8_PlaylistFile.Extension.IsEmptyString Then + If M3U8_PlaylistFile.Extension.ToLower = "m3u8" Then + m3u8Row = GetPlaylistRow(Me, __file) + ElseIf M3U8_PlaylistFile.Extension.ToLower = "m3u" Then + m3u8Row = __file.IfNullOrEmpty(File).ToString + End If + End If + If Not m3u8Row.IsEmptyString Then + Dim m3u8Text$ + If M3U8_PlaylistFile.Exists Then + m3u8Text = M3U8_PlaylistFile.GetText + M3U8_PlaylistFile.Delete(SFO.File, SFODelete.DeleteToRecycleBin, EDP.SendToLog) + Else + m3u8Text = "#EXTM3U" + End If + m3u8Text.StringAppendLine(m3u8Row, vbCrLf) + TextSaver.SaveTextToFile(m3u8Text, M3U8_PlaylistFile,,, EDP.SendToLog) + End If + End If + End Sub #End Region #Region "Load" Private Sub ApplyElementCheckedValue(ByVal e As EContainer) diff --git a/SCrawler/Download/TDownloader.vb b/SCrawler/Download/TDownloader.vb index e08b725..1df37c1 100644 --- a/SCrawler/Download/TDownloader.vb +++ b/SCrawler/Download/TDownloader.vb @@ -511,6 +511,7 @@ Namespace DownloadObjects FilesUpdatePendingUsers() If FilesChanged Then FilesSave() : RaiseEvent FeedFilesChanged(True) If _SessionSavedPosts <> -1 Then Session = _SessionSavedPosts : _SessionSavedPosts = -1 + Settings.Plugins.ForEach(Sub(p) p.Settings.ResetIndexes()) End Try End Sub Private Sub StartDownloading(ByRef _Job As Job) diff --git a/SCrawler/PluginsEnvironment/Hosts/SettingsHostCollection.vb b/SCrawler/PluginsEnvironment/Hosts/SettingsHostCollection.vb index 38c0668..eec287a 100644 --- a/SCrawler/PluginsEnvironment/Hosts/SettingsHostCollection.vb +++ b/SCrawler/PluginsEnvironment/Hosts/SettingsHostCollection.vb @@ -320,6 +320,9 @@ Namespace Plugin.Hosts End Property #End Region #Region "Forks" + Friend Sub ResetIndexes() + HostsUnavailableIndexes.Clear() + End Sub Friend Function Available(ByVal What As Download, ByVal Silent As Boolean, Optional ByVal FillIndexes As Boolean = True, Optional ByVal HostNames As IEnumerable(Of String) = Nothing, Optional ByVal HostNamesPassed As Boolean = False) As Boolean