XBMC Metadata fixes
This commit is contained in:
@@ -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
|
self.createFile(dest, filedata, binary = True)
|
||||||
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)
|
|
||||||
|
|
||||||
return dest
|
return dest
|
||||||
|
|
||||||
def add(self, path = '', part = 1, type = (), available = 1, properties = {}):
|
def add(self, path = '', part = 1, type = (), available = 1, properties = {}):
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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')
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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):
|
||||||
""""""
|
""""""
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user