2023-04-09 06:36:18 +03:00
|
|
|
import store from './store';
|
2023-03-26 18:18:36 +03:00
|
|
|
|
|
|
|
export function groupBoosts(values) {
|
|
|
|
let newValues = [];
|
|
|
|
let boostStash = [];
|
|
|
|
let serialBoosts = 0;
|
|
|
|
for (let i = 0; i < values.length; i++) {
|
|
|
|
const item = values[i];
|
|
|
|
if (item.reblog) {
|
|
|
|
boostStash.push(item);
|
|
|
|
serialBoosts++;
|
|
|
|
} else {
|
|
|
|
newValues.push(item);
|
|
|
|
if (serialBoosts < 3) {
|
|
|
|
serialBoosts = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// if boostStash is more than quarter of values
|
|
|
|
// or if there are 3 or more boosts in a row
|
2023-04-05 13:52:15 +03:00
|
|
|
if (
|
|
|
|
values.length > 10 &&
|
|
|
|
(boostStash.length > values.length / 4 || serialBoosts >= 3)
|
|
|
|
) {
|
2023-03-26 18:18:36 +03:00
|
|
|
// if boostStash is more than 3 quarter of values
|
|
|
|
const boostStashID = boostStash.map((status) => status.id);
|
|
|
|
if (boostStash.length > (values.length * 3) / 4) {
|
|
|
|
// insert boost array at the end of specialHome list
|
|
|
|
newValues = [
|
|
|
|
...newValues,
|
|
|
|
{ id: boostStashID, items: boostStash, type: 'boosts' },
|
|
|
|
];
|
|
|
|
} else {
|
|
|
|
// insert boosts array in the middle of specialHome list
|
|
|
|
const half = Math.floor(newValues.length / 2);
|
|
|
|
newValues = [
|
|
|
|
...newValues.slice(0, half),
|
|
|
|
{
|
|
|
|
id: boostStashID,
|
|
|
|
items: boostStash,
|
|
|
|
type: 'boosts',
|
|
|
|
},
|
|
|
|
...newValues.slice(half),
|
|
|
|
];
|
|
|
|
}
|
|
|
|
return newValues;
|
|
|
|
} else {
|
|
|
|
return values;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function dedupeBoosts(items, instance) {
|
2023-04-09 06:36:18 +03:00
|
|
|
const boostedStatusIDs = store.account.get('boostedStatusIDs') || {};
|
|
|
|
const filteredItems = items.filter((item) => {
|
2023-03-26 18:18:36 +03:00
|
|
|
if (!item.reblog) return true;
|
2023-04-09 06:36:18 +03:00
|
|
|
const statusKey = `${instance}-${item.reblog.id}`;
|
|
|
|
const boosterID = boostedStatusIDs[statusKey];
|
|
|
|
if (boosterID && boosterID !== item.id) {
|
2023-03-27 10:05:07 +03:00
|
|
|
console.warn(
|
|
|
|
`🚫 Duplicate boost by ${item.account.displayName}`,
|
|
|
|
item,
|
2023-04-09 06:36:18 +03:00
|
|
|
item.reblog,
|
2023-03-27 10:05:07 +03:00
|
|
|
);
|
2023-03-26 18:18:36 +03:00
|
|
|
return false;
|
2023-04-09 06:36:18 +03:00
|
|
|
} else {
|
|
|
|
boostedStatusIDs[statusKey] = item.id;
|
2023-03-26 18:18:36 +03:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
});
|
2023-04-09 06:36:18 +03:00
|
|
|
// Limit to 50
|
|
|
|
const keys = Object.keys(boostedStatusIDs);
|
|
|
|
if (keys.length > 50) {
|
|
|
|
keys.slice(0, keys.length - 50).forEach((key) => {
|
|
|
|
delete boostedStatusIDs[key];
|
|
|
|
});
|
|
|
|
}
|
|
|
|
store.account.set('boostedStatusIDs', boostedStatusIDs);
|
|
|
|
return filteredItems;
|
2023-03-26 18:18:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
export function groupContext(items) {
|
|
|
|
const contexts = [];
|
|
|
|
let contextIndex = 0;
|
|
|
|
items.forEach((item) => {
|
|
|
|
for (let i = 0; i < contexts.length; i++) {
|
|
|
|
if (contexts[i].find((t) => t.id === item.id)) return;
|
|
|
|
if (
|
|
|
|
contexts[i].find((t) => t.id === item.inReplyToId) ||
|
|
|
|
contexts[i].find((t) => t.inReplyToId === item.id)
|
|
|
|
) {
|
|
|
|
contexts[i].push(item);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const repliedItem = items.find((i) => i.id === item.inReplyToId);
|
|
|
|
if (repliedItem) {
|
|
|
|
contexts[contextIndex++] = [item, repliedItem];
|
|
|
|
}
|
|
|
|
});
|
2023-05-05 11:59:06 +03:00
|
|
|
|
|
|
|
// Check for cross-item contexts
|
|
|
|
// Merge contexts into one if they have a common item (same id)
|
|
|
|
for (let i = 0; i < contexts.length; i++) {
|
|
|
|
for (let j = i + 1; j < contexts.length; j++) {
|
|
|
|
const commonItem = contexts[i].find((t) => contexts[j].includes(t));
|
|
|
|
if (commonItem) {
|
|
|
|
contexts[i] = [...contexts[i], ...contexts[j]];
|
|
|
|
// Remove duplicate items
|
|
|
|
contexts[i] = contexts[i].filter(
|
|
|
|
(item, index, self) =>
|
|
|
|
self.findIndex((t) => t.id === item.id) === index,
|
|
|
|
);
|
|
|
|
contexts.splice(j, 1);
|
|
|
|
j--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sort items by checking inReplyToId
|
|
|
|
contexts.forEach((context) => {
|
|
|
|
context.sort((a, b) => {
|
2023-05-11 13:13:13 +03:00
|
|
|
if (!a.inReplyToId && !b.inReplyToId) {
|
|
|
|
return new Date(a.createdAt) - new Date(b.createdAt);
|
|
|
|
}
|
|
|
|
if (!a.inReplyToId) return -1;
|
|
|
|
if (!b.inReplyToId) return 1;
|
|
|
|
return new Date(a.createdAt) - new Date(b.createdAt);
|
2023-05-05 11:59:06 +03:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2023-03-26 18:18:36 +03:00
|
|
|
if (contexts.length) console.log('🧵 Contexts', contexts);
|
|
|
|
|
|
|
|
const newItems = [];
|
|
|
|
const appliedContextIndices = [];
|
|
|
|
items.forEach((item) => {
|
|
|
|
if (item.reblog) {
|
|
|
|
newItems.push(item);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (let i = 0; i < contexts.length; i++) {
|
|
|
|
if (contexts[i].find((t) => t.id === item.id)) {
|
|
|
|
if (appliedContextIndices.includes(i)) return;
|
|
|
|
const contextItems = contexts[i];
|
|
|
|
contextItems.sort((a, b) => {
|
|
|
|
const aDate = new Date(a.createdAt);
|
|
|
|
const bDate = new Date(b.createdAt);
|
|
|
|
return aDate - bDate;
|
|
|
|
});
|
|
|
|
const firstItemAccountID = contextItems[0].account.id;
|
|
|
|
newItems.push({
|
|
|
|
id: contextItems.map((i) => i.id),
|
|
|
|
items: contextItems,
|
|
|
|
type: contextItems.every((it) => it.account.id === firstItemAccountID)
|
|
|
|
? 'thread'
|
|
|
|
: 'conversation',
|
|
|
|
});
|
|
|
|
appliedContextIndices.push(i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
newItems.push(item);
|
|
|
|
});
|
|
|
|
|
|
|
|
return newItems;
|
|
|
|
}
|