︙ | | |
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
+
-
+
-
-
+
+
-
+
+
|
# depend on a recent Pillow2 python module (superseding the PIL module).
# Else may display images with fragments if converted from ICO files.
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
# Ensure that we don't try to download a single favicon twice per session.
# If it's not available the first time, we won't get it after switching
# stations back and forth either. So URLs are skipped simply.
tried_urls = []
# 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..
#
# · Still need to consolidate config options → Move main favicon
# options here?
|
︙ | | |
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
+
+
+
|
parent.hooks["play"].append(self.update_playing)
# 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):
#kwargs[pixstore] = self.parent.channel()._ls, ...
self.parent.thread(self.update_rows, *args, **kwargs)
|
︙ | | |
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
|
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
|
+
+
+
-
+
|
try:
p = gtk.gdk.pixbuf_new_from_file(fn)
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"):
rx_t = re.compile('^(([^-:]+.?){1,2})')
rx_u = re.compile(r'/url\?q=(https?://[^"&/]+)')
|
︙ | | |
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
|
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
|
+
+
-
-
+
+
|
pass
#-----------------
# 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
# Copy banner row["img"] into icons/ directory
def banner_localcopy(url, fn):
|
︙ | | |