Browse Source

XBMC Metadata fixes

pull/84/head
Ruud 13 years ago
parent
commit
154a5dc099
  1. 11
      couchpotato/core/plugins/file/main.py
  2. 21
      couchpotato/core/plugins/library/main.py
  3. 4
      couchpotato/core/plugins/movie/main.py
  4. 2
      couchpotato/core/plugins/movie/static/search.js
  5. 7
      couchpotato/core/plugins/scanner/main.py
  6. 35
      couchpotato/core/providers/metadata/base.py
  7. 35
      couchpotato/core/providers/metadata/xbmc/main.py
  8. 14
      couchpotato/core/providers/movie/imdbapi/main.py
  9. 6
      couchpotato/core/providers/movie/themoviedb/main.py
  10. 27
      couchpotato/core/settings/model.py

11
couchpotato/core/plugins/file/main.py

@ -31,17 +31,18 @@ class FileManager(Plugin):
def download(self, url = '', dest = None, overwrite = False): def download(self, url = '', dest = None, overwrite = False):
if not dest: # to Cache
dest = os.path.join(Env.get('cache_dir'), '%s.%s' % (md5(url), getExt(url)))
if not overwrite and os.path.isfile(dest):
return dest
try: try:
filedata = self.urlopen(url) filedata = self.urlopen(url)
except: except:
return False return False
if not dest: # to Cache
dest = os.path.join(Env.get('cache_dir'), '%s.%s' % (md5(url), getExt(url)))
if overwrite or not os.path.isfile(dest):
self.createFile(dest, filedata, binary = True) self.createFile(dest, filedata, binary = True)
return dest return dest
def add(self, path = '', part = 1, type = (), available = 1, properties = {}): def add(self, path = '', part = 1, type = (), available = 1, properties = {}):

21
couchpotato/core/plugins/library/main.py

@ -3,16 +3,16 @@ from couchpotato.core.event import addEvent, fireEventAsync, fireEvent
from couchpotato.core.helpers.encoding import toUnicode, simplifyString from couchpotato.core.helpers.encoding import toUnicode, simplifyString
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
from string import ascii_letters from string import ascii_letters
import json
import traceback import traceback
log = CPLog(__name__) log = CPLog(__name__)
class LibraryPlugin(Plugin): class LibraryPlugin(Plugin):
default_dict = {'titles': {}, 'files':{}, 'info':{}, 'genres':{}} default_dict = {'titles': {}, 'files':{}}
def __init__(self): def __init__(self):
addEvent('library.add', self.add) addEvent('library.add', self.add)
@ -75,6 +75,7 @@ class LibraryPlugin(Plugin):
library.tagline = toUnicode(info.get('tagline', '')) library.tagline = toUnicode(info.get('tagline', ''))
library.year = info.get('year', 0) library.year = info.get('year', 0)
library.status_id = done_status.get('id') library.status_id = done_status.get('id')
library.info = toUnicode(json.dumps(info))
db.commit() db.commit()
# Titles # Titles
@ -93,20 +94,6 @@ 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 = toUnicode(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:

4
couchpotato/core/plugins/movie/main.py

@ -8,7 +8,7 @@ from couchpotato.core.plugins.base import Plugin
from couchpotato.core.settings.model import Movie, Library, LibraryTitle from couchpotato.core.settings.model import Movie, Library, LibraryTitle
from couchpotato.environment import Env from couchpotato.environment import Env
from sqlalchemy.orm import joinedload_all from sqlalchemy.orm import joinedload_all
from sqlalchemy.sql.expression import func, or_, asc, not_ from sqlalchemy.sql.expression import or_, asc, not_
from string import ascii_lowercase from string import ascii_lowercase
from urllib import urlencode from urllib import urlencode
@ -43,7 +43,7 @@ class MoviePlugin(Plugin):
def get(self, movie_id): def get(self, movie_id):
db = get_session() db = get_session()
m = db.query(Movie).filter_by(movie_id = movie_id).first() m = db.query(Movie).filter_by(id = movie_id).first()
return m.to_dict(self.default_dict) return m.to_dict(self.default_dict)

2
couchpotato/core/plugins/movie/static/search.js

@ -211,7 +211,7 @@ Block.Search.Item = new Class({
if(info.actors){ if(info.actors){
Object.each(info.actors, function(actor){ Object.each(info.actors, function(actor){
new Element('span', { new Element('span', {
'text': actor.name 'text': actor
}).inject(self.starring) }).inject(self.starring)
}) })
} }

7
couchpotato/core/plugins/scanner/main.py

@ -100,7 +100,7 @@ class Scanner(Plugin):
if group['library']: if group['library']:
fireEvent('release.add', group = group) fireEvent('release.add', group = group)
def scanFolderToLibrary(self, folder = None): def scanFolderToLibrary(self, folder = None, newer_as = None):
if not os.path.isdir(folder): if not os.path.isdir(folder):
return return
@ -322,6 +322,7 @@ class Scanner(Plugin):
data['audio'] = meta.get('audio', self.getCodec(cur_file, self.codecs['audio'])) data['audio'] = meta.get('audio', self.getCodec(cur_file, self.codecs['audio']))
data['resolution_width'] = meta.get('resolution_width', 720) data['resolution_width'] = meta.get('resolution_width', 720)
data['resolution_height'] = meta.get('resolution_height', 480) data['resolution_height'] = meta.get('resolution_height', 480)
data['aspect'] = meta.get('resolution_width', 720) / meta.get('resolution_height', 480)
except: except:
log.debug('Error parsing metadata: %s %s' % (cur_file, traceback.format_exc())) log.debug('Error parsing metadata: %s %s' % (cur_file, traceback.format_exc()))
pass pass
@ -348,8 +349,8 @@ class Scanner(Plugin):
return { return {
'video': p.video[0].codec, 'video': p.video[0].codec,
'audio': p.audio[0].codec, 'audio': p.audio[0].codec,
'resolution_width': p.video[0].width, 'resolution_width': tryInt(p.video[0].width),
'resolution_height': p.video[0].height, 'resolution_height': tryInt(p.video[0].height),
} }
except ParseError: except ParseError:
log.debug('Failed to parse meta for %s' % filename) log.debug('Failed to parse meta for %s' % filename)

35
couchpotato/core/providers/metadata/base.py

@ -1,6 +1,8 @@
from couchpotato.core.event import addEvent, fireEvent from couchpotato.core.event import addEvent, fireEvent
from couchpotato.core.helpers.variable import mergeDicts
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
import json
import os.path import os.path
import shutil import shutil
import traceback import traceback
@ -20,8 +22,21 @@ class MetaDataBase(Plugin):
log.info('Creating %s metadata.' % self.getName()) log.info('Creating %s metadata.' % self.getName())
# Update library to get latest info
try:
updated_library = fireEvent('library.update', release['library']['identifier'], force = True, single = True)
release['library'] = mergeDicts(release['library'], updated_library)
except:
log.error('Failed to update movie, before creating metadata: %s' % traceback.format_exc())
root = self.getRootName(release) root = self.getRootName(release)
try:
movie_info = json.loads(release['library'].get('info'))
except:
log.error('Failed to parse movie info: %s' % traceback.format_exc())
movie_info = {}
for file_type in ['nfo', 'thumbnail', 'fanart']: for file_type in ['nfo', 'thumbnail', 'fanart']:
try: try:
# Get file path # Get file path
@ -30,7 +45,7 @@ class MetaDataBase(Plugin):
if name and self.conf('meta_' + file_type): if name and self.conf('meta_' + file_type):
# Get file content # Get file content
content = getattr(self, 'get' + file_type.capitalize())(release) content = getattr(self, 'get' + file_type.capitalize())(movie_info = movie_info, data = release)
if content: if content:
log.debug('Creating %s file: %s' % (file_type, name)) log.debug('Creating %s file: %s' % (file_type, name))
if os.path.isfile(content): if os.path.isfile(content):
@ -38,7 +53,7 @@ class MetaDataBase(Plugin):
else: else:
self.createFile(name, content) self.createFile(name, content)
except Exception, e: except:
log.error('Unable to create %s file: %s' % (file_type, traceback.format_exc())) log.error('Unable to create %s file: %s' % (file_type, traceback.format_exc()))
def getRootName(self, data): def getRootName(self, data):
@ -53,18 +68,18 @@ class MetaDataBase(Plugin):
def getNfoName(self, root): def getNfoName(self, root):
return return
def getNfo(self, data): def getNfo(self, movie_info = {}, data = {}):
return return
def getThumbnail(self, data, file_type = 'poster_original'): def getThumbnail(self, movie_info = {}, data = {}, wanted_file_type = 'poster_original'):
file_types = fireEvent('file.types', single = True) file_types = fireEvent('file.types', single = True)
for type in file_types: for file_type in file_types:
if type.get('identifier') == file_type: if file_type.get('identifier') == wanted_file_type:
break break
for cur_file in data['library'].get('files'): for cur_file in data['library'].get('files', []):
if cur_file.get('type_id') is type.get('id'): if cur_file.get('type_id') is file_type.get('id'):
return cur_file.get('path') return cur_file.get('path')
def getFanart(self, data): def getFanart(self, movie_info = {}, data = {}):
return self.getThumbnail(data, file_type = 'backdrop_original') return self.getThumbnail(movie_info = movie_info, data = data, wanted_file_type = 'backdrop_original')

35
couchpotato/core/providers/metadata/xbmc/main.py

@ -1,10 +1,14 @@
from couchpotato.core.helpers.encoding import toUnicode from couchpotato.core.helpers.encoding import toUnicode
from couchpotato.core.logger import CPLog
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 os
import re import re
import traceback
import xml.dom.minidom import xml.dom.minidom
log = CPLog(__name__)
class XBMC(MetaDataBase): class XBMC(MetaDataBase):
def getRootName(self, data = {}): def getRootName(self, data = {}):
@ -19,11 +23,9 @@ class XBMC(MetaDataBase):
def getNfoName(self, root): def getNfoName(self, root):
return '%s.nfo' % root return '%s.nfo' % root
def getNfo(self, data): def getNfo(self, movie_info = {}, data = {}):
nfoxml = Element('movie') nfoxml = Element('movie')
types = ['rating', 'year', 'votes', 'rating', 'mpaa', 'originaltitle:original_title', 'outline:plot', 'premiered:released']
# Title # Title
try: try:
el = SubElement(nfoxml, 'title') el = SubElement(nfoxml, 'title')
@ -41,11 +43,12 @@ class XBMC(MetaDataBase):
# Runtime # Runtime
try: try:
runtime = SubElement(nfoxml, 'runtime') runtime = SubElement(nfoxml, 'runtime')
runtime.text = '%s min' % data['library']['runtime'] runtime.text = '%s min' % movie_info.get('runtime')
except: except:
pass pass
# Other values # Other values
types = ['rating', 'year', 'mpaa', 'originaltitle:original_title', 'outline', 'plot', 'tagline', 'premiered:released']
for type in types: for type in types:
if ':' in type: if ':' in type:
@ -56,14 +59,32 @@ class XBMC(MetaDataBase):
try: try:
if data['library'].get(type): if data['library'].get(type):
el = SubElement(nfoxml, name) el = SubElement(nfoxml, name)
el.text = toUnicode(data['library'].get(type, '')) el.text = toUnicode(movie_info.get(type, ''))
except: except:
pass pass
# Rating
for rating_type in ['imdb', 'rotten', 'tmdb']:
try:
r, v = movie_info['rating'][rating_type]
rating = SubElement(nfoxml, 'rating')
rating.text = str(r)
votes = SubElement(nfoxml, 'votes')
votes.text = str(v)
break
except:
log.error('Failed adding rating info from %s: %s' % (rating_type, traceback.format_exc()))
# Genre # Genre
for genre in data['library'].get('genres', []): for genre in movie_info.get('genres', []):
genres = SubElement(nfoxml, 'genre') genres = SubElement(nfoxml, 'genre')
genres.text = genre.get('name') genres.text = toUnicode(genre)
# Actors
for actor in movie_info.get('actors', []):
actors = SubElement(nfoxml, 'actor')
name = SubElement(actors, 'name')
name.text = toUnicode(actor)
# Clean up the xml and return it # Clean up the xml and return it

14
couchpotato/core/providers/movie/imdbapi/main.py

@ -4,6 +4,7 @@ from couchpotato.core.logger import CPLog
from couchpotato.core.providers.movie.base import MovieProvider from couchpotato.core.providers.movie.base import MovieProvider
from urllib import urlencode from urllib import urlencode
import json import json
import re
import traceback import traceback
log = CPLog(__name__) log = CPLog(__name__)
@ -63,7 +64,7 @@ class IMDBAPI(MovieProvider):
'rotten': (tryFloat(movie.get('tomatoRating', 0)), tryInt(movie.get('tomatoReviews', 0))), 'rotten': (tryFloat(movie.get('tomatoRating', 0)), tryInt(movie.get('tomatoReviews', 0))),
}, },
'imdb': str(movie.get('ID', '')), 'imdb': str(movie.get('ID', '')),
'runtime': movie.get('Runtime', ''), 'runtime': self.runtimeToMinutes(movie.get('Runtime', '')),
'released': movie.get('Released', ''), 'released': movie.get('Released', ''),
'year': movie.get('Year', ''), 'year': movie.get('Year', ''),
'plot': movie.get('Plot', ''), 'plot': movie.get('Plot', ''),
@ -75,3 +76,14 @@ class IMDBAPI(MovieProvider):
log.error('Failed parsing IMDB API json: %s' % traceback.format_exc()) log.error('Failed parsing IMDB API json: %s' % traceback.format_exc())
return movie_data return movie_data
def runtimeToMinutes(self, runtime_str):
runtime = 0
regex = '(\d*.?\d+).(hr|hrs|mins|min)+'
matches = re.findall(regex, runtime_str)
for match in matches:
nr, size = match
runtime += tryInt(nr) * (60 if 'hr' in str(size) else 1)
return runtime

6
couchpotato/core/providers/movie/themoviedb/main.py

@ -131,9 +131,9 @@ class TheMovieDb(MovieProvider):
# Images # Images
poster = self.getImage(movie, type = 'poster') poster = self.getImage(movie, type = 'poster')
backdrop = None #self.getImage(movie, type = 'backdrop') backdrop = self.getImage(movie, type = 'backdrop')
poster_original = None #self.getImage(movie, type = 'poster', size = 'mid') poster_original = self.getImage(movie, type = 'poster', size = 'mid')
backdrop_original = None #self.getImage(movie, type = 'backdrop', size = 'w1280') backdrop_original = self.getImage(movie, type = 'backdrop', size = 'w1280')
# Genres # Genres
try: try:

27
couchpotato/core/settings/model.py

@ -1,9 +1,8 @@
from elixir.entity import Entity from elixir.entity import Entity
from elixir.fields import Field from elixir.fields import Field
from elixir.options import options_defaults from elixir.options import options_defaults, using_options
from elixir.relationships import OneToMany, ManyToOne from elixir.relationships import ManyToMany, OneToMany, ManyToOne
from elixir.options import using_options from libs.elixir.relationships import OneToOne
from elixir.relationships import ManyToMany
from sqlalchemy.types import Integer, Unicode, UnicodeText, Boolean, Float, \ from sqlalchemy.types import Integer, Unicode, UnicodeText, Boolean, Float, \
String String
@ -40,22 +39,12 @@ class Library(Entity):
plot = Field(UnicodeText) plot = Field(UnicodeText)
tagline = Field(UnicodeText(255)) tagline = Field(UnicodeText(255))
info = Field(UnicodeText)
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')
class LibraryInfo(Entity):
""""""
identifier = Field(String(50))
value = Field(Unicode(255), nullable = False)
library = ManyToOne('Library')
class LibraryTitle(Entity): class LibraryTitle(Entity):
@ -70,14 +59,6 @@ class LibraryTitle(Entity):
libraries = ManyToOne('Library') libraries = ManyToOne('Library')
class LibraryGenre(Entity):
""""""
name = Field(Unicode)
libraries = ManyToMany('Library')
class Language(Entity): class Language(Entity):
"""""" """"""

Loading…
Cancel
Save