meta
This commit is contained in:
parent
d385853186
commit
0e6b9533b4
12 changed files with 521 additions and 154 deletions
17
README
17
README
|
@ -4,6 +4,23 @@ Open Media Library
|
||||||
|
|
||||||
soon
|
soon
|
||||||
|
|
||||||
|
== Networking ==
|
||||||
|
|
||||||
|
At this time you need a working IPv6 connection to use Open Media Libary.
|
||||||
|
If you dont have native IPv6 you can use Teredo/Miredo (apt-get install miredo)
|
||||||
|
or get a tunnel Hurricane Electric (https://tunnelbroker.net/)
|
||||||
|
or SixSS (https://sixxs.net).
|
||||||
|
|
||||||
|
== Platform ==
|
||||||
|
|
||||||
|
If you install Open Media Library on a architecture thats not directly supported,
|
||||||
|
you need a working python 2.7.x installation and the following packages:
|
||||||
|
|
||||||
|
apt-get install \
|
||||||
|
python-pypdf python-stdnum python-html5lib python-chardet python-openssl \
|
||||||
|
python-simplejson python-lxml
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
== Development ==
|
== Development ==
|
||||||
|
|
||||||
mkdir client
|
mkdir client
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
"columnRequired": true,
|
"columnRequired": true,
|
||||||
"columnWidth": 192,
|
"columnWidth": 192,
|
||||||
"filter": true,
|
"filter": true,
|
||||||
|
"find": true,
|
||||||
"sort": true,
|
"sort": true,
|
||||||
"sortType": "person"
|
"sortType": "person"
|
||||||
},
|
},
|
||||||
|
|
3
ctl
3
ctl
|
@ -25,6 +25,9 @@ export PATH
|
||||||
PYTHONPATH="$PLATFORM_ENV/lib/python2.7/site-packages:$SHARED_ENV/lib/python2.7/site-packages:$BASE/$NAME"
|
PYTHONPATH="$PLATFORM_ENV/lib/python2.7/site-packages:$SHARED_ENV/lib/python2.7/site-packages:$BASE/$NAME"
|
||||||
export PYTHONPATH
|
export PYTHONPATH
|
||||||
|
|
||||||
|
oxCACHE="$BASE/config/ox"
|
||||||
|
export oxCACHE
|
||||||
|
|
||||||
#must be called to update commands in $PATH
|
#must be called to update commands in $PATH
|
||||||
hash -r 2>/dev/null
|
hash -r 2>/dev/null
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,8 @@ from changelog import Changelog
|
||||||
import re
|
import re
|
||||||
import state
|
import state
|
||||||
|
|
||||||
|
import meta
|
||||||
|
|
||||||
import utils
|
import utils
|
||||||
|
|
||||||
@returns_json
|
@returns_json
|
||||||
|
@ -108,7 +110,7 @@ actions.register(edit, cache=False)
|
||||||
|
|
||||||
|
|
||||||
@returns_json
|
@returns_json
|
||||||
def identify(request):
|
def findMetadata(request):
|
||||||
'''
|
'''
|
||||||
takes {
|
takes {
|
||||||
title: string,
|
title: string,
|
||||||
|
@ -124,26 +126,22 @@ def identify(request):
|
||||||
'''
|
'''
|
||||||
response = {}
|
response = {}
|
||||||
data = json.loads(request.form['data']) if 'data' in request.form else {}
|
data = json.loads(request.form['data']) if 'data' in request.form else {}
|
||||||
response = {
|
print 'findMetadata', data
|
||||||
'items': [
|
response['items'] = meta.find(**data)
|
||||||
{
|
|
||||||
u'title': u'Cinema',
|
|
||||||
u'author': [u'Gilles Deleuze'],
|
|
||||||
u'date': u'1986-10',
|
|
||||||
u'publisher': u'University of Minnesota Press',
|
|
||||||
u'isbn10': u'0816613990',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
u'title': u'How to Change the World: Reflections on Marx and Marxism',
|
|
||||||
u'author': [u'Eric Hobsbawm'],
|
|
||||||
u'date': u'2011-09-06',
|
|
||||||
u'publisher': u'Yale University Press',
|
|
||||||
u'isbn13': u'9780300176162',
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
return response
|
return response
|
||||||
actions.register(identify)
|
actions.register(findMetadata)
|
||||||
|
|
||||||
|
@returns_json
|
||||||
|
def getMetadata(request):
|
||||||
|
data = json.loads(request.form['data']) if 'data' in request.form else {}
|
||||||
|
print 'getMetadata', data
|
||||||
|
key, value = data.iteritems().next()
|
||||||
|
if key in ('isbn10', 'isbn13'):
|
||||||
|
value = utils.normalize_isbn(value)
|
||||||
|
response = meta.lookup(key, value)
|
||||||
|
response['mainid'] = key
|
||||||
|
return response
|
||||||
|
actions.register(getMetadata)
|
||||||
|
|
||||||
@returns_json
|
@returns_json
|
||||||
def download(request):
|
def download(request):
|
||||||
|
|
|
@ -16,8 +16,11 @@ providers = [
|
||||||
('abebooks', 'isbn10')
|
('abebooks', 'isbn10')
|
||||||
]
|
]
|
||||||
|
|
||||||
def find(title, author=None, publisher=None, year=None):
|
def find(title, author=None, publisher=None, date=None):
|
||||||
return []
|
results = openlibrary.find(title=title, author=author, publisher=publisher, date=date)
|
||||||
|
for r in results:
|
||||||
|
r['mainid'] = 'olid'
|
||||||
|
return results
|
||||||
|
|
||||||
def lookup(key, value):
|
def lookup(key, value):
|
||||||
data = {key: value}
|
data = {key: value}
|
||||||
|
@ -32,16 +35,16 @@ def lookup(key, value):
|
||||||
if not kv in ids:
|
if not kv in ids:
|
||||||
ids.append(kv)
|
ids.append(kv)
|
||||||
done = False
|
done = False
|
||||||
print ids
|
print 'lookup %s=%s =>' % ids[0], ids
|
||||||
for k, v in ids:
|
for k, v in ids:
|
||||||
for provider, id in providers:
|
for provider, id in providers:
|
||||||
if id == k:
|
if id == k and provider not in provider_data:
|
||||||
provider_data[provider] = globals()[provider].lookup(v)
|
provider_data[provider] = globals()[provider].lookup(v)
|
||||||
for provider in sorted(
|
for provider in sorted(
|
||||||
provider_data.keys(),
|
provider_data.keys(),
|
||||||
key=lambda x: -len(provider_data[x])
|
key=lambda x: -len(provider_data[x])
|
||||||
):
|
):
|
||||||
print provider, len(provider_data[provider])
|
print provider, len(provider_data[provider]), provider_data[provider].keys()
|
||||||
for k_, v_ in provider_data[provider].iteritems():
|
for k_, v_ in provider_data[provider].iteritems():
|
||||||
if not k_ in data:
|
if not k_ in data:
|
||||||
data[k_] = v_
|
data[k_] = v_
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from ox.cache import read_url
|
from ox.cache import read_url
|
||||||
from ox import find_re, strip_tags
|
from ox import find_re, strip_tags, decode_html
|
||||||
import re
|
import re
|
||||||
|
import stdnum.isbn
|
||||||
|
|
||||||
base = 'http://www.lookupbyisbn.com'
|
base = 'http://www.lookupbyisbn.com'
|
||||||
|
|
||||||
|
@ -13,6 +14,9 @@ def get_ids(key, value):
|
||||||
if m:
|
if m:
|
||||||
asin = m[0].split('/')[-3]
|
asin = m[0].split('/')[-3]
|
||||||
ids.append(('asin', asin))
|
ids.append(('asin', asin))
|
||||||
|
if key == 'asin':
|
||||||
|
if stdnum.isbn.is_valid(value):
|
||||||
|
ids.append(('isbn10', value))
|
||||||
if ids:
|
if ids:
|
||||||
print 'lookupbyisbn.get_ids', key, value
|
print 'lookupbyisbn.get_ids', key, value
|
||||||
print ids
|
print ids
|
||||||
|
@ -43,10 +47,13 @@ def lookup(id):
|
||||||
r[key] = int(r[key])
|
r[key] = int(r[key])
|
||||||
desc = find_re(data, '<h2>Description:<\/h2>(.*?)<div ')
|
desc = find_re(data, '<h2>Description:<\/h2>(.*?)<div ')
|
||||||
desc = desc.replace('<br /><br />', ' ').replace('<br /> ', ' ').replace('<br />', ' ')
|
desc = desc.replace('<br /><br />', ' ').replace('<br /> ', ' ').replace('<br />', ' ')
|
||||||
r['description'] = strip_tags(desc).strip()
|
r['description'] = desc
|
||||||
if r['description'] == u'Description of this item is not available at this time.':
|
if r['description'] == u'Description of this item is not available at this time.':
|
||||||
r['description'] = ''
|
r['description'] = ''
|
||||||
r['cover'] = find_re(data, '<img src="(.*?)" alt="Book cover').replace('._SL160_', '')
|
r['cover'] = find_re(data, '<img src="(.*?)" alt="Book cover').replace('._SL160_', '')
|
||||||
|
for key in r:
|
||||||
|
if isinstance(r[key], basestring):
|
||||||
|
r[key] = decode_html(strip_tags(r[key])).strip()
|
||||||
if 'author' in r and isinstance(r['author'], basestring):
|
if 'author' in r and isinstance(r['author'], basestring):
|
||||||
r['author'] = [r['author']]
|
r['author'] = [r['author']]
|
||||||
return r
|
return r
|
||||||
|
|
|
@ -2,12 +2,60 @@
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
# vi:si:et:sw=4:sts=4:ts=4
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
|
|
||||||
|
from urllib import urlencode
|
||||||
from ox.cache import read_url
|
from ox.cache import read_url
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from marc_countries import COUNTRIES
|
from marc_countries import COUNTRIES
|
||||||
from utils import normalize_isbn
|
from utils import normalize_isbn
|
||||||
|
|
||||||
|
KEYS = {
|
||||||
|
'authors': 'author',
|
||||||
|
'covers': 'cover',
|
||||||
|
'dewey_decimal_class': 'classification',
|
||||||
|
'isbn_10': 'isbn10',
|
||||||
|
'isbn_13': 'isbn13',
|
||||||
|
'languages': 'language',
|
||||||
|
'lccn': 'lccn',
|
||||||
|
'number_of_pages': 'pages',
|
||||||
|
'oclc_numbers': 'oclc',
|
||||||
|
'publish_country': 'country',
|
||||||
|
'publish_date': 'date',
|
||||||
|
'publishers': 'publisher',
|
||||||
|
'publish_places': 'place',
|
||||||
|
'series': 'series',
|
||||||
|
'title': 'title',
|
||||||
|
}
|
||||||
|
|
||||||
|
def find(*args, **kargs):
|
||||||
|
args = [a.replace(':', ' ') for a in args]
|
||||||
|
for k in ('date', 'publisher'):
|
||||||
|
if k in kargs:
|
||||||
|
print 'ignoring %s on openlibrary' % k, kargs[k]
|
||||||
|
del kargs[k]
|
||||||
|
for k, v in kargs.iteritems():
|
||||||
|
key = KEYS.keys()[KEYS.values().index(k)]
|
||||||
|
if v:
|
||||||
|
if not isinstance(v, list):
|
||||||
|
v = [v]
|
||||||
|
#v = ['%s:"%s"' % (key, value.replace(':', '\:')) for value in v]
|
||||||
|
v = ['"%s"' % value.replace(':', ' ') for value in v]
|
||||||
|
args += v
|
||||||
|
query = ' '.join(args)
|
||||||
|
query = query.strip()
|
||||||
|
print 'openlibrary.find', query
|
||||||
|
r = api.search(query)
|
||||||
|
results = []
|
||||||
|
ids = [b for b in r.get('result', []) if b.startswith('/books')]
|
||||||
|
books = api.get_many(ids).get('result', [])
|
||||||
|
for olid, value in books.iteritems():
|
||||||
|
olid = olid.split('/')[-1]
|
||||||
|
book = format(value)
|
||||||
|
book['olid'] = olid
|
||||||
|
results.append(book)
|
||||||
|
return results
|
||||||
|
|
||||||
|
|
||||||
def get_ids(key, value):
|
def get_ids(key, value):
|
||||||
ids = []
|
ids = []
|
||||||
if key == 'olid':
|
if key == 'olid':
|
||||||
|
@ -17,15 +65,13 @@ def get_ids(key, value):
|
||||||
for v in data[id]:
|
for v in data[id]:
|
||||||
if (id, v) not in ids:
|
if (id, v) not in ids:
|
||||||
ids.append((id, v))
|
ids.append((id, v))
|
||||||
elif key in ('isbn10', 'isbn13'):
|
elif key in ('isbn10', 'isbn13', 'oclc', 'lccn'):
|
||||||
print 'openlibraryid.get_ids', key, value
|
print 'openlibraryid.get_ids', key, value
|
||||||
r = find('isbn:%s' % value)
|
r = api.things({'type': '/type/edition', key.replace('isbn', 'isbn_'): value})
|
||||||
for d in sorted(r.get('docs', []), key=lambda d: -d['last_modified_i']):
|
for b in r.get('result', []):
|
||||||
if 'edition_key' in d:
|
if b.startswith('/books'):
|
||||||
v = d['edition_key']
|
olid = b.split('/')[-1]
|
||||||
if isinstance(v, list):
|
for kv in [('olid', olid)] + get_ids('olid', olid):
|
||||||
v = v[0]
|
|
||||||
for kv in [('olid', v)] + get_ids('olid', v):
|
|
||||||
if kv not in ids:
|
if kv not in ids:
|
||||||
ids.append(kv)
|
ids.append(kv)
|
||||||
if ids:
|
if ids:
|
||||||
|
@ -35,38 +81,29 @@ def get_ids(key, value):
|
||||||
|
|
||||||
def lookup(id, return_all=False):
|
def lookup(id, return_all=False):
|
||||||
#print 'openlibrary.lookup', id
|
#print 'openlibrary.lookup', id
|
||||||
data = {
|
info = api.get('/books/' + id).get('result', {})
|
||||||
'olid': id
|
#url = 'https://openlibrary.org/books/%s.json' % id
|
||||||
}
|
#info = json.loads(read_url(url))
|
||||||
url = 'https://openlibrary.org/books/%s.json' % id
|
data = format(info, return_all)
|
||||||
info = json.loads(read_url(url))
|
data['olid'] = id
|
||||||
keys = {
|
print 'openlibrary.lookup', id, data.keys()
|
||||||
'title': 'title',
|
return data
|
||||||
'authors': 'author',
|
|
||||||
'publishers': 'publisher',
|
def format(info, return_all=False):
|
||||||
'languages': 'language',
|
data = {}
|
||||||
'publish_places': 'place',
|
for key in KEYS:
|
||||||
'publish_country': 'country',
|
|
||||||
'covers': 'cover',
|
|
||||||
'isbn_10': 'isbn10',
|
|
||||||
'isbn_13': 'isbn13',
|
|
||||||
'lccn': 'lccn',
|
|
||||||
'oclc_numbers': 'oclc',
|
|
||||||
'dewey_decimal_class': 'classification',
|
|
||||||
'number_of_pages': 'pages',
|
|
||||||
}
|
|
||||||
for key in keys:
|
|
||||||
if key in info:
|
if key in info:
|
||||||
value = info[key]
|
value = info[key]
|
||||||
if key == 'authors':
|
if key == 'authors':
|
||||||
value = authors(value)
|
value = resolve_names(value)
|
||||||
elif key == 'publish_country':
|
elif key == 'publish_country':
|
||||||
|
value = value.strip()
|
||||||
value = COUNTRIES.get(value, value)
|
value = COUNTRIES.get(value, value)
|
||||||
elif key == 'covers':
|
elif key == 'covers':
|
||||||
value = 'https://covers.openlibrary.org/b/id/%s.jpg' % value[0]
|
value = 'https://covers.openlibrary.org/b/id/%s.jpg' % value[0]
|
||||||
value = COUNTRIES.get(value, value)
|
value = COUNTRIES.get(value, value)
|
||||||
elif key == 'languages':
|
elif key == 'languages':
|
||||||
value = languages(value)
|
value = resolve_names(value)
|
||||||
elif not return_all and isinstance(value, list) and key not in ('publish_places'):
|
elif not return_all and isinstance(value, list) and key not in ('publish_places'):
|
||||||
value = value[0]
|
value = value[0]
|
||||||
if key in ('isbn_10', 'isbn_13'):
|
if key in ('isbn_10', 'isbn_13'):
|
||||||
|
@ -74,27 +111,52 @@ def lookup(id, return_all=False):
|
||||||
value = map(normalize_isbn, value)
|
value = map(normalize_isbn, value)
|
||||||
else:
|
else:
|
||||||
value = normalize_isbn(value)
|
value = normalize_isbn(value)
|
||||||
data[keys[key]] = value
|
data[KEYS[key]] = value
|
||||||
return data
|
return data
|
||||||
|
|
||||||
info = lookup
|
|
||||||
|
|
||||||
def find(query):
|
|
||||||
url = 'https://openlibrary.org/search.json?q=%s' % query
|
|
||||||
data = json.loads(read_url(url))
|
|
||||||
return data
|
|
||||||
|
|
||||||
def authors(authors):
|
|
||||||
return resolve_names(authors)
|
|
||||||
|
|
||||||
def resolve_names(objects, key='name'):
|
def resolve_names(objects, key='name'):
|
||||||
r = []
|
r = []
|
||||||
for o in objects:
|
data = api.get_many([k['key'] for k in objects]).get('result', {})
|
||||||
url = 'https://openlibrary.org%s.json' % o['key']
|
for k, value in data.iteritems():
|
||||||
data = json.loads(read_url(url))
|
if 'location' in value and value.get('type', {}).get('key') == '/type/redirect':
|
||||||
r.append(data[key])
|
value = api.get(value['location']).get('result', {})
|
||||||
|
r.append(value[key])
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def languages(languages):
|
class API(object):
|
||||||
return resolve_names(languages)
|
base = 'https://openlibrary.org/api'
|
||||||
|
|
||||||
|
def _request(self, action, data):
|
||||||
|
for key in data:
|
||||||
|
if not isinstance(data[key], basestring):
|
||||||
|
data[key] = json.dumps(data[key])
|
||||||
|
url = self.base + '/' + action + '?' + urlencode(data)
|
||||||
|
result = json.loads(read_url(url))
|
||||||
|
if 'status' in result and result['status'] == 'error' or 'error' in result:
|
||||||
|
print 'FAILED', action, data
|
||||||
|
print 'URL', url
|
||||||
|
return result
|
||||||
|
|
||||||
|
def get(self, key):
|
||||||
|
data = self._request('get', {'key': key})
|
||||||
|
return data
|
||||||
|
|
||||||
|
def get_many(self, keys):
|
||||||
|
data = self._request('get_many', {'keys': keys})
|
||||||
|
return data
|
||||||
|
|
||||||
|
def search(self, query):
|
||||||
|
if isinstance(query, basestring):
|
||||||
|
query = {
|
||||||
|
'query': query
|
||||||
|
}
|
||||||
|
data = self._request('search', {'q': query})
|
||||||
|
if 'status' in data and data['status'] == 'error':
|
||||||
|
print 'FAILED', query
|
||||||
|
return data
|
||||||
|
|
||||||
|
def things(self, query):
|
||||||
|
data = self._request('things', {'query': query})
|
||||||
|
return data
|
||||||
|
|
||||||
|
api = API()
|
||||||
|
|
7
requirements-shared.txt
Normal file
7
requirements-shared.txt
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
tornado==3.1.1
|
||||||
|
requests==2.2.1
|
||||||
|
chardet
|
||||||
|
html5lib
|
||||||
|
ox
|
||||||
|
python-stdnum==0.9
|
||||||
|
pyPdf==1.13
|
9
requirements.txt
Normal file
9
requirements.txt
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
Twisted
|
||||||
|
simplejson
|
||||||
|
ed25519
|
||||||
|
Flask==0.10.1
|
||||||
|
SQLAlchemy==0.9.4
|
||||||
|
Flask-SQLAlchemy==1.0
|
||||||
|
Flask-Script==2.0.3
|
||||||
|
Flask-Migrate==1.2.0
|
||||||
|
pyopenssl>=0.13.1
|
|
@ -9,108 +9,130 @@ oml.ui.identifyDialog = function(data) {
|
||||||
].map(function(id) {
|
].map(function(id) {
|
||||||
return {
|
return {
|
||||||
id: id,
|
id: id,
|
||||||
title: Ox._(Ox.getObjectById(oml.config.itemKeys, id).title)
|
title: Ox.getObjectById(oml.config.itemKeys, id).title
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
|
|
||||||
keys = [
|
keys = [
|
||||||
'title', 'author', 'publisher', 'date'
|
'title', 'author', 'publisher', 'date'
|
||||||
].map(function(id) {
|
].map(function(id) {
|
||||||
|
var key = Ox.getObjectById(oml.config.sortKeys, id);
|
||||||
return {
|
return {
|
||||||
|
format: key.format,
|
||||||
id: id,
|
id: id,
|
||||||
title: Ox._(Ox.getObjectById(oml.config.itemKeys, id).title)
|
operator: key.operator,
|
||||||
|
width: {
|
||||||
|
title: 288,
|
||||||
|
author: 224,
|
||||||
|
publisher: 160,
|
||||||
|
date: 96 - Ox.UI.SCROLLBAR_SIZE
|
||||||
|
}[id],
|
||||||
|
title: key.title,
|
||||||
|
visible: true
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
|
|
||||||
$input = Ox.FormElementGroup({
|
originalData = Ox.clone(data, true),
|
||||||
elements: [
|
|
||||||
Ox.Select({
|
|
||||||
items: ids,
|
|
||||||
overlap: 'right',
|
|
||||||
value: 'isbn10',
|
|
||||||
width: 128
|
|
||||||
}),
|
|
||||||
Ox.Input({
|
|
||||||
value: data['isbn10'] || '',
|
|
||||||
width: 610
|
|
||||||
})
|
|
||||||
]
|
|
||||||
})
|
|
||||||
.css({margin: '16px'}),
|
|
||||||
|
|
||||||
$preview = Ox.Element(),
|
$idForm = renderIdForm(data),
|
||||||
|
|
||||||
|
$preview = data.mainid
|
||||||
|
? oml.ui.infoView(data)
|
||||||
|
: Ox.Element(),
|
||||||
|
|
||||||
$idPanel = Ox.SplitPanel({
|
$idPanel = Ox.SplitPanel({
|
||||||
elements: [
|
elements: [
|
||||||
{element: Ox.Element().append($input), size: 48},
|
{element: Ox.Element().append($idForm), size: 96},
|
||||||
{element: $preview}
|
{element: $preview}
|
||||||
],
|
],
|
||||||
orientation: 'vertical'
|
orientation: 'vertical'
|
||||||
}),
|
}),
|
||||||
|
|
||||||
$form = Ox.Form({
|
$titleForm = Ox.Element(),
|
||||||
items: keys.map(function(key) {
|
|
||||||
return Ox.Input({
|
|
||||||
id: key.id,
|
|
||||||
labelWidth: 128,
|
|
||||||
label: key.title,
|
|
||||||
value: key == 'author'
|
|
||||||
? (data[key.id] || []).join(', ')
|
|
||||||
: data[key.id],
|
|
||||||
width: 736
|
|
||||||
});
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.css({padding: '16px'})
|
|
||||||
.bindEvent({
|
|
||||||
change: function(data) {
|
|
||||||
Ox.print('FORM CHANGE', data);
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
|
|
||||||
$list = Ox.TableList({
|
$inputs = keys.map(function(key, index) {
|
||||||
columns: [
|
return Ox.Input({
|
||||||
{
|
label: Ox._(key.title),
|
||||||
id: 'index'
|
labelWidth: 64,
|
||||||
},
|
value: data[key.id],
|
||||||
{
|
width: 360
|
||||||
id: 'title',
|
})
|
||||||
visible: true,
|
.css({
|
||||||
width: 288,
|
position: 'absolute',
|
||||||
},
|
left: index < 2 ? '16px' : '392px',
|
||||||
{
|
top: index % 2 == 0 ? '16px' : '40px'
|
||||||
id: 'author',
|
})
|
||||||
visible: true,
|
.bindEvent({
|
||||||
width: 224
|
submit: function(data) {
|
||||||
},
|
$findButton.triggerEvent('click');
|
||||||
{
|
|
||||||
id: 'publisher',
|
|
||||||
visible: true,
|
|
||||||
width: 160
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'date',
|
|
||||||
visible: true,
|
|
||||||
width: 96
|
|
||||||
}
|
}
|
||||||
],
|
})
|
||||||
items: [],
|
.appendTo($titleForm);
|
||||||
max: 1,
|
}),
|
||||||
sort: [{key: 'index', operator: '+'}],
|
|
||||||
unique: 'index'
|
$clearButton = Ox.Button({
|
||||||
|
title: Ox._('Clear'),
|
||||||
|
width: 64
|
||||||
|
})
|
||||||
|
.css({
|
||||||
|
position: 'absolute',
|
||||||
|
right: '160px',
|
||||||
|
top: '64px'
|
||||||
})
|
})
|
||||||
.bindEvent({
|
.bindEvent({
|
||||||
select: function(data) {
|
click: function() {
|
||||||
$that.options('buttons')[1].options({
|
keys.forEach(function(key) {
|
||||||
disabled: data.ids.length == 0
|
inputValue(key.id, '');
|
||||||
});
|
});
|
||||||
|
updateButtons();
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
|
.appendTo($titleForm),
|
||||||
|
|
||||||
|
$resetButton = Ox.Button({
|
||||||
|
disabled: true,
|
||||||
|
title: Ox._('Reset'),
|
||||||
|
width: 64
|
||||||
|
})
|
||||||
|
.css({
|
||||||
|
position: 'absolute',
|
||||||
|
right: '88px',
|
||||||
|
top: '64px'
|
||||||
|
})
|
||||||
|
.bindEvent({
|
||||||
|
click: function() {
|
||||||
|
keys.forEach(function(key) {
|
||||||
|
inputValue(key.id, originalData[key.id]);
|
||||||
|
});
|
||||||
|
updateButtons();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.appendTo($titleForm),
|
||||||
|
|
||||||
|
$findButton = Ox.Button({
|
||||||
|
title: Ox._('Find'),
|
||||||
|
width: 64
|
||||||
|
})
|
||||||
|
.css({
|
||||||
|
position: 'absolute',
|
||||||
|
right: '16px',
|
||||||
|
top: '64px'
|
||||||
|
})
|
||||||
|
.bindEvent({
|
||||||
|
click: function() {
|
||||||
|
var data = {};
|
||||||
|
keys.forEach(function(key) {
|
||||||
|
data[key.id] = inputValue(key.id);
|
||||||
|
});
|
||||||
|
findMetadata(data);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.appendTo($titleForm),
|
||||||
|
|
||||||
$titlePanel = Ox.SplitPanel({
|
$titlePanel = Ox.SplitPanel({
|
||||||
elements: [
|
elements: [
|
||||||
{element: Ox.Element().append($form), size: 120},
|
{element: $titleForm, size: 96},
|
||||||
{element: $list}
|
{element: renderResults([Ox.extend({index: '0'}, data)])}
|
||||||
],
|
],
|
||||||
orientation: 'vertical'
|
orientation: 'vertical'
|
||||||
}),
|
}),
|
||||||
|
@ -186,6 +208,233 @@ oml.ui.identifyDialog = function(data) {
|
||||||
width: 768
|
width: 768
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function findMetadata(data) {
|
||||||
|
$titlePanel.replaceElement(1, Ox.LoadingScreen().start());
|
||||||
|
oml.api.findMetadata(data, function(result) {
|
||||||
|
Ox.print('GOT RESULTS', result.data);
|
||||||
|
var items = result.data.items.map(function(item, index) {
|
||||||
|
return Ox.extend({index: index.toString()}, item);
|
||||||
|
}).concat([
|
||||||
|
Ox.extend({index: result.data.items.length.toString()}, data)
|
||||||
|
]);
|
||||||
|
$titlePanel.replaceElement(1, renderResults(items));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMetadata(key, value) {
|
||||||
|
$idPanel.replaceElement(1, Ox.LoadingScreen().start());
|
||||||
|
oml.api.getMetadata(Ox.extend({}, key, value), function(result) {
|
||||||
|
Ox.print('GOT RESULT', result.data);
|
||||||
|
$idForm = renderIdForm(result.data);
|
||||||
|
$preview = oml.ui.infoView(result.data);
|
||||||
|
$idPanel
|
||||||
|
.replaceElement(0, $idForm)
|
||||||
|
.replaceElement(1, $preview);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function inputValue(key, value) {
|
||||||
|
// FIXME: UNELEGANT
|
||||||
|
Ox.print('INPUTVALUE', key, value)
|
||||||
|
var $input = $inputs[[
|
||||||
|
'title', 'author', 'publisher', 'date'
|
||||||
|
].indexOf(key)];
|
||||||
|
if (Ox.isUndefined(value)) {
|
||||||
|
value = $input.value();
|
||||||
|
if (key == 'author') {
|
||||||
|
value = value ? value.split(', ') : [];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$input.value(
|
||||||
|
key == 'author' ? (value || []).join(', ') : value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isEmpty(data) {
|
||||||
|
return Ox.every(data, Ox.isEmpty);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isOriginal(data) {
|
||||||
|
return Ox.every(data, function(value, key) {
|
||||||
|
return value == originalData[key];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderIdForm(data) {
|
||||||
|
var $element = Ox.Element(),
|
||||||
|
$elements = ids.map(function(id, index) {
|
||||||
|
return Ox.FormElementGroup({
|
||||||
|
elements: [
|
||||||
|
Ox.Checkbox({
|
||||||
|
overlap: 'right',
|
||||||
|
title: Ox._(id.title),
|
||||||
|
value: id.id == data.mainid,
|
||||||
|
width: 80
|
||||||
|
})
|
||||||
|
.bindEvent({
|
||||||
|
change: function(data) {
|
||||||
|
var value = $elements[index].options('elements')[1].value()
|
||||||
|
if (data.value) {
|
||||||
|
if (value) {
|
||||||
|
$elements.forEach(function($element, i) {
|
||||||
|
if (i != index) {
|
||||||
|
$elements[i].options('elements')[0].value(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
getMetadata(id.id, value, function() {
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.value(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.value(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
Ox.Input({
|
||||||
|
value: data[id.id] || '',
|
||||||
|
width: 160
|
||||||
|
})
|
||||||
|
.bindEvent({
|
||||||
|
submit: function(data) {
|
||||||
|
if (data.value) {
|
||||||
|
$elements.forEach(function($element, i) {
|
||||||
|
$element.options('elements')[0].options({
|
||||||
|
disabled: true,
|
||||||
|
value: i == index
|
||||||
|
});
|
||||||
|
$element.options('elements')[1].options({
|
||||||
|
disabled: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
getMetadata(id.id, data.value, function() {
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
],
|
||||||
|
float: 'left'
|
||||||
|
})
|
||||||
|
.css({
|
||||||
|
position: 'absolute',
|
||||||
|
left: 16 + Math.floor(index / 2) * 248 + 'px',
|
||||||
|
top: 16 + (index % 2) * 24 + 'px'
|
||||||
|
})
|
||||||
|
.appendTo($element);
|
||||||
|
}),
|
||||||
|
$resetButton = Ox.Button({
|
||||||
|
disabled: true,
|
||||||
|
title: Ox._('Reset'),
|
||||||
|
width: 64
|
||||||
|
})
|
||||||
|
.css({
|
||||||
|
position: 'absolute',
|
||||||
|
right: '16px',
|
||||||
|
top: '64px'
|
||||||
|
})
|
||||||
|
.bindEvent({
|
||||||
|
click: function() {
|
||||||
|
/*
|
||||||
|
keys.forEach(function(key) {
|
||||||
|
inputValue(key.id, originalData[key.id]);
|
||||||
|
});
|
||||||
|
updateButtons();
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.appendTo($element);
|
||||||
|
return $element;
|
||||||
|
Ox.print('???', data.mainid)
|
||||||
|
return Ox.Form({
|
||||||
|
items: Ox.flatten(ids.map(function(id) {
|
||||||
|
return [
|
||||||
|
Ox.Checkbox({
|
||||||
|
disabled: !data[id.id] || id.id == data.mainid,
|
||||||
|
id: id.id + 'Checkbox',
|
||||||
|
title: Ox._(id.title),
|
||||||
|
value: id.id == data.mainid,
|
||||||
|
width: 128
|
||||||
|
})
|
||||||
|
.bindEvent({
|
||||||
|
change: function() {
|
||||||
|
getMetadata(id.id, data[id.id]);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
Ox.Input({
|
||||||
|
id: id.id + 'Input',
|
||||||
|
value: data[id.id] || '',
|
||||||
|
width: 128
|
||||||
|
})
|
||||||
|
.css({marginBottom: '16px'})
|
||||||
|
.bindEvent({
|
||||||
|
change: function(data) {
|
||||||
|
if (data.value) {
|
||||||
|
getMetadata(id.id, data.value, function() {
|
||||||
|
//...
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Ox.print('this', this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
];
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
.css({margin: '16px'});
|
||||||
|
return $form;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderResults(items) {
|
||||||
|
Ox.print('LIST ITEMS::::', items);
|
||||||
|
var $list = Ox.TableList({
|
||||||
|
columns: Ox.clone(keys, true),
|
||||||
|
items: items,
|
||||||
|
min: 1,
|
||||||
|
max: 1,
|
||||||
|
scrollbarVisible: true,
|
||||||
|
selected: ['0'],
|
||||||
|
sort: [{key: 'index', operator: '+'}],
|
||||||
|
unique: 'index'
|
||||||
|
})
|
||||||
|
.bindEvent({
|
||||||
|
select: function(data) {
|
||||||
|
var index = data.ids[0];
|
||||||
|
data = Ox.getObject(items, 'index', index);
|
||||||
|
$results.replaceElement(1, Ox.LoadingScreen().start());
|
||||||
|
Ox.print('OLID', data.olid);
|
||||||
|
oml.api.getMetadata({olid: data.olid}, function(result) {
|
||||||
|
Ox.print('#### GOT DATA', result.data);
|
||||||
|
$results.replaceElement(1, oml.ui.infoView(result.data));
|
||||||
|
that.options('buttons')[1].options({disabled: false});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
$results = Ox.SplitPanel({
|
||||||
|
elements: [
|
||||||
|
{element: $list, size: 80},
|
||||||
|
{element: oml.ui.infoView(items[0])}
|
||||||
|
],
|
||||||
|
orientation: 'vertical'
|
||||||
|
});
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateButtons() {
|
||||||
|
var data = {}, empty, original;
|
||||||
|
keys.forEach(function(key) {
|
||||||
|
data[key.id] = inputValue(key.id);
|
||||||
|
});
|
||||||
|
empty = isEmpty(data);
|
||||||
|
original = isOriginal(data);
|
||||||
|
$clearButton.options({disabled: empty});
|
||||||
|
$resetButton.options({disabled: original});
|
||||||
|
$findButton.options({disabled: empty});
|
||||||
|
}
|
||||||
|
|
||||||
return that;
|
return that;
|
||||||
|
|
||||||
};
|
};
|
|
@ -1,6 +1,6 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
oml.ui.infoView = function() {
|
oml.ui.infoView = function(identifyData) {
|
||||||
|
|
||||||
var ui = oml.user.ui,
|
var ui = oml.user.ui,
|
||||||
|
|
||||||
|
@ -34,11 +34,14 @@ oml.ui.infoView = function() {
|
||||||
.css({
|
.css({
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
left: '288px',
|
left: '288px',
|
||||||
right: '176px',
|
right: !identifyData ? '176px' : 16 + Ox.UI.SCROLLBAR_SIZE + 'px',
|
||||||
top: '16px'
|
top: '16px'
|
||||||
})
|
})
|
||||||
.appendTo(that),
|
.appendTo(that),
|
||||||
|
|
||||||
|
$data;
|
||||||
|
|
||||||
|
if (!identifyData) {
|
||||||
$data = Ox.Element()
|
$data = Ox.Element()
|
||||||
.addClass('OxSelectable')
|
.addClass('OxSelectable')
|
||||||
.css({
|
.css({
|
||||||
|
@ -48,6 +51,7 @@ oml.ui.infoView = function() {
|
||||||
width: '128px'
|
width: '128px'
|
||||||
})
|
})
|
||||||
.appendTo(that);
|
.appendTo(that);
|
||||||
|
}
|
||||||
|
|
||||||
function formatLight(str) {
|
function formatLight(str) {
|
||||||
return '<span class="OxLight">' + str + '</span>';
|
return '<span class="OxLight">' + str + '</span>';
|
||||||
|
@ -218,7 +222,9 @@ oml.ui.infoView = function() {
|
||||||
width = Math.round(ratio >= 1 ? size : size * ratio),
|
width = Math.round(ratio >= 1 ? size : size * ratio),
|
||||||
height = Math.round(ratio <= 1 ? size : size / ratio),
|
height = Math.round(ratio <= 1 ? size : size / ratio),
|
||||||
left = Math.floor((size - width) / 2),
|
left = Math.floor((size - width) / 2),
|
||||||
src = '/' + data.id + '/cover256.jpg',
|
src = !identifyData
|
||||||
|
? '/' + data.id + '/cover256.jpg'
|
||||||
|
: data.cover,
|
||||||
reflectionSize = Math.round(size / 2);
|
reflectionSize = Math.round(size / 2);
|
||||||
|
|
||||||
$elements.forEach(function($element) {
|
$elements.forEach(function($element) {
|
||||||
|
@ -334,6 +340,7 @@ oml.ui.infoView = function() {
|
||||||
.appendTo($info);
|
.appendTo($info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$('<div>').css({height: '16px'}).appendTo($info);
|
||||||
|
|
||||||
} else if ($element == $data) {
|
} else if ($element == $data) {
|
||||||
|
|
||||||
|
@ -424,7 +431,11 @@ oml.ui.infoView = function() {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ui.item && that.update(ui.item);
|
if (!identifyData) {
|
||||||
|
ui.item && that.update(ui.item);
|
||||||
|
} else {
|
||||||
|
that.update(identifyData, [$cover, $info]);
|
||||||
|
}
|
||||||
|
|
||||||
oml.bindEvent({
|
oml.bindEvent({
|
||||||
transfer: function(data) {
|
transfer: function(data) {
|
||||||
|
|
|
@ -73,8 +73,8 @@
|
||||||
? Ox['format' + Ox.toTitleCase(key.format.type)].apply(
|
? Ox['format' + Ox.toTitleCase(key.format.type)].apply(
|
||||||
this, [value].concat(key.format.args || [])
|
this, [value].concat(key.format.args || [])
|
||||||
)
|
)
|
||||||
: Ox.isArray(key.type) ? value.join(', ')
|
: Ox.isArray(key.type) ? (value || []).join(', ')
|
||||||
: value;
|
: (value || '');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue