Compare commits
16 Commits
2024.2.25.
...
2024.5.4.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec2266f1bf | ||
|
|
7d9255c916 | ||
|
|
5b5857e31d | ||
|
|
46372ec9fb | ||
|
|
7296fda977 | ||
|
|
5f90bf6a99 | ||
|
|
718eccc3c3 | ||
|
|
efa09fb457 | ||
|
|
b252d32a7e | ||
|
|
34cd510507 | ||
|
|
f5dd791941 | ||
|
|
2a2c12c651 | ||
|
|
2bacc17ac4 | ||
|
|
7a68067d77 | ||
|
|
d1eacc2db2 | ||
|
|
3f38803643 |
@@ -8,9 +8,10 @@ I welcome requests! Follow these steps to contribute:
|
||||
1. If you have a code change suggestion, you can post a replacement code block.<!-- I also accept pull requests.-->
|
||||
|
||||
# How to report a problem
|
||||
1. Attach a **profile URL** that you cannot download.
|
||||
1. Attach the **profile URLs or links** that you cannot download.
|
||||
1. Attach the **LOG** if it exists.
|
||||
1. **Attach information to the issue with data copied from SCrawler (click the top right info button in the main window, then the `Environment` button, then the `Copy` button, and paste the copied text into the issue).**
|
||||
1. **Attach the environment information copied from SCrawler (click the top right info button in the main window, then the `Environment` button, then the `Copy` button, and paste the copied text into the issue).**
|
||||
1. *Add screenshots to illustrate the problem (**optional**)*
|
||||
|
||||
# How to build from source
|
||||
1. Delete the `PersonalUtilities` project from the solution.
|
||||
|
||||
117
Changelog.md
@@ -1,3 +1,120 @@
|
||||
# 2024.5.4.0
|
||||
|
||||
*2024-05-04*
|
||||
|
||||
- Added
|
||||
- YouTube (standalone app): setting to remove specific characters (`Defaults` - `Remove characters`)
|
||||
- Instagram: simplify the `Connection closed` error
|
||||
- Users search: add 'FriendlyName' to search results
|
||||
- Fixed
|
||||
- YouTube (standalone app): incorrect download processing when the file name ends with a dot (Issue #188)
|
||||
- The program is freezes when editing users in some cases
|
||||
- Sites
|
||||
- Reddit: token update error
|
||||
- Threads: unable to obtain credentials (ID)
|
||||
|
||||
# 2024.4.26.0
|
||||
|
||||
*2024-04-26*
|
||||
|
||||
- Added
|
||||
- Site settings: the values that can be extracted from cookies immediately populate fields
|
||||
- Feed: ability to load the last session of the current day (if it exists) as the current session after restarting SCrawler
|
||||
- Users search: include friendly name matches in search result
|
||||
- Updated
|
||||
- gallery-dl up to version **1.26.9**
|
||||
- Fixed
|
||||
- xHamster: **saved posts aren't downloading**
|
||||
|
||||
# 2024.4.14.0
|
||||
|
||||
*2024-04-14*
|
||||
|
||||
- Fixed
|
||||
- Facebook: can't get tokens
|
||||
|
||||
# 2024.4.13.0
|
||||
|
||||
*2024-04-13*
|
||||
|
||||
- Added
|
||||
- Minor improvements
|
||||
- PluginProvider
|
||||
- IPluginContentProvider: added `ResetHistoryData` function
|
||||
- Fixed
|
||||
- Sites
|
||||
- TikTok: remove last download date when erasing history data
|
||||
- YouTube: remove last download date when erasing history data
|
||||
- Instagram: **saved posts aren't downloading**
|
||||
|
||||
# 2024.4.10.0
|
||||
|
||||
*2024-04-10*
|
||||
|
||||
**For those of you who use TikTok, it is highly recommended to update TikTok plugin (using [these instructions](https://github.com/AAndyProgram/SCrawler/wiki/Settings#how-to-install-yt-dlp-ttuser-plugin)) to the latest version!**
|
||||
|
||||
**ATTENTION! This version includes changes to downloading groups (including the scheduler) and the settings file. Once you start using it, you won't be able to downgrade. I recommend making a backup of your SCrawler settings folder. It is also recommended to check all of your download groups settings and scheduler plans settings.**
|
||||
|
||||
- Added
|
||||
- Sites
|
||||
- TikTok: more settings for standalone downloader
|
||||
- Instagram:
|
||||
- automatically reset download options after updating credentials
|
||||
- **ability to extract an image (if it exists) from a video that contains a static image**
|
||||
- updated reels downloading function
|
||||
- GraphQL support
|
||||
- request timers (per request)
|
||||
- OnlyFans:
|
||||
- **download stories**
|
||||
- option to disable timeline downloading
|
||||
- Reddit: added `Check image` setting (unchecked by default) to make Reddit downloading faster
|
||||
- **YouTube (standalone app)**:
|
||||
- **the ability to add downloaded item(s) to a playlist**
|
||||
- **the ability to create a playlist from downloaded music**
|
||||
- calculation and display of the actual size of downloaded files
|
||||
- **the ability to change audio bitrate** *(you can also set the default bitrate in `Defaults Audio` - `Bitrate`)*
|
||||
- **embed thumbnail in the extracted audio (`mp3` only) as cover art** (Settings: `Defaults Audio` - `Embed thumbnail (extracted files)`)
|
||||
- Exclude `drc` *(dynamic range compression)* from parsing results
|
||||
- Standalone downloader:
|
||||
- allow thumbnail to be saved with file
|
||||
- calculation and display of the actual size of downloaded files
|
||||
- Feed:
|
||||
- add hotkeys: `Home`, `End`, `Up`, `Page Up`, `Down`, `Page Down`
|
||||
- ability to save/load views
|
||||
- Scheduler: **`All` and `Default` options removed.** *Only `Disabled`, `Specified` and `Groups` are available.*
|
||||
- Download groups: **filter users who have been (not)downloaded in the last `x` days** *(download groups, advanced filter (main window), scheduler)*.
|
||||
- Main window:
|
||||
- ability to save/load views (`View` - `Save/Load view`)
|
||||
- **all filter options from the `View` menu have now been moved to `Filter`**
|
||||
- Settings:
|
||||
- ability to confirm mass download using the `F6` key *(to protect against accidental pressing) (`Settings` - `Behavior`)*
|
||||
- the ability to find the program environment
|
||||
- default headers (`Settings` - `Headers`)
|
||||
- Added the ability to display group users *(works in scheduler, scheduler plans, download groups)*
|
||||
- Added exclusion of last 3 days from deleting session files
|
||||
- Other improvements
|
||||
- Updated
|
||||
- **yt-dlp up to version 2024.04.09**
|
||||
- PluginProvider
|
||||
- Add `PropertyValueEventArgs` class
|
||||
- PropertyValue:
|
||||
- add `Checked` parameter
|
||||
- add `OnCheckboxCheckedChange` handler
|
||||
- ISiteSettings:
|
||||
- add `CMDEncoding`, `EnvironmentPrograms` properties
|
||||
- add `EnvironmentProgramsUpdated` function
|
||||
- Fixed
|
||||
- Sites
|
||||
- PornHub: some videos won't download
|
||||
- xHamster:
|
||||
- some videos are missing when downloading creators
|
||||
- user videos aren't downloading
|
||||
- **JustForFans: fixed video downloading**
|
||||
- TikTok (standalone downloader): files with long names aren't downloaded
|
||||
- Users: incorrect decision to set last update date, which resulted in an incorrect last download date for some users
|
||||
- Feed: a scrolling bug where the feed scrolls up after returning to it
|
||||
- Minor bugs
|
||||
|
||||
# 2024.2.25.0
|
||||
|
||||
*2024-02-25*
|
||||
|
||||
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 101 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 20 KiB |
BIN
ProgramScreenshots/SettingsGlobalHeaders.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 23 KiB |
@@ -38,6 +38,8 @@ Namespace Plugin.Attributes
|
||||
Public Property LabelTextAlign As Drawing.ContentAlignment = Drawing.ContentAlignment.TopCenter
|
||||
''' <summary>This is an authorization property</summary>
|
||||
Public Property IsAuth As Boolean = False
|
||||
Public Property Category As String = Nothing
|
||||
Public Property InheritanceName As String = Nothing
|
||||
''' <summary>Initialize a new property option attribute</summary>
|
||||
''' <param name="PropertyName">Property name</param>
|
||||
Public Sub New(<CallerMemberName()> Optional ByVal PropertyName As String = Nothing)
|
||||
@@ -57,6 +59,7 @@ Namespace Plugin.Attributes
|
||||
''' <summary>Store property value in settings XML file</summary>
|
||||
<AttributeUsage(AttributeTargets.Property, AllowMultiple:=False, Inherited:=False)> Public NotInheritable Class PXML : Inherits Attribute
|
||||
Public ReadOnly ElementName As String
|
||||
Public Property OnlyForChecked As Boolean = False
|
||||
''' <summary>Initialize a new XML attribute</summary>
|
||||
''' <param name="XMLElementName">XML element name</param>
|
||||
Public Sub New(<CallerMemberName()> Optional ByVal XMLElementName As String = Nothing)
|
||||
|
||||
@@ -40,5 +40,6 @@ Namespace Plugin
|
||||
Sub GetMedia(ByVal Token As Threading.CancellationToken)
|
||||
Sub Download(ByVal Token As Threading.CancellationToken)
|
||||
Sub DownloadSingleObject(ByVal Data As IDownloadableMedia, ByVal Token As Threading.CancellationToken)
|
||||
Sub ResetHistoryData()
|
||||
End Interface
|
||||
End Namespace
|
||||
@@ -17,6 +17,9 @@ Namespace Plugin
|
||||
ReadOnly Property Icon As Icon
|
||||
ReadOnly Property Image As Image
|
||||
ReadOnly Property Site As String
|
||||
Property CMDEncoding As String
|
||||
Property EnvironmentPrograms As IEnumerable(Of String)
|
||||
Sub EnvironmentProgramsUpdated()
|
||||
Property AccountName As String
|
||||
Property Temporary As Boolean
|
||||
Property DefaultInstance As ISiteSettings
|
||||
|
||||
@@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices
|
||||
' by using the '*' as shown below:
|
||||
' <Assembly: AssemblyVersion("1.0.*")>
|
||||
|
||||
<Assembly: AssemblyVersion("2024.2.25.0")>
|
||||
<Assembly: AssemblyFileVersion("2024.2.25.0")>
|
||||
<Assembly: AssemblyVersion("2024.4.13.0")>
|
||||
<Assembly: AssemblyFileVersion("2024.4.13.0")>
|
||||
<Assembly: NeutralResourcesLanguage("en")>
|
||||
|
||||
@@ -9,8 +9,23 @@
|
||||
Namespace Plugin
|
||||
Public NotInheritable Class PropertyValue : Implements IPropertyValue
|
||||
Public Event ValueChanged As IPropertyValue.ValueChangedEventHandler Implements IPropertyValue.ValueChanged
|
||||
Public Event CheckedChanged As IPropertyValue.ValueChangedEventHandler
|
||||
Public Property [Type] As Type Implements IPropertyValue.Type
|
||||
Public Property OnChangeFunction As IPropertyValue.ValueChangedEventHandler
|
||||
Public Property OnCheckboxCheckedChange As EventHandler(Of PropertyValueEventArgs)
|
||||
Private _Checked As Boolean = False
|
||||
Public Property Checked As Boolean
|
||||
Get
|
||||
Return _Checked
|
||||
End Get
|
||||
Set(ByVal IsChecked As Boolean)
|
||||
_Checked = IsChecked
|
||||
If Not _Initialization Then
|
||||
If Not OnCheckboxCheckedChange Is Nothing Then OnCheckboxCheckedChange.Invoke(Me, EventArgs.Empty)
|
||||
RaiseEvent CheckedChanged(_Checked)
|
||||
End If
|
||||
End Set
|
||||
End Property
|
||||
Private _Initialization As Boolean = False
|
||||
''' <inheritdoc cref="PropertyValue.New(Object, Type, ByRef IPropertyValue.ValueChangedEventHandler)"/>
|
||||
''' <exception cref="ArgumentNullException"></exception>
|
||||
@@ -59,6 +74,7 @@ Namespace Plugin
|
||||
Type = Source.Type
|
||||
OnChangeFunction = Source.OnChangeFunction
|
||||
_Value = Source._Value
|
||||
_Checked = Source._Checked
|
||||
_Initialization = False
|
||||
End Sub
|
||||
End Class
|
||||
@@ -71,4 +87,8 @@ Namespace Plugin
|
||||
''' <summary>Property value</summary>
|
||||
Property Value As Object
|
||||
End Interface
|
||||
Public Class PropertyValueEventArgs : Inherits EventArgs
|
||||
Public Property Checked As Boolean = False
|
||||
Public Property ControlEnabled As Boolean = True
|
||||
End Class
|
||||
End Namespace
|
||||
@@ -81,6 +81,7 @@ Namespace API.YouTube.Base
|
||||
Public Structure MediaObject : Implements IIndexable, IComparable(Of MediaObject)
|
||||
Public Type As Plugin.UserMediaTypes
|
||||
Public ID As String
|
||||
Public ID_DRC As Boolean
|
||||
Public Extension As String
|
||||
Public Width As Integer
|
||||
Public Height As Integer
|
||||
@@ -110,10 +111,14 @@ Namespace API.YouTube.Base
|
||||
End Function
|
||||
Private Function CompareTo(ByVal Other As MediaObject) As Integer Implements IComparable(Of MediaObject).CompareTo
|
||||
If Type = Other.Type Then
|
||||
If Width.CompareTo(Other.Width) = 0 Then
|
||||
Return Size.CompareTo(Other.Size) * -1
|
||||
If ID_DRC.CompareTo(Other.ID_DRC) = 0 Then
|
||||
If Width.CompareTo(Other.Width) = 0 Then
|
||||
Return Size.CompareTo(Other.Size) * -1
|
||||
Else
|
||||
Return Width.CompareTo(Other.Width) * -1
|
||||
End If
|
||||
Else
|
||||
Return Width.CompareTo(Other.Width) * -1
|
||||
Return ID_DRC.CompareTo(Other.ID_DRC)
|
||||
End If
|
||||
Else
|
||||
Return CInt(Type).CompareTo(CInt(Other.Type))
|
||||
|
||||
@@ -174,7 +174,7 @@ Namespace API.YouTube.Base
|
||||
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"
|
||||
Dim command$ = $"{YTDLP_NAME} --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}", " ")
|
||||
|
||||
@@ -36,7 +36,9 @@ Namespace API.YouTube.Base
|
||||
<Browsable(False)> Private Property Mode As GridUpdateModes = GridUpdateModes.OnConfirm Implements IGridValuesContainer.Mode
|
||||
<Browsable(False), XMLVV(-1)> Friend ReadOnly Property PlaylistFormSplitterDistance As XMLValue(Of Integer)
|
||||
<Browsable(False)> Friend ReadOnly Property DownloadLocations As DownloadLocationsCollection
|
||||
<Browsable(False)> Friend ReadOnly Property PlaylistsLocations As DownloadLocationsCollection
|
||||
<Browsable(False)> Public Overridable Property AccountName As String
|
||||
<Browsable(False), XMLVV(0)> Private ReadOnly Property SettingsVersion As XMLValue(Of Integer)
|
||||
#Region "Environment"
|
||||
#Region "Programs"
|
||||
<Browsable(True), GridVisible(False), XMLVN({"Environment"}), Category("Environment programs"), DisplayName("Path to yt-dlp.exe"),
|
||||
@@ -84,6 +86,18 @@ Namespace API.YouTube.Base
|
||||
Description("The default output path where files should be downloaded."),
|
||||
Editor(GetType(GridSFileTypeEditorPath), GetType(UITypeEditor))>
|
||||
Public ReadOnly Property OutputPath As XMLValue(Of SFile)
|
||||
<Browsable(True), GridVisible(False), XMLVN({"Environment"}), Category("Environment"), DisplayName("Playlist file"),
|
||||
Description("Last selected playlist file"),
|
||||
Editor(GetType(GridSFileTypeEditor_M3U8), GetType(UITypeEditor))>
|
||||
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
|
||||
<Browsable(True), GridVisible(False), XMLVN({"Environment"}), Category("Environment"), DisplayName("Output path auto change"),
|
||||
Description("Automatically change the output path when a new destination is selected in the opening forms.")>
|
||||
Public ReadOnly Property OutputPathAutoChange As XMLValue(Of Boolean)
|
||||
@@ -229,6 +243,9 @@ Namespace API.YouTube.Base
|
||||
<Browsable(True), GridVisible(False), XMLVN({"Defaults"}), Category("Defaults"), DisplayName("Program description"),
|
||||
Description("Add some additional info to the program info if you need")>
|
||||
Friend ReadOnly Property ProgramDescription As XMLValue(Of String)
|
||||
<Browsable(True), GridVisible(False), XMLVN({"Defaults"}, "%"""), Category("Defaults"), DisplayName("Remove characters"),
|
||||
Description("Remove specific characters from a file name")>
|
||||
Friend ReadOnly Property FileRemoveCharacters As XMLValue(Of String)
|
||||
#End Region
|
||||
#Region "Defaults ChannelsDownload"
|
||||
<Browsable(True), GridVisible, XMLVN({"Defaults", "Channels"}), Category("Defaults"), DisplayName("Default download tabs for channels"),
|
||||
@@ -366,6 +383,32 @@ Namespace API.YouTube.Base
|
||||
<Browsable(True), GridVisible, XMLVN({"DefaultsAudio"}, True), Category("Defaults Audio"), DisplayName("Embed thumbnail"),
|
||||
Description("Embed thumbnail in the audio as cover art. Default: true.")>
|
||||
Public ReadOnly Property DefaultAudioEmbedThumbnail As XMLValue(Of Boolean)
|
||||
<Browsable(True), GridVisible, XMLVN({"DefaultsAudio"}, True), Category("Defaults Audio"), DisplayName("Embed thumbnail (extracted files)"),
|
||||
Description("Embed thumbnail in the extracted (additional file ('mp3' only)) audio as cover art. Default: true.")>
|
||||
Public ReadOnly Property DefaultAudioEmbedThumbnail_ExtractedFiles As XMLValue(Of Boolean)
|
||||
<Browsable(True), GridVisible, XMLVN({"DefaultsAudio"}, -1), Category("Defaults Audio"), DisplayName("Bitrate"),
|
||||
Description("Default audio bitrate if you want to change it during download. -1 to disable. Default: -1.")>
|
||||
Public ReadOnly Property DefaultAudioBitrate As XMLValue(Of Integer)
|
||||
<Browsable(True), GridVisible, XMLVN({"DefaultsAudio"}, 20), Category("Defaults Audio"), DisplayName("Bitrate: ffmpeg crf"),
|
||||
Description("This is the ffmpeg argument. Change it only if you know what you're doing. Default: 20.")>
|
||||
Public ReadOnly Property DefaultAudioBitrate_crf As XMLValue(Of Integer)
|
||||
#Region "Music"
|
||||
<Browsable(True), GridVisible, XMLVN({"Playlists"}, True), Category("Music"), DisplayName("Create M3U8"),
|
||||
Description("Create M3U8 playlist for music. Default: true.")>
|
||||
Public ReadOnly Property MusicPlaylistCreate_M3U8 As XMLValue(Of Boolean)
|
||||
<Browsable(True), GridVisible, XMLVN({"Playlists"}), Category("Music"), DisplayName("Create M3U"),
|
||||
Description("Create M3U playlist for music. Default: false.")>
|
||||
Public ReadOnly Property MusicPlaylistCreate_M3U As XMLValue(Of Boolean)
|
||||
<Browsable(True), GridVisible, XMLVN({"Playlists"}), Category("Music"), DisplayName("M3U8 Append artist"),
|
||||
Description("Add artist to file name. Default: false.")>
|
||||
Public ReadOnly Property MusicPlaylistCreate_M3U8_AppendArtist As XMLValue(Of Boolean)
|
||||
<Browsable(True), GridVisible, XMLVN({"Playlists"}), Category("Music"), DisplayName("M3U8 Append file extension"),
|
||||
Description("Add file extension to file name. Default: false.")>
|
||||
Public ReadOnly Property MusicPlaylistCreate_M3U8_AppendExt As XMLValue(Of Boolean)
|
||||
<Browsable(True), GridVisible, XMLVN({"Playlists"}), Category("Music"), DisplayName("M3U8 Append file number"),
|
||||
Description("Add file number to file name. Default: false.")>
|
||||
Public ReadOnly Property MusicPlaylistCreate_M3U8_AppendNumber As XMLValue(Of Boolean)
|
||||
#End Region
|
||||
#End Region
|
||||
#Region "Defaults Subtitles"
|
||||
<XMLVN({"DefaultsSubtitles"}, {"en"}, CollectionMode:=IXMLValuesCollection.Modes.String)>
|
||||
@@ -418,7 +461,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
|
||||
|
||||
136
SCrawler.YouTube/Controls/MusicPlaylistsForm.Designer.vb
generated
@@ -43,8 +43,16 @@ Namespace API.YouTube.Controls
|
||||
Dim ActionButton8 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||
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 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 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 ActionButton15 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||
Dim ActionButton16 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||
Dim ActionButton17 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||
Dim ActionButton18 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 +66,8 @@ 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()
|
||||
Me.TXT_AUDIO_BITRATE = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
||||
TP_MAIN = New System.Windows.Forms.TableLayoutPanel()
|
||||
TP_BUTTONS = New System.Windows.Forms.TableLayoutPanel()
|
||||
TP_PLS = New System.Windows.Forms.TableLayoutPanel()
|
||||
@@ -83,6 +93,8 @@ 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()
|
||||
CType(Me.TXT_AUDIO_BITRATE, System.ComponentModel.ISupportInitialize).BeginInit()
|
||||
Me.SuspendLayout()
|
||||
'
|
||||
'TP_MAIN
|
||||
@@ -97,10 +109,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, 140.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, 317)
|
||||
TP_MAIN.TabIndex = 0
|
||||
'
|
||||
'TP_BUTTONS
|
||||
@@ -112,14 +124,14 @@ 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, 292)
|
||||
TP_BUTTONS.Margin = New System.Windows.Forms.Padding(0)
|
||||
TP_BUTTONS.Name = "TP_BUTTONS"
|
||||
TP_BUTTONS.RowCount = 1
|
||||
TP_BUTTONS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||
TP_BUTTONS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||
TP_BUTTONS.Size = New System.Drawing.Size(434, 25)
|
||||
TP_BUTTONS.TabIndex = 2
|
||||
TP_BUTTONS.TabIndex = 1
|
||||
'
|
||||
'BTT_DOWN
|
||||
'
|
||||
@@ -147,7 +159,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, 143)
|
||||
Me.SPLITTER_MAIN.Name = "SPLITTER_MAIN"
|
||||
'
|
||||
'SPLITTER_MAIN.Panel1
|
||||
@@ -263,16 +275,20 @@ Namespace API.YouTube.Controls
|
||||
TP_SETTINGS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||
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.TXT_OUTPUT_PATH, 0, 3)
|
||||
TP_SETTINGS.Controls.Add(Me.CMB_PLS, 0, 4)
|
||||
TP_SETTINGS.Controls.Add(Me.TXT_AUDIO_BITRATE, 0, 2)
|
||||
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 = 5
|
||||
TP_SETTINGS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 20.0!))
|
||||
TP_SETTINGS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 20.0!))
|
||||
TP_SETTINGS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 20.0!))
|
||||
TP_SETTINGS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 20.0!))
|
||||
TP_SETTINGS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 20.0!))
|
||||
TP_SETTINGS.Size = New System.Drawing.Size(434, 140)
|
||||
TP_SETTINGS.TabIndex = 1
|
||||
'
|
||||
'TP_FORMATS
|
||||
@@ -291,7 +307,7 @@ Namespace API.YouTube.Controls
|
||||
TP_FORMATS.RowCount = 1
|
||||
TP_FORMATS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||
TP_FORMATS.Size = New System.Drawing.Size(434, 28)
|
||||
TP_FORMATS.TabIndex = 1
|
||||
TP_FORMATS.TabIndex = 5
|
||||
'
|
||||
'TXT_FORMATS_ADDIT
|
||||
'
|
||||
@@ -360,7 +376,7 @@ Namespace API.YouTube.Controls
|
||||
TP_LYRICS.RowCount = 1
|
||||
TP_LYRICS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||
TP_LYRICS.Size = New System.Drawing.Size(434, 28)
|
||||
TP_LYRICS.TabIndex = 0
|
||||
TP_LYRICS.TabIndex = 6
|
||||
'
|
||||
'TXT_SUBS
|
||||
'
|
||||
@@ -410,23 +426,28 @@ Namespace API.YouTube.Controls
|
||||
'TXT_OUTPUT_PATH
|
||||
'
|
||||
ActionButton7.BackgroundImage = CType(resources.GetObject("ActionButton7.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton7.Name = "Open"
|
||||
ActionButton7.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Open
|
||||
ActionButton7.ToolTipText = "Choose a new location (Ctrl+O)"
|
||||
ActionButton7.Name = "Save"
|
||||
ActionButton7.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Save
|
||||
ActionButton7.ToolTipText = "Save destination"
|
||||
ActionButton8.BackgroundImage = CType(resources.GetObject("ActionButton8.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton8.Name = "Add"
|
||||
ActionButton8.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Add
|
||||
ActionButton8.ToolTipText = "Choose a new location and add it to the list (Alt+O)"
|
||||
ActionButton8.Name = "Open"
|
||||
ActionButton8.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Open
|
||||
ActionButton8.ToolTipText = "Choose a new location (Ctrl+O)"
|
||||
ActionButton9.BackgroundImage = CType(resources.GetObject("ActionButton9.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton9.Name = "Clear"
|
||||
ActionButton9.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
||||
ActionButton9.Name = "Add"
|
||||
ActionButton9.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Add
|
||||
ActionButton9.ToolTipText = "Choose a new location and add it to the list (Alt+O)"
|
||||
ActionButton10.BackgroundImage = CType(resources.GetObject("ActionButton10.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton10.Name = "ArrowDown"
|
||||
ActionButton10.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.ArrowDown
|
||||
ActionButton10.Name = "Clear"
|
||||
ActionButton10.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
||||
ActionButton11.BackgroundImage = CType(resources.GetObject("ActionButton11.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton11.Name = "ArrowDown"
|
||||
ActionButton11.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.ArrowDown
|
||||
Me.TXT_OUTPUT_PATH.Buttons.Add(ActionButton7)
|
||||
Me.TXT_OUTPUT_PATH.Buttons.Add(ActionButton8)
|
||||
Me.TXT_OUTPUT_PATH.Buttons.Add(ActionButton9)
|
||||
Me.TXT_OUTPUT_PATH.Buttons.Add(ActionButton10)
|
||||
Me.TXT_OUTPUT_PATH.Buttons.Add(ActionButton11)
|
||||
Me.TXT_OUTPUT_PATH.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.CheckBox
|
||||
Me.TXT_OUTPUT_PATH.CaptionText = "Output path"
|
||||
Me.TXT_OUTPUT_PATH.CaptionToolTipEnabled = True
|
||||
@@ -446,23 +467,82 @@ Namespace API.YouTube.Controls
|
||||
Me.TXT_OUTPUT_PATH.Columns.Add(ListColumn1)
|
||||
Me.TXT_OUTPUT_PATH.Columns.Add(ListColumn2)
|
||||
Me.TXT_OUTPUT_PATH.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.TXT_OUTPUT_PATH.Location = New System.Drawing.Point(3, 59)
|
||||
Me.TXT_OUTPUT_PATH.Location = New System.Drawing.Point(3, 87)
|
||||
Me.TXT_OUTPUT_PATH.Name = "TXT_OUTPUT_PATH"
|
||||
Me.TXT_OUTPUT_PATH.Size = New System.Drawing.Size(428, 22)
|
||||
Me.TXT_OUTPUT_PATH.TabIndex = 2
|
||||
Me.TXT_OUTPUT_PATH.TextBoxBorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
|
||||
'
|
||||
'CMB_PLS
|
||||
'
|
||||
ActionButton12.BackgroundImage = CType(resources.GetObject("ActionButton12.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton12.Name = "Save"
|
||||
ActionButton12.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Save
|
||||
ActionButton12.ToolTipText = "Save playlist"
|
||||
ActionButton13.BackgroundImage = CType(resources.GetObject("ActionButton13.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton13.Name = "List"
|
||||
ActionButton13.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.List
|
||||
ActionButton13.ToolTipText = "Select multiple playlists"
|
||||
ActionButton14.BackgroundImage = CType(resources.GetObject("ActionButton14.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton14.Name = "Open"
|
||||
ActionButton14.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Open
|
||||
ActionButton14.ToolTipText = "Choose an output file"
|
||||
ActionButton15.BackgroundImage = CType(resources.GetObject("ActionButton15.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton15.Name = "Add"
|
||||
ActionButton15.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Add
|
||||
ActionButton15.ToolTipText = "Choose an output file (add a new location to the list)"
|
||||
ActionButton16.BackgroundImage = CType(resources.GetObject("ActionButton16.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton16.Name = "Clear"
|
||||
ActionButton16.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
||||
ActionButton17.BackgroundImage = CType(resources.GetObject("ActionButton17.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton17.Name = "ArrowDown"
|
||||
ActionButton17.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.ArrowDown
|
||||
Me.CMB_PLS.Buttons.Add(ActionButton12)
|
||||
Me.CMB_PLS.Buttons.Add(ActionButton13)
|
||||
Me.CMB_PLS.Buttons.Add(ActionButton14)
|
||||
Me.CMB_PLS.Buttons.Add(ActionButton15)
|
||||
Me.CMB_PLS.Buttons.Add(ActionButton16)
|
||||
Me.CMB_PLS.Buttons.Add(ActionButton17)
|
||||
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, 115)
|
||||
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
|
||||
'
|
||||
'TXT_AUDIO_BITRATE
|
||||
'
|
||||
ActionButton18.BackgroundImage = CType(resources.GetObject("ActionButton18.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton18.Name = "Clear"
|
||||
ActionButton18.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
||||
Me.TXT_AUDIO_BITRATE.Buttons.Add(ActionButton18)
|
||||
Me.TXT_AUDIO_BITRATE.CaptionText = "Audio bitrate"
|
||||
Me.TXT_AUDIO_BITRATE.CaptionToolTipEnabled = True
|
||||
Me.TXT_AUDIO_BITRATE.CaptionToolTipText = "Default audio bitrate if you want to change it during download"
|
||||
Me.TXT_AUDIO_BITRATE.CaptionWidth = 112.0R
|
||||
Me.TXT_AUDIO_BITRATE.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.TXT_AUDIO_BITRATE.Location = New System.Drawing.Point(3, 59)
|
||||
Me.TXT_AUDIO_BITRATE.Name = "TXT_AUDIO_BITRATE"
|
||||
Me.TXT_AUDIO_BITRATE.Size = New System.Drawing.Size(428, 22)
|
||||
Me.TXT_AUDIO_BITRATE.TabIndex = 4
|
||||
'
|
||||
'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, 317)
|
||||
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, 356)
|
||||
Me.Name = "MusicPlaylistsForm"
|
||||
Me.Text = "Albums"
|
||||
TP_MAIN.ResumeLayout(False)
|
||||
@@ -481,6 +561,8 @@ 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()
|
||||
CType(Me.TXT_AUDIO_BITRATE, System.ComponentModel.ISupportInitialize).EndInit()
|
||||
Me.ResumeLayout(False)
|
||||
|
||||
End Sub
|
||||
@@ -496,5 +578,7 @@ 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
|
||||
Private WithEvents TXT_AUDIO_BITRATE As PersonalUtilities.Forms.Controls.TextBoxExtended
|
||||
End Class
|
||||
End Namespace
|
||||
@@ -222,6 +222,13 @@
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton7.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
wwAADsMBx2+oZAAAAFFJREFUOE9joAr49u3bf1Lw169f50O1QgBI0MnJCY4/vP8Ix8hiILqtrQ3TEFIM
|
||||
AGGYIVDtpBsAwkQbgIyR1dDWAGLwqAGD0gByMFQ7JYCBAQChNviRiQ8ETwAAAABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton8.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
wwAADsMBx2+oZAAAAR5JREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbGujg3ZATZPKYdC6FQhPwlAMkg3dP
|
||||
@@ -232,7 +239,7 @@
|
||||
cMaRN0UdBBkAAAAASUVORK5CYII=
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton8.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<data name="ActionButton9.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6
|
||||
JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsTAAALEwEAmpwYAAADmUlE
|
||||
@@ -254,7 +261,7 @@
|
||||
0AUyNxOP1DOwcaG/8I+/LRB+At7psBnyDBG0AAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton9.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<data name="ActionButton10.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
|
||||
@@ -262,7 +269,7 @@
|
||||
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton10.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<data name="ActionButton11.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABGdBTUEAALGPC/xhBQAAE65JREFUeF7t
|
||||
3X2sJWddB/DdLi2lQG2hdOHuvfM887J7Cxca4ELTQMDWKigIFpBAEAgi9g+CJpJo9Q8NJhgBiYZIYspL
|
||||
@@ -350,6 +357,161 @@
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6LEtW/4flgYiLD1qeX0A
|
||||
AAAASUVORK5CYII=
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton12.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
wwAADsMBx2+oZAAAAFFJREFUOE9joAr49u3bf1Lw169f50O1QgBI0MnJCY4/vP8Ix8hiILqtrQ3TEFIM
|
||||
AGGYIVDtpBsAwkQbgIyR1dDWAGLwqAGD0gByMFQ7JYCBAQChNviRiQ8ETwAAAABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton13.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6
|
||||
JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAeElE
|
||||
QVQ4T2P4//8/RRhMFHQfKgDi/yAaXQEhDCZAmkNbnvyXta4CciESLEws//FhmDqYAQUgzUBMngsowVgF
|
||||
ScFgYjQQsUsQi8FEYsXyAiD+D6LRFRDCYAKk2bPo6H9J40wgFyKBLeCQMUwdzIACkGYgHnKB+J8BAD5Q
|
||||
tqhi4tzWAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton14.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
wwAADsMBx2+oZAAAAR5JREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbGujg3ZATZPKYdC6FQhPwlAMkg3dP
|
||||
WQwhyWIyJIUW5NqyPb7oCVtIlhVTwYf8nv7/t2zJagel9KmqKsIACYL9RjI8UHz5zshougZr/AEvbxEP
|
||||
aZCDBY3VslixaJvX3wzkkDiOwbZtDRGA5vdNAg+TL27qgmt5XkBG/gTdAG7Gt+3PP9oOaEGFCVEC6rp+
|
||||
5g9MfM/c5e4OsEZMZkQEtGL5H2DdZ5JRArDwPA+iKII0TfkC9vroC9j5vq8JTWw3WzWgLMtZGIaa0MR8
|
||||
vlAD8PYlSaIJTTiOowY0p0Bc19XEJo6HE59FAPuMzyAINKGJ1XLFZxHALtMrnkBXOIQIIIQ8YvF/KrgB
|
||||
cMaRN0UdBBkAAAAASUVORK5CYII=
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton15.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6
|
||||
JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsTAAALEwEAmpwYAAADmUlE
|
||||
QVRIS62WWWxMURjHL220JW1HausmlFrDFKUhnUGH6bRFzJ2idImlC0Vp2mlji1A8iNhCPIjIRES8EU+W
|
||||
h2oEtbSDTk3HNNM7S01VKsXjkb/vXBo3k1Ee7sMvmZzzzf//ne/+z50RAAxL1MUIG4G/YAv3HSVhF5Vw
|
||||
IYNdz3LadVj9RgdTB+HQYYPHIJuE1ocSdlEJFzG+1bPRLQLinglIeCkg+XUkKvz56hnkOfQs/rmA8S9H
|
||||
YEp7FDI64tAQtKhnsMapZ7zzNHsUFnbGY4VzIk70l6hnIH4wsDR7NBZ3apDrSqL5T8eFgUr1DLZ78lim
|
||||
Q4N8VzK29MxEpZSBa4M16hnU+c3M9CEFpdJsVHsXos63DDcHrf9nQEXD5VymwW/5USLNwl5vJhp7dTgW
|
||||
NML2pR7jbsUMS+KdMTa5Q8NQxinfBU4dRFcOyjy52OtbhwOBDTgZLKPPmTgY0ON4MBdNfSbYBupxY8Aq
|
||||
G10dqMG5/nIc7ytGQ6CQRliAamkTN/g1Ai4e95Qy3iogpX0UtBRDnhRzdxq2SXOxz5eFQ70rScCEU335
|
||||
ssGxj0YS06HSm4GN3ekwdE2C1hGH1LZR0JDOJof5jwHvnIvzTa0jlooTYfktvt+fhcOBHDQFTWRgxJGP
|
||||
ObAGsulZLMLWnjlY756K5c4JmNcRi6T2SGheCIihS2l5ozAo6NRhMolnUAcGV6IcwwqvFrX+JTjYuwKH
|
||||
SfRAYDms/mzs9y1GFe2VSnOw1j0FejqpLN4WCX4ZufiIBwLMLxQGm12rsLQzgWKYgmLPLNTQw6ynpDSS
|
||||
IBet8y+TqaVRVdFIeJrWuCcj+/0EzH43BomvIhBLI45uFiDcJ+6QwROFwa6+Amb9bGFNg6Xs9Ncd7Oy3
|
||||
Knb2eyU7/20nu9y/m136tIvEl6BC0qKoZwby3alo9JVhj7T5R7m/kJVIIityi8zyXmTiW+I10SqyIQNb
|
||||
uIgNwYuuf25kFd75KPKkI49OmUWnrfYWyXv/wBb2cijhhVf6a9lGei65XclYRDd6mj0GWz2iLBJaH0rY
|
||||
RSVc5Eywmhm7kuQXHX+bJlBStrh+zTi0PpSwi0q4yNFAOVvgiEcKJWUsxZn/NhT+znlofShhF5VwkRpv
|
||||
MUtti4KGYjj6sYCIh5QSu4oG27stjItHU+cjeQzvkcFzFQ2KnSKLoc4FukDCXeI2GbSoaFD4ziyPxNxK
|
||||
0AUyNxOP1DOwcaG/8I+/LRB+At7psBnyDBG0AAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton16.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
|
||||
tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX
|
||||
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton17.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABGdBTUEAALGPC/xhBQAAE65JREFUeF7t
|
||||
3X2sJWddB/DdLi2lQG2hdOHuvfM887J7Cxca4ELTQMDWKigIFpBAEAgi9g+CJpJo9Q8NJhgBiYZIYspL
|
||||
GlAKCkhEC4KgQlsLQkqhKi/lrYWWlxaw3dLddrerz/Q89+7dc2fbfTn3npf5fJJv2rS758z85nnOzJz5
|
||||
nZktAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMK3O3r79wVUIz65jfGNVxI/VIX69CvGO9M//a9P+e8o3B/8v
|
||||
vKn9s+3fyX8dAJgmaWd+fl3E96Wd/E9XdvZHkfbvXNa+Rn45AGCS3bvjj/E/h3box5OrmxjPyy8PAEyS
|
||||
XXO7zqhCeH/HDnwUOdCE+J6zdux4eH47YIrEGE8uy/Ls9Bnx/LooL0oH9b9Th/I1TVG+rCqKC+q6Xsh/
|
||||
FJgmO8vy6WknfdPQTnsjckMdwlPy2wITLO3wF6si/lGas1ekuXvX0Fzuyg9S3psOCl6qDwimQB3ji9Ok
|
||||
3btmEm907kpnEa/Mbw9Mlq1pB/6cdHZ/ZcfcPZrcXoXyrVVVFfl1gUmSdsS/libqPUMTd5NSvjktwrbB
|
||||
kgDjVi1UT26K+Nnu+XrMuaud60uPWHpIfhtg3JqyfEaanHcPTdZNTRPCPy4uLj40LxIwBudt2fKAtOP/
|
||||
0zQnN+5koIg3tpca81sC49J+LZcm5a3rJulYEq6LSV40YBOFEB6V5uFV6+flRiTsSwf9r81vDYzBCSO4
|
||||
vjfq/KAuiqfm5QM2QRPjuWnubUbz71DCn6W33zpYCmDT1EX5m92Tcuy5q47xFXkxgQ3UduqnOXfn0Bzc
|
||||
xJSvz4sCbIb2pzlp8v1w/WScnKSzkjekRT1hsMTAKC0vL5/Ydud3zb1NT1FelBcL2GiDm3d0TMTJy0ea
|
||||
pjk1LzYwAu3NvtLc+uTQXBtn7tYYCJtja/vQno5JOJFpQrzWb4hhNJoQnpjm1Q3D82wCcnNRFKfnxQQ2
|
||||
Qttk1zH5JjzhFmcIcHzyzb6O5aFem5J0sP/OvKjARmg7b7sm3xRkT3vDorwawJHb1t6Ep2NOTVoOtDch
|
||||
yssMjFr6IPh8x8SbnsT4lrQamgPhCMzPzz+sifHjnXNpMnN5XnRglJaWlk5KE2z/0ISbxnzQQ0bgvlXz
|
||||
1ePSXPnG0NyZ+DRF8Zi8CsCo7Azh0V0TbkrzRc2B0G3wIJ9429CcmZLce4MgYJTyff87JtzU5uayLM/J
|
||||
qwcM7vD5+jQ3DgzNlWnKDXldgFFJZwW/2jHZpj1727uZ5VWE3mofqJXmw4eG5sdUpqqqXXm1gFGoQnhJ
|
||||
12SbgRxoYvzjtIruK04vxRjPSvPgK0PzYmqTPqtemVcNGIU6xgu7JtusJH1ovH9ubu6UvLrQC2ncPyuN
|
||||
/58Mz4fpTvnmvHrAKJQL5dO6J9ssJXxucWFhLq8yzLKtaUf5h2ncb9zz+8eUKsYP53UERmHX/PyOrsk2
|
||||
g7nJDUWYZUuPWHpIE8oPdIz92UiMn86rCoxIOmOYta8KD5uftk2Peb1hZtTzdVOHcF3HmJ+ZVCF+Ia8u
|
||||
MCppcl0+PNlmOG1zYPtYYc2BzIQ0np+ZxvWPh8b5LObqvMrAqEzRo4BHmctijCfnEsBUqkP5u2ksz8Kd
|
||||
PI8g5SfyagOj0jbIpQk2c01DR5Brmh3NfC4DTI324LWO8V0dY3pm48mAsEGm7OEgo0sRb9wZ4+NzGWDi
|
||||
lWUZ0ti9Zt1YnvUU8fdyCYBRmsFbAh9xqhDvqEN4Xi4FTKz8s93vD4/hPiSdpJyXywCMWPtrgKuGJ12P
|
||||
ck/6gPmDXAuYOHVR/lY6UN3XMXb7kDv17MAGqhaqJ6WJ1sdegDUJ726a5oG5JDB2917vL+Kl3eO1N/lQ
|
||||
LgewUdIO8E0dk69vubosy+25JDA2bYNuFeJnOsZovxLjhbkkwEZZXl4+0QfOvfl2Ogg4O5cFNl1dFE9N
|
||||
4/B7Q+Oyj7mh/VzKZQE2UtM0j6iL+LWOidizhN3OPBiHuigvSmPwrvVjsn9pQnh1LguwGQa3Fo3fHp6M
|
||||
Pcw97c1WcllgQy0tLZ2UDr7/qmMc9jJNiF/WkwNjMHhQ0GzfX/yIU8RLfRCxkdq+kzTfrugcf/3MgZ1l
|
||||
+fRcHmCztU8Yq2P8h47J2cdcpTmQjdCE8IQ0vnzjdkjKP8nlAcZoWxXin3dP0n4l1eGb9UL92FwXOG51
|
||||
Ub48ja09w2Otz2nvTJpKs21QIWDs0lnKb6TJqTEphN3NQvncXBY4VtvSju4N3WOs17l6cXHxoblGwKRo
|
||||
r8mlHeAtHZO2b9mfDohem8sCR2XX3K4z0hj65NCYklSTGONpuUzApNlVFFWaqP81NHF7mvD2tnM7lwbu
|
||||
V/vwqTR2vrV+LPU7VSjf4ff+MAU0B65NeWVd12fm0sBhpTnzosHDp7rGUV8T9lVFvDiXCJgSrmEezDea
|
||||
onhMrgsM25rmyuvSODkwNG56nvZyYvi5XCNg2mgOXM3tVVH9ci4L3KtpmlN9W7Y+VYhfiEkuEzCt8n3L
|
||||
fzA8yXuY/b7OZEVZlovt3ew6xknf8965ublTcpmAaac5cG3C2zQ09Vv7bVAaC/+7fmz0Og6QYVZpDlyT
|
||||
GD/dPlgpl4b+2Nru5NIYuGfdmOhxmhB/VBblL+QaATNKc+DBfH1nCI/OdWHGtTewSdv874fGgIT4xfYb
|
||||
wlwmYNZpDlzNbVUIz85lYUblJ2i6BDacGP/u7O3bH5zLBPSF5sDV7K+L+Nu5LMyYtJP7xbSNfzy0zfue
|
||||
A+03gak8WwdVAnpHc+CaxHiJ5sCZsnK9f/+6bd3v3JZ2/r+SawT0mebAg0kfjB93v/Pp136t3X693bWN
|
||||
e56v6nsBhmkOXE24Ph0EnJXrwpSp63qhDuXnu7dtn1P+U1VVP5PLBHAozYGDtD+LchvU6TN4Iqa+lqGs
|
||||
XO8/YVAlgMPQHLiSsC+dNb0ml4UJVxflRWm73b1+O/Y5YXcVwvNziQDun+bANYnxkvO2bHlALg0TJsZ4
|
||||
cl3ESzu3Xa8Trm+KYimXCeDIaQ48mKqIH9McOHl2zc/vaIr42a5t1vN8tCiK03OZAI6J5sCVFPFr7QNk
|
||||
cl0Ys3yp6nvrtlO/s3K9f9ugSgDHSXPgILk58PxcFsYkX+93J8s1qUK8oynKF+YSAYyO5sCVhH3pgOjV
|
||||
uSxsoqZpHpjq//bu7dLjFPHGND+Xc5kARk9z4JrE+JZUEl+1bpLFhYW5VPf/WLcd5N/ruj4zlwlg42gO
|
||||
PCQfdXOVjdeE8MRU6xuGai9uXw2MgebA1YTrFkMoc10YsaYoX5rqfOf6uvc6e9LO/xW5RACbT3Pgam5N
|
||||
B0Q/m8vCCLT3XnCQ2ZXwnWqhenIuE8D4aA5czV3OykZj19yuM1I9PzlUXwnhirIst+cyAYyf5sA1GTQH
|
||||
uu/6MdoZ4+NTHb+1rq59j+v9wKTSHHhIPtI0zam5NByhNH5enGr306Fa9j1720ttuUQAE0tz4Epi/FJM
|
||||
cl24b8ZNd25KdTk31whg8mkOXEm4pX1EbS4LHebn5x+WdnIf765fr3NVCOFRuUwA00Nz4Gr21kX58lwW
|
||||
1qjmq8el+nxjqF4S4yVLS0sn5TIBTB/NgWuiOfAQTVE+J9XltnV16nXCvqqIF+cSAUw3zYGH5INnb9/+
|
||||
4Fyavtra7uRSLe4Zqk3f88MmxvNyjQBmhiavg/liVVVFrkuvLC4uPjSt/4eG6iEhXlOWZchlApg9mgNX
|
||||
c3P6wD8nl6UXqvlqZ1rv/xmqQ+/ThPJv5ufnH5TLBDC7NAeuZm97n/tclplWhfCstL4/GVr/nsf1fqCH
|
||||
NAeu5kB7aSSVZFabA13v786tVVFckGsE0C+aAw8mnSG/f25u7pRcmpnQbt8mlB/oWt8+pwnxWk+PBNAc
|
||||
uJoqxC/MSnNgs7BQ1yFc17WePc97Z+1AD+C4aA5czU3T/qjXdED3zLQePx5ar75nf77ev3VQJQBWaQ5c
|
||||
zZ4qhJfkskyVuigvapvbOtapt2lC/FFTls/IJQKgi+bA1aw0B07FGWOM8eQ6xnd1rEe/E+OX2jGdywTA
|
||||
fdEcuCYx/u2kXzNudjTz6az/c53L3+NUMX7YI6EBjp7mwIO5pt3J5rpMlHKhfFpavu8PLW/fM+s/7QTY
|
||||
eJoDV/PduiiWc1kmwuB6f7x7aDn7ntvrGC/MJQLgeGgOHKQK8Y46hOflsoxN0zQPbEJ8Z9cy9jxf3RnC
|
||||
o3OZABgFzYGrab9efl0qyViaAxcXFubSgchnOpar77k8xnhaLhMAo6Q5cE2K+L7NfoBMHcJT0nvfvG5Z
|
||||
+h3X+wE2iebAg7m6LMvtuS4bKl/v14txSMLuKoQX5BIBsBk0B64kfCfV4om5LCN33pYtD3DA1ZVwfb1Q
|
||||
PzaXCYDNpDlwJWH3RnSe75rbdUZ6/X9b/369z0eLojg9lwmAcdAcuJqV5sCRaEJ4QnrNbw+9R9+zcr1/
|
||||
26BKAIyV5sBDcll7W95cmmPSPocgvc6dQ6/b9+xpivJluUQATBDNgQdz1TE2B6phV4p446TdhAmAIens
|
||||
9ZXpQ1tz4KA58Am5LPfrrB07Hp7+zr90v1Z/UxXxU3Vdn5nLBMAk0xy4krC7WSifm8tyWGVZnl2F+M3u
|
||||
1+hxYrxkeXn5xFwmAKaB5sDV7E9nsRfnsqyTdnIvGtxiuPPv9jV7Ul1ekUsEwLTRHHgwVSjfsbS0dFIu
|
||||
TWtr+6uB9P8ODP/Znue7ZVmek2sEwBTT2Laa8sr2enb7jHoHRl0JV8QYH5nHDQCzwJ0DV/P1tKO7vuO/
|
||||
9zpVKN/qej/AjNIcKB3Z24TyVXmIADCrNAfKmtzUxHhuHhoAzDrNgZJyVQjhUXlIANAjmgN7m/Du471d
|
||||
MgBTzp0D+5Sw777uiQBAz2gO7EPCLSnn500OAAOaA2c615RlGfKmBoBDaQ6cvTQhvmd+fv5BeRMDwGFp
|
||||
DpyJuN4PwDHQHDjVubUqigvypgSAo6M5cPrShHjtYghl3oQAcGw0B05Rivi+ubm5U/KmA4Djozlw4rM/
|
||||
X+/fOthiADA6mgMnME2IP2rK8hl5GwHAxtAcOFH5SozxrLxpAGBjaQ4cf6oYP9w0zal5kwDA5tAcOLYc
|
||||
aC/FpE1wwmBLAMAm0xy46bk91fvCXH4AGCvNgZuRIn6tKYrH5JoDwGTQHLihuTzGeFouNQBMFs2BI4/r
|
||||
/QBMB82Bo0rYXYXwglxWAJh8mgOPN+H6eqF+bC4nAEwVzYHHkiL+c1EUp+caAsB00hx4FInxLalk2waV
|
||||
A4AppznwfrOnLsqX53IBwOzQHHiYFPHGaqF6Ui4TAMwezYGHpirip+q6PjOXBwBmmubANjFesry8fGKu
|
||||
CQD0Q4+bA/dWMf56LgMA9E8PmwO/W5blOXn1AaC/+tMcWF4ZY3xkXm0AYOabA2O8ZGlp6aS8ugDAGrPY
|
||||
HLi3CeWr8voBAIczQ82BN6UDmnPzagEA92f6mwPLz1dVVeTVAQCO1LQ2B1Yh/PX8/PyD8moAAEdrupoD
|
||||
w76qiBfnRQcAjtMUNAeGW1LOz8sLAIzKBDcHXlOWZciLCQCM2gQ2B142Nzd3Sl48AGCjTEhz4H7X+wFg
|
||||
k425OfDWqqh+Pi8KALDJtqWDgDemHfKBoR30hqUJ8dqY5PcHAMalKcrnpJ3z94Z31qNO+/t+1/sBYIKk
|
||||
k/LT6hD+Mu2oR/4rgXTW/+X02r+U3woAmDTtz/GaIv5F2nH/ZHhHfpS5J+Vf01n/S9LLbhu8OgAw0dpb
|
||||
8TYL5XPTmfvb0o78v/MOvWtHvybtzXzKT1Qx/n5d1wv5pQCAaXXvAUFRLLXd+3WMFzZF+cKUl7X/rIri
|
||||
gsWFhbn8RwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6LEtW/4flgYiLD1qeX0A
|
||||
AAAASUVORK5CYII=
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton18.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
|
||||
tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX
|
||||
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -19,10 +19,17 @@ Namespace API.YouTube.Controls
|
||||
Friend Class MusicPlaylistsForm : Implements IDesignXMLContainer
|
||||
#Region "Declarations"
|
||||
Private MyView As FormView
|
||||
Private ReadOnly MyFieldsChecker As FieldsChecker
|
||||
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 ReadOnly MyContainer As IYouTubeMediaContainer
|
||||
Private ReadOnly M3U8Files As List(Of SFile)
|
||||
Private ReadOnly Property M3U8FilesFull As List(Of SFile)
|
||||
Get
|
||||
Return ListAddList(Nothing, M3U8Files, LAP.NotContainsOnly).ListAddValue(CMB_PLS.Text, LAP.NotContainsOnly)
|
||||
End Get
|
||||
End Property
|
||||
Private Initializing As Boolean = True
|
||||
Private ReadOnly Property Current As IYouTubeMediaContainer
|
||||
Get
|
||||
@@ -40,7 +47,9 @@ Namespace API.YouTube.Controls
|
||||
#Region "Initializer"
|
||||
Friend Sub New(ByVal Container As IYouTubeMediaContainer)
|
||||
InitializeComponent()
|
||||
M3U8Files = New List(Of SFile)
|
||||
MyContainer = Container
|
||||
MyFieldsChecker = New FieldsChecker
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Form handlers"
|
||||
@@ -52,6 +61,9 @@ Namespace API.YouTube.Controls
|
||||
End If
|
||||
|
||||
MyYouTubeSettings.DownloadLocations.PopulateComboBox(TXT_OUTPUT_PATH)
|
||||
MyYouTubeSettings.PlaylistsLocations.PopulateComboBox(CMB_PLS,, True)
|
||||
CMB_PLS.Text = MyYouTubeSettings.LatestPlaylistFile.Value
|
||||
If MyYouTubeSettings.DefaultAudioBitrate > 0 Then TXT_AUDIO_BITRATE.Text = MyYouTubeSettings.DefaultAudioBitrate.Value
|
||||
|
||||
CMB_FORMATS.Items.AddRange(AvailableAudioFormats)
|
||||
If MyYouTubeSettings.PlaylistFormSplitterDistance > 0 Then SPLITTER_MAIN.SplitterDistancePercentageSet(MyYouTubeSettings.PlaylistFormSplitterDistance)
|
||||
@@ -104,6 +116,9 @@ Namespace API.YouTube.Controls
|
||||
Text = .PlaylistTitle
|
||||
End If
|
||||
|
||||
MyFieldsChecker.AddControl(Of Integer)(TXT_AUDIO_BITRATE, TXT_AUDIO_BITRATE.CaptionText, True)
|
||||
MyFieldsChecker.EndLoaderOperations()
|
||||
|
||||
UpdateSizeText()
|
||||
End With
|
||||
RefillAddit()
|
||||
@@ -111,7 +126,9 @@ Namespace API.YouTube.Controls
|
||||
End Sub
|
||||
Private Sub MusicPlaylistsForm_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
|
||||
MyYouTubeSettings.PlaylistFormSplitterDistance.Value = SPLITTER_MAIN.SplitterDistancePercentageGet
|
||||
MyView.DisposeIfReady()
|
||||
MyView.DisposeIfReady
|
||||
MyFieldsChecker.DisposeIfReady
|
||||
M3U8Files.Clear()
|
||||
End Sub
|
||||
Private Sub MusicPlaylistsForm_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
|
||||
Dim b As Boolean = True
|
||||
@@ -181,8 +198,52 @@ Namespace API.YouTube.Controls
|
||||
End With
|
||||
End Sub
|
||||
Private Sub TXT_OUTPUT_PATH_ActionOnButtonClick(ByVal Sender As ActionButton, ByVal e As ActionButtonEventArgs) Handles TXT_OUTPUT_PATH.ActionOnButtonClick
|
||||
If Sender.DefaultButton = ADB.Open Or Sender.DefaultButton = ADB.Add Then _
|
||||
MyYouTubeSettings.DownloadLocations.ChooseNewLocation(TXT_OUTPUT_PATH, Sender.DefaultButton = ADB.Add, MyDownloaderSettings.OutputPathAskForName)
|
||||
Select Case e.DefaultButton
|
||||
Case ADB.Open, ADB.Add
|
||||
MyYouTubeSettings.DownloadLocations.ChooseNewLocation(TXT_OUTPUT_PATH, e.DefaultButton = ADB.Add, MyDownloaderSettings.OutputPathAskForName)
|
||||
Case ADB.Save
|
||||
If Not TXT_OUTPUT_PATH.Text.IsEmptyString Then
|
||||
With MyYouTubeSettings.PlaylistsLocations
|
||||
.Add(TXT_OUTPUT_PATH.Text, True)
|
||||
.PopulateComboBox(TXT_OUTPUT_PATH, TXT_OUTPUT_PATH.Text)
|
||||
End With
|
||||
End If
|
||||
End Select
|
||||
End Sub
|
||||
Private Sub CMB_PLS_ActionOnButtonClick(ByVal Sender As ActionButton, ByVal e As ActionButtonEventArgs) Handles CMB_PLS.ActionOnButtonClick
|
||||
Try
|
||||
Select Case e.DefaultButton
|
||||
Case ADB.Add, ADB.Open
|
||||
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
|
||||
Case ADB.List
|
||||
Dim result As Boolean = False
|
||||
Dim selectedFiles As IEnumerable(Of SFile) = MyYouTubeSettings.PlaylistsLocations.ChooseNewPlaylistArray(CMB_PLS, result)
|
||||
If result Then M3U8Files.ListAddList(selectedFiles, LAP.NotContainsOnly, LAP.ClearBeforeAdd)
|
||||
Case ADB.Save
|
||||
With MyYouTubeSettings.PlaylistsLocations
|
||||
If Not CMB_PLS.Text.IsEmptyString AndAlso .IndexOf(CMB_PLS.Text,, True) = -1 Then
|
||||
.Add(CMB_PLS.Text, True, True)
|
||||
.PopulateComboBox(CMB_PLS, CMB_PLS.Text, True)
|
||||
End If
|
||||
End With
|
||||
Case ADB.Clear : M3U8Files.Clear()
|
||||
End Select
|
||||
Catch ex As Exception
|
||||
ErrorsDescriber.Execute(EDP.SendToLog, ex, "[API.YouTube.Controls.MusicPlaylistsForm.SelectPlaylist]")
|
||||
End Try
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Lists' handlers"
|
||||
@@ -268,7 +329,7 @@ Namespace API.YouTube.Controls
|
||||
Private Sub BTT_DOWN_Click(sender As Object, e As EventArgs) Handles BTT_DOWN.Click
|
||||
If TXT_OUTPUT_PATH.IsEmptyString Then
|
||||
MsgBoxE({"The output path cannot be null.", "Download music"}, vbCritical)
|
||||
Else
|
||||
ElseIf MyFieldsChecker.AllParamsOK Then
|
||||
With DirectCast(MyContainer, YouTubeMediaContainerBase)
|
||||
.OutputSubtitlesFormat = IIf(CH_DOWN_LYRICS.Checked, "LRC", String.Empty)
|
||||
If Not TXT_SUBS.Checked Then .PostProcessing_OutputSubtitlesFormats.Clear()
|
||||
@@ -276,8 +337,12 @@ 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_PlaylistFiles = M3U8FilesFull
|
||||
.OutputAudioBitrate = AConvert(Of Integer)(TXT_AUDIO_BITRATE.Text, -1)
|
||||
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()
|
||||
|
||||
@@ -27,6 +27,7 @@ Namespace API.YouTube.Controls
|
||||
Friend Sub New(ByVal m As MediaObject, Optional ByVal SelectedAudio As MediaObject = Nothing)
|
||||
Me.New
|
||||
Const d$ = " " & ChrW(183) & " "
|
||||
Const DRC$ = Objects.YouTubeMediaContainerBase.DRC
|
||||
MyMedia = m
|
||||
If m.Type = Plugin.UserMediaTypes.Audio Then
|
||||
If m.Bitrate >= 320 Then
|
||||
@@ -38,6 +39,7 @@ Namespace API.YouTube.Controls
|
||||
End If
|
||||
LBL_DEFINITION.Text = $"{m.Bitrate}k"
|
||||
LBL_CODECS.Text = $"{m.Extension} {d} {m.Codec} {d} {m.Bitrate}k"
|
||||
If Not m.ID.IsEmptyString AndAlso m.ID.StringToLower.Contains(DRC) Then LBL_CODECS.Text &= $" {d} DRC"
|
||||
Else
|
||||
If m.Height >= 1440 Then
|
||||
LBL_DEFINITION_INFO.Text = "Ultra High Definition"
|
||||
@@ -53,7 +55,9 @@ Namespace API.YouTube.Controls
|
||||
LBL_DEFINITION.Text = $"{m.Height}p"
|
||||
LBL_CODECS.Text = $"{m.Extension.StringToUpper}{d}{m.Codec.StringToUpper}{d}{m.FPS}fps{d}{m.Bitrate}k"
|
||||
If Not m.Protocol.IsEmptyString Then LBL_CODECS.Text &= $" ({m.Protocol})"
|
||||
If Not m.ID.IsEmptyString AndAlso m.ID.StringToLower.Contains(DRC) Then LBL_CODECS.Text &= $"{d}DRC"
|
||||
If Not SelectedAudio.ID.IsEmptyString Then LBL_CODECS.Text &= $" / {SelectedAudio.Extension}{d}{SelectedAudio.Codec}{d}{SelectedAudio.Bitrate}k"
|
||||
If Not SelectedAudio.ID.IsEmptyString AndAlso SelectedAudio.ID.StringToLower.Contains(DRC) Then LBL_CODECS.Text &= $"{d}DRC"
|
||||
End If
|
||||
|
||||
Dim sv% = m.Size / 1024
|
||||
|
||||
411
SCrawler.YouTube/Controls/VideoOptionsForm.Designer.vb
generated
@@ -31,9 +31,15 @@ Namespace API.YouTube.Controls
|
||||
Dim TP_DESTINATION As System.Windows.Forms.TableLayoutPanel
|
||||
Dim ActionButton1 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||
Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(VideoOptionsForm))
|
||||
Dim ActionButton2 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 TP_OK_CANCEL As System.Windows.Forms.TableLayoutPanel
|
||||
Dim TP_PLS As System.Windows.Forms.TableLayoutPanel
|
||||
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()
|
||||
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,16 +47,18 @@ 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()
|
||||
Dim TP_FPS_BITRATE As System.Windows.Forms.TableLayoutPanel
|
||||
Dim ActionButton7 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||
Dim ActionButton8 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||
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()
|
||||
Dim ActionButton14 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||
Dim ActionButton15 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||
Dim ActionButton16 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||
Dim ActionButton17 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,9 +68,13 @@ 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()
|
||||
Me.TXT_FPS = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
||||
Me.TXT_AUDIO_BITRATE = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
||||
Me.TP_HEADER_BASE = New System.Windows.Forms.TableLayoutPanel()
|
||||
Me.TP_SUBS = New System.Windows.Forms.TableLayoutPanel()
|
||||
Me.TXT_SUBS = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
||||
@@ -72,7 +84,6 @@ Namespace API.YouTube.Controls
|
||||
Me.CMB_FORMAT = New System.Windows.Forms.ComboBox()
|
||||
Me.CMB_AUDIO_CODEC = New System.Windows.Forms.ComboBox()
|
||||
Me.NUM_RES = New System.Windows.Forms.NumericUpDown()
|
||||
Me.TXT_FPS = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
||||
Me.TP_CONTROLS = New System.Windows.Forms.TableLayoutPanel()
|
||||
Me.TXT_SUBS_ADDIT = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
||||
Me.TXT_EXTRA_AUDIO_FORMATS = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
||||
@@ -83,6 +94,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()
|
||||
@@ -90,6 +102,7 @@ Namespace API.YouTube.Controls
|
||||
LBL_FORMAT = New System.Windows.Forms.Label()
|
||||
LBL_SUBS_FORMAT = New System.Windows.Forms.Label()
|
||||
TT_MAIN = New System.Windows.Forms.ToolTip(Me.components)
|
||||
TP_FPS_BITRATE = New System.Windows.Forms.TableLayoutPanel()
|
||||
TP_HEADER.SuspendLayout()
|
||||
CType(Me.ICON_VIDEO, System.ComponentModel.ISupportInitialize).BeginInit()
|
||||
TP_HEADER_INFO.SuspendLayout()
|
||||
@@ -100,14 +113,18 @@ 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()
|
||||
TP_FPS_BITRATE.SuspendLayout()
|
||||
CType(Me.TXT_FPS, System.ComponentModel.ISupportInitialize).BeginInit()
|
||||
CType(Me.TXT_AUDIO_BITRATE, System.ComponentModel.ISupportInitialize).BeginInit()
|
||||
Me.TP_HEADER_BASE.SuspendLayout()
|
||||
Me.TP_SUBS.SuspendLayout()
|
||||
CType(Me.TXT_SUBS, System.ComponentModel.ISupportInitialize).BeginInit()
|
||||
Me.TP_MAIN.SuspendLayout()
|
||||
Me.TP_OPTIONS.SuspendLayout()
|
||||
CType(Me.NUM_RES, System.ComponentModel.ISupportInitialize).BeginInit()
|
||||
CType(Me.TXT_FPS, System.ComponentModel.ISupportInitialize).BeginInit()
|
||||
CType(Me.TXT_SUBS_ADDIT, System.ComponentModel.ISupportInitialize).BeginInit()
|
||||
CType(Me.TXT_EXTRA_AUDIO_FORMATS, System.ComponentModel.ISupportInitialize).BeginInit()
|
||||
Me.SuspendLayout()
|
||||
@@ -126,7 +143,7 @@ Namespace API.YouTube.Controls
|
||||
TP_HEADER.Name = "TP_HEADER"
|
||||
TP_HEADER.RowCount = 1
|
||||
TP_HEADER.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||
TP_HEADER.Size = New System.Drawing.Size(719, 63)
|
||||
TP_HEADER.Size = New System.Drawing.Size(599, 63)
|
||||
TP_HEADER.TabIndex = 0
|
||||
'
|
||||
'ICON_VIDEO
|
||||
@@ -155,7 +172,7 @@ Namespace API.YouTube.Controls
|
||||
TP_HEADER_INFO.RowCount = 2
|
||||
TP_HEADER_INFO.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
|
||||
TP_HEADER_INFO.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
|
||||
TP_HEADER_INFO.Size = New System.Drawing.Size(589, 63)
|
||||
TP_HEADER_INFO.Size = New System.Drawing.Size(469, 63)
|
||||
TP_HEADER_INFO.TabIndex = 0
|
||||
'
|
||||
'LBL_TITLE
|
||||
@@ -164,7 +181,7 @@ Namespace API.YouTube.Controls
|
||||
Me.LBL_TITLE.Font = New System.Drawing.Font("Arial", 9.0!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, CType(204, Byte))
|
||||
Me.LBL_TITLE.Location = New System.Drawing.Point(3, 0)
|
||||
Me.LBL_TITLE.Name = "LBL_TITLE"
|
||||
Me.LBL_TITLE.Size = New System.Drawing.Size(583, 31)
|
||||
Me.LBL_TITLE.Size = New System.Drawing.Size(463, 31)
|
||||
Me.LBL_TITLE.TabIndex = 0
|
||||
Me.LBL_TITLE.Text = "Video title"
|
||||
Me.LBL_TITLE.TextAlign = System.Drawing.ContentAlignment.MiddleLeft
|
||||
@@ -186,7 +203,7 @@ Namespace API.YouTube.Controls
|
||||
Me.TP_HEADER_INFO_2.Name = "TP_HEADER_INFO_2"
|
||||
Me.TP_HEADER_INFO_2.RowCount = 1
|
||||
Me.TP_HEADER_INFO_2.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||
Me.TP_HEADER_INFO_2.Size = New System.Drawing.Size(589, 32)
|
||||
Me.TP_HEADER_INFO_2.Size = New System.Drawing.Size(469, 32)
|
||||
Me.TP_HEADER_INFO_2.TabIndex = 1
|
||||
'
|
||||
'ICON_CLOCK
|
||||
@@ -233,7 +250,7 @@ Namespace API.YouTube.Controls
|
||||
Me.LBL_URL.LinkColor = System.Drawing.Color.FromArgb(CType(CType(0, Byte), Integer), CType(CType(0, Byte), Integer), CType(CType(192, Byte), Integer))
|
||||
Me.LBL_URL.Location = New System.Drawing.Point(115, 0)
|
||||
Me.LBL_URL.Name = "LBL_URL"
|
||||
Me.LBL_URL.Size = New System.Drawing.Size(471, 32)
|
||||
Me.LBL_URL.Size = New System.Drawing.Size(351, 32)
|
||||
Me.LBL_URL.TabIndex = 1
|
||||
Me.LBL_URL.TabStop = True
|
||||
Me.LBL_URL.Text = "https://www.youtube.com/watch?v=abcdefghijk"
|
||||
@@ -243,17 +260,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.Location = New System.Drawing.Point(6, 243)
|
||||
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(589, 81)
|
||||
TP_FOOTER.TabIndex = 5
|
||||
'
|
||||
'TP_DESTINATION
|
||||
@@ -264,20 +282,25 @@ 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(589, 27)
|
||||
TP_DESTINATION.TabIndex = 0
|
||||
'
|
||||
'TXT_FILE
|
||||
'
|
||||
ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton1.Name = "ArrowDown"
|
||||
ActionButton1.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.ArrowDown
|
||||
ActionButton1.Name = "Save"
|
||||
ActionButton1.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Save
|
||||
ActionButton1.ToolTipText = "Save destination"
|
||||
ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton2.Name = "ArrowDown"
|
||||
ActionButton2.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.ArrowDown
|
||||
Me.TXT_FILE.Buttons.Add(ActionButton1)
|
||||
Me.TXT_FILE.Buttons.Add(ActionButton2)
|
||||
Me.TXT_FILE.ChangeControlsEnableOnCheckedChange = False
|
||||
ListColumn1.Name = "COL_NAME"
|
||||
ListColumn1.Text = "Name"
|
||||
@@ -293,17 +316,17 @@ Namespace API.YouTube.Controls
|
||||
Me.TXT_FILE.Location = New System.Drawing.Point(1, 1)
|
||||
Me.TXT_FILE.Margin = New System.Windows.Forms.Padding(1)
|
||||
Me.TXT_FILE.Name = "TXT_FILE"
|
||||
Me.TXT_FILE.Size = New System.Drawing.Size(627, 22)
|
||||
Me.TXT_FILE.Size = New System.Drawing.Size(507, 22)
|
||||
Me.TXT_FILE.TabIndex = 0
|
||||
Me.TXT_FILE.TextBoxBorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
|
||||
'
|
||||
'BTT_BROWSE
|
||||
'
|
||||
Me.BTT_BROWSE.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.BTT_BROWSE.Location = New System.Drawing.Point(632, 2)
|
||||
Me.BTT_BROWSE.Location = New System.Drawing.Point(512, 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,22 +341,22 @@ 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(589, 27)
|
||||
TP_OK_CANCEL.TabIndex = 1
|
||||
'
|
||||
'BTT_DOWN
|
||||
'
|
||||
Me.BTT_DOWN.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.BTT_DOWN.Location = New System.Drawing.Point(552, 2)
|
||||
Me.BTT_DOWN.Location = New System.Drawing.Point(432, 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
|
||||
@@ -342,32 +365,95 @@ Namespace API.YouTube.Controls
|
||||
'
|
||||
Me.BTT_CANCEL.DialogResult = System.Windows.Forms.DialogResult.Cancel
|
||||
Me.BTT_CANCEL.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.BTT_CANCEL.Location = New System.Drawing.Point(632, 2)
|
||||
Me.BTT_CANCEL.Location = New System.Drawing.Point(512, 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(589, 27)
|
||||
TP_PLS.TabIndex = 2
|
||||
'
|
||||
'CMB_PLS
|
||||
'
|
||||
ActionButton3.BackgroundImage = CType(resources.GetObject("ActionButton3.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton3.Name = "Save"
|
||||
ActionButton3.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Save
|
||||
ActionButton3.ToolTipText = "Save playlist"
|
||||
ActionButton4.BackgroundImage = CType(resources.GetObject("ActionButton4.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton4.Name = "List"
|
||||
ActionButton4.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.List
|
||||
ActionButton4.ToolTipText = "Select multiple playlists"
|
||||
ActionButton5.BackgroundImage = CType(resources.GetObject("ActionButton5.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton5.Name = "Clear"
|
||||
ActionButton5.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
||||
ActionButton6.BackgroundImage = CType(resources.GetObject("ActionButton6.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton6.Name = "ArrowDown"
|
||||
ActionButton6.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.ArrowDown
|
||||
Me.CMB_PLS.Buttons.Add(ActionButton3)
|
||||
Me.CMB_PLS.Buttons.Add(ActionButton4)
|
||||
Me.CMB_PLS.Buttons.Add(ActionButton5)
|
||||
Me.CMB_PLS.Buttons.Add(ActionButton6)
|
||||
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(507, 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(512, 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)
|
||||
LB_SEP_1.BackColor = System.Drawing.SystemColors.ControlDark
|
||||
LB_SEP_1.Location = New System.Drawing.Point(6, 179)
|
||||
LB_SEP_1.Location = New System.Drawing.Point(6, 207)
|
||||
LB_SEP_1.Margin = New System.Windows.Forms.Padding(6, 0, 6, 0)
|
||||
LB_SEP_1.Name = "LB_SEP_1"
|
||||
LB_SEP_1.Size = New System.Drawing.Size(709, 1)
|
||||
LB_SEP_1.Size = New System.Drawing.Size(589, 1)
|
||||
LB_SEP_1.TabIndex = 3
|
||||
'
|
||||
'LB_SEP_2
|
||||
'
|
||||
LB_SEP_2.Anchor = CType((System.Windows.Forms.AnchorStyles.Left Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
|
||||
LB_SEP_2.BackColor = System.Drawing.SystemColors.ControlDark
|
||||
LB_SEP_2.Location = New System.Drawing.Point(6, 209)
|
||||
LB_SEP_2.Location = New System.Drawing.Point(6, 237)
|
||||
LB_SEP_2.Margin = New System.Windows.Forms.Padding(6, 0, 6, 0)
|
||||
LB_SEP_2.Name = "LB_SEP_2"
|
||||
LB_SEP_2.Size = New System.Drawing.Size(709, 1)
|
||||
LB_SEP_2.Size = New System.Drawing.Size(589, 1)
|
||||
LB_SEP_2.TabIndex = 5
|
||||
'
|
||||
'TP_WHAT
|
||||
@@ -439,7 +525,7 @@ Namespace API.YouTube.Controls
|
||||
'
|
||||
LBL_SUBS_FORMAT.AutoSize = True
|
||||
LBL_SUBS_FORMAT.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
LBL_SUBS_FORMAT.Location = New System.Drawing.Point(552, 0)
|
||||
LBL_SUBS_FORMAT.Location = New System.Drawing.Point(432, 0)
|
||||
LBL_SUBS_FORMAT.Name = "LBL_SUBS_FORMAT"
|
||||
LBL_SUBS_FORMAT.Size = New System.Drawing.Size(74, 28)
|
||||
LBL_SUBS_FORMAT.TabIndex = 2
|
||||
@@ -451,7 +537,7 @@ Namespace API.YouTube.Controls
|
||||
'
|
||||
Me.LBL_AUDIO_CODEC.AutoSize = True
|
||||
Me.LBL_AUDIO_CODEC.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.LBL_AUDIO_CODEC.Location = New System.Drawing.Point(552, 0)
|
||||
Me.LBL_AUDIO_CODEC.Location = New System.Drawing.Point(432, 0)
|
||||
Me.LBL_AUDIO_CODEC.Name = "LBL_AUDIO_CODEC"
|
||||
Me.LBL_AUDIO_CODEC.Size = New System.Drawing.Size(74, 28)
|
||||
Me.LBL_AUDIO_CODEC.TabIndex = 5
|
||||
@@ -459,6 +545,59 @@ Namespace API.YouTube.Controls
|
||||
Me.LBL_AUDIO_CODEC.TextAlign = System.Drawing.ContentAlignment.MiddleRight
|
||||
TT_MAIN.SetToolTip(Me.LBL_AUDIO_CODEC, "Output Audio Codec")
|
||||
'
|
||||
'TP_FPS_BITRATE
|
||||
'
|
||||
TP_FPS_BITRATE.ColumnCount = 2
|
||||
TP_FPS_BITRATE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
|
||||
TP_FPS_BITRATE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
|
||||
TP_FPS_BITRATE.Controls.Add(Me.TXT_FPS, 0, 0)
|
||||
TP_FPS_BITRATE.Controls.Add(Me.TXT_AUDIO_BITRATE, 1, 0)
|
||||
TP_FPS_BITRATE.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
TP_FPS_BITRATE.Location = New System.Drawing.Point(6, 93)
|
||||
TP_FPS_BITRATE.Margin = New System.Windows.Forms.Padding(6, 0, 6, 0)
|
||||
TP_FPS_BITRATE.Name = "TP_FPS_BITRATE"
|
||||
TP_FPS_BITRATE.RowCount = 1
|
||||
TP_FPS_BITRATE.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||
TP_FPS_BITRATE.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
|
||||
TP_FPS_BITRATE.Size = New System.Drawing.Size(589, 28)
|
||||
TP_FPS_BITRATE.TabIndex = 6
|
||||
'
|
||||
'TXT_FPS
|
||||
'
|
||||
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 = "Video FPS"
|
||||
Me.TXT_FPS.CaptionToolTipEnabled = True
|
||||
Me.TXT_FPS.CaptionToolTipText = "Set the video FPS by setting the FPS value in this field. Leave blank so as not t" &
|
||||
"o change"
|
||||
Me.TXT_FPS.CaptionWidth = 60.0R
|
||||
Me.TXT_FPS.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.TXT_FPS.Location = New System.Drawing.Point(3, 2)
|
||||
Me.TXT_FPS.Margin = New System.Windows.Forms.Padding(3, 2, 3, 3)
|
||||
Me.TXT_FPS.Name = "TXT_FPS"
|
||||
Me.TXT_FPS.Size = New System.Drawing.Size(288, 22)
|
||||
Me.TXT_FPS.TabIndex = 0
|
||||
Me.TXT_FPS.TextBoxWidthMinimal = 30
|
||||
'
|
||||
'TXT_AUDIO_BITRATE
|
||||
'
|
||||
ActionButton8.BackgroundImage = CType(resources.GetObject("ActionButton8.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton8.Name = "Clear"
|
||||
ActionButton8.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
||||
Me.TXT_AUDIO_BITRATE.Buttons.Add(ActionButton8)
|
||||
Me.TXT_AUDIO_BITRATE.CaptionText = "Audio bitrate"
|
||||
Me.TXT_AUDIO_BITRATE.CaptionToolTipEnabled = True
|
||||
Me.TXT_AUDIO_BITRATE.CaptionToolTipText = "Set the video FPS if you want to change it during download. Leave blank so as not" &
|
||||
" to change."
|
||||
Me.TXT_AUDIO_BITRATE.CaptionWidth = 75.0R
|
||||
Me.TXT_AUDIO_BITRATE.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.TXT_AUDIO_BITRATE.Location = New System.Drawing.Point(297, 3)
|
||||
Me.TXT_AUDIO_BITRATE.Name = "TXT_AUDIO_BITRATE"
|
||||
Me.TXT_AUDIO_BITRATE.Size = New System.Drawing.Size(289, 22)
|
||||
Me.TXT_AUDIO_BITRATE.TabIndex = 1
|
||||
'
|
||||
'TP_HEADER_BASE
|
||||
'
|
||||
Me.TP_HEADER_BASE.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single]
|
||||
@@ -473,8 +612,8 @@ Namespace API.YouTube.Controls
|
||||
Me.TP_HEADER_BASE.RowCount = 1
|
||||
Me.TP_HEADER_BASE.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||
Me.TP_HEADER_BASE.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 64.0!))
|
||||
Me.TP_HEADER_BASE.Size = New System.Drawing.Size(721, 65)
|
||||
Me.TP_HEADER_BASE.TabIndex = 6
|
||||
Me.TP_HEADER_BASE.Size = New System.Drawing.Size(601, 65)
|
||||
Me.TP_HEADER_BASE.TabIndex = 7
|
||||
'
|
||||
'TP_SUBS
|
||||
'
|
||||
@@ -486,31 +625,31 @@ Namespace API.YouTube.Controls
|
||||
Me.TP_SUBS.Controls.Add(LBL_SUBS_FORMAT, 1, 0)
|
||||
Me.TP_SUBS.Controls.Add(Me.CMB_SUBS_FORMAT, 2, 0)
|
||||
Me.TP_SUBS.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.TP_SUBS.Location = New System.Drawing.Point(6, 93)
|
||||
Me.TP_SUBS.Location = New System.Drawing.Point(6, 121)
|
||||
Me.TP_SUBS.Margin = New System.Windows.Forms.Padding(6, 0, 6, 0)
|
||||
Me.TP_SUBS.Name = "TP_SUBS"
|
||||
Me.TP_SUBS.RowCount = 1
|
||||
Me.TP_SUBS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||
Me.TP_SUBS.Size = New System.Drawing.Size(709, 28)
|
||||
Me.TP_SUBS.Size = New System.Drawing.Size(589, 28)
|
||||
Me.TP_SUBS.TabIndex = 2
|
||||
'
|
||||
'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)
|
||||
Me.TXT_SUBS.Buttons.Add(ActionButton4)
|
||||
ActionButton9.BackgroundImage = CType(resources.GetObject("ActionButton9.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton9.Name = "Open"
|
||||
ActionButton9.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Open
|
||||
ActionButton9.ToolTipText = "Choose subtitles"
|
||||
ActionButton10.BackgroundImage = CType(resources.GetObject("ActionButton10.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton10.Name = "Refresh"
|
||||
ActionButton10.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Refresh
|
||||
ActionButton10.ToolTipText = "Reset subtitles to initial selected"
|
||||
ActionButton11.BackgroundImage = CType(resources.GetObject("ActionButton11.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton11.Name = "Clear"
|
||||
ActionButton11.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
||||
ActionButton11.ToolTipText = "Clear subtitles selection (don't download subtitles)"
|
||||
Me.TXT_SUBS.Buttons.Add(ActionButton9)
|
||||
Me.TXT_SUBS.Buttons.Add(ActionButton10)
|
||||
Me.TXT_SUBS.Buttons.Add(ActionButton11)
|
||||
Me.TXT_SUBS.CaptionText = "Subtitles"
|
||||
Me.TXT_SUBS.CaptionToolTipEnabled = True
|
||||
Me.TXT_SUBS.CaptionToolTipText = "The selected subtitles will also be downloaded"
|
||||
@@ -519,7 +658,7 @@ Namespace API.YouTube.Controls
|
||||
Me.TXT_SUBS.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.TXT_SUBS.Location = New System.Drawing.Point(3, 3)
|
||||
Me.TXT_SUBS.Name = "TXT_SUBS"
|
||||
Me.TXT_SUBS.Size = New System.Drawing.Size(543, 22)
|
||||
Me.TXT_SUBS.Size = New System.Drawing.Size(423, 22)
|
||||
Me.TXT_SUBS.TabIndex = 0
|
||||
Me.TXT_SUBS.TextBoxReadOnly = True
|
||||
'
|
||||
@@ -528,7 +667,7 @@ Namespace API.YouTube.Controls
|
||||
Me.CMB_SUBS_FORMAT.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.CMB_SUBS_FORMAT.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList
|
||||
Me.CMB_SUBS_FORMAT.FormattingEnabled = True
|
||||
Me.CMB_SUBS_FORMAT.Location = New System.Drawing.Point(632, 3)
|
||||
Me.CMB_SUBS_FORMAT.Location = New System.Drawing.Point(512, 3)
|
||||
Me.CMB_SUBS_FORMAT.Name = "CMB_SUBS_FORMAT"
|
||||
Me.CMB_SUBS_FORMAT.Size = New System.Drawing.Size(74, 21)
|
||||
Me.CMB_SUBS_FORMAT.TabIndex = 1
|
||||
@@ -538,55 +677,56 @@ Namespace API.YouTube.Controls
|
||||
Me.TP_MAIN.ColumnCount = 1
|
||||
Me.TP_MAIN.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||
Me.TP_MAIN.Controls.Add(Me.TP_HEADER_BASE, 0, 0)
|
||||
Me.TP_MAIN.Controls.Add(TP_FOOTER, 0, 8)
|
||||
Me.TP_MAIN.Controls.Add(TP_FOOTER, 0, 9)
|
||||
Me.TP_MAIN.Controls.Add(Me.TP_OPTIONS, 0, 1)
|
||||
Me.TP_MAIN.Controls.Add(Me.TP_CONTROLS, 0, 6)
|
||||
Me.TP_MAIN.Controls.Add(LB_SEP_1, 0, 5)
|
||||
Me.TP_MAIN.Controls.Add(LB_SEP_2, 0, 7)
|
||||
Me.TP_MAIN.Controls.Add(Me.TP_SUBS, 0, 2)
|
||||
Me.TP_MAIN.Controls.Add(Me.TXT_SUBS_ADDIT, 0, 3)
|
||||
Me.TP_MAIN.Controls.Add(Me.TXT_EXTRA_AUDIO_FORMATS, 0, 4)
|
||||
Me.TP_MAIN.Controls.Add(Me.TP_CONTROLS, 0, 7)
|
||||
Me.TP_MAIN.Controls.Add(LB_SEP_1, 0, 6)
|
||||
Me.TP_MAIN.Controls.Add(LB_SEP_2, 0, 8)
|
||||
Me.TP_MAIN.Controls.Add(Me.TP_SUBS, 0, 3)
|
||||
Me.TP_MAIN.Controls.Add(Me.TXT_SUBS_ADDIT, 0, 4)
|
||||
Me.TP_MAIN.Controls.Add(Me.TXT_EXTRA_AUDIO_FORMATS, 0, 5)
|
||||
Me.TP_MAIN.Controls.Add(TP_FPS_BITRATE, 0, 2)
|
||||
Me.TP_MAIN.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.TP_MAIN.Location = New System.Drawing.Point(0, 0)
|
||||
Me.TP_MAIN.Name = "TP_MAIN"
|
||||
Me.TP_MAIN.RowCount = 10
|
||||
Me.TP_MAIN.RowCount = 11
|
||||
Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 65.0!))
|
||||
Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
|
||||
Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
|
||||
Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
|
||||
Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
|
||||
Me.TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.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, 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(601, 328)
|
||||
Me.TP_MAIN.TabIndex = 0
|
||||
'
|
||||
'TP_OPTIONS
|
||||
'
|
||||
Me.TP_OPTIONS.ColumnCount = 7
|
||||
Me.TP_OPTIONS.ColumnCount = 6
|
||||
Me.TP_OPTIONS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||
Me.TP_OPTIONS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 80.0!))
|
||||
Me.TP_OPTIONS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 80.0!))
|
||||
Me.TP_OPTIONS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 80.0!))
|
||||
Me.TP_OPTIONS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 120.0!))
|
||||
Me.TP_OPTIONS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 80.0!))
|
||||
Me.TP_OPTIONS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 80.0!))
|
||||
Me.TP_OPTIONS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20.0!))
|
||||
Me.TP_OPTIONS.Controls.Add(LBL_FORMAT, 1, 0)
|
||||
Me.TP_OPTIONS.Controls.Add(TP_WHAT, 0, 0)
|
||||
Me.TP_OPTIONS.Controls.Add(Me.CMB_FORMAT, 2, 0)
|
||||
Me.TP_OPTIONS.Controls.Add(Me.LBL_AUDIO_CODEC, 5, 0)
|
||||
Me.TP_OPTIONS.Controls.Add(Me.CMB_AUDIO_CODEC, 6, 0)
|
||||
Me.TP_OPTIONS.Controls.Add(Me.LBL_AUDIO_CODEC, 4, 0)
|
||||
Me.TP_OPTIONS.Controls.Add(Me.CMB_AUDIO_CODEC, 5, 0)
|
||||
Me.TP_OPTIONS.Controls.Add(Me.NUM_RES, 3, 0)
|
||||
Me.TP_OPTIONS.Controls.Add(Me.TXT_FPS, 4, 0)
|
||||
Me.TP_OPTIONS.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.TP_OPTIONS.Location = New System.Drawing.Point(6, 65)
|
||||
Me.TP_OPTIONS.Margin = New System.Windows.Forms.Padding(6, 0, 6, 0)
|
||||
Me.TP_OPTIONS.Name = "TP_OPTIONS"
|
||||
Me.TP_OPTIONS.RowCount = 1
|
||||
Me.TP_OPTIONS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||
Me.TP_OPTIONS.Size = New System.Drawing.Size(709, 28)
|
||||
Me.TP_OPTIONS.Size = New System.Drawing.Size(589, 28)
|
||||
Me.TP_OPTIONS.TabIndex = 1
|
||||
'
|
||||
'CMB_FORMAT
|
||||
@@ -604,7 +744,7 @@ Namespace API.YouTube.Controls
|
||||
Me.CMB_AUDIO_CODEC.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.CMB_AUDIO_CODEC.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList
|
||||
Me.CMB_AUDIO_CODEC.FormattingEnabled = True
|
||||
Me.CMB_AUDIO_CODEC.Location = New System.Drawing.Point(632, 3)
|
||||
Me.CMB_AUDIO_CODEC.Location = New System.Drawing.Point(512, 3)
|
||||
Me.CMB_AUDIO_CODEC.Name = "CMB_AUDIO_CODEC"
|
||||
Me.CMB_AUDIO_CODEC.Size = New System.Drawing.Size(74, 21)
|
||||
Me.CMB_AUDIO_CODEC.TabIndex = 3
|
||||
@@ -621,57 +761,39 @@ Namespace API.YouTube.Controls
|
||||
Me.NUM_RES.TextAlign = System.Windows.Forms.HorizontalAlignment.Center
|
||||
Me.NUM_RES.Value = New Decimal(New Integer() {1080, 0, 0, 0})
|
||||
'
|
||||
'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)
|
||||
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."
|
||||
Me.TXT_FPS.CaptionWidth = 30.0R
|
||||
Me.TXT_FPS.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.TXT_FPS.Location = New System.Drawing.Point(432, 2)
|
||||
Me.TXT_FPS.Margin = New System.Windows.Forms.Padding(3, 2, 3, 3)
|
||||
Me.TXT_FPS.Name = "TXT_FPS"
|
||||
Me.TXT_FPS.Size = New System.Drawing.Size(114, 22)
|
||||
Me.TXT_FPS.TabIndex = 6
|
||||
Me.TXT_FPS.TextBoxWidthMinimal = 30
|
||||
'
|
||||
'TP_CONTROLS
|
||||
'
|
||||
Me.TP_CONTROLS.ColumnCount = 1
|
||||
Me.TP_CONTROLS.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||
Me.TP_CONTROLS.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.TP_CONTROLS.Location = New System.Drawing.Point(3, 182)
|
||||
Me.TP_CONTROLS.Location = New System.Drawing.Point(3, 210)
|
||||
Me.TP_CONTROLS.Margin = New System.Windows.Forms.Padding(3, 0, 3, 0)
|
||||
Me.TP_CONTROLS.Name = "TP_CONTROLS"
|
||||
Me.TP_CONTROLS.RowCount = 1
|
||||
Me.TP_CONTROLS.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||
Me.TP_CONTROLS.Size = New System.Drawing.Size(715, 25)
|
||||
Me.TP_CONTROLS.Size = New System.Drawing.Size(595, 25)
|
||||
Me.TP_CONTROLS.TabIndex = 0
|
||||
'
|
||||
'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)
|
||||
Me.TXT_SUBS_ADDIT.Buttons.Add(ActionButton8)
|
||||
ActionButton12.BackgroundImage = CType(resources.GetObject("ActionButton12.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton12.Enabled = False
|
||||
ActionButton12.Name = "Open"
|
||||
ActionButton12.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Open
|
||||
ActionButton12.ToolTipText = "Choose additional formats"
|
||||
ActionButton13.BackgroundImage = CType(resources.GetObject("ActionButton13.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton13.Enabled = False
|
||||
ActionButton13.Name = "Refresh"
|
||||
ActionButton13.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Refresh
|
||||
ActionButton13.ToolTipText = "Fill in additional formats from the defaults"
|
||||
ActionButton14.BackgroundImage = CType(resources.GetObject("ActionButton14.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton14.Enabled = False
|
||||
ActionButton14.Name = "Clear"
|
||||
ActionButton14.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
||||
ActionButton14.ToolTipText = "Remove all additional formats"
|
||||
Me.TXT_SUBS_ADDIT.Buttons.Add(ActionButton12)
|
||||
Me.TXT_SUBS_ADDIT.Buttons.Add(ActionButton13)
|
||||
Me.TXT_SUBS_ADDIT.Buttons.Add(ActionButton14)
|
||||
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
|
||||
@@ -679,44 +801,44 @@ Namespace API.YouTube.Controls
|
||||
Me.TXT_SUBS_ADDIT.CaptionWidth = 150.0R
|
||||
Me.TXT_SUBS_ADDIT.ClearTextByButtonClear = False
|
||||
Me.TXT_SUBS_ADDIT.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.TXT_SUBS_ADDIT.Location = New System.Drawing.Point(6, 124)
|
||||
Me.TXT_SUBS_ADDIT.Location = New System.Drawing.Point(6, 152)
|
||||
Me.TXT_SUBS_ADDIT.Margin = New System.Windows.Forms.Padding(6, 3, 6, 3)
|
||||
Me.TXT_SUBS_ADDIT.Name = "TXT_SUBS_ADDIT"
|
||||
Me.TXT_SUBS_ADDIT.Size = New System.Drawing.Size(709, 22)
|
||||
Me.TXT_SUBS_ADDIT.Size = New System.Drawing.Size(589, 22)
|
||||
Me.TXT_SUBS_ADDIT.TabIndex = 3
|
||||
Me.TXT_SUBS_ADDIT.Tag = "s"
|
||||
Me.TXT_SUBS_ADDIT.TextBoxReadOnly = True
|
||||
'
|
||||
'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.ToolTipText = "Choose additional formats"
|
||||
Me.TXT_EXTRA_AUDIO_FORMATS.Buttons.Add(ActionButton9)
|
||||
Me.TXT_EXTRA_AUDIO_FORMATS.Buttons.Add(ActionButton10)
|
||||
Me.TXT_EXTRA_AUDIO_FORMATS.Buttons.Add(ActionButton11)
|
||||
ActionButton15.BackgroundImage = CType(resources.GetObject("ActionButton15.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton15.Enabled = False
|
||||
ActionButton15.Name = "Open"
|
||||
ActionButton15.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Open
|
||||
ActionButton15.ToolTipText = "Choose additional formats"
|
||||
ActionButton16.BackgroundImage = CType(resources.GetObject("ActionButton16.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton16.Enabled = False
|
||||
ActionButton16.Name = "Refresh"
|
||||
ActionButton16.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Refresh
|
||||
ActionButton16.ToolTipText = "Fill in additional formats from the defaults"
|
||||
ActionButton17.BackgroundImage = CType(resources.GetObject("ActionButton17.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton17.Enabled = False
|
||||
ActionButton17.Name = "Clear"
|
||||
ActionButton17.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
||||
ActionButton17.ToolTipText = "Choose additional formats"
|
||||
Me.TXT_EXTRA_AUDIO_FORMATS.Buttons.Add(ActionButton15)
|
||||
Me.TXT_EXTRA_AUDIO_FORMATS.Buttons.Add(ActionButton16)
|
||||
Me.TXT_EXTRA_AUDIO_FORMATS.Buttons.Add(ActionButton17)
|
||||
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
|
||||
Me.TXT_EXTRA_AUDIO_FORMATS.CaptionWidth = 150.0R
|
||||
Me.TXT_EXTRA_AUDIO_FORMATS.ClearTextByButtonClear = False
|
||||
Me.TXT_EXTRA_AUDIO_FORMATS.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.TXT_EXTRA_AUDIO_FORMATS.Location = New System.Drawing.Point(6, 152)
|
||||
Me.TXT_EXTRA_AUDIO_FORMATS.Location = New System.Drawing.Point(6, 180)
|
||||
Me.TXT_EXTRA_AUDIO_FORMATS.Margin = New System.Windows.Forms.Padding(6, 3, 6, 3)
|
||||
Me.TXT_EXTRA_AUDIO_FORMATS.Name = "TXT_EXTRA_AUDIO_FORMATS"
|
||||
Me.TXT_EXTRA_AUDIO_FORMATS.Size = New System.Drawing.Size(709, 22)
|
||||
Me.TXT_EXTRA_AUDIO_FORMATS.Size = New System.Drawing.Size(589, 22)
|
||||
Me.TXT_EXTRA_AUDIO_FORMATS.TabIndex = 4
|
||||
Me.TXT_EXTRA_AUDIO_FORMATS.Tag = "a"
|
||||
Me.TXT_EXTRA_AUDIO_FORMATS.TextBoxReadOnly = True
|
||||
@@ -727,14 +849,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(601, 328)
|
||||
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(617, 367)
|
||||
Me.Name = "VideoOptionsForm"
|
||||
Me.ShowInTaskbar = False
|
||||
Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide
|
||||
@@ -750,8 +872,13 @@ 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()
|
||||
TP_FPS_BITRATE.ResumeLayout(False)
|
||||
CType(Me.TXT_FPS, System.ComponentModel.ISupportInitialize).EndInit()
|
||||
CType(Me.TXT_AUDIO_BITRATE, System.ComponentModel.ISupportInitialize).EndInit()
|
||||
Me.TP_HEADER_BASE.ResumeLayout(False)
|
||||
Me.TP_SUBS.ResumeLayout(False)
|
||||
Me.TP_SUBS.PerformLayout()
|
||||
@@ -760,7 +887,6 @@ Namespace API.YouTube.Controls
|
||||
Me.TP_OPTIONS.ResumeLayout(False)
|
||||
Me.TP_OPTIONS.PerformLayout()
|
||||
CType(Me.NUM_RES, System.ComponentModel.ISupportInitialize).EndInit()
|
||||
CType(Me.TXT_FPS, System.ComponentModel.ISupportInitialize).EndInit()
|
||||
CType(Me.TXT_SUBS_ADDIT, System.ComponentModel.ISupportInitialize).EndInit()
|
||||
CType(Me.TXT_EXTRA_AUDIO_FORMATS, System.ComponentModel.ISupportInitialize).EndInit()
|
||||
Me.ResumeLayout(False)
|
||||
@@ -791,5 +917,8 @@ 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
|
||||
Private WithEvents TXT_AUDIO_BITRATE As PersonalUtilities.Forms.Controls.TextBoxExtended
|
||||
End Class
|
||||
End Namespace
|
||||
@@ -137,6 +137,13 @@
|
||||
</metadata>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="ActionButton1.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
wwAADsMBx2+oZAAAAFFJREFUOE9joAr49u3bf1Lw169f50O1QgBI0MnJCY4/vP8Ix8hiILqtrQ3TEFIM
|
||||
AGGYIVDtpBsAwkQbgIyR1dDWAGLwqAGD0gByMFQ7JYCBAQChNviRiQ8ETwAAAABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton2.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABGdBTUEAALGPC/xhBQAAE65JREFUeF7t
|
||||
3X2sJWddB/DdLi2lQG2hdOHuvfM887J7Cxca4ELTQMDWKigIFpBAEAgi9g+CJpJo9Q8NJhgBiYZIYspL
|
||||
@@ -235,6 +242,123 @@
|
||||
<metadata name="TP_OK_CANCEL.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>False</value>
|
||||
</metadata>
|
||||
<metadata name="TP_PLS.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>False</value>
|
||||
</metadata>
|
||||
<data name="ActionButton3.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
wwAADsMBx2+oZAAAAFFJREFUOE9joAr49u3bf1Lw169f50O1QgBI0MnJCY4/vP8Ix8hiILqtrQ3TEFIM
|
||||
AGGYIVDtpBsAwkQbgIyR1dDWAGLwqAGD0gByMFQ7JYCBAQChNviRiQ8ETwAAAABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton4.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6
|
||||
JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAeElE
|
||||
QVQ4T2P4//8/RRhMFHQfKgDi/yAaXQEhDCZAmkNbnvyXta4CciESLEws//FhmDqYAQUgzUBMngsowVgF
|
||||
ScFgYjQQsUsQi8FEYsXyAiD+D6LRFRDCYAKk2bPo6H9J40wgFyKBLeCQMUwdzIACkGYgHnKB+J8BAD5Q
|
||||
tqhi4tzWAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton5.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
|
||||
tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX
|
||||
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton6.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABGdBTUEAALGPC/xhBQAAE65JREFUeF7t
|
||||
3X2sJWddB/DdLi2lQG2hdOHuvfM887J7Cxca4ELTQMDWKigIFpBAEAgi9g+CJpJo9Q8NJhgBiYZIYspL
|
||||
GlAKCkhEC4KgQlsLQkqhKi/lrYWWlxaw3dLddrerz/Q89+7dc2fbfTn3npf5fJJv2rS758z85nnOzJz5
|
||||
nZktAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMK3O3r79wVUIz65jfGNVxI/VIX69CvGO9M//a9P+e8o3B/8v
|
||||
vKn9s+3fyX8dAJgmaWd+fl3E96Wd/E9XdvZHkfbvXNa+Rn45AGCS3bvjj/E/h3box5OrmxjPyy8PAEyS
|
||||
XXO7zqhCeH/HDnwUOdCE+J6zdux4eH47YIrEGE8uy/Ls9Bnx/LooL0oH9b9Th/I1TVG+rCqKC+q6Xsh/
|
||||
FJgmO8vy6WknfdPQTnsjckMdwlPy2wITLO3wF6si/lGas1ekuXvX0Fzuyg9S3psOCl6qDwimQB3ji9Ok
|
||||
3btmEm907kpnEa/Mbw9Mlq1pB/6cdHZ/ZcfcPZrcXoXyrVVVFfl1gUmSdsS/libqPUMTd5NSvjktwrbB
|
||||
kgDjVi1UT26K+Nnu+XrMuaud60uPWHpIfhtg3JqyfEaanHcPTdZNTRPCPy4uLj40LxIwBudt2fKAtOP/
|
||||
0zQnN+5koIg3tpca81sC49J+LZcm5a3rJulYEq6LSV40YBOFEB6V5uFV6+flRiTsSwf9r81vDYzBCSO4
|
||||
vjfq/KAuiqfm5QM2QRPjuWnubUbz71DCn6W33zpYCmDT1EX5m92Tcuy5q47xFXkxgQ3UduqnOXfn0Bzc
|
||||
xJSvz4sCbIb2pzlp8v1w/WScnKSzkjekRT1hsMTAKC0vL5/Ydud3zb1NT1FelBcL2GiDm3d0TMTJy0ea
|
||||
pjk1LzYwAu3NvtLc+uTQXBtn7tYYCJtja/vQno5JOJFpQrzWb4hhNJoQnpjm1Q3D82wCcnNRFKfnxQQ2
|
||||
Qttk1zH5JjzhFmcIcHzyzb6O5aFem5J0sP/OvKjARmg7b7sm3xRkT3vDorwawJHb1t6Ep2NOTVoOtDch
|
||||
yssMjFr6IPh8x8SbnsT4lrQamgPhCMzPzz+sifHjnXNpMnN5XnRglJaWlk5KE2z/0ISbxnzQQ0bgvlXz
|
||||
1ePSXPnG0NyZ+DRF8Zi8CsCo7Azh0V0TbkrzRc2B0G3wIJ9429CcmZLce4MgYJTyff87JtzU5uayLM/J
|
||||
qwcM7vD5+jQ3DgzNlWnKDXldgFFJZwW/2jHZpj1727uZ5VWE3mofqJXmw4eG5sdUpqqqXXm1gFGoQnhJ
|
||||
12SbgRxoYvzjtIruK04vxRjPSvPgK0PzYmqTPqtemVcNGIU6xgu7JtusJH1ovH9ubu6UvLrQC2ncPyuN
|
||||
/58Mz4fpTvnmvHrAKJQL5dO6J9ssJXxucWFhLq8yzLKtaUf5h2ncb9zz+8eUKsYP53UERmHX/PyOrsk2
|
||||
g7nJDUWYZUuPWHpIE8oPdIz92UiMn86rCoxIOmOYta8KD5uftk2Peb1hZtTzdVOHcF3HmJ+ZVCF+Ia8u
|
||||
MCppcl0+PNlmOG1zYPtYYc2BzIQ0np+ZxvWPh8b5LObqvMrAqEzRo4BHmctijCfnEsBUqkP5u2ksz8Kd
|
||||
PI8g5SfyagOj0jbIpQk2c01DR5Brmh3NfC4DTI324LWO8V0dY3pm48mAsEGm7OEgo0sRb9wZ4+NzGWDi
|
||||
lWUZ0ti9Zt1YnvUU8fdyCYBRmsFbAh9xqhDvqEN4Xi4FTKz8s93vD4/hPiSdpJyXywCMWPtrgKuGJ12P
|
||||
ck/6gPmDXAuYOHVR/lY6UN3XMXb7kDv17MAGqhaqJ6WJ1sdegDUJ726a5oG5JDB2917vL+Kl3eO1N/lQ
|
||||
LgewUdIO8E0dk69vubosy+25JDA2bYNuFeJnOsZovxLjhbkkwEZZXl4+0QfOvfl2Ogg4O5cFNl1dFE9N
|
||||
4/B7Q+Oyj7mh/VzKZQE2UtM0j6iL+LWOidizhN3OPBiHuigvSmPwrvVjsn9pQnh1LguwGQa3Fo3fHp6M
|
||||
Pcw97c1WcllgQy0tLZ2UDr7/qmMc9jJNiF/WkwNjMHhQ0GzfX/yIU8RLfRCxkdq+kzTfrugcf/3MgZ1l
|
||||
+fRcHmCztU8Yq2P8h47J2cdcpTmQjdCE8IQ0vnzjdkjKP8nlAcZoWxXin3dP0n4l1eGb9UL92FwXOG51
|
||||
Ub48ja09w2Otz2nvTJpKs21QIWDs0lnKb6TJqTEphN3NQvncXBY4VtvSju4N3WOs17l6cXHxoblGwKRo
|
||||
r8mlHeAtHZO2b9mfDohem8sCR2XX3K4z0hj65NCYklSTGONpuUzApNlVFFWaqP81NHF7mvD2tnM7lwbu
|
||||
V/vwqTR2vrV+LPU7VSjf4ff+MAU0B65NeWVd12fm0sBhpTnzosHDp7rGUV8T9lVFvDiXCJgSrmEezDea
|
||||
onhMrgsM25rmyuvSODkwNG56nvZyYvi5XCNg2mgOXM3tVVH9ci4L3KtpmlN9W7Y+VYhfiEkuEzCt8n3L
|
||||
fzA8yXuY/b7OZEVZlovt3ew6xknf8965ublTcpmAaac5cG3C2zQ09Vv7bVAaC/+7fmz0Og6QYVZpDlyT
|
||||
GD/dPlgpl4b+2Nru5NIYuGfdmOhxmhB/VBblL+QaATNKc+DBfH1nCI/OdWHGtTewSdv874fGgIT4xfYb
|
||||
wlwmYNZpDlzNbVUIz85lYUblJ2i6BDacGP/u7O3bH5zLBPSF5sDV7K+L+Nu5LMyYtJP7xbSNfzy0zfue
|
||||
A+03gak8WwdVAnpHc+CaxHiJ5sCZsnK9f/+6bd3v3JZ2/r+SawT0mebAg0kfjB93v/Pp136t3X693bWN
|
||||
e56v6nsBhmkOXE24Ph0EnJXrwpSp63qhDuXnu7dtn1P+U1VVP5PLBHAozYGDtD+LchvU6TN4Iqa+lqGs
|
||||
XO8/YVAlgMPQHLiSsC+dNb0ml4UJVxflRWm73b1+O/Y5YXcVwvNziQDun+bANYnxkvO2bHlALg0TJsZ4
|
||||
cl3ESzu3Xa8Trm+KYimXCeDIaQ48mKqIH9McOHl2zc/vaIr42a5t1vN8tCiK03OZAI6J5sCVFPFr7QNk
|
||||
cl0Ys3yp6nvrtlO/s3K9f9ugSgDHSXPgILk58PxcFsYkX+93J8s1qUK8oynKF+YSAYyO5sCVhH3pgOjV
|
||||
uSxsoqZpHpjq//bu7dLjFPHGND+Xc5kARk9z4JrE+JZUEl+1bpLFhYW5VPf/WLcd5N/ruj4zlwlg42gO
|
||||
PCQfdXOVjdeE8MRU6xuGai9uXw2MgebA1YTrFkMoc10YsaYoX5rqfOf6uvc6e9LO/xW5RACbT3Pgam5N
|
||||
B0Q/m8vCCLT3XnCQ2ZXwnWqhenIuE8D4aA5czV3OykZj19yuM1I9PzlUXwnhirIst+cyAYyf5sA1GTQH
|
||||
uu/6MdoZ4+NTHb+1rq59j+v9wKTSHHhIPtI0zam5NByhNH5enGr306Fa9j1720ttuUQAE0tz4Epi/FJM
|
||||
cl24b8ZNd25KdTk31whg8mkOXEm4pX1EbS4LHebn5x+WdnIf765fr3NVCOFRuUwA00Nz4Gr21kX58lwW
|
||||
1qjmq8el+nxjqF4S4yVLS0sn5TIBTB/NgWuiOfAQTVE+J9XltnV16nXCvqqIF+cSAUw3zYGH5INnb9/+
|
||||
4Fyavtra7uRSLe4Zqk3f88MmxvNyjQBmhiavg/liVVVFrkuvLC4uPjSt/4eG6iEhXlOWZchlApg9mgNX
|
||||
c3P6wD8nl6UXqvlqZ1rv/xmqQ+/ThPJv5ufnH5TLBDC7NAeuZm97n/tclplWhfCstL4/GVr/nsf1fqCH
|
||||
NAeu5kB7aSSVZFabA13v786tVVFckGsE0C+aAw8mnSG/f25u7pRcmpnQbt8mlB/oWt8+pwnxWk+PBNAc
|
||||
uJoqxC/MSnNgs7BQ1yFc17WePc97Z+1AD+C4aA5czU3T/qjXdED3zLQePx5ar75nf77ev3VQJQBWaQ5c
|
||||
zZ4qhJfkskyVuigvapvbOtapt2lC/FFTls/IJQKgi+bA1aw0B07FGWOM8eQ6xnd1rEe/E+OX2jGdywTA
|
||||
fdEcuCYx/u2kXzNudjTz6az/c53L3+NUMX7YI6EBjp7mwIO5pt3J5rpMlHKhfFpavu8PLW/fM+s/7QTY
|
||||
eJoDV/PduiiWc1kmwuB6f7x7aDn7ntvrGC/MJQLgeGgOHKQK8Y46hOflsoxN0zQPbEJ8Z9cy9jxf3RnC
|
||||
o3OZABgFzYGrab9efl0qyViaAxcXFubSgchnOpar77k8xnhaLhMAo6Q5cE2K+L7NfoBMHcJT0nvfvG5Z
|
||||
+h3X+wE2iebAg7m6LMvtuS4bKl/v14txSMLuKoQX5BIBsBk0B64kfCfV4om5LCN33pYtD3DA1ZVwfb1Q
|
||||
PzaXCYDNpDlwJWH3RnSe75rbdUZ6/X9b/369z0eLojg9lwmAcdAcuJqV5sCRaEJ4QnrNbw+9R9+zcr1/
|
||||
26BKAIyV5sBDcll7W95cmmPSPocgvc6dQ6/b9+xpivJluUQATBDNgQdz1TE2B6phV4p446TdhAmAIens
|
||||
9ZXpQ1tz4KA58Am5LPfrrB07Hp7+zr90v1Z/UxXxU3Vdn5nLBMAk0xy4krC7WSifm8tyWGVZnl2F+M3u
|
||||
1+hxYrxkeXn5xFwmAKaB5sDV7E9nsRfnsqyTdnIvGtxiuPPv9jV7Ul1ekUsEwLTRHHgwVSjfsbS0dFIu
|
||||
TWtr+6uB9P8ODP/Znue7ZVmek2sEwBTT2Laa8sr2enb7jHoHRl0JV8QYH5nHDQCzwJ0DV/P1tKO7vuO/
|
||||
9zpVKN/qej/AjNIcKB3Z24TyVXmIADCrNAfKmtzUxHhuHhoAzDrNgZJyVQjhUXlIANAjmgN7m/Du471d
|
||||
MgBTzp0D+5Sw777uiQBAz2gO7EPCLSnn500OAAOaA2c615RlGfKmBoBDaQ6cvTQhvmd+fv5BeRMDwGFp
|
||||
DpyJuN4PwDHQHDjVubUqigvypgSAo6M5cPrShHjtYghl3oQAcGw0B05Rivi+ubm5U/KmA4Djozlw4rM/
|
||||
X+/fOthiADA6mgMnME2IP2rK8hl5GwHAxtAcOFH5SozxrLxpAGBjaQ4cf6oYP9w0zal5kwDA5tAcOLYc
|
||||
aC/FpE1wwmBLAMAm0xy46bk91fvCXH4AGCvNgZuRIn6tKYrH5JoDwGTQHLihuTzGeFouNQBMFs2BI4/r
|
||||
/QBMB82Bo0rYXYXwglxWAJh8mgOPN+H6eqF+bC4nAEwVzYHHkiL+c1EUp+caAsB00hx4FInxLalk2waV
|
||||
A4AppznwfrOnLsqX53IBwOzQHHiYFPHGaqF6Ui4TAMwezYGHpirip+q6PjOXBwBmmubANjFesry8fGKu
|
||||
CQD0Q4+bA/dWMf56LgMA9E8PmwO/W5blOXn1AaC/+tMcWF4ZY3xkXm0AYOabA2O8ZGlp6aS8ugDAGrPY
|
||||
HLi3CeWr8voBAIczQ82BN6UDmnPzagEA92f6mwPLz1dVVeTVAQCO1LQ2B1Yh/PX8/PyD8moAAEdrupoD
|
||||
w76qiBfnRQcAjtMUNAeGW1LOz8sLAIzKBDcHXlOWZciLCQCM2gQ2B142Nzd3Sl48AGCjTEhz4H7X+wFg
|
||||
k425OfDWqqh+Pi8KALDJtqWDgDemHfKBoR30hqUJ8dqY5PcHAMalKcrnpJ3z94Z31qNO+/t+1/sBYIKk
|
||||
k/LT6hD+Mu2oR/4rgXTW/+X02r+U3woAmDTtz/GaIv5F2nH/ZHhHfpS5J+Vf01n/S9LLbhu8OgAw0dpb
|
||||
8TYL5XPTmfvb0o78v/MOvWtHvybtzXzKT1Qx/n5d1wv5pQCAaXXvAUFRLLXd+3WMFzZF+cKUl7X/rIri
|
||||
gsWFhbn8RwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6LEtW/4flgYiLD1qeX0A
|
||||
AAAASUVORK5CYII=
|
||||
</value>
|
||||
</data>
|
||||
<metadata name="LB_SEP_1.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>False</value>
|
||||
</metadata>
|
||||
@@ -253,74 +377,15 @@
|
||||
<metadata name="LBL_SUBS_FORMAT.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>False</value>
|
||||
</metadata>
|
||||
<data name="ActionButton2.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
wwAADsMBx2+oZAAAAR5JREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbGujg3ZATZPKYdC6FQhPwlAMkg3dP
|
||||
WQwhyWIyJIUW5NqyPb7oCVtIlhVTwYf8nv7/t2zJagel9KmqKsIACYL9RjI8UHz5zshougZr/AEvbxEP
|
||||
aZCDBY3VslixaJvX3wzkkDiOwbZtDRGA5vdNAg+TL27qgmt5XkBG/gTdAG7Gt+3PP9oOaEGFCVEC6rp+
|
||||
5g9MfM/c5e4OsEZMZkQEtGL5H2DdZ5JRArDwPA+iKII0TfkC9vroC9j5vq8JTWw3WzWgLMtZGIaa0MR8
|
||||
vlAD8PYlSaIJTTiOowY0p0Bc19XEJo6HE59FAPuMzyAINKGJ1XLFZxHALtMrnkBXOIQIIIQ8YvF/KrgB
|
||||
cMaRN0UdBBkAAAAASUVORK5CYII=
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton3.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
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==
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton4.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
|
||||
tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX
|
||||
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton5.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
|
||||
tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX
|
||||
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton6.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
wwAADsMBx2+oZAAAAR5JREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbGujg3ZATZPKYdC6FQhPwlAMkg3dP
|
||||
WQwhyWIyJIUW5NqyPb7oCVtIlhVTwYf8nv7/t2zJagel9KmqKsIACYL9RjI8UHz5zshougZr/AEvbxEP
|
||||
aZCDBY3VslixaJvX3wzkkDiOwbZtDRGA5vdNAg+TL27qgmt5XkBG/gTdAG7Gt+3PP9oOaEGFCVEC6rp+
|
||||
5g9MfM/c5e4OsEZMZkQEtGL5H2DdZ5JRArDwPA+iKII0TfkC9vroC9j5vq8JTWw3WzWgLMtZGIaa0MR8
|
||||
vlAD8PYlSaIJTTiOowY0p0Bc19XEJo6HE59FAPuMzyAINKGJ1XLFZxHALtMrnkBXOIQIIIQ8YvF/KrgB
|
||||
cMaRN0UdBBkAAAAASUVORK5CYII=
|
||||
</value>
|
||||
</data>
|
||||
<metadata name="TP_FPS_BITRATE.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>False</value>
|
||||
</metadata>
|
||||
<data name="ActionButton7.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
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
|
||||
tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX
|
||||
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton8.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
@@ -364,6 +429,76 @@
|
||||
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
|
||||
tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX
|
||||
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton12.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
wwAADsMBx2+oZAAAAR5JREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbGujg3ZATZPKYdC6FQhPwlAMkg3dP
|
||||
WQwhyWIyJIUW5NqyPb7oCVtIlhVTwYf8nv7/t2zJagel9KmqKsIACYL9RjI8UHz5zshougZr/AEvbxEP
|
||||
aZCDBY3VslixaJvX3wzkkDiOwbZtDRGA5vdNAg+TL27qgmt5XkBG/gTdAG7Gt+3PP9oOaEGFCVEC6rp+
|
||||
5g9MfM/c5e4OsEZMZkQEtGL5H2DdZ5JRArDwPA+iKII0TfkC9vroC9j5vq8JTWw3WzWgLMtZGIaa0MR8
|
||||
vlAD8PYlSaIJTTiOowY0p0Bc19XEJo6HE59FAPuMzyAINKGJ1XLFZxHALtMrnkBXOIQIIIQ8YvF/KrgB
|
||||
cMaRN0UdBBkAAAAASUVORK5CYII=
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton13.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
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==
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton14.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
|
||||
tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX
|
||||
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton15.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
wwAADsMBx2+oZAAAAR5JREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbGujg3ZATZPKYdC6FQhPwlAMkg3dP
|
||||
WQwhyWIyJIUW5NqyPb7oCVtIlhVTwYf8nv7/t2zJagel9KmqKsIACYL9RjI8UHz5zshougZr/AEvbxEP
|
||||
aZCDBY3VslixaJvX3wzkkDiOwbZtDRGA5vdNAg+TL27qgmt5XkBG/gTdAG7Gt+3PP9oOaEGFCVEC6rp+
|
||||
5g9MfM/c5e4OsEZMZkQEtGL5H2DdZ5JRArDwPA+iKII0TfkC9vroC9j5vq8JTWw3WzWgLMtZGIaa0MR8
|
||||
vlAD8PYlSaIJTTiOowY0p0Bc19XEJo6HE59FAPuMzyAINKGJ1XLFZxHALtMrnkBXOIQIIIQ8YvF/KrgB
|
||||
cMaRN0UdBBkAAAAASUVORK5CYII=
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton16.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
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==
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton17.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
|
||||
tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX
|
||||
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -26,11 +26,17 @@ Namespace API.YouTube.Controls
|
||||
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 Const ControlsRow As Integer = 6
|
||||
Private Const ControlsRow As Integer = 7
|
||||
Private ReadOnly Property CNT_PROCESSOR As TableControlsProcessor
|
||||
Friend Property MyContainer As YouTubeMediaContainerBase
|
||||
Private Initialization As Boolean = True
|
||||
Private ReadOnly InheritsFromContainer As Boolean
|
||||
Private ReadOnly M3U8Files As List(Of SFile)
|
||||
Private ReadOnly Property M3U8FilesFull As List(Of SFile)
|
||||
Get
|
||||
Return ListAddList(Nothing, M3U8Files, LAP.NotContainsOnly).ListAddValue(CMB_PLS.Text, LAP.NotContainsOnly)
|
||||
End Get
|
||||
End Property
|
||||
Private Class FpsFieldChecker : Inherits FieldsCheckerProviderBase
|
||||
Private ReadOnly MyProvider As ANumbers = YouTubeSettings.FpsFormatProvider.MyProviderDefault
|
||||
Public Overrides Property ErrorMessage As String
|
||||
@@ -54,6 +60,7 @@ Namespace API.YouTube.Controls
|
||||
#Region "Initializers"
|
||||
Friend Sub New(ByVal Container As YouTubeMediaContainerBase, Optional ByVal InheritsFromContainer As Boolean = False)
|
||||
InitializeComponent()
|
||||
M3U8Files = New List(Of SFile)
|
||||
MyContainer = Container
|
||||
CNT_PROCESSOR = New TableControlsProcessor(TP_CONTROLS)
|
||||
Me.InheritsFromContainer = InheritsFromContainer
|
||||
@@ -69,6 +76,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
|
||||
@@ -155,11 +164,16 @@ Namespace API.YouTube.Controls
|
||||
|
||||
If InheritsFromContainer Then
|
||||
If .OutputVideoFPS > 0 Then TXT_FPS.Text = .OutputVideoFPS
|
||||
If .OutputAudioBitrate > 0 Then TXT_AUDIO_BITRATE.Text = .OutputAudioBitrate
|
||||
Else
|
||||
If MyYouTubeSettings.DefaultVideoFPS > 0 Then TXT_FPS.Text = MyYouTubeSettings.DefaultVideoFPS
|
||||
If MyYouTubeSettings.DefaultAudioBitrate > 0 Then TXT_AUDIO_BITRATE.Text = MyYouTubeSettings.DefaultAudioBitrate.Value
|
||||
End If
|
||||
MyFieldsChecker.AddControl(Of Double)(TXT_FPS, TXT_FPS.CaptionText, True, New FpsFieldChecker)
|
||||
MyFieldsChecker.EndLoaderOperations()
|
||||
With MyFieldsChecker
|
||||
.AddControl(Of Double)(TXT_FPS, TXT_FPS.CaptionText, True, New FpsFieldChecker)
|
||||
.AddControl(Of Integer)(TXT_AUDIO_BITRATE, TXT_AUDIO_BITRATE.CaptionText, True)
|
||||
.EndLoaderOperations()
|
||||
End With
|
||||
TP_SUBS.Enabled = .Subtitles.Count > 0
|
||||
TXT_SUBS_ADDIT.Enabled = .Subtitles.Count > 0
|
||||
RefillTextBoxes()
|
||||
@@ -180,6 +194,7 @@ Namespace API.YouTube.Controls
|
||||
Private Sub VideoOptionsForm_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
|
||||
MyView.DisposeIfReady()
|
||||
MyFieldsChecker.DisposeIfReady()
|
||||
M3U8Files.Clear()
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Refill"
|
||||
@@ -313,9 +328,11 @@ Namespace API.YouTube.Controls
|
||||
ControlInvokeFast(TP_CONTROLS, Sub()
|
||||
With DirectCast(Container, YouTubeMediaContainerBase)
|
||||
.File = $"{TXT_FILE.Text.CSFilePS}{ .File.File}"
|
||||
.M3U8_PlaylistFiles = M3U8FilesFull
|
||||
If Full Then
|
||||
.OutputVideoExtension = CMB_FORMAT.Text.StringToLower
|
||||
.OutputVideoFPS = AConvert(Of Double)(TXT_FPS.Text, YouTubeSettings.FpsFormatProvider.MyProviderDefault, -1)
|
||||
.OutputAudioBitrate = AConvert(Of Integer)(TXT_AUDIO_BITRATE.Text, -1)
|
||||
.OutputAudioCodec = CMB_AUDIO_CODEC.Text.StringToLower
|
||||
.OutputSubtitlesFormat = CMB_SUBS_FORMAT.Text.StringToLower
|
||||
.IsAudioSelected = OPT_AUDIO.Checked
|
||||
@@ -335,12 +352,15 @@ Namespace API.YouTube.Controls
|
||||
Else
|
||||
f = TXT_FILE.Text
|
||||
End If
|
||||
f = CleanFileName(f)
|
||||
If f.IsEmptyString Then Throw New ArgumentNullException("File", "The output file cannot be null")
|
||||
With MyContainer
|
||||
.OutputVideoExtension = CMB_FORMAT.Text.StringToLower
|
||||
.OutputVideoFPS = AConvert(Of Double)(TXT_FPS.Text, YouTubeSettings.FpsFormatProvider.MyProviderDefault, -1)
|
||||
.OutputAudioBitrate = AConvert(Of Integer)(TXT_AUDIO_BITRATE.Text, -1)
|
||||
.OutputAudioCodec = CMB_AUDIO_CODEC.Text.StringToLower
|
||||
.OutputSubtitlesFormat = CMB_SUBS_FORMAT.Text.StringToLower
|
||||
.M3U8_PlaylistFiles = M3U8FilesFull
|
||||
|
||||
If Not .HasElements Then
|
||||
Dim cntIndex% = -1
|
||||
@@ -357,6 +377,7 @@ Namespace API.YouTube.Controls
|
||||
Else
|
||||
.SelectedVideoIndex = -1
|
||||
.SelectedAudioIndex = cntIndex
|
||||
.MediaType = UMTypes.Audio
|
||||
End If
|
||||
.FileSetManually = True
|
||||
.File = f
|
||||
@@ -367,6 +388,7 @@ Namespace API.YouTube.Controls
|
||||
Else
|
||||
If OPT_AUDIO.Checked Then
|
||||
.SetMaxResolution(-2)
|
||||
.MediaType = UMTypes.Audio
|
||||
Else
|
||||
.SetMaxResolution(NUM_RES.Value)
|
||||
End If
|
||||
@@ -377,6 +399,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 +532,42 @@ Namespace API.YouTube.Controls
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Footer"
|
||||
Private Sub CMB_PLS_ActionOnButtonClick(ByVal Sender As Object, ByVal e As ActionButtonEventArgs) Handles CMB_PLS.ActionOnButtonClick
|
||||
Select Case e.DefaultButton
|
||||
Case ADB.List
|
||||
Dim result As Boolean = False
|
||||
Dim selectedFiles As IEnumerable(Of SFile) = MyYouTubeSettings.PlaylistsLocations.ChooseNewPlaylistArray(CMB_PLS, result)
|
||||
If result And selectedFiles.ListExists Then M3U8Files.ListAddList(selectedFiles, LAP.NotContainsOnly, LAP.ClearBeforeAdd)
|
||||
Case ADB.Save
|
||||
With MyYouTubeSettings.PlaylistsLocations
|
||||
If Not CMB_PLS.Text.IsEmptyString AndAlso .IndexOf(CMB_PLS.Text,, True) = -1 Then
|
||||
.Add(CMB_PLS.Text, True, True)
|
||||
.PopulateComboBox(CMB_PLS, CMB_PLS.Text, True)
|
||||
End If
|
||||
End With
|
||||
Case ADB.Clear : M3U8Files.Clear()
|
||||
End Select
|
||||
End Sub
|
||||
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
|
||||
@@ -529,6 +589,14 @@ Namespace API.YouTube.Controls
|
||||
_FilePathBeforeItemChange = Nothing
|
||||
End Try
|
||||
End Sub
|
||||
Private Sub TXT_FILE_ActionOnButtonClick(ByVal Sender As Object, ByVal e As ActionButtonEventArgs) Handles TXT_FILE.ActionOnButtonClick
|
||||
If e.DefaultButton = ADB.Save And Not TXT_FILE.Text.IsEmptyString Then
|
||||
With MyYouTubeSettings.PlaylistsLocations
|
||||
.Add(TXT_FILE.Text, True)
|
||||
.PopulateComboBox(TXT_FILE, TXT_FILE.Text)
|
||||
End With
|
||||
End If
|
||||
End Sub
|
||||
Private Sub BTT_BROWSE_MouseDown(sender As Object, e As MouseEventArgs) Handles BTT_BROWSE.MouseDown
|
||||
Dim f As SFile
|
||||
#Disable Warning BC40000
|
||||
@@ -537,12 +605,15 @@ Namespace API.YouTube.Controls
|
||||
f = SFile.SelectPath(f, "Select the destination of the video files", EDP.ReturnValue)
|
||||
Else
|
||||
f = TXT_FILE.Text
|
||||
Dim sPattern$ = $"Video|{AvailableVideoFormats.Select(Function(vf) $"*.{vf.ToLower}").ListToString(";")}" &
|
||||
$"|Audio|{AvailableAudioFormats.Select(Function(af) $"*.{af.ToLower}").ListToString(";")}" &
|
||||
"|All Files|*.*"
|
||||
f = SFile.SaveAs(f, "Select the destination of the video file",,, sPattern, EDP.ReturnValue)
|
||||
Dim ext$ = f.Extension
|
||||
Dim sPattern$ = "All Files|*.*|" &
|
||||
$"Video|{AvailableVideoFormats.Select(Function(vf) $"*.{vf.ToLower}").ListToString(";")}" &
|
||||
$"|Audio|{AvailableAudioFormats.Select(Function(af) $"*.{af.ToLower}").ListToString(";")}"
|
||||
f = SFile.SaveAs(f, "Select the destination of the video file",, ext, sPattern, EDP.ReturnValue)
|
||||
f.Extension = ext
|
||||
End If
|
||||
#Enable Warning
|
||||
f = CleanFileName(f)
|
||||
If Not f.IsEmptyString Then
|
||||
If e.Button = MouseButtons.Right Then
|
||||
MyYouTubeSettings.DownloadLocations.Add(f, MyDownloaderSettings.OutputPathAskForName)
|
||||
|
||||
@@ -17,10 +17,21 @@ Namespace API.YouTube
|
||||
Public Const DownloaderDataFolderYouTube As String = DownloadObjects.STDownloader.DownloaderDataFolder & "YouTube\"
|
||||
Friend Const YouTubeDownloadPathDefault As String = "YouTubeDownloads\"
|
||||
Friend Const SimpleArraysFormNode As String = "SimpleFormatsChooserForm"
|
||||
Private Const YTDLP_DefaultName As String = "yt-dlp"
|
||||
Public Property MyYouTubeSettings As Base.YouTubeSettings
|
||||
Public Property MyCache As CacheKeeper
|
||||
Friend ReadOnly Property MyCacheSettings As New CacheKeeper(DownloaderDataFolderYouTube) With {.DeleteCacheOnDispose = False, .DeleteRootOnDispose = False}
|
||||
Public ReadOnly Property YouTubeCookieNetscapeFile As New SFile($"Settings\Responser_{YouTubeSite}_Cookies_Netscape.txt")
|
||||
Friend ReadOnly Property YTDLP_NAME As String
|
||||
Get
|
||||
Dim n$ = MyYouTubeSettings.YTDLP.Value.Name
|
||||
If Not n.IsEmptyString Then
|
||||
Return If(n.ToLower = YTDLP_DefaultName, n, $"""{n}""")
|
||||
Else
|
||||
Return YTDLP_DefaultName
|
||||
End If
|
||||
End Get
|
||||
End Property
|
||||
Friend ReadOnly Property AvailableSubtitlesFormats As String()
|
||||
Get
|
||||
Return {"ASS", "LRC", "SRT", "VTT"}
|
||||
@@ -45,6 +56,19 @@ Namespace API.YouTube
|
||||
Friend ReadOnly TitleHtmlConverter As Func(Of String, String) = Function(Input) Input.StringRemoveWinForbiddenSymbols().StringTrim()
|
||||
Friend ReadOnly ProgressProvider As IMyProgressNumberProvider = MyProgressNumberProvider.Percentage
|
||||
Public ReadOnly TrueUrlRegEx As RParams = RParams.DM(Base.YouTubeFunctions.TrueUrlPattern, 0, EDP.ReturnValue)
|
||||
Friend Function CleanFileName(ByVal f As SFile) As SFile
|
||||
If Not f.IsEmptyString And Not f.Name.IsEmptyString Then
|
||||
Dim ff As SFile = f
|
||||
ff.Name = ff.Name.StringRemoveWinForbiddenSymbols.StringTrim
|
||||
ff.Name = ff.Name.StringTrimEnd(".")
|
||||
If Not ff.Name.IsEmptyString And Not MyYouTubeSettings.FileRemoveCharacters.IsEmptyString Then _
|
||||
ff.Name = ff.Name.StringReplaceSymbols(MyYouTubeSettings.FileRemoveCharacters.Value.AsList.ListCast(Of String).ToArray, String.Empty, EDP.ReturnValue)
|
||||
If ff.Name.IsEmptyString Then ff.Name = "file"
|
||||
Return ff
|
||||
Else
|
||||
Return f
|
||||
End If
|
||||
End Function
|
||||
Private Class TimeToStringConverter : Implements ICustomProvider
|
||||
Private ReadOnly _Provider As New ADateTime("mm\:ss") With {.TimeParseMode = ADateTime.TimeModes.TimeSpan}
|
||||
Private ReadOnly _ProviderWithHours As New ADateTime("h\:mm\:ss") With {.TimeParseMode = ADateTime.TimeModes.TimeSpan}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
Imports PersonalUtilities.Functions.XML
|
||||
Imports PersonalUtilities.Functions.XML.Base
|
||||
Imports PersonalUtilities.Functions.XML.Attributes
|
||||
Imports PersonalUtilities.Forms
|
||||
Imports PersonalUtilities.Forms.Controls
|
||||
Imports PersonalUtilities.Forms.Controls.Base
|
||||
Imports PersonalUtilities.Tools
|
||||
@@ -103,7 +104,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 +125,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
|
||||
@@ -141,6 +142,44 @@ Namespace DownloadObjects.STDownloader
|
||||
End If
|
||||
Return f
|
||||
End Function
|
||||
Friend Function ChooseNewPlaylistArray(ByRef CMB As ComboBoxExtended, ByRef Result As Boolean) As IEnumerable(Of SFile)
|
||||
Try
|
||||
Dim initFiles As IEnumerable(Of SFile) = Nothing
|
||||
Dim selectedFiles As IEnumerable(Of SFile) = Nothing
|
||||
If Count > 0 Then initFiles = Me.Select(Function(l) l.Path.CSFile)
|
||||
Dim addh As New EventHandler(Of SimpleListFormEventArgs)(Sub(ByVal s As Object, ByVal ee As SimpleListFormEventArgs)
|
||||
Dim ff As List(Of SFile) = SFile.SelectFiles(,, "Select playlist files", "Playlist|*.m3u;*.m3u8|AllFiles|*.*", EDP.ReturnValue)
|
||||
If ff.ListExists Then
|
||||
ee.AddItem(ff.Cast(Of Object))
|
||||
ee.Result = True
|
||||
Else
|
||||
ee.Result = False
|
||||
End If
|
||||
End Sub)
|
||||
Using f As New SimpleListForm(Of SFile)(initFiles, API.YouTube.MyYouTubeSettings.DesignXml) With {
|
||||
.DesignXMLNodeName = "M3U8SelectorForm",
|
||||
.FormText = "Playlists",
|
||||
.Buttons = {ActionButton.DefaultButtons.Add},
|
||||
.Icon = ImageRenderer.GetIcon(My.Resources.StartPic_Green_16, EDP.ReturnValue),
|
||||
.AddFunction = addh
|
||||
}
|
||||
If f.ShowDialog = DialogResult.OK Then Result = True : selectedFiles = ListAddList(Nothing, f.DataResult, LAP.NotContainsOnly)
|
||||
End Using
|
||||
If selectedFiles.ListExists Then
|
||||
Dim added As Boolean = False
|
||||
selectedFiles.ListForEach(Sub(ByVal plsFile As SFile, ByVal ii As Integer)
|
||||
If IndexOf(plsFile.ToString,, True) = -1 Then Add(plsFile.ToString, True, True) : added = True
|
||||
End Sub)
|
||||
If added Then PopulateComboBox(CMB, selectedFiles(0).ToString, True)
|
||||
CMB.Text = selectedFiles(0)
|
||||
Return selectedFiles
|
||||
Else
|
||||
Return Nothing
|
||||
End If
|
||||
Catch ex As Exception
|
||||
Return ErrorsDescriber.Execute(EDP.LogMessageValue, ex, "Select playlist array")
|
||||
End Try
|
||||
End Function
|
||||
Private Sub Update()
|
||||
If Locations.Count > 0 Then
|
||||
Using x As New XmlFile With {.AllowSameNames = True}
|
||||
@@ -158,9 +197,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 +222,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
|
||||
|
||||
@@ -12,6 +12,7 @@ Imports SCrawler.API.YouTube.Objects
|
||||
Imports SCrawler.API.YouTube.Controls
|
||||
Imports PersonalUtilities.Tools
|
||||
Imports PersonalUtilities.Forms.Toolbars
|
||||
Imports PersonalUtilities.Functions.Messaging
|
||||
Namespace DownloadObjects.STDownloader
|
||||
Public Delegate Sub MediaItemEventHandler(ByVal Sender As MediaItem, ByVal Container As IYouTubeMediaContainer)
|
||||
<DefaultEvent("DoubleClick"), DesignTimeVisible(False), ToolboxItem(False)>
|
||||
@@ -135,7 +136,7 @@ Namespace DownloadObjects.STDownloader
|
||||
LBL_TITLE.Text = .ToString(True)
|
||||
If Not .SiteKey = YouTubeSiteKey And .ContentType = Plugin.UserMediaTypes.Picture Then
|
||||
LBL_INFO.Text = .File.Extension.StringToUpper
|
||||
ElseIf Not .IsMusic Then
|
||||
ElseIf Not .IsMusic And Not (.MediaType = Plugin.UserMediaTypes.Audio Or .MediaType = Plugin.UserMediaTypes.AudioPre) Then
|
||||
If .Height > 0 Then
|
||||
LBL_INFO.Text = $"{ .File.Extension.StringToUpper}{d}{ .Height}p"
|
||||
Else
|
||||
@@ -180,10 +181,10 @@ Namespace DownloadObjects.STDownloader
|
||||
With MyContainer
|
||||
If Not .SiteKey = YouTubeSiteKey And .ContentType = Plugin.UserMediaTypes.Picture Then
|
||||
ICON_WHAT.Image = My.Resources.ImagePic_32
|
||||
ElseIf Not .IsMusic Then
|
||||
ICON_WHAT.Image = My.Resources.VideoCamera_32
|
||||
Else
|
||||
ElseIf .IsMusic Or .MediaType = Plugin.UserMediaTypes.Audio Or .MediaType = Plugin.UserMediaTypes.AudioPre Then
|
||||
ICON_WHAT.Image = My.Resources.AudioMusic_32
|
||||
Else
|
||||
ICON_WHAT.Image = My.Resources.VideoCamera_32
|
||||
End If
|
||||
End With
|
||||
End Sub, EDP.None)
|
||||
@@ -229,7 +230,7 @@ Namespace DownloadObjects.STDownloader
|
||||
.ColumnStyles.Clear()
|
||||
.ColumnCount = 0
|
||||
If ContainerHasElements Or MyContainer.MediaState = Plugin.UserMediaStates.Downloaded Then
|
||||
If Not MyContainer.SiteKey = YouTubeSiteKey Then UpdateMediaIcon()
|
||||
UpdateMediaIcon()
|
||||
If ContainerHasElements Then
|
||||
BTT_OPEN_FOLDER.Visible = False
|
||||
BTT_OPEN_FILE.Visible = False
|
||||
@@ -476,12 +477,28 @@ Namespace DownloadObjects.STDownloader
|
||||
RaiseEvent Removal(Me, MyContainer)
|
||||
End Sub
|
||||
Private Sub BTT_DELETE_FILE_Click(sender As Object, e As EventArgs) Handles BTT_DELETE_FILE.Click
|
||||
If MsgBoxE({$"Are you sure you want to delete the following {FileOption.ToString.ToLower}:{vbCr}" &
|
||||
If(FileOption = SFO.File, MyContainer.File.ToString, MyContainer.File.PathWithSeparator),
|
||||
$"Deleting a {FileOption.ToString.ToLower}"}, vbExclamation,,, {"Process", "Cancel"}) = 0 Then
|
||||
Dim opt$
|
||||
Dim opt2$ = String.Empty
|
||||
If FileOption = SFO.File Then
|
||||
opt = "file"
|
||||
Else
|
||||
opt = "item"
|
||||
opt2 = "THE ITEM MAY CONTAIN MULTIPLE FILES" & vbCr
|
||||
End If
|
||||
Dim b As New List(Of MsgBoxButton) From {New MsgBoxButton("Process")}
|
||||
If Not opt2.IsEmptyString Then _
|
||||
b.Add(New MsgBoxButton("Show files", "Show files to delete") With {
|
||||
.IsDialogResultButton = False,
|
||||
.CallBack = Function(r, m, bb) MsgBoxE(New MMessage($"The following files will be deleted:{vbCr}{vbCr}{MyContainer.Files.ListToString(vbCr)}",
|
||||
"Files to delete",, vbExclamation) With {.Editable = True})})
|
||||
b.Add(New MsgBoxButton("Cancel"))
|
||||
If MsgBoxE({$"Are you sure you want to delete the following {opt}:{vbCr}{opt2}" &
|
||||
If(FileOption = SFO.File, MyContainer.File.ToString, MyContainer.ToString(True)),
|
||||
$"Deleting {opt}"}, vbExclamation,,, b) = 0 Then
|
||||
MyContainer.Delete(True)
|
||||
RaiseEvent Removal(Me, MyContainer)
|
||||
End If
|
||||
b.Clear()
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "ISupportInitialize Support"
|
||||
|
||||
@@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices
|
||||
' by using the '*' as shown below:
|
||||
' <Assembly: AssemblyVersion("1.0.*")>
|
||||
|
||||
<Assembly: AssemblyVersion("2024.2.25.0")>
|
||||
<Assembly: AssemblyFileVersion("2024.2.25.0")>
|
||||
<Assembly: AssemblyVersion("2024.5.4.0")>
|
||||
<Assembly: AssemblyFileVersion("2024.5.4.0")>
|
||||
<Assembly: NeutralResourcesLanguage("en")>
|
||||
|
||||
@@ -19,17 +19,18 @@ Namespace API.YouTube.Objects
|
||||
Dim __title$ = $" - {Title}"
|
||||
If Not s.IsEmptyString Then s = $" [{s}]"
|
||||
If Not PlaylistTitle.IsEmptyString And Not ForMediaItem Then t = $"{PlaylistTitle} - "
|
||||
Dim c% = {Count, ElementsNumber}.Max
|
||||
If IsMusic Then
|
||||
If Count <= 1 Then t &= "Single" Else t &= "Album"
|
||||
If c <= 1 Then t &= "Single" Else t &= "Album"
|
||||
Else
|
||||
t &= "Playlist"
|
||||
End If
|
||||
If Not PlaylistTitle.IsEmptyString And Not ForMediaItem Then t &= $" - {PlaylistTitle}"
|
||||
If PlaylistTitle = Title Then __title = String.Empty
|
||||
If ForMediaItem Then
|
||||
Return $"{t} ({Count}){__title}"
|
||||
Return $"{t} ({c}){__title}"
|
||||
Else
|
||||
Return $"{t} ({Count}){__title} ({AConvert(Of String)(Duration, TimeToStringProvider)}){s}"
|
||||
Return $"{t} ({c}){__title} ({AConvert(Of String)(Duration, TimeToStringProvider)}){s}"
|
||||
End If
|
||||
End Function
|
||||
Public Overrides Function Parse(ByVal Container As EContainer, ByVal Path As SFile, ByVal IsMusic As Boolean,
|
||||
|
||||
@@ -27,6 +27,7 @@ Namespace API.YouTube.Objects
|
||||
Else
|
||||
_File.Extension = mp3
|
||||
End If
|
||||
_File = CleanFileName(_File)
|
||||
End If
|
||||
End Sub
|
||||
Public Overrides Function ToString(ByVal ForMediaItem As Boolean) As String
|
||||
@@ -46,12 +47,17 @@ Namespace API.YouTube.Objects
|
||||
_ObjectType = Base.YouTubeMediaType.Single
|
||||
Me.IsMusic = IsMusic
|
||||
If MyBase.Parse(Container, Path, IsMusic, Token, Progress) Then
|
||||
Dim f As SFile = MyYouTubeSettings.OutputPath
|
||||
If f.IsEmptyString Then f = "YouTubeDownloads\OutputFile.mp3"
|
||||
Dim ext$ = MyYouTubeSettings.DefaultAudioCodec.Value.StringToLower
|
||||
If ext.IsEmptyString Then ext = "mp3"
|
||||
f.Extension = ext
|
||||
File = f
|
||||
With MyYouTubeSettings
|
||||
Dim f As SFile = .OutputPath
|
||||
If f.IsEmptyString Then f = "YouTubeDownloads\OutputFile.mp3"
|
||||
Dim ext$ = .DefaultAudioCodecMusic.Value.StringToLower.IfNullOrEmpty(.DefaultAudioCodec.Value.StringToLower)
|
||||
If ext.IsEmptyString Then ext = "mp3"
|
||||
f.Extension = ext
|
||||
'If f.Name.IsEmptyString Then f.Name = File.Name
|
||||
File = f
|
||||
If _File.Extension.IsEmptyString Then _File.Extension = ext
|
||||
_File = CleanFileName(_File)
|
||||
End With
|
||||
Return True
|
||||
Else
|
||||
Return False
|
||||
|
||||
@@ -123,6 +123,15 @@ Namespace API.YouTube.Objects
|
||||
<XMLEC> Public Property UserTitle As String Implements IYouTubeMediaContainer.UserTitle
|
||||
#End Region
|
||||
#Region "Playlist support"
|
||||
Private _ElementsNumber As Integer = 0
|
||||
<XMLEC> Protected Property ElementsNumber As Integer
|
||||
Get
|
||||
Return If(HasElements, Count, _ElementsNumber)
|
||||
End Get
|
||||
Set(ByVal _ElementsNumber As Integer)
|
||||
Me._ElementsNumber = _ElementsNumber
|
||||
End Set
|
||||
End Property
|
||||
Friend ReadOnly Property Elements As List(Of IYouTubeMediaContainer) Implements IYouTubeMediaContainer.Elements
|
||||
Friend ReadOnly Property HasElements As Boolean Implements IYouTubeMediaContainer.HasElements
|
||||
Get
|
||||
@@ -265,6 +274,18 @@ Namespace API.YouTube.Objects
|
||||
PostProcessing_OutputAudioFormats.RemoveAll(Function(s) s = -1)
|
||||
End If
|
||||
End Sub
|
||||
<XMLEC("OutputAudioBitrate")> Protected _OutputAudioBitrate As Integer = -1
|
||||
Friend Property OutputAudioBitrate As Integer
|
||||
Get
|
||||
Return _OutputAudioBitrate
|
||||
End Get
|
||||
Set(ByVal NewBitrate As Integer)
|
||||
If Not [Protected] Then
|
||||
_OutputAudioBitrate = NewBitrate
|
||||
If HasElements Then Elements.ForEach(Sub(elem) DirectCast(elem, YouTubeMediaContainerBase).OutputAudioBitrate = NewBitrate)
|
||||
End If
|
||||
End Set
|
||||
End Property
|
||||
#End Region
|
||||
#Region "Subtitles"
|
||||
Protected ReadOnly _Subtitles As List(Of Subtitles)
|
||||
@@ -376,10 +397,13 @@ Namespace API.YouTube.Objects
|
||||
End Set
|
||||
End Property
|
||||
Protected _Size As Integer = 0
|
||||
<XMLEC("SizeRecalculated")> Protected _SizeRecalculated As Boolean = False
|
||||
<XMLEC> Public Overridable Property Size As Integer Implements IDownloadableMedia.Size
|
||||
Get
|
||||
If HasElements Then
|
||||
Return Elements.Sum(Function(e) If(e.Checked, e.Size, 0))
|
||||
ElseIf _SizeRecalculated Then
|
||||
Return _Size
|
||||
Else
|
||||
If Checked Then
|
||||
If IsMusic And SelectedAudioIndex.ValueBetween(0, MediaObjects.Count - 1) Then
|
||||
@@ -559,7 +583,25 @@ Namespace API.YouTube.Objects
|
||||
If ObjectType = YouTubeMediaType.Single AndAlso Not GetPlayListTitle.IsEmptyString Then _SpecialPath.StringAppend(GetPlayListTitle(), "\")
|
||||
If Elements.Count > 0 Then Elements.ForEach(Sub(e) e.SpecialFolder = Path)
|
||||
End Sub
|
||||
<XMLEC> Protected Friend ReadOnly Property Files As List(Of SFile) Implements IYouTubeMediaContainer.Files
|
||||
Private ReadOnly _Files As List(Of SFile)
|
||||
<XMLEC> Protected Friend Property Files As List(Of SFile) Implements IYouTubeMediaContainer.Files
|
||||
Get
|
||||
If HasElements Then
|
||||
Return GetFilesFiles()
|
||||
Else
|
||||
Return _Files
|
||||
End If
|
||||
End Get
|
||||
Set(ByVal f As List(Of SFile))
|
||||
_Files.ListAddList(f, LAP.NotContainsOnly)
|
||||
End Set
|
||||
End Property
|
||||
Protected Overloads Sub AddFile(ByVal f As SFile)
|
||||
_Files.ListAddValue(f, LAP.NotContainsOnly)
|
||||
End Sub
|
||||
Protected Overloads Sub AddFile(ByVal f As IEnumerable(Of SFile))
|
||||
_Files.ListAddList(f, LAP.NotContainsOnly)
|
||||
End Sub
|
||||
<XMLEC> Protected _File As SFile
|
||||
<XMLEC> Protected Friend Property FileSetManually As Boolean = False
|
||||
Public Property FileIgnorePlaylist As Boolean = False
|
||||
@@ -628,6 +670,26 @@ 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 Function GetFilesFiles() As IEnumerable(Of SFile)
|
||||
Dim f As New List(Of SFile)
|
||||
If File.Exists Then f.Add(File)
|
||||
If _Files.Count > 0 Then f.AddRange(_Files)
|
||||
If ThumbnailFile.Exists Then f.Add(ThumbnailFile)
|
||||
If HasElements Then f.ListAddList(Elements.SelectMany(Function(elem As YouTubeMediaContainerBase) elem.GetFilesFiles()), LAP.NotContainsOnly)
|
||||
Return f
|
||||
End Function
|
||||
Private _M3U8_PlaylistFiles As IEnumerable(Of SFile) = Nothing
|
||||
Friend Property M3U8_PlaylistFiles As IEnumerable(Of SFile)
|
||||
Get
|
||||
Return _M3U8_PlaylistFiles
|
||||
End Get
|
||||
Set(ByVal f As IEnumerable(Of SFile))
|
||||
If Not [Protected] Then
|
||||
_M3U8_PlaylistFiles = f
|
||||
If HasElements Then Elements.ForEach(Sub(e As YouTubeMediaContainerBase) e.M3U8_PlaylistFiles = f)
|
||||
End If
|
||||
End Set
|
||||
End Property
|
||||
#End Region
|
||||
#Region "Command"
|
||||
<XMLEC> Public Property UseCookies As Boolean = MyYouTubeSettings.DefaultUseCookies Implements IYouTubeMediaContainer.UseCookies
|
||||
@@ -635,6 +697,7 @@ Namespace API.YouTube.Objects
|
||||
Private Const aac As String = "aac"
|
||||
Private Const ac3 As String = "ac3"
|
||||
Protected PostProcessing_AudioAC3 As Boolean = False
|
||||
Protected PostProcessing_AudioMP3 As Boolean = False
|
||||
Public Overridable ReadOnly Property Command(ByVal WithCookies As Boolean) As String Implements IYouTubeMediaContainer.Command
|
||||
Get
|
||||
If Not File.IsEmptyString Then
|
||||
@@ -646,7 +709,7 @@ Namespace API.YouTube.Objects
|
||||
Bitrate = 0
|
||||
_MediaType = UMTypes.Undefined
|
||||
If SelectedVideoIndex >= 0 Then
|
||||
'URGENT: 2023.3.4 -> 2023.7.6
|
||||
'2023.3.4 -> 2023.7.6
|
||||
'cmd.StringAppend($"bv*[format_id={SelectedVideo.ID}]")
|
||||
cmd.StringAppend(SelectedVideo.ID)
|
||||
_Size = SelectedVideo.Size
|
||||
@@ -663,13 +726,17 @@ Namespace API.YouTube.Objects
|
||||
End If
|
||||
If SelectedAudioIndex >= 0 Then
|
||||
Dim atCodec$
|
||||
'URGENT: 2023.3.4 -> 2023.7.6
|
||||
'2023.3.4 -> 2023.7.6
|
||||
'cmd.StringAppend($"ba*[format_id={SelectedAudio.ID}]", "+")
|
||||
cmd.StringAppend(SelectedAudio.ID, "+")
|
||||
If OutputAudioCodec.StringToLower = ac3 Then
|
||||
PostProcessing_AudioAC3 = True
|
||||
formats.StringAppend($"--audio-format {aac}", " ")
|
||||
atCodec = aac
|
||||
ElseIf SelectedVideoIndex >= 0 And OutputAudioCodec.StringToLower = mp3 Then
|
||||
PostProcessing_AudioMP3 = True
|
||||
formats.StringAppend($"--audio-format {aac}", " ")
|
||||
atCodec = aac
|
||||
Else
|
||||
formats.StringAppend($"--audio-format {OutputAudioCodec.StringToLower}", " ")
|
||||
atCodec = OutputAudioCodec.StringToLower
|
||||
@@ -702,9 +769,10 @@ Namespace API.YouTube.Objects
|
||||
subs = $"--write-subs --write-auto-subs --sub-format {OutputSubtitlesFormat.StringToLower} --sub-langs ""{subs}"" --convert-subs {OutputSubtitlesFormat.StringToLower}"
|
||||
End If
|
||||
If Not cmd.IsEmptyString Then
|
||||
'URGENT: 2023.3.4 -> 2023.7.6
|
||||
'2023.3.4 -> 2023.7.6
|
||||
'cmd = $"yt-dlp -f ""{cmd}"""
|
||||
cmd = $"yt-dlp -f {cmd}"
|
||||
'cmd = $"yt-dlp -f {cmd}"
|
||||
cmd = $"{YTDLP_NAME} -f {cmd}"
|
||||
If Not MyYouTubeSettings.ReplaceModificationDate Then cmd &= " --no-mtime"
|
||||
cmd.StringAppend(formats, " ")
|
||||
cmd.StringAppend(subs, " ")
|
||||
@@ -726,7 +794,7 @@ Namespace API.YouTube.Objects
|
||||
_SubtitlesDelegated = New List(Of Subtitles)
|
||||
SubtitlesSelectedIndexes = New List(Of Integer)
|
||||
MediaObjects = New List(Of MediaObject)
|
||||
Files = New List(Of SFile)
|
||||
_Files = New List(Of SFile)
|
||||
|
||||
PostProcessing_OutputSubtitlesFormats = New List(Of String)
|
||||
PostProcessing_OutputSubtitlesFormats.ListAddList(MyYouTubeSettings.DefaultSubtitlesFormatAddit)
|
||||
@@ -755,9 +823,19 @@ Namespace API.YouTube.Objects
|
||||
If RemoveFiles Then
|
||||
Dim fErr As New ErrorsDescriber(EDP.None)
|
||||
Dim dMode As SFODelete = SFODelete.DeleteToRecycleBin
|
||||
Dim paths As New List(Of SFile)
|
||||
Dim l As New ListAddParams(LAP.NotContainsOnly) With {.Comparer = New FComparer(Of SFile)(Function(x, y) x.PathNoSeparator = y.PathNoSeparator)}
|
||||
Dim isArr As Boolean = ObjectType <> YouTubeMediaType.Single And ObjectType <> YouTubeMediaType.Undefined
|
||||
If isArr And AbsolutePath Then paths.ListAddValue(File, l)
|
||||
File.Delete(SFO.File, dMode, fErr)
|
||||
If isArr Then paths.ListAddValue(ThumbnailFile, l)
|
||||
ThumbnailFile.Delete(SFO.File, dMode, fErr)
|
||||
If Files.Count > 0 Then Files.ForEach(Sub(f) f.Delete(SFO.File, dMode, fErr))
|
||||
If Files.Count > 0 Then
|
||||
If isArr Then paths.ListAddList(Files, l)
|
||||
Files.ForEach(Sub(f) f.Delete(SFO.File, dMode, fErr))
|
||||
End If
|
||||
If paths.Count > 0 Then paths.ForEach(Sub(p) If SFile.GetFiles(p,, IO.SearchOption.AllDirectories, EDP.ReturnValue).Count = 0 Then _
|
||||
p.Delete(SFO.Path, dMode, EDP.SendToLog))
|
||||
End If
|
||||
If HasElements Then Elements.ForEach(Sub(e) e.Delete(RemoveFiles))
|
||||
End Sub
|
||||
@@ -788,6 +866,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 And .PlaylistIndex > 0 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 +917,32 @@ 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
|
||||
Dim f As SFile
|
||||
If MyYouTubeSettings.MusicPlaylistCreate_M3U8 Then
|
||||
t = New TextSaver
|
||||
t.AppendLine("#EXTM3U")
|
||||
Elements.ForEach(Sub(e) t.AppendLine(GetPlaylistRow(e)))
|
||||
f = $"{Elements(0).File.PathWithSeparator}Playlist.m3u8"
|
||||
t.SaveAs(f, EDP.SendToLog)
|
||||
If f.Exists Then AddFile(f)
|
||||
t.Dispose()
|
||||
End If
|
||||
If MyYouTubeSettings.MusicPlaylistCreate_M3U Then
|
||||
t = New TextSaver
|
||||
Elements.ForEach(Sub(e) t.AppendLine(e.File))
|
||||
f = $"{Elements(0).File.PathWithSeparator}Playlist.m3u"
|
||||
t.SaveAs(f, EDP.SendToLog)
|
||||
If f.Exists Then AddFile(f)
|
||||
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
|
||||
@@ -891,7 +1012,7 @@ Namespace API.YouTube.Objects
|
||||
ff.Name = "album"
|
||||
ff.Extension = "url"
|
||||
CreateUrlFile(url, ff)
|
||||
If ff.Exists Then Files.Add(ff)
|
||||
If ff.Exists Then AddFile(ff)
|
||||
End If
|
||||
If MyYouTubeSettings.CreateThumbnails_Music Then
|
||||
Using resp As New Responser
|
||||
@@ -917,7 +1038,7 @@ Namespace API.YouTube.Objects
|
||||
url = LinkFormatterSecure(u)
|
||||
f.Name = "cover"
|
||||
f.Extension = "jpg"
|
||||
If resp.DownloadFile(url, f, EDP.ReturnValue) And f.Exists Then CoverDownloaded = True
|
||||
If resp.DownloadFile(url, f, EDP.ReturnValue) And f.Exists Then CoverDownloaded = True : AddFile(f)
|
||||
End If
|
||||
End If
|
||||
End Using
|
||||
@@ -926,19 +1047,61 @@ Namespace API.YouTube.Objects
|
||||
ErrorsDescriber.Execute(EDP.SendToLog, ex, $"DownloadPlaylistCover({PlsId}, {f})")
|
||||
End Try
|
||||
End Sub
|
||||
Private Structure TempFileConversion
|
||||
Friend File As SFile
|
||||
Friend Requested As Boolean
|
||||
Friend ToReplace As Boolean
|
||||
Friend ReadOnly Property Exists As Boolean
|
||||
Get
|
||||
Return File.Exists
|
||||
End Get
|
||||
End Property
|
||||
Friend Sub Delete()
|
||||
If Not Requested Then File.Delete()
|
||||
End Sub
|
||||
Private Sub New(ByVal f As SFile)
|
||||
File = f
|
||||
Requested = False
|
||||
ToReplace = False
|
||||
End Sub
|
||||
Friend Sub New(ByVal f As SFile, ByVal Source As YouTubeMediaContainerBase)
|
||||
Me.New(f)
|
||||
Requested = Source.PostProcessing_OutputAudioFormats.Count > 0 AndAlso
|
||||
Source.PostProcessing_OutputAudioFormats.Exists(Function(af) af.StringToLower = f.Extension)
|
||||
End Sub
|
||||
Public Shared Widening Operator CType(ByVal f As SFile) As TempFileConversion
|
||||
Return New TempFileConversion(f)
|
||||
End Operator
|
||||
Public Shared Widening Operator CType(ByVal f As TempFileConversion) As SFile
|
||||
Return f.File
|
||||
End Operator
|
||||
Public Overrides Function Equals(ByVal Obj As Object) As Boolean
|
||||
If Not IsNothing(Obj) Then
|
||||
If TypeOf Obj Is TempFileConversion Then
|
||||
Return DirectCast(Obj, TempFileConversion).File = File
|
||||
ElseIf TypeOf Obj Is SFile Then
|
||||
Return DirectCast(Obj, SFile) = File
|
||||
ElseIf TypeOf Obj Is String Then
|
||||
Return New TempFileConversion(CStr(Obj)).File = File
|
||||
End If
|
||||
End If
|
||||
Return False
|
||||
End Function
|
||||
End Structure
|
||||
Protected Sub DownloadCommand(ByVal UseCookies As Boolean, ByVal Token As CancellationToken)
|
||||
Dim dCommand$ = String.Empty
|
||||
Try
|
||||
ThrowAny(Token)
|
||||
If MediaState = UMStates.Downloaded Or Not Checked Then Exit Sub
|
||||
Dim h As DataReceivedEventHandler = Sub(ByVal Sender As Object, ByVal e As DataReceivedEventArgs)
|
||||
If Not e.Data.IsEmptyString Then
|
||||
Dim v# = AConvert(Of Double)(RegexReplace(e.Data, DownloadProgressPattern), NumberProvider, -1)
|
||||
If v >= 0 Then Progress.Value = v : Progress.Perform(0)
|
||||
End If
|
||||
End Sub
|
||||
RaiseEvent FileDownloadStarted(Me, Nothing)
|
||||
Using batch As New BatchExecutor(True) With {.Encoding = 65001}
|
||||
Dim h As DataReceivedEventHandler = Sub(ByVal Sender As Object, ByVal e As DataReceivedEventArgs)
|
||||
If Not e.Data.IsEmptyString Then
|
||||
Dim v# = AConvert(Of Double)(RegexReplace(e.Data, DownloadProgressPattern), NumberProvider, -1)
|
||||
If v >= 0 Then Progress.Value = v : Progress.Perform(0)
|
||||
If Token.IsCancellationRequested Then batch.Kill()
|
||||
End If
|
||||
End Sub
|
||||
With batch
|
||||
Dim prExists As Boolean = Not Progress Is Nothing
|
||||
If prExists Then
|
||||
@@ -951,7 +1114,7 @@ Namespace API.YouTube.Objects
|
||||
.Information = $"Download {MediaType}"
|
||||
End With
|
||||
End If
|
||||
.MainProcessName = "yt-dlp"
|
||||
.MainProcessName = MyYouTubeSettings.YTDLP.Name '"yt-dlp"
|
||||
.FileExchanger = MyCache.NewInstance(Of BatchFileExchanger)(CachePath, EDP.ReturnValue)
|
||||
.FileExchanger.DeleteCacheOnDispose = True
|
||||
.AddCommand("chcp 65001")
|
||||
@@ -971,18 +1134,20 @@ 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"
|
||||
CreateUrlFile(URL, fileUrl)
|
||||
If fileUrl.Exists Then Files.Add(fileUrl)
|
||||
If fileUrl.Exists Then AddFile(fileUrl)
|
||||
End If
|
||||
|
||||
If MyYouTubeSettings.CreateDescriptionFiles And Not Description.IsEmptyString Then
|
||||
Dim fileDesr As SFile = File
|
||||
fileDesr.Extension = "txt"
|
||||
TextSaver.SaveTextToFile(Description, fileDesr,,, EDP.None)
|
||||
If fileDesr.Exists Then Files.Add(fileDesr)
|
||||
If fileDesr.Exists Then AddFile(fileDesr)
|
||||
End If
|
||||
|
||||
If PlaylistCount > 0 And Not CoverDownloaded And Not PlaylistID.IsEmptyString Then DownloadPlaylistCover(PlaylistID, File, UseCookies)
|
||||
@@ -1006,65 +1171,147 @@ Namespace API.YouTube.Objects
|
||||
Dim format$
|
||||
Dim fPattern$ = $"{File.PathWithSeparator}{File.Name}." & "{0}"
|
||||
Dim fPatternFiles$ = $"{File.Name}*." & "{0}"
|
||||
Dim fAacAudio As New SFile(String.Format(fPattern, aac))
|
||||
Dim fAc3Audio As New SFile(String.Format(fPattern, ac3))
|
||||
Dim aacRequested As Boolean = PostProcessing_OutputAudioFormats.Count > 0 AndAlso
|
||||
PostProcessing_OutputAudioFormats.Exists(Function(af) af.StringToLower = aac)
|
||||
Dim ac3Requested As Boolean = PostProcessing_OutputAudioFormats.Count > 0 AndAlso
|
||||
PostProcessing_OutputAudioFormats.Exists(Function(af) af.StringToLower = ac3)
|
||||
Dim fAacAudio As New TempFileConversion(New SFile(String.Format(fPattern, aac)), Me)
|
||||
Dim mp3ThumbEmbedded As Boolean = False
|
||||
|
||||
Dim tempFilesList As New List(Of TempFileConversion)
|
||||
Dim ttFile As TempFileConversion
|
||||
|
||||
Dim __updateBitrate As Boolean = OutputAudioBitrate > 0 AndAlso (SelectedAudioIndex = -1 OrElse SelectedAudio.Bitrate <> OutputAudioBitrate)
|
||||
If __updateBitrate Then Bitrate = OutputAudioBitrate
|
||||
Dim updateBitrate As Action(Of SFile) =
|
||||
Sub(ByVal sourceFile As SFile)
|
||||
If __updateBitrate AndAlso sourceFile.Exists Then
|
||||
Dim destFile As SFile = sourceFile
|
||||
destFile.Name &= "_new00"
|
||||
.Execute($"ffmpeg -i ""{sourceFile}"" -crf {MyYouTubeSettings.DefaultAudioBitrate_crf.Value} -b:a {OutputAudioBitrate}k ""{destFile}""")
|
||||
If destFile.Exists AndAlso sourceFile.Delete Then SFile.Rename(destFile, sourceFile)
|
||||
End If
|
||||
End Sub
|
||||
Dim __getAAC_tried As Boolean = False
|
||||
Dim AACExists As Func(Of Boolean) = Function() As Boolean
|
||||
If Not __getAAC_tried Then
|
||||
__getAAC_tried = True
|
||||
.Execute($"ffmpeg -i ""{File}"" -vn -acodec {aac} ""{fAacAudio.File}""")
|
||||
tempFilesList.Add(fAacAudio)
|
||||
updateBitrate.Invoke(fAacAudio.File)
|
||||
End If
|
||||
Return fAacAudio.Exists
|
||||
End Function
|
||||
Dim tryToConvert As Action(Of String, SFile) =
|
||||
Sub(ByVal codec As String, ByVal dFile As SFile)
|
||||
ThrowAny(Token)
|
||||
.Execute($"ffmpeg -i ""{File}"" -vn -acodec {codec} ""{dFile}""")
|
||||
If Not codec = aac AndAlso Not dFile.Exists AndAlso AACExists.Invoke Then
|
||||
ThrowAny(Token)
|
||||
.Execute($"ffmpeg -i ""{fAacAudio.File}"" -f {codec} ""{dFile}""")
|
||||
End If
|
||||
End Sub
|
||||
Dim embedThumbTo As Action(Of SFile) =
|
||||
Sub(ByVal dFile As SFile)
|
||||
If dFile.Exists And ThumbnailFile.Exists Then
|
||||
Dim dFileNew As SFile = dFile
|
||||
dFileNew.Name &= "_NEW"
|
||||
.Execute($"ffmpeg -i ""{dFile}"" -i ""{ThumbnailFile}"" -map 0:0 -map 1:0 -c copy -id3v2_version 3 -metadata:s:v title=""Cover"" -metadata:s:v comment=""Cover"" ""{dFileNew}""")
|
||||
If dFileNew.Exists AndAlso dFile.Delete(,, EDP.ReturnValue) Then SFile.Rename(dFileNew, dFile)
|
||||
End If
|
||||
End Sub
|
||||
|
||||
'Subtitles
|
||||
ThrowAny(Token)
|
||||
If PostProcessing_OutputSubtitlesFormats.Count > 0 Then
|
||||
If SubtitlesSelectedIndexes.Count > 0 And Not OutputSubtitlesFormat.IsEmptyString Then
|
||||
files = SFile.GetFiles(File, String.Format(fPatternFiles, OutputSubtitlesFormat.StringToLower),, EDP.ReturnValue)
|
||||
If files.ListExists Then
|
||||
For Each f In files
|
||||
For Each format In PostProcessing_OutputSubtitlesFormats
|
||||
format = format.StringToLower
|
||||
commandFile = $"{f.PathWithSeparator}{f.Name}.{format}"
|
||||
Me.Files.Add(commandFile)
|
||||
ThrowAny(Token)
|
||||
.Execute($"ffmpeg -i ""{f}"" ""{commandFile}""")
|
||||
AddFile(files)
|
||||
If PostProcessing_OutputSubtitlesFormats.Count > 0 Then
|
||||
For Each f In files
|
||||
For Each format In PostProcessing_OutputSubtitlesFormats
|
||||
format = format.StringToLower
|
||||
commandFile = $"{f.PathWithSeparator}{f.Name}.{format}"
|
||||
AddFile(commandFile)
|
||||
ThrowAny(Token)
|
||||
.Execute($"ffmpeg -i ""{f}"" ""{commandFile}""")
|
||||
Next
|
||||
Next
|
||||
Next
|
||||
End If
|
||||
End If
|
||||
End If
|
||||
|
||||
'Audio
|
||||
ThrowAny(Token)
|
||||
If PostProcessing_OutputAudioFormats.Count > 0 Or PostProcessing_AudioAC3 Then
|
||||
If Not fAacAudio.Exists Then .Execute($"ffmpeg -i ""{File}"" -vn -acodec {aac} ""{fAacAudio}""")
|
||||
If PostProcessing_AudioAC3 And Not fAc3Audio.Exists Then
|
||||
ThrowAny(Token)
|
||||
.Execute($"ffmpeg -i ""{File}"" -vn -acodec {ac3} ""{fAc3Audio}""")
|
||||
If Not fAc3Audio.Exists And fAacAudio.Exists Then ThrowAny(Token) : .Execute($"ffmpeg -i ""{fAacAudio}"" -f {ac3} ""{fAc3Audio}""")
|
||||
If PostProcessing_OutputAudioFormats.Count > 0 Or PostProcessing_AudioAC3 Or PostProcessing_AudioMP3 Or __updateBitrate Then
|
||||
|
||||
If PostProcessing_AudioAC3 Then
|
||||
ttFile = New TempFileConversion(New SFile(String.Format(fPattern, ac3)), Me) With {.ToReplace = True}
|
||||
tempFilesList.Add(ttFile)
|
||||
If Not ttFile.Exists Then tryToConvert.Invoke(ac3, ttFile.File)
|
||||
updateBitrate.Invoke(ttFile.File)
|
||||
End If
|
||||
|
||||
If PostProcessing_AudioMP3 Then
|
||||
ttFile = New TempFileConversion(New SFile(String.Format(fPattern, mp3)), Me) With {.ToReplace = True}
|
||||
tempFilesList.Add(ttFile)
|
||||
If Not ttFile.Requested Then ttFile.Requested = SelectedVideoIndex = -1 And OutputAudioCodec.StringToLower = mp3
|
||||
If Not ttFile.Exists Then tryToConvert.Invoke(mp3, ttFile.File)
|
||||
updateBitrate.Invoke(ttFile.File)
|
||||
embedThumbTo.Invoke(ttFile.File)
|
||||
mp3ThumbEmbedded = True
|
||||
End If
|
||||
|
||||
If __updateBitrate Then
|
||||
format = OutputAudioCodec.StringToLower
|
||||
If Not format.IsEmptyString Then
|
||||
f = String.Format(fPattern, format)
|
||||
ttFile = New TempFileConversion(f, Me) With {.ToReplace = True}
|
||||
If Not ttFile.Requested Then ttFile.Requested = SelectedVideoIndex = -1
|
||||
If Not f.Exists Then
|
||||
tempFilesList.ListAddValue(ttFile, LAP.NotContainsOnly)
|
||||
tryToConvert.Invoke(format, f)
|
||||
updateBitrate.Invoke(f)
|
||||
ElseIf Not tempFilesList.Contains(ttFile) Then
|
||||
tempFilesList.Add(ttFile)
|
||||
updateBitrate.Invoke(f)
|
||||
End If
|
||||
End If
|
||||
End If
|
||||
|
||||
If PostProcessing_OutputAudioFormats.Count > 0 Then
|
||||
For Each format In PostProcessing_OutputAudioFormats
|
||||
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}""")
|
||||
AddFile(f)
|
||||
If Not f.Exists Then
|
||||
tryToConvert.Invoke(format, f)
|
||||
updateBitrate(f)
|
||||
If format = mp3 And Not mp3ThumbEmbedded And MyYouTubeSettings.DefaultAudioEmbedThumbnail_ExtractedFiles Then _
|
||||
embedThumbTo.Invoke(f) : mp3ThumbEmbedded = True
|
||||
If Not M3U8_PlaylistFiles.ListExists AndAlso f.Exists Then M3U8_Append(f)
|
||||
End If
|
||||
Next
|
||||
End If
|
||||
End If
|
||||
|
||||
'Update video
|
||||
ThrowAny(Token)
|
||||
If PostProcessing_AudioAC3 Then
|
||||
If SelectedVideoIndex >= 0 AndAlso tempFilesList.Count > 0 AndAlso tempFilesList.Exists(Function(tf) tf.ToReplace) Then
|
||||
f = File
|
||||
If SelectedVideoIndex >= 0 Then
|
||||
f.Name &= "tmp00"
|
||||
Else
|
||||
f.Extension = ac3
|
||||
f.Name &= "tmp00"
|
||||
Dim tfr As SFile = tempFilesList.FirstOrDefault(Function(tf) tf.ToReplace).File
|
||||
If tfr.Exists And Not f.Exists Then
|
||||
ThrowAny(Token)
|
||||
.Execute($"ffmpeg -i ""{File}"" -i ""{tfr}"" -c:v copy -c copy -map 0:v:0 -map 1:a:0 ""{f}""")
|
||||
End If
|
||||
If Not f.Exists Then ThrowAny(Token) : .Execute($"ffmpeg -i ""{File}"" -i ""{fAc3Audio}"" -c:v copy -c copy -map 0:v:0 -map 1:a:0 ""{f}""")
|
||||
If f.Exists Then
|
||||
File.Delete()
|
||||
If SelectedVideoIndex >= 0 Then SFile.Rename(f, File,, EDP.LogMessageValue)
|
||||
End If
|
||||
If fAacAudio.Exists And Not aacRequested Then fAacAudio.Delete()
|
||||
If fAc3Audio.Exists And Not ac3Requested And SelectedVideoIndex >= 0 Then fAc3Audio.Delete()
|
||||
End If
|
||||
|
||||
If SelectedVideoIndex >= 0 AndAlso OutputVideoFPS > 0 AndAlso SelectedVideo.Bitrate > OutputVideoFPS Then
|
||||
'Delete unrequsted files
|
||||
If tempFilesList.Count > 0 Then tempFilesList.ForEach(Sub(tfr) If Not tfr.Requested Then tfr.File.Delete(,, EDP.None)) : tempFilesList.Clear()
|
||||
|
||||
'Update video FPS
|
||||
If SelectedVideoIndex >= 0 AndAlso OutputVideoFPS > 0 AndAlso SelectedVideo.Bitrate <> OutputVideoFPS Then
|
||||
f = File
|
||||
f.Name &= "tmp00"
|
||||
.Execute($"ffmpeg -i ""{File}"" -filter:v fps={OutputVideoFPS.ToString.Replace(",", ".")} -c:a copy ""{f}""")
|
||||
@@ -1076,6 +1323,12 @@ Namespace API.YouTube.Objects
|
||||
End If
|
||||
End If
|
||||
End With
|
||||
|
||||
Dim newSize# = 0
|
||||
If File.Exists Then newSize += File.Size
|
||||
If Files.Count > 0 Then newSize += (From eFile As SFile In Files Where eFile.Exists Select eFile.Size).Sum
|
||||
If ThumbnailFile.Exists Then newSize += ThumbnailFile.Size
|
||||
If newSize > 0 Then newSize /= 1024 : Size = newSize : _SizeRecalculated = True
|
||||
End Using
|
||||
_MediaState = UMStates.Downloaded
|
||||
Catch oex As OperationCanceledException When Token.IsCancellationRequested
|
||||
@@ -1092,6 +1345,33 @@ Namespace API.YouTube.Objects
|
||||
End If
|
||||
End Try
|
||||
End Sub
|
||||
Private Sub M3U8_Append(Optional ByVal __file As SFile = Nothing)
|
||||
If M3U8_PlaylistFiles.ListExists Then
|
||||
For Each m3u8_file As SFile In M3U8_PlaylistFiles
|
||||
If Not m3u8_file.IsEmptyString Then
|
||||
Dim m3u8Row$ = String.Empty
|
||||
If Not m3u8_file.Extension.IsEmptyString Then
|
||||
If m3u8_file.Extension.ToLower = "m3u8" Then
|
||||
m3u8Row = GetPlaylistRow(Me, __file)
|
||||
ElseIf m3u8_file.Extension.ToLower = "m3u" Then
|
||||
m3u8Row = __file.IfNullOrEmpty(File).ToString
|
||||
End If
|
||||
End If
|
||||
If Not m3u8Row.IsEmptyString Then
|
||||
Dim m3u8Text$
|
||||
If m3u8_file.Exists Then
|
||||
m3u8Text = m3u8_file.GetText
|
||||
m3u8_file.Delete(SFO.File, SFODelete.DeleteToRecycleBin, EDP.SendToLog)
|
||||
Else
|
||||
m3u8Text = "#EXTM3U"
|
||||
End If
|
||||
m3u8Text.StringAppendLine(m3u8Row, vbCrLf)
|
||||
TextSaver.SaveTextToFile(m3u8Text, m3u8_file,,, EDP.SendToLog)
|
||||
End If
|
||||
End If
|
||||
Next
|
||||
End If
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Load"
|
||||
Private Sub ApplyElementCheckedValue(ByVal e As EContainer)
|
||||
@@ -1221,6 +1501,7 @@ Namespace API.YouTube.Objects
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Parse"
|
||||
Friend Const DRC As String = "drc"
|
||||
Public Overridable Function Parse(ByVal Container As EContainer, ByVal Path As SFile, ByVal IsMusic As Boolean,
|
||||
Optional ByVal Token As CancellationToken = Nothing, Optional ByVal Progress As IMyProgress = Nothing) As Boolean Implements IYouTubeMediaContainer.Parse
|
||||
Try
|
||||
@@ -1283,6 +1564,7 @@ Namespace API.YouTube.Objects
|
||||
_File.Name = $"{ID}.{ext}"
|
||||
End If
|
||||
If Not MyYouTubeSettings.OutputPath.IsEmptyString Then _File.Path = MyYouTubeSettings.OutputPath.Value.Path
|
||||
_File = CleanFileName(_File)
|
||||
File = _File
|
||||
|
||||
If .Contains("duration") Then
|
||||
@@ -1372,7 +1654,8 @@ Namespace API.YouTube.Objects
|
||||
obj = New MediaObject With {
|
||||
.ID = ee.Value("format_id"),
|
||||
.URL = ee.Value("url"),
|
||||
.Extension = ee.Value("ext")
|
||||
.Extension = ee.Value("ext"),
|
||||
.ID_DRC = Not .ID.IsEmptyString AndAlso .ID.StringToLower.Contains(DRC)
|
||||
}
|
||||
obj.Width = AConvert(Of Integer)(ee.Value("width"), NumberProvider, -1)
|
||||
obj.Height = AConvert(Of Integer)(ee.Value("height"), NumberProvider, -1)
|
||||
@@ -1427,6 +1710,14 @@ Namespace API.YouTube.Objects
|
||||
If MediaObjects.Count > 0 AndAlso MediaObjects.LongCount(CountAVC) > 0 Then MediaObjects.RemoveAll(RemoveAVC)
|
||||
Next
|
||||
End If
|
||||
If t = UMTypes.Audio And MediaObjects.Count > 0 Then
|
||||
Dim __audioComparerCount As Func(Of MediaObject, MediaObject, Boolean) =
|
||||
Function(mo, mo2) (mo2.Type = t And mo2.Extension = mo.Extension And mo2.Bitrate = mo.Bitrate) AndAlso
|
||||
mo2.Size.RoundDown = mo.Size.RoundDown AndAlso ACheck(Of Integer)(mo2.ID)
|
||||
Dim RemoveDRC As Predicate(Of MediaObject) = Function(mo) mo.Type = t AndAlso Not ACheck(Of Integer)(mo.ID) AndAlso
|
||||
MediaObjects.LongCount(Function(mo2) __audioComparerCount.Invoke(mo, mo2)) > 0
|
||||
MediaObjects.RemoveAll(RemoveDRC)
|
||||
End If
|
||||
End Sub
|
||||
Dim protocolCleaner As Action =
|
||||
Sub()
|
||||
@@ -1608,7 +1899,7 @@ Namespace API.YouTube.Objects
|
||||
_SubtitlesDelegated.Clear()
|
||||
SubtitlesSelectedIndexes.Clear()
|
||||
MediaObjects.Clear()
|
||||
Files.Clear()
|
||||
_Files.Clear()
|
||||
PostProcessing_OutputAudioFormats.Clear()
|
||||
PostProcessing_OutputSubtitlesFormats.Clear()
|
||||
End If
|
||||
|
||||
@@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices
|
||||
' by using the '*' as shown below:
|
||||
' <Assembly: AssemblyVersion("1.0.*")>
|
||||
|
||||
<Assembly: AssemblyVersion("2024.2.25.0")>
|
||||
<Assembly: AssemblyFileVersion("2024.2.25.0")>
|
||||
<Assembly: AssemblyVersion("2024.5.4.0")>
|
||||
<Assembly: AssemblyFileVersion("2024.5.4.0")>
|
||||
<Assembly: NeutralResourcesLanguage("en")>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
'
|
||||
' This program is distributed in the hope that it will be useful,
|
||||
' but WITHOUT ANY WARRANTY
|
||||
Imports System.Runtime.CompilerServices
|
||||
Imports PersonalUtilities.Forms
|
||||
Imports PersonalUtilities.Functions.RegularExpressions
|
||||
Namespace API.Base
|
||||
@@ -49,7 +50,7 @@ Namespace API.Base
|
||||
End Sub
|
||||
Public Overrides 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
|
||||
Dim v% = AConvert(Of Integer)(Value, -1)
|
||||
Dim v% = AConvert(Of Integer)(Value, -1, EDP.ReturnValue)
|
||||
If v > 0 Then
|
||||
Return Value
|
||||
ElseIf Not ACheck(Of Integer)(Value) Then
|
||||
@@ -72,5 +73,12 @@ Namespace API.Base
|
||||
$"Current query: [{CurrentQuery}]{vbCr}New query: [{NewQuery}]",
|
||||
"Changing a query"}, vbExclamation,,, {"Process", "Cancel"}) = 0
|
||||
End Function
|
||||
<Extension> Friend Function GetCookieValue(ByVal Cookies As IEnumerable(Of System.Net.Cookie), ByVal CookieName As String) As String
|
||||
If Cookies.ListExists Then Return If(Cookies.FirstOrDefault(Function(c) c.Name.ToLower = CookieName.ToLower)?.Value, String.Empty) Else Return String.Empty
|
||||
End Function
|
||||
<Extension> Friend Function GetCookieValue(ByVal Cookies As IEnumerable(Of System.Net.Cookie), ByVal CookieName As String,
|
||||
ByVal PropName As String, ByVal PropNameComp As String) As String
|
||||
Return If(PropName = PropNameComp, Cookies.GetCookieValue(CookieName), String.Empty)
|
||||
End Function
|
||||
End Module
|
||||
End Namespace
|
||||
@@ -11,8 +11,6 @@ Namespace API.Base
|
||||
Friend Const Header_Authorization As String = "authorization"
|
||||
Friend Const Header_CSRFToken As String = "x-csrf-token"
|
||||
|
||||
Friend Const Header_FB_FRIENDLY_NAME As String = "x-fb-friendly-name"
|
||||
|
||||
Friend Const ConcurrentDownloadsCaption As String = "Concurrent downloads"
|
||||
Friend Const ConcurrentDownloadsToolTip As String = "The number of concurrent downloads."
|
||||
Friend Const SavedPostsUserNameCaption As String = "Saved posts user"
|
||||
|
||||
@@ -59,7 +59,6 @@ Namespace API.Base
|
||||
ReadOnly Property DownloadedTotal(Optional ByVal Total As Boolean = True) As Integer
|
||||
ReadOnly Property DownloadedInformation As String
|
||||
Property HasError As Boolean
|
||||
ReadOnly Property FitToAddParams As Boolean
|
||||
ReadOnly Property Key As String
|
||||
Property DownloadImages As Boolean
|
||||
Property DownloadVideos As Boolean
|
||||
|
||||
@@ -42,6 +42,13 @@ Namespace API.Base
|
||||
Friend NotInheritable Class M3U8Base
|
||||
Friend Const TempCacheFolderName As String = "tmpCache"
|
||||
Friend Const TempFilePrefix As String = "ConPart_"
|
||||
Friend Const TempFileDefaultExtension As String = "ts"
|
||||
''' <summary><c>SFileNumbers.NumberProviderDefault</c></summary>
|
||||
Friend Shared ReadOnly Property NumberProviderDefault As ANumbers
|
||||
Get
|
||||
Return SFileNumbers.NumberProviderDefault
|
||||
End Get
|
||||
End Property
|
||||
Private Sub New()
|
||||
End Sub
|
||||
Friend Shared Function CreateUrl(ByVal Appender As String, ByVal File As String) As String
|
||||
@@ -63,8 +70,7 @@ Namespace API.Base
|
||||
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"
|
||||
Optional ByVal OnlyDownload As Boolean = False, Optional ByVal SkipBroken As Boolean = False) As SFile
|
||||
Dim Cache As CacheKeeper = Nothing
|
||||
Using tmpPr As New PreProgress(Progress)
|
||||
Try
|
||||
@@ -89,13 +95,13 @@ Namespace API.Base
|
||||
End If
|
||||
End If
|
||||
Dim p As SFileNumbers = SFileNumbers.Default(ConcatFile.Name)
|
||||
Dim pNum As ANumbers = SFileNumbers.NumberProviderDefault
|
||||
Dim pNum As ANumbers = 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 = defaultExtension
|
||||
dFile.Extension = TempFileDefaultExtension
|
||||
Using w As New DownloadObjects.WebClient2(Responser)
|
||||
For i = 0 To URLs.Count - 1
|
||||
If progressExists Then
|
||||
@@ -107,9 +113,13 @@ Namespace API.Base
|
||||
End If
|
||||
Token.ThrowIfCancellationRequested()
|
||||
dFile.Name = $"{TempFilePrefix}{i.NumToString(pNum)}"
|
||||
dFile.Extension = URLs(i).Extension.IfNullOrEmpty(defaultExtension)
|
||||
w.DownloadFile(URLs(i).URL, dFile)
|
||||
cache2.AddFile(dFile, True)
|
||||
dFile.Extension = URLs(i).Extension.IfNullOrEmpty(TempFileDefaultExtension)
|
||||
Try
|
||||
w.DownloadFile(URLs(i).URL, dFile)
|
||||
cache2.AddFile(dFile, True)
|
||||
Catch ex As Exception
|
||||
If Not SkipBroken Then Throw ex
|
||||
End Try
|
||||
Next
|
||||
End Using
|
||||
If Not OnlyDownload Then _
|
||||
|
||||
@@ -17,6 +17,7 @@ Imports Download = SCrawler.Plugin.ISiteSettings.Download
|
||||
Namespace API.Base
|
||||
Friend MustInherit Class SiteSettingsBase : Implements ISiteSettings, IResponserContainer
|
||||
#Region "Declarations"
|
||||
<PXML> Protected ReadOnly Property SettingsVersion As PropertyValue
|
||||
Friend ReadOnly Property Site As String Implements ISiteSettings.Site
|
||||
Protected _Icon As Icon = Nothing
|
||||
Friend Overridable ReadOnly Property Icon As Icon Implements ISiteSettings.Icon
|
||||
@@ -54,7 +55,14 @@ Namespace API.Base
|
||||
End Set
|
||||
End Property
|
||||
#End Region
|
||||
#Region "EnvironmentPrograms"
|
||||
Private Property CMDEncoding As String Implements ISiteSettings.CMDEncoding
|
||||
Private Property EnvironmentPrograms As IEnumerable(Of String) Implements ISiteSettings.EnvironmentPrograms
|
||||
Private Sub EnvironmentProgramsUpdated() Implements ISiteSettings.EnvironmentProgramsUpdated
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Responser and cookies support"
|
||||
Friend Const ResponserFilePrefix As String = "Responser_"
|
||||
Private _CookiesNetscapeFile As SFile = Nothing
|
||||
Friend ReadOnly Property CookiesNetscapeFile As SFile
|
||||
Get
|
||||
@@ -85,7 +93,7 @@ Namespace API.Base
|
||||
End Property
|
||||
Protected Sub UpdateResponserFile()
|
||||
Dim acc$ = If(AccountName.IsEmptyString OrElse AccountName = Hosts.SettingsHost.NameAccountNameDefault, String.Empty, $"_{AccountName}")
|
||||
Responser.File = $"{SettingsFolderName}\Responser_{Site}{acc}.xml"
|
||||
Responser.File = $"{SettingsFolderName}\{ResponserFilePrefix}{Site}{acc}.xml"
|
||||
_CookiesNetscapeFile = Responser.File
|
||||
_CookiesNetscapeFile.Name &= "_Cookies_Netscape"
|
||||
_CookiesNetscapeFile.Extension = "txt"
|
||||
@@ -100,6 +108,7 @@ Namespace API.Base
|
||||
_Icon = __Icon
|
||||
_Image = __Image
|
||||
Responser = New Responser With {.DeclaredError = EDP.ThrowException}
|
||||
SettingsVersion = New PropertyValue(0)
|
||||
UpdateResponserFile()
|
||||
End Sub
|
||||
Friend Sub New(ByVal SiteName As String, ByVal CookiesDomain As String, ByVal AccName As String, ByVal Temp As Boolean,
|
||||
|
||||
@@ -312,7 +312,7 @@ Namespace API.Base
|
||||
End Set
|
||||
End Property
|
||||
Protected Sub UserSiteNameUpdate(ByVal NewName As String)
|
||||
If Not NewName.IsEmptyString And (UserSiteName.IsEmptyString Or Settings.UserSiteNameUpdateEveryTime) Then UserSiteName = NewName
|
||||
If Not NewName.IsEmptyString And (UserSiteName.IsEmptyString Or Settings.UpdateUserSiteNameEveryTime) Then UserSiteName = NewName
|
||||
End Sub
|
||||
Friend ReadOnly Property UserModel As UsageModel Implements IUserData.UserModel
|
||||
Get
|
||||
@@ -829,48 +829,19 @@ BlockNullPicture:
|
||||
Return ListImagesLoader.ApplyLVIColor(Me, New ListViewItem(ToString(), GetLVIGroup(Destination)) With {.Name = LVIKey, .Tag = LVIKey}, True)
|
||||
End If
|
||||
End Function
|
||||
Friend Overridable ReadOnly Property FitToAddParams As Boolean Implements IUserData.FitToAddParams
|
||||
Get
|
||||
With Settings
|
||||
If IsSubscription And Not .MainFrameUsersShowSubscriptions Then Return False
|
||||
If Not IsSubscription And Not .MainFrameUsersShowDefaults Then Return False
|
||||
If LastUpdated.HasValue And Not .ViewDateMode.Value = ShowingDates.Off Then
|
||||
Dim f As Date = If(.ViewDateFrom.HasValue, .ViewDateFrom.Value.Date, Date.MinValue.Date)
|
||||
Dim t As Date = If(.ViewDateTo.HasValue, .ViewDateTo.Value.Date, Date.MaxValue.Date)
|
||||
Select Case DirectCast(.ViewDateMode.Value, ShowingDates)
|
||||
Case ShowingDates.In : If Not LastUpdated.Value.ValueBetween(f, t) Then Return False
|
||||
Case ShowingDates.Not : If LastUpdated.Value.ValueBetween(f, t) Then Return False
|
||||
End Select
|
||||
End If
|
||||
If Not .Labels.ExcludedIgnore AndAlso .Labels.Excluded.ValuesList.ListContains(Labels) Then Return False
|
||||
If .SelectedSites.Count = 0 OrElse .SelectedSites.Contains(Site) Then
|
||||
Select Case .ShowingMode.Value
|
||||
Case ShowingModes.Regular : Return Not Temporary And Not Favorite
|
||||
Case ShowingModes.Temporary : Return Temporary
|
||||
Case ShowingModes.Favorite : Return Favorite
|
||||
Case ShowingModes.Deleted : Return Not UserExists
|
||||
Case ShowingModes.Suspended : Return UserSuspended
|
||||
Case ShowingModes.Labels : Return Settings.Labels.Current.ValuesList.ListContains(Labels)
|
||||
Case ShowingModes.NoLabels : Return Labels.Count = 0
|
||||
Case Else : Return True
|
||||
End Select
|
||||
Else
|
||||
Return False
|
||||
End If
|
||||
End With
|
||||
End Get
|
||||
End Property
|
||||
Friend Function GetLVIGroup(ByVal Destination As ListView) As ListViewGroup Implements IUserData.GetLVIGroup
|
||||
Try
|
||||
If Settings.ShowingMode.Value = ShowingModes.Labels And Not Settings.ShowGroupsInsteadLabels Then
|
||||
If Labels.Count > 0 And Settings.Labels.Current.Count > 0 Then
|
||||
For i% = 0 To Labels.Count - 1
|
||||
If Settings.Labels.Current.Contains(Labels(i)) Then Return Destination.Groups.Item(Labels(i))
|
||||
Next
|
||||
With Settings
|
||||
If Not .ShowAllUsers.Value AndAlso (.AdvancedFilter.Labels.Count > 0 Or .AdvancedFilter.LabelsNo) AndAlso Not .ShowGroupsInsteadLabels Then
|
||||
If Labels.Count > 0 And .AdvancedFilter.Labels.Count > 0 Then
|
||||
For i% = 0 To Labels.Count - 1
|
||||
If .AdvancedFilter.Labels.Contains(Labels(i)) Then Return Destination.Groups.Item(Labels(i))
|
||||
Next
|
||||
End If
|
||||
ElseIf Settings.GroupUsers Then
|
||||
Return Destination.Groups.Item(GetLviGroupName(HOST, Temporary, Favorite, IsCollection))
|
||||
End If
|
||||
ElseIf Settings.ShowGroups Then
|
||||
Return Destination.Groups.Item(GetLviGroupName(HOST, Temporary, Favorite, IsCollection))
|
||||
End If
|
||||
End With
|
||||
Return Destination.Groups.Item(LabelsKeeper.NoLabeledName)
|
||||
Catch ex As Exception
|
||||
Return Destination.Groups.Item(LabelsKeeper.NoLabeledName)
|
||||
@@ -1030,7 +1001,7 @@ BlockNullPicture:
|
||||
|
||||
x.Save(MyFileSettings)
|
||||
End Using
|
||||
If Not IsSavedPosts Then Settings.UpdateUsersList(User)
|
||||
If Not IsSavedPosts Then Settings.UpdateUsersList(User, True)
|
||||
Catch ex As Exception
|
||||
LogError(ex, "user information saving error")
|
||||
End Try
|
||||
@@ -1194,7 +1165,7 @@ BlockNullPicture:
|
||||
If Not Responser Is Nothing Then Responser.Dispose()
|
||||
Responser = New Responser
|
||||
If Not HOST.Responser Is Nothing Then Responser.Copy(HOST.Responser)
|
||||
If Not Responser Is Nothing And _ResponserAutoUpdateCookies Then
|
||||
If Not Responser Is Nothing And (_ResponserAutoUpdateCookies Or _ResponserAddResponseReceivedHandler) Then
|
||||
If _ResponserAutoUpdateCookies Then
|
||||
Responser.CookiesUpdateMode = CookieUpdateModes.ReplaceByNameAll
|
||||
Responser.CookiesExtractMode = Responser.CookiesExtractModes.Any
|
||||
@@ -1269,8 +1240,10 @@ BlockNullPicture:
|
||||
Dim mca& = If(ContentMissingExists, _ContentList.LongCount(Function(c) MissingFinder(c)), 0)
|
||||
If DownloadedTotal(False) > 0 Or _EnvirChanged Or Not mcb = mca Or _ForceSaveUserData Then
|
||||
If Not __isChannelsSupport Then
|
||||
LastUpdated = Now
|
||||
RunScript()
|
||||
If DownloadedTotal(False) > 0 Then
|
||||
LastUpdated = Now
|
||||
RunScript()
|
||||
End If
|
||||
DownloadedPictures(True) = SFile.GetFiles(MyFile.CutPath, "*.jpg|*.jpeg|*.png|*.gif|*.webm",, EDP.ReturnValue).Count
|
||||
DownloadedVideos(True) = SFile.GetFiles(MyFile.CutPath, "*.mp4|*.mkv|*.mov", SearchOption.AllDirectories, EDP.ReturnValue).Count
|
||||
If Labels.Contains(LabelsKeeper.NoParsedUser) Then Labels.Remove(LabelsKeeper.NoParsedUser)
|
||||
@@ -1366,6 +1339,7 @@ BlockNullPicture:
|
||||
ResetHost()
|
||||
URL = Data.URL
|
||||
AccountName = Data.AccountName
|
||||
TokenQueue = Token
|
||||
If HOST Is Nothing Then Throw New ExitException($"Host '{AccountName}' not found")
|
||||
Data.DownloadState = UserMediaStates.Tried
|
||||
Progress = Data.Progress
|
||||
@@ -1409,12 +1383,14 @@ BlockNullPicture:
|
||||
If _ContentNew.Count > 0 Then
|
||||
If _ContentNew.Any(Function(mm) mm.State = UStates.Downloaded) Then
|
||||
Data.DownloadState = UserMediaStates.Downloaded
|
||||
Dim thumbAlong As Boolean = False
|
||||
If TypeOf Data Is DownloadableMediaHost Then thumbAlong = DirectCast(Data, DownloadableMediaHost).ThumbAlong
|
||||
If _ContentNew(0).Type = UTypes.Picture Or _ContentNew(0).Type = UTypes.GIF Then
|
||||
DirectCast(Data, IDownloadableMedia).ThumbnailFile = _ContentNew(0).File
|
||||
ElseIf Settings.STDownloader_TakeSnapshot And Settings.FfmpegFile.Exists And Not Settings.STDownloader_RemoveDownloadedAutomatically Then
|
||||
Dim f As SFile = _ContentNew(0).File
|
||||
Dim ff As SFile
|
||||
If Settings.STDownloader_SnapshotsKeepWithFiles Then
|
||||
If Settings.STDownloader_SnapshotsKeepWithFiles Or thumbAlong Then
|
||||
ff = f
|
||||
Else
|
||||
ff = Settings.CacheSnapshots(Settings.STDownloader_SnapShotsCachePermamnent).NewFile
|
||||
@@ -1424,6 +1400,9 @@ BlockNullPicture:
|
||||
f = Web.FFMPEG.TakeSnapshot(f, ff, Settings.FfmpegFile, TimeSpan.FromSeconds(1),,, EDP.SendToLog + EDP.ReturnValue)
|
||||
If f.Exists Then DirectCast(Data, IDownloadableMedia).ThumbnailFile = f
|
||||
End If
|
||||
Dim filesSize# = (From mm As UserMedia In _ContentNew Where mm.State = UStates.Downloaded AndAlso mm.File.Exists Select mm.File.Size).Sum
|
||||
If filesSize > 0 Then filesSize /= 1024
|
||||
Data.Size = filesSize
|
||||
Else
|
||||
Data.DownloadState = UserMediaStates.Missing
|
||||
End If
|
||||
@@ -1796,6 +1775,7 @@ BlockNullPicture:
|
||||
Protected Overridable Function ValidateDownloadFile(ByVal URL As String, ByVal Media As UserMedia, ByRef Interrupt As Boolean) As Boolean
|
||||
Return True
|
||||
End Function
|
||||
''' <returns><c>MyFile.CutPath(IIf(IsSingleObjectDownload, 0, 1)).PathNoSeparator</c></returns>
|
||||
Protected Overridable Function DownloadContentDefault_GetRootDir() As String
|
||||
Return MyFile.CutPath(IIf(IsSingleObjectDownload, 0, 1)).PathNoSeparator
|
||||
End Function
|
||||
@@ -1914,7 +1894,9 @@ BlockNullPicture:
|
||||
If m.Contains(IUserData.EraseMode.History) Then
|
||||
If MyFilePosts.Delete(SFO.File, SFODelete.DeleteToRecycleBin, e) Then result = True
|
||||
If MyFileData.Delete(SFO.File, SFODelete.DeleteToRecycleBin, e) Then result = True
|
||||
LastUpdated = Nothing
|
||||
EraseData_AdditionalDataFiles()
|
||||
UpdateUserInformation()
|
||||
End If
|
||||
If m.Contains(IUserData.EraseMode.Data) Then
|
||||
Dim files As List(Of SFile) = SFile.GetFiles(DownloadContentDefault_GetRootDir.CSFileP,, SearchOption.AllDirectories, e)
|
||||
@@ -1936,7 +1918,7 @@ BlockNullPicture:
|
||||
Return ErrorsDescriber.Execute(EDP.SendToLog + EDP.ReturnValue, ex, $"EraseData({CInt(Mode)}): {ToStringForLog()}", False)
|
||||
End Try
|
||||
End Function
|
||||
Protected Overridable Sub EraseData_AdditionalDataFiles()
|
||||
Protected Overridable Sub EraseData_AdditionalDataFiles() Implements IPluginContentProvider.ResetHistoryData
|
||||
End Sub
|
||||
Friend Overridable Function Delete(Optional ByVal Multiple As Boolean = False, Optional ByVal CollectionValue As Integer = -1) As Integer Implements IUserData.Delete
|
||||
Dim f As SFile = SFile.GetPath(MyFile.CutPath.Path)
|
||||
|
||||
@@ -11,7 +11,7 @@ Namespace API.Base.YTDLP
|
||||
Friend Sub New(ByVal _Token As Threading.CancellationToken)
|
||||
MyBase.New(_Token)
|
||||
Commands.Clear()
|
||||
MainProcessName = "yt-dlp"
|
||||
MainProcessName = Settings.YtdlpFile.File.Name '"yt-dlp"
|
||||
ChangeDirectory(Settings.YtdlpFile.File)
|
||||
End Sub
|
||||
End Class
|
||||
|
||||
@@ -11,9 +11,8 @@ Imports PersonalUtilities.Functions.XML.Base
|
||||
Imports PersonalUtilities.Functions.RegularExpressions
|
||||
Namespace API.Facebook
|
||||
Friend Module Declarations
|
||||
Friend ReadOnly Regex_UserToken_dtsg As RParams = RParams.DMS("DTSGInitialData.:.?{\s*.token.:\s*""([^""]+)", 1, EDP.ReturnValue)
|
||||
Friend ReadOnly Regex_UserToken_lsd As RParams = RParams.DMS("LSD.:.?{\s*.token.:\s*""([^""]+)", 1, EDP.ReturnValue)
|
||||
Friend ReadOnly Regex_UserID As RParams = RParams.DMS("userid.:.(\d+)", 1, RegexOptions.IgnoreCase, EDP.ReturnValue)
|
||||
Friend ReadOnly Regex_AppID As RParams = RParams.DMS("APP_ID.:.(\d+)", 1, RegexOptions.IgnoreCase, EDP.ReturnValue)
|
||||
|
||||
Friend ReadOnly Regex_Photos_by As RParams = RParams.DMS("photos_by"",""id"":""([^""]+)", 1, EDP.ReturnValue)
|
||||
Friend ReadOnly Regex_FileName As RParams = RParams.DM("([^/\?]+\..{3,4})(?=(\?|\Z))", 0, EDP.ReturnValue)
|
||||
|
||||
@@ -18,7 +18,7 @@ Namespace API.Facebook
|
||||
#Region "Auth"
|
||||
<PropertyOption(AllowNull:=False, ControlText:="Accept", ControlToolTip:="Header 'Accept'", IsAuth:=True), ControlNumber(21), PXML, PClonable>
|
||||
Friend ReadOnly Property Header_Accept As PropertyValue
|
||||
<PropertyOption(ControlText:="x-ig-app-id", AllowNull:=True, IsAuth:=True)>
|
||||
<PropertyOption(ControlText:="x-ig-app-id", AllowNull:=True, IsAuth:=True), HiddenControl>
|
||||
Friend Overrides ReadOnly Property HH_IG_APP_ID As PropertyValue
|
||||
Get
|
||||
Return __HH_IG_APP_ID
|
||||
@@ -29,8 +29,6 @@ Namespace API.Facebook
|
||||
Return __HH_CSRF_TOKEN
|
||||
End Get
|
||||
End Property
|
||||
<PropertyOption(ControlText:="sec-ch-ua-platform-ver", ControlToolTip:="sec-ch-ua-platform-version", IsAuth:=True, LeftOffset:=120), ControlNumber(51), PXML, PClonable>
|
||||
Friend ReadOnly Property HH_PLATFORM_VER As PropertyValue
|
||||
#End Region
|
||||
#Region "Defaults"
|
||||
<PropertyOption(ControlText:="Download photos", IsAuth:=False), PXML, PClonable>
|
||||
@@ -48,10 +46,9 @@ Namespace API.Facebook
|
||||
With Responser.Headers
|
||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.Authority, "www.facebook.com"))
|
||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.Origin, "https://www.facebook.com"))
|
||||
.Remove(DeclaredNames.Header_FB_FRIENDLY_NAME)
|
||||
.Remove(Instagram.UserData.GQL_HEADER_FB_FRINDLY_NAME)
|
||||
End With
|
||||
Header_Accept = New PropertyValue(String.Empty, GetType(String))
|
||||
HH_PLATFORM_VER = New PropertyValue(String.Empty, GetType(String))
|
||||
ParsePhotoBlock = New PropertyValue(True)
|
||||
ParseVideoBlock = New PropertyValue(True)
|
||||
ParseStoriesBlock = New PropertyValue(True)
|
||||
@@ -77,7 +74,7 @@ Namespace API.Facebook
|
||||
#End Region
|
||||
#Region "BaseAuthExists, GetUserUrl, GetUserPostUrl, IsMyUser, IsMyImageVideo"
|
||||
Friend Overrides Function BaseAuthExists() As Boolean
|
||||
Return Responser.CookiesExists And ACheck(HH_IG_APP_ID.Value)
|
||||
Return Responser.CookiesExists And CBool(DownloadData_Impl.Value) 'And ACheck(HH_IG_APP_ID.Value)
|
||||
End Function
|
||||
Friend Overrides Function GetUserUrl(ByVal User As IPluginContentProvider) As String
|
||||
Return DirectCast(User, UserData).GetProfileUrl
|
||||
|
||||
@@ -124,26 +124,35 @@ Namespace API.Facebook
|
||||
.SendToLogOnlyMessage = True, .ReplaceMainMessage = True})
|
||||
End Sub
|
||||
End Class
|
||||
Private Token_dtsg As String = String.Empty
|
||||
Private Token_lsd As String = String.Empty
|
||||
Private Token_Photosby As String = String.Empty
|
||||
Private Limit As Integer = -1
|
||||
Private Sub WaitTimer()
|
||||
If CInt(MySettings.RequestsWaitTimer_Any.Value) > 0 Then Thread.Sleep(CInt(MySettings.RequestsWaitTimer_Any.Value))
|
||||
End Sub
|
||||
Private Sub DisableDownload()
|
||||
MySettings.DownloadData_Impl.Value = False
|
||||
MyMainLOG = $"{Site} downloading is disabled until you update your credentials"
|
||||
End Sub
|
||||
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
|
||||
Try
|
||||
GetUserTokens(Token)
|
||||
LoadSavePostsKV(True)
|
||||
Limit = If(DownloadTopCount, -1)
|
||||
If IsSavedPosts Then
|
||||
DownloadData_SavedPosts(String.Empty, Token)
|
||||
Else
|
||||
If DownloadImages And ParsePhotoBlock Then DownloadData_Photo(String.Empty, Token)
|
||||
If DownloadVideos And ParseVideoBlock Then DownloadData_Video(String.Empty, Token)
|
||||
If (DownloadImages Or DownloadVideos) And ParseStoriesBlock Then DownloadData_Stories(Token)
|
||||
End If
|
||||
LoadSavePostsKV(False)
|
||||
Finally
|
||||
MySettings.UpdateResponserData(Responser)
|
||||
End Try
|
||||
If CBool(MySettings.DownloadData_Impl.Value) Then
|
||||
Try
|
||||
If Responser.Headers.Value(IG.Header_IG_APP_ID).IsEmptyString Then Responser.Headers.Remove(IG.Header_IG_APP_ID)
|
||||
ResetBaseTokens()
|
||||
GetUserTokens(Token)
|
||||
LoadSavePostsKV(True)
|
||||
Limit = If(DownloadTopCount, -1)
|
||||
If IsSavedPosts Then
|
||||
DownloadData_SavedPosts(String.Empty, Token)
|
||||
Else
|
||||
If DownloadImages And ParsePhotoBlock Then DownloadData_Photo(String.Empty, Token)
|
||||
If DownloadVideos And ParseVideoBlock Then DownloadData_Video(String.Empty, Token)
|
||||
If (DownloadImages Or DownloadVideos) And ParseStoriesBlock Then DownloadData_Stories(Token)
|
||||
End If
|
||||
LoadSavePostsKV(False)
|
||||
Finally
|
||||
MySettings.UpdateResponserData(Responser)
|
||||
End Try
|
||||
End If
|
||||
End Sub
|
||||
Private Const Header_fb_fr_name_Photo As String = "ProfileCometAppCollectionPhotosRendererPaginationQuery"
|
||||
Private Const Header_fb_fr_name_Video As String = "PagesCometChannelTabAllVideosCardImplPaginationQuery"
|
||||
@@ -167,13 +176,13 @@ Namespace API.Facebook
|
||||
ValidateBaseTokens()
|
||||
If Token_Photosby.IsEmptyString Then Throw New TokensException("Unable to obtain token 'Token_Photosby'", False)
|
||||
|
||||
URL = String.Format(Graphql_UrlPattern, Token_lsd, DocID_Photo, Header_fb_fr_name_Photo,
|
||||
SymbolsConverter.ASCII.EncodeSymbolsOnly(Token_dtsg),
|
||||
URL = String.Format(Graphql_UrlPattern, Token_lsd, DocID_Photo, Header_fb_fr_name_Photo, Token_dtsg_Var,
|
||||
SymbolsConverter.ASCII.EncodeSymbolsOnly("{" & String.Format(VarPattern, Cursor, Token_Photosby) & "}"))
|
||||
|
||||
ResponserApplyDefs(Header_fb_fr_name_Photo)
|
||||
ThrowAny(Token)
|
||||
|
||||
WaitTimer()
|
||||
Dim r$ = Responser.GetResponse(URL)
|
||||
If Not r.IsEmptyString Then
|
||||
Using j As EContainer = JsonDocument.Parse(r)
|
||||
@@ -233,13 +242,13 @@ Namespace API.Facebook
|
||||
If VideoPageID.IsEmptyString Then Throw New TokensException("Unable to obtain 'VideoPageID'", False)
|
||||
ValidateBaseTokens()
|
||||
|
||||
URL = String.Format(Graphql_UrlPattern, Token_lsd, DocID_Video, Header_fb_fr_name_Video,
|
||||
SymbolsConverter.ASCII.EncodeSymbolsOnly(Token_dtsg),
|
||||
URL = String.Format(Graphql_UrlPattern, Token_lsd, DocID_Video, Header_fb_fr_name_Video, Token_dtsg_Var,
|
||||
SymbolsConverter.ASCII.EncodeSymbolsOnly("{" & String.Format(VarPattern, If(Cursor.IsEmptyString, "null", $"""{Cursor}"""), VideoPageID) & "}"))
|
||||
|
||||
ResponserApplyDefs(Header_fb_fr_name_Video)
|
||||
ThrowAny(Token)
|
||||
|
||||
WaitTimer()
|
||||
Dim r$ = Responser.GetResponse(URL)
|
||||
If Not r.IsEmptyString Then
|
||||
Using j As EContainer = JsonDocument.Parse(r)
|
||||
@@ -288,13 +297,13 @@ Namespace API.Facebook
|
||||
ValidateBaseTokens()
|
||||
If StoryBucket.IsEmptyString Then Throw New TokensException("Unable to obtain 'StoryBucket'", False)
|
||||
|
||||
URL = String.Format(Graphql_UrlPattern, Token_lsd, DocID_Stories, Header_fb_fr_name_Stories,
|
||||
SymbolsConverter.ASCII.EncodeSymbolsOnly(Token_dtsg),
|
||||
URL = String.Format(Graphql_UrlPattern, Token_lsd, DocID_Stories, Header_fb_fr_name_Stories, Token_dtsg_Var,
|
||||
SymbolsConverter.ASCII.EncodeSymbolsOnly("{" & String.Format(VarPattern, StoryBucket) & "}"))
|
||||
|
||||
ResponserApplyDefs(Header_fb_fr_name_Stories)
|
||||
ThrowAny(Token)
|
||||
|
||||
WaitTimer()
|
||||
Dim r$ = Responser.GetResponse(URL)
|
||||
If Not r.IsEmptyString Then r = RegexReplace(r, RParams.DM("[^\r\n]+", 0, EDP.ReturnValue))
|
||||
If Not r.IsEmptyString Then
|
||||
@@ -357,13 +366,13 @@ Namespace API.Facebook
|
||||
Dim pid As PostKV
|
||||
|
||||
ValidateBaseTokens()
|
||||
URL = String.Format(Graphql_UrlPattern, Token_lsd, DocID_SavedPosts, Header_fb_fr_name_SavedPosts,
|
||||
SymbolsConverter.ASCII.EncodeSymbolsOnly(Token_dtsg),
|
||||
URL = String.Format(Graphql_UrlPattern, Token_lsd, DocID_SavedPosts, Header_fb_fr_name_SavedPosts, Token_dtsg_Var,
|
||||
SymbolsConverter.ASCII.EncodeSymbolsOnly("{" & String.Format(VarPattern, If(Cursor.IsEmptyString, "null", $"""{Cursor}""")) & "}"))
|
||||
|
||||
ResponserApplyDefs(Header_fb_fr_name_SavedPosts)
|
||||
ThrowAny(Token)
|
||||
|
||||
WaitTimer()
|
||||
Dim r$ = Responser.GetResponse(URL)
|
||||
If Not r.IsEmptyString Then
|
||||
Using j As EContainer = JsonDocument.Parse(r)
|
||||
@@ -421,6 +430,7 @@ Namespace API.Facebook
|
||||
If Round > 0 Then ThrowAny(Token)
|
||||
Dim script$, newUrl$
|
||||
Dim jNode As EContainer, jNode2 As EContainer
|
||||
WaitTimer()
|
||||
Dim r$ = resp.GetResponse(PostUrl)
|
||||
|
||||
If Not r.IsEmptyString Then
|
||||
@@ -488,16 +498,20 @@ Namespace API.Facebook
|
||||
#End Region
|
||||
#Region "ValidateBaseTokens, GetVideoPageID, GetUserTokens"
|
||||
''' <exception cref="ArgumentNullException"></exception>
|
||||
Private Sub ValidateBaseTokens()
|
||||
Protected Overrides Function ValidateBaseTokens() As Boolean
|
||||
Dim tokens$ = String.Empty
|
||||
If Token_dtsg.IsEmptyString Then tokens.StringAppend("Token_dtsg")
|
||||
If Token_lsd.IsEmptyString Then tokens.StringAppend("Token_lsd")
|
||||
If Not tokens.IsEmptyString Then Throw New TokensException($"Unable to obtain token(s) ({tokens}){vbCr}Your credentials may have expired.", True)
|
||||
End Sub
|
||||
If Not ValidateBaseTokens(tokens) Then
|
||||
DisableDownload()
|
||||
Throw New TokensException($"Unable to obtain token(s) ({tokens}). Your credentials may have expired.", True)
|
||||
Else
|
||||
Return True
|
||||
End If
|
||||
End Function
|
||||
Private Sub GetVideoPageID(ByVal Token As CancellationToken)
|
||||
Dim URL$ = $"{GetProfileUrl()}\videos"
|
||||
Dim resp As Responser = HtmlResponserCreate()
|
||||
Try
|
||||
WaitTimer()
|
||||
Dim r$ = resp.GetResponse(URL)
|
||||
If Not r.IsEmptyString Then VideoPageID = RegexReplace(r, Regex_VideoPageID)
|
||||
Catch ex As Exception
|
||||
@@ -510,14 +524,20 @@ Namespace API.Facebook
|
||||
Dim URL$ = If(IsSavedPosts, "https://www.facebook.com/saved", GetProfileUrl())
|
||||
Dim resp As Responser = HtmlResponserCreate()
|
||||
Try
|
||||
Token_dtsg = String.Empty
|
||||
Token_lsd = String.Empty
|
||||
ResetBaseTokens()
|
||||
Token_Photosby = String.Empty
|
||||
WaitTimer()
|
||||
Dim r$ = resp.GetResponse(URL)
|
||||
If Not r.IsEmptyString Then
|
||||
If Responser.CookiesExists Then Responser.Cookies.Update(resp.Cookies)
|
||||
Token_dtsg = RegexReplace(r, Regex_UserToken_dtsg)
|
||||
Token_lsd = RegexReplace(r, Regex_UserToken_lsd)
|
||||
ParseTokens(r, 0)
|
||||
Dim app_id$ = RegexReplace(r, Regex_AppID)
|
||||
If Not app_id.IsEmptyString Then
|
||||
If Not AEquals(Of String)(MySettings.HH_IG_APP_ID.Value, app_id) Then
|
||||
MySettings.HH_IG_APP_ID.Value = app_id
|
||||
Responser.Headers.Add(IG.Header_IG_APP_ID, app_id)
|
||||
End If
|
||||
End If
|
||||
Token_Photosby = RegexReplace(r, Regex_Photos_by)
|
||||
If StoryBucket.IsEmptyString Then StoryBucket = RegexReplace(r, Regex_StoryBucket)
|
||||
If ID.IsEmptyString Then
|
||||
@@ -535,8 +555,7 @@ Namespace API.Facebook
|
||||
#Region "Responser options"
|
||||
Private Sub ResponserApplyDefs(ByVal __fb_friendly_name As String)
|
||||
With Responser
|
||||
.Headers.Add(ThreadsNet.UserData.Header_FB_LSD, Token_lsd)
|
||||
.Headers.Add(DeclaredNames.Header_FB_FRIENDLY_NAME, __fb_friendly_name)
|
||||
UpdateHeadersGQL(__fb_friendly_name)
|
||||
.Method = "POST"
|
||||
.Accept = "*/*"
|
||||
.Referer = GetProfileUrl()
|
||||
@@ -556,14 +575,14 @@ Namespace API.Facebook
|
||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecFetchSite, "none"))
|
||||
.Add("Sec-Fetch-User", "?1")
|
||||
.Add("Upgrade-Insecure-Requests", 1)
|
||||
Dim h$ = Responser.Headers.Value(IG.Header_Browser)
|
||||
If Not h.IsEmptyString Then .Add(IG.Header_Browser, h)
|
||||
h = Responser.Headers.Value(IG.Header_BrowserExt)
|
||||
If Not h.IsEmptyString Then .Add(IG.Header_BrowserExt, h)
|
||||
h = .Value(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecChUaPlatform))
|
||||
If Not h.IsEmptyString Then .Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecChUaPlatform, h))
|
||||
If ACheck(MySettings.HH_PLATFORM_VER.Value) Then _
|
||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecChUaPlatformVersion, MySettings.HH_PLATFORM_VER.Value))
|
||||
Dim cloneHeader As Action(Of String) = Sub(ByVal hName As String)
|
||||
Dim hValue$ = Responser.Headers.Value(hName)
|
||||
If Not hValue.IsEmptyString Then .Add(hName, hValue)
|
||||
End Sub
|
||||
cloneHeader.Invoke(IG.Header_Browser)
|
||||
cloneHeader.Invoke(IG.Header_BrowserExt)
|
||||
cloneHeader.Invoke(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecChUaPlatform).Name)
|
||||
cloneHeader.Invoke(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecChUaPlatformVersion).Name)
|
||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecChUaMobile, "?0"))
|
||||
.Add("Sec-Ch-Ua-Model", "")
|
||||
End With
|
||||
@@ -655,6 +674,7 @@ Namespace API.Facebook
|
||||
Else
|
||||
URL = String.Format(VideoHtmlUrlPattern, m.Post.ID)
|
||||
End If
|
||||
WaitTimer()
|
||||
r = resp.GetResponse(URL)
|
||||
If Not r.IsEmptyString Then
|
||||
re.Pattern = String.Format(pattern, nameHD)
|
||||
|
||||
@@ -18,7 +18,9 @@ Namespace API.Instagram
|
||||
Friend ReadOnly ObtainMedia_SizeFuncPic_RegexP As RParams = RParams.DMS("_p(\d+)x(\d+)", 1, EDP.ReturnValue)
|
||||
Friend ReadOnly ObtainMedia_SizeFuncPic_RegexS As RParams = RParams.DMS("_s(\d+)x(\d+)", 1, EDP.ReturnValue)
|
||||
Friend Const PageTokenRegexPatternDefault As String = "\[\],{""token"":""(.*?)""},\d+\]"
|
||||
Friend Sub UpdateResponser(ByVal Source As IResponse, ByRef Destination As Responser)
|
||||
Friend ReadOnly Regex_UserToken_dtsg As RParams = RParams.DMS("DTSGInitialData["":,.\[\]]*?{\s*.token.:\s*""([^""]+)", 1, EDP.ReturnValue)
|
||||
Friend ReadOnly Regex_UserToken_lsd As RParams = RParams.DMS("LSD["":,.\[\]]*?{\s*.token.:\s*""([^""]+)", 1, EDP.ReturnValue)
|
||||
Friend Sub UpdateResponser(ByVal Source As IResponse, ByRef Destination As Responser, ByVal UpdateWwwClaim As Boolean)
|
||||
Const r_wwwClaimName$ = "x-ig-set-www-claim"
|
||||
Const r_tokenName$ = SiteSettings.Header_CSRF_TOKEN_COOKIE
|
||||
If Not Source Is Nothing Then
|
||||
@@ -35,17 +37,17 @@ Namespace API.Instagram
|
||||
Dim token$ = String.Empty
|
||||
With Source
|
||||
If isInternal Then
|
||||
If .HeadersExists Then wwwClaim = .Headers.Value(wwwClaimName)
|
||||
If UpdateWwwClaim And .HeadersExists Then wwwClaim = .Headers.Value(wwwClaimName)
|
||||
If .CookiesExists Then token = If(.Cookies.FirstOrDefault(Function(c) c.Name = tokenName)?.Value, String.Empty)
|
||||
Else
|
||||
If .HeadersExists Then
|
||||
wwwClaim = .Headers.Value(wwwClaimName)
|
||||
If UpdateWwwClaim Then wwwClaim = .Headers.Value(wwwClaimName)
|
||||
token = .Headers.Value(tokenName)
|
||||
End If
|
||||
End If
|
||||
End With
|
||||
|
||||
If Not wwwClaim.IsEmptyString Then Destination.Headers.Add(SiteSettings.Header_IG_WWW_CLAIM, wwwClaim)
|
||||
If UpdateWwwClaim And Not wwwClaim.IsEmptyString Then Destination.Headers.Add(SiteSettings.Header_IG_WWW_CLAIM, wwwClaim)
|
||||
If Not token.IsEmptyString Then Destination.Headers.Add(SiteSettings.Header_CSRF_TOKEN, token)
|
||||
If Not isInternal Then
|
||||
Destination.Cookies.Update(Source.Cookies, CookieKeeper.UpdateModes.ReplaceByNameAll, False, EDP.SendToLog)
|
||||
|
||||
@@ -19,7 +19,7 @@ Namespace API.Instagram
|
||||
Friend Class SiteSettings : Inherits SiteSettingsBase
|
||||
#Region "Declarations"
|
||||
#Region "Providers"
|
||||
Private Class TimersChecker : Inherits FieldsCheckerProviderBase
|
||||
Friend Class TimersChecker : Inherits FieldsCheckerProviderBase
|
||||
Private ReadOnly LVProvider As New ANumbers With {.FormatOptions = ANumbers.Options.GroupIntegral}
|
||||
Private ReadOnly _LowestValue As Integer
|
||||
Friend Sub New(ByVal LowestValue As Integer)
|
||||
@@ -32,7 +32,7 @@ Namespace API.Instagram
|
||||
If Not ACheck(Of Integer)(Value) Then
|
||||
TypeError = True
|
||||
ElseIf CInt(Value) < _LowestValue Then
|
||||
ErrorMessage = $"The value of [{Name}] field must be greater than or equal to {_LowestValue.NumToString(LVProvider)}"
|
||||
ErrorMessage = $"The value of '{Name}' field must be greater than or equal to {_LowestValue.NumToString(LVProvider)}"
|
||||
HasError = True
|
||||
Else
|
||||
Return Value
|
||||
@@ -47,7 +47,7 @@ Namespace API.Instagram
|
||||
If v > 0 Or v = -1 Then
|
||||
Return Value
|
||||
Else
|
||||
ErrorMessage = $"The value of [{Name}] field must be greater than 0 or equal to -1"
|
||||
ErrorMessage = $"The value of '{Name}' field must be greater than 0 or equal to -1"
|
||||
HasError = True
|
||||
Return Nothing
|
||||
End If
|
||||
@@ -62,24 +62,38 @@ Namespace API.Instagram
|
||||
Friend Const Header_ASBD_ID As String = "X-Asbd-Id"
|
||||
Friend Const Header_Browser As String = "Sec-Ch-Ua"
|
||||
Friend Const Header_BrowserExt As String = "Sec-Ch-Ua-Full-Version-List"
|
||||
Friend Const Header_Platform As String = "Sec-Ch-Ua-Platform-Version"
|
||||
Friend Const Header_Platform_Verion As String = "Sec-Ch-Ua-Platform-Version"
|
||||
<PropertyOption(ControlText:="x-csrftoken", ControlToolTip:="Can be automatically extracted from cookies", IsAuth:=True, AllowNull:=True), ControlNumber(2), PClonable(Clone:=False)>
|
||||
Friend ReadOnly Property HH_CSRF_TOKEN As PropertyValue
|
||||
<CookieValueExtractor(NameOf(HH_CSRF_TOKEN))>
|
||||
Private Function GetValueFromCookies(ByVal PropName As String, ByVal c As CookieKeeper) As String
|
||||
Return c.GetCookieValue(Header_CSRF_TOKEN_COOKIE, PropName, NameOf(HH_CSRF_TOKEN))
|
||||
End Function
|
||||
<PropertyOption(ControlText:="x-ig-app-id", IsAuth:=True, AllowNull:=False), ControlNumber(3), PClonable(Clone:=False)>
|
||||
Friend Property HH_IG_APP_ID As PropertyValue
|
||||
Friend ReadOnly Property HH_IG_APP_ID As PropertyValue
|
||||
<PropertyOption(ControlText:="x-asbd-id", IsAuth:=True, AllowNull:=True), ControlNumber(4), PClonable(Clone:=False)>
|
||||
Friend Property HH_ASBD_ID As PropertyValue
|
||||
Friend ReadOnly Property HH_ASBD_ID As PropertyValue
|
||||
'PropertyOption(ControlText:="x-ig-www-claim", IsAuth:=True, AllowNull:=True)
|
||||
<ControlNumber(5), PClonable(Clone:=False)>
|
||||
Friend Property HH_IG_WWW_CLAIM As PropertyValue
|
||||
<PropertyOption(ControlText:="sec-ch-ua", IsAuth:=True, AllowNull:=True), ControlNumber(6), PClonable>
|
||||
Private Property HH_BROWSER As PropertyValue
|
||||
<PropertyOption(ControlText:="sec-ch-ua-full", ControlToolTip:="sec-ch-ua-full-version-list", IsAuth:=True, AllowNull:=True), ControlNumber(7), PClonable>
|
||||
Private Property HH_BROWSER_EXT As PropertyValue
|
||||
<PropertyOption(ControlText:="sec-ch-ua-platform-ver", ControlToolTip:="sec-ch-ua-platform-version", IsAuth:=True, AllowNull:=True), ControlNumber(8), PClonable>
|
||||
Private Property HH_PLATFORM As PropertyValue
|
||||
<PropertyOption(ControlText:="UserAgent", IsAuth:=True, AllowNull:=True), ControlNumber(9), PClonable>
|
||||
Private Property HH_USER_AGENT As PropertyValue
|
||||
Friend ReadOnly Property HH_IG_WWW_CLAIM As PropertyValue
|
||||
Private ReadOnly Property HH_IG_WWW_CLAIM_IS_ZERO As Boolean
|
||||
Get
|
||||
Dim v$ = AConvert(Of String)(HH_IG_WWW_CLAIM.Value, String.Empty)
|
||||
Return Not v.IsEmptyString AndAlso v = "0"
|
||||
End Get
|
||||
End Property
|
||||
<PropertyOption(ControlText:="sec-ch-ua", IsAuth:=True, AllowNull:=True,
|
||||
InheritanceName:=SettingsCLS.HEADER_DEF_sec_ch_ua), ControlNumber(6), PClonable, PXML(OnlyForChecked:=True)>
|
||||
Private ReadOnly Property HH_BROWSER As PropertyValue
|
||||
<PropertyOption(ControlText:="sec-ch-ua-full", ControlToolTip:="sec-ch-ua-full-version-list", IsAuth:=True, AllowNull:=True,
|
||||
InheritanceName:=SettingsCLS.HEADER_DEF_sec_ch_ua_full_version_list), ControlNumber(7), PClonable, PXML(OnlyForChecked:=True)>
|
||||
Private ReadOnly Property HH_BROWSER_EXT As PropertyValue
|
||||
<PropertyOption(ControlText:="sec-ch-ua-platform-ver", ControlToolTip:="sec-ch-ua-platform-version", IsAuth:=True, AllowNull:=True, LeftOffset:=135,
|
||||
InheritanceName:=SettingsCLS.HEADER_DEF_sec_ch_ua_platform_version), ControlNumber(8), PClonable, PXML(OnlyForChecked:=True)>
|
||||
Private ReadOnly Property HH_PLATFORM As PropertyValue
|
||||
<PropertyOption(ControlText:="UserAgent", IsAuth:=True, AllowNull:=True,
|
||||
InheritanceName:=SettingsCLS.HEADER_DEF_UserAgent), ControlNumber(9), PClonable, PXML(OnlyForChecked:=True)>
|
||||
Private ReadOnly Property HH_USER_AGENT As PropertyValue
|
||||
Friend Overrides Function BaseAuthExists() As Boolean
|
||||
Return Responser.CookiesExists And ACheck(HH_IG_APP_ID.Value) And ACheck(HH_CSRF_TOKEN.Value)
|
||||
End Function
|
||||
@@ -95,7 +109,7 @@ Namespace API.Instagram
|
||||
Case NameOf(HH_CSRF_TOKEN) : f = Header_CSRF_TOKEN
|
||||
Case NameOf(HH_BROWSER) : f = Header_Browser
|
||||
Case NameOf(HH_BROWSER_EXT) : f = Header_BrowserExt
|
||||
Case NameOf(HH_PLATFORM) : f = Header_Platform
|
||||
Case NameOf(HH_PLATFORM) : f = Header_Platform_Verion
|
||||
Case NameOf(HH_USER_AGENT) : isUserAgent = True
|
||||
End Select
|
||||
If Not f.IsEmptyString Then
|
||||
@@ -106,17 +120,55 @@ Namespace API.Instagram
|
||||
End If
|
||||
End If
|
||||
End Sub
|
||||
#Region "HH_IG_WWW_CLAIM"
|
||||
<PropertyOption(ControlText:="ig-www-claim update interval", IsAuth:=True, LeftOffset:=150), PXML, ControlNumber(10), PClonable, HiddenControl>
|
||||
Private ReadOnly Property HH_IG_WWW_CLAIM_UPDATE_INTERVAL As PropertyValue
|
||||
<PropertyOption(ControlText:="ig-www-claim: always 0", ControlToolTip:="Keep token value always = 0", IsAuth:=True),
|
||||
PXML, ControlNumber(11), PClonable, HiddenControl>
|
||||
Friend ReadOnly Property HH_IG_WWW_CLAIM_ALWAYS_ZERO As PropertyValue
|
||||
<PropertyOption(ControlText:="ig-www-claim: reset each session", ControlToolTip:="Set 'x-ig-www-claim' to '0' before each session", IsAuth:=True),
|
||||
PXML, ControlNumber(12), PClonable, HiddenControl>
|
||||
Friend ReadOnly Property HH_IG_WWW_CLAIM_RESET_EACH_SESSION As PropertyValue
|
||||
<PropertyOption(ControlText:="ig-www-claim: reset each target", ControlToolTip:="Set 'x-ig-www-claim' to '0' before each target", IsAuth:=True),
|
||||
PXML, ControlNumber(13), PClonable, HiddenControl>
|
||||
Friend ReadOnly Property HH_IG_WWW_CLAIM_RESET_EACH_TARGET As PropertyValue
|
||||
<PropertyOption(ControlText:="ig-www-claim: use in requests", IsAuth:=True), PXML, ControlNumber(14), PClonable, HiddenControl>
|
||||
Friend ReadOnly Property HH_IG_WWW_CLAIM_USE As PropertyValue
|
||||
<PropertyOption(ControlText:="ig-www-claim: use default algorithm to update", IsAuth:=True), PXML, ControlNumber(15), PClonable, HiddenControl>
|
||||
Friend ReadOnly Property HH_IG_WWW_CLAIM_USE_DEFAULT_ALGO As PropertyValue
|
||||
<Provider(NameOf(HH_IG_WWW_CLAIM_UPDATE_INTERVAL), FieldsChecker:=True)>
|
||||
Private ReadOnly Property TokenUpdateIntervalProvider As IFormatProvider
|
||||
#End Region
|
||||
<PropertyOption(ControlText:="Use GraphQL to download", IsAuth:=True), PXML, ControlNumber(16), PClonable>
|
||||
Friend ReadOnly Property USE_GQL As PropertyValue
|
||||
#End Region
|
||||
#Region "Download properties"
|
||||
<PropertyOption(ControlText:="Request timer", AllowNull:=False), PXML("RequestsWaitTimer"), ControlNumber(20), PClonable>
|
||||
Friend Const TimersUrgentTip As String = vbCr & "It is highly recommended not to change the default value."
|
||||
<PropertyOption(ControlText:="Request timer (any)",
|
||||
ControlToolTip:="The timer (in milliseconds) that SCrawler should wait before executing the next request." &
|
||||
vbCr & "The default value is 1'000." & vbCr & "The minimum value is 0." & TimersUrgentTip, AllowNull:=False),
|
||||
PXML, ControlNumber(19), PClonable>
|
||||
Friend ReadOnly Property RequestsWaitTimer_Any As PropertyValue
|
||||
<Provider(NameOf(RequestsWaitTimer_Any), FieldsChecker:=True)>
|
||||
Private ReadOnly Property RequestsWaitTimer_AnyProvider As IFormatProvider
|
||||
<PropertyOption(ControlText:="Request timer",
|
||||
ControlToolTip:="The time value (in milliseconds) that the program will wait before processing the next 'Request time counter' request." &
|
||||
vbCr & "The default value is 1'000." & vbCr & "The minimum value is 100." & TimersUrgentTip,
|
||||
AllowNull:=False), PXML, ControlNumber(20), PClonable>
|
||||
Friend ReadOnly Property RequestsWaitTimer As PropertyValue
|
||||
<Provider(NameOf(RequestsWaitTimer), FieldsChecker:=True)>
|
||||
Private ReadOnly Property RequestsWaitTimerProvider As IFormatProvider
|
||||
<PropertyOption(ControlText:="Request timer counter", AllowNull:=False, LeftOffset:=120), PXML("RequestsWaitTimerTaskCount"), ControlNumber(21), PClonable>
|
||||
<PropertyOption(ControlText:="Request timer counter",
|
||||
ControlToolTip:="How many requests will be sent to Instagram before the program waits 'Request timer'." &
|
||||
vbCr & "The default value is 1." & vbCr & "The minimum value is 1." & TimersUrgentTip,
|
||||
AllowNull:=False, LeftOffset:=120), PXML, ControlNumber(21), PClonable>
|
||||
Friend ReadOnly Property RequestsWaitTimerTaskCount As PropertyValue
|
||||
<Provider(NameOf(RequestsWaitTimerTaskCount), FieldsChecker:=True)>
|
||||
Private ReadOnly Property RequestsWaitTimerTaskCountProvider As IFormatProvider
|
||||
<PropertyOption(ControlText:="Posts limit timer", AllowNull:=False), PXML("SleepTimerOnPostsLimit"), ControlNumber(22), PClonable>
|
||||
<PropertyOption(ControlText:="Posts limit timer",
|
||||
ControlToolTip:="The time value (in milliseconds) the program will wait before processing the next request after 195 requests." &
|
||||
vbCr & "The default value is 60'000." & vbCr & "The minimum value is 10'000." & TimersUrgentTip,
|
||||
AllowNull:=False), PXML, ControlNumber(22), PClonable>
|
||||
Friend ReadOnly Property SleepTimerOnPostsLimit As PropertyValue
|
||||
<Provider(NameOf(SleepTimerOnPostsLimit), FieldsChecker:=True)>
|
||||
Private ReadOnly Property SleepTimerOnPostsLimitProvider As IFormatProvider
|
||||
@@ -140,18 +192,38 @@ Namespace API.Instagram
|
||||
#Region "Download ready"
|
||||
<PropertyOption(ControlText:="Download timeline", ControlToolTip:="Download timeline"), PXML, ControlNumber(10), PClonable>
|
||||
Friend ReadOnly Property DownloadTimeline As PropertyValue
|
||||
<PXML> Private ReadOnly Property DownloadTimeline_Def As PropertyValue
|
||||
<PropertyOption(ControlText:="Download reels", ControlToolTip:="Download reels"), PXML, ControlNumber(11), PClonable>
|
||||
Friend ReadOnly Property DownloadReels As PropertyValue
|
||||
<PXML> Private ReadOnly Property DownloadReels_Def As PropertyValue
|
||||
<PropertyOption(ControlText:="Download stories", ControlToolTip:="Download stories"), PXML, ControlNumber(12), PClonable>
|
||||
Friend ReadOnly Property DownloadStories As PropertyValue
|
||||
<PXML> Private ReadOnly Property DownloadStories_Def As PropertyValue
|
||||
<PropertyOption(ControlText:="Download stories: user", ControlToolTip:="Download stories (user)"), PXML, ControlNumber(13), PClonable>
|
||||
Friend ReadOnly Property DownloadStoriesUser As PropertyValue
|
||||
<PXML> Private ReadOnly Property DownloadStoriesUser_Def As PropertyValue
|
||||
<PropertyOption(ControlText:="Download tagged", ControlToolTip:="Download tagged posts"), PXML, ControlNumber(14), PClonable>
|
||||
Friend ReadOnly Property DownloadTagged As PropertyValue
|
||||
<PXML> Private ReadOnly Property DownloadTagged_Def As PropertyValue
|
||||
#End Region
|
||||
#Region "429 bypass"
|
||||
<PXML("InstagramDownloadingErrorDate")>
|
||||
Private ReadOnly Property DownloadingErrorDate As PropertyValue
|
||||
<Provider(NameOf(DownloadingErrorDate))>
|
||||
Private ReadOnly Property DownloadingErrorDateProvider As IFormatProvider =
|
||||
New CustomProvider(Function(ByVal v As Object, ByVal d As Type) As Object
|
||||
If d Is GetType(Date) Then
|
||||
Return AConvert(Of Date)(v, AModes.Var, Nothing)
|
||||
ElseIf d Is GetType(String) Then
|
||||
If Not IsNothing(v) AndAlso TypeOf v Is Date AndAlso CDate(v) = Date.MinValue Then
|
||||
Return String.Empty
|
||||
Else
|
||||
Return AConvert(Of String)(v, AModes.XML, String.Empty)
|
||||
End If
|
||||
Else
|
||||
Return Nothing
|
||||
End If
|
||||
End Function)
|
||||
Friend Property LastApplyingValue As Integer? = Nothing
|
||||
Friend ReadOnly Property ReadyForDownload As Boolean
|
||||
Get
|
||||
@@ -165,11 +237,64 @@ Namespace API.Instagram
|
||||
End With
|
||||
End Get
|
||||
End Property
|
||||
Private Const LastDownloadDateResetInterval As Integer = 60
|
||||
<PXML> Private ReadOnly Property LastDownloadDate As PropertyValue
|
||||
<PXML> Private ReadOnly Property LastRequestsCount As PropertyValue
|
||||
Private ReadOnly MyLastRequests As Dictionary(Of Date, Integer)
|
||||
Private ReadOnly Property MyLastRequestsDate As Date
|
||||
Get
|
||||
Try
|
||||
Return If(MyLastRequests.Count > 0, MyLastRequests.Keys.Max, Now.AddDays(-1))
|
||||
Catch ex As Exception
|
||||
Return ErrorsDescriber.Execute(EDP.SendToLog + EDP.ReturnValue, ex, "[SiteSettings.Instagram.MyLastRequestsDate]", Now.AddDays(-1))
|
||||
End Try
|
||||
End Get
|
||||
End Property
|
||||
Private Property MyLastRequestsCount As Integer
|
||||
Get
|
||||
Try
|
||||
Return If(MyLastRequests.Count > 0, MyLastRequests.Values.Sum, 0)
|
||||
Catch ex As Exception
|
||||
Return ErrorsDescriber.Execute(EDP.SendToLog + EDP.ReturnValue, ex, "[SiteSettings.Instagram.MyLastRequestsCount]", 0)
|
||||
End Try
|
||||
End Get
|
||||
Set(ByVal NewValue As Integer)
|
||||
If Not MyLastRequests.ContainsKey(ActiveSessionDate) Then
|
||||
MyLastRequests.Add(ActiveSessionDate, NewValue)
|
||||
Else
|
||||
MyLastRequests(ActiveSessionDate) += NewValue
|
||||
End If
|
||||
End Set
|
||||
End Property
|
||||
Private Sub RefreshMyLastRequests(Optional ByVal DateToReplace As Date? = Nothing)
|
||||
Try
|
||||
With MyLastRequests
|
||||
If .Count > 0 Then
|
||||
Dim d As Date
|
||||
For i% = .Count - 1 To 0 Step -1
|
||||
d = .Keys(i)
|
||||
If (Not DateToReplace.HasValue OrElse ActiveJobs < 1 OrElse d <> ActiveSessionDate) And
|
||||
d.AddMinutes(LastDownloadDateResetInterval) < Now Then .Remove(d)
|
||||
Next
|
||||
End If
|
||||
If .Count > 0 Then
|
||||
If DateToReplace.HasValue Then
|
||||
If .Keys.Contains(ActiveSessionDate) Then
|
||||
Dim v% = .Item(ActiveSessionDate)
|
||||
.Remove(ActiveSessionDate)
|
||||
.Add(DateToReplace.Value, v)
|
||||
End If
|
||||
End If
|
||||
LastDownloadDate.Value = .Keys.Max
|
||||
LastRequestsCount.Value = .Values.Sum
|
||||
End If
|
||||
End With
|
||||
Catch ex As Exception
|
||||
ErrorsDescriber.Execute(EDP.SendToLog, ex, "[SiteSettings.Instagram.RefreshMyLastRequests]")
|
||||
End Try
|
||||
End Sub
|
||||
<PropertyOption(IsInformationLabel:=True), ControlNumber(100)>
|
||||
Private Property LastRequestsCountLabel As PropertyValue
|
||||
Private ReadOnly LastRequestsCountLabelStr As Func(Of Integer, String) = Function(r) $"Number of spent requests: {r.NumToGroupIntegral}"
|
||||
Private ReadOnly Property LastRequestsCountLabel As PropertyValue
|
||||
Private TooManyRequestsReadyForCatch As Boolean = True
|
||||
Friend Function GetWaitDate() As Date
|
||||
With DownloadingErrorDate
|
||||
@@ -224,13 +349,16 @@ Namespace API.Instagram
|
||||
asbd = .Value(Header_ASBD_ID)
|
||||
browser = .Value(Header_Browser)
|
||||
browserExt = .Value(Header_BrowserExt)
|
||||
platform = .Value(Header_Platform)
|
||||
platform = .Value(Header_Platform_Verion)
|
||||
End If
|
||||
'.Add(Header_IG_WWW_CLAIM, 0)
|
||||
.Add("Dnt", 1)
|
||||
.Add("Dpr", 1)
|
||||
.Add("Sec-Ch-Ua-Mobile", "?0")
|
||||
.Add("Sec-Ch-Ua-Model", """""")
|
||||
.Add("Sec-Ch-Ua-Platform", """Windows""")
|
||||
.Add("Sec-Fetch-Dest", "empty")
|
||||
.Add("Sec-Fetch-Mode", "cors")
|
||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecFetchDest, "empty"))
|
||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecFetchMode, "cors"))
|
||||
.Add("Sec-Fetch-Site", "same-origin")
|
||||
.Add("X-Requested-With", "XMLHttpRequest")
|
||||
End With
|
||||
@@ -248,12 +376,28 @@ Namespace API.Instagram
|
||||
HH_PLATFORM = New PropertyValue(platform, GetType(String), Sub(v) ChangeResponserFields(NameOf(HH_PLATFORM), v))
|
||||
HH_USER_AGENT = New PropertyValue(useragent, GetType(String), Sub(v) ChangeResponserFields(NameOf(HH_USER_AGENT), v))
|
||||
|
||||
DownloadTimeline = New PropertyValue(True)
|
||||
DownloadReels = New PropertyValue(False)
|
||||
DownloadStories = New PropertyValue(True)
|
||||
DownloadStoriesUser = New PropertyValue(True)
|
||||
DownloadTagged = New PropertyValue(False)
|
||||
HH_IG_WWW_CLAIM_UPDATE_INTERVAL = New PropertyValue(120)
|
||||
HH_IG_WWW_CLAIM_ALWAYS_ZERO = New PropertyValue(False)
|
||||
HH_IG_WWW_CLAIM_RESET_EACH_SESSION = New PropertyValue(True)
|
||||
HH_IG_WWW_CLAIM_RESET_EACH_TARGET = New PropertyValue(True)
|
||||
HH_IG_WWW_CLAIM_USE = New PropertyValue(True)
|
||||
HH_IG_WWW_CLAIM_USE_DEFAULT_ALGO = New PropertyValue(True)
|
||||
TokenUpdateIntervalProvider = New TokenRefreshIntervalProvider
|
||||
USE_GQL = New PropertyValue(False)
|
||||
|
||||
DownloadTimeline = New PropertyValue(True)
|
||||
DownloadTimeline_Def = New PropertyValue(DownloadTimeline.Value, GetType(Boolean))
|
||||
DownloadReels = New PropertyValue(False)
|
||||
DownloadReels_Def = New PropertyValue(DownloadReels.Value, GetType(Boolean))
|
||||
DownloadStories = New PropertyValue(True)
|
||||
DownloadStories_Def = New PropertyValue(DownloadStories.Value, GetType(Boolean))
|
||||
DownloadStoriesUser = New PropertyValue(True)
|
||||
DownloadStoriesUser_Def = New PropertyValue(DownloadStoriesUser.Value, GetType(Boolean))
|
||||
DownloadTagged = New PropertyValue(False)
|
||||
DownloadTagged_Def = New PropertyValue(DownloadTagged.Value, GetType(Boolean))
|
||||
|
||||
RequestsWaitTimer_Any = New PropertyValue(1000)
|
||||
RequestsWaitTimer_AnyProvider = New TimersChecker(0)
|
||||
RequestsWaitTimer = New PropertyValue(1000)
|
||||
RequestsWaitTimerProvider = New TimersChecker(100)
|
||||
RequestsWaitTimerTaskCount = New PropertyValue(1)
|
||||
@@ -269,17 +413,22 @@ Namespace API.Instagram
|
||||
TaggedNotifyLimit = New PropertyValue(200)
|
||||
TaggedNotifyLimitProvider = New TaggedNotifyLimitChecker
|
||||
|
||||
DownloadingErrorDate = New PropertyValue(Nothing, GetType(Date))
|
||||
DownloadingErrorDate = New PropertyValue(Now.AddYears(10), GetType(Date))
|
||||
LastDownloadDate = New PropertyValue(Now.AddDays(-1))
|
||||
LastRequestsCount = New PropertyValue(0)
|
||||
LastRequestsCountLabel = New PropertyValue(LastRequestsCountLabelStr.Invoke(LastRequestsCount.Value))
|
||||
LastRequestsCount.OnChangeFunction = Sub(vv) LastRequestsCountLabel.Value = LastRequestsCountLabelStr.Invoke(vv)
|
||||
LastRequestsCountLabel = New PropertyValue(String.Empty, GetType(String))
|
||||
MyLastRequests = New Dictionary(Of Date, Integer)
|
||||
|
||||
_AllowUserAgentUpdate = False
|
||||
UrlPatternUser = "https://www.instagram.com/{0}/"
|
||||
UserRegex = RParams.DMS(String.Format(UserRegexDefaultPattern, "instagram.com/"), 1)
|
||||
ImageVideoContains = "instagram.com"
|
||||
End Sub
|
||||
Friend Overrides Sub EndInit()
|
||||
Try : MyLastRequests.Add(LastDownloadDate.Value, LastRequestsCount.Value) : Catch : End Try
|
||||
If Not CBool(HH_IG_WWW_CLAIM_USE.Value) Then Responser.Headers.Remove(Header_IG_WWW_CLAIM)
|
||||
MyBase.EndInit()
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "PropertiesDataChecker"
|
||||
<PropertiesDataChecker({NameOf(TaggedNotifyLimit)})>
|
||||
@@ -312,11 +461,23 @@ Namespace API.Instagram
|
||||
Return ActiveJobs < 2 AndAlso Not SkipUntilNextSession AndAlso ReadyForDownload AndAlso BaseAuthExists() AndAlso DownloadTimeline.Value
|
||||
End Function
|
||||
Private ActiveJobs As Integer = 0
|
||||
Private ActiveSessionDate As Date
|
||||
Private _NextWNM As UserData.WNM = UserData.WNM.Notify
|
||||
Private _NextTagged As Boolean = True
|
||||
Friend Overrides Sub DownloadStarted(ByVal What As Download)
|
||||
ActiveJobs += 1
|
||||
If CDate(LastDownloadDate.Value).AddMinutes(120) < Now Or Not ACheck(HH_IG_WWW_CLAIM.Value) Then HH_IG_WWW_CLAIM.Value = "0"
|
||||
If ActiveJobs = 1 Then ActiveSessionDate = Now
|
||||
If Not HH_IG_WWW_CLAIM_IS_ZERO AndAlso
|
||||
(
|
||||
(CBool(HH_IG_WWW_CLAIM_USE_DEFAULT_ALGO.Value) AndAlso MyLastRequestsDate.AddMinutes(HH_IG_WWW_CLAIM_UPDATE_INTERVAL.Value) < Now) Or
|
||||
Not ACheck(HH_IG_WWW_CLAIM.Value) Or
|
||||
(
|
||||
Not (
|
||||
CBool(HH_IG_WWW_CLAIM_USE_DEFAULT_ALGO.Value) And
|
||||
(CBool(HH_IG_WWW_CLAIM_RESET_EACH_SESSION.Value) Or CBool(HH_IG_WWW_CLAIM_ALWAYS_ZERO.Value))
|
||||
)
|
||||
)
|
||||
) Then HH_IG_WWW_CLAIM.Value = "0"
|
||||
End Sub
|
||||
Friend Overrides Sub BeforeStartDownload(ByVal User As Object, ByVal What As Download)
|
||||
With DirectCast(User, UserData)
|
||||
@@ -324,10 +485,9 @@ Namespace API.Instagram
|
||||
.WaitNotificationMode = _NextWNM
|
||||
.TaggedCheckSession = _NextTagged
|
||||
End If
|
||||
If CDate(LastDownloadDate.Value).AddMinutes(60) > Now Then
|
||||
.RequestsCount = LastRequestsCount.Value
|
||||
If MyLastRequestsDate.AddMinutes(LastDownloadDateResetInterval) > Now Then
|
||||
.RequestsCount = MyLastRequestsCount
|
||||
Else
|
||||
LastRequestsCount.Value = 0
|
||||
.RequestsCount = 0
|
||||
End If
|
||||
End With
|
||||
@@ -337,8 +497,7 @@ Namespace API.Instagram
|
||||
_NextWNM = .WaitNotificationMode
|
||||
If _NextWNM = UserData.WNM.SkipTemp Or _NextWNM = UserData.WNM.SkipCurrent Then _NextWNM = UserData.WNM.Notify
|
||||
_NextTagged = .TaggedCheckSession
|
||||
LastDownloadDate.Value = Now
|
||||
LastRequestsCount.Value = .RequestsCount
|
||||
MyLastRequestsCount = .RequestsCountSession
|
||||
_FieldsChangerSuspended = True
|
||||
HH_IG_WWW_CLAIM.Value = Responser.Headers.Value(Header_IG_WWW_CLAIM)
|
||||
HH_CSRF_TOKEN.Value = Responser.Headers.Value(Header_CSRF_TOKEN)
|
||||
@@ -348,7 +507,7 @@ Namespace API.Instagram
|
||||
Friend Overrides Sub DownloadDone(ByVal What As Download)
|
||||
_NextWNM = UserData.WNM.Notify
|
||||
_NextTagged = True
|
||||
LastDownloadDate.Value = Now
|
||||
RefreshMyLastRequests(Now)
|
||||
ActiveJobs -= 1
|
||||
SkipUntilNextSession = False
|
||||
End Sub
|
||||
@@ -362,7 +521,17 @@ Namespace API.Instagram
|
||||
Private ____HH_PLATFORM As String = String.Empty
|
||||
Private ____HH_USER_AGENT As String = String.Empty
|
||||
Private ____Cookies As CookieKeeper = Nothing
|
||||
Private __DownloadTimeline As Boolean = False
|
||||
Private __DownloadReels As Boolean = False
|
||||
Private __DownloadStories As Boolean = False
|
||||
Private __DownloadStoriesUser As Boolean = False
|
||||
Private __DownloadTagged As Boolean = False
|
||||
Friend Overrides Sub BeginEdit()
|
||||
RefreshMyLastRequests()
|
||||
Dim v% = MyLastRequestsCount
|
||||
Dim d$ = String.Empty
|
||||
If v > 0 Then d = $" ({MyLastRequestsDate.ToStringDate(DateTimeDefaultProvider)})"
|
||||
LastRequestsCountLabel.Value = $"Number of spent requests: {v.NumToGroupIntegral}{d}"
|
||||
____HH_CSRF_TOKEN = AConvert(Of String)(HH_CSRF_TOKEN.Value, String.Empty)
|
||||
____HH_IG_APP_ID = AConvert(Of String)(HH_IG_APP_ID.Value, String.Empty)
|
||||
____HH_ASBD_ID = AConvert(Of String)(HH_ASBD_ID.Value, String.Empty)
|
||||
@@ -371,6 +540,11 @@ Namespace API.Instagram
|
||||
____HH_PLATFORM = AConvert(Of String)(HH_PLATFORM.Value, String.Empty)
|
||||
____HH_USER_AGENT = AConvert(Of String)(HH_USER_AGENT.Value, String.Empty)
|
||||
____Cookies = Responser.Cookies.Copy
|
||||
__DownloadTimeline = DownloadTimeline.Value
|
||||
__DownloadReels = DownloadReels.Value
|
||||
__DownloadStories = DownloadStories.Value
|
||||
__DownloadStoriesUser = DownloadStoriesUser.Value
|
||||
__DownloadTagged = DownloadTagged.Value
|
||||
MyBase.BeginEdit()
|
||||
End Sub
|
||||
Friend Overrides Sub Update()
|
||||
@@ -383,12 +557,33 @@ Namespace API.Instagram
|
||||
New With {.ValueOld = ____HH_PLATFORM, .ValueNew = AConvert(Of String)(HH_PLATFORM.Value, String.Empty).ToString},
|
||||
New With {.ValueOld = ____HH_USER_AGENT, .ValueNew = AConvert(Of String)(HH_USER_AGENT.Value, String.Empty).ToString}
|
||||
}
|
||||
Dim credentialsUpdated As Boolean = False
|
||||
If vals.Any(Function(v) Not v.ValueOld = v.ValueNew) OrElse
|
||||
Not Responser.Cookies.ListEquals(____Cookies) Then HH_IG_WWW_CLAIM.Value = 0
|
||||
Not Responser.Cookies.ListEquals(____Cookies) Then HH_IG_WWW_CLAIM.Value = 0 : credentialsUpdated = True
|
||||
If Responser.CookiesExists Then
|
||||
Dim csrf$ = If(Responser.Cookies.FirstOrDefault(Function(c) c.Name.StringToLower = Header_CSRF_TOKEN_COOKIE)?.Value, String.Empty)
|
||||
If Not csrf.IsEmptyString Then HH_CSRF_TOKEN.Value = csrf
|
||||
Dim csrf$ = GetValueFromCookies(NameOf(HH_CSRF_TOKEN), Responser.Cookies)
|
||||
If Not csrf.IsEmptyString Then
|
||||
If Not AEquals(Of String)(CStr(HH_CSRF_TOKEN.Value), csrf) Then credentialsUpdated = True
|
||||
HH_CSRF_TOKEN.Value = csrf
|
||||
End If
|
||||
End If
|
||||
If credentialsUpdated AndAlso {New With {.ValueOld = __DownloadTimeline, .ValueNew = CBool(DownloadTimeline.Value)},
|
||||
New With {.ValueOld = __DownloadReels, .ValueNew = CBool(DownloadReels.Value)},
|
||||
New With {.ValueOld = __DownloadStories, .ValueNew = CBool(DownloadStories.Value)},
|
||||
New With {.ValueOld = __DownloadStoriesUser, .ValueNew = CBool(DownloadStoriesUser.Value)},
|
||||
New With {.ValueOld = __DownloadTagged, .ValueNew = CBool(DownloadTagged.Value)}}.
|
||||
All(Function(v) v.ValueOld = v.ValueNew) Then
|
||||
DownloadTimeline.Value = DownloadTimeline_Def.Value
|
||||
DownloadReels.Value = DownloadReels_Def.Value
|
||||
DownloadStories.Value = DownloadStories_Def.Value
|
||||
DownloadStoriesUser.Value = DownloadStoriesUser_Def.Value
|
||||
DownloadTagged.Value = DownloadTagged_Def.Value
|
||||
End If
|
||||
DownloadTimeline_Def.Value = DownloadTimeline.Value
|
||||
DownloadReels_Def.Value = DownloadReels.Value
|
||||
DownloadStories_Def.Value = DownloadStories.Value
|
||||
DownloadStoriesUser_Def.Value = DownloadStoriesUser.Value
|
||||
DownloadTagged_Def.Value = DownloadTagged.Value
|
||||
End If
|
||||
MyBase.Update()
|
||||
End Sub
|
||||
@@ -415,6 +610,12 @@ Namespace API.Instagram
|
||||
Return ErrorsDescriber.Execute(EDP.SendToLog, ex, "Can't open user's post", String.Empty)
|
||||
End Try
|
||||
End Function
|
||||
#End Region
|
||||
#Region "IDisposable Support"
|
||||
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
|
||||
If Not disposedValue And disposing And Not MyLastRequests Is Nothing Then MyLastRequests.Clear()
|
||||
MyBase.Dispose(disposing)
|
||||
End Sub
|
||||
#End Region
|
||||
End Class
|
||||
End Namespace
|
||||
347
SCrawler/API/Instagram/UserData.GQL.vb
Normal file
@@ -0,0 +1,347 @@
|
||||
' 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 System.Threading
|
||||
Imports SCrawler.API.Base
|
||||
Imports PersonalUtilities.Functions.XML
|
||||
Imports PersonalUtilities.Functions.RegularExpressions
|
||||
Imports PersonalUtilities.Tools.Web.Clients
|
||||
Imports PersonalUtilities.Tools.Web.Documents.JSON
|
||||
Namespace API.Instagram
|
||||
Partial Friend Class UserData
|
||||
#Region "Tokens"
|
||||
Protected Property Token_dtsg As String = String.Empty
|
||||
Protected ReadOnly Property Token_dtsg_Var As String
|
||||
Get
|
||||
Return If(Token_dtsg.IsEmptyString, String.Empty, SymbolsConverter.ASCII.EncodeSymbolsOnly(Token_dtsg))
|
||||
End Get
|
||||
End Property
|
||||
Protected Property Token_lsd As String = String.Empty
|
||||
Protected Sub ResetBaseTokens()
|
||||
Token_dtsg = String.Empty
|
||||
Token_lsd = String.Empty
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Headers"
|
||||
Friend Const GQL_HEADER_FB_FRINDLY_NAME As String = "x-fb-friendly-name"
|
||||
Friend Const GQL_HEADER_FB_LSD As String = "x-fb-lsd"
|
||||
#End Region
|
||||
#Region "Data constants"
|
||||
Private Const GQL_UserData_DocId As String = "7381344031985950"
|
||||
Private Const GQL_UserData_FbFriendlyName As String = "PolarisProfilePageContentQuery"
|
||||
|
||||
Private Const GQL_Highlights_DocId As String = "8298007123561120"
|
||||
Private Const GQL_Highlights_DocId_Second As String = "7559771384111300"
|
||||
Private Const GQL_Highlights_FbFriendlyName As String = "PolarisProfileStoryHighlightsTrayContentQuery"
|
||||
Private Const GQL_Highlights_FbFriendlyName_Second As String = "PolarisStoriesV3HighlightsPageQuery"
|
||||
|
||||
Private Const GQL_UserStories_DocId As String = "25231722019806941"
|
||||
Private Const GQL_UserStories_FbFriendlyName As String = "PolarisStoriesV3ReelPageStandaloneQuery"
|
||||
|
||||
Private Const GQL_Timeline_DocId As String = "7268577773270422"
|
||||
Private Const GQL_Timeline_FbFriendlyName As String = "PolarisProfilePostsQuery"
|
||||
Private Const GQL_Timeline_DocId_Second As String = "7286316061475375"
|
||||
Private Const GQL_Timeline_FbFriendlyName_Second As String = "PolarisProfilePostsTabContentQuery_connection"
|
||||
|
||||
Private Const GQL_Reels_DocId As String = "7191572580905225"
|
||||
Private Const GQL_Reels_FbFriendlyName As String = "PolarisProfileReelsTabContentQuery"
|
||||
|
||||
Private Const GQL_Tagged_DocId As String = "7289408964443685"
|
||||
Private Const GQL_Tagged_FbFriendlyName As String = "PolarisProfileTaggedTabContentQuery"
|
||||
#End Region
|
||||
#Region "Url & var constants"
|
||||
Private Const GQL_URL_PATTERN_VARS As String = "doc_id={0}&lsd={1}&fb_dtsg={2}&fb_api_req_friendly_name={3}&variables={4}"
|
||||
Private Const GQL_URL As String = "https://www.instagram.com/api/graphql"
|
||||
Private Const GQL_URL_Q As String = "https://www.instagram.com/graphql/query"
|
||||
#End Region
|
||||
#Region "Download functions"
|
||||
Protected Sub UpdateHeadersGQL(ByVal HeaderValue As String)
|
||||
Responser.Headers.Add(GQL_HEADER_FB_FRINDLY_NAME, HeaderValue)
|
||||
Responser.Headers.Add(GQL_HEADER_FB_LSD, Token_lsd)
|
||||
End Sub
|
||||
<Obsolete("Use 'GET' function: 'GetUserData'", False)>
|
||||
Private Sub GetUserDataGQL(ByVal Token As CancellationToken)
|
||||
Dim vars$ = String.Format(GQL_URL_PATTERN_VARS, GQL_UserData_DocId, Token_lsd, Token_dtsg_Var, GQL_UserData_FbFriendlyName,
|
||||
SymbolsConverter.ASCII.EncodeSymbolsOnly("{" & $"""id"":""{ID}"",""relay_header"":false,""render_surface"":""PROFILE""" & "}"))
|
||||
UpdateRequestNumber()
|
||||
ChangeResponserMode(True)
|
||||
UpdateHeadersGQL(GQL_UserData_FbFriendlyName)
|
||||
Dim r$ = Responser.GetResponse(GQL_URL, vars)
|
||||
If Not r.IsEmptyString Then
|
||||
Using j As EContainer = JsonDocument.Parse(r)
|
||||
If j.ListExists Then
|
||||
With j({"data", "user"})
|
||||
If .ListExists Then
|
||||
UserSiteName = .Value("full_name").IfNullOrEmpty(UserSiteName)
|
||||
Dim f As New SFile With {.Path = DownloadContentDefault_GetRootDir(), .Name = "ProfilePicture", .Extension = "jpg"}
|
||||
Dim pic$ = .Value({"hd_profile_pic_url_info"}, "url").IfNullOrEmpty(.Value("profile_pic_url"))
|
||||
If Not pic.IsEmptyString Then GetWebFile(pic, f, EDP.ReturnValue)
|
||||
UserDescriptionUpdate(.Value("biography"))
|
||||
End If
|
||||
End With
|
||||
End If
|
||||
End Using
|
||||
End If
|
||||
End Sub
|
||||
Private Function GetTimelineGQL(ByVal Cursor As String, ByVal Token As CancellationToken) As String
|
||||
Const none_cursor$ = "none"
|
||||
Dim nextCursor$ = String.Empty, hasNextPage$ = String.Empty
|
||||
Dim vars$
|
||||
|
||||
ThrowAny(Token)
|
||||
UpdateRequestNumber()
|
||||
ChangeResponserMode(True)
|
||||
|
||||
If Cursor.IsEmptyString Then
|
||||
vars = "{""data"":{""count"":50,""include_relationship_info"":true,""latest_besties_reel_media"":true,""latest_reel_media"":true},""username"":""" &
|
||||
NameTrue & """,""__relay_internal__pv__PolarisShareMenurelayprovider"":false}"
|
||||
vars = String.Format(GQL_URL_PATTERN_VARS, GQL_Timeline_DocId, Token_lsd, Token_dtsg_Var, GQL_Timeline_FbFriendlyName,
|
||||
SymbolsConverter.ASCII.EncodeSymbolsOnly(vars))
|
||||
UpdateHeadersGQL(GQL_Timeline_FbFriendlyName)
|
||||
Else
|
||||
vars = "{""after"":""" & Cursor & """,""before"":null,""data"":{""count"":50,""include_relationship_info"":true,""latest_besties_reel_media"":true,""latest_reel_media"":true},""first"":50,""last"":null,""username"":""" &
|
||||
NameTrue & """,""__relay_internal__pv__PolarisShareMenurelayprovider"":false}"
|
||||
vars = String.Format(GQL_URL_PATTERN_VARS, GQL_Timeline_DocId_Second, Token_lsd, Token_dtsg_Var, GQL_Timeline_FbFriendlyName_Second,
|
||||
SymbolsConverter.ASCII.EncodeSymbolsOnly(vars))
|
||||
UpdateHeadersGQL(GQL_Timeline_FbFriendlyName_Second)
|
||||
End If
|
||||
|
||||
DefaultParser_ElemNode = {"node"}
|
||||
|
||||
Dim r$ = Responser.GetResponse(GQL_URL, vars)
|
||||
If Not r.IsEmptyString Then
|
||||
Using j As EContainer = JsonDocument.Parse(r)
|
||||
If j.ListExists Then
|
||||
With j({"data", "xdt_api__v1__feed__user_timeline_graphql_connection"})
|
||||
If .ListExists Then
|
||||
With .Item("page_info")
|
||||
If .ListExists Then
|
||||
nextCursor = .Value("end_cursor")
|
||||
hasNextPage = .Value("has_next_page").FromXML(Of Boolean)(False)
|
||||
End If
|
||||
End With
|
||||
With .Item("edges")
|
||||
If .ListExists Then
|
||||
If Not DefaultParser(.Self, Sections.Timeline, Token) Then Throw New ExitException
|
||||
End If
|
||||
End With
|
||||
End If
|
||||
End With
|
||||
End If
|
||||
End Using
|
||||
End If
|
||||
|
||||
Return If(hasNextPage And (Not nextCursor.IsEmptyString AndAlso Not nextCursor.StringToLower = none_cursor), nextCursor, String.Empty)
|
||||
End Function
|
||||
Private Function GetHighlightsGQL_List() As List(Of String)
|
||||
|
||||
Dim nextCursor$ = String.Empty, hasNextPage$ = String.Empty
|
||||
Dim i% = -1
|
||||
Dim hList As New List(Of String)
|
||||
Dim tmpList As New List(Of String)
|
||||
Dim vars$ = String.Format(GQL_URL_PATTERN_VARS, GQL_Highlights_DocId, Token_lsd, Token_dtsg_Var, GQL_Highlights_FbFriendlyName,
|
||||
SymbolsConverter.ASCII.EncodeSymbolsOnly("{" & $"""user_id"":""{ID}""" & "}"))
|
||||
UpdateRequestNumber()
|
||||
ChangeResponserMode(True)
|
||||
UpdateHeadersGQL(GQL_Highlights_FbFriendlyName)
|
||||
Dim r$ = Responser.GetResponse(GQL_URL_Q, vars)
|
||||
|
||||
If Not r.IsEmptyString Then
|
||||
Using j As EContainer = JsonDocument.Parse(r)
|
||||
If j.ListExists Then
|
||||
'With j({"data"})
|
||||
With j({"data", "highlights"})
|
||||
If .ListExists Then
|
||||
With .Item("page_info")
|
||||
If .ListExists Then
|
||||
nextCursor = .Value("end_cursor")
|
||||
hasNextPage = .Value("has_next_page").FromXML(Of Boolean)(False)
|
||||
End If
|
||||
End With
|
||||
With .Item({"edges"})
|
||||
If .ListExists Then hList.ListAddList(.Select(Function(jj) jj.Value({"node"}, "id")), LNC)
|
||||
End With
|
||||
End If
|
||||
End With
|
||||
End If
|
||||
End Using
|
||||
End If
|
||||
Return hList
|
||||
End Function
|
||||
Private Sub GetHighlightsGQL(ByRef StoriesList As List(Of String), ByVal Token As CancellationToken)
|
||||
Const highlightData$ = """first"":50,""initial_reel_id"":""{0}"",""last"":2,""reel_ids"":[{1}]"
|
||||
Dim tmpList As New List(Of String)
|
||||
Dim i% = -1
|
||||
If StoriesList.ListExists Then
|
||||
tmpList.AddRange(StoriesList.Take(10))
|
||||
StoriesList.RemoveRange(0, tmpList.Count)
|
||||
|
||||
Dim vars$ = String.Format(GQL_URL_PATTERN_VARS, GQL_Highlights_DocId_Second, Token_lsd, Token_dtsg_Var, GQL_Highlights_FbFriendlyName_Second,
|
||||
SymbolsConverter.ASCII.EncodeSymbolsOnly("{" & String.Format(highlightData, tmpList(0), tmpList.Select(Function(hl) $"""{hl}""").ListToString(",")) & "}"))
|
||||
ThrowAny(Token)
|
||||
UpdateRequestNumber()
|
||||
ChangeResponserMode(True)
|
||||
UpdateHeadersGQL(GQL_Highlights_FbFriendlyName_Second)
|
||||
Dim r$ = Responser.GetResponse(GQL_URL_Q, vars)
|
||||
If Not r.IsEmptyString Then
|
||||
Using j As EContainer = JsonDocument.Parse(r)
|
||||
If j.ListExists Then
|
||||
With j({"data", "xdt_api__v1__feed__reels_media__connection", "edges"})
|
||||
If .ListExists Then
|
||||
ProgressPre.ChangeMax(.Count)
|
||||
For Each n As EContainer In .Self : GetStoriesData_ParseSingleHighlight(n("node"), i, False, Token) : Next
|
||||
End If
|
||||
End With
|
||||
End If
|
||||
End Using
|
||||
End If
|
||||
tmpList.Clear()
|
||||
End If
|
||||
|
||||
tmpList.Clear()
|
||||
End Sub
|
||||
Private Sub GetUserStoriesGQL(ByVal Token As CancellationToken)
|
||||
'"{" & $"""user_id"":""{ID}""" & "}"
|
||||
Dim vars$ = String.Format(GQL_URL_PATTERN_VARS, GQL_UserStories_DocId, Token_lsd, Token_dtsg_Var, GQL_UserStories_FbFriendlyName,
|
||||
SymbolsConverter.ASCII.EncodeSymbolsOnly("{" & $"""reel_ids_arr"":[""{ID}""]" & "}"))
|
||||
UpdateRequestNumber()
|
||||
ChangeResponserMode(True)
|
||||
UpdateHeadersGQL(GQL_UserStories_FbFriendlyName)
|
||||
Dim r$ = Responser.GetResponse(GQL_URL, vars)
|
||||
If Not r.IsEmptyString Then
|
||||
Using j As EContainer = JsonDocument.Parse(r)
|
||||
If j.ListExists Then
|
||||
Dim i% = -1
|
||||
GetStoriesData_ParseSingleHighlight(j.ItemF({"data", "xdt_api__v1__feed__reels_media", "reels_media", 0}), i, True, Token)
|
||||
End If
|
||||
End Using
|
||||
End If
|
||||
End Sub
|
||||
Private WriteOnly Property GetReelsGQL_SetEnvir As Boolean
|
||||
Set(ByVal init As Boolean)
|
||||
If init Then
|
||||
ObtainMedia_SetReelsFunc()
|
||||
DefaultParser_PostUrlCreator = Function(post) $"{MySiteSettings.GetUserUrl(Me).TrimEnd("/")}/reel/{post.Code}"
|
||||
Else
|
||||
ObtainMedia_SizeFuncPic = Nothing
|
||||
ObtainMedia_SizeFuncVid = Nothing
|
||||
DefaultParser_PostUrlCreator = DefaultParser_PostUrlCreator_Default
|
||||
End If
|
||||
End Set
|
||||
End Property
|
||||
''' <returns>Response</returns>
|
||||
Private Function GetReelsGQL(ByVal Cursor As String) As String
|
||||
GetReelsGQL_SetEnvir = True
|
||||
|
||||
Dim errData$ = String.Empty
|
||||
If Cursor.IsEmptyString And Not ValidateBaseTokens() Then GetPageTokens()
|
||||
If Cursor.IsEmptyString And Not ValidateBaseTokens(errData) Then ValidateBaseTokens_Error(errData)
|
||||
|
||||
Dim vars$ = """data"":{""include_feed_video"":true,""page_size"":50,""target_user_id"":""" & ID & """}"
|
||||
If Not Cursor.IsEmptyString Then vars = $"""after"":""{Cursor}"",""before"":null,{vars},""first"":4,""last"":null"
|
||||
vars = String.Format(GQL_URL_PATTERN_VARS, GQL_Reels_DocId, Token_lsd, Token_dtsg_Var, GQL_Reels_FbFriendlyName,
|
||||
SymbolsConverter.ASCII.EncodeSymbolsOnly("{" & vars & "}"))
|
||||
UpdateRequestNumber()
|
||||
ChangeResponserMode(True)
|
||||
UpdateHeadersGQL(GQL_Reels_FbFriendlyName)
|
||||
Return Responser.GetResponse(GQL_URL, vars)
|
||||
End Function
|
||||
''' <summary>Response</summary>
|
||||
Private Function GetTaggedGQL(ByVal Cursor As String) As String
|
||||
'default count = 12
|
||||
'max count = 21
|
||||
Dim vars$
|
||||
If Cursor.IsEmptyString Then
|
||||
vars = String.Format(GQL_URL_PATTERN_VARS, GQL_Tagged_DocId, Token_lsd, Token_dtsg_Var, GQL_Tagged_FbFriendlyName,
|
||||
SymbolsConverter.ASCII.EncodeSymbolsOnly("{" & $"""count"":50,""user_id"":""{ID}""" & "}"))
|
||||
Else
|
||||
vars = String.Format(GQL_URL_PATTERN_VARS, GQL_Tagged_DocId, Token_lsd, Token_dtsg_Var, GQL_Tagged_FbFriendlyName,
|
||||
SymbolsConverter.ASCII.EncodeSymbolsOnly("{" & $"""after"":""{Cursor}"",""before"":null,""count"":50,""first"":50,""last"":null,""user_id"":""{ID}""" & "}"))
|
||||
End If
|
||||
UpdateRequestNumber()
|
||||
ChangeResponserMode(True)
|
||||
UpdateHeadersGQL(GQL_Tagged_FbFriendlyName)
|
||||
Return Responser.GetResponse(GQL_URL, vars)
|
||||
End Function
|
||||
#End Region
|
||||
#Region "ValidateBaseTokens"
|
||||
Protected Overridable Overloads Function ValidateBaseTokens() As Boolean
|
||||
Return ValidateBaseTokens(Nothing)
|
||||
End Function
|
||||
Protected Overridable Overloads Function ValidateBaseTokens(ByRef ErrData As String) As Boolean
|
||||
ErrData = String.Empty
|
||||
If Token_dtsg.IsEmptyString Then ErrData.StringAppend("dtsg")
|
||||
If Token_lsd.IsEmptyString Then ErrData.StringAppend("lsd")
|
||||
Return ErrData.IsEmptyString
|
||||
End Function
|
||||
Protected Overridable Sub ValidateBaseTokens_Error(Optional ByVal ErrData As String = "")
|
||||
If _UseGQL Then DisableSection(Sections.Timeline)
|
||||
ExitException.ThrowTokens(Me, ErrData)
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "GetPageTokens"
|
||||
Private Sub GetPageTokens()
|
||||
ResetBaseTokens()
|
||||
Try
|
||||
UpdateRequestNumber()
|
||||
ChangeResponserMode(False, Not _UseGQL)
|
||||
With Responser
|
||||
With .Headers
|
||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecFetchDest, "document"))
|
||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecFetchMode, "navigate"))
|
||||
End With
|
||||
End With
|
||||
Dim r$ = Responser.GetResponse(MySiteSettings.GetUserUrl(Me))
|
||||
ParseTokens(r, 0)
|
||||
Catch ex As Exception
|
||||
Finally
|
||||
ChangeResponserMode(_UseGQL, Not _UseGQL)
|
||||
End Try
|
||||
End Sub
|
||||
Protected Sub ParseTokens(ByVal r As String, ByVal Attempt As Integer)
|
||||
Try
|
||||
If Not r.IsEmptyString Then
|
||||
ResetBaseTokens()
|
||||
Select Case Attempt
|
||||
Case 0
|
||||
Dim rr As RParams = RParams.DM(PageTokenRegexPatternDefault, 0, RegexReturn.List, EDP.ReturnValue)
|
||||
Dim tokens As List(Of String) = RegexReplace(r, rr)
|
||||
Dim tt$, ttVal$
|
||||
If tokens.ListExists Then
|
||||
With rr
|
||||
.Match = Nothing
|
||||
.MatchSub = 1
|
||||
.WhatGet = RegexReturn.Value
|
||||
End With
|
||||
For Each tt In tokens
|
||||
If Not Token_lsd.IsEmptyString And Not Token_dtsg.IsEmptyString Then
|
||||
Exit For
|
||||
Else
|
||||
ttVal = RegexReplace(tt, rr)
|
||||
If Not ttVal.IsEmptyString Then
|
||||
If ttVal.Contains(":") Then
|
||||
If Token_dtsg.IsEmptyString Then Token_dtsg = ttVal
|
||||
Else
|
||||
If Token_lsd.IsEmptyString Then Token_lsd = ttVal
|
||||
End If
|
||||
End If
|
||||
End If
|
||||
Next
|
||||
End If
|
||||
Case 1
|
||||
Token_dtsg = RegexReplace(r, Regex_UserToken_dtsg)
|
||||
Token_lsd = RegexReplace(r, Regex_UserToken_lsd)
|
||||
End Select
|
||||
If Not ValidateBaseTokens() And Attempt = 0 Then ParseTokens(r, Attempt + 1)
|
||||
End If
|
||||
Catch
|
||||
End Try
|
||||
End Sub
|
||||
#End Region
|
||||
End Class
|
||||
End Namespace
|
||||
@@ -69,7 +69,6 @@ Namespace API.Instagram
|
||||
Return New EContainer("Post", ID, {New EAttribute(Name_Section, CInt(Section)), New EAttribute(Name_Code, Code)})
|
||||
End Function
|
||||
End Structure
|
||||
Friend Const Header_FB_LSD As String = "x-fb-lsd"
|
||||
Private ReadOnly Property MySiteSettings As SiteSettings
|
||||
Get
|
||||
Return DirectCast(HOST.Source, SiteSettings)
|
||||
@@ -139,14 +138,19 @@ Namespace API.Instagram
|
||||
Friend Sub New()
|
||||
PostsKVIDs = New List(Of PostKV)
|
||||
PostsToReparse = New List(Of PostKV)
|
||||
_ResponserAutoUpdateCookies = True
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Download data"
|
||||
Private WwwClaimUpdate As Boolean = True
|
||||
Private WwwClaimUpdate_R As Boolean = True
|
||||
Private WwwClaimDefaultAlgo As Boolean = True
|
||||
Private WwwClaimUse As Boolean = True
|
||||
Private E560Thrown As Boolean = False
|
||||
Friend Err5xx As Integer = -1
|
||||
Private Class ExitException : Inherits Exception
|
||||
Friend Property Is560 As Boolean = False
|
||||
Friend Property IsTokens As Boolean = False
|
||||
Friend Property TokensData As String = String.Empty
|
||||
Friend Shared Sub Throw560(ByRef Source As UserData)
|
||||
If Not Source.E560Thrown Then
|
||||
MyMainLOG = $"{Source.ToStringForLog}: ({IIf(Source.Err5xx > 0, Source.Err5xx, 560)}) Download skipped until next session"
|
||||
@@ -154,6 +158,10 @@ Namespace API.Instagram
|
||||
End If
|
||||
Throw New ExitException With {.Is560 = True}
|
||||
End Sub
|
||||
Friend Shared Sub ThrowTokens(ByRef Source As UserData, ByVal Data As String)
|
||||
MyMainLOG = $"{Source.ToStringForLog}: failed to update some{IIf(Data.IsEmptyString, String.Empty, $" ({Data})")} credentials"
|
||||
Throw New ExitException With {.IsTokens = True, .TokensData = Data}
|
||||
End Sub
|
||||
End Class
|
||||
Private ReadOnly Property MyFilePostsKV As SFile
|
||||
Get
|
||||
@@ -235,8 +243,75 @@ Namespace API.Instagram
|
||||
Private _DownloadingInProgress As Boolean = False
|
||||
Private _Limit As Integer = -1
|
||||
Private _TotalPostsParsed As Integer = 0
|
||||
Private _LastWwwClaim As String = String.Empty
|
||||
Private _ResponserGQLMode As Boolean = False
|
||||
Private _UseGQL As Boolean = False
|
||||
Private Sub ChangeResponserMode(ByVal GQL As Boolean, Optional ByVal Force As Boolean = False)
|
||||
If Not _ResponserGQLMode = GQL Or Force Then
|
||||
_ResponserGQLMode = GQL
|
||||
ChangeResponserMode_StoreWwwClaim()
|
||||
Responser.Headers.Clear()
|
||||
Responser.Headers.AddRange(MySiteSettings.Responser.Headers)
|
||||
If GQL Then
|
||||
WwwClaimUpdate = False
|
||||
With Responser
|
||||
.Method = "POST"
|
||||
.ContentType = "application/x-www-form-urlencoded"
|
||||
.Referer = MySiteSettings.GetUserUrl(Me)
|
||||
.CookiesExtractMode = Responser.CookiesExtractModes.Any
|
||||
With .Headers
|
||||
.Remove(SiteSettings.Header_IG_WWW_CLAIM)
|
||||
.Add("origin", "https://www.instagram.com")
|
||||
.Add("authority", "www.instagram.com")
|
||||
End With
|
||||
End With
|
||||
Else
|
||||
WwwClaimUpdate = WwwClaimUpdate_R
|
||||
With Responser
|
||||
.Method = "GET"
|
||||
.ContentType = Nothing
|
||||
.Referer = Nothing
|
||||
.CookiesExtractMode = MySiteSettings.Responser.CookiesExtractMode
|
||||
With .Headers
|
||||
.Remove("origin")
|
||||
.Remove("authority")
|
||||
.Remove(GQL_HEADER_FB_FRINDLY_NAME)
|
||||
.Remove(GQL_HEADER_FB_LSD)
|
||||
Dim hv$ = MySiteSettings.Responser.Headers.Value(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecFetchDest)).IfNullOrEmpty("empty")
|
||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecFetchDest, hv))
|
||||
hv = MySiteSettings.Responser.Headers.Value(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecFetchMode)).IfNullOrEmpty("cors")
|
||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecFetchMode, hv))
|
||||
If Not _UseGQL And WwwClaimUse Then .Add(SiteSettings.Header_IG_WWW_CLAIM, _LastWwwClaim)
|
||||
End With
|
||||
End With
|
||||
End If
|
||||
End If
|
||||
End Sub
|
||||
Private Sub ChangeResponserMode_StoreWwwClaim()
|
||||
If Not _UseGQL Then
|
||||
With Responser.Headers
|
||||
If .Contains(SiteSettings.Header_IG_WWW_CLAIM) AndAlso Not .Value(SiteSettings.Header_IG_WWW_CLAIM).IsEmptyString Then _LastWwwClaim = .Value(SiteSettings.Header_IG_WWW_CLAIM)
|
||||
End With
|
||||
End If
|
||||
End Sub
|
||||
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
|
||||
ResetBaseTokens()
|
||||
UserNameRequested = False
|
||||
RequestsCountSession = 0
|
||||
_LastWwwClaim = String.Empty
|
||||
_ResponserGQLMode = False
|
||||
_UseGQL = MySiteSettings.USE_GQL.Value
|
||||
WwwClaimUse = MySiteSettings.HH_IG_WWW_CLAIM_USE.Value
|
||||
WwwClaimDefaultAlgo = MySiteSettings.HH_IG_WWW_CLAIM_USE_DEFAULT_ALGO.Value
|
||||
With MySiteSettings : WwwClaimUpdate = (Not CBool(.HH_IG_WWW_CLAIM_ALWAYS_ZERO.Value) And CBool(.HH_IG_WWW_CLAIM_USE.Value)) Or
|
||||
WwwClaimDefaultAlgo : End With
|
||||
WwwClaimUpdate_R = WwwClaimUpdate
|
||||
Dim upClaimRequest As Action = Sub() If WwwClaimUpdate And Not WwwClaimDefaultAlgo And CBool(MySiteSettings.HH_IG_WWW_CLAIM_RESET_EACH_TARGET.Value) Then _
|
||||
Responser.Headers.Add(SiteSettings.Header_IG_WWW_CLAIM, 0)
|
||||
|
||||
DefaultParser_ElemNode = Nothing
|
||||
ChangeResponserMode(_UseGQL)
|
||||
|
||||
Dim s As Sections = Sections.Timeline
|
||||
Dim errorFound As Boolean = False
|
||||
Try
|
||||
@@ -251,6 +326,7 @@ Namespace API.Instagram
|
||||
Dim dt As Func(Of Boolean) = Function() (CBool(MySiteSettings.DownloadTimeline.Value) And GetTimeline) Or IsSavedPosts
|
||||
If dt.Invoke And Not LastCursor.IsEmptyString Then
|
||||
s = IIf(IsSavedPosts, Sections.SavedPosts, Sections.Timeline)
|
||||
upClaimRequest.Invoke
|
||||
DownloadData(LastCursor, s, Token)
|
||||
ProgressPre.Done()
|
||||
ThrowAny(Token)
|
||||
@@ -258,27 +334,51 @@ Namespace API.Instagram
|
||||
End If
|
||||
If dt.Invoke And Not HasError Then
|
||||
s = IIf(IsSavedPosts, Sections.SavedPosts, Sections.Timeline)
|
||||
upClaimRequest.Invoke
|
||||
ChangeResponserMode(_UseGQL)
|
||||
DownloadData(String.Empty, s, Token)
|
||||
ProgressPre.Done()
|
||||
ThrowAny(Token)
|
||||
If Not HasError Then FirstLoadingDone = True
|
||||
End If
|
||||
DefaultParser_ElemNode = Nothing
|
||||
If FirstLoadingDone Then LastCursor = String.Empty
|
||||
If Not IsSavedPosts AndAlso MySiteSettings.BaseAuthExists() Then
|
||||
DefaultParser_ElemNode = Nothing
|
||||
ChangeResponserMode(_UseGQL)
|
||||
If CBool(MySiteSettings.DownloadReels.Value) And GetReels Then
|
||||
s = Sections.Reels
|
||||
DefaultParser_ElemNode = {"node", "media"}
|
||||
upClaimRequest.Invoke
|
||||
ChangeResponserMode(True)
|
||||
DownloadData(String.Empty, s, Token)
|
||||
DefaultParser_ElemNode = Nothing
|
||||
DownloadReels_SetEnvir = False
|
||||
GetReelsGQL_SetEnvir = False
|
||||
ProgressPre.Done()
|
||||
End If
|
||||
If CBool(MySiteSettings.DownloadStories.Value) And GetStories Then s = Sections.Stories : DownloadData(String.Empty, s, Token) : ProgressPre.Done()
|
||||
If CBool(MySiteSettings.DownloadStoriesUser.Value) And GetStoriesUser Then s = Sections.UserStories : DownloadData(String.Empty, s, Token) : ProgressPre.Done()
|
||||
If CBool(MySiteSettings.DownloadTagged.Value) And GetTaggedData Then
|
||||
s = Sections.Tagged
|
||||
DefaultParser_ElemNode = Nothing
|
||||
ChangeResponserMode(_UseGQL)
|
||||
If CBool(MySiteSettings.DownloadStories.Value) And GetStories Then
|
||||
s = Sections.Stories
|
||||
upClaimRequest.Invoke
|
||||
DownloadData(String.Empty, s, Token)
|
||||
ProgressPre.Done()
|
||||
End If
|
||||
DefaultParser_ElemNode = Nothing
|
||||
ChangeResponserMode(_UseGQL)
|
||||
If CBool(MySiteSettings.DownloadStoriesUser.Value) And GetStoriesUser Then
|
||||
s = Sections.UserStories
|
||||
upClaimRequest.Invoke
|
||||
DownloadData(String.Empty, s, Token)
|
||||
ProgressPre.Done()
|
||||
End If
|
||||
DefaultParser_ElemNode = Nothing
|
||||
ChangeResponserMode(_UseGQL)
|
||||
If CBool(MySiteSettings.DownloadTagged.Value) And GetTaggedData Then
|
||||
s = Sections.Tagged
|
||||
upClaimRequest.Invoke
|
||||
DownloadData(String.Empty, s, Token)
|
||||
ProgressPre.Done()
|
||||
DefaultParser_ElemNode = Nothing
|
||||
If PostsToReparse.Count > 0 Then DownloadPosts(Token, True)
|
||||
End If
|
||||
End If
|
||||
@@ -289,7 +389,7 @@ Namespace API.Instagram
|
||||
Throw ex
|
||||
Finally
|
||||
DefaultParser_ElemNode = Nothing
|
||||
DownloadReels_SetEnvir = False
|
||||
GetReelsGQL_SetEnvir = False
|
||||
E560Thrown = False
|
||||
UpdateResponser()
|
||||
ValidateExtension()
|
||||
@@ -315,13 +415,13 @@ Namespace API.Instagram
|
||||
If _DownloadingInProgress AndAlso Not Responser Is Nothing AndAlso Not Responser.Disposed Then
|
||||
_DownloadingInProgress = False
|
||||
Responser_ResponseReceived_RemoveHandler()
|
||||
Declarations.UpdateResponser(Responser, MySiteSettings.Responser)
|
||||
Declarations.UpdateResponser(Responser, MySiteSettings.Responser, WwwClaimUpdate)
|
||||
End If
|
||||
Catch
|
||||
End Try
|
||||
End Sub
|
||||
Protected Overrides Sub Responser_ResponseReceived(ByVal Sender As Object, ByVal e As EventArguments.WebDataResponse)
|
||||
Declarations.UpdateResponser(e, Responser)
|
||||
Declarations.UpdateResponser(e, Responser, WwwClaimUpdate)
|
||||
End Sub
|
||||
Protected Enum Sections : Timeline : Reels : Tagged : Stories : UserStories : SavedPosts : End Enum
|
||||
Protected Const StoriesFolder As String = "Stories"
|
||||
@@ -329,6 +429,12 @@ Namespace API.Instagram
|
||||
#Region "429 bypass"
|
||||
Private Const MaxPostsCount As Integer = 200
|
||||
Friend Property RequestsCount As Integer = 0
|
||||
Friend Property RequestsCountSession As Integer = 0
|
||||
Private Sub UpdateRequestNumber()
|
||||
If CInt(MySiteSettings.RequestsWaitTimer_Any.Value) > 0 Then Thread.Sleep(CInt(MySiteSettings.RequestsWaitTimer_Any.Value))
|
||||
RequestsCount += 1
|
||||
RequestsCountSession += 1
|
||||
End Sub
|
||||
Friend Enum WNM As Integer
|
||||
Notify = 0
|
||||
SkipCurrent = 1
|
||||
@@ -468,46 +574,74 @@ Namespace API.Instagram
|
||||
Dim HasNextPage As Boolean = False
|
||||
Dim EndCursor$ = String.Empty
|
||||
Dim PostID$ = String.Empty, PostDate$ = String.Empty, SpecFolder$ = String.Empty
|
||||
Dim TokensErrData$ = String.Empty
|
||||
Dim PostIDKV As PostKV
|
||||
Dim ENode() As Object = Nothing
|
||||
Dim processGetResponse As Boolean = True
|
||||
NextRequest(True)
|
||||
|
||||
'Check environment
|
||||
If Not IsSavedPosts Then
|
||||
If ID.IsEmptyString Then GetUserId()
|
||||
If ID.IsEmptyString Then GetUserData()
|
||||
If ID.IsEmptyString Then Throw New Plugin.ExitException("can't get user ID")
|
||||
If _UseGQL And Cursor.IsEmptyString And Not Section = Sections.SavedPosts Then
|
||||
If Not ValidateBaseTokens() Then GetPageTokens()
|
||||
If Not ValidateBaseTokens(TokensErrData) Then ValidateBaseTokens_Error(TokensErrData)
|
||||
End If
|
||||
End If
|
||||
|
||||
'Create query
|
||||
Select Case Section
|
||||
Case Sections.Timeline
|
||||
URL = $"https://www.instagram.com/api/v1/feed/user/{NameTrue}/username/?count=50" &
|
||||
If(Cursor.IsEmptyString, String.Empty, $"&max_id={Cursor}")
|
||||
ENode = Nothing
|
||||
If _UseGQL Then
|
||||
EndCursor = GetTimelineGQL(Cursor, Token)
|
||||
HasNextPage = Not EndCursor.IsEmptyString
|
||||
MySiteSettings.TooManyRequests(False)
|
||||
GoTo NextPageBlock
|
||||
Else
|
||||
URL = $"https://www.instagram.com/api/v1/feed/user/{NameTrue}/username/?count=50" &
|
||||
If(Cursor.IsEmptyString, String.Empty, $"&max_id={Cursor}")
|
||||
ENode = Nothing
|
||||
End If
|
||||
Case Sections.Reels
|
||||
r = DownloadReels(Cursor, Token)
|
||||
ChangeResponserMode(True)
|
||||
r = GetReelsGQL(Cursor)
|
||||
ENode = {"data", "xdt_api__v1__clips__user__connection_v2"}
|
||||
processGetResponse = False
|
||||
Case Sections.SavedPosts
|
||||
SavedPostsDownload(String.Empty, Token)
|
||||
Exit Sub
|
||||
ChangeResponserMode(False)
|
||||
EndCursor = SavedPostsDownload(String.Empty, Token)
|
||||
HasNextPage = Not EndCursor.IsEmptyString
|
||||
MySiteSettings.TooManyRequests(False)
|
||||
ThrowAny(Token)
|
||||
GoTo NextPageBlock
|
||||
Case Sections.Tagged
|
||||
Dim vars$ = "{""id"":" & ID & ",""first"":50,""after"":""" & Cursor & """}"
|
||||
vars = SymbolsConverter.ASCII.EncodeSymbolsOnly(vars)
|
||||
URL = $"https://www.instagram.com/graphql/query/?doc_id=17946422347485809&variables={vars}"
|
||||
ENode = {"data", "user", "edge_user_to_photos_of_you"}
|
||||
SpecFolder = TaggedFolder
|
||||
If _UseGQL Then
|
||||
r = GetTaggedGQL(Cursor)
|
||||
ENode = {"data", "xdt_api__v1__usertags__user_id__feed_connection"}
|
||||
processGetResponse = False
|
||||
Else
|
||||
Dim vars$ = "{""id"":" & ID & ",""first"":50,""after"":""" & Cursor & """}"
|
||||
vars = SymbolsConverter.ASCII.EncodeSymbolsOnly(vars)
|
||||
URL = $"https://www.instagram.com/graphql/query/?doc_id=17946422347485809&variables={vars}"
|
||||
ENode = {"data", "user", "edge_user_to_photos_of_you"}
|
||||
End If
|
||||
Case Sections.Stories
|
||||
If Not StoriesRequested Then
|
||||
StoriesList = GetStoriesList()
|
||||
StoriesList = If(_UseGQL, GetHighlightsGQL_List(), GetStoriesList())
|
||||
StoriesRequested = True
|
||||
MySiteSettings.TooManyRequests(False)
|
||||
RequestsCount += 1
|
||||
ThrowAny(Token)
|
||||
Continue Do
|
||||
End If
|
||||
If StoriesList.ListExists Then
|
||||
GetStoriesData(StoriesList, False, Token)
|
||||
If _UseGQL Then
|
||||
GetHighlightsGQL(StoriesList, Token)
|
||||
Else
|
||||
GetStoriesData(StoriesList, False, Token)
|
||||
End If
|
||||
MySiteSettings.TooManyRequests(False)
|
||||
RequestsCount += 1
|
||||
End If
|
||||
If StoriesList.ListExists Then
|
||||
Continue Do
|
||||
@@ -515,16 +649,17 @@ Namespace API.Instagram
|
||||
Throw New ExitException
|
||||
End If
|
||||
Case Sections.UserStories
|
||||
GetStoriesData(Nothing, True, Token)
|
||||
If _UseGQL Then GetUserStoriesGQL(Token) Else GetStoriesData(Nothing, True, Token)
|
||||
MySiteSettings.TooManyRequests(False)
|
||||
RequestsCount += 1
|
||||
Throw New ExitException
|
||||
End Select
|
||||
|
||||
'Get response
|
||||
If Not Section = Sections.Reels Then r = Responser.GetResponse(URL,, EDP.ThrowException)
|
||||
If processGetResponse Then
|
||||
UpdateRequestNumber()
|
||||
r = Responser.GetResponse(URL)
|
||||
End If
|
||||
MySiteSettings.TooManyRequests(False)
|
||||
RequestsCount += 1
|
||||
ThrowAny(Token)
|
||||
|
||||
'Parsing
|
||||
@@ -608,9 +743,11 @@ Namespace API.Instagram
|
||||
Else
|
||||
Throw New ExitException
|
||||
End If
|
||||
NextPageBlock:
|
||||
dValue = 0
|
||||
If HasNextPage And Not EndCursor.IsEmptyString Then DownloadData(EndCursor, Section, Token)
|
||||
Catch jsonNull As JsonDocumentException When jsonNull.State = WebDocumentEventArgs.States.Error And Section = Sections.Reels
|
||||
Catch jsonNull As JsonDocumentException When jsonNull.State = WebDocumentEventArgs.States.Error And
|
||||
(Section = Sections.Reels Or Section = Sections.SavedPosts)
|
||||
Throw jsonNull
|
||||
Catch eex As ExitException
|
||||
Throw eex
|
||||
@@ -618,10 +755,14 @@ Namespace API.Instagram
|
||||
dValue = ProcessException(ex, Token, $"data downloading error [{URL}]",, Section, False)
|
||||
End Try
|
||||
Loop
|
||||
Catch jsonNull2 As JsonDocumentException When jsonNull2.State = WebDocumentEventArgs.States.Error And Section = Sections.Reels
|
||||
Catch jsonNull2 As JsonDocumentException When jsonNull2.State = WebDocumentEventArgs.States.Error And
|
||||
(Section = Sections.Reels Or Section = Sections.SavedPosts)
|
||||
If Section = Sections.SavedPosts Then DisableSection(Section)
|
||||
Catch eex2 As ExitException
|
||||
If eex2.Is560 Then
|
||||
Throw New Plugin.ExitException With {.Silent = True}
|
||||
ElseIf eex2.IsTokens And _UseGQL Then
|
||||
Throw New Plugin.ExitException With {.Silent = True}
|
||||
Else
|
||||
If Not Section = Sections.Reels And (Section = Sections.Timeline Or Section = Sections.Tagged) And Not Cursor.IsEmptyString Then Throw eex2
|
||||
End If
|
||||
@@ -638,6 +779,7 @@ Namespace API.Instagram
|
||||
Dim before%
|
||||
Dim specFolder$ = IIf(IsTagged, "Tagged", String.Empty)
|
||||
If PostsToReparse.Count > 0 Then ProgressPre.ChangeMax(PostsToReparse.Count)
|
||||
ChangeResponserMode(False)
|
||||
Try
|
||||
Do While dValue = 1
|
||||
ThrowAny(Token)
|
||||
@@ -657,9 +799,9 @@ Namespace API.Instagram
|
||||
ThrowAny(Token)
|
||||
NextRequest(((i + 1) Mod 5) = 0)
|
||||
ThrowAny(Token)
|
||||
UpdateRequestNumber()
|
||||
r = Responser.GetResponse(URL,, e)
|
||||
MySiteSettings.TooManyRequests(False)
|
||||
RequestsCount += 1
|
||||
If Not r.IsEmptyString Then
|
||||
j = JsonDocument.Parse(r)
|
||||
If Not j Is Nothing Then
|
||||
@@ -692,27 +834,30 @@ Namespace API.Instagram
|
||||
ProcessException(DoEx, Token, $"downloading posts error [{URL}]",, Sections.Tagged)
|
||||
End Try
|
||||
End Sub
|
||||
Private Sub SavedPostsDownload(ByVal Cursor As String, ByVal Token As CancellationToken)
|
||||
''' <summary>Cursor</summary>
|
||||
Private Function SavedPostsDownload(ByVal Cursor As String, ByVal Token As CancellationToken) As String
|
||||
Dim URL$ = $"https://www.instagram.com/api/v1/feed/saved/posts/?max_id={Cursor}"
|
||||
Dim HasNextPage As Boolean = False
|
||||
Dim NextCursor$ = String.Empty
|
||||
ThrowAny(Token)
|
||||
Dim processNext As Boolean = False
|
||||
UpdateRequestNumber()
|
||||
Dim r$ = Responser.GetResponse(URL)
|
||||
Dim nodes As IEnumerable(Of EContainer) = Nothing
|
||||
If Not r.IsEmptyString Then
|
||||
Using e As EContainer = JsonDocument.Parse(r)
|
||||
If If(e?.Count, 0) > 0 Then
|
||||
If e.ListExists Then
|
||||
With e
|
||||
HasNextPage = .Value("more_available").FromXML(Of Boolean)(False)
|
||||
NextCursor = .Value("next_max_id")
|
||||
If .Contains("items") Then nodes = (From ee As EContainer In .Item("items") Where ee.Count > 0 Select ee(0))
|
||||
End With
|
||||
If nodes.ListExists AndAlso DefaultParser(nodes, Sections.SavedPosts, Token) AndAlso
|
||||
HasNextPage AndAlso Not NextCursor.IsEmptyString Then SavedPostsDownload(NextCursor, Token)
|
||||
HasNextPage AndAlso Not NextCursor.IsEmptyString Then processNext = True
|
||||
End If
|
||||
End Using
|
||||
End If
|
||||
End Sub
|
||||
Return If(processNext, NextCursor, String.Empty)
|
||||
End Function
|
||||
Protected DefaultParser_ElemNode() As Object = Nothing
|
||||
Protected DefaultParser_IgnorePass As Boolean = False
|
||||
Private ReadOnly DefaultParser_PostUrlCreator_Default As Func(Of PostKV, String) = Function(post) $"https://www.instagram.com/p/{post.Code}/"
|
||||
@@ -737,25 +882,29 @@ Namespace API.Instagram
|
||||
For Each nn In Items
|
||||
ProgressPre.Perform()
|
||||
With If(Not DefaultParser_ElemNode Is Nothing, nn.ItemF(DefaultParser_ElemNode), nn)
|
||||
PostIDKV = New PostKV(.Value("code"), .Value("id"), Section)
|
||||
PostOriginUrl = DefaultParser_PostUrlCreator(PostIDKV)
|
||||
Pinned = .Contains("timeline_pinned_user_ids")
|
||||
If Not DefaultParser_IgnorePass AndAlso PostKvExists(PostIDKV) Then
|
||||
If Not Pinned Then Return False
|
||||
Else
|
||||
_TempPostsList.Add(PostIDKV.ID)
|
||||
PostsKVIDs.ListAddValue(PostIDKV, LNC)
|
||||
PostDate = .Value("taken_at")
|
||||
If Not DefaultParser_IgnorePass And Not IsSavedPosts Then
|
||||
Select Case CheckDatesLimit(PostDate, UnixDate32Provider)
|
||||
Case DateResult.Skip : Continue For
|
||||
Case DateResult.Exit : If Not Pinned Then Return False
|
||||
End Select
|
||||
If .ListExists Then
|
||||
PostIDKV = New PostKV(.Value("code"), .Value("id"), Section)
|
||||
PostOriginUrl = DefaultParser_PostUrlCreator(PostIDKV)
|
||||
Pinned = .Contains("timeline_pinned_user_ids")
|
||||
If Not DefaultParser_IgnorePass AndAlso PostKvExists(PostIDKV) Then
|
||||
If Not Section = Sections.Timeline OrElse Not Pinned Then Return False
|
||||
Else
|
||||
_TempPostsList.Add(PostIDKV.ID)
|
||||
PostsKVIDs.ListAddValue(PostIDKV, LNC)
|
||||
PostDate = .Value("taken_at")
|
||||
If Not DefaultParser_IgnorePass And Not IsSavedPosts Then
|
||||
Select Case CheckDatesLimit(PostDate, UnixDate32Provider)
|
||||
Case DateResult.Skip : Continue For
|
||||
Case DateResult.Exit : If Not Pinned Then Return False
|
||||
End Select
|
||||
End If
|
||||
before = _TempMediaList.Count
|
||||
ObtainMedia(.Self, PostIDKV.ID, SpecFolder, PostDate,, PostOriginUrl, State, Attempts)
|
||||
If Not before = _TempMediaList.Count Then _TotalPostsParsed += 1
|
||||
If _Limit > 0 And _TotalPostsParsed >= _Limit Then Return False
|
||||
End If
|
||||
before = _TempMediaList.Count
|
||||
ObtainMedia(.Self, PostIDKV.ID, SpecFolder, PostDate,, PostOriginUrl, State, Attempts)
|
||||
If Not before = _TempMediaList.Count Then _TotalPostsParsed += 1
|
||||
If _Limit > 0 And _TotalPostsParsed >= _Limit Then Return False
|
||||
Else
|
||||
Return False
|
||||
End If
|
||||
End With
|
||||
Next
|
||||
@@ -765,106 +914,6 @@ Namespace API.Instagram
|
||||
End If
|
||||
End Function
|
||||
#End Region
|
||||
#Region "Get reels"
|
||||
Private _GetReels_LSD As String = String.Empty
|
||||
Private _GetReels_dtsg As String = String.Empty
|
||||
Private ReadOnly Property DownloadReels_Tokens_Valid As Boolean
|
||||
Get
|
||||
Return Not _GetReels_LSD.IsEmptyString And Not _GetReels_dtsg.IsEmptyString
|
||||
End Get
|
||||
End Property
|
||||
Private WriteOnly Property DownloadReels_SetEnvir As Boolean
|
||||
Set(ByVal init As Boolean)
|
||||
If init Then
|
||||
ObtainMedia_SetReelsFunc()
|
||||
DefaultParser_PostUrlCreator = Function(post) $"{MySiteSettings.GetUserUrl(Me).TrimEnd("/")}/reel/{post.Code}"
|
||||
Else
|
||||
ObtainMedia_SizeFuncPic = Nothing
|
||||
ObtainMedia_SizeFuncVid = Nothing
|
||||
DefaultParser_PostUrlCreator = DefaultParser_PostUrlCreator_Default
|
||||
End If
|
||||
End Set
|
||||
End Property
|
||||
Private Class Responser2 : Inherits Responser
|
||||
Friend Sub New(ByVal Source As Responser)
|
||||
MyBase.New
|
||||
Copy(Source)
|
||||
ErrorProcessor = New ResponserErrorProcessor(Source)
|
||||
End Sub
|
||||
End Class
|
||||
''' <returns>Response</returns>
|
||||
Private Function DownloadReels(ByVal Cursor As String, ByVal Token As CancellationToken) As String
|
||||
Const requestPattern$ = "https://www.instagram.com/api/graphql?fb_dtsg={0}&fb_api_req_friendly_name=PolarisProfileReelsTabContentQuery&lsd={1}&doc_id=7191572580905225&variables={2}"
|
||||
|
||||
DownloadReels_SetEnvir = True
|
||||
|
||||
If Cursor.IsEmptyString And Not DownloadReels_Tokens_Valid Then GetPageTokens()
|
||||
If Cursor.IsEmptyString And Not DownloadReels_Tokens_Valid Then Throw New ExitException
|
||||
|
||||
Using resp As New Responser2(Responser)
|
||||
Try
|
||||
resp.Method = "POST"
|
||||
AddHandler resp.ResponseReceived, AddressOf Responser_ResponseReceived
|
||||
resp.Headers.Add(Header_FB_LSD, _GetReels_LSD)
|
||||
|
||||
Dim vars$ = """data"":{""include_feed_video"":true,""page_size"":50,""target_user_id"":""" & ID & """}"
|
||||
If Not Cursor.IsEmptyString Then vars = $"""after"":""{Cursor}"",""before"":null,{vars},""first"":4,""last"":null"
|
||||
vars = "{" & vars & "}"
|
||||
|
||||
Dim url$ = String.Format(requestPattern, _GetReels_dtsg, _GetReels_LSD, SymbolsConverter.ASCII.EncodeSymbolsOnly(vars))
|
||||
|
||||
Return resp.GetResponse(url,, EDP.ThrowException)
|
||||
Finally
|
||||
With resp
|
||||
Responser.Cookies.Update(.Cookies)
|
||||
With .Headers
|
||||
If .Contains(SiteSettings.Header_IG_WWW_CLAIM) Then Responser.Headers.Add(SiteSettings.Header_IG_WWW_CLAIM, .Value(SiteSettings.Header_IG_WWW_CLAIM))
|
||||
If .Contains(SiteSettings.Header_CSRF_TOKEN) Then Responser.Headers.Add(SiteSettings.Header_CSRF_TOKEN, .Value(SiteSettings.Header_CSRF_TOKEN))
|
||||
End With
|
||||
End With
|
||||
End Try
|
||||
End Using
|
||||
End Function
|
||||
Private Function GetPageTokens() As Boolean
|
||||
_GetReels_LSD = String.Empty
|
||||
_GetReels_dtsg = String.Empty
|
||||
Try
|
||||
Dim r$ = Responser.GetResponse(MySiteSettings.GetUserUrl(Me),, EDP.ThrowException)
|
||||
If Not r.IsEmptyString Then
|
||||
Dim rr As RParams = RParams.DM(PageTokenRegexPatternDefault, 0, RegexReturn.List, EDP.ReturnValue)
|
||||
Dim tokens As List(Of String) = RegexReplace(r, rr)
|
||||
Dim tt$, ttVal$
|
||||
If tokens.ListExists Then
|
||||
With rr
|
||||
.Match = Nothing
|
||||
.MatchSub = 1
|
||||
.WhatGet = RegexReturn.Value
|
||||
End With
|
||||
For Each tt In tokens
|
||||
If Not _GetReels_LSD.IsEmptyString And Not _GetReels_dtsg.IsEmptyString Then
|
||||
Exit For
|
||||
Else
|
||||
ttVal = RegexReplace(tt, rr)
|
||||
If Not ttVal.IsEmptyString Then
|
||||
If ttVal.Contains(":") Then
|
||||
If _GetReels_dtsg.IsEmptyString Then _GetReels_dtsg = ttVal
|
||||
Else
|
||||
If _GetReels_LSD.IsEmptyString Then _GetReels_LSD = ttVal
|
||||
End If
|
||||
End If
|
||||
End If
|
||||
Next
|
||||
End If
|
||||
End If
|
||||
Catch ex As Exception
|
||||
Dim notFound$ = String.Empty
|
||||
If _GetReels_dtsg.IsEmptyString Then notFound.StringAppend(Header_FB_LSD)
|
||||
If _GetReels_LSD.IsEmptyString Then notFound.StringAppend("lsd")
|
||||
LogError(ex, $"failed to update some{IIf(notFound.IsEmptyString, String.Empty, $" ({notFound})")} credentials", EDP.SendToLog)
|
||||
End Try
|
||||
Return DownloadReels_Tokens_Valid
|
||||
End Function
|
||||
#End Region
|
||||
#Region "Code ID converters"
|
||||
Protected Function CodeToID(ByVal Code As String) As String
|
||||
Const CodeSymbols$ = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||
@@ -909,7 +958,8 @@ Namespace API.Instagram
|
||||
Protected Sub ObtainMedia(ByVal n As EContainer, ByVal PostID As String, Optional ByVal SpecialFolder As String = Nothing,
|
||||
Optional ByVal DateObj As String = Nothing, Optional ByVal InitialType As Integer = -1,
|
||||
Optional ByVal PostOriginUrl As String = Nothing,
|
||||
Optional ByVal State As UStates = UStates.Unknown, Optional ByVal Attempts As Integer = 0)
|
||||
Optional ByVal State As UStates = UStates.Unknown, Optional ByVal Attempts As Integer = 0,
|
||||
Optional ByVal TryExtractImage As Boolean = False)
|
||||
Try
|
||||
Dim maxSize As Func(Of EContainer, Integer) = Function(ByVal _ss As EContainer) As Integer
|
||||
Dim w% = AConvert(Of Integer)(_ss.Value("width"), 0)
|
||||
@@ -953,7 +1003,10 @@ Namespace API.Instagram
|
||||
'2 - one video
|
||||
'1 - one picture
|
||||
t = n.Value("media_type").FromXML(Of Integer)(-1)
|
||||
If t = -1 And InitialType = 8 And ObtainMedia_AllowAbstract Then
|
||||
If TryExtractImage Then
|
||||
t = 1
|
||||
abstractDecision = True
|
||||
ElseIf t = -1 And InitialType = 8 And ObtainMedia_AllowAbstract Then
|
||||
If n.Contains(vid) Then
|
||||
t = 2
|
||||
abstractDecision = True
|
||||
@@ -964,7 +1017,7 @@ Namespace API.Instagram
|
||||
End If
|
||||
If t >= 0 Then
|
||||
Select Case t
|
||||
Case 1
|
||||
Case 1 'one picture
|
||||
If n.Contains(img) Then
|
||||
If Not abstractDecision Then t = n.Value("media_type").FromXML(Of Integer)(-1)
|
||||
DateObj = mDate(n)
|
||||
@@ -983,7 +1036,7 @@ Namespace API.Instagram
|
||||
End With
|
||||
End If
|
||||
End If
|
||||
Case 2
|
||||
Case 2 'one video
|
||||
If n.Contains(vid) Then
|
||||
DateObj = mDate(n)
|
||||
With n.ItemF({vid}).XmlIfNothing
|
||||
@@ -999,7 +1052,8 @@ Namespace API.Instagram
|
||||
End If
|
||||
End With
|
||||
End If
|
||||
Case 8
|
||||
If Not TryExtractImage Then ObtainMedia(n, PostID, SpecialFolder, DateObj, InitialType, PostOriginUrl, State, Attempts, True)
|
||||
Case 8 'gallery
|
||||
DateObj = mDate(n)
|
||||
With n("carousel_media").XmlIfNothing
|
||||
If .Count > 0 Then
|
||||
@@ -1016,11 +1070,12 @@ Namespace API.Instagram
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "GetUserId, GetUserName"
|
||||
Private Sub GetUserId()
|
||||
Private Sub GetUserData()
|
||||
Dim __idFound As Boolean = False
|
||||
Try
|
||||
RequestsCount += 1
|
||||
Dim r$ = Responser.GetResponse($"https://i.instagram.com/api/v1/users/web_profile_info/?username={NameTrue}",, EDP.ThrowException)
|
||||
ChangeResponserMode(False)
|
||||
UpdateRequestNumber()
|
||||
Dim r$ = Responser.GetResponse($"https://i.instagram.com/api/v1/users/web_profile_info/?username={NameTrue}")
|
||||
If Not r.IsEmptyString Then
|
||||
Using j As EContainer = JsonDocument.Parse(r)
|
||||
If Not j Is Nothing AndAlso j.Contains({"data", "user"}) Then
|
||||
@@ -1034,7 +1089,7 @@ Namespace API.Instagram
|
||||
Dim eUrl$ = .Value("external_url")
|
||||
If Not eUrl.IsEmptyString AndAlso (descr.IsEmptyString OrElse Not descr.Contains(eUrl)) Then descr.StringAppendLine(eUrl)
|
||||
UserDescriptionUpdate(descr)
|
||||
Dim f As New SFile With {.Path = MyFile.CutPath.Path, .Name = "ProfilePicture", .Extension = "jpg"}
|
||||
Dim f As New SFile With {.Path = DownloadContentDefault_GetRootDir(), .Name = "ProfilePicture", .Extension = "jpg"}
|
||||
If Not f.Exists Then
|
||||
Dim profilePicture$ = .Value("profile_pic_url_hd")
|
||||
If profilePicture.IsEmptyString OrElse Not GetWebFile(profilePicture, f, EDP.ReturnValue) Then
|
||||
@@ -1054,13 +1109,15 @@ Namespace API.Instagram
|
||||
LogError(ex, "get Instagram user ID")
|
||||
End If
|
||||
End If
|
||||
Finally
|
||||
ChangeResponserMode(_UseGQL)
|
||||
End Try
|
||||
End Sub
|
||||
Private Function GetUserNameById() As Boolean
|
||||
UserNameRequested = True
|
||||
Try
|
||||
If Not ID.IsEmptyString Then
|
||||
RequestsCount += 1
|
||||
UpdateRequestNumber()
|
||||
Dim r$ = Responser.GetResponse($"https://i.instagram.com/api/v1/users/{ID}/info/",, EDP.ReturnValue)
|
||||
If Not r.IsEmptyString Then
|
||||
Using j As EContainer = JsonDocument.Parse(r, EDP.ReturnValue)
|
||||
@@ -1093,9 +1150,9 @@ Namespace API.Instagram
|
||||
Private Sub GetStoriesData(ByRef StoriesList As List(Of String), ByVal GetUserStory As Boolean, ByVal Token As CancellationToken)
|
||||
Const ReqUrl$ = "https://i.instagram.com/api/v1/feed/reels_media/?{0}"
|
||||
Dim tmpList As IEnumerable(Of String) = Nothing
|
||||
Dim qStr$, r$, sFolder$, storyID$, pid$
|
||||
Dim qStr$, r$
|
||||
Dim i% = -1
|
||||
Dim jj As EContainer, s As EContainer
|
||||
Dim jj As EContainer
|
||||
ThrowAny(Token)
|
||||
If StoriesList.ListExists Or GetUserStory Then
|
||||
If Not GetUserStory Then tmpList = StoriesList.Take(5)
|
||||
@@ -1105,38 +1162,14 @@ Namespace API.Instagram
|
||||
Else
|
||||
qStr = String.Format(ReqUrl, tmpList.Select(Function(q) $"reel_ids=highlight:{q}").ListToString("&"))
|
||||
End If
|
||||
UpdateRequestNumber()
|
||||
r = Responser.GetResponse(qStr,, EDP.ThrowException)
|
||||
ThrowAny(Token)
|
||||
If Not r.IsEmptyString Then
|
||||
Using j As EContainer = JsonDocument.Parse(r).XmlIfNothing
|
||||
If j.Contains("reels") Then
|
||||
ProgressPre.ChangeMax(j("reels").Count)
|
||||
For Each jj In j("reels")
|
||||
ProgressPre.Perform()
|
||||
i += 1
|
||||
sFolder = jj.Value("title").StringRemoveWinForbiddenSymbols
|
||||
storyID = jj.Value("id").Replace("highlight:", String.Empty)
|
||||
If GetUserStory Then
|
||||
sFolder = $"{StoriesFolder} (user)"
|
||||
Else
|
||||
If sFolder.IsEmptyString Then sFolder = $"Story_{storyID}"
|
||||
If sFolder.IsEmptyString Then sFolder = $"Story_{i}"
|
||||
sFolder = $"{StoriesFolder}\{sFolder}"
|
||||
End If
|
||||
If Not storyID.IsEmptyString Then storyID &= ":"
|
||||
With jj("items").XmlIfNothing
|
||||
If .Count > 0 Then
|
||||
For Each s In .Self
|
||||
pid = storyID & s.Value("id")
|
||||
If Not _TempPostsList.Contains(pid) Then
|
||||
ThrowAny(Token)
|
||||
ObtainMedia(s, pid, sFolder)
|
||||
_TempPostsList.Add(pid)
|
||||
End If
|
||||
Next
|
||||
End If
|
||||
End With
|
||||
Next
|
||||
For Each jj In j("reels") : GetStoriesData_ParseSingleHighlight(jj, i, GetUserStory, Token) : Next
|
||||
End If
|
||||
End Using
|
||||
End If
|
||||
@@ -1144,8 +1177,39 @@ Namespace API.Instagram
|
||||
End If
|
||||
End If
|
||||
End Sub
|
||||
Private Sub GetStoriesData_ParseSingleHighlight(ByVal Node As EContainer, ByRef Index As Integer, ByVal GetUserStory As Boolean, ByVal Token As CancellationToken)
|
||||
If Not Node Is Nothing Then
|
||||
With Node
|
||||
ProgressPre.Perform()
|
||||
Index += 1
|
||||
Dim pid$
|
||||
Dim sFolder$ = .Value("title").StringRemoveWinForbiddenSymbols
|
||||
Dim storyID$ = .Value("id").Replace("highlight:", String.Empty)
|
||||
If GetUserStory Then
|
||||
sFolder = $"{StoriesFolder} (user)"
|
||||
Else
|
||||
If sFolder.IsEmptyString Then sFolder = $"Story_{storyID.IfNullOrEmpty(Index)}"
|
||||
sFolder = $"{StoriesFolder}\{sFolder}"
|
||||
End If
|
||||
If Not storyID.IsEmptyString Then storyID &= ":"
|
||||
With .Item("items")
|
||||
If .ListExists Then
|
||||
For Each s As EContainer In .Self
|
||||
pid = storyID & s.Value("id")
|
||||
If Not _TempPostsList.Contains(pid) Then
|
||||
ThrowAny(Token)
|
||||
ObtainMedia(s, pid, sFolder)
|
||||
_TempPostsList.Add(pid)
|
||||
End If
|
||||
Next
|
||||
End If
|
||||
End With
|
||||
End With
|
||||
End If
|
||||
End Sub
|
||||
Private Function GetStoriesList() As List(Of String)
|
||||
Try
|
||||
UpdateRequestNumber()
|
||||
Dim r$ = Responser.GetResponse($"https://i.instagram.com/api/v1/highlights/{ID}/highlights_tray/",, EDP.ThrowException)
|
||||
If Not r.IsEmptyString Then
|
||||
Dim ee As New ErrorsDescriber(EDP.ReturnValue) With {.DeclaredMessage = New MMessage($"{ToStringForLog()}:")}
|
||||
@@ -1169,6 +1233,7 @@ Namespace API.Instagram
|
||||
Protected Overrides Sub EraseData_AdditionalDataFiles()
|
||||
Dim f As SFile = MyFilePostsKV
|
||||
If f.Exists Then f.Delete(SFO.File, SFODelete.DeleteToRecycleBin, EDP.ReturnValue)
|
||||
FirstLoadingDone = False
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Exceptions"
|
||||
@@ -1204,6 +1269,9 @@ Namespace API.Instagram
|
||||
ElseIf Responser.StatusCode = 560 Or Responser.StatusCode = HttpStatusCode.InternalServerError Then '560, 500
|
||||
MySiteSettings.SkipUntilNextSession = True
|
||||
Err5xx = Responser.StatusCode
|
||||
ElseIf Responser.StatusCode = -1 And Responser.Status = -1 Then
|
||||
MySiteSettings.SkipUntilNextSession = True
|
||||
Err5xx = Responser.StatusCode
|
||||
Else
|
||||
MyMainLOG = $"Something is wrong. Your credentials may have expired [{CInt(Responser.StatusCode)}/{CInt(Responser.Status)}]: {ToString()} [{s}]"
|
||||
DisableSection(s)
|
||||
@@ -1215,16 +1283,26 @@ Namespace API.Instagram
|
||||
Private Sub DisableSection(ByVal Section As Object)
|
||||
If Not IsNothing(Section) AndAlso TypeOf Section Is Sections Then
|
||||
Dim s As Sections = DirectCast(Section, Sections)
|
||||
Select Case s
|
||||
Case Sections.Timeline : MySiteSettings.DownloadTimeline.Value = False
|
||||
Case Sections.Reels : MySiteSettings.DownloadReels.Value = False
|
||||
Case Sections.Tagged : MySiteSettings.DownloadTagged.Value = False
|
||||
Case Sections.Stories, Sections.UserStories
|
||||
MySiteSettings.DownloadTimeline.Value = False
|
||||
MySiteSettings.DownloadStories.Value = False
|
||||
MySiteSettings.DownloadStoriesUser.Value = False
|
||||
End Select
|
||||
MyMainLOG = $"[{s}] downloading is disabled until you update your credentials".ToUpper
|
||||
Dim ss As New List(Of Sections)([Enum].GetValues(GetType(Sections)).ToObjectsList(Of Sections))
|
||||
If s = Sections.Reels And Not _UseGQL Then
|
||||
ss.Clear()
|
||||
ss.Add(s)
|
||||
ElseIf s = Sections.Tagged Then
|
||||
ss.Clear()
|
||||
ss.Add(s)
|
||||
End If
|
||||
If ss.Count > 0 Then
|
||||
For Each s In ss
|
||||
Select Case s
|
||||
Case Sections.Reels : MySiteSettings.DownloadReels.Value = False
|
||||
Case Sections.Tagged : MySiteSettings.DownloadTagged.Value = False
|
||||
Case Sections.Timeline, Sections.SavedPosts : MySiteSettings.DownloadTimeline.Value = False
|
||||
Case Sections.Stories : MySiteSettings.DownloadStories.Value = False
|
||||
Case Sections.UserStories : MySiteSettings.DownloadStoriesUser.Value = False
|
||||
End Select
|
||||
Next
|
||||
MyMainLOG = $"[{ss.ListToStringE(, New ANumbers.EnumToStringProvider(GetType(Sections)))}] downloading is disabled until you update your credentials".ToUpper
|
||||
End If
|
||||
End If
|
||||
End Sub
|
||||
#End Region
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
'
|
||||
' This program is distributed in the hope that it will be useful,
|
||||
' but WITHOUT ANY WARRANTY
|
||||
Imports System.Threading
|
||||
Imports System.Net
|
||||
Imports SCrawler.API.Base
|
||||
Imports PersonalUtilities.Tools
|
||||
Imports PersonalUtilities.Tools.Web
|
||||
@@ -18,8 +18,10 @@ Namespace API.JustForFans
|
||||
Friend NotInheritable Class M3U8 : Implements IDisposable
|
||||
#Region "Declarations"
|
||||
Friend Const AllVid As UTypes = UTypes.m3u8 + UTypes.VideoPre
|
||||
Private ReadOnly DataVideo As List(Of String)
|
||||
Private ReadOnly DataAudio As List(Of String)
|
||||
Private Structure M3U8URL_Indexed
|
||||
Friend Index As Integer
|
||||
Friend File As SFile
|
||||
End Structure
|
||||
Private Media As UserMedia
|
||||
Private DestinationFile As SFile
|
||||
Private ReadOnly Thrower As Plugin.IThrower
|
||||
@@ -32,31 +34,37 @@ Namespace API.JustForFans
|
||||
Private UrlAudio As String
|
||||
Private FileVideo As SFile
|
||||
Private FileAudio As SFile
|
||||
Private FileVideo_M3U8 As SFile
|
||||
Private FileAudio_M3U8 As SFile
|
||||
Private ReadOnly FileVideo_IndexedParts As List(Of M3U8URL_Indexed)
|
||||
Private ReadOnly FileAudio_IndexedParts As List(Of M3U8URL_Indexed)
|
||||
Private RootPlaylistUrl As String
|
||||
Private ReadOnly Cache As CacheKeeper
|
||||
Private ReadOnly Progress As MyProgress
|
||||
Private ReadOnly ProgressPre As PreProgress
|
||||
Private ReadOnly ProgressExists As Boolean
|
||||
Private ReadOnly UsePreProgress As Boolean
|
||||
Private Property Token As CancellationToken
|
||||
Private ReadOnly REGEX_FILE_EXT As RParams = RParams.DMS("[^\s""]+\.(\w+)([\?&]{1}.+|)", 1, EDP.ReturnValue)
|
||||
Private ReadOnly REGEX_FILE_EXT_M4S As RParams = RParams.DM("[^\s""]+\.m4s([\?&]{1}.+|)", 0, EDP.ReturnValue)
|
||||
Private ReadOnly MyFileNumberProvider As ANumbers
|
||||
#End Region
|
||||
#Region "Initializer"
|
||||
Private Sub New(ByVal m As UserMedia, ByVal Destination As SFile, ByVal Resp As Responser, ByVal _Thrower As Plugin.IThrower,
|
||||
ByVal _Progress As MyProgress, ByVal _UsePreProgress As Boolean, ByVal _Token As CancellationToken)
|
||||
ByVal _Progress As MyProgress, ByVal _UsePreProgress As Boolean)
|
||||
Media = m
|
||||
DataVideo = New List(Of String)
|
||||
DataAudio = New List(Of String)
|
||||
DestinationFile = Destination
|
||||
Thrower = _Thrower
|
||||
'Responser = Resp
|
||||
Responser = New Responser
|
||||
ResponserInternal = True
|
||||
FileVideo_IndexedParts = New List(Of M3U8URL_Indexed)
|
||||
FileAudio_IndexedParts = New List(Of M3U8URL_Indexed)
|
||||
Progress = _Progress
|
||||
ProgressExists = Not Progress Is Nothing
|
||||
If ProgressExists Then ProgressPre = New PreProgress(Progress)
|
||||
UsePreProgress = _UsePreProgress
|
||||
Token = _Token
|
||||
Cache = New CacheKeeper($"{DestinationFile.PathWithSeparator}_{M3U8Base.TempCacheFolderName}\")
|
||||
MyFileNumberProvider = M3U8Base.NumberProviderDefault
|
||||
Cache = New CacheKeeper($"{DestinationFile.PathWithSeparator}_{M3U8Base.TempCacheFolderName}\") With {.DisposeSuspended = True}
|
||||
With Cache
|
||||
.CacheDeleteError = CacheDeletionError(Cache)
|
||||
.DisposeSuspended = True
|
||||
@@ -91,30 +99,138 @@ Namespace API.JustForFans
|
||||
UrlVideo = RegexReplace(r, RParams.DMS(R_VIDEO_REGEX_PATTERN, 6, EDP.ReturnValue))
|
||||
UrlAudio = RegexReplace(r, REGEX_AUDIO_URL)
|
||||
If UrlVideo.IsEmptyString Then Throw New ArgumentException("Unable to identify m3u8 video track", "M3U8 video track")
|
||||
|
||||
Thrower.ThrowAny()
|
||||
GetFiles(UrlVideo, FileVideo, False)
|
||||
GetFileParts(UrlVideo, FileVideo_M3U8, FileVideo_IndexedParts, False)
|
||||
Thrower.ThrowAny()
|
||||
If Not UrlAudio.IsEmptyString Then GetFiles(UrlAudio, FileAudio, True)
|
||||
If Not UrlAudio.IsEmptyString Then GetFileParts(UrlAudio, FileAudio_M3U8, FileAudio_IndexedParts, True)
|
||||
|
||||
If FileVideo_IndexedParts.Count > 0 Then _
|
||||
FileVideo = GetTempFile(FileVideo_M3U8, FileVideo_IndexedParts, False, FileAudio_IndexedParts, FileAudio_IndexedParts.Count = 0)
|
||||
If FileAudio_IndexedParts.Count > 0 Then _
|
||||
FileAudio = GetTempFile(FileAudio_M3U8, FileAudio_IndexedParts, True, FileVideo_IndexedParts, False)
|
||||
Thrower.ThrowAny()
|
||||
MergeFiles()
|
||||
End If
|
||||
End If
|
||||
End Sub
|
||||
Private Sub GetFiles(ByVal URL As String, ByRef File As SFile, ByVal IsAudio As Boolean)
|
||||
Private Function GetTempFile(ByVal M3U8File As SFile, ByVal IndexedList As List(Of M3U8URL_Indexed), ByVal IsAudio As Boolean,
|
||||
ByVal IndexedListOther As List(Of M3U8URL_Indexed), ByVal IgnoreAudio As Boolean) As SFile
|
||||
Const mapStr$ = "#EXT-X-MAP:URI"
|
||||
Const extinfStr$ = "#EXTINF:"
|
||||
Const m4s$ = "m4s"
|
||||
Dim M3U8FileLines$() = M3U8File.GetLines
|
||||
If M3U8FileLines.ListExists AndAlso IndexedList.Count > 0 AndAlso (IndexedListOther.Count > 0 Or (Not IsAudio And IgnoreAudio)) Then
|
||||
Dim outputFile As SFile = $"{Cache.RootDirectory.PathWithSeparator}{IIf(IsAudio, "AUDIO.aac", "VIDEO.mp4")}"
|
||||
Dim M3U8FileNew As SFile = M3U8File
|
||||
M3U8FileNew.Path = IndexedList(0).File.Path
|
||||
Dim v$
|
||||
Dim i%, fIndx%, fIndx2%
|
||||
Dim extIsm4s As Boolean
|
||||
Dim LookingIndex% = -1
|
||||
Dim ignoreOtherList As Boolean = IndexedListOther.Count = 0 And (Not IsAudio And IgnoreAudio)
|
||||
Dim fileFinder As Predicate(Of M3U8URL_Indexed) = Function(input) input.Index = LookingIndex
|
||||
|
||||
Using m3u8Text As New TextSaver
|
||||
For i = 0 To M3U8FileLines.Length - 1
|
||||
v = M3U8FileLines(i)
|
||||
|
||||
If Not v.IsEmptyString Then
|
||||
If v.StartsWith(mapStr) Then
|
||||
LookingIndex += 1
|
||||
fIndx = IndexedList.FindIndex(fileFinder)
|
||||
If fIndx >= 0 Then
|
||||
extIsm4s = Not IndexedList(fIndx).File.Extension.IsEmptyString AndAlso IndexedList(fIndx).File.Extension = m4s
|
||||
v = v.Replace(RegexReplace(v, If(extIsm4s, REGEX_FILE_EXT_M4S, REGEX_FILE_EXT)), IndexedList(fIndx).File.File)
|
||||
m3u8Text.AppendLine(v)
|
||||
Else
|
||||
Throw New Exception($"The map file is missing ({IIf(IsAudio, "audio", "video")})")
|
||||
End If
|
||||
ElseIf v.StartsWith(extinfStr) Then
|
||||
LookingIndex += 1
|
||||
If (i + 1) <= M3U8FileLines.Length - 1 Then
|
||||
fIndx = IndexedList.FindIndex(fileFinder)
|
||||
fIndx2 = If(ignoreOtherList, -1, IndexedListOther.FindIndex(fileFinder))
|
||||
If fIndx >= 0 And (fIndx2 >= 0 Or ignoreOtherList) Then
|
||||
If ignoreOtherList OrElse IndexedListOther(fIndx2).Index = IndexedList(fIndx).Index Then
|
||||
m3u8Text.AppendLine(v)
|
||||
m3u8Text.AppendLine(IndexedList(fIndx).File.File)
|
||||
End If
|
||||
End If
|
||||
i += 1
|
||||
Else
|
||||
Throw New Exception($"Unexpected end of m3u8 file ({IIf(IsAudio, "audio", "video")})")
|
||||
End If
|
||||
Else
|
||||
m3u8Text.AppendLine(v)
|
||||
End If
|
||||
End If
|
||||
Next
|
||||
|
||||
m3u8Text.SaveAs(M3U8FileNew)
|
||||
End Using
|
||||
|
||||
If M3U8FileNew.Exists Then
|
||||
Using b As New BatchExecutor
|
||||
AddHandler b.ErrorDataReceived, AddressOf Batch_OutputDataReceived
|
||||
Thrower.ThrowAny()
|
||||
ProgressChangeMax(IndexedList.Count)
|
||||
b.ChangeDirectory(M3U8FileNew)
|
||||
b.Execute($"""{Settings.FfmpegFile}"" -i {M3U8FileNew.File} -vcodec copy -strict -2 ""{outputFile}""")
|
||||
End Using
|
||||
If Not outputFile.Exists Then outputFile = Nothing
|
||||
End If
|
||||
|
||||
Return outputFile
|
||||
Else
|
||||
Return Nothing
|
||||
End If
|
||||
End Function
|
||||
Private Sub GetFileParts(ByVal URL As String, ByRef M3U8File As SFile, ByRef IndexedList As List(Of M3U8URL_Indexed), ByVal IsAudio As Boolean)
|
||||
Try
|
||||
Dim r$ = Responser.GetResponse(URL)
|
||||
If Not r.IsEmptyString Then
|
||||
Dim data As List(Of RegexMatchStruct) = RegexFields(Of RegexMatchStruct)(r, {REGEX_PLS_FILES}, {1, 2}, EDP.ReturnValue)
|
||||
If data.ListExists Then
|
||||
File = $"{Cache.RootDirectory.PathWithSeparator}{IIf(IsAudio, "AUDIO.aac", "VIDEO.mp4")}"
|
||||
Using b As New TokenBatch(Token) With {.Encoding = Settings.CMDEncoding, .MainProcessName = "ffmpeg"}
|
||||
AddHandler b.ErrorDataReceived, AddressOf Batch_OutputDataReceived
|
||||
ProgressChangeMax(data.Count)
|
||||
b.ChangeDirectory(Cache.RootDirectory)
|
||||
b.Execute($"""{Settings.FfmpegFile}"" -i {URL} -vcodec copy -strict -2 ""{File}""")
|
||||
Token.ThrowIfCancellationRequested()
|
||||
If Not File.Exists Then File = Nothing
|
||||
End Using
|
||||
Dim appender$ = URL.Replace(URL.Split("/").LastOrDefault, String.Empty)
|
||||
Dim createM3U8URL As Func(Of String, M3U8URL) =
|
||||
Function(input) New M3U8URL(M3U8Base.CreateUrl(appender, input), RegexReplace(input, REGEX_FILE_EXT))
|
||||
With (From d As RegexMatchStruct In data
|
||||
Where Not d.Arr(0).IfNullOrEmpty(d.Arr(1)).IsEmptyString
|
||||
Select createM3U8URL.Invoke(d.Arr(0).IfNullOrEmpty(d.Arr(1)).StringTrim))
|
||||
If .ListExists Then
|
||||
ProgressChangeMax(.Count)
|
||||
M3U8File = $"{Cache.RootDirectory.PathWithSeparator}{IIf(IsAudio, "AUDIO", "VIDEO")}.m3u8"
|
||||
M3U8File = TextSaver.SaveTextToFile(r, M3U8File, True)
|
||||
|
||||
Dim tmpCache As CacheKeeper = Cache.NewInstance
|
||||
Dim dFile As SFile = tmpCache.RootDirectory
|
||||
dFile.Extension = .ElementAt(0).Extension.IfNullOrEmpty("m4s")
|
||||
MyFileNumberProvider.GroupSize = { .Count.ToString.Length, 3}.Max
|
||||
If tmpCache.Validate Then
|
||||
Using w As New WebClient
|
||||
For i% = 0 To .Count - 1
|
||||
Thrower.ThrowAny()
|
||||
dFile.Name = $"{M3U8Base.TempFilePrefix}{i.NumToString(MyFileNumberProvider)}"
|
||||
dFile.Extension = .ElementAt(i).Extension.IfNullOrEmpty(M3U8Base.TempFileDefaultExtension)
|
||||
Try
|
||||
ProgressPerform()
|
||||
w.DownloadFile(.ElementAt(i).URL, dFile)
|
||||
tmpCache.AddFile(dFile, True)
|
||||
IndexedList.Add(New M3U8URL_Indexed With {.File = dFile, .Index = i})
|
||||
Catch down_oex As OperationCanceledException
|
||||
Throw down_oex
|
||||
Catch down_dex As ObjectDisposedException
|
||||
Throw down_dex
|
||||
Catch ex As Exception
|
||||
End Try
|
||||
Next
|
||||
End Using
|
||||
Else
|
||||
Throw New Exception("Can't create cache directory")
|
||||
End If
|
||||
End If
|
||||
End With
|
||||
End If
|
||||
End If
|
||||
Catch oex As OperationCanceledException
|
||||
@@ -123,7 +239,7 @@ Namespace API.JustForFans
|
||||
Throw dex
|
||||
Catch ex As Exception
|
||||
ErrorsDescriber.Execute(EDP.SendToLog + EDP.ThrowException, ex,
|
||||
$"API.JustForFans.M3U8.GetFiles({IIf(IsAudio, "audio", "video")}):{vbCr}URL: {URL}{vbCr}File: {File}")
|
||||
$"API.JustForFans.M3U8.GetFileParts({IIf(IsAudio, "audio", "video")}):{vbCr}URL: {URL}{vbCr}Post: {Media.URL_BASE}")
|
||||
End Try
|
||||
End Sub
|
||||
Private Async Sub Batch_OutputDataReceived(ByVal Sender As Object, ByVal e As DataReceivedEventArgs)
|
||||
@@ -135,8 +251,10 @@ Namespace API.JustForFans
|
||||
Dim f As SFile = SFile.IndexReindex(DestinationFile,,, p, EDP.ReturnValue).IfNullOrEmpty(DestinationFile)
|
||||
If Not FileVideo.IsEmptyString And Not FileAudio.IsEmptyString Then
|
||||
DestinationFile = FFMPEG.MergeFiles({FileVideo, FileAudio}, Settings.FfmpegFile, f, Settings.CMDEncoding, p, EDP.ThrowException)
|
||||
Else
|
||||
ElseIf FileVideo.Exists Then
|
||||
If Not SFile.Move(FileVideo, f) Then DestinationFile = FileVideo
|
||||
Else
|
||||
Throw New Exception($"Unable to download file ({Media.URL_BASE})")
|
||||
End If
|
||||
Catch ex As Exception
|
||||
ErrorsDescriber.Execute(EDP.SendToLog + EDP.ThrowException, ex, $"[M3U8.MergeFiles]")
|
||||
@@ -165,8 +283,8 @@ Namespace API.JustForFans
|
||||
#End Region
|
||||
#Region "Static Download"
|
||||
Friend Shared Function Download(ByVal Media As UserMedia, ByVal DestinationFile As SFile, ByVal Resp As Responser, ByVal Thrower As Plugin.IThrower,
|
||||
ByVal Progress As MyProgress, ByVal UsePreProgress As Boolean, ByVal _Token As CancellationToken) As SFile
|
||||
Using m As New M3U8(Media, DestinationFile, Resp, Thrower, Progress, UsePreProgress, _Token)
|
||||
ByVal Progress As MyProgress, ByVal UsePreProgress As Boolean) As SFile
|
||||
Using m As New M3U8(Media, DestinationFile, Resp, Thrower, Progress, UsePreProgress)
|
||||
m.Download()
|
||||
If m.DestinationFile.Exists Then Return m.DestinationFile Else Return Nothing
|
||||
End Using
|
||||
@@ -177,8 +295,8 @@ Namespace API.JustForFans
|
||||
Private Overloads Sub Dispose(ByVal disposing As Boolean)
|
||||
If Not disposedValue Then
|
||||
If disposing Then
|
||||
DataVideo.Clear()
|
||||
DataAudio.Clear()
|
||||
FileVideo_IndexedParts.Clear()
|
||||
FileAudio_IndexedParts.Clear()
|
||||
ProgressPre.DisposeIfReady
|
||||
Cache.Dispose()
|
||||
If ResponserInternal Then Responser.DisposeIfReady
|
||||
|
||||
@@ -20,9 +20,14 @@ Namespace API.JustForFans
|
||||
Friend ReadOnly Property UserID As PropertyValue
|
||||
<PropertyOption, PXML, PClonable(Clone:=False)>
|
||||
Friend ReadOnly Property UserHash4 As PropertyValue
|
||||
<CookieValueExtractor(NameOf(UserHash4))>
|
||||
Private Function GetValueFromCookies(ByVal PropName As String, ByVal c As CookieKeeper) As String
|
||||
Return c.GetCookieValue(UserHash4_CookieName, PropName, NameOf(UserHash4))
|
||||
End Function
|
||||
<PropertyOption(ControlText:="Accept", ControlToolTip:="Header 'Accept'"), PClonable>
|
||||
Friend ReadOnly Property HeaderAccept As PropertyValue
|
||||
<PropertyOption, PClonable> Friend ReadOnly Property UserAgent As PropertyValue
|
||||
<PropertyOption(InheritanceName:=SettingsCLS.HEADER_DEF_UserAgent), PClonable, PXML(OnlyForChecked:=True)>
|
||||
Friend ReadOnly Property UserAgent As PropertyValue
|
||||
Private Sub UpdateHeader(ByVal HeaderName As String, ByVal HeaderValue As String)
|
||||
Select Case HeaderName
|
||||
Case NameOf(HeaderAccept) : If HeaderValue.IsEmptyString Then Responser.Accept = Nothing Else Responser.Accept = HeaderValue
|
||||
@@ -60,7 +65,7 @@ Namespace API.JustForFans
|
||||
Private Sub UpdateUserHash4()
|
||||
If Responser.CookiesExists Then
|
||||
Dim hv_current$ = UserHash4.Value
|
||||
Dim hv_cookie$ = If(Responser.Cookies.FirstOrDefault(Function(cc) cc.Name.ToLower = UserHash4_CookieName)?.Value, String.Empty)
|
||||
Dim hv_cookie$ = GetValueFromCookies(NameOf(UserHash4), Responser.Cookies)
|
||||
If Not hv_cookie.IsEmptyString And Not hv_cookie = hv_current And Responser.Cookies.Changed Then UserHash4.Value = hv_cookie
|
||||
End If
|
||||
End Sub
|
||||
|
||||
@@ -336,7 +336,7 @@ Namespace API.JustForFans
|
||||
DownloadContentDefault(Token)
|
||||
End Sub
|
||||
Protected Overrides Function DownloadM3U8(ByVal URL As String, ByVal Media As UserMedia, ByVal DestinationFile As SFile, ByVal Token As CancellationToken) As SFile
|
||||
Return M3U8.Download(Media, DestinationFile, ResponserNoHandlers, Me, Progress, Not IsSingleObjectDownload, Token)
|
||||
Return M3U8.Download(Media, DestinationFile, ResponserNoHandlers, Me, Progress, Not IsSingleObjectDownload)
|
||||
End Function
|
||||
#End Region
|
||||
#Region "DownloadSingleObject"
|
||||
|
||||
@@ -18,10 +18,14 @@ Namespace API.OnlyFans
|
||||
Friend Class SiteSettings : Inherits SiteSettingsBase
|
||||
#Region "Declarations"
|
||||
#Region "Options"
|
||||
<PropertyOption(ControlText:="Download timeline", ControlToolTip:="Download user timeline"), PXML, PClonable>
|
||||
Friend ReadOnly Property DownloadTimeline As PropertyValue
|
||||
<PropertyOption(ControlText:="Download stories", ControlToolTip:="Download profile stories if they exists"), PXML, PClonable>
|
||||
Friend ReadOnly Property DownloadStories As PropertyValue
|
||||
<PropertyOption(ControlText:="Download highlights", ControlToolTip:="Download profile highlights if they exists"), PXML, PClonable>
|
||||
Friend Property DownloadHighlights As PropertyValue
|
||||
Friend ReadOnly Property DownloadHighlights As PropertyValue
|
||||
<PropertyOption(ControlText:="Download chat", ControlToolTip:="Download unlocked chat media"), PXML, PClonable>
|
||||
Friend Property DownloadChatMedia As PropertyValue
|
||||
Friend ReadOnly Property DownloadChatMedia As PropertyValue
|
||||
#End Region
|
||||
#Region "Headers"
|
||||
Private Const HeaderBrowser As String = "sec-ch-ua"
|
||||
@@ -34,9 +38,10 @@ Namespace API.OnlyFans
|
||||
Private ReadOnly Property HH_X_BC As PropertyValue
|
||||
<PropertyOption(ControlText:=HeaderAppToken, AllowNull:=False), PClonable(Clone:=False)>
|
||||
Private ReadOnly Property HH_APP_TOKEN As PropertyValue
|
||||
<PropertyOption(ControlText:=HeaderBrowser, ControlToolTip:="Can be null", AllowNull:=True), PClonable>
|
||||
<PropertyOption(ControlText:=HeaderBrowser, ControlToolTip:="Can be null", AllowNull:=True,
|
||||
InheritanceName:=SettingsCLS.HEADER_DEF_sec_ch_ua), PClonable, PXML(OnlyForChecked:=True)>
|
||||
Private ReadOnly Property HH_BROWSER As PropertyValue
|
||||
<PropertyOption(AllowNull:=False), PClonable>
|
||||
<PropertyOption(AllowNull:=False, InheritanceName:=SettingsCLS.HEADER_DEF_UserAgent), PClonable, PXML(OnlyForChecked:=True)>
|
||||
Friend ReadOnly Property UserAgent As PropertyValue
|
||||
Private Sub UpdateHeader(ByVal PropertyName As String, ByVal Value As String)
|
||||
Dim hName$ = String.Empty
|
||||
@@ -54,6 +59,16 @@ Namespace API.OnlyFans
|
||||
Responser.UserAgent = Value
|
||||
End If
|
||||
End Sub
|
||||
<CookieValueExtractor(NameOf(HH_USER_ID)), CookieValueExtractor(NameOf(HH_X_BC))>
|
||||
Private Function GetValueFromCookies(ByVal PropName As String, ByVal c As CookieKeeper) As String
|
||||
If c.ListExists Then
|
||||
Select Case PropName
|
||||
Case NameOf(HH_USER_ID) : Return c.GetCookieValue("auth_id")
|
||||
Case NameOf(HH_X_BC) : Return c.GetCookieValue("fp")
|
||||
End Select
|
||||
End If
|
||||
Return String.Empty
|
||||
End Function
|
||||
#End Region
|
||||
#Region "Rules"
|
||||
<PXML("LastDateUpdated")> Private ReadOnly Property LastDateUpdated_XML As PropertyValue
|
||||
@@ -144,6 +159,8 @@ Namespace API.OnlyFans
|
||||
UserAgent = New PropertyValue(IIf(.UserAgentExists, .UserAgent, String.Empty), GetType(String), Sub(v) UpdateHeader(NameOf(UserAgent), v))
|
||||
End With
|
||||
|
||||
DownloadTimeline = New PropertyValue(True)
|
||||
DownloadStories = New PropertyValue(True)
|
||||
DownloadHighlights = New PropertyValue(True)
|
||||
DownloadChatMedia = New PropertyValue(True)
|
||||
|
||||
|
||||
@@ -22,6 +22,8 @@ Imports UStates = SCrawler.API.Base.UserMedia.States
|
||||
Namespace API.OnlyFans
|
||||
Friend Class UserData : Inherits UserDataBase
|
||||
#Region "XML names"
|
||||
Private Const Name_MediaDownloadTimeline As String = "MediaDownloadTimeline"
|
||||
Private Const Name_MediaDownloadStories As String = "MediaDownloadStories"
|
||||
Private Const Name_MediaDownloadHighlights As String = "DownloadHighlights"
|
||||
Private Const Name_MediaDownloadChatMedia As String = "DownloadChatMedia"
|
||||
#End Region
|
||||
@@ -30,6 +32,8 @@ Namespace API.OnlyFans
|
||||
Private Const HeaderSign As String = "Sign"
|
||||
Private Const HeaderTime As String = "Time"
|
||||
Private ReadOnly HighlightsList As List(Of String)
|
||||
Friend Property MediaDownloadTimeline As Boolean = True
|
||||
Friend Property MediaDownloadStories As Boolean = True
|
||||
Friend Property MediaDownloadHighlights As Boolean = True
|
||||
Friend Property MediaDownloadChatMedia As Boolean = True
|
||||
Private ReadOnly Property MySettings As SiteSettings
|
||||
@@ -42,9 +46,13 @@ Namespace API.OnlyFans
|
||||
Protected Overrides Sub LoadUserInformation_OptionalFields(ByRef Container As XmlFile, ByVal Loading As Boolean)
|
||||
With Container
|
||||
If Loading Then
|
||||
MediaDownloadTimeline = .Value(Name_MediaDownloadTimeline).FromXML(Of Boolean)(True)
|
||||
MediaDownloadStories = .Value(Name_MediaDownloadStories).FromXML(Of Boolean)(True)
|
||||
MediaDownloadHighlights = .Value(Name_MediaDownloadHighlights).FromXML(Of Boolean)(True)
|
||||
MediaDownloadChatMedia = .Value(Name_MediaDownloadChatMedia).FromXML(Of Boolean)(True)
|
||||
Else
|
||||
.Add(Name_MediaDownloadTimeline, MediaDownloadTimeline.BoolToInteger)
|
||||
.Add(Name_MediaDownloadStories, MediaDownloadStories.BoolToInteger)
|
||||
.Add(Name_MediaDownloadHighlights, MediaDownloadHighlights.BoolToInteger)
|
||||
.Add(Name_MediaDownloadChatMedia, MediaDownloadChatMedia.BoolToInteger)
|
||||
End If
|
||||
@@ -58,6 +66,8 @@ Namespace API.OnlyFans
|
||||
Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object)
|
||||
If Not Obj Is Nothing AndAlso TypeOf Obj Is UserExchangeOptions Then
|
||||
With DirectCast(Obj, UserExchangeOptions)
|
||||
MediaDownloadTimeline = .DownloadTimeline
|
||||
MediaDownloadStories = .DownloadStories
|
||||
MediaDownloadHighlights = .DownloadHighlights
|
||||
MediaDownloadChatMedia = .DownloadChatMedia
|
||||
End With
|
||||
@@ -90,8 +100,15 @@ Namespace API.OnlyFans
|
||||
Responser.Cookies.Clear()
|
||||
AddHandler Responser.ResponseReceived, AddressOf Responser_ResponseReceived
|
||||
UpdateCookieHeader()
|
||||
DownloadTimeline(IIf(IsSavedPosts, 0, String.Empty), Token)
|
||||
|
||||
If Not IsSavedPosts Then
|
||||
If ID.IsEmptyString Then GetUserID()
|
||||
If ID.IsEmptyString Then Throw New ArgumentNullException("ID", "Unable to get user ID")
|
||||
End If
|
||||
|
||||
If MediaDownloadTimeline Then DownloadTimeline(IIf(IsSavedPosts, 0, String.Empty), Token)
|
||||
If Not IsSavedPosts Then
|
||||
If MediaDownloadStories And FunctionErr = FunctionErrDef Then DownloadStories(Token)
|
||||
If MediaDownloadHighlights And FunctionErr = FunctionErrDef Then DownloadHighlights(Token)
|
||||
If MediaDownloadChatMedia And FunctionErr = FunctionErrDef Then DownloadChatMedia(0, Token)
|
||||
End If
|
||||
@@ -114,6 +131,7 @@ Namespace API.OnlyFans
|
||||
Return ErrValue <> 2
|
||||
End Function
|
||||
Friend Const A_HIGHLIGHT As String = "HL"
|
||||
Friend Const A_STORIES As String = "ST"
|
||||
Friend Const A_MESSAGE As String = "MSG"
|
||||
Private Const BaseUrlPattern As String = "https://onlyfans.com{0}"
|
||||
#Region "Download timeline"
|
||||
@@ -133,9 +151,6 @@ Namespace API.OnlyFans
|
||||
If IsSavedPosts Then
|
||||
path = $"/api2/v2/posts/bookmarks/all/?format=infinite&limit=10&offset={Cursor}"
|
||||
Else
|
||||
If ID.IsEmptyString Then GetUserID()
|
||||
If ID.IsEmptyString Then Throw New ArgumentNullException("ID", "Unable to get user ID")
|
||||
|
||||
path = $"/api2/v2/users/{ID}/posts/medias?limit=50&order=publish_date_desc&skip_users=all&format=infinite&counters=1"
|
||||
If Not Cursor.IsEmptyString Then path &= $"&counters=0&beforePublishTime={Cursor}" Else path &= "&counters=1"
|
||||
End If
|
||||
@@ -250,7 +265,7 @@ Namespace API.OnlyFans
|
||||
If Not r.IsEmptyString Then
|
||||
Using j As EContainer = JsonDocument.Parse(r)
|
||||
If j.ListExists Then
|
||||
specFolder = j.Value("title").StringRemoveWinForbiddenSymbols.IfNullOrEmpty(HLID)
|
||||
specFolder = "Highlights\" & j.Value("title").StringRemoveWinForbiddenSymbols.IfNullOrEmpty(HLID)
|
||||
specFolder &= "*"
|
||||
With j("stories")
|
||||
If .ListExists Then
|
||||
@@ -280,6 +295,57 @@ Namespace API.OnlyFans
|
||||
Loop While Not _complete
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Download stories"
|
||||
Private Sub DownloadStories(ByVal Token As CancellationToken)
|
||||
Dim url$ = String.Empty
|
||||
Dim _complete As Boolean = True
|
||||
Do
|
||||
Try
|
||||
Dim specFolder$ = "Stories"
|
||||
Dim postID$, postDate$
|
||||
Dim media As List(Of UserMedia)
|
||||
Dim result As Boolean
|
||||
Dim path$ = $"/api2/v2/users/{ID}/stories"
|
||||
If UpdateSignature(path) Then
|
||||
url = String.Format(BaseUrlPattern, path)
|
||||
ThrowAny(Token)
|
||||
Dim r$ = Responser.GetResponse(url)
|
||||
If Not r.IsEmptyString Then
|
||||
Using j As EContainer = JsonDocument.Parse(r)
|
||||
If j.ListExists Then
|
||||
ProgressPre.ChangeMax(j.Count)
|
||||
For Each n As EContainer In j
|
||||
ProgressPre.Perform()
|
||||
With n.ItemF({"media", 0})
|
||||
If .ListExists Then
|
||||
postID = $"{A_STORIES}_{ .Value("id")}"
|
||||
postDate = .Value("createdAt")
|
||||
Else
|
||||
postID = String.Empty
|
||||
postDate = String.Empty
|
||||
End If
|
||||
End With
|
||||
If Not postID.IsEmptyString Then
|
||||
If Not _TempPostsList.Contains(postID) Then
|
||||
_TempPostsList.Add(postID)
|
||||
Else
|
||||
Exit Sub
|
||||
End If
|
||||
End If
|
||||
result = False
|
||||
media = TryCreateMedia(n, postID, postDate, result, True, specFolder,, False)
|
||||
If result Then _TempMediaList.ListAddList(media, LNC)
|
||||
Next
|
||||
End If
|
||||
End Using
|
||||
End If
|
||||
End If
|
||||
Catch ex As Exception
|
||||
_complete = ProcessFunctionErrComplete(ProcessException(ex, Token, $"stories downloading error [{url}]"))
|
||||
End Try
|
||||
Loop While Not _complete
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Download chat media"
|
||||
Private Sub DownloadChatMedia(ByVal Cursor As Integer, ByVal Token As CancellationToken)
|
||||
Dim url$ = String.Empty
|
||||
@@ -329,7 +395,8 @@ Namespace API.OnlyFans
|
||||
#End Region
|
||||
Private Function TryCreateMedia(ByVal n As EContainer, ByVal PostID As String, Optional ByVal PostDate As String = Nothing,
|
||||
Optional ByRef Result As Boolean = False, Optional ByVal IsHL As Boolean = False,
|
||||
Optional ByVal SpecFolder As String = Nothing, Optional ByVal PostUserID As String = Nothing) As List(Of UserMedia)
|
||||
Optional ByVal SpecFolder As String = Nothing, Optional ByVal PostUserID As String = Nothing,
|
||||
Optional ByVal TryUseOFS As Boolean = True) As List(Of UserMedia)
|
||||
Dim postUrl$, postUrlBase$, ext$
|
||||
Dim t As UTypes
|
||||
Dim mList As New List(Of UserMedia)
|
||||
@@ -348,7 +415,7 @@ Namespace API.OnlyFans
|
||||
Case "video"
|
||||
t = UTypes.Video
|
||||
ext = "mp4"
|
||||
If postUrl.IsEmptyString And Not IsHL Then
|
||||
If postUrl.IsEmptyString And Not IsHL And TryUseOFS Then
|
||||
t = UTypes.VideoPre
|
||||
_AbsMediaIndex += 1
|
||||
If Not PostUserID.IsEmptyString And IsSingleObjectDownload Then _
|
||||
|
||||
@@ -9,17 +9,25 @@
|
||||
Imports SCrawler.Plugin.Attributes
|
||||
Namespace API.OnlyFans
|
||||
Friend Class UserExchangeOptions
|
||||
<PSetting(NameOf(SiteSettings.DownloadTimeline), NameOf(MySettings))>
|
||||
Friend Property DownloadTimeline As Boolean
|
||||
<PSetting(NameOf(SiteSettings.DownloadStories), NameOf(MySettings))>
|
||||
Friend Property DownloadStories As Boolean
|
||||
<PSetting(NameOf(SiteSettings.DownloadHighlights), NameOf(MySettings))>
|
||||
Friend Property DownloadHighlights As Boolean
|
||||
<PSetting(NameOf(SiteSettings.DownloadChatMedia), NameOf(MySettings))>
|
||||
Friend Property DownloadChatMedia As Boolean
|
||||
Private ReadOnly MySettings As SiteSettings
|
||||
Friend Sub New(ByVal u As UserData)
|
||||
DownloadTimeline = u.MediaDownloadTimeline
|
||||
DownloadStories = u.MediaDownloadStories
|
||||
DownloadHighlights = u.MediaDownloadHighlights
|
||||
DownloadChatMedia = u.MediaDownloadChatMedia
|
||||
MySettings = u.HOST.Source
|
||||
End Sub
|
||||
Friend Sub New(ByVal s As SiteSettings)
|
||||
DownloadTimeline = s.DownloadTimeline.Value
|
||||
DownloadStories = s.DownloadStories.Value
|
||||
DownloadHighlights = s.DownloadHighlights.Value
|
||||
DownloadChatMedia = s.DownloadChatMedia.Value
|
||||
MySettings = s
|
||||
|
||||
@@ -287,7 +287,7 @@ Namespace API.Pinterest
|
||||
End Function
|
||||
End Class
|
||||
Private Function GetDataFromGalleryDL(ByVal URL As String, ByVal IsBoardsRequested As Boolean, ByVal Token As CancellationToken) As List(Of String)
|
||||
Dim command$ = $"gallery-dl --verbose --simulate "
|
||||
Dim command$ = $"""{Settings.GalleryDLFile.File}"" --verbose --simulate "
|
||||
Try
|
||||
If Not URL.IsEmptyString Then
|
||||
If MySettings.CookiesNetscapeFile.Exists Then command &= $"--cookies ""{MySettings.CookiesNetscapeFile}"" "
|
||||
|
||||
@@ -29,7 +29,6 @@ Namespace API.PornHub
|
||||
Private Const Name_DownloadFavorite As String = "DownloadFavorite"
|
||||
Private Const Name_DownloadGifs As String = "DownloadGifs"
|
||||
Private Const Name_DownloadPhotoOnlyFromModelHub As String = "DownloadPhotoOnlyFromModelHub"
|
||||
<Obsolete> Private Const Name_IsUser As String = "IsUser"
|
||||
#End Region
|
||||
#Region "Structures"
|
||||
Private Structure FlashVar : Implements IRegExCreator
|
||||
@@ -254,14 +253,7 @@ Namespace API.PornHub
|
||||
DownloadFavorite = .Value(Name_DownloadFavorite).FromXML(Of Boolean)(False)
|
||||
DownloadGifs = .Value(Name_DownloadGifs).FromXML(Of Integer)(False)
|
||||
DownloadPhotoOnlyFromModelHub = .Value(Name_DownloadPhotoOnlyFromModelHub).FromXML(Of Boolean)(True)
|
||||
If .Contains(Name_SiteMode) Then
|
||||
SiteMode = .Value(Name_SiteMode).FromXML(Of Integer)(SiteModes.User)
|
||||
Else
|
||||
'TODELETE: PornHub 'IsUser' 20231113
|
||||
#Disable Warning BC40008
|
||||
SiteMode = IIf(.Value(Name_IsUser).FromXML(Of Boolean)(True), SiteModes.User, SiteModes.Search)
|
||||
#Enable Warning
|
||||
End If
|
||||
SiteMode = .Value(Name_SiteMode).FromXML(Of Integer)(SiteModes.User)
|
||||
UpdateUserOptions()
|
||||
Else
|
||||
If UpdateUserOptions() Then .Value(Name_LabelsName) = LabelsString
|
||||
@@ -404,7 +396,8 @@ Namespace API.PornHub
|
||||
Dim r$ = Responser.GetResponse(URL)
|
||||
If Not r.IsEmptyString Then
|
||||
Dim l As List(Of UserVideo) = RegexFields(Of UserVideo)(r, {RegexUserVideos}, {6, 7, 3, 10})
|
||||
If l.ListExists And Not SiteMode = SiteModes.Playlists Then l = l.ListTake(3, l.Count).ToList
|
||||
'If l.ListExists And Not SiteMode = SiteModes.Playlists Then l = l.ListTake(3, l.Count).ToList
|
||||
If l.ListExists And Not SiteMode = SiteModes.Playlists Then l = l.ListTake(1, l.Count).ToList
|
||||
If l.ListExists Then
|
||||
If IsUser Then
|
||||
If Type = VideoTypes.Favorite Then
|
||||
|
||||
@@ -10,6 +10,7 @@ Imports SCrawler.API.Base
|
||||
Imports SCrawler.Plugin
|
||||
Imports SCrawler.Plugin.Attributes
|
||||
Imports PersonalUtilities.Tools.Web.Clients
|
||||
Imports PersonalUtilities.Tools.Web.Clients.Base
|
||||
Imports PersonalUtilities.Tools.Web.Documents.JSON
|
||||
Imports PersonalUtilities.Functions.XML
|
||||
Imports PersonalUtilities.Functions.RegularExpressions
|
||||
@@ -34,6 +35,8 @@ Namespace API.Reddit
|
||||
"You can find different tokens in the responses. Make sure that bearer token belongs to Reddit and not RedGifs." & vbCr &
|
||||
"There is not need to add a token if you are not using cookies to download the timeline.", IsAuth:=True)>
|
||||
Friend ReadOnly Property BearerToken As PropertyValue
|
||||
<PropertyOption(ControlText:="Use 'cUrl' to get a token", IsAuth:=True), PXML, PClonable, HiddenControl>
|
||||
Private ReadOnly Property BearerTokenUseCurl As PropertyValue
|
||||
#Region "TokenUpdateInterval"
|
||||
<PropertyOption(ControlText:="Token refresh interval", ControlToolTip:="Interval (in minutes) to refresh the token",
|
||||
AllowNull:=False, LeftOffset:=120, IsAuth:=True), PXML, PClonable>
|
||||
@@ -60,6 +63,10 @@ Namespace API.Reddit
|
||||
#Region "Other"
|
||||
<PropertyOption(ControlText:="Use M3U8", ControlToolTip:="Use M3U8 or mp4 for Reddit videos", IsAuth:=False), PXML, PClonable>
|
||||
Friend ReadOnly Property UseM3U8 As PropertyValue
|
||||
<PropertyOption(ControlText:="Check image", ControlToolTip:="Check the image if it exists before downloading (it makes downloading very slow)", IsAuth:=False), PXML, PClonable>
|
||||
Friend ReadOnly Property CheckImage As PropertyValue
|
||||
<PropertyOption(ControlText:="Check image: get original", ControlToolTip:="Get the original image if it exists", IsAuth:=False), PXML, PClonable>
|
||||
Friend ReadOnly Property CheckImageReturnOrig As PropertyValue
|
||||
#End Region
|
||||
#End Region
|
||||
#Region "Initializer"
|
||||
@@ -78,6 +85,7 @@ Namespace API.Reddit
|
||||
ApiClientID = New PropertyValue(String.Empty, GetType(String))
|
||||
ApiClientSecret = New PropertyValue(String.Empty, GetType(String))
|
||||
BearerToken = New PropertyValue(token, GetType(String), Sub(v) Responser.Headers.Add(DeclaredNames.Header_Authorization, v))
|
||||
BearerTokenUseCurl = New PropertyValue(True)
|
||||
TokenUpdateInterval = New PropertyValue(60 * 12)
|
||||
TokenUpdateIntervalProvider = New TokenRefreshIntervalProvider
|
||||
BearerTokenDateUpdate = New PropertyValue(Now.AddYears(-1))
|
||||
@@ -87,6 +95,8 @@ Namespace API.Reddit
|
||||
SavedPostsUserName = New PropertyValue(String.Empty, GetType(String))
|
||||
|
||||
UseM3U8 = New PropertyValue(True)
|
||||
CheckImage = New PropertyValue(False)
|
||||
CheckImageReturnOrig = New PropertyValue(True)
|
||||
|
||||
UrlPatternUser = "https://www.reddit.com/{0}/{1}/"
|
||||
ImageVideoContains = "reddit.com"
|
||||
@@ -263,29 +273,51 @@ Namespace API.Reddit
|
||||
result = False
|
||||
Dim r$ = String.Empty
|
||||
Dim c% = 0
|
||||
Dim _found As Boolean
|
||||
Dim useCurl As Boolean = Settings.CurlFile.Exists And CBool(BearerTokenUseCurl.Value)
|
||||
Dim curlUsed As Boolean = useCurl
|
||||
Do
|
||||
c += 1
|
||||
Using resp As New Responser With {
|
||||
.Method = "POST",
|
||||
.ProcessExceptionDecision = Function(status, obj, ee) If(status.StatusCode = 429, EDP.ReturnValue, ee)
|
||||
.ProcessExceptionDecision = Function(ByVal status As IResponserStatus, ByVal nullArg As Object, ByVal currErr As ErrorsDescriber) As ErrorsDescriber
|
||||
If status.StatusCode = 429 Then
|
||||
useCurl = False
|
||||
Return EDP.ReturnValue
|
||||
ElseIf status.StatusCode = Net.HttpStatusCode.Forbidden And Not useCurl And Settings.CurlFile.Exists Then
|
||||
useCurl = True
|
||||
Return EDP.ReturnValue
|
||||
Else
|
||||
Return currErr
|
||||
End If
|
||||
End Function
|
||||
}
|
||||
With resp
|
||||
With .PayLoadValues
|
||||
.Add("grant_type", "password")
|
||||
.Add("username", UserName)
|
||||
.Add("password", Password)
|
||||
End With
|
||||
.CredentialsUserName = ClientID
|
||||
.CredentialsPassword = ClientSecret
|
||||
.PreAuthenticate = True
|
||||
If useCurl Then
|
||||
If Settings.CurlFile.Exists Then
|
||||
curlUsed = True
|
||||
.Mode = Responser.Modes.Curl
|
||||
.CurlPath = Settings.CurlFile
|
||||
.CurlArgumentsLeft = $"-d ""grant_type=password&username={UserName}&password={Password}"" --user ""{ClientID}:{ClientSecret}"""
|
||||
Else
|
||||
Throw New ArgumentNullException("cUrl file", "The path to the cUrl file is not specified")
|
||||
End If
|
||||
Else
|
||||
.Mode = Responser.Modes.Default
|
||||
With .PayLoadValues
|
||||
.Add("grant_type", "password")
|
||||
.Add("username", UserName)
|
||||
.Add("password", Password)
|
||||
End With
|
||||
.CredentialsUserName = ClientID
|
||||
.CredentialsPassword = ClientSecret
|
||||
.PreAuthenticate = True
|
||||
End If
|
||||
End With
|
||||
r = resp.GetResponse("https://www.reddit.com/api/v1/access_token",, EDP.ThrowException)
|
||||
End Using
|
||||
If Not r.IsEmptyString Then
|
||||
Using j As EContainer = JsonDocument.Parse(r)
|
||||
If j.ListExists Then
|
||||
_found = True
|
||||
Dim newToken$ = j.Value("access_token")
|
||||
If Not newToken.IsEmptyString Then
|
||||
BearerToken.Value = $"Bearer {newToken}"
|
||||
@@ -296,7 +328,7 @@ Namespace API.Reddit
|
||||
End If
|
||||
End Using
|
||||
End If
|
||||
Loop While c < 5 And Not _found
|
||||
Loop While c < 5 And Not result
|
||||
End If
|
||||
Return result
|
||||
Catch ex As Exception
|
||||
|
||||
@@ -681,12 +681,16 @@ Namespace API.Reddit
|
||||
End Function
|
||||
Private Function TryImage(ByVal URL As String) As Boolean
|
||||
Try
|
||||
Dim img As Image = GetImage(SFile.GetBytesFromNet(URL, EDP.ThrowException), EDP.ThrowException)
|
||||
If Not img Is Nothing Then
|
||||
img.Dispose()
|
||||
Return True
|
||||
If Not CBool(MySiteSettings.CheckImage.Value) Then
|
||||
Return MySiteSettings.CheckImageReturnOrig.Value
|
||||
Else
|
||||
Return False
|
||||
Dim img As Image = GetImage(SFile.GetBytesFromNet(URL, EDP.ThrowException), EDP.ThrowException)
|
||||
If Not img Is Nothing Then
|
||||
img.Dispose()
|
||||
Return True
|
||||
Else
|
||||
Return False
|
||||
End If
|
||||
End If
|
||||
Catch
|
||||
Return False
|
||||
|
||||
@@ -25,6 +25,10 @@ Namespace API.ThreadsNet
|
||||
Return __HH_CSRF_TOKEN
|
||||
End Get
|
||||
End Property
|
||||
<CookieValueExtractor(NameOf(HH_CSRF_TOKEN))>
|
||||
Private Function GetValueFromCookies(ByVal PropName As String, ByVal c As CookieKeeper) As String
|
||||
Return c.GetCookieValue(IG.Header_CSRF_TOKEN_COOKIE, PropName, NameOf(HH_CSRF_TOKEN))
|
||||
End Function
|
||||
<PClonable> Protected ReadOnly __HH_IG_APP_ID As PropertyValue
|
||||
<PropertyOption(ControlText:="x-ig-app-id", AllowNull:=False, IsAuth:=True), ControlNumber(10)>
|
||||
Friend Overridable ReadOnly Property HH_IG_APP_ID As PropertyValue
|
||||
@@ -34,13 +38,17 @@ Namespace API.ThreadsNet
|
||||
End Property
|
||||
<PropertyOption(ControlText:="x-asbd-id", AllowNull:=True, IsAuth:=True), ControlNumber(20), PClonable>
|
||||
Friend ReadOnly Property HH_ASBD_ID As PropertyValue
|
||||
<PropertyOption(ControlText:="sec-ch-ua", AllowNull:=True, IsAuth:=True), ControlNumber(30), PClonable>
|
||||
Private ReadOnly Property HH_BROWSER As PropertyValue
|
||||
<PropertyOption(ControlText:="sec-ch-ua-full", ControlToolTip:="sec-ch-ua-full-version-list", AllowNull:=True, IsAuth:=True), ControlNumber(40), PClonable>
|
||||
Private ReadOnly Property HH_BROWSER_EXT As PropertyValue
|
||||
<PropertyOption(ControlText:="sec-ch-ua-platform", ControlToolTip:="sec-ch-ua-platform", AllowNull:=True, IsAuth:=True, LeftOffset:=120), ControlNumber(50), PClonable>
|
||||
Private ReadOnly Property HH_PLATFORM As PropertyValue
|
||||
<PropertyOption(ControlText:="UserAgent", IsAuth:=True), ControlNumber(60), PClonable>
|
||||
<PropertyOption(ControlText:="sec-ch-ua", AllowNull:=True, IsAuth:=True,
|
||||
InheritanceName:=SettingsCLS.HEADER_DEF_sec_ch_ua), ControlNumber(30), PClonable, PXML(OnlyForChecked:=True)>
|
||||
Friend ReadOnly Property HH_BROWSER As PropertyValue
|
||||
<PropertyOption(ControlText:="sec-ch-ua-full", ControlToolTip:=SettingsCLS.HEADER_DEF_sec_ch_ua_full_version_list, AllowNull:=True, IsAuth:=True,
|
||||
InheritanceName:=SettingsCLS.HEADER_DEF_sec_ch_ua_full_version_list), ControlNumber(40), PClonable, PXML(OnlyForChecked:=True)>
|
||||
Friend ReadOnly Property HH_BROWSER_EXT As PropertyValue
|
||||
<PropertyOption(ControlText:="sec-ch-ua-platform-ver", ControlToolTip:=SettingsCLS.HEADER_DEF_sec_ch_ua_platform_version, AllowNull:=True, IsAuth:=True, LeftOffset:=135,
|
||||
InheritanceName:=SettingsCLS.HEADER_DEF_sec_ch_ua_platform_version), ControlNumber(50), PClonable, PXML(OnlyForChecked:=True)>
|
||||
Friend ReadOnly Property HH_PLATFORM_VER As PropertyValue
|
||||
<PropertyOption(ControlText:="UserAgent", IsAuth:=True,
|
||||
InheritanceName:=SettingsCLS.HEADER_DEF_UserAgent), ControlNumber(60), PClonable, PXML(OnlyForChecked:=True)>
|
||||
Private ReadOnly Property HH_USER_AGENT As PropertyValue
|
||||
Private Sub ChangeResponserFields(ByVal PropName As String, ByVal Value As Object)
|
||||
If Not PropName.IsEmptyString Then
|
||||
@@ -52,7 +60,7 @@ Namespace API.ThreadsNet
|
||||
Case NameOf(HH_CSRF_TOKEN) : f = IG.Header_CSRF_TOKEN
|
||||
Case NameOf(HH_BROWSER) : f = IG.Header_Browser
|
||||
Case NameOf(HH_BROWSER_EXT) : f = IG.Header_BrowserExt
|
||||
Case NameOf(HH_PLATFORM) : f = IG.Header_Platform
|
||||
Case NameOf(HH_PLATFORM_VER) : f = IG.Header_Platform_Verion
|
||||
Case NameOf(HH_USER_AGENT) : isUserAgent = True
|
||||
End Select
|
||||
If Not f.IsEmptyString Then
|
||||
@@ -64,6 +72,19 @@ Namespace API.ThreadsNet
|
||||
End If
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Other properties"
|
||||
<PropertyOption(ControlText:="Request timer (any)",
|
||||
ControlToolTip:="The timer (in milliseconds) that SCrawler should wait before executing the next request." &
|
||||
vbCr & "The default value is 1'000." & vbCr & "The minimum value is 0." & IG.TimersUrgentTip, AllowNull:=False),
|
||||
PXML, PClonable>
|
||||
Friend ReadOnly Property RequestsWaitTimer_Any As PropertyValue
|
||||
<Provider(NameOf(RequestsWaitTimer_Any), FieldsChecker:=True)>
|
||||
Private ReadOnly Property RequestsWaitTimer_AnyProvider As IFormatProvider
|
||||
<PropertyOption(ControlText:="Download data",
|
||||
ControlToolTip:="The internal value indicates that site data should be downloaded." & vbCr &
|
||||
"It becomes unchecked when the site returns an error."), PXML>
|
||||
Friend ReadOnly Property DownloadData_Impl As PropertyValue
|
||||
#End Region
|
||||
#End Region
|
||||
#Region "Initializer"
|
||||
Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean)
|
||||
@@ -86,8 +107,6 @@ Namespace API.ThreadsNet
|
||||
|
||||
With Responser
|
||||
.Accept = "*/*"
|
||||
'URGENT: remove after debug
|
||||
.DeclaredError = EDP.SendToLog + EDP.ThrowException
|
||||
If .UserAgentExists Then useragent = .UserAgent
|
||||
With .Headers
|
||||
If .Count > 0 Then
|
||||
@@ -96,7 +115,7 @@ Namespace API.ThreadsNet
|
||||
asbd = .Value(IG.Header_ASBD_ID)
|
||||
browser = .Value(IG.Header_Browser)
|
||||
browserExt = .Value(IG.Header_BrowserExt)
|
||||
platform = .Value(IG.Header_Platform)
|
||||
platform = .Value(IG.Header_Platform_Verion)
|
||||
End If
|
||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.Authority, "www.threads.net"))
|
||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.Origin, "https://www.threads.net"))
|
||||
@@ -108,7 +127,10 @@ Namespace API.ThreadsNet
|
||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecFetchMode, "cors"))
|
||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecFetchSite, "same-origin"))
|
||||
.Add("Sec-Fetch-User", "?1")
|
||||
.Add(DeclaredNames.Header_FB_FRIENDLY_NAME, "BarcelonaProfileThreadsTabRefetchableQuery")
|
||||
.Add("dnt", 1)
|
||||
.Add("drp", 1)
|
||||
.Add(Instagram.UserData.GQL_HEADER_FB_FRINDLY_NAME, "BarcelonaProfileThreadsTabRefetchableQuery")
|
||||
.Remove("dht")
|
||||
End With
|
||||
.CookiesExtractMode = Responser.CookiesExtractModes.Any
|
||||
.CookiesUpdateMode = CookieKeeper.UpdateModes.ReplaceByNameAll
|
||||
@@ -122,9 +144,13 @@ Namespace API.ThreadsNet
|
||||
HH_ASBD_ID = New PropertyValue(asbd, GetType(String), Sub(v) ChangeResponserFields(NameOf(HH_ASBD_ID), v))
|
||||
HH_BROWSER = New PropertyValue(browser, GetType(String), Sub(v) ChangeResponserFields(NameOf(HH_BROWSER), v))
|
||||
HH_BROWSER_EXT = New PropertyValue(browserExt, GetType(String), Sub(v) ChangeResponserFields(NameOf(HH_BROWSER_EXT), v))
|
||||
HH_PLATFORM = New PropertyValue(platform, GetType(String), Sub(v) ChangeResponserFields(NameOf(HH_PLATFORM), v))
|
||||
HH_PLATFORM_VER = New PropertyValue(platform, GetType(String), Sub(v) ChangeResponserFields(NameOf(HH_PLATFORM_VER), v))
|
||||
HH_USER_AGENT = New PropertyValue(useragent, GetType(String), Sub(v) ChangeResponserFields(NameOf(HH_USER_AGENT), v))
|
||||
|
||||
RequestsWaitTimer_Any = New PropertyValue(1000)
|
||||
RequestsWaitTimer_AnyProvider = New IG.TimersChecker(0)
|
||||
DownloadData_Impl = New PropertyValue(True)
|
||||
|
||||
UrlPatternUser = "https://www.threads.net/@{0}"
|
||||
UserRegex = RParams.DMS(String.Format(UserRegexDefaultPattern, "threads.net/@"), 1)
|
||||
ImageVideoContains = "threads.net"
|
||||
@@ -151,7 +177,7 @@ Namespace API.ThreadsNet
|
||||
#End Region
|
||||
#Region "BaseAuthExists, GetUserUrl, GetUserPostUrl"
|
||||
Friend Overrides Function BaseAuthExists() As Boolean
|
||||
Return Responser.CookiesExists And {HH_CSRF_TOKEN, HH_IG_APP_ID}.All(Function(v) ACheck(Of String)(v.Value))
|
||||
Return Responser.CookiesExists And {HH_CSRF_TOKEN, HH_IG_APP_ID}.All(Function(v) ACheck(Of String)(v.Value)) And CBool(DownloadData_Impl.Value)
|
||||
End Function
|
||||
Friend Overrides Function GetUserUrl(ByVal User As IPluginContentProvider) As String
|
||||
Return String.Format(UrlPatternUser, DirectCast(User, UserData).NameTrue)
|
||||
@@ -167,13 +193,23 @@ Namespace API.ThreadsNet
|
||||
End Function
|
||||
#End Region
|
||||
#Region "Update"
|
||||
Private __Cookies As CookieKeeper = Nothing
|
||||
Friend Overrides Sub BeginEdit()
|
||||
__Cookies = Responser.Cookies.Copy
|
||||
MyBase.BeginEdit()
|
||||
End Sub
|
||||
Friend Overrides Sub Update()
|
||||
If _SiteEditorFormOpened And Responser.CookiesExists Then
|
||||
Dim csrf$ = If(Responser.Cookies.FirstOrDefault(Function(c) c.Name.StringToLower = IG.Header_CSRF_TOKEN_COOKIE)?.Value, String.Empty)
|
||||
Dim csrf$ = GetValueFromCookies(NameOf(HH_CSRF_TOKEN), Responser.Cookies)
|
||||
If Not csrf.IsEmptyString Then HH_CSRF_TOKEN.Value = csrf
|
||||
If Not __Cookies Is Nothing AndAlso Not __Cookies.ListEquals(Responser.Cookies) Then DownloadData_Impl.Value = True
|
||||
End If
|
||||
MyBase.Update()
|
||||
End Sub
|
||||
Friend Overrides Sub EndEdit()
|
||||
__Cookies.DisposeIfReady
|
||||
MyBase.EndEdit()
|
||||
End Sub
|
||||
#End Region
|
||||
End Class
|
||||
End Namespace
|
||||
@@ -24,11 +24,9 @@ Namespace API.ThreadsNet
|
||||
End Get
|
||||
End Property
|
||||
Private ReadOnly DefaultParser_ElemNode_Default() As Object = {"node", "thread_items", 0, "post"}
|
||||
Private OPT_LSD As String = String.Empty
|
||||
Private OPT_FB_DTSG As String = String.Empty
|
||||
Private ReadOnly Property Valid As Boolean
|
||||
Get
|
||||
Return Not OPT_LSD.IsEmptyString And Not OPT_FB_DTSG.IsEmptyString And Not ID.IsEmptyString
|
||||
Return ValidateBaseTokens() And Not ID.IsEmptyString
|
||||
End Get
|
||||
End Property
|
||||
#End Region
|
||||
@@ -54,23 +52,31 @@ Namespace API.ThreadsNet
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Download functions"
|
||||
Private Sub WaitTimer()
|
||||
If CInt(MySettings.RequestsWaitTimer_Any.Value) > 0 Then Thread.Sleep(CInt(MySettings.RequestsWaitTimer_Any.Value))
|
||||
End Sub
|
||||
Private Sub DisableDownload()
|
||||
MySettings.DownloadData_Impl.Value = False
|
||||
MyMainLOG = $"{Site} downloading is disabled until you update your credentials"
|
||||
End Sub
|
||||
Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken)
|
||||
Dim errorFound As Boolean = False
|
||||
Try
|
||||
Responser.Method = "POST"
|
||||
LoadSavePostsKV(True)
|
||||
OPT_LSD = String.Empty
|
||||
OPT_FB_DTSG = String.Empty
|
||||
DownloadData(String.Empty, Token)
|
||||
Catch ex As Exception
|
||||
errorFound = True
|
||||
Throw ex
|
||||
Finally
|
||||
Responser.Method = "POST"
|
||||
UpdateResponser()
|
||||
MySettings.UpdateResponserData(Responser)
|
||||
If Not errorFound Then LoadSavePostsKV(False)
|
||||
End Try
|
||||
If CBool(MySettings.DownloadData_Impl.Value) Then
|
||||
Dim errorFound As Boolean = False
|
||||
Try
|
||||
Responser.Method = "POST"
|
||||
LoadSavePostsKV(True)
|
||||
ResetBaseTokens()
|
||||
DownloadData(String.Empty, Token)
|
||||
Catch ex As Exception
|
||||
errorFound = True
|
||||
Throw ex
|
||||
Finally
|
||||
Responser.Method = "POST"
|
||||
UpdateResponser()
|
||||
MySettings.UpdateResponserData(Responser)
|
||||
If Not errorFound Then LoadSavePostsKV(False)
|
||||
End Try
|
||||
End If
|
||||
End Sub
|
||||
Protected Overrides Sub UpdateResponser()
|
||||
If Not Responser Is Nothing AndAlso Not Responser.Disposed Then
|
||||
@@ -95,11 +101,11 @@ Namespace API.ThreadsNet
|
||||
UpdateCredentials()
|
||||
If idIsNull And Not ID.IsEmptyString Then _ForceSaveUserInfo = True
|
||||
End If
|
||||
If Not Valid Then Throw New Plugin.ExitException("Some credentials are missing")
|
||||
If Not Valid Then DisableDownload() : Throw New Plugin.ExitException("Some credentials are missing")
|
||||
|
||||
Responser.Method = "POST"
|
||||
Responser.Referer = $"https://www.threads.net/@{NameTrue}"
|
||||
Responser.Headers.Add(Header_FB_LSD, OPT_LSD)
|
||||
Responser.Headers.Add(GQL_HEADER_FB_LSD, Token_lsd)
|
||||
|
||||
Dim nextCursor$ = String.Empty
|
||||
Dim dataFound As Boolean = False
|
||||
@@ -112,7 +118,7 @@ Namespace API.ThreadsNet
|
||||
End If
|
||||
vars = SymbolsConverter.ASCII.EncodeSymbolsOnly("{" & vars & "}")
|
||||
|
||||
URL = String.Format(urlPattern, OPT_LSD, vars, SymbolsConverter.ASCII.EncodeSymbolsOnly(OPT_FB_DTSG))
|
||||
URL = String.Format(urlPattern, Token_lsd, vars, Token_dtsg_Var)
|
||||
|
||||
Using j As EContainer = GetDocument(URL, Token)
|
||||
If j.ListExists Then
|
||||
@@ -135,8 +141,9 @@ Namespace API.ThreadsNet
|
||||
Private Function GetDocument(ByVal URL As String, ByVal Token As CancellationToken, Optional ByVal Round As Integer = 0) As EContainer
|
||||
Try
|
||||
ThrowAny(Token)
|
||||
If Round > 0 AndAlso Not UpdateCredentials() Then Throw New Exception("Failed to update credentials")
|
||||
If Round > 0 AndAlso Not UpdateCredentials() Then DisableDownload() : Throw New Exception("Failed to update credentials")
|
||||
ThrowAny(Token)
|
||||
WaitTimer()
|
||||
Dim r$ = Responser.GetResponse(URL)
|
||||
If Not r.IsEmptyString Then Return JsonDocument.Parse(r) Else Throw New Exception("Failed to get a response")
|
||||
Catch ex As Exception
|
||||
@@ -149,47 +156,43 @@ Namespace API.ThreadsNet
|
||||
End Function
|
||||
Private Function UpdateCredentials(Optional ByVal e As ErrorsDescriber = Nothing) As Boolean
|
||||
Dim URL$ = $"https://www.threads.net/@{NameTrue}"
|
||||
OPT_LSD = String.Empty
|
||||
OPT_FB_DTSG = String.Empty
|
||||
ResetBaseTokens()
|
||||
Dim headers As New HttpHeaderCollection
|
||||
headers.AddRange(Responser.Headers)
|
||||
Try
|
||||
Responser.Method = "GET"
|
||||
Responser.Referer = URL
|
||||
Responser.Headers.Remove(Header_FB_LSD)
|
||||
With Responser
|
||||
.Method = "GET"
|
||||
.Referer = URL
|
||||
With .Headers
|
||||
.Clear()
|
||||
.Add("dnt", 1)
|
||||
.Add("drp", 1)
|
||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.Authority, "www.threads.net"))
|
||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.Origin, "https://www.threads.net"))
|
||||
.Add("Sec-Ch-Ua-Model", "")
|
||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecChUaMobile, "?0"))
|
||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecChUaPlatform, """Windows"""))
|
||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecFetchDest, "document"))
|
||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecFetchMode, "navigate"))
|
||||
.Add(HttpHeaderCollection.GetSpecialHeader(MyHeaderTypes.SecFetchSite, "none"))
|
||||
.Add("Upgrade-Insecure-Requests", 1)
|
||||
.Add("Sec-Fetch-User", "?1")
|
||||
.Add(IGS.Header_Browser, MySettings.HH_BROWSER.Value)
|
||||
.Add(IGS.Header_BrowserExt, MySettings.HH_BROWSER_EXT.Value)
|
||||
End With
|
||||
End With
|
||||
WaitTimer()
|
||||
Dim r$ = Responser.GetResponse(URL,, EDP.ThrowException)
|
||||
Dim rr As RParams
|
||||
Dim tt$, ttVal$
|
||||
If Not r.IsEmptyString Then
|
||||
rr = RParams.DM(Instagram.PageTokenRegexPatternDefault, 0, RegexReturn.List, EDP.ReturnValue)
|
||||
Dim tokens As List(Of String) = RegexReplace(r, rr)
|
||||
If tokens.ListExists Then
|
||||
With rr
|
||||
.Match = Nothing
|
||||
.MatchSub = 1
|
||||
.WhatGet = RegexReturn.Value
|
||||
End With
|
||||
For Each tt In tokens
|
||||
If Not OPT_FB_DTSG.IsEmptyString And Not OPT_LSD.IsEmptyString Then
|
||||
Exit For
|
||||
Else
|
||||
ttVal = RegexReplace(tt, rr)
|
||||
If Not ttVal.IsEmptyString Then
|
||||
If ttVal.Contains(":") Then
|
||||
If OPT_FB_DTSG.IsEmptyString Then OPT_FB_DTSG = ttVal
|
||||
Else
|
||||
If OPT_LSD.IsEmptyString Then OPT_LSD = ttVal
|
||||
End If
|
||||
End If
|
||||
End If
|
||||
Next
|
||||
End If
|
||||
If ID.IsEmptyString Then ID = RegexReplace(r, RParams.DMS("""props"":\{""user_id"":""(\d+)""\},", 1, EDP.ReturnValue))
|
||||
ParseTokens(r, 0)
|
||||
If ID.IsEmptyString Then ID = RegexReplace(r, RParams.DMS("""props"":\{""user_id"":""(\d+)""", 1, EDP.ReturnValue))
|
||||
End If
|
||||
Return Valid
|
||||
Catch ex As Exception
|
||||
Dim notFound$ = String.Empty
|
||||
If OPT_FB_DTSG.IsEmptyString Then notFound.StringAppend(Header_FB_LSD)
|
||||
If OPT_LSD.IsEmptyString Then notFound.StringAppend("lsd")
|
||||
ValidateBaseTokens(notFound)
|
||||
If ID.IsEmptyString Then notFound.StringAppend("User ID")
|
||||
DisableDownload()
|
||||
Dim eex As New ErrorsDescriberException($"{ToStringForLog()}: failed to update some{IIf(notFound.IsEmptyString, String.Empty, $" ({notFound})")} credentials",,, ex) With {
|
||||
.ReplaceMainMessage = True,
|
||||
.SendToLogOnlyMessage = Responser.StatusCode = Net.HttpStatusCode.InternalServerError And Responser.Status = Net.WebExceptionStatus.ProtocolError
|
||||
@@ -197,6 +200,12 @@ Namespace API.ThreadsNet
|
||||
'LogError(ex, $"failed to update some{IIf(notFound.IsEmptyString, String.Empty, $" ({notFound})")} credentials", e)
|
||||
LogError(eex, String.Empty, e)
|
||||
Return False
|
||||
Finally
|
||||
If headers.ListExists Then
|
||||
Responser.Headers.Clear()
|
||||
Responser.Headers.AddRange(headers)
|
||||
headers.Dispose()
|
||||
End If
|
||||
End Try
|
||||
End Function
|
||||
#End Region
|
||||
@@ -224,7 +233,7 @@ Namespace API.ThreadsNet
|
||||
If m.State = UserMedia.States.Missing And Not m.Post.ID.IsEmptyString Then
|
||||
ThrowAny(Token)
|
||||
vars = SymbolsConverter.ASCII.EncodeSymbolsOnly("{" & String.Format(varsPattern, m.Post.ID.Split("_").FirstOrDefault, ID) & "}")
|
||||
URL = String.Format(urlPattern, OPT_LSD, vars, SymbolsConverter.ASCII.EncodeSymbolsOnly(OPT_FB_DTSG))
|
||||
URL = String.Format(urlPattern, Token_lsd, vars, Token_dtsg_Var)
|
||||
|
||||
j = GetDocument(URL, Token)
|
||||
If j.ListExists Then
|
||||
|
||||
@@ -17,11 +17,13 @@ Namespace API.TikTok
|
||||
Friend ReadOnly Property RemoveTagsFromTitle As PropertyValue
|
||||
<PropertyOption(ControlText:="Use native title", ControlToolTip:="Use a user-created video title for the filename instead of the video ID."), PXML, PClonable>
|
||||
Friend ReadOnly Property TitleUseNative As PropertyValue
|
||||
<PropertyOption(ControlText:="Use native title in standalone downloader",
|
||||
<PropertyOption(ControlText:="Use native title (standalone downloader)",
|
||||
ControlToolTip:="Use a user-created video title for the filename instead of the video ID."), PXML, PClonable>
|
||||
Friend ReadOnly Property TitleUseNativeSTD As PropertyValue
|
||||
<PropertyOption(ControlText:="Add video ID to video title"), PXML, PClonable>
|
||||
Friend ReadOnly Property TitleAddVideoID As PropertyValue
|
||||
<PropertyOption(ControlText:="Add video ID to video title (standalone downloader)"), PXML, PClonable>
|
||||
Friend ReadOnly Property TitleAddVideoIDSTD As PropertyValue
|
||||
<PropertyOption(ControlText:="Use regex to clean video title"), PXML, PClonable>
|
||||
Friend ReadOnly Property TitleUseRegexForTitle As PropertyValue
|
||||
<PropertyOption(ControlText:="Title regex", ControlToolTip:="Regex to clean video title"), PXML, PClonable>
|
||||
@@ -29,15 +31,20 @@ Namespace API.TikTok
|
||||
<PropertyOption(ControlText:="Use video date as file date",
|
||||
ControlToolTip:="Set the file date to the date the video was added (website) (if available)."), PXML, PClonable>
|
||||
Friend ReadOnly Property UseParsedVideoDate As PropertyValue
|
||||
<PropertyOption(ControlText:="Use video date as file date (standalone downloader)",
|
||||
ControlToolTip:="Set the file date to the date the video was added (website) (if available)."), PXML, PClonable>
|
||||
Friend ReadOnly Property UseParsedVideoDateSTD As PropertyValue
|
||||
Friend Sub New(ByVal AccName As String, ByVal Temp As Boolean)
|
||||
MyBase.New("TikTok", "www.tiktok.com", AccName, Temp, My.Resources.SiteResources.TikTokIcon_32, My.Resources.SiteResources.TikTokPic_192)
|
||||
RemoveTagsFromTitle = New PropertyValue(False)
|
||||
TitleUseNative = New PropertyValue(True)
|
||||
TitleUseNativeSTD = New PropertyValue(False)
|
||||
TitleUseNativeSTD = New PropertyValue(True)
|
||||
TitleAddVideoID = New PropertyValue(True)
|
||||
TitleAddVideoIDSTD = New PropertyValue(True)
|
||||
TitleUseRegexForTitle = New PropertyValue(False)
|
||||
TitleUseRegexForTitle_Value = New PropertyValue(String.Empty, GetType(String))
|
||||
UseParsedVideoDate = New PropertyValue(True)
|
||||
UseParsedVideoDateSTD = New PropertyValue(False)
|
||||
UseNetscapeCookies = True
|
||||
UrlPatternUser = "https://www.tiktok.com/@{0}/"
|
||||
UserRegex = RParams.DMS(String.Format(UserRegexDefaultPattern, "tiktok.com/@"), 1)
|
||||
|
||||
@@ -151,6 +151,23 @@ Namespace API.TikTok
|
||||
End Try
|
||||
Return Title
|
||||
End Function
|
||||
Private Function GetNewFileName(ByVal Title As String, ByVal Native As Boolean, ByVal RemoveTags As Boolean, ByVal AddVideoID As Boolean,
|
||||
ByVal PostID As String, ByVal TitleRegex As RParams) As String
|
||||
If Not Title.IsEmptyString Then Title = Left(Title, 150).StringTrim
|
||||
If Title.IsEmptyString Or Not Native Then
|
||||
Title = PostID
|
||||
Else
|
||||
If RemoveTags Then Title = RegexReplace(Title, RegexTagsReplacer)
|
||||
Title = Title.StringTrim
|
||||
If Title.IsEmptyString Then
|
||||
Title = PostID
|
||||
ElseIf AddVideoID Then
|
||||
Title &= $" ({PostID})"
|
||||
End If
|
||||
Title = ChangeTitleRegex(Title, TitleRegex)
|
||||
End If
|
||||
Return Title
|
||||
End Function
|
||||
Friend Overrides Sub DownloadData(ByVal Token As CancellationToken)
|
||||
MyBase.DownloadData(Token)
|
||||
UserCache.DisposeIfReady(False)
|
||||
@@ -228,20 +245,8 @@ Namespace API.TikTok
|
||||
Else
|
||||
Exit Sub
|
||||
End If
|
||||
title = j.Value("title").StringRemoveWinForbiddenSymbols
|
||||
If Not title.IsEmptyString Then title = Left(title, 150)
|
||||
If title.IsEmptyString Or Not TitleUseNative Then
|
||||
title = postID
|
||||
Else
|
||||
If RemoveTagsFromTitle Then title = RegexReplace(title, RegexTagsReplacer)
|
||||
title = title.StringTrim
|
||||
If title.IsEmptyString Then
|
||||
title = postID
|
||||
ElseIf TitleAddVideoID Then
|
||||
title &= $" ({postID})"
|
||||
End If
|
||||
title = ChangeTitleRegex(title, titleRegex)
|
||||
End If
|
||||
title = GetNewFileName(j.Value("title").StringRemoveWinForbiddenSymbols,
|
||||
TitleUseNative, RemoveTagsFromTitle, TitleAddVideoID, postID, titleRegex)
|
||||
postDate = AConvert(Of Date)(j.Value("timestamp"), UnixDate32Provider, Nothing)
|
||||
If Not postDate.HasValue Then postDate = AConvert(Of Date)(j.Value("upload_date"), SimpleDateConverter, Nothing)
|
||||
Select Case CheckDatesLimit(postDate, SimpleDateConverter)
|
||||
@@ -296,7 +301,7 @@ Namespace API.TikTok
|
||||
End If
|
||||
If DateBefore.HasValue Then command &= $"--datebefore {DateBefore.Value.AddDays(1).ToStringDate(SimpleDateConverter)} "
|
||||
If DateAfter.HasValue Then command &= $"--dateafter {DateAfter.Value.AddDays(-1).ToStringDate(SimpleDateConverter)} "
|
||||
If Not CBool(MySettings.UseParsedVideoDate.Value) Then command &= "--no-mtime "
|
||||
If Not CBool(If(IsSingleObjectDownload, MySettings.UseParsedVideoDateSTD, MySettings.UseParsedVideoDate).Value) Then command &= "--no-mtime "
|
||||
If MySettings.CookiesNetscapeFile.Exists Then command &= $"--no-cookies-from-browser --cookies ""{MySettings.CookiesNetscapeFile}"" "
|
||||
command &= $"{URL} "
|
||||
If SupportOutput Then
|
||||
@@ -347,17 +352,18 @@ Namespace API.TikTok
|
||||
Dim m As New UserMedia(Data.URL, UserMedia.Types.Video)
|
||||
If Not f.IsEmptyString Then f = TitleHtmlConverter(f)
|
||||
If Not f.IsEmptyString Then
|
||||
If CBool(MySettings.RemoveTagsFromTitle.Value) Then f = RegexReplace(f, RegexTagsReplacer)
|
||||
f = f.StringTrim
|
||||
If Not f.IsEmptyString Then
|
||||
If CBool(MySettings.TitleAddVideoID.Value) Then f &= $" ({m.File.Name})"
|
||||
f = ChangeTitleRegex(f, GetTitleRegex)
|
||||
m.File.Name = f
|
||||
End If
|
||||
f = GetNewFileName(f, MySettings.TitleUseNativeSTD.Value, MySettings.RemoveTagsFromTitle.Value, MySettings.TitleAddVideoIDSTD.Value,
|
||||
m.File.Name, GetTitleRegex)
|
||||
If Not f.IsEmptyString Then m.File.Name = f.StringTrim
|
||||
End If
|
||||
_TempMediaList.Add(m)
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "EraseData"
|
||||
Protected Overrides Sub EraseData_AdditionalDataFiles()
|
||||
LastDownloadDate = Nothing
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Exception"
|
||||
Protected Overrides Function DownloadingException(ByVal ex As Exception, ByVal Message As String, Optional ByVal FromPE As Boolean = False,
|
||||
Optional ByVal EObj As Object = Nothing) As Integer
|
||||
|
||||
@@ -276,11 +276,6 @@ Namespace API
|
||||
Set(ByVal NewDate As Date?)
|
||||
End Set
|
||||
End Property
|
||||
Friend Overrides ReadOnly Property FitToAddParams As Boolean
|
||||
Get
|
||||
Return Count > 0 AndAlso Collections.Exists(Function(c) c.FitToAddParams)
|
||||
End Get
|
||||
End Property
|
||||
Friend Overrides Property ScriptUse As Boolean
|
||||
Get
|
||||
Return Count > 0 AndAlso Collections.All(Function(c) c.ScriptUse)
|
||||
|
||||
@@ -184,6 +184,7 @@ Namespace API.Xhamster
|
||||
#End Region
|
||||
#Region "Download functions"
|
||||
Friend Function GetNonUserUrl(ByVal Page As Integer) As String
|
||||
Const newest$ = "/newest"
|
||||
If SiteMode = SiteModes.User And Not IsCreator Then
|
||||
Return String.Empty
|
||||
Else
|
||||
@@ -200,6 +201,7 @@ Namespace API.Xhamster
|
||||
url &= $"/{TrueName}"
|
||||
|
||||
Dim args$ = Arguments
|
||||
If (args.IsEmptyString OrElse Not args.Contains(newest)) And Not SiteMode = SiteModes.Search Then url &= newest
|
||||
If Page > 1 Then
|
||||
If args.IsEmptyString Then
|
||||
If SiteMode = SiteModes.Search Then
|
||||
@@ -262,30 +264,39 @@ Namespace API.Xhamster
|
||||
Dim m As UserMedia
|
||||
Dim checkLimit As Func(Of Boolean) = Function() limit > 0 And SearchPostsCount >= limit And IsVideo
|
||||
|
||||
If IsSavedPosts Then
|
||||
If IsVideo Then
|
||||
containerNodes.Add({"favoriteVideoListComponent", "models"})
|
||||
containerNodes.Add({"favoriteVideoListComponent", "videoThumbProps"})
|
||||
Else
|
||||
containerNodes.Add({"favoritesGalleriesAndPhotosCollection"})
|
||||
End If
|
||||
ElseIf Not SiteMode = SiteModes.Search Then
|
||||
If IsVideo Then
|
||||
containerNodes.Add({"trendingVideoListComponent", "models"})
|
||||
containerNodes.Add({"pagesCategoryComponent", "trendingVideoListProps", "models"})
|
||||
containerNodes.Add({"trendingVideoSectionComponent", "videoModels"})
|
||||
containerNodes.Add({"trendingVideoSectionComponent", "videoListProps", "videoThumbProps"})
|
||||
containerNodes.Add({"userVideoCollection"})
|
||||
containerNodes.Add({"videoListComponent", "models"})
|
||||
containerNodes.Add({"videoListComponent", "videoThumbProps"})
|
||||
Else
|
||||
containerNodes.Add({"userGalleriesCollection"})
|
||||
End If
|
||||
End If
|
||||
|
||||
If IsSavedPosts Then
|
||||
URL = $"https://xhamster.com/my/favorites/{IIf(IsVideo, "videos", "photos-and-galleries")}{IIf(Page = 1, String.Empty, $"/{Page}")}"
|
||||
containerNodes.Add(If(IsVideo, {"favoriteVideoListComponent", "models"}, {"favoritesGalleriesAndPhotosCollection"}))
|
||||
ElseIf IsChannel Then
|
||||
URL = $"https://xhamster.com/channels/{TrueName}/newest{IIf(Page = 1, String.Empty, $"/{Page}")}"
|
||||
containerNodes.Add({"trendingVideoListComponent", "models"})
|
||||
containerNodes.Add({"pagesCategoryComponent", "trendingVideoListProps", "models"})
|
||||
ElseIf SiteMode = SiteModes.Search Then
|
||||
URL = GetNonUserUrl(Page)
|
||||
containerNodes.Add({"searchResult", "models"})
|
||||
ElseIf IsCreator Or SiteMode = SiteModes.Tags Or SiteMode = SiteModes.Categories Or SiteMode = SiteModes.Pornstars Then
|
||||
URL = GetNonUserUrl(Page)
|
||||
If SiteMode = SiteModes.Pornstars Then
|
||||
containerNodes.Add({"trendingVideoListComponent", "models"})
|
||||
containerNodes.Add({"pagesCategoryComponent", "trendingVideoListProps", "models"})
|
||||
Else
|
||||
containerNodes.Add({"pagesCategoryComponent", "trendingVideoListProps", "models"})
|
||||
containerNodes.Add({"trendingVideoListComponent", "models"})
|
||||
End If
|
||||
containerNodes.Add({"trendingVideoSectionComponent", "videoModels"})
|
||||
Else
|
||||
URL = $"https://xhamster.com/users/{TrueName}/{IIf(IsVideo, "videos", "photos")}{IIf(Page = 1, String.Empty, $"/{Page}")}"
|
||||
containerNodes.Add({If(IsVideo, "userVideoCollection", "userGalleriesCollection")})
|
||||
containerNodes.Add(If(IsVideo, {"videoListComponent", "models"}, {"userGalleriesCollection"}))
|
||||
End If
|
||||
ThrowAny(Token)
|
||||
|
||||
|
||||
@@ -230,7 +230,7 @@ Namespace API.YouTube
|
||||
End If
|
||||
If list.Count > 0 Then
|
||||
With list(0)
|
||||
If Settings.UserSiteNameUpdateEveryTime Or UserSiteName.IsEmptyString Then UserSiteName = .UserTitle
|
||||
If Settings.UpdateUserSiteNameEveryTime Or UserSiteName.IsEmptyString Then UserSiteName = .UserTitle
|
||||
If FriendlyName.IsEmptyString Then FriendlyName = UserSiteName
|
||||
End With
|
||||
_TempMediaList.AddRange(list.Select(Function(c) New UserMedia(c) With {.URL = If(IsSubscription, c.ThumbnailUrlMedia, .URL)}))
|
||||
@@ -467,6 +467,13 @@ Namespace API.YouTube
|
||||
_TempMediaList.Add(New UserMedia(Data))
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "EraseData"
|
||||
Protected Overrides Sub EraseData_AdditionalDataFiles()
|
||||
LastDownloadDateVideos = Nothing
|
||||
LastDownloadDateShorts = Nothing
|
||||
LastDownloadDatePlaylist = Nothing
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "DownloadingException"
|
||||
Protected Overrides Function DownloadingException(ByVal ex As Exception, ByVal Message As String, Optional ByVal FromPE As Boolean = False,
|
||||
Optional ByVal EObj As Object = Nothing) As Integer
|
||||
|
||||
@@ -18,8 +18,6 @@ Namespace DownloadObjects
|
||||
Friend Event PauseChanged(ByVal Value As PauseModes)
|
||||
Friend Enum Modes As Integer
|
||||
None = 0
|
||||
[Default] = 1
|
||||
All = 2
|
||||
Specified = 3
|
||||
Groups = 4
|
||||
End Enum
|
||||
@@ -295,6 +293,9 @@ Namespace DownloadObjects
|
||||
Return $"{Name} ({GetWorkingState()}): last download date: {GetLastDateString()}; next run: {GetNextDateString()}"
|
||||
End If
|
||||
End Function
|
||||
Friend Overrides Function ToStringViewFilters() As String
|
||||
Return $"Scheduler plan '{Name}'{IIf(IsManual, " (manual)", String.Empty)}"
|
||||
End Function
|
||||
#End Region
|
||||
#End Region
|
||||
#Region "Initializer"
|
||||
@@ -314,7 +315,9 @@ Namespace DownloadObjects
|
||||
Friend Sub New(ByVal x As EContainer)
|
||||
Me.New
|
||||
Initialization = True
|
||||
Mode = x.Value(Name_Mode).FromXML(Of Integer)(Modes.None)
|
||||
Dim m% = x.Value(Name_Mode).FromXML(Of Integer)(Modes.None)
|
||||
If m = 1 Or m = 2 Then m = Modes.Specified
|
||||
Mode = m
|
||||
Import(x)
|
||||
If Name.IsEmptyString Then Name = "Default"
|
||||
Groups.ListAddList(x.Value(Name_Groups).StringToList(Of String)("|"), LAP.NotContainsOnly)
|
||||
@@ -555,38 +558,6 @@ Namespace DownloadObjects
|
||||
End Try
|
||||
End Sub
|
||||
Select Case Mode
|
||||
Case Modes.All
|
||||
Dim CheckLabels As Predicate(Of IUserData) = Function(ByVal u As IUserData) As Boolean
|
||||
If LabelsExcluded.Count = 0 Then
|
||||
Return True
|
||||
ElseIf u.Labels.Count = 0 Then
|
||||
Return True
|
||||
Else
|
||||
Return Not u.Labels.ListContains(LabelsExcluded)
|
||||
End If
|
||||
End Function
|
||||
Dim CheckSites As Predicate(Of IUserData) = Function(u) SitesExcluded.Count = 0 OrElse Not SitesExcluded.Contains(u.Site)
|
||||
Dim ExistsPredicate As Predicate(Of IUserData)
|
||||
If Subscriptions Then
|
||||
If SubscriptionsOnly Then
|
||||
ExistsPredicate = UserExistsSubscriptionsPredicate
|
||||
Else
|
||||
ExistsPredicate = UserExistsPredicate
|
||||
End If
|
||||
Else
|
||||
ExistsPredicate = UserExistsNonSubscriptionsPredicate
|
||||
End If
|
||||
users.ListAddList(Settings.GetUsers(Function(u) ExistsPredicate(u) And CheckLabels.Invoke(u) And CheckSites.Invoke(u)))
|
||||
If UsersCount <> 0 And users.Count > 0 Then
|
||||
users = users.ListTake(If(UsersCount > 0, -1, -2), Math.Abs(UsersCount))
|
||||
If UsersCount < 0 Then users = users.ListReverse
|
||||
End If
|
||||
Case Modes.Default
|
||||
Using g As New GroupParameters
|
||||
g.LabelsExcluded.ListAddList(LabelsExcluded)
|
||||
g.SitesExcluded.ListAddList(SitesExcluded)
|
||||
users.ListAddList(DownloadGroup.GetUsers(g))
|
||||
End Using
|
||||
Case Modes.Specified : users.ListAddList(DownloadGroup.GetUsers(Me))
|
||||
Case Modes.Groups
|
||||
If Groups.Count > 0 And Settings.Groups.Count > 0 Then
|
||||
@@ -601,7 +572,19 @@ Namespace DownloadObjects
|
||||
With Downloader
|
||||
.AutoDownloaderWorking = True
|
||||
If .Downloaded.Count > 0 Then .Downloaded.RemoveAll(Function(u) Keys.Contains(u.Key)) : .InvokeDownloadsChangeEvent()
|
||||
Do : Try : doRound += 1 : .AddRange(users, True) : Exit Do : Catch iex As IndexOutOfRangeException : Thread.Sleep(200) : End Try : Loop While doRound < doLim
|
||||
Do
|
||||
Try
|
||||
doRound += 1
|
||||
.AddRange(users, True)
|
||||
Exit Do
|
||||
Catch iex As Exception
|
||||
If doRound = doLim Then
|
||||
Throw iex
|
||||
Else
|
||||
Thread.Sleep(200)
|
||||
End If
|
||||
End Try
|
||||
Loop While doRound <= doLim
|
||||
While .Working Or .Count > 0 : notify.Invoke() : Thread.Sleep(200) : End While
|
||||
.AutoDownloaderWorking = False
|
||||
notify.Invoke
|
||||
@@ -615,7 +598,7 @@ Namespace DownloadObjects
|
||||
End With
|
||||
End If
|
||||
Catch ex As Exception
|
||||
ErrorsDescriber.Execute(EDP.SendToLog, ex, "[AutoDownloader.Download]")
|
||||
ErrorsDescriber.Execute(EDP.SendToLog, ex, $"[AutoDownloader.Download({Name})]")
|
||||
Finally
|
||||
Keys.Clear()
|
||||
LastDownloadDate = Now
|
||||
|
||||
@@ -25,16 +25,14 @@ Namespace DownloadObjects
|
||||
Me.components = New System.ComponentModel.Container()
|
||||
Dim CONTAINER_MAIN As System.Windows.Forms.ToolStripContainer
|
||||
Dim TP_MODE As System.Windows.Forms.TableLayoutPanel
|
||||
Dim ActionButton5 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||
Dim ActionButton1 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||
Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(AutoDownloaderEditorForm))
|
||||
Dim ActionButton6 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||
Dim ActionButton2 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||
Dim TP_NOTIFY As System.Windows.Forms.TableLayoutPanel
|
||||
Dim ActionButton7 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||
Dim ActionButton8 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 TT_MAIN As System.Windows.Forms.ToolTip
|
||||
Me.DEF_GROUP = New SCrawler.DownloadObjects.Groups.GroupDefaults()
|
||||
Me.OPT_ALL = New System.Windows.Forms.RadioButton()
|
||||
Me.OPT_DEFAULT = New System.Windows.Forms.RadioButton()
|
||||
Me.OPT_SPEC = New System.Windows.Forms.RadioButton()
|
||||
Me.OPT_DISABLED = New System.Windows.Forms.RadioButton()
|
||||
Me.OPT_GROUP = New System.Windows.Forms.RadioButton()
|
||||
@@ -67,13 +65,13 @@ Namespace DownloadObjects
|
||||
'CONTAINER_MAIN.ContentPanel
|
||||
'
|
||||
CONTAINER_MAIN.ContentPanel.Controls.Add(Me.DEF_GROUP)
|
||||
CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(476, 388)
|
||||
CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(476, 519)
|
||||
CONTAINER_MAIN.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
CONTAINER_MAIN.LeftToolStripPanelVisible = False
|
||||
CONTAINER_MAIN.Location = New System.Drawing.Point(0, 0)
|
||||
CONTAINER_MAIN.Name = "CONTAINER_MAIN"
|
||||
CONTAINER_MAIN.RightToolStripPanelVisible = False
|
||||
CONTAINER_MAIN.Size = New System.Drawing.Size(476, 413)
|
||||
CONTAINER_MAIN.Size = New System.Drawing.Size(476, 519)
|
||||
CONTAINER_MAIN.TabIndex = 0
|
||||
CONTAINER_MAIN.TopToolStripPanelVisible = False
|
||||
'
|
||||
@@ -83,23 +81,27 @@ Namespace DownloadObjects
|
||||
Me.DEF_GROUP.ColumnCount = 1
|
||||
Me.DEF_GROUP.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||
Me.DEF_GROUP.Controls.Add(TP_MODE, 0, 0)
|
||||
Me.DEF_GROUP.Controls.Add(Me.TXT_GROUPS, 0, 8)
|
||||
Me.DEF_GROUP.Controls.Add(TP_NOTIFY, 0, 9)
|
||||
Me.DEF_GROUP.Controls.Add(Me.TXT_TIMER, 0, 11)
|
||||
Me.DEF_GROUP.Controls.Add(Me.NUM_DELAY, 0, 12)
|
||||
Me.DEF_GROUP.Controls.Add(Me.LBL_LAST_TIME_UP, 0, 13)
|
||||
Me.DEF_GROUP.Controls.Add(Me.CH_MANUAL, 0, 10)
|
||||
Me.DEF_GROUP.Controls.Add(Me.TXT_GROUPS, 0, 12)
|
||||
Me.DEF_GROUP.Controls.Add(TP_NOTIFY, 0, 13)
|
||||
Me.DEF_GROUP.Controls.Add(Me.TXT_TIMER, 0, 15)
|
||||
Me.DEF_GROUP.Controls.Add(Me.NUM_DELAY, 0, 16)
|
||||
Me.DEF_GROUP.Controls.Add(Me.LBL_LAST_TIME_UP, 0, 17)
|
||||
Me.DEF_GROUP.Controls.Add(Me.CH_MANUAL, 0, 14)
|
||||
Me.DEF_GROUP.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.DEF_GROUP.Location = New System.Drawing.Point(0, 0)
|
||||
Me.DEF_GROUP.Name = "DEF_GROUP"
|
||||
Me.DEF_GROUP.RowCount = 15
|
||||
Me.DEF_GROUP.RowCount = 19
|
||||
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
|
||||
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
|
||||
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
|
||||
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
|
||||
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
|
||||
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
|
||||
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
|
||||
@@ -108,23 +110,21 @@ Namespace DownloadObjects
|
||||
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
|
||||
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||
Me.DEF_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||
Me.DEF_GROUP.Size = New System.Drawing.Size(476, 388)
|
||||
Me.DEF_GROUP.Size = New System.Drawing.Size(476, 519)
|
||||
Me.DEF_GROUP.TabIndex = 0
|
||||
'
|
||||
'TP_MODE
|
||||
'
|
||||
TP_MODE.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single]
|
||||
TP_MODE.ColumnCount = 5
|
||||
TP_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 20.0!))
|
||||
TP_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 20.0!))
|
||||
TP_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 20.0!))
|
||||
TP_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 20.0!))
|
||||
TP_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 20.0!))
|
||||
TP_MODE.Controls.Add(Me.OPT_ALL, 1, 0)
|
||||
TP_MODE.Controls.Add(Me.OPT_DEFAULT, 2, 0)
|
||||
TP_MODE.Controls.Add(Me.OPT_SPEC, 3, 0)
|
||||
TP_MODE.ColumnCount = 3
|
||||
TP_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333!))
|
||||
TP_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333!))
|
||||
TP_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333!))
|
||||
TP_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20.0!))
|
||||
TP_MODE.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20.0!))
|
||||
TP_MODE.Controls.Add(Me.OPT_SPEC, 1, 0)
|
||||
TP_MODE.Controls.Add(Me.OPT_DISABLED, 0, 0)
|
||||
TP_MODE.Controls.Add(Me.OPT_GROUP, 4, 0)
|
||||
TP_MODE.Controls.Add(Me.OPT_GROUP, 2, 0)
|
||||
TP_MODE.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
TP_MODE.Location = New System.Drawing.Point(1, 1)
|
||||
TP_MODE.Margin = New System.Windows.Forms.Padding(0)
|
||||
@@ -134,39 +134,13 @@ Namespace DownloadObjects
|
||||
TP_MODE.Size = New System.Drawing.Size(474, 25)
|
||||
TP_MODE.TabIndex = 0
|
||||
'
|
||||
'OPT_ALL
|
||||
'
|
||||
Me.OPT_ALL.AutoSize = True
|
||||
Me.OPT_ALL.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.OPT_ALL.Location = New System.Drawing.Point(98, 4)
|
||||
Me.OPT_ALL.Name = "OPT_ALL"
|
||||
Me.OPT_ALL.Size = New System.Drawing.Size(87, 17)
|
||||
Me.OPT_ALL.TabIndex = 1
|
||||
Me.OPT_ALL.TabStop = True
|
||||
Me.OPT_ALL.Text = "ALL"
|
||||
TT_MAIN.SetToolTip(Me.OPT_ALL, "Download all users")
|
||||
Me.OPT_ALL.UseVisualStyleBackColor = True
|
||||
'
|
||||
'OPT_DEFAULT
|
||||
'
|
||||
Me.OPT_DEFAULT.AutoSize = True
|
||||
Me.OPT_DEFAULT.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.OPT_DEFAULT.Location = New System.Drawing.Point(192, 4)
|
||||
Me.OPT_DEFAULT.Name = "OPT_DEFAULT"
|
||||
Me.OPT_DEFAULT.Size = New System.Drawing.Size(87, 17)
|
||||
Me.OPT_DEFAULT.TabIndex = 2
|
||||
Me.OPT_DEFAULT.TabStop = True
|
||||
Me.OPT_DEFAULT.Text = "Default"
|
||||
TT_MAIN.SetToolTip(Me.OPT_DEFAULT, "All users marked ""Ready for download""")
|
||||
Me.OPT_DEFAULT.UseVisualStyleBackColor = True
|
||||
'
|
||||
'OPT_SPEC
|
||||
'
|
||||
Me.OPT_SPEC.AutoSize = True
|
||||
Me.OPT_SPEC.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.OPT_SPEC.Location = New System.Drawing.Point(286, 4)
|
||||
Me.OPT_SPEC.Location = New System.Drawing.Point(161, 4)
|
||||
Me.OPT_SPEC.Name = "OPT_SPEC"
|
||||
Me.OPT_SPEC.Size = New System.Drawing.Size(87, 17)
|
||||
Me.OPT_SPEC.Size = New System.Drawing.Size(150, 17)
|
||||
Me.OPT_SPEC.TabIndex = 3
|
||||
Me.OPT_SPEC.TabStop = True
|
||||
Me.OPT_SPEC.Text = "Specified"
|
||||
@@ -179,7 +153,7 @@ Namespace DownloadObjects
|
||||
Me.OPT_DISABLED.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.OPT_DISABLED.Location = New System.Drawing.Point(4, 4)
|
||||
Me.OPT_DISABLED.Name = "OPT_DISABLED"
|
||||
Me.OPT_DISABLED.Size = New System.Drawing.Size(87, 17)
|
||||
Me.OPT_DISABLED.Size = New System.Drawing.Size(150, 17)
|
||||
Me.OPT_DISABLED.TabIndex = 0
|
||||
Me.OPT_DISABLED.TabStop = True
|
||||
Me.OPT_DISABLED.Text = "Disabled"
|
||||
@@ -190,9 +164,9 @@ Namespace DownloadObjects
|
||||
'
|
||||
Me.OPT_GROUP.AutoSize = True
|
||||
Me.OPT_GROUP.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.OPT_GROUP.Location = New System.Drawing.Point(380, 4)
|
||||
Me.OPT_GROUP.Location = New System.Drawing.Point(318, 4)
|
||||
Me.OPT_GROUP.Name = "OPT_GROUP"
|
||||
Me.OPT_GROUP.Size = New System.Drawing.Size(90, 17)
|
||||
Me.OPT_GROUP.Size = New System.Drawing.Size(152, 17)
|
||||
Me.OPT_GROUP.TabIndex = 4
|
||||
Me.OPT_GROUP.TabStop = True
|
||||
Me.OPT_GROUP.Text = "Groups"
|
||||
@@ -201,16 +175,16 @@ Namespace DownloadObjects
|
||||
'
|
||||
'TXT_GROUPS
|
||||
'
|
||||
ActionButton5.BackgroundImage = CType(resources.GetObject("ActionButton5.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton5.Name = "Edit"
|
||||
ActionButton6.BackgroundImage = CType(resources.GetObject("ActionButton6.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton6.Name = "Clear"
|
||||
Me.TXT_GROUPS.Buttons.Add(ActionButton5)
|
||||
Me.TXT_GROUPS.Buttons.Add(ActionButton6)
|
||||
ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton1.Name = "Edit"
|
||||
ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton2.Name = "Clear"
|
||||
Me.TXT_GROUPS.Buttons.Add(ActionButton1)
|
||||
Me.TXT_GROUPS.Buttons.Add(ActionButton2)
|
||||
Me.TXT_GROUPS.CaptionText = "Groups"
|
||||
Me.TXT_GROUPS.CaptionWidth = 50.0R
|
||||
Me.TXT_GROUPS.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.TXT_GROUPS.Location = New System.Drawing.Point(4, 224)
|
||||
Me.TXT_GROUPS.Location = New System.Drawing.Point(4, 331)
|
||||
Me.TXT_GROUPS.Name = "TXT_GROUPS"
|
||||
Me.TXT_GROUPS.Size = New System.Drawing.Size(468, 22)
|
||||
Me.TXT_GROUPS.TabIndex = 1
|
||||
@@ -228,7 +202,7 @@ Namespace DownloadObjects
|
||||
TP_NOTIFY.Controls.Add(Me.CH_SHOW_PIC_USER, 3, 0)
|
||||
TP_NOTIFY.Controls.Add(Me.CH_NOTIFY_SIMPLE, 1, 0)
|
||||
TP_NOTIFY.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
TP_NOTIFY.Location = New System.Drawing.Point(1, 250)
|
||||
TP_NOTIFY.Location = New System.Drawing.Point(1, 357)
|
||||
TP_NOTIFY.Margin = New System.Windows.Forms.Padding(0)
|
||||
TP_NOTIFY.Name = "TP_NOTIFY"
|
||||
TP_NOTIFY.RowCount = 1
|
||||
@@ -286,24 +260,24 @@ Namespace DownloadObjects
|
||||
'
|
||||
'TXT_TIMER
|
||||
'
|
||||
ActionButton7.BackgroundImage = CType(resources.GetObject("ActionButton7.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton7.Name = "Refresh"
|
||||
Me.TXT_TIMER.Buttons.Add(ActionButton7)
|
||||
ActionButton3.BackgroundImage = CType(resources.GetObject("ActionButton3.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton3.Name = "Refresh"
|
||||
Me.TXT_TIMER.Buttons.Add(ActionButton3)
|
||||
Me.TXT_TIMER.CaptionText = "Timer"
|
||||
Me.TXT_TIMER.CaptionToolTipEnabled = True
|
||||
Me.TXT_TIMER.CaptionToolTipText = "Timer (in minutes)"
|
||||
Me.TXT_TIMER.CaptionWidth = 50.0R
|
||||
Me.TXT_TIMER.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.TXT_TIMER.Location = New System.Drawing.Point(4, 308)
|
||||
Me.TXT_TIMER.Location = New System.Drawing.Point(4, 415)
|
||||
Me.TXT_TIMER.Name = "TXT_TIMER"
|
||||
Me.TXT_TIMER.Size = New System.Drawing.Size(468, 22)
|
||||
Me.TXT_TIMER.TabIndex = 4
|
||||
'
|
||||
'NUM_DELAY
|
||||
'
|
||||
ActionButton8.BackgroundImage = CType(resources.GetObject("ActionButton8.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton8.Name = "Refresh"
|
||||
Me.NUM_DELAY.Buttons.Add(ActionButton8)
|
||||
ActionButton4.BackgroundImage = CType(resources.GetObject("ActionButton4.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton4.Name = "Refresh"
|
||||
Me.NUM_DELAY.Buttons.Add(ActionButton4)
|
||||
Me.NUM_DELAY.CaptionText = "Delay"
|
||||
Me.NUM_DELAY.CaptionToolTipEnabled = True
|
||||
Me.NUM_DELAY.CaptionToolTipText = "Startup delay"
|
||||
@@ -311,7 +285,7 @@ Namespace DownloadObjects
|
||||
Me.NUM_DELAY.ClearTextByButtonClear = False
|
||||
Me.NUM_DELAY.ControlMode = PersonalUtilities.Forms.Controls.TextBoxExtended.ControlModes.NumericUpDown
|
||||
Me.NUM_DELAY.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.NUM_DELAY.Location = New System.Drawing.Point(4, 337)
|
||||
Me.NUM_DELAY.Location = New System.Drawing.Point(4, 444)
|
||||
Me.NUM_DELAY.Name = "NUM_DELAY"
|
||||
Me.NUM_DELAY.NumberMaximum = New Decimal(New Integer() {1440, 0, 0, 0})
|
||||
Me.NUM_DELAY.NumberUpDownAlign = System.Windows.Forms.LeftRightAlignment.Left
|
||||
@@ -324,7 +298,7 @@ Namespace DownloadObjects
|
||||
Me.LBL_LAST_TIME_UP.AutoSize = True
|
||||
Me.LBL_LAST_TIME_UP.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.LBL_LAST_TIME_UP.Font = New System.Drawing.Font("Microsoft Sans Serif", 8.25!, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Point, CType(204, Byte))
|
||||
Me.LBL_LAST_TIME_UP.Location = New System.Drawing.Point(4, 363)
|
||||
Me.LBL_LAST_TIME_UP.Location = New System.Drawing.Point(4, 470)
|
||||
Me.LBL_LAST_TIME_UP.Name = "LBL_LAST_TIME_UP"
|
||||
Me.LBL_LAST_TIME_UP.Size = New System.Drawing.Size(468, 25)
|
||||
Me.LBL_LAST_TIME_UP.TabIndex = 6
|
||||
@@ -335,7 +309,7 @@ Namespace DownloadObjects
|
||||
'
|
||||
Me.CH_MANUAL.AutoSize = True
|
||||
Me.CH_MANUAL.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.CH_MANUAL.Location = New System.Drawing.Point(4, 282)
|
||||
Me.CH_MANUAL.Location = New System.Drawing.Point(4, 389)
|
||||
Me.CH_MANUAL.Name = "CH_MANUAL"
|
||||
Me.CH_MANUAL.Size = New System.Drawing.Size(468, 19)
|
||||
Me.CH_MANUAL.TabIndex = 3
|
||||
@@ -348,15 +322,15 @@ Namespace DownloadObjects
|
||||
'
|
||||
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
|
||||
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
|
||||
Me.ClientSize = New System.Drawing.Size(476, 413)
|
||||
Me.ClientSize = New System.Drawing.Size(476, 519)
|
||||
Me.Controls.Add(CONTAINER_MAIN)
|
||||
Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle
|
||||
Me.Icon = Global.SCrawler.My.Resources.Resources.ArrowDownIcon_Blue_24
|
||||
Me.KeyPreview = True
|
||||
Me.MaximizeBox = False
|
||||
Me.MaximumSize = New System.Drawing.Size(492, 452)
|
||||
Me.MaximumSize = New System.Drawing.Size(492, 558)
|
||||
Me.MinimizeBox = False
|
||||
Me.MinimumSize = New System.Drawing.Size(492, 452)
|
||||
Me.MinimumSize = New System.Drawing.Size(492, 558)
|
||||
Me.Name = "AutoDownloaderEditorForm"
|
||||
Me.ShowInTaskbar = False
|
||||
Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide
|
||||
@@ -378,8 +352,6 @@ Namespace DownloadObjects
|
||||
End Sub
|
||||
Private WithEvents DEF_GROUP As DownloadObjects.Groups.GroupDefaults
|
||||
Private WithEvents TXT_GROUPS As PersonalUtilities.Forms.Controls.TextBoxExtended
|
||||
Private WithEvents OPT_ALL As RadioButton
|
||||
Private WithEvents OPT_DEFAULT As RadioButton
|
||||
Private WithEvents OPT_SPEC As RadioButton
|
||||
Private WithEvents OPT_DISABLED As RadioButton
|
||||
Private WithEvents CH_NOTIFY As CheckBox
|
||||
|
||||
@@ -123,8 +123,14 @@
|
||||
<metadata name="TP_MODE.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>False</value>
|
||||
</metadata>
|
||||
<metadata name="TT_MAIN.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>False</value>
|
||||
</metadata>
|
||||
<metadata name="TT_MAIN.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="ActionButton5.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<data name="ActionButton1.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAACH
|
||||
DwAAjA8AAP1SAACBQAAAfXkAAOmLAAA85QAAGcxzPIV3AAAKOWlDQ1BQaG90b3Nob3AgSUNDIHByb2Zp
|
||||
@@ -182,7 +188,7 @@
|
||||
AAAASUVORK5CYII=
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton6.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<data name="ActionButton2.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
|
||||
@@ -193,53 +199,41 @@
|
||||
<metadata name="TP_NOTIFY.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>False</value>
|
||||
</metadata>
|
||||
<data name="ActionButton7.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
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==
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton8.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
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==
|
||||
</value>
|
||||
</data>
|
||||
<metadata name="TT_MAIN.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>False</value>
|
||||
</metadata>
|
||||
<metadata name="TT_MAIN.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="TT_MAIN.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>False</value>
|
||||
</metadata>
|
||||
<metadata name="TT_MAIN.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<data name="CH_NOTIFY_SIMPLE.ToolTip" xml:space="preserve">
|
||||
<value>Show a simple notification instead of a user notification.
|
||||
This means that if any user data has been downloaded with the plan, a simple notification will be shown with the number of users downloaded.
|
||||
The 'Image' and 'User icon' parameters will be ignored.</value>
|
||||
</data>
|
||||
<data name="ActionButton3.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
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==
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton4.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
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==
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -6,6 +6,7 @@
|
||||
'
|
||||
' This program is distributed in the hope that it will be useful,
|
||||
' but WITHOUT ANY WARRANTY
|
||||
Imports SCrawler.DownloadObjects.Groups
|
||||
Imports PersonalUtilities.Forms
|
||||
Imports PersonalUtilities.Forms.Controls.Base
|
||||
Imports DModes = SCrawler.DownloadObjects.AutoDownloader.Modes
|
||||
@@ -46,11 +47,14 @@ Namespace DownloadObjects
|
||||
With Plan
|
||||
Select Case .Mode
|
||||
Case DModes.None : OPT_DISABLED.Checked = True
|
||||
Case DModes.All : OPT_ALL.Checked = True
|
||||
Case DModes.Default : OPT_DEFAULT.Checked = True
|
||||
Case DModes.Specified : OPT_SPEC.Checked = True
|
||||
Case DModes.Groups : OPT_GROUP.Checked = True
|
||||
End Select
|
||||
|
||||
TXT_GROUPS.CaptionWidth = GroupDefaults.CaptionWidthDefault
|
||||
TXT_TIMER.CaptionWidth = GroupDefaults.CaptionWidthDefault
|
||||
NUM_DELAY.CaptionWidth = GroupDefaults.CaptionWidthDefault
|
||||
|
||||
DEF_GROUP.Set(Plan)
|
||||
If MyGroups.Count > 0 Then TXT_GROUPS.Text = MyGroups.ListToString
|
||||
If Settings.Groups.Count = 0 Then TXT_GROUPS.Clear() : TXT_GROUPS.Enabled = False
|
||||
@@ -67,7 +71,7 @@ Namespace DownloadObjects
|
||||
.MyFieldsChecker = New FieldsChecker
|
||||
With .MyFieldsCheckerE
|
||||
.AddControl(Of String)(DEF_GROUP.TXT_NAME, DEF_GROUP.TXT_NAME.CaptionText,,
|
||||
New Groups.GroupEditorForm.NameChecker(Plan.Name, Settings.Automation, "Plan"))
|
||||
New GroupEditorForm.NameChecker(Plan.Name, Settings.Automation, "Plan"))
|
||||
.AddControl(Of Integer)(TXT_TIMER, TXT_TIMER.CaptionText,, New AutomationTimerChecker)
|
||||
.EndLoaderOperations()
|
||||
End With
|
||||
@@ -78,13 +82,36 @@ Namespace DownloadObjects
|
||||
Private Sub AutoDownloaderEditorForm_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed
|
||||
MyGroups.Clear()
|
||||
End Sub
|
||||
Private Sub AutoDownloaderEditorForm_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
|
||||
Try
|
||||
If e = ShowUsersButtonKey AndAlso Not OPT_DISABLED.Checked Then
|
||||
Dim users As New List(Of API.Base.IUserData)
|
||||
If OPT_GROUP.Checked Then
|
||||
If MyGroups.Count > 0 Then
|
||||
Dim i%
|
||||
For Each groupName$ In MyGroups
|
||||
i = Settings.Groups.IndexOf(groupName)
|
||||
If i >= 0 Then users.ListAddList(DownloadGroup.GetUsers(Settings.Groups(i)), LAP.NotContainsOnly, LAP.IgnoreICopier)
|
||||
Next
|
||||
End If
|
||||
Else
|
||||
Using g As New GroupParameters
|
||||
DEF_GROUP.Get(g)
|
||||
users.ListAddList(DownloadGroup.GetUsers(g))
|
||||
End Using
|
||||
End If
|
||||
GroupUsersViewer.Show(users, $"S {DEF_GROUP.TXT_NAME.Text}")
|
||||
users.Clear()
|
||||
End If
|
||||
Catch ex As Exception
|
||||
ErrorsDescriber.Execute(EDP.LogMessageValue, ex, "Show plan users")
|
||||
End Try
|
||||
End Sub
|
||||
Private Sub MyDefs_ButtonOkClick(ByVal Sender As Object, ByVal e As KeyHandleEventArgs) Handles MyDefs.ButtonOkClick
|
||||
If MyDefs.MyFieldsChecker.AllParamsOK Then
|
||||
With Plan
|
||||
Select Case True
|
||||
Case OPT_DISABLED.Checked : .Mode = DModes.None
|
||||
Case OPT_ALL.Checked : .Mode = DModes.All
|
||||
Case OPT_DEFAULT.Checked : .Mode = DModes.Default
|
||||
Case OPT_SPEC.Checked : .Mode = DModes.Specified
|
||||
Case OPT_GROUP.Checked : .Mode = DModes.Groups
|
||||
End Select
|
||||
@@ -107,17 +134,17 @@ Namespace DownloadObjects
|
||||
Private Sub TXT_GROUPS_ActionOnButtonClick(ByVal Sender As ActionButton, ByVal e As EventArgs) Handles TXT_GROUPS.ActionOnButtonClick
|
||||
Select Case Sender.DefaultButton
|
||||
Case ActionButton.DefaultButtons.Edit
|
||||
Using f As New LabelsForm(MyGroups, Settings.Groups.Select(Function(g) g.Name)) With {.Text = "Groups", .Icon = My.Resources.GroupByIcon_16}
|
||||
Using f As New LabelsForm(MyGroups, (From g As DownloadGroup In Settings.Groups Where Not g.IsViewFilter Select g.Name)) With {.Text = "Groups", .Icon = My.Resources.GroupByIcon_16}
|
||||
f.ShowDialog()
|
||||
If f.DialogResult = DialogResult.OK Then MyGroups.ListAddList(f.LabelsList, LAP.ClearBeforeAdd) : TXT_GROUPS.Text = MyGroups.ListToString
|
||||
End Using
|
||||
Case ActionButton.DefaultButtons.Clear : MyGroups.Clear()
|
||||
End Select
|
||||
End Sub
|
||||
Private Sub ChangeEnabled() Handles OPT_DISABLED.CheckedChanged, OPT_ALL.CheckedChanged, OPT_DEFAULT.CheckedChanged,
|
||||
Private Sub ChangeEnabled() Handles OPT_DISABLED.CheckedChanged,
|
||||
OPT_SPEC.CheckedChanged, OPT_GROUP.CheckedChanged,
|
||||
CH_NOTIFY.CheckedChanged, CH_NOTIFY_SIMPLE.CheckedChanged
|
||||
DEF_GROUP.Enabled(OPT_ALL.Checked Or OPT_DEFAULT.Checked Or OPT_SPEC.Checked, OPT_ALL.Checked) = OPT_SPEC.Checked
|
||||
DEF_GROUP.Enabled = OPT_SPEC.Checked
|
||||
TXT_GROUPS.Enabled = OPT_GROUP.Checked
|
||||
TXT_TIMER.Enabled = Not OPT_DISABLED.Checked
|
||||
NUM_DELAY.Enabled = Not OPT_DISABLED.Checked
|
||||
|
||||
@@ -131,7 +131,12 @@ Namespace DownloadObjects
|
||||
End With
|
||||
End Sub
|
||||
Private Sub SchedulerEditorForm_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
|
||||
If e.KeyCode = Keys.Escape Then Close()
|
||||
If e.KeyCode = Keys.Escape Then
|
||||
Close()
|
||||
ElseIf e = ShowUsersButtonKey Then
|
||||
ShowPlanUsers()
|
||||
e.Handled = True
|
||||
End If
|
||||
End Sub
|
||||
Private Sub SchedulerEditorForm_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed
|
||||
PauseArr.Dispose()
|
||||
@@ -241,7 +246,7 @@ Namespace DownloadObjects
|
||||
If l.Count > 0 Then
|
||||
Using chooser As New SimpleListForm(Of String)(l.Values.Cast(Of String), Settings.Design) With {
|
||||
.DesignXMLNodeName = "SchedulerChooserForm",
|
||||
.Icon = PersonalUtilities.Tools.ImageRenderer.GetIcon(My.Resources.ScriptPic_32, EDP.ReturnValue),
|
||||
.Icon = ImageRenderer.GetIcon(My.Resources.ScriptPic_32, EDP.ReturnValue),
|
||||
.FormText = "Schedulers",
|
||||
.Mode = SimpleListFormModes.SelectedItems,
|
||||
.MultiSelect = False
|
||||
@@ -356,6 +361,34 @@ Namespace DownloadObjects
|
||||
Refill()
|
||||
End If
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "ShowPlanUsers"
|
||||
Private Sub ShowPlanUsers()
|
||||
Try
|
||||
If _LatestSelected.ValueBetween(0, Settings.Automation.Count - 1) Then
|
||||
With Settings.Automation(_LatestSelected)
|
||||
Dim users As New List(Of API.Base.IUserData)
|
||||
If Not .Mode = AutoDownloader.Modes.None Then
|
||||
If .Mode = AutoDownloader.Modes.Groups Then
|
||||
If .Groups.Count > 0 Then
|
||||
Dim i%
|
||||
For Each groupName$ In .Groups
|
||||
i = Settings.Groups.IndexOf(groupName)
|
||||
If i >= 0 Then users.ListAddList(Groups.DownloadGroup.GetUsers(Settings.Groups(i)), LAP.NotContainsOnly, LAP.IgnoreICopier)
|
||||
Next
|
||||
End If
|
||||
Else
|
||||
users.ListAddList(Groups.DownloadGroup.GetUsers(.Self))
|
||||
End If
|
||||
End If
|
||||
Groups.GroupUsersViewer.Show(users, $"S { .Name}")
|
||||
users.Clear()
|
||||
End With
|
||||
End If
|
||||
Catch ex As Exception
|
||||
ErrorsDescriber.Execute(EDP.LogMessageValue, ex, "Show plan users")
|
||||
End Try
|
||||
End Sub
|
||||
#End Region
|
||||
End Class
|
||||
End Namespace
|
||||
@@ -28,7 +28,7 @@ Namespace DownloadObjects
|
||||
End Enum
|
||||
Friend Property ViewMode As ViewModes
|
||||
Get
|
||||
Return IIf(MENU_VIEW_ALL.Checked, ViewModes.All, ViewModes.Session)
|
||||
Return IIf(ControlInvokeFast(ToolbarTOP, MENU_VIEW_ALL, Function() MENU_VIEW_ALL.Checked, True, EDP.ReturnValue), ViewModes.All, ViewModes.Session)
|
||||
End Get
|
||||
Set(ByVal SMode As ViewModes)
|
||||
Settings.InfoViewMode.Value = CInt(SMode)
|
||||
@@ -57,7 +57,7 @@ Namespace DownloadObjects
|
||||
InitializeComponent()
|
||||
_UsersListSession = New List(Of IUserData)
|
||||
_UsersListAll = New List(Of IUserData)
|
||||
If Settings.InfoViewMode.Value = CInt(ViewModes.All) Then
|
||||
If Settings.InfoViewMode.Value = ViewModes.All Then
|
||||
MENU_VIEW_SESSION.Checked = False
|
||||
MENU_VIEW_ALL.Checked = True
|
||||
Else
|
||||
@@ -66,8 +66,6 @@ Namespace DownloadObjects
|
||||
End If
|
||||
OPT_DEFAULT.Checked = Settings.InfoViewDefault
|
||||
OPT_SUBSCRIPTIONS.Checked = Not Settings.InfoViewDefault
|
||||
Settings.InfoViewMode.Value = ViewMode
|
||||
RefillList()
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Form handlers"
|
||||
@@ -78,11 +76,11 @@ Namespace DownloadObjects
|
||||
MyView.Import()
|
||||
MyView.SetFormSize()
|
||||
End If
|
||||
BTT_CLEAR.Visible = ViewMode = ViewModes.Session
|
||||
RefillList()
|
||||
ControlInvokeFast(ToolbarTOP, BTT_CLEAR, Sub() BTT_CLEAR.Visible = ViewMode = ViewModes.Session, EDP.None)
|
||||
Catch
|
||||
Finally
|
||||
Opened = True
|
||||
RefillList()
|
||||
End Try
|
||||
End Sub
|
||||
Private Sub DownloadedInfoForm_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
|
||||
@@ -116,51 +114,50 @@ Namespace DownloadObjects
|
||||
End Function
|
||||
End Class
|
||||
Private Sub RefillList() Handles BTT_REFRESH.Click
|
||||
Try
|
||||
Dim lClear As Action = Sub() LIST_DOWN.Items.Clear()
|
||||
If LIST_DOWN.InvokeRequired Then LIST_DOWN.Invoke(lClear) Else lClear.Invoke
|
||||
If ViewMode = ViewModes.Session Then
|
||||
With Downloader.Downloaded
|
||||
If .Count > 0 Then
|
||||
With .Select(Function(u) Settings.GetUser(u, False)).Reverse
|
||||
If _UsersListSession.Count > 0 Then _UsersListSession.ListWithRemove(.Self, New ListAddParams With {.DisableDispose = True})
|
||||
If _UsersListSession.Count > 0 Then
|
||||
_UsersListSession.InsertRange(0, .Self)
|
||||
Else
|
||||
_UsersListSession.AddRange(.Self)
|
||||
End If
|
||||
End With
|
||||
End If
|
||||
End With
|
||||
Else
|
||||
_UsersListAll.ListAddList(Settings.GetUsers(Function(u) True), LAP.ClearBeforeAdd)
|
||||
If _UsersListAll.Count > 0 Then _UsersListAll.Sort(New UsersDateOrder)
|
||||
End If
|
||||
Dim isDefault As Boolean = OPT_DEFAULT.Checked
|
||||
If Current.Count > 0 Then Current.RemoveAll(Function(u) u.IsSubscription = isDefault)
|
||||
If Current.Count > 0 Then
|
||||
For Each user As IUserData In Current
|
||||
If LIST_DOWN.InvokeRequired Then
|
||||
LIST_DOWN.Invoke(Sub() LIST_DOWN.Items.Add(user.DownloadedInformation))
|
||||
Else
|
||||
LIST_DOWN.Items.Add(user.DownloadedInformation)
|
||||
End If
|
||||
Next
|
||||
If _LatestSelected.ValueBetween(0, LIST_DOWN.Items.Count - 1) Then
|
||||
Dim aSel As Action = Sub() LIST_DOWN.SelectedIndex = _LatestSelected
|
||||
If LIST_DOWN.InvokeRequired Then LIST_DOWN.Invoke(aSel) Else aSel.Invoke
|
||||
If Opened Then
|
||||
Try
|
||||
ControlInvokeFast(LIST_DOWN, Sub() LIST_DOWN.Items.Clear())
|
||||
If ViewMode = ViewModes.Session Then
|
||||
With Downloader.Downloaded
|
||||
If .Count > 0 Then
|
||||
With .Select(Function(u) Settings.GetUser(u, False)).Reverse
|
||||
If _UsersListSession.Count > 0 Then _UsersListSession.ListWithRemove(.Self, New ListAddParams With {.DisableDispose = True})
|
||||
If _UsersListSession.Count > 0 Then
|
||||
_UsersListSession.InsertRange(0, .Self)
|
||||
Else
|
||||
_UsersListSession.AddRange(.Self)
|
||||
End If
|
||||
End With
|
||||
End If
|
||||
End With
|
||||
Else
|
||||
_UsersListAll.ListAddList(Settings.GetUsers(Function(u) True), LAP.ClearBeforeAdd)
|
||||
If _UsersListAll.Count > 0 Then _UsersListAll.Sort(New UsersDateOrder)
|
||||
End If
|
||||
Dim isDefault As Boolean = OPT_DEFAULT.Checked
|
||||
If Current.Count > 0 Then Current.RemoveAll(Function(u) u Is Nothing OrElse u.IsSubscription = isDefault)
|
||||
If Current.Count > 0 Then
|
||||
ControlInvokeFast(LIST_DOWN,
|
||||
Sub()
|
||||
For Each user As IUserData In Current
|
||||
LIST_DOWN.Items.Add(user.DownloadedInformation)
|
||||
Next
|
||||
If _LatestSelected.ValueBetween(0, LIST_DOWN.Items.Count - 1) Then
|
||||
LIST_DOWN.SelectedIndex = _LatestSelected
|
||||
Else
|
||||
_LatestSelected = -1
|
||||
End If
|
||||
End Sub)
|
||||
Else
|
||||
_LatestSelected = -1
|
||||
End If
|
||||
Else
|
||||
_LatestSelected = -1
|
||||
End If
|
||||
Catch ies As InvalidOperationException
|
||||
Catch ex As Exception
|
||||
ErrorsDescriber.Execute(EDP.SendToLog, ex, "[DownloadedInfoForm.RefillList]")
|
||||
Finally
|
||||
UpdateNavigationButtons(Nothing)
|
||||
End Try
|
||||
Catch ies As InvalidOperationException
|
||||
Catch ex As Exception
|
||||
ErrorsDescriber.Execute(EDP.SendToLog, ex, "[DownloadedInfoForm.RefillList]")
|
||||
Finally
|
||||
UpdateNavigationButtons(Nothing)
|
||||
End Try
|
||||
End If
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Toolbar controls"
|
||||
@@ -251,7 +248,7 @@ Namespace DownloadObjects
|
||||
#End Region
|
||||
#Region "Downloader handlers"
|
||||
Friend Sub Downloader_DownloadCountChange()
|
||||
If ViewMode = ViewModes.Session Then RefillList()
|
||||
If Opened AndAlso ViewMode = ViewModes.Session Then RefillList()
|
||||
End Sub
|
||||
#End Region
|
||||
End Class
|
||||
|
||||
27
SCrawler/Download/Feed/DownloadFeedForm.Designer.vb
generated
@@ -34,6 +34,7 @@ Namespace DownloadObjects
|
||||
Dim MENU_LOAD_SEP_6 As System.Windows.Forms.ToolStripSeparator
|
||||
Dim MENU_LOAD_SEP_7 As System.Windows.Forms.ToolStripSeparator
|
||||
Dim MENU_LOAD_SEP_0 As System.Windows.Forms.ToolStripSeparator
|
||||
Dim MENU_LOAD_SEP_8 As System.Windows.Forms.ToolStripSeparator
|
||||
Me.OPT_DEFAULT = New System.Windows.Forms.ToolStripMenuItem()
|
||||
Me.OPT_SUBSCRIPTIONS = New System.Windows.Forms.ToolStripMenuItem()
|
||||
Me.ToolbarTOP = New System.Windows.Forms.ToolStrip()
|
||||
@@ -67,6 +68,8 @@ Namespace DownloadObjects
|
||||
Me.BTT_DOWN_SELECTED = New System.Windows.Forms.ToolStripMenuItem()
|
||||
Me.BTT_REFRESH = New System.Windows.Forms.ToolStripButton()
|
||||
Me.TP_DATA = New System.Windows.Forms.TableLayoutPanel()
|
||||
Me.BTT_VIEW_SAVE = New System.Windows.Forms.ToolStripMenuItem()
|
||||
Me.BTT_VIEW_LOAD = New System.Windows.Forms.ToolStripMenuItem()
|
||||
SEP_1 = New System.Windows.Forms.ToolStripSeparator()
|
||||
SEP_2 = New System.Windows.Forms.ToolStripSeparator()
|
||||
MENU_VIEW = New System.Windows.Forms.ToolStripDropDownButton()
|
||||
@@ -78,6 +81,7 @@ Namespace DownloadObjects
|
||||
MENU_LOAD_SEP_6 = New System.Windows.Forms.ToolStripSeparator()
|
||||
MENU_LOAD_SEP_7 = New System.Windows.Forms.ToolStripSeparator()
|
||||
MENU_LOAD_SEP_0 = New System.Windows.Forms.ToolStripSeparator()
|
||||
MENU_LOAD_SEP_8 = New System.Windows.Forms.ToolStripSeparator()
|
||||
Me.ToolbarTOP.SuspendLayout()
|
||||
Me.SuspendLayout()
|
||||
'
|
||||
@@ -166,7 +170,7 @@ Namespace DownloadObjects
|
||||
'
|
||||
Me.MENU_LOAD_SESSION.AutoToolTip = False
|
||||
Me.MENU_LOAD_SESSION.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image
|
||||
Me.MENU_LOAD_SESSION.DropDownItems.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_LOAD_SESSION_CURRENT, Me.BTT_LOAD_SESSION_LAST, Me.BTT_LOAD_SESSION_CHOOSE, MENU_LOAD_SEP_0, Me.BTT_COPY_TO, Me.BTT_MOVE_TO, MENU_LOAD_SEP_1, Me.BTT_LOAD_FAV, Me.BTT_LOAD_SPEC, MENU_LOAD_SEP_2, Me.BTT_FEED_ADD_FAV, Me.BTT_FEED_ADD_FAV_REMOVE, Me.BTT_FEED_REMOVE_FAV, MENU_LOAD_SEP_3, Me.BTT_FEED_ADD_SPEC, Me.BTT_FEED_ADD_SPEC_REMOVE, Me.BTT_FEED_REMOVE_SPEC, MENU_LOAD_SEP_4, Me.BTT_FEED_CLEAR_FAV, Me.BTT_FEED_CLEAR_SPEC, Me.BTT_FEED_DELETE_SPEC, Me.BTT_FEED_DELETE_DAILY_LIST, Me.BTT_FEED_DELETE_DAILY_DATE, MENU_LOAD_SEP_5, Me.BTT_MERGE_SESSIONS, Me.BTT_CLEAR_DAILY, MENU_LOAD_SEP_6, Me.BTT_MERGE_FEEDS, MENU_LOAD_SEP_7, Me.BTT_CHECK_ALL, Me.BTT_CHECK_NONE})
|
||||
Me.MENU_LOAD_SESSION.DropDownItems.AddRange(New System.Windows.Forms.ToolStripItem() {Me.BTT_LOAD_SESSION_CURRENT, Me.BTT_LOAD_SESSION_LAST, Me.BTT_LOAD_SESSION_CHOOSE, MENU_LOAD_SEP_0, Me.BTT_COPY_TO, Me.BTT_MOVE_TO, MENU_LOAD_SEP_1, Me.BTT_LOAD_FAV, Me.BTT_LOAD_SPEC, MENU_LOAD_SEP_2, Me.BTT_FEED_ADD_FAV, Me.BTT_FEED_ADD_FAV_REMOVE, Me.BTT_FEED_REMOVE_FAV, MENU_LOAD_SEP_3, Me.BTT_FEED_ADD_SPEC, Me.BTT_FEED_ADD_SPEC_REMOVE, Me.BTT_FEED_REMOVE_SPEC, MENU_LOAD_SEP_4, Me.BTT_FEED_CLEAR_FAV, Me.BTT_FEED_CLEAR_SPEC, Me.BTT_FEED_DELETE_SPEC, Me.BTT_FEED_DELETE_DAILY_LIST, Me.BTT_FEED_DELETE_DAILY_DATE, MENU_LOAD_SEP_5, Me.BTT_MERGE_SESSIONS, Me.BTT_CLEAR_DAILY, MENU_LOAD_SEP_6, Me.BTT_MERGE_FEEDS, MENU_LOAD_SEP_7, Me.BTT_CHECK_ALL, Me.BTT_CHECK_NONE, MENU_LOAD_SEP_8, Me.BTT_VIEW_SAVE, Me.BTT_VIEW_LOAD})
|
||||
Me.MENU_LOAD_SESSION.Image = Global.SCrawler.My.Resources.Resources.ArrowDownPic_Blue_24
|
||||
Me.MENU_LOAD_SESSION.ImageTransparentColor = System.Drawing.Color.Magenta
|
||||
Me.MENU_LOAD_SESSION.Name = "MENU_LOAD_SESSION"
|
||||
@@ -405,6 +409,25 @@ Namespace DownloadObjects
|
||||
Me.TP_DATA.Size = New System.Drawing.Size(484, 436)
|
||||
Me.TP_DATA.TabIndex = 1
|
||||
'
|
||||
'MENU_LOAD_SEP_8
|
||||
'
|
||||
MENU_LOAD_SEP_8.Name = "MENU_LOAD_SEP_8"
|
||||
MENU_LOAD_SEP_8.Size = New System.Drawing.Size(349, 6)
|
||||
'
|
||||
'BTT_VIEW_SAVE
|
||||
'
|
||||
Me.BTT_VIEW_SAVE.Name = "BTT_VIEW_SAVE"
|
||||
Me.BTT_VIEW_SAVE.Size = New System.Drawing.Size(352, 22)
|
||||
Me.BTT_VIEW_SAVE.Text = "Save current view"
|
||||
'
|
||||
'BTT_VIEW_LOAD
|
||||
'
|
||||
Me.BTT_VIEW_LOAD.AutoToolTip = True
|
||||
Me.BTT_VIEW_LOAD.Name = "BTT_VIEW_LOAD"
|
||||
Me.BTT_VIEW_LOAD.Size = New System.Drawing.Size(352, 22)
|
||||
Me.BTT_VIEW_LOAD.Text = "Load view (from saved)"
|
||||
Me.BTT_VIEW_LOAD.ToolTipText = "Load one of your previously saved views"
|
||||
'
|
||||
'DownloadFeedForm
|
||||
'
|
||||
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
|
||||
@@ -458,5 +481,7 @@ Namespace DownloadObjects
|
||||
Private WithEvents BTT_CHECK_NONE As ToolStripMenuItem
|
||||
Private WithEvents BTT_COPY_TO As ToolStripMenuItem
|
||||
Private WithEvents BTT_MOVE_TO As ToolStripMenuItem
|
||||
Private WithEvents BTT_VIEW_SAVE As ToolStripMenuItem
|
||||
Private WithEvents BTT_VIEW_LOAD As ToolStripMenuItem
|
||||
End Class
|
||||
End Namespace
|
||||
@@ -162,4 +162,7 @@
|
||||
<metadata name="ToolbarTOP.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="MENU_LOAD_SEP_8.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>False</value>
|
||||
</metadata>
|
||||
</root>
|
||||
@@ -21,13 +21,14 @@ Namespace DownloadObjects
|
||||
#End Region
|
||||
#Region "Declarations"
|
||||
Private Const FeedTitleDefault As String = "Feed"
|
||||
Private WithEvents MyDefs As DefaultFormOptions
|
||||
Friend WithEvents MyDefs As DefaultFormOptions
|
||||
Private WithEvents MyRange As RangeSwitcherToolbar(Of UserMediaD)
|
||||
Private ReadOnly DataList As List(Of UserMediaD)
|
||||
Private WithEvents BTT_DELETE_SELECTED As ToolStripButton
|
||||
Private DataRows As Integer = 10
|
||||
Private DataColumns As Integer = 1
|
||||
Private FeedEndless As Boolean = False
|
||||
Private ReadOnly GoToButton As New ButtonKey(Keys.G, True)
|
||||
Private ReadOnly FilterSubscriptions As New FPredicate(Of UserMediaD)(Function(d) If(d.User?.IsSubscription, False))
|
||||
Private ReadOnly FilterUsers As New FPredicate(Of UserMediaD)(Function(d) Not FilterSubscriptions.Invoke(d))
|
||||
Private ReadOnly FileNotExist As New FPredicate(Of UserMediaD)(Function(d) Not d.Data.File.Exists And Not FilterSubscriptions.Invoke(d))
|
||||
@@ -133,9 +134,14 @@ Namespace DownloadObjects
|
||||
With MyRange
|
||||
.AutoToolTip = True
|
||||
.Buttons = {RCI.First, RCI.Previous, RCI.Label, RCI.Next, RCI.Last, RCI.Separator, RCI.GoTo}
|
||||
.ButtonKey(RCI.Previous) = Keys.F3
|
||||
.ButtonKey(RCI.Next) = Keys.F4
|
||||
.ButtonKey(RCI.GoTo) = New ButtonKey(Keys.G, True)
|
||||
'.ButtonKey(RCI.Previous) = Keys.F3
|
||||
'.ButtonKey(RCI.Next) = Keys.F4
|
||||
'.ButtonKey(RCI.GoTo) = GoToButton
|
||||
.ToolTip(RCI.First) = "Go to first page (Home)"
|
||||
.ToolTip(RCI.Last) = "Go to last page (End)"
|
||||
.ToolTip(RCI.Previous) = "Previous (F3, Up, Page Up)"
|
||||
.ToolTip(RCI.Next) = "Next (F4, Down, Page Down)"
|
||||
.ToolTip(RCI.GoTo) = "GoTo (Ctrl+G)"
|
||||
.AddThisToolbar()
|
||||
End With
|
||||
ToolbarTOP.Items.AddRange({New ToolStripSeparator, BTT_DELETE_SELECTED})
|
||||
@@ -167,6 +173,7 @@ Namespace DownloadObjects
|
||||
MENU_DOWN.Visible = OPT_SUBSCRIPTIONS.Checked
|
||||
UpdateSettings()
|
||||
FeedChangeMode(FeedModes.Current)
|
||||
Downloader.FilesLoadLastSession()
|
||||
RefillList(True, False)
|
||||
.EndLoaderOperations(False)
|
||||
End With
|
||||
@@ -176,14 +183,42 @@ Namespace DownloadObjects
|
||||
Hide()
|
||||
End Sub
|
||||
Private Sub DownloadFeedForm_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed
|
||||
ClearTable()
|
||||
'ClearTable()
|
||||
MyRange.Dispose()
|
||||
LoadedFeedNames.Clear()
|
||||
BTT_CLEAR_DAILY.Dispose()
|
||||
DataList.Clear()
|
||||
End Sub
|
||||
Private Sub DownloadFeedForm_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
|
||||
If e.KeyCode = Keys.F5 Then RefillList() : e.Handled = True
|
||||
'If e.KeyCode = Keys.F5 Then RefillList() : e.Handled = True
|
||||
If Not e.Handled Then
|
||||
Dim b As Boolean = False
|
||||
If e = GoToButton Then
|
||||
b = True
|
||||
MyRange.GoToF()
|
||||
Else
|
||||
Dim changePage%? = Nothing
|
||||
Dim gotoHome As Boolean? = Nothing
|
||||
Select Case e.KeyCode
|
||||
Case Keys.F5 : RefillList() : b = True
|
||||
Case Keys.F3 : changePage = -1
|
||||
Case Keys.F4 : changePage = 1
|
||||
Case Keys.Up, Keys.Left, Keys.PageUp : changePage = -1
|
||||
Case Keys.Down, Keys.Right, Keys.PageDown : changePage = 1
|
||||
Case Keys.Home : gotoHome = True
|
||||
Case Keys.End : gotoHome = False
|
||||
End Select
|
||||
If changePage.HasValue Then
|
||||
b = True
|
||||
If MyRange.TryMove(changePage.Value) Then MyRange.Move(changePage.Value)
|
||||
ElseIf gotoHome.HasValue Then
|
||||
b = True
|
||||
Dim indx% = IIf(gotoHome.Value, 0, MyRange.Count - 1)
|
||||
If MyRange.CurrentIndex <> indx Then MyRange.GoTo(indx)
|
||||
End If
|
||||
End If
|
||||
If b Then e.Handled = True
|
||||
End If
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Feeds handlers"
|
||||
@@ -507,6 +542,7 @@ Namespace DownloadObjects
|
||||
Dim data As IEnumerable(Of UserMediaD) = Nothing
|
||||
Dim dd As UserMediaD
|
||||
Dim data_files As IEnumerable(Of SFile) = Nothing
|
||||
Dim new_files As New List(Of SFile)
|
||||
Dim mm As UserMediaD
|
||||
Dim mm_data As API.Base.UserMedia
|
||||
Dim indx%
|
||||
@@ -605,10 +641,11 @@ Namespace DownloadObjects
|
||||
df = ff
|
||||
df.Path = moveOptions.DestinationTrue(dd).Path
|
||||
If isCopy Then
|
||||
If ff.Copy(df) Then result = True
|
||||
If ff.Copy(df) Then new_files.Add(df) : result = True
|
||||
Else
|
||||
If df.Exists And renameExisting Then df = SFile.IndexReindex(df,,,, New ErrorsDescriber(False, False, False, df))
|
||||
If SFile.Move(ff, df) Then
|
||||
new_files.Add(df)
|
||||
result = True
|
||||
If updateFileLocations Then
|
||||
filesReplace.Add(New KeyValuePair(Of SFile, SFile)(ff, df))
|
||||
@@ -668,7 +705,10 @@ Namespace DownloadObjects
|
||||
If filesReplace.Count > 0 Then filesReplace.ForEach(Sub(fr) Settings.Feeds.UpdateDataByFile(fr.Key, fr.Value, moveOptions))
|
||||
filesReplace.Clear()
|
||||
End If
|
||||
If IsInternal Then MsgBoxE(New MMessage($"The following files were {IIf(isCopy, "copied", "moved")} to{vbCr}{moveOptions.Destination}{vbCr}{vbCr}{data_files.ListToString(vbCr)}", MsgTitle) With {.Editable = True})
|
||||
If IsInternal Then MsgBoxE(New MMessage($"The following files were {IIf(isCopy, "copied", "moved")} to{vbCr}{moveOptions.Destination}{vbCr}{vbCr}" &
|
||||
$"Source:{vbCr}{data_files.ListToString(vbCr)}{vbCr}" &
|
||||
$"Destination:{vbCr}{new_files.ListToString(vbCr)}", MsgTitle) With {.Editable = True})
|
||||
new_files.Clear()
|
||||
If Not isCopy And updateFileLocations Then RefillList()
|
||||
End If
|
||||
Else
|
||||
@@ -1005,6 +1045,59 @@ Namespace DownloadObjects
|
||||
End Sub, EDP.None)
|
||||
If __refill Then RefillList()
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "View changer"
|
||||
Private Sub BTT_VIEW_SAVE_Click(sender As Object, e As EventArgs) Handles BTT_VIEW_SAVE.Click
|
||||
Dim fName$ = String.Empty
|
||||
Dim __process As Boolean = False
|
||||
If Settings.FeedViews Is Nothing Then Settings.FeedViews = New FeedViewCollection
|
||||
Do
|
||||
fName = InputBoxE("Enter a new name for the view:", "Feed view name", fName)
|
||||
If Not fName.IsEmptyString Then
|
||||
If Settings.FeedViews.IndexOf(fName) >= 0 Then
|
||||
Select Case MsgBoxE({$"The '{fName}' feed view already exists!", "Save view"}, vbExclamation,,, {"Try again", "Replace", "Cancel"}).Index
|
||||
Case 1 : __process = True
|
||||
Case 2 : Exit Sub
|
||||
End Select
|
||||
Else
|
||||
__process = True
|
||||
End If
|
||||
Else
|
||||
Exit Sub
|
||||
End If
|
||||
Loop While Not __process
|
||||
If __process Then
|
||||
Settings.FeedViews.Add(FeedView.FromCurrent(fName))
|
||||
MsgBoxE({$"The '{fName}' feed view has been saved", "Save view"})
|
||||
End If
|
||||
End Sub
|
||||
Private Sub BTT_VIEW_LOAD_Click(sender As Object, e As EventArgs) Handles BTT_VIEW_LOAD.Click
|
||||
Try
|
||||
If Settings.FeedViews Is Nothing Then Settings.FeedViews = New FeedViewCollection
|
||||
If Settings.FeedViews.Count = 0 Then
|
||||
MsgBoxE({"There are no saved feed views", "Load feed view"}, vbExclamation)
|
||||
Else
|
||||
Using f As New SimpleListForm(Of FeedView)(Settings.FeedViews, Settings.Design) With {
|
||||
.DesignXMLNodeName = "SavedFeedViewsForm",
|
||||
.FormText = "Feed view",
|
||||
.Mode = SimpleListFormModes.SelectedItems,
|
||||
.MultiSelect = False
|
||||
}
|
||||
If f.ShowDialog = DialogResult.OK Then
|
||||
Dim v As FeedView = f.DataResult.FirstOrDefault
|
||||
If Not v.Name.IsEmptyString Then
|
||||
ControlInvokeFast(Me, Sub() WindowState = FormWindowState.Normal)
|
||||
v.Populate()
|
||||
ControlInvokeFast(Me, Sub() MyDefs.MyView.SetFormSize())
|
||||
UpdateSettings()
|
||||
End If
|
||||
End If
|
||||
End Using
|
||||
End If
|
||||
Catch ex As Exception
|
||||
ErrorsDescriber.Execute(EDP.LogMessageValue, ex, "Load feed view")
|
||||
End Try
|
||||
End Sub
|
||||
#End Region
|
||||
Friend Sub Downloader_FilesChanged(ByVal Added As Boolean)
|
||||
ControlInvokeFast(ToolbarTOP, BTT_REFRESH, Sub() BTT_REFRESH.ToolTipText = If(Added, "New files found", "Some files have been removed"))
|
||||
@@ -1282,6 +1375,10 @@ Namespace DownloadObjects
|
||||
DataPopulated = True
|
||||
IndexChanged = True
|
||||
End If
|
||||
ControlInvokeFast(Me, Sub()
|
||||
Activate()
|
||||
Focus()
|
||||
End Sub, EDP.None)
|
||||
End Try
|
||||
End Sub
|
||||
#End Region
|
||||
@@ -1353,6 +1450,9 @@ Namespace DownloadObjects
|
||||
If Not b Then ScrollSuspended = False
|
||||
End Sub)
|
||||
End Sub
|
||||
Private Sub DownloadFeedForm_Deactivate(sender As Object, e As EventArgs) Handles Me.Deactivate
|
||||
If Not LatestScrollValueDisabled Then LatestScrollValue = ControlInvokeFast(TP_DATA, Function() TP_DATA.VerticalScroll.Value, 0, EDP.ReturnValue)
|
||||
End Sub
|
||||
Private Sub TP_DATA_Paint(sender As Object, e As PaintEventArgs) Handles TP_DATA.Paint
|
||||
If Not MyDefs.Initializing And Not ScrollSuspended And FeedEndless Then
|
||||
If Not LatestScrollValueDisabled Then LatestScrollValue = ControlInvokeFast(TP_DATA, Function() TP_DATA.VerticalScroll.Value, 0)
|
||||
|
||||
@@ -498,13 +498,13 @@ Namespace DownloadObjects
|
||||
If f.DialogResult = DialogResult.OK Then moveOptions = f.Result
|
||||
End Using
|
||||
If Not moveOptions.Destination.IsEmptyString Then
|
||||
ff.Path = moveOptions.Destination.Path
|
||||
ff.Path = moveOptions.DestinationTrue(Media).Path
|
||||
If isCopy Then
|
||||
result = File.Copy(ff)
|
||||
Else
|
||||
RaiseEvent MediaMove(Me, moveOptions, result)
|
||||
End If
|
||||
If result Then MsgBoxE({$"File {IIf(isCopy, "copied", "moved")}{vbCr}Source: '{File}'{vbCr}Destination: '{ff}'", MsgTitle})
|
||||
If result Then MsgBoxE(New MMessage($"File {IIf(isCopy, "copied", "moved")}{vbCr}Source: '{File}'{vbCr}Destination: '{ff}'", MsgTitle) With {.Editable = True})
|
||||
End If
|
||||
End If
|
||||
Catch ex As Exception
|
||||
@@ -549,7 +549,7 @@ Namespace DownloadObjects
|
||||
If Not UserKey.IsEmptyString Then MainFrameObj.FocusUser(UserKey, True)
|
||||
End Sub
|
||||
Private Sub BTT_CONTEXT_INFO_Click(sender As Object, e As EventArgs) Handles BTT_CONTEXT_INFO.Click
|
||||
MsgBoxE({Information, "Post information"})
|
||||
MsgBoxE(New MMessage(Information, "Post information") With {.Editable = True})
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Delete"
|
||||
|
||||
@@ -236,7 +236,7 @@ Namespace DownloadObjects
|
||||
Friend Sub UpdateUsers(ByVal InitialUser As UserInfo, ByVal NewUser As UserInfo)
|
||||
Try
|
||||
Load()
|
||||
If Count > 0 Then
|
||||
If Count > 0 AndAlso Not UserInfo.ExactEquals(InitialUser, NewUser) Then
|
||||
Feeds.ForEach(Sub(f) f.UpdateUsers(InitialUser, NewUser))
|
||||
If Downloader.Files.Count > 0 Then
|
||||
PendingUsersToUpdate.Add(New KeyValuePair(Of UserInfo, UserInfo)(InitialUser, NewUser))
|
||||
|
||||
203
SCrawler/Download/Feed/FeedView.vb
Normal file
@@ -0,0 +1,203 @@
|
||||
' 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.Tools
|
||||
Imports PersonalUtilities.Functions.XML
|
||||
Imports PersonalUtilities.Functions.XML.Base
|
||||
Namespace DownloadObjects
|
||||
Friend Structure FeedView : Implements IEContainerProvider, IComparable(Of FeedView)
|
||||
#Region "Names"
|
||||
Private Const Name_Name As String = "Name"
|
||||
Private Const Name_Rows As String = "Rows"
|
||||
Private Const Name_Columns As String = "Columns"
|
||||
Private Const Name_CenterImage As String = "CenterImage"
|
||||
Private Const Name_CenterImageUse As String = "CenterImageUse"
|
||||
Private Const Name_Endless As String = "Endless"
|
||||
Private Const Name_BackColor As String = "BackColor"
|
||||
Private Const Name_ForeColor As String = "ForeColor"
|
||||
Private Const Name_View As String = "View"
|
||||
#End Region
|
||||
#Region "Declarations"
|
||||
Friend Name As String
|
||||
Friend Rows As Integer
|
||||
Friend Columns As Integer
|
||||
Friend CenterImage As Integer
|
||||
Friend CenterImageUse As Boolean
|
||||
Friend Endless As Boolean
|
||||
Friend BackColor As Color?
|
||||
Friend ForeColor As Color?
|
||||
Friend View As FormView
|
||||
#End Region
|
||||
#Region "Initializers"
|
||||
Friend Sub New(ByVal e As EContainer)
|
||||
With e
|
||||
Name = .Value(Name_Name)
|
||||
Rows = .Value(Name_Rows).FromXML(Of Integer)(10)
|
||||
Columns = .Value(Name_Columns).FromXML(Of Integer)(1)
|
||||
CenterImage = .Value(Name_CenterImage).FromXML(Of Integer)(1)
|
||||
CenterImageUse = .Value(Name_CenterImageUse).FromXML(Of Boolean)(False)
|
||||
Endless = .Value(Name_Endless).FromXML(Of Boolean)(True)
|
||||
BackColor = AConvert(Of Color)(.Value(Name_BackColor), AModes.Var, Nothing)
|
||||
ForeColor = AConvert(Of Color)(.Value(Name_ForeColor), AModes.Var, Nothing)
|
||||
View = New FormView
|
||||
View.Import(e, {Name_View})
|
||||
End With
|
||||
End Sub
|
||||
Friend Shared Function FromCurrent(Optional ByVal Name As String = "") As FeedView
|
||||
Dim v As New FeedView
|
||||
With Settings
|
||||
v.Name = Name
|
||||
v.Rows = .FeedDataRows
|
||||
v.Columns = .FeedDataColumns
|
||||
v.Endless = .FeedEndless
|
||||
v.CenterImage = .FeedCenterImage
|
||||
v.CenterImageUse = .FeedCenterImage.Use
|
||||
If .FeedBackColor.Exists Then
|
||||
v.BackColor = .FeedBackColor
|
||||
Else
|
||||
v.BackColor = Nothing
|
||||
End If
|
||||
If .FeedForeColor.Exists Then
|
||||
v.ForeColor = .FeedForeColor
|
||||
Else
|
||||
v.ForeColor = Nothing
|
||||
End If
|
||||
v.View = New FormView
|
||||
With MainFrameObj.MF.MyFeed.MyDefs.MyView
|
||||
v.View.Location = .Location
|
||||
v.View.LocationOnly = .LocationOnly
|
||||
v.View.Size = .Size
|
||||
v.View.WindowState = .WindowState
|
||||
End With
|
||||
End With
|
||||
Return v
|
||||
End Function
|
||||
#End Region
|
||||
Friend Sub Populate()
|
||||
With Settings
|
||||
.BeginUpdate()
|
||||
|
||||
.FeedDataRows.Value = Rows
|
||||
.FeedDataColumns.Value = Columns
|
||||
.FeedEndless.Value = Endless
|
||||
.FeedCenterImage.Value = CenterImage
|
||||
.FeedCenterImage.Use = CenterImageUse
|
||||
If BackColor.HasValue Then
|
||||
.FeedBackColor.Value = BackColor.Value
|
||||
Else
|
||||
.FeedBackColor.ValueF = Nothing
|
||||
End If
|
||||
If ForeColor.HasValue Then
|
||||
.FeedForeColor.Value = ForeColor.Value
|
||||
Else
|
||||
.FeedForeColor.ValueF = Nothing
|
||||
End If
|
||||
If Not View Is Nothing Then
|
||||
With MainFrameObj.MF.MyFeed.MyDefs.MyView
|
||||
.Location = View.Location
|
||||
.LocationOnly = View.LocationOnly
|
||||
.Size = View.Size
|
||||
.WindowState = View.WindowState
|
||||
End With
|
||||
End If
|
||||
|
||||
.EndUpdate()
|
||||
End With
|
||||
End Sub
|
||||
Public Overrides Function ToString() As String
|
||||
Return Name
|
||||
End Function
|
||||
Public Overrides Function Equals(ByVal Obj As Object) As Boolean
|
||||
If Not IsNothing(Obj) AndAlso TypeOf Obj Is FeedView Then
|
||||
Return Name.StringToLower = DirectCast(Obj, FeedView).Name.StringToLower
|
||||
Else
|
||||
Return False
|
||||
End If
|
||||
End Function
|
||||
Private Function CompareTo(ByVal Other As FeedView) As Integer Implements IComparable(Of FeedView).CompareTo
|
||||
Return Name.CompareTo(Other.Name)
|
||||
End Function
|
||||
Private Function ToEContainer(Optional ByVal e As ErrorsDescriber = Nothing) As EContainer Implements IEContainerProvider.ToEContainer
|
||||
Dim container As New EContainer("FeedView") From {
|
||||
New EContainer(Name_Name, Name),
|
||||
New EContainer(Name_Rows, Rows),
|
||||
New EContainer(Name_Columns, Columns),
|
||||
New EContainer(Name_CenterImage, CenterImage),
|
||||
New EContainer(Name_CenterImageUse, CenterImageUse.BoolToInteger),
|
||||
New EContainer(Name_Endless, Endless.BoolToInteger),
|
||||
New EContainer(Name_BackColor, AConvert(Of String)(BackColor, AModes.Var, String.Empty)),
|
||||
New EContainer(Name_ForeColor, AConvert(Of String)(ForeColor, AModes.Var, String.Empty))
|
||||
}
|
||||
View.Export(container, {Name_View})
|
||||
Return container
|
||||
End Function
|
||||
End Structure
|
||||
Friend Class FeedViewCollection : Implements IEnumerable(Of FeedView), IMyEnumerator(Of FeedView)
|
||||
Private ReadOnly Views As List(Of FeedView)
|
||||
Private ReadOnly File As SFile = $"{SettingsFolderName}\FeedView.xml"
|
||||
Friend Sub New()
|
||||
Views = New List(Of FeedView)
|
||||
If File.Exists Then
|
||||
Using x As New XmlFile(File, Protector.Modes.All, False) With {.AllowSameNames = True}
|
||||
x.LoadData()
|
||||
If x.Count > 0 Then Views.ListAddList(x, LAP.IgnoreICopier)
|
||||
End Using
|
||||
End If
|
||||
If Views.Count > 0 Then Views.Sort()
|
||||
End Sub
|
||||
Default Friend ReadOnly Property Item(ByVal Index As Integer) As FeedView Implements IMyEnumerator(Of FeedView).MyEnumeratorObject
|
||||
Get
|
||||
Return Views(Index)
|
||||
End Get
|
||||
End Property
|
||||
Friend ReadOnly Property Count As Integer Implements IMyEnumerator(Of FeedView).MyEnumeratorCount
|
||||
Get
|
||||
Return Views.Count
|
||||
End Get
|
||||
End Property
|
||||
Friend Sub Update()
|
||||
If Count > 0 Then
|
||||
Views.Sort()
|
||||
Using x As New XmlFile With {.AllowSameNames = True}
|
||||
x.AddRange(Views)
|
||||
x.Name = "FeedViews"
|
||||
x.Save(File, EDP.LogMessageValue)
|
||||
End Using
|
||||
Else
|
||||
If File.Exists Then File.Delete()
|
||||
End If
|
||||
End Sub
|
||||
Friend Sub Add(ByVal Item As FeedView, Optional ByVal AutoUpdate As Boolean = True)
|
||||
Dim i% = IndexOf(Item)
|
||||
If i >= 0 Then
|
||||
Views(i) = Item
|
||||
Else
|
||||
Views.Add(Item)
|
||||
End If
|
||||
Views.Sort()
|
||||
If AutoUpdate Then Update()
|
||||
End Sub
|
||||
Friend Overloads Function IndexOf(ByVal Item As FeedView) As Integer
|
||||
If Count > 0 Then
|
||||
Return Views.IndexOf(Item)
|
||||
Else
|
||||
Return -1
|
||||
End If
|
||||
End Function
|
||||
Friend Overloads Function IndexOf(ByVal Name As String) As Integer
|
||||
Return IndexOf(New FeedView With {.Name = Name})
|
||||
End Function
|
||||
Private Function GetEnumerator() As IEnumerator(Of FeedView) Implements IEnumerable(Of FeedView).GetEnumerator
|
||||
Return New MyEnumerator(Of FeedView)(Me)
|
||||
End Function
|
||||
Private Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
|
||||
Return GetEnumerator()
|
||||
End Function
|
||||
End Class
|
||||
End Namespace
|
||||
@@ -10,22 +10,44 @@ Imports SCrawler.API.Base
|
||||
Imports PersonalUtilities.Functions.XML
|
||||
Imports PersonalUtilities.Functions.XML.Base
|
||||
Namespace DownloadObjects.Groups
|
||||
Friend Class DownloadGroup : Inherits GroupParameters : Implements IIndexable, IEContainerProvider
|
||||
Friend Class DownloadGroup : Inherits GroupParameters : Implements IIndexable, IEContainerProvider, IComparable(Of DownloadGroup)
|
||||
#Region "Events"
|
||||
Friend Delegate Sub GroupEventHandler(ByVal Sender As DownloadGroup)
|
||||
Friend Event Deleted As GroupEventHandler
|
||||
Friend Event Updated As GroupEventHandler
|
||||
#End Region
|
||||
#Region "XML names"
|
||||
Private Const Name_FilterViewMode As String = "FilterViewMode"
|
||||
Private Const Name_FilterGroupUsers As String = "FilterGroupUsers"
|
||||
Private Const Name_FilterShowGroupsInsteadLabels As String = "FilterShowGroupsInsteadLabels"
|
||||
#End Region
|
||||
#Region "Declarations"
|
||||
#Region "Controls"
|
||||
Private WithEvents BTT_EDIT As ToolStripMenuItem
|
||||
Private WithEvents BTT_DELETE As ToolStripMenuItem
|
||||
Private WithEvents BTT_DOWNLOAD As ToolStripMenuItem
|
||||
Private WithEvents BTT_DOWNLOAD_FULL As ToolStripMenuItem
|
||||
Private WithEvents BTT_DOWNLOAD As ToolStripKeyMenuItem
|
||||
Private WithEvents BTT_CLONE_ADD As ToolStripMenuItem
|
||||
Private WithEvents BTT_CLONE_TEMP As ToolStripKeyMenuItem
|
||||
Private ReadOnly SEP_1 As ToolStripSeparator
|
||||
Private WithEvents BTT_MENU As ToolStripMenuItem
|
||||
Private ReadOnly SEP_2 As ToolStripSeparator
|
||||
Private WithEvents BTT_MENU As ToolStripKeyMenuItem
|
||||
#End Region
|
||||
#Region "Filter declarations"
|
||||
Friend Property FilterViewMode As ViewModes = ViewModes.IconLarge
|
||||
Friend Property FilterGroupUsers As Boolean = True
|
||||
Friend Property FilterShowGroupsInsteadLabels As Boolean = True
|
||||
#End Region
|
||||
Private File As SFile = Nothing
|
||||
Friend Overrides Property Name As String
|
||||
Get
|
||||
Return MyBase.Name
|
||||
End Get
|
||||
Set(ByVal NewName As String)
|
||||
Dim b As Boolean = Not MyBase.Name.IsEmptyString AndAlso Not MyBase.Name = NewName
|
||||
MyBase.Name = NewName
|
||||
If b Then RaiseEvent Updated(Me)
|
||||
End Set
|
||||
End Property
|
||||
Friend Property NameBefore As String = String.Empty
|
||||
Private _Key As String = String.Empty
|
||||
Friend ReadOnly Property Key As String
|
||||
@@ -49,55 +71,114 @@ Namespace DownloadObjects.Groups
|
||||
DirectCast(Obj, DownloadGroup).Index = _Index
|
||||
Return Obj
|
||||
End Function
|
||||
Friend Shared ReadOnly Property GroupImage As Bitmap
|
||||
Get
|
||||
Return My.Resources.GroupByIcon_16.ToBitmap
|
||||
End Get
|
||||
End Property
|
||||
#End Region
|
||||
#Region "Initializers"
|
||||
Friend ReadOnly NeedToSave As Boolean = False
|
||||
Friend Sub New()
|
||||
BTT_MENU = New ToolStripMenuItem With {
|
||||
Me.New(True)
|
||||
End Sub
|
||||
Friend Sub New(ByVal InitButtons As Boolean)
|
||||
If InitButtons Then
|
||||
BTT_MENU = New ToolStripKeyMenuItem With {
|
||||
.ToolTipText = "Download users of this group",
|
||||
.AutoToolTip = True,
|
||||
.Image = My.Resources.GroupByIcon_16.ToBitmap
|
||||
.Image = GroupImage
|
||||
}
|
||||
BTT_DELETE = New ToolStripMenuItem With {
|
||||
.Image = PersonalUtilities.My.Resources.DeletePic_Red_24,
|
||||
.BackColor = MyColor.DeleteBack,
|
||||
.ForeColor = MyColor.DeleteFore,
|
||||
.Text = "Delete",
|
||||
.ToolTipText = String.Empty,
|
||||
.AutoToolTip = False
|
||||
}
|
||||
BTT_EDIT = New ToolStripMenuItem With {
|
||||
.Image = PersonalUtilities.My.Resources.PencilPic_16,
|
||||
.BackColor = MyColor.EditBack,
|
||||
.ForeColor = MyColor.EditFore,
|
||||
.Text = "Edit",
|
||||
.ToolTipText = String.Empty,
|
||||
.AutoToolTip = False
|
||||
}
|
||||
SEP_1 = New ToolStripSeparator
|
||||
BTT_DOWNLOAD = New ToolStripMenuItem With {
|
||||
.Image = My.Resources.StartPic_Green_16,
|
||||
.Text = "Download",
|
||||
.ToolTipText = "Download users of this group (respect the 'Ready for download' parameter)",
|
||||
.AutoToolTip = True
|
||||
}
|
||||
BTT_DOWNLOAD_FULL = New ToolStripMenuItem With {
|
||||
.Image = My.Resources.StartPic_Green_16,
|
||||
.Text = "Download FULL",
|
||||
.ToolTipText = "Download users of this group (ignore the 'Ready for download' parameter)",
|
||||
.AutoToolTip = True
|
||||
}
|
||||
BTT_MENU.DropDownItems.AddRange({BTT_EDIT, BTT_DELETE, SEP_1, BTT_DOWNLOAD, BTT_DOWNLOAD_FULL})
|
||||
BTT_DELETE = New ToolStripMenuItem With {
|
||||
.Image = PersonalUtilities.My.Resources.DeletePic_Red_24,
|
||||
.BackColor = MyColor.DeleteBack,
|
||||
.ForeColor = MyColor.DeleteFore,
|
||||
.Text = "Delete",
|
||||
.ToolTipText = String.Empty,
|
||||
.AutoToolTip = False
|
||||
}
|
||||
BTT_EDIT = New ToolStripMenuItem With {
|
||||
.Image = PersonalUtilities.My.Resources.PencilPic_16,
|
||||
.BackColor = MyColor.EditBack,
|
||||
.ForeColor = MyColor.EditFore,
|
||||
.Text = "Edit",
|
||||
.ToolTipText = String.Empty,
|
||||
.AutoToolTip = False
|
||||
}
|
||||
BTT_CLONE_ADD = New ToolStripMenuItem With {
|
||||
.Image = PersonalUtilities.My.Resources.PlusPic_Green_24,
|
||||
.BackColor = MyColor.OkBack,
|
||||
.ForeColor = MyColor.OkFore,
|
||||
.Text = "Clone and add",
|
||||
.ToolTipText = "Clone the group, change parameters and add this group as a new one",
|
||||
.AutoToolTip = True
|
||||
}
|
||||
BTT_CLONE_TEMP = New ToolStripKeyMenuItem With {
|
||||
.Image = PersonalUtilities.My.Resources.PlusPic_Green_24,
|
||||
.BackColor = MyColor.OkBack,
|
||||
.ForeColor = MyColor.OkFore,
|
||||
.Text = "Clone and download",
|
||||
.ToolTipText = "Clone the group, change parameters and download filtered users (this group will not be added as a new one)",
|
||||
.AutoToolTip = True
|
||||
}
|
||||
SEP_1 = New ToolStripSeparator
|
||||
SEP_2 = New ToolStripSeparator
|
||||
BTT_DOWNLOAD = New ToolStripKeyMenuItem With {
|
||||
.Image = My.Resources.StartPic_Green_16,
|
||||
.Text = "Download",
|
||||
.ToolTipText = "Download users of this group (respect the 'Ready for download' parameter)",
|
||||
.AutoToolTip = True
|
||||
}
|
||||
BTT_MENU.DropDownItems.AddRange({BTT_EDIT, BTT_DELETE, SEP_1, BTT_CLONE_ADD, BTT_CLONE_TEMP, SEP_2, BTT_DOWNLOAD})
|
||||
End If
|
||||
End Sub
|
||||
Friend Sub New(ByVal e As EContainer)
|
||||
Me.New
|
||||
Me.New(Not e.Value(Name_IsViewFilter).FromXML(Of Boolean)(False))
|
||||
Import(e)
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Import/Export"
|
||||
Protected Overrides Sub Import(ByVal e As EContainer)
|
||||
MyBase.Import(e)
|
||||
If IsViewFilter Then
|
||||
FilterViewMode = e.Value(Name_FilterViewMode).FromXML(Of Integer)(ViewModes.IconLarge)
|
||||
FilterGroupUsers = e.Value(Name_FilterGroupUsers).FromXML(Of Boolean)(True)
|
||||
FilterShowGroupsInsteadLabels = e.Value(Name_FilterShowGroupsInsteadLabels).FromXML(Of Boolean)(True)
|
||||
End If
|
||||
End Sub
|
||||
Protected Overrides Function Export(ByVal e As EContainer) As EContainer
|
||||
MyBase.Export(e)
|
||||
e.AddRange({New EContainer(Name_FilterViewMode, CInt(FilterViewMode)),
|
||||
New EContainer(Name_FilterGroupUsers, FilterGroupUsers.BoolToInteger),
|
||||
New EContainer(Name_FilterShowGroupsInsteadLabels, FilterShowGroupsInsteadLabels.BoolToInteger)})
|
||||
Return e
|
||||
End Function
|
||||
#End Region
|
||||
#Region "Copy"
|
||||
Friend Overloads Overrides Function Copy() As Object
|
||||
Return (New DownloadGroup).Copy(Me)
|
||||
End Function
|
||||
Friend Overloads Overrides Function Copy(ByVal Source As Object) As Object
|
||||
MyBase.Copy(Source)
|
||||
If TypeOf Source Is DownloadGroup Then
|
||||
With DirectCast(Source, DownloadGroup)
|
||||
If .IsViewFilter Then
|
||||
FilterViewMode = .FilterViewMode
|
||||
FilterGroupUsers = .FilterGroupUsers
|
||||
FilterShowGroupsInsteadLabels = .FilterShowGroupsInsteadLabels
|
||||
End If
|
||||
End With
|
||||
End If
|
||||
Return Me
|
||||
End Function
|
||||
#End Region
|
||||
#Region "ToString"
|
||||
Public Overrides Function ToString() As String
|
||||
Return $"{IIf(Index.ValueBetween(0, 8), $"#{Index + 1}: ", String.Empty)}{Name}"
|
||||
End Function
|
||||
Friend Overrides Function ToStringViewFilters() As String
|
||||
Return $"{IIf(IsViewFilter, "View filter", "Group")} '{Name}'"
|
||||
End Function
|
||||
#End Region
|
||||
#Region "GetControl"
|
||||
Private _ControlSent As Boolean = False
|
||||
@@ -111,9 +192,39 @@ Namespace DownloadObjects.Groups
|
||||
End Function
|
||||
#End Region
|
||||
#Region "Buttons"
|
||||
Private Sub BTT_MENU_Click(sender As Object, e As EventArgs) Handles BTT_MENU.Click
|
||||
DownloadUsers()
|
||||
Private Sub BTT_MENU_Click(ByVal Sender As Object, ByVal e As MyKeyEventArgs) Handles BTT_MENU.KeyClick
|
||||
Try
|
||||
With BTT_MENU
|
||||
.HideDropDown()
|
||||
Dim obj As Object = .Owner
|
||||
Dim r% = 0
|
||||
Do While Not obj Is Nothing And r < 5 : obj = TryHide(obj) : r += 1 : Loop
|
||||
End With
|
||||
Catch
|
||||
End Try
|
||||
ProcessDownloadUsers(e.IncludeInTheFeed)
|
||||
End Sub
|
||||
Private Function TryHide(ByVal Sender As Object) As Object
|
||||
Dim retObj As Object = Nothing
|
||||
Try
|
||||
If Not Sender Is Nothing Then
|
||||
If TypeOf Sender Is ToolStripDropDownMenu Then
|
||||
With DirectCast(Sender, ToolStripDropDownMenu)
|
||||
retObj = .OwnerItem
|
||||
.Hide()
|
||||
End With
|
||||
ElseIf TypeOf Sender Is ToolStripMenuItem Then
|
||||
With DirectCast(Sender, ToolStripMenuItem)
|
||||
retObj = .Owner
|
||||
.HideDropDown()
|
||||
End With
|
||||
End If
|
||||
End If
|
||||
Catch
|
||||
End Try
|
||||
If Not retObj Is Nothing AndAlso Not (TypeOf retObj Is ToolStripMenuItem Or TypeOf retObj Is ToolStripDropDownMenu) Then retObj = Nothing
|
||||
Return retObj
|
||||
End Function
|
||||
Private Sub BTT_EDIT_Click(sender As Object, e As EventArgs) Handles BTT_EDIT.Click
|
||||
Using f As New GroupEditorForm(Me)
|
||||
f.ShowDialog()
|
||||
@@ -121,67 +232,98 @@ Namespace DownloadObjects.Groups
|
||||
End Using
|
||||
End Sub
|
||||
Private Sub BTT_DELETE_Click(sender As Object, e As EventArgs) Handles BTT_DELETE.Click
|
||||
If MsgBoxE({$"Are you sure you want to delete the [{Name}] group?", "Deleting a group"}, vbExclamation + vbYesNo) = vbYes Then
|
||||
Delete()
|
||||
End Sub
|
||||
Friend Function Delete(Optional ByVal Silent As Boolean = False) As Boolean
|
||||
Dim msgTitle$ = $"Deleting a {IIf(IsViewFilter, "filter", "group")}"
|
||||
If Silent OrElse MsgBoxE({$"Are you sure you want to delete the '{Name}' {IIf(IsViewFilter, "filter", "group")}?", msgTitle}, vbExclamation + vbYesNo) = vbYes Then
|
||||
If Not Settings.Automation Is Nothing AndAlso Settings.Automation.Count > 0 Then
|
||||
Dim aIncl As New List(Of String)
|
||||
For Each plan As AutoDownloader In Settings.Automation
|
||||
If plan.Mode = AutoDownloader.Modes.Groups AndAlso plan.Groups.Count > 0 AndAlso plan.Groups.Contains(Name) Then aIncl.Add(plan.Name)
|
||||
Next
|
||||
If aIncl.Count > 0 Then
|
||||
MsgBoxE({$"The '{Name}' group cannot be deleted because it is included in the following scheduler plans:{vbCr}{vbCr}" &
|
||||
aIncl.ListToString(vbCr), msgTitle}, vbCritical)
|
||||
aIncl.Clear()
|
||||
Return False
|
||||
End If
|
||||
End If
|
||||
RaiseEvent Deleted(Me)
|
||||
MsgBoxE({$"Group [{Name}] deleted", "Deleting a group"})
|
||||
If Not Silent Then MsgBoxE({$"{IIf(IsViewFilter, "Filter", "Group")} '{Name}' deleted", msgTitle})
|
||||
Return True
|
||||
End If
|
||||
Return False
|
||||
End Function
|
||||
Private Sub BTT_CLONE_ADD_Click(sender As Object, e As EventArgs) Handles BTT_CLONE_ADD.Click
|
||||
Settings.Groups.CloneAndAdd(Me)
|
||||
End Sub
|
||||
Private Sub BTT_DOWNLOAD_Click(sender As Object, e As EventArgs) Handles BTT_DOWNLOAD.Click
|
||||
DownloadUsers()
|
||||
Private Sub BTT_CLONE_TEMP_Click(ByVal Sender As Object, ByVal e As MyKeyEventArgs) Handles BTT_CLONE_TEMP.KeyClick
|
||||
Using f As New GroupEditorForm(New DownloadGroup(False).Copy(Me)) With {.IsTemporaryGroup = True}
|
||||
f.ShowDialog()
|
||||
If f.DialogResult = DialogResult.OK AndAlso Not f.MyGroup Is Nothing Then
|
||||
f.MyGroup.Name = String.Empty
|
||||
f.MyGroup.ProcessDownloadUsers(e.IncludeInTheFeed)
|
||||
End If
|
||||
If Not f.MyGroup Is Nothing Then f.MyGroup.Dispose()
|
||||
End Using
|
||||
End Sub
|
||||
Private Sub BTT_DOWNLOAD_FULL_Click(sender As Object, e As EventArgs) Handles BTT_DOWNLOAD_FULL.Click
|
||||
DownloadUsers(, False)
|
||||
Private Sub BTT_DOWNLOAD_Click(ByVal Sender As Object, ByVal e As MyKeyEventArgs) Handles BTT_DOWNLOAD.KeyClick
|
||||
ProcessDownloadUsers(e.IncludeInTheFeed)
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Get users"
|
||||
Friend Overloads Function GetUsers() As IEnumerable(Of IUserData)
|
||||
Return GetUsers(Me)
|
||||
End Function
|
||||
Friend Overloads Shared Function GetUsers(ByVal Instance As IGroup, Optional ByVal UseReadyOption As Boolean = True,
|
||||
Optional ByVal IncludeNonExistentUsers As Boolean = False,
|
||||
Optional ByVal OnlyNonExistentUsers As Boolean = False) As IEnumerable(Of IUserData)
|
||||
Friend Overloads Shared Function GetUsers(ByVal Instance As IGroup) As IEnumerable(Of IUserData)
|
||||
Try
|
||||
If Settings.Users.Count > 0 Then
|
||||
With Instance
|
||||
Dim downDate As Date? = Nothing
|
||||
If .DaysNumber > 0 Then
|
||||
With Now.AddDays(- .DaysNumber) : downDate = New Date(.Year, .Month, .Day, 0, 0, 0) : End With
|
||||
End If
|
||||
Dim CheckUserExists As Predicate(Of IUserData) = Function(ByVal user As IUserData) As Boolean
|
||||
If user.Exists Then
|
||||
If IncludeNonExistentUsers And OnlyNonExistentUsers Then
|
||||
Return False
|
||||
Else
|
||||
Return True
|
||||
End If
|
||||
ElseIf IncludeNonExistentUsers Then
|
||||
Return True
|
||||
If Not user.Exists Then
|
||||
Return .UserDeleted
|
||||
ElseIf user.Suspended Then
|
||||
Return .UserSuspended
|
||||
Else
|
||||
Return False
|
||||
Return .UserExists
|
||||
End If
|
||||
End Function
|
||||
Dim CheckParams As Predicate(Of IUserData) = Function(user) _
|
||||
(.Temporary = CheckState.Indeterminate Or user.Temporary = CBool(.Temporary)) And
|
||||
(.Favorite = CheckState.Indeterminate Or (user.Favorite = CBool(.Favorite))) And
|
||||
(Not UseReadyOption Or .ReadyForDownloadIgnore Or user.ReadyForDownload = .ReadyForDownload) And CheckUserExists.Invoke(user)
|
||||
Dim CheckSubscription As Predicate(Of IUserData) = Function(ByVal user As IUserData) As Boolean
|
||||
If .Subscriptions Then
|
||||
If .SubscriptionsOnly Then
|
||||
Return user.IsSubscription = True
|
||||
Else
|
||||
Return True
|
||||
End If
|
||||
Dim CheckUserCategory As Predicate(Of IUserData) = Function(ByVal user As IUserData) As Boolean
|
||||
If user.Favorite Then
|
||||
Return .Favorite
|
||||
ElseIf user.Temporary Then
|
||||
Return .Temporary
|
||||
Else
|
||||
Return user.IsSubscription = False
|
||||
Return .Regular
|
||||
End If
|
||||
End Function
|
||||
Dim CheckParams As Predicate(Of IUserData) = Function(user) _
|
||||
CheckUserCategory.Invoke(user) And
|
||||
(.ReadyForDownloadIgnore Or user.ReadyForDownload = .ReadyForDownload) And CheckUserExists.Invoke(user)
|
||||
Dim CheckSubscription As Predicate(Of IUserData) = Function(user) (.DownloadSubscriptions And user.IsSubscription) Or
|
||||
(.DownloadUsers And Not user.IsSubscription)
|
||||
Dim CheckLabelsExcluded As Predicate(Of IUserData) = Function(ByVal user As IUserData) As Boolean
|
||||
If .LabelsExcluded.Count = 0 Then
|
||||
Return True
|
||||
ElseIf user.Labels.Count = 0 Then
|
||||
Return True
|
||||
If Not .LabelsExcludedIgnore Then
|
||||
If .LabelsExcluded.Count = 0 Then
|
||||
Return True
|
||||
ElseIf user.Labels.Count = 0 Then
|
||||
Return True
|
||||
Else
|
||||
Return Not user.Labels.ListContains(.LabelsExcluded)
|
||||
End If
|
||||
Else
|
||||
Return Not user.Labels.ListContains(.LabelsExcluded)
|
||||
Return True
|
||||
End If
|
||||
End Function
|
||||
Dim CheckLabels As Predicate(Of IUserData) = Function(ByVal user As IUserData) As Boolean
|
||||
If .Labels.Count = 0 Then
|
||||
If .LabelsNo Then
|
||||
Return user.Labels.Count = 0
|
||||
ElseIf .Labels.Count = 0 Then
|
||||
Return CheckLabelsExcluded.Invoke(user)
|
||||
ElseIf user.Labels.Count = 0 Then
|
||||
Return False
|
||||
@@ -189,19 +331,42 @@ Namespace DownloadObjects.Groups
|
||||
Return user.Labels.ListContains(.Labels) And CheckLabelsExcluded.Invoke(user)
|
||||
End If
|
||||
End Function
|
||||
Dim CheckDays As Predicate(Of IUserData) = Function(ByVal user As IUserData) As Boolean
|
||||
If downDate.HasValue Then
|
||||
Dim ld As Date? = DirectCast(user, UserDataBase).LastUpdated
|
||||
If .DaysIsDownloaded Then
|
||||
Return ld.HasValue AndAlso ld.Value >= downDate.Value
|
||||
Else
|
||||
Return Not ld.HasValue OrElse ld.Value < downDate.Value
|
||||
End If
|
||||
Else
|
||||
Return True
|
||||
End If
|
||||
End Function
|
||||
Dim CheckDateRange As Predicate(Of IUserData) =
|
||||
Function(ByVal user As IUserData) As Boolean
|
||||
If Not .DateMode = ShowingDates.Off Then
|
||||
Dim ld As Date? = DirectCast(user, UserDataBase).LastUpdated
|
||||
If ld.HasValue Then
|
||||
Dim df As Date = If(.DateFrom, Date.MinValue.Date)
|
||||
Dim dt As Date = If(.DateTo, Date.MaxValue.Date)
|
||||
Return ld.Value.ValueBetween(df, dt) = (.DateMode = ShowingDates.In)
|
||||
End If
|
||||
End If
|
||||
Return True
|
||||
End Function
|
||||
Dim CheckSites As Predicate(Of IUserData) = Function(user) _
|
||||
(.Sites.Count = 0 OrElse .Sites.Contains(user.Site)) AndAlso
|
||||
(.SitesExcluded.Count = 0 OrElse Not .SitesExcluded.Contains(user.Site))
|
||||
Dim users As IEnumerable(Of IUserData) =
|
||||
Settings.GetUsers(Function(user) CheckLabels.Invoke(user) AndAlso CheckSites.Invoke(user) AndAlso
|
||||
CheckParams.Invoke(user) AndAlso CheckSubscription.Invoke(user))
|
||||
If .UsersCount = 0 Or Not users.ListExists Then
|
||||
Return users
|
||||
Else
|
||||
CheckParams.Invoke(user) AndAlso CheckSubscription.Invoke(user) AndAlso
|
||||
CheckDays.Invoke(user) AndAlso CheckDateRange.Invoke(user))
|
||||
If .UsersCount <> 0 And users.ListExists Then
|
||||
users = users.ListTake(If(.UsersCount > 0, -1, -2), Math.Abs(.UsersCount))
|
||||
If .UsersCount < 0 Then users = users.ListReverse
|
||||
Return users
|
||||
End If
|
||||
Return users
|
||||
End With
|
||||
Else
|
||||
Return Nothing
|
||||
@@ -212,16 +377,14 @@ Namespace DownloadObjects.Groups
|
||||
End Function
|
||||
#End Region
|
||||
#Region "Download users"
|
||||
Friend Sub DownloadUsers(Optional ByVal IncludeInTheFeed As Boolean = True, Optional ByVal UseReadyOption As Boolean = True,
|
||||
Optional ByVal IncludeNonExistentUsers As Boolean = False,
|
||||
Optional ByVal OnlyNonExistentUsers As Boolean = False)
|
||||
Friend Sub ProcessDownloadUsers(Optional ByVal IncludeInTheFeed As Boolean = True, Optional ByVal ShowNoUsersMessage As Boolean = True)
|
||||
Try
|
||||
If Settings.Users.Count > 0 Then
|
||||
Dim u As IEnumerable(Of IUserData) = GetUsers(Me, UseReadyOption, IncludeNonExistentUsers, OnlyNonExistentUsers)
|
||||
Dim u As IEnumerable(Of IUserData) = GetUsers(Me)
|
||||
If u.ListExists Then
|
||||
Downloader.AddRange(u, IncludeInTheFeed)
|
||||
Else
|
||||
MsgBoxE({$"No users found for group [{Name}].", "No users found"}, vbExclamation)
|
||||
ElseIf ShowNoUsersMessage Then
|
||||
MsgBoxE({$"No users found{If(Not Name.IsEmptyString, $" in group '{Name}'", String.Empty)}!", "No users found"}, vbExclamation)
|
||||
End If
|
||||
End If
|
||||
Catch ex As Exception
|
||||
@@ -245,19 +408,41 @@ Namespace DownloadObjects.Groups
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "IEContainerProvider Support"
|
||||
Private Function ToEContainer(Optional ByVal e As ErrorsDescriber = Nothing) As EContainer Implements IEContainerProvider.ToEContainer
|
||||
Friend Function ToEContainer(Optional ByVal e As ErrorsDescriber = Nothing) As EContainer Implements IEContainerProvider.ToEContainer
|
||||
Return Export(New EContainer("Group"))
|
||||
End Function
|
||||
#End Region
|
||||
#Region "IComparable Support"
|
||||
Private Function CompareTo(ByVal Other As DownloadGroup) As Integer Implements IComparable(Of DownloadGroup).CompareTo
|
||||
If IsViewFilter Then
|
||||
Return IIf(Other.IsViewFilter, Name.CompareTo(Other.Name), 1)
|
||||
ElseIf Other.IsViewFilter Then
|
||||
Return -1
|
||||
Else
|
||||
Return Index.CompareTo(Other.Index)
|
||||
End If
|
||||
End Function
|
||||
#End Region
|
||||
#Region "IDisposable Support"
|
||||
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
|
||||
If Not disposedValue And disposing Then
|
||||
BTT_DELETE.Dispose()
|
||||
BTT_EDIT.Dispose()
|
||||
BTT_MENU.Dispose()
|
||||
SEP_1.Dispose()
|
||||
BTT_DOWNLOAD.Dispose()
|
||||
BTT_DOWNLOAD_FULL.Dispose()
|
||||
If Not disposedValue Then
|
||||
If disposing Then
|
||||
BTT_EDIT.DisposeIfReady
|
||||
BTT_DELETE.DisposeIfReady
|
||||
BTT_DOWNLOAD.DisposeIfReady
|
||||
BTT_CLONE_ADD.DisposeIfReady
|
||||
BTT_CLONE_TEMP.DisposeIfReady
|
||||
SEP_1.DisposeIfReady
|
||||
SEP_2.DisposeIfReady
|
||||
If Not BTT_MENU Is Nothing Then BTT_MENU.DropDownItems.Clear()
|
||||
BTT_MENU.DisposeIfReady
|
||||
End If
|
||||
BTT_EDIT = Nothing
|
||||
BTT_DELETE = Nothing
|
||||
BTT_DOWNLOAD = Nothing
|
||||
BTT_CLONE_ADD = Nothing
|
||||
BTT_CLONE_TEMP = Nothing
|
||||
BTT_MENU = Nothing
|
||||
End If
|
||||
MyBase.Dispose(disposing)
|
||||
End Sub
|
||||
|
||||
@@ -10,11 +10,16 @@ Imports PersonalUtilities.Tools
|
||||
Imports PersonalUtilities.Functions.XML
|
||||
Namespace DownloadObjects.Groups
|
||||
Friend Class DownloadGroupCollection : Implements IEnumerable(Of DownloadGroup), IMyEnumerator(Of DownloadGroup)
|
||||
#Region "Events"
|
||||
Friend Event Deleted As DownloadGroup.GroupEventHandler
|
||||
Friend Event Added As DownloadGroup.GroupEventHandler
|
||||
Friend Event Updated As DownloadGroup.GroupEventHandler
|
||||
#End Region
|
||||
#Region "Declarations"
|
||||
Private ReadOnly GroupsList As List(Of DownloadGroup)
|
||||
Private ReadOnly GroupFile As SFile = "Settings\Groups.xml"
|
||||
#End Region
|
||||
#Region "Initializer"
|
||||
Friend Sub New()
|
||||
GroupsList = New List(Of DownloadGroup)
|
||||
If GroupFile.Exists Then
|
||||
@@ -32,8 +37,10 @@ Namespace DownloadObjects.Groups
|
||||
End If
|
||||
End With
|
||||
End If
|
||||
GroupsList.ListReindex
|
||||
Reindex()
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Base properties"
|
||||
Default Friend ReadOnly Property Item(ByVal Index As Integer) As DownloadGroup Implements IMyEnumerator(Of DownloadGroup).MyEnumeratorObject
|
||||
Get
|
||||
Return GroupsList(Index)
|
||||
@@ -44,59 +51,125 @@ Namespace DownloadObjects.Groups
|
||||
Return GroupsList.Count
|
||||
End Get
|
||||
End Property
|
||||
#End Region
|
||||
#Region "Update, BeginUpdate, EndUpdate"
|
||||
Friend Sub Update()
|
||||
If Count > 0 Then
|
||||
Using x As New XmlFile With {.Name = "Groups", .AllowSameNames = True} : x.AddRange(GroupsList) : x.Save(GroupFile) : End Using
|
||||
Else
|
||||
GroupFile.Delete()
|
||||
If Not _UpdateMode Then
|
||||
If Count > 0 Then
|
||||
Using x As New XmlFile With {.Name = "Groups", .AllowSameNames = True} : x.AddRange(GroupsList) : x.Save(GroupFile) : End Using
|
||||
Else
|
||||
GroupFile.Delete()
|
||||
End If
|
||||
End If
|
||||
End Sub
|
||||
Private _UpdateMode As Boolean = False
|
||||
Friend Sub BeginUpdate()
|
||||
_UpdateMode = True
|
||||
End Sub
|
||||
Friend Sub EndUpdate()
|
||||
_UpdateMode = False
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Sort, Reindex"
|
||||
Friend Sub Sort()
|
||||
GroupsList.Sort()
|
||||
End Sub
|
||||
Friend Sub Reindex()
|
||||
Dim initUpValue As Boolean = _UpdateMode
|
||||
BeginUpdate()
|
||||
GroupsList.ListReindex
|
||||
If Not initUpValue Then EndUpdate()
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Group handlers"
|
||||
Private _GroupAddInProgress As Boolean = False
|
||||
Private Sub OnGroupUpdated(ByVal Sender As DownloadGroup)
|
||||
If Not _GroupAddInProgress Then Update() : RaiseEvent Updated(Sender)
|
||||
If Not _GroupAddInProgress Then
|
||||
Update()
|
||||
If Not Sender.IsViewFilter Then RaiseEvent Updated(Sender)
|
||||
End If
|
||||
End Sub
|
||||
Private Sub OnGroupDeleted(ByVal Sender As DownloadGroup)
|
||||
RaiseEvent Deleted(Sender)
|
||||
If Not Sender.IsViewFilter Then RaiseEvent Deleted(Sender)
|
||||
Dim i% = GroupsList.FindIndex(Function(g) g.Key = Sender.Key)
|
||||
If i >= 0 Then
|
||||
GroupsList(i).Dispose()
|
||||
GroupsList.RemoveAt(i)
|
||||
GroupsList.ListReindex
|
||||
Reindex()
|
||||
Update()
|
||||
End If
|
||||
End Sub
|
||||
Friend Sub Add()
|
||||
Using f As New GroupEditorForm(Nothing)
|
||||
#End Region
|
||||
#Region "Add"
|
||||
Friend Sub CloneAndAdd(ByVal Group As DownloadGroup)
|
||||
Using f As New GroupEditorForm(Group.Copy) With {.IsClone = True}
|
||||
f.ShowDialog()
|
||||
If f.DialogResult = DialogResult.OK Then
|
||||
_GroupAddInProgress = True
|
||||
GroupsList.Add(f.MyGroup)
|
||||
With GroupsList.Last
|
||||
AddHandler .Deleted, AddressOf OnGroupDeleted
|
||||
AddHandler .Updated, AddressOf OnGroupUpdated
|
||||
End With
|
||||
GroupsList.ListReindex
|
||||
RaiseEvent Added(GroupsList.Last)
|
||||
Update()
|
||||
_GroupAddInProgress = False
|
||||
End If
|
||||
If f.DialogResult = DialogResult.OK Then Add(f.MyGroup)
|
||||
End Using
|
||||
End Sub
|
||||
Friend Function DownloadGroupIfExists(ByVal Index As Integer) As Boolean
|
||||
If Index.ValueBetween(0, Count - 1) Then Item(Index).DownloadUsers() : Return True Else Return False
|
||||
Friend Overloads Function Add() As Integer
|
||||
Using f As New GroupEditorForm(Nothing)
|
||||
f.ShowDialog()
|
||||
If f.DialogResult = DialogResult.OK Then Add(f.MyGroup) : Return IndexOf(f.MyGroup.Name)
|
||||
End Using
|
||||
Return -1
|
||||
End Function
|
||||
Friend Function IndexOf(ByVal Name As String) As Integer
|
||||
Friend Overloads Sub Add(ByVal Item As DownloadGroup, Optional ByVal IsFilter As Boolean = False, Optional ByVal ReplaceExisting As Boolean = False)
|
||||
Dim i% = IndexOf(Item.Name, IsFilter)
|
||||
Dim exists As Boolean = i >= 0
|
||||
_GroupAddInProgress = True
|
||||
|
||||
If exists Then
|
||||
If ReplaceExisting Then
|
||||
GroupsList(i).Dispose()
|
||||
GroupsList(i) = Item
|
||||
Else
|
||||
i = -1
|
||||
End If
|
||||
Else
|
||||
GroupsList.Add(Item)
|
||||
i = Count - 1
|
||||
End If
|
||||
|
||||
If i >= 0 Then
|
||||
With GroupsList(i)
|
||||
AddHandler .Deleted, AddressOf OnGroupDeleted
|
||||
AddHandler .Updated, AddressOf OnGroupUpdated
|
||||
If Not exists Then
|
||||
Reindex()
|
||||
GroupsList.Sort()
|
||||
Reindex()
|
||||
If Not Item.IsViewFilter And Not _UpdateMode Then RaiseEvent Added(.Self)
|
||||
Else
|
||||
If Not Item.IsViewFilter And Not _UpdateMode Then RaiseEvent Updated(.Self)
|
||||
End If
|
||||
End With
|
||||
Update()
|
||||
End If
|
||||
_GroupAddInProgress = False
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "DownloadGroupIfExists"
|
||||
Friend Function DownloadGroupIfExists(ByVal Index As Integer) As Boolean
|
||||
If Index.ValueBetween(0, Count - 1) Then Item(Index).ProcessDownloadUsers() : Return True Else Return False
|
||||
End Function
|
||||
#End Region
|
||||
#Region "IndexOf"
|
||||
Friend Function IndexOf(ByVal Name As String, Optional ByVal IsFilter As Boolean = False) As Integer
|
||||
If Count > 0 Then
|
||||
Return GroupsList.FindIndex(Function(g) g.Name = Name)
|
||||
Return GroupsList.FindIndex(Function(g) g.Name = Name And g.IsViewFilter = IsFilter)
|
||||
Else
|
||||
Return -1
|
||||
End If
|
||||
End Function
|
||||
#End Region
|
||||
#Region "IEnumerable Support"
|
||||
Private Function GetEnumerator() As IEnumerator(Of DownloadGroup) Implements IEnumerable(Of DownloadGroup).GetEnumerator
|
||||
Return New MyEnumerator(Of DownloadGroup)(Me)
|
||||
End Function
|
||||
Private Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
|
||||
Return GetEnumerator()
|
||||
End Function
|
||||
#End Region
|
||||
End Class
|
||||
End Namespace
|
||||
@@ -6,33 +6,64 @@
|
||||
'
|
||||
' This program is distributed in the hope that it will be useful,
|
||||
' but WITHOUT ANY WARRANTY
|
||||
Imports PersonalUtilities.Forms
|
||||
Imports PersonalUtilities.Forms.Controls
|
||||
Imports PersonalUtilities.Forms.Controls.Base
|
||||
Imports ADB = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons
|
||||
Namespace DownloadObjects.Groups
|
||||
Public Class GroupDefaults : Inherits TableLayoutPanel
|
||||
Private ReadOnly TP_1 As TableLayoutPanel
|
||||
Private ReadOnly TP_2 As TableLayoutPanel
|
||||
Private ReadOnly TP_3 As TableLayoutPanel
|
||||
#Region "Constants"
|
||||
Friend Const CaptionWidthDefault As Integer = 55
|
||||
#End Region
|
||||
#Region "Declarations"
|
||||
Private ReadOnly TP_1 As TableLayoutPanel 'CH_REGULAR, CH_TEMPORARY, CH_FAV
|
||||
Private ReadOnly TP_2 As TableLayoutPanel 'CH_READY_FOR_DOWN, CH_READY_FOR_DOWN_IGNORE
|
||||
Private ReadOnly TP_3 As TableLayoutPanel 'CH_USERS, CH_SUBSCRIPTIONS
|
||||
Private ReadOnly TP_4 As TableLayoutPanel 'CH_USER_EXISTS, CH_USER_SUSPENDED, CH_USER_DELETED
|
||||
Private ReadOnly TP_5 As TableLayoutPanel 'CH_LABELS_NO, CH_LABELS_EXCLUDED_IGNORE
|
||||
Private ReadOnly TP_6 As TableLayoutPanel 'CH_DATE_IN_RANGE, DT_FROM, DT_TO
|
||||
|
||||
Private ReadOnly CH_REGULAR As CheckBox
|
||||
Private ReadOnly CH_TEMPORARY As CheckBox
|
||||
Private ReadOnly CH_FAV As CheckBox
|
||||
|
||||
Private ReadOnly CH_READY_FOR_DOWN As CheckBox
|
||||
Private ReadOnly CH_READY_FOR_DOWN_IGNORE As CheckBox
|
||||
|
||||
Private ReadOnly CH_USERS As CheckBox
|
||||
Private ReadOnly CH_SUBSCRIPTIONS As CheckBox
|
||||
Private ReadOnly CH_SUBSCRIPTIONS_ONLY As CheckBox
|
||||
|
||||
Private ReadOnly CH_USER_EXISTS As CheckBox
|
||||
Private ReadOnly CH_USER_SUSPENDED As CheckBox
|
||||
Private ReadOnly CH_USER_DELETED As CheckBox
|
||||
|
||||
Private ReadOnly CH_LABELS_NO As CheckBox
|
||||
Private ReadOnly CH_LABELS_EXCLUDED_IGNORE As CheckBox
|
||||
|
||||
Private ReadOnly DT_FROM As TextBoxExtended
|
||||
Private ReadOnly DT_TO As TextBoxExtended
|
||||
Private ReadOnly CH_DATE_IN_RANGE As CheckBox
|
||||
|
||||
Private WithEvents NUM_USERS_COUNT As TextBoxExtended
|
||||
Private WithEvents NUM_DAYS As TextBoxExtended
|
||||
|
||||
Private WithEvents TXT_LABELS As TextBoxExtended
|
||||
Private WithEvents TXT_SITES As TextBoxExtended
|
||||
Friend WithEvents TXT_NAME As TextBoxExtended
|
||||
|
||||
Private ReadOnly Labels As List(Of String)
|
||||
Private ReadOnly LabelsExcluded As List(Of String)
|
||||
Private ReadOnly Sites As List(Of String)
|
||||
Private ReadOnly SitesExcluded As List(Of String)
|
||||
Private ReadOnly TT_MAIN As ToolTip
|
||||
#End Region
|
||||
#Region "Initializer"
|
||||
Public Sub New()
|
||||
Labels = New List(Of String)
|
||||
LabelsExcluded = New List(Of String)
|
||||
Sites = New List(Of String)
|
||||
SitesExcluded = New List(Of String)
|
||||
TT_MAIN = New ToolTip
|
||||
|
||||
InitTextBox(TXT_LABELS, "Labels", {New ActionButton(ADB.Edit) With {.ToolTipText = "Edit selected labels"},
|
||||
New ActionButton(ADB.Delete) With {.ToolTipText = "Edit excluded labels"}, ADB.Clear})
|
||||
@@ -44,19 +75,94 @@ Namespace DownloadObjects.Groups
|
||||
|
||||
InitTextBox(TXT_NAME, "Name", {ADB.Clear})
|
||||
|
||||
CH_TEMPORARY = New CheckBox With {.Text = "Temporary", .Name = "CH_TEMPORARY", .ThreeState = True, .CheckState = CheckState.Indeterminate, .Dock = DockStyle.Fill}
|
||||
CH_FAV = New CheckBox With {.Text = "Favorite", .Name = "CH_FAV", .ThreeState = True, .CheckState = CheckState.Indeterminate, .Dock = DockStyle.Fill}
|
||||
CH_READY_FOR_DOWN = New CheckBox With {.Text = "Ready for download", .Name = "CH_READY_FOR_DOWN", .Checked = True, .Dock = DockStyle.Fill}
|
||||
CH_READY_FOR_DOWN_IGNORE = New CheckBox With {.Text = "Ignore ready for download", .Name = "CH_READY_FOR_DOWN_IGNORE", .Checked = False, .Dock = DockStyle.Fill}
|
||||
CH_REGULAR = New CheckBox With {.Text = "Regular", .Name = "CH_REGULAR", .Checked = True, .Dock = DockStyle.Fill}
|
||||
TT_MAIN.SetToolTip(CH_REGULAR, "Users not marked as temporary or favorite")
|
||||
CH_TEMPORARY = New CheckBox With {.Text = "Temporary", .Name = "CH_TEMPORARY", .Checked = True, .Dock = DockStyle.Fill}
|
||||
TT_MAIN.SetToolTip(CH_TEMPORARY, "Users marked as temporary")
|
||||
CH_FAV = New CheckBox With {.Text = "Favorite", .Name = "CH_FAV", .Checked = True, .Dock = DockStyle.Fill}
|
||||
TT_MAIN.SetToolTip(CH_FAV, "Users marked as favorite")
|
||||
TP_1 = New TableLayoutPanel With {.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single, .Margin = New Padding(0), .Dock = DockStyle.Fill}
|
||||
FillTP(TP_1, CH_TEMPORARY, CH_FAV)
|
||||
FillTP(TP_1, CH_REGULAR, CH_TEMPORARY, CH_FAV)
|
||||
|
||||
CH_READY_FOR_DOWN = New CheckBox With {.Text = "Ready for download", .Name = "CH_READY_FOR_DOWN", .Checked = True, .Dock = DockStyle.Fill}
|
||||
TT_MAIN.SetToolTip(CH_READY_FOR_DOWN, "Users marked as 'Ready for download'")
|
||||
CH_READY_FOR_DOWN_IGNORE = New CheckBox With {.Text = "Ignore ready for download", .Name = "CH_READY_FOR_DOWN_IGNORE", .Checked = False, .Dock = DockStyle.Fill}
|
||||
TT_MAIN.SetToolTip(CH_READY_FOR_DOWN_IGNORE, "Ignore the 'Ready for download' mark")
|
||||
TP_2 = New TableLayoutPanel With {.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single, .Margin = New Padding(0), .Dock = DockStyle.Fill}
|
||||
FillTP(TP_2, CH_READY_FOR_DOWN, CH_READY_FOR_DOWN_IGNORE)
|
||||
|
||||
CH_USERS = New CheckBox With {.Text = "Users", .Name = "CH_USERS", .Checked = True, .Dock = DockStyle.Fill}
|
||||
TT_MAIN.SetToolTip(CH_USERS, "Download/filter users")
|
||||
CH_SUBSCRIPTIONS = New CheckBox With {.Text = "Subscriptions", .Name = "CH_SUBSCRIPTIONS", .Checked = False, .Dock = DockStyle.Fill}
|
||||
CH_SUBSCRIPTIONS_ONLY = New CheckBox With {.Text = "Subscriptions only", .Name = "CH_SUBSCRIPTIONS_ONLY", .Checked = False, .Dock = DockStyle.Fill}
|
||||
TT_MAIN.SetToolTip(CH_SUBSCRIPTIONS, "Download/filter subscriptions")
|
||||
TP_3 = New TableLayoutPanel With {.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single, .Margin = New Padding(0), .Dock = DockStyle.Fill}
|
||||
FillTP(TP_3, CH_SUBSCRIPTIONS, CH_SUBSCRIPTIONS_ONLY)
|
||||
FillTP(TP_3, CH_USERS, CH_SUBSCRIPTIONS)
|
||||
|
||||
CH_USER_EXISTS = New CheckBox With {.Text = "User exists", .Name = "CH_USER_EXISTS", .Checked = True, .Dock = DockStyle.Fill}
|
||||
TT_MAIN.SetToolTip(CH_USER_EXISTS, "Include users not marked as 'Suspended' or 'Deleted'")
|
||||
CH_USER_SUSPENDED = New CheckBox With {.Text = "User suspended", .Name = "CH_USER_SUSPENDED", .Checked = True, .Dock = DockStyle.Fill,
|
||||
.BackColor = MyColor.EditBack, .ForeColor = MyColor.EditFore}
|
||||
TT_MAIN.SetToolTip(CH_USER_SUSPENDED, "Include users marked as 'Suspended'")
|
||||
CH_USER_DELETED = New CheckBox With {.Text = "User deleted", .Name = "CH_USER_DELETED", .Checked = False, .Dock = DockStyle.Fill,
|
||||
.BackColor = MyColor.DeleteBack, .ForeColor = MyColor.DeleteFore}
|
||||
TT_MAIN.SetToolTip(CH_USER_DELETED, "Include users marked as 'Deleted'")
|
||||
TP_4 = New TableLayoutPanel With {.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single, .Margin = New Padding(0), .Dock = DockStyle.Fill}
|
||||
FillTP(TP_4, CH_USER_EXISTS, CH_USER_SUSPENDED, CH_USER_DELETED)
|
||||
|
||||
CH_LABELS_NO = New CheckBox With {.Text = "No labels", .Name = "CH_LABELS_NO", .Checked = False, .Dock = DockStyle.Fill}
|
||||
TT_MAIN.SetToolTip(CH_LABELS_NO, "Only users that have no labels at all." & vbCr & "If checked, the list of labels will be ignored!")
|
||||
CH_LABELS_EXCLUDED_IGNORE = New CheckBox With {.Text = "Ignore excluded labels", .Name = "CH_LABELS_EXCLUDED_IGNORE", .Checked = False, .Dock = DockStyle.Fill}
|
||||
TT_MAIN.SetToolTip(CH_LABELS_EXCLUDED_IGNORE, "Ignore excluded labels if they exist")
|
||||
TP_5 = New TableLayoutPanel With {.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single, .Margin = New Padding(0), .Dock = DockStyle.Fill}
|
||||
FillTP(TP_5, CH_LABELS_NO, CH_LABELS_EXCLUDED_IGNORE)
|
||||
|
||||
Dim initDtTxt As Action(Of TextBoxExtended, String, String) =
|
||||
Sub(ByVal cnt As TextBoxExtended, ByVal captionText As String, ByVal toolTip As String)
|
||||
With cnt
|
||||
.BeginInit()
|
||||
.CaptionText = captionText
|
||||
.CaptionToolTipText = toolTip
|
||||
.CaptionToolTipEnabled = True
|
||||
.CaptionWidth = 30
|
||||
.ControlMode = TextBoxExtended.ControlModes.DateTimePicker
|
||||
.DateShowCheckBox = True
|
||||
.DateMin = DateTimePicker.MinimumDateTime
|
||||
.DateMax = DateTimePicker.MaximumDateTime
|
||||
.DateChecked = False
|
||||
.DateShowUpDown = False
|
||||
.CaptionMargin = New PaddingE(.CaptionMargin).Add(, 1)
|
||||
.Dock = DockStyle.Fill
|
||||
.Value = Now.Date
|
||||
.EndInit()
|
||||
End With
|
||||
End Sub
|
||||
DT_FROM = New TextBoxExtended
|
||||
initDtTxt.Invoke(DT_FROM, "From", "Minimum date")
|
||||
DT_TO = New TextBoxExtended
|
||||
initDtTxt.Invoke(DT_TO, "To", "Maximum date")
|
||||
CH_DATE_IN_RANGE = New CheckBox With {.Text = "In range", .Name = "CH_DATE_IN_RANGE", .Checked = True, .Dock = DockStyle.Fill}
|
||||
TT_MAIN.SetToolTip(CH_DATE_IN_RANGE, "Last download date range." & vbCr &
|
||||
"If checked, filter users whose last download date is within the selected date range." & vbCr &
|
||||
"If unchecked, filter users whose last download date is outside the selected date range." & vbCr &
|
||||
"If no dates are checked, this option will be ignored.")
|
||||
CH_DATE_IN_RANGE.Margin = New PaddingE(CH_DATE_IN_RANGE.Margin).Add(, 2,, -2)
|
||||
TP_6 = New TableLayoutPanel With {.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single, .Margin = New Padding(0), .Dock = DockStyle.Fill}
|
||||
|
||||
With TP_6
|
||||
.ColumnCount = 3
|
||||
With .ColumnStyles
|
||||
.Add(New ColumnStyle(SizeType.Absolute, 80))
|
||||
.Add(New ColumnStyle(SizeType.Percent, 50))
|
||||
.Add(New ColumnStyle(SizeType.Percent, 50))
|
||||
End With
|
||||
.RowCount = 1
|
||||
.RowStyles.Add(New RowStyle(SizeType.Percent, 100))
|
||||
With .Controls
|
||||
.Add(CH_DATE_IN_RANGE, 0, 0)
|
||||
.Add(DT_FROM, 1, 0)
|
||||
.Add(DT_TO, 2, 0)
|
||||
End With
|
||||
End With
|
||||
|
||||
NUM_USERS_COUNT = New TextBoxExtended
|
||||
With NUM_USERS_COUNT
|
||||
@@ -67,7 +173,7 @@ Namespace DownloadObjects.Groups
|
||||
"Number greater than 0 = number of users from the beginning to the end of the list." & vbCr &
|
||||
"Number less than 0 = number of users from end to the beginning of the list."
|
||||
.CaptionToolTipEnabled = True
|
||||
.CaptionWidth = 50
|
||||
.CaptionWidth = CaptionWidthDefault
|
||||
.ControlMode = TextBoxExtended.ControlModes.NumericUpDown
|
||||
.NumberMinimum = Integer.MinValue
|
||||
.NumberMaximum = Integer.MaxValue
|
||||
@@ -78,6 +184,30 @@ Namespace DownloadObjects.Groups
|
||||
.Value = 0
|
||||
.EndInit()
|
||||
End With
|
||||
NUM_DAYS = New TextBoxExtended
|
||||
With NUM_DAYS
|
||||
.BeginInit()
|
||||
.CaptionText = "Down"
|
||||
.CaptionToolTipText = "Filter users who have been (not)downloaded in the last x days." & vbCr &
|
||||
"-1 to disable" & vbCr &
|
||||
"Checked = downloaded in the last x days" & vbCr &
|
||||
"Unchecked = NOT downloaded in the last x days"
|
||||
.CaptionToolTipEnabled = True
|
||||
.CaptionMode = ICaptionControl.Modes.CheckBox
|
||||
.CaptionCheckAlign = ContentAlignment.MiddleLeft
|
||||
.CaptionMargin = New PaddingE(.CaptionMargin).Add(1)
|
||||
.CaptionWidth = CaptionWidthDefault
|
||||
.ChangeControlsEnableOnCheckedChange = False
|
||||
.ControlMode = TextBoxExtended.ControlModes.NumericUpDown
|
||||
.NumberMinimum = -1
|
||||
.NumberMaximum = Integer.MaxValue
|
||||
.NumberUpDownAlign = LeftRightAlignment.Left
|
||||
.Dock = DockStyle.Fill
|
||||
.Buttons.Add(New ActionButton(ADB.Clear) With {.ToolTipText = "Reset value"})
|
||||
.ClearTextByButtonClear = False
|
||||
.Value = -1
|
||||
.EndInit()
|
||||
End With
|
||||
End Sub
|
||||
Private Sub InitTextBox(ByRef TXT As TextBoxExtended, ByVal Caption As String, ByVal Buttons As ActionButton())
|
||||
TXT = New TextBoxExtended
|
||||
@@ -85,48 +215,21 @@ Namespace DownloadObjects.Groups
|
||||
.BeginInit()
|
||||
.Buttons.AddRange(Buttons)
|
||||
.CaptionText = Caption
|
||||
.CaptionWidth = 50
|
||||
.CaptionWidth = CaptionWidthDefault
|
||||
.Dock = DockStyle.Fill
|
||||
.EndInit()
|
||||
End With
|
||||
End Sub
|
||||
Private Sub FillTP(ByRef TP As TableLayoutPanel, ByVal CNT1 As Control, ByVal CNT2 As Control)
|
||||
Private Sub FillTP(ByRef TP As TableLayoutPanel, ByVal ParamArray CNT As Control())
|
||||
With TP
|
||||
.ColumnCount = 2
|
||||
.ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 50))
|
||||
.ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 50))
|
||||
Dim i%
|
||||
.ColumnCount = CNT.Count
|
||||
For i = 0 To CNT.Count - 1 : .ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 50)) : Next
|
||||
.RowCount = 1
|
||||
.RowStyles.Add(New RowStyle(SizeType.Percent, 100))
|
||||
With .Controls : .Add(CNT1, 0, 0) : .Add(CNT2, 1, 0) : End With
|
||||
End With
|
||||
End Sub
|
||||
Private Sub GroupDefaults_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed
|
||||
Labels.Clear()
|
||||
CH_TEMPORARY.Dispose()
|
||||
CH_FAV.Dispose()
|
||||
CH_READY_FOR_DOWN.Dispose()
|
||||
CH_READY_FOR_DOWN_IGNORE.Dispose()
|
||||
CH_SUBSCRIPTIONS.Dispose()
|
||||
CH_SUBSCRIPTIONS_ONLY.Dispose()
|
||||
NUM_USERS_COUNT.Dispose()
|
||||
TXT_LABELS.Dispose()
|
||||
With TP_1
|
||||
.Controls.Clear()
|
||||
.RowStyles.Clear()
|
||||
.ColumnStyles.Clear()
|
||||
.Dispose()
|
||||
End With
|
||||
With TP_2
|
||||
.Controls.Clear()
|
||||
.RowStyles.Clear()
|
||||
.ColumnStyles.Clear()
|
||||
.Dispose()
|
||||
End With
|
||||
With TP_3
|
||||
.Controls.Clear()
|
||||
.RowStyles.Clear()
|
||||
.ColumnStyles.Clear()
|
||||
.Dispose()
|
||||
With .Controls
|
||||
For i = 0 To CNT.Count - 1 : .Add(CNT(i), i, 0) : Next
|
||||
End With
|
||||
End With
|
||||
End Sub
|
||||
Protected Overrides Sub InitLayout()
|
||||
@@ -137,25 +240,81 @@ Namespace DownloadObjects.Groups
|
||||
CellBorderStyle = TableLayoutPanelCellBorderStyle.Single
|
||||
ColumnCount = 1
|
||||
ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 100))
|
||||
RowCount = 9
|
||||
RowCount = 13
|
||||
RowStyles.Add(New RowStyle(SizeType.Absolute, 25))
|
||||
RowStyles.Add(New RowStyle(SizeType.Absolute, 28))
|
||||
RowStyles.Add(New RowStyle(SizeType.Absolute, 25))
|
||||
RowStyles.Add(New RowStyle(SizeType.Absolute, 25))
|
||||
RowStyles.Add(New RowStyle(SizeType.Absolute, 25))
|
||||
RowStyles.Add(New RowStyle(SizeType.Absolute, 25))
|
||||
RowStyles.Add(New RowStyle(SizeType.Absolute, 25))
|
||||
RowStyles.Add(New RowStyle(SizeType.Absolute, 28))
|
||||
RowStyles.Add(New RowStyle(SizeType.Absolute, 28))
|
||||
RowStyles.Add(New RowStyle(SizeType.Absolute, 25))
|
||||
RowStyles.Add(New RowStyle(SizeType.Absolute, 28))
|
||||
RowStyles.Add(New RowStyle(SizeType.Absolute, 28))
|
||||
RowStyles.Add(New RowStyle(SizeType.Percent, 100))
|
||||
End If
|
||||
Controls.Add(TXT_NAME, 0, 1)
|
||||
Controls.Add(TP_1, 0, 2)
|
||||
Controls.Add(TP_2, 0, 3)
|
||||
Controls.Add(TP_3, 0, 4)
|
||||
Controls.Add(NUM_USERS_COUNT, 0, 5)
|
||||
Controls.Add(TXT_LABELS, 0, 6)
|
||||
Controls.Add(TXT_SITES, 0, 7)
|
||||
Controls.Add(TP_4, 0, 3)
|
||||
Controls.Add(TP_2, 0, 4)
|
||||
Controls.Add(TP_3, 0, 5)
|
||||
Controls.Add(TP_6, 0, 6)
|
||||
|
||||
Controls.Add(NUM_DAYS, 0, 5)
|
||||
Controls.Add(NUM_USERS_COUNT, 0, 8)
|
||||
|
||||
Controls.Add(TP_5, 0, 9)
|
||||
|
||||
Controls.Add(TXT_LABELS, 0, 10)
|
||||
Controls.Add(TXT_SITES, 0, 11)
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Control handlers"
|
||||
Private Sub GroupDefaults_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed
|
||||
Labels.Clear()
|
||||
LabelsExcluded.Clear()
|
||||
Sites.Clear()
|
||||
SitesExcluded.Clear()
|
||||
CH_REGULAR.Dispose()
|
||||
CH_TEMPORARY.Dispose()
|
||||
CH_FAV.Dispose()
|
||||
CH_READY_FOR_DOWN.Dispose()
|
||||
CH_READY_FOR_DOWN_IGNORE.Dispose()
|
||||
CH_USERS.Dispose()
|
||||
CH_SUBSCRIPTIONS.Dispose()
|
||||
CH_USER_EXISTS.Dispose()
|
||||
CH_USER_SUSPENDED.Dispose()
|
||||
CH_USER_DELETED.Dispose()
|
||||
CH_LABELS_NO.Dispose()
|
||||
CH_LABELS_EXCLUDED_IGNORE.Dispose()
|
||||
DT_FROM.Dispose()
|
||||
DT_TO.Dispose()
|
||||
CH_DATE_IN_RANGE.Dispose()
|
||||
NUM_USERS_COUNT.Dispose()
|
||||
NUM_DAYS.Dispose()
|
||||
TXT_LABELS.Dispose()
|
||||
TXT_SITES.Dispose()
|
||||
TXT_NAME.Dispose()
|
||||
TT_MAIN.Dispose()
|
||||
ClearTP(TP_1)
|
||||
ClearTP(TP_2)
|
||||
ClearTP(TP_3)
|
||||
ClearTP(TP_4)
|
||||
ClearTP(TP_5)
|
||||
ClearTP(TP_6)
|
||||
End Sub
|
||||
Private Sub ClearTP(ByRef TP As TableLayoutPanel)
|
||||
With TP
|
||||
.Controls.Clear()
|
||||
.RowStyles.Clear()
|
||||
.ColumnStyles.Clear()
|
||||
.Dispose()
|
||||
End With
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Controls"
|
||||
Friend Sub HideName()
|
||||
Controls.Remove(TXT_NAME)
|
||||
RowStyles(1).Height = 0
|
||||
@@ -163,6 +322,9 @@ Namespace DownloadObjects.Groups
|
||||
Private Sub NUM_USERS_COUNT_ActionOnButtonClick(ByVal Sender As ActionButton, ByVal e As ActionButtonEventArgs) Handles NUM_USERS_COUNT.ActionOnButtonClick
|
||||
If Sender.DefaultButton = ADB.Clear Then NUM_USERS_COUNT.Value = 0
|
||||
End Sub
|
||||
Private Sub NUM_DAYS_ActionOnButtonClick(ByVal Sender As ActionButton, ByVal e As ActionButtonEventArgs) Handles NUM_DAYS.ActionOnButtonClick
|
||||
If Sender.DefaultButton = ADB.Clear Then NUM_DAYS.Value = -1
|
||||
End Sub
|
||||
Private Sub TXT_LABELS_ActionOnButtonClick(ByVal Sender As ActionButton, ByVal e As ActionButtonEventArgs) Handles TXT_LABELS.ActionOnButtonClick
|
||||
Select Case Sender.DefaultButton
|
||||
Case ADB.Edit, ADB.Delete
|
||||
@@ -205,17 +367,41 @@ Namespace DownloadObjects.Groups
|
||||
If Not _JustExcludeOptions Then TXT_SITES.Text = Sites.ListToString
|
||||
If SitesExcluded.Count > 0 Then TXT_SITES.Text.StringAppend($"EXCLUDED: {SitesExcluded.ListToString}", "; ")
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Get/set"
|
||||
Friend Sub [Get](ByRef Instance As IGroup)
|
||||
If Not Instance Is Nothing Then
|
||||
With Instance
|
||||
.Name = TXT_NAME.Text
|
||||
.Temporary = CH_TEMPORARY.CheckState
|
||||
.Favorite = CH_FAV.CheckState
|
||||
.Regular = CH_REGULAR.Checked
|
||||
.Temporary = CH_TEMPORARY.Checked
|
||||
.Favorite = CH_FAV.Checked
|
||||
.ReadyForDownload = CH_READY_FOR_DOWN.Checked
|
||||
.ReadyForDownloadIgnore = CH_READY_FOR_DOWN_IGNORE.Checked
|
||||
.Subscriptions = CH_SUBSCRIPTIONS.Checked
|
||||
.SubscriptionsOnly = CH_SUBSCRIPTIONS_ONLY.Checked
|
||||
.DownloadUsers = CH_USERS.Checked
|
||||
.DownloadSubscriptions = CH_SUBSCRIPTIONS.Checked
|
||||
.UsersCount = NUM_USERS_COUNT.Value
|
||||
.DaysNumber = NUM_DAYS.Value
|
||||
.DaysIsDownloaded = NUM_DAYS.Checked
|
||||
.UserDeleted = CH_USER_DELETED.Checked
|
||||
.UserSuspended = CH_USER_SUSPENDED.Checked
|
||||
.UserExists = CH_USER_EXISTS.Checked
|
||||
|
||||
If DT_FROM.DateChecked Then .DateFrom = DT_FROM.Date.Date Else .DateFrom = Nothing
|
||||
If DT_TO.DateChecked Then
|
||||
With DT_TO.Date.Date : Instance.DateTo = New Date(.Year, .Month, .Day, 23, 59, 59) : End With
|
||||
Else
|
||||
.DateTo = Nothing
|
||||
End If
|
||||
If .DateFrom.HasValue Or .DateTo.HasValue Then
|
||||
.DateMode = If(CH_DATE_IN_RANGE.Checked, ShowingDates.In, ShowingDates.Not)
|
||||
Else
|
||||
.DateMode = ShowingDates.Off
|
||||
End If
|
||||
|
||||
.LabelsNo = CH_LABELS_NO.Checked
|
||||
.LabelsExcludedIgnore = CH_LABELS_EXCLUDED_IGNORE.Checked
|
||||
|
||||
.Labels.Clear()
|
||||
.Labels.ListAddList(Labels)
|
||||
.LabelsExcluded.Clear()
|
||||
@@ -231,13 +417,38 @@ Namespace DownloadObjects.Groups
|
||||
If Not Instance Is Nothing Then
|
||||
With Instance
|
||||
TXT_NAME.Text = .Name
|
||||
CH_TEMPORARY.CheckState = .Temporary
|
||||
CH_FAV.CheckState = .Favorite
|
||||
CH_REGULAR.Checked = .Regular
|
||||
CH_TEMPORARY.Checked = .Temporary
|
||||
CH_FAV.Checked = .Favorite
|
||||
CH_READY_FOR_DOWN.Checked = .ReadyForDownload
|
||||
CH_READY_FOR_DOWN_IGNORE.Checked = .ReadyForDownloadIgnore
|
||||
CH_SUBSCRIPTIONS.Checked = .Subscriptions
|
||||
CH_SUBSCRIPTIONS_ONLY.Checked = .SubscriptionsOnly
|
||||
CH_USERS.Checked = .DownloadUsers
|
||||
CH_SUBSCRIPTIONS.Checked = .DownloadSubscriptions
|
||||
NUM_USERS_COUNT.Value = .UsersCount
|
||||
NUM_DAYS.Value = .DaysNumber
|
||||
NUM_DAYS.Checked = .DaysIsDownloaded
|
||||
CH_USER_DELETED.Checked = .UserDeleted
|
||||
CH_USER_SUSPENDED.Checked = .UserSuspended
|
||||
CH_USER_EXISTS.Checked = .UserExists
|
||||
|
||||
If .DateFrom.HasValue Then
|
||||
DT_FROM.DateChecked = True
|
||||
DT_FROM.Value = .DateFrom.Value
|
||||
Else
|
||||
DT_FROM.DateChecked = False
|
||||
DT_FROM.Value = Now.Date
|
||||
End If
|
||||
If .DateTo.HasValue Then
|
||||
DT_TO.DateChecked = True
|
||||
DT_TO.Value = .DateTo.Value
|
||||
Else
|
||||
DT_TO.DateChecked = False
|
||||
DT_TO.Value = Now.Date
|
||||
End If
|
||||
CH_DATE_IN_RANGE.Checked = .DateMode = ShowingDates.In
|
||||
|
||||
CH_LABELS_NO.Checked = .LabelsNo
|
||||
CH_LABELS_EXCLUDED_IGNORE.Checked = .LabelsExcludedIgnore
|
||||
|
||||
Labels.ListAddList(.Labels)
|
||||
LabelsExcluded.ListAddList(.LabelsExcluded)
|
||||
@@ -249,10 +460,11 @@ Namespace DownloadObjects.Groups
|
||||
End With
|
||||
End If
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Enabled"
|
||||
Private _Enabled As Boolean = True
|
||||
Private _JustExcludeOptions As Boolean = False
|
||||
Friend Overloads Property Enabled(Optional ByVal LeaveExcludeOptions As Boolean = False,
|
||||
Optional ByVal LeaveSubscriptionsAndUsersCount As Boolean = False) As Boolean
|
||||
Friend Overloads Property Enabled() As Boolean
|
||||
Get
|
||||
Return _Enabled
|
||||
End Get
|
||||
@@ -261,29 +473,18 @@ Namespace DownloadObjects.Groups
|
||||
_JustExcludeOptions = False
|
||||
TP_1.Enabled = e
|
||||
TP_2.Enabled = e
|
||||
TP_3.Enabled = e Or LeaveSubscriptionsAndUsersCount
|
||||
NUM_USERS_COUNT.Enabled = e Or LeaveSubscriptionsAndUsersCount
|
||||
If e Then
|
||||
TXT_LABELS.Enabled = True
|
||||
TXT_SITES.Enabled = True
|
||||
ElseIf LeaveExcludeOptions Then
|
||||
_JustExcludeOptions = True
|
||||
TXT_LABELS.Enabled = True
|
||||
TXT_LABELS.Button(ADB.Edit).Enabled = False
|
||||
TXT_LABELS.Button(ADB.Delete).Enabled = True
|
||||
TXT_LABELS.Button(ADB.Clear).Enabled = False
|
||||
|
||||
TXT_SITES.Enabled = True
|
||||
TXT_SITES.Button(ADB.Edit).Enabled = False
|
||||
TXT_SITES.Button(ADB.Delete).Enabled = True
|
||||
TXT_SITES.Button(ADB.Clear).Enabled = False
|
||||
Else
|
||||
TXT_LABELS.Enabled = False
|
||||
TXT_SITES.Enabled = False
|
||||
End If
|
||||
TP_3.Enabled = e
|
||||
TP_4.Enabled = e
|
||||
TP_5.Enabled = e
|
||||
TP_6.Enabled = e
|
||||
NUM_USERS_COUNT.Enabled = e
|
||||
NUM_DAYS.Enabled = e
|
||||
TXT_LABELS.Enabled = e
|
||||
TXT_SITES.Enabled = e
|
||||
UpdateLabelsText()
|
||||
UpdateSitesText()
|
||||
End Set
|
||||
End Property
|
||||
#End Region
|
||||
End Class
|
||||
End Namespace
|
||||
18
SCrawler/Download/Groups/GroupEditorForm.Designer.vb
generated
@@ -35,13 +35,13 @@ Namespace DownloadObjects.Groups
|
||||
'CONTAINER_MAIN.ContentPanel
|
||||
'
|
||||
CONTAINER_MAIN.ContentPanel.Controls.Add(Me.DEFS_GROUP)
|
||||
CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(476, 196)
|
||||
CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(476, 328)
|
||||
CONTAINER_MAIN.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
CONTAINER_MAIN.LeftToolStripPanelVisible = False
|
||||
CONTAINER_MAIN.Location = New System.Drawing.Point(0, 0)
|
||||
CONTAINER_MAIN.Name = "CONTAINER_MAIN"
|
||||
CONTAINER_MAIN.RightToolStripPanelVisible = False
|
||||
CONTAINER_MAIN.Size = New System.Drawing.Size(476, 221)
|
||||
CONTAINER_MAIN.Size = New System.Drawing.Size(476, 328)
|
||||
CONTAINER_MAIN.TabIndex = 0
|
||||
CONTAINER_MAIN.TopToolStripPanelVisible = False
|
||||
'
|
||||
@@ -53,32 +53,36 @@ Namespace DownloadObjects.Groups
|
||||
Me.DEFS_GROUP.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.DEFS_GROUP.Location = New System.Drawing.Point(0, 0)
|
||||
Me.DEFS_GROUP.Name = "DEFS_GROUP"
|
||||
Me.DEFS_GROUP.RowCount = 9
|
||||
Me.DEFS_GROUP.RowCount = 13
|
||||
Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 0!))
|
||||
Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
|
||||
Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||
Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||
Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||
Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||
Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||
Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
|
||||
Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
|
||||
Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
|
||||
Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
|
||||
Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!))
|
||||
Me.DEFS_GROUP.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
|
||||
Me.DEFS_GROUP.Size = New System.Drawing.Size(476, 196)
|
||||
Me.DEFS_GROUP.Size = New System.Drawing.Size(476, 328)
|
||||
Me.DEFS_GROUP.TabIndex = 0
|
||||
'
|
||||
'GroupEditorForm
|
||||
'
|
||||
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
|
||||
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
|
||||
Me.ClientSize = New System.Drawing.Size(476, 221)
|
||||
Me.ClientSize = New System.Drawing.Size(476, 328)
|
||||
Me.Controls.Add(CONTAINER_MAIN)
|
||||
Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle
|
||||
Me.Icon = Global.SCrawler.My.Resources.Resources.GroupByIcon_16
|
||||
Me.KeyPreview = True
|
||||
Me.MaximizeBox = False
|
||||
Me.MaximumSize = New System.Drawing.Size(492, 260)
|
||||
Me.MaximumSize = New System.Drawing.Size(492, 367)
|
||||
Me.MinimizeBox = False
|
||||
Me.MinimumSize = New System.Drawing.Size(492, 260)
|
||||
Me.MinimumSize = New System.Drawing.Size(492, 367)
|
||||
Me.Name = "GroupEditorForm"
|
||||
Me.ShowInTaskbar = False
|
||||
Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide
|
||||
|
||||
@@ -13,6 +13,8 @@ Namespace DownloadObjects.Groups
|
||||
Friend Property MyGroup As DownloadGroup
|
||||
Friend Property DownloadMode As Boolean = False
|
||||
Friend Property FilterMode As Boolean = False
|
||||
Friend Property IsTemporaryGroup As Boolean = False
|
||||
Friend Property IsClone As Boolean
|
||||
Friend Sub New(ByRef g As DownloadGroup)
|
||||
InitializeComponent()
|
||||
MyGroup = g
|
||||
@@ -60,7 +62,7 @@ Namespace DownloadObjects.Groups
|
||||
Text = "New Group"
|
||||
End If
|
||||
.MyFieldsChecker = New FieldsChecker
|
||||
If DownloadMode Or FilterMode Then
|
||||
If DownloadMode Or FilterMode Or IsTemporaryGroup Then
|
||||
DEFS_GROUP.HideName()
|
||||
Dim s As Size = Size
|
||||
s.Height -= 31
|
||||
@@ -71,15 +73,28 @@ Namespace DownloadObjects.Groups
|
||||
MaximumSize = s
|
||||
Else
|
||||
.MyFieldsCheckerE.AddControl(Of String)(DEFS_GROUP.TXT_NAME, DEFS_GROUP.TXT_NAME.CaptionText,,
|
||||
New NameChecker(If(MyGroup?.Name, String.Empty), Settings.Groups, "Group"))
|
||||
New NameChecker(If(Not IsClone, If(MyGroup?.Name, String.Empty), String.Empty), Settings.Groups, "Group"))
|
||||
End If
|
||||
.MyFieldsChecker.EndLoaderOperations()
|
||||
.EndLoaderOperations()
|
||||
.MyOkCancel.EnableOK = True
|
||||
End With
|
||||
End Sub
|
||||
Private Sub GroupEditorForm_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
|
||||
Try
|
||||
If e = ShowUsersButtonKey Then
|
||||
Using g As New GroupParameters
|
||||
DEFS_GROUP.Get(g)
|
||||
GroupUsersViewer.Show(DownloadGroup.GetUsers(g), $"{IIf(FilterMode, "F", "G")} {g.Name}")
|
||||
End Using
|
||||
End If
|
||||
Catch ex As Exception
|
||||
ErrorsDescriber.Execute(EDP.LogMessageValue, ex, "Show plan users")
|
||||
End Try
|
||||
End Sub
|
||||
Private Sub MyDefs_ButtonOkClick(ByVal Sender As Object, ByVal e As KeyHandleEventArgs) Handles MyDefs.ButtonOkClick
|
||||
If MyDefs.MyFieldsChecker.AllParamsOK Then
|
||||
If MyGroup Is Nothing Then MyGroup = New DownloadGroup
|
||||
If MyGroup Is Nothing Then MyGroup = New DownloadGroup(Not FilterMode)
|
||||
With MyGroup
|
||||
.NameBefore = .Name
|
||||
DEFS_GROUP.Get(MyGroup)
|
||||
|
||||
78
SCrawler/Download/Groups/GroupListForm.Designer.vb
generated
Normal file
@@ -0,0 +1,78 @@
|
||||
' 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 DownloadObjects.Groups
|
||||
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()>
|
||||
Partial Friend Class GroupListForm : 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()
|
||||
Me.CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer()
|
||||
Me.LIST_GROUPS = New System.Windows.Forms.ListBox()
|
||||
Me.CONTAINER_MAIN.ContentPanel.SuspendLayout()
|
||||
Me.CONTAINER_MAIN.SuspendLayout()
|
||||
Me.SuspendLayout()
|
||||
'
|
||||
'CONTAINER_MAIN
|
||||
'
|
||||
Me.CONTAINER_MAIN.BottomToolStripPanelVisible = False
|
||||
'
|
||||
'CONTAINER_MAIN.ContentPanel
|
||||
'
|
||||
Me.CONTAINER_MAIN.ContentPanel.Controls.Add(Me.LIST_GROUPS)
|
||||
Me.CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(284, 236)
|
||||
Me.CONTAINER_MAIN.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.CONTAINER_MAIN.LeftToolStripPanelVisible = False
|
||||
Me.CONTAINER_MAIN.Location = New System.Drawing.Point(0, 0)
|
||||
Me.CONTAINER_MAIN.Name = "CONTAINER_MAIN"
|
||||
Me.CONTAINER_MAIN.RightToolStripPanelVisible = False
|
||||
Me.CONTAINER_MAIN.Size = New System.Drawing.Size(284, 261)
|
||||
Me.CONTAINER_MAIN.TabIndex = 0
|
||||
'
|
||||
'LIST_GROUPS
|
||||
'
|
||||
Me.LIST_GROUPS.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.LIST_GROUPS.FormattingEnabled = True
|
||||
Me.LIST_GROUPS.Location = New System.Drawing.Point(0, 0)
|
||||
Me.LIST_GROUPS.Name = "LIST_GROUPS"
|
||||
Me.LIST_GROUPS.Size = New System.Drawing.Size(284, 236)
|
||||
Me.LIST_GROUPS.TabIndex = 0
|
||||
'
|
||||
'GroupListForm
|
||||
'
|
||||
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
|
||||
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
|
||||
Me.ClientSize = New System.Drawing.Size(284, 261)
|
||||
Me.Controls.Add(Me.CONTAINER_MAIN)
|
||||
Me.Icon = Global.SCrawler.My.Resources.Resources.GroupByIcon_16
|
||||
Me.KeyPreview = True
|
||||
Me.MinimumSize = New System.Drawing.Size(300, 300)
|
||||
Me.Name = "GroupListForm"
|
||||
Me.ShowInTaskbar = False
|
||||
Me.Text = "Groups"
|
||||
Me.CONTAINER_MAIN.ContentPanel.ResumeLayout(False)
|
||||
Me.CONTAINER_MAIN.ResumeLayout(False)
|
||||
Me.CONTAINER_MAIN.PerformLayout()
|
||||
Me.ResumeLayout(False)
|
||||
|
||||
End Sub
|
||||
|
||||
Private WithEvents LIST_GROUPS As ListBox
|
||||
Private WithEvents CONTAINER_MAIN As ToolStripContainer
|
||||
End Class
|
||||
End Namespace
|
||||
120
SCrawler/Download/Groups/GroupListForm.resx
Normal file
@@ -0,0 +1,120 @@
|
||||
<?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>
|
||||
</root>
|
||||
346
SCrawler/Download/Groups/GroupListForm.vb
Normal file
@@ -0,0 +1,346 @@
|
||||
' 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 System.ComponentModel
|
||||
Imports System.Collections.ObjectModel
|
||||
Imports PersonalUtilities.Forms
|
||||
Imports PersonalUtilities.Forms.Toolbars
|
||||
Imports ECI = PersonalUtilities.Forms.Toolbars.EditToolbar.ControlItem
|
||||
Namespace DownloadObjects.Groups
|
||||
Friend Class GroupListForm
|
||||
#Region "Declarations"
|
||||
Private WithEvents MyDefs As DefaultFormOptions
|
||||
Private ReadOnly IsViewFilter As Boolean
|
||||
Private WithEvents BTT_MOVE_UP As ToolStripButton
|
||||
Private WithEvents BTT_MOVE_DOWN As ToolStripButton
|
||||
Private WithEvents BTT_DOWNLOAD As ToolStripKeyMenuItem
|
||||
Private ReadOnly MyGroups As ObservableCollection(Of String)
|
||||
Private ReadOnly MyGroupParams As List(Of GroupParameters)
|
||||
Private _GroupsUpdated As Boolean = False
|
||||
Friend ReadOnly Property GroupsUpdated As Boolean
|
||||
Get
|
||||
Return _GroupsUpdated
|
||||
End Get
|
||||
End Property
|
||||
Private _GroupToDownload As String = String.Empty
|
||||
Friend ReadOnly Property GroupToDownload As String
|
||||
Get
|
||||
Return _GroupToDownload
|
||||
End Get
|
||||
End Property
|
||||
Private _GroupToDownloadIncludeInTheFeed As Boolean = True
|
||||
Friend ReadOnly Property GroupToDownloadIncludeInTheFeed As Boolean
|
||||
Get
|
||||
Return _GroupToDownloadIncludeInTheFeed
|
||||
End Get
|
||||
End Property
|
||||
Private _FilterSelected As GroupParameters = Nothing
|
||||
Friend ReadOnly Property FilterSelected As GroupParameters
|
||||
Get
|
||||
Return _FilterSelected
|
||||
End Get
|
||||
End Property
|
||||
#End Region
|
||||
#Region "Initializer"
|
||||
Friend Sub New(ByVal _IsViewFilter As Boolean)
|
||||
InitializeComponent()
|
||||
MyDefs = New DefaultFormOptions(Me, Settings.Design)
|
||||
MyGroups = New ObservableCollection(Of String)
|
||||
MyGroupParams = New List(Of GroupParameters)
|
||||
IsViewFilter = _IsViewFilter
|
||||
If Not IsViewFilter Then
|
||||
BTT_MOVE_UP = New ToolStripButton With {
|
||||
.Image = PersonalUtilities.My.Resources.ArrowUpPic_Blue_32,
|
||||
.Text = String.Empty,
|
||||
.DisplayStyle = ToolStripItemDisplayStyle.Image,
|
||||
.ToolTipText = "Move up",
|
||||
.AutoToolTip = True
|
||||
}
|
||||
BTT_MOVE_DOWN = New ToolStripButton With {
|
||||
.Image = PersonalUtilities.My.Resources.ArrowDownPic_Blue_32,
|
||||
.Text = String.Empty,
|
||||
.DisplayStyle = ToolStripItemDisplayStyle.Image,
|
||||
.ToolTipText = "Move down",
|
||||
.AutoToolTip = True
|
||||
}
|
||||
BTT_DOWNLOAD = New ToolStripKeyMenuItem("Download", My.Resources.StartPic_Green_16) With {.ToolTipText = "Download selected group"}
|
||||
Else
|
||||
Text = "Filters"
|
||||
End If
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Form handlers"
|
||||
Private Sub GroupListForm_Load(sender As Object, e As EventArgs) Handles Me.Load
|
||||
Try
|
||||
With MyDefs
|
||||
.MyViewInitialize()
|
||||
|
||||
If Not IsViewFilter Then
|
||||
.AddEditToolbarPlus({BTT_MOVE_UP, BTT_MOVE_DOWN, ECI.Separator, BTT_DOWNLOAD})
|
||||
With Settings.Groups.Where(Function(g) g.IsViewFilter = IsViewFilter)
|
||||
If .ListExists Then .ListForEach(Sub(g, i) MyGroups.Add(g.Name))
|
||||
End With
|
||||
Else
|
||||
.AddEditToolbar()
|
||||
With .MyEditToolbar : .ButtonKey(ECI.Add) = Nothing : .Enabled(ECI.Add) = False : End With
|
||||
With Settings.Groups.Cast(Of GroupParameters).Concat(Settings.Automation.Cast(Of GroupParameters)).ToList.
|
||||
ListSort(New FComparer(Of GroupParameters)(
|
||||
Function(ByVal x As GroupParameters, ByVal y As GroupParameters) As Integer
|
||||
Dim getVal As Func(Of GroupParameters, Long) =
|
||||
Function(ByVal g As GroupParameters) As Long
|
||||
Dim v& = 0
|
||||
If TypeOf g Is AutoDownloader Then
|
||||
v = CLng(Integer.MaxValue) * 1000
|
||||
ElseIf TypeOf g Is DownloadGroup Then
|
||||
If Not g.IsViewFilter Then v = CLng(Integer.MaxValue) * 100
|
||||
End If
|
||||
v += g.ToStringViewFilters.GetHashCode
|
||||
Return v
|
||||
End Function
|
||||
Return getVal(x).CompareTo(getVal(y))
|
||||
End Function))
|
||||
If .ListExists Then .ListForEach(Sub(ByVal g As GroupParameters, ByVal __indx As Integer)
|
||||
MyGroups.Add(g.Name)
|
||||
MyGroupParams.Add(g)
|
||||
End Sub)
|
||||
End With
|
||||
CONTAINER_MAIN.BottomToolStripPanel.Visible = True
|
||||
.AddOkCancelToolbar()
|
||||
.MyOkCancel.ToolTipOk = "Apply selected filter"
|
||||
End If
|
||||
|
||||
RefillList()
|
||||
If Not IsViewFilter Then Settings.Groups.BeginUpdate()
|
||||
|
||||
.DelegateClosingChecker = False
|
||||
|
||||
.EndLoaderOperations()
|
||||
End With
|
||||
Catch ex As Exception
|
||||
MyDefs.InvokeLoaderError(ex)
|
||||
End Try
|
||||
End Sub
|
||||
Private Sub GroupListForm_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
|
||||
If Not IsViewFilter And GroupsUpdated And MyGroups.Count > 0 Then
|
||||
With Settings.Groups
|
||||
Dim myIndx%, grIndx%
|
||||
For myIndx = 0 To MyGroups.Count - 1
|
||||
grIndx = .IndexOf(MyGroups(myIndx))
|
||||
If grIndx >= 0 Then .Item(grIndx).Index = myIndx
|
||||
Next
|
||||
.Sort()
|
||||
.Reindex()
|
||||
.Sort()
|
||||
End With
|
||||
End If
|
||||
MyGroups.Clear()
|
||||
MyGroupParams.Clear()
|
||||
Settings.Groups.EndUpdate()
|
||||
If GroupsUpdated Then Settings.Groups.Update()
|
||||
End Sub
|
||||
Private Sub GroupListForm_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
|
||||
If e.KeyCode = Keys.Escape Then
|
||||
Close()
|
||||
ElseIf e = ShowUsersButtonKey Then
|
||||
ShowUsers()
|
||||
End If
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Refill"
|
||||
Private Sub RefillList(Optional ByVal OffsetIndex As Integer? = Nothing)
|
||||
Try
|
||||
With LIST_GROUPS
|
||||
.BeginUpdate()
|
||||
With .Items
|
||||
.Clear()
|
||||
If IsViewFilter Then
|
||||
If MyGroupParams.Count > 0 Then .AddRange(MyGroupParams.Select(Function(g) g.ToStringViewFilters).Cast(Of Object).ToArray)
|
||||
Else
|
||||
If MyGroups.Count > 0 Then .AddRange(MyGroups.Cast(Of Object).ToArray)
|
||||
End If
|
||||
End With
|
||||
.EndUpdate()
|
||||
If OffsetIndex.HasValue Then
|
||||
Dim newIndx% = _LatestSelected + OffsetIndex.Value
|
||||
If newIndx.ValueBetween(0, .Items.Count - 1) Then .SelectedIndex = newIndx : _LatestSelected = newIndx
|
||||
ElseIf .Items.Count > 0 Then
|
||||
If _LatestSelected.ValueBetween(0, .Items.Count - 1) Then
|
||||
.SelectedIndex = _LatestSelected
|
||||
ElseIf (_LatestSelected - 1).ValueBetween(0, .Items.Count - 1) Then
|
||||
_LatestSelected -= 1
|
||||
.SelectedIndex = _LatestSelected
|
||||
ElseIf (_LatestSelected + 1).ValueBetween(0, .Items.Count - 1) Then
|
||||
_LatestSelected += 1
|
||||
.SelectedIndex = _LatestSelected
|
||||
End If
|
||||
End If
|
||||
End With
|
||||
Catch ex As Exception
|
||||
ErrorsDescriber.Execute(EDP.SendToLog, ex, "[GroupListForm.RefillList]")
|
||||
End Try
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Ok Cancel"
|
||||
Private Sub MyDefs_ButtonOkClick(ByVal Sender As Object, ByVal e As KeyHandleEventArgs) Handles MyDefs.ButtonOkClick
|
||||
If _LatestSelected.ValueBetween(0, MyGroupParams.Count - 1) Then
|
||||
_FilterSelected = MyGroupParams(_LatestSelected)
|
||||
MyDefs.CloseForm()
|
||||
Else
|
||||
MsgBoxE({"You haven't selected a filter", "Apply filter"}, vbCritical)
|
||||
End If
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Toolbar buttons"
|
||||
Private Sub MyDefs_ButtonAddClick(ByVal Sender As Object, ByVal e As EditToolbarEventArgs) Handles MyDefs.ButtonAddClick
|
||||
If Not IsViewFilter Then
|
||||
Dim i% = Settings.Groups.Add
|
||||
If i >= 0 Then
|
||||
MyGroups.Add(Settings.Groups(i).Name)
|
||||
_LatestSelected = MyGroups.Count - 1
|
||||
_GroupsUpdated = True
|
||||
RefillList()
|
||||
End If
|
||||
End If
|
||||
End Sub
|
||||
Private Sub MyDefs_ButtonEditClick(ByVal Sender As Object, ByVal e As EditToolbarEventArgs) Handles MyDefs.ButtonEditClick
|
||||
EditItem()
|
||||
End Sub
|
||||
Private Function ItemEditDeleteReady(ByVal Operation As String) As DialogResult
|
||||
If IsViewFilter Then
|
||||
If _LatestSelected.ValueBetween(0, MyGroupParams.Count - 1) Then
|
||||
With MyGroupParams(_LatestSelected)
|
||||
If TypeOf .Self Is AutoDownloader Then
|
||||
MsgBoxE({$"You cannot {Operation} the scheduler plan through this form", $"{Operation.ToUpperFirstChar} filter"}, vbCritical)
|
||||
Return DialogResult.Abort
|
||||
ElseIf TypeOf .Self Is DownloadGroup AndAlso Not DirectCast(.Self, DownloadGroup).IsViewFilter Then
|
||||
MsgBoxE({$"You cannot {Operation} the group through this form", $"{Operation.ToUpperFirstChar} filter"}, vbCritical)
|
||||
Return DialogResult.Abort
|
||||
End If
|
||||
End With
|
||||
End If
|
||||
End If
|
||||
Return DialogResult.OK
|
||||
End Function
|
||||
Private Sub EditItem()
|
||||
If _LatestSelected.ValueBetween(0, MyGroups.Count - 1) AndAlso ItemEditDeleteReady("edit") = DialogResult.OK Then
|
||||
Dim i% = Settings.Groups.IndexOf(MyGroups(_LatestSelected), IsViewFilter)
|
||||
If i >= 0 Then
|
||||
Using f As New GroupEditorForm(Settings.Groups(i))
|
||||
f.ShowDialog()
|
||||
If f.DialogResult = DialogResult.OK Then
|
||||
If IsViewFilter Then
|
||||
MyGroups(_LatestSelected) = Settings.Groups(i).ToStringViewFilters
|
||||
Settings.Groups.Update()
|
||||
Else
|
||||
MyGroups(_LatestSelected) = Settings.Groups(i).Name
|
||||
_GroupsUpdated = True
|
||||
End If
|
||||
RefillList()
|
||||
End If
|
||||
End Using
|
||||
End If
|
||||
End If
|
||||
End Sub
|
||||
Private Sub MyDefs_ButtonDeleteClickEdit(ByVal Sender As Object, ByVal e As EditToolbarEventArgs) Handles MyDefs.ButtonDeleteClickE
|
||||
Try
|
||||
If _LatestSelected.ValueBetween(0, MyGroups.Count - 1) AndAlso ItemEditDeleteReady("delete") = DialogResult.OK Then
|
||||
Dim i% = Settings.Groups.IndexOf(MyGroups(_LatestSelected), IsViewFilter)
|
||||
If i >= 0 Then
|
||||
Dim n$ = Settings.Groups(i).Name
|
||||
If Settings.Groups(i).Delete Then
|
||||
If _LatestSelected.ValueBetween(0, MyGroupParams.Count - 1) Then MyGroupParams.RemoveAt(_LatestSelected)
|
||||
MyGroups.Remove(n)
|
||||
RefillList()
|
||||
If IsViewFilter Then
|
||||
Settings.Groups.Update()
|
||||
Else
|
||||
_GroupsUpdated = True
|
||||
End If
|
||||
End If
|
||||
End If
|
||||
End If
|
||||
Catch ex As Exception
|
||||
ErrorsDescriber.Execute(EDP.SendToLog, ex, "[GroupListForm.Delete]")
|
||||
End Try
|
||||
End Sub
|
||||
Private Sub BTT_MOVE_UP_DOWN_Click(sender As Object, e As EventArgs) Handles BTT_MOVE_UP.Click, BTT_MOVE_DOWN.Click
|
||||
Try
|
||||
Dim offset% = IIf(sender Is BTT_MOVE_UP, -1, 1)
|
||||
If _LatestSelected.ValueBetween(0, MyGroups.Count - 1) And (_LatestSelected + offset).ValueBetween(0, MyGroups.Count - 1) Then
|
||||
MyGroups.Move(_LatestSelected, _LatestSelected + offset)
|
||||
RefillList(offset)
|
||||
_GroupsUpdated = True
|
||||
End If
|
||||
Catch ex As Exception
|
||||
ErrorsDescriber.Execute(EDP.SendToLog, ex, "[GroupListForm.Move]")
|
||||
End Try
|
||||
End Sub
|
||||
Private Sub BTT_DOWNLOAD_KeyClick(ByVal Sender As Object, ByVal e As MyKeyEventArgs) Handles BTT_DOWNLOAD.KeyClick
|
||||
If Not IsViewFilter AndAlso _LatestSelected.ValueBetween(0, MyGroups.Count - 1) Then
|
||||
Dim i% = Settings.Groups.IndexOf(MyGroups(_LatestSelected))
|
||||
If i >= 0 Then _GroupToDownload = Settings.Groups(i).Name : _GroupToDownloadIncludeInTheFeed = e.IncludeInTheFeed : Close()
|
||||
End If
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "List handlers"
|
||||
Private _LatestSelected As Integer = -1
|
||||
Private Sub LIST_GROUPS_Click(sender As Object, e As EventArgs) Handles LIST_GROUPS.Click
|
||||
_LatestSelected = LIST_GROUPS.SelectedIndex
|
||||
End Sub
|
||||
Private Sub LIST_GROUPS_DoubleClick(sender As Object, e As EventArgs) Handles LIST_GROUPS.DoubleClick
|
||||
If IsViewFilter Then
|
||||
MyDefs.MyOkCancel.BTT_OK.PerformClick()
|
||||
Else
|
||||
EditItem()
|
||||
End If
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "ShowUsers"
|
||||
Private Sub ShowUsers()
|
||||
Try
|
||||
If _LatestSelected.ValueBetween(0, MyGroups.Count - 1) Then
|
||||
Dim i%
|
||||
Dim n$ = String.Empty
|
||||
Dim users As New List(Of API.Base.IUserData)
|
||||
If Not IsViewFilter Then
|
||||
i = Settings.Groups.IndexOf(MyGroups(_LatestSelected))
|
||||
If i >= 0 Then users.ListAddList(DownloadGroup.GetUsers(Settings.Groups(i))) : n = $"F {Settings.Groups(i).Name}"
|
||||
ElseIf _LatestSelected.ValueBetween(0, MyGroupParams.Count - 1) Then
|
||||
With MyGroupParams(_LatestSelected)
|
||||
If TypeOf .Self Is AutoDownloader Then
|
||||
With DirectCast(.Self, AutoDownloader)
|
||||
If Not .Mode = AutoDownloader.Modes.None Then
|
||||
If .Mode = AutoDownloader.Modes.Groups Then
|
||||
If .Groups.Count > 0 Then
|
||||
For Each groupName$ In .Groups
|
||||
i = Settings.Groups.IndexOf(groupName)
|
||||
If i >= 0 Then users.ListAddList(DownloadGroup.GetUsers(Settings.Groups(i)), LAP.NotContainsOnly, LAP.IgnoreICopier)
|
||||
Next
|
||||
End If
|
||||
Else
|
||||
users.ListAddList(DownloadGroup.GetUsers(.Self))
|
||||
End If
|
||||
End If
|
||||
n = $"S { .Name}"
|
||||
End With
|
||||
ElseIf TypeOf .Self Is DownloadGroup Then
|
||||
i = Settings.Groups.IndexOf(.Name, .IsViewFilter)
|
||||
If i >= 0 Then users.ListAddList(DownloadGroup.GetUsers(Settings.Groups(i))) : n = $"G {Settings.Groups(i).Name}"
|
||||
End If
|
||||
End With
|
||||
End If
|
||||
GroupUsersViewer.Show(users, n)
|
||||
users.Clear()
|
||||
End If
|
||||
Catch ex As Exception
|
||||
ErrorsDescriber.Execute(EDP.LogMessageValue, ex, "Show plan users")
|
||||
End Try
|
||||
End Sub
|
||||
#End Region
|
||||
End Class
|
||||
End Namespace
|
||||
@@ -10,49 +10,104 @@ Imports PersonalUtilities.Functions.XML
|
||||
Namespace DownloadObjects.Groups
|
||||
Friend Interface IGroup
|
||||
Property Name As String
|
||||
Property LabelsNo As Boolean
|
||||
ReadOnly Property Labels As List(Of String)
|
||||
ReadOnly Property LabelsExcluded As List(Of String)
|
||||
Property LabelsExcludedIgnore As Boolean
|
||||
ReadOnly Property Sites As List(Of String)
|
||||
ReadOnly Property SitesExcluded As List(Of String)
|
||||
Property Temporary As CheckState
|
||||
Property Favorite As CheckState
|
||||
Property Regular As Boolean
|
||||
Property Temporary As Boolean
|
||||
Property Favorite As Boolean
|
||||
Property ReadyForDownload As Boolean
|
||||
Property ReadyForDownloadIgnore As Boolean
|
||||
Property Subscriptions As Boolean
|
||||
Property SubscriptionsOnly As Boolean
|
||||
Property DownloadUsers As Boolean
|
||||
Property DownloadSubscriptions As Boolean
|
||||
Property UsersCount As Integer
|
||||
Property DaysNumber As Integer
|
||||
Property DaysIsDownloaded As Boolean
|
||||
Property UserDeleted As Boolean
|
||||
Property UserSuspended As Boolean
|
||||
Property UserExists As Boolean
|
||||
Property DateFrom As Date?
|
||||
Property DateTo As Date?
|
||||
Property DateMode As ShowingDates
|
||||
End Interface
|
||||
Friend Class GroupParameters : Implements IGroup, IDisposable, ICopier
|
||||
#Region "XML names"
|
||||
#Region "Old"
|
||||
Protected Const Name_Subscriptions As String = "Subscriptions"
|
||||
Protected Const Name_SubscriptionsOnly As String = "SubscriptionsOnly"
|
||||
#End Region
|
||||
Protected Const Name_Name As String = "Name"
|
||||
Protected Const Name_Regular As String = "Regular"
|
||||
Protected Const Name_Temporary As String = "Temporary"
|
||||
Protected Const Name_Favorite As String = "Favorite"
|
||||
Protected Const Name_ReadyForDownload As String = "RFD"
|
||||
Protected Const Name_ReadyForDownloadIgnore As String = "RFDI"
|
||||
Protected Const Name_Subscriptions As String = "Subscriptions"
|
||||
Protected Const Name_SubscriptionsOnly As String = "SubscriptionsOnly"
|
||||
|
||||
Protected Const Name_DownloadUsers As String = "DownloadUsers"
|
||||
Protected Const Name_DownloadSubscriptions As String = "DownloadSubscriptions"
|
||||
|
||||
Protected Const Name_UsersCount As String = "UsersCount"
|
||||
Protected Const Name_LabelsNo As String = "LabelsNo"
|
||||
Protected Const Name_Labels As String = "Labels"
|
||||
Protected Const Name_Labels_Excluded As String = "LabelsExcluded"
|
||||
Protected Const Name_LabelsExcludedIgnore As String = "LabelsExcludedIgnore"
|
||||
Protected Const Name_Sites As String = "Sites"
|
||||
Protected Const Name_Sites_Excluded As String = "SitesExcluded"
|
||||
Friend Property Name As String Implements IGroup.Name
|
||||
Protected Const Name_DaysNumber As String = "DaysNumber"
|
||||
Protected Const Name_DaysIsDownloaded As String = "DaysIsDownloaded"
|
||||
Protected Const Name_UserDeleted As String = "UserDeleted"
|
||||
Protected Const Name_UserSuspended As String = "UserSuspended"
|
||||
Protected Const Name_UserExists As String = "UserExists"
|
||||
Protected Const Name_DateFrom As String = "DateFrom"
|
||||
Protected Const Name_DateTo As String = "DateTo"
|
||||
Protected Const Name_DateMode As String = "DateMode"
|
||||
Protected Const Name_IsViewFilter As String = "IsViewFilter"
|
||||
#End Region
|
||||
#Region "Declarations"
|
||||
Friend Overridable Property Name As String Implements IGroup.Name
|
||||
Friend Property LabelsNo As Boolean = False Implements IGroup.LabelsNo
|
||||
Friend ReadOnly Property Labels As List(Of String) Implements IGroup.Labels
|
||||
Friend ReadOnly Property LabelsExcluded As List(Of String) Implements IGroup.LabelsExcluded
|
||||
Friend Property LabelsExcludedIgnore As Boolean = False Implements IGroup.LabelsExcludedIgnore
|
||||
Friend ReadOnly Property Sites As List(Of String) Implements IGroup.Sites
|
||||
Friend ReadOnly Property SitesExcluded As List(Of String) Implements IGroup.SitesExcluded
|
||||
Friend Property Temporary As CheckState = CheckState.Indeterminate Implements IGroup.Temporary
|
||||
Friend Property Favorite As CheckState = CheckState.Indeterminate Implements IGroup.Favorite
|
||||
Friend Property Regular As Boolean = True Implements IGroup.Regular
|
||||
Friend Property Temporary As Boolean = True Implements IGroup.Temporary
|
||||
Friend Property Favorite As Boolean = True Implements IGroup.Favorite
|
||||
Friend Property ReadyForDownload As Boolean = True Implements IGroup.ReadyForDownload
|
||||
Friend Property ReadyForDownloadIgnore As Boolean = False Implements IGroup.ReadyForDownloadIgnore
|
||||
Friend Property Subscriptions As Boolean = False Implements IGroup.Subscriptions
|
||||
Friend Property SubscriptionsOnly As Boolean = False Implements IGroup.SubscriptionsOnly
|
||||
Friend Property DownloadUsers As Boolean = True Implements IGroup.DownloadUsers
|
||||
Friend Property DownloadSubscriptions As Boolean = True Implements IGroup.DownloadSubscriptions
|
||||
Friend Property UsersCount As Integer = 0 Implements IGroup.UsersCount
|
||||
Friend Property DaysNumber As Integer = -1 Implements IGroup.DaysNumber
|
||||
Friend Property DaysIsDownloaded As Boolean = False Implements IGroup.DaysIsDownloaded
|
||||
Friend Property UserDeleted As Boolean = False Implements IGroup.UserDeleted
|
||||
Friend Property UserSuspended As Boolean = True Implements IGroup.UserSuspended
|
||||
Friend Property UserExists As Boolean = True Implements IGroup.UserExists
|
||||
Friend Property DateFrom As Date? = Nothing Implements IGroup.DateFrom
|
||||
Friend Property DateTo As Date? = Nothing Implements IGroup.DateTo
|
||||
Friend Property DateMode As ShowingDates = ShowingDates.Off Implements IGroup.DateMode
|
||||
Friend Property IsViewFilter As Boolean = False
|
||||
#End Region
|
||||
#Region "Initializer"
|
||||
Friend Sub New()
|
||||
Labels = New List(Of String)
|
||||
LabelsExcluded = New List(Of String)
|
||||
Sites = New List(Of String)
|
||||
SitesExcluded = New List(Of String)
|
||||
End Sub
|
||||
#End Region
|
||||
#Region "Base functions"
|
||||
Public Overrides Function ToString() As String
|
||||
Return Name
|
||||
End Function
|
||||
Friend Overridable Function ToStringViewFilters() As String
|
||||
Return ToString()
|
||||
End Function
|
||||
#End Region
|
||||
#Region "ICopier Support"
|
||||
Friend Overridable Overloads Function Copy() As Object Implements ICopier.Copy
|
||||
Return (New GroupParameters).Copy(Me)
|
||||
@@ -60,52 +115,101 @@ Namespace DownloadObjects.Groups
|
||||
Friend Overridable Overloads Function Copy(ByVal Source As Object) As Object Implements ICopier.Copy
|
||||
With DirectCast(Source, GroupParameters)
|
||||
Name = .Name
|
||||
LabelsNo = .LabelsNo
|
||||
Labels.ListAddList(.Labels, LAP.ClearBeforeAdd)
|
||||
LabelsExcluded.ListAddList(.LabelsExcluded, LAP.ClearBeforeAdd)
|
||||
LabelsExcludedIgnore = .LabelsExcludedIgnore
|
||||
Sites.ListAddList(.Sites, LAP.ClearBeforeAdd)
|
||||
SitesExcluded.ListAddList(.SitesExcluded, LAP.ClearBeforeAdd)
|
||||
Regular = .Regular
|
||||
Temporary = .Temporary
|
||||
Favorite = .Favorite
|
||||
ReadyForDownload = .ReadyForDownload
|
||||
ReadyForDownloadIgnore = .ReadyForDownloadIgnore
|
||||
Subscriptions = .Subscriptions
|
||||
SubscriptionsOnly = .SubscriptionsOnly
|
||||
DownloadUsers = .DownloadUsers
|
||||
DownloadSubscriptions = .DownloadSubscriptions
|
||||
UsersCount = .UsersCount
|
||||
DaysNumber = .DaysNumber
|
||||
DaysIsDownloaded = .DaysIsDownloaded
|
||||
UserDeleted = .UserDeleted
|
||||
UserSuspended = .UserSuspended
|
||||
UserExists = .UserExists
|
||||
DateFrom = .DateFrom
|
||||
DateTo = .DateTo
|
||||
DateMode = .DateMode
|
||||
IsViewFilter = .IsViewFilter
|
||||
End With
|
||||
Return Source
|
||||
Return Me
|
||||
End Function
|
||||
#End Region
|
||||
Protected Sub Import(ByVal e As EContainer)
|
||||
#Region "Import/Export"
|
||||
Protected Overridable Sub Import(ByVal e As EContainer)
|
||||
Name = e.Value(Name_Name)
|
||||
Temporary = e.Value(Name_Temporary).FromXML(Of Integer)(CInt(CheckState.Indeterminate))
|
||||
Favorite = e.Value(Name_Favorite).FromXML(Of Integer)(CInt(CheckState.Indeterminate))
|
||||
ReadyForDownload = e.Value(Name_ReadyForDownload).FromXML(Of Boolean)(True)
|
||||
ReadyForDownloadIgnore = e.Value(Name_ReadyForDownloadIgnore).FromXML(Of Boolean)(False)
|
||||
Subscriptions = e.Value(Name_Subscriptions).FromXML(Of Boolean)(False)
|
||||
SubscriptionsOnly = e.Value(Name_SubscriptionsOnly).FromXML(Of Boolean)(False)
|
||||
UsersCount = e.Value(Name_UsersCount).FromXML(Of Integer)(0)
|
||||
|
||||
Dim l As New ListAddParams(LAP.NotContainsOnly)
|
||||
LabelsNo = e.Value(Name_LabelsNo).FromXML(Of Boolean)(False)
|
||||
If Not e.Value(Name_Labels).IsEmptyString Then Labels.ListAddList(e.Value(Name_Labels).Split("|"), l)
|
||||
If Not e.Value(Name_Labels_Excluded).IsEmptyString Then LabelsExcluded.ListAddList(e.Value(Name_Labels_Excluded).Split("|"), l)
|
||||
LabelsExcludedIgnore = e.Value(Name_LabelsExcludedIgnore).FromXML(Of Boolean)(False)
|
||||
If Not e.Value(Name_Sites).IsEmptyString Then Sites.ListAddList(e.Value(Name_Sites).Split("|"), l)
|
||||
If Not e.Value(Name_Sites_Excluded).IsEmptyString Then SitesExcluded.ListAddList(e.Value(Name_Sites_Excluded).Split("|"), l)
|
||||
|
||||
Regular = e.Value(Name_Regular).FromXML(Of Boolean)(True)
|
||||
Temporary = e.Value(Name_Temporary).FromXML(Of Boolean)(True)
|
||||
Favorite = e.Value(Name_Favorite).FromXML(Of Boolean)(True)
|
||||
ReadyForDownload = e.Value(Name_ReadyForDownload).FromXML(Of Boolean)(True)
|
||||
ReadyForDownloadIgnore = e.Value(Name_ReadyForDownloadIgnore).FromXML(Of Boolean)(False)
|
||||
|
||||
If e.Contains(Name_SubscriptionsOnly) Then
|
||||
DownloadUsers = Not e.Value(Name_SubscriptionsOnly).FromXML(Of Boolean)(False)
|
||||
Else
|
||||
DownloadUsers = e.Value(Name_DownloadUsers).FromXML(Of Boolean)(True)
|
||||
End If
|
||||
If e.Contains(Name_Subscriptions) Then
|
||||
DownloadSubscriptions = e.Value(Name_Subscriptions).FromXML(Of Boolean)(False)
|
||||
Else
|
||||
DownloadSubscriptions = e.Value(Name_DownloadSubscriptions).FromXML(Of Boolean)(False)
|
||||
End If
|
||||
|
||||
UsersCount = e.Value(Name_UsersCount).FromXML(Of Integer)(0)
|
||||
DaysNumber = e.Value(Name_DaysNumber).FromXML(Of Integer)(-1)
|
||||
DaysIsDownloaded = e.Value(Name_DaysIsDownloaded).FromXML(Of Boolean)(False)
|
||||
UserDeleted = e.Value(Name_UserDeleted).FromXML(Of Boolean)(False)
|
||||
UserSuspended = e.Value(Name_UserSuspended).FromXML(Of Boolean)(True)
|
||||
UserExists = e.Value(Name_UserExists).FromXML(Of Boolean)(True)
|
||||
DateFrom = AConvert(Of Date)(e.Value(Name_DateFrom), DateTimeDefaultProvider, Nothing)
|
||||
DateTo = AConvert(Of Date)(e.Value(Name_DateTo), DateTimeDefaultProvider, Nothing)
|
||||
DateMode = e.Value(Name_DateMode).FromXML(Of Integer)(ShowingDates.Off)
|
||||
IsViewFilter = e.Value(Name_IsViewFilter).FromXML(Of Boolean)(False)
|
||||
End Sub
|
||||
Protected Function Export(ByVal e As EContainer) As EContainer
|
||||
Protected Overridable Function Export(ByVal e As EContainer) As EContainer
|
||||
e.AddRange({New EContainer(Name_Name, Name),
|
||||
New EContainer(Name_Temporary, CInt(Temporary)),
|
||||
New EContainer(Name_Favorite, CInt(Favorite)),
|
||||
New EContainer(Name_ReadyForDownload, ReadyForDownload.BoolToInteger),
|
||||
New EContainer(Name_ReadyForDownloadIgnore, ReadyForDownloadIgnore.BoolToInteger),
|
||||
New EContainer(Name_Subscriptions, Subscriptions.BoolToInteger),
|
||||
New EContainer(Name_SubscriptionsOnly, SubscriptionsOnly.BoolToInteger),
|
||||
New EContainer(Name_UsersCount, UsersCount),
|
||||
New EContainer(Name_LabelsNo, LabelsNo.BoolToInteger),
|
||||
New EContainer(Name_Labels, Labels.ListToString("|")),
|
||||
New EContainer(Name_Labels_Excluded, LabelsExcluded.ListToString("|")),
|
||||
New EContainer(Name_LabelsExcludedIgnore, LabelsExcludedIgnore.BoolToInteger),
|
||||
New EContainer(Name_Sites, Sites.ListToString("|")),
|
||||
New EContainer(Name_Sites_Excluded, SitesExcluded.ListToString("|"))})
|
||||
New EContainer(Name_Sites_Excluded, SitesExcluded.ListToString("|")),
|
||||
New EContainer(Name_Regular, Regular.BoolToInteger),
|
||||
New EContainer(Name_Temporary, Temporary.BoolToInteger),
|
||||
New EContainer(Name_Favorite, Favorite.BoolToInteger),
|
||||
New EContainer(Name_ReadyForDownload, ReadyForDownload.BoolToInteger),
|
||||
New EContainer(Name_ReadyForDownloadIgnore, ReadyForDownloadIgnore.BoolToInteger),
|
||||
New EContainer(Name_DownloadUsers, DownloadUsers.BoolToInteger),
|
||||
New EContainer(Name_DownloadSubscriptions, DownloadSubscriptions.BoolToInteger),
|
||||
New EContainer(Name_UsersCount, UsersCount),
|
||||
New EContainer(Name_DaysNumber, DaysNumber),
|
||||
New EContainer(Name_DaysIsDownloaded, DaysIsDownloaded.BoolToInteger),
|
||||
New EContainer(Name_UserDeleted, UserDeleted.BoolToInteger),
|
||||
New EContainer(Name_UserSuspended, UserSuspended.BoolToInteger),
|
||||
New EContainer(Name_UserExists, UserExists.BoolToInteger),
|
||||
New EContainer(Name_DateFrom, AConvert(Of String)(DateFrom, DateTimeDefaultProvider, String.Empty)),
|
||||
New EContainer(Name_DateTo, AConvert(Of String)(DateTo, DateTimeDefaultProvider, String.Empty)),
|
||||
New EContainer(Name_DateMode, CInt(DateMode)),
|
||||
New EContainer(Name_IsViewFilter, IsViewFilter.BoolToInteger)})
|
||||
Return e
|
||||
End Function
|
||||
#End Region
|
||||
#Region "IDisposable Support"
|
||||
Protected disposedValue As Boolean = False
|
||||
Protected Overridable Overloads Sub Dispose(ByVal disposing As Boolean)
|
||||
|
||||
78
SCrawler/Download/Groups/GroupUsersViewer.vb
Normal file
@@ -0,0 +1,78 @@
|
||||
' 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 SCrawler.API.Base
|
||||
Imports PersonalUtilities.Forms
|
||||
Namespace DownloadObjects.Groups
|
||||
Friend Class GroupUsersViewer : Inherits SimpleListForm(Of IUserData)
|
||||
Friend Sub New(ByVal Users As IEnumerable(Of IUserData), ByVal AdditText As String)
|
||||
MyBase.New(Users, Settings.Design)
|
||||
DesignXMLNodeName = "GroupUsersViewer"
|
||||
Provider = New CustomProvider(Function(u As UserDataBase) u.ToStringForLog)
|
||||
FormText = $"Users ({If(Users?.Count, 0)})"
|
||||
If Not AdditText.IsEmptyString Then
|
||||
Dim a$ = AdditText.Trim.Take(100).ListToStringE(String.Empty,,, " ", EDP.ReturnValue)
|
||||
If Not a = AdditText Then AdditText &= "..."
|
||||
FormText &= $" [{a}]"
|
||||
End If
|
||||
Icon = My.Resources.UsersIcon_32
|
||||
MyDefs.DelegateClosingChecker = False
|
||||
Mode = SimpleListFormModes.SelectedItems
|
||||
MultiSelect = False
|
||||
Size = New Size(300, 400)
|
||||
End Sub
|
||||
Protected Overrides Sub MyForm_KeyDown(sender As Object, e As KeyEventArgs)
|
||||
Try
|
||||
Dim b As Boolean = True
|
||||
If e.KeyCode = Keys.F And e.Control Then
|
||||
FocusUser()
|
||||
ElseIf e.KeyCode = Keys.F3 Then
|
||||
EditUser(e.Alt)
|
||||
ElseIf e = ShowUsersButtonKey Then
|
||||
MsgBoxE(New MMessage(DataSourceCollection.ListToStringE(vbCr, Provider,,, EDP.LogMessageValue), "User list") With {.Editable = True})
|
||||
ElseIf e.KeyCode = Keys.F1 And Not e.Alt And Not e.Control Then
|
||||
MsgBoxE({$"Hotkeys:{vbCr}Alt+F1 - show user list{vbCr}Ctrl+F - find the selected user in the main window{vbCr}" &
|
||||
$"F3 - edit selected user{vbCr}Alt+F3 - edit selected collection", "Hotkeys"})
|
||||
Else
|
||||
b = False
|
||||
End If
|
||||
If b Then e.Handled = True
|
||||
Catch
|
||||
End Try
|
||||
End Sub
|
||||
Friend Overloads Shared Sub Show(ByVal Users As IEnumerable(Of IUserData), ByVal AdditText As String)
|
||||
If Users.ListExists Then
|
||||
MainFrameObj.OpenedGroupUsersForms.Add(New GroupUsersViewer(Users, AdditText))
|
||||
MainFrameObj.OpenedGroupUsersForms.Last.Show()
|
||||
Else
|
||||
MsgBoxE({"No users were found based on the selected parameters", "Show group users"}, vbExclamation)
|
||||
End If
|
||||
End Sub
|
||||
Protected Overrides Sub CMB_DATA_ActionOnListDoubleClick(ByVal Sender As Object, ByVal e As EventArgs, ByVal Item As ListViewItem)
|
||||
FocusUser()
|
||||
End Sub
|
||||
Private Sub FocusUser()
|
||||
Try
|
||||
If _LatestSelected.ValueBetween(0, DataSourceCollection.Count - 1) Then MainFrameObj.FocusUser(DataSourceCollection(_LatestSelected).Key, True)
|
||||
Catch
|
||||
End Try
|
||||
End Sub
|
||||
Private Sub EditUser(ByVal EditCollection As Boolean)
|
||||
Try
|
||||
If _LatestSelected.ValueBetween(0, DataSourceCollection.Count - 1) Then
|
||||
Dim u As IUserData = Settings.GetUser(DataSourceCollection(_LatestSelected).Key, EditCollection)
|
||||
If Not u Is Nothing Then ControlInvokeFast(MainFrameObj.MF, Sub() MainFrameObj.MF.EditSelectedUser(u), EDP.None)
|
||||
End If
|
||||
Catch
|
||||
End Try
|
||||
End Sub
|
||||
Friend Overloads Sub Show()
|
||||
MyForm.Show()
|
||||
End Sub
|
||||
End Class
|
||||
End Namespace
|
||||
@@ -36,6 +36,7 @@ Namespace DownloadObjects.STDownloader
|
||||
Me.TXT_URL = New PersonalUtilities.Forms.Controls.TextBoxExtended()
|
||||
Me.TXT_PATH = New PersonalUtilities.Forms.Controls.ComboBoxExtended()
|
||||
Me.CMB_ACCOUNT = New PersonalUtilities.Forms.Controls.ComboBoxExtended()
|
||||
Me.CH_THUMB_ALONG = New System.Windows.Forms.CheckBox()
|
||||
CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer()
|
||||
TP_MAIN = New System.Windows.Forms.TableLayoutPanel()
|
||||
CONTAINER_MAIN.ContentPanel.SuspendLayout()
|
||||
@@ -52,13 +53,13 @@ Namespace DownloadObjects.STDownloader
|
||||
'CONTAINER_MAIN.ContentPanel
|
||||
'
|
||||
CONTAINER_MAIN.ContentPanel.Controls.Add(TP_MAIN)
|
||||
CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(484, 88)
|
||||
CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(484, 114)
|
||||
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(484, 113)
|
||||
CONTAINER_MAIN.Size = New System.Drawing.Size(484, 139)
|
||||
CONTAINER_MAIN.TabIndex = 0
|
||||
CONTAINER_MAIN.TopToolStripPanelVisible = False
|
||||
'
|
||||
@@ -70,15 +71,17 @@ Namespace DownloadObjects.STDownloader
|
||||
TP_MAIN.Controls.Add(Me.TXT_URL, 0, 0)
|
||||
TP_MAIN.Controls.Add(Me.TXT_PATH, 0, 1)
|
||||
TP_MAIN.Controls.Add(Me.CMB_ACCOUNT, 0, 2)
|
||||
TP_MAIN.Controls.Add(Me.CH_THUMB_ALONG, 0, 3)
|
||||
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 = 4
|
||||
TP_MAIN.RowCount = 5
|
||||
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, 28.0!))
|
||||
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.Percent, 100.0!))
|
||||
TP_MAIN.Size = New System.Drawing.Size(484, 88)
|
||||
TP_MAIN.Size = New System.Drawing.Size(484, 114)
|
||||
TP_MAIN.TabIndex = 0
|
||||
'
|
||||
'TXT_URL
|
||||
@@ -158,19 +161,30 @@ Namespace DownloadObjects.STDownloader
|
||||
Me.CMB_ACCOUNT.TabIndex = 2
|
||||
Me.CMB_ACCOUNT.TextBoxBorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
|
||||
'
|
||||
'CH_THUMB_ALONG
|
||||
'
|
||||
Me.CH_THUMB_ALONG.AutoSize = True
|
||||
Me.CH_THUMB_ALONG.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.CH_THUMB_ALONG.Location = New System.Drawing.Point(4, 91)
|
||||
Me.CH_THUMB_ALONG.Name = "CH_THUMB_ALONG"
|
||||
Me.CH_THUMB_ALONG.Size = New System.Drawing.Size(476, 19)
|
||||
Me.CH_THUMB_ALONG.TabIndex = 3
|
||||
Me.CH_THUMB_ALONG.Text = "Save thumbnail with file"
|
||||
Me.CH_THUMB_ALONG.UseVisualStyleBackColor = True
|
||||
'
|
||||
'DownloaderUrlForm
|
||||
'
|
||||
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
|
||||
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
|
||||
Me.ClientSize = New System.Drawing.Size(484, 113)
|
||||
Me.ClientSize = New System.Drawing.Size(484, 139)
|
||||
Me.Controls.Add(CONTAINER_MAIN)
|
||||
Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle
|
||||
Me.Icon = Global.SCrawler.My.Resources.Resources.ArrowDownIcon_Blue_24
|
||||
Me.KeyPreview = True
|
||||
Me.MaximizeBox = False
|
||||
Me.MaximumSize = New System.Drawing.Size(500, 152)
|
||||
Me.MaximumSize = New System.Drawing.Size(500, 178)
|
||||
Me.MinimizeBox = False
|
||||
Me.MinimumSize = New System.Drawing.Size(500, 152)
|
||||
Me.MinimumSize = New System.Drawing.Size(500, 178)
|
||||
Me.Name = "DownloaderUrlForm"
|
||||
Me.ShowInTaskbar = False
|
||||
Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide
|
||||
@@ -179,6 +193,7 @@ Namespace DownloadObjects.STDownloader
|
||||
CONTAINER_MAIN.ResumeLayout(False)
|
||||
CONTAINER_MAIN.PerformLayout()
|
||||
TP_MAIN.ResumeLayout(False)
|
||||
TP_MAIN.PerformLayout()
|
||||
CType(Me.TXT_URL, System.ComponentModel.ISupportInitialize).EndInit()
|
||||
CType(Me.TXT_PATH, System.ComponentModel.ISupportInitialize).EndInit()
|
||||
CType(Me.CMB_ACCOUNT, System.ComponentModel.ISupportInitialize).EndInit()
|
||||
@@ -188,5 +203,6 @@ Namespace DownloadObjects.STDownloader
|
||||
Private WithEvents TXT_URL As PersonalUtilities.Forms.Controls.TextBoxExtended
|
||||
Private WithEvents TXT_PATH As PersonalUtilities.Forms.Controls.ComboBoxExtended
|
||||
Private WithEvents CMB_ACCOUNT As PersonalUtilities.Forms.Controls.ComboBoxExtended
|
||||
Private WithEvents CH_THUMB_ALONG As CheckBox
|
||||
End Class
|
||||
End Namespace
|
||||
@@ -19,6 +19,11 @@ Namespace DownloadObjects.STDownloader
|
||||
Return CMB_ACCOUNT.Text
|
||||
End Get
|
||||
End Property
|
||||
Friend ReadOnly Property ThumbAlong As Boolean
|
||||
Get
|
||||
Return CH_THUMB_ALONG.Checked
|
||||
End Get
|
||||
End Property
|
||||
Friend Sub New()
|
||||
InitializeComponent()
|
||||
MyDefs = New DefaultFormOptions(Me, Settings.Design)
|
||||
@@ -32,6 +37,7 @@ Namespace DownloadObjects.STDownloader
|
||||
TXT_PATH.Text = Settings.LatestSavingPath.Value
|
||||
If TXT_PATH.Text.IsEmptyString Then TXT_PATH.Text = Application.StartupPath.CSFileP.PathWithSeparator
|
||||
TXT_URL_ActionOnTextChanged()
|
||||
CH_THUMB_ALONG.Checked = Settings.STDownloader_SnapshotsKeepWithFiles_ThumbAlong
|
||||
.MyFieldsChecker = New FieldsChecker
|
||||
With .MyFieldsCheckerE
|
||||
.AddControl(Of String)(TXT_URL, TXT_URL.CaptionText)
|
||||
|
||||
@@ -24,18 +24,19 @@ Namespace DownloadObjects.STDownloader
|
||||
Private Sub InitializeComponent()
|
||||
Dim CONTAINER_MAIN As System.Windows.Forms.ToolStripContainer
|
||||
Dim TP_MAIN As System.Windows.Forms.TableLayoutPanel
|
||||
Dim ActionButton1 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()
|
||||
Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(DownloaderUrlsArrForm))
|
||||
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 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 ActionButton7 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||
Dim ActionButton8 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||
Dim ActionButton9 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton()
|
||||
Dim ListColumn3 As PersonalUtilities.Forms.Controls.Base.ListColumn = New PersonalUtilities.Forms.Controls.Base.ListColumn()
|
||||
Dim ListColumn4 As PersonalUtilities.Forms.Controls.Base.ListColumn = New PersonalUtilities.Forms.Controls.Base.ListColumn()
|
||||
Dim FRM_URLS As System.Windows.Forms.GroupBox
|
||||
Dim ActionButton5 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()
|
||||
Me.TXT_OUTPUT = New PersonalUtilities.Forms.Controls.ComboBoxExtended()
|
||||
Me.TXT_URLS = New System.Windows.Forms.TextBox()
|
||||
Me.CMB_ACCOUNT = New PersonalUtilities.Forms.Controls.ComboBoxExtended()
|
||||
Me.CH_THUMB_ALONG = New System.Windows.Forms.CheckBox()
|
||||
CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer()
|
||||
TP_MAIN = New System.Windows.Forms.TableLayoutPanel()
|
||||
FRM_URLS = New System.Windows.Forms.GroupBox()
|
||||
@@ -68,50 +69,52 @@ Namespace DownloadObjects.STDownloader
|
||||
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.TXT_OUTPUT, 0, 0)
|
||||
TP_MAIN.Controls.Add(FRM_URLS, 0, 2)
|
||||
TP_MAIN.Controls.Add(FRM_URLS, 0, 3)
|
||||
TP_MAIN.Controls.Add(Me.CMB_ACCOUNT, 0, 1)
|
||||
TP_MAIN.Controls.Add(Me.CH_THUMB_ALONG, 0, 2)
|
||||
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 = 3
|
||||
TP_MAIN.RowCount = 4
|
||||
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, 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.Percent, 100.0!))
|
||||
TP_MAIN.Size = New System.Drawing.Size(384, 261)
|
||||
TP_MAIN.TabIndex = 0
|
||||
'
|
||||
'TXT_OUTPUT
|
||||
'
|
||||
ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton1.Name = "Open"
|
||||
ActionButton1.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Open
|
||||
ActionButton1.ToolTipText = "Choose a new location (Ctrl+O)"
|
||||
ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton2.Name = "Add"
|
||||
ActionButton2.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Add
|
||||
ActionButton2.ToolTipText = "Choose a new location and add it to the list (Alt+O)"
|
||||
ActionButton3.BackgroundImage = CType(resources.GetObject("ActionButton3.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton3.Name = "Clear"
|
||||
ActionButton3.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
||||
ActionButton4.BackgroundImage = CType(resources.GetObject("ActionButton4.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton4.Name = "ArrowDown"
|
||||
ActionButton4.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.ArrowDown
|
||||
Me.TXT_OUTPUT.Buttons.Add(ActionButton1)
|
||||
Me.TXT_OUTPUT.Buttons.Add(ActionButton2)
|
||||
Me.TXT_OUTPUT.Buttons.Add(ActionButton3)
|
||||
Me.TXT_OUTPUT.Buttons.Add(ActionButton4)
|
||||
ActionButton6.BackgroundImage = CType(resources.GetObject("ActionButton6.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton6.Name = "Open"
|
||||
ActionButton6.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Open
|
||||
ActionButton6.ToolTipText = "Choose a new location (Ctrl+O)"
|
||||
ActionButton7.BackgroundImage = CType(resources.GetObject("ActionButton7.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton7.Name = "Add"
|
||||
ActionButton7.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Add
|
||||
ActionButton7.ToolTipText = "Choose a new location and add it to the list (Alt+O)"
|
||||
ActionButton8.BackgroundImage = CType(resources.GetObject("ActionButton8.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton8.Name = "Clear"
|
||||
ActionButton8.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear
|
||||
ActionButton9.BackgroundImage = CType(resources.GetObject("ActionButton9.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton9.Name = "ArrowDown"
|
||||
ActionButton9.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.ArrowDown
|
||||
Me.TXT_OUTPUT.Buttons.Add(ActionButton6)
|
||||
Me.TXT_OUTPUT.Buttons.Add(ActionButton7)
|
||||
Me.TXT_OUTPUT.Buttons.Add(ActionButton8)
|
||||
Me.TXT_OUTPUT.Buttons.Add(ActionButton9)
|
||||
Me.TXT_OUTPUT.CaptionText = "Output path"
|
||||
Me.TXT_OUTPUT.CaptionWidth = 70.0R
|
||||
ListColumn1.Name = "COL_NAME"
|
||||
ListColumn1.Text = "Name"
|
||||
ListColumn1.Width = -1
|
||||
ListColumn2.DisplayMember = True
|
||||
ListColumn2.Name = "COL_VALUE"
|
||||
ListColumn2.Text = "Value"
|
||||
ListColumn2.ValueMember = True
|
||||
ListColumn2.Visible = False
|
||||
Me.TXT_OUTPUT.Columns.Add(ListColumn1)
|
||||
Me.TXT_OUTPUT.Columns.Add(ListColumn2)
|
||||
ListColumn3.Name = "COL_NAME"
|
||||
ListColumn3.Text = "Name"
|
||||
ListColumn3.Width = -1
|
||||
ListColumn4.DisplayMember = True
|
||||
ListColumn4.Name = "COL_VALUE"
|
||||
ListColumn4.Text = "Value"
|
||||
ListColumn4.ValueMember = True
|
||||
ListColumn4.Visible = False
|
||||
Me.TXT_OUTPUT.Columns.Add(ListColumn3)
|
||||
Me.TXT_OUTPUT.Columns.Add(ListColumn4)
|
||||
Me.TXT_OUTPUT.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.TXT_OUTPUT.ListAutoCompleteMode = PersonalUtilities.Forms.Controls.ComboBoxExtended.AutoCompleteModes.Disabled
|
||||
Me.TXT_OUTPUT.Location = New System.Drawing.Point(3, 3)
|
||||
@@ -124,9 +127,9 @@ Namespace DownloadObjects.STDownloader
|
||||
'
|
||||
FRM_URLS.Controls.Add(Me.TXT_URLS)
|
||||
FRM_URLS.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
FRM_URLS.Location = New System.Drawing.Point(3, 59)
|
||||
FRM_URLS.Location = New System.Drawing.Point(3, 84)
|
||||
FRM_URLS.Name = "FRM_URLS"
|
||||
FRM_URLS.Size = New System.Drawing.Size(378, 199)
|
||||
FRM_URLS.Size = New System.Drawing.Size(378, 174)
|
||||
FRM_URLS.TabIndex = 2
|
||||
FRM_URLS.TabStop = False
|
||||
FRM_URLS.Text = "URLs (new line as delimiter)"
|
||||
@@ -139,15 +142,15 @@ Namespace DownloadObjects.STDownloader
|
||||
Me.TXT_URLS.Multiline = True
|
||||
Me.TXT_URLS.Name = "TXT_URLS"
|
||||
Me.TXT_URLS.ScrollBars = System.Windows.Forms.ScrollBars.Both
|
||||
Me.TXT_URLS.Size = New System.Drawing.Size(372, 180)
|
||||
Me.TXT_URLS.Size = New System.Drawing.Size(372, 155)
|
||||
Me.TXT_URLS.TabIndex = 0
|
||||
'
|
||||
'CMB_ACCOUNT
|
||||
'
|
||||
ActionButton5.BackgroundImage = CType(resources.GetObject("ActionButton5.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton5.Name = "ArrowDown"
|
||||
ActionButton5.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.ArrowDown
|
||||
Me.CMB_ACCOUNT.Buttons.Add(ActionButton5)
|
||||
ActionButton10.BackgroundImage = CType(resources.GetObject("ActionButton10.BackgroundImage"), System.Drawing.Image)
|
||||
ActionButton10.Name = "ArrowDown"
|
||||
ActionButton10.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.ArrowDown
|
||||
Me.CMB_ACCOUNT.Buttons.Add(ActionButton10)
|
||||
Me.CMB_ACCOUNT.CaptionMode = PersonalUtilities.Forms.Controls.Base.ICaptionControl.Modes.Label
|
||||
Me.CMB_ACCOUNT.CaptionText = "Account"
|
||||
Me.CMB_ACCOUNT.CaptionToolTipEnabled = True
|
||||
@@ -161,6 +164,17 @@ Namespace DownloadObjects.STDownloader
|
||||
Me.CMB_ACCOUNT.TabIndex = 1
|
||||
Me.CMB_ACCOUNT.TextBoxBorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
|
||||
'
|
||||
'CH_THUMB_ALONG
|
||||
'
|
||||
Me.CH_THUMB_ALONG.AutoSize = True
|
||||
Me.CH_THUMB_ALONG.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.CH_THUMB_ALONG.Location = New System.Drawing.Point(3, 59)
|
||||
Me.CH_THUMB_ALONG.Name = "CH_THUMB_ALONG"
|
||||
Me.CH_THUMB_ALONG.Size = New System.Drawing.Size(378, 19)
|
||||
Me.CH_THUMB_ALONG.TabIndex = 3
|
||||
Me.CH_THUMB_ALONG.Text = "Save thumbnail with file"
|
||||
Me.CH_THUMB_ALONG.UseVisualStyleBackColor = True
|
||||
'
|
||||
'DownloaderUrlsArrForm
|
||||
'
|
||||
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
|
||||
@@ -177,6 +191,7 @@ Namespace DownloadObjects.STDownloader
|
||||
CONTAINER_MAIN.ResumeLayout(False)
|
||||
CONTAINER_MAIN.PerformLayout()
|
||||
TP_MAIN.ResumeLayout(False)
|
||||
TP_MAIN.PerformLayout()
|
||||
CType(Me.TXT_OUTPUT, System.ComponentModel.ISupportInitialize).EndInit()
|
||||
FRM_URLS.ResumeLayout(False)
|
||||
FRM_URLS.PerformLayout()
|
||||
@@ -187,5 +202,6 @@ Namespace DownloadObjects.STDownloader
|
||||
Private WithEvents TXT_OUTPUT As PersonalUtilities.Forms.Controls.ComboBoxExtended
|
||||
Private WithEvents TXT_URLS As TextBox
|
||||
Private WithEvents CMB_ACCOUNT As PersonalUtilities.Forms.Controls.ComboBoxExtended
|
||||
Private WithEvents CH_THUMB_ALONG As CheckBox
|
||||
End Class
|
||||
End Namespace
|
||||
@@ -124,7 +124,7 @@
|
||||
<value>False</value>
|
||||
</metadata>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="ActionButton1.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<data name="ActionButton6.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
wwAADsMBx2+oZAAAAR5JREFUOE+VkjFqwzAUhn2D9iShRyi+QhYbGujg3ZATZPKYdC6FQhPwlAMkg3dP
|
||||
@@ -135,7 +135,7 @@
|
||||
cMaRN0UdBBkAAAAASUVORK5CYII=
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton2.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<data name="ActionButton7.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6
|
||||
JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsTAAALEwEAmpwYAAADmUlE
|
||||
@@ -157,7 +157,7 @@
|
||||
0AUyNxOP1DOwcaG/8I+/LRB+At7psBnyDBG0AAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton3.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<data name="ActionButton8.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go
|
||||
@@ -165,7 +165,7 @@
|
||||
AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="ActionButton4.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<data name="ActionButton9.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABGdBTUEAALGPC/xhBQAAE65JREFUeF7t
|
||||
3X2sJWddB/DdLi2lQG2hdOHuvfM887J7Cxca4ELTQMDWKigIFpBAEAgi9g+CJpJo9Q8NJhgBiYZIYspL
|
||||
@@ -258,7 +258,7 @@
|
||||
<metadata name="FRM_URLS.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>False</value>
|
||||
</metadata>
|
||||
<data name="ActionButton5.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<data name="ActionButton10.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABGdBTUEAALGPC/xhBQAAE65JREFUeF7t
|
||||
3X2sJWddB/DdLi2lQG2hdOHuvfM887J7Cxca4ELTQMDWKigIFpBAEAgi9g+CJpJo9Q8NJhgBiYZIYspL
|
||||
|
||||
@@ -31,6 +31,11 @@ Namespace DownloadObjects.STDownloader
|
||||
Return CMB_ACCOUNT.Text
|
||||
End Get
|
||||
End Property
|
||||
Friend ReadOnly Property ThumbAlong As Boolean
|
||||
Get
|
||||
Return CH_THUMB_ALONG.Checked
|
||||
End Get
|
||||
End Property
|
||||
Private _UseAccountName As Boolean = False
|
||||
Friend ReadOnly Property UseAccountName As Boolean
|
||||
Get
|
||||
@@ -50,6 +55,7 @@ Namespace DownloadObjects.STDownloader
|
||||
TXT_OUTPUT.Text = Settings.LatestSavingPath.Value.PathWithSeparator
|
||||
If TXT_OUTPUT.Text.IsEmptyString Then TXT_OUTPUT.Text = Application.StartupPath.CSFileP.PathWithSeparator
|
||||
TXT_URLS_TextChanged()
|
||||
CH_THUMB_ALONG.Checked = Settings.STDownloader_SnapshotsKeepWithFiles_ThumbAlong
|
||||
.MyFieldsChecker = New FieldsChecker
|
||||
With .MyFieldsCheckerE
|
||||
.AddControl(Of String)(TXT_OUTPUT, TXT_OUTPUT.CaptionText)
|
||||
|
||||