From c15f91812b83631838feaa38b1ae6ab05f35dbb3 Mon Sep 17 00:00:00 2001
From: Charles Haley <>
Date: Fri, 3 Sep 2010 16:22:48 +0100
Subject: [PATCH 1/3] Add custom column information to standard and mobile
versions of the content server
---
resources/content_server/gui.js | 11 +++++--
src/calibre/library/server/mobile.py | 47 ++++++++++++++++++++++++----
src/calibre/library/server/xml.py | 34 ++++++++++++++++++++
3 files changed, 84 insertions(+), 8 deletions(-)
diff --git a/resources/content_server/gui.js b/resources/content_server/gui.js
index 9c20037207..7dd056b959 100644
--- a/resources/content_server/gui.js
+++ b/resources/content_server/gui.js
@@ -59,7 +59,14 @@ function render_book(book) {
title = title.slice(0, title.length-2);
title += ' ({0} MB) '.format(size);
}
- if (tags) title += '[{0}]'.format(tags);
+ if (tags) title += 'Tags=[{0}] '.format(tags);
+ custcols = book.attr("custcols").split(',')
+ for ( i = 0; i < custcols.length; i++) {
+ if (custcols[i].length > 0) {
+ vals = book.attr(custcols[i]).split(':#:', 2);
+ title += '{0}=[{1}] '.format(vals[0], vals[1]);
+ }
+ }
title += '
'.format(id);
title += '
'.format(comments)
// Render authors cell
@@ -290,7 +297,7 @@ function layout() {
}
$(function() {
- // document is ready
+ // document is ready
create_table_headers();
// Setup widgets
diff --git a/src/calibre/library/server/mobile.py b/src/calibre/library/server/mobile.py
index aa7a740972..7642164899 100644
--- a/src/calibre/library/server/mobile.py
+++ b/src/calibre/library/server/mobile.py
@@ -17,7 +17,7 @@ from calibre.library.server.utils import strftime
from calibre.ebooks.metadata import fmt_sidx
from calibre.constants import __appname__
from calibre import human_readable
-from calibre.utils.date import utcfromtimestamp
+from calibre.utils.date import utcfromtimestamp, format_date
def CLASS(*args, **kwargs): # class is a reserved word in Python
kwargs['class'] = ' '.join(args)
@@ -85,7 +85,7 @@ def build_navigation(start, num, total, url_base): # {{{
# }}}
-def build_index(books, num, search, sort, order, start, total, url_base):
+def build_index(books, num, search, sort, order, start, total, url_base, CKEYS):
logo = DIV(IMG(src='/static/calibre.png', alt=__appname__), id='logo')
search_box = build_search_box(num, search, sort, order)
@@ -123,10 +123,16 @@ def build_index(books, num, search, sort, order, start, total, url_base):
series = u'[%s - %s]'%(book['series'], book['series_index']) \
if book['series'] else ''
- tags = u'[%s]'%book['tags'] if book['tags'] else ''
+ tags = u'Tags=[%s]'%book['tags'] if book['tags'] else ''
- text = u'\u202f%s %s by %s - %s - %s %s' % (book['title'], series,
- book['authors'], book['size'], book['timestamp'], tags)
+ ctext = ''
+ for key in CKEYS:
+ val = book.get(key, None)
+ if val:
+ ctext += '%s=[%s] '%tuple(val.split(':#:'))
+
+ text = u'\u202f%s %s by %s - %s - %s %s %s' % (book['title'], series,
+ book['authors'], book['size'], book['timestamp'], tags, ctext)
if last is None:
data.text = text
@@ -189,6 +195,10 @@ class MobileServer(object):
if sort is not None:
self.sort(items, sort, (order.lower().strip() == 'ascending'))
+ CFM = self.db.field_metadata
+ CKEYS = [key for key in sorted(CFM.get_custom_fields(),
+ cmp=lambda x,y: cmp(CFM[x]['name'].lower(),
+ CFM[y]['name'].lower()))]
books = []
for record in items[(start-1):(start-1)+num]:
book = {'formats':record[FM['formats']], 'size':record[FM['size']]}
@@ -209,6 +219,31 @@ class MobileServer(object):
book[x] = strftime('%Y/%m/%d %H:%M:%S', record[FM[x]])
book['id'] = record[FM['id']]
books.append(book)
+ for key in CKEYS:
+ def concat(name, val):
+ return '%s:#:%s'%(name, unicode(val))
+ val = record[CFM[key]['rec_index']]
+ if val:
+ datatype = CFM[key]['datatype']
+ if datatype in ['comments']:
+ continue
+ name = CFM[key]['name']
+ if datatype == 'text' and CFM[key]['is_multiple']:
+ book[key] = concat(name, ', '.join(val.split('|')))
+ elif datatype == 'series':
+ book[key] = concat(name, '%s [%s]'%(val,
+ fmt_sidx(record[CFM.cc_series_index_column_for(key)])))
+ elif datatype == 'datetime':
+ book[key] = concat(name,
+ format_date(val, CFM[key]['display'].get('date_format','dd MMM yyyy')))
+ elif datatype == 'bool':
+ if val:
+ book[key] = concat(name, __builtin__._('Yes'))
+ else:
+ book[key] = concat(name, __builtin__._('No'))
+ else:
+ book[key] = concat(name, val)
+
updated = self.db.last_modified()
cherrypy.response.headers['Content-Type'] = 'text/html; charset=utf-8'
@@ -218,7 +253,7 @@ class MobileServer(object):
url_base = "/mobile?search=" + search+";order="+order+";sort="+sort+";num="+str(num)
return html.tostring(build_index(books, num, search, sort, order,
- start, len(ids), url_base),
+ start, len(ids), url_base, CKEYS),
encoding='utf-8', include_meta_content_type=True,
pretty_print=True)
diff --git a/src/calibre/library/server/xml.py b/src/calibre/library/server/xml.py
index 9db786953e..0d7aabc629 100644
--- a/src/calibre/library/server/xml.py
+++ b/src/calibre/library/server/xml.py
@@ -15,6 +15,7 @@ from calibre.library.server.utils import strftime
from calibre.ebooks.metadata import fmt_sidx
from calibre.constants import preferred_encoding
from calibre import isbytestring
+from calibre.utils.date import format_date
E = ElementMaker()
@@ -86,6 +87,39 @@ class XMLServer(object):
kwargs[x] = serialize(y) if y else ''
c = kwargs.pop('comments')
+
+ CFM = self.db.field_metadata
+ CKEYS = [key for key in sorted(CFM.get_custom_fields(),
+ cmp=lambda x,y: cmp(CFM[x]['name'].lower(),
+ CFM[y]['name'].lower()))]
+ custcols = []
+ for key in CKEYS:
+ def concat(name, val):
+ return '%s:#:%s'%(name, unicode(val))
+ val = record[CFM[key]['rec_index']]
+ if val:
+ datatype = CFM[key]['datatype']
+ if datatype in ['comments']:
+ continue
+ k = str('CF_'+key[1:])
+ name = CFM[key]['name']
+ custcols.append(k)
+ if datatype == 'text' and CFM[key]['is_multiple']:
+ kwargs[k] = concat(name, ', '.join(val.split('|')))
+ elif datatype == 'series':
+ kwargs[k] = concat(name, '%s [%s]'%(val,
+ fmt_sidx(record[CFM.cc_series_index_column_for(key)])))
+ elif datatype == 'datetime':
+ kwargs[k] = concat(name,
+ format_date(val, CFM[key]['display'].get('date_format','dd MMM yyyy')))
+ elif datatype == 'bool':
+ if val:
+ kwargs[k] = concat(name, __builtin__._('Yes'))
+ else:
+ kwargs[k] = concat(name, __builtin__._('No'))
+ else:
+ kwargs[k] = concat(name, val)
+ kwargs['custcols'] = ','.join(custcols)
books.append(E.book(c, **kwargs))
updated = self.db.last_modified()
From 7ea0e198404103d6ce4cf11fdd252f61538e8be6 Mon Sep 17 00:00:00 2001
From: Charles Haley <>
Date: Fri, 3 Sep 2010 16:33:59 +0100
Subject: [PATCH 2/3] Remove blanks in text/is_multiple field representation
---
src/calibre/library/server/mobile.py | 2 +-
src/calibre/library/server/xml.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/calibre/library/server/mobile.py b/src/calibre/library/server/mobile.py
index 7642164899..6a0744c317 100644
--- a/src/calibre/library/server/mobile.py
+++ b/src/calibre/library/server/mobile.py
@@ -229,7 +229,7 @@ class MobileServer(object):
continue
name = CFM[key]['name']
if datatype == 'text' and CFM[key]['is_multiple']:
- book[key] = concat(name, ', '.join(val.split('|')))
+ book[key] = concat(name, ','.join(val.split('|')))
elif datatype == 'series':
book[key] = concat(name, '%s [%s]'%(val,
fmt_sidx(record[CFM.cc_series_index_column_for(key)])))
diff --git a/src/calibre/library/server/xml.py b/src/calibre/library/server/xml.py
index 0d7aabc629..3897faf31e 100644
--- a/src/calibre/library/server/xml.py
+++ b/src/calibre/library/server/xml.py
@@ -105,7 +105,7 @@ class XMLServer(object):
name = CFM[key]['name']
custcols.append(k)
if datatype == 'text' and CFM[key]['is_multiple']:
- kwargs[k] = concat(name, ', '.join(val.split('|')))
+ kwargs[k] = concat(name, ','.join(val.split('|')))
elif datatype == 'series':
kwargs[k] = concat(name, '%s [%s]'%(val,
fmt_sidx(record[CFM.cc_series_index_column_for(key)])))
From f383f6ee5c257c1ab97445db13cf1de6ea7f8776 Mon Sep 17 00:00:00 2001
From: Charles Haley <>
Date: Fri, 3 Sep 2010 17:43:25 +0100
Subject: [PATCH 3/3] 1) Add limit to number of tags that display in content
server 2) Add tweak to set the limit.
---
resources/content_server/gui.js | 2 +-
resources/default_tweaks.py | 3 +++
src/calibre/library/server/__init__.py | 14 +++++++++++++-
src/calibre/library/server/mobile.py | 5 +++--
src/calibre/library/server/xml.py | 5 ++++-
5 files changed, 24 insertions(+), 5 deletions(-)
diff --git a/resources/content_server/gui.js b/resources/content_server/gui.js
index 7dd056b959..8368866a5e 100644
--- a/resources/content_server/gui.js
+++ b/resources/content_server/gui.js
@@ -50,7 +50,7 @@ function render_book(book) {
var comments = $.trim(book.text()).replace(/\n\n/, '
');
var formats = new Array();
var size = (parseFloat(book.attr('size'))/(1024*1024)).toFixed(1);
- var tags = book.attr('tags').replace(/,/g, ', ');
+ var tags = book.attr('tags')
formats = book.attr("formats").split(",");
if (formats.length > 0) {
for (i=0; i < formats.length; i++) {
diff --git a/resources/default_tweaks.py b/resources/default_tweaks.py
index afbc6e7334..2897860ec4 100644
--- a/resources/default_tweaks.py
+++ b/resources/default_tweaks.py
@@ -110,3 +110,6 @@ grouped_search_terms = {}
# a book' are added when copying books to another library
add_new_book_tags_when_importing_books = False
+
+# Set the maximum number of tags to show in the content server
+max_content_server_tags_shown=5
\ No newline at end of file
diff --git a/src/calibre/library/server/__init__.py b/src/calibre/library/server/__init__.py
index 5050dfaa99..7b283be854 100644
--- a/src/calibre/library/server/__init__.py
+++ b/src/calibre/library/server/__init__.py
@@ -7,7 +7,7 @@ __docformat__ = 'restructuredtext en'
import os
-from calibre.utils.config import Config, StringConfig, config_dir
+from calibre.utils.config import Config, StringConfig, config_dir, tweaks
listen_on = '0.0.0.0'
@@ -49,3 +49,15 @@ def server_config(defaults=None):
def main():
from calibre.library.server.main import main
return main()
+
+def format_tag_string(tags, sep):
+ MAX = tweaks['max_content_server_tags_shown']
+ if tags:
+ tlist = [t.strip() for t in tags.split(sep)]
+ else:
+ tlist = []
+ tlist.sort(cmp=lambda x,y:cmp(x.lower(), y.lower()))
+ if len(tlist) > MAX:
+ tlist = tlist[:MAX]+['...']
+ return u'%s'%(', '.join(tlist)) if tlist else ''
+
diff --git a/src/calibre/library/server/mobile.py b/src/calibre/library/server/mobile.py
index 6a0744c317..961c33fe79 100644
--- a/src/calibre/library/server/mobile.py
+++ b/src/calibre/library/server/mobile.py
@@ -18,6 +18,7 @@ from calibre.ebooks.metadata import fmt_sidx
from calibre.constants import __appname__
from calibre import human_readable
from calibre.utils.date import utcfromtimestamp, format_date
+from . import format_tag_string
def CLASS(*args, **kwargs): # class is a reserved word in Python
kwargs['class'] = ' '.join(args)
@@ -213,7 +214,7 @@ class MobileServer(object):
book['authors'] = authors
book['series_index'] = fmt_sidx(float(record[FM['series_index']]))
book['series'] = record[FM['series']]
- book['tags'] = record[FM['tags']]
+ book['tags'] = format_tag_string(record[FM['tags']], ',')
book['title'] = record[FM['title']]
for x in ('timestamp', 'pubdate'):
book[x] = strftime('%Y/%m/%d %H:%M:%S', record[FM[x]])
@@ -229,7 +230,7 @@ class MobileServer(object):
continue
name = CFM[key]['name']
if datatype == 'text' and CFM[key]['is_multiple']:
- book[key] = concat(name, ','.join(val.split('|')))
+ book[key] = concat(name, format_tag_string(val, '|'))
elif datatype == 'series':
book[key] = concat(name, '%s [%s]'%(val,
fmt_sidx(record[CFM.cc_series_index_column_for(key)])))
diff --git a/src/calibre/library/server/xml.py b/src/calibre/library/server/xml.py
index 3897faf31e..8cfb45c66f 100644
--- a/src/calibre/library/server/xml.py
+++ b/src/calibre/library/server/xml.py
@@ -16,6 +16,7 @@ from calibre.ebooks.metadata import fmt_sidx
from calibre.constants import preferred_encoding
from calibre import isbytestring
from calibre.utils.date import format_date
+from . import format_tag_string
E = ElementMaker()
@@ -84,6 +85,8 @@ class XMLServer(object):
for x in ('isbn', 'formats', 'series', 'tags', 'publisher',
'comments'):
y = record[FM[x]]
+ if x == 'tags':
+ y = format_tag_string(y, ',')
kwargs[x] = serialize(y) if y else ''
c = kwargs.pop('comments')
@@ -105,7 +108,7 @@ class XMLServer(object):
name = CFM[key]['name']
custcols.append(k)
if datatype == 'text' and CFM[key]['is_multiple']:
- kwargs[k] = concat(name, ','.join(val.split('|')))
+ kwargs[k] = concat(name, format_tag_string(val,'|'))
elif datatype == 'series':
kwargs[k] = concat(name, '%s [%s]'%(val,
fmt_sidx(record[CFM.cc_series_index_column_for(key)])))