mirror of
https://github.com/AMNatty/Mastodon-Circles.git
synced 2024-11-24 20:17:27 -07:00
Merge pull request #1 from TheOneric/pleroma-emoji-reactions
Support Pleroma’s emoji reactions (+small Masto fix)
This commit is contained in:
commit
2cf6058d06
2 changed files with 81 additions and 6 deletions
|
@ -42,6 +42,7 @@ async function apiRequest(url, options = null)
|
||||||
* replies: number,
|
* replies: number,
|
||||||
* renotes: number,
|
* renotes: number,
|
||||||
* favorites: number,
|
* favorites: number,
|
||||||
|
* extra_reacts: boolean,
|
||||||
* instance: string,
|
* instance: string,
|
||||||
* author?: FediUser,
|
* author?: FediUser,
|
||||||
* }} Note
|
* }} Note
|
||||||
|
@ -109,6 +110,14 @@ class ApiClient {
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let features = apiResponse?.metadata?.features;
|
||||||
|
if (Array.isArray(features) && features.includes("pleroma_api")) {
|
||||||
|
const has_emoji_reacts = features.includes("pleroma_emoji_reactions");
|
||||||
|
const client = new PleromaApiClient(instance, has_emoji_reacts);
|
||||||
|
instanceTypeCache.set(instance, client);
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
const client = new MastodonApiClient(instance);
|
const client = new MastodonApiClient(instance);
|
||||||
instanceTypeCache.set(instance, client);
|
instanceTypeCache.set(instance, client);
|
||||||
return client;
|
return client;
|
||||||
|
@ -144,10 +153,11 @@ class ApiClient {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Note} note
|
* @param {Note} note
|
||||||
|
* @param {boolean} extra_reacts
|
||||||
*
|
*
|
||||||
* return {Promise<FediUser[] | null>}
|
* return {Promise<FediUser[] | null>}
|
||||||
*/
|
*/
|
||||||
async getFavs(note) { throw new Error("Not implemented"); }
|
async getFavs(note, extra_reacts) { throw new Error("Not implemented"); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
|
@ -193,6 +203,8 @@ 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?.["pleroma"]?.["emoji_reactions"]?.length > 0,
|
||||||
instance: this._instance,
|
instance: this._instance,
|
||||||
author: user
|
author: user
|
||||||
}));
|
}));
|
||||||
|
@ -223,7 +235,7 @@ class MastodonApiClient extends ApiClient {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return response["ancestors"].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 {
|
||||||
|
@ -231,6 +243,8 @@ 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?.["pleroma"]?.["emoji_reactions"]?.length > 0,
|
||||||
instance: handle.instance,
|
instance: handle.instance,
|
||||||
author: {
|
author: {
|
||||||
id: note["account"]["id"],
|
id: note["account"]["id"],
|
||||||
|
@ -243,7 +257,7 @@ class MastodonApiClient extends ApiClient {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getFavs(note) {
|
async getFavs(note, extra_reacts) {
|
||||||
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);
|
||||||
|
|
||||||
|
@ -265,6 +279,61 @@ class MastodonApiClient extends ApiClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class PleromaApiClient extends MastodonApiClient {
|
||||||
|
/**
|
||||||
|
* @param {string} instance
|
||||||
|
* @param {boolean} emoji_reacts
|
||||||
|
*/
|
||||||
|
constructor(instance, emoji_reacts) {
|
||||||
|
super(instance);
|
||||||
|
this._emoji_reacts = emoji_reacts;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getFavs(note, extra_reacts) {
|
||||||
|
// Pleroma/Akkoma supports both favs and emoji reacts
|
||||||
|
// with several emoji reacts per users being possible.
|
||||||
|
// Coalesce them and count every user only once
|
||||||
|
let favs = await super.getFavs(note);
|
||||||
|
|
||||||
|
if (!this._emoji_reacts || !extra_reacts)
|
||||||
|
return favs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Map<string, FediUser>}
|
||||||
|
*/
|
||||||
|
let 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) {
|
||||||
|
reaction["accounts"]
|
||||||
|
.map(account => ({
|
||||||
|
id: account["id"],
|
||||||
|
avatar: account["avatar"],
|
||||||
|
bot: account["bot"],
|
||||||
|
name: account["display_name"],
|
||||||
|
handle: parseHandle(account["acct"], note.instance)
|
||||||
|
}))
|
||||||
|
.forEach(u => {
|
||||||
|
if(!users.has(u.id))
|
||||||
|
users.set(u.id, u);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.from(users.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
getClientName() {
|
||||||
|
return "pleroma";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class MisskeyApiClient extends ApiClient {
|
class MisskeyApiClient extends ApiClient {
|
||||||
/**
|
/**
|
||||||
* @param {string} instance
|
* @param {string} instance
|
||||||
|
@ -316,6 +385,7 @@ class MisskeyApiClient extends ApiClient {
|
||||||
replies: note["repliesCount"],
|
replies: note["repliesCount"],
|
||||||
renotes: note["renoteCount"],
|
renotes: note["renoteCount"],
|
||||||
favorites: Object.values(note["reactions"]).reduce((a, b) => a + b, 0),
|
favorites: Object.values(note["reactions"]).reduce((a, b) => a + b, 0),
|
||||||
|
extra_reacts: false,
|
||||||
instance: this._instance,
|
instance: this._instance,
|
||||||
author: user
|
author: user
|
||||||
}));
|
}));
|
||||||
|
@ -366,6 +436,7 @@ class MisskeyApiClient extends ApiClient {
|
||||||
replies: reply["repliesCount"],
|
replies: reply["repliesCount"],
|
||||||
renotes: reply["renoteCount"],
|
renotes: reply["renoteCount"],
|
||||||
favorites: Object.values(reply["reactions"]).reduce((a, b) => a + b, 0),
|
favorites: Object.values(reply["reactions"]).reduce((a, b) => a + b, 0),
|
||||||
|
extra_reacts: false,
|
||||||
instance: handle.instance,
|
instance: handle.instance,
|
||||||
author: {
|
author: {
|
||||||
id: reply["user"]["id"],
|
id: reply["user"]["id"],
|
||||||
|
@ -378,7 +449,7 @@ class MisskeyApiClient extends ApiClient {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getFavs(note) {
|
async getFavs(note, extra_reacts) {
|
||||||
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",
|
||||||
|
@ -455,6 +526,9 @@ async function circleMain() {
|
||||||
case "mastodon":
|
case "mastodon":
|
||||||
client = new MastodonApiClient(selfUser.instance);
|
client = new MastodonApiClient(selfUser.instance);
|
||||||
break;
|
break;
|
||||||
|
case "pleroma":
|
||||||
|
client = new PleromaApiClient(selfUser.instance, true);
|
||||||
|
break;
|
||||||
case "misskey":
|
case "misskey":
|
||||||
client = new MisskeyApiClient(selfUser.instance);
|
client = new MisskeyApiClient(selfUser.instance);
|
||||||
break;
|
break;
|
||||||
|
@ -524,8 +598,8 @@ async function processNotes(client, connectionList, notes) {
|
||||||
* @param {Note} note
|
* @param {Note} note
|
||||||
*/
|
*/
|
||||||
async function evaluateNote(client, connectionList, note) {
|
async function evaluateNote(client, connectionList, note) {
|
||||||
if (note.favorites > 0) {
|
if (note.favorites > 0 || note.extra_reacts) {
|
||||||
await client.getFavs(note).then(users => {
|
await client.getFavs(note, note.extra_reacts).then(users => {
|
||||||
if (!users)
|
if (!users)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
<label><input type="radio" name="backend" value="detect" autocomplete="off" checked> Autodetect</label>
|
<label><input type="radio" name="backend" value="detect" autocomplete="off" checked> Autodetect</label>
|
||||||
<label><input type="radio" name="backend" value="mastodon" autocomplete="off"> Mastodon API</label>
|
<label><input type="radio" name="backend" value="mastodon" autocomplete="off"> Mastodon API</label>
|
||||||
<label><input type="radio" name="backend" value="misskey" autocomplete="off"> Misskey API</label>
|
<label><input type="radio" name="backend" value="misskey" autocomplete="off"> Misskey API</label>
|
||||||
|
<label><input type="radio" name="backend" value="pleroma" autocomplete="off"> Pleroma API</label>
|
||||||
</span>
|
</span>
|
||||||
<br>
|
<br>
|
||||||
<button type="submit" id="generateButton">Generate circle</button>
|
<button type="submit" id="generateButton">Generate circle</button>
|
||||||
|
|
Loading…
Reference in a new issue