Internet radio browser GUI for music/video streams from various directory services.

⌈⌋ branch:  streamtuner2


Check-in [b0a6a50a20]

Overview
Comment:Release as 2.1.8
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk | 2.1.8
Files: files | file ages | folders
SHA1: b0a6a50a20e2a5842c755f11730337a60802da9c
User & Date: mario on 2015-05-06 00:08:20
Other Links: manifest | tags
Context
2015-05-06
00:21
Remove default ["empty",] category. check-in: d958ddb71e user: mario tags: trunk
00:08
Release as 2.1.8 check-in: b0a6a50a20 user: mario tags: trunk, 2.1.8
00:07
Fix some print and log statements. check-in: d0a9fca2bd user: mario tags: trunk
Changes

Modified NEWS from [8a25cfeebf] to [d5a50a4514].


























1
2
3
4
5
6
7

























2.1.7 (2015-04-26)
- Experimental support for drag and drop, which allows playback,
  importing, or exporting stations from/to files.
- Configuration dialog became more clearly arranged by separating
  channels and feature plugins.
- More manual examples on recording configuration added.
- Several enhancements to playlist conversion, support for .desktop
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

2.1.8 (2015-05-05)
 * New channel plugins for Radionomy.com, Filtermusic.net, Delicast.com.
 * Added Dirble channel again, using new API.
 * Removed iCast plugin. Removed 8tracks plugin.
 * Brought back Xiph XML extraction, and added direct website extraction,
   in addition to JSON cache mode.
 * Add TV list for UbuntuUsers channel.
 * Introduction of User Plugin Manager and channel module updating,
   automatic plugin activation, contrib plugins: PublicRadioFan, GLRP.
 * Change Youtube plugin to use only v3 API henceforth.
 * Minor fixes to action/playlist extraction, add specific JAMJ extractor.
 * Update manual on new channel/feature plugins.
 * Separated config and pluginconf modules.
 * Fixes to contrib/ plugins: compound, file, punkcast.
 * Scroll back to last category on initialization, simplified window
   and state storage.
 * Some Gtk3 fixes, catch invalid favicons while updating columns,
   another fix for search function.
 * Better inline documentation for player configuration, more thorough
   program binary detection. Simplified channel parsing utility code,
   added @use_rx decorator. And a few more internal cleanups.
 * Add new configuration dialog group for Playlist processing.
 * Experimental new package for Arch Linux / pacman.

2.1.7 (2015-04-26)
- Experimental support for drag and drop, which allows playback,
  importing, or exporting stations from/to files.
- Configuration dialog became more clearly arranged by separating
  channels and feature plugins.
- More manual examples on recording configuration added.
- Several enhancements to playlist conversion, support for .desktop

Modified PKG-INFO from [09ee67ca0a] to [1adf7674b8].

1
2
3
4
5
6
7
8
9
10
11
12
Metadata-Version: 1.0
Name: streamtuner2
Version: 2.1.7-dev
Summary: Streamtuner2 is an internet radio browser
Home-page: http://fossil.include-once.org/streamtuner2/
Author: Mario Salzer
Author-email: xmilky+st2@gmail....
License: Public Domain
Description: Streamtuner2 lists radio directory services like Shoutcast, Xiph, Live365, MyOggRadio, Jamendo. It allows listening via any audio player, and recording of streams via streamripper.
Platform: ALL
Keywords: internet-radio, python, streaming, audio



|









1
2
3
4
5
6
7
8
9
10
11
12
Metadata-Version: 1.0
Name: streamtuner2
Version: 2.1.8
Summary: Streamtuner2 is an internet radio browser
Home-page: http://fossil.include-once.org/streamtuner2/
Author: Mario Salzer
Author-email: xmilky+st2@gmail....
License: Public Domain
Description: Streamtuner2 lists radio directory services like Shoutcast, Xiph, Live365, MyOggRadio, Jamendo. It allows listening via any audio player, and recording of streams via streamripper.
Platform: ALL
Keywords: internet-radio, python, streaming, audio

Modified pluginconf.py from [16bafd8a99] to [a5813116de].

60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#  Probes a new plugins` depends: list against installed base modules.
#  Very crude and tied to streamtuner2 base names.
#
#
#


from __future__ import print_function
import sys
import os
import re
import pkgutil
import inspect
try: from compat2and3 import gzip_decode
except: from gzip import decompress as gzip_decode # Py3 only







<







60
61
62
63
64
65
66

67
68
69
70
71
72
73
#  Probes a new plugins` depends: list against installed base modules.
#  Very crude and tied to streamtuner2 base names.
#
#
#



import sys
import os
import re
import pkgutil
import inspect
try: from compat2and3 import gzip_decode
except: from gzip import decompress as gzip_decode # Py3 only
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

__all__ = ["get_data", "module_list", "plugin_meta", "dependency", "add_plugin_defaults"]



# Injectables
# ‾‾‾‾‾‾‾‾‾‾‾
log_WARN = lambda *x:None
log_ERR = lambda *x:None

# File lookup relation for get_data(), should name a top-level module/package
module_base = "config"

# Package names or base paths for module_list() and plugin_meta() lookups
plugin_base = ["channels"]







<







76
77
78
79
80
81
82

83
84
85
86
87
88
89

__all__ = ["get_data", "module_list", "plugin_meta", "dependency", "add_plugin_defaults"]



# Injectables
# ‾‾‾‾‾‾‾‾‾‾‾

log_ERR = lambda *x:None

# File lookup relation for get_data(), should name a top-level module/package
module_base = "config"

# Package names or base paths for module_list() and plugin_meta() lookups
plugin_base = ["channels"]
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
        if gz:
            bin = gzip_decode(bin)
        if decode:
            return bin.decode("utf-8", errors='ignore')
        else:
            return str(bin)
    except:
        pass#log_WARN("get_data() didn't find:", fn, "in", file_base)



# Plugin name lookup
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
# Search through ./plugins/ (and other configured plugin_base
# names or paths) and get module basenames.







|







105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
        if gz:
            bin = gzip_decode(bin)
        if decode:
            return bin.decode("utf-8", errors='ignore')
        else:
            return str(bin)
    except:
        pass#log_ERR("get_data() didn't find:", fn, "in", file_base)



# Plugin name lookup
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
# Search through ./plugins/ (and other configured plugin_base
# names or paths) and get module basenames.
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
    typing = re.findall("bool|str|\[\]|const|false|true", opt["type"])
    naming = re.findall("\[\]", opt["name"])
    name   = re.findall("(?<!-)\\b\\w+", opt["name"])
    nargs  = re.findall("\\b\d+\\b|[\?\*\+]", opt["type"]) or [None]
    is_arr = "[]" in (naming + typing) and nargs == [None]
    is_bool= "bool" in typing
    false_b = "false" in typing or opt["value"] in ("0", "false")
    #print "\nname=", name, "is_arr=", is_arr, "is_bool=", is_bool, "bool_d=", false_b, "naming=", naming, "typing=", typing

    # Populate partially - ArgumentParser has aversions to many parameter combinations
    kwargs = dict(
        args     = args,
        dest     = name[0] if not name[0] in args else None,
        action   = is_arr and "append"  or  is_bool and false_b and "store_false"  or  is_bool and "store_true"  or  "store",
        nargs    = nargs[0],







|







332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
    typing = re.findall("bool|str|\[\]|const|false|true", opt["type"])
    naming = re.findall("\[\]", opt["name"])
    name   = re.findall("(?<!-)\\b\\w+", opt["name"])
    nargs  = re.findall("\\b\d+\\b|[\?\*\+]", opt["type"]) or [None]
    is_arr = "[]" in (naming + typing) and nargs == [None]
    is_bool= "bool" in typing
    false_b = "false" in typing or opt["value"] in ("0", "false")
    #print("\nname=", name, "is_arr=", is_arr, "is_bool=", is_bool, "bool_d=", false_b, "naming=", naming, "typing=", typing)

    # Populate partially - ArgumentParser has aversions to many parameter combinations
    kwargs = dict(
        args     = args,
        dest     = name[0] if not name[0] in args else None,
        action   = is_arr and "append"  or  is_bool and false_b and "store_false"  or  is_bool and "store_true"  or  "store",
        nargs    = nargs[0],

Modified releases.json from [c7a7214195] to [aa01b242f2].

8
9
10
11
12
13
14
15
16

17
18








19
20
21
22
23
24
25
    "image": "http://milki.include-once.org/streamtuner2/screenshot.mini.png",
    "urls": {
        "fossil": "http://fossil.include-once.org/streamtuner2/",
        "src": "http://milki.include-once.org/streamtuner2/streamtuner2-$version.src.txz",
        "deb": "http://milki.include-once.org/streamtuner2/streamtuner2-$version.deb",
        "rpm": "http://milki.include-once.org/streamtuner2/streamtuner2-$version.rpm",
        "pyz": "http://milki.include-once.org/streamtuner2/streamtuner2-$version.pyz",
        "bin": "http://milki.include-once.org/streamtuner2/streamtuner2-$version.bin.txz",
        "exe": "http://milki.include-once.org/streamtuner2/streamtuner2-$version.exe"

    },
    "releases": [








        {
            "version": "2.1.7",
            "state": "beta",
            "scope": "minor feature",
            "changes": "Experimental support for drag and drop, which allows playback, importing, or exporting stations from/to files.  Configuration dialog became more clearly arranged by separating channels and feature plugins.  More manual examples on recording configuration added.  Several enhancements to playlist conversion, support for .desktop links, better heuristics, and working url+title extraction.  All MOD files use generic audio/mod+zip MIME type. Use new and distinct /tmp/streamtuner2/ directory for cache+export. Implemented hashing for cached m3u/pls files.  Support 'feeds' stream in Jamendo, more complete Ogg Vorbis support and JAMJSON extraction instead of using old v2 API.  Initial startup and application state restoration became more robust, active category is tracked more dynamically.  Some internal simplifications and code cleanup (logging simplified, more uikit wrappers for Gtk3, removed outdated PIL workaround, cleanup up remnant module descriptions).  Statusbar is just a plain text label, automatically emptied. Disable partial stream refreshing, and threading per --nt flag or config option, because Gtk3 support is still flaky.  Let gtk_idle callbacks run in order through an internal precedence spool.  Browser invocations corrected. Crash in cache search fixed.  PYZ building now supported by xpm and Packfile for custom adaptions.",
            "download": "http://sourceforge.net/projects/streamtuner2/files/",
            "published": "2015-04-27T01:30:00+0000"







|

>


>
>
>
>
>
>
>
>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
    "image": "http://milki.include-once.org/streamtuner2/screenshot.mini.png",
    "urls": {
        "fossil": "http://fossil.include-once.org/streamtuner2/",
        "src": "http://milki.include-once.org/streamtuner2/streamtuner2-$version.src.txz",
        "deb": "http://milki.include-once.org/streamtuner2/streamtuner2-$version.deb",
        "rpm": "http://milki.include-once.org/streamtuner2/streamtuner2-$version.rpm",
        "pyz": "http://milki.include-once.org/streamtuner2/streamtuner2-$version.pyz",
        "raw": "http://milki.include-once.org/streamtuner2/streamtuner2-$version.bin.txz",
        "exe": "http://milki.include-once.org/streamtuner2/streamtuner2-$version.exe"
        "arch": "http://milki.include-once.org/streamtuner2/streamtuner2-$version.arch.txz"
    },
    "releases": [
        {
            "version": "2.1.8",
            "state": "beta",
            "scope": "feature creep",
            "changes": "New channel plugins for Radionomy.com, Filtermusic.net, Delicast.com. Added Dirble channel again, using new API. Removed iCast plugin. Removed 8tracks plugin. Brought back Xiph XML extraction, and added direct website extraction, in addition to JSON cache mode. Add TV list for UbuntuUsers channel. Introduction of User Plugin Manager and channel module updating, automatic plugin activation, contrib plugins: PublicRadioFan, GLRP. Change Youtube plugin to use only v3 API henceforth. Minor fixes to action/playlist extraction, add specific JAMJ extractor. Update manual on new channel/feature plugins. Separated config and pluginconf modules. Fixes to contrib/ plugins: compound, file, punkcast. Scroll back to last category on initialization, simplified window and state storage. Some Gtk3 fixes, catch invalid favicons while updating columns, another fix for search function. Better inline documentation for player configuration, more thorough program binary detection. Simplified channel parsing utility code, added @use_rx decorator. And a few more internal cleanups. Add new configuration dialog group for Playlist processing. Experimental new package for Arch Linux / pacman.",
            "download": "http://sourceforge.net/projects/streamtuner2/files/",
            "published": "2015-05-05T23:55:00+0000"
        },
        {
            "version": "2.1.7",
            "state": "beta",
            "scope": "minor feature",
            "changes": "Experimental support for drag and drop, which allows playback, importing, or exporting stations from/to files.  Configuration dialog became more clearly arranged by separating channels and feature plugins.  More manual examples on recording configuration added.  Several enhancements to playlist conversion, support for .desktop links, better heuristics, and working url+title extraction.  All MOD files use generic audio/mod+zip MIME type. Use new and distinct /tmp/streamtuner2/ directory for cache+export. Implemented hashing for cached m3u/pls files.  Support 'feeds' stream in Jamendo, more complete Ogg Vorbis support and JAMJSON extraction instead of using old v2 API.  Initial startup and application state restoration became more robust, active category is tracked more dynamically.  Some internal simplifications and code cleanup (logging simplified, more uikit wrappers for Gtk3, removed outdated PIL workaround, cleanup up remnant module descriptions).  Statusbar is just a plain text label, automatically emptied. Disable partial stream refreshing, and threading per --nt flag or config option, because Gtk3 support is still flaky.  Let gtk_idle callbacks run in order through an internal precedence spool.  Browser invocations corrected. Crash in cache search fixed.  PYZ building now supported by xpm and Packfile for custom adaptions.",
            "download": "http://sourceforge.net/projects/streamtuner2/files/",
            "published": "2015-04-27T01:30:00+0000"

Modified st2.py from [5d8e044644] to [f5518a5d34].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/env python
# encoding: UTF-8
# api: python
# type: application
# title: streamtuner2
# description: Directory browser for internet radio, audio and video streams
# version: 2.1.7-dev
# state: beta
# author: Mario Salzer <mario@include-once.org>
# license: Public Domain
# url: http://freshcode.club/projects/streamtuner2
# config:  
#   { type: env, name: http_proxy, description: proxy for HTTP access }
#   { type: env, name: XDG_CONFIG_HOME, description: relocates user .config subdirectory }






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/env python
# encoding: UTF-8
# api: python
# type: application
# title: streamtuner2
# description: Directory browser for internet radio, audio and video streams
# version: 2.1.8
# state: beta
# author: Mario Salzer <mario@include-once.org>
# license: Public Domain
# url: http://freshcode.club/projects/streamtuner2
# config:  
#   { type: env, name: http_proxy, description: proxy for HTTP access }
#   { type: env, name: XDG_CONFIG_HOME, description: relocates user .config subdirectory }
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288

    # Open stream homepage in web browser
    def on_homepage_stream_clicked(self, widget):
        url = self.selected("homepage")
        if url and len(url): action.browser(url)
        else: self.status("No homepage URL present.")

    # Browse to channel homepage (double click on notebook tab)
    def on_homepage_channel_clicked(self, widget, event=2):
        if event == 2 or event.type == gtk.gdk._2BUTTON_PRESS:
            log.UI("dblclick")
            url = self.channel().meta.get("url", "https://duckduckgo.com/?q=" + self.channel().module)
            action.browser(url)

    # Reload stream list in current channel-category







|







274
275
276
277
278
279
280
281
282
283
284
285
286
287
288

    # Open stream homepage in web browser
    def on_homepage_stream_clicked(self, widget):
        url = self.selected("homepage")
        if url and len(url): action.browser(url)
        else: self.status("No homepage URL present.")

    # Browse to channel homepage (@BROKEN: double click on notebook tab)
    def on_homepage_channel_clicked(self, widget, event=2):
        if event == 2 or event.type == gtk.gdk._2BUTTON_PRESS:
            log.UI("dblclick")
            url = self.channel().meta.get("url", "https://duckduckgo.com/?q=" + self.channel().module)
            action.browser(url)

    # Reload stream list in current channel-category