Skip to content

Commit aedcebc

Browse files
committed
2024.10.24.0
YT YouTubeSettings: add 'DefaultVideoAllowWebm' and 'DefaultAudioEmbedThumbnail_Cover' settings YouTubeMediaContainerBase: change cover selection for music download; fix adding incorrect playlist lines; allow 'webm' formats is there are no 'mp4' formats via http protocol SCrawler DeclaredNames: add new names UserDataBase: add '_ForceSaveUserInfoOnException' field and 'UpdateUserInformation_Ex' function to update user info on exception; clear '_MD5List' when clearing data and/or history API.Instagram: add manual 'UserName' changing; mark user as non-existent if user ID cannot be obtained API.Twitter: add manual 'UserName' changing API.Mastodon: bypass inherited property API.Reddit: fix incorrect UNIX date parsing DownloadFeedForm: add exception handling to the 'RefillAfterDelete' function MainFrame: add 'MENU_INFO_USER_SEARCH' to the 'Info' menu SettingsHostCollection: fix a bug when changing data paths
1 parent 00a06d3 commit aedcebc

25 files changed

+172
-52
lines changed

Changelog.md

+25
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,28 @@
1+
# 2024.10.24.0
2+
3+
*2024-10-24*
4+
5+
- Added
6+
- YouTube (standalone app)
7+
- settings `Embed thumbnail (cover)` and `Allow webm formats`
8+
- changed cover selection for music downloads
9+
- allow `webm` formats is there are no `mp4` formats via http protocol (issue #211)
10+
- Sites:
11+
- Instagram
12+
- **ability to manually change username**
13+
- **mark user as non-existent if user `ID` cannot be obtained**
14+
- Twitter: **ability to manually change username**
15+
- Main window: add users search button to 'Info' menu
16+
- Minor improvements
17+
- Updated
18+
- yt-dlp up to version **2024.10.22**
19+
- gallery-dl up to version **1.27.6**
20+
- Fixed
21+
- YouTube (standalone app): adding incorrect playlist lines
22+
- Reddit: incorrect UNIX date parsing
23+
- Can't change data path (issue #206)
24+
- Minor bugs
25+
126
# 2024.9.2.0
227

328
*2024-09-02*

FAQ.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ I strongly recommend you to **regularly** create backup copies of the settings f
2626

2727
# Most frequently questions about SCrawler
2828

29-
**Is something doesn't download, always check the [SITE'S REQUIREMENTS](https://github.com/AAndyProgram/SCrawler/wiki/Settings#sites-requirements) before asking questions!**
29+
**If something doesn't download, always check the [SITE'S REQUIREMENTS](https://github.com/AAndyProgram/SCrawler/wiki/Settings#sites-requirements) before asking questions!**
3030

3131
*How to use: find your problem in the list and read the answer.*
3232

SCrawler.YouTube/Base/YouTubeSettings.vb

+6
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,9 @@ Namespace API.YouTube.Base
311311
<Browsable(True), GridVisible, XMLVN({"DefaultsVideo"}, 1080), Category("Defaults Video"), DisplayName("Default definition"),
312312
Description("The default maximum video resolution. -1 for max definition")>
313313
Public ReadOnly Property DefaultVideoDefinition As XMLValue(Of Integer)
314+
<Browsable(True), GridVisible, XMLVN({"DefaultsVideo"}, True), Category("Defaults Video"), DisplayName("Allow webm formats"),
315+
Description("Allow webm formats over http if mp4 formats are not available. Default: true.")>
316+
Public ReadOnly Property DefaultVideoAllowWebm As XMLValue(Of Boolean)
314317
<Browsable(True), GridVisible, XMLVN({"DefaultsVideo"}), Category("Defaults Video"), DisplayName("Convert non-AVC codecs to AVC"),
315318
Description("Convert non-AVC codecs (eg 'VP9') to AVC. Not recommended due to high CPU usage!")>
316319
Public ReadOnly Property DefaultVideoConvertNonAVC As XMLValue(Of Boolean)
@@ -416,6 +419,9 @@ Namespace API.YouTube.Base
416419
<Browsable(True), GridVisible, XMLVN({"DefaultsAudio"}, True), Category("Defaults Audio"), DisplayName("Embed thumbnail"),
417420
Description("Embed thumbnail in the audio as cover art. Default: true.")>
418421
Public ReadOnly Property DefaultAudioEmbedThumbnail As XMLValue(Of Boolean)
422+
<Browsable(True), GridVisible, XMLVN({"DefaultsAudio"}, True), Category("Defaults Audio"), DisplayName("Embed thumbnail (cover)"),
423+
Description("Try embedding the playlist cover (if it exists) as cover art. Default: true.")>
424+
Public ReadOnly Property DefaultAudioEmbedThumbnail_Cover As XMLValue(Of Boolean)
419425
<Browsable(True), GridVisible, XMLVN({"DefaultsAudio"}, True), Category("Defaults Audio"), DisplayName("Embed thumbnail (extracted files)"),
420426
Description("Embed thumbnail in the extracted (additional file ('mp3' only)) audio as cover art. Default: true.")>
421427
Public ReadOnly Property DefaultAudioEmbedThumbnail_ExtractedFiles As XMLValue(Of Boolean)

SCrawler.YouTube/Declarations.vb

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ Namespace API.YouTube
5959
Public ReadOnly TrueUrlRegEx As RParams = RParams.DM(Base.YouTubeFunctions.TrueUrlPattern, 0, EDP.ReturnValue)
6060
Friend ReadOnly MusicUrlApply As RParams = RParams.DMS("https://([w\.]*)youtube.com.+", 1, RegexReturn.Replace, EDP.ReturnValue,
6161
CType(Function(input$) "music.", Func(Of String, String)), String.Empty)
62+
Friend ReadOnly M3U8ExcludedSymbols As String() = {".", ",", ":", "/", "\", "(", ")", "[", "]"}
6263
<Extension> Friend Function ToMusicUrl(ByVal URL As String, ByVal IsMusic As Boolean) As String
6364
Try : Return If(IsMusic And Not URL.IsEmptyString, CStr(RegexReplace(URL, MusicUrlApply)).IfNullOrEmpty(URL), URL) : Catch : Return URL : End Try
6465
End Function

SCrawler.YouTube/My Project/AssemblyInfo.vb

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices
3232
' by using the '*' as shown below:
3333
' <Assembly: AssemblyVersion("1.0.*")>
3434

35-
<Assembly: AssemblyVersion("2024.8.10.0")>
36-
<Assembly: AssemblyFileVersion("2024.8.10.0")>
35+
<Assembly: AssemblyVersion("2024.10.24.0")>
36+
<Assembly: AssemblyFileVersion("2024.10.24.0")>
3737
<Assembly: NeutralResourcesLanguage("en")>

SCrawler.YouTube/Objects/YouTubeMediaContainerBase.vb

+31-12
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,9 @@ Namespace API.YouTube.Objects
175175
Protected _ThumbnailUrl As String = String.Empty
176176
<XMLEC> Public Overridable Property ThumbnailUrl As String Implements IDownloadableMedia.ThumbnailUrl
177177
Get
178-
If _ThumbnailUrl.IsEmptyString And Thumbnails.Count > 0 Then
178+
If Not CoverURL.IsEmptyString Then
179+
Return CoverURL
180+
ElseIf _ThumbnailUrl.IsEmptyString And Thumbnails.Count > 0 Then
179181
Return Thumbnails.FirstOrDefault.URL
180182
Else
181183
Return _ThumbnailUrl
@@ -904,7 +906,8 @@ Namespace API.YouTube.Objects
904906
Const m3u8DataRow$ = "#EXTINF:{0},{1}" & vbCrLf & "{2}"
905907
With Element
906908
Dim f As SFile = __file.IfNullOrEmpty(.File)
907-
Dim __f$ = SymbolsConverter.ASCII.EncodeSymbolsOnly(If(Mode = M3U8CreationMode.Absolute, f.ToString, f.File))
909+
Dim fStr$ = f.ToString.StringReplaceSymbols({"\"}, "/", EDP.ReturnValue)
910+
Dim __f$ = SymbolsConverter.ASCII.Extended.EncodeSymbolsOnly(If(Mode = M3U8CreationMode.Absolute, fStr, f.File), M3U8ExcludedSymbols)
908911
If Mode = M3U8CreationMode.Absolute Then __f = $"file:///{__f}"
909912
Dim fName$ = .Title.IfNullOrEmpty(f.Name)
910913
If MyYouTubeSettings.MusicPlaylistCreate_M3U8_AppendNumber And .PlaylistIndex > 0 Then fName = $"{ .PlaylistIndex}. {fName}"
@@ -1022,12 +1025,19 @@ Namespace API.YouTube.Objects
10221025
End If
10231026

10241027
Dim cDown As Boolean = False
1028+
Dim fCover As SFile = Nothing
1029+
Dim cUrl$ = String.Empty
10251030
For Each elem In Elements
10261031
With DirectCast(elem, YouTubeMediaContainerBase)
1027-
If Not .CoverDownloaded Then .CoverDownloaded = cDown
1032+
'If Not .CoverDownloaded Then .CoverDownloaded = cDown
1033+
.CoverDownloaded = cDown
1034+
.CoverFile = fCover
1035+
.CoverURL = cUrl
10281036
AddHandler .FileDownloadStarted, fDown
10291037
.Download(UseCookies, Token)
10301038
cDown = .CoverDownloaded
1039+
fCover = .CoverFile
1040+
cUrl = .CoverURL
10311041
RemoveHandler .FileDownloadStarted, fDown
10321042
End With
10331043
If Token.IsCancellationRequested Or disposedValue Then Exit For
@@ -1054,6 +1064,8 @@ Namespace API.YouTube.Objects
10541064
End Try
10551065
End Sub
10561066
Protected CoverDownloaded As Boolean = False
1067+
Protected CoverFile As SFile = Nothing
1068+
Protected CoverURL As String = String.Empty
10571069
Private Sub DownloadPlaylistCover(ByVal PlsId As String, ByVal f As SFile, ByVal UseCookies As Boolean)
10581070
Try
10591071
Dim url$ = $"https://{IIf(IsMusic, "music", "www")}.youtube.com/playlist?list={PlsId}"
@@ -1089,7 +1101,8 @@ Namespace API.YouTube.Objects
10891101
url = LinkFormatterSecure(u)
10901102
f.Name = "cover"
10911103
f.Extension = "jpg"
1092-
If resp.DownloadFile(url, f, EDP.ReturnValue) And f.Exists Then CoverDownloaded = True : AddFile(f)
1104+
If resp.DownloadFile(url, f, EDP.ReturnValue) And f.Exists Then _
1105+
CoverFile = f : CoverURL = url : CoverDownloaded = True : AddFile(f)
10931106
End If
10941107
End If
10951108
End Using
@@ -1270,10 +1283,10 @@ Namespace API.YouTube.Objects
12701283
End Sub
12711284
Dim embedThumbTo As Action(Of SFile) =
12721285
Sub(ByVal dFile As SFile)
1273-
If dFile.Exists And ThumbnailFile.Exists Then
1286+
If dFile.Exists And CoverFile.IfNullOrEmpty(ThumbnailFile).Exists Then
12741287
Dim dFileNew As SFile = dFile
12751288
dFileNew.Name &= "_NEW"
1276-
.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}""")
1289+
.Execute($"ffmpeg -i ""{dFile}"" -i ""{CoverFile.IfNullOrEmpty(ThumbnailFile)}"" -map 0:0 -map 1:0 -c copy -id3v2_version 3 -metadata:s:v title=""Cover"" -metadata:s:v comment=""Cover"" ""{dFileNew}""")
12771290
If dFileNew.Exists AndAlso dFile.Delete(,, EDP.ReturnValue) Then SFile.Rename(dFileNew, dFile)
12781291
End If
12791292
End Sub
@@ -1353,6 +1366,10 @@ Namespace API.YouTube.Objects
13531366
End If
13541367
End If
13551368

1369+
'mp3
1370+
If IsMusic And ObjectType = YouTubeMediaType.Single And File.Extension = mp3 And
1371+
Not mp3ThumbEmbedded And CoverFile.Exists And MyYouTubeSettings.DefaultAudioEmbedThumbnail_Cover Then embedThumbTo.Invoke(File)
1372+
13561373
'Update video
13571374
ThrowAny(Token)
13581375
If SelectedVideoIndex >= 0 AndAlso tempFilesList.Count > 0 AndAlso tempFilesList.Exists(Function(tf) tf.ToReplace) Then
@@ -1725,6 +1742,7 @@ Namespace API.YouTube.Objects
17251742
Dim obj As MediaObject
17261743
Dim nValue#
17271744
Dim sValue$
1745+
Dim allowWebm As Boolean = MyYouTubeSettings.DefaultVideoAllowWebm
17281746
Dim validCodecValue As Func(Of String, Boolean) = Function(codec) Not codec.IsEmptyString AndAlso Not codec = "none"
17291747

17301748
For Each ee In e({"formats"})
@@ -1775,12 +1793,13 @@ Namespace API.YouTube.Objects
17751793
Dim d As MediaObject = Nothing
17761794
Dim expWebm As Predicate(Of MediaObject) = Function(mo) mo.Extension = webm
17771795
Dim expAVC As Predicate(Of MediaObject) = Function(mo) mo.Codec.IfNullOrEmpty("/").ToLower.StartsWith(avc)
1778-
Dim comp As Func(Of MediaObject, Predicate(Of MediaObject), Boolean, Boolean) =
1779-
Function(mo, exp, isTrue) mo.Type = t And exp.Invoke(mo) = isTrue And mo.Width = d.Width
1780-
Dim CountWebm As Func(Of MediaObject, Boolean) = Function(mo) comp.Invoke(mo, expWebm, False)
1781-
Dim RemoveWebm As Predicate(Of MediaObject) = Function(mo) comp.Invoke(mo, expWebm, True)
1782-
Dim CountAVC As Func(Of MediaObject, Boolean) = Function(mo) comp.Invoke(mo, expAVC, True)
1783-
Dim RemoveAVC As Predicate(Of MediaObject) = Function(mo) comp.Invoke(mo, expAVC, False)
1796+
Dim comp As Func(Of MediaObject, Predicate(Of MediaObject), Boolean, Boolean, Boolean) =
1797+
Function(mo, exp, isTrue, checkHttp) mo.Type = t And exp.Invoke(mo) = isTrue And mo.Width = d.Width And
1798+
(Not checkHttp OrElse mo.ProtocolType = Protocols.https)
1799+
Dim CountWebm As Func(Of MediaObject, Boolean) = Function(mo) comp.Invoke(mo, expWebm, False, allowWebm)
1800+
Dim RemoveWebm As Predicate(Of MediaObject) = Function(mo) comp.Invoke(mo, expWebm, True, allowWebm)
1801+
Dim CountAVC As Func(Of MediaObject, Boolean) = Function(mo) comp.Invoke(mo, expAVC, True, False)
1802+
Dim RemoveAVC As Predicate(Of MediaObject) = Function(mo) comp.Invoke(mo, expAVC, False, False)
17841803
For Each d In data
17851804
If MediaObjects.Count = 0 Then Exit For
17861805
If MediaObjects.LongCount(CountWebm) > 0 Then MediaObjects.RemoveAll(RemoveWebm)

SCrawler.YouTubeDownloader/My Project/AssemblyInfo.vb

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices
3232
' by using the '*' as shown below:
3333
' <Assembly: AssemblyVersion("1.0.*")>
3434

35-
<Assembly: AssemblyVersion("2024.8.10.0")>
36-
<Assembly: AssemblyFileVersion("2024.8.10.0")>
35+
<Assembly: AssemblyVersion("2024.10.24.0")>
36+
<Assembly: AssemblyFileVersion("2024.10.24.0")>
3737
<Assembly: NeutralResourcesLanguage("en")>

SCrawler/API/Base/DeclaredNames.vb

+2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ Namespace API.Base
2828
Friend Const GifsDownloadCaption As String = "Download GIFs"
2929
Friend Const UseMD5ComparisonCaption As String = "Use MD5 comparison"
3030
Friend Const UseMD5ComparisonToolTip As String = "Each image will be checked for existence using MD5"
31+
Friend Const UserNameChangeCaption As String = "UserName"
32+
Friend Const UserNameChangeToolTip As String = "If the user has changed their UserName, you can set a new name here. Not required for new users."
3133
Private Sub New()
3234
End Sub
3335
End Class

SCrawler/API/Base/UserDataBase.vb

+11
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,9 @@ BlockNullPicture:
947947
LogError(ex, "user information loading error")
948948
End Try
949949
End Sub
950+
Private Sub UpdateUserInformation_Ex()
951+
If _ForceSaveUserInfoOnException Then UpdateUserInformation()
952+
End Sub
950953
Friend Overridable Overloads Sub UpdateUserInformation() Implements IUserData.UpdateUserInformation
951954
UpdateUserInformation(False)
952955
End Sub
@@ -1117,6 +1120,7 @@ BlockNullPicture:
11171120
Protected UseClientTokens As Boolean = False
11181121
Protected _ForceSaveUserData As Boolean = False
11191122
Protected _ForceSaveUserInfo As Boolean = False
1123+
Protected _ForceSaveUserInfoOnException As Boolean = False
11201124
Private _DownloadInProgress As Boolean = False
11211125
Private _EnvirUserExists As Boolean
11221126
Private _EnvirUserSuspended As Boolean
@@ -1136,6 +1140,7 @@ BlockNullPicture:
11361140
_DescriptionEveryTime = Settings.UpdateUserDescriptionEveryTime
11371141
_ForceSaveUserData = False
11381142
_ForceSaveUserInfo = False
1143+
_ForceSaveUserInfoOnException = False
11391144
_EnvirUserExists = UserExists
11401145
_EnvirUserSuspended = UserSuspended
11411146
_EnvirCreatedByChannel = CreatedByChannel
@@ -1265,9 +1270,11 @@ BlockNullPicture:
12651270
ThrowIfDisposed()
12661271
If Not _PictureExists Or _EnvirInvokeUserUpdated Then OnUserUpdated()
12671272
Catch oex As OperationCanceledException When Token.IsCancellationRequested Or TokenPersonal.IsCancellationRequested Or TokenQueue.IsCancellationRequested
1273+
UpdateUserInformation_Ex()
12681274
MyMainLOG = $"{ToStringForLog()}: downloading canceled"
12691275
Canceled = True
12701276
Catch exit_ex As ExitException
1277+
UpdateUserInformation_Ex()
12711278
If Not exit_ex.Silent Then
12721279
If exit_ex.SimpleLogLine Then
12731280
MyMainLOG = $"{ToStringForLog()}: downloading interrupted (exit) ({exit_ex.Message})"
@@ -1279,6 +1286,7 @@ BlockNullPicture:
12791286
Catch dex As ObjectDisposedException When Disposed
12801287
Canceled = True
12811288
Catch ex As Exception
1289+
UpdateUserInformation_Ex()
12821290
LogError(ex, "downloading data error")
12831291
HasError = True
12841292
Finally
@@ -1912,6 +1920,7 @@ BlockNullPicture:
19121920
If m.Contains(IUserData.EraseMode.History) Then
19131921
If MyFilePosts.Delete(SFO.File, SFODelete.DeleteToRecycleBin, e) Then result = True
19141922
If MyFileData.Delete(SFO.File, SFODelete.DeleteToRecycleBin, e) Then result = True
1923+
If MyMD5File.Delete(SFO.File, SFODelete.DeleteToRecycleBin, e) Then result = True
19151924
LastUpdated = Nothing
19161925
EraseData_AdditionalDataFiles()
19171926
UpdateUserInformation()
@@ -1928,6 +1937,8 @@ BlockNullPicture:
19281937
_TempMediaList.Clear()
19291938
_ContentNew.Clear()
19301939
_ContentList.Clear()
1940+
_MD5List.Clear()
1941+
_MD5Loaded = False
19311942
End If
19321943
End If
19331944
End If

SCrawler/API/Instagram/EditorExchangeOptions.vb

+5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
' This program is distributed in the hope that it will be useful,
88
' but WITHOUT ANY WARRANTY
99
Imports SCrawler.Plugin.Attributes
10+
Imports DN = SCrawler.API.Base.DeclaredNames
1011
Namespace API.Instagram
1112
Friend Class EditorExchangeOptions
1213
#Region "Download"
@@ -35,6 +36,8 @@ Namespace API.Instagram
3536
#End Region
3637
<PSetting(Caption:="Place the extracted image into the video folder")>
3738
Friend Property PutImageVideoFolder As Boolean
39+
<PSetting(Address:=SettingAddress.User, Caption:=DN.UserNameChangeCaption, ToolTip:=DN.UserNameChangeToolTip)>
40+
Friend Overridable Property UserName As String = String.Empty
3841
Friend Sub New(ByVal u As UserData)
3942
With u
4043
GetTimeline = .GetTimeline
@@ -50,6 +53,8 @@ Namespace API.Instagram
5053
GetTagged_VideoPic = .GetTaggedData_VideoPic
5154

5255
PutImageVideoFolder = .PutImageVideoFolder
56+
57+
UserName = .NameTrue(True)
5358
End With
5459
End Sub
5560
Friend Sub New(ByVal s As SiteSettings)

SCrawler/API/Instagram/UserData.vb

+6-3
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,9 @@ Namespace API.Instagram
112112
End Select
113113
End Function
114114
Protected _NameTrue As String = String.Empty
115-
Friend ReadOnly Property NameTrue As String
115+
Friend ReadOnly Property NameTrue(Optional ByVal Exact As Boolean = False) As String
116116
Get
117-
Return _NameTrue.IfNullOrEmpty(Name)
117+
Return If(Exact, _NameTrue, _NameTrue.IfNullOrEmpty(Name))
118118
End Get
119119
End Property
120120
Private UserNameRequested As Boolean = False
@@ -178,6 +178,8 @@ Namespace API.Instagram
178178
GetTaggedData_VideoPic = .GetTagged_VideoPic
179179

180180
PutImageVideoFolder = .PutImageVideoFolder
181+
182+
_NameTrue = .UserName
181183
End With
182184
End If
183185
End Sub
@@ -631,7 +633,7 @@ Namespace API.Instagram
631633
'Check environment
632634
If Not IsSavedPosts Then
633635
If ID.IsEmptyString Then GetUserData()
634-
If ID.IsEmptyString Then Throw New Plugin.ExitException("can't get user ID")
636+
If ID.IsEmptyString Then UserExists = False : _ForceSaveUserInfoOnException = True : Throw New Plugin.ExitException("can't get user ID")
635637
If _UseGQL And Cursor.IsEmptyString And Not Section = Sections.SavedPosts Then
636638
If Not ValidateBaseTokens() Then GetPageTokens()
637639
If Not ValidateBaseTokens(TokensErrData) Then ValidateBaseTokens_Error(TokensErrData)
@@ -1171,6 +1173,7 @@ NextPageBlock:
11711173
End Using
11721174
End If
11731175
Catch ex As Exception
1176+
UserExists = False
11741177
If Not __idFound Then
11751178
If Responser.StatusCode = HttpStatusCode.NotFound Or Responser.StatusCode = HttpStatusCode.BadRequest Then
11761179
Throw ex

0 commit comments

Comments
 (0)