diff --git a/README b/README
index c7add47..adacb44 100644
--- a/README
+++ b/README
@@ -4,6 +4,23 @@ Open Media Library
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 ==
mkdir client
diff --git a/config.json b/config.json
index 0ad448e..f218671 100644
--- a/config.json
+++ b/config.json
@@ -26,6 +26,7 @@
"columnRequired": true,
"columnWidth": 192,
"filter": true,
+ "find": true,
"sort": true,
"sortType": "person"
},
diff --git a/ctl b/ctl
index 0560fe7..88571a3 100755
--- a/ctl
+++ b/ctl
@@ -25,6 +25,9 @@ export PATH
PYTHONPATH="$PLATFORM_ENV/lib/python2.7/site-packages:$SHARED_ENV/lib/python2.7/site-packages:$BASE/$NAME"
export PYTHONPATH
+oxCACHE="$BASE/config/ox"
+export oxCACHE
+
#must be called to update commands in $PATH
hash -r 2>/dev/null
diff --git a/oml/item/api.py b/oml/item/api.py
index 7ace6d1..4e73a32 100644
--- a/oml/item/api.py
+++ b/oml/item/api.py
@@ -14,6 +14,8 @@ from changelog import Changelog
import re
import state
+import meta
+
import utils
@returns_json
@@ -108,7 +110,7 @@ actions.register(edit, cache=False)
@returns_json
-def identify(request):
+def findMetadata(request):
'''
takes {
title: string,
@@ -124,26 +126,22 @@ def identify(request):
'''
response = {}
data = json.loads(request.form['data']) if 'data' in request.form else {}
- response = {
- 'items': [
- {
- 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',
- }
- ]
- }
+ print 'findMetadata', data
+ response['items'] = meta.find(**data)
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
def download(request):
diff --git a/oml/meta/__init__.py b/oml/meta/__init__.py
index 7a933a3..3e46318 100644
--- a/oml/meta/__init__.py
+++ b/oml/meta/__init__.py
@@ -16,8 +16,11 @@ providers = [
('abebooks', 'isbn10')
]
-def find(title, author=None, publisher=None, year=None):
- return []
+def find(title, author=None, publisher=None, date=None):
+ results = openlibrary.find(title=title, author=author, publisher=publisher, date=date)
+ for r in results:
+ r['mainid'] = 'olid'
+ return results
def lookup(key, value):
data = {key: value}
@@ -32,16 +35,16 @@ def lookup(key, value):
if not kv in ids:
ids.append(kv)
done = False
- print ids
+ print 'lookup %s=%s =>' % ids[0], ids
for k, v in ids:
for provider, id in providers:
- if id == k:
+ if id == k and provider not in provider_data:
provider_data[provider] = globals()[provider].lookup(v)
for provider in sorted(
provider_data.keys(),
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():
if not k_ in data:
data[k_] = v_
diff --git a/oml/meta/lookupbyisbn.py b/oml/meta/lookupbyisbn.py
index 15da05c..20550b2 100644
--- a/oml/meta/lookupbyisbn.py
+++ b/oml/meta/lookupbyisbn.py
@@ -1,6 +1,7 @@
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 stdnum.isbn
base = 'http://www.lookupbyisbn.com'
@@ -13,6 +14,9 @@ def get_ids(key, value):
if m:
asin = m[0].split('/')[-3]
ids.append(('asin', asin))
+ if key == 'asin':
+ if stdnum.isbn.is_valid(value):
+ ids.append(('isbn10', value))
if ids:
print 'lookupbyisbn.get_ids', key, value
print ids
@@ -43,10 +47,13 @@ def lookup(id):
r[key] = int(r[key])
desc = find_re(data, '
Description:<\/h2>(.*?)
', ' ').replace('
', ' ').replace('
', ' ')
- r['description'] = strip_tags(desc).strip()
+ r['description'] = desc
if r['description'] == u'Description of this item is not available at this time.':
r['description'] = ''
r['cover'] = find_re(data, '=0.13.1
diff --git a/static/js/identifyDialog.js b/static/js/identifyDialog.js
index 7d5d6fe..d6cfaf9 100644
--- a/static/js/identifyDialog.js
+++ b/static/js/identifyDialog.js
@@ -9,108 +9,130 @@ oml.ui.identifyDialog = function(data) {
].map(function(id) {
return {
id: id,
- title: Ox._(Ox.getObjectById(oml.config.itemKeys, id).title)
+ title: Ox.getObjectById(oml.config.itemKeys, id).title
};
}),
keys = [
'title', 'author', 'publisher', 'date'
].map(function(id) {
+ var key = Ox.getObjectById(oml.config.sortKeys, id);
return {
+ format: key.format,
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({
- elements: [
- Ox.Select({
- items: ids,
- overlap: 'right',
- value: 'isbn10',
- width: 128
- }),
- Ox.Input({
- value: data['isbn10'] || '',
- width: 610
- })
- ]
- })
- .css({margin: '16px'}),
+ originalData = Ox.clone(data, true),
- $preview = Ox.Element(),
+ $idForm = renderIdForm(data),
+
+ $preview = data.mainid
+ ? oml.ui.infoView(data)
+ : Ox.Element(),
$idPanel = Ox.SplitPanel({
elements: [
- {element: Ox.Element().append($input), size: 48},
+ {element: Ox.Element().append($idForm), size: 96},
{element: $preview}
],
orientation: 'vertical'
}),
- $form = Ox.Form({
- 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);
- }
- }),
+ $titleForm = Ox.Element(),
- $list = Ox.TableList({
- columns: [
- {
- id: 'index'
- },
- {
- id: 'title',
- visible: true,
- width: 288,
- },
- {
- id: 'author',
- visible: true,
- width: 224
- },
- {
- id: 'publisher',
- visible: true,
- width: 160
- },
- {
- id: 'date',
- visible: true,
- width: 96
+ $inputs = keys.map(function(key, index) {
+ return Ox.Input({
+ label: Ox._(key.title),
+ labelWidth: 64,
+ value: data[key.id],
+ width: 360
+ })
+ .css({
+ position: 'absolute',
+ left: index < 2 ? '16px' : '392px',
+ top: index % 2 == 0 ? '16px' : '40px'
+ })
+ .bindEvent({
+ submit: function(data) {
+ $findButton.triggerEvent('click');
}
- ],
- items: [],
- max: 1,
- sort: [{key: 'index', operator: '+'}],
- unique: 'index'
+ })
+ .appendTo($titleForm);
+ }),
+
+ $clearButton = Ox.Button({
+ title: Ox._('Clear'),
+ width: 64
+ })
+ .css({
+ position: 'absolute',
+ right: '160px',
+ top: '64px'
})
.bindEvent({
- select: function(data) {
- $that.options('buttons')[1].options({
- disabled: data.ids.length == 0
+ click: function() {
+ keys.forEach(function(key) {
+ 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({
elements: [
- {element: Ox.Element().append($form), size: 120},
- {element: $list}
+ {element: $titleForm, size: 96},
+ {element: renderResults([Ox.extend({index: '0'}, data)])}
],
orientation: 'vertical'
}),
@@ -186,6 +208,233 @@ oml.ui.identifyDialog = function(data) {
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;
};
\ No newline at end of file
diff --git a/static/js/infoView.js b/static/js/infoView.js
index 42dcacb..5204d1b 100644
--- a/static/js/infoView.js
+++ b/static/js/infoView.js
@@ -1,6 +1,6 @@
'use strict';
-oml.ui.infoView = function() {
+oml.ui.infoView = function(identifyData) {
var ui = oml.user.ui,
@@ -34,11 +34,14 @@ oml.ui.infoView = function() {
.css({
position: 'absolute',
left: '288px',
- right: '176px',
+ right: !identifyData ? '176px' : 16 + Ox.UI.SCROLLBAR_SIZE + 'px',
top: '16px'
})
.appendTo(that),
+ $data;
+
+ if (!identifyData) {
$data = Ox.Element()
.addClass('OxSelectable')
.css({
@@ -48,6 +51,7 @@ oml.ui.infoView = function() {
width: '128px'
})
.appendTo(that);
+ }
function formatLight(str) {
return '' + str + '';
@@ -218,7 +222,9 @@ oml.ui.infoView = function() {
width = Math.round(ratio >= 1 ? size : size * ratio),
height = Math.round(ratio <= 1 ? size : size / ratio),
left = Math.floor((size - width) / 2),
- src = '/' + data.id + '/cover256.jpg',
+ src = !identifyData
+ ? '/' + data.id + '/cover256.jpg'
+ : data.cover,
reflectionSize = Math.round(size / 2);
$elements.forEach(function($element) {
@@ -334,6 +340,7 @@ oml.ui.infoView = function() {
.appendTo($info);
}
+ $('').css({height: '16px'}).appendTo($info);
} 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({
transfer: function(data) {
diff --git a/static/js/oml.js b/static/js/oml.js
index d5ca508..8ffa751 100644
--- a/static/js/oml.js
+++ b/static/js/oml.js
@@ -73,8 +73,8 @@
? Ox['format' + Ox.toTitleCase(key.format.type)].apply(
this, [value].concat(key.format.args || [])
)
- : Ox.isArray(key.type) ? value.join(', ')
- : value;
+ : Ox.isArray(key.type) ? (value || []).join(', ')
+ : (value || '');
}
});
})