import items

This commit is contained in:
j 2014-05-16 16:30:16 +02:00
parent e41942ea99
commit 823ae2a676
11 changed files with 181 additions and 36 deletions

5
README
View File

@ -21,6 +21,11 @@ you need a working python 2.7.x installation and the following packages:
python-simplejson python-lxml
pip install -r requirements.txt
On Linux you need to always install:
apt-get install \
python-imaging python-lxml ghostscript
== Development ==
mkdir client

View File

@ -56,6 +56,15 @@ class Changelog(db.Model):
def timestamp(self):
return self.created.strftime('%s')
@classmethod
def apply_changes(cls, user, changes):
for change in changes:
if not Changelog.apply_change(user, change):
print 'FAIL', change
break
return False
return True
@classmethod
def apply_change(cls, user, change, rebuild=False):
revision, timestamp, sig, data = change

View File

@ -183,6 +183,8 @@ actions.register(scan, cache=False)
@returns_json
def _import(request):
state.main.add_callback(state.websockets[0].put, json.dumps(['import', {}]))
data = json.loads(request.form['data']) if 'data' in request.form else {}
print 'api.import', data
state.main.add_callback(state.websockets[0].put, json.dumps(['import', data]))
return {}
actions.register(_import, 'import', cache=False)

View File

@ -12,13 +12,15 @@ from app import app
import settings
from settings import db
from item.models import File
from user.models import User
from user.models import User, List
from changelog import Changelog
import media
from websocket import trigger_event
extensions = ['epub', 'pdf', 'txt']
def remove_missing():
dirty = False
with app.app_context():
@ -49,7 +51,6 @@ def run_scan():
prefix += '/'
user = User.get_or_create(settings.USER_ID)
assert isinstance(prefix, unicode)
extensions = ['pdf', 'epub', 'txt']
books = []
for root, folders, files in os.walk(prefix):
for f in files:
@ -62,8 +63,7 @@ def run_scan():
books.append(f)
trigger_event('scan', {
'path': prefix,
'files': len(books)
'progress': [0, len(books)],
})
position = 0
added = 0
@ -96,29 +96,37 @@ def run_scan():
item.scrape()
added += 1
trigger_event('scan', {
'position': position,
'length': len(books),
'path': path,
'progress': position/len(books),
'added': added,
'progress': [position, len(books)],
'path': path,
})
trigger_event('scan', {
'progress': 1,
'progress': [position, len(books)],
'added': added,
'done': True
'status': {'code': 200, 'text': ''}
})
def run_import():
def run_import(options=None):
options = options or {}
with app.app_context():
prefs = settings.preferences
prefix = os.path.expanduser(prefs['importPath'])
prefix = options.get('path', os.path.expanduser(prefs['importPath']))
prefix_books = os.path.join(os.path.expanduser(prefs['libraryPath']), 'Books/')
prefix_imported = os.path.join(prefix_books, 'Imported/')
if not prefix[-1] == '/':
prefix += '/'
if not os.path.exists(prefix):
trigger_event('import', {
'progress': [0, 0],
'status': {'code': 404, 'text': 'path not found'}
})
user = User.get_or_create(settings.USER_ID)
listname = options.get('list')
if listname:
listitems = []
assert isinstance(prefix, unicode)
extensions = ['pdf', 'epub', 'txt']
books = []
for root, folders, files in os.walk(prefix):
for f in files:
@ -131,8 +139,7 @@ def run_import():
books.append(f)
trigger_event('import', {
'path': prefix,
'files': len(books)
'progress': [0, len(books)],
})
position = 0
added = 0
@ -145,7 +152,10 @@ def run_import():
f_import = f
f = f.replace(prefix, prefix_imported)
ox.makedirs(os.path.dirname(f))
shutil.move(f_import, f)
if options.get('mode') == 'move':
shutil.move(f_import, f)
else:
shutil.copy(f_import, f)
path = f[len(prefix_books):]
data = media.metadata(f)
ext = f.split('.')[-1]
@ -167,16 +177,19 @@ def run_import():
item.meta['mainid']: item.meta[item.meta['mainid']]
})
item.scrape()
if listname:
listitems.append(item.id)
added += 1
trigger_event('import', {
'position': position,
'length': len(books),
'progress': [position, len(books)],
'path': path,
'progress': position/len(books),
'added': added,
})
if listname:
l = List.get_or_create(settings.USER_ID, listname)
l.add_items(listitems)
trigger_event('import', {
'progress': 1,
'progress': [position, len(books)],
'status': {'code': 200, 'text': ''},
'added': added,
'done': True
})

View File

@ -46,6 +46,8 @@ def info(epub):
isbn = extract_isbn(text)
if isbn:
data['isbn'] = isbn
if 'date' in data and 'T' in data['date']:
data['date'] = data['date'].split('T')[0]
return data
def extract_text(path):

View File

@ -29,11 +29,10 @@ def api_pullChanges(app, remote_id, user_id=None, from_=None, to=None):
def api_pushChanges(app, user_id, changes):
user = User.get(user_id)
for change in changes:
if not Changelog.apply_change(user, change):
print 'FAILED TO APPLY CHANGE', change
state.nodes.queue(user_id, 'pullChanges')
return False
if not Changelog.apply_changes(user, changes):
print 'FAILED TO APPLY CHANGE'
state.nodes.queue(user_id, 'pullChanges')
return False
return True
def api_requestPeering(app, user_id, username, message):

View File

@ -164,12 +164,7 @@ class Node(object):
changes = self.request('pullChanges', from_revision)
if not changes:
return False
for change in changes:
if not Changelog.apply_change(self.user, change):
print 'FAIL', change
break
return False
return True
return Changelog.apply_changes(self.user, changes)
def pushChanges(self, changes):
print 'pushing changes to', self.user_id, changes

View File

@ -33,7 +33,7 @@ class Background:
if action == 'ping':
self.post(['pong', data])
elif action == 'import':
item.scan.run_import()
item.scan.run_import(data)
elif action == 'scan':
item.scan.run_scan()
elif action == 'update':

117
static/js/importDialog.js Normal file
View File

@ -0,0 +1,117 @@
'use strict';
oml.ui.importDialog = function() {
var ui = oml.user.ui,
username = oml.user.preferences.username,
lists = ui._lists.filter(function(list) {
return list.user == username && list.type == 'static';
}),
items = [
{id: ':', title: Ox._('Library')}
].concat(
lists.length ? [{}] : []
).concat(
lists.map(function(list) {
return {id: list.id, title: list.name};
})
).concat([
{},
{id: '', title: Ox._('New List...')}
]),
listNames = ui._lists.filter(function(list) {
return list.user == username;
}).map(function(list) {
return list.name;
}),
$form = Ox.Form({
items: [
Ox.Input({
changeOnKeypress: true,
id: 'path',
label: 'Source Path',
labelWidth: 128,
width: 480
}),
Ox.SelectInput({
id: 'list',
inputValue: oml.validateName(Ox._('Untitled'), listNames),
inputWidth: 224,
items: items,
label: 'Destination',
labelWidth: 128,
max: 1,
min: 1,
value: ':',
width: 480
}),
Ox.Select({
id: 'action',
items: [
{id: 'copy', title: Ox._('Keep files in source path')},
{id: 'move', title: Ox._('Remove files from source path')}
],
label: Ox._('Import Mode'),
labelWidth: 128,
width: 480
})
]
})
.css({margin: '16px'})
.bindEvent({
change: function(data) {
var values = $form.values();
Ox.print('FORM CHANGE', data);
if (data.id == 'list') {
// FIXME: WRONG
if (data.data.value[0] != ':') {
$form.values('list', oml.validateName(data.data.value, listNames))
}
}
that[
values.path && values.list ? 'enableButton' : 'disableButton'
]('import');
}
}),
that = Ox.Dialog({
buttons: [
Ox.Button({
id: 'dontimport',
title: Ox._('No, Don\'t Import')
})
.bindEvent({
click: function() {
that.close();
}
}),
Ox.Button({
disabled: true,
id: 'import',
title: Ox._('Yes, Import')
})
.bindEvent({
click: function() {
var data = $form.values();
oml.api.import({
path: data.path,
list: data.list == ':' ? null : data.list
}, function() {
// ...
})
that.close();
}
})
],
content: $form,
height: 128,
title: Ox._('Import Books'),
width: 512
});
return that;
};

View File

@ -370,6 +370,8 @@ oml.ui.mainMenu = function() {
oml.ui.listDialog.open();
} else if (id == 'deletelist') {
oml.ui.deleteListDialog().open();
} else if (id == 'import') {
oml.ui.importDialog().open();
} else if (id == 'selectall') {
oml.$ui.list.selectAll();
} else if (id == 'selectnone') {
@ -545,11 +547,11 @@ oml.ui.mainMenu = function() {
title: Ox._('Edit'),
items: [
{
id: 'importitems',
id: 'import',
title: Ox._('Import Books...')
},
{
id: 'exportitems',
id: 'export',
title: Ox._('Export Books...')
},
{},

View File

@ -25,6 +25,7 @@
"gridView.js",
"iconDialog.js",
"identifyDialog.js",
"importDialog.js",
"info.js",
"infoView.js",
"itemInnerPanel.js",