1
0
mirror of https://github.com/chylex/Discord-History-Tracker.git synced 2024-10-19 05:42:50 +02:00

Compare commits

..

No commits in common. "af48bf60ce30fda95680b07936705be8fff4daf0" and "6ca386b7419e4769423f2e9d1eac3fe79193ea93" have entirely different histories.

10 changed files with 1329 additions and 1456 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -8,8 +8,8 @@ import os
import re import re
import distutils.dir_util import distutils.dir_util
VERSION_SHORT = "v.31g" VERSION_SHORT = "v.31f"
VERSION_FULL = VERSION_SHORT + ", released 25 December 2023" VERSION_FULL = VERSION_SHORT + ", released 20 November 2023"
EXEC_UGLIFYJS_WIN = "{2}/lib/uglifyjs.cmd --parse bare_returns --compress --output \"{1}\" \"{0}\"" EXEC_UGLIFYJS_WIN = "{2}/lib/uglifyjs.cmd --parse bare_returns --compress --output \"{1}\" \"{0}\""
EXEC_UGLIFYJS_AUTO = "uglifyjs --parse bare_returns --compress --output \"{1}\" \"{0}\"" EXEC_UGLIFYJS_AUTO = "uglifyjs --parse bare_returns --compress --output \"{1}\" \"{0}\""

View File

@ -61,11 +61,9 @@ const onTrackingContinued = function(anyNewMessages) {
let action = null; let action = null;
if (!DISCORD.hasMoreMessages()) { if (!DISCORD.hasMoreMessages()) {
console.debug("[DHT] Reached first message.");
action = SETTINGS.afterFirstMsg; action = SETTINGS.afterFirstMsg;
} }
if (isNoAction(action) && !anyNewMessages) { if (isNoAction(action) && !anyNewMessages) {
console.debug("[DHT] No new messages.");
action = SETTINGS.afterSavedMsg; action = SETTINGS.afterSavedMsg;
} }
@ -108,7 +106,7 @@ const onMessagesUpdated = async messages => {
isSending = true; isSending = true;
try { try {
STATE.addDiscordChannel(info.server, info.channel); await STATE.addDiscordChannel(info.server, info.channel);
} catch (e) { } catch (e) {
onError(e); onError(e);
return; return;

View File

@ -1,23 +1,5 @@
// noinspection JSUnresolvedVariable // noinspection JSUnresolvedVariable
// noinspection LocalVariableNamingConventionJS
class DISCORD { class DISCORD {
// https://discord.com/developers/docs/resources/channel#channel-object-channel-types
static CHANNEL_TYPE = {
DM: 1,
GROUP_DM: 3,
ANNOUNCEMENT_THREAD: 10,
PUBLIC_THREAD: 11,
PRIVATE_THREAD: 12
};
// https://discord.com/developers/docs/resources/channel#message-object-message-types
static MESSAGE_TYPE = {
DEFAULT: 0,
REPLY: 19,
THREAD_STARTER: 21
};
static getMessageOuterElement() { static getMessageOuterElement() {
return DOM.queryReactClass("messagesWrapper"); return DOM.queryReactClass("messagesWrapper");
} }
@ -46,11 +28,46 @@ class DISCORD {
* Calls the provided function with a list of messages whenever the currently loaded messages change. * Calls the provided function with a list of messages whenever the currently loaded messages change.
*/ */
static setupMessageCallback(callback) { static setupMessageCallback(callback) {
let skipsLeft = 0;
let waitForCleanup = false;
const previousMessages = new Set(); const previousMessages = new Set();
const onMessageElementsChanged = function() { const timer = window.setInterval(() => {
const messages = DISCORD.getMessages(); if (skipsLeft > 0) {
const hasChanged = messages.some(message => !previousMessages.has(message.id)) || !DISCORD.hasMoreMessages(); --skipsLeft;
return;
}
const view = this.getMessageOuterElement();
if (!view) {
skipsLeft = 2;
return;
}
const anyMessage = DOM.queryReactClass("message", this.getMessageOuterElement());
const messageCount = anyMessage ? anyMessage.parentElement.children.length : 0;
if (messageCount > 300) {
if (waitForCleanup) {
return;
}
skipsLeft = 3;
waitForCleanup = true;
window.setTimeout(() => {
const view = this.getMessageScrollerElement();
// noinspection JSUnusedGlobalSymbols
view.scrollTop = view.scrollHeight / 2;
}, 1);
}
else {
waitForCleanup = false;
}
const messages = this.getMessages();
const hasChanged = messages.some(message => !previousMessages.has(message.id)) || !this.hasMoreMessages();
if (!hasChanged) { if (!hasChanged) {
return; return;
@ -62,74 +79,24 @@ class DISCORD {
} }
callback(messages); callback(messages);
}; }, 200);
let debounceTimer; window.DHT_ON_UNLOAD.push(() => window.clearInterval(timer));
/**
* Do not trigger the callback too often due to autoscrolling.
*/
const onMessageElementsChangedLater = function() {
window.clearTimeout(debounceTimer);
debounceTimer = window.setTimeout(onMessageElementsChanged, 100);
};
const observer = new MutationObserver(function () {
onMessageElementsChangedLater();
});
let skipsLeft = 0;
let observedElement = null;
const observerTimer = window.setInterval(() => {
if (skipsLeft > 0) {
--skipsLeft;
return;
}
const view = this.getMessageOuterElement();
if (!view) {
skipsLeft = 1;
return;
}
if (observedElement !== null && observedElement.isConnected) {
return;
}
observedElement = view.querySelector("[data-list-id='chat-messages']");
if (observedElement) {
console.debug("[DHT] Observed message container.");
observer.observe(observedElement, { childList: true });
onMessageElementsChangedLater();
}
}, 400);
window.DHT_ON_UNLOAD.push(() => {
observer.disconnect();
observedElement = null;
window.clearInterval(observerTimer);
});
} }
/** /**
* Returns the message from a message element. * Returns the property object of a message element.
* @returns { null | DiscordMessage } } * @returns { null | { message: DiscordMessage, channel: Object } }
*/ */
static getMessageFromElement(ele) { static getMessageElementProps(ele) {
const props = DOM.getReactProps(ele); const props = DOM.getReactProps(ele);
if (props && Array.isArray(props.children)) { if (props.children && props.children.length) {
for (const child of props.children) { for (let i = 3; i < props.children.length; i++) {
if (!(child instanceof Object)) { const childProps = props.children[i].props;
continue;
}
const childProps = child.props; if (childProps && "message" in childProps && "channel" in childProps) {
if (childProps instanceof Object && "message" in childProps) { return childProps;
return childProps.message;
} }
} }
} }
@ -146,10 +113,10 @@ class DISCORD {
for (const ele of this.getMessageElements()) { for (const ele of this.getMessageElements()) {
try { try {
const message = this.getMessageFromElement(ele); const props = this.getMessageElementProps(ele);
if (message != null) { if (props != null) {
messages.push(message); messages.push(props.message);
} }
} catch (e) { } catch (e) {
console.error("[DHT] Error extracing message data, skipping it.", e, ele, DOM.tryGetReactProps(ele)); console.error("[DHT] Error extracing message data, skipping it.", e, ele, DOM.tryGetReactProps(ele));
@ -170,7 +137,7 @@ class DISCORD {
*/ */
static getSelectedChannel() { static getSelectedChannel() {
try { try {
let obj = null; let obj;
try { try {
for (const child of DOM.getReactProps(DOM.queryReactClass("chatContent")).children) { for (const child of DOM.getReactProps(DOM.queryReactClass("chatContent")).children) {
@ -181,6 +148,15 @@ class DISCORD {
} }
} catch (e) { } catch (e) {
console.error("[DHT] Error retrieving selected channel from 'chatContent' element.", e); console.error("[DHT] Error retrieving selected channel from 'chatContent' element.", e);
for (const ele of this.getMessageElements()) {
const props = this.getMessageElementProps(ele);
if (props != null) {
obj = props.channel;
break;
}
}
} }
if (!obj || typeof obj.id !== "string") { if (!obj || typeof obj.id !== "string") {
@ -209,8 +185,8 @@ class DISCORD {
// https://discord.com/developers/docs/resources/channel#channel-object-channel-types // https://discord.com/developers/docs/resources/channel#channel-object-channel-types
switch (obj.type) { switch (obj.type) {
case DISCORD.CHANNEL_TYPE.DM: type = "DM"; break; case 1: type = "DM"; break;
case DISCORD.CHANNEL_TYPE.GROUP_DM: type = "GROUP"; break; case 3: type = "GROUP"; break;
default: return null; default: return null;
} }
@ -248,7 +224,7 @@ class DISCORD {
} }
}; };
if (obj.type === DISCORD.CHANNEL_TYPE.ANNOUNCEMENT_THREAD || obj.type === DISCORD.CHANNEL_TYPE.PUBLIC_THREAD || obj.type === DISCORD.CHANNEL_TYPE.PRIVATE_THREAD) { if (obj.parent_id) {
channel["extra"]["parent"] = obj.parent_id; channel["extra"]["parent"] = obj.parent_id;
} }
else { else {

View File

@ -204,12 +204,12 @@ ${btn("close", "X")}`);
<label><input id='dht-cfg-autoscroll' type='checkbox'> Autoscroll</label><br> <label><input id='dht-cfg-autoscroll' type='checkbox'> Autoscroll</label><br>
<br> <br>
<label>After reaching the first message in channel...</label><br> <label>After reaching the first message in channel...</label><br>
${radio("afm", "nothing", "Continue Tracking")} ${radio("afm", "nothing", "Do Nothing")}
${radio("afm", "pause", "Pause Tracking")} ${radio("afm", "pause", "Pause Tracking")}
${radio("afm", "switch", "Switch to Next Channel")} ${radio("afm", "switch", "Switch to Next Channel")}
<br> <br>
<label>After reaching a previously saved message...</label><br> <label>After reaching a previously saved message...</label><br>
${radio("asm", "nothing", "Continue Tracking")} ${radio("asm", "nothing", "Do Nothing")}
${radio("asm", "pause", "Pause Tracking")} ${radio("asm", "pause", "Pause Tracking")}
${radio("asm", "switch", "Switch to Next Channel")} ${radio("asm", "switch", "Switch to Next Channel")}
<p id='dht-cfg-note'> <p id='dht-cfg-note'>

View File

@ -269,9 +269,11 @@ class SAVEFILE{
addMessagesFromDiscord(discordMessageArray){ addMessagesFromDiscord(discordMessageArray){
var hasNewMessages = false; var hasNewMessages = false;
for(var discordMessage of discordMessageArray){ for(var discordMessage of discordMessageArray){
if (this.addMessage(discordMessage.channel_id, discordMessage.id, this.convertToMessageObject(discordMessage))){ var type = discordMessage.type;
// https://discord.com/developers/docs/resources/channel#message-object-message-reference-structure
if ((type === 0 || type === 19) && discordMessage.state === "SENT" && this.addMessage(discordMessage.channel_id, discordMessage.id, this.convertToMessageObject(discordMessage))){
hasNewMessages = true; hasNewMessages = true;
} }
} }

View File

@ -122,13 +122,12 @@ const STATE = (function() {
this._triggerStateChanged("data", "channel"); this._triggerStateChanged("data", "channel");
} }
} }
// Right. Upstream desktop `bootstrap.js` expects an `async` here. I think it's fine.
/* /*
* Adds all messages from the array to the specified channel. Returns true if the savefile was updated. * Adds all messages from the array to the specified channel. Returns true if the savefile was updated.
*/ */
addDiscordMessages(discordMessageArray){ addDiscordMessages(discordMessageArray){
discordMessageArray = discordMessageArray.filter(msg => (msg.type === DISCORD.MESSAGE_TYPE.DEFAULT || msg.type === DISCORD.MESSAGE_TYPE.REPLY || msg.type === DISCORD.MESSAGE_TYPE.THREAD_STARTER) && msg.state === "SENT");
if (this.getSavefile().addMessagesFromDiscord(discordMessageArray)){ if (this.getSavefile().addMessagesFromDiscord(discordMessageArray)){
this._triggerStateChanged("data", "messages"); this._triggerStateChanged("data", "messages");
return true; return true;

View File

@ -1,8 +1,7 @@
var DISCORD = (function(){ var DISCORD = (function(){
var REGEX = { var REGEX = {
formatBold: /\*\*([\s\S]+?)\*\*(?!\*)/g, formatBold: /\*\*([\s\S]+?)\*\*(?!\*)/g,
formatItalic1: /\*([\s\S]+?)\*(?!\*)/g, formatItalic: /(.)?\*([\s\S]+?)\*(?!\*)/g,
formatItalic2: /_([\s\S]+?)_(?!_)\b/g,
formatUnderline: /__([\s\S]+?)__(?!_)/g, formatUnderline: /__([\s\S]+?)__(?!_)/g,
formatStrike: /~~([\s\S]+?)~~(?!~)/g, formatStrike: /~~([\s\S]+?)~~(?!~)/g,
formatCodeInline: /(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/g, formatCodeInline: /(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/g,
@ -55,8 +54,7 @@ var DISCORD = (function(){
.replace(REGEX.specialEscapedSingle, escapeHtmlMatch) .replace(REGEX.specialEscapedSingle, escapeHtmlMatch)
.replace(REGEX.specialEscapedDouble, full => full.replace(/\\/g, "").replace(/(.)/g, escapeHtmlMatch)) .replace(REGEX.specialEscapedDouble, full => full.replace(/\\/g, "").replace(/(.)/g, escapeHtmlMatch))
.replace(REGEX.formatBold, "<b>$1</b>") .replace(REGEX.formatBold, "<b>$1</b>")
.replace(REGEX.formatItalic1, "<i>$1</i>") .replace(REGEX.formatItalic, (full, pre, match) => pre === '\\' ? full : (pre || "")+"<i>"+match+"</i>")
.replace(REGEX.formatItalic2, "<i>$1</i>")
.replace(REGEX.formatUnderline, "<u>$1</u>") .replace(REGEX.formatUnderline, "<u>$1</u>")
.replace(REGEX.formatStrike, "<s>$1</s>"); .replace(REGEX.formatStrike, "<s>$1</s>");
} }