anime-downloader/anime_downloader/sites/animepahe.py

151 lines
4.6 KiB
Python

import logging
import re
from anime_downloader.sites.anime import AnimeEpisode, SearchResult, Anime
from anime_downloader.sites.exceptions import NotFoundError
from anime_downloader.sites import helpers
from anime_downloader import util
logger = logging.getLogger(__name__)
class AnimePaheEpisode(AnimeEpisode):
QUALITIES = ['360p', '480p', '720p', '1080p']
def _get_source(self, episode_id, server):
# We will extract the episodes data through the animepahe api
# which returns the available qualities and the episode sources.
params = {
'id': episode_id,
'm': 'embed',
'p': server
}
episode = util.get_json('https://animepahe.com/api', params=params)
sources = episode['data'][episode_id]
if self.quality in sources:
return (server, sources[self.quality]['url'])
return
def _get_sources(self):
supported_servers = ['kwik','mp4upload','rapidvideo']
episode_id = self.url.rsplit('/', 1)[-1]
sourcetext = helpers.get(self.url, cf=True).text
sources = []
serverlist = re.findall(r'data-provider="([^"]+)', sourcetext)
for server in serverlist:
if server not in supported_servers:
continue
source = self._get_source(episode_id, server)
if source:
sources.append(source)
if sources:
return sources
raise NotFoundError
class AnimePahe(Anime):
sitename = 'animepahe'
api_url = 'https://animepahe.com/api'
base_anime_url = 'https://animepahe.com/anime/'
QUALITIES = ['360p', '480p', '720p', '1080p']
_episodeClass = AnimePaheEpisode
@classmethod
def search(cls, query):
params = {
'l': 8,
'm': 'search',
'q': query
}
search_results = util.get_json(
cls.api_url,
params=params,
)
results = []
for search_result in search_results['data']:
search_result_info = SearchResult(
title=search_result['title'],
url=cls.base_anime_url + search_result['slug'],
poster=search_result['image']
)
logger.debug(search_result_info)
results.append(search_result_info)
return results
def get_data(self):
# Extract anime id from page, using this shoddy approach as
# I have neglected my regular expression skills to the point of
# disappointment
resp = helpers.get(self.url, cf=True).text
first_search = '$.getJSON(\'/api?m=release&id='
last_search = '&l=\' + limit + \'&sort=\' + sort + \'&page=\' + page'
anime_id = (resp[resp.find(first_search)+len(first_search):
resp.find(last_search)])
self.params = {
'm': 'release',
'id': anime_id,
'sort': 'episode_asc',
'page': 1
}
resp = util.get_json(self.api_url, params=self.params)
self._scrape_metadata(resp['data'])
self._episode_urls = self._scrape_episodes(resp)
self._len = len(self._episode_urls)
return self._episode_urls
def _collect_episodes(self, ani_json, episodes=[]):
# Avoid changing original list
episodes = episodes[:]
# If episodes is not an empty list we ensure that we start off
# from the length of the episodes list to get correct episode
# numbers
for no, anime_ep in enumerate(ani_json, len(episodes)):
episodes.append(
(no+1, self.url + '/' + str(anime_ep['id']),)
)
return episodes
def _scrape_episodes(self, ani_json):
episodes = self._collect_episodes(ani_json['data'])
if not episodes:
raise NotFoundError(
'No episodes found in url "{}"'.format(self.url),
self.url
)
else:
# Check if other pages exist since animepahe only loads
# first page and make subsequent calls to the api for every
# page
start_page = ani_json['current_page'] + 1
end_page = ani_json['last_page'] + 1
for i in range(start_page, end_page):
self.params['page'] = i
resp = util.get_json(self.api_url, params=self.params)
episodes = self._collect_episodes(resp['data'], episodes)
return episodes
def _scrape_metadata(self, data):
self.title = data[0]['anime_title']