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

⌈⌋ ⎇ branch:  streamtuner2


Diff

Differences From Artifact [cbc6a632be]:

To Artifact [eacd2e641f]:

  • Executable file st2.py — part of check-in [ea628d6426] at 2015-04-08 17:59:53 on branch trunk — Remove extraneous class wrapper action.action. Start to regroup listformat mapping (pls-url → m3u-fn rewrites). Will need some heuristics, as depending just on the channel.listformat assumption won't work in practice (some .pls servers actually host direct server links, or occasionally .m3u references even). Currently does nothing, just returns the pls/etc URL. (user: mario, size: 21325) [annotate] [blame] [check-ins using] [more...]

104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
          "configwin": channels.configwin.configwin(self),
          "streamedit": channels.streamedit.streamedit(self),
        }
        gui_startup(4/20.0)

        # early module coupling
        action.main = self            # action (play/record) module needs a reference to main window for gtk interaction and some URL/URI callbacks
        self.action = action.action   # shorter name (could also become a features. entry...)
        ahttp.feedback = self.status  # http module gives status feedbacks too
        
        # append other channel modules and plugins
        self.load_plugin_channels()


        # load application state (widget sizes, selections, etc.)







<







104
105
106
107
108
109
110

111
112
113
114
115
116
117
          "configwin": channels.configwin.configwin(self),
          "streamedit": channels.streamedit.streamedit(self),
        }
        gui_startup(4/20.0)

        # early module coupling
        action.main = self            # action (play/record) module needs a reference to main window for gtk interaction and some URL/URI callbacks

        ahttp.feedback = self.status  # http module gives status feedbacks too
        
        # append other channel modules and plugins
        self.load_plugin_channels()


        # load application state (widget sizes, selections, etc.)
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
            # else
            "update_categories": self.update_categories,
            "update_favicons": self.update_favicons,
            "app_state": self.app_state,
            "bookmark": self.bookmark,
            "save_as": self.save_as,
            "menu_about": lambda w: AboutStreamtuner2(self),
            "menu_help": self.action.help,
            "menu_onlineforum": lambda w: self.action.browser("http://sourceforge.net/projects/streamtuner2/forums/forum/1173108"),
            "menu_fossilwiki": lambda w: self.action.browser("http://fossil.include-once.org/streamtuner2/"),
            "menu_projhomepage": lambda w: self.action.browser("http://milki.include-once.org/streamtuner2/"),
           # "menu_bugreport": lambda w: BugReport(),
            "menu_copy": self.menu_copy,
            "delete_entry": self.delete_entry,
            # search dialog
            "quicksearch_set": self.search.quicksearch_set,
            "search_open": self.search.menu_search,
            "search_go": self.search.cache_search,







|
|
|
|







177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
            # else
            "update_categories": self.update_categories,
            "update_favicons": self.update_favicons,
            "app_state": self.app_state,
            "bookmark": self.bookmark,
            "save_as": self.save_as,
            "menu_about": lambda w: AboutStreamtuner2(self),
            "menu_help": action.help,
            "menu_onlineforum": lambda w: action.browser("http://sourceforge.net/projects/streamtuner2/forums/forum/1173108"),
            "menu_fossilwiki": lambda w: action.browser("http://fossil.include-once.org/streamtuner2/"),
            "menu_projhomepage": lambda w: action.browser("http://milki.include-once.org/streamtuner2/"),
           # "menu_bugreport": lambda w: BugReport(),
            "menu_copy": self.menu_copy,
            "delete_entry": self.delete_entry,
            # search dialog
            "quicksearch_set": self.search.quicksearch_set,
            "search_open": self.search.menu_search,
            "search_go": self.search.cache_search,
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
        if row:
            self.channel().play(row)
            [callback(row) for callback in self.hooks["play"]]

    # Recording: invoke streamripper for current stream URL
    def on_record_clicked(self, widget):
        row = self.row()
        self.action.record(row.get("url"), row.get("format", "audio/mpeg"), "url/direct", row=row)

    # Open stream homepage in web browser
    def on_homepage_stream_clicked(self, widget):
        url = self.selected("homepage")
        if url and len(url): self.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:
            __print__(dbg.UI, "dblclick")
            url = self.channel().meta.get("url", "https://duckduckgo.com/?q=" + self.channel().module)
            self.action.browser(url)

    # Reload stream list in current channel-category
    def on_reload_clicked(self, widget=None, reload=1):
        __print__(dbg.UI, "on_reload_clicked()", "reload=", reload, "current_channel=", self.current_channel, "c=", self.channels[self.current_channel], "cat=", self.channel().current)
        category = self.channel().current
        self.thread(
                       #@TODO: should get a wrapper, for HTTP errors, and optionalize bookamrks







|




|







|







288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
        if row:
            self.channel().play(row)
            [callback(row) for callback in self.hooks["play"]]

    # Recording: invoke streamripper for current stream URL
    def on_record_clicked(self, widget):
        row = self.row()
        action.record(row.get("url"), row.get("format", "audio/mpeg"), "url/direct", row=row)

    # 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:
            __print__(dbg.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
    def on_reload_clicked(self, widget=None, reload=1):
        __print__(dbg.UI, "on_reload_clicked()", "reload=", reload, "current_channel=", self.current_channel, "c=", self.channels[self.current_channel], "cat=", self.channel().current)
        category = self.channel().current
        self.thread(
                       #@TODO: should get a wrapper, for HTTP errors, and optionalize bookamrks
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368

    # Save stream to file (.m3u)
    def save_as(self, widget):
        row = self.row()
        default_fn = row["title"] + ".m3u"
        fn = uikit.save_file("Save Stream", None, default_fn, [(".m3u","*m3u"),(".pls","*pls"),(".xspf","*xspf"),(".smil","*smil"),(".asx","*asx"),("all files","*")])
        if fn:
            self.action.save(row, fn)
        pass

    # Save current stream URL into clipboard
    def menu_copy(self, w):
        gtk.clipboard_get().set_text(self.selected("url"))

    # Remove a stream entry







|







353
354
355
356
357
358
359
360
361
362
363
364
365
366
367

    # Save stream to file (.m3u)
    def save_as(self, widget):
        row = self.row()
        default_fn = row["title"] + ".m3u"
        fn = uikit.save_file("Save Stream", None, default_fn, [(".m3u","*m3u"),(".pls","*pls"),(".xspf","*xspf"),(".smil","*smil"),(".asx","*asx"),("all files","*")])
        if fn:
            action.save(row, fn)
        pass

    # Save current stream URL into clipboard
    def menu_copy(self, w):
        gtk.clipboard_get().set_text(self.selected("url"))

    # Remove a stream entry