|
6 | 6 | ' |
7 | 7 | ' This program is distributed in the hope that it will be useful, |
8 | 8 | ' but WITHOUT ANY WARRANTY |
| 9 | +Imports System.Text |
9 | 10 | Imports System.Threading |
10 | | -Imports SCrawler.API.Base |
11 | | -Imports SCrawler.API.YouTube.Objects |
| 11 | +Imports PersonalUtilities.Functions.RegularExpressions |
12 | 12 | Imports PersonalUtilities.Functions.XML |
13 | 13 | Imports PersonalUtilities.Functions.XML.Base |
14 | | -Imports PersonalUtilities.Functions.RegularExpressions |
15 | 14 | Imports PersonalUtilities.Tools.Web.Clients |
16 | 15 | Imports PersonalUtilities.Tools.Web.Documents.JSON |
| 16 | +Imports SCrawler.API.Base |
| 17 | +Imports SCrawler.API.YouTube.Objects |
17 | 18 | Imports UTypes = SCrawler.API.Base.UserMedia.Types |
18 | 19 | Namespace API.Xhamster |
19 | 20 | Friend Class UserData : Inherits UserDataBase : Implements IPSite |
@@ -564,15 +565,85 @@ Namespace API.Xhamster |
564 | 565 | Return ErrorsDescriber.Execute(EDP.ReturnValue, ex, $"[{ToStringForLog()}]: API.Xhamster.GetM3U8({URL})", False) |
565 | 566 | End Try |
566 | 567 | End Function |
567 | | - Private Overloads Function GetM3U8(ByRef m As UserMedia, ByVal j As EContainer, ByVal SpecFolder As String) As Boolean |
568 | | - Dim node As EContainer = j({"xplayerSettings", "sources", "hls"}) |
| 568 | + Private Overloads Function GetM3U8(ByRef m As UserMedia, ByVal j As EContainer, ByVal SpecFolder As String, Optional ByVal r As Integer = 0) As Boolean |
| 569 | + Const urlNode$ = "url" |
| 570 | + Dim node As EContainer = j({"xplayerSettings", "sources", If(r = 0, "hls", "standard")}) |
569 | 571 | If node.ListExists Then |
570 | | - Dim url$ = node.GetNode({New NodeParams("url", True, True, True, True, 2)}).XmlIfNothingValue |
571 | | - If Not url.IsEmptyString Then m.URL = url : m.Type = UTypes.m3u8 : Return True |
| 572 | + Dim url$ 'node.GetNode({New NodeParams("url", True, True, True, True, 2)}).XmlIfNothingValue |
| 573 | + Dim jn As EContainer, jn2 As EContainer |
| 574 | + Dim __getUrl As Func(Of EContainer, String) = Function(jj) If(jj.Contains(urlNode), Decipher_URL(jj.Value(urlNode)), String.Empty) |
| 575 | + url = __getUrl(node) |
| 576 | + If url.IsEmptyString Then |
| 577 | + For Each jn In node |
| 578 | + If jn.Contains(urlNode) Then |
| 579 | + url = __getUrl(jn) |
| 580 | + ElseIf jn.Count > 0 Then |
| 581 | + For Each jn2 In jn |
| 582 | + url = __getUrl(jn2) |
| 583 | + If Not url.IsEmptyString Then Exit For |
| 584 | + Next |
| 585 | + End If |
| 586 | + If Not url.IsEmptyString Then Exit For |
| 587 | + Next |
| 588 | + End If |
| 589 | + If Not url.IsEmptyString Then |
| 590 | + m.URL = url |
| 591 | + m.Type = UTypes.m3u8 |
| 592 | + Return True |
| 593 | + End If |
572 | 594 | End If |
| 595 | + If r = 0 Then Return GetM3U8(m, j, SpecFolder, r + 1) |
573 | 596 | Return False |
574 | 597 | End Function |
575 | 598 | #End Region |
| 599 | +#Region "Decipher" |
| 600 | + 'https://github.com/yt-dlp/yt-dlp/blob/5513036104ed9710f624c537fb3644b07a0680db/yt_dlp/extractor/xhamster.py#L146-L165 |
| 601 | + Private Function Decipher_URL(ByVal Input As String) As String |
| 602 | + If Input.IsEmptyString Then Return String.Empty |
| 603 | + |
| 604 | + Dim _XOR_KEY As Byte() = Encoding.ASCII.GetBytes("xh7999") |
| 605 | + Dim cipher_type$ = String.Empty |
| 606 | + Dim ciphertext$ = String.Empty |
| 607 | + |
| 608 | + Try |
| 609 | + Dim decoded$ = Encoding.ASCII.GetString(Convert.FromBase64String(Input)) |
| 610 | + Dim parts$() = decoded.Split(New Char() {"_"c}, 2) |
| 611 | + If parts.Length = 2 Then cipher_type = parts(0) : ciphertext = parts(1) |
| 612 | + Catch |
| 613 | + End Try |
| 614 | + |
| 615 | + If cipher_type.IsEmptyString Or ciphertext.IsEmptyString Then Return String.Empty |
| 616 | + |
| 617 | + If cipher_type = "xor" Then |
| 618 | + Dim ciphertextBytes() As Byte = Encoding.ASCII.GetBytes(ciphertext) |
| 619 | + Dim resultBytes(ciphertextBytes.Length - 1) As Byte |
| 620 | + For i% = 0 To ciphertextBytes.Length - 1 |
| 621 | + resultBytes(i) = ciphertextBytes(i) Xor _XOR_KEY(i Mod _XOR_KEY.Length) |
| 622 | + Next |
| 623 | + Return Encoding.ASCII.GetString(resultBytes) |
| 624 | + End If |
| 625 | + |
| 626 | + If cipher_type = "rot13" Then Return Decipher_URL_Rot13(ciphertext) |
| 627 | + |
| 628 | + Return String.Empty |
| 629 | + End Function |
| 630 | + Private Function Decipher_URL_Rot13(ByVal Input As String) As String |
| 631 | + Dim result As New Text.StringBuilder(Input.Length) |
| 632 | + For Each c As Char In Input |
| 633 | + Dim offset% |
| 634 | + If c >= "a"c AndAlso c <= "z"c Then |
| 635 | + offset = Asc("a"c) |
| 636 | + result.Append(ChrW((Asc(c) - offset + 13) Mod 26 + offset)) |
| 637 | + ElseIf c >= "A"c AndAlso c <= "Z"c Then |
| 638 | + offset = Asc("A"c) |
| 639 | + result.Append(ChrW((Asc(c) - offset + 13) Mod 26 + offset)) |
| 640 | + Else |
| 641 | + result.Append(c) |
| 642 | + End If |
| 643 | + Next |
| 644 | + Return result.ToString |
| 645 | + End Function |
| 646 | +#End Region |
576 | 647 | #Region "DownloadSingleObject" |
577 | 648 | Protected Overrides Sub DownloadSingleObject_GetPosts(ByVal Data As IYouTubeMediaContainer, ByVal Token As CancellationToken) |
578 | 649 | _ContentList.Add(New UserMedia(Data.URL_BASE) With {.State = UserMedia.States.Missing}) |
|
0 commit comments