XBMC Metadata .nfo generation
This commit is contained in:
@@ -42,17 +42,11 @@ class FileManager(Plugin):
|
|||||||
if not dest: # to Cache
|
if not dest: # to Cache
|
||||||
dest = os.path.join(Env.get('cache_dir'), '%s.%s' % (md5(url), getExt(url)))
|
dest = os.path.join(Env.get('cache_dir'), '%s.%s' % (md5(url), getExt(url)))
|
||||||
|
|
||||||
if overwrite or not os.path.exists(dest):
|
if overwrite or not os.path.isfile(dest):
|
||||||
log.debug('Writing file to: %s' % dest)
|
self.createFile(dest, file)
|
||||||
output = open(dest, 'wb')
|
|
||||||
output.write(file)
|
|
||||||
output.close()
|
|
||||||
else:
|
|
||||||
log.debug('File already exists: %s' % dest)
|
|
||||||
|
|
||||||
return dest
|
return dest
|
||||||
|
|
||||||
|
|
||||||
def add(self, path = '', part = 1, type = (), available = 1, properties = {}):
|
def add(self, path = '', part = 1, type = (), available = 1, properties = {}):
|
||||||
db = get_session()
|
db = get_session()
|
||||||
|
|
||||||
|
|||||||
@@ -2,14 +2,15 @@ from couchpotato import get_session
|
|||||||
from couchpotato.core.event import addEvent, fireEventAsync, fireEvent
|
from couchpotato.core.event import addEvent, fireEventAsync, fireEvent
|
||||||
from couchpotato.core.logger import CPLog
|
from couchpotato.core.logger import CPLog
|
||||||
from couchpotato.core.plugins.base import Plugin
|
from couchpotato.core.plugins.base import Plugin
|
||||||
from couchpotato.core.settings.model import Library, LibraryTitle, File
|
from couchpotato.core.settings.model import Library, LibraryTitle, File, \
|
||||||
|
LibraryGenre
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
log = CPLog(__name__)
|
log = CPLog(__name__)
|
||||||
|
|
||||||
class LibraryPlugin(Plugin):
|
class LibraryPlugin(Plugin):
|
||||||
|
|
||||||
default_dict = {'titles': {}, 'files':{}, 'info':{}}
|
default_dict = {'titles': {}, 'files':{}, 'info':{}, 'genres':{}}
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
addEvent('library.add', self.add)
|
addEvent('library.add', self.add)
|
||||||
@@ -77,7 +78,6 @@ class LibraryPlugin(Plugin):
|
|||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
titles = info.get('titles', [])
|
titles = info.get('titles', [])
|
||||||
|
|
||||||
log.debug('Adding titles: %s' % titles)
|
log.debug('Adding titles: %s' % titles)
|
||||||
for title in titles:
|
for title in titles:
|
||||||
t = LibraryTitle(
|
t = LibraryTitle(
|
||||||
@@ -88,6 +88,20 @@ class LibraryPlugin(Plugin):
|
|||||||
|
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
|
# Genres
|
||||||
|
[db.delete(genre) for genre in library.genres]
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
genres = info.get('genres', [])
|
||||||
|
log.debug('Adding genres: %s' % genres)
|
||||||
|
for genre in genres:
|
||||||
|
g = LibraryGenre(
|
||||||
|
name = genre
|
||||||
|
)
|
||||||
|
library.genres.append(g)
|
||||||
|
|
||||||
|
db.commit()
|
||||||
|
|
||||||
# Files
|
# Files
|
||||||
images = info.get('images', [])
|
images = info.get('images', [])
|
||||||
for type in images:
|
for type in images:
|
||||||
|
|||||||
@@ -8,9 +8,7 @@ log = CPLog(__name__)
|
|||||||
class MetaData(Plugin):
|
class MetaData(Plugin):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
addEvent('renaming.after', self.add)
|
addEvent('renamer.after', self.add)
|
||||||
|
|
||||||
addEvent('app.load', self.add)
|
|
||||||
|
|
||||||
def add(self, data = {}):
|
def add(self, data = {}):
|
||||||
log.info('Getting meta data')
|
log.info('Getting meta data')
|
||||||
|
|||||||
@@ -77,11 +77,6 @@ config = [{
|
|||||||
'label': 'Trailer naming',
|
'label': 'Trailer naming',
|
||||||
'default': '<filename>-trailer.<ext>',
|
'default': '<filename>-trailer.<ext>',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
'name': 'backdrop_name',
|
|
||||||
'label': 'Backdrop naming',
|
|
||||||
'default': '<filename>-backdrop.<ext>',
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -119,14 +119,13 @@ class Renamer(Plugin):
|
|||||||
final_folder_name = self.doReplace(folder_name, replacements)
|
final_folder_name = self.doReplace(folder_name, replacements)
|
||||||
final_file_name = self.doReplace(file_name, replacements)
|
final_file_name = self.doReplace(file_name, replacements)
|
||||||
replacements['filename'] = final_file_name[:-(len(getExt(final_file_name)) + 1)]
|
replacements['filename'] = final_file_name[:-(len(getExt(final_file_name)) + 1)]
|
||||||
|
group['filename'] = replacements['filename']
|
||||||
|
|
||||||
# Meta naming
|
# Meta naming
|
||||||
if file_type is 'trailer':
|
if file_type is 'trailer':
|
||||||
final_file_name = self.doReplace(trailer_name, replacements)
|
final_file_name = self.doReplace(trailer_name, replacements)
|
||||||
elif file_type is 'nfo':
|
elif file_type is 'nfo':
|
||||||
final_file_name = self.doReplace(nfo_name, replacements)
|
final_file_name = self.doReplace(nfo_name, replacements)
|
||||||
elif file_type is 'backdrop':
|
|
||||||
final_file_name = self.doReplace(backdrop_name, replacements)
|
|
||||||
|
|
||||||
# Seperator replace
|
# Seperator replace
|
||||||
if separator:
|
if separator:
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ class Scanner(Plugin):
|
|||||||
'subtitle_extra': self.getSubtitlesExtras(group['unsorted_files']),
|
'subtitle_extra': self.getSubtitlesExtras(group['unsorted_files']),
|
||||||
'nfo': self.getNfo(group['unsorted_files']),
|
'nfo': self.getNfo(group['unsorted_files']),
|
||||||
'trailer': self.getTrailers(group['unsorted_files']),
|
'trailer': self.getTrailers(group['unsorted_files']),
|
||||||
'backdrop': images['backdrop'],
|
#'backdrop': images['backdrop'],
|
||||||
'leftover': set(group['unsorted_files']),
|
'leftover': set(group['unsorted_files']),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from couchpotato.core.event import addEvent
|
from couchpotato.core.event import addEvent, fireEvent
|
||||||
from couchpotato.core.logger import CPLog
|
from couchpotato.core.logger import CPLog
|
||||||
from couchpotato.core.plugins.base import Plugin
|
from couchpotato.core.plugins.base import Plugin
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ class MetaDataBase(Plugin):
|
|||||||
|
|
||||||
log.info('Creating %s metadata.' % self.getName())
|
log.info('Creating %s metadata.' % self.getName())
|
||||||
|
|
||||||
root = self.getRootName()
|
root = self.getRootName(release)
|
||||||
|
|
||||||
for type in ['nfo', 'thumbnail', 'fanart']:
|
for type in ['nfo', 'thumbnail', 'fanart']:
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
|
from couchpotato.core.helpers.encoding import toUnicode
|
||||||
from couchpotato.core.providers.metadata.base import MetaDataBase
|
from couchpotato.core.providers.metadata.base import MetaDataBase
|
||||||
from xml.etree.ElementTree import Element, SubElement, tostring
|
from xml.etree.ElementTree import Element, SubElement, tostring
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
import xml.dom.minidom
|
import xml.dom.minidom
|
||||||
|
|
||||||
class XBMC(MetaDataBase):
|
class XBMC(MetaDataBase):
|
||||||
|
|
||||||
def getRootName(self, data = {}):
|
def getRootName(self, data = {}):
|
||||||
|
return os.path.join(data['destination_dir'], data['filename'])
|
||||||
|
|
||||||
|
|
||||||
return '/Users/ruud/Downloads/Test/Transformers'
|
|
||||||
|
|
||||||
def getFanartName(self, root):
|
def getFanartName(self, root):
|
||||||
return '%s-fanart.jpg' % root
|
return '%s-fanart.jpg' % root
|
||||||
@@ -23,8 +22,30 @@ class XBMC(MetaDataBase):
|
|||||||
def getNfo(self, data):
|
def getNfo(self, data):
|
||||||
nfoxml = Element('movie')
|
nfoxml = Element('movie')
|
||||||
|
|
||||||
types = ['title', 'rating', 'year', 'votes', 'rating', 'mpaa', 'originaltitle:original_title', 'outline:overview', 'premiered:released', 'id:imdb_id']
|
types = ['rating', 'year', 'votes', 'rating', 'mpaa', 'originaltitle:original_title', 'outline:plot', 'premiered:released']
|
||||||
|
|
||||||
|
# Title
|
||||||
|
try:
|
||||||
|
el = SubElement(nfoxml, 'title')
|
||||||
|
el.text = toUnicode(data['library']['titles'][0]['title'])
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# IMDB id
|
||||||
|
try:
|
||||||
|
el = SubElement(nfoxml, 'id')
|
||||||
|
el.text = toUnicode(data['library']['identifier'])
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Runtime
|
||||||
|
try:
|
||||||
|
runtime = SubElement(nfoxml, 'runtime')
|
||||||
|
runtime.text = '%s min' % data['library']['runtime']
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Other values
|
||||||
for type in types:
|
for type in types:
|
||||||
|
|
||||||
if ':' in type:
|
if ':' in type:
|
||||||
@@ -33,20 +54,17 @@ class XBMC(MetaDataBase):
|
|||||||
name = type
|
name = type
|
||||||
|
|
||||||
try:
|
try:
|
||||||
el = SubElement(nfoxml, name)
|
if data['library'].get(type):
|
||||||
el.text = data.get(type, '')
|
el = SubElement(nfoxml, name)
|
||||||
|
el.text = toUnicode(data['library'].get(type, ''))
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
#for genre in self.get('genres'):
|
# Genre
|
||||||
# genres = SubElement(nfoxml, 'genre')
|
for genre in data['library'].get('genres', []):
|
||||||
# genres.text = genre
|
genres = SubElement(nfoxml, 'genre')
|
||||||
|
genres.text = genre.get('name')
|
||||||
|
|
||||||
try:
|
|
||||||
runtime = SubElement(nfoxml, 'runtime')
|
|
||||||
runtime.text = data.get('runtime') + " min"
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Clean up the xml and return it
|
# Clean up the xml and return it
|
||||||
nfoxml = xml.dom.minidom.parseString(tostring(nfoxml))
|
nfoxml = xml.dom.minidom.parseString(tostring(nfoxml))
|
||||||
@@ -55,130 +73,3 @@ class XBMC(MetaDataBase):
|
|||||||
xml_string = text_re.sub('>\g<1></', xml_string)
|
xml_string = text_re.sub('>\g<1></', xml_string)
|
||||||
|
|
||||||
return xml_string.encode('utf-8')
|
return xml_string.encode('utf-8')
|
||||||
"""
|
|
||||||
def _get_fanart(self, min_height, min_width):
|
|
||||||
''' Fetches the fanart for the specified imdb_id and saves it to dir.
|
|
||||||
Arguments
|
|
||||||
|
|
||||||
min_height/width: Sets lowest acceptable resolution fanart. 0 means
|
|
||||||
disregard. If no fanart available at specified resolution or greater, then
|
|
||||||
we disregard.
|
|
||||||
'''
|
|
||||||
images = [image['image'] for image in self.tmdb_data['backdrops'] if image['image'].get('size') == 'original']
|
|
||||||
if len(images) == 0:
|
|
||||||
return
|
|
||||||
|
|
||||||
return self._get_image(images, min_height, min_width)
|
|
||||||
|
|
||||||
def get_fanart_url(self, min_height, min_width):
|
|
||||||
return self._get_fanart(min_height, min_width)['url']
|
|
||||||
|
|
||||||
def write_fanart(self, filename_root, path, min_height, min_width):
|
|
||||||
fanart_url = self.get_fanart_url(min_height, min_width)
|
|
||||||
#fetch and write to disk
|
|
||||||
dest = os.path.join(path, filename_root)
|
|
||||||
try:
|
|
||||||
f = open(dest, 'wb')
|
|
||||||
except:
|
|
||||||
raise IOError("Can't open for writing: %s" % dest)
|
|
||||||
|
|
||||||
response = urllib2.urlopen(fanart_url)
|
|
||||||
f.write(response.read())
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _get_poster(self, min_height, min_width):
|
|
||||||
''' Fetches the poster for the specified imdb_id and saves it to dir.
|
|
||||||
Arguments
|
|
||||||
|
|
||||||
min_height/width: Sets lowest acceptable resolution poster. 0 means
|
|
||||||
disregard. If no poster available at specified resolution or greater, then
|
|
||||||
we disregard.
|
|
||||||
'''
|
|
||||||
images = [image['image'] for image in self.tmdb_data['posters'] if image['image'].get('size') == 'original']
|
|
||||||
if len(images) == 0:
|
|
||||||
return
|
|
||||||
|
|
||||||
return self._get_image(images, min_height, min_width)
|
|
||||||
|
|
||||||
def get_poster_url(self, min_height, min_width):
|
|
||||||
return self._get_poster(min_height, min_width)['url']
|
|
||||||
|
|
||||||
def write_poster(self, filename_root, path, min_height, min_width):
|
|
||||||
poster_url = self.get_poster_url(min_height, min_width)
|
|
||||||
dest = os.path.join(path, filename_root)
|
|
||||||
|
|
||||||
try:
|
|
||||||
f = open(dest, 'wb')
|
|
||||||
except:
|
|
||||||
raise IOError("Can't open for writing: %s" % dest)
|
|
||||||
|
|
||||||
response = urllib2.urlopen(poster_url)
|
|
||||||
f.write(response.read())
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _get_tmdb_imdb(self):
|
|
||||||
url = "http://api.themoviedb.org/2.1/Movie.imdbLookup/en/json/%s/%s" % (__tmdb_apikey__, self.imdbid)
|
|
||||||
|
|
||||||
count = 0
|
|
||||||
while 1:
|
|
||||||
count += 1
|
|
||||||
response = urllib2.urlopen(url)
|
|
||||||
json_string = response.read()
|
|
||||||
try:
|
|
||||||
tmdb_data = json.loads(json_string)[0]
|
|
||||||
return tmdb_data
|
|
||||||
except ValueError, e:
|
|
||||||
if count < 3:
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
raise ApiError("Invalid JSON: %s: %s" % (e, json_string))
|
|
||||||
except:
|
|
||||||
ApiError("JSON error with: %s" % json_string)
|
|
||||||
|
|
||||||
|
|
||||||
def _get_image(self, image_list, min_height, min_width):
|
|
||||||
#Select image
|
|
||||||
images = []
|
|
||||||
for image in image_list:
|
|
||||||
if not min_height or min_width:
|
|
||||||
images.append(image)
|
|
||||||
break
|
|
||||||
elif min_height and not min_width:
|
|
||||||
if image['height'] >= min_height:
|
|
||||||
images.append(image)
|
|
||||||
break
|
|
||||||
elif min_width and not min_height:
|
|
||||||
if image['width'] >= min_width:
|
|
||||||
images.append(image)
|
|
||||||
break
|
|
||||||
elif min_width and min_height:
|
|
||||||
if image['width'] >= min_width and image['height'] >= min_height:
|
|
||||||
images.append(image)
|
|
||||||
break
|
|
||||||
|
|
||||||
#No image meets our resolution requirements, so disregard those requirements
|
|
||||||
if len(images) == 0 and min_height or min_width:
|
|
||||||
images.append(image_list[0])
|
|
||||||
|
|
||||||
return images[0]
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
import sys
|
|
||||||
try:
|
|
||||||
id = sys.argv[1]
|
|
||||||
except:
|
|
||||||
id = 'tt0111161'
|
|
||||||
|
|
||||||
x = MetaGen(id)
|
|
||||||
x.write_nfo("movie.nfo")
|
|
||||||
try:
|
|
||||||
x.write_fanart("fanart.jpg", ".", 0, 0)
|
|
||||||
except: pass
|
|
||||||
try:
|
|
||||||
x.write_poster("movie.tbn", ".", 0, 0)
|
|
||||||
except: pass
|
|
||||||
"""
|
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ class TheMovieDb(MovieProvider):
|
|||||||
def getInfo(self, identifier = None):
|
def getInfo(self, identifier = None):
|
||||||
|
|
||||||
cache_key = 'tmdb.cache.%s' % identifier
|
cache_key = 'tmdb.cache.%s' % identifier
|
||||||
result = self.getCache(cache_key)
|
result = None #self.getCache(cache_key)
|
||||||
|
|
||||||
if not result:
|
if not result:
|
||||||
result = {}
|
result = {}
|
||||||
@@ -112,27 +112,33 @@ class TheMovieDb(MovieProvider):
|
|||||||
|
|
||||||
def parseMovie(self, movie):
|
def parseMovie(self, movie):
|
||||||
|
|
||||||
year = str(movie.get('released', 'none'))[:4]
|
|
||||||
|
|
||||||
# Poster url
|
# Poster url
|
||||||
poster = self.getImage(movie, type = 'poster')
|
poster = self.getImage(movie, type = 'poster')
|
||||||
backdrop = self.getImage(movie, type = 'backdrop')
|
backdrop = self.getImage(movie, type = 'backdrop')
|
||||||
|
|
||||||
|
# Genres
|
||||||
|
genres = self.getCategory(movie, 'genre')
|
||||||
|
|
||||||
# 1900 is the same as None
|
# 1900 is the same as None
|
||||||
|
year = str(movie.get('released', 'none'))[:4]
|
||||||
if year == '1900' or year.lower() == 'none':
|
if year == '1900' or year.lower() == 'none':
|
||||||
year = None
|
year = None
|
||||||
|
|
||||||
movie_data = {
|
movie_data = {
|
||||||
'id': int(movie.get('id', 0)),
|
'id': int(movie.get('id', 0)),
|
||||||
'titles': [toUnicode(movie.get('name'))],
|
'titles': [toUnicode(movie.get('name'))],
|
||||||
|
'original_title': movie.get('original_name'),
|
||||||
'images': {
|
'images': {
|
||||||
'posters': [poster],
|
'posters': [poster],
|
||||||
'backdrops': [backdrop],
|
'backdrops': [backdrop],
|
||||||
},
|
},
|
||||||
'imdb': movie.get('imdb_id'),
|
'imdb': movie.get('imdb_id'),
|
||||||
|
'runtime': movie.get('runtime'),
|
||||||
|
'released': movie.get('released'),
|
||||||
'year': year,
|
'year': year,
|
||||||
'plot': movie.get('overview', ''),
|
'plot': movie.get('overview', ''),
|
||||||
'tagline': '',
|
'tagline': '',
|
||||||
|
'genres': genres,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Add alternative names
|
# Add alternative names
|
||||||
@@ -153,6 +159,19 @@ class TheMovieDb(MovieProvider):
|
|||||||
|
|
||||||
return image
|
return image
|
||||||
|
|
||||||
|
def getCategory(self, movie, type = 'genre'):
|
||||||
|
|
||||||
|
cats = movie.get('categories', {}).get(type)
|
||||||
|
|
||||||
|
categories = []
|
||||||
|
for category in cats:
|
||||||
|
try:
|
||||||
|
categories.append(category)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return categories
|
||||||
|
|
||||||
def isDisabled(self):
|
def isDisabled(self):
|
||||||
if self.conf('api_key') == '':
|
if self.conf('api_key') == '':
|
||||||
log.error('No API key provided.')
|
log.error('No API key provided.')
|
||||||
|
|||||||
@@ -44,12 +44,10 @@ class Library(Entity):
|
|||||||
status = ManyToOne('Status')
|
status = ManyToOne('Status')
|
||||||
movies = OneToMany('Movie')
|
movies = OneToMany('Movie')
|
||||||
titles = OneToMany('LibraryTitle')
|
titles = OneToMany('LibraryTitle')
|
||||||
|
genres = ManyToMany('LibraryGenre')
|
||||||
files = ManyToMany('File')
|
files = ManyToMany('File')
|
||||||
info = OneToMany('LibraryInfo')
|
info = OneToMany('LibraryInfo')
|
||||||
|
|
||||||
def title(self):
|
|
||||||
return self.titles[0]['title']
|
|
||||||
|
|
||||||
|
|
||||||
class LibraryInfo(Entity):
|
class LibraryInfo(Entity):
|
||||||
""""""
|
""""""
|
||||||
@@ -71,6 +69,14 @@ class LibraryTitle(Entity):
|
|||||||
libraries = ManyToOne('Library')
|
libraries = ManyToOne('Library')
|
||||||
|
|
||||||
|
|
||||||
|
class LibraryGenre(Entity):
|
||||||
|
""""""
|
||||||
|
|
||||||
|
name = Field(Unicode)
|
||||||
|
|
||||||
|
libraries = ManyToMany('Library')
|
||||||
|
|
||||||
|
|
||||||
class Language(Entity):
|
class Language(Entity):
|
||||||
""""""
|
""""""
|
||||||
|
|
||||||
|
|||||||
@@ -350,7 +350,7 @@ class MovieDb:
|
|||||||
etree = XmlHandler(url).getEt()
|
etree = XmlHandler(url).getEt()
|
||||||
lookup_results = SearchResults()
|
lookup_results = SearchResults()
|
||||||
for cur_lookup in etree.find("movies").findall("movie"):
|
for cur_lookup in etree.find("movies").findall("movie"):
|
||||||
cur_movie = self._parseSearchResults(cur_lookup)
|
cur_movie = self._parseMovie(cur_lookup)
|
||||||
lookup_results.append(cur_movie)
|
lookup_results.append(cur_movie)
|
||||||
return lookup_results
|
return lookup_results
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user