Skip to content

Commit

Permalink
MyAnimeList Agent v7.0.0
Browse files Browse the repository at this point in the history
Total rework of the Agent with new features:

* API backend changed from Atarashii to Jikan (Atarashii is not
maintained anymore while Jikan is)
* Additional Images can now be requested from either TheMovieDB or
TheTVDB for either of the TV-Show or Movie libraries (this requires an
API Key for either that needs to be provided by the User)
* HAMA and the XBMCNFO importer (#18) for TV and Movies were added as
accepted metadata provider
* With Jikan providing more information, the Studio metadata is now
correctly filles with the Studio instead of the Producers (#4)
* The user can now select which preferred language should be used as the
metadat title (#5)
* The Cast is now being added to the Metadata (#6)
* The user can select which Image should be used for the Metadata
"Role". Either the Voice Actor themselves or the Character they Voice
* added Ant build script to handle the version and packaging of the
project
  • Loading branch information
Fribb committed Aug 26, 2021
1 parent 0c7b40b commit f2f968f
Show file tree
Hide file tree
Showing 14 changed files with 1,134 additions and 716 deletions.
198 changes: 39 additions & 159 deletions Contents/Code/__init__.py
Original file line number Diff line number Diff line change
@@ -1,190 +1,70 @@
'''
Last update on 26.05.2018
Plex Media Server Metadata Agent for MyAnimeList.net
This Agent will look up the title of the Anime and get the Metadata for the ID.
The Metadata will be cached in Plex for 1 Day
@author: Fribb http://coding.fribbtastic.net/
'''
import re
from datetime import datetime
from myanimelist import MyAnimeListUtils
from theTVDB import TheTVDBUtils
from theMovieDB import TheMovieDbUtils
from utils import Utils

'''The Constants'''
AGENT_NAME = "MyAnimeList.net Agent"
AGENT_VERSION = "v6.0.5"
AGENT_LANGUAGES = [Locale.Language.English]
AGENT_PRIMARY_PROVIDER = True
AGENT_ACCEPTS_FROM = [ 'com.plexapp.agents.localmedia', 'com.plexapp.agents.opensubtitles', 'com.plexapp.agents.subzero' ]
AGENT_CACHE_TIME = CACHE_1HOUR * 24
from utils import *

AGENT_MAPPING_URL = "https://atarashii.fribbtastic.net/mapping/animeMapping_full.json"
AGENT_MAPPING_CACHE_TIME = CACHE_1HOUR * 24

AGENT_UTILS = None
AGENT_MYANIMELIST = None
AGENT_THETVDB = None
AGENT_THEMOVIEDB = None
global COMMON_UTILS
COMMON_UTILS = CommonUtils()

def Start():
Log.Info("[" + AGENT_NAME + "] " + "Starting MyAnimeList.net Metadata Agent " + AGENT_VERSION)
Log.Info("[" + COMMON_UTILS.getAgentName() + "] " + "Starting MyAnimeList.net Metadata Agent v" + COMMON_UTILS.getVersion())

# Initialize Utils
global AGENT_UTILS
AGENT_UTILS = Utils()
global AGENT_MYANIMELIST
AGENT_MYANIMELIST = MyAnimeListUtils()
global AGENT_THETVDB
AGENT_THETVDB = TheTVDBUtils()
global AGENT_THEMOVIEDB
AGENT_THEMOVIEDB = TheMovieDbUtils()
return


def ValidatePrefs():
Log.Info("[" + AGENT_NAME + "] " + "Validating Preferences")
Log.Info("[" + COMMON_UTILS.getAgentName() + "] " + "Validating Preferences")

Log.Debug("[" + AGENT_NAME + "] " + "Fetch TheMovieDB images: " + str(Prefs["getTheMovieDbImages"]))
Log.Debug("[" + AGENT_NAME + "] " + "Fetch TheTVDB images: " + str(Prefs["getTheTVDBImages"]))
Log.Debug("[" + AGENT_NAME + "] " + "TheMovieDB Background Image size: " + Prefs["theMovieDbBackgroundSize"])
Log.Debug("[" + AGENT_NAME + "] " + "TheMovieDB Poster Image size: " + Prefs["theMovieDbPosterSize"])
Log.Info("[" + COMMON_UTILS.getAgentName() + "] " + "Preferred Title Language: " + str(Prefs["preferredTitle"]))
Log.Info("[" + COMMON_UTILS.getAgentName() + "] " + "Preferred Staff Image: " + str(Prefs["actorImage"]))
Log.Info("[" + COMMON_UTILS.getAgentName() + "] " + "Preferred Staff Language: " + str(Prefs["actorLanguage"]))
Log.Info("[" + COMMON_UTILS.getAgentName() + "] " + "Preferred Image Source for Shows: " + str(Prefs["tvshowImageSource"]))
Log.Info("[" + COMMON_UTILS.getAgentName() + "] " + "Preferred Image Source for Movies: " + str(Prefs["movieImageSource"]))
Log.Info("[" + COMMON_UTILS.getAgentName() + "] " + "TheMovieDB API Key: " + "-redacted-") #str(Prefs["tmdbAPIKey"]))
Log.Info("[" + COMMON_UTILS.getAgentName() + "] " + "TheMovieDB Poster Size: " + str(Prefs["tmdbPosterSize"]))
Log.Info("[" + COMMON_UTILS.getAgentName() + "] " + "TheMovieDB Background Size: " + str(Prefs["tmdbBackgroundSize"]))
Log.Info("[" + COMMON_UTILS.getAgentName() + "] " + "TheTVDB API Key: " + "-redacted-") #str(Prefs["tvdbAPIKey"]))
Log.Info("[" + COMMON_UTILS.getAgentName() + "] " + "TheTVDB API PIN: " + "-redacted-") #str(Prefs["tvdbAPIPIN"]))

Log.Info("[" + AGENT_NAME + "] " + "Validation Complete")

'''
Class declaration for The Agent
'''
class MALAgent:
'''
Method to search for an Anime TV-Show on the API
'''
def searchAnime(self, results, media, lang, type):
Log.Info("[" + AGENT_NAME + "] " + "Searching for Anime")

# check on mediaType if it is tv or movie
if type == "tv":
title = AGENT_UTILS.removeASCII(media.show)
elif type == "movie":
title = AGENT_UTILS.removeASCII(media.name)
else:
Log.Error("[" + AGENT_NAME + "] " + "No type defined, don't know which name to pick")

AGENT_MYANIMELIST.search(title, results, lang)

Log.Info("[" + AGENT_NAME + "] " + "Search Complete")
return

'''
Method to update the metadata information of an Anime TV-Show
'''
def updateTvShow(self, metadata, media, lang):
Log.Info("[" + AGENT_NAME + "] " + "Updating TV-Show Anime with ID: " + metadata.id)

AGENT_MYANIMELIST.getData(metadata, "tvshow", media)

if Prefs["getTheTVDBImages"] == True:
Log.Debug("[" + AGENT_NAME + "] " + "Fetching TheTVDB Mapping")
mappingId = self.getMapping(metadata.id, "thetvdb")

if mappingId is not None:
Log.Debug("[" + AGENT_NAME + "] " + "Fetching TheTVDB Information")
AGENT_THETVDB.getData(mappingId, metadata)

Log.Info("[" + AGENT_NAME + "] " + "Update Complete")
return

'''
Method to update the metadata information of an Anime Movie
'''
def updateMovie(self, metadata, media, lang):
Log.Info("[" + AGENT_NAME + "] " + "Updating Movie Anime with ID: " + metadata.id)

AGENT_MYANIMELIST.getData(metadata, "movie", media)

if Prefs["getTheMovieDbImages"] == True:
Log.Debug("[" + AGENT_NAME + "] " + "Fetching TheMovieDB Mapping")
mappingId = self.getMapping(metadata.id, "themoviedb")

if mappingId is not None:
Log.Debug("[" + AGENT_NAME + "] " + "Fetching TheMovieDB Information")
AGENT_THEMOVIEDB.getData(mappingId, metadata)

Log.Info("[" + AGENT_NAME + "] " + "Update Complete")
return

'''
Method to get the Mapping for a given ID
'''
def getMapping(self, id, key):

mappingFull = None

try:
Log.Info("[" + AGENT_NAME + "] [Utils] " + "Fetching URL " + str(AGENT_MAPPING_URL))
mappingFull = JSON.ObjectFromString(HTTP.Request(AGENT_MAPPING_URL, sleep=2.0, cacheTime=AGENT_MAPPING_CACHE_TIME).content)
except Exception as e:
Log.Info("[" + AGENT_NAME + "] " + "Mapping could not be requested " + str(e))

if mappingFull is None:
Log.Error("[" + AGENT_NAME + "] " + "Mapping could not be loaded")
return None
else:
Log.Info("[" + AGENT_NAME + "] " + "Searching for mapping for ID " + id)

mappingString = str(key) + "_id"
mappingId = None

for mapping in mappingFull:
if "mal_id" in mapping:
malId = AGENT_UTILS.getJSONValue("mal_id", mapping)

if str(malId) == id:
mappingId = AGENT_UTILS.getJSONValue(mappingString, mapping)

if mappingId == -1:
Log.Info("[" + AGENT_NAME + "] " + "Mapping entry was available but ID is not a valid TheTVDB or TheMovieDB ID")
return None
else:
Log.Info("[" + AGENT_NAME + "] " + "Mapping entry for ID found: " + str(key) + " = " + str(mappingId))
return mappingId # don't need to search further if I already got the ID
return mappingId
return

'''
Class declaration for The TV-Show Agent
'''
class MyAnimeList_TV(Agent.TV_Shows, MALAgent):
class MyAnimeList_TV(Agent.TV_Shows, MyAnimeListAgent):
# initialize configuration
name = AGENT_NAME
languages = AGENT_LANGUAGES
primary_provider = AGENT_PRIMARY_PROVIDER
accepts_from = AGENT_ACCEPTS_FROM
name = COMMON_UTILS.getAgentName()
languages = COMMON_UTILS.getLanguages()
primary_provider = COMMON_UTILS.getPrimaryProvider()
accepts_from = COMMON_UTILS.getAcceptsFrom()

MYANIMELIST = MyAnimeListAgent()

TYPE = "show"

def search(self, results, media, lang, manual):
self.searchAnime(results, media, lang, "tv")
self.MYANIMELIST.search(results, media, lang, manual, self.TYPE)
return

def update(self, metadata, media, lang, force):
self.updateTvShow(metadata, media, lang)
self.MYANIMELIST.update(metadata, media, lang, force, self.TYPE)
return

'''
Class declaration for The Movie Agent
'''
class MyAnimeList_Movie(Agent.Movies, MALAgent):
class MyAnimeList_Movie(Agent.Movies, MyAnimeListAgent):
# initialize configuration
name = AGENT_NAME
languages = AGENT_LANGUAGES
primary_provider = AGENT_PRIMARY_PROVIDER
accepts_from = AGENT_ACCEPTS_FROM
name = COMMON_UTILS.getAgentName()
languages = COMMON_UTILS.getLanguages()
primary_provider = COMMON_UTILS.getPrimaryProvider()
accepts_from = COMMON_UTILS.getAcceptsFrom()

MYANIMELIST = MyAnimeListAgent()

TYPE = "movie"

def search(self, results, media, lang, manual):
self.searchAnime(results, media, lang, "movie")
self.MYANIMELIST.search(results, media, lang, manual, self.TYPE)
return

def update(self, metadata, media, lang, force):
self.updateMovie(metadata, media, lang)
self.MYANIMELIST.update(metadata, media, lang, force, self.TYPE)
return
Loading

0 comments on commit f2f968f

Please sign in to comment.