diff --git a/package.json b/package.json index d98a5c6..5ba3874 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "spacesocial-client", - "version": "0.2.0_rev1", + "version": "0.2.0_rev2", "description": "social media for the galaxy-wide-web! 🌌", "type": "module", "scripts": { diff --git a/src/App.svelte b/src/App.svelte index 7538a88..6f05334 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -20,6 +20,7 @@ } if (client.app && client.app.token) { + // this triggers the client actually getting the authenticated user's data. client.verifyCredentials().then(res => { if (res) { console.log(`Logged in as @${client.user.username}@${client.user.host}`); diff --git a/src/client/api.js b/src/client/api.js index dfcf733..e063e75 100644 --- a/src/client/api.js +++ b/src/client/api.js @@ -131,6 +131,83 @@ export async function getPostContext(post_id) { return data; } +export async function boostPost(post_id) { + let client = get(Client.get()); + let url = `https://${client.instance.host}/api/v1/statuses/${post_id}/reblog`; + const data = await fetch(url, { + method: 'POST', + headers: { "Authorization": "Bearer " + client.app.token } + }).then(res => { return res.ok ? res.json() : false }); + + if (data === false) return false; + return data; +} + +export async function unboostPost(post_id) { + let client = get(Client.get()); + let url = `https://${client.instance.host}/api/v1/statuses/${post_id}/unreblog`; + const data = await fetch(url, { + method: 'POST', + headers: { "Authorization": "Bearer " + client.app.token } + }).then(res => { return res.ok ? res.json() : false }); + + if (data === false) return false; + return data; +} + +export async function favouritePost(post_id) { + let client = get(Client.get()); + let url = `https://${client.instance.host}/api/v1/statuses/${post_id}/favourite`; + const data = await fetch(url, { + method: 'POST', + headers: { "Authorization": "Bearer " + client.app.token } + }).then(res => { return res.ok ? res.json() : false }); + + if (data === false) return false; + return data; +} + +export async function unfavouritePost(post_id) { + let client = get(Client.get()); + let url = `https://${client.instance.host}/api/v1/statuses/${post_id}/unfavourite`; + const data = await fetch(url, { + method: 'POST', + headers: { "Authorization": "Bearer " + client.app.token } + }).then(res => { return res.ok ? res.json() : false }); + + if (data === false) return false; + return data; +} + +export async function reactPost(post_id, shortcode) { + // for whatever reason (at least in my testing on iceshrimp) + // using shortcodes for external emoji results in a fallback + // to the default like emote. + // identical api calls on chuckya instances do not display + // this behaviour. + let client = get(Client.get()); + let url = `https://${client.instance.host}/api/v1/statuses/${post_id}/react/${encodeURIComponent(shortcode)}`; + const data = await fetch(url, { + method: 'POST', + headers: { "Authorization": "Bearer " + client.app.token } + }).then(res => { return res.ok ? res.json() : false }); + + if (data === false) return false; + return data; +} + +export async function unreactPost(post_id, shortcode) { + let client = get(Client.get()); + let url = `https://${client.instance.host}/api/v1/statuses/${post_id}/unreact/${encodeURIComponent(shortcode)}`; + const data = await fetch(url, { + method: 'POST', + headers: { "Authorization": "Bearer " + client.app.token } + }).then(res => { return res.ok ? res.json() : false }); + + if (data === false) return false; + return data; +} + export async function parsePost(data, parent_replies, child_replies) { let client = get(Client.get()); let post = new Post(); @@ -166,6 +243,9 @@ export async function parsePost(data, parent_replies, child_replies) { post.warning = data.spoiler_text; post.boost_count = data.reblogs_count; post.reply_count = data.replies_count; + post.favourite_count = data.favourites_count; + post.favourited = data.favourited; + post.boosted = data.boosted; post.mentions = data.mentions; post.files = data.media_attachments; post.url = data.url; @@ -185,33 +265,7 @@ export async function parsePost(data, parent_replies, child_replies) { } if (data.reactions && client.instance.capabilities.includes(capabilities.REACTIONS)) { - post.reactions = []; - data.reactions.forEach(reaction_data => { - if (/^[\w\-.@]+$/g.exec(reaction_data.name)) { - let name = reaction_data.name.split('@')[0]; - let host = reaction_data.name.includes('@') ? reaction_data.name.split('@')[1] : client.instance.host; - post.reactions.push({ - count: reaction_data.count, - emoji: parseEmoji({ - id: name + '@' + host, - name: name, - host: host, - url: reaction_data.url, - }), - me: reaction_data.me, - }); - } else { - if (reaction_data.name == '❤') reaction_data.name = '❤️'; // stupid heart unicode - post.reactions.push({ - count: reaction_data.count, - emoji: { - html: reaction_data.name, - name: reaction_data.name, - }, - me: reaction_data.me, - }); - } - }); + post.reactions = parseReactions(data.reactions); } return post; } @@ -251,6 +305,21 @@ export async function parseUser(data) { return user; } +export function parseReactions(data) { + let client = get(Client.get()); + let reactions = []; + data.forEach(reaction_data => { + let reaction = { + count: reaction_data.count, + name: reaction_data.name, + me: reaction_data.me, + }; + if (reaction_data.url) reaction.url = reaction_data.url; + reactions.push(reaction); + }); + return reactions; +} + export function parseEmoji(data) { let emoji = new Emoji( data.id, diff --git a/src/client/client.js b/src/client/client.js index 575c293..862f1d2 100644 --- a/src/client/client.js +++ b/src/client/client.js @@ -100,6 +100,30 @@ export class Client { return await api.getPost(post_id, parent_replies, child_replies); } + async boostPost(post_id) { + return await api.boostPost(post_id); + } + + async unboostPost(post_id) { + return await api.unboostPost(post_id); + } + + async favouritePost(post_id) { + return await api.favouritePost(post_id); + } + + async unfavouritePost(post_id) { + return await api.unfavouritePost(post_id); + } + + async reactPost(post_id, shortcode) { + return await api.reactPost(post_id, shortcode); + } + + async unreactPost(post_id, shortcode) { + return await api.unreactPost(post_id, shortcode); + } + putCacheUser(user) { this.cache.users[user.id] = user; client.set(this); @@ -148,7 +172,6 @@ export class Client { if (!json) return false; let saved = JSON.parse(json); if (!saved.version || saved.version !== APP_VERSION) { - localStorage.setItem(save_name + '-backup', json); localStorage.removeItem(save_name); return false; } diff --git a/src/emoji.js b/src/emoji.js index 9cd5e12..4fdd161 100644 --- a/src/emoji.js +++ b/src/emoji.js @@ -5,9 +5,7 @@ export const EMOJI_REGEX = /:[\w\-.]{0,32}@[\w\-.]{0,32}:/g; export const EMOJI_NAME_REGEX = /:[\w\-.]{0,32}:/g; export default class Emoji { - id; name; - host; url; constructor(id, name, host, url) { @@ -18,7 +16,10 @@ export default class Emoji { } get html() { - return `${this.name}`; + if (this.url) + return `${this.name}`; + else + return `${this.name}`; } } diff --git a/src/post.js b/src/post.js index 1468ef9..9971daa 100644 --- a/src/post.js +++ b/src/post.js @@ -8,6 +8,9 @@ export default class Post { warning; boost_count; reply_count; + favourite_count; + favourited; + boosted; mentions; reactions; emojis; diff --git a/src/sound.js b/src/sound.js index c5dc1fb..bc12022 100644 --- a/src/sound.js +++ b/src/sound.js @@ -1,10 +1,11 @@ const sounds = { - "default": new Audio("sound/log.ogg"), - "post": new Audio("sound/success.ogg"), - "boost": new Audio("sound/hello.ogg"), + "default": new Audio("/sound/log.ogg"), + "post": new Audio("/sound/success.ogg"), + "boost": new Audio("/sound/hello.ogg"), }; export function play_sound(name) { + if (name === false) return; if (!name) name = "default"; const sound = sounds[name]; if (!sound) { diff --git a/src/ui/post/ActionButton.svelte b/src/ui/post/ActionButton.svelte index e62ce0f..ab34e5c 100644 --- a/src/ui/post/ActionButton.svelte +++ b/src/ui/post/ActionButton.svelte @@ -1,21 +1,36 @@