More than two months ago I globed about QStrings and
paths.
The problem was this: my app accepts paths via command line, which are
processed via KCmdLineOptions; which in turn converts everything to
QStrings. What I wanted were paths, which are more like QByteArrays, not
QStrings (because the latter have internally an unicode representation;
more on that later). Including PyQt4 in the equation forced me to resort
to QByteArray to get the path as a str instead of using
QString.constData() (PyQt4 doesn't export that function). But that's
only the beginning of the problem.
Take for instance this situation. I have a music collection that I've been
building for years now (more that 10, I think). In the old times of this
collection the filenames were encoded in iso-8859-1. Then the future came
and converted all my machines to utf-8. But only the software; the
filesystems were in one way or another inherited from system to system, from
machine to machine. So I ended with a mixture of utf and iso filenames, to
the point where I have a file whose filename is in iso, but the directory
where it is is in utf. Yes, I know, it is a mess. But if I take any decent
media player, I can play the file allright. That's because the filesystem
knows nothing of encodings (otherwise it would reject badly encoded
filenames).
I just spent last saturday making sure that satyr only stored filepaths in
strs, not unicodes or QStrings. It took concentration, but having just
a bunch of classes and only 3 or 4 points where the filepaths are managed it
wasn't that difficult. Still, it took a day. But then, as I mentioned in
that post, Phonon the is not able to play such files... or so I thought.
If you run satyr after executing export PHONON_XINE_DEBUG=1 you'll see a
lot of Phonon debug info in the console (not that there is another way to
run satyr right now anyways). Among all that info you'll see lines such as
these two:
void Phonon::Xine::XineStream::setMrl(const QByteArray&, Phonon::Xine::XineStream::StateForNewMrl) ...
bool Phonon::Xine::XineStream::xineOpen(Phonon::State) xine_open succeeded for m_mrl = ...
If you're sharp enough (I'm not; sandsmark from #phonon had to tell me)
you'll note the mention of MRL's. MRL's are xine's URL for media. As any
URL, they can (and most of the time must) encode 'strange' characters with
the so-called "percent encoding". This means that no matter what encodings
the different parts of a filepath is in, I just add file:// at the
beginning and then I can safely encode it scaping non-ascii characters to
%xx representations... or that's what the theory says. One thing to note is
that the file:// part must not be scaped; xine complains that the file
does not exist in that case.
Looking for help in Qt's classes one can find QUrl and the already known
QByteArray. I can call QByteArray.toPercentEnconding() from my str and
feed that to QUrl.fromPercentEncoding() (which strangely returns a
QString, which is exactly what we're avoiding) or QUrl.fromEncoded().
But then the first function encodes too much, replacing :// with
%3A%2F%2F. No fun.
Ok, let's try creating a QByteArray with only the file:// and then
append() the toPercentEncoding() of the path only. It works:
PyQt4.QtCore.QByteArray('file://%2Fhome%2Fmdione...%2F%C3%9Altimo%20bondi%20a%20Finisterre%2F07-%20La%20peque%F1a%20novia%20del%20carioca.wav')
But then calling QUrl.fromEncoded() gives:
PyQt4.QtCore.QUrl("file://xn--/home/mdione.../ltimo bondi a finisterre/07- la pequea novia del carioca-wkmz60758d.wav")
The URL got somehow puny-encoded,
which of course xine doesn't recognize for local files.
Another option is to create an empty QUrl, call setEncodedUrl() with
the ParsingMode to QUrl.StrictMode so we avoid 50 lines of code that start
here[1]
that try to escape everything all over again (and I already had some
double-or-even-triple-enconding nightmares parsing RSS/Atom feeds last year,
thank you), but we get puny-encoded again (maybe it is 'pwny-encoded'?).
Last resort: backtrack to the point were we created only one QByteArray
with the path and call toPercentEncoding(); feed that to the method
setEncodedPath() of an empty QUrl. Then we add the last piece calling
setScheme('file') and we're ready! Of course we're not:
PyQt4.QtCore.QByteArray('file:%2Fhome%2Fmdione...%2F%C3%9Altimo%20bondi%20a%20Finisterre%2F07-%20La%20peque%F1a%20novia%20del%20carioca.wav')
Notice the lack of the two // after file:? xine doesn't like it;
hence, I don't either.
Ok, this post got too long. I hope I can resolve this soon, I already spent too much time on it. At least a good part of it was expaining it, so others don't have to suffer the same as I did.
BTW, satyr will shortly be released, whether I fix this bug or not.
[1] Look at the size of that file! 6k lines to handle URL's! Who would say it was so difficult... Once more I'm remembered of how lucky I am to have this libraries at the tips of my fingers, yay!
Some directives that use PageSpecs allow specifying the order that matching pages are shown in. The following sort orders can be specified.
age- List pages from the most recently created to the oldest.mtime- List pages with the most recently modified first.title- Order by title.title_natural- Only available if [[!cpan Sort::Naturally]] is installed. Orders by title, but numbers in the title are treated as such, ("1 2 9 10 20" instead of "1 10 2 20 9")
For a couple of months I've been globbing about PyKDE4 stuff, and laterally
talking about my last project: satyr. satyr (it's name should always be
written in lowercase) should have the following features:
- The PlayList and the Collection(s)[0] are the same thing.
- Yours is a Collection of Albums, nothing else[3].
- Some Albums are from the same artists and some are compilations[3].
- If you want an ephemeral playlist you could queue songs[1].
- If you want non-ephemeral playlists, then this player is not for you.
- Ability to search à la
xmms, but in the same interface[2] - Tag reading and writing[3].
- Order you collection based on the tags[3].
- The collection discovers new files and adds them to the playlist on the fly[4].
- Be able to use all the program only with your keyboard (die, mouse, die!)
This and other features should be available soon. The coding has been fast
lately, mainly because the Qt/KDE libs are fantastic to work with. The only
thing I couldn't do was to read the tags before playing them, so I relied
into the kaa libraries.
The project is hosted in
savannah, and right now there
is no tarball (It's marked as alpha state because I sent a couple of
tarballs to some friends who asked for them), so the only way right now is
to branch anonimously the bazaar
repo. I hope you download and
enjoy it as much as I do.
[0] The support for several collections is not complete yet.
[1] Functionality available via dbus only at the moment.
[2] This is with the current GUI. I'm also thinking in several/pluginable GUI's
[3] Not yet available.
[4] Of course this only works if it's running. Otherwise, you can always ask for a rescanning[1].