home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2009 June / maximum-cd-2009-06.iso / DiscContents / digsby_setup.exe / lib / common / favicons.pyo (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2009-02-26  |  7.2 KB  |  252 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.5)
  3.  
  4. from __future__ import with_statement
  5. from threading import RLock, currentThread
  6. from time import time
  7. import wx
  8. from util import WeakDelegate
  9. from util.cacheable import get_cache_root
  10. from common import netcall
  11. import common.asynchttp as asynchttp
  12. from logging import getLogger
  13. log = getLogger('favicons')
  14. __all__ = ('favicon',)
  15. FETCHING = object()
  16. EMPTY = object()
  17. FAVICON_EXPIRE_SECS = 2592000
  18. FAVICON_EXPIRE_ERROR_SECS = 86400
  19. FAVICON_CACHE_DIR = 'favicons'
  20. ICON_EXT = '.ico'
  21. LINK_EXT = '.redirect'
  22. MAX_SUBDOMAIN_CHECK = 5
  23. _favicons_lru = { }
  24. _domain_lru = { }
  25. manual_redirects = {
  26.     'gmail.com': 'mail.google.com',
  27.     'facebookmail.com': 'www.facebook.com',
  28.     'papajohns-specials.com': 'papajohns.com',
  29.     'papajohnsonline.com': 'papajohns.com' }
  30.  
  31. def favicon(domain):
  32.     cached = get_cached(domain)
  33.     if cached in (FETCHING, EMPTY):
  34.         return None
  35.     elif cached is not None:
  36.         return cached
  37.     else:
  38.         fetch_favicon(domain)
  39.  
  40. on_icon = WeakDelegate()
  41.  
  42. def cache_path():
  43.     p = get_cache_root() / FAVICON_CACHE_DIR
  44.     if not p.isdir():
  45.         p.makedirs()
  46.     
  47.     return p
  48.  
  49.  
  50. def clear_cache():
  51.     cache_path().rmtree()
  52.  
  53.  
  54. def get_icon_domain(domain):
  55.     domain = manual_redirects.get(domain, domain)
  56.     if domain in _domain_lru:
  57.         return _domain_lru[domain]
  58.     
  59.     root = cache_path()
  60.     p = root / (domain + LINK_EXT)
  61.     if p.isfile():
  62.         result = p.bytes()
  63.     else:
  64.         result = domain
  65.     _domain_lru[domain] = result
  66.     return result
  67.  
  68.  
  69. def get_cached(domain, done_fetching = False):
  70.     domain = get_icon_domain(domain)
  71.     if domain in _favicons_lru:
  72.         return _favicons_lru[domain]
  73.     
  74.     if not done_fetching and is_fetching(domain):
  75.         return FETCHING
  76.     
  77.     cache_file = cache_path() / domain + ICON_EXT
  78.     if not cache_file.isfile():
  79.         return None
  80.     
  81.     age = time() - cache_file.mtime
  82.     if not done_fetching:
  83.         if age > FAVICON_EXPIRE_SECS or age < 0:
  84.             log.info('expiring favicon for %s' % domain)
  85.             cache_file.remove()
  86.             return None
  87.         
  88.     
  89.     if cache_file.size == 0:
  90.         if age > FAVICON_EXPIRE_ERROR_SECS:
  91.             log.info('expiring empty favicon cache file for %s' % domain)
  92.             cache_file.remove()
  93.             return None
  94.         
  95.         log.debug('%s has an empty cache file', domain)
  96.         _favicons_lru[domain] = EMPTY
  97.         return EMPTY
  98.     
  99.     
  100.     try:
  101.         log.debug('loading favicon cache file for %s', domain)
  102.         bitmap = wx.Bitmap(cache_file)
  103.         if not bitmap.IsOk():
  104.             raise Exception('bitmap.IsOk() != True')
  105.     except Exception:
  106.         e = None
  107.         log.warning('Error loading image file: %s' % e)
  108.         cache_file.remove()
  109.  
  110.     _favicons_lru[domain] = bitmap
  111.     on_icon(domain)
  112.     return bitmap
  113.  
  114.  
  115. def cache_icon(domain, linked_domains, data):
  116.     cp = cache_path()
  117.     icon_file = cp / domain + ICON_EXT
  118.     if icon_file.isfile():
  119.         log.warning('caching file to %s but it already exists', icon_file)
  120.     
  121.     icon_file.write_bytes(data)
  122.     for d in linked_domains:
  123.         (cp / d + LINK_EXT).write_bytes(domain)
  124.     
  125.     _domain_lru.clear()
  126.     wx.CallAfter(get_cached, domain, done_fetching = True)
  127.     log.debug('cached %d bytes of data for %r (linked: %s)', len(data), domain, ', '.join(linked_domains))
  128.  
  129.  
  130. def cache_noicon(domain, linked_domains):
  131.     return cache_icon(domain, linked_domains, '')
  132.  
  133.  
  134. def link_tag_url(html):
  135.     HTML = HTML
  136.     import lxml.etree
  137.     doc = HTML(html)
  138.     link_tag = doc.find('.//link[@rel="shortcut icon"]')
  139.     if link_tag is not None:
  140.         favicon_url = link_tag.get('href', '')
  141.         if favicon_url:
  142.             return favicon_url
  143.         
  144.     
  145.  
  146.  
  147. def fetch_favicon(domain, linked_domains = None):
  148.     start_domain = domain
  149.     real_domain = get_icon_domain(domain)
  150.     if linked_domains is None:
  151.         linked_domains = []
  152.     
  153.     if real_domain != domain:
  154.         linked_domains.append(domain)
  155.     
  156.     domain = real_domain
  157.     wwwdomain = 'www.' + domain
  158.     if not domain.startswith('www') or wwwdomain in linked_domains:
  159.         linked_domains.append(domain)
  160.         domain = wwwdomain
  161.     
  162.     log.info('Using %r for %r (linked = %r)', domain, start_domain, linked_domains)
  163.     url = 'http://' + domain + '/favicon.ico'
  164.     
  165.     def on_success(req, resp):
  166.         data = resp.read()
  167.         log.info('httpopen(%s): received %d bytes of data', url, len(data))
  168.         log.info('%r', resp)
  169.         cache_icon(domain, linked_domains, data)
  170.         unset_fetching([
  171.             domain])
  172.  
  173.     
  174.     def on_error(req = (None, None, None), resp = (None, None)):
  175.         log.error('on_error for domain=%r, linked_domains=%r', domain, linked_domains)
  176.         if domain.count('.') < domain.count('.'):
  177.             pass
  178.         elif domain.count('.') < MAX_SUBDOMAIN_CHECK:
  179.             new_domain = '.'.join(domain.split('.')[1:])
  180.             wx.CallAfter(fetch_favicon, new_domain, linked_domains + [
  181.                 domain])
  182.             return None
  183.         else:
  184.             log.error('No more subdomains to try for %r. Error response was: %r', domain, resp)
  185.             cache_noicon(domain, linked_domains)
  186.         unset_fetching(linked_domains + [
  187.             domain])
  188.  
  189.     
  190.     def on_redirect(req):
  191.         if 'favicon' not in req.get_selector():
  192.             new_url = 'http://%s/%s' % (req.get_host(), 'favicon.ico')
  193.             old_req = req._orig_request
  194.             checked_urls = getattr(old_req, '_favicons_checked_urls', set())
  195.             if new_url in checked_urls:
  196.                 return None
  197.             
  198.             checked_urls.add(new_url)
  199.             req = req.copy(url = new_url)
  200.             req._favicons_checked_urls = old_req._favicons_checked_urls = checked_urls
  201.             req._orig_request = old_req
  202.         
  203.         return req
  204.  
  205.     fetch_lock.__enter__()
  206.     
  207.     try:
  208.         if domain in currently_fetching:
  209.             log.info('already fetching %r', url)
  210.             return None
  211.         else:
  212.             log.info('getting %r', url)
  213.             currently_fetching.add(domain)
  214.     finally:
  215.         pass
  216.  
  217.     (None, None, fetch_lock, netcall)((lambda : asynchttp.httpopen(url, success = on_success, error = on_error, on_redirect = on_redirect)))
  218.  
  219. fetch_lock = RLock()
  220. currently_fetching = set()
  221.  
  222. def set_fetching(domain):
  223.     fetch_lock.__enter__()
  224.     
  225.     try:
  226.         currently_fetching.add(domain)
  227.     finally:
  228.         pass
  229.  
  230.  
  231.  
  232. def unset_fetching(domains):
  233.     global currently_fetching
  234.     fetch_lock.__enter__()
  235.     
  236.     try:
  237.         currently_fetching -= set(domains)
  238.     finally:
  239.         pass
  240.  
  241.  
  242.  
  243. def is_fetching(domain):
  244.     fetch_lock.__enter__()
  245.     
  246.     try:
  247.         return domain in currently_fetching
  248.     finally:
  249.         pass
  250.  
  251.  
  252.