mirror of
https://github.com/AMNatty/Mastodon-Circles.git
synced 2024-11-21 18:47:26 -07:00
Merge branch 'add-fedibird-support'
This commit is contained in:
commit
9b664cbffc
2 changed files with 147 additions and 34 deletions
180
create-circle.js
180
create-circle.js
|
@ -168,7 +168,7 @@ class ApiClient {
|
||||||
let nodeInfo = await apiRequest(url);
|
let nodeInfo = await apiRequest(url);
|
||||||
|
|
||||||
if (!nodeInfo || !Array.isArray(nodeInfo.links)) {
|
if (!nodeInfo || !Array.isArray(nodeInfo.links)) {
|
||||||
const client = new MastodonApiClient(instance);
|
const client = new MastodonApiClient(instance, true);
|
||||||
instanceTypeCache.set(instance, client);
|
instanceTypeCache.set(instance, client);
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
@ -182,7 +182,7 @@ class ApiClient {
|
||||||
|
|
||||||
if (!apiLink) {
|
if (!apiLink) {
|
||||||
console.error(`No NodeInfo API found for ${instance}}`);
|
console.error(`No NodeInfo API found for ${instance}}`);
|
||||||
const client = new MastodonApiClient(instance);
|
const client = new MastodonApiClient(instance, true);
|
||||||
instanceTypeCache.set(instance, client);
|
instanceTypeCache.set(instance, client);
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
@ -205,7 +205,7 @@ class ApiClient {
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
const client = new MastodonApiClient(instance);
|
const client = new MastodonApiClient(instance, true);
|
||||||
instanceTypeCache.set(instance, client);
|
instanceTypeCache.set(instance, client);
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
@ -213,6 +213,12 @@ class ApiClient {
|
||||||
let { software } = apiResponse;
|
let { software } = apiResponse;
|
||||||
software.name = software.name.toLowerCase();
|
software.name = software.name.toLowerCase();
|
||||||
|
|
||||||
|
if (software.name.includes("fedibird")) {
|
||||||
|
const client = new FedibirdApiClient(instance, true);
|
||||||
|
instanceTypeCache.set(instance, client);
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
if (software.name.includes("misskey") ||
|
if (software.name.includes("misskey") ||
|
||||||
software.name.includes("calckey") ||
|
software.name.includes("calckey") ||
|
||||||
software.name.includes("foundkey") ||
|
software.name.includes("foundkey") ||
|
||||||
|
@ -231,7 +237,7 @@ class ApiClient {
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
const client = new MastodonApiClient(instance);
|
const client = new MastodonApiClient(instance, true);
|
||||||
instanceTypeCache.set(instance, client);
|
instanceTypeCache.set(instance, client);
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
@ -266,11 +272,50 @@ class ApiClient {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Note} note
|
* @param {Note} note
|
||||||
* @param {boolean} extra_reacts
|
|
||||||
*
|
*
|
||||||
* @returns {Promise<FediUser[] | null>}
|
* @returns {Promise<FediUser[] | null>}
|
||||||
*/
|
*/
|
||||||
async getFavs(note, extra_reacts) { throw new Error("Not implemented"); }
|
async getReactions(note){ return []; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Note} note
|
||||||
|
*
|
||||||
|
* @returns {Promise<FediUser[] | null>}
|
||||||
|
*/
|
||||||
|
async getFavs(note) { throw new Error("Not implemented"); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Note} note
|
||||||
|
* @param {boolean} extra_reacts Also include emoji reacts
|
||||||
|
*
|
||||||
|
* return {Promise<FediUser[] | null>}
|
||||||
|
*/
|
||||||
|
async getConsolidatedReactions(note, extra_reacts = false){
|
||||||
|
let favs = await this.getFavs(note);
|
||||||
|
|
||||||
|
if (!extra_reacts)
|
||||||
|
return favs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Map<string, FediUser>}
|
||||||
|
*/
|
||||||
|
let users = new Map();
|
||||||
|
if (favs !== null) {
|
||||||
|
favs.forEach(u => {
|
||||||
|
users.set(u.id, u);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const reactions = await this.getReactions(note);
|
||||||
|
if (reactions !== null) {
|
||||||
|
reactions.forEach(u => {
|
||||||
|
users.set(u.id, u);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return Array.from(users.values());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns string
|
* @returns string
|
||||||
|
@ -281,9 +326,13 @@ class ApiClient {
|
||||||
class MastodonApiClient extends ApiClient {
|
class MastodonApiClient extends ApiClient {
|
||||||
/**
|
/**
|
||||||
* @param {string} instance
|
* @param {string} instance
|
||||||
|
* @param {boolean} emoji_reacts
|
||||||
|
* @param {MastodonApiClient} flavor
|
||||||
*/
|
*/
|
||||||
constructor(instance) {
|
constructor(instance, emoji_reacts, flavor = MastodonFlavor.MASTODON) {
|
||||||
super(instance);
|
super(instance);
|
||||||
|
this._emoji_reacts = emoji_reacts;
|
||||||
|
this._flavor = flavor;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getUserIdFromHandle(handle) {
|
async getUserIdFromHandle(handle) {
|
||||||
|
@ -316,13 +365,18 @@ class MastodonApiClient extends ApiClient {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (response?.some(note => note?.["emoji_reactions"]?.length)) {
|
||||||
|
this._flavor = MastodonFlavor.FEDIBIRD;
|
||||||
|
} else if (response?.some(note => note?.["pleroma"]?.["emoji_reactions"]?.length)) {
|
||||||
|
this._flavor = MastodonFlavor.PLEROMA;
|
||||||
|
}
|
||||||
|
|
||||||
return response.map(note => ({
|
return response.map(note => ({
|
||||||
id: note.id,
|
id: note.id,
|
||||||
replies: note["replies_count"] || 0,
|
replies: note["replies_count"] || 0,
|
||||||
renotes: note["reblogs_count"] || 0,
|
renotes: note["reblogs_count"] || 0,
|
||||||
favorites: note["favourites_count"],
|
favorites: note["favourites_count"],
|
||||||
// Actually a Pleroma/Akkoma thing
|
extra_reacts: note?.["emoji_reactions"]?.length > 0 || note?.["pleroma"]?.["emoji_reactions"]?.length > 0,
|
||||||
extra_reacts: note?.["pleroma"]?.["emoji_reactions"]?.length > 0,
|
|
||||||
instance: this._instance,
|
instance: this._instance,
|
||||||
author: user
|
author: user
|
||||||
}));
|
}));
|
||||||
|
@ -353,7 +407,14 @@ class MastodonApiClient extends ApiClient {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (response["descendants"]?.some(note => note?.["emoji_reactions"]?.length)) {
|
||||||
|
this._flavor = MastodonFlavor.FEDIBIRD;
|
||||||
|
} else if (response["descendants"]?.some(note => note?.["pleroma"]?.["emoji_reactions"]?.length)) {
|
||||||
|
this._flavor = MastodonFlavor.PLEROMA;
|
||||||
|
}
|
||||||
|
|
||||||
return response["descendants"].map(note => {
|
return response["descendants"].map(note => {
|
||||||
|
|
||||||
let handle = parseHandle(note["account"]["acct"], noteIn.instance);
|
let handle = parseHandle(note["account"]["acct"], noteIn.instance);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -361,8 +422,7 @@ class MastodonApiClient extends ApiClient {
|
||||||
replies: note["replies_count"] || 0,
|
replies: note["replies_count"] || 0,
|
||||||
renotes: note["reblogs_count"] || 0,
|
renotes: note["reblogs_count"] || 0,
|
||||||
favorites: note["favourites_count"],
|
favorites: note["favourites_count"],
|
||||||
// Actually a Pleroma/Akkoma thing
|
extra_reacts: note?.["emoji_reactions"]?.length > 0 || note?.["pleroma"]?.["emoji_reactions"]?.length > 0,
|
||||||
extra_reacts: note?.["pleroma"]?.["emoji_reactions"]?.length > 0,
|
|
||||||
instance: handle.instance,
|
instance: handle.instance,
|
||||||
author: {
|
author: {
|
||||||
id: note["account"]["id"],
|
id: note["account"]["id"],
|
||||||
|
@ -375,7 +435,7 @@ class MastodonApiClient extends ApiClient {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getFavs(note, extra_reacts) {
|
async getFavs(note) {
|
||||||
const url = `https://${this._instance}/api/v1/statuses/${note.id}/favourited_by`;
|
const url = `https://${this._instance}/api/v1/statuses/${note.id}/favourited_by`;
|
||||||
const response = await apiRequest(url);
|
const response = await apiRequest(url);
|
||||||
|
|
||||||
|
@ -392,6 +452,14 @@ class MastodonApiClient extends ApiClient {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getReactions(note) {
|
||||||
|
if (this._flavor === MastodonFlavor.MASTODON) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._flavor.getReactions.call(this, note);
|
||||||
|
}
|
||||||
|
|
||||||
getClientName() {
|
getClientName() {
|
||||||
return "mastodon";
|
return "mastodon";
|
||||||
}
|
}
|
||||||
|
@ -403,31 +471,20 @@ class PleromaApiClient extends MastodonApiClient {
|
||||||
* @param {boolean} emoji_reacts
|
* @param {boolean} emoji_reacts
|
||||||
*/
|
*/
|
||||||
constructor(instance, emoji_reacts) {
|
constructor(instance, emoji_reacts) {
|
||||||
super(instance);
|
super(instance, emoji_reacts, MastodonFlavor.PLEROMA);
|
||||||
this._emoji_reacts = emoji_reacts;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getFavs(note, extra_reacts) {
|
async getReactions(note) {
|
||||||
// Pleroma/Akkoma supports both favs and emoji reacts
|
if (!this._emoji_reacts)
|
||||||
// with several emoji reacts per users being possible.
|
return [];
|
||||||
// Coalesce them and count every user only once
|
|
||||||
let favs = await super.getFavs(note);
|
|
||||||
|
|
||||||
if (!this._emoji_reacts || !extra_reacts)
|
const url = `https://${this._instance}/api/v1/pleroma/statuses/${note.id}/reactions`;
|
||||||
return favs;
|
const response = await apiRequest(url) ?? [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {Map<string, FediUser>}
|
* @type {Map<string, FediUser>}
|
||||||
*/
|
*/
|
||||||
let users = new Map();
|
const users = new Map();
|
||||||
if (favs !== null) {
|
|
||||||
favs.forEach(u => {
|
|
||||||
users.set(u.id, u);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const url = `https://${this._instance}/api/v1/pleroma/statuses/${note.id}/reactions`;
|
|
||||||
const response = await apiRequest(url) ?? [];
|
|
||||||
|
|
||||||
for (const reaction of response) {
|
for (const reaction of response) {
|
||||||
reaction["accounts"]
|
reaction["accounts"]
|
||||||
|
@ -452,6 +509,55 @@ class PleromaApiClient extends MastodonApiClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class FedibirdApiClient extends MastodonApiClient {
|
||||||
|
/**
|
||||||
|
* @param {string} instance
|
||||||
|
* @param {boolean} emoji_reacts
|
||||||
|
*/
|
||||||
|
constructor(instance, emoji_reacts) {
|
||||||
|
super(instance, emoji_reacts, MastodonFlavor.FEDIBIRD);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getReactions(note) {
|
||||||
|
if (!this._emoji_reacts)
|
||||||
|
return [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Map<string, FediUser>}
|
||||||
|
*/
|
||||||
|
let users = new Map();
|
||||||
|
|
||||||
|
const url = `https://${this._instance}/api/v1/statuses/${note.id}/emoji_reactioned_by`;
|
||||||
|
const response = await apiRequest(url) ?? [];
|
||||||
|
|
||||||
|
for (const reaction of response) {
|
||||||
|
let account = reaction["account"];
|
||||||
|
let u = {
|
||||||
|
id: account["id"],
|
||||||
|
avatar: account["avatar"],
|
||||||
|
bot: account["bot"],
|
||||||
|
name: account["display_name"],
|
||||||
|
handle: parseHandle(account["acct"], note.instance)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!users.has(u.id))
|
||||||
|
users.set(u.id, u);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.from(users.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
getClientName() {
|
||||||
|
return "fedibird";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const MastodonFlavor = {
|
||||||
|
MASTODON: MastodonApiClient.prototype,
|
||||||
|
PLEROMA: PleromaApiClient.prototype,
|
||||||
|
FEDIBIRD: FedibirdApiClient.prototype,
|
||||||
|
};
|
||||||
|
|
||||||
class MisskeyApiClient extends ApiClient {
|
class MisskeyApiClient extends ApiClient {
|
||||||
/**
|
/**
|
||||||
* @param {string} instance
|
* @param {string} instance
|
||||||
|
@ -605,7 +711,7 @@ class MisskeyApiClient extends ApiClient {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getFavs(note, extra_reacts) {
|
async getFavs(note) {
|
||||||
const url = `https://${this._instance}/api/notes/reactions`;
|
const url = `https://${this._instance}/api/notes/reactions`;
|
||||||
const response = await apiRequest(url, {
|
const response = await apiRequest(url, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
|
@ -676,7 +782,7 @@ async function circleMain() {
|
||||||
let client;
|
let client;
|
||||||
switch (backend.value) {
|
switch (backend.value) {
|
||||||
case "mastodon":
|
case "mastodon":
|
||||||
client = new MastodonApiClient(selfUser.apiInstance);
|
client = new MastodonApiClient(selfUser.apiInstance, true);
|
||||||
break;
|
break;
|
||||||
case "pleroma":
|
case "pleroma":
|
||||||
client = new PleromaApiClient(selfUser.apiInstance, true);
|
client = new PleromaApiClient(selfUser.apiInstance, true);
|
||||||
|
@ -687,7 +793,13 @@ async function circleMain() {
|
||||||
default:
|
default:
|
||||||
progress.innerText = "Detecting instance...";
|
progress.innerText = "Detecting instance...";
|
||||||
client = await ApiClient.getClient(selfUser.apiInstance);
|
client = await ApiClient.getClient(selfUser.apiInstance);
|
||||||
backend.value = client.getClientName();
|
|
||||||
|
backend.value = (() => {
|
||||||
|
switch (client.getClientName()) {
|
||||||
|
case "fedibird": return "mastodon";
|
||||||
|
default: return client.getClientName();
|
||||||
|
}
|
||||||
|
})();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -749,7 +861,7 @@ async function processNotes(client, connectionList, notes) {
|
||||||
*/
|
*/
|
||||||
async function evaluateNote(client, connectionList, note) {
|
async function evaluateNote(client, connectionList, note) {
|
||||||
if (note.favorites > 0 || note.extra_reacts) {
|
if (note.favorites > 0 || note.extra_reacts) {
|
||||||
await client.getFavs(note, note.extra_reacts).then(users => {
|
await client.getConsolidatedReactions(note, note.extra_reacts).then(users => {
|
||||||
if (!users)
|
if (!users)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
<br><br><br>
|
<br><br><br>
|
||||||
<div id="credits" style="width: 100%;">
|
<div id="credits" style="width: 100%;">
|
||||||
<p>Contribute on <a href="https://github.com/AMNatty/Mastodon-Circles">GitHub: AMNatty/Mastodon-Circles</a></p>
|
<p>Contribute on <a href="https://github.com/AMNatty/Mastodon-Circles">GitHub: AMNatty/Mastodon-Circles</a></p>
|
||||||
|
<p>Fedibird support by <a href="https://github.com/noellabo/Mastodon-Circles">noellabo</a></p>
|
||||||
<p>Based on <a href="https://github.com/andigandhi/Mastodon-Circles">andigandhi/Mastodon-Circles</a> </p>
|
<p>Based on <a href="https://github.com/andigandhi/Mastodon-Circles">andigandhi/Mastodon-Circles</a> </p>
|
||||||
</div>
|
</div>
|
||||||
<!-- Preload the background image -->
|
<!-- Preload the background image -->
|
||||||
|
|
Loading…
Reference in a new issue