Update MBViewer

This commit is contained in:
octospacc 2024-01-25 01:43:25 +01:00
parent 7d8b73406a
commit 9acf326d92
1 changed files with 116 additions and 36 deletions

View File

@ -17,11 +17,13 @@
// * fix imported SVG buttons not fitting with dark theme // * fix imported SVG buttons not fitting with dark theme
// * I think we might need to handle acronicized names for users when needed? // * I think we might need to handle acronicized names for users when needed?
// * show, and/or sort by, posts tags/categories // * show, and/or sort by, posts tags/categories
// * scroll to post id when loading from dataInject or RSS
// * fix XML feeds parsing on Firefox
let MbState = {}; let MbState = {};
let MbApiTransformer; let MbApiTransformer;
function ArgsRewrite (props={}) { function ArgsRewrite (props={}, navigate=true) {
for (const key in props) { for (const key in props) {
const value = props[key]; const value = props[key];
value ? (MbState.args[key] = value) : (delete MbState.args[key]); value ? (MbState.args[key] = value) : (delete MbState.args[key]);
@ -30,7 +32,10 @@ function ArgsRewrite (props={}) {
for (const arg in MbState.args) { for (const arg in MbState.args) {
hash += `${arg}=${MbState.args[arg]}|`; hash += `${arg}=${MbState.args[arg]}|`;
} }
location.hash = hash; if (navigate) {
location.hash = hash;
}
return hash
} }
const SureArray = (obj) => (Array.isArray(obj) ? obj : [obj]); const SureArray = (obj) => (Array.isArray(obj) ? obj : [obj]);
@ -198,7 +203,72 @@ async function MbViewerInit () {
MbState.platform = /*SureArray(*/MbState.args.platform/*)*/; MbState.platform = /*SureArray(*/MbState.args.platform/*)*/;
MbState.postId = MbState.args.postid; MbState.postId = MbState.args.postid;
//MbState.postSlug = MbState.args.postslug; //MbState.postSlug = MbState.args.postslug;
if (MbState.siteUrl) { if (MbState.args.dataurl) {
// TODO initially remove built-in site data?
MbState.dataInject = {};
try {
const fileUrlPrefix = (MbState.args.dataurl.split('/').slice(0, -1).join('/') || '.');
const dataRequest = await fetch(MbState.args.dataurl);
MbState.dataInject = await dataRequest.json();
let messagesNew = [];
if (MbState.platform === 'telegram.export') {//(["telegram.export", "telegram.json"].includes(MbState.platform)) {
MbState.siteData = {
name: MbState.dataInject.name,
description: `${MbState.dataInject.type} ${MbState.dataInject.id}`,
acroName: (!MbState.siteData.iconUrl ? MbState.dataInject.name && MakeAcroName(MbState.dataInject.name) : ''),
bgColor: ~~(Math.random() * 7),
};
const textEncoder = document.createElement('textarea');
for (const message of MbState.dataInject.messages) {
if (message.type !== 'message') {
continue;
}
messagesNew.push({
content: '',
quoting: (message.forwarded_from && {
author: {
name: `Forwarded from ${message.forwarded_from}`,
},
}),
time: message.date,
url: `#${ArgsRewrite({ postid: null }, false)}PostId=${message.id}`,
});
//for (const piece of (Array.isArray(message.text) ? message.text : [message.text])) {
// messagesNew[messagesNew.length - 1].content += (piece.text || piece);
//}
//const encoder = document.createElement('textarea');
//encoder.innerHTML = messagesNew[messagesNew.length - 1].content;
//messagesNew[messagesNew.length - 1].content = encoder.innerHTML.replaceAll('\n', '<br/>');
for (const entity of message.text_entities) {
const entityTag = { bold: "b", italic: "i", link: "a", text_link: "a", pre: "pre", blockquote: "blockquote" }[entity.type];
const entityHref = (entityTag === 'a' && (entity.href || entity.text));
textEncoder.innerHTML = entity.text;
entity.text = textEncoder.innerHTML.replaceAll('\n', '<br/>');
messagesNew[messagesNew.length - 1].content += (entityTag
? `<${entityTag} ${entityHref ? `href="${entityHref}"` : ''}>${entity.text}</${entityTag}>`
: entity.text);
}
if (messagesNew[messagesNew.length - 1].content) {
messagesNew[messagesNew.length - 1].content = `<p>${messagesNew[messagesNew.length - 1].content}</p>`;
}
if (message.photo) {
messagesNew[messagesNew.length - 1].content = `<img src="${fileUrlPrefix}/${message.photo}"/>${messagesNew[messagesNew.length - 1].content}`;
} else if (message.file && message.mime_type?.split('/')[0] === 'video') {
messagesNew[messagesNew.length - 1].content = `<video controls="true" src="${fileUrlPrefix}/${message.file}"></video>${messagesNew[messagesNew.length - 1].content}`;
}
}
} else {
messagesNew = MbApiTransformer('message[]', MbState.platform, MbState.dataInject);
}
$('section.tgme_channel_history.js-message_history').html(MakeMoreWrapperHtml());
TWeb.loadMore($('.js-messages_more_wrap > a'), messagesNew);
} catch(err) {
console.log(err);
setTimeout(MbViewerInit, 1000);
return;
}
}
else if (MbState.siteUrl) {
if (!MbState.platform) { if (!MbState.platform) {
if (GetDomainFromUrl(MbState.siteUrl).toLowerCase().endsWith('wordpress.com')) { if (GetDomainFromUrl(MbState.siteUrl).toLowerCase().endsWith('wordpress.com')) {
MbState.platform = 'wordpress.com'; MbState.platform = 'wordpress.com';
@ -248,6 +318,8 @@ async function MbViewerInit () {
$('form.tgme_header_search_form')[0].action = `${siteLink}/?s`; $('form.tgme_header_search_form')[0].action = `${siteLink}/?s`;
$('form.tgme_header_search_form')[0].onsubmit = null; $('form.tgme_header_search_form')[0].onsubmit = null;
$('.tgme_channel_info_header_username').html(`<a href="${siteLink}">${GetDomainFromUrl(siteLink).toLowerCase()}</a>`); $('.tgme_channel_info_header_username').html(`<a href="${siteLink}">${GetDomainFromUrl(siteLink).toLowerCase()}</a>`);
}
if (MbState.siteUrl || MbState.dataInject) {
$('a[name="goBack"]')[0].hidden = false; $('a[name="goBack"]')[0].hidden = false;
} }
if (["atom", "rss"].includes(MbState.platform)) { if (["atom", "rss"].includes(MbState.platform)) {
@ -261,7 +333,7 @@ async function MbViewerInit () {
if (MbState.siteData.iconUrl && !["http", "https"].includes(MbState.siteData.iconUrl.split('://')[0])) { if (MbState.siteData.iconUrl && !["http", "https"].includes(MbState.siteData.iconUrl.split('://')[0])) {
MbState.siteData.iconUrl = `${MbState.siteUrl}${MbState.siteData.iconUrl}`; MbState.siteData.iconUrl = `${MbState.siteUrl}${MbState.siteData.iconUrl}`;
} }
if (!MbState.siteUrl) { if (!MbState.siteUrl && !MbState.dataInject) {
$('a[name="goBack"]')[0].hidden = true; $('a[name="goBack"]')[0].hidden = true;
$('section.tgme_channel_history.js-message_history').html(MakeMoreWrapperHtml()); $('section.tgme_channel_history.js-message_history').html(MakeMoreWrapperHtml());
TWeb.loadMore($('.js-messages_more_wrap > a'), [{ content: `<p> TWeb.loadMore($('.js-messages_more_wrap > a'), [{ content: `<p>
@ -311,6 +383,12 @@ async function MbViewerInit () {
<br/> * Initial, experimental support for Mastodon profiles (broken) <br/> * Initial, experimental support for Mastodon profiles (broken)
<br/> * Hotfixed a defiant parsing bug on Firefox <br/> * Hotfixed a defiant parsing bug on Firefox
</p>`, time: '2024-01-24T01:00' }, { content: `<p> </p>`, time: '2024-01-24T01:00' }, { content: `<p>
New changes:
<br/> * Read Telegram's JSON chat exports (experimental, very slow and resource-heavy)
<br/>
Regarding Trasformapi, I transformed some of my development tears into words, read here if you're curious:
<a href="https://octospacc.altervista.org/2024/01/25/mbviewer-per-distrarci/">https://octospacc.altervista.org/2024/01/25/mbviewer-per-distrarci/</a>.
</p>`, time: '2024-01-25T01:00' }, { content: `<p>
Copyright notice: MBViewer uses code borrowed from <a href="https://t.me">t.me</a>, Copyright notice: MBViewer uses code borrowed from <a href="https://t.me">t.me</a>,
specially modified to handle customized data visualizations in an MB-style. specially modified to handle customized data visualizations in an MB-style.
<br/> <br/>
@ -364,7 +442,7 @@ async function MakeMbHtml (postData, makeMoreWrap) {
const siteLink = (MbState.siteData.url || MbState.siteData.URL || MbState.siteLink); const siteLink = (MbState.siteData.url || MbState.siteData.URL || MbState.siteLink);
const siteHref = (siteLink ? `href="${siteLink}"` : ''); const siteHref = (siteLink ? `href="${siteLink}"` : '');
for (postData of (postData.posts ? postData.posts : SureArray(postData))) { for (postData of (postData.posts ? postData.posts : SureArray(postData))) {
if (MbState.platform) { if (MbState.platform && MbState.platform !== 'telegram.export') {
postData = MbApiTransformer('message', MbState.platform, postData); postData = MbApiTransformer('message', MbState.platform, postData);
} }
const authorId = (postData.author?.id || postData._links?.author[0]?.href?.split('/')?.slice(-1)[0]); const authorId = (postData.author?.id || postData._links?.author[0]?.href?.split('/')?.slice(-1)[0]);
@ -373,7 +451,7 @@ async function MakeMbHtml (postData, makeMoreWrap) {
? postData.author ? postData.author
: await (await fetch(MakeSiteRestUrl(MakeApiEndpoint('users', { id: authorId })))).json()); : await (await fetch(MakeSiteRestUrl(MakeApiEndpoint('users', { id: authorId })))).json());
} }
const authorData = MbState.authors[authorId]; const authorData = (MbState.authors[authorId] || postData.author || (postData.quoting?.author && !postData.quoting?.content));
const authorLink = (authorData?.link || (siteLink && `${siteLink}/author/${authorData?.name}`)); const authorLink = (authorData?.link || (siteLink && `${siteLink}/author/${authorData?.name}`));
const authorHref = (authorLink ? `href="${authorLink}"` : ''); const authorHref = (authorLink ? `href="${authorLink}"` : '');
const iconUrl = (Object.values(authorData?.avatar_urls || {}).slice(-1)[0] || authorData?.icon?.url || MbState.siteData.iconUrl); const iconUrl = (Object.values(authorData?.avatar_urls || {}).slice(-1)[0] || authorData?.icon?.url || MbState.siteData.iconUrl);
@ -410,8 +488,8 @@ async function MakeMbHtml (postData, makeMoreWrap) {
<div class="tgme_widget_message_author accent_color"> <div class="tgme_widget_message_author accent_color">
<a class="tgme_widget_message_owner_name" ${authorHref || siteHref}> <a class="tgme_widget_message_owner_name" ${authorHref || siteHref}>
<span dir="auto"> <span dir="auto">
${MbState.authors[authorId]?.name ${authorData?.name
? `${MbState.authors[authorId]?.name} [${MbState.siteData.name}]` ? `${authorData.name} [${MbState.siteData.name}]`
: MbState.siteData.name : MbState.siteData.name
} }
</span> </span>
@ -421,7 +499,7 @@ async function MakeMbHtml (postData, makeMoreWrap) {
<div class="MbPost"> <div class="MbPost">
${attachmentsHtml} ${attachmentsHtml}
${ReformatPostHtml(postData.content)} ${ReformatPostHtml(postData.content)}
${postData.quoting ? `[♻️ Reblog]: ${ReformatPostHtml(postData.quoting.content)}` : ''} ${postData.quoting?.content ? `[♻️ Reblog]: ${ReformatPostHtml(postData.quoting.content)}` : ''}
</div> </div>
</div> </div>
<div class="tgme_widget_message_footer compact js-message_footer"> <div class="tgme_widget_message_footer compact js-message_footer">
@ -458,33 +536,35 @@ function ReformatPostHtml (html) {
const content = $(`<div>${html}</div>`); const content = $(`<div>${html}</div>`);
// bypass Altervista's anti-hotlinking protection by hiding our HTTP Referer header // bypass Altervista's anti-hotlinking protection by hiding our HTTP Referer header
// TODO: only do this for altervista sites maybe // TODO: only do this for altervista sites maybe
for (const videoElem of content.find('video').toArray()) { if (MbState.platform === 'wordpress.org') {
videoElem.preload = 'none'; for (const videoElem of content.find('video').toArray()) {
const frameElem = document.createElement('iframe'); videoElem.preload = 'none';
frameElem.style = 'border: none; width: 100%;'; const frameElem = document.createElement('iframe');
frameElem.allowFullscreen = true; frameElem.style = 'border: none; width: 100%;';
frameElem.src = `data:text/html;utf8,<!DOCTYPE html><body> frameElem.allowFullscreen = true;
<style> frameElem.src = `data:text/html;utf8,<!DOCTYPE html><body>
html, body { margin: 0; overflow: hidden; } <style>
video { max-width: 100%; } html, body { margin: 0; overflow: hidden; }
</style> video { max-width: 100%; }
${encodeURIComponent(videoElem.outerHTML)} </style>
<button style="position: absolute; top: 0; right: 0; z-index: 1;"> ${encodeURIComponent(videoElem.outerHTML)}
Reload Media <button style="position: absolute; top: 0; right: 0; z-index: 1;">
</button> Reload Media
<script> </button>
var videoElem = document.querySelector('video'); <script>
var buttonElem = document.querySelector('button'); var videoElem = document.querySelector('video');
buttonElem.onclick = function(){ var buttonElem = document.querySelector('button');
buttonElem.onclick = function(){
videoElem.load();
};
videoElem.onloadedmetadata = function(){
top.postMessage((videoElem.src + ' ' + getComputedStyle(videoElem).height), '*');
};
videoElem.load(); videoElem.load();
}; </script>
videoElem.onloadedmetadata = function(){ </body>`;
top.postMessage((videoElem.src + ' ' + getComputedStyle(videoElem).height), '*'); videoElem.replaceWith(frameElem);
}; }
videoElem.load();
</script>
</body>`;
videoElem.replaceWith(frameElem);
} }
return content.html(); return content.html();
} }
@ -509,7 +589,7 @@ function ResizeLayouts () {
} }
$('a[name="goBack"]')[0].onclick = function(){ $('a[name="goBack"]')[0].onclick = function(){
ArgsRewrite({ siteurl: null, postid: null, platform: null, /*postslug: null*/ }); ArgsRewrite({ dataurl: null, siteurl: null, postid: null, platform: null, /*postslug: null*/ });
}; };
window.onmessage = function(event){ window.onmessage = function(event){