Compare commits

..

7 Commits

Author SHA1 Message Date
Andy
a446df1f66 2023.9.20.0 2023-09-20 12:17:00 +03:00
Andy
0026e905a4 2023.9.19.0
YT: add priority download protocol
2023-09-19 12:55:53 +03:00
Andy
f8116fd048 2023.9.18.0
API.Instagram: handle error 500; fix saved posts bug
API.Reddit: disable token refresh if there are no profiles to download
API.UserDataBind: consolidate colors; update labels only for the added user
AutoDownloader: change pause event; update pause function for scheduler; fix incorrect pause in scheduler; add icon for SchedulerEditorForm
2023-09-18 07:54:26 +03:00
Andy
8d33fdc8f3 Update README.md 2023-09-18 07:34:00 +03:00
Andy
dab94acc32 2023.9.6.0
Add scheduler changer
2023-09-06 23:38:16 +03:00
Andy
c61c817585 2023.9.3.0
API.Instagram: add user (non-pinned) stories
API.UserDataBase: fix 'StartMD5Checked' initial value
2023-09-03 19:54:01 +03:00
Andy
3ea59a6acd 2023.8.27.0
YT: fix 'Shorts' downloading
2023-09-03 19:38:18 +03:00
26 changed files with 386 additions and 116 deletions

View File

@@ -1,3 +1,19 @@
# 2023.9.20.0
*2023-09-20*
- Added
- **Instagram: user active (non-pinned) stories (Issue #17)**
- Reddit: reduce the number of token updates (refresh the token if there are Reddit users in the download queue)
- YouTube (standalone app): priority download protocol *(`Settings` - `Defaults` - `Protocol`)* (you can now select the default protocol you want to download media on: `Any`, `https`, `m3u8`))
- Automation: ability to change schedulers (`Download` - `Automation` - `Script icon`)
- Collections: update colors for the added user
- Fixed
- YouTube: can't detect `shorts` links
- Incorrect MD5 validation initial value
- Instagram: handle error 500
- Collections: update labels only for the added user
# 2023.8.27.0
*2023-08-27*

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

@@ -1,5 +1,5 @@
# :rainbow_flag: Happy LGBT Pride Month :tada:
<!-- # :rainbow_flag: Happy LGBT Pride Month :tada:
-->
# :rainbow_flag: Social networks crawler :rainbow_flag:
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/AAndyProgram/SCrawler)](https://github.com/AAndyProgram/SCrawler/releases/latest)
@@ -189,6 +189,10 @@ F5-->[*]
# Contact me
Discord server: https://discord.gg/uFNUXvFFmg
[e-mail](mailto:andyprogram@proton.me): andyprogram@proton.me
<!--
[e-mail](mailto:andyprogram@proton.me): andyprogram@proton.me
Matrix (Element): https://matrix.to/#/@andyprogram:matrix.org
@@ -198,3 +202,4 @@ Discord (contact the developer): andyprogram
Discord server: https://discord.gg/uFNUXvFFmg
[Wire](https://account.wire.com/user-profile/?id=93985052-cf2c-4b72-ac75-bbe3231cf544): @andyprogram
-->

View File

@@ -6,6 +6,10 @@
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY
Imports System.Drawing.Design
Imports System.ComponentModel
Imports PersonalUtilities.Tools.Grid.Attributes
Imports PersonalUtilities.Tools.Grid.EnumObjects
Namespace API.YouTube.Base
Public Structure Thumbnail : Implements IIndexable, IComparable(Of Thumbnail)
Public ID As String
@@ -47,6 +51,14 @@ Namespace API.YouTube.Base
Channel = 2
PlayList = 3
End Enum
<Editor(GetType(EnumDropDownEditor), GetType(UITypeEditor))>
Public Enum Protocols As Integer
<EnumValue(ExcludeFromList:=True)>
Undefined = -1
Any = 0
https = 1
m3u8 = 2
End Enum
Public Structure MediaObject : Implements IIndexable, IComparable(Of MediaObject)
Public Type As Plugin.UserMediaTypes
Public ID As String
@@ -59,6 +71,17 @@ Namespace API.YouTube.Base
Public Size As Double
Public Codec As String
Public Protocol As String
Public ReadOnly Property ProtocolType As Protocols
Get
If Not Protocol.IsEmptyString Then
Select Case Protocol.StringToLower.StringTrim
Case "http", "https" : Return Protocols.https
Case "m3u8" : Return Protocols.m3u8
End Select
End If
Return Protocols.Undefined
End Get
End Property
Public URL As String
Public Property Index As Integer Implements IIndexable.Index
Private Function SetIndex(ByVal Obj As Object, ByVal Index As Integer) As Object Implements IIndexable.SetIndex

View File

@@ -23,17 +23,19 @@ Namespace API.YouTube.Base
Public Shared Function IsMyUrl(ByVal URL As String) As Boolean
Return Not Info_GetUrlType(URL) = YouTubeMediaType.Undefined
End Function
Public Shared Function Info_GetUrlType(ByVal URL As String, Optional ByRef IsMusic As Boolean = False,
Public Shared Function Info_GetUrlType(ByVal URL As String, Optional ByRef IsMusic As Boolean = False, Optional ByRef IsShorts As Boolean = False,
Optional ByRef IsChannelUser As Boolean = False, Optional ByRef Id As String = Nothing) As YouTubeMediaType
If Not URL.IsEmptyString Then
IsMusic = URL.Contains("music.youtube.com")
IsChannelUser = False
IsShorts = False
Dim data As List(Of String) = RegexReplace(URL, RParams.DMS(UrlTypePattern, 0, RegexReturn.ListByMatch, EDP.ReturnValue))
If data.ListExists Then
If data.Count >= 6 Then Id = data(5)
If data.Count >= 3 And Not data(2).IsEmptyString Then
Select Case data(2).ToLower
Case "watch" : Return YouTubeMediaType.Single
Case "shorts" : IsShorts = True : Return YouTubeMediaType.Single
Case "playlist" : Return YouTubeMediaType.PlayList
Case UserChannelOption, "@" : IsChannelUser = data(2).ToLower = UserChannelOption : Return YouTubeMediaType.Channel
End Select
@@ -64,8 +66,8 @@ Namespace API.YouTube.Base
Dim urlOrig$ = URL
URL = RegexReplace(URL, TrueUrlRegEx)
If URL.IsEmptyString Then Throw New ArgumentNullException("URL", $"Can't get true URL from [{urlOrig}]")
Dim isMusic As Boolean = False
Dim objType As YouTubeMediaType = Info_GetUrlType(URL, isMusic)
Dim isMusic As Boolean = False, isShorts As Boolean = False
Dim objType As YouTubeMediaType = Info_GetUrlType(URL, isMusic, isShorts)
If Not objType = YouTubeMediaType.Undefined Then
Dim __GetDefault As Boolean = If(GetDefault, True)
Dim __GetShorts As Boolean = If(GetShorts, True)
@@ -105,7 +107,7 @@ Namespace API.YouTube.Base
If result Then
container.Parse(Nothing, _CachePathDefault, isMusic, Token, Progress)
If Not container.HasError Then container.URL = URL : Return container
If Not container.HasError Then container.URL = URL : container.IsShorts = isShorts : Return container
End If
container.Dispose()
End If

View File

@@ -139,6 +139,9 @@ Namespace API.YouTube.Base
<Browsable(True), GridVisible, XMLVN({"Defaults"}), Category("Defaults"), DisplayName("Use cookies"),
Description("By default, use cookies when downloading from YouTube.")>
Public ReadOnly Property DefaultUseCookies As XMLValue(Of Boolean)
<Browsable(True), GridVisible, XMLVN({"Defaults"}, Protocols.Any), Category("Defaults"), DisplayName("Protocol"),
Description("Priority download protocol. Default: 'Any'")>
Public ReadOnly Property DefaultProtocol As XMLValue(Of Protocols)
<Browsable(True), GridVisible(False), XMLVN({"Defaults"}), Category("Defaults"),
DisplayName("Auto remove"), Description("Automatically remove downloaded items from the list.")>
Public ReadOnly Property RemoveDownloadedAutomatically As XMLValue(Of Boolean)

View File

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

View File

@@ -25,6 +25,7 @@ Namespace API.YouTube.Objects
ReadOnly Property MediaType As UMTypes
ReadOnly Property MediaState As UMStates
Property IsMusic As Boolean
Property IsShorts As Boolean
Property ID As String
Property Description As String
Property PlaylistID As String

View File

@@ -112,7 +112,7 @@ Namespace API.YouTube.Objects
End Set
End Property
<XMLEC(Name_IsMusic)> Public Property IsMusic As Boolean = False Implements IYouTubeMediaContainer.IsMusic
<XMLEC> Public Property IsShorts As Boolean = False
<XMLEC> Public Property IsShorts As Boolean = False Implements IYouTubeMediaContainer.IsShorts
<XMLEC> Public Property ID As String Implements IYouTubeMediaContainer.ID, IUserMedia.PostID
<XMLEC> Public Property Title As String Implements IDownloadableMedia.Title
<XMLEC> Public Property Description As String Implements IYouTubeMediaContainer.Description
@@ -1309,9 +1309,29 @@ Namespace API.YouTube.Objects
Next
End If
End Sub
Dim protocolCleaner As Action =
Sub()
If Not MyYouTubeSettings.DefaultProtocol.Value = Protocols.Undefined And
Not MyYouTubeSettings.DefaultProtocol.Value = Protocols.Any Then
Dim data As New List(Of MediaObject)(MediaObjects.Where(Function(mo) mo.ProtocolType = MyYouTubeSettings.DefaultProtocol.Value))
If data.ListExists Then
Dim dRem As Protocols = IIf(MyYouTubeSettings.DefaultProtocol.Value = Protocols.https, Protocols.m3u8, Protocols.https)
Dim d As MediaObject
Dim dr As New FPredicate(Of MediaObject)(Function(mo) mo.Height = d.Height And mo.ProtocolType = dRem)
For Each d In data
If MediaObjects.Count = 0 Then
Exit For
ElseIf MediaObjects.LongCount(dr) > 0 Then
MediaObjects.RemoveAll(dr)
End If
Next
End If
End If
End Sub
If MediaObjects.Count > 0 And Not MyYouTubeSettings.DefaultVideoIncludeNullSize Then MediaObjects.RemoveAll(Function(mo) mo.Size <= 0)
If MediaObjects.Count > 0 Then DupRemover.Invoke(UMTypes.Audio)
If MediaObjects.Count > 0 Then DupRemover.Invoke(UMTypes.Video)
If MediaObjects.Count > 0 Then protocolCleaner.Invoke
If MediaObjects.Count > 0 Then
MediaObjects.Sort()
SelectedAudioIndex = MediaObjects.FindIndex(Function(mo) mo.Type = UMTypes.Audio)

View File

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

View File

@@ -1371,7 +1371,7 @@ BlockNullPicture:
#Region "MD5 support"
Protected Const VALIDATE_MD5_ERROR As String = "VALIDATE_MD5_ERROR"
Friend Property UseMD5Comparison As Boolean = False
Protected Property StartMD5Checked As Boolean = True
Protected Property StartMD5Checked As Boolean = False
Friend Property RemoveExistingDuplicates As Boolean = False
Protected Overridable Sub ValidateMD5(ByVal Token As CancellationToken)
Try

View File

@@ -11,14 +11,17 @@ Namespace API.Instagram
Friend Class EditorExchangeOptions
<PSetting(Caption:="Get timeline", ToolTip:="Download user timeline")>
Friend Property GetTimeline As Boolean
<PSetting(Caption:="Get stories", ToolTip:="Download user stories")>
<PSetting(Caption:="Get stories", ToolTip:="Download user stories (pinned)")>
Friend Property GetStories As Boolean
<PSetting(Caption:="Get stories: user", ToolTip:="Download user stories")>
Friend Property GetStoriesUser As Boolean
<PSetting(Caption:="Get tagged posts", ToolTip:="Download user tagged posts")>
Friend Property GetTagged As Boolean
Friend Sub New(ByVal u As UserData)
With u
GetTimeline = .GetTimeline
GetStories = .GetStories
GetStoriesUser = .GetStoriesUser
GetTagged = .GetTaggedData
End With
End Sub
@@ -26,6 +29,7 @@ Namespace API.Instagram
With s
GetTimeline = CBool(.GetTimeline.Value)
GetStories = CBool(.GetStories.Value)
GetStoriesUser = CBool(.GetStoriesUser.Value)
GetTagged = CBool(.GetTagged.Value)
End With
End Sub

View File

@@ -139,11 +139,13 @@ Namespace API.Instagram
Friend ReadOnly Property GetTimeline As PropertyValue
<PropertyOption(ControlText:="Get stories", ControlToolTip:="Default value for new users"), PXML, ControlNumber(24)>
Friend ReadOnly Property GetStories As PropertyValue
<PropertyOption(ControlText:="Get tagged photos", ControlToolTip:="Default value for new users"), PXML, ControlNumber(25)>
<PropertyOption(ControlText:="Get stories: user", ControlToolTip:="Default value for new users"), PXML, ControlNumber(25)>
Friend ReadOnly Property GetStoriesUser As PropertyValue
<PropertyOption(ControlText:="Get tagged photos", ControlToolTip:="Default value for new users"), PXML, ControlNumber(26)>
Friend ReadOnly Property GetTagged As PropertyValue
<PropertyOption(ControlText:="Tagged notify limit",
ControlToolTip:="If the number of tagged posts exceeds this number you will be notified." & vbCr &
"-1 to disable"), PXML, ControlNumber(26)>
"-1 to disable"), PXML, ControlNumber(27)>
Friend ReadOnly Property TaggedNotifyLimit As PropertyValue
<Provider(NameOf(TaggedNotifyLimit), FieldsChecker:=True)>
Private ReadOnly Property TaggedNotifyLimitProvider As IFormatProvider
@@ -153,7 +155,9 @@ Namespace API.Instagram
Friend ReadOnly Property DownloadTimeline As PropertyValue
<PropertyOption(ControlText:="Download stories", ControlToolTip:="Download stories"), PXML, ControlNumber(11)>
Friend ReadOnly Property DownloadStories As PropertyValue
<PropertyOption(ControlText:="Download tagged", ControlToolTip:="Download tagged posts"), PXML, ControlNumber(12)>
<PropertyOption(ControlText:="Download stories: user", ControlToolTip:="Download stories (user)"), PXML, ControlNumber(12)>
Friend ReadOnly Property DownloadStoriesUser As PropertyValue
<PropertyOption(ControlText:="Download tagged", ControlToolTip:="Download tagged posts"), PXML, ControlNumber(13)>
Friend ReadOnly Property DownloadTagged As PropertyValue
#End Region
#Region "429 bypass"
@@ -259,6 +263,7 @@ Namespace API.Instagram
DownloadTimeline = New PropertyValue(True)
DownloadStories = New PropertyValue(True)
DownloadStoriesUser = New PropertyValue(True)
DownloadTagged = New PropertyValue(False)
RequestsWaitTimer = New PropertyValue(1000)
@@ -270,6 +275,7 @@ Namespace API.Instagram
GetTimeline = New PropertyValue(True)
GetStories = New PropertyValue(False)
GetStoriesUser = New PropertyValue(False)
GetTagged = New PropertyValue(False)
TaggedNotifyLimit = New PropertyValue(200)
TaggedNotifyLimitProvider = New TaggedNotifyLimitChecker

View File

@@ -24,6 +24,7 @@ Namespace API.Instagram
Private Const Name_FirstLoadingDone As String = "FirstLoadingDone"
Private Const Name_GetTimeline As String = "GetTimeline"
Private Const Name_GetStories As String = "GetStories"
Private Const Name_GetStoriesUser As String = "GetStoriesUser"
Private Const Name_GetTagged As String = "GetTaggedData"
Private Const Name_TaggedChecked As String = "TaggedChecked"
Private Const Name_NameTrue As String = "NameTrue"
@@ -75,6 +76,7 @@ Namespace API.Instagram
Private FirstLoadingDone As Boolean = False
Friend Property GetTimeline As Boolean = True
Friend Property GetStories As Boolean
Friend Property GetStoriesUser As Boolean
Friend Property GetTaggedData As Boolean
Private _NameTrue As String = String.Empty
Private ReadOnly Property NameTrue As String
@@ -84,6 +86,31 @@ Namespace API.Instagram
End Property
Private UserNameRequested As Boolean = False
#End Region
#Region "Loader"
Protected Overrides Sub LoadUserInformation_OptionalFields(ByRef Container As XmlFile, ByVal Loading As Boolean)
With Container
If Loading Then
LastCursor = .Value(Name_LastCursor)
FirstLoadingDone = .Value(Name_FirstLoadingDone).FromXML(Of Boolean)(False)
GetTimeline = .Value(Name_GetTimeline).FromXML(Of Boolean)(CBool(MySiteSettings.GetTimeline.Value))
GetStories = .Value(Name_GetStories).FromXML(Of Boolean)(CBool(MySiteSettings.GetStories.Value))
GetStoriesUser = .Value(Name_GetStoriesUser).FromXML(Of Boolean)(MySiteSettings.GetStoriesUser.Value)
GetTaggedData = .Value(Name_GetTagged).FromXML(Of Boolean)(CBool(MySiteSettings.GetTagged.Value))
TaggedChecked = .Value(Name_TaggedChecked).FromXML(Of Boolean)(False)
_NameTrue = .Value(Name_NameTrue)
Else
.Add(Name_LastCursor, LastCursor)
.Add(Name_FirstLoadingDone, FirstLoadingDone.BoolToInteger)
.Add(Name_GetTimeline, GetTimeline.BoolToInteger)
.Add(Name_GetStories, GetStories.BoolToInteger)
.Add(Name_GetStoriesUser, GetStoriesUser.BoolToInteger)
.Add(Name_GetTagged, GetTaggedData.BoolToInteger)
.Add(Name_TaggedChecked, TaggedChecked.BoolToInteger)
.Add(Name_NameTrue, _NameTrue)
End If
End With
End Sub
#End Region
#Region "Exchange options"
Friend Overrides Function ExchangeOptionsGet() As Object
Return New EditorExchangeOptions(Me)
@@ -93,37 +120,17 @@ Namespace API.Instagram
With DirectCast(Obj, EditorExchangeOptions)
GetTimeline = .GetTimeline
GetStories = .GetStories
GetStoriesUser = .GetStoriesUser
GetTaggedData = .GetTagged
End With
End If
End Sub
#End Region
#Region "Initializer, loader"
#Region "Initializer"
Friend Sub New()
PostsKVIDs = New List(Of PostKV)
PostsToReparse = New List(Of PostKV)
End Sub
Protected Overrides Sub LoadUserInformation_OptionalFields(ByRef Container As XmlFile, ByVal Loading As Boolean)
With Container
If Loading Then
LastCursor = .Value(Name_LastCursor)
FirstLoadingDone = .Value(Name_FirstLoadingDone).FromXML(Of Boolean)(False)
GetTimeline = .Value(Name_GetTimeline).FromXML(Of Boolean)(CBool(MySiteSettings.GetTimeline.Value))
GetStories = .Value(Name_GetStories).FromXML(Of Boolean)(CBool(MySiteSettings.GetStories.Value))
GetTaggedData = .Value(Name_GetTagged).FromXML(Of Boolean)(CBool(MySiteSettings.GetTagged.Value))
TaggedChecked = .Value(Name_TaggedChecked).FromXML(Of Boolean)(False)
_NameTrue = .Value(Name_NameTrue)
Else
.Add(Name_LastCursor, LastCursor)
.Add(Name_FirstLoadingDone, FirstLoadingDone.BoolToInteger)
.Add(Name_GetTimeline, GetTimeline.BoolToInteger)
.Add(Name_GetStories, GetStories.BoolToInteger)
.Add(Name_GetTagged, GetTaggedData.BoolToInteger)
.Add(Name_TaggedChecked, TaggedChecked.BoolToInteger)
.Add(Name_NameTrue, _NameTrue)
End If
End With
End Sub
#End Region
#Region "Download data"
Private E560Thrown As Boolean = False
@@ -234,6 +241,7 @@ Namespace API.Instagram
If FirstLoadingDone Then LastCursor = String.Empty
If Not IsSavedPosts AndAlso MySiteSettings.BaseAuthExists() Then
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 ACheck(MySiteSettings.HashTagged.Value) And GetTaggedData Then s = Sections.Tagged : DownloadData(String.Empty, s, Token) : ProgressPre.Done()
End If
If WaitNotificationMode = WNM.SkipTemp Or WaitNotificationMode = WNM.SkipCurrent Then WaitNotificationMode = WNM.Notify
@@ -275,7 +283,7 @@ Namespace API.Instagram
Private Sub Responser_ResponseReceived(ByVal Sender As Object, ByVal e As EventArguments.WebDataResponse)
Declarations.UpdateResponser(e, Responser)
End Sub
Private Enum Sections : Timeline : Tagged : Stories : SavedPosts : End Enum
Private Enum Sections : Timeline : Tagged : Stories : UserStories : SavedPosts : End Enum
Private Const StoriesFolder As String = "Stories"
Private Const TaggedFolder As String = "Tagged"
#Region "429 bypass"
@@ -455,7 +463,7 @@ Namespace API.Instagram
ThrowAny(Token)
End If
If StoriesList.ListExists Then
GetStoriesData(StoriesList, Token)
GetStoriesData(StoriesList, False, Token)
MySiteSettings.TooManyRequests(False)
RequestsCount += 1
End If
@@ -464,6 +472,11 @@ Namespace API.Instagram
Else
Throw New ExitException
End If
Case Sections.UserStories
GetStoriesData(Nothing, True, Token)
MySiteSettings.TooManyRequests(False)
RequestsCount += 1
Throw New ExitException
End Select
'Get response
@@ -624,10 +637,8 @@ Namespace API.Instagram
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 Then
DefaultParser(nodes, Sections.SavedPosts, Token)
If HasNextPage And Not NextCursor.IsEmptyString Then SavedPostsDownload(NextCursor, Token)
End If
If nodes.ListExists AndAlso DefaultParser(nodes, Sections.SavedPosts, Token) AndAlso
HasNextPage AndAlso Not NextCursor.IsEmptyString Then SavedPostsDownload(NextCursor, Token)
End If
End Using
End If
@@ -854,17 +865,21 @@ Namespace API.Instagram
End Function
#End Region
#Region "Pinned stories"
Private Sub GetStoriesData(ByRef StoriesList As List(Of String), ByVal Token As CancellationToken)
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)
Dim tmpList As IEnumerable(Of String) = Nothing
Dim qStr$, r$, sFolder$, storyID$, pid$
Dim i% = -1
Dim jj As EContainer, s As EContainer
ThrowAny(Token)
If StoriesList.ListExists Then
tmpList = StoriesList.Take(5)
If tmpList.ListExists Then
qStr = String.Format(ReqUrl, tmpList.Select(Function(q) $"reel_ids=highlight:{q}").ListToString("&"))
If StoriesList.ListExists Or GetUserStory Then
If Not GetUserStory Then tmpList = StoriesList.Take(5)
If tmpList.ListExists Or GetUserStory Then
If GetUserStory Then
qStr = $"https://www.instagram.com/api/v1/feed/reels_media/?reel_ids={ID}"
Else
qStr = String.Format(ReqUrl, tmpList.Select(Function(q) $"reel_ids=highlight:{q}").ListToString("&"))
End If
r = Responser.GetResponse(qStr,, EDP.ThrowException)
ThrowAny(Token)
If Not r.IsEmptyString Then
@@ -876,9 +891,13 @@ Namespace API.Instagram
i += 1
sFolder = jj.Value("title").StringRemoveWinForbiddenSymbols
storyID = jj.Value("id").Replace("highlight:", String.Empty)
If sFolder.IsEmptyString Then sFolder = $"Story_{storyID}"
If sFolder.IsEmptyString Then sFolder = $"Story_{i}"
sFolder = $"{StoriesFolder}\{sFolder}"
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
@@ -896,7 +915,7 @@ Namespace API.Instagram
End If
End Using
End If
StoriesList.RemoveRange(0, tmpList.Count)
If Not GetUserStory Then StoriesList.RemoveRange(0, tmpList.Count)
End If
End If
End Sub
@@ -933,15 +952,15 @@ Namespace API.Instagram
''' </summary>
Protected Overrides Function DownloadingException(ByVal ex As Exception, ByVal Message As String, Optional ByVal FromPE As Boolean = False,
Optional ByVal s As Object = Nothing) As Integer
If Responser.StatusCode = HttpStatusCode.NotFound Then
If Responser.StatusCode = HttpStatusCode.NotFound Then '404
If Not UserNameRequested AndAlso GetUserNameById() Then Return 1 Else UserExists = False
ElseIf Responser.StatusCode = HttpStatusCode.BadRequest Then
ElseIf Responser.StatusCode = HttpStatusCode.BadRequest Then '400
HasError = True
MyMainLOG = $"Instagram credentials have expired [{CInt(Responser.StatusCode)}]: {ToStringForLog()} [{s}]"
DisableSection(s)
ElseIf Responser.StatusCode = HttpStatusCode.Forbidden And s = Sections.Tagged Then
ElseIf Responser.StatusCode = HttpStatusCode.Forbidden And s = Sections.Tagged Then '403
Return 3
ElseIf Responser.StatusCode = 429 Then
ElseIf Responser.StatusCode = 429 Then '429
With MySiteSettings
Dim WaiterExists As Boolean = .LastApplyingValue.HasValue
.TooManyRequests(True)
@@ -950,10 +969,10 @@ Namespace API.Instagram
Caught429 = True
MyMainLOG = $"Number of requests before error 429: {RequestsCount}"
Return 1
ElseIf Responser.StatusCode = 560 Then
ElseIf Responser.StatusCode = 560 Or Responser.StatusCode = HttpStatusCode.InternalServerError Then '560, 500
MySiteSettings.SkipUntilNextSession = True
Else
MyMainLOG = $"Something is wrong. Your credentials may have expired [{CInt(Responser.StatusCode)}]: {ToString()} [{s}]"
MyMainLOG = $"Something is wrong. Your credentials may have expired [{CInt(Responser.StatusCode)}/{CInt(Responser.Status)}]: {ToString()} [{s}]"
DisableSection(s)
If Not FromPE Then LogError(ex, Message) : HasError = True
Return 0
@@ -965,6 +984,10 @@ Namespace API.Instagram
Dim s As Sections = DirectCast(Section, Sections)
Select Case s
Case Sections.Timeline : MySiteSettings.DownloadTimeline.Value = False
Case Sections.Stories, Sections.UserStories
MySiteSettings.DownloadTimeline.Value = False
MySiteSettings.DownloadStories.Value = False
MySiteSettings.DownloadStoriesUser.Value = False
Case Else : MySiteSettings.DownloadTagged.Value = False
End Select
MyMainLOG = $"[{s}] downloading is disabled until you update your credentials".ToUpper

View File

@@ -104,12 +104,45 @@ Namespace API.Reddit
Return New UserData
End Function
#End Region
#Region "Available, UpdateRedGifsToken"
#Region "DownloadStarted, ReadyToDownload, Available, DownloadDone, UpdateRedGifsToken"
Private ____DownloadStarted As Boolean = False
Friend Overrides Sub DownloadStarted(ByVal What As Download)
If What = Download.Main Then ____DownloadStarted = True
MyBase.DownloadStarted(What)
End Sub
Friend Property SessionInterrupted As Boolean = False
Friend Overrides Function ReadyToDownload(ByVal What As Download) As Boolean
If What = Download.Main Then Return Not SessionInterrupted Else Return True
If What = Download.Main Then
Dim result As Boolean = Not SessionInterrupted
If result Then
If ____DownloadStarted And ____AvailableRequested Then
____AvailableResult = AvailableImpl(What, ____AvailableSilent)
____AvailableChecked = True
____AvailableRequested = False
result = ____AvailableResult
ElseIf ____AvailableChecked Then
result = ____AvailableResult
End If
End If
Return result
Else
Return True
End If
End Function
Private ____AvailableRequested As Boolean = False
Private ____AvailableSilent As Boolean = True
Private ____AvailableChecked As Boolean = False
Private ____AvailableResult As Boolean = False
Friend Overrides Function Available(ByVal What As Download, ByVal Silent As Boolean) As Boolean
If What = Download.Main And ____DownloadStarted Then
____AvailableRequested = True
____AvailableSilent = Silent
Return True
Else
Return AvailableImpl(What, Silent)
End If
End Function
Private Function AvailableImpl(ByVal What As Download, ByVal Silent As Boolean) As Boolean
Try
Dim trueValue As Boolean = Not What = Download.SavedPosts OrElse (Responser.CookiesExists And ACheck(SavedPostsUserName.Value))
If Not trueValue Then Return False
@@ -141,6 +174,11 @@ Namespace API.Reddit
End Function
Friend Overrides Sub DownloadDone(ByVal What As Download)
SessionInterrupted = False
____DownloadStarted = False
____AvailableRequested = False
____AvailableChecked = False
____AvailableSilent = True
____AvailableResult = False
MyBase.DownloadDone(What)
End Sub
Private Sub UpdateRedGifsToken()

View File

@@ -507,8 +507,9 @@ Namespace API
.Temporary = Temporary
.Favorite = Favorite
.ReadyForDownload = ReadyForDownload
ConsolidateLabels()
ConsolidateLabels(_Item)
ConsolidateScripts()
ConsolidateColors(_Item)
.UpdateUserInformation()
End If
MainFrameObj.ImageHandler(_Item, False)
@@ -546,12 +547,22 @@ Namespace API
Catch ex As Exception
End Try
End Sub
Private Sub ConsolidateLabels()
UpdateLabels(Me, ListAddList(Nothing, Labels.ListWithRemove(SpecialLabels)), 1, True)
Private Sub ConsolidateLabels(ByVal Destination As UserDataBase)
UpdateLabels(If(Destination, Me), ListAddList(Nothing, Labels.ListWithRemove(SpecialLabels)), 1, True)
End Sub
Private Sub ConsolidateScripts()
If Count > 1 AndAlso ScriptUse Then Collections.ForEach(Sub(c) c.ScriptUse = True)
End Sub
Private Sub ConsolidateColors(ByVal Destination As UserDataBase)
If Count > 0 And Not Destination.ForeColor.HasValue And Not Destination.BackColor.HasValue Then
Dim b As Color? = BackColor
Dim f As Color? = ForeColor
If b.HasValue AndAlso Not Collections.All(Function(u) Not u Is Destination AndAlso u.BackColor.HasValue AndAlso u.BackColor.Value = b.Value) Then b = Nothing
If f.HasValue AndAlso Not Collections.All(Function(u) Not u Is Destination AndAlso u.ForeColor.HasValue AndAlso u.ForeColor.Value = f.Value) Then f = Nothing
If b.HasValue Then Destination.BackColor = b
If f.HasValue Then Destination.ForeColor = f
End If
End Sub
#End Region
#Region "Move, Merge"
Friend Overrides Function MoveFiles(ByVal __CollectionName As String, ByVal __SpecialCollectionPath As SFile) As Boolean

View File

@@ -82,7 +82,7 @@ Namespace API.YouTube
Dim isMusic As Boolean = False
Dim id$ = String.Empty
Dim isChannelUser As Boolean = False
Dim t As YouTubeMediaType = YouTubeFunctions.Info_GetUrlType(UserURL, isMusic, isChannelUser, id)
Dim t As YouTubeMediaType = YouTubeFunctions.Info_GetUrlType(UserURL, isMusic,, isChannelUser, id)
If Not t = YouTubeMediaType.Undefined And Not t = YouTubeMediaType.Single And Not id.IsEmptyString Then
Return New ExchangeOptions(Site, $"{id}@{CInt(t) + IIf(isMusic, UserMedia.Types.Audio, 0) + IIf(isChannelUser, ChannelUserInt, 0)}")
End If

View File

@@ -15,7 +15,7 @@ Imports PersonalUtilities.Tools
Imports PersonalUtilities.Tools.Notifications
Namespace DownloadObjects
Friend Class AutoDownloader : Inherits GroupParameters : Implements IIndexable, IEContainerProvider
Friend Event PauseDisabled()
Friend Event PauseChanged(ByVal Value As PauseModes)
Friend Enum Modes As Integer
None = 0
[Default] = 1
@@ -412,6 +412,7 @@ Namespace DownloadObjects
Case PauseModes.Until : _PauseValue = DateLimit
Case Else : _PauseValue = Nothing
End Select
RaiseEvent PauseChanged(p)
End Set
End Property
Private ReadOnly Property IsPaused As Boolean
@@ -423,7 +424,7 @@ Namespace DownloadObjects
Else
_Pause = PauseModes.Disabled
_PauseValue = Nothing
RaiseEvent PauseDisabled()
RaiseEvent PauseChanged(_Pause)
Return False
End If
Else

View File

@@ -92,34 +92,39 @@ Namespace DownloadObjects
BTT_PAUSE_H6.Click, BTT_PAUSE_H12.Click,
BTT_PAUSE_UNTIL.Click, BTT_PAUSE_UNLIMITED.Click,
BTT_PAUSE_DISABLE.Click
If (Place = ButtonsPlace.Scheduler And PlanIndex >= 0 And PlanIndex.ValueBetween(0, Settings.Automation.Count - 1)) Or Not Place = ButtonsPlace.Scheduler Then
Dim p As PauseModes = CInt(AConvert(Of Integer)(Sender.Tag, -10))
If p > -10 Then
Dim d As Date? = Nothing
Dim _SetPauseValue As Action = Sub()
If Place = ButtonsPlace.Scheduler And PlanIndex.ValueBetween(0, Settings.Automation.Count - 1) Then
Settings.Automation(PlanIndex).Pause(d) = p
ElseIf Not Place = ButtonsPlace.Scheduler Then
Settings.Automation.Pause(d) = p
End If
End Sub
If p = PauseModes.Until Then
Using f As New DateTimeSelectionForm(TimeSelectionModes.End + TimeSelectionModes.Date + TimeSelectionModes.Time, Settings.Design)
f.ShowDialog()
If f.DialogResult = DialogResult.OK Then d = f.MyDateEnd
End Using
If d.HasValue Then _SetPauseValue.Invoke
Else
_SetPauseValue.Invoke
End If
UpdatePauseButtons()
Dim p As PauseModes = CInt(AConvert(Of Integer)(Sender.Tag, -10))
If p > -10 AndAlso ((Place = ButtonsPlace.Scheduler And PlanIndex >= 0 And PlanIndex.ValueBetween(0, Settings.Automation.Count - 1)) OrElse
Not Place = ButtonsPlace.Scheduler OrElse
(Place = ButtonsPlace.Scheduler AndAlso PlanIndex = -1 AndAlso
MsgBoxE({$"Do you want to turn {IIf(p = PauseModes.Disabled, "off", "on")} pause for all plans?", "Pause plan"},
vbExclamation + vbYesNo) = vbYes)) Then
Dim d As Date? = Nothing
Dim _SetPauseValue As Action = Sub()
If Place = ButtonsPlace.Scheduler And PlanIndex.ValueBetween(0, Settings.Automation.Count - 1) Then
Settings.Automation(PlanIndex).Pause(d) = p
ElseIf Not Place = ButtonsPlace.Scheduler Or Place = ButtonsPlace.Scheduler And PlanIndex = -1 Then
Settings.Automation.Pause(d) = p
End If
End Sub
If p = PauseModes.Until Then
Using f As New DateTimeSelectionForm(TimeSelectionModes.End + TimeSelectionModes.Date + TimeSelectionModes.Time, Settings.Design)
f.ShowDialog()
If f.DialogResult = DialogResult.OK Then d = f.MyDateEnd
End Using
If d.HasValue Then _SetPauseValue.Invoke
Else
_SetPauseValue.Invoke
End If
ElseIf Place = ButtonsPlace.Scheduler And PlanIndex = -1 Then
UpdatePauseButtons()
ElseIf p > -10 And Place = ButtonsPlace.Scheduler And PlanIndex = -1 Then
MsgBoxE({"The plan to be paused is not selected", "Pause plan"}, vbExclamation)
End If
End Sub
#End Region
#Region "Update buttons"
Friend Overloads Sub UpdatePauseButtons_Handler(ByVal Value As PauseModes)
UpdatePauseButtons()
End Sub
Friend Overloads Sub UpdatePauseButtons() Handles TrayButtons.Updating
UpdatePauseButtons(True)
End Sub

View File

@@ -14,12 +14,14 @@ Imports PauseModes = SCrawler.DownloadObjects.AutoDownloader.PauseModes
Namespace DownloadObjects
Friend Class Scheduler : Implements IEnumerable(Of AutoDownloader), IMyEnumerator(Of AutoDownloader), IDisposable
Friend Const Name_Plan As String = "Plan"
Friend Event PauseDisabled As AutoDownloader.PauseDisabledEventHandler
Private Sub OnPauseDisabled()
RaiseEvent PauseDisabled()
Friend Event PauseChanged As AutoDownloader.PauseChangedEventHandler
Private Sub OnPauseChanged(ByVal Value As PauseModes)
RaiseEvent PauseChanged(Pause)
End Sub
Private ReadOnly Plans As List(Of AutoDownloader)
Private ReadOnly File As SFile = $"Settings\AutoDownload.xml"
Friend Const FileNameDefault As String = "AutoDownload"
Friend ReadOnly FileDefault As SFile = $"{SettingsFolderName}\{FileNameDefault}.xml"
Friend File As SFile = Nothing
Private ReadOnly PlanWorking As Predicate(Of AutoDownloader) = Function(Plan) Plan.Working
Private ReadOnly PlanDownloading As Predicate(Of AutoDownloader) = Function(Plan) Plan.Downloading
Private ReadOnly PlansWaiter As Action(Of Predicate(Of AutoDownloader)) = Sub(ByVal Predicate As Predicate(Of AutoDownloader))
@@ -27,20 +29,9 @@ Namespace DownloadObjects
End Sub
Friend Sub New()
Plans = New List(Of AutoDownloader)
If File.Exists Then
Using x As New XmlFile(File,, False) With {.AllowSameNames = True}
x.LoadData()
If x.Contains(Name_Plan) Then
For Each e In x : Plans.Add(New AutoDownloader(e)) : Next
Else
Plans.Add(New AutoDownloader(x))
End If
End Using
End If
If Plans.Count > 0 Then Plans.ForEach(Sub(p)
p.Source = Me
AddHandler p.PauseDisabled, AddressOf OnPauseDisabled
End Sub) : Plans.ListReindex
File = Settings.AutomationFile.Value.IfNullOrEmpty(FileDefault)
If Not File.Exists Then File = FileDefault
Reset(File, True)
End Sub
Default Friend ReadOnly Property Item(ByVal Index As Integer) As AutoDownloader Implements IMyEnumerator(Of AutoDownloader).MyEnumeratorObject
Get
@@ -62,7 +53,7 @@ Namespace DownloadObjects
End Function
Friend Sub Add(ByVal Plan As AutoDownloader)
Plan.Source = Me
AddHandler Plan.PauseDisabled, AddressOf OnPauseDisabled
AddHandler Plan.PauseChanged, AddressOf OnPauseChanged
Plans.Add(Plan)
Plans.ListReindex
Update()
@@ -96,6 +87,39 @@ Namespace DownloadObjects
Catch
End Try
End Sub
Friend Function Reset(ByVal f As SFile, ByVal IsInit As Boolean) As Boolean
If Plans.Count > 0 Then
If Not Plans.Exists(PlanWorking) Then
Pause = PauseModes.Unlimited
If Plans.Exists(PlanWorking) Then
MsgBoxE({$"Some plans are already being worked.{vbCr}Wait for the plans to complete their work and try again.",
"Change scheduler"}, vbCritical)
Pause = PauseModes.Unlimited
Return False
End If
End If
[Stop]()
If _UpdateRequired Then Update()
Plans.ListClearDispose(,, EDP.LogMessageValue)
End If
If f.Exists Then
File = f
Using x As New XmlFile(File,, False) With {.AllowSameNames = True}
x.LoadData()
If x.Contains(Name_Plan) Then
For Each e In x : Plans.Add(New AutoDownloader(e)) : Next
Else
Plans.Add(New AutoDownloader(x))
End If
End Using
If Plans.Count > 0 Then Plans.ForEach(Sub(ByVal p As AutoDownloader)
p.Source = Me
If Not IsInit Then p.Pause = PauseModes.Unlimited
AddHandler p.PauseChanged, AddressOf OnPauseChanged
End Sub) : Plans.ListReindex
End If
Return True
End Function
#Region "Groups Support"
Friend Sub GROUPS_Updated(ByVal Sender As DownloadGroup)
If Count > 0 Then Plans.ForEach(Sub(p) p.GROUPS_Updated(Sender))

View File

@@ -63,7 +63,7 @@ Namespace DownloadObjects
Me.KeyPreview = True
Me.MinimumSize = New System.Drawing.Size(430, 380)
Me.Name = "SchedulerEditorForm"
Me.ShowIcon = False
Me.ShowIcon = True
Me.ShowInTaskbar = False
Me.Text = "Scheduler"
CONTAINER_MAIN.ContentPanel.ResumeLayout(False)

View File

@@ -8,11 +8,14 @@
' but WITHOUT ANY WARRANTY
Imports PersonalUtilities.Forms
Imports PersonalUtilities.Forms.Toolbars
Imports PersonalUtilities.Tools
Imports ECI = PersonalUtilities.Forms.Toolbars.EditToolbar.ControlItem
Imports ADB = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons
Namespace DownloadObjects
Friend Class SchedulerEditorForm
#Region "Declarations"
Private WithEvents MyDefs As DefaultFormOptions
Private WithEvents BTT_SETTINGS As ToolStripButton
Private WithEvents BTT_CLONE As ToolStripButton
Private ReadOnly MENU_SKIP As ToolStripDropDownButton
Private WithEvents BTT_SKIP As ToolStripMenuItem
@@ -28,6 +31,13 @@ Namespace DownloadObjects
Friend Sub New()
InitializeComponent()
MyDefs = New DefaultFormOptions(Me, Settings.Design)
BTT_SETTINGS = New ToolStripButton With {
.Text = String.Empty,
.AutoToolTip = True,
.ToolTipText = "Change scheduler",
.DisplayStyle = ToolStripItemDisplayStyle.Image,
.Image = My.Resources.ScriptPic_32
}
BTT_CLONE = New ToolStripButton With {
.Text = "Clone",
.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText,
@@ -89,13 +99,15 @@ Namespace DownloadObjects
}
PauseArr = New AutoDownloaderPauseButtons(AutoDownloaderPauseButtons.ButtonsPlace.Scheduler) With {
.MainFrameButtonsInstance = MainFrameObj.PauseButtons}
Icon = ImageRenderer.GetIcon(My.Resources.ScriptPic_32, EDP.ReturnValue)
End Sub
#End Region
#Region "Form handlers"
Private Sub SchedulerEditorForm_Load(sender As Object, e As EventArgs) Handles Me.Load
With MyDefs
.MyViewInitialize()
.AddEditToolbar({ECI.Add, BTT_CLONE, ECI.Edit, ECI.Delete, ECI.Update, ECI.Separator, BTT_START, BTT_START_FORCE, MENU_SKIP, BTT_PAUSE})
.AddEditToolbar({BTT_SETTINGS, ECI.Separator, ECI.Add, BTT_CLONE, ECI.Edit, ECI.Delete, ECI.Update, ECI.Separator,
BTT_START, BTT_START_FORCE, MENU_SKIP, BTT_PAUSE})
PauseArr.AddButtons(BTT_PAUSE, .MyEditToolbar.ToolStrip)
Refill()
.EndLoaderOperations(False)
@@ -186,7 +198,80 @@ Namespace DownloadObjects
Edit()
End Sub
#End Region
#Region "Start, Skip, Pause"
#Region "Settings, Start, Skip, Pause"
Private Sub BTT_SETTINGS_Click(sender As Object, e As EventArgs) Handles BTT_SETTINGS.Click
Const msgTitle$ = "Change scheduler"
Try
Const defName$ = "Default"
Dim l As New Dictionary(Of SFile, String)
With SFile.GetFiles(SettingsFolderName.CSFileP, $"{Scheduler.FileNameDefault}*.xml",, EDP.ReturnValue)
If .ListExists Then .ForEach(Sub(ff) l.Add(ff, ff.Name.Replace(Scheduler.FileNameDefault, String.Empty).StringTrimStart("_").IfNullOrEmpty(defName)))
End With
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),
.FormText = "Schedulers",
.Mode = SimpleListFormModes.SelectedItems,
.MultiSelect = False
}
With chooser
Dim i%
Dim f As SFile
Dim selectedName$
Dim addedObj$ = String.Empty
.ClearButtons()
.Buttons = {ADB.Add, ADB.Delete}
AddHandler .AddClick, Sub(ByVal obj As Object, ByVal args As SimpleListFormEventArgs)
If addedObj.IsEmptyString Then
addedObj = InputBoxE("Enter a new scheduler name:", msgTitle)
args.Result = Not addedObj.IsEmptyString
If args.Result Then args.Item = addedObj
Else
MsgBoxE({"You can only create one scheduler at a time", "Create a new scheduler"}, vbCritical)
End If
End Sub
If Settings.Automation.File.Name = Scheduler.FileNameDefault Then
.DataSelectedIndexes.Add(0)
Else
i = l.Keys.ListIndexOf(Function(ff) ff = Settings.Automation.File)
If i >= 0 Then .DataSelectedIndexes.Add(i)
End If
If .ShowDialog() = DialogResult.OK Then
selectedName = .DataResult.FirstOrDefault
If Not selectedName.IsEmptyString Then
If selectedName = defName Then
f = Settings.Automation.FileDefault
Else
f = $"{SettingsFolderName}\{Scheduler.FileNameDefault}_{selectedName.StringRemoveWinForbiddenSymbols}.xml"
End If
If Not Settings.Automation.File = f AndAlso Settings.Automation.Reset(f, False) Then
Settings.Automation.File = f
If selectedName = defName Then
Settings.AutomationFile.Value = Nothing
Else
Settings.AutomationFile.Value = f
End If
PauseArr.UpdatePauseButtons()
Refill()
If Not .DataSource.Count = l.Count Then
For i = l.Count - 1 To 0 Step -1
If Not .DataSource.Contains(l(l.Keys(i))) Then l.Keys(i).Delete(, SFODelete.DeleteToRecycleBin, EDP.SendToLog)
Next
End If
End If
End If
End If
End With
End Using
l.Clear()
Else
MsgBoxE({"There are no plans created", msgTitle}, vbExclamation)
End If
Catch ex As Exception
ErrorsDescriber.Execute(EDP.LogMessageValue, ex, msgTitle)
End Try
End Sub
Private Sub BTT_START_Click(sender As Object, e As EventArgs) Handles BTT_START.Click
If _LatestSelected.ValueBetween(0, LIST_PLANS.Items.Count - 1) Then
With Settings.Automation(_LatestSelected) : .Start(.IsNewPlan) : End With

View File

@@ -8,4 +8,5 @@ Imports System.Diagnostics.CodeAnalysis
<Assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification:="<Pending>", Scope:="member", Target:="~M:SCrawler.API.UserDataBind.DownloadData(System.Threading.CancellationToken,System.Boolean)")>
<Assembly: SuppressMessage("Style", "IDE0044:Add readonly modifier", Justification:="<Pending>", Scope:="member", Target:="~F:SCrawler.MainFrame.DownloadQueue")>
<Assembly: SuppressMessage("Style", "IDE0044:Add readonly modifier", Justification:="<Pending>", Scope:="member", Target:="~F:SCrawler.MainFrame.MyMissingPosts")>
<Assembly: SuppressMessage("Style", "IDE0044:Add readonly modifier", Justification:="<Pending>", Scope:="member", Target:="~F:SCrawler.MainFrame.MyUserMetrics")>
<Assembly: SuppressMessage("Style", "IDE0044:Add readonly modifier", Justification:="<Pending>", Scope:="member", Target:="~F:SCrawler.MainFrame.MyUserMetrics")>
<Assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification:="<Pending>", Scope:="member", Target:="~M:SCrawler.DownloadObjects.AutoDownloaderPauseButtons.UpdatePauseButtons_Handler(SCrawler.DownloadObjects.AutoDownloader.PauseModes)")>

View File

@@ -122,7 +122,7 @@ Public Class MainFrame
.Automation = New Scheduler
AddHandler .Groups.Updated, AddressOf .Automation.GROUPS_Updated
AddHandler .Groups.Deleted, AddressOf .Automation.GROUPS_Deleted
AddHandler .Automation.PauseDisabled, AddressOf MainFrameObj.PauseButtons.UpdatePauseButtons
AddHandler .Automation.PauseChanged, AddressOf MainFrameObj.PauseButtons.UpdatePauseButtons_Handler
If .Automation.Count > 0 Then .Labels.AddRange(.Automation.GetGroupsLabels, False) : .Labels.Update()
_UFinit = False
Await .Automation.Start(True)

View File

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

View File

@@ -130,6 +130,7 @@ Friend Class SettingsCLS : Implements IDownloaderSettings, IDisposable
Friend ReadOnly Property DownloadLocations As STDownloader.DownloadLocationsCollection
Friend ReadOnly Property GlobalLocations As STDownloader.DownloadLocationsCollection
Friend Property Automation As Scheduler
Friend ReadOnly Property AutomationFile As XMLValue(Of SFile)
Friend ReadOnly Property BlackList As List(Of UserBan)
Private ReadOnly BlackListFile As SFile = $"{SettingsFolderName}\BlackList.txt"
Private ReadOnly UsersSettingsFile As SFile = $"{SettingsFolderName}\Users.xml"
@@ -170,6 +171,7 @@ Friend Class SettingsCLS : Implements IDownloaderSettings, IDisposable
SeparateVideoFolder = New XMLValue(Of Boolean)("SeparateVideoFolder", True, MyXML)
CollectionsPath = New XMLValue(Of String)("CollectionsPath", CollectionsFolderName, MyXML)
AutomationFile = New XMLValue(Of SFile)("AutomationFile",, MyXML)
UserAgent = New XMLValue(Of String)("UserAgent",, MyXML)
If Not UserAgent.IsEmptyString Then DefaultUserAgent = UserAgent