write a plugin
Writing a new plugin is often trivial.
Just create a new channels/myplugin.py
following this structure:
# title: MyPlugin
# description: my radio list
# url: http://www.mymusicstation.com/
# version: 0.1
# type: channel
# category: radio
# priority: optional
# config: -
from config import *
from channels import *
import ahttp
class myplugin (ChannelPlugin):
has_search = False
titles = dict(listeners=False)
categories = []
catmap = {}
listformat = "pls"
def update_categories(self):
self.categories = ["Pop", "Rock", "etc"]
def update_streams(self, cat, search=None):
entries = []
# ...
# get it from somewhere
# ...
return entries
The class name must match the script basename.
Plugin meta block
The description block on top is used for the plugin management (and documentative purposes). This is meant to cleanly separate in-application values (like .module or .has_search, .catmap) from attributes that just serve initialization.
All fields show up in self.meta
, for instance the meta["title"]
or meta["url"]
are occasionally used. The config[]
entry is a list/dict combination, and its defaults automatically thrown into conf.*
variables. Therefore plugins can use their settings right away (e.g. conf.myplugin_bitrate=128
)
update_categories()
Each plugin needs a update_categories()
method. This can be a stub, if the channel plugin has a static list of genres. If so, just set the categories = [...]
declaration right away. The method is only used if the default categories list is empty, needs to be renewed from the service (e.g. whenever the menu entry Channel>Update_categories is used). There's also a catmap={}
dict in case category/genre titles have to be associated with service ids.
update_streams()
More importantly you need the update_streams()
method to fetch station lists. It receives a cat
parameter, for instance "Pop"
. Then do whatever API query or website scraping (regex/pyquery) is necessary to populate a list.
ahttp.get()
for fetching resourcespq()
to use PyQuery- or import
json
etc.
Most plugins will return a list of dicts like:
[
{title: Radio123, url: http://pls, genre: Pop, playing: Song123},
{title: Next.Radio, url: http://pls, genre: Pop, playing: Next Song},
...
]
The title is required, and the streaming URL of course. Other fields are mostly optional.
Standard fields are:
- genre - the category name
- title - station title
- url - streaming url (to pls or m3u resource)
- playing - currently playing song, if any
- homepage - station homepage
- bitrate - (int) audio bitrate (like 128)
- listeners - (int) number of listeners
- format - to set a custom audio format (audio/ogg)
- listformat - url playlist type (pls)
Internal fields are:
- favicon - path to localized favicon, either from homepage or img url
- state - a gtk icon
- deleted - strikethrough for deleted entries
- favourite - add a star for bookmarked stations
- search_col - search color
- search_set - search state
Often you just want to rename the column titles however - per
title=dict(listeners="Whatever")
in the class declaration.
You can add any additional fields of your choosing.
streams = {}
Received station lists get stored internally in a streams={"Pop":[...]}
dict, and cached in the ~/.config/streamtuner2/cache/
directory of course.
conf. options
You can access your config: options through the global conf.*
dict. Take care to prefer unambigious names like conf.myplugin_pagesize
etc.
Attributes
There are a couple of possible class/object flags.
has_search
= False
This flag documents if live server searches are available. If it's supported, then theupdate_streams()
method may be called withcat=None
andsearch="Find me maybe"
instead; and is then responsible to do some searching.audioformat
= "audio/mpeg"
Sets the default audio stream type for this channel. (Note that each individual stream entry may carry its ownformat
attribute, just in case.)listformat
= "pls"
Declares the channel service playlist type. Can be either "pls" or "m3u" or "xspf" if the server is super modern. Most directories providehttp://myradiolist.com/listen-12345.pls
URLs, so should use"pls"
here. It's also possible to use "href" here, if you can't be sure of audio or playlist format types. And "srv" if the provider has a clean list of direct MP3/Ogg streaming URLs only.titles =
dict(listeners=False)
This defines which station column titles to show. There are title=, genre= which you commonly have. And there is playing= or bitrate= and homepage= which you can omit by setting it to=False
. Alternatively just rename them withplaying="Artist/Album name"
.datamap =
[...]
If you want some complexity, such as elaborate column title renaming, extra pixmaps/favicons, or using custom row fields/attributes - then this can all be accomplished with a Gtk TreeView datamap. No, you don't want to do that.Other internal fields are listed in
channels/__init__.py
Installation
To have a new plugin picked up, you need to copy/symlink the file into /usr/share/streamtuner2/channels/
. It's imported from the channels
module group automatically. Which allows relocatability, or loading it from ~/.config/streamtuner/plugins/ even.