@@ -838,6 +838,58 @@ var siteInfo = [
838
838
}
839
839
}
840
840
} ,
841
+ {
842
+ name : "Twitch" ,
843
+ url : / ^ h t t p s : \/ \/ ( w w w \. t w i t c h \. t v \/ | w w w \. r e d d i t \. c o m \/ r \/ T w i t c h C l i p s \/ ) / ,
844
+ xhr : {
845
+ url : function ( a , p , xhr ) {
846
+ if ( ! a ) return ;
847
+ if ( ! / t w i t c h \. t v / . test ( a . href ) ) return ;
848
+ let m = a . href . match ( / ( \/ c l i p \/ | c l i p s \. t w i t c h \. t v \/ ) ( [ ^ ? ] { 1 , } ) / ) ;
849
+ if ( m ) {
850
+ var slug = m [ 2 ] ;
851
+ var operationNameClip = "VideoAccessToken_Clip" ;
852
+ var operationNameLiveOrVOD = "PlaybackAccessToken" ;
853
+ var sha256HashClip = "36b89d2507fce29e5ca551df756d27c1cfe079e2609642b4390aa4c35796eb11" ;
854
+ var sha256HashLiveOrVOD = "0828119ded1c13477966434e15800ff57ddacf13ba1911c129dc2200705b0712" ;
855
+ return `https://gql.twitch.tv/gql#p{{"operationName":"${ operationNameClip } ","variables":{"slug":"${ slug } "},"extensions":{"persistedQuery":{"version":1,"sha256Hash":"${ sha256HashClip } "}}}}` ;
856
+ } else {
857
+ m = a . href . match ( / (?: m \. | w w w \. ) ? t w i t c h \. t v \/ (?: (? ! d i r e c t o r y | d o w n l o a d s | j o b s | s t o r e | t w i t c h a r t i s t s | t u r b o | p r i v a c y ) ( \w + ) $ | (?: \w + \/ ) ? v i d e o s \/ ( \d + ) ) / ) ;
858
+ if ( m ) {
859
+ xhr . m = m ;
860
+ return `https://gql.twitch.tv/gql#p{{"operationName":"PlaybackAccessToken_Template","query":"query PlaybackAccessToken_Template($login: String!, $isLive: Boolean!, $vodID: ID!, $isVod: Boolean!, $playerType: String!, $platform: String!) { streamPlaybackAccessToken(channelName: $login, params: {platform: $platform, playerBackend: \\"mediaplayer\\", playerType: $playerType}) @include(if: $isLive) { value signature authorization { isForbidden forbiddenReasonCode } __typename } videoPlaybackAccessToken(id: $vodID, params: {platform: $platform, playerBackend: \\"mediaplayer\\", playerType: $playerType}) @include(if: $isVod) { value signature __typename }}","variables":{"isLive":${ m [ 1 ] ?'true' :'false' } ,"login":"${ m [ 1 ] || '' } ","isVod":true,"vodID":"${ m [ 2 ] || '' } ","playerType":"site","platform":"web"}}}` ;
861
+ }
862
+ }
863
+ } ,
864
+ headers : function ( url , xhr , getCookie ) {
865
+ return { "Client-ID" :"kimne78kx3ncx6brgo4mv6wki5h1ko" , "X-Device-Id" : getCookie ( 'unique_id' ) || getCookie ( 'unique_id_durable' ) || 'd56e8463c57c7cd7' }
866
+ } ,
867
+ cacheNum : 20 ,
868
+ query : function ( html , doc , u , xhr ) {
869
+ try {
870
+ let r = JSON . parse ( html ) ;
871
+ if ( r . data . clip ) {
872
+ let signature = r . data . clip . playbackAccessToken . signature ;
873
+ let token = r . data . clip . playbackAccessToken . value ;
874
+ let t = JSON . parse ( token ) ;
875
+ let clip_uri = r . data . clip . videoQualities [ 0 ] . sourceURL ;
876
+ let fullsizeUrl = clip_uri + '?sig=' + signature + '&token=' + encodeURIComponent ( token ) ;
877
+
878
+ return { url : [ "video:" + fullsizeUrl ] , cap : "" } ;
879
+ } else {
880
+ let tokens = r . data . streamPlaybackAccessToken || r . data . videoPlaybackAccessToken ;
881
+ if ( ! tokens ) return ;
882
+ let hex = [ 'A' , 'B' , 'C' , 'D' , 'E' , 'F' , '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' ] ;
883
+ let url = xhr . m [ 1 ] ? 'api/channel/hls' : 'vod' ;
884
+ let p = Math . floor ( 999999 * Math . random ( ) ) ;
885
+ let id = '' ;
886
+ for ( let i = 0 ; i < 32 ; i ++ ) id += hex [ Math . floor ( Math . random ( ) * 16 ) ] ;
887
+ return `video:https://usher.ttvnw.net/${ url } /${ xhr . m [ 1 ] || xhr . m [ 2 ] } .m3u8?acmb=eyJBcHBWZXJzaW9uIjoiYjlhNjU4ZWMtMTcyMS00Y2FjLThkMjgtZjk0NmJmY2E3YzUwIn0%3D&allow_source=true&p=${ p } &platform=web&play_session_id=${ id } &sig=${ tokens . signature } &supported_codecs=av1,h264&token=${ encodeURIComponent ( tokens . value ) } &transcode_mode=cbr_v1` ;
888
+ }
889
+ } catch { }
890
+ }
891
+ }
892
+ } ,
841
893
{
842
894
name : "Rule34hentai" ,
843
895
url : / r u l e 3 4 h e n t a i \. n e t / ,
@@ -1368,7 +1420,7 @@ var siteInfo = [
1368
1420
const images = items0 . image_versions2 ;
1369
1421
const carousel = items0 . carousel_media ;
1370
1422
if ( videos ) {
1371
- const videoUrl = videos [ 0 ] . url + '.video' ;
1423
+ const videoUrl = "video:" + videos [ 0 ] . url ;
1372
1424
let videoAudioSubtitlesUrl = videoUrl ;
1373
1425
const caption = ( items0 . caption ? items0 . caption . text : ( items0 . accessibility_caption ? items0 . accessibility_caption : items0 . user . full_name ) ) ;
1374
1426
return { url : [ videoUrl ] , cap : caption } ;
0 commit comments