Merge pull request #331 from Critical-Impact/anidb-authentication

AniDB Authentication and Tag Builder
This commit is contained in:
meisnate12 2021-07-13 14:59:00 -04:00 committed by GitHub
commit fe80501bfd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 77 additions and 7 deletions

View file

@ -89,3 +89,6 @@ mal:
token_type: token_type:
expires_in: expires_in:
refresh_token: refresh_token:
anidb:
username: ###### - optional
password: ######

View file

@ -1,4 +1,4 @@
import logging, requests import logging, requests,time
from lxml import html from lxml import html
from modules import util from modules import util
from modules.util import Failed from modules.util import Failed
@ -6,20 +6,42 @@ from retrying import retry
logger = logging.getLogger("Plex Meta Manager") logger = logging.getLogger("Plex Meta Manager")
builders = ["anidb_id", "anidb_relation", "anidb_popular"] builders = ["anidb_id", "anidb_relation", "anidb_popular", 'anidb_tag']
class AniDB: class AniDB:
def __init__(self, config): def __init__(self, params, config):
self.config = config self.config = config
# Create a session so if we login we can continue to use the same session
self.anidb_session = requests.Session()
self.urls = { self.urls = {
"anime": "https://anidb.net/anime", "anime": "https://anidb.net/anime",
"popular": "https://anidb.net/latest/anime/popular/?h=1", "popular": "https://anidb.net/latest/anime/popular/?h=1",
"relation": "/relation/graph" "relation": "/relation/graph",
"anidb_tag": "https://anidb.net/tag",
"login": "https://anidb.net/perl-bin/animedb.pl"
} }
if params and "username" in params and "password" in params:
result = str(self._login(params["username"], params["password"]).content)
# Login response does not use proper status codes so we have to check the content of the document
if "Wrong username/password" in result:
raise Failed("AniDB Error: Login failed")
@retry(stop_max_attempt_number=6, wait_fixed=10000) @retry(stop_max_attempt_number=6, wait_fixed=10000)
def _request(self, url, language): def _request(self, url, language):
return html.fromstring(requests.get(url, headers={"Accept-Language": language, "User-Agent": "Mozilla/5.0 x64"}).content) return html.fromstring(self.anidb_session.get(url, headers={"Accept-Language": language, "User-Agent": "Mozilla/5.0 x64"}).content)
def _login(self, username, password):
data = {
"show": "main",
"xuser": username,
"xpass": password,
"xdoautologin": "on"
}
return self.anidb_session.post(self.urls["login"], data, headers={"Accept-Language": "en-US,en;q=0.5", "User-Agent": "Mozilla/5.0 x64"})
def _popular(self, language): def _popular(self, language):
response = self._request(self.urls["popular"], language) response = self._request(self.urls["popular"], language)
@ -47,12 +69,36 @@ class AniDB:
return anidb_values return anidb_values
raise Failed(f"AniDB Error: No valid AniDB IDs in {anidb_list}") raise Failed(f"AniDB Error: No valid AniDB IDs in {anidb_list}")
def _tag(self, tag, limit, language):
anidb_ids = []
next_page = True
current_url = self.urls["anidb_tag"] + "/" + str(tag)
while next_page:
logger.debug(f"Sending request to {current_url}")
response = self._request(current_url, language)
int_list = util.get_int_list(response.xpath("//td[@class='name main anime']/a/@href"), "AniDB ID")
anidb_ids.extend(int_list)
next_page_list = response.xpath("//li[@class='next']/a/@href")
logger.debug(f"next page list {next_page_list}")
if len(next_page_list) != 0 and len(anidb_ids) <= limit:
logger.debug(f"Loading next anidb page")
time.sleep(2)# Sleep as we are paging through anidb and don't want the ban hammer
current_url = "https://anidb.net" + next_page_list[0]
else:
logger.debug(f"Got to last page")
next_page = False
anidb_ids = anidb_ids[:limit]
return anidb_ids
def get_items(self, method, data, language): def get_items(self, method, data, language):
pretty = util.pretty_names[method] if method in util.pretty_names else method pretty = util.pretty_names[method] if method in util.pretty_names else method
anidb_ids = [] anidb_ids = []
if method == "anidb_popular": if method == "anidb_popular":
logger.info(f"Processing {pretty}: {data} Anime") logger.info(f"Processing {pretty}: {data} Anime")
anidb_ids.extend(self._popular(language)[:data]) anidb_ids.extend(self._popular(language)[:data])
elif method == "anidb_tag":
anidb_ids = self._tag(data["tag"], data["limit"], language)
logger.info(f"Processing {pretty}: {data['limit'] if data['limit'] > 0 else 'All'} Anime from the Tag ID: {data['tag']}")
else: else:
logger.info(f"Processing {pretty}: {data}") logger.info(f"Processing {pretty}: {data}")
if method == "anidb_id": anidb_ids.append(data) if method == "anidb_id": anidb_ids.append(data)
@ -63,4 +109,4 @@ class AniDB:
logger.debug(f"{len(anidb_ids)} AniDB IDs Found: {anidb_ids}") logger.debug(f"{len(anidb_ids)} AniDB IDs Found: {anidb_ids}")
logger.debug(f"{len(movie_ids)} TMDb IDs Found: {movie_ids}") logger.debug(f"{len(movie_ids)} TMDb IDs Found: {movie_ids}")
logger.debug(f"{len(show_ids)} TVDb IDs Found: {show_ids}") logger.debug(f"{len(show_ids)} TVDb IDs Found: {show_ids}")
return movie_ids, show_ids return movie_ids, show_ids

View file

@ -108,6 +108,7 @@ class Config:
if "omdb" in new_config: new_config["omdb"] = new_config.pop("omdb") if "omdb" in new_config: new_config["omdb"] = new_config.pop("omdb")
if "trakt" in new_config: new_config["trakt"] = new_config.pop("trakt") if "trakt" in new_config: new_config["trakt"] = new_config.pop("trakt")
if "mal" in new_config: new_config["mal"] = new_config.pop("mal") if "mal" in new_config: new_config["mal"] = new_config.pop("mal")
if "anidb" in new_config: new_config["anidb"] = new_config.pop("anidb")
yaml.round_trip_dump(new_config, open(self.config_path, "w", encoding="utf-8"), indent=ind, block_seq_indent=bsi) yaml.round_trip_dump(new_config, open(self.config_path, "w", encoding="utf-8"), indent=ind, block_seq_indent=bsi)
self.data = new_config self.data = new_config
except yaml.scanner.ScannerError as e: except yaml.scanner.ScannerError as e:
@ -270,9 +271,29 @@ class Config:
else: else:
logger.warning("mal attribute not found") logger.warning("mal attribute not found")
util.separator()
self.AniDB = None
anidb_username = check_for_attribute(self.data, "username", parent="anidb", throw=False, default=False)
anidb_password = check_for_attribute(self.data, "username", parent="anidb", throw=False, default=False)
if "anidb" in self.data and anidb_username and anidb_password:
logger.info("Connecting to AniDB...")
self.anidb = {}
try:
self.anidb["username"] = check_for_attribute(self.data, "username", parent="anidb", throw=True)
self.anidb["password"] = check_for_attribute(self.data, "password", parent="anidb", throw=True)
self.AniDB = AniDB(self.anidb, self)
except Failed as e:
logger.error(e)
logger.info(f"My Anime List Connection {'Failed' if self.MyAnimeList is None else 'Successful'}")
else:
logger.info("Using guest authentication for AniDB")
self.AniDB = AniDB(None, self)
util.separator()
self.TVDb = TVDb(self) self.TVDb = TVDb(self)
self.IMDb = IMDb(self) self.IMDb = IMDb(self)
self.AniDB = AniDB(self)
self.Convert = Convert(self) self.Convert = Convert(self)
self.AniList = AniList(self) self.AniList = AniList(self)
self.Letterboxd = Letterboxd(self) self.Letterboxd = Letterboxd(self)