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

⌈⌋ ⎇ branch:  streamtuner2


Check-in [276ae3ef5f]

Overview
Comment:Removed export_format config option for exportcat plugin (as that's selectable now in the file dialog anyway). Recategorized dnd plugin to appear earlier in the [features] config tab.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 276ae3ef5f9f5400f62bcd3dba2977843d376b5e
User & Date: mario on 2015-04-28 20:55:55
Other Links: manifest | tags
Context
2015-04-29
05:37
Also scroll to last category after .select_current (didn't automatically happen for current notebook.) check-in: 53bfeeff06 user: mario tags: trunk
2015-04-28
20:55
Removed export_format config option for exportcat plugin (as that's selectable now in the file dialog anyway). Recategorized dnd plugin to appear earlier in the [features] config tab. check-in: 276ae3ef5f user: mario tags: trunk
17:35
Move `state.json` and .current restoration into GenericChannel.gui(). Current category is reselected by TreeView traversal on instantion now. Previous state now load through config.state() for channels/__init__, not in main/init_app_state anymore (just row:expand / winsizes now). Disable .currentcat() overwriting, redundant now in display_categories(). Still need to avoid second .select_current() call in first_show(). check-in: ffaf262c43 user: mario tags: trunk
Changes

Modified Makefile from [50b1c88694] to [acb4436e93].

50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
pyz:
        #@BUG: relative package references leave a /tmp/doc/ folder
	$(PACK) -u packfile -s src -t zip --zip-shebang "/usr/bin/env python"	\
		-f -p "$(NAME)-$(VERSION).pyz" --prefix=./  .zip.py st2.py
src:
	cd .. && pax -wvJf streamtuner2/streamtuner2-$(VERSION).src.txz \
		streamtuner2/*.{py,png,svg,desktop} streamtuner2/channels/*.{py,png} \
		streamtuner2/{bundle/,help/,gtk,NEWS,READ,PACK,PKG,CRED,Make,bin,.zip}*

# test .deb contents
check:
	dpkg-deb -c streamtuner2*deb
	dpkg-deb -I streamtuner2*deb
	rpm -qpil *rpm








|







50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
pyz:
        #@BUG: relative package references leave a /tmp/doc/ folder
	$(PACK) -u packfile -s src -t zip --zip-shebang "/usr/bin/env python"	\
		-f -p "$(NAME)-$(VERSION).pyz" --prefix=./  .zip.py st2.py
src:
	cd .. && pax -wvJf streamtuner2/streamtuner2-$(VERSION).src.txz \
		streamtuner2/*.{py,png,svg,desktop} streamtuner2/channels/*.{py,png} \
		streamtuner2/{bundle/,contrib/,help/,gtk,NEWS,READ,PACK,PKG,CRED,Make,bin,.zip}*

# test .deb contents
check:
	dpkg-deb -c streamtuner2*deb
	dpkg-deb -I streamtuner2*deb
	rpm -qpil *rpm

Modified channels/dnd.py from [b8955f0866] to [af2a92a118].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# encoding: UTF-8
# api: streamtuner2
# title: Drag and Drop (experimental)
# description: Copy streams/stations from and to other applications.
# depends: uikit
# version: 0.5
# type: interface
# config:
#   { name: dnd_format, type: select, value: xspf, select: "pls|m3u|xspf|jspf|asx|smil|desktop", description: "Default temporary file format for copying a station." }
# category: ui
# priority: default
# support: experimental
#
# Implements Gtk/X11 drag and drop support for station lists.
# Should allow to export either just stream URLs, or complete
# PLS, XSPF collections.
#






|


|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# encoding: UTF-8
# api: streamtuner2
# title: Drag and Drop (experimental)
# description: Copy streams/stations from and to other applications.
# depends: uikit
# version: 0.5
# type: feature
# config:
#   { name: dnd_format, type: select, value: xspf, select: "pls|m3u|xspf|jspf|asx|smil|desktop", description: "Default temporary file format for copying a station." }
# category: io
# priority: default
# support: experimental
#
# Implements Gtk/X11 drag and drop support for station lists.
# Should allow to export either just stream URLs, or complete
# PLS, XSPF collections.
#

Modified channels/exportcat.py from [911a034c54] to [66f2154eb8].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# encoding: UTF-8
# api: streamtuner2
# title: Export Category
# description: Exports a complete channel category (all stations into one file).
# version: 0.2
# type: feature
# category: file
# priority: optional
# config:
#   { name: export_format, value: xspf, type: select, select: "pls|xspf|m3u|jspf|smil|asx|json", description: Default export format. }
# hooks: config_save
#
# Adds a context menu "Extensions > Export all", which can be used
# in any channel and category to save all stations into one playlist.
# Defaults to exporting as .PLS file, but meanwhile can be used for
# XSPF or old M3U files as well.








|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# encoding: UTF-8
# api: streamtuner2
# title: Export Category
# description: Exports a complete channel category (all stations into one file).
# version: 0.2
# type: feature
# category: file
# priority: optional
# -disabled-config:
#   { name: export_format, value: xspf, type: select, select: "pls|xspf|m3u|jspf|smil|asx|json", description: Default export format. }
# hooks: config_save
#
# Adds a context menu "Extensions > Export all", which can be used
# in any channel and category to save all stations into one playlist.
# Defaults to exporting as .PLS file, but meanwhile can be used for
# XSPF or old M3U files as well.
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
            uikit.add_menu([parent.extensions, parent.extensions_context], "Export all stations", self.savewindow)

    # Fetch streams from category, show "Save as" dialog, then convert URLs and export as playlist file
    def savewindow(self, *w):
        cn = self.parent.channel()
        source = cn.listformat
        streams = cn.streams[cn.current]
        fn = uikit.save_file("Export category", None, "%s.%s.%s" % (cn.module, cn.current, conf.export_format))
        log.PROC("Exporting category to", fn)
        if fn:
            dest = re.findall("\.(m3u|pls|xspf|jspf|json|smil|asx|desktop|url)8?$", fn.lower())
            if dest:
                dest = dest[0]
            else:
                self.parent.status("Unsupported export playlist type (file extension).")
                return
            action.save_playlist(source="asis", multiply=False).file(rows=streams, fn=fn, dest=dest)
        pass            







|










46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
            uikit.add_menu([parent.extensions, parent.extensions_context], "Export all stations", self.savewindow)

    # Fetch streams from category, show "Save as" dialog, then convert URLs and export as playlist file
    def savewindow(self, *w):
        cn = self.parent.channel()
        source = cn.listformat
        streams = cn.streams[cn.current]
        fn = uikit.save_file("Export category", None, "%s.%s.%s" % (cn.module, cn.current, "xspf"))
        log.PROC("Exporting category to", fn)
        if fn:
            dest = re.findall("\.(m3u|pls|xspf|jspf|json|smil|asx|desktop|url)8?$", fn.lower())
            if dest:
                dest = dest[0]
            else:
                self.parent.status("Unsupported export playlist type (file extension).")
                return
            action.save_playlist(source="asis", multiply=False).file(rows=streams, fn=fn, dest=dest)
        pass            

Modified st2.py from [f820dd49d8] to [64a9872a0a].

422
423
424
425
426
427
428

429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
                # or .features{} for other plugin types
                else:
                    self.features[name] = plugin_obj
                
            except Exception as e:
                log.INIT("load_plugin_channels: error initializing:", name, ", exception:")
                traceback.print_exc()


    # load application state (widget sizes, selections, etc.)
    def init_app_state(self):
        winlayout = conf.load("window")
        if (winlayout):
            try: uikit.app_restore(self, winlayout)
            except Exception as e: log.APPSTATE_RESTORE(e) # may fail for disabled/reordered plugin channels

        #winstate = conf.state()    # now handled by channels.gui() already
        #if (winstate):
        #    for id,prev in winstate.items():
        #        try: self.channels[id].current = prev["current"]
        #        except Exception as e: log.APPSTATE_RESTORE(e)

    # store window/widget states (sizes, selections, etc.)
    def save_app_state(self, widget):
        # gtk widget states
        widgetnames = ["win_streamtuner2", "toolbar", "notebook_channels", ] \
                    + [id+"_list" for id in self.channel_names] \
                    + [id+"_cat" for id in self.channel_names]







>








<
<
<
<
<







422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437





438
439
440
441
442
443
444
                # or .features{} for other plugin types
                else:
                    self.features[name] = plugin_obj
                
            except Exception as e:
                log.INIT("load_plugin_channels: error initializing:", name, ", exception:")
                traceback.print_exc()


    # load application state (widget sizes, selections, etc.)
    def init_app_state(self):
        winlayout = conf.load("window")
        if (winlayout):
            try: uikit.app_restore(self, winlayout)
            except Exception as e: log.APPSTATE_RESTORE(e) # may fail for disabled/reordered plugin channels







    # store window/widget states (sizes, selections, etc.)
    def save_app_state(self, widget):
        # gtk widget states
        widgetnames = ["win_streamtuner2", "toolbar", "notebook_channels", ] \
                    + [id+"_list" for id in self.channel_names] \
                    + [id+"_cat" for id in self.channel_names]