~stub/ubuntu/precise/calibre/devel

« back to all changes in this revision

Viewing changes to src/calibre/web/feeds/recipes/collection.py

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2011-04-12 11:29:25 UTC
  • mfrom: (42.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20110412112925-c7171kt2bb5rmft4
Tags: 0.7.50+dfsg-2
* debian/control: Build with libpodofo-dev to enable PDF metadata.
  (Closes: #619632)
* debian/control: Add libboost1.42-dev build dependency. Apparently it is
  needed in some setups. (Closes: #619807)
* debian/rules: Call dh_sip to generate a proper sip API dependency, to
  prevent crashes like #616372 for partial upgrades.
* debian/control: Bump python-qt4 dependency to >= 4.8.3-2, which reportedly
  fixes crashes on startup. (Closes: #619701, #620125)

Show diffs side-by-side

added added

removed removed

Lines of Context:
88
88
def get_builtin_recipe_collection():
89
89
    return etree.parse(P('builtin_recipes.xml')).getroot()
90
90
 
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, \
 
93
            custom_recipes
 
94
    bdir = os.path.dirname(custom_recipes.file_path)
93
95
    rmap = {}
94
 
    for id, title, recipe in db.get_custom_recipes():
 
96
    for id_, x in custom_recipes.iteritems():
 
97
        title, fname = x
 
98
        recipe = os.path.join(bdir, fname)
95
99
        try:
 
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
99
104
        except:
 
105
            import traceback
 
106
            traceback.print_exc()
100
107
            continue
101
 
 
102
108
    return etree.fromstring(serialize_collection(rmap))
103
109
 
 
110
 
 
111
def update_custom_recipe(id_, title, script):
 
112
    from calibre.web.feeds.recipes import custom_recipes, \
 
113
            custom_recipe_filename
 
114
    id_ = str(int(id_))
 
115
    existing = custom_recipes.get(id_, None)
 
116
    bdir = os.path.dirname(custom_recipes.file_path)
 
117
 
 
118
    if existing is None:
 
119
        fname = custom_recipe_filename(id_, title)
 
120
    else:
 
121
        fname = existing[1]
 
122
    if isinstance(script, unicode):
 
123
        script = script.encode('utf-8')
 
124
 
 
125
    custom_recipes[id_] = (title, fname)
 
126
 
 
127
    with open(os.path.join(bdir, fname), 'wb') as f:
 
128
        f.write(script)
 
129
 
 
130
 
 
131
def add_custom_recipe(title, script):
 
132
    from calibre.web.feeds.recipes import custom_recipes, \
 
133
            custom_recipe_filename
 
134
    id_ = 1000
 
135
    keys = tuple(map(int, custom_recipes.iterkeys()))
 
136
    if keys:
 
137
        id_ = max(keys)+1
 
138
    id_ = str(id_)
 
139
    bdir = os.path.dirname(custom_recipes.file_path)
 
140
 
 
141
    fname = custom_recipe_filename(id_, title)
 
142
    if isinstance(script, unicode):
 
143
        script = script.encode('utf-8')
 
144
 
 
145
    custom_recipes[id_] = (title, fname)
 
146
 
 
147
    with open(os.path.join(bdir, fname), 'wb') as f:
 
148
        f.write(script)
 
149
 
 
150
 
 
151
def remove_custom_recipe(id_):
 
152
    from calibre.web.feeds.recipes import custom_recipes
 
153
    id_ = str(int(id_))
 
154
    existing = custom_recipes.get(id_, None)
 
155
    if existing is not None:
 
156
        bdir = os.path.dirname(custom_recipes.file_path)
 
157
        fname = existing[1]
 
158
        del custom_recipes[id_]
 
159
        try:
 
160
            os.remove(os.path.join(bdir, fname))
 
161
        except:
 
162
            pass
 
163
 
 
164
def get_custom_recipe(id_):
 
165
    from calibre.web.feeds.recipes import custom_recipes
 
166
    id_ = str(int(id_))
 
167
    existing = custom_recipes.get(id_, None)
 
168
    if existing is not None:
 
169
        bdir = os.path.dirname(custom_recipes.file_path)
 
170
        fname = existing[1]
 
171
        with open(os.path.join(bdir, fname), 'rb') as f:
 
172
            return f.read().decode('utf-8')
 
173
 
104
174
def get_builtin_recipe_titles():
105
175
    return [r.get('title') for r in get_builtin_recipe_collection()]
106
176
 
201
271
            self.root.append(sr)
202
272
            self.write_scheduler_file()
203
273
 
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):
205
276
        with self.lock:
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,
210
282
                'id' : urn,
211
283
                'add_title_tag' : 'yes' if add_title_tag else 'no',
212
284
                'custom_tags' : ','.join(custom_tags),
229
301
                if x.get('id', False) == recipe_id:
230
302
                    typ, sch, last_downloaded = self.un_serialize_schedule(x)
231
303
                    if typ == 'interval':
 
304
                        # Prevent downloads more frequent than once an hour
232
305
                        actual_interval = now - last_downloaded
233
306
                        nominal_interval = timedelta(days=sch)
234
307
                        if abs(actual_interval - nominal_interval) < \
262
335
    def serialize_schedule(self, typ, schedule):
263
336
        s = E.schedule({'type':typ})
264
337
        if typ == 'interval':
265
 
            if schedule < 0.1:
266
 
                schedule = 1/24.
 
338
            if schedule < 0.04:
 
339
                schedule = 0.04
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])
 
346
        else:
 
347
            raise ValueError('Unknown schedule type: %r'%typ)
270
348
        s.text = text
271
349
        return s
272
350
 
278
356
                    sch = float(sch)
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'))
282
365
 
283
366
    def recipe_needs_to_be_downloaded(self, recipe):
285
368
            typ, sch, ld = self.un_serialize_schedule(recipe)
286
369
        except:
287
370
            return False
 
371
 
 
372
        def is_time(now, hour, minute):
 
373
            return now.hour > hour or \
 
374
                    (now.hour == hour and now.minute >= minute)
 
375
 
 
376
        def is_weekday(day, now):
 
377
            return day < 0 or day > 6 or \
 
378
                    day == calendar.weekday(now.year, now.month, now.day)
 
379
 
 
380
        def was_downloaded_already_today(ld_local, now):
 
381
            return ld_local.date() == now.date()
 
382
 
288
383
        if typ == 'interval':
289
384
            return utcnow() - ld > timedelta(sch)
290
385
        elif typ == 'day/time':
291
386
            now = nowf()
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':
 
393
            now = nowf()
 
394
            ld_local = ld.astimezone(tzlocal())
 
395
            days, hour, minute = sch
 
396
            have_day = False
 
397
            for day in days:
 
398
                if is_weekday(day, now):
 
399
                    have_day = True
 
400
                    break
 
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':
 
405
            now = nowf()
 
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)
294
412
 
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
301
413
        return False
302
414
 
303
415
    def set_account_info(self, urn, un, pw):
317
429
                    return x.get('username', ''), x.get('password', '')
318
430
 
319
431
    def get_customize_info(self, urn):
 
432
        keep_issues = 0
320
433
        add_title_tag = True
321
434
        custom_tags = []
322
435
        with self.lock:
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',
327
441
                        '').split(',')]
328
442
                    break
329
 
        return add_title_tag, custom_tags
 
443
        return add_title_tag, custom_tags, keep_issues
330
444
 
331
445
    def get_schedule_info(self, urn):
332
446
        with self.lock: