diff --git a/resources/images/news/fstream.png b/resources/images/news/fstream.png
new file mode 100644
index 0000000000..a9fc6b4aae
Binary files /dev/null and b/resources/images/news/fstream.png differ
diff --git a/resources/recipes/fstream.recipe b/resources/recipes/fstream.recipe
new file mode 100644
index 0000000000..f6d56042d1
--- /dev/null
+++ b/resources/recipes/fstream.recipe
@@ -0,0 +1,64 @@
+from calibre.web.feeds.news import BasicNewsRecipe
+
+class FIELDSTREAM(BasicNewsRecipe):
+ title = 'Field and Stream'
+ __author__ = 'Starson17 and Tonythebookworm'
+ description = 'Hunting and Fishing and Gun Talk'
+ language = 'en'
+ no_stylesheets = True
+ publisher = 'Starson17 and Tonythebookworm'
+ category = 'food recipes, hunting, fishing, guns'
+ use_embedded_content= False
+ no_stylesheets = True
+ oldest_article = 24
+ remove_javascript = True
+ remove_empty_feeds = True
+ masthead_url = 'http://www.fieldandstream.com/sites/all/themes/fs/logo.png'
+ cover_url = 'http://www.arrowheadflyangler.com/Portals/1/Articles/FieldStream/Field%20and%20Stream%20March%20Fishing%20Edition%20Article%20Cover.jpg'
+ # recursions = 0
+ max_articles_per_feed = 10
+ INDEX = 'http://www.fieldandstream.com'
+
+ keep_only_tags = [dict(name='div', attrs={'class':['interior-main']})
+ ]
+ remove_tags = [dict(name='div', attrs={'id':['comments']})]
+
+ def parse_index(self):
+ feeds = []
+ for title, url in [
+ (u"Wild Chef", u"http://www.fieldandstream.com/blogs/wild-chef"),
+ (u"The Gun Nut", u"http://www.fieldandstream.com/blogs/gun-nut"),
+ (u"Whitetail 365", u"http://www.fieldandstream.com/blogs/whitetail-365"),
+ (u"Fly Talk", u"http://www.fieldandstream.com/blogs/flytalk"),
+ (u"Generation Wild", u"http://www.fieldandstream.com/blogs/generation-wild"),
+ (u"Conservationist", u"http://www.fieldandstream.com/blogs/conservationist"),
+ (u"Honest Angler", u"http://www.fieldandstream.com/blogs/honest-angler"),
+ (u"Mans Best Friend", u"http://www.fieldandstream.com/blogs/mans-best-friend"),
+
+ ]:
+ articles = self.make_links(url)
+ if articles:
+ feeds.append((title, articles))
+ return feeds
+
+ def make_links(self, url):
+ title = 'Temp'
+ current_articles = []
+ soup = self.index_to_soup(url)
+ print 'The soup is: ', soup
+ for item in soup.findAll('h2'):
+ print 'item is: ', item
+ link = item.find('a')
+ print 'the link is: ', link
+ if link:
+ url = self.INDEX + link['href']
+ title = self.tag_to_string(link)
+ print 'the title is: ', title
+ print 'the url is: ', url
+ print 'the title is: ', title
+ current_articles.append({'title': title, 'url': url, 'description':'', 'date':''}) # append all this
+ return current_articles
+
+
+
+
diff --git a/resources/recipes/winnipeg_free_press.recipe b/resources/recipes/winnipeg_free_press.recipe
new file mode 100644
index 0000000000..8c59dff645
--- /dev/null
+++ b/resources/recipes/winnipeg_free_press.recipe
@@ -0,0 +1,30 @@
+from calibre.web.feeds.news import BasicNewsRecipe
+
+class WinnipegFreePress(BasicNewsRecipe):
+ title = u'Winnipeg Free Press'
+ __author__ = 'buyo'
+ description = 'News from Winnipeg, Manitoba, Canada'
+ oldest_article = 1
+ max_articles_per_feed = 15
+ category = 'News, Winnipeg, Canada'
+ cover_url = 'http://media.winnipegfreepress.com/designimages/winnipegfreepress_WFP.gif'
+ no_stylesheets = True
+ encoding = 'UTF-8'
+ remove_javascript = True
+ use_embedded_content = False
+ language = 'en_CA'
+
+ feeds = [(u'Breaking News', u'http://www.winnipegfreepress.com/rss?path=/breakingnews'),
+ (u'Local News',u'http://www.winnipegfreepress.com/rss?path=/local'),
+ (u'Breaking Business News',u'http://www.winnipegfreepress.com/rss?path=/business/finance'),
+ (u'Business',u'http://www.winnipegfreepress.com/rss?path=/business'),
+ (u'Editorials',u'http://www.winnipegfreepress.com/rss?path=/opinion/editorials'),
+ (u'Views from the West',u'http://www.winnipegfreepress.com/rss?path=/opinion/westview'),
+ (u'Life & Style',u'http://www.winnipegfreepress.com/rss?path=/life'),
+ (u'Food & Drink',u'http://www.winnipegfreepress.com/rss?path=/life/food')
+ ]
+
+ keep_only_tags = [
+ dict(name='div', attrs={'id':'article_header'}),
+ dict(name='div', attrs={'class':'article'}),
+ ]
diff --git a/src/calibre/gui2/library/views.py b/src/calibre/gui2/library/views.py
index 389208fdcd..966180467c 100644
--- a/src/calibre/gui2/library/views.py
+++ b/src/calibre/gui2/library/views.py
@@ -229,6 +229,8 @@ class BooksView(QTableView): # {{{
def cleanup_sort_history(self, sort_history):
history = []
for col, order in sort_history:
+ if col == 'date':
+ col = 'timestamp'
if col in self.column_map and (not history or history[0][0] != col):
history.append([col, order])
return history
diff --git a/src/calibre/library/server/opds.py b/src/calibre/library/server/opds.py
index 87a0fecee3..c3a1d68749 100644
--- a/src/calibre/library/server/opds.py
+++ b/src/calibre/library/server/opds.py
@@ -19,6 +19,7 @@ from calibre.ebooks.metadata import fmt_sidx
from calibre.library.comments import comments_to_html
from calibre import guess_type
from calibre.utils.ordered_dict import OrderedDict
+from calibre.utils.date import format_date
BASE_HREFS = {
0 : '/stanza',
@@ -130,7 +131,7 @@ def CATALOG_GROUP_ENTRY(item, category, base_href, version, updated):
link
)
-def ACQUISITION_ENTRY(item, version, FM, updated):
+def ACQUISITION_ENTRY(item, version, FM, updated, CFM, CKEYS):
title = item[FM['title']]
if not title:
title = _('Unknown')
@@ -153,6 +154,21 @@ def ACQUISITION_ENTRY(item, version, FM, updated):
extra.append(_('SERIES: %s [%s]
')%\
(series,
fmt_sidx(float(item[FM['series_index']]))))
+ for key in CKEYS:
+ val = item[CFM[key]['rec_index']]
+ if val is not None:
+ name = CFM[key]['name']
+ datatype = CFM[key]['datatype']
+ if datatype == 'text' and CFM[key]['is_multiple']:
+ extra.append('%s: %s
'%(name, ', '.join(val.split('|'))))
+ elif datatype == 'series':
+ extra.append('%s: %s [%s]
'%(name, val,
+ fmt_sidx(item[CFM.cc_series_index_column_for(key)])))
+ elif datatype == 'datetime':
+ extra.append('%s: %s
'%(name,
+ format_date(val, CFM[key]['display'].get('date_format','dd MMM yyyy'))))
+ else:
+ extra.append('%s: %s
' % (CFM[key]['name'], val))
comments = item[FM['comments']]
if comments:
comments = comments_to_html(comments)
@@ -260,10 +276,14 @@ class NavFeed(Feed):
class AcquisitionFeed(NavFeed):
def __init__(self, updated, id_, items, offsets, page_url, up_url, version,
- FM):
+ FM, CFM):
NavFeed.__init__(self, id_, updated, version, offsets, page_url, up_url)
+ CKEYS = [key for key in sorted(CFM.get_custom_fields(),
+ cmp=lambda x,y: cmp(CFM[x]['name'].lower(),
+ CFM[y]['name'].lower()))]
for item in items:
- self.root.append(ACQUISITION_ENTRY(item, version, FM, updated))
+ self.root.append(ACQUISITION_ENTRY(item, version, FM, updated,
+ CFM, CKEYS))
class CategoryFeed(NavFeed):
@@ -360,7 +380,7 @@ class OPDSServer(object):
cherrypy.response.headers['Last-Modified'] = self.last_modified(updated)
cherrypy.response.headers['Content-Type'] = 'application/atom+xml;profile=opds-catalog'
return str(AcquisitionFeed(updated, id_, items, offsets,
- page_url, up_url, version, self.db.FIELD_MAP))
+ page_url, up_url, version, self.db.FIELD_MAP, self.db.field_metadata))
def opds_search(self, query=None, version=0, offset=0):
try:
@@ -568,7 +588,10 @@ class OPDSServer(object):
(_('Newest'), _('Date'), 'Onewest'),
(_('Title'), _('Title'), 'Otitle'),
]
- for category in categories:
+ def getter(x):
+ return category_meta[x]['name'].lower()
+ for category in sorted(categories,
+ cmp=lambda x,y: cmp(getter(x), getter(y))):
if len(categories[category]) == 0:
continue
if category == 'formats':