Release 4chan X v1.7.32.

This commit is contained in:
ccd0 2014-05-10 01:09:14 -07:00
parent 93628fb502
commit 368baebfc1
9 changed files with 287 additions and 312 deletions

View File

@ -1,3 +1,6 @@
### v1.7.32
*2014-05-10*
**Zixaphir, ccd0** **Zixaphir, ccd0**
- Bug fixes in linkification/embedding. - Bug fixes in linkification/embedding.

View File

@ -1,5 +1,5 @@
/* /*
* 4chan X - Version 1.7.31 - 2014-05-08 * 4chan X - Version 1.7.32 - 2014-05-10
* *
* Licensed under the MIT license. * Licensed under the MIT license.
* https://github.com/ccd0/4chan-x/blob/master/LICENSE * https://github.com/ccd0/4chan-x/blob/master/LICENSE

View File

@ -1,6 +1,6 @@
// ==UserScript== // ==UserScript==
// @name 4chan X // @name 4chan X
// @version 1.7.31 // @version 1.7.32
// @minGMVer 1.14 // @minGMVer 1.14
// @minFFVer 26 // @minFFVer 26
// @namespace 4chan-X // @namespace 4chan-X

View File

@ -1,7 +1,7 @@
// Generated by CoffeeScript // Generated by CoffeeScript
// ==UserScript== // ==UserScript==
// @name 4chan X // @name 4chan X
// @version 1.7.31 // @version 1.7.32
// @minGMVer 1.14 // @minGMVer 1.14
// @minFFVer 26 // @minFFVer 26
// @namespace 4chan-X // @namespace 4chan-X
@ -24,7 +24,7 @@
// ==/UserScript== // ==/UserScript==
/* /*
* 4chan X - Version 1.7.31 - 2014-05-08 * 4chan X - Version 1.7.32 - 2014-05-10
* *
* Licensed under the MIT license. * Licensed under the MIT license.
* https://github.com/ccd0/4chan-x/blob/master/LICENSE * https://github.com/ccd0/4chan-x/blob/master/LICENSE
@ -372,7 +372,7 @@
doc = d.documentElement; doc = d.documentElement;
g = { g = {
VERSION: '1.7.31', VERSION: '1.7.32',
NAMESPACE: '4chan X.', NAMESPACE: '4chan X.',
boards: {} boards: {}
}; };
@ -8488,7 +8488,6 @@
if (g.VIEW === 'catalog' || !Conf['Linkify']) { if (g.VIEW === 'catalog' || !Conf['Linkify']) {
return; return;
} }
this.regString = /((https?|mailto|git|magnet|ftp|irc):([a-z\d%\/])|[-a-z\d]+[.](aero|asia|biz|cat|com|coop|info|int|jobs|mobi|museum|name|net|org|post|pro|tel|travel|xxx|edu|gov|mil|[a-z]{2})(\/|(?!.))|[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}|[-\w\d.@]+@[a-z\d.-]+\.[a-z\d])/i;
this.types = {}; this.types = {};
_ref = this.ordered_types; _ref = this.ordered_types;
for (_i = 0, _len = _ref.length; _i < _len; _i++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
@ -8498,27 +8497,28 @@
if (Conf['Comment Expansion']) { if (Conf['Comment Expansion']) {
ExpandComment.callbacks.push(this.node); ExpandComment.callbacks.push(this.node);
} }
if (Conf['Title Link']) {
$.sync('CachedTitles', Linkify.titleSync);
}
return Post.callbacks.push({ return Post.callbacks.push({
name: 'Linkify', name: 'Linkify',
cb: this.node cb: this.node
}); });
}, },
node: function() { events: function(post) {
var data, el, end, endNode, i, index, items, length, link, links, node, result, saved, snapshot, space, test, word, _i, _len, _ref; var el, i, items;
if (this.isClone) { i = 0;
if (Conf['Embedding']) { items = $$('.embedder', post.nodes.comment);
i = 0; while (el = items[i++]) {
items = $$('.embed', this.nodes.comment); $.on(el, 'click', Linkify.cb.toggle);
while (el = items[i++]) { if ($.hasClass(el, 'embedded')) {
$.on(el, 'click', Linkify.cb.toggle); Linkify.cb.toggle.call(el);
if ($.hasClass(el, 'embedded')) {
Linkify.cb.toggle.call(el);
}
}
} }
}
},
node: function() {
var data, end, endNode, i, index, length, link, links, node, result, saved, snapshot, space, test, word;
if (this.isClone) {
return (Conf['Embedding'] ? Linkify.events(this) : null);
}
if (!Linkify.regString.test(this.info.comment)) {
return; return;
} }
test = /[^\s'"]+/g; test = /[^\s'"]+/g;
@ -8528,7 +8528,7 @@
links = []; links = [];
while (node = snapshot.snapshotItem(i++)) { while (node = snapshot.snapshotItem(i++)) {
data = node.data; data = node.data;
if (node.parentElement.nodeName === "A" || !data) { if (!data || node.parentElement.nodeName === "A") {
continue; continue;
} }
while (result = test.exec(data)) { while (result = test.exec(data)) {
@ -8560,28 +8560,25 @@
} }
} }
} }
_ref = links.reverse(); i = links.length;
for (_i = 0, _len = _ref.length; _i < _len; _i++) { while (i--) {
link = _ref[_i]; link = links[i];
this.nodes.links.push(Linkify.makeLink(link, this)); Linkify.embedProcess(Linkify.makeLink(link, this), this);
link.detach();
} }
if (!(Conf['Embedding'] || Conf['Link Title'])) { },
return; embedProcess: function(link, post) {
} var data;
links = this.nodes.links; if (data = Linkify.services(link)) {
i = 0; data.push(post);
while (link = links[i++]) { if (Conf['Embedding']) {
if (data = Linkify.services(link)) { Linkify.embed(data);
if (Conf['Embedding']) { }
Linkify.embed(data); if (Conf['Link Title']) {
} return Linkify.title(data);
if (Conf['Link Title']) {
Linkify.title(data);
}
} }
} }
}, },
regString: /((https?|mailto|git|magnet|ftp|irc):([a-z\d%\/])|[-a-z\d]+[.](aero|asia|biz|cat|com|coop|info|int|jobs|mobi|museum|name|net|org|post|pro|tel|travel|xxx|edu|gov|mil|[a-z]{2})([:\/]|(?!.))|[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}|[-\w\d.@]+@[a-z\d.-]+\.[a-z\d])/i,
makeRange: function(startNode, endNode, startOffset, endOffset) { makeRange: function(startNode, endNode, startOffset, endOffset) {
var range; var range;
range = document.createRange(); range = document.createRange();
@ -8590,7 +8587,7 @@
return range; return range;
}, },
makeLink: function(range) { makeLink: function(range) {
var a, char, i, text; var a, i, t, text;
text = range.toString(); text = range.toString();
i = 0; i = 0;
while (/[(\[{<>]/.test(text.charAt(i))) { while (/[(\[{<>]/.test(text.charAt(i))) {
@ -8606,8 +8603,8 @@
} }
} }
i = 0; i = 0;
while (/[)\]}>.,]/.test(char = text.charAt(text.length - (1 + i)))) { while (/[)\]}>.,]/.test(t = text.charAt(text.length - (1 + i)))) {
if (!(/[.,]/.test(char) || (text.match(/[()\[\]{}<>]/g)).length % 2)) { if (!(/[.,]/.test(t) || (text.match(/[()\[\]{}<>]/g)).length % 2)) {
break; break;
} }
i++; i++;
@ -8621,7 +8618,7 @@
range.setEnd(range.endContainer, range.endOffset - i); range.setEnd(range.endContainer, range.endOffset - i);
} }
} }
if (!/(https?|mailto|git|magnet|ftp|irc):/.test(text)) { if (!/(mailto:|.+:\/\/)/.test(text)) {
text = (/@/.test(text) ? 'mailto:' : 'http://') + text; text = (/@/.test(text) ? 'mailto:' : 'http://') + text;
} }
a = $.el('a', { a = $.el('a', {
@ -8632,6 +8629,7 @@
}); });
$.add(a, range.extractContents()); $.add(a, range.extractContents());
range.insertNode(a); range.insertNode(a);
range.detach();
return a; return a;
}, },
services: function(link) { services: function(link) {
@ -8644,14 +8642,14 @@
continue; continue;
} }
if (type.dummy) { if (type.dummy) {
break; return;
} }
return [type.key, match[1], match[2], link]; return [type.key, match[1], match[2], link];
} }
}, },
embed: function(data) { embed: function(data) {
var embed, href, key, link, name, options, uid, value, _ref; var embed, href, key, link, name, options, post, uid, value, _ref;
key = data[0], uid = data[1], options = data[2], link = data[3]; key = data[0], uid = data[1], options = data[2], link = data[3], post = data[4];
href = link.href; href = link.href;
embed = $.el('a', { embed = $.el('a', {
className: 'embedder', className: 'embedder',
@ -8668,57 +8666,47 @@
value = _ref[name]; value = _ref[name];
embed.dataset[name] = value; embed.dataset[name] = value;
} }
embed.dataset.nodedata = link.innerHTML;
$.addClass(link, "" + embed.dataset.key); $.addClass(link, "" + embed.dataset.key);
$.on(embed, 'click', Linkify.cb.toggle); $.on(embed, 'click', Linkify.cb.toggle);
$.after(link, [$.tn(' '), embed]); $.after(link, [$.tn(' '), embed]);
if (Conf['Auto-embed']) { if (Conf['Auto-embed']) {
Linkify.cb.toggle.call(embed); return Linkify.cb.toggle.call(embed);
} }
data.push(embed);
}, },
title: function(data) { title: function(data) {
var embed, err, key, link, options, service, title, titles, uid; var err, key, link, options, post, service, title, titles, uid;
key = data[0], uid = data[1], options = data[2], link = data[3], embed = data[4]; key = data[0], uid = data[1], options = data[2], link = data[3], post = data[4];
if (!(service = Linkify.types[key].title)) { if (!(service = Linkify.types[key].title)) {
return; return;
} }
titles = Conf['CachedTitles']; titles = Conf['CachedTitles'];
if (title = titles[uid]) { if (title = titles[uid]) {
if (link) { return link.textContent = title[0];
link.textContent = title[0];
}
if (Conf['Embedding']) {
return embed.dataset.title = title[0];
}
} else { } else {
try { try {
$.cache(service.api(uid), function() { return $.cache(service.api(uid), (function() {
return title = Linkify.cb.title(this, data); return Linkify.cb.title(this, data);
}, { }), {
responseType: 'json' responseType: 'json'
}); });
} catch (_error) { } catch (_error) {
err = _error; err = _error;
if (link) { link.innerHTML = '<span class="warning">Title Link Blocked</span> (are you using NoScript?)</a>';
link.innerHTML = "[" + key + "] <span class=warning>Title Link Blocked</span> (are you using NoScript?)</a>"; $.prepend(link, $.tn("[" + key + "] "));
}
return;
}
if (title) {
titles[uid] = [title, Date.now()];
return $.set('CachedTitles', titles);
} }
} }
}, },
titleSync: function(value) {
return Conf['CachedTitles'] = value;
},
cb: { cb: {
toggle: function() { toggle: function() {
var string, _ref; if ($.hasClass(this, "embedded")) {
_ref = $.hasClass(this, "embedded") ? ['unembed', '(embed)'] : ['embed', '(unembed)'], string = _ref[0], this.textContent = _ref[1]; $.rm(this.previousElementSibling);
$.replace(this.previousElementSibling, Linkify.cb[string](this)); this.previousElementSibling.hidden = false;
this.textContent = '(embed)';
} else {
this.previousElementSibling.hidden = true;
$.before(this, Linkify.cb.embed(this));
this.textContent = '(unembed)';
}
return $.toggleClass(this, 'embedded'); return $.toggleClass(this, 'embedded');
}, },
embed: function(a) { embed: function(a) {
@ -8727,45 +8715,35 @@
el.style.cssText = type.style != null ? type.style : "border: 0; width: 640px; height: 390px"; el.style.cssText = type.style != null ? type.style : "border: 0; width: 640px; height: 390px";
return el; return el;
}, },
unembed: function(a) { title: function(req, data) {
var el; var key, link, link2, options, post, post2, service, status, text, uid, _i, _j, _len, _len1, _ref, _ref1;
el = $.el('a', { key = data[0], uid = data[1], options = data[2], link = data[3], post = data[4];
rel: 'nofollow noreferrer', status = req.status;
target: 'blank',
className: 'linkify',
href: a.dataset.href
});
if (a.dataset.title) {
el.textContent = a.dataset.title;
} else {
el.innerHTML = a.dataset.nodedata;
}
$.addClass(el, a.dataset.key);
return el;
},
title: function(response, data) {
var embed, key, link, options, service, text, uid;
key = data[0], uid = data[1], options = data[2], link = data[3], embed = data[4];
service = Linkify.types[key].title; service = Linkify.types[key].title;
switch (response.status) { text = "[" + key + "] " + ((function() {
case 200: switch (status) {
case 304: case 200:
text = "" + (service.text(response.response)); case 304:
if (Conf['Embedding']) { return service.text(req.response);
embed.dataset.title = text; case 404:
return "Not Found";
case 403:
return "Forbidden or Private";
default:
return "" + status + "'d";
}
})());
link.textContent = text;
_ref = post.clones;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
post2 = _ref[_i];
_ref1 = $$('a', post2.nodes.comment);
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
link2 = _ref1[_j];
if (link2.href === link.href) {
link2.textContent = text;
} }
break; }
case 404:
text = "[" + key + "] Not Found";
break;
case 403:
text = "[" + key + "] Forbidden or Private";
break;
default:
text = "[" + key + "] " + this.status + "'d";
}
if (link) {
return link.textContent = text;
} }
} }
}, },
@ -8809,18 +8787,11 @@
regExp: /(http|www).*\.(gif|png|jpg|jpeg|bmp)$/, regExp: /(http|www).*\.(gif|png|jpg|jpeg|bmp)$/,
style: 'border: 0; width: auto; height: auto;', style: 'border: 0; width: auto; height: auto;',
el: function(a) { el: function(a) {
var div, img, link; var el;
img = $.el('img', { el = $.el('div');
src: a.dataset.href el.innerHTML = '<a target="_blank"><img></a>';
}); el.firstChild.href = el.firstChild.firstChild.src = a.dataset.href;
link = $.el('a', { return el;
target: '_blank',
href: a.dataset.href
});
div = $.el('div');
$.add(link, img);
$.add(div, link);
return div;
} }
}, { }, {
key: 'InstallGentoo', key: 'InstallGentoo',
@ -8860,13 +8831,13 @@
var el; var el;
el = $.el('div'); el = $.el('div');
$.cache("https://mediacru.sh/" + a.dataset.uid + ".json", function() { $.cache("https://mediacru.sh/" + a.dataset.uid + ".json", function() {
var embed, file, files, status, type, _i, _j, _len, _len1, _ref; var embed, ext, file, files, i, status, type, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _results, _results1;
status = this.status; status = this.status;
if (status !== 200 && status !== 304) { if (status !== 200 && status !== 304) {
return el.textContent = "ERROR " + status; return el.textContent = "ERROR " + status;
} }
files = this.response.files; files = this.response.files;
_ref = ['video/mp4', 'video/ogv', 'image/svg+xml', 'image/png', 'image/gif', 'image/jpeg', 'image/svg', 'audio/mpeg']; _ref = ['video/mp4', 'video/webm', 'video/ogv', 'image/svg+xml', 'image/png', 'image/gif', 'image/jpeg', 'audio/mpeg', 'audio/ogg'];
for (_i = 0, _len = _ref.length; _i < _len; _i++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
type = _ref[_i]; type = _ref[_i];
for (_j = 0, _len1 = files.length; _j < _len1; _j++) { for (_j = 0, _len1 = files.length; _j < _len1; _j++) {
@ -8885,20 +8856,35 @@
} }
switch (embed.type) { switch (embed.type) {
case 'video/mp4': case 'video/mp4':
case 'video/webm':
case 'video/ogv': case 'video/ogv':
return el.innerHTML = "<video autoplay loop>\n <source src=\"https://mediacru.sh/" + a.dataset.uid + ".mp4\" type=\"video/mp4;\">\n <source src=\"https://mediacru.sh/" + a.dataset.uid + ".ogv\" type=\"video/ogg; codecs='theora, vorbis'\">\n</video>"; el.innerHTML = '<video autoplay loop><source type="video/mp4"><source type="video/webm"><source type="video/ogg"></video>';
_ref1 = ['mp4', 'webm', 'ogv'];
_results = [];
for (i = _k = 0, _len2 = _ref1.length; _k < _len2; i = ++_k) {
ext = _ref1[i];
_results.push(el.firstChild.children[i].src = "https://mediacru.sh/" + a.dataset.uid + "." + ext);
}
return _results;
break;
case 'image/svg+xml':
case 'image/png': case 'image/png':
case 'image/gif': case 'image/gif':
case 'image/jpeg': case 'image/jpeg':
case 'image/svg': el.innerHTML = '<a target="_blank"><img></a>';
case 'image/svg+xml': el.firstChild.href = a.dataset.href;
return $.add(el, $.el('a', { return el.firstChild.firstChild.src = "https://mediacru.sh/" + file.file;
target: '_blank',
href: a.dataset.href,
innerHTML: "<img src='https://mediacru.sh/" + file.file + "'>"
}));
case 'audio/mpeg': case 'audio/mpeg':
return el.innerHTML = "<audio controls><source src='https://mediacru.sh/" + file.file + "'></audio>"; case 'audio/ogg':
el.innerHTML = '<audio controls><source type="audio/ogg"><source type="audio/mpeg"></audio>';
_ref2 = ['ogg', 'mp3'];
_results1 = [];
for (i = _l = 0, _len3 = _ref2.length; _l < _len3; i = ++_l) {
ext = _ref2[i];
_results1.push(el.firstChild.children[i].src = "https://mediacru.sh/" + a.dataset.uid + "." + ext);
}
return _results1;
break;
default: default:
return el.textContent = "ERROR: No valid filetype."; return el.textContent = "ERROR: No valid filetype.";
} }
@ -8926,23 +8912,15 @@
}, { }, {
key: 'SoundCloud', key: 'SoundCloud',
regExp: /.*(?:soundcloud.com\/|snd.sc\/)([^#\&\?]*).*/, regExp: /.*(?:soundcloud.com\/|snd.sc\/)([^#\&\?]*).*/,
style: 'height: auto; width: 500px; display: inline-block;', style: 'border: 0; width: 500px; height: 400px;',
el: function(a) { el: function(a) {
var div; return $.el('iframe', {
div = $.el('div', { src: "//w.soundcloud.com/player/?visual=true&show_comments=false&url=https%3A%2F%2Fsoundcloud.com%2F" + (encodeURIComponent(a.dataset.uid))
className: "soundcloud",
name: "soundcloud"
}); });
$.ajax("//soundcloud.com/oembed?show_artwork=false&&maxwidth=500px&show_comments=false&format=json&url=https://www.soundcloud.com/" + a.dataset.uid, {
onloadend: function() {
return div.innerHTML = JSON.parse(this.responseText).html;
}
}, false);
return div;
}, },
title: { title: {
api: function(uid) { api: function(uid) {
return "//soundcloud.com/oembed?show_artwork=false&&maxwidth=500px&show_comments=false&format=json&url=https://www.soundcloud.com/" + uid; return "//soundcloud.com/oembed?format=json&url=https%3A%2F%2Fsoundcloud.com%2F" + (encodeURIComponent(uid));
}, },
text: function(_) { text: function(_) {
return _.title; return _.title;
@ -8962,19 +8940,27 @@
regExp: /.*(?:twitch.tv\/)([^#\&\?]*).*/, regExp: /.*(?:twitch.tv\/)([^#\&\?]*).*/,
style: "border: none; width: 640px; height: 360px;", style: "border: none; width: 640px; height: 360px;",
el: function(a) { el: function(a) {
var channel, chapter, result, _; var channel, id, idparam, obj, result, type, _;
if (result = /(\w+)\/(?:[a-z]\/)?(\d+)/i.exec(a.dataset.uid)) { if (result = /(\w+)\/([bc])\/(\d+)/i.exec(a.dataset.uid)) {
_ = result[0], channel = result[1], chapter = result[2]; _ = result[0], channel = result[1], type = result[2], id = result[3];
return $.el('object', { idparam = {
data: 'http://www.twitch.tv/widgets/archive_embed_player.swf', 'b': 'archive_id',
innerHTML: "<param name='allowFullScreen' value='true' />\n<param name='flashvars' value='channel=" + channel + "&start_volume=25&auto_play=false" + (chapter ? "&chapter_id=" + chapter : "") + "' />" 'c': 'chapter_id'
};
obj = $.el('object', {
data: 'http://www.twitch.tv/widgets/archive_embed_player.swf'
}); });
obj.innerHTML = '<param name="allowFullScreen" value="true"><param name="flashvars">';
obj.children[1].value = "channel=" + channel + "&start_volume=25&auto_play=false&" + idparam[type] + "=" + id;
return obj;
} else { } else {
channel = (/(\w+)/.exec(a.dataset.uid))[0]; channel = (/(\w+)/.exec(a.dataset.uid))[0];
return $.el('object', { obj = $.el('object', {
data: "http://www.twitch.tv/widgets/live_embed_player.swf?channel=" + channel, data: "http://www.twitch.tv/widgets/live_embed_player.swf?channel=" + channel
innerHTML: "<param name=\"allowFullScreen\" value=\"true\" />\n<param name=\"movie\" value=\"http://www.twitch.tv/widgets/live_embed_player.swf\" />\n<param name=\"flashvars\" value=\"hostname=www.twitch.tv&channel=" + channel + "&auto_play=true&start_volume=25\" />"
}); });
obj.innerHTML = '<param name="allowFullScreen" value="true"><param name="flashvars">';
obj.children[1].value = "hostname=www.twitch.tv&channel=" + channel + "&auto_play=true&start_volume=25";
return obj;
} }
} }
}, { }, {

Binary file not shown.

View File

@ -1,6 +1,6 @@
{ {
"name": "4chan X", "name": "4chan X",
"version": "1.7.31", "version": "1.7.32",
"manifest_version": 2, "manifest_version": 2,
"description": "Cross-browser userscript for maximum lurking on 4chan.", "description": "Cross-browser userscript for maximum lurking on 4chan.",
"icons": { "icons": {

View File

@ -1,6 +1,6 @@
// Generated by CoffeeScript // Generated by CoffeeScript
/* /*
* 4chan X - Version 1.7.31 - 2014-05-08 * 4chan X - Version 1.7.32 - 2014-05-10
* *
* Licensed under the MIT license. * Licensed under the MIT license.
* https://github.com/ccd0/4chan-x/blob/master/LICENSE * https://github.com/ccd0/4chan-x/blob/master/LICENSE
@ -348,7 +348,7 @@
doc = d.documentElement; doc = d.documentElement;
g = { g = {
VERSION: '1.7.31', VERSION: '1.7.32',
NAMESPACE: '4chan X.', NAMESPACE: '4chan X.',
boards: {} boards: {}
}; };
@ -8485,7 +8485,6 @@
if (g.VIEW === 'catalog' || !Conf['Linkify']) { if (g.VIEW === 'catalog' || !Conf['Linkify']) {
return; return;
} }
this.regString = /((https?|mailto|git|magnet|ftp|irc):([a-z\d%\/])|[-a-z\d]+[.](aero|asia|biz|cat|com|coop|info|int|jobs|mobi|museum|name|net|org|post|pro|tel|travel|xxx|edu|gov|mil|[a-z]{2})(\/|(?!.))|[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}|[-\w\d.@]+@[a-z\d.-]+\.[a-z\d])/i;
this.types = {}; this.types = {};
_ref = this.ordered_types; _ref = this.ordered_types;
for (_i = 0, _len = _ref.length; _i < _len; _i++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
@ -8495,27 +8494,28 @@
if (Conf['Comment Expansion']) { if (Conf['Comment Expansion']) {
ExpandComment.callbacks.push(this.node); ExpandComment.callbacks.push(this.node);
} }
if (Conf['Title Link']) {
$.sync('CachedTitles', Linkify.titleSync);
}
return Post.callbacks.push({ return Post.callbacks.push({
name: 'Linkify', name: 'Linkify',
cb: this.node cb: this.node
}); });
}, },
node: function() { events: function(post) {
var data, el, end, endNode, i, index, items, length, link, links, node, result, saved, snapshot, space, test, word, _i, _len, _ref; var el, i, items;
if (this.isClone) { i = 0;
if (Conf['Embedding']) { items = $$('.embedder', post.nodes.comment);
i = 0; while (el = items[i++]) {
items = $$('.embed', this.nodes.comment); $.on(el, 'click', Linkify.cb.toggle);
while (el = items[i++]) { if ($.hasClass(el, 'embedded')) {
$.on(el, 'click', Linkify.cb.toggle); Linkify.cb.toggle.call(el);
if ($.hasClass(el, 'embedded')) {
Linkify.cb.toggle.call(el);
}
}
} }
}
},
node: function() {
var data, end, endNode, i, index, length, link, links, node, result, saved, snapshot, space, test, word;
if (this.isClone) {
return (Conf['Embedding'] ? Linkify.events(this) : null);
}
if (!Linkify.regString.test(this.info.comment)) {
return; return;
} }
test = /[^\s'"]+/g; test = /[^\s'"]+/g;
@ -8525,7 +8525,7 @@
links = []; links = [];
while (node = snapshot.snapshotItem(i++)) { while (node = snapshot.snapshotItem(i++)) {
data = node.data; data = node.data;
if (node.parentElement.nodeName === "A" || !data) { if (!data || node.parentElement.nodeName === "A") {
continue; continue;
} }
while (result = test.exec(data)) { while (result = test.exec(data)) {
@ -8557,28 +8557,25 @@
} }
} }
} }
_ref = links.reverse(); i = links.length;
for (_i = 0, _len = _ref.length; _i < _len; _i++) { while (i--) {
link = _ref[_i]; link = links[i];
this.nodes.links.push(Linkify.makeLink(link, this)); Linkify.embedProcess(Linkify.makeLink(link, this), this);
link.detach();
} }
if (!(Conf['Embedding'] || Conf['Link Title'])) { },
return; embedProcess: function(link, post) {
} var data;
links = this.nodes.links; if (data = Linkify.services(link)) {
i = 0; data.push(post);
while (link = links[i++]) { if (Conf['Embedding']) {
if (data = Linkify.services(link)) { Linkify.embed(data);
if (Conf['Embedding']) { }
Linkify.embed(data); if (Conf['Link Title']) {
} return Linkify.title(data);
if (Conf['Link Title']) {
Linkify.title(data);
}
} }
} }
}, },
regString: /((https?|mailto|git|magnet|ftp|irc):([a-z\d%\/])|[-a-z\d]+[.](aero|asia|biz|cat|com|coop|info|int|jobs|mobi|museum|name|net|org|post|pro|tel|travel|xxx|edu|gov|mil|[a-z]{2})([:\/]|(?!.))|[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}|[-\w\d.@]+@[a-z\d.-]+\.[a-z\d])/i,
makeRange: function(startNode, endNode, startOffset, endOffset) { makeRange: function(startNode, endNode, startOffset, endOffset) {
var range; var range;
range = document.createRange(); range = document.createRange();
@ -8587,7 +8584,7 @@
return range; return range;
}, },
makeLink: function(range) { makeLink: function(range) {
var a, char, i, text; var a, i, t, text;
text = range.toString(); text = range.toString();
i = 0; i = 0;
while (/[(\[{<>]/.test(text.charAt(i))) { while (/[(\[{<>]/.test(text.charAt(i))) {
@ -8603,8 +8600,8 @@
} }
} }
i = 0; i = 0;
while (/[)\]}>.,]/.test(char = text.charAt(text.length - (1 + i)))) { while (/[)\]}>.,]/.test(t = text.charAt(text.length - (1 + i)))) {
if (!(/[.,]/.test(char) || (text.match(/[()\[\]{}<>]/g)).length % 2)) { if (!(/[.,]/.test(t) || (text.match(/[()\[\]{}<>]/g)).length % 2)) {
break; break;
} }
i++; i++;
@ -8618,7 +8615,7 @@
range.setEnd(range.endContainer, range.endOffset - i); range.setEnd(range.endContainer, range.endOffset - i);
} }
} }
if (!/(https?|mailto|git|magnet|ftp|irc):/.test(text)) { if (!/(mailto:|.+:\/\/)/.test(text)) {
text = (/@/.test(text) ? 'mailto:' : 'http://') + text; text = (/@/.test(text) ? 'mailto:' : 'http://') + text;
} }
a = $.el('a', { a = $.el('a', {
@ -8629,6 +8626,7 @@
}); });
$.add(a, range.extractContents()); $.add(a, range.extractContents());
range.insertNode(a); range.insertNode(a);
range.detach();
return a; return a;
}, },
services: function(link) { services: function(link) {
@ -8641,14 +8639,14 @@
continue; continue;
} }
if (type.dummy) { if (type.dummy) {
break; return;
} }
return [type.key, match[1], match[2], link]; return [type.key, match[1], match[2], link];
} }
}, },
embed: function(data) { embed: function(data) {
var embed, href, key, link, name, options, uid, value, _ref; var embed, href, key, link, name, options, post, uid, value, _ref;
key = data[0], uid = data[1], options = data[2], link = data[3]; key = data[0], uid = data[1], options = data[2], link = data[3], post = data[4];
href = link.href; href = link.href;
embed = $.el('a', { embed = $.el('a', {
className: 'embedder', className: 'embedder',
@ -8665,57 +8663,47 @@
value = _ref[name]; value = _ref[name];
embed.dataset[name] = value; embed.dataset[name] = value;
} }
embed.dataset.nodedata = link.innerHTML;
$.addClass(link, "" + embed.dataset.key); $.addClass(link, "" + embed.dataset.key);
$.on(embed, 'click', Linkify.cb.toggle); $.on(embed, 'click', Linkify.cb.toggle);
$.after(link, [$.tn(' '), embed]); $.after(link, [$.tn(' '), embed]);
if (Conf['Auto-embed']) { if (Conf['Auto-embed']) {
Linkify.cb.toggle.call(embed); return Linkify.cb.toggle.call(embed);
} }
data.push(embed);
}, },
title: function(data) { title: function(data) {
var embed, err, key, link, options, service, title, titles, uid; var err, key, link, options, post, service, title, titles, uid;
key = data[0], uid = data[1], options = data[2], link = data[3], embed = data[4]; key = data[0], uid = data[1], options = data[2], link = data[3], post = data[4];
if (!(service = Linkify.types[key].title)) { if (!(service = Linkify.types[key].title)) {
return; return;
} }
titles = Conf['CachedTitles']; titles = Conf['CachedTitles'];
if (title = titles[uid]) { if (title = titles[uid]) {
if (link) { return link.textContent = title[0];
link.textContent = title[0];
}
if (Conf['Embedding']) {
return embed.dataset.title = title[0];
}
} else { } else {
try { try {
$.cache(service.api(uid), function() { return $.cache(service.api(uid), (function() {
return title = Linkify.cb.title(this, data); return Linkify.cb.title(this, data);
}, { }), {
responseType: 'json' responseType: 'json'
}); });
} catch (_error) { } catch (_error) {
err = _error; err = _error;
if (link) { link.innerHTML = '<span class="warning">Title Link Blocked</span> (are you using NoScript?)</a>';
link.innerHTML = "[" + key + "] <span class=warning>Title Link Blocked</span> (are you using NoScript?)</a>"; $.prepend(link, $.tn("[" + key + "] "));
}
return;
}
if (title) {
titles[uid] = [title, Date.now()];
return $.set('CachedTitles', titles);
} }
} }
}, },
titleSync: function(value) {
return Conf['CachedTitles'] = value;
},
cb: { cb: {
toggle: function() { toggle: function() {
var string, _ref; if ($.hasClass(this, "embedded")) {
_ref = $.hasClass(this, "embedded") ? ['unembed', '(embed)'] : ['embed', '(unembed)'], string = _ref[0], this.textContent = _ref[1]; $.rm(this.previousElementSibling);
$.replace(this.previousElementSibling, Linkify.cb[string](this)); this.previousElementSibling.hidden = false;
this.textContent = '(embed)';
} else {
this.previousElementSibling.hidden = true;
$.before(this, Linkify.cb.embed(this));
this.textContent = '(unembed)';
}
return $.toggleClass(this, 'embedded'); return $.toggleClass(this, 'embedded');
}, },
embed: function(a) { embed: function(a) {
@ -8724,45 +8712,35 @@
el.style.cssText = type.style != null ? type.style : "border: 0; width: 640px; height: 390px"; el.style.cssText = type.style != null ? type.style : "border: 0; width: 640px; height: 390px";
return el; return el;
}, },
unembed: function(a) { title: function(req, data) {
var el; var key, link, link2, options, post, post2, service, status, text, uid, _i, _j, _len, _len1, _ref, _ref1;
el = $.el('a', { key = data[0], uid = data[1], options = data[2], link = data[3], post = data[4];
rel: 'nofollow noreferrer', status = req.status;
target: 'blank',
className: 'linkify',
href: a.dataset.href
});
if (a.dataset.title) {
el.textContent = a.dataset.title;
} else {
el.innerHTML = a.dataset.nodedata;
}
$.addClass(el, a.dataset.key);
return el;
},
title: function(response, data) {
var embed, key, link, options, service, text, uid;
key = data[0], uid = data[1], options = data[2], link = data[3], embed = data[4];
service = Linkify.types[key].title; service = Linkify.types[key].title;
switch (response.status) { text = "[" + key + "] " + ((function() {
case 200: switch (status) {
case 304: case 200:
text = "" + (service.text(response.response)); case 304:
if (Conf['Embedding']) { return service.text(req.response);
embed.dataset.title = text; case 404:
return "Not Found";
case 403:
return "Forbidden or Private";
default:
return "" + status + "'d";
}
})());
link.textContent = text;
_ref = post.clones;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
post2 = _ref[_i];
_ref1 = $$('a', post2.nodes.comment);
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
link2 = _ref1[_j];
if (link2.href === link.href) {
link2.textContent = text;
} }
break; }
case 404:
text = "[" + key + "] Not Found";
break;
case 403:
text = "[" + key + "] Forbidden or Private";
break;
default:
text = "[" + key + "] " + this.status + "'d";
}
if (link) {
return link.textContent = text;
} }
} }
}, },
@ -8806,18 +8784,11 @@
regExp: /(http|www).*\.(gif|png|jpg|jpeg|bmp)$/, regExp: /(http|www).*\.(gif|png|jpg|jpeg|bmp)$/,
style: 'border: 0; width: auto; height: auto;', style: 'border: 0; width: auto; height: auto;',
el: function(a) { el: function(a) {
var div, img, link; var el;
img = $.el('img', { el = $.el('div');
src: a.dataset.href el.innerHTML = '<a target="_blank"><img></a>';
}); el.firstChild.href = el.firstChild.firstChild.src = a.dataset.href;
link = $.el('a', { return el;
target: '_blank',
href: a.dataset.href
});
div = $.el('div');
$.add(link, img);
$.add(div, link);
return div;
} }
}, { }, {
key: 'InstallGentoo', key: 'InstallGentoo',
@ -8857,13 +8828,13 @@
var el; var el;
el = $.el('div'); el = $.el('div');
$.cache("https://mediacru.sh/" + a.dataset.uid + ".json", function() { $.cache("https://mediacru.sh/" + a.dataset.uid + ".json", function() {
var embed, file, files, status, type, _i, _j, _len, _len1, _ref; var embed, ext, file, files, i, status, type, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _results, _results1;
status = this.status; status = this.status;
if (status !== 200 && status !== 304) { if (status !== 200 && status !== 304) {
return el.textContent = "ERROR " + status; return el.textContent = "ERROR " + status;
} }
files = this.response.files; files = this.response.files;
_ref = ['video/mp4', 'video/ogv', 'image/svg+xml', 'image/png', 'image/gif', 'image/jpeg', 'image/svg', 'audio/mpeg']; _ref = ['video/mp4', 'video/webm', 'video/ogv', 'image/svg+xml', 'image/png', 'image/gif', 'image/jpeg', 'audio/mpeg', 'audio/ogg'];
for (_i = 0, _len = _ref.length; _i < _len; _i++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
type = _ref[_i]; type = _ref[_i];
for (_j = 0, _len1 = files.length; _j < _len1; _j++) { for (_j = 0, _len1 = files.length; _j < _len1; _j++) {
@ -8882,20 +8853,35 @@
} }
switch (embed.type) { switch (embed.type) {
case 'video/mp4': case 'video/mp4':
case 'video/webm':
case 'video/ogv': case 'video/ogv':
return el.innerHTML = "<video autoplay loop>\n <source src=\"https://mediacru.sh/" + a.dataset.uid + ".mp4\" type=\"video/mp4;\">\n <source src=\"https://mediacru.sh/" + a.dataset.uid + ".ogv\" type=\"video/ogg; codecs='theora, vorbis'\">\n</video>"; el.innerHTML = '<video autoplay loop><source type="video/mp4"><source type="video/webm"><source type="video/ogg"></video>';
_ref1 = ['mp4', 'webm', 'ogv'];
_results = [];
for (i = _k = 0, _len2 = _ref1.length; _k < _len2; i = ++_k) {
ext = _ref1[i];
_results.push(el.firstChild.children[i].src = "https://mediacru.sh/" + a.dataset.uid + "." + ext);
}
return _results;
break;
case 'image/svg+xml':
case 'image/png': case 'image/png':
case 'image/gif': case 'image/gif':
case 'image/jpeg': case 'image/jpeg':
case 'image/svg': el.innerHTML = '<a target="_blank"><img></a>';
case 'image/svg+xml': el.firstChild.href = a.dataset.href;
return $.add(el, $.el('a', { return el.firstChild.firstChild.src = "https://mediacru.sh/" + file.file;
target: '_blank',
href: a.dataset.href,
innerHTML: "<img src='https://mediacru.sh/" + file.file + "'>"
}));
case 'audio/mpeg': case 'audio/mpeg':
return el.innerHTML = "<audio controls><source src='https://mediacru.sh/" + file.file + "'></audio>"; case 'audio/ogg':
el.innerHTML = '<audio controls><source type="audio/ogg"><source type="audio/mpeg"></audio>';
_ref2 = ['ogg', 'mp3'];
_results1 = [];
for (i = _l = 0, _len3 = _ref2.length; _l < _len3; i = ++_l) {
ext = _ref2[i];
_results1.push(el.firstChild.children[i].src = "https://mediacru.sh/" + a.dataset.uid + "." + ext);
}
return _results1;
break;
default: default:
return el.textContent = "ERROR: No valid filetype."; return el.textContent = "ERROR: No valid filetype.";
} }
@ -8923,23 +8909,15 @@
}, { }, {
key: 'SoundCloud', key: 'SoundCloud',
regExp: /.*(?:soundcloud.com\/|snd.sc\/)([^#\&\?]*).*/, regExp: /.*(?:soundcloud.com\/|snd.sc\/)([^#\&\?]*).*/,
style: 'height: auto; width: 500px; display: inline-block;', style: 'border: 0; width: 500px; height: 400px;',
el: function(a) { el: function(a) {
var div; return $.el('iframe', {
div = $.el('div', { src: "//w.soundcloud.com/player/?visual=true&show_comments=false&url=https%3A%2F%2Fsoundcloud.com%2F" + (encodeURIComponent(a.dataset.uid))
className: "soundcloud",
name: "soundcloud"
}); });
$.ajax("//soundcloud.com/oembed?show_artwork=false&&maxwidth=500px&show_comments=false&format=json&url=https://www.soundcloud.com/" + a.dataset.uid, {
onloadend: function() {
return div.innerHTML = JSON.parse(this.responseText).html;
}
}, false);
return div;
}, },
title: { title: {
api: function(uid) { api: function(uid) {
return "//soundcloud.com/oembed?show_artwork=false&&maxwidth=500px&show_comments=false&format=json&url=https://www.soundcloud.com/" + uid; return "//soundcloud.com/oembed?format=json&url=https%3A%2F%2Fsoundcloud.com%2F" + (encodeURIComponent(uid));
}, },
text: function(_) { text: function(_) {
return _.title; return _.title;
@ -8959,19 +8937,27 @@
regExp: /.*(?:twitch.tv\/)([^#\&\?]*).*/, regExp: /.*(?:twitch.tv\/)([^#\&\?]*).*/,
style: "border: none; width: 640px; height: 360px;", style: "border: none; width: 640px; height: 360px;",
el: function(a) { el: function(a) {
var channel, chapter, result, _; var channel, id, idparam, obj, result, type, _;
if (result = /(\w+)\/(?:[a-z]\/)?(\d+)/i.exec(a.dataset.uid)) { if (result = /(\w+)\/([bc])\/(\d+)/i.exec(a.dataset.uid)) {
_ = result[0], channel = result[1], chapter = result[2]; _ = result[0], channel = result[1], type = result[2], id = result[3];
return $.el('object', { idparam = {
data: 'http://www.twitch.tv/widgets/archive_embed_player.swf', 'b': 'archive_id',
innerHTML: "<param name='allowFullScreen' value='true' />\n<param name='flashvars' value='channel=" + channel + "&start_volume=25&auto_play=false" + (chapter ? "&chapter_id=" + chapter : "") + "' />" 'c': 'chapter_id'
};
obj = $.el('object', {
data: 'http://www.twitch.tv/widgets/archive_embed_player.swf'
}); });
obj.innerHTML = '<param name="allowFullScreen" value="true"><param name="flashvars">';
obj.children[1].value = "channel=" + channel + "&start_volume=25&auto_play=false&" + idparam[type] + "=" + id;
return obj;
} else { } else {
channel = (/(\w+)/.exec(a.dataset.uid))[0]; channel = (/(\w+)/.exec(a.dataset.uid))[0];
return $.el('object', { obj = $.el('object', {
data: "http://www.twitch.tv/widgets/live_embed_player.swf?channel=" + channel, data: "http://www.twitch.tv/widgets/live_embed_player.swf?channel=" + channel
innerHTML: "<param name=\"allowFullScreen\" value=\"true\" />\n<param name=\"movie\" value=\"http://www.twitch.tv/widgets/live_embed_player.swf\" />\n<param name=\"flashvars\" value=\"hostname=www.twitch.tv&channel=" + channel + "&auto_play=true&start_volume=25\" />"
}); });
obj.innerHTML = '<param name="allowFullScreen" value="true"><param name="flashvars">';
obj.children[1].value = "hostname=www.twitch.tv&channel=" + channel + "&auto_play=true&start_volume=25";
return obj;
} }
} }
}, { }, {

View File

@ -1,7 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?> <?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'> <gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
<app appid='lacclbnghgdicfifcamcmcnilckjamag'> <app appid='lacclbnghgdicfifcamcmcnilckjamag'>
<updatecheck codebase='https://ccd0.github.io/4chan-x/builds/crx.crx' version='1.7.31' /> <updatecheck codebase='https://ccd0.github.io/4chan-x/builds/crx.crx' version='1.7.32' />
</app> </app>
</gupdate> </gupdate>

View File

@ -1,6 +1,6 @@
{ {
"name": "4chan-X", "name": "4chan-X",
"version": "1.7.31", "version": "1.7.32",
"description": "Cross-browser userscript for maximum lurking on 4chan.", "description": "Cross-browser userscript for maximum lurking on 4chan.",
"meta": { "meta": {
"name": "4chan X", "name": "4chan X",