Friday, October 23, 2009

Windows 7 editions

Did you know there's an entire article on Wikipedia about the various Windows 7 editions? Talk about confusing.

Sunday, October 11, 2009

RhythmToWeb moved to Google Code

I have moved the RhythmToWeb project to Google code. Apart from a small bugfix (it used to send empty requests every x seconds when Rhythmbox was first started), I have also added a couple of server-side examples.

Saturday, October 10, 2009

Apache nice URLs without mod_rewrite

I recently noticed a peculiar behavior in Apache. It seems that if I have, for example, a file /var/www/hello.php, the following URLs will load the same file:
  • http://localhost/hello.php
  • http://localhost/hello
  • http://localhost/hello/goodbye/
After a bit of researching, I found that this behavior is dictated by MultiViews, so if you have that option turned on on your server you can practically forget about rewriting URLs and use this instead.

The only situation I can imagine where you would absolutely need mod_rewrite is if you need to have URLs like http://example.com/1234, you can't handle that with MultiViews (but you can handle http://example.com/article/1234).

Monday, October 5, 2009

RhythmToWeb Updated

I've recently received an e-mail from Aaron Hill, about some modifications he's done to RhythmToWeb. I took his idea of storing information about more than one song, and adapted it in my own way. You can now use the buttons under the song information on the right to browse the last 5 songs I've played. It will also automatically refresh, so if you wait around long enough you'll see it switch to a new song when I start playing one (I really don't know who I'm kidding, no one will ever wait on my blog to see when my song changes :P). Anyway, on to the code: PHP, this gets called by Rhythmbox: <?php define('CALLBACK', 'rtw_callback'); define('JS_FILE', 'nowplaying.js'); define('MAX_ENTRIES', 5); define('SERIALIZE_FILE', './data'); function test_value($var) { if ( strlen($var) && mb_strtolower($var) != 'unknown' && $var != '0' ) { return true; } return false; } $song_info = array(); foreach ($_GET as $key => $value) { if (test_value($value)) { $song_info[$key] = $value; } } $last_songs = unserialize(file_get_contents(SERIALIZE_FILE)); if ($last_songs === false) $last_songs = array(); elseif (count($last_songs) >= MAX_ENTRIES) { while (count($last_songs) >= MAX_ENTRIES) { array_shift($last_songs); } } $last_songs[] = $song_info; file_put_contents(SERIALIZE_FILE, serialize($last_songs)); file_put_contents(JS_FILE, CALLBACK . '(' . json_encode($last_songs) . ')'); ?>
Syntax Highlighting by Pygmentool
HTML, this is in the HTML widget on my blog: <div id="rtw_info">Loading...</div> <button style="padding: 2px 3px; font-size: 0.6em; background: #454545; border: solid 1px #7f7f7f; color: #fff; font-weight: bold; float: right" onclick="rtw_newer()" title="Show more recent songs">&gt;</button> <button style="padding: 2px 3px; font-size: 0.6em; background: #454545; border: solid 1px #7f7f7f; color: #fff; font-weight: bold" onclick="rtw_older()" title="Show older songs">&lt;</button> <script type="text/javascript"> rtw_songs = null; rtw_curIndex = 0; rtw_script_url = "http://znupi.no-ip.org/felix/nowplayingv2/nowplaying.js"; function rtw_callback(aSongs) { // store the received data and show the last song played if (rtw_songs == null || rtw_songs[0].title != aSongs[0].title) { rtw_songs = aSongs; rtw_curIndex = aSongs.length - 1; rtw_update(); } } function rtw_refresh() { var script = document.createElement('script'); script.src = rtw_script_url + "?" + Math.random(); document.body.appendChild(script); setTimeout(rtw_refresh, 5000); } function rtw_older() { if (rtw_songs === null) return; if (rtw_curIndex > 0) { rtw_curIndex --; rtw_update(); } } function rtw_newer() { if (rtw_songs === null) return; if (rtw_curIndex < rtw_songs.length - 1) { rtw_curIndex ++; rtw_update(); } } function rtw_update() { // update the DOM var toFill = document.getElementById('rtw_info'); // first, clear everything in the div while (toFill.childNodes.length) { toFill.removeChild(toFill.childNodes[0]); } // now fill it according to what data we have var curSong = rtw_songs[rtw_curIndex]; // no data: if (curSong.length == 0) { toFill.appendChild(document.createTextNode('Nothing currently playing.')); } // some data: else { var b; if (curSong.title) { b = document.createElement("b"); b.appendChild(document.createTextNode("Song: ")); toFill.appendChild(b); toFill.appendChild(document.createTextNode(curSong.title)); toFill.appendChild(document.createElement("br")); } if (curSong.artist) { b = document.createElement("b"); b.appendChild(document.createTextNode("By: ")); toFill.appendChild(b); toFill.appendChild(document.createTextNode(curSong.artist)); toFill.appendChild(document.createElement("br")); } if (curSong.album) { b = document.createElement("b"); b.appendChild(document.createTextNode("From: ")); toFill.appendChild(b); toFill.appendChild(document.createTextNode(curSong.album)); toFill.appendChild(document.createElement("br")); } if (curSong.genre) { b = document.createElement("b"); b.appendChild(document.createTextNode("Genre: ")); toFill.appendChild(b); toFill.appendChild(document.createTextNode(curSong.genre)); toFill.appendChild(document.createElement("br")); } if (curSong.year) { b = document.createElement("b"); b.appendChild(document.createTextNode("Year: ")); toFill.appendChild(b); toFill.appendChild(document.createTextNode(curSong.year)); toFill.appendChild(document.createElement("br")); } if (curSong.duration) { b = document.createElement("b"); b.appendChild(document.createTextNode("Length: ")); toFill.appendChild(b); var len = parseInt(curSong.duration); var mins = Math.floor(len / 60); var secs = len % 60; toFill.appendChild(document.createTextNode(mins + ":" + secs)); toFill.appendChild(document.createElement("br")); } } } rtw_refresh(); </script>
Syntax Highlighting by Pygmentool
Pretty kewl, eh?