[Solved] Greasemonkey/Tampermonkey jQuery sideload and setInterval

i was having a heck of a time keeping a reliable handle on jQuery in the Pandora page… it would be there upon initial Greasemonkey script execution but then upon subsequent setInterval executions, the jQuery global variable was undefined… fascinating…
 

notable: as i was debugging, i started to see that Chrome was cycling through four ( 4 ! ) different VMxxxx “copies” of the greasemonkey script upon each setInterval execution… questions like why? and why 4? abound if anyone cares to enlighten me
 

so it struck me that i just need to make sure jQuery is available in each one of those “sessions”…
 

noteable: the “sideload” is accomplished via jQuery’s native “noConflict” facility… this post explains how it works… the gist is that each load of jQuery does indeed replace “$” BUT it also saves the previous into _$, such that $.noConflict can restore “$” to the previous version… this is what allows Pandora’s copy of jQuery to remain as-is… crucial in this case because Pandora depends on additional add-ons that it loads as expando properties on its instance of jQuery.
 

after that was in the bag, i couldn’t help dwelling on what else might be possible and had another aha moment… from tracing the pandora js execution i learned that there were pretty obvious variables getting set for allowed features (e.g. “allowSkipTrackWithoutLimit”)… i banged around quite a bit trying to replace the main pandora.js script with one where those values were tweaked… blocking the original script via AdBlockPlus was easy as well as loading the tweaked pandora.js inline <script> but that approach ran aground on not being able to load other dependency scripts in proper sequence with the replacement… Chrome doesn’t implement the crucial window.beforescriptexecute event which would probably make this feasible… the main pandora.js is wrappered in a self contained function call so we can’t monkey patch its innards…

but then it struck me, jQuery is global… and what if they’re getting these values via jQuery.ajax… such that i could override and tweak… sure enough, that approach panned all the way out!
 

update – after that last round, i realized the whole thing about sideloading jQuery was unnecessary, i just needed to use the inline script approach to make sure my code executed on the page context vs whatever weird context TamperMonkey normally does… so the following script now reflects the cleaner evolved approach

// ==UserScript==
// @name          Pandora - "still listening" click
// @author        Brent Anderson
// @homepage      /2016/08/solved-greasemonkey-jquery-sideload-and-setinterval.html
// @match         http://www.pandora.com/*
// @grants        none
// @run-at        document-end
// ==/UserScript==

function recurringTweaks() {
  //this click, remove, click sequence skips embedded video ads and gets the tunes playing again
  var stillListeningButton = $("#still_listening_ignore");
  if (stillListeningButton.is(":visible")) {
    stillListeningButton.click();
    $("#videoPlayerContainer").remove();
    stillListeningButton.click();
    $(".playButton").click();
    //above brute force video ad skip leaves player controls disabled, this resolves that side effect
    $(".disabled").removeClass("disabled");
  }

  var adContainer = $("#ad_container");
  if (adContainer.length) {
    //remove right side ad section...
    $("#ad_container").remove();
    //and allow the album covers area to fill the space
    $(".contentContainer").css("width", "100%");
    $("#adLayout").css("width", "80%");

    //remove some other "upgrade" bits
    $(".registeredUser").remove();
    $("#rightColumnDivider").remove();
    $(".audioAdInfo").remove();
  }
}


// monkey patch jQuery.ajax so we can override some nice stuff =)
var hijax = function() {
  if (typeof $ !== 'undefined') {
    var oldAjax = $.ajax;
    var newAjax = function(a, b) {
      var oldSuccess = a.success;
      a.success = function(data, textStatus, jqHXR) {

        // infinite skip! =)
        $(data).find('name:contains(allowSkipTrackWithoutLimit) + value > boolean').replaceWith('<boolean>1</boolean>');

        //auto skip ads
        if (a.url.indexOf("method=registerImpression") !== -1) {
          $(".skipButton a").click();
        }

        //debug: console.log('url: ' + a.url + ', data: '+(''+data === '[object XMLDocument]' ? data.children[0].innerHTML : data));
        oldSuccess(data, textStatus, jqHXR);
      };
      oldAjax(a, b);
    };
    $.ajax = newAjax;

    setInterval(recurringTweaks, 2000);

  }

};

// load <script> inline to the page so it has access to jQuery "$" global vs TamperMonkey's alternative context
if (!document.getElementById("hijax")) {
  var hijaxScript = document.createElement("script");
  hijaxScript.setAttribute("id", "hijax");
  hijaxScript.innerHTML = recurringTweaks.toString() + "\r\n" + hijax.toString().replace(/^function.*{|}$/g, "");
  document.head.appendChild(hijaxScript);
}



///////////////////////////////////////////////////////////////////////////////////////////////////////
//sorry, turning this post into a catch all for stuff that might come in handy elsewhere
/*

//the original jquery "sideload" code
function loadJq() {
    if (!window.jq) {
        script = document.createElement("script");
        script.src = "http://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.1/jquery.min.js";
        script.onload = function() { window.jq = $.noConflict(true); cosmetics(); };
        document.getElementsByTagName("head")[0].appendChild(script);
    }
    else cosmetics();
}

    //helpful: http://userscripts-mirror.org/scripts/show/125936

  window.addEventListener('beforescriptexecute', function(e) {
      if (e.target.src.indexOf("pandora.js") != -1) {
          e.preventDefault();
          //e.stopPropagation(); //??
          e.target.src = ''; //??
          e.target.innerHTML = "patched script";
      }
  }, true);

var a = document.getElementsByTagName("script");
for each (var e in a) {
  if (!e) continue; // oddly, this does sometimes grab null elements.
  var b = e.getAttribute("src");
  if (b && b.indexOf("pandora.js") != -1) {
    e.parentNode.removeChild(e);
    debugger;
    break;
  }
}
*/

// @grants         GM_xmlhttpRequest
/*GM_xmlhttpRequest({
  method: "GET",
  url: "http://rawgit.com/Beej126/567a36f2dd1e3ce613ad8ec5846a40d4/raw/fac20b4ab17681b5da41b07c2549676ff3571fc9/dorPanda.js", //"http://www.pandora.com/pandora.js?v=440211416",
  onload: function(response) {
    debugger;

    //here's the beef!
    //var tweaked = response.responseText.replace("this.PC=b.allowSkipTrackWithoutLimit", "this.PC = true;");
    //$("script[src*='/pandora.js'").af

    var tweaked = response.responseText;
    document.head.appendChild(document.createElement('script')).innerHTML = tweaked;
  }
});*

*/

starting the same hijinx for Spotify… they load MooTools into $ and for some reason the selector wasn’t finding obvious classes… i’ve never picked up MooTools so maybe the syntax is different than jQuery… so i just went back to the jQuery sideload approach on this one… after that, worked it down into pure DOM, no jQuery needed

// ==UserScript==
// @name          Spotify tweaks
// @author        Brent Anderson
// homepage      /2016/08/solved-greasemonkey-jquery-sideload-and-setinterval.html
// @match         https://play.spotify.com/*
// @grants        none
// @run-at        document-end
// ==/UserScript==

function terminator() {
  var target = document.getElementsByClassName("ads-leaderboard-container");
  if (target.length) {
    console.log("bye bye =)");
    target[0].remove();
    clearInterval(timerId); //kill the timer once the targeted element finally shows up
  }
}

//replace main.js with hacked version
//(block original with AdBlockPlus plugin)
//was easy to enable "next" button during ads but it sticks to the ad anyway, would take further effort and not worth it until they actually fire enough ads to be annoying
var scripts = document.getElementsByTagName("script");
for(var i = 0; i<scripts.length; i++) { if(scripts[i].src.indexOf("https://play.spotify.edgekey.net/apps/player/4.2.0/main.js") != -1) {
  //debugger;
  var mainjs = document.createElement("script");
  mainjs.crossorigin = "anonymous";
  mainjs.src = "https://rawgit.com/Beej126/1501d5acb4fd20a6fcdcfe6599ce0c5e/raw/2725727f297a00444ef51c490a6009458a513e07/SpotifyMain.js";
  document.body.appendChild(mainjs);
  break;
}}

//there were multiple iframes, targeting the one that actually gets the ads
if (document.body && document.body.classList.length && document.body.classList[0] === "non-mobile" && document.body.attributes.length === 1) {
  //setup a recurring check to see when ads get dynamically inserted into page
  var script = document.createElement("script");
  script.innerHTML = terminator.toString() + "\r\n" + "var timerId = setInterval(terminator, 2000);";
  document.head.appendChild(script);
}

Ode to Griffin AirClick USB – Radio Frequency PC Media Remote

This little bugger just so totally rocks!!!  IMHO the most compelling aspects are:

  • It’s cheap :). They tend to go for around $10-$25. There are still some out there on eBay from time to time (not now) and also Amazon at the moment.
  • It’s Radio Frequency technology – so you can zap iTunes to the next song from around the corner or out in the yard!!  Even my fancy iMON VFD remote is Infrared based (limited by line-of-site) and that winds up being a deal breaker in my environment… couch faces projector wall away from the PC, IR = major fail! 🙁
  • It’s simple! – there are only the 5 most critical buttons to distract you… none of that typical Windows Media Center remote overload to worry about here… Play/Pause, Previous, Next & Volume Up/Down, that’s it.

Unfortunately, the vendor, Griffin, has chosen to discontinue this little wonder.  If you’re interested in driving your PC based Media Players, make sure get the USB version, not the iPod version which appears to still be in production. Take note, the transmitters that come with the readily available iPod version are 100% compatible with the USB receiver. This is a nice way for us to obtain replacement transmitters to have around.  Just check eBay… I just got a pair of clickers, including the iPod receiver and an interesting Velcro mount for $4.50, including shipping!!! Griffin is nice enough to continue hosting their support page with drivers <whew>.  These native drivers work on any 32bit Windows since XP (more on 64bit support below). And Dmitry Fedorov has been keeping the dream alive by showing us how to build our own little application-specific .Net plugins for the basic Griffin driver API. AirClickOk so that’s all fine and dandy, now let’s get to the good stuff!!
I currently like iTunes and VLC and Windows 7 64bit and I’ve found a couple free wares that well, make beautiful music together (couldn’t resist 🙂

iTunesControl – In his infinite wisdom, Mr. Jobs hasn’t seen fit to support global Windows Media Keys in iTunes … fortunately for us, Carson created iTunesControl. Within the HotKeys section, one must simply click the desired key event (e.g. “Next Track”) and then press the corresponding AirClick button to make the assignment (Don’t forget to hit the Apply button).  It also provides a very nifty, super configurable Heads Up Display that I absolutely love. To be more specific, I only mapped Play/Pause, Next & Previous this way.  I left volume up/down defaulted to Windows global volume which provides convenient system wide volume control no matter what’s active (see last paragraph).

Now, the dark clouds started rolling in when I upgraded to Win 7 64bit and realized that the basic Griffin software install does not happen under 64bit, zip, nada, no-go <waaahh>… then I found this next little gem, affectionately called…

AirClick Interface Script” – The way Jared explains it, fortunately for us, at least the HID layer of the Griffin driver is operational under 64bit. So he wrote an AutoHotKey script which picks up on the HID messages coming from the AirClick and turns those into Windows Media Keys.  The WinMedia Keys are then caught by iTunesControl and iTunes immediately does our bidding, brilliant! Jared provides his original script source as well as a convenient compiled exe version that you just run and go.

AirClick_DiagramNOTE: Jared’s script maps a 4 second press of the volume-down to PC go night-night. To me this isn’t so handy and I much rather have a repetitive volume adjust when held down. So I tweaked his script a little, find that here (ready-to-run EXE version). If you wish to run this raw script or perhaps compile some of your own tweaks, then you must use the original AutoHotKey. The newer “AutoHotKey_L” branch would not work for me. The last thing I’ll mention is subtle but neato… Jared’s script actually checks to see which window is active.  If none of the well knowners is focused (VLC, Winamp, MediaPlayerClassic, PowerDVD), then it defaults to firing Windows Media Key events.  The nice thing is, if say VLC is active, then Jared’s script fires VLC specific play/pause, rewind & fast forward keys … so if I’m bouncing around the house, iTunes is getting the WinMedia events… if I’m sitting down watching a movie, I just have to make sure VLC is the active window and iTunes is left alone, perfectly intuitive! UPDATE 10 March 2012 It’s a nice pastime to watch a photo slideshow while listening to tunez. Previously I’d been using the Google Photo Screensaver. But we soon wanted the ability to back up and stare at one of the slideshow photos, via the remote. I found Photo Screensaver Plus by Kamil Svoboda to fit very well. Among other very robust functionality, it supports left cursor to back up in the photo stream and space to pause the slideshow. With that, I edited my new AutoHotKey script (exe) to provide the following:

  • when slideshow screensaver is not running, hold down play/pause remote button to start up screensaver slideshow
  • when slideshow is running, reverse button goes to the previous image and pauses the slideshow
  • when slideshow is paused, play/pause restarts the slideshow
  • otherwise all buttons pass through to media events as usual

I really like how you can dual purpose the buttons depending on the context… that’s powerful. Kamil’s screensaver also provides a hotkey to copy the current image to a favorites folder, very cool.  And a hotkey to edit the image’s EXIF metadata – Name, Description & Comment.  The nifty thing there is we also publish our photos via a Zenphoto web image gallery. Once we edit the EXIF info in the screensaver, a little PowerShell script of mine refreshes ZenPhoto’s MySQL database entry for that image so the new image name and comments are immediately available for viewing and SEARCHING via the web gallery’s search facility, nice!  The PowerShell script uses Microsoft’s PowerShellPack to provide effortless FileSystemWatcher integration. We really do have everything we need to mix and match unintentional building blocks into our own satisfying hobby solutions these days with amazingly little effort. I mean, who could’ve anticipated using a screensaver of all things as a data entry front end?   Hot Corners – This free tool does the job and AutoIT source code is provided.

CTRL, 1 – Mutes Windows Sound?!?!

Is this a standard???  I can’t find reference to this hot key sequence out there in Google land. You need to hit CTRL, release and then hit 1, not CTRL-1, i.e don’t hold down CTRL. On my (*non* Windows Media Keys Keyboard under Windows 7) system here, it works with both left and right CTRL and main keyboard or numeric keyboard “1”.   Google Keywords: Windows 7, Audio, Mute, Volume, Control, CTRL, 1, One

iTunesControl

This thing totally rocks!… essentially flawless implementation of global hotkeys plugin to control iTunes and also sweet configurable heads-up-display functionality (example shot below)… if you’ve been looking for this kind of functionality, look no further! (waaaay more functional than the clunky Aqua-Soft mmKeys.dll plugin that’s out there) Super bonus points: the developer Carson Morrow is a great guy… very responsive! image

Considering Home Network Storage Alternatives

My current bottom line is that I’ve got a 6 x SATA ICH9R just sitting there on my main Windows 7 machine’s mobo for free so I slapped on 2 TB x 2 in RAID1, published a few shared folders and leave that machine powered on 24/7. After everything else (optical & OS drives) I had two ports left doing nothing so the previous gen 750GB’s x 2 are in RAID0 receiving scheduled backups for a little more cheap peace of mind. I’m hoping by the time I actually need more space, that there will be something along the lines of a 5-bay Drobo engineered around SATA 3.0 (6 Gb/s) internally and USB 3.0 (5 Gb/s!!) externally to finally give us some serious speed for that $700 price point. My big up front consideration: NAS vs DAS

  • What’s better, a true stand alone NAS box –OR- a large/fast DAS array shared from your primary machine???
  • FOR THE HOME scenario: I always go back to preferring DAS connected to my main beefiest workstation/”home-server”
  • You get to rally the performance wagons around at least one location where you have absolute top end HDD access when you want it…
  • If you go with a NAS, you basically accept that GbE is your top end… true, even DAS RAID0 HDD configs generally level out around 100MB/s average xfer rate which is basically the GbE saturation point (1 Gb/s = 125 MB/s minus some packet overhead puts you right around 100 MB/s)… but sequential burst rates can go upwards of 300MB/s (2.4 Gb/s) … so I believe NAS over GbE could very well prevent your drives from spitting the bits as fast as they’re capable.
  • After chasing NAS box performance specs for a while you start to realize that the end game is basically spec’ing out a mid-range PC… so that’s why I can’t stop swinging back to throwing my money at the primary machine’s horsepower and just leave that powered up all the time to share files.
  • My current working scenario is based on a main machine that’s sits at the center of our home’s media universe as the do-it-all living room media player… projector, good speakers, VLC, iTunes, etc… after that, it’s a matter of streaming (primarily video) wirelessly for individual needs (internet tablet, wifey’s PC, etc)… even if I did have the luxury of hiding that main machine somewhere other than the main living space, I think I’d just roll with a cheapo networked media player (e.g. Western Digital TV) in the living room with network storage requirements still covered by the main box.
  • Invariably one wants to share a few things out on the internet as well as around the home… my config readily lends itself to accomplishing this from simple IIS Directory Browsing up to a full blown photo gallery (PHP/MySQL based zenPhoto, love it!!)… other NAS boxes (Synology, etc.) market themselves on more and more “server” oriented features, but why fuss with learning and navigating around the limitations of various embedded linux flavors when you can have the full power of your primary machine’s OS to load up all kinds of goodies?? e.g. Synology’s built in photo gallery is nice but open source is always going to be ahead of the game
  • Another consideration: you don’t hear much talk about virus checking and NAS… maybe I’m worrying about this too much but full scans are something that one must do from time to time… ok yes, most of what we’re putting out there is going to be non executable media that doesn’t require scanning… but being a developer, I’ve developed a fairly extensive library of software that I like to have on hand… it’s doesn’t add up as fast as movies but it’s substantial… and apparently even JPG’s can get viruses… the thought of scanning all those files over the wire (repeatedly) just doesn’t appeal to me.
  • I like the idea of running a reasonable database in this space… granted the optimal database drive configuration is not the same as your primary storage volume –BUT- you do still benefit from having those byte buckets near each other for backups and such
  • [29 Sep 2010] Another one hit me: We finally have full symbolic/hard-link flexibility under Windows 7 NTFS… we can cross phyiscal drives with a link, etc… this allows full granularity to choose exactly what consumes the more valuable RAID1 space but still symlink anything into the same visible folder hierarchy… e.g. a single “movie” shared folder is physically comprised of “classics” subfolder (hosted on RAID1) in addition to “unwatched” (hosted on RAID0)… Shell Link Extension makes symlinks awesomely convenient to create with Windows Explorer.
  • For the HOME sized problem: There starts to be a pile of compelling reasons in favor of connecting the physical storage to the main CPU horsepower over the highest bandwidth possible

Pertinent specs:

  • MB/s = MegaBytes per second, Mbit/s & Mb/s = MegaBits per sec, GbE = GigaBit Ethernet, Gb/s = GigaBits per sec
  • Notable NAS vendors: Synology, QNapBuffalo, LaCieHP, Acer, AsusNetGear, Cisco, ZyXEL
  • Performance rundown of many popular NAS boxes
    • RAID0 based units hold the crown – and nothing tops out much over 100MB/s read or write
    • Didn’t realize the Qnap’s were kicking so much arse
    • The NetGear seems to be the champ but she’s pricey (see my note about their X-RAID technology below under Holy Grail)
  • HD Video Streaming, minimum required bandwidth: in the ballpark of <10MB/s (per client)
    • Blu-ray spec max data transfer rate = 54 Mbit/s (~7 MB/s)
    • HD DVD spec max data transfer rate = 36 Mbit/s
The Holy Grail (at the raw storage level):
  1. Single Volume – a single logical storage pool
  2. Redundancy – at least single drive failure redundancy (with RAID 5 style efficiency)
  3. Different Size Drives – we all want to take advantage of the biggest/cheapest drive available from one year to the next

These are the only options I’m currently aware of:
  • Drobo
  • Windows Home Server
  • NeatGear has something called X-RAID2 in their ReadyNAS line that looks pretty good as well… 6 bay Pro model (empty) = $1000 street <yikes>
  • zFS – Solaris only…various OpenSolaris based versions out there… people do run it under a Windows VM with some success but seems clunky
  • BeyondRAID is like RAID 5 striping & redundancy yet with the freedom of on-the-fly swapping of any drive size
  • Pre-emptive, automatic self healing
  • Tool-less, Tray-less HDD slots
  • Sexy Health lights
  • OS X TimeMachine compatible
  • Downsides:
    • – a bit pricey (5 bay, eSata “Drobo S” = ~$700 empty!) … i feel like they’re charging about $100-$200 over average hardware for their secret sauce
    • – unfortunately it’s run of the mill speedy (60-90 MB/s over eSATA)… too bad we can’t justify the cost with some extra performance
    • – unavoidably it’s running a proprietary format in order to work its magic … the million dollar questions is: What is Drobo’s track record now that they’ve been out there a while??  Definitely need to dig up some solid reliability satistics…  If it ever does totally puke on you, you’d have to wait for a replacement unit to drop in your drives and see what’s still there… and after that, only Data Robotics Inc can possibly save you and it’ll cost you.
    • but is this really any different than RAID5?  RAID is pretty much the same vendor specific lock-in isn’t it??… if your RAID controller up and dies (for me that’d be my mobo 😐 … you’d have to obtain nearly identical duplicate hardware to salvage your drives… apparently you can migrate across same vendor like ICH9R –> ICH10R which does give slightly more flexibility
Windows Home Server
  • You can install PHP
  • It does run fine in a VM
  • OS X TimeMachine compatible
  • – When you add a drive you must designate it as either Storage or Backup (the Storage pool offers no redundancy)
  • – Obnoxious – there’s something whacky about how it does not balance allocation very well across available drives
  • WHS “v2” aka “Vail” due sometime 2010 (V2 is Windows 2008 based, V1 is Windows 2003 based)
  • Great AnandTech.com dissection
    • v1 was basically a fancy tack-on above NTFS – “Drive Extender was the biggest component of the secret sauce that made WHS unique from any other Microsoft OS. It was Drive Extender that abstracted the individual hard drives from the user so that the OS could present a single storage pool, and it was Drive Extender that enabled RAID-1 like file duplication on WHS v1. Drive Extender was also the most problematic component of WHS v1 however: it had to be partially rewritten for WHS Power Pack 1 after it was discovered that Drive Extender was leading to file corruption under certain situations.
    • v2 Drive Extender is now ‘below’ NTFS… proprietary block based storage… single file can/will be spread across multiple disks (“chunking”)
      • biggest downside is that you can no longer just plop a WHS drive in another server to pull files in an emergency
      • chunking means that you’re in a more RAID0 like risk category for your main storage
      • enables backup of open files… to me, Drive Extender v2 provides similar freedoms to what Volume Shadow Copy provides us elsewhere
    • Great stuff in the many comments:
      • This comment basically sums up my WHS vs Drobo question => [RE: Almost there by davepermen on Wednesday, April 28, 2010, on comment page 2] – “in storage-loss for the security, raid5 is superior. if all your data is in duplication mode on whs, it needs 2x the storage space. raid5 needs "one additional disk".” … so Drobo is more like WHS flexibility + RAID5 reliability… so they really are the only game in town and hence the price.
  • Generally accepted as a solid WHS implementation: HP Storage Works x510 (rebranded MediaSmart EX495)


Links:

Logitech S715i Portable iPod Speakers Review

My primary usage scenarios is small group biking… want something that can carry some punchy bass to nearby riders over typical road/wind noise w/o being clunky or adding too much weight (we have to hop on/off a lot of trains/stairs, etc)…

Highlights Reviews / Links
image image P1030099-800x600  P1030100-800x600Battery NiMH 180AAHC3TMX 3.6V 1800mAh-800x600
  • Retail: $150, Street: $132
  • Released Aug 2010
  • 8 speakers! = 2 x 3” neodymium mid drivers, 2 x 1.5” neodymium tweeters, 4 x 2” passive bass
  • Rechargeable proprietary NiMh battery (highly marketed @ 8 hours)… too bad they’re not rocking a Li-ion slab… but supposedly these batts are user serviceable through a screw panel so we’ll see.
  • 3.5 lbs (perfect)
  • Standard 3.5mm AUX input (required for me)
  • Remote (worthless for me)
  • A/C wall brick
  • Travel sack

My review:

  • just gave them a test run tonight 22 Sep 2010
  • they bang pretty nice off the back bike rack
  • compared to the logitech 28mm (eBay = $30, no longer available) they are better enough to be worth $150 to me
  • iPhone compatible
  • feel solid, not as bulky as i expected
  • Battery = NiMH 180AAHC3TMX 3.6V 1800mAh (see photo)
Batteries!!  I’ve already started maxing out the battery life during our rides… we saw around 6 hours last ride… that’s not 8 hours 🙂 … to be fair, once I turned down the volume, then the light went back green for another hour or so… but who wants low volume!?!? So now I’m looking to hack in some Lithium rechargables like what I’ve started to experience with these CREE LED’s I’ve already received one of these buggers to the right ($20 bux, 6 days Air Mail from Hong Kong to Germany! you gotta love the Chinese economy! 🙂 I plan on cannibalizing the battery box and springy cable for feeding the speakers :)  we shall see To answer Peirre’s question in the comments: The direct battery feed is 3.6v (based on an packaged bundle of 3 x 1.2v AA NiCads in series)… but the DC charging input port is rated at 12v so there’s hurdle to get over there… I feel like we could use a fancy more expensive battery pack (like the Tekkeon’s) to drive the 12v input in a physically clean but likely power wasteful approach… I’m more inclined to fiddle around tapping the existing battery feed first and see how far I get that way. [Update: 2012 May 05] To finish off this thread, the headlamp at the right was cheap yet very capable as a lighting solution. It was a shame to cannibalize it for the battery pack experiment. And unfortunately, while the pack and cable were physically promising, the arrangement was based on a remote switch at the light head which was not a simple circuit loop that could be shorted to be always on. It was a real bear getting the little wires soldered back to the light head after this disappointment. Fear not. What has worked out quite practically is using a simple 18650 plastic case with wires soldered to pennies on either end to form a simple battery case with power leads. The case also provides an easy place for a spare backup battery… Or one could probably run them in parallel but I haven’t bothered. I removed the stock NiCad battery leads and spliced them to the makeshift 18650 battery pack so that it could be easily connected and removed. The makeshift battery case is too big to fit anywhere inside the original battery cavity but the built in speaker stand lends itself to use as a strap mounting point. Actually, eBay seems to have some nice single 18650 battery cases with leads ready to go. Untitled-5
DSC_6341-medium
Lastly, a buddy got the Bose SoundLink Bluetooth speakers and I definitely consider them another notch or two up this ladder.
Highlights:

  • $300 – this is the only downside really
  • The internal battery pack is made of no less than 3 good ol’ 18650’s! Yay! finally somebody gets it!
    • They’re rated pretty low (less than 2000mAh if memory serves)… so beyond the already good base 10 hour rating, presumably there’s some good room for improvement with solid upgrade cells, like the latest Redilast 3100mAh’s.
    • From what we could tell after getting the battery cage open (there are screws under a label), the cells appear to be bare, i.e. no protective cap chip. There’s a pretty dense logic board right after the cells so presumably it’s all well buffered from spikes.
    • I emailed the owner and he indicated $14 a piece for the naked 3100’s in qty 5 or greater.
  • Bluetooth is pretty handy with today’s devices… there’s also a standard 3.5mm AUX port.
  • A bit more sound punch for sure… very clear…
  • nice tight, well built, rectangular package that lends itself to bungee’ing to a rear bike rack, etc.
  • also, the cover can be easily removed which leaves some raised Allen screws convenient for mounting.

Free iTunes Album Cover Artwork + Embed Artwork Image to MP3 via iTunes COM API SDK w/JavaScript

Misc Notes:

  • Given: iTunes has some pretty high quality cover art for many albums (all images are standard 600 x 600 pixels).
  • The basic trick here is that you can sign up for a free iTunes account (without providing any credit card or other personal info)…
  • And use that account to download the cover artwork for free.
  • Then run my script which will automate iTunes to extract the cover from iTunes’ special stash and save it as a real local image file
  • -AND- then embed that image back into the MP3 file so that it stays with the MP3 file no matter where it gets transferred.
  • The iTunes API is clean, the .CHM based API document that comes with the SDK is easy to navigate and is readily understandable… this really opens a lot of possibility with some quick javascript.
  • Note: if you’re experiencing the kind of trouble where the MP3 tag changes simply don’t take no matter what you do, try entirely wiping out the existing tags and start from scratch… for me, the “APE” metatag format always seemed to be a culprit (vs. “ID3” which is much more common)
  • MP3Tag is an excellent tool for bulk tag cleanup efforts like this… tons of good wizard driven actions you can perform on mp3 files names & tags… remove string, mixed case conversion, etc.
  • Standard list of iTunes genres for handy reference
  • Image size increasing MP3 size – if you’re trying to cram your music on a smart phone this could matter and I was asked about it.  Taking a quick random sampling of my covers I saw from 50k to 80k per 600 x 600 pixel JPG artwork added to each file.  Rounding up to 100k and assuming an average of 4MB’s per MP3 means for every 40 MP3’s you’re adding the size of an additional MP3 to your library.  A 16GB SSD would hold ~4 thousand MP3’s… adding images would knock that down by ~100.

Steps:

  1. Follow steps below to create free iTunes account… thus providing free artwork download capability
  2. in iTunes press CTRL-A to select all your tracks
    • now ONLY IF YOU WANT TO REPLACE all your existing artwork with iTunes covers… with your entire library selected in iTunes, right mouse and select “Get Info”, and then check the box next to the blank cover image and hit OK, this will clear the artwork from all your MP3 files!  Make sure you save any of the ones you care to keep ahead of time. It will take quite a while to complete that wipe, of course depending on the size of your library.
  3. Right-mouse and select “Get Album Artwork” – this will download covers for every MP3 file that doesn’t already have artwork embedded in the file. `
  4. Now run my script from CMD.EXE
    1. cscript EmbediTunesDLArtwork.js
    2. I’ll be honest, a handful of albums always proved stubborn, the scripted image embedding simply wouldn’t take for no apparent reasons, no errors… just had to do those few by hand.
  5. That’s basically it, go have a look!

Enjoy!

EmbediTunesDLArtwork.js
  1. var tracks = WScript.CreateObject("iTunes.Application").LibraryPlaylist.Tracks;
  2. var fso = WScript.CreateObject("Scripting.FileSystemObject");
  3. WScript.Echo("Tracks to analyze: " + tracks.Count);
  4. forEach(tracks, function (track)
  5. {
  6.   if (track.Kind == 1 && track.VideoKind == 0)
  7.   {
  8.     //"VideoKind: " + track.VideoKind + ", Kind: " + track.Kind + ", KindAsString: " + track.KindAsString +
  9.     //"Index: " + track.Index + ", PlayOrderIndex : " + track.PlayOrderIndex +
  10.     /* uncomment to collect missing artwork into a big group that’s easily grouped together in the iTunes GUI by sorting on the "Show" column header
  11.     if (track.Artwork.Count == 0)
  12.     {
  13.     track.Show = "!!missing artwork!!";
  14.     WScript.Echo("Missing artwork – Artist: " + track.Artist + ", Album: " + track.Album + ", Name: " + track.Name);
  15.     }
  16.     continue;
  17.     */
  18.     //now for all downloaded artwork, save it to an image file and then write it back into the mp3 file so that we’re free to carry music with artwork out of iTunes
  19.     var AlbumFolderName = fso.GetParentFolderName(track.Location) + "";
  20.     forEach(track.Artwork, function (art)
  21.     {
  22.       //debug:WScript.Echo("  IsDownloadedArtwork: " + art.IsDownloadedArtwork + ", Format: " + art.Format + ", Description: " + art.Description);
  23.       var AlbumArtworkFullPath = AlbumFolderName + track.Album.replace(new RegExp("[:?$/@*]", "g"), ".") + ArtworkFormatAsString(art.Format);
  24.       if (art.IsDownloadedArtwork)
  25.       {
  26.         try
  27.         {
  28.           if (!fso.FileExists(AlbumArtworkFullPath))
  29.           {
  30.             WScript.Echo("*** Saving Art to file: " + AlbumArtworkFullPath + " ***");
  31.             art.SaveArtworkToFile(AlbumArtworkFullPath);
  32.           }
  33.           WScript.Echo("    Saving art to MP3: " + track.Location);
  34.           art.SetArtworkFromFile(AlbumArtworkFullPath);
  35.         }
  36.         catch (ex)
  37.         {
  38.           WScript.Echo("        Error: " + ex.message);
  39.         }
  40.       }
  41.     });
  42.   }
  43. });
  44. function ArtworkFormatAsString(format)
  45. {
  46.   switch (format)
  47.   {
  48.     case 0: return (".unk"); break;
  49.     case 1: return (".jpg"); break;
  50.     case 2: return (".png"); break;
  51.     case 3: return (".bmp"); break;
  52.   }
  53. }
  54.  
  55. function forEach(enumerable, delegate)
  56. {
  57.   for (var enumerator = new Enumerator(enumerable); !enumerator.atEnd(); enumerator.moveNext())
  58.   {
  59.     delegate(enumerator.item());
  60.   }
  61. }
Register for free iTunes account:
Enter iTunes App Store Select “Free Apps” (currently in lower right page gutter) image
Select “Free App” image
Create New Account image
Continue image
Accept & Continue image
Enter Personal Info and Continue image
This is the big enchilada… Select “None” for payment type. Note: this option only shows up when you start by selecting a free download. image
Done image
Confirm the verification eMail via embedded link image
Pop the little iTunes download thingy and sign in <finally> image image
If all has gone according to plan… you should be greeted with this pleasantry You now have an album art download capable yet free iTunes account 🙂 image

WinAmp Play History Blog “Badge”

update: alas, yahoo pipes is no more : (

 

  • So hopefully you’re already a WinAmp fan if you’re reading this but if not, load up the latest WinAmp (v5.56 at the moment)
  • Orgler is the name for WinAmp’s recent Play History plug-in
  • Sign up for a music.AOL.com account via the Orgler options menu shown below (this provides the bucket for your personal play history data… takes 2 seconds, no fee)
  • Play some music 🙂
  • (a) Your feed will start showing up at a URL like this: http://music.aol.com/profile/beej126@hotmail.com
  • Now here’s the fun part… fire up Yahoo Pipes
  • Search for Orgler and you should find my published pipe that already does the right filtering
  • Clone it and replace the “Fetch Page” URL with your own like (a) above
  • Then you can publish it to your blog with various badges… sure wish I could show you a screenshot of that but the Yahoo gods appear to have the pipe usage quota dialed way down low… I run into 999 errors all over the place.
  • I didn’t have any luck with the specific Blogger badge… never changed from a continual “working on it…” style generic Pipes image… So I just went with a plain vanilla RSS feed widget.

    image image image

(Fairly) Quick & Painless Streaming of Your Local Audio

Here’s the basic pieces I plugged together:

  • MediaMonkey is my preferred mp3 player: www.MediaMonkey.com
    1. MediaMonkey supports WinAmp API plugins which provides an excellent pool to draw nifty add-ons from
  • EdCast (formerly “OddCast”) comes in various implementations, one of which is a WinAmp plugin that sends your current song to a ShoutCast (or IceCast) server: http://www.oddsock.org/tools/edcast/
    1. I chose the EdCast plugin versus ShoutCast’s own plugin because EdCast got the song name and artist to come through Media Monkey and ShoutCast’s plugin has a known issue that this feature only works with WinAmp
  • ShoutCast DNAS (Distributed Network Audio Server) – streams the audio out to clients: http://www.shoutcast.com/download-files

Install/configure/run:

  • Drop the EdCast plugin into Program FilesMediaMonkeyPlugins
  • Fire up your Monkey and get some tunes rolling
  • Then in Monkey > Tools > Options > Player > DSP Plugins > edcast DSP…
    1. Click on the meter in the middle of the dialog to turn on the
      broadcast
    2. Hit “Add Encoder” and then right click the entry to configure for MP3 and
      localhost, change password to what you want
    3. Personalize your stream on the YP Settings
  • Now install the ShoutCast server and fire that up
  • Cruise through the config file via the menu option in that GUI… it’s very self explanatory and all the defaults are good… probably just have to make sure you get the password lined up with what you put in the plugin config
  • Then just browse to http://yourserveraddress:8000/listen.pls from another machine and it’ll fire up your local media player (if you’ve got .pls associated of course)
  • There’s some interesting stuff kicked out as a default web page if you browse to http://yourserveraddress:8000… including an admin page where you can monitor listeners, etc.
  • The default DNAS config automatically publishes you to the global ShoutCast directory (so you might want to watch your intake from that vector victor 🙂
  • PS- The main reason I did this was so I could listen to my tunez at work w/minimal effort 🙂