Index: channels/favicon.py ================================================================== --- channels/favicon.py +++ channels/favicon.py @@ -80,11 +80,11 @@ # Register with main def __init__(self, parent): # Prepare favicon cache directory - conf.icon_dir = conf.dir + "/icons" + conf.icon_dir = conf.datadir + "/icons" if not os.path.exists(conf.icon_dir): os.mkdir(conf.icon_dir) open(conf.icon_dir+"/.nobackup", "a").close() # Reference main, and register station .play() hook Index: config.py ================================================================== --- config.py +++ config.py @@ -11,11 +11,11 @@ # { arg: -D, type: boolean, name: debug, description: Enable debug messages on console } # { arg: action, type: str *, name: action[], description: CLI interface commands. } # { arg: -x, type: boolean, name: exit, hidden: 1 } # { arg: -V, type: boolean, name: version, description: Print version. } # { arg: -w, type: boolean, name: pydoc, hiden: 1 } -# version: 2.7 +# version: 2.8 # priority: core # depends: pluginconf >= 0.1, os, json, re, zlib, pkgutil # # Ties together the global conf.* object. It's typically used # in the main application and modules with: @@ -204,29 +204,38 @@ # http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html def xdg(self, path="/streamtuner2"): home = os.environ.get("HOME", self.tmp) config = os.environ.get("XDG_CONFIG_HOME", os.environ.get("APPDATA", home+"/.config")) - datadir = os.environ.get("XDG_DATA_HOME", os.environ.get("APPDATA", home+"/.cache")) + datadir = os.environ.get("XDG_CACHE_HOME", os.environ.get("APPDATA", home+"/.cache")) # storage dir self.dir = config + path - self.datadir = datadir + path # not actually used, for now we have subdir symlinks from .config to .cache + self.datadir = datadir + path # create if necessary if (not os.path.exists(self.dir)): os.makedirs(self.dir) if (not os.path.exists(self.datadir)): os.makedirs(self.datadir) - - # move/symlink cache files/dirs into datadir - if not self.windows: - for source, target in [(self.dir+"/"+sub, self.datadir+"/"+sub) for sub in ["cache", "icons", "themes"]]: - if os.path.exists(source) and not os.path.exists(target): + + # symlink subdirs from .config to .cache + self.xdg_move(self.dir, self.datadir, ["cache", "icons", "themes"]) + + # move/symlink cache files/dirs into datadir + def xdg_move(self, config_dir, cache_dir, folders): + if self.windows: + return + for sub in folders: + source, target = (dir+"/"+sub for dir in [config_dir, cache_dir]) + if not os.path.exists(target): + if os.path.exists(source): # move .config/* to .cache/* os.rename(source, target) - if os.path.exists(target) and not os.path.exists(source): - os.symlink(target, source) + else: + os.makedirs(target) # create .cache/* + if os.path.exists(target) and not os.path.exists(source): + os.symlink(target, source) # symlink .config → .cache # store some configuration list/dict into a file def save(self, name="settings", data=None, gz=0, nice=0): name = name + ".json" @@ -233,19 +242,20 @@ if (data is None): data = vars(self) if "args" in data: data.pop("args") nice = 1 + # target filename + file = self.dir + "/" + name # check for subdir if (name.find("/") > 0): subdir = name[0:name.find("/")] - subdir = self.dir + "/" + subdir + subdir = self.datadir + "/" + subdir if (not os.path.exists(subdir)): os.mkdir(subdir) open(subdir+"/.nobackup", "w").close() - # target filename - file = self.dir + "/" + name + file = self.datadir + "/" + name # encode as JSON try: data = json.dumps(data, indent=(4 if nice else None), sort_keys=True) except Exception as e: log.ERR("JSON encoding failed", e) @@ -265,11 +275,14 @@ f.close() # retrieve data from config file def load(self, name): name = name + ".json" - file = self.dir + "/" + name + if (name.find("/") > 0): + file = self.datadir + "/" + name + else: + file = self.dir + "/" + name try: # .gz or normal file if os.path.exists(file + ".gz"): f = gzip.open(file + ".gz", self.open_mode) elif os.path.exists(file): Index: contrib/cachereset.py ================================================================== --- contrib/cachereset.py +++ contrib/cachereset.py @@ -1,10 +1,10 @@ # encoding: UTF-8 # api: streamtuner2 # title: Cache Reset # description: Allows to empty cached stations and favicons -# version: 0.2 +# version: 0.3 # type: feature # category: config # priority: optional # hooks: config_load # @@ -51,12 +51,12 @@ self.l3 = self.t3.get_children()[0] # Update size labels def dialog_update(self, *w): - s1 = self.foldersize(conf.dir + "/cache") / 1024 - s2 = self.foldersize(conf.dir + "/icons") / 1024 + s1 = self.foldersize(conf.datadir + "/cache") / 1024 + s2 = self.foldersize(conf.datadir + "/icons") / 1024 s3 = self.foldersize(conf.tmp) / 1024 self.l1.set_text("Channels (%s KB)" % s1) self.l2.set_text("Icons (%s KB)" % s2) self.l3.set_text("Temp (%s KB)" % s3) @@ -70,14 +70,14 @@ return 0 # Actually delete stuff def execute(self, *w): - for dir, btn in [(conf.dir+"/cache/", self.t1), (conf.dir+"/icons/", self.t2), (conf.tmp+"/", self.t3)]: + for dir, btn in [(conf.datadir+"/cache/", self.t1), (conf.datadir+"/icons/", self.t2), (conf.tmp+"/", self.t3)]: # check if checked if not btn.get_state(): continue # list dir + delete files for fn in os.listdir(dir): os.unlink(dir + fn) open(dir + ".nobackup", "a").close() self.dialog_update() Index: help/favicon.page ================================================================== --- help/favicon.page +++ help/favicon.page @@ -24,11 +24,11 @@

Downloaded image files are meanwhile all sanitized (internally converted to ensure they're really image files). Albeit that's not strictly necessary for modern Gtk versions. (But better safe than sorry). -Images are kept in the ~/.config/streamtuner2/icons directory +Images are kept in the ~/.cache/streamtuner2/icons directory (or below %APPDATA%\ on Windows).

Index: help/pluginmanager2.page ================================================================== --- help/pluginmanager2.page +++ help/pluginmanager2.page @@ -52,11 +52,13 @@
User plugins -

Downloaded plugins are stored in ~/.config/streamtuner2/plugins/. +

Downloaded plugins are stored in ~/.config/streamtuner2/plugins/ + (not in ~/.cache, because they're sort of configuration + and should be backed up in case of local modifications). To remove them, delete the individual *.py files there manually. But keep the __init__.py stub.

On Windows they're stored in %APPDATA%\streamtuner2\plugins\.

Core plugins (those which are installed system-wide) can often also be updated. The user-saved plugin will Index: help/technical.page ================================================================== --- help/technical.page +++ help/technical.page @@ -37,10 +37,16 @@ <file>/home/$USER/.config/streamtuner2/</file>

Corresponds to the XDG_CONFIG_HOME setting. All ST2 configuration settings are contained within here and are in JSON format.

+ + <file>/home/$USER/.cache/streamtuner2/</file> +

Set from XDG_CACHE_HOME environment variable. Contains the + channel cache/ and icons/. Symlinks in .config + remain for convenience.

+
<file>~/.config/streamtuner2/settings.json</file>

General runtime options, plugin settings, and configured audio players.

@@ -54,25 +60,26 @@ <file>~/.config/streamtuner2/bookmarks.json</file>

Is a separate cache file for your bookmarked/favourite radio stations.

- <file>~/.config/streamtuner2/cache/***.json</file> -

JSON files for stream lists in each channel.

+ <file>~/.cache/streamtuner2/cache/***.json</file> +

Channel cache, with station/stream lists in JSON files.

- <file>~/.config/streamtuner2/icons/*.png</file> + <file>~/.cache/streamtuner2/icons/*.png</file>

Holds downloaded favicons for station homepages.

<file>~/.config/streamtuner2/plugins/*.py</file>

Contain downloaded contrib/ plugins.

On Windows the ~/.config/ directory is called %APPDATA% instead. The paths in there are equally - structured.

+ structured. On Linux ~/.cache/ is used to separate + temporary from configuration data.

Installation spread