// ==UserScript==
// @name Enhancement Userscript for LIHKG
// @version 0.4
// @description An Enhancement Userscript for LIHKG
// @include /https?\:\/\/lihkg\.com/
// @icon https://www.google.com/s2/favicons?domain=lihkg.com
// @grant GM_addStyle
// @namespace https://greasyfork.org/users/371179
// ==/UserScript==
(function() {
'use strict';
GM_addStyle(`
.EGBBkGyEbfIEpHMLTW84H:not([dragmode]),.EGBBkGyEbfIEpHMLTW84H[dragmode="text"]{position:fixed;left:-9999px;top:-9999px;width:2px;height:2px;}
div[contenteditable] p>img~br:last-child,div[contenteditable] p>a~br:last-child,div[contenteditable] p>div~br:last-child{content:'';}
body ._21IQKhlBjN2jlHS_TVgI3l:after {left:0.4rem}
body ._21IQKhlBjN2jlHS_TVgI3l .vv9keWAXpwoonDah6rSIU ._3D2lzCKDMcdgEkexZrTSUh{margin-left: -6px;width: 16px;}
body label[for*="-dislike-like"]{display:inline-block !important;}
body label[for*="-like-like"]{display:inline-block !important;}
body ._3ExaynSI6tUp5h1U50MHtI ._3imUf8qB9LmLpk_t5PjDm4>div:first-child+div:last-child{margin-left:-6px;}
span[data-tip="正評"]:not([data-score])::after{content: " ";
font-size: .6rem;
font-weight: 400;
margin-top: .3rem;}
span[data-tip="負評"]:not([data-score])::after{content: " ";
font-size: .6rem;
font-weight: 400;
margin-top: .3rem;}
span[data-tip="正評"],span[data-tip="負評"]{padding-top:0px !important;}
`)
//fix copy editing
var isNumCheck = function(n) {
return n > 0 || n < 0 || n === 0
}
var postDetails = {}
var threadDetails = {}
var pendingRefreshThread = false;
var testBlockElm = function(elm) {
if (elm && elm.nodeType == 1) {
switch (elm.tagName) {
case 'DIV':
case 'P':
case 'BLOCKQUOTE':
return true;
default:
return false;
}
}
}
var getElementText = function(el) {
var text = '';
// Text node (3) or CDATA node (4) - return its text
if ((el.nodeType === 3) || (el.nodeType === 4)) {
text = el.nodeValue;
// If node is an element (1) and an img, input[type=image], or area element, return its alt text
} else if ((el.nodeType === 1) && (
(el.tagName.toLowerCase() == 'img') ||
(el.tagName.toLowerCase() == 'area') ||
((el.tagName.toLowerCase() == 'input') && el.getAttribute('type') && (el.getAttribute('type').toLowerCase() == 'image'))
)) {
text = el.getAttribute('alt') || '';
if (el.tagName.toLowerCase() == 'img' && text == '' && el.getAttribute('data-original')) {
text = '[img]' + el.getAttribute('data-original') + '[/img]';
} else if (el.tagName.toLowerCase() == 'img' && text == '' && el.getAttribute('src')) {
text = '[img]' + el.getAttribute('src') + '[/img]';
}
// Traverse children unless this is a script or style element
} else if ((el.nodeType === 1) && (
(el.tagName.toLowerCase() == 'br')
)) {
text = '\n';
// Traverse children unless this is a script or style element
} else if ((el.nodeType === 1) && !el.tagName.match(/^(script|style)$/i)) {
var children = el.childNodes;
if (el && testBlockElm(el) && el.previousSibling ? testBlockElm(el.previousSibling) : false) {
text += '\n'
}
if (el.tagName.toLowerCase() == 'blockquote') {
text += '[quote]'
}
for (var i = 0, l = children.length; i < l; i++) {
text += getElementText(children[i]);
}
if (el.tagName.toLowerCase() == 'blockquote') {
text += '[/quote]'
}
}
return text;
};
document.cssAll = function() {
var s = document.querySelectorAll.apply(this, arguments)
s = Array.prototype.slice.call(s, 0)
return s
}
function urlConvert(url) {
var src = url.replace(/\w+\:\/\//, '')
var replacements = [...src.matchAll(/[\w\.]+/g)].filter((t) => /\./.test(t))
if (replacements.length > 1) {
replacements.length--;
}
replacements.forEach((s) => {
src = src.replace(s, '')
})
src = src.replace(/\/+/g, '/')
return src;
}
var emoji = {};
setTimeout(function() {
console.log(emoji)
}, 1500)
setInterval(() => {
document.cssAll('img[src*="lihkg.com"][alt]:not([title])').forEach(function(imgElm) {
var src = imgElm.getAttribute('src');
var erc = urlConvert(src)
var imgAlt = imgElm.getAttribute('alt') || "";
if (/^[\x20-\x7E]+$/.test(imgAlt) && /\W/.test(imgAlt)) {
emoji[erc] = imgAlt.trim()
}
imgElm.setAttribute('title', imgAlt)
})
document.cssAll('a[href*="profile/"]:not([href*="//"]):not([title])').forEach(function(aElm) {
aElm.setAttribute('title', aElm.getAttribute('href'))
})
document.cssAll('[data-ic~="hkgmoji"]:not([title])>img[src*="lihkg.com"]:not([alt])').forEach(function(imgElm) {
var src = imgElm.getAttribute('src');
var erc = urlConvert(src)
var text = emoji[erc] ? emoji[erc] : "[img]" + erc + "[/img]"
imgElm.parentNode.setAttribute('title', text)
imgElm.setAttribute('alt', text)
})
document.cssAll('a[href*="local.lihkg.com"]>img:not([anchored])').forEach(function(img) {
img.setAttribute('anchored', 'true')
var originalSrc = img.getAttribute('src') || img.getAttribute('data-original') || ""
var newSrc = originalSrc.replace('local.lihkg.com', 'cdn.lihkg.com');
if (newSrc && originalSrc != newSrc) {
// console.log(originalSrc, newSrc)
var fx = function() {
if (img.complete == false) return setTimeout(fx, 33);
if (img.currentSrc == "") {
var b = img.cloneNode(false);
b.removeAttribute('data-original');
b.removeAttribute('data-src');
if (b.getAttribute('alt') == "") b.removeAttribute('alt')
if (b.getAttribute('title') == "") b.removeAttribute('title')
b.setAttribute('src', newSrc);
img.parentNode.replaceChild(b, img)
if (b.parentNode.getAttribute('href')) {
b.parentNode.setAttribute('href', b.parentNode.getAttribute('href').replace(originalSrc, newSrc));
if (b.nextElementSibling && b.nextElementSibling.hasAttribute('data-error')) b.nextElementSibling.parentNode.removeChild(b.nextElementSibling);
if (b.nextElementSibling && b.nextElementSibling.outerHTML.toLocaleLowerCase() == '<ins></ins>') b.nextElementSibling.parentNode.removeChild(b.nextElementSibling);
}
b.removeAttribute('anchored')
}
}
fx();
}
})
document.cssAll('div[contenteditable] div[data-ic][contenteditable="false"]').forEach((elm) => {
elm.removeAttribute('contenteditable')
})
document.cssAll('img[src]:not([alt]),img[src][alt=""]').forEach((el) => {
if (el.getAttribute('alt') || el.getAttribute('title')) return;
var text = '';
if (el.tagName.toLowerCase() == 'img' && el.getAttribute('data-original')) {
text = '[img]' + el.getAttribute('data-original') + '[/img]';
} else if (el.tagName.toLowerCase() == 'img' && el.getAttribute('src')) {
text = '[img]' + el.getAttribute('src') + '[/img]';
}
if (text) el.setAttribute('alt', text)
if (text) el.setAttribute('title', text)
})
document.cssAll('[data-post-id]:not([hacked])').forEach((el) => {
el.setAttribute('hacked', 'true');
var post_id = el.getAttribute('data-post-id');
if (!post_id) return;
//console.log(post_id, postDetails)
var post_detail = postDetails[post_id]
if (post_detail) {
// console.log(55,post_detail)
}
})
//postDetails
//data-post-id="5226a9cb7b395fbc182d183a6ee9b35c8adfd2fe"
}, 33)
function refreshingThreadEvent(thread_id) {
console.log(threadDetails[thread_id])
if (thread_id && threadDetails[thread_id]) {
document.cssAll('span[data-tip="正評"]').forEach((elm) => {
elm.setAttribute('data-score', threadDetails[thread_id]["like_count"]);
elm.style.paddingTop = '0px';
})
document.cssAll('span[data-tip="負評"]').forEach((elm) => {
elm.setAttribute('data-score', threadDetails[thread_id]["dislike_count"]);
elm.style.paddingTop = '0px';
})
}
}
var cid_refreshingThread = 0;
function refreshingThread() {
if (!cid_refreshingThread) return;
var titlespan = document.cssAll('a[href^="/category/"]+span');
if (titlespan.length == 1) {
var titlespanElm = titlespan[0]
if (!titlespanElm.querySelector('noscript')) {
titlespanElm.appendChild(document.createElement('noscript'))
if (pendingRefreshThread) {
var thread_id = pendingRefreshThread === true ? (/thread\/(\d+)\//.exec(location + "") || [null, null])[1] : pendingRefreshThread
pendingRefreshThread = false;
clearInterval(cid_refreshingThread);
cid_refreshingThread = 0;
refreshingThreadEvent(thread_id)
}
}
}
}
var makePlain = false;
document.addEventListener('drop', function(evt) {
// console.log(evt, makePlain, evt.target)
var p = evt.target;
var contenteditable = false;
while (p) {
if (p.hasAttribute('contenteditable') && p.getAttribute('contenteditable') != 'false') {
contenteditable = true;
break;
}
p = p.parentNode;
}
if (contenteditable) {
if (makePlain && evt.dataTransfer.getData('text/html')) {
var text = evt.dataTransfer.getData('text/html');
setTimeout(function() {
var sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
var range = sel.getRangeAt(0);
var cloneContents = range.cloneContents();
var hh = document.createElement('html')
hh.innerHTML = text;
console.log(hh.cloneNode(true))
var hhPlain = getElementText(hh)
console.log(hhPlain)
hh.innerText = hhPlain
if (cloneContents.textContent !== hhPlain) {
range.deleteContents();
var trueHTML = '<p>' + hh.innerHTML.toLowerCase().replace(/<br\s*\/?>/g, "<br></p><p>") + "</p>"
console.log(trueHTML)
document.execCommand('insertHTML', false, trueHTML);
}
}
}, 10);
}
}
}, true)
document.addEventListener('dragstart', function(evt) {
var editable = document.querySelector('div[contenteditable]')
var dragFrom = evt.target
if (editable && dragFrom) {
if (editable == dragFrom || editable.contains(dragFrom)) {
} else {
makePlain = true;
}
}
// console.log(evt)
}, false);
document.addEventListener('dragend', function(evt) {
if (Event.prototype._preventDefault) {
Event.prototype.preventDefault = Event.prototype._preventDefault
Event.prototype._preventDefault = null
}
setTimeout(function() {
makePlain = false;
}, 77);
}, false);
document.addEventListener('drop', function(evt) {
setTimeout(function() {
makePlain = false;
}, 77);
if (Event.prototype._preventDefault) {
Event.prototype.preventDefault = Event.prototype._preventDefault
Event.prototype._preventDefault = null
}
var dropZone = document.querySelector('.EGBBkGyEbfIEpHMLTW84H');
if (!dropZone) return;
dropZone.removeAttribute('dragmode');
}, true)
document.addEventListener('dragenter', function(evt) {
var dropZone = document.querySelector('.EGBBkGyEbfIEpHMLTW84H');
var isFileTransfer = false;
if (evt.dataTransfer.types) {
for (var i = 0; i < evt.dataTransfer.types.length; i++) {
if (evt.dataTransfer.types[i] == "Files") {
isFileTransfer = true;
break;
}
}
}
if (!isFileTransfer) {
if (dropZone)
dropZone.setAttribute('dragmode', 'text');
// evt.dataTransfer.effectAllowed='copy';
if (!Event.prototype._preventDefault) {
Event.prototype._preventDefault = Event.prototype.preventDefault;
Event.prototype.preventDefault = function() {
if (this.type == 'dragover') {
} else {
return this._preventDefault();
}
//console.log(this)
};
}
} else {
makePlain = false;
if (dropZone)
dropZone.setAttribute('dragmode', 'file');
}
// console.log('dragenter',!isFileTransfer)
}, false)
var injection = function() {
var api_callback = "uleccyqjstui"
;
((xmlhr, xmlhr_pt) => {
if (!xmlhr_pt._open) {
xmlhr_pt._open = xmlhr_pt.open;
xmlhr_pt.open = function() {
console.log('xmlhr_open', arguments)
if (/https?\:\/\/[\x20-2E\x30-5B\x5D-\x7E]*lihkg\.com\/[\x20-\x7E]*api[\x20-\x7E]+/.test(arguments[1])) {
this._url = arguments[1];
console.log('_url', this._url)
}
this._open.apply(this, arguments)
}
}
if (!xmlhr_pt._send) {
xmlhr_pt._send = xmlhr_pt.send;
xmlhr_pt.send = function() {
if (this._url) {
this.addEventListener('load', function() {
var resText = this.responseText;
var jsonObj = null;
if (resText && typeof resText == 'string') {
try {
jsonObj = JSON.parse(resText)
} catch (e) {}
}
if (jsonObj) {
//like_count
var code_num = 0
if (jsonObj.success == 1 && jsonObj.response && jsonObj.response.item_data && jsonObj.response.item_data.length >= 1 && jsonObj.response.item_data[0]["post_id"]) {
code_num = 361
} else if (jsonObj.success == 1 && jsonObj.response && jsonObj.response.thread_id) {
code_num = 351
}
console.log('code', code_num)
var event = new CustomEvent(api_callback, {
detail: {
code: code_num,
responseJSON: jsonObj
}
});
document.dispatchEvent(event);
//console.log(jsonObj)
}
})
}
console.log('xmlhr_send', arguments)
this._send.apply(this, arguments)
}
}
})(XMLHttpRequest, XMLHttpRequest.prototype)
}
var jsscript = document.createElement('script');
jsscript.type = 'text/javascript';
jsscript.innerHTML = '(' + injection + ')()';
document.documentElement.appendChild(jsscript)
var api_callback = "uleccyqjstui"
//data-post-id="5226a9cb7b395fbc182d183a6ee9b35c8adfd2fe"
document.addEventListener(api_callback, function(e) {
if (!e || !e.detail) return;
console.log(e.detail)
var jsonObj;
switch (e.detail.code) {
case 351:
case 361:
jsonObj = e.detail.responseJSON;
if (jsonObj.success == 1 && jsonObj.response && jsonObj.response.item_data && jsonObj.response.item_data.length >= 1 && jsonObj.response.item_data[0]["post_id"]) {
var reply_post_fx = (reply_item) => {
if ('dislike_count' in reply_item && 'like_count' in reply_item && reply_item["post_id"]) {
var like_count = +reply_item['like_count']
var dislike_count = +reply_item['dislike_count']
var post_id = reply_item['post_id']
if (isNumCheck(like_count) && isNumCheck(dislike_count) && post_id) {
postDetails[post_id] = {
'like_count': like_count,
'dislike_count': dislike_count
}
}
}
};
jsonObj.response.item_data.forEach(reply_post_fx)
if (jsonObj.response.pinned_post && jsonObj.response.pinned_post["post_id"]) reply_post_fx(jsonObj.response.pinned_post)
}
if (jsonObj.success == 1 && jsonObj.response && jsonObj.response.thread_id) {
var thread_fx = (thread_item) => {
if ('like_count' in thread_item && 'dislike_count' in thread_item && thread_item["thread_id"]) {
var like_count = +thread_item['like_count']
var dislike_count = +thread_item['dislike_count']
var thread_id = thread_item['thread_id']
if (isNumCheck(like_count) && isNumCheck(dislike_count) && thread_id) {
threadDetails[thread_id] = {
'like_count': like_count,
'dislike_count': dislike_count
}
pendingRefreshThread = thread_id;
if (!cid_refreshingThread) cid_refreshingThread = setInterval(refreshingThread, 1);
}
}
};
thread_fx(jsonObj.response)
console.log(99, threadDetails)
}
console.log(jsonObj)
break;
default:
}
});
// Your code here...
})();