stupid nano
This will allow you to change the default editor of you system. Works for most if not all debian derivatives. SVN commits were really annoying until I switched over to VI.
$ sudo update-alternatives --config editor
file enumeration by readable timestamp
This little bash command let's us order files sequentially based on their actual time while being human readable using. This uses the full year and 24 hour time format.
FORMAT: FILE.date +%Y-%m-%d_%H-%M-%S
OUTPUT: FILE.2010-02-25_11-50-32
Playlist.com + YQL + PHP = true XSPF
The second round of this moves most of the labor off of the PHP side and onto YQL. YQL now handles the normalization of the XSPF. I still need PHP to make sure the node structure is correct though since YQL provides XML with a root node of "query" not "playlist".
The original PHP file can be found here in case you're wondering about the decryption mechanism.
And the original post can be found here.
Let's look at an example for one of my playlists on playlist.com. The playlist is called "Hit List" and is located at http://www.playlist.com/playlist/18903645451.
To access the xspf feed for this playlist use the original feed at http://pl.playlist.com/pl.php?playlist=73842365.
To load the correct/standardized xspf feed use the proxy at http://chronx.info/lib/ef.ymp.playlistProxy.php?playlist=73842365.
Below is a look at the file "http://github.com/oxchronxo/YMP/raw/master/ef.ymp.playlistProxy.php"
header("Content-Type: application/xspf+xml"); // start a buffer ob_start(); // create document to work with $dom = new DOMDocument("1.0", "UTF-8"); // grab playlist id $playlist = $_GET["playlist"]; if ($playlist) { // fetch normalized xml using yql $xml = simplexml_load_file("http://query.yahooapis.com/v1/public/yql?q=USE%20%22http%3A%2F%2Fgithub.com%2Foxchronxo%2FYQL%2Fraw%2Fmaster%2Fplaylist.com.db.table.xml%22%20AS%20playlists%3B%0ASELECT%20*%20FROM%20playlists%20WHERE%20playlist%3D" . $playlist . "%3B&format=xml"); // attach to document $dom->loadXML($xml->results->playlist->asXML()); } // export as xml echo $dom->saveXML(); // send buffer ob_end_flush();
And for those wondering about the table structure located at "http://github.com/oxchronxo/YQL/raw/master/playlist.com.db.table.xml" ?
You can check out the results here
<table xmlns="http://query.yahooapis.com/v1/schema/table.xsd"> <meta> <author>Eric Fehrenbacher</author> <sampleQuery>select * from playlists where playlist=@playlist</sampleQuery> </meta> <bindings> <select itemPath="" produces="XML"> <urls> <url>http://pl.playlist.com/pl.php</url> </urls> <inputs> <key id="playlist" type="xs:string" paramType="variable" required="true"/> </inputs> <execute><![CDATA[ y.include("http://github.com/oxchronxo/YQL/raw/master/playlist.com.db.table.js"); var url = "http://pl.playlist.com/pl.php?playlist=" + playlist; var xml = y.rest(url).get().response; // standardize format //<meta http-equiv="Cache-Control" content="no-cache"/> //<meta http-equiv="Pragma" content="no-cache"/> var xspf = <playlist xmlns="http://xspf.org/ns/0/" version="0"> <id>{playlist}</id> <url>{url}</url> <title>{xml.title.text()}</title> </playlist>; // cleanup tracks for (var i = 0, track = ""; i < xml.trackList.track.length(); i++) { track = xml.trackList.track[i]; // normalize track location track.location = !track.location.split("").length ? track.originallocation : decrypt(track.location); // add aliases track.img = String(track.image) || ""; track.title = String(track.tracktitle) || ""; // clear empty fields if (track.album == "Untitled") { track.album = ""; } // remove attributes delete track.@*; // remove nodes delete track.trackid; delete track.bluewireid; delete track.annotation; delete track.originallocation; } //append the tracklist xspf.trackList = xml.trackList; response.object = xspf; ]]></execute> </select> </bindings> </table>
And the content of the "http://github.com/oxchronxo/YQL/raw/master/playlist.com.db.table.js" file ?
function decrypt(src) { var key = "sdf883jsdf22"; var str = ""; var sbx = []; var mky = []; var ptx = []; var psw = []; var chr = []; ptx_a = (src.substr(0, 2) == "0x") ? 2 : 0; while (ptx_a < src.split("").length) { ptx.push(parseInt(src.substr(ptx_a, 2), 16)); ptx_a += 2; } delete ptx_a; psw_a = 0; while (psw_a < key.split("").length) { psw.push(key.charCodeAt(psw_a)); ++psw_a; } delete psw_a; nit_a = 0; nit_b = 0; while (nit_b <= 255) { mky[nit_b] = psw[nit_b % psw.length]; sbx[nit_b] = nit_b; ++nit_b; } delete nit_b; nit_c = 0; nit_d = 0; while (nit_c <= 255) { nit_a = (nit_a + sbx[nit_c] + mky[nit_c]) % 256; nit_d = sbx[nit_c]; sbx[nit_c] = sbx[nit_a]; sbx[nit_a] = nit_d; ++nit_c; } delete nit_a; delete nit_c; delete nit_d; chr_a = 0; chr_b = 0; chr_d = 0; chr_e = 0; chr_f = 0; chr_g = 0; chr_h = 0; while (chr_h < ptx.length) { chr_a = (chr_a + 1) % 256; chr_b = (chr_b + sbx[chr_a]) % 256; chr_e = sbx[chr_a]; sbx[chr_a] = sbx[chr_b]; sbx[chr_b] = chr_e; chr_d = sbx[(sbx[chr_a] + sbx[chr_b]) % 256]; chr_f = ptx[chr_h] ^ chr_d; chr.push(chr_f); ++chr_h; } delete chr_a; delete chr_b; delete chr_d; delete chr_e; delete chr_f; delete chr_g; delete chr_h; str_a = 0; while (str_a < chr.length) { str += String.fromCharCode(chr[str_a]); ++str_a; } delete str_a; return str; }
And shutup about my style, this is all adhoc... cleanup comes l8r.
Want XSPF playlists from playlist.com ?
Recently I found that I could not use the playlists I had created on playlist.com in my media player. The quick and short of this is that they are not providing a standardized XSPF format in their RSS feed.
All I really had to do was determine how to decrypt their hash which was pretty easy thanks to OneWeirdKid90, rename a few fields, and export a correctly formatted XSPF file. Below is the resultant code. I am using the script to access all the playlists on this site via playlist.com.
function hexToChars($hex) { $a = array(); $b = (substr($hex, 0, 2) == "0x") ? 2 : 0; while ($b < strlen($hex)) { array_push($a, intval(substr($hex, $b, 2), 16)); $b += 2; } return $a; } function charsToStr($chars) { $a = ""; $b = 0; while ($b < count($chars)) { $a .= chr($chars[$b]); ++$b; } return $a; } function strToChars($str) { $a = array(); $b = 0; while ($b < strlen($str)) { array_push($a, ord($str[$b])); ++$b; } return $a; } function calculate($plaintxt, $psw) { $sbox = array(); $mykey = array(); $a = 0; $b; $c = count($psw); $d = 0; while ($d <= 255) { $mykey[$d] = $psw[$d % $c]; $sbox[$d] = $d; ++$d; } $d = 0; while ($d <= 255) { $a = ($a + $sbox[$d] + $mykey[$d]) % 256; $b = $sbox[$d]; $sbox[$d] = $sbox[$a]; $sbox[$a] = $b; ++$d; } $a = 0; $b = 0; $c = array(); $d; $e; $f; $g = 0; while ($g < count($plaintxt)) { $a = ($a + 1) % 256; $b = ($b + $sbox[$a]) % 256; $e = $sbox[$a]; $sbox[$a] = $sbox[$b]; $sbox[$b] = $e; $h = ($sbox[$a] + $sbox[$b]) % 256; $d = $sbox[$h]; $f = $plaintxt[$g] ^ $d; array_push($c, $f); ++$g; } return $c; } function decrypt($src, $key) { return charsToStr(calculate(hexToChars($src), strToChars($key))); } $hashKey = "sdf883jsdf22"; $playlist = $_GET["playlist"]; if (!$playlist) { exit; } $url = "http://pl.playlist.com/pl.php?playlist=".$playlist; $dom = new DOMDocument("1.0", "UTF-8"); $dom->formatOutput = true; $playlist = $dom->createElement("playlist"); $playlist->setAttribute("version", "0"); $playlist->setAttribute("xmlns", "http://xspf.org/ns/0/"); $dom->appendChild($playlist); $metaCacheControl = $dom->createElement("meta"); $metaCacheControl->setAttribute("http-equiv", "Cache-Control"); $metaCacheControl->setAttribute("content", "no-cache"); $playlist->appendChild($metaCacheControl); $metaPragma = $dom->createElement("meta"); $metaPragma->setAttribute("http-equiv", "Pragma"); $metaPragma->setAttribute("content", "no-cache"); $playlist->appendChild($metaPragma); $info = $dom->createElement("info", $url); $playlist->appendChild($info); $contents = file_get_contents($url, "r"); if (!empty($contents)) { $xml = new SimpleXMLElement($contents); if (!empty($xml)) { $title = $dom->createElement("title", $xml->title); $playlist->appendChild($title); $trackList = $dom->createElement("trackList"); $playlist->appendChild($trackList); if ($xml->trackList && (count($xml->trackList) > 0)) { foreach ($xml->trackList->track as $item) { $track = $dom->createElement("track"); $trackList->appendChild($track); $location = $dom->createElement("location"); $usableLocation = empty($item->location) ? $item->originallocation : decrypt($item->location, $hashKey); $location->appendChild($dom->createTextNode($usableLocation)); $track->appendChild($location); $title = $dom->createElement("title"); $title->appendChild($dom->createTextNode($item->tracktitle)); $track->appendChild($title); $creator = $dom->createElement("creator"); $creator->appendChild($dom->createTextNode($item->artist)); $track->appendChild($creator); /* $duration = $dom->createElement("duration"); $creator->appendChild($dom->createTextNode($item->duration)); $track->appendChild($duration); */ /* $album = $dom->createElement("album"); $creator->appendChild($dom->createTextNode($item->album)); $track->appendChild($album); */ /* $image = $dom->createElement("image"); $creator->appendChild($dom->createTextNode($item->image)); $track->appendChild($image); */ } } } } header("Content-Type: application/xspf+xml"); echo $dom->saveXML();