88
88
def get_builtin_recipe_collection():
89
89
return etree.parse(P('builtin_recipes.xml')).getroot()
91
def get_custom_recipe_collection(db):
92
from calibre.web.feeds.recipes import compile_recipe
91
def get_custom_recipe_collection(*args):
92
from calibre.web.feeds.recipes import compile_recipe, \
94
bdir = os.path.dirname(custom_recipes.file_path)
94
for id, title, recipe in db.get_custom_recipes():
96
for id_, x in custom_recipes.iteritems():
98
recipe = os.path.join(bdir, fname)
100
recipe = open(recipe, 'rb').read().decode('utf-8')
96
101
recipe_class = compile_recipe(recipe)
97
102
if recipe_class is not None:
98
rmap['custom:%d'%id] = recipe_class
103
rmap['custom:%s'%id_] = recipe_class
106
traceback.print_exc()
102
108
return etree.fromstring(serialize_collection(rmap))
111
def update_custom_recipe(id_, title, script):
112
from calibre.web.feeds.recipes import custom_recipes, \
113
custom_recipe_filename
115
existing = custom_recipes.get(id_, None)
116
bdir = os.path.dirname(custom_recipes.file_path)
119
fname = custom_recipe_filename(id_, title)
122
if isinstance(script, unicode):
123
script = script.encode('utf-8')
125
custom_recipes[id_] = (title, fname)
127
with open(os.path.join(bdir, fname), 'wb') as f:
131
def add_custom_recipe(title, script):
132
from calibre.web.feeds.recipes import custom_recipes, \
133
custom_recipe_filename
135
keys = tuple(map(int, custom_recipes.iterkeys()))
139
bdir = os.path.dirname(custom_recipes.file_path)
141
fname = custom_recipe_filename(id_, title)
142
if isinstance(script, unicode):
143
script = script.encode('utf-8')
145
custom_recipes[id_] = (title, fname)
147
with open(os.path.join(bdir, fname), 'wb') as f:
151
def remove_custom_recipe(id_):
152
from calibre.web.feeds.recipes import custom_recipes
154
existing = custom_recipes.get(id_, None)
155
if existing is not None:
156
bdir = os.path.dirname(custom_recipes.file_path)
158
del custom_recipes[id_]
160
os.remove(os.path.join(bdir, fname))
164
def get_custom_recipe(id_):
165
from calibre.web.feeds.recipes import custom_recipes
167
existing = custom_recipes.get(id_, None)
168
if existing is not None:
169
bdir = os.path.dirname(custom_recipes.file_path)
171
with open(os.path.join(bdir, fname), 'rb') as f:
172
return f.read().decode('utf-8')
104
174
def get_builtin_recipe_titles():
105
175
return [r.get('title') for r in get_builtin_recipe_collection()]
201
271
self.root.append(sr)
202
272
self.write_scheduler_file()
204
def customize_recipe(self, urn, add_title_tag, custom_tags):
274
# 'keep_issues' argument for recipe-specific number of copies to keep
275
def customize_recipe(self, urn, add_title_tag, custom_tags, keep_issues):
206
277
for x in list(self.iter_customization()):
207
278
if x.get('id') == urn:
208
279
self.root.remove(x)
209
280
cs = E.recipe_customization({
281
'keep_issues' : keep_issues,
211
283
'add_title_tag' : 'yes' if add_title_tag else 'no',
212
284
'custom_tags' : ','.join(custom_tags),
262
335
def serialize_schedule(self, typ, schedule):
263
336
s = E.schedule({'type':typ})
264
337
if typ == 'interval':
267
340
text = '%f'%schedule
268
341
elif typ == 'day/time':
269
342
text = '%d:%d:%d'%schedule
343
elif typ in ('days_of_week', 'days_of_month'):
344
dw = ','.join(map(str, map(int, schedule[0])))
345
text = '%s:%d:%d'%(dw, schedule[1], schedule[2])
347
raise ValueError('Unknown schedule type: %r'%typ)
279
357
elif typ == 'day/time':
280
358
sch = list(map(int, sch.split(':')))
359
elif typ in ('days_of_week', 'days_of_month'):
360
parts = sch.split(':')
361
days = list(map(int, [x.strip() for x in
362
parts[0].split(',')]))
363
sch = [days, int(parts[1]), int(parts[2])]
281
364
return typ, sch, parse_date(recipe.get('last_downloaded'))
283
366
def recipe_needs_to_be_downloaded(self, recipe):
285
368
typ, sch, ld = self.un_serialize_schedule(recipe)
372
def is_time(now, hour, minute):
373
return now.hour > hour or \
374
(now.hour == hour and now.minute >= minute)
376
def is_weekday(day, now):
377
return day < 0 or day > 6 or \
378
day == calendar.weekday(now.year, now.month, now.day)
380
def was_downloaded_already_today(ld_local, now):
381
return ld_local.date() == now.date()
288
383
if typ == 'interval':
289
384
return utcnow() - ld > timedelta(sch)
290
385
elif typ == 'day/time':
292
387
ld_local = ld.astimezone(tzlocal())
293
388
day, hour, minute = sch
389
return is_weekday(day, now) and \
390
not was_downloaded_already_today(ld_local, now) and \
391
is_time(now, hour, minute)
392
elif typ == 'days_of_week':
394
ld_local = ld.astimezone(tzlocal())
395
days, hour, minute = sch
398
if is_weekday(day, now):
401
return have_day and \
402
not was_downloaded_already_today(ld_local, now) and \
403
is_time(now, hour, minute)
404
elif typ == 'days_of_month':
406
ld_local = ld.astimezone(tzlocal())
407
days, hour, minute = sch
408
have_day = now.day in days
409
return have_day and \
410
not was_downloaded_already_today(ld_local, now) and \
411
is_time(now, hour, minute)
295
is_today = day < 0 or day > 6 or \
296
day == calendar.weekday(now.year, now.month, now.day)
297
is_time = now.hour > hour or \
298
(now.hour == hour and now.minute >= minute)
299
was_downloaded_already_today = ld_local.date() == now.date()
300
return is_today and not was_downloaded_already_today and is_time
303
415
def set_account_info(self, urn, un, pw):
317
429
return x.get('username', ''), x.get('password', '')
319
431
def get_customize_info(self, urn):
320
433
add_title_tag = True
323
436
for x in self.iter_customization():
324
437
if x.get('id', False) == urn:
438
keep_issues = x.get('keep_issues', '0')
325
439
add_title_tag = x.get('add_title_tag', 'yes') == 'yes'
326
440
custom_tags = [i.strip() for i in x.get('custom_tags',
329
return add_title_tag, custom_tags
443
return add_title_tag, custom_tags, keep_issues
331
445
def get_schedule_info(self, urn):