Index: channels/__init__.py ================================================================== --- channels/__init__.py +++ channels/__init__.py @@ -182,11 +182,14 @@ uikit.add_menu([parent.channelmenuitems], self.meta["title"], lambda w: parent.channel_switch_by_name(self.module) or 1) # Just wraps uikit.columns() to retain liststore, rowmap and pix_entry def columns(self, entries=None): - self.ls, self.rowmap, self.pix_entry = uikit.columns(self.gtk_list, self.datamap, entries, show_favicons=conf.show_favicons) + self.ls, self.rowmap, self.pix_entry = uikit.columns( + self.gtk_list, self.datamap, entries, show_favicons=True + ) + # no longer using `conf.show_favicons` # Statusbar stub (defers to parent/main window, if in GUI mode) def status(self, *args, **kw): if self.parent: self.parent.status(*args, **kw) Index: channels/favicon.py ================================================================== --- channels/favicon.py +++ channels/favicon.py @@ -1,32 +1,37 @@ # encoding: utf-8 # api: streamtuner2 # title: Favicons # description: Display station favicons/logos. Instantly download them when ▸playing. # config: +# { name: load_favicon, type: bool, value: 1, description: "Load favicon instantly when ▸playing a station.", color: yellow } # { name: favicon_google_first, type: bool, value: 1, description: "Prefer faster Google favicon to PNG conversion service." } # { name: favicon_delete_stub , type: bool, value: 1, description: "Don't accept any placeholder favicons." } -# [ main-name: google_homepage ] -# [ main-name: load_favicon ] +# { name: google_homepage, type: bool, value: 0, description: "Google missing station homepages right away." } # type: feature # category: ui # version: 1.9 # depends: streamtuner2 >= 2.1.9, python:pil # priority: standard -# -# This module fetches a favicon for each station, or a small banner -# or logo for some channel modules. It converts .ico image files and -# sanitizes .png or .jpeg images even prior display. -# -# It prepares cache files in ~/.config/streamtuner2/icons/ in silent -# agreement with the station list display logic. Either uses station -# row["homepage"] or row["img"] URLs from any entry. -# -# While it can often discover favicons directly from station homepages, -# it's often speedier to use the Google PNG conversion service. Both -# depend on a recent Pillow2 python module (superseding the PIL module). -# Else may display images with fragments if converted from ICO files. +# png: +# iVBORw0KGgoAAAANSUhEUgAAABYAAAAWBAMAAAA2mnEIAAAAJ1BMVEUAAACwDw5oKh1RRU5OTSCOTxp0Um9zcyFUhSXsbwChdp/lgCNbrA7VFTQPAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHU +# gAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQffBQ4ENQJMtfdfAAAAmUlEQVQY02NgcAECYxBgYODeOXPmTKtVQLCAwXsmjL2YQRPINDNGsFclI7GXQdmzZ87MSoOyI0pnpgHVLAOy1c+c +# mTkzeFWioBSUbQZkiy1mcPFpCXUxTksTFEtm8Ojp6OhQVDJWVFJi8DkDBIIgIARhKyKx3c8g2GfOBCKxFeHspg6EmiZFJDbEHB44W4CBwQNor5MSEDAAAGcoaQmD1t8TAAAAAElFTkSuQmCC +# +# This module fetches a favicon for each station. Some channels +# provide small logos/banners even. It sanitizes and converts +# any .ico/.png/.jpeg file prior display. +# +# Cache files are kept in ~/.config/streamtuner2/icons/ where +# the station column display picks them up form. +# +# While it can often discover favicons directly from station +# homepages, it's mostly speedier to use the PNG conversion +# service from Google. +# Both methods depend on a recent Pillow2 python module (that +# superseded the PIL module). Else icon display may have some +# transparency fragments. import os, os.path from io import BytesIO import re @@ -55,18 +60,10 @@ # · uikit.columns() merely checks row["favicon"] for file existence # when redrawing a station list. # # · main calls .update_playing() on hooks["play"], # or .update_all() per menu command -# -# · urllib is no longer required. Using just ahttp/requests API now. -# -# · Might need unhtml() utility from channels/__init__ later.. -# -# · Still need to consolidate config options → Move main favicon -# options here? -# # Hook up as feature plugin # @@ -78,50 +75,51 @@ # Register with main def __init__(self, parent): - # Reference main, and register hook + # Reference main, and register station .play() hook for conf.load_favicon self.parent, self.main = parent, parent parent.hooks["play"].append(self.update_playing) + + # Register in channel/streams updating pipeline (to predefine row["favicon"] filename from `homepage` or `img`) + channels.GenericChannel.prepare_filters.append(self.prepare_filter_favicon) # 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 + # Main menu "Update favicons": update favicon cache for complete list of station rows def update_all(self, *args, **kwargs): #kwargs[pixstore] = self.parent.channel()._ls, ... self.parent.thread(self.update_rows, *args, **kwargs) - # Main callback for a single play() event + # Main [▸play] event for a single station def update_playing(self, row, pixstore=None, channel=None, **x): # Homepage search if conf.google_homepage and not len(row.get("homepage", "")): found = google_find_homepage(row) - # could call channel.save() now to preserve found homepage URL + # Save channel list right away to preserve found homepage URL + if found and conf.auto_save_stations: + channel.save() else: found = False # Favicon only for currently playing station if conf.load_favicon: if row.get("homepage") or row.get("img"): - self.update_all([row], pixstore=pixstore, always_update=found) + self.parent.thread(self.update_rows, [row], pixstore=pixstore, always_update=found) # Run through rows[] to update "favicon" from "homepage" or "img", # optionally display new image right away in ListStore - def update_rows(self, entries, pixstore=None, always_update=False): + def update_rows(self, entries, pixstore=None, always_update=False, **x): for i,row in enumerate(entries): ok = False # Try just once if row.get("homepage") in tried_urls: @@ -195,10 +193,11 @@ # Run after any channel .update_streams() to populate row["favicon"] # from `homepage` or `img` url. def prepare_filter_favicon(self, row): + # if conf.show_favicons: (do we still need that?) row["favicon"] = row_to_fn(row) Index: config.py ================================================================== --- config.py +++ config.py @@ -138,10 +138,11 @@ self.show_favicons = 1 self.load_favicon = 1 self.heuristic_bookmark_update = 0 self.retain_deleted = 0 self.auto_save_appstate = 1 + self.auto_save_stations = 0 self.reuse_m3u = 1 self.playlist_asis = 0 self.google_homepage = 0 self.windows = platform.system()=="Windows" self.pyquery = 1 Index: gtk3.xml.gz ================================================================== --- gtk3.xml.gz +++ gtk3.xml.gz cannot compute difference between binary files