diff --git a/recipes/vanityfair.recipe b/recipes/vanityfair.recipe new file mode 100644 index 0000000000..61ec76e003 --- /dev/null +++ b/recipes/vanityfair.recipe @@ -0,0 +1,98 @@ +from datetime import date +import re +from calibre.web.feeds.news import BasicNewsRecipe + +class VanityFair(BasicNewsRecipe): + title = u"Vanity Fair" + description = 'Vanity Fair Magazine (U.S.)' + language = 'en' + __author__ = 'Barty' + max_articles_per_feed = 100 + no_stylesheets = False + auto_cleanup = False + timefmt = ' [%B %Y]' + oldest_article = 365 + + masthead_url = 'http://www.vanityfair.com/etc/designs/vanityfair/images/shell/print-logo.png' + + INDEX = 'http://www.vanityfair.com' + CATEGORIES = [ + # comment out categories you don't want + # (user friendly name, url suffix, max number of articles to load) + ('Hollywood','hollywood',10), + ('Culture','culture',10), + ('Business','business',10), + ('Politics','politics',10), + ('Society','society',10), + ('Style','style',10), + ('VF Daily','online/daily',10), + ("James Wolcott's Blog",'online/wolcott',10), + ("The Oscars",'online/oscars',10), + ] + # set this to False if you don't want to put the first article + # that appears in each section to a "Featured" section + FEATURED_CAT = True + + + remove_tags = [ + {'name':['nav']}, + {'class':re.compile(r'_(header|rubric|share|subnav|leaderboard)|comments-count|ecom_placement')} + ] + remove_tags_after = [{'class':'cn_blogpost'},{'id':'wrapper'}] + + def parse_index(self): + self.cover_url = 'http://www.vanityfair.com/magazine/toc/contents-%s/_jcr_content/par/cn_contentwell/par-main/cn_pagination_contai/cn_image.size.cover_vanityfair_300.jpg' % (date.today().strftime('%Y%m')) + feeds = [] + seen_urls = set([]) + features = [] + + for category in self.CATEGORIES: + + (cat_name, tag, max_articles) = category + self.log('Reading category:', cat_name) + articles = [] + + page = "%s/%s" % (self.INDEX, tag) + soup = self.index_to_soup(page) + headers = soup.findAll(attrs={'class':'headline '}) + add_featured = self.FEATURED_CAT + + for header in headers: + self.log(self.tag_to_string(header)) + atags = header.findAll('a') + # if there's more than one a tag, it's some kind of list, skip + if not atags or len(atags)>1: + continue + atag = atags[0] + url = atag['href'] + if url.startswith('/'): + url = self.INDEX + url + if url in seen_urls: + continue + seen_urls.add(url) + title = self.tag_to_string(atag) + self.log('\tFound article:', title) + self.log('\t', url) + par = header.findParent('article') if tag.startswith('online/') else header.findParent('section') + if par is not None: + desc = par.find(attrs={'class':'body '}) + desc = self.tag_to_string(desc) if desc else '' + #self.log('\t', desc) + if add_featured: + features.append({'title':title,'url':url,'description':desc}) + add_featured = False + else: + articles.append({'title':title,'url':url,'description':desc}) + if len(articles) >= max_articles: + break + + if articles: + feeds.append((cat_name, articles)) + + if features: + feeds.insert(0,('Featured', features)) + + return feeds + + def print_version(self, url): + return url.replace('.html', '.print') diff --git a/src/calibre/devices/__init__.py b/src/calibre/devices/__init__.py index e47cd82b50..dce04034c8 100644 --- a/src/calibre/devices/__init__.py +++ b/src/calibre/devices/__init__.py @@ -39,15 +39,15 @@ def get_connected_device(): if ok: dev = d dev.reset(log_packets=False, detected_device=det) - connected_devices.append(dev) + connected_devices.append((det, dev)) if dev is None: print >>sys.stderr, 'Unable to find a connected ebook reader.' return - for d in connected_devices: + for det, d in connected_devices: try: - d.open(None) + d.open(det, None) except: continue else: @@ -121,7 +121,7 @@ def debug(ioreg_to_tmp=False, buf=None): out('Trying to open', dev.name, '...', end=' ') try: dev.reset(detected_device=det) - dev.open(None) + dev.open(det, None) out('OK') except: import traceback diff --git a/src/calibre/devices/android/driver.py b/src/calibre/devices/android/driver.py index f3aa465476..d478f47cea 100644 --- a/src/calibre/devices/android/driver.py +++ b/src/calibre/devices/android/driver.py @@ -199,6 +199,18 @@ class ANDROID(USBMS): dirs = list(map(aldiko_tweak, dirs)) return dirs + def windows_sort_drives(self, drives): + try: + vid, pid, bcd = self.device_being_opened[:3] + except: + vid, pid, bcd = -1, -1, -1 + if (vid, pid, bcd) == (0x0e79, 0x1408, 0x0222): + letter_a = drives.get('carda', None) + if letter_a is not None: + drives['carda'] = drives['main'] + drives['main'] = letter_a + return drives + class S60(USBMS): name = 'S60 driver' diff --git a/src/calibre/devices/apple/driver.py b/src/calibre/devices/apple/driver.py index d6dd5ccf73..d8584600ae 100644 --- a/src/calibre/devices/apple/driver.py +++ b/src/calibre/devices/apple/driver.py @@ -808,7 +808,7 @@ class ITUNES(DriverBase): self.log.info("ITUNES.get_file(): exporting '%s'" % path) outfile.write(open(self.cached_books[path]['lib_book'].location().path).read()) - def open(self, library_uuid): + def open(self, connected_device, library_uuid): ''' Perform any device specific initialization. Called after the device is detected but before any other functions that communicate with the device. @@ -3224,7 +3224,7 @@ class ITUNES_ASYNC(ITUNES): only_presence=False): return self.connected, self - def open(self, library_uuid): + def open(self, connected_device, library_uuid): ''' Perform any device specific initialization. Called after the device is detected but before any other functions that communicate with the device. diff --git a/src/calibre/devices/bambook/driver.py b/src/calibre/devices/bambook/driver.py index 5068a9c4d8..fecdd53ac4 100644 --- a/src/calibre/devices/bambook/driver.py +++ b/src/calibre/devices/bambook/driver.py @@ -59,9 +59,9 @@ class BAMBOOK(DeviceConfig, DevicePlugin): def reset(self, key='-1', log_packets=False, report_progress=None, detected_device=None) : - self.open(None) + self.open(None, None) - def open(self, library_uuid): + def open(self, connected_device, library_uuid): # Make sure the Bambook library is ready if not is_bambook_lib_ready(): raise OpenFeedback(_("Unable to connect to Bambook, you need to install Bambook library first.")) @@ -309,8 +309,8 @@ class BAMBOOK(DeviceConfig, DevicePlugin): with TemporaryFile('.snb') as snbfile: if self.bambook.PackageSNB(snbfile, tdir) and self.bambook.VerifySNB(snbfile): guid = self.bambook.SendFile(snbfile, self.get_guid(metadata[i].uuid)) - - elif f[-3:].upper() == 'SNB': + + elif f[-3:].upper() == 'SNB': if self.bambook.VerifySNB(f): guid = self.bambook.SendFile(f, self.get_guid(metadata[i].uuid)) else: diff --git a/src/calibre/devices/folder_device/driver.py b/src/calibre/devices/folder_device/driver.py index f9a3a1508c..09df8cd6d8 100644 --- a/src/calibre/devices/folder_device/driver.py +++ b/src/calibre/devices/folder_device/driver.py @@ -79,7 +79,7 @@ class FOLDER_DEVICE(USBMS): only_presence=False): return self.is_connected, self - def open(self, library_uuid): + def open(self, connected_device, library_uuid): self.current_library_uuid = library_uuid if not self._main_prefix: return False diff --git a/src/calibre/devices/interface.py b/src/calibre/devices/interface.py index 15c9e9c55f..cc26c15192 100644 --- a/src/calibre/devices/interface.py +++ b/src/calibre/devices/interface.py @@ -133,8 +133,14 @@ class DevicePlugin(Plugin): if debug: self.print_usb_device_info(device_id) if only_presence or self.can_handle_windows(device_id, debug=debug): - return True - return False + try: + bcd = int(device_id.rpartition( + 'rev_')[-1].replace(':', 'a'), 16) + except: + bcd = None + return True, (vendor_id, product_id, bcd, None, + None, None) + return False, None def test_bcd(self, bcdDevice, bcd): if bcd is None or len(bcd) == 0: @@ -154,7 +160,7 @@ class DevicePlugin(Plugin): ''' if iswindows: return self.is_usb_connected_windows(devices_on_system, - debug=debug, only_presence=only_presence), None + debug=debug, only_presence=only_presence) vendors_on_system = set([x[0] for x in devices_on_system]) vendors = self.VENDOR_ID if hasattr(self.VENDOR_ID, '__len__') else [self.VENDOR_ID] @@ -224,7 +230,7 @@ class DevicePlugin(Plugin): return True - def open(self, library_uuid): + def open(self, connected_device, library_uuid): ''' Perform any device specific initialization. Called after the device is detected but before any other functions that communicate with the device. @@ -238,6 +244,16 @@ class DevicePlugin(Plugin): This method can raise an OpenFeedback exception to display a message to the user. + + :param connected_device: The device that we are trying to open. It is + a tuple of (vendor id, product id, bcd, manufacturer name, product + name, device serial number). However, some device have no serial number + and on windows only the first three fields are present, the rest are + None. + + :param library_uuid: The UUID of the current calibre library. Can be + None if there is no library (for example when used from the command + line. ''' raise NotImplementedError() diff --git a/src/calibre/devices/prs500/cli/main.py b/src/calibre/devices/prs500/cli/main.py index f122f6332e..e32d5e362e 100755 --- a/src/calibre/devices/prs500/cli/main.py +++ b/src/calibre/devices/prs500/cli/main.py @@ -205,15 +205,15 @@ def main(): if ok: dev = d dev.reset(log_packets=options.log_packets, detected_device=det) - connected_devices.append(dev) + connected_devices.append((det, dev)) if dev is None: print >>sys.stderr, 'Unable to find a connected ebook reader.' return 1 - for d in connected_devices: + for det, d in connected_devices: try: - d.open(None) + d.open(det, None) except: continue else: diff --git a/src/calibre/devices/prs500/driver.py b/src/calibre/devices/prs500/driver.py index aaba094fb3..28545b2d86 100644 --- a/src/calibre/devices/prs500/driver.py +++ b/src/calibre/devices/prs500/driver.py @@ -240,7 +240,7 @@ class PRS500(DeviceConfig, DevicePlugin): def set_progress_reporter(self, report_progress): self.report_progress = report_progress - def open(self, library_uuid) : + def open(self, connected_device, library_uuid) : """ Claim an interface on the device for communication. Requires write privileges to the device file. diff --git a/src/calibre/devices/usbms/device.py b/src/calibre/devices/usbms/device.py index 3b4075f601..f62dc44149 100644 --- a/src/calibre/devices/usbms/device.py +++ b/src/calibre/devices/usbms/device.py @@ -847,38 +847,42 @@ class Device(DeviceConfig, DevicePlugin): self._card_b_prefix = None # ------------------------------------------------------ - def open(self, library_uuid): + def open(self, connected_device, library_uuid): time.sleep(5) self._main_prefix = self._card_a_prefix = self._card_b_prefix = None - if islinux: - try: - self.open_linux() - except DeviceError: - time.sleep(7) - self.open_linux() - if isfreebsd: - self._main_dev = self._card_a_dev = self._card_b_dev = None - try: - self.open_freebsd() - except DeviceError: - subprocess.Popen(["camcontrol", "rescan", "all"]) - time.sleep(2) - self.open_freebsd() - if iswindows: - try: - self.open_windows() - except DeviceError: - time.sleep(7) - self.open_windows() - if isosx: - try: - self.open_osx() - except DeviceError: - time.sleep(7) - self.open_osx() + self.device_being_opened = connected_device + try: + if islinux: + try: + self.open_linux() + except DeviceError: + time.sleep(7) + self.open_linux() + if isfreebsd: + self._main_dev = self._card_a_dev = self._card_b_dev = None + try: + self.open_freebsd() + except DeviceError: + subprocess.Popen(["camcontrol", "rescan", "all"]) + time.sleep(2) + self.open_freebsd() + if iswindows: + try: + self.open_windows() + except DeviceError: + time.sleep(7) + self.open_windows() + if isosx: + try: + self.open_osx() + except DeviceError: + time.sleep(7) + self.open_osx() - self.current_library_uuid = library_uuid - self.post_open_callback() + self.current_library_uuid = library_uuid + self.post_open_callback() + finally: + self.device_being_opened = None def post_open_callback(self): pass diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py index 7be64e002d..51e4a1a8c1 100644 --- a/src/calibre/gui2/device.py +++ b/src/calibre/gui2/device.py @@ -162,7 +162,7 @@ class DeviceManager(Thread): # {{{ try: dev.reset(detected_device=detected_device, report_progress=self.report_progress) - dev.open(self.current_library_uuid) + dev.open(detected_device, self.current_library_uuid) except OpenFeedback as e: if dev not in self.ejected_devices: self.open_feedback_msg(dev.get_gui_name(), e) diff --git a/src/calibre/web/feeds/news.py b/src/calibre/web/feeds/news.py index 14021cb142..13b79fa947 100644 --- a/src/calibre/web/feeds/news.py +++ b/src/calibre/web/feeds/news.py @@ -1398,6 +1398,8 @@ class BasicNewsRecipe(Recipe): oldest_article=self.oldest_article, max_articles_per_feed=self.max_articles_per_feed, get_article_url=self.get_article_url)) + if (self.delay > 0): + time.sleep(self.delay) except Exception as err: feed = Feed() msg = 'Failed feed: %s'%(title if title else url)