Sync to trunk.

This commit is contained in:
John Schember 2011-11-04 18:56:53 -04:00
commit 771b4845c1
34 changed files with 671 additions and 71 deletions

View File

@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-
__license__ = 'GPL v3'
__copyright__ = u'2011, Silviu Cotoar\u0103'
'''
b365.realitatea.net
'''
from calibre.web.feeds.news import BasicNewsRecipe
class b365Realitatea(BasicNewsRecipe):
title = u'b365 Realitatea'
__author__ = u'Silviu Cotoar\u0103'
publisher = u'b365 Realitatea'
description = u'b365 Realitatea'
oldest_article = 5
language = 'ro'
max_articles_per_feed = 100
no_stylesheets = True
use_embedded_content = False
category = 'Ziare,Romania,Bucuresti'
encoding = 'utf-8'
cover_url = 'http://b365.realitatea.net/wp-content/themes/b/images/b365-logo.png'
conversion_options = {
'comments' : description
,'tags' : category
,'language' : language
,'publisher' : publisher
}
keep_only_tags = [
dict(name='div', attrs={'class':'newsArticle'})
]
remove_tags = [
dict(name='div', attrs={'class':'date'})
, dict(name='dic', attrs={'class':'addthis_toolbox addthis_default_style'})
, dict(name='div', attrs={'class':'related_posts'})
, dict(name='div', attrs={'id':'RelevantiWidget'})
]
remove_tags_after = [
dict(name='div', attrs={'id':'RelevantiWidget'})
]
feeds = [
(u'\u0218tiri', u'http://b365.realitatea.net/rss-full/')
]
def preprocess_html(self, soup):
return self.adeify_images(soup)

35
recipes/capital_gr.recipe Normal file
View File

@ -0,0 +1,35 @@
from calibre.web.feeds.recipes import BasicNewsRecipe
class Capital(BasicNewsRecipe):
title = 'Capital.gr'
__author__ ='Stelios'
description = 'Financial News from Greece'
#max_articles_per_feed = 100
oldest_article = 3
publisher = 'Capital.gr'
category = 'news, GR'
language = 'el'
encoding = 'windows-1253'
cover_url = 'http://files.capital.gr/images/caplogo.gif'
no_stylesheets = True
use_embedded_content = False
remove_empty_feeds = True
keep_only_tags = [
dict(name='h1'),
dict(name='p'),
dict(name='span', attrs={'id' : ["textbody"]})
]
#3 posts seemed to have utf8 encoding
feeds = [
(u'\u039F\u039B\u0395\u03A3 \u039F\u0399 \u0395\u0399\u0394\u0397\u03A3\u0395\u0399\u03A3', 'http://www.capital.gr/news/newsrss.asp?s=-1'),
(u'\u0395\u03A0\u0399\u03A7\u0395\u0399\u03A1\u0397\u03A3\u0395\u0399\u03A3', 'http://www.capital.gr/news/newsrss.asp?s=-2'),
(u'\u0391\u0393\u039F\u03A1\u0395\u03A3', 'http://www.capital.gr/news/newsrss.asp?s=-3'),
(u'\u039F\u0399\u039A\u039F\u039D\u039F\u039C\u0399\u0391', 'http://www.capital.gr/news/newsrss.asp?s=-4'),
(u'\u03A7\u03A1\u0397\u039C. \u0391\u039D\u0391\u039A\u039F\u0399\u039D\u03A9\u03A3\u0395\u0399\u03A3', 'http://www.capital.gr/news/newsrss.asp?s=-6'),
(u'\u039C\u03CC\u03BD\u03B9\u03BC\u03B5\u03C2 \u03C3\u03C4\u03AE\u03BB\u03B5\u03C2: \u039C\u0395 \u0391\u03A0\u039F\u03A8\u0397', 'http://www.capital.gr/articles/articlesrss.asp?catid=4'),
(u'\u039C\u03CC\u03BD\u03B9\u03BC\u03B5\u03C2 \u03C3\u03C4\u03AE\u03BB\u03B5\u03C2: \u03A3\u0399\u03A9\u03A0\u0397\u03A4\u0397\u03A1\u0399\u039F', 'http://www.capital.gr/articles/articlesrss.asp?catid=6'),
(u'\u039C\u03CC\u03BD\u03B9\u03BC\u03B5\u03C2 \u03C3\u03C4\u03AE\u03BB\u03B5\u03C2: \u03A0\u0399\u03A3\u03A9 \u0391\u03A0\u039F \u03A4\u0399\u03A3 \u0393\u03A1\u0391\u039C\u039C\u0395\u03A3', 'http://www.capital.gr/articles/articlesrss.asp?catid=8'),
#(u'\u039C\u03CC\u03BD\u03B9\u03BC\u03B5\u03C2 \u03C3\u03C4\u03AE\u03BB\u03B5\u03C2: \u03A4\u0395\u03A7\u039D\u039F\u039B\u039F\u0393\u0399\u0391', 'http://www.capital.gr/news/newsrss.asp?s=-8') not working for now
]

51
recipes/catavencii.recipe Normal file
View File

@ -0,0 +1,51 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = u'2011, Silviu Cotoar\u0103'
'''
catavencii.ro
'''
from calibre.web.feeds.news import BasicNewsRecipe
class Catavencii(BasicNewsRecipe):
title = u'Ca\u0163avencii'
__author__ = u'Silviu Cotoar\u0103'
publisher = u'Ca\u0163avencii'
description = u'Ca\u0163avencii'
oldest_article = 5
language = 'ro'
max_articles_per_feed = 100
no_stylesheets = True
use_embedded_content = False
category = 'Ziare,Romania'
encoding = 'utf-8'
cover_url = 'http://www.simonatache.ro/wp-content/uploads/2011/06/catavencii-logo.png'
conversion_options = {
'comments' : description
,'tags' : category
,'language' : language
,'publisher' : publisher
}
keep_only_tags = [
dict(name='div', attrs={'id':'content'})
]
remove_tags = [
dict(name='div', attrs={'id':'breadcrumbs'})
, dict(name='span', attrs={'class':'info'})
, dict(name='div', attrs={'id':'social-media-article'})
]
remove_tags_after = [
dict(name='div', attrs={'id':'social-media-article'})
]
feeds = [
(u'\u0218tiri', u'http://www.catavencii.ro/rss')
]
def preprocess_html(self, soup):
return self.adeify_images(soup)

View File

@ -1,10 +1,11 @@
from calibre.web.feeds.news import BasicNewsRecipe
import re
class AdvancedUserRecipe1306061239(BasicNewsRecipe):
title = u'The Daily Mirror'
description = 'News as provide by The Daily Mirror -UK'
__author__ = 'Dave Asbury'
# last updated 30/10/11
language = 'en_GB'
cover_url = 'http://yookeo.com/screens/m/i/mirror.co.uk.jpg'
@ -12,26 +13,30 @@ class AdvancedUserRecipe1306061239(BasicNewsRecipe):
masthead_url = 'http://www.nmauk.co.uk/nma/images/daily_mirror.gif'
oldest_article = 1
max_articles_per_feed = 100
oldest_article = 2
max_articles_per_feed = 30
remove_empty_feeds = True
remove_javascript = True
no_stylesheets = True
extra_css = '''
body{ text-align: justify; font-family:Arial,Helvetica,sans-serif; font-size:11px; font-size-adjust:none; font-stretch:normal; font-style:normal; font-variant:normal; font-weight:normal;}
'''
keep_only_tags = [
dict(name='h1'),
dict(attrs={'class':['article-attr']}),
dict(name='div', attrs={'class' : [ 'article-body', 'crosshead']})
dict(name='div',attrs={'id' : 'body-content'})
]
]
remove_tags_after = [dict (name='div',attrs={'class' : 'related'})]
remove_tags = [
dict(name='div', attrs={'class' : ['caption', 'article-resize']}),
dict( attrs={'class':'append-html'})
]
dict(name='div',attrs={'id' : ['sidebar','menu','search-box','roffers-top']}),
dict(name='div',attrs={'class' :['inline-ad span-16 last','article-resize','related','list teasers']}),
dict(attrs={'class' : ['channellink','article-tags','replace','append-html']}),
dict(name='div',attrs={'class' : 'span-12 last sl-others addthis_toolbox addthis_default_style'})
]
preprocess_regexps = [
(re.compile(r'<dl class="q-search">.*?</dl>', re.IGNORECASE | re.DOTALL), lambda match: '')]
feeds = [
@ -43,10 +48,10 @@ class AdvancedUserRecipe1306061239(BasicNewsRecipe):
,(u'Music News','http://www.mirror.co.uk/celebs/music/rss.xml')
,(u'Celebs and Tv Gossip','http://www.mirror.co.uk/celebs/tv/rss.xml')
,(u'Sport','http://www.mirror.co.uk/sport/rss.xml')
,(u'Life Style','http://www.mirror.co.uk/life-style/rss.xml')
,(u'Advice','http://www.mirror.co.uk/advice/rss.xml')
,(u'Travel','http://www.mirror.co.uk/advice/travel/rss.xml')
,(u'Life Style','http://www.mirror.co.uk/life-style/rss.xml')
,(u'Advice','http://www.mirror.co.uk/advice/rss.xml')
,(u'Travel','http://www.mirror.co.uk/advice/travel/rss.xml')
# example of commented out feed not needed ,(u'Travel','http://www.mirror.co.uk/advice/travel/rss.xml')
]
]

View File

@ -16,7 +16,7 @@ class DeutscheWelle_es(BasicNewsRecipe):
max_articles_per_feed = 100
use_embedded_content = False
no_stylesheets = True
language = 'de_ES'
language = 'de'
publication_type = 'newsportal'
remove_empty_feeds = True
masthead_url = 'http://www.dw-world.de/skins/std/channel1/pics/dw_logo1024.gif'

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 600 B

34
recipes/in_gr.recipe Normal file
View File

@ -0,0 +1,34 @@
from calibre.web.feeds.recipes import BasicNewsRecipe
class ingr(BasicNewsRecipe):
title = 'in.gr'
__author__ = 'Stelios'
description = 'News from Greece'
# max_articles_per_feed = 100
oldest_article = 4
publisher = 'in.gr'
category = 'news, GR'
language = 'el'
encoding = 'utf8'
no_stylesheets = True
use_embedded_content = False
remove_empty_feeds = True
encoding = 'utf8'
keep_only_tags = [
dict(name='h1'),
dict(name='div', attrs={'id' : ['in-news-article']})
]
remove_tags = [
dict(name='em', attrs={'class' : ['credits']}),
dict(name='div', attrs={'class' : ['article-tools-hor', 'promo-banners gAds', 'main', 'article-listen-player', 'article-tools-hor-bttm', 'tools-sec', 'article-tools', 'article-listen-player-ver']})
]
feeds = [
(u'\u0395\u03BB\u03BB\u03AC\u03B4\u03B1', 'http://rss.in.gr/feed/news/greece'),
(u'\u0395\u03B9\u03B4\u03AE\u03C3\u03B5\u03B9\u03C2', 'http://rss.in.gr/feed/news'),
(u'\u039A\u03CC\u03C3\u03BC\u03BF\u03C2', 'http://rss.in.gr/feed/news/world'),
(u'\u0395\u03C0\u03B9\u03C3\u03C4\u03AE\u03BC\u03B7', 'http://rss.in.gr/feed/news/science'),
(u'\u03A0\u03BF\u03BB\u03B9\u03C4\u03B9\u03C3\u03BC\u03CC\u03C2', 'http://rss.in.gr/feed/news/culture')
]

43
recipes/men24_gr.recipe Normal file
View File

@ -0,0 +1,43 @@
from calibre.web.feeds.recipes import BasicNewsRecipe
class Men24(BasicNewsRecipe):
title = 'Men24.gr'
__author__ = 'Stelios'
description = 'Greek Mens portal'
oldest_article = 14
max_articles_per_feed = 100
language = 'el'
cover_url = 'http://www.men24.gr/ast/img/men24Logo.jpg'
category = 'magazines, GR'
language = 'el'
encoding = 'windows-1253'
no_stylesheets = True
use_embedded_content = False
remove_empty_feeds = True
extra_css = '''
.artPrintTitle{font-family :Arial,Helvetica,sans-serif; font-weight: bold; font-size:large;}
.artPrintSubtitle{font-family :Arial,Helvetica,sans-serif; font-size:x-small;}
'''
remove_tags = [
dict(name='td', attrs={'class':['artPrintCategory']}),
dict(name='table', attrs={'class':['footer']}),
dict(name='img')
]
feeds = [
(u'\u038C\u03BB\u03B5\u03C2 \u03BF\u03B9 \u03B5\u03B9\u03B4\u03AE\u03C3\u03B5\u03B9\u03C2', 'http://www.men24.gr/svc/rss/lastNews/'),
(u'\u03A3\u03C4\u03C5\u03BB', 'http://www.men24.gr/svc/rss/categoryNews/?category=style'),
(u'Fitness', 'http://www.men24.gr/svc/rss/categoryNews/?category=fitness'),
(u'Gadgets', 'http://www.men24.gr/svc/rss/categoryNews/?category=gadgets'),
(u'\u0394\u03B9\u03B1\u03C3\u03BA\u03AD\u03B4\u03B1\u03C3\u03B7', 'http://www.men24.gr/svc/rss/categoryNews/?category=fun'),
(u'\u03A7\u03C1\u03AE\u03BC\u03B1 \u03BA\u03B1\u03B9 \u039A\u03B1\u03C1\u03B9\u03AD\u03C1\u03B1', 'http://www.men24.gr/svc/rss/categoryNews/?category=money'),
(u'Special Edition', 'http://www.men24.gr/svc/rss/categoryNews/?category=special'),
(u'\u0388\u03C1\u03C9\u03C4\u03B1\u03C2 \u03BA\u03B1\u03B9 Sex', 'http://www.men24.gr/svc/rss/categoryNews/?category=love'),
(u'\u0386\u03BD\u03C4\u03C1\u03B5\u03C2 \u03C4\u03BF\u03C5 24', 'http://www.men24.gr/svc/rss/categoryNews/?category=men'),
(u'\u0393\u03C5\u03BD\u03B1\u03AF\u03BA\u03B5\u03C2', 'http://www.men24.gr/svc/rss/categoryNews/?category=women'),
(u'\u039F\u03B4\u03B7\u03B3\u03BF\u03AF', 'http://www.men24.gr/svc/rss/categoryNews/?category=guides'),
(u'\u03A4\u03B6\u03CC\u03B3\u03BF\u03C2', 'http://www.men24.gr/svc/rss/categoryNews/?category=gamble')
]
def print_version(self, url):
return url.replace('.asp', '.print.asp')

48
recipes/newsbeast.recipe Normal file
View File

@ -0,0 +1,48 @@
from calibre.web.feeds.recipes import BasicNewsRecipe
class newsbeast(BasicNewsRecipe):
title = 'Newsbeast'
__author__ = 'Stelios'
description = 'News from Greece'
oldest_article = 2
max_articles_per_feed = 100
publisher = 'newsbeast'
category = 'news, GR'
language = 'el'
encoding = 'utf8'
no_stylesheets = True
use_embedded_content = False
remove_empty_feeds = True
encoding = 'utf8'
keep_only_tags = [
dict(name='div', attrs={'class' : ['article-title']}),
# dict(name='img', attrs={'class' : ['article_photo']}),
#If enabled feeds exceede 15MB
dict(name='div', attrs={'class' : ['txt']})
]
remove_tags = [
dict(name='table', attrs={'id':['artFoot']}),
dict(name='img'),
#If removed feeds exceede 15MB
dict(name='p', attrs={'class':['article-details']})
]
feeds = [
(u'\u0395\u03BB\u03BB\u03AC\u03B4\u03B1', 'http://www.newsbeast.gr/feeds/greece'),
(u'\u039A\u03CC\u03C3\u03BC\u03BF\u03C2', 'http://www.newsbeast.gr/feeds/world'),
(u'\u03A0\u03BF\u03BB\u03B9\u03C4\u03B9\u03BA\u03AE', 'http://www.newsbeast.gr/feeds/politiki'),
(u'\u039F\u03B9\u03BA\u03BF\u03BD\u03BF\u03BC\u03AF\u03B1', 'http://www.newsbeast.gr/feeds/financial'),
(u'\u0391\u03B8\u03BB\u03B7\u03C4\u03B9\u03BA\u03AC', 'http://www.newsbeast.gr/feeds/sports'),
(u'\u039A\u03BF\u03B9\u03BD\u03C9\u03BD\u03AF\u03B1', 'http://www.newsbeast.gr/feeds/society'),
(u'\u03A0\u03B5\u03C1\u03B9\u03B2\u03AC\u03BB\u03BB\u03BF\u03BD', 'http://www.newsbeast.gr/feeds/environment'),
(u'Media', 'http://www.newsbeast.gr/feeds/media'),
(u'\u0394\u03B9\u03B1\u03C3\u03BA\u03AD\u03B4\u03B1\u03C3\u03B7', 'http://www.newsbeast.gr/feeds/entertainment'),
(u'Lifestyle', 'http://www.newsbeast.gr/feeds/lifestyle'),
(u'\u03A4\u03B5\u03C7\u03BD\u03BF\u03BB\u03BF\u03B3\u03AF\u03B1', 'http://www.newsbeast.gr/feeds/technology'),
(u'\u0391\u03C5\u03C4\u03BF\u03BA\u03AF\u03BD\u03B7\u03C4\u03BF', 'http://www.newsbeast.gr/feeds/car'),
(u'\u0393\u03C5\u03BD\u03B1\u03AF\u03BA\u03B1', 'http://www.newsbeast.gr/feeds/woman'),
(u'\u03A5\u03B3\u03B5\u03AF\u03B1', 'http://www.newsbeast.gr/feeds/health'),
(u'\u03A0\u03BF\u03BB\u03B9\u03C4\u03B9\u03C3\u03BC\u03CC\u03C2', 'http://www.newsbeast.gr/feeds/culture'),
(u'\u038C,\u03C4\u03B9 \u03BD\u03B1 \u03BD\u03B1\u03B9', 'http://www.newsbeast.gr/feeds/weird')
]

View File

@ -1,6 +1,6 @@
__license__ = 'GPL v3'
__copyright__ = '2008-2010, Darko Miletic <darko.miletic at gmail.com>'
__copyright__ = '2008-2011, Darko Miletic <darko.miletic at gmail.com>'
'''
www.nin.co.rs
'''
@ -29,6 +29,7 @@ class Nin(BasicNewsRecipe):
use_embedded_content = False
language = 'sr'
publication_type = 'magazine'
masthead_url = 'http://www.nin.co.rs/img/head/logo.jpg'
extra_css = """
@font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)}
body{font-family: Verdana, Lucida, sans1, sans-serif}
@ -72,9 +73,11 @@ class Nin(BasicNewsRecipe):
def get_cover_url(self):
cover_url = None
soup = self.index_to_soup(self.INDEX)
link_item = soup.find('img',attrs={'width':'100','border':'0'})
if link_item:
cover_url = self.PREFIX + link_item['src']
for item in soup.findAll('a', href=True):
if item['href'].startswith('/pages/issue.php?id='):
simg = item.find('img')
if simg:
return self.PREFIX + item.img['src']
return cover_url
def parse_index(self):

26
recipes/protagon.recipe Normal file
View File

@ -0,0 +1,26 @@
from calibre.web.feeds.recipes import BasicNewsRecipe
class protagon(BasicNewsRecipe):
title = 'Protagon'
__author__ = 'Stelios'
description = 'Opinion articles in Greek'
oldest_article = 7
max_articles_per_feed = 100
publisher = 'Various'
category = 'GR'
language = 'el'
encoding = 'utf8'
no_stylesheets = True
use_embedded_content = False
remove_empty_feeds = True
keep_only_tags = [
dict(name='h1', attrs={'id' : ['title']}),
dict(name='div', attrs={'class' : ['freetext']})
]
feeds = [
(u'\u0398\u03AD\u03BC\u03B1\u03C4\u03B1', 'http://www.protagon.gr/rss?i=protagon.el.8emata')
]

View File

@ -40,7 +40,7 @@ class Sciencenews(BasicNewsRecipe):
,dict(name='div', attrs={'class': 'embiggen'})
]
feeds = [(u"Science News / News Items", u'http://sciencenews.org/view/feed/type/news/name/news.rss')]
feeds = [(u"Science News / News Items", u'http://sciencenews.org/index.php/feed/type/news/name/news.rss/view/feed/name/all.rss')]
def get_cover_url(self):
cover_url = None

14
recipes/sigma_live.recipe Normal file
View File

@ -0,0 +1,14 @@
from calibre.web.feeds.news import BasicNewsRecipe
class sigmalive(BasicNewsRecipe):
title = u'SigmaLive'
__author__ = 'Stelios'
oldest_article = 7
max_articles_per_feed = 100
auto_cleanup = True
category = 'news, CY'
description = 'Cypriot News'
language = 'el'
encoding = 'utf8'
feeds = [(u'sigmalive', u'http://sigmalive.com/rss/latest')]

37
recipes/skai.recipe Normal file
View File

@ -0,0 +1,37 @@
from calibre.web.feeds.recipes import BasicNewsRecipe
class SKAI(BasicNewsRecipe):
title = 'SKAI'
__author__ = 'Stelios'
description = 'News from Greece'
oldest_article = 2
max_articles_per_feed = 100
publisher = 'skai.gr'
category = 'news, GR'
language = 'el'
encoding = 'utf8'
no_stylesheets = True
use_embedded_content = False
remove_empty_feeds = True
encoding = 'utf8'
keep_only_tags = [
dict(name='h1'),
dict(name='div', attrs={'class' : ['articleText']})
]
feeds = [
(u'\u039A\u03C5\u03C1\u03B9\u03CC\u03C4\u03B5\u03C1\u03B5\u03C2 \u0395\u03B9\u03B4\u03AE\u03C3\u03B5\u03B9\u03C2', 'http://feeds.feedburner.com/skai/Uulu'),
(u'\u0395\u03BB\u03BB\u03AC\u03B4\u03B1', 'http://feeds.feedburner.com/skai/PLwa'),
(u'\u039A\u03CC\u03C3\u03BC\u03BF\u03C2', 'http://feeds.feedburner.com/skai/aqOL'),
(u'\u03A0\u03BF\u03BB\u03B9\u03C4\u03B9\u03BA\u03AE','http://feeds.feedburner.com/skai/yinm'),
(u'\u039F\u03B9\u03BA\u03BF\u03BD\u03BF\u03BC\u03AF\u03B1', 'http://feeds.feedburner.com/skai/oPUt'),
(u'\u03A4\u03B5\u03C7\u03BD\u03BF\u03BB\u03BF\u03B3\u03AF\u03B1', 'http://feeds.feedburner.com/skai/fqsg'),
(u'\u0391\u03B8\u03BB\u03B7\u03C4\u03B9\u03C3\u03BC\u03CC\u03C2', 'http://feeds.feedburner.com/skai/TfmK'),
(u'\u03A5\u03B3\u03B5\u03AF\u03B1', 'http://feeds.feedburner.com/skai/TABn'),
(u'\u03A0\u03BF\u03BB\u03B9\u03C4\u03B9\u03C3\u03BC\u03CC\u03C2', 'http://feeds.feedburner.com/skai/ppGl'),
(u'\u0391\u03C5\u03C4\u03BF\u03BA\u03AF\u03BD\u03B7\u03C3\u03B7', 'http://feeds.feedburner.com/skai/HCCc'),
(u'\u03A0\u03B5\u03C1\u03B9\u03B2\u03AC\u03BB\u03BB\u03BF\u03BD', 'http://feeds.feedburner.com/skai/jVWs'),
(u'\u03A0\u03B1\u03C1\u03AC\u03BE\u03B5\u03BD\u03B1', 'http://feeds.feedburner.com/skai/bpAR')
]

39
recipes/tovima.recipe Normal file
View File

@ -0,0 +1,39 @@
from calibre.web.feeds.recipes import BasicNewsRecipe
class Tovima(BasicNewsRecipe):
title = 'To Vima'
__author__ = 'Stelios'
description = ' News from Greece'
#max_articles_per_feed = 100
oldest_article = 3
publisher = 'To Vima'
category = 'news, GR'
language = 'el'
encoding = 'utf8'
cover_url = 'http://www.tovima.gr/Themes/1/Default/Media/Home//small-n-short-logo.jpg'
no_stylesheets = True
use_embedded_content = False
remove_empty_feeds = True
extra_css = '''
.article_title{font-family :Arial,Helvetica,sans-serif; font-weight: bold; font-size:large;}
.article_text{font-family :Arial,Helvetica,sans-serif; font-size:x-small;}
'''
keep_only_tags = [
dict(name='div', attrs={'class' : ['article_title']}),
dict(name='div', attrs={'class' : ['article_text']})
]
remove_tags = [
dict(name='div', attrs={'class' : ['article_cat']})
]
feeds = [
(u'\u03C0\u03BF\u03BB\u03B9\u03C4\u03B9\u03BA\u03AE', 'http://www.tovima.gr/feed/politics/'),
(u'\u03BF\u03B9\u03BA\u03BF\u03BD\u03BF\u03BC\u03AF\u03B1', 'http://www.tovima.gr/feed/finance/'),
(u'\u03B3\u03BD\u03CE\u03BC\u03B5\u03C2', 'http://www.tovima.gr/feed/opinions/'),
(u'blogs', 'http://www.tovima.gr/feed/blogs/'),
(u'\u03BA\u03CC\u03C3\u03BC\u03BF\u03C2','http://www.tovima.gr/feed/world/'),
(u'science', 'http://www.tovima.gr/feed/science/'),
(u'\u03BA\u03BF\u03B9\u03BD\u03C9\u03BD\u03AF\u03B1', 'http://www.tovima.gr/feed/society/'),
(u'\u03C0\u03BF\u03BB\u03B9\u03C4\u03B9\u03C3\u03BC\u03CC\u03C2', 'http://www.tovima.gr/feed/culture/'),
(u'\u03B1\u03B8\u03BB\u03B7\u03C4\u03B9\u03C3\u03BC\u03CC\u03C2', 'http://www.tovima.gr/feed/sports/')
]

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2
# -*- coding: utf-8 mode: python -*-
__license__ = 'GPL v3'
@ -123,6 +123,9 @@ class ZeitEPUBAbo(BasicNewsRecipe):
# new login process
response = browser.open(url)
# Get rid of nested form
response.set_data(response.get_data().replace('<div><form action="/abo/zeit_digital?destination=node%2F94" accept-charset="UTF-8" method="post" id="user-login-form" class="zol_inlinelabel">', ''))
browser.set_response(response)
browser.select_form(nr=2)
browser.form['name']=self.username
browser.form['pass']=self.password
@ -178,7 +181,11 @@ class ZeitEPUBAbo(BasicNewsRecipe):
browser = self.get_browser()
# new login process
browser.open(url)
response=browser.open(url)
# Get rid of nested form
response.set_data(response.get_data().replace('<div><form action="/abo/zeit_digital?destination=node%2F94" accept-charset="UTF-8" method="post" id="user-login-form" class="zol_inlinelabel">', ''))
browser.set_response(response)
browser.select_form(nr=2)
browser.form['name']=self.username
browser.form['pass']=self.password
@ -211,4 +218,3 @@ class ZeitEPUBAbo(BasicNewsRecipe):
self.log.warning('Using static old low-res cover')
cover_url = 'http://images.zeit.de/bilder/titelseiten_zeit/1946/001_001.jpg'
return cover_url

12
recipes/zougla.recipe Normal file
View File

@ -0,0 +1,12 @@
from calibre.web.feeds.news import BasicNewsRecipe
class AdvancedUserRecipe1320264153(BasicNewsRecipe):
title = u'zougla'
__author__ = 'Stelios'
language = 'el'
oldest_article = 7
max_articles_per_feed = 100
auto_cleanup = True
feeds = [(u'zougla', u'http://www.zougla.gr/ArticleRss.xml')]

View File

@ -36,7 +36,8 @@ class ANDROID(USBMS):
0xca2 : [0x100, 0x0227, 0x0226, 0x222],
0xca3 : [0x100, 0x0227, 0x0226, 0x222],
0xca4 : [0x100, 0x0227, 0x0226, 0x222],
0xca9 : [0x100, 0x0227, 0x0226, 0x222]
0xca9 : [0x100, 0x0227, 0x0226, 0x222],
0xcac : [0x100, 0x0227, 0x0226, 0x222],
},
# Eken
@ -138,8 +139,12 @@ class ANDROID(USBMS):
# Advent
0x0955 : { 0x7100 : [0x9999] }, # This is the same as the Notion Ink Adam
# Kobo
0x2237: { 0x2208 : [0x0226] },
}
EBOOK_DIR_MAIN = ['eBooks/import', 'wordplayer/calibretransfer', 'Books']
EBOOK_DIR_MAIN = ['eBooks/import', 'wordplayer/calibretransfer', 'Books',
'sdcard/ebooks']
EXTRA_CUSTOMIZATION_MESSAGE = _('Comma separated list of directories to '
'send e-books to on the device. The first one that exists will '
'be used')
@ -149,7 +154,7 @@ class ANDROID(USBMS):
'GT-I5700', 'SAMSUNG', 'DELL', 'LINUX', 'GOOGLE', 'ARCHOS',
'TELECHIP', 'HUAWEI', 'T-MOBILE', 'SEMC', 'LGE', 'NVIDIA',
'GENERIC-', 'ZTE', 'MID', 'QUALCOMM', 'PANDIGIT', 'HYSTON',
'VIZIO', 'GOOGLE', 'FREESCAL']
'VIZIO', 'GOOGLE', 'FREESCAL', 'KOBO_INC']
WINDOWS_MAIN_MEM = ['ANDROID_PHONE', 'A855', 'A853', 'INC.NEXUS_ONE',
'__UMS_COMPOSITE', '_MB200', 'MASS_STORAGE', '_-_CARD', 'SGH-I897',
'GT-I9000', 'FILE-STOR_GADGET', 'SGH-T959', 'SAMSUNG_ANDROID',
@ -160,7 +165,8 @@ class ANDROID(USBMS):
'MB860', 'MULTI-CARD', 'MID7015A', 'INCREDIBLE', 'A7EB', 'STREAK',
'MB525', 'ANDROID2.3', 'SGH-I997', 'GT-I5800_CARD', 'MB612',
'GT-S5830_CARD', 'GT-S5570_CARD', 'MB870', 'MID7015A',
'ALPANDIGITAL', 'ANDROID_MID', 'VTAB1008', 'EMX51_BBG_ANDROI']
'ALPANDIGITAL', 'ANDROID_MID', 'VTAB1008', 'EMX51_BBG_ANDROI',
'UMS', '.K080']
WINDOWS_CARD_A_MEM = ['ANDROID_PHONE', 'GT-I9000_CARD', 'SGH-I897',
'FILE-STOR_GADGET', 'SGH-T959', 'SAMSUNG_ANDROID', 'GT-P1000_CARD',
'A70S', 'A101IT', '7', 'INCREDIBLE', 'A7EB', 'SGH-T849_CARD',

View File

@ -61,18 +61,25 @@ class KOBO(USBMS):
' ebook file itself. With this option, calibre will send a '
'separate cover image to the reader, useful if you '
'have modified the cover.'),
_('Upload Black and White Covers')
_('Upload Black and White Covers'),
_('Show expired books') +
':::'+_('A bug in an earlier version left non kepubs book records'
' in the datbase. With this option Calibre will show the '
'expired records and allow you to delete them with '
'the new delete logic.'),
]
EXTRA_CUSTOMIZATION_DEFAULT = [
', '.join(['tags']),
True,
True,
True
]
OPT_COLLECTIONS = 0
OPT_UPLOAD_COVERS = 1
OPT_UPLOAD_GRAYSCALE_COVERS = 2
OPT_SHOW_EXPIRED_BOOK_RECORDS = 3
def initialize(self):
USBMS.initialize(self)
@ -232,18 +239,23 @@ class KOBO(USBMS):
self.dbversion = result[0]
debug_print("Database Version: ", self.dbversion)
opts = self.settings()
if self.dbversion >= 16:
query= 'select Title, Attribution, DateCreated, ContentID, MimeType, ContentType, ' \
query= ('select Title, Attribution, DateCreated, ContentID, MimeType, ContentType, ' \
'ImageID, ReadStatus, ___ExpirationStatus, FavouritesIndex, Accessibility from content where ' \
'BookID is Null and ( ___ExpirationStatus <> "3" or ___ExpirationStatus is Null)'
'BookID is Null and not ((___ExpirationStatus=3 or ___ExpirationStatus is Null) %(expiry)s') % dict(expiry=' and ContentType = 6)' \
if opts.extra_customization[self.OPT_SHOW_EXPIRED_BOOK_RECORDS] else ')')
elif self.dbversion < 16 and self.dbversion >= 14:
query= 'select Title, Attribution, DateCreated, ContentID, MimeType, ContentType, ' \
query= ('select Title, Attribution, DateCreated, ContentID, MimeType, ContentType, ' \
'ImageID, ReadStatus, ___ExpirationStatus, FavouritesIndex, "-1" as Accessibility from content where ' \
'BookID is Null and ( ___ExpirationStatus <> "3" or ___ExpirationStatus is Null)'
'BookID is Null and not ((___ExpirationStatus=3 or ___ExpirationStatus is Null) %(expiry)s') % dict(expiry=' and ContentType = 6)' \
if opts.extra_customization[self.OPT_SHOW_EXPIRED_BOOK_RECORDS] else ')')
elif self.dbversion < 14 and self.dbversion >= 8:
query= 'select Title, Attribution, DateCreated, ContentID, MimeType, ContentType, ' \
query= ('select Title, Attribution, DateCreated, ContentID, MimeType, ContentType, ' \
'ImageID, ReadStatus, ___ExpirationStatus, "-1" as FavouritesIndex, "-1" as Accessibility from content where ' \
'BookID is Null and ( ___ExpirationStatus <> "3" or ___ExpirationStatus is Null)'
'BookID is Null and not ((___ExpirationStatus=3 or ___ExpirationStatus is Null) %(expiry)s') % dict(expiry=' and ContentType = 6)' \
if opts.extra_customization[self.OPT_SHOW_EXPIRED_BOOK_RECORDS] else ')')
else:
query= 'select Title, Attribution, DateCreated, ContentID, MimeType, ContentType, ' \
'ImageID, ReadStatus, "-1" as ___ExpirationStatus, "-1" as FavouritesIndex, "-1" as Accessibility from content where BookID is Null'
@ -343,21 +355,23 @@ class KOBO(USBMS):
# Kobo does not delete the Book row (ie the row where the BookID is Null)
# The next server sync should remove the row
cursor.execute('delete from content where BookID = ?', t)
try:
cursor.execute('update content set ReadStatus=0, FirstTimeReading = \'true\', ___PercentRead=0, ___ExpirationStatus=3 ' \
'where BookID is Null and ContentID =?',t)
except Exception as e:
if 'no such column' not in str(e):
raise
if ContentType == 6:
try:
cursor.execute('update content set ReadStatus=0, FirstTimeReading = \'true\', ___PercentRead=0 ' \
cursor.execute('update content set ReadStatus=0, FirstTimeReading = \'true\', ___PercentRead=0, ___ExpirationStatus=3 ' \
'where BookID is Null and ContentID =?',t)
except Exception as e:
if 'no such column' not in str(e):
raise
cursor.execute('update content set ReadStatus=0, FirstTimeReading = \'true\' ' \
'where BookID is Null and ContentID =?',t)
try:
cursor.execute('update content set ReadStatus=0, FirstTimeReading = \'true\', ___PercentRead=0 ' \
'where BookID is Null and ContentID =?',t)
except Exception as e:
if 'no such column' not in str(e):
raise
cursor.execute('update content set ReadStatus=0, FirstTimeReading = \'true\' ' \
'where BookID is Null and ContentID =?',t)
else:
cursor.execute('delete from content where BookID is Null and ContentID =?',t)
connection.commit()

View File

@ -1,3 +1,4 @@
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
@ -7,8 +8,11 @@
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <strings.h>
#define MARKER ".created_by_calibre_mount_helper"
#define DEV "/dev/"
#define MEDIA "/media/"
#define False 0
#define True 1
@ -33,6 +37,20 @@ void ensure_root() {
}
}
void check_mount_point(const char *mp) {
if (mp == NULL || strlen(mp) < strlen(MEDIA)) {
fprintf(stderr, "Invalid arguments\n");
exit(EXIT_FAILURE);
}
if (strncmp(MEDIA, mp, strlen(MEDIA)) != 0) {
fprintf(stderr, "Trying to operate on a mount point not under /media is not allowed\n");
exit(EXIT_FAILURE);
}
}
int do_mount(const char *dev, const char *mp) {
char options[1000], marker[2000];
#ifdef __NetBSD__
@ -44,12 +62,24 @@ int do_mount(const char *dev, const char *mp) {
fprintf(stderr, "Specified device node does not exist\n");
return EXIT_FAILURE;
}
if (!exists(mp)) {
if (mkdir(mp, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) != 0) {
errsv = errno;
fprintf(stderr, "Failed to create mount point with error: %s\n", strerror(errsv));
}
}
/* only mount if mp is under /media */
mp = realpath(mp, NULL);
if (mp == NULL) {
fprintf(stderr, "realpath on mp failed.\n");
exit(EXIT_FAILURE);
}
if (strncmp(MEDIA, mp, strlen(MEDIA)) != 0) {
fprintf(stderr, "mount point is not under /media\n");
exit(EXIT_FAILURE);
}
snprintf(marker, 2000, "%s/%s", mp, MARKER);
if (!exists(marker)) {
int fd = creat(marker, S_IRUSR|S_IWUSR);
@ -195,10 +225,42 @@ int cleanup(const char *dev, const char *mp) {
return cleanup_mount_point(mp);
}
void check_dev(const char *dev) {
struct stat file_info;
if (dev == NULL || strlen(dev) < strlen(DEV)) {
fprintf(stderr, "Invalid arguments\n");
exit(EXIT_FAILURE);
}
if (strncmp(DEV, dev, strlen(DEV)) != 0) {
fprintf(stderr, "Trying to operate on a dev node not under /dev\n");
exit(EXIT_FAILURE);
}
if (stat(dev, &file_info) != 0) {
fprintf(stderr, "stat call on dev node failed\n");
exit(EXIT_FAILURE);
}
if (strstr(dev, "/shm/") != NULL) {
fprintf(stderr, "naughty, naughty!\n");
exit(EXIT_FAILURE);
}
if (!S_ISBLK(file_info.st_mode)) {
fprintf(stderr, "dev node is not a block device\n");
exit(EXIT_FAILURE);
}
}
int main(int argc, char** argv)
{
char *action, *dev, *mp;
char *action, *dev, *mp, *temp;
int status = EXIT_FAILURE;
exit(EXIT_FAILURE);
/*printf("Real UID\t= %d\n", getuid());
printf("Effective UID\t= %d\n", geteuid());
@ -211,11 +273,46 @@ int main(int argc, char** argv)
}
action = argv[1]; dev = argv[2]; mp = argv[3];
/* Ensure that PATH only contains system directories to prevent execution of
arbitrary executables as root */
if (setenv("PATH",
"/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin\0",
1) != 0) {
fprintf(stderr, "Failed to restrict PATH env var, aborting.\n");
exit(EXIT_FAILURE);
}
if (strncmp(action, "mount", 5) == 0) {
dev = realpath(argv[2], NULL);
if (dev == NULL) {
fprintf(stderr, "Failed to resolve device node.\n");
exit(EXIT_FAILURE);
}
mp = get_real_mount_point(mp);
check_dev(dev); check_mount_point(mp);
status = do_mount(dev, mp);
} else if (strncmp(action, "eject", 5) == 0) {
dev = realpath(argv[2], NULL);
if (dev == NULL) {
fprintf(stderr, "Failed to resolve device node.\n");
exit(EXIT_FAILURE);
}
temp = realpath(mp, NULL);
if (temp == NULL) {
fprintf(stderr, "Mount point does not exist\n");
exit(EXIT_FAILURE);
}
chdir(temp);
check_dev(dev); check_mount_point(mp);
status = do_eject(dev, mp);
} else if (strncmp(action, "cleanup", 7) == 0) {
temp = realpath(mp, NULL);
if (temp == NULL) {
fprintf(stderr, "Mount point does not exist\n");
exit(EXIT_FAILURE);
}
mp = temp;
check_mount_point(mp);
status = cleanup(dev, mp);
} else {
fprintf(stderr, "Unrecognized action: must be mount, eject or cleanup\n");

View File

@ -560,14 +560,21 @@ class PRST1(USBMS):
cursor = connection.cursor()
periodical_schema = \
"'http://xmlns.sony.net/e-book/prs/periodicals/1.0/newspaper/1.0'"
# Setting this to the SONY periodical schema apparently causes errors
# with some periodicals, therefore set it to null, since the special
# periodical navigation doesn't work anyway.
periodical_schema = 'null'
query = '''
UPDATE books
SET conforms_to = 'http://xmlns.sony.net/e-book/prs/periodicals/1.0/newspaper/1.0',
SET conforms_to = %s,
periodical_name = ?,
description = ?,
publication_date = ?
WHERE _id = ?
'''
'''%periodical_schema
t = (name, None, pubdate, book.bookId,)
cursor.execute(query, t)

View File

@ -622,8 +622,11 @@ class Device(DeviceConfig, DevicePlugin):
if getattr(sys, 'frozen', False):
cmd = os.path.join(sys.executables_location, 'bin', cmd)
cmd = [cmd, 'mount']
mlabel = label
if mlabel.endswith('/'):
mlabel = mlabel[:-1]
try:
p = subprocess.Popen(cmd + [node, '/media/'+label])
p = subprocess.Popen(cmd + [node, '/media/'+mlabel])
except OSError:
raise DeviceError(
_('Could not find mount helper: %s.')%cmd[0])
@ -777,9 +780,12 @@ class Device(DeviceConfig, DevicePlugin):
# try all the nodes to see what we can mount
for dev in devs[i].split():
mp='/media/'+label+'-'+dev
mmp = mp
if mmp.endswith('/'):
mmp = mmp[:-1]
#print "trying ", dev, "on", mp
try:
p = subprocess.Popen(cmd + ["/dev/"+dev, mp])
p = subprocess.Popen(cmd + ["/dev/"+dev, mmp])
except OSError:
raise DeviceError(_('Could not find mount helper: %s.')%cmd[0])
while p.poll() is None:

View File

@ -109,14 +109,16 @@ class HTMLFile(object):
try:
with open(self.path, 'rb') as f:
src = f.read()
src = f.read(4096)
self.is_binary = level > 0 and not bool(self.HTML_PAT.search(src))
if not self.is_binary:
src += f.read()
except IOError as err:
msg = 'Could not read from file: %s with error: %s'%(self.path, as_unicode(err))
if level == 0:
raise IOError(msg)
raise IgnoreFile(msg, err.errno)
self.is_binary = level > 0 and not bool(self.HTML_PAT.search(src[:4096]))
if not self.is_binary:
if not encoding:
encoding = xml_to_unicode(src[:4096], verbose=verbose)[-1]

View File

@ -116,10 +116,14 @@ def title_sort(title, order=None):
title = title[1:]
match = _title_pat.search(title)
if match:
prep = match.group(1)
title = title[len(prep):] + ', ' + prep
if title[0] in _ignore_starts:
title = title[1:]
try:
prep = match.group(1)
except IndexError:
pass
else:
title = title[len(prep):] + ', ' + prep
if title[0] in _ignore_starts:
title = title[1:]
return title.strip()
coding = zip(

View File

@ -15,7 +15,6 @@ from calibre.customize.conversion import OutputFormatPlugin, \
OptionRecommendation
from calibre.ebooks.metadata.opf2 import OPF
from calibre.ptempfile import TemporaryDirectory
from calibre.ebooks.pdf.writer import PDFWriter, ImagePDFWriter, PDFMetadata
from calibre.ebooks.pdf.pageoptions import UNITS, PAPER_SIZES, \
ORIENTATIONS
@ -90,6 +89,7 @@ class PDFOutput(OutputFormatPlugin):
self.convert_text(oeb_book)
def convert_images(self, images):
from calibre.ebooks.pdf.writer import ImagePDFWriter
self.write(ImagePDFWriter, images)
def get_cover_data(self):
@ -105,6 +105,7 @@ class PDFOutput(OutputFormatPlugin):
self.cover_data = None
def convert_text(self, oeb_book):
from calibre.ebooks.pdf.writer import PDFWriter
self.log.debug('Serializing oeb input to disk for processing...')
self.get_cover_data()
@ -119,6 +120,7 @@ class PDFOutput(OutputFormatPlugin):
self.write(PDFWriter, [s.path for s in opf.spine])
def write(self, Writer, items):
from calibre.ebooks.pdf.writer import PDFMetadata
writer = Writer(self.opts, self.log, cover_data=self.cover_data)
close = False

View File

@ -587,7 +587,6 @@ class CoversModel(QAbstractListModel): # {{{
return 1
return pmap.width()*pmap.height()
def clear_failed(self):
good = []
pmap = {}
@ -729,7 +728,8 @@ class CoversWidget(QWidget): # {{{
except Empty:
break
self.covers_view.clear_failed()
if self.continue_processing:
self.covers_view.clear_failed()
if self.worker.error is not None:
error_dialog(self, _('Download failed'),
@ -759,7 +759,7 @@ class CoversWidget(QWidget): # {{{
self.continue_processing = False
def cancel(self):
self.continue_processing = False
self.cleanup()
self.abort.set()
def cover_pixmap(self):

View File

@ -146,9 +146,12 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
r('default_author_link', gprefs)
choices = set([k for k in db.field_metadata.all_field_keys()
if db.field_metadata[k]['is_category'] and
if (db.field_metadata[k]['is_category'] and
(db.field_metadata[k]['datatype'] in ['text', 'series', 'enumeration']) and
not db.field_metadata[k]['display'].get('is_names', False)])
not db.field_metadata[k]['display'].get('is_names', False))
or
(db.field_metadata[k]['datatype'] in ['composite'] and
db.field_metadata[k]['display'].get('make_category', False))])
choices -= set(['authors', 'publisher', 'formats', 'news', 'identifiers'])
choices |= set(['search'])
self.opt_categories_using_hierarchy.update_items_cache(choices)

View File

@ -156,7 +156,7 @@ def build_index(books, num, search, sort, order, start, total, url_base, CKEYS,
body.append(HR())
body.append(DIV(
A(_('Switch to the full interface (non-mobile interface)'),
href="/browse",
href=prefix+"/browse",
style="text-decoration: none; color: blue",
title=_('The full interface gives you many more features, '
'but it may not work well on a small screen')),

View File

@ -258,6 +258,14 @@ The following functions are available in addition to those described in single-f
MMMM : the long localized month name (e.g. "January" to "December").
yy : the year as two digit number (00 to 99).
yyyy : the year as four digit number.
h : the hours without a leading 0 (0 to 11 or 0 to 23, depending on am/pm)
hh : the hours with a leading 0 (00 to 11 or 00 to 23, depending on am/pm)
m : the minutes without a leading 0 (0 to 59)
mm : the minutes with a leading 0 (00 to 59)
s : the seconds without a leading 0 (0 to 59)
ss : the seconds with a leading 0 (00 to 59)
ap : use a 12-hour clock instead of a 24-hour clock, with 'ap' replaced by the localized string for am or pm.
AP : use a 12-hour clock instead of a 24-hour clock, with 'AP' replaced by the localized string for AM or PM.
iso : the date with time and timezone. Must be the only format present.
* ``eval(string)`` -- evaluates the string as a program, passing the local variables (those ``assign`` ed to). This permits using the template processor to construct complex results from local variables.

View File

@ -194,4 +194,8 @@ class SpooledTemporaryFile(tempfile.SpooledTemporaryFile):
tempfile.SpooledTemporaryFile.__init__(self, max_size=max_size, suffix=suffix,
prefix=prefix, dir=dir, mode=mode, bufsize=bufsize)
def better_mktemp(*args, **kwargs):
fd, path = tempfile.mkstemp(*args, **kwargs)
os.close(fd)
return path

View File

@ -170,11 +170,37 @@ def format_date(dt, format, assume_utc=False, as_utc=False):
if format == 'iso':
return isoformat(dt, assume_utc=assume_utc, as_utc=as_utc)
ampm = 'ap' in format.lower()
if dt == UNDEFINED_DATE:
return ''
strf = partial(strftime, t=dt.timetuple())
def format_hour(hr):
l = len(hr)
h = dt.hour
if ampm:
h = h%12
if l == 1: return '%d'%h
return '%02d'%h
def format_minute(min):
l = len(min)
if l == 1: return '%d'%dt.minute
return '%02d'%dt.minute
def format_second(min):
l = len(min)
if l == 1: return '%d'%dt.second
return '%02d'%dt.second
def format_ampm(ap):
res = strf('%p')
if ap == 'AP':
return res
return res.lower()
def format_day(dy):
l = len(dy)
if l == 1: return '%d'%dt.day
@ -193,17 +219,25 @@ def format_date(dt, format, assume_utc=False, as_utc=False):
if len(yr) == 2: return '%02d'%(dt.year % 100)
return '%04d'%dt.year
function_index = {
'd': format_day,
'M': format_month,
'y': format_year,
'h': format_hour,
'm': format_minute,
's': format_second,
'a': format_ampm,
'A': format_ampm,
}
def repl_func(mo):
s = mo.group(0)
if s is None:
return ''
if s[0] == 'd':
return format_day(s)
if s[0] == 'M':
return format_month(s)
return format_year(s)
return function_index[s[0]](s)
return re.sub('(d{1,4}|M{1,4}|(?:yyyy|yy))', repl_func, format)
return re.sub(
'(s{1,2})|(m{1,2})|(h{1,2})|(ap)|(AP)|(d{1,4}|M{1,4}|(?:yyyy|yy))',
repl_func, format)
def replace_months(datestr, clang):
# Replace months by english equivalent for parse_date

View File

@ -747,6 +747,14 @@ class BuiltinFormatDate(BuiltinFormatterFunction):
'MMMM : the long localized month name (e.g. "January" to "December"). '
'yy : the year as two digit number (00 to 99). '
'yyyy : the year as four digit number. '
'h : the hours without a leading 0 (0 to 11 or 0 to 23, depending on am/pm) '
'hh : the hours with a leading 0 (00 to 11 or 00 to 23, depending on am/pm) '
'm : the minutes without a leading 0 (0 to 59) '
'mm : the minutes with a leading 0 (00 to 59) '
's : the seconds without a leading 0 (0 to 59) '
'ss : the seconds with a leading 0 (00 to 59) '
'ap : use a 12-hour clock instead of a 24-hour clock, with "ap" replaced by the localized string for am or pm '
'AP : use a 12-hour clock instead of a 24-hour clock, with "AP" replaced by the localized string for AM or PM '
'iso : the date with time and timezone. Must be the only format present')
def evaluate(self, formatter, kwargs, mi, locals, val, format_string):

View File

@ -121,7 +121,7 @@ _extra_lang_codes = {
'en_TH' : _('English (Thailand)'),
'en_TR' : _('English (Turkey)'),
'en_CY' : _('English (Cyprus)'),
'en_CZ' : _('English (Czechoslovakia)'),
'en_CZ' : _('English (Czech Republic)'),
'en_PK' : _('English (Pakistan)'),
'en_HR' : _('English (Croatia)'),
'en_ID' : _('English (Indonesia)'),