You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tellico/src/translators/griffith2tellico.py

320 lines
10 KiB

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
# ***************************************************************************
# copyright : (C) 2007 by Robby Stephenson
# email : robby@periapsis.org
# based on : fr.allocine.py by Mathias Monnerville
# ***************************************************************************
#
# ***************************************************************************
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of version 2 of the GNU General Public License as *
# * published by the Free Software Foundation; *
# * *
# ***************************************************************************
import os, sys
import base64
import xml.dom.minidom
try:
import sqlite3
except:
print(sys.stderr, "The Python sqlite3 module is required to import Griffith databases.")
exit(1)
DB_PATH = os.environ['HOME'] + '/.griffith/griffith.db'
POSTERS_PATH = os.environ['HOME'] + '/.griffith/posters/'
XML_HEADER = """<?xml version="1.0" encoding="UTF-8"?>"""
DOCTYPE = """<!DOCTYPE tellico PUBLIC "-//Robby Stephenson/DTD Tellico V9.0//EN" "http://periapsis.org/tellico/dtd/v9/tellico.dtd">"""
class BasicTellicoDOM:
def __init__(self):
self.__doc = xml.dom.minidom.Document()
self.__root = self.__doc.createElement('tellico')
self.__root.setAttribute('xmlns', 'http://periapsis.org/tellico/')
self.__root.setAttribute('syntaxVersion', '9')
self.__collection = self.__doc.createElement('collection')
self.__collection.setAttribute('title', 'Griffith Import')
self.__collection.setAttribute('type', '3')
self.__fields = self.__doc.createElement('fields')
# Add all default (standard) fields
self.__dfltField = self.__doc.createElement('field')
self.__dfltField.setAttribute('name', '_default')
# change the rating to have a maximum of 10
self.__ratingField = self.__doc.createElement('field')
self.__ratingField.setAttribute('name', 'rating')
self.__ratingField.setAttribute('title', 'Personal Rating')
self.__ratingField.setAttribute('flags', '2')
self.__ratingField.setAttribute('category', 'Personal')
self.__ratingField.setAttribute('format', '4')
self.__ratingField.setAttribute('type', '14')
self.__ratingField.setAttribute('i18n', 'yes')
propNode = self.__doc.createElement('prop')
propNode.setAttribute('name', 'maximum')
propNode.appendChild(self.__doc.createTextNode('10'))
self.__ratingField.appendChild(propNode);
propNode = self.__doc.createElement('prop')
propNode.setAttribute('name', 'minimum')
propNode.appendChild(self.__doc.createTextNode('1'))
self.__ratingField.appendChild(propNode);
# Add a custom 'Original Title' field
self.__titleField = self.__doc.createElement('field')
self.__titleField.setAttribute('name', 'orig-title')
self.__titleField.setAttribute('title', 'Original Title')
self.__titleField.setAttribute('flags', '8')
self.__titleField.setAttribute('category', 'General')
self.__titleField.setAttribute('format', '1')
self.__titleField.setAttribute('type', '1')
self.__titleField.setAttribute('i18n', 'yes')
self.__keywordField = self.__doc.createElement('field')
self.__keywordField.setAttribute('name', 'keyword')
self.__keywordField.setAttribute('title', 'Keywords')
self.__keywordField.setAttribute('flags', '7')
self.__keywordField.setAttribute('category', 'Personal')
self.__keywordField.setAttribute('format', '4')
self.__keywordField.setAttribute('type', '1')
self.__keywordField.setAttribute('i18n', 'yes')
self.__urlField = self.__doc.createElement('field')
self.__urlField.setAttribute('name', 'url')
self.__urlField.setAttribute('title', 'URL')
self.__urlField.setAttribute('flags', '0')
self.__urlField.setAttribute('category', 'General')
self.__urlField.setAttribute('format', '4')
self.__urlField.setAttribute('type', '7')
self.__urlField.setAttribute('i18n', 'yes')
self.__fields.appendChild(self.__dfltField)
self.__fields.appendChild(self.__ratingField)
self.__fields.appendChild(self.__titleField)
self.__fields.appendChild(self.__keywordField)
self.__fields.appendChild(self.__urlField)
self.__collection.appendChild(self.__fields)
self.__images = self.__doc.createElement('images')
self.__root.appendChild(self.__collection)
self.__doc.appendChild(self.__root)
self.__fieldsMap = dict(country='nationality',
classification='certification',
runtime='running-time',
o_title='orig-title',
notes='comments',
image='cover',
tag='keyword',
site='url')
def addMedia(self, media):
if len(media) == 0: return
# add default Tellico values
orig_media = 'DVD;VHS;VCD;DivX;Blu-ray;HD DVD'.split(';')
orig_media.extend(media)
# make sure unique
set = {}
media = [set.setdefault(e,e) for e in orig_media if e not in set]
mediaField = self.__doc.createElement('field')
mediaField.setAttribute('name', 'medium')
mediaField.setAttribute('title', 'Medium')
mediaField.setAttribute('flags', '2')
mediaField.setAttribute('category', 'General')
mediaField.setAttribute('format', '4')
mediaField.setAttribute('type', '3')
mediaField.setAttribute('i18n', 'yes')
mediaField.setAttribute('allowed', ';'.join(media))
self.__fields.appendChild(mediaField)
def addEntry(self, movieData):
"""
Add a movie entry
"""
entryNode = self.__doc.createElement('entry')
entryNode.setAttribute('id', movieData['id'])
for key, values in movieData.items():
if key == 'id':
continue
if key in self.__fieldsMap:
field = self.__fieldsMap[key]
else:
field = key
parentNode = self.__doc.createElement(field + 's')
for value in values:
if len(value) == 0: continue
node = self.__doc.createElement(field)
if field == 'certification': value += " (USA)"
elif field == 'region': value = "Region " + value
elif field == 'cover':
imageNode = self.__doc.createElement('image')
imageNode.setAttribute('format', 'JPEG')
imageNode.setAttribute('id', value[0])
imageNode.appendChild(self.__doc.createTextNode(value[1]))
self.__images.appendChild(imageNode)
value = value[0] # value was (id, md5)
if field == 'cast':
for v in value:
columnNode = self.__doc.createElement('column')
columnNode.appendChild(self.__doc.createTextNode(v.strip()))
node.appendChild(columnNode)
else:
node.appendChild(self.__doc.createTextNode(value.strip()))
if node.hasChildNodes(): parentNode.appendChild(node)
if parentNode.hasChildNodes(): entryNode.appendChild(parentNode)
self.__collection.appendChild(entryNode)
def printXML(self):
"""
Outputs XML content to stdout
"""
self.__collection.appendChild(self.__images)
print(XML_HEADER); print(DOCTYPE)
print(self.__root.toxml())
class GriffithParser:
def __init__(self):
self.__dbPath = DB_PATH
self.__domTree = BasicTellicoDOM()
def run(self):
"""
Runs the parser: fetch movie ids, then fills and prints the DOM tree
to stdout (in tellico format) so that tellico can use it.
"""
self.__conn = sqlite3.connect(self.__dbPath)
self.__loadDatabase()
# Print results to stdout
self.__domTree.printXML()
def __addMediaValues(self):
c = self.__conn.cursor()
c.execute("SELECT name FROM media")
media = list([row[0].encode('utf-8') for row in c.fetchall()])
self.__domTree.addMedia(media)
def __fetchMovieIds(self):
"""
Retrieve all movie ids
"""
c = self.__conn.cursor()
c.execute("SELECT movie_id FROM movies")
data = c.fetchall()
dataList = [row[0] for row in data]
return dataList
def __fetchMovieInfo(self, id):
"""
Fetches movie information
"""
#cast is a reserved word
columns = ('title','director','rating','year','region',
'country','genre','classification','plot',
'runtime','o_title','studio','notes','image',
'[cast]','loaned','color','site')
c = self.__conn.cursor()
c.execute("SELECT %s FROM movies WHERE movie_id=%s" % (','.join(columns),id))
row = c.fetchone()
data = {}
data['id'] = str(id)
for i in range(len(columns)):
if row[i] == None : continue
try:
value = row[i].encode('utf-8')
except:
value = str(row[i])
col = columns[i].replace('[','').replace(']','')
if col == 'genre' or col == 'studio':
values = value.split('/')
elif col == 'plot' or col == 'notes':
value = value.replace('\n', '\n<br/>')
values = (value,)
elif col == 'cast':
values = []
lines = value.split('\n')
for line in lines:
cast = line.split('as')
values.append(cast)
elif col == 'image':
imgfile = POSTERS_PATH + value + '.jpg'
img = file(imgfile,'rb').read()
values = ((value + '.jpg', base64.encodestring(img)),)
elif col == 'loaned':
if value == '0': value = ''
values = (value,)
elif col == 'color':
if value == '1': value = 'Color'
elif value == '2': value = 'Black & White'
values = (value,)
else:
values = (value,)
col = col.replace('"','')
data[col] = values
# get medium
c.execute("SELECT name FROM media WHERE medium_id IN (SELECT medium_id FROM movies WHERE movie_id=%s)" % id)
media = list([row[0].encode('utf-8') for row in c.fetchall()])
if len(media) > 0: data['medium'] = media
# get all tags
c.execute("SELECT name FROM tags WHERE tag_id IN (SELECT tag_id FROM movie_tag WHERE movie_id=%s)" % id)
tags = list([row[0].encode('utf-8') for row in c.fetchall()])
if len(tags) > 0: data['tag'] = tags
# get all languages
c.execute("SELECT name FROM languages WHERE lang_id IN (SELECT lang_id FROM movie_lang WHERE movie_id=%s)" % id)
langs = list([row[0].encode('utf-8') for row in c.fetchall()])
if len(langs) > 0: data['language'] = langs
return data
def __loadDatabase(self):
# Get all ids
self.__addMediaValues();
ids = self.__fetchMovieIds()
# Now retrieve data
if ids:
for entry in ids:
data = self.__fetchMovieInfo(entry)
self.__domTree.addEntry(data)
else:
return None
def main():
parser = GriffithParser()
parser.run()
if __name__ == '__main__':
main()