Click to install this script

DJ Steveboy: Playlist Displayer

  • Added: October 27, 2007
  • Last Updated: October 27, 2007

File Name: djsteveboy_playlist.user.js

Click to hide sectionDescription

DJ Steve Boyett is a talented DJ (and apparently a writer as well) who has two podcasts (Podrunner and Groovelectic) that I currently am loving. However, I didn't really like certain aspects of his site. I was particularly aggravated by the following:
  • Clicking the faux-download link under the "latest mix" doesn't start the download process, but rather opens up another section that has download instructions and a true download button to actually download the file. I don't need no stinkin' instructions— I just want the file.
  • Expanding a description for a particular mix doesn't show the playlist. Sure, I can click another link to get the playlist, but who has time for that?
  • There is no way to view all mix descriptions at once.

This script fixes all that- the download link now initiates the download, playlists are displayed when a mix is expanded, and an Expand/Collapse All Descriptions link is added under the "Archive" header.

Screenshot of script modifications

Click to hide sectionScript Source

// DJ Steveboy: Playlist Displayer // Copyright (c) 2006-2007 Orbona // Version 1.0 // Release Date: 2007-10-22 // // See also: http://www.orbona.com/greasemonkey/ // // Original file name: djsteveboy_playlist.user.js // Please reference the original file name when contacting me regarding this // script. // // This software is licensed under the CC-GNU GPL: // http://creativecommons.org/license/cc-gpl // // ---------------------------------------------------------------------------- // DESCRIPTION // // Adds the track listing to the expanded "archive" entries on DJ Steveboy's // site. Also modifies the "Download" link under the latest offering so that // it actually initiates a download, instead of expanding the section that // explains how to download a file. // ---------------------------------------------------------------------------- // ==UserScript== // @name DJ Steveboy: Playlist Displayer // @description Includes the track listing when expanding the "archive" entries on DJ Steveboy's site // @namespace http://www.orbona.com/greasemonkey/ // @include http://www.djsteveboy.com/groovelectric.html // @include http://www.djsteveboy.com/podrunner.html // @include http://www.djsteveboy.com/intervals.html // @include http://djsteveboy.com/groovelectric.html // @include http://djsteveboy.com/podrunner.html // @include http://djsteveboy.com/intervals.html // ==/UserScript== String.prototype.startsWith = function(s) { return this.indexOf(s)==0; } String.prototype.endsWith = function (str) { var offset = this.length - str.length; return offset >= 0 && this.lastIndexOf(str) === offset; }; // ---------------------------------------------------------------------------- // Retrieves the playlist based on the "id" associated with the button/link/ // whatever that was clicked // ---------------------------------------------------------------------------- function showPlaylist(event) { var target = event ? event.target : this; var id = target.id; if (!id && target.parentNode) id = target.parentNode.id; if (id.startsWith('link')) id = id.substr(4) unsafeWindow.retrievePlaylist(id); } // ---------------------------------------------------------------------------- // Main function that does everything described in the description area above. // ---------------------------------------------------------------------------- function doIt() { var currentDownloadSection; if (document.URL.endsWith('intervals.html')) currentDownloadSection = document.getElementById('qC') ; else currentDownloadSection=document.getElementById('qB') || document.getElementById('q2'); var regexID = /showParagraph\('([^)]+)'\)/im; var allShowParagraphs=""; var i, archiveDiv, expandCollapseAll, actualDownloadLink, oldDownloadLinks, oldDownloadLink, thisLink, paragraphID, pID, script, scriptText, paragraphLinks, divsSetHeight,divSetHeight; if (currentDownloadSection) { actualDownloadLink=document.evaluate(".//A[contains(@href,'.mp3')]", currentDownloadSection, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); if (actualDownloadLink.snapshotLength) { actualDownloadLink = actualDownloadLink.snapshotItem(0).href; oldDownloadLinks = document.evaluate(".//A[contains(@href, '" + currentDownloadSection.id + "')]", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); for (i=0; i < oldDownloadLinks.snapshotLength; i++) { oldDownloadLink = oldDownloadLinks.snapshotItem(i); if (oldDownloadLink.innerHTML.match(/download/i)) oldDownloadLink.href = actualDownloadLink; } } } archiveDiv= document.getElementById('qE') || document.getElementById('qD') || document.getElementById('q4'); if (!archiveDiv) return false; expandCollapseAll = document.createElement('div'); expandCollapseAll.innerHTML='<div><table width="324" height="22" border="1" align="center" cellpadding="0" cellspacing="0" bordercolor="#CCCCCC" bgcolor="#000000"><tr><td width="287" bgcolor="#003366"><div align="center"><a href="#" onclick="toggleAllParagraphDisplay(); return false;" id="expandCollapseAll">Expand All Descriptions</a></div></td></tr></table></div>'; archiveDiv.insertBefore(expandCollapseAll, archiveDiv.firstChild); paragraphLinks=document.evaluate(".//A[contains(@href,'javascript:showParagraph')]", archiveDiv, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); divsSetHeight= document.evaluate('//div[@class="style4"]', document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); fixHeight: for (i=0; i < divsSetHeight.snapshotLength; i++) { divSetHeight = divsSetHeight.snapshotItem(i); if (divSetHeight.style.height=="500px") { divSetHeight.style.height=null; break fixHeight; } } for (i=0; i < paragraphLinks.snapshotLength; i++) { thisLink = paragraphLinks.snapshotItem(i); if (paragraphID = regexID.exec( thisLink.href ) ) { pID = paragraphID[1]; if (pID) { //writing the code on the fly as we're going through the items we are interested in allShowParagraphs += " forceToggleParagraphDisplay(displayStyle, '" +pID + "');\n"; thisLink.id ='link' + pID; thisLink.addEventListener('click', showPlaylist, true); } //have a paragraph id } //paragraph match } //for all showParagraph links // yes, this could be written in a loop similar to the above // but since we already know the paragraph ids, it seemed more efficient to not // search for the ids again if (allShowParagraphs) { script = document.createElement('script'); script.type = 'text/javascript'; scriptText = "var showingAll=false;\n\nfunction forceToggleParagraphDisplay(displayStyle, parID) {\n var paragraph = document.getElementById(parID);\n if (paragraph != null) paragraph.style.display = displayStyle;\n if (showingAll) retrievePlaylist(parID);\n}\n"; scriptText += "\nfunction toggleAllParagraphDisplay() {\n showingAll=!showingAll;\n var displayStyle= showingAll ? 'block' : 'none';\n var expandCollapseAll = document.getElementById('expandCollapseAll');\n expandCollapseAll.innerHTML= !showingAll ? 'Expand All Descriptions' : 'Collapse All Descriptions';\n" + allShowParagraphs + "}\n"; scriptText += "\nfunction retrievePlaylist(id) {\n var paragraph, trackDiv, popupLinks, url, http, tracks, actualListing, track;\n var counter=0;\n var tracksRetrieved= document.getElementById('tracks'+id);\n if (tracksRetrieved) return;\n paragraph = document.getElementById(id);\n\n if (!paragraph ) return;\n\n trackDiv = document.createElement('div');\n trackDiv.innerHTML = '<div id=\\'tracks' + id +'\\'>Retrieving playlist...</div>';\n paragraph.appendChild(trackDiv);\n\n popupLinks=document.evaluate(\"//DIV[@id='\" + id + \"']//p//A[contains(@href,'javascript:popUp')]\",document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);\n\n if (popupLinks.snapshotLength !=1) return;\n\n url = '/' + popupLinks.snapshotItem(0).href.substring(18, popupLinks.snapshotItem(0).href.length-2);\n\n http = new XMLHttpRequest();\n http.open('GET',url,true)\n http.send(null);\n\n http.onreadystatechange = function() {\n if (http.readyState==4) {\n if (http.status==200) {\n tracks = http.responseText.replace(/<[^>]+>/gim, '');\n tracks = tracks.split('\\n');\n\n actualListing='';\n for (var i=0; i <tracks.length; i++) {\n track = tracks[i].replace(/^\\s+/g, '').replace(/\\s+$/g, '');\n\n if (track.match(/^\\d+\./)) {\n if (counter++>0)actualListing+='<br />\\n';\n actualListing+= track;\n }\n }\n\n trackDiv.innerHTML = '<div id=\\'tracks' + id +'\\'>' + actualListing + '</div>';\n\n }\n else{\n trackDiv.innerHTML = '<div id=\\'tracks' + id +'\\'>Unable to retrieve playlist.</div>';\n alert('Problem retrieving playlist data for id: ' + id)\n }\n } //if ready\n } //function definition for readystatechange\n}"; //GM_log(scriptText); script.innerHTML = scriptText; document.body.appendChild(script); } } // ------------------END OF FUNCTIONS ----------------------------- window.addEventListener("load", function() { doIt(); }, false);