commit
c54c9d8927
|
@ -74,6 +74,7 @@ Yeah. Me too! That's why this tool exists.
|
||||||
- Darkanime
|
- Darkanime
|
||||||
- Dbanimes
|
- Dbanimes
|
||||||
- EraiRaws
|
- EraiRaws
|
||||||
|
- EgyAnime - usually m3u8 (good for streaming, not so much for downloading)
|
||||||
- FastAni
|
- FastAni
|
||||||
- GurminderBoparai (AnimeChameleon)
|
- GurminderBoparai (AnimeChameleon)
|
||||||
- itsaturday
|
- itsaturday
|
||||||
|
|
|
@ -48,6 +48,13 @@ DEFAULT_CONFIG = {
|
||||||
'animefrenzy': {
|
'animefrenzy': {
|
||||||
'version': 'subbed'
|
'version': 'subbed'
|
||||||
},
|
},
|
||||||
|
'egyanime': {
|
||||||
|
'version': 'subbed',
|
||||||
|
'servers': [
|
||||||
|
'clipwatching',
|
||||||
|
'streamtape'
|
||||||
|
]
|
||||||
|
},
|
||||||
'animebinge': {
|
'animebinge': {
|
||||||
'version': 'subbed',
|
'version': 'subbed',
|
||||||
'servers': [
|
'servers': [
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
from anime_downloader.extractors.base_extractor import BaseExtractor
|
||||||
|
from anime_downloader.sites import helpers
|
||||||
|
from anime_downloader.util import deobfuscate_packed_js
|
||||||
|
import re
|
||||||
|
import json
|
||||||
|
|
||||||
|
class clipwatching(BaseExtractor):
|
||||||
|
def _get_data(self):
|
||||||
|
fix_json = [['src:', '"src":'], ['type:', '"type":']]
|
||||||
|
sources = re.search(r"sources:\s*(\[.*?\])", helpers.get(self.url).text).group(1)
|
||||||
|
for x, y in fix_json:
|
||||||
|
sources = sources.replace(x, y)
|
||||||
|
sources = json.loads(sources)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'stream_url': sources[0]['src'],
|
||||||
|
'referer': self.url
|
||||||
|
}
|
|
@ -1,176 +1,182 @@
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
|
|
||||||
ALL_EXTRACTORS = [
|
ALL_EXTRACTORS = [
|
||||||
{
|
{
|
||||||
'sitename': 'rapidvideo',
|
'sitename': 'rapidvideo',
|
||||||
'modulename': 'rapidvideo',
|
'modulename': 'rapidvideo',
|
||||||
'regex': 'rapidvideo',
|
'regex': 'rapidvideo',
|
||||||
'class': 'RapidVideo'
|
'class': 'RapidVideo'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'sitename': 'no_extractor',
|
'sitename': 'clipwatching',
|
||||||
'modulename': 'fake_extractor',
|
'modulename': 'clipwatching',
|
||||||
'regex': 'no_extractor',
|
'regex': 'clipwatching',
|
||||||
'class': 'AnimeVideo',
|
'class': 'clipwatching'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'sitename': 'animeonline360',
|
'sitename': 'no_extractor',
|
||||||
'modulename': 'animeonline360',
|
'modulename': 'fake_extractor',
|
||||||
'regex': 'animeonline360',
|
'regex': 'no_extractor',
|
||||||
'class': 'AnimeOnline360',
|
'class': 'AnimeVideo',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'sitename': 'stream.moe',
|
'sitename': 'animeonline360',
|
||||||
'modulename': 'moe',
|
'modulename': 'animeonline360',
|
||||||
'regex': 'stream.moe',
|
'regex': 'animeonline360',
|
||||||
'class': 'StreamMoe',
|
'class': 'AnimeOnline360',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'sitename': 'streamango',
|
'sitename': 'stream.moe',
|
||||||
'modulename': 'streamango',
|
'modulename': 'moe',
|
||||||
'regex': 'streamango',
|
'regex': 'stream.moe',
|
||||||
'class': 'Streamango',
|
'class': 'StreamMoe',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'sitename': 'mp4upload',
|
'sitename': 'streamango',
|
||||||
'modulename': 'mp4upload',
|
'modulename': 'streamango',
|
||||||
'regex': 'mp4upload',
|
'regex': 'streamango',
|
||||||
'class': 'MP4Upload'
|
'class': 'Streamango',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'sitename': 'kwik',
|
'sitename': 'mp4upload',
|
||||||
'modulename': 'kwik',
|
'modulename': 'mp4upload',
|
||||||
'regex': 'kwik',
|
'regex': 'mp4upload',
|
||||||
'class': 'Kwik'
|
'class': 'MP4Upload'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'sitename': 'trollvid',
|
'sitename': 'kwik',
|
||||||
'modulename': 'trollvid',
|
'modulename': 'kwik',
|
||||||
'regex': 'trollvid',
|
'regex': 'kwik',
|
||||||
'class': 'Trollvid'
|
'class': 'Kwik'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'sitename': 'mp4sh',
|
'sitename': 'trollvid',
|
||||||
'modulename': 'mp4sh',
|
'modulename': 'trollvid',
|
||||||
'regex': 'mp4sh',
|
'regex': 'trollvid',
|
||||||
'class': 'MP4Sh'
|
'class': 'Trollvid'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'sitename': 'yourupload',
|
'sitename': 'mp4sh',
|
||||||
'modulename': 'yourupload',
|
'modulename': 'mp4sh',
|
||||||
'regex': 'yourupload',
|
'regex': 'mp4sh',
|
||||||
'class': 'Yourupload'
|
'class': 'MP4Sh'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'sitename': 'vidstream',
|
'sitename': 'yourupload',
|
||||||
'modulename': 'vidstream',
|
'modulename': 'yourupload',
|
||||||
'regex': 'vidstream',
|
'regex': 'yourupload',
|
||||||
'class': 'VidStream'
|
'class': 'Yourupload'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'sitename': 'haloani',
|
'sitename': 'vidstream',
|
||||||
'modulename': 'haloani',
|
'modulename': 'vidstream',
|
||||||
'regex': 'haloani',
|
'regex': 'vidstream',
|
||||||
'class': 'Haloani'
|
'class': 'VidStream'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'sitename': 'gcloud',
|
'sitename': 'haloani',
|
||||||
'modulename': 'gcloud',
|
'modulename': 'haloani',
|
||||||
'regex': 'gcloud',
|
'regex': 'haloani',
|
||||||
'class': 'Gcloud'
|
'class': 'Haloani'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'sitename': 'xstreamcdn',
|
'sitename': 'gcloud',
|
||||||
'modulename': 'xstreamcdn',
|
'modulename': 'gcloud',
|
||||||
'regex': 'xstreamcdn',
|
'regex': 'gcloud',
|
||||||
'class': 'XStreamCDN'
|
'class': 'Gcloud'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'sitename': 'cloud9',
|
'sitename': 'xstreamcdn',
|
||||||
'modulename': 'cloud9',
|
'modulename': 'xstreamcdn',
|
||||||
'regex': 'cloud9',
|
'regex': 'xstreamcdn',
|
||||||
'class': 'Cloud9'
|
'class': 'XStreamCDN'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'sitename': 'hydrax',
|
'sitename': 'cloud9',
|
||||||
'modulename': 'hydrax',
|
'modulename': 'cloud9',
|
||||||
'regex': 'hydrax',
|
'regex': 'cloud9',
|
||||||
'class': 'Hydrax'
|
'class': 'Cloud9'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'sitename': 'streamx',
|
'sitename': 'hydrax',
|
||||||
'modulename': 'streamx',
|
'modulename': 'hydrax',
|
||||||
'regex': 'streamx',
|
'regex': 'hydrax',
|
||||||
'class': 'StreamX'
|
'class': 'Hydrax'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'sitename': '3rdparty',
|
'sitename': 'streamx',
|
||||||
'modulename': '3rdparty',
|
'modulename': 'streamx',
|
||||||
'regex': '3rdparty',
|
'regex': 'streamx',
|
||||||
'class': 'Thirdparty'
|
'class': 'StreamX'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'sitename': 'yify',
|
'sitename': '3rdparty',
|
||||||
'modulename': 'yify',
|
'modulename': '3rdparty',
|
||||||
'regex': 'yify',
|
'regex': '3rdparty',
|
||||||
'class': 'Yify'
|
'class': 'Thirdparty'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'sitename': 'mixdrop',
|
'sitename': 'yify',
|
||||||
'modulename': 'mixdrop',
|
'modulename': 'yify',
|
||||||
'regex': 'mixdrop',
|
'regex': 'yify',
|
||||||
'class': 'Mixdrop'
|
'class': 'Yify'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'sitename': 'sendvid',
|
'sitename': 'mixdrop',
|
||||||
'modulename': 'sendvid',
|
'modulename': 'mixdrop',
|
||||||
'regex': 'sendvid',
|
'regex': 'mixdrop',
|
||||||
'class': 'SendVid'
|
'class': 'Mixdrop'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'sitename': 'sibnet',
|
'sitename': 'sendvid',
|
||||||
'modulename': 'sibnet',
|
'modulename': 'sendvid',
|
||||||
'regex': 'sibnet',
|
'regex': 'sendvid',
|
||||||
'class': 'SibNet'
|
'class': 'SendVid'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'sitename': 'uqload',
|
'sitename': 'sibnet',
|
||||||
'modulename': 'uqload',
|
'modulename': 'sibnet',
|
||||||
'regex': 'uqload',
|
'regex': 'sibnet',
|
||||||
'class': 'Uqload'
|
'class': 'SibNet'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'sitename': 'vudeo',
|
'sitename': 'uqload',
|
||||||
'modulename': 'vudeo',
|
'modulename': 'uqload',
|
||||||
'regex': 'vudeo',
|
'regex': 'uqload',
|
||||||
'class': 'Vudeo'
|
'class': 'Uqload'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'sitename': 'eplay',
|
'sitename': 'vudeo',
|
||||||
'modulename': 'eplay',
|
'modulename': 'vudeo',
|
||||||
'regex': 'eplay',
|
'regex': 'vudeo',
|
||||||
'class': 'EPlay'
|
'class': 'Vudeo'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'sitename': 'streamtape',
|
'sitename': 'eplay',
|
||||||
'modulename': 'streamtape',
|
'modulename': 'eplay',
|
||||||
'regex': 'streamtape',
|
'regex': 'eplay',
|
||||||
'class': 'StreamTape'
|
'class': 'EPlay'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'sitename': 'streamium',
|
'sitename': 'streamtape',
|
||||||
'modulename': 'streamium',
|
'modulename': 'streamtape',
|
||||||
'regex': 'streamium',
|
'regex': 'streamtape',
|
||||||
'class': 'Streamium'
|
'class': 'StreamTape'
|
||||||
}
|
},
|
||||||
]
|
{
|
||||||
|
'sitename': 'streamium',
|
||||||
|
'modulename': 'streamium',
|
||||||
def get_extractor(name):
|
'regex': 'streamium',
|
||||||
for extractor in ALL_EXTRACTORS:
|
'class': 'Streamium'
|
||||||
if extractor['regex'] in name.lower():
|
}
|
||||||
module = import_module(
|
]
|
||||||
'anime_downloader.extractors.{}'.format(
|
|
||||||
extractor['modulename'])
|
|
||||||
)
|
def get_extractor(name):
|
||||||
return getattr(module, extractor['class'])
|
for extractor in ALL_EXTRACTORS:
|
||||||
|
if extractor['regex'] in name.lower():
|
||||||
|
module = import_module(
|
||||||
|
'anime_downloader.extractors.{}'.format(
|
||||||
|
extractor['modulename'])
|
||||||
|
)
|
||||||
|
return getattr(module, extractor['class'])
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
import logging
|
||||||
|
import re
|
||||||
|
import urllib.parse
|
||||||
|
from anime_downloader.sites.anime import Anime, AnimeEpisode, SearchResult
|
||||||
|
from anime_downloader.sites import helpers
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class EgyAnime(Anime, sitename='egyanime'):
|
||||||
|
sitename = 'egyanime'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def search(cls, query):
|
||||||
|
soup = helpers.soupify(helpers.get('https://www.egyanime.com/a.php', params={'term': query}).text)
|
||||||
|
|
||||||
|
search_results = [
|
||||||
|
SearchResult(
|
||||||
|
title = i.text,
|
||||||
|
url= "https://www.egyanime.com/" + i['href']
|
||||||
|
)
|
||||||
|
for i in soup.find_all('a', href=True)
|
||||||
|
]
|
||||||
|
return search_results
|
||||||
|
|
||||||
|
def _scrape_episodes(self):
|
||||||
|
soup = helpers.soupify(helpers.get(self.url).text)
|
||||||
|
eps = ["https://www.egyanime.com/" + x['href'] for x in soup.select('a.tag.is-dark.is-medium.m-5')]
|
||||||
|
if len(eps) == 0:
|
||||||
|
return [self.url.replace('do', 'w')]
|
||||||
|
return eps
|
||||||
|
|
||||||
|
def _scrape_metadata(self):
|
||||||
|
soup = helpers.soupify(helpers.get(self.url).text)
|
||||||
|
self.title = soup.title.text.split('مشاهدة')[0].strip()
|
||||||
|
|
||||||
|
|
||||||
|
class EgyAnimeEpisode(AnimeEpisode, sitename='egyanime'):
|
||||||
|
def _get_sources(self):
|
||||||
|
soup = helpers.soupify(helpers.get(self.url).text)
|
||||||
|
servers = soup.select('div.server-watch#server-watch > a')
|
||||||
|
if servers:
|
||||||
|
servers = [x['data-link'] for x in servers]
|
||||||
|
logger.debug('Hosts: ' + str([urllib.parse.urlparse(x).netloc for x in servers]))
|
||||||
|
else:
|
||||||
|
servers = soup.find_all('a', {'data-link': True, 'class': 'panel-block'})
|
||||||
|
servers = [x['data-link'] for x in servers]
|
||||||
|
sources = []
|
||||||
|
for i in servers:
|
||||||
|
if 'clipwatching' in i:
|
||||||
|
sources.append({
|
||||||
|
'extractor': 'clipwatching',
|
||||||
|
'url': i,
|
||||||
|
'server': 'clipwatching',
|
||||||
|
'version': '1'
|
||||||
|
})
|
||||||
|
elif 'streamtape' in i:
|
||||||
|
sources.append({
|
||||||
|
'extractor': 'streamtape',
|
||||||
|
'url': i,
|
||||||
|
'server': 'streamtape',
|
||||||
|
'version': '1'
|
||||||
|
})
|
||||||
|
if sources:
|
||||||
|
return self.sort_sources(sources)
|
||||||
|
else:
|
||||||
|
logger.error('No episode source was found, file might have been deleted.')
|
||||||
|
return
|
|
@ -1,70 +1,71 @@
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
|
|
||||||
ALL_ANIME_SITES = [
|
ALL_ANIME_SITES = [
|
||||||
# ('filename', 'sitename', 'classname')
|
# ('filename', 'sitename', 'classname')
|
||||||
('_4anime', '4anime', 'Anime4'),
|
('_4anime', '4anime', 'Anime4'),
|
||||||
('anitube', 'anitube', 'AniTube'),
|
('anitube', 'anitube', 'AniTube'),
|
||||||
('anime8', 'anime8', 'Anime8'),
|
('anime8', 'anime8', 'Anime8'),
|
||||||
('animebinge', 'animebinge', 'AnimeBinge'),
|
('animebinge', 'animebinge', 'AnimeBinge'),
|
||||||
('animechameleon', 'gurminder', 'AnimeChameleon'),
|
('animechameleon', 'gurminder', 'AnimeChameleon'),
|
||||||
('animedaisuki', 'animedaisuki', 'Animedaisuki'),
|
('animedaisuki', 'animedaisuki', 'Animedaisuki'),
|
||||||
('animeflix', 'animeflix', 'AnimeFlix'),
|
('animeflix', 'animeflix', 'AnimeFlix'),
|
||||||
('animeflv', 'animeflv', 'Animeflv'),
|
('animeflv', 'animeflv', 'Animeflv'),
|
||||||
('animefreak', 'animefreak', 'AnimeFreak'),
|
('animefreak', 'animefreak', 'AnimeFreak'),
|
||||||
('animefree','animefree','AnimeFree'),
|
('animefree','animefree','AnimeFree'),
|
||||||
('animefrenzy','animefrenzy','AnimeFrenzy'),
|
('animefrenzy','animefrenzy','AnimeFrenzy'),
|
||||||
('animekisa','animekisa','AnimeKisa'),
|
('animekisa','animekisa','AnimeKisa'),
|
||||||
('animetake','animetake','AnimeTake'),
|
('animetake','animetake','AnimeTake'),
|
||||||
('animeonline','animeonline360','AnimeOnline'),
|
('animeonline','animeonline360','AnimeOnline'),
|
||||||
('animeout', 'animeout', 'AnimeOut'),
|
('animeout', 'animeout', 'AnimeOut'),
|
||||||
('animerush', 'animerush', 'AnimeRush'),
|
('animerush', 'animerush', 'AnimeRush'),
|
||||||
('animesimple', 'animesimple', 'AnimeSimple'),
|
('animesimple', 'animesimple', 'AnimeSimple'),
|
||||||
('animesuge', 'animesuge', 'AnimeSuge'),
|
('animesuge', 'animesuge', 'AnimeSuge'),
|
||||||
('animevibe', 'animevibe', 'AnimeVibe'),
|
('animevibe', 'animevibe', 'AnimeVibe'),
|
||||||
('animixplay', 'animixplay', 'AniMixPlay'),
|
('animixplay', 'animixplay', 'AniMixPlay'),
|
||||||
('darkanime', 'darkanime', 'DarkAnime'),
|
('darkanime', 'darkanime', 'DarkAnime'),
|
||||||
('dbanimes', 'dbanimes', 'DBAnimes'),
|
('dbanimes', 'dbanimes', 'DBAnimes'),
|
||||||
('erairaws', 'erai-raws', 'EraiRaws'),
|
('erairaws', 'erai-raws', 'EraiRaws'),
|
||||||
('fastani', 'fastani', 'FastAni'),
|
('egyanime', 'egyanime', 'EgyAnime'),
|
||||||
('itsaturday', 'itsaturday', 'Itsaturday'),
|
('fastani', 'fastani', 'FastAni'),
|
||||||
('justdubs', 'justdubs', 'JustDubs'),
|
('itsaturday', 'itsaturday', 'Itsaturday'),
|
||||||
('kickass', 'kickass', 'KickAss'),
|
('justdubs', 'justdubs', 'JustDubs'),
|
||||||
('kissanimex', 'kissanimex', 'KissAnimeX'),
|
('kickass', 'kickass', 'KickAss'),
|
||||||
('kisscartoon', 'kisscartoon', 'KissCartoon'),
|
('kissanimex', 'kissanimex', 'KissAnimeX'),
|
||||||
('nineanime', '9anime', 'NineAnime'),
|
('kisscartoon', 'kisscartoon', 'KissCartoon'),
|
||||||
('nyaa', 'nyaa', 'Nyaa'),
|
('nineanime', '9anime', 'NineAnime'),
|
||||||
('putlockers', 'putlockers', 'PutLockers'),
|
('nyaa', 'nyaa', 'Nyaa'),
|
||||||
('ryuanime', 'ryuanime', 'RyuAnime'),
|
('putlockers', 'putlockers', 'PutLockers'),
|
||||||
('subsplease', 'subsplease', 'SubsPlease'),
|
('ryuanime', 'ryuanime', 'RyuAnime'),
|
||||||
('twistmoe', 'twist.moe', 'TwistMoe'),
|
('subsplease', 'subsplease', 'SubsPlease'),
|
||||||
('tenshimoe', 'tenshi.moe', 'TenshiMoe'),
|
('twistmoe', 'twist.moe', 'TwistMoe'),
|
||||||
('vidstream', 'vidstream', 'VidStream'),
|
('tenshimoe', 'tenshi.moe', 'TenshiMoe'),
|
||||||
('voiranime', 'voiranime', 'VoirAnime'),
|
('vidstream', 'vidstream', 'VidStream'),
|
||||||
('vostfree', 'vostfree', 'VostFree'),
|
('voiranime', 'voiranime', 'VoirAnime'),
|
||||||
]
|
('vostfree', 'vostfree', 'VostFree'),
|
||||||
|
]
|
||||||
|
|
||||||
def get_anime_class(url):
|
|
||||||
"""
|
def get_anime_class(url):
|
||||||
Get anime class corresposing to url or name.
|
"""
|
||||||
See :py:data:`anime_downloader.sites.ALL_ANIME_SITES` to get the possible anime sites.
|
Get anime class corresposing to url or name.
|
||||||
|
See :py:data:`anime_downloader.sites.ALL_ANIME_SITES` to get the possible anime sites.
|
||||||
Parameters
|
|
||||||
----------
|
Parameters
|
||||||
url: string
|
----------
|
||||||
URL of the anime.
|
url: string
|
||||||
|
URL of the anime.
|
||||||
Returns
|
|
||||||
-------
|
Returns
|
||||||
:py:class:`anime_downloader.sites.anime.Anime`
|
-------
|
||||||
Concrete implementation of :py:class:`anime_downloader.sites.anime.Anime`
|
:py:class:`anime_downloader.sites.anime.Anime`
|
||||||
"""
|
Concrete implementation of :py:class:`anime_downloader.sites.anime.Anime`
|
||||||
for site in ALL_ANIME_SITES:
|
"""
|
||||||
if site[1] in url:
|
for site in ALL_ANIME_SITES:
|
||||||
try:
|
if site[1] in url:
|
||||||
module = import_module(
|
try:
|
||||||
'anime_downloader.sites.{}'.format(site[0])
|
module = import_module(
|
||||||
)
|
'anime_downloader.sites.{}'.format(site[0])
|
||||||
except ImportError:
|
)
|
||||||
raise
|
except ImportError:
|
||||||
return getattr(module, site[2])
|
raise
|
||||||
|
return getattr(module, site[2])
|
||||||
|
|
Loading…
Reference in New Issue