Index: channels/favicon.py ================================================================== --- channels/favicon.py +++ channels/favicon.py @@ -28,10 +28,11 @@ import os, os.path from io import BytesIO import re +import channels from config import * import ahttp from PIL import Image from uikit import gtk #import traceback @@ -45,20 +46,21 @@ # Has recently been rewritten, is somewhat less entangled with other # modules now: # -# · GenericChannel presets row["favicon"] with cache image filename +# · GenericChannel presets row["favicon"] with cache image filenames # in any case. It uses row["homepage"] or row["img"] as template. # -# · The url-to-filename shortening functionality is therefore shared. -# GenericChannel.prepare() duplicates all row_to_fn() logic. +# · The url-to-filename shortening functionality in GenChan.prepare() +# is identical to that in row_to_fn() here. # # · uikit.columns() merely checks row["favicon"] for file existence # when redrawing a station list. # -# · main.play() only calls .update_playing() or .update_all() +# · main only calls .update_playing() via hooks["play"], and the menu +# invokes .update_all() # # · urllib is no longer required. Using just ahttp/requests API now. # # · Might need unhtml() utility from channels/__init__ later.. # @@ -87,10 +89,13 @@ # Prepare favicon cache directory conf.icon_dir = conf.dir + "/icons" if not os.path.exists(conf.icon_dir): os.mkdir(conf.icon_dir) open(icon_dir+"/.nobackup", "a").close() + + # Hook into channel/streams updating pipine + channels.GenericChannel.prepare_filters.append(self.prepare_filter_favicon) # Main callback: update favicon cache for complete list of station rows def update_all(self, *args, **kwargs): @@ -180,20 +185,23 @@ ls[i][pix_entry] = p except Exception as e: log.ERR("Update_pixstore image", fn, "error:", e) + # Run after any channel .update_streams() to populate "favicon" + def prepare_filter_favicon(self, row): + row["favicon"] = row_to_fn(row) #--- somewhat unrelated --- # # Should become a distinct feature plugin. - It just depends on correct # invocation order for both plugins to interact. # Googling is often blocked anyway, because this is clearly a bot request. # And requests are tagged with ?client=streamtuner2 still purposefully. # -def google_find_homepage(self, row): +def google_find_homepage(row): """ Searches for missing homepage URL via Google. """ if row.get("url") not in tried_urls: tried_urls.append(row.get("url")) if row.get("title"): @@ -216,16 +224,18 @@ # Convert row["img"] or row["homepage"] into local favicon cache filename +rx_strip_proto = re.compile("^\w+://|/$") +rx_non_wordchr = re.compile("[^\w._-]") def row_to_fn(row): url = row.get("img") or row.get("homepage") or None if url: url = url.lower() - url = re.sub("^\w+://|/$", "", url) # strip proto:// and trailing / - url = re.sub("[^\w._-]", "_", url) # remove any non-word characters + url = rx_strip_proto.sub("", url) # strip proto:// and trailing / + url = rx_non_wordchr.sub("_", url) # remove any non-word characters url = "{}/{}.png".format(conf.icon_dir, url) return url