How to unfuck Hootsuite's shite new dashboard and revert to the old one

Hootsuite is a method of using twitter that has a much better user interface than the shite twitter website. This is very useful.

Unfortunately, the people who run it have decided to be cunts. They have changed the appearance of the Hootsuite dashboard and fucked it up, with the result that everyone hates it and wants the old one back. Only because they are cunts their response is "it's staying how it is, so fuck you". This is not acceptable.

The first news I had of this was when an overlay started appearing plugging the new dashboard, with a button to click to change to the new one, and a warning that you wouldn't be able to change back. So I simply avoided clicking the button and it was OK for a while. It was a minor annoyance but since it only appeared at the start of a session it was of little moment. However in January 2015 the fuckers started forcing the new dashboard on everyone regardless of whether or not they had clicked, and at this point I got significantly angry.

They are also cunts because they have changed it for fucking stupid reasons. They say: "we wanted to bring it in line with our new brand, and with social media industry trends. Facebook and Twitter have updated the look of their networks several times in the last few years." This must be one of the stupidest excuses I've ever heard. For fuck's sake have they not noticed that every time facebook and twitter "update the look of their networks" everyone fucking hates it? If they had the brains of a diseased frog they would realise that you DON'T change the appearance unless there is a FUCKING GOOD REASON to do so because all it does is piss people off. And "to bring it in line with our new brand, and with social media industry trends" is not a fucking good reason. It's a fucking STUPID reason. Any "reason" that includes the words "brand" or "trend" is a fucking stupid reason because these things are a load of shitey bollocks that nobody gives a shit about unless they are some moronic fucking marketing cunt in a suit with their head shoved so far up their arse they can see daylight and fuck all idea about what is and isn't important in the real world. It's high time someone created a global security force that would round up all the people who think that sort of fucking stupid bollocks is worth anything and put them all up against a wall and shoot the fucking cunts.

And they are cunts because they claim they changed it because "people asked them to". Which is palpable bullshit because if they really did care about what people wanted they would fucking well listen to the people who want to be able to change it back. Instead they persist with their bloodyminded insistence that it will remain shite no matter how much people complain so it's flaming bloody obvious that they don't actually give a fuck what people think and are just doing it because of their fucking stupid moronic "brand" and "trend" bullshit. Making a big thing out of publishing all the tweets from people who didn't like the old dashboard but ignoring all the tweets from people who don't like the new one. Fucking wankers. All they have to do is provide a fucking choice, and it isn't difficult otherwise I would have had to swear a lot more when writing this script.

Further evidence that they haven't got a fucking clue is that they think "More white space around messages means quicker and easier reading", when in fact this is what the majority of the complaints are about: the extra space means fewer tweets show up in a given size of window, and the extra whiteness is too glary. (I don't think it is too glary but everyone else does.) They have also made it so that if someone tweets a photo the fucking thing shows up in the timeline, like twitter did, so you get hardly any tweets on the screen because this sodding picture is taking up all the room, only unlike twitter they haven't provided an option to turn the sodding things off. And they are shit anyway because they are clipped top and bottom so if it is a standing or sitting picture of a person their face gets chopped off.

Well, I thought all this was FUCKING SHITE so I decided to fix it myself, like I always have to fucking do when someone else does something stupid and shite and I am sick to the fucking bollocks of it.

The result is this UserJS for Opera: hootsuite-unfuck_opera.js.gz
...and this Greasemonkey script for Firefox: hootsuite-unfuck_firefox.user.js.gz

(Yes, they are sodding huge; see the description for add_local_css() for the reason.)

It restores the appearance to how it was before Hootsuite fucked it up, and as a bonus it blocks ads (note: I am assuming that you already have blocking rules set up to kill the various bits of Google ad and tag and tracking shite) and gets rid of those bastard "promoted tweets" (ie. fucking spam).

Below is what the code for the Opera version looks like, with the enormous CSS section removed because it would be really boring and replaced with // CSS GOES HERE. I have left in the last two lines of CSS that I have added myself, just for context like.

remove_images() is triggered by load events, and replaces the inline images in the twitter stream with links to the images. Since it obtains the URL for the link from the inline image, the link points to the raw image, not to the tweet containing it. This is a good thing because otherwise clicking it would load a whole fucking massive great bloated twitter page and the whole reason I use Hootsuite in the first place is because twitter's own web interface is dysfunctional bloated slow-as-shite nigh-unusable crap. It relies on the structure of the individual tweets being of the form:

<div> <!-- .-messageBody --> <p> <!-- Tweet text --> </p> <div> <!-- .mediaGallery --> <a> <!-- link to pic --> <img /> <!-- inline image --> </a> </div> </div>

I thought there was a bug in this function on 2015-10-01 when someone retweeted something that could be seen to include a pic.twitter.com image on the twitter website itself but there was no sign of this image in Hootsuite. However it turned out to be a bug in Hootsuite itself because the same thing happened without this script active.

There seems to be another bug in Hootsuite's handling of tweeted images as well because quite a lot of them still show up as pic.twitter.com links instead of inline images. This script doesn't touch such links of course.

remove_remote_css() is called before a stylesheet is parsed and blocks stylesheets from cloudfront.net. The e.target.href || e.element.href bit is because Opera went weird on me. e.target.href worked when I first wrote the script, but then it stopped working and e.element.href had to be used instead. So I put them both in in case the weirdness changes back again. I fucking hate this sort of shit with javascript, and I wish to fuck it had a native equivalent of PHP's var_dump() because it would make it one whole fucking enormous massive sight easier to find out what you're dealing with than it is with the useless fucking cacata carta of all the bleeding web references. Is it really too much to ask that the description of the BeforeCSS event on the Opera website should include a complete tree of everything that descends from it? I don't think it's something you should need to ask at all, but for fuck only knows what reason the people who wrote the website didn't include it, and nor did any other fucker on any other website. This is a giant pain in the arse and therefore they are all a bunch of cunts.

misc_fixes() exists to deal with minor odds and sods that need fixing. At the moment there is only one fix in it. As of 2015-01-10 a dirty great button marked "Upgrade to Pro" appeared next to the "compose message" box. It is somewhat spectacularly bad timing of Hootsuite to decide to try and plug a paid product to me when I have just had to put this much effort into unfucking the free version, so I added some code to delete the bloody thing.

remove_adscripts() blocks ad scripts, like wot it says it does. The test for an ad script is extremely crude but it seems to be enough for what it has to deal with.

fix_scripts() is a workaround for a bug in hs.require(). The dashboard-new.js script is supposed to pull in streams-new.js which it uses bits of, but it doesn't always wait for it to be loaded and parsed before it tries to use it, which fucks the whole thing up. fix_scripts() is run after core-new.js has been loaded, so that it can use hs.util.rootifyJs to work out the correct alphabet soup for the script URLs, and then loads them both as (effectively) static elements in the head. This successfully bodges everything to be in place when it needs to be. It also comes alive after the inline script which sets up a load of variables in order to turn off the rich bollocks.

add_local_css() inserts the CSS for the old-style dashboard. Hootsuite in Opera fucked up while Hootsuite in Firefox was still OK so I was able to pinch the good CSS out of Firefox and use it to make this stylesheet. All the icons and images and thingies are represented using data: URLs because presumably sooner or later they won't be available off the server any more. It also loads a fuck sight faster this way. So although it does make the thing sodding huge it is definitely better.

// ==UserScript== // @include http://hootsuite.com/* // @include https://hootsuite.com/* // @include http://www.hootsuite.com/* // @include https://www.hootsuite.com/* // ==/UserScript== (function() { var fs = false; function remove_images(e) { var u, m, n; if (!(u = e.target.src)) return; if (!u.match(/https?:\/\/pbs\.twimg\.com\/media\/[A-Za-z0-9_-]+\.(jp|pn)g/)) return; m = e.target.parentNode.parentNode; // should be div.mediaGallery n = m.parentNode; // should be div.-messageBody m.removeChild(e.target.parentNode); if (m.getElementsByTagName('a').length == 0) n.removeChild(m); n = n.getElementsByTagName('p')[0]; m = document.createElement('a'); m.appendChild(document.createTextNode(u.replace(/^.*\//, ''))); if (!u.match(/:large$/)) u += ':large'; m.href = u; m.target = '_blank'; n.appendChild(document.createTextNode(' ')); n.appendChild(m); } function remove_remote_css(e) { var h, i, z, x; z = ['cloudfront.net', 'fonts.googleapis', 'dashboardPrimary', 'dashboardSecondary']; h = e.target.href || e.element.href || ''; x = false; for (i = 0; z[i]; i++) if (h.indexOf(z[i]) >= 0) { x = true; break; } if (x) e.preventDefault(); } function misc_fixes() { var a, i; a = document.getElementsByTagName('button'); for (i=0; a[i]; i++) if (a[i].innerHTML.indexOf('Upgrade to Pro') >= 0) { a[i].parentNode.removeChild(a[i]); break; } } function remove_adscripts(e) { var a, b; if (e.element.id && (e.element.id.indexOf('bird') >= 0)) return; a = e.element.src || e.element.baseURI || ''; if (a == '') return; if ((b = a.indexOf('cloudfront.net')) >= 0) a = a.substr(b).replace(/(.*\/[a-z]+\.)[0-9a-f]+\.gz\.js$/, "$1.gz.js"); if ((a.indexOf('ad') >= 0) || (a.indexOf('nr-data') >= 0) || (e.element.text.indexOf('ad') == 0)) e.preventDefault(); } function fix_scripts(e) { if (fs) return; if (e.element.id && (e.element.id.indexOf('bird') >= 0)) return; var u, v, s, t, i; if (e.element.text.indexOf('var hs = hs || {};') >= 0) for (i = 0; i < hs.features.length; i++) { if (hs.features[i].c.indexOf('PUB-UNIFIED_MENTIONS_MASTER') >= 0) hs.features[i].v = 0; if (hs.features[i].c.indexOf('ADS_') == 0) hs.features[i].v = 0; } u = e.element.src || e.element.baseURI || ''; if (u && (u.indexOf('core') >= 0)) { s = document.createElement('script'); s.id = 'birdstreams'; s.type = 'text/javascript'; s.src = hs.util.rootifyJs('/hs/streams.js').replace(/\.js$/, '.' + hs.gZipVersionOrNot + 'js'); t = document.createElement('script'); t.id = 'birddashboard'; t.type = 'text/javascript'; t.src = hs.util.rootifyJs('/hs/dashboard.js').replace(/\.js$/, '.' + hs.gZipVersionOrNot + 'js'); v = document.getElementsByTagName('head')[0]; v.appendChild(t); v.appendChild(s); fs = true; } } function add_local_css(e) { var s, t; if (document.getElementById('unfuck')) return; s = document.createElement('style'); s.type = 'text/css'; s.id = 'unfuck'; t = ' \ // CSS GOES HERE button._imageToggle { display: none; } \ .-counts { float: right; margin-right: 25px; } \ '; s.appendChild(document.createTextNode(t)); document.getElementsByTagName('head')[0].appendChild(s); misc_fixes(); } window.opera.addEventListener('BeforeScript', remove_adscripts, true); if (location.href.indexOf('dashboard') > -1) { window.opera.addEventListener('AfterScript', fix_scripts, true); document.addEventListener('load', remove_images, true); window.opera.addEventListener('BeforeCSS', remove_remote_css, true); window.opera.addEventListener('BeforeEvent.DOMContentLoaded', add_local_css, true); } })();

And here is the CSS-less version of the Firefox script (the CSS in the real version is the same as the Opera script). It is more or less the same as the Opera script with a few Firefox-specific differences. Of course. The most significant difference is not in the script itself, but in how you install it. Installing the Opera one is dead simple as you just copy it into the appropriate directory (ie. ~/.opera/js/user). I fucked around for bleeding ages trying to do this with Greasemonkey and swore the fucking place down trying to get the cunt to install the bastard thing instead of ignoring it or overwriting it with an empty script like a massive great tagnut. Turns out that you have to open the script from Firefox's File -> Open File... menu; when you do this a message pops up asking if you want to install it as a Greasemonkey script. Fucksake. Once you have done this, though, it is perfectly possible to edit the file that has appeared in the ~/.mozilla/firefox/alphabetsoup.default/gm_scripts/hootsuite-unfuck directory and fuck about with it. This stupid fucking shite gave me another reason to consider Opera to be better than Firefox.

The event handlers are slightly different, of course. Also with Firefox you can't wrap the whole thing in an anonymous function because it throws an error, like a cunt, but it gives it its own namespace anyway so it doesn't really matter.

remove_remote_css() is a bit different because Firefox doesn't have the BeforeCSS event, so instead it just deletes all the relevant stylesheet nodes after add_local_css() inserts the good CSS.

There is no fix_scripts() in this version because Firefox doesn't seem to have that bug so we don't need to fuck about. Maybe it does have it but it just hasn't showed up yet, in which case I shall wait until it does and then swear a lot and edit this script. Accordingly the updated code to get rid of the rich bollocks is in a separate function fix_features().

// ==UserScript== // @name hootsuite-unfuck // @namespace xx // @include http://hootsuite.com/* // @include https://hootsuite.com/* // @include http://www.hootsuite.com/* // @include https://www.hootsuite.com/* // @grant none // @run-at document-start // ==/UserScript== function remove_images(e) { var u, m, n; if (!(u = e.target.src)) return; if (!u.match(/https?:\/\/pbs\.twimg\.com\/media\/[A-Za-z0-9_-]+\.(jp|pn)g/)) return; m = e.target.parentNode.parentNode; // should be div.mediaGallery n = m.parentNode; // should be div.-messageBody m.removeChild(e.target.parentNode); if (m.getElementsByTagName('a').length == 0) n.removeChild(m); n = n.getElementsByTagName('p')[0]; m = document.createElement('a'); m.appendChild(document.createTextNode(u.replace(/^.*\//, ''))); if (!u.match(/:large$/)) u += ':large'; m.href = u; m.target = '_blank'; n.appendChild(document.createTextNode(' ')); n.appendChild(m); } function remove_remote_css() { var e, a, l, i, j, z, x; z = ['cloudfront.net', 'fonts.googleapis', 'dashboardPrimary', 'dashboardSecondary']; l = document.getElementsByTagName('link'); a = new Array(); for (i=0; l[i]; i++) a.push(l[i]); while (e = a.shift()) { if (e.href) { x = false; for (j = 0; z[j]; j++) if (e.href.indexOf(z[j]) >= 0) { x = true; break; } if (x) e.parentNode.removeChild(e); } } } function misc_fixes() { var a, i; a = document.getElementsByTagName('button'); for (i=0; a[i]; i++) if (a[i].innerHTML.indexOf('Upgrade to Pro') >= 0) { a[i].parentNode.removeChild(a[i]); break; } } function fix_features(e) { var i; if (e.target.text.indexOf('var hs = hs || {};') >= 0) for (i = 0; i < hs.features.length; i++) { if (hs.features[i].c.indexOf('PUB-UNIFIED_MENTIONS_MASTER') >= 0) hs.features[i].v = 0; if (hs.features[i].c.indexOf('ADS_') == 0) hs.features[i].v = 0; } } function remove_adscripts(e) { var a, b; a = e.target.src || e.target.baseURI || ''; if ((b = a.indexOf('cloudfront.net')) >= 0) a = a.substr(b).replace(/(.*\/[a-z]+)\.[0-9a-f]+\.gz\.js$/, "$1.gz.js"); if ((a.indexOf('ad') >= 0) || (a.indexOf('nr-data') >= 0) || (e.target.text.indexOf('ad') == 0)) e.preventDefault(); } function add_local_css(e) { var s, t; if (document.getElementById('unfuck')) return; s = document.createElement('style'); s.type = 'text/css'; s.id = 'unfuck'; t = ' \ // CSS GOES HERE button._imageToggle { display: none; } \ .-counts { float: right; margin-right: 25px; } \ '; s.appendChild(document.createTextNode(t)); document.getElementsByTagName('head')[0].appendChild(s); remove_remote_css(); misc_fixes(); } document.addEventListener('beforescriptexecute', remove_adscripts, true); document.addEventListener('afterscriptexecute', fix_features, true); if (location.href.indexOf('dashboard') > -1) { document.addEventListener('load', remove_images, true); document.addEventListener('DOMContentLoaded', add_local_css, true); }

Anyway it seems to work as of 2015-01-10 but since I have only just written it there is still plenty of opportunity for it to fuck up, so I hope I will remember to update this page with the fixes if it does.

Update 2015-03-16: The fucking "Upgrade to Pro" changed from being an <a> element to a <button> element; script updated to continue getting rid of it. Also the active tab header colour somehow changed so as to make it nearly invisible so the CSS has been updated to turn it white and legible again.

Update 2015-04-12: The stupid bastards made the "retweets" links and several other things that used to be links into fucking buttons, which looked like utter shite. Updated CSS makes them look like links again. The "More" icon at the top right of the tabs went loopy and displayed as bits of three other icons, which was fucking annoying because I couldn't actually remember what used to be there and I couldn't find an icon which rang any bells, so I made it a + sign. I also noticed that the "add tab" and "delete tab" buttons were actually still there, just black on a fucking nearly-black background so I couldn't see the bastard things, so I made them white. And Hootsuite implemented their own version of my replacement image links, but it was really messy and shit, so I've turned their implementation back into my one.

Update 2015-05-18: The wankers added some more CSS, from URLs of the form https://alphabetsoup.content.hootsuite.com/v2/css/dashboard{Primary|Secondary}.alphabetsoup.gz.css, which had the effect of royally fucking shit up. Function remove_remote_css() updated to get rid of this arse. Also noticed (while watching network traffic with wireshark for totally unrelated reasons) that some fucking spy script from bam.nr-data.net has been added and keeps sending data to those cunts. Function remove_adscripts() updated to kill this shit.

Looking over this page after adding the above paragraph I notice that the need to alter the script to fix new stupid fucking shite has arisen at pretty regular monthly intervals. It seems that Hootsuite have adopted a policy of fucking shit up half way through every month. It would be much better if they would adopt a policy of not fucking shit up at all.

Update 2015-11-03: Add an extra condition to the adscript identification in remove_adscripts() to avoid problems when the hex_bollocks in scripts named something_useful.hex_bollocks.gz.js happens to have ad in it.

Update 2016-04-18: More bollocks from Hootsuite: the plain textarea for entering tweets has been replaced by some spazzy-arsed "rich composer" shite, which like any user interface thing with "rich" in the name is a load of fucking arse. Turns out the inline script which sets up a load of variables has grown something called PUB-UNIFIED_MENTIONS_MASTER which it sets to 1; setting this to 0 turns the rich bollocks off and puts the plain textarea back. So I added code to run immediately after the inline script to set this to 0. While doing this I found a load of shit to do with ads so I made it set all those values to 0 as well. This code is in fix_features() in the Firefox version, and is part of fix_scripts() in the Opera version.

Note that I only use Hootsuite for twitter so I can't say if this script still leaves things fucked on any of the other sites it can handle. I do know the inline images bit won't work because it looks specifically for twitter URLs, but you could always add your own regexes for other sites if you want to. The rest of it would probably be all right at a guess.

Note also that the last version of Opera which is available for Linux is 12.16. So if you are using a Windows version which is later than that and Opera too have fucked shit up so the script doesn't work then you are on your own I'm afraid.




Back to Pigeon's Nest


Be kind to pigeons




Valid HTML 4.01!