There are 15 previous versions of this script.
// ==UserScript==
// @name YouTube Link Fixer
// @author Mick Koch
// @description Remove the JavaScript magic from YouTube navigation.
// @version 0.2.6
// @namespace http://userscripts.org/users/79579
// @include http://*youtube.tld/*
// @require http://userscripts.org/scripts/source/44063.user.js
// ==/UserScript==
// This script is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What The Fuck You Want
// To Public License, Version 2, as published by Sam Hocevar. See
// http://sam.zoy.org/wtfpl/COPYING for more details.
Element.implement({
fix: function(fixers) {
fixers.some(function(fixer) {
return new fixer(this).fix();
}.bind(this));
return this;
}
});
Object.from_query_string = function(query_string) {
/* Create an Object from a query string.
@notes:
Any leading question marks will be removed.
Keys with no value will be set to null.
@example:
Object.from_query_string("a=b&c=d&e=f");
-> {a: "b", c: "d", e: "f"}
Object.from_query_string("a=&b=c");
-> {a: null, b: "c"}
@arg query_string (optional):
A query string to parse or undefined to use the current location's.
@return: an Object. */
if (query_string === undefined) {
query_string = location.search;
}
if (query_string[0] == "?") {
query_string = query_string.substring(1);
}
var params = query_string.split("&");
var object = {};
params.each(function(param) {
var pair = param.split("=").map(function(item) {
return unescape(item);
});
var key = pair[0];
var value = pair[1];
if (value === "") {
value = null;
}
object[key] = value;
});
return object;
};
var URL = new Class({
initialize: function(params, base) {
/* @arg params:
An Object of params to use as a query string.
@arg base (optional):
A hostname/pathname or undefined to use the current
location's. */
this.base = base;
this.params = params;
},
path: function() {
return this.base || location.pathname;
},
query: function() {
/* Get the query string part of a URL.
@example:
new URL({a: "b", c: "d" }, "/path").query();
-> "a=b&c=d"
@return: a String. */
return Hash.toQueryString(this.params);
},
full: function() {
/* Get a constructed URL.
@example:
new URL({a: "b", c: "d" }, "/path").full();
-> "/path?a=b&c=d"
@return: a String. */
if (this.params) {
return [this.path(), this.query()].join("?");
}
return this.path();
}
});
var ExtendedURL = new Class({ Extends: URL,
/* URL parameters are merged with the current location's. */
initialize: function(params, base) {
/* @arg params: new parameters to merge. */
this.parent($merge(Object.from_query_string(), params), base);
}
});
var Fixer = new Class({
fixes: [],
initialize: function(el) {
this.el = el;
this.attrs = [this.el.get("onclick"), this.el.get("href")];
},
url: function(link) {},
replace: function(url) {
return this.el.set("href", url.full());
},
attempt: function(fix) {
return this.attrs.some(function(attr) {
var matches = fix.exec(attr);
if (matches) {
return this.replace(this.url(matches[1]));
}
}.bind(this));
},
fix: function() {
return this.fixes.some(this.attempt.bind(this));
}
});
var OverwriteFixer = new Class({ Extends: Fixer,
replace: function(url) {
return this.parent(url).erase("onclick");
}
});
var Fixers = new Class({
initialize: function() {
this.fixers = Array.slice(arguments);
},
elements: function() {
return $$("a");
},
fix: function() {
return this.elements().fix(this.fixers);
}
});
// Fixers
var PlayVideo = new Class({ Extends: OverwriteFixer,
fixes: [new RegExp("onPlayVideos\\('/watch\\?v=(.+)'\\)"),
new RegExp("fireEvent\\('PlayVideos', \\['(.+)'\\]\\)"),
new RegExp("onPlayVideos\\(\\['(.+)'\\]\\)")],
url: function(link) {
return new URL({v: link}, "/watch");
}
});
var EditVideo = new Class({ Extends: OverwriteFixer,
fixes: [new RegExp("fireEvent\\('EditVideos', \\['(.+)'\\]\\)")],
url: function(link) {
return new URL({video_id: link}, "/my_videos_edit");
}
});
var Annotations = new Class({ Extends: OverwriteFixer,
fixes: [new RegExp("fireEvent\\('AnnotateVideos', \\['(.+)'\\]\\)")],
url: function(link) {
return new URL({v: link}, "/my_videos_annotate");
}
});
var AudioSwap = new Class({ Extends: OverwriteFixer,
fixes: [
new RegExp("fireEvent\\('AudioSwap', \\['(.+)'\\]\\)")],
url: function(link) {
return new URL({v: link}, "/watch_editaudio");
}
});
var Insight = new Class({ Extends: OverwriteFixer,
fixes: [new RegExp("fireEvent\\('InsightVideos', \\['(.+)'\\]\\)")],
url: function(link) {
return new URL({v: link}, "/my_videos_insight");
}
});
var Subscription = new Class({ Extends: OverwriteFixer,
fixes: [new RegExp("changeSubscription\\('(.+)'\\)"),
new RegExp("changeSubscription\\(null\\)")],
url: function(link) {
if (link) {
return new ExtendedURL({s: link});
}
return new URL(null, "/my_subscriptions");
}
});
var Playlist = new Class({ Extends: OverwriteFixer,
fixes: [new RegExp("changePlaylist\\('(.+)'\\)")],
url: function(link) {
return new ExtendedURL({p: link});
}
});
var Page = new Class({ Extends: OverwriteFixer,
fixes: [new RegExp("applyPage\\((\\d+)\\)")],
url: function(link) {
return new ExtendedURL({pi: link});
}
});
var SharePlaylist = new Class({ Extends: OverwriteFixer,
fixes: [new RegExp("fireEvent\\('SharePlaylist', '(.+)'\\)"),
new RegExp("share\\('(.+)'\\)")],
url: function(link) {
return new URL({p: link}, "/share");
}
});
window.addEvent("load", function() {
var fixers = new Fixers(PlayVideo,
EditVideo,
Annotations,
AudioSwap,
Insight,
Subscription,
Playlist,
Page,
SharePlaylist);
return fixers.fix();
});
