11// ==UserScript==
22// @name AniLINK - Episode Link Extractor
33// @namespace https://greasyfork.org/en/users/781076-jery-js
4- // @version 6.26 .0
4+ // @version 6.27 .0
55// @description Stream or download your favorite anime series effortlessly with AniLINK! Unlock the power to play any anime series directly in your preferred video player or download entire seasons in a single click using popular download managers like IDM. AniLINK generates direct download links for all episodes, conveniently sorted by quality. Elevate your anime-watching experience now!
6- // @icon https://www.google .com/s2/favicons?domain=animepahe.ru
6+ // @icon https://upload-os-bbs.hoyolab .com/upload/2024/06/03/136787680/795963af96e199b14106441a955376fa_6229706912856146042.jpg
77// @author Jery
88// @license MIT
99// @match https://anitaku.*/*
4949// @match https://anikai.to/*
5050// @match https://yflix.to/watch/*
5151// @match https://anime.uniquestream.net/*/*/*
52+ // @match https://www.fmovies.gd/*/*
53+ // @match https://*fmovies.*/*/*
5254// @grant GM_registerMenuCommand
5355// @grant GM_xmlhttpRequest
5456// @grant GM.xmlHttpRequest
@@ -502,7 +504,7 @@ const Websites = [
502504 document . getElementById ( 'AniLINK_Overlay' ) ?. remove ( ) ;
503505 }
504506 // Append the extract button
505- const target = document . querySelector ( '.App + div > div > div + div > div > div > div > div + div > div + div' ) ;
507+ const target = document . querySelector ( 'div[class^="_tagRow"] > div+ div' ) ;
506508 if ( target && ! document . getElementById ( id ) ) {
507509 // clearInterval(intervalId);
508510 const btn = document . createElement ( 'button' ) ;
@@ -521,10 +523,10 @@ const Websites = [
521523 extractEpisodes : async function * ( status ) {
522524 status . text = 'Fetching episode list...' ;
523525 const animeTitle = ( document . querySelector ( 'p.title-romaji' ) || document . querySelector ( this . animeTitle ) ) . textContent ;
524- const malId = document . querySelector ( `a[href*="/myanimelist.net /anime/"]` ) ?. href . split ( '/' ) . pop ( ) ;
525- if ( ! malId ) return showToast ( 'MAL ID not found.' ) ;
526+ const anilistId = document . querySelector ( `a[href*="/anilist.co /anime/"]` ) ?. href . split ( '/' ) . pop ( ) ;
527+ if ( ! anilistId ) return showToast ( 'anilistId not found.' ) ;
526528
527- const res = await this . _secureFetch ( `${ this . baseApiUrl } /episodes` , { query : { malId } } ) ;
529+ const res = await this . _secureFetch ( `${ this . baseApiUrl } /episodes` , { query : { anilistId } } ) ;
528530 const eps = Object . entries ( res . providers ) . reduce ( ( a , [ provider , { episodes } ] ) => (
529531 Object . entries ( episodes ) . forEach ( ( [ type , list ] ) => list . forEach ( ep => ( a [ ep . number ] ??= [ ] ) . push ( { ...ep , provider, type } ) ) ) , a
530532 ) , { } ) ;
@@ -538,7 +540,7 @@ const Websites = [
538540 const source = this . _getLocalSourceName ( provider , type ) ;
539541 try {
540542 const sresJson = await this . _secureFetch ( `${ this . baseApiUrl } /sources` , { query : { episodeId : id , provider, category : type } } ) ;
541- const referer = provider == 'KICKASSANIME ' ? 'https:// kaa.to/ ' : provider == 'ZORO ' ? 'https:// megacloud.blog/ ' : provider == 'ANIMEPAHE ' ? 'https:// kwik.cx/ ' : location . href ;
543+ const referer = "https://" + ( provider == 'kaa ' ? 'kaa.to' : provider == 'zoro ' ? 'megacloud.blog' : provider == 'kiwi ' ? 'kwik.cx' : provider == 'arc' ? 'anikai.to' : location . origin ) + "/" ;
542544 links [ source ] = { stream : sresJson . streams [ 0 ] . url , type : "m3u8" , tracks : sresJson . tracks || sresJson . subtitles || [ ] , referer } ;
543545 } catch ( e ) { showToast ( `Failed to fetch ep-${ epNum } from ${ source } : ${ e } ` ) ; }
544546 } ;
@@ -875,6 +877,42 @@ const Websites = [
875877 return ! Object . keys ( links ) . length ? null : new Episode ( epNum , _$ ( '.series-title' ) . textContent , links , epElm . querySelector ( 'img' ) ?. src || '' , epTitle ) ;
876878 } catch ( e ) { showToast ( `error ${ e . status } : ${ e . message } ` ) ; return null ; } } ) ) ;
877879 }
880+ } ,
881+ {
882+ name : 'FMovies' ,
883+ url : [ 'fmovies' ] ,
884+ _chunkSize : 12 ,
885+ extractEpisodes : async function * ( status ) {
886+ const epElms = await applyEpisodeRangeFilter ( [ ..._$$ ( 'a[href^="/watch/"]' ) ] . slice ( location . pathname . startsWith ( '/tv/' ) ) ) ;
887+ for ( let i = 0 ; i < epElms . length ; i += this . _chunkSize ) {
888+ yield * yieldEpisodesFromPromises ( ( epElms . slice ( i , i + this . _chunkSize ) ) . map ( async epElm => {
889+ const ifr = Object . assign ( document . createElement ( 'iframe' ) , { src : epElm . href , style : 'position:fixed;top:-9999px;left:-9999px;width:1px;height:1px;' } ) ;
890+ try {
891+ const epNum = epElm . querySelector ( '.w-8' ) ?. textContent ?. trim ( ) || '0' ;
892+ status . text = `Extracting Ep ${ epNum - epNum + 1 } - ${ epNum } ...` ;
893+ document . body . appendChild ( ifr ) ;
894+ let links = { } , attempts = 0 ;
895+ await new Promise ( ( r , t ) => {
896+ const check = ( ) => {
897+ try {
898+ if ( ifr . contentWindow ?. availableServers ?. length ) {
899+ links = Object . fromEntries ( ifr . contentWindow . availableServers . flatMap ( s => s . source ?. sources ?. map ( src => [ `${ s . name } -${ src . quality || 'auto' } ` , { stream : src . file || src . url , type : 'm3u8' , tracks : ( s . source . subtitles || [ ] ) . map ( t => ( { file : t . url , label : t . lang , kind : 'caption' } ) ) } ] ) || [ ] ) ) ;
900+ if ( Object . keys ( links ) . length ) { clearInterval ( checkInt ) ; r ( ) ; return ; }
901+ }
902+ } catch ( e ) { }
903+ attempts ++ ; if ( attempts >= 40 ) { clearInterval ( checkInt ) ; t ( 'timeout' ) ; }
904+ } ;
905+ const checkInt = setInterval ( check , 500 ) ;
906+ setTimeout ( ( ) => { clearInterval ( checkInt ) ; if ( ! Object . keys ( links ) . length ) t ( 'timeout' ) ; } , 20000 ) ;
907+ } ) ;
908+ if ( ! Object . keys ( links ) . length ) throw new Error ( 'no sources' ) ;
909+ return new Episode ( epNum , ( _$ ( 'h1' ) ?. textContent ?. trim ( ) || '' ) , links , epElm . querySelector ( 'img' ) ?. src , ( epElm . querySelector ( 'h4' ) ?. textContent ?. trim ( ) ) ) ;
910+ }
911+ catch ( e ) { return showToast ( `: ${ e } ` ) ; }
912+ finally { ifr . remove ( ) ; }
913+ } ) ) ;
914+ }
915+ }
878916 }
879917] ;
880918
0 commit comments