diff --git a/src/components/list-add-edit.jsx b/src/components/list-add-edit.jsx index d9a21a4b..17279b7b 100644 --- a/src/components/list-add-edit.jsx +++ b/src/components/list-add-edit.jsx @@ -24,7 +24,9 @@ function ListAddEdit({ list, onClose }) { } } }, [editMode]); - const supportsExclusive = supports('@mastodon/list-exclusive'); + const supportsExclusive = + supports('@mastodon/list-exclusive') || + supports('@gotosocial/list-exclusive'); return (
diff --git a/src/data/features.json b/src/data/features.json index 6ff4bb1e..7376418b 100644 --- a/src/data/features.json +++ b/src/data/features.json @@ -1,6 +1,7 @@ { "@mastodon/edit-media-attributes": ">=4.1", "@mastodon/list-exclusive": ">=4.2", + "@gotosocial/list-exclusive": ">=0.17", "@mastodon/filtered-notifications": "~4.3 || >=4.3", "@mastodon/fetch-multiple-statuses": "~4.3 || >=4.3", "@mastodon/trending-link-posts": "~4.3 || >=4.3", diff --git a/src/locales/en.po b/src/locales/en.po index f32729e4..2ae08b2e 100644 --- a/src/locales/en.po +++ b/src/locales/en.po @@ -408,7 +408,7 @@ msgstr "" #: src/components/embed-modal.jsx:12 #: src/components/generic-accounts.jsx:142 #: src/components/keyboard-shortcuts-help.jsx:39 -#: src/components/list-add-edit.jsx:33 +#: src/components/list-add-edit.jsx:35 #: src/components/media-alt-modal.jsx:33 #: src/components/media-modal.jsx:352 #: src/components/notification-service.jsx:156 @@ -452,7 +452,7 @@ msgid "No lists." msgstr "" #: src/components/account-info.jsx:1939 -#: src/components/list-add-edit.jsx:37 +#: src/components/list-add-edit.jsx:39 #: src/pages/lists.jsx:58 msgid "New list" msgstr "" @@ -479,7 +479,7 @@ msgid "Unable to update profile." msgstr "" #: src/components/account-info.jsx:2155 -#: src/components/list-add-edit.jsx:102 +#: src/components/list-add-edit.jsx:104 msgid "Name" msgstr "" @@ -500,7 +500,7 @@ msgid "Content" msgstr "" #: src/components/account-info.jsx:2223 -#: src/components/list-add-edit.jsx:147 +#: src/components/list-add-edit.jsx:149 #: src/components/shortcuts-settings.jsx:715 #: src/pages/filters.jsx:554 #: src/pages/notifications.jsx:934 @@ -891,7 +891,7 @@ msgid "Error deleting draft! Please try again." msgstr "" #: src/components/drafts.jsx:127 -#: src/components/list-add-edit.jsx:183 +#: src/components/list-add-edit.jsx:185 #: src/components/status.jsx:1336 #: src/pages/filters.jsx:587 msgid "Deleteā€¦" @@ -1126,44 +1126,44 @@ msgstr "" msgid "<0>Shift + <1>Alt + <2>k" msgstr "" -#: src/components/list-add-edit.jsx:37 +#: src/components/list-add-edit.jsx:39 msgid "Edit list" msgstr "" -#: src/components/list-add-edit.jsx:93 +#: src/components/list-add-edit.jsx:95 msgid "Unable to edit list." msgstr "" -#: src/components/list-add-edit.jsx:94 +#: src/components/list-add-edit.jsx:96 msgid "Unable to create list." msgstr "" -#: src/components/list-add-edit.jsx:122 +#: src/components/list-add-edit.jsx:124 msgid "Show replies to list members" msgstr "" -#: src/components/list-add-edit.jsx:125 +#: src/components/list-add-edit.jsx:127 msgid "Show replies to people I follow" msgstr "" -#: src/components/list-add-edit.jsx:128 +#: src/components/list-add-edit.jsx:130 msgid "Don't show replies" msgstr "" -#: src/components/list-add-edit.jsx:141 +#: src/components/list-add-edit.jsx:143 msgid "Hide posts on this list from Home/Following" msgstr "" -#: src/components/list-add-edit.jsx:147 +#: src/components/list-add-edit.jsx:149 #: src/pages/filters.jsx:554 msgid "Create" msgstr "" -#: src/components/list-add-edit.jsx:154 +#: src/components/list-add-edit.jsx:156 msgid "Delete this list?" msgstr "" -#: src/components/list-add-edit.jsx:173 +#: src/components/list-add-edit.jsx:175 msgid "Unable to delete list." msgstr "" diff --git a/src/utils/api.js b/src/utils/api.js index cf6652bc..7c311e4c 100644 --- a/src/utils/api.js +++ b/src/utils/api.js @@ -89,6 +89,7 @@ export async function initInstance(client, instance) { domain, configuration: { urls: { streaming } = {} } = {}, } = info; + const instances = store.local.getJSON('instances') || {}; if (uri || domain) { instances[ @@ -102,6 +103,34 @@ export async function initInstance(client, instance) { instances[instance.toLowerCase()] = info; } store.local.setJSON('instances', instances); + + let nodeInfo; + // GoToSocial requires we get the NodeInfo to identify server type + // spec: https://github.com/jhass/nodeinfo + try { + if (uri || domain) { + let urlBase = uri || `https://${domain}`; + const wellKnown = await ( + await fetch(`${urlBase}/.well-known/nodeinfo`) + ).json(); + if (Array.isArray(wellKnown?.links)) { + const nodeInfoUrl = wellKnown.links.find( + (link) => + typeof link.rel === 'string' && + link.rel.startsWith('http://nodeinfo.diaspora.software/ns/schema/'), + )?.href; + if (nodeInfoUrl && nodeInfoUrl.startsWith(urlBase)) { + nodeInfo = await (await fetch(nodeInfoUrl)).json(); + } + } + } + } catch (e) {} + const nodeInfos = store.local.getJSON('nodeInfos') || {}; + if (nodeInfo) { + nodeInfos[instance.toLowerCase()] = nodeInfo; + } + store.local.setJSON('nodeInfos', nodeInfos); + // This is a weird place to put this but here's updating the masto instance with the streaming API URL set in the configuration // Reason: Streaming WebSocket URL may change, unlike the standard API REST URLs const supportsWebSocket = 'WebSocket' in window; diff --git a/src/utils/store-utils.js b/src/utils/store-utils.js index 5f8fcd73..02fd38b2 100644 --- a/src/utils/store-utils.js +++ b/src/utils/store-utils.js @@ -115,6 +115,20 @@ export function getCurrentInstance() { } } +let currentNodeInfo = null; +export function getCurrentNodeInfo() { + if (currentNodeInfo) return currentNodeInfo; + try { + const account = getCurrentAccount(); + const nodeInfos = store.local.getJSON('nodeInfos') || {}; + const instanceURL = account.instanceURL.toLowerCase(); + return (currentNodeInfo = nodeInfos[instanceURL] || {}); + } catch (e) { + console.error(e); + return {}; + } +} + // Massage these instance configurations to match the Mastodon API // - Pleroma function getInstanceConfiguration(instance) { diff --git a/src/utils/supports.js b/src/utils/supports.js index 66454224..e240037a 100644 --- a/src/utils/supports.js +++ b/src/utils/supports.js @@ -2,13 +2,14 @@ import { satisfies } from 'compare-versions'; import features from '../data/features.json'; -import { getCurrentInstance } from './store-utils'; +import { getCurrentInstance, getCurrentNodeInfo } from './store-utils'; // Non-semver(?) UA string detection const containPixelfed = /pixelfed/i; const notContainPixelfed = /^(?!.*pixelfed).*$/i; const containPleroma = /pleroma/i; const containAkkoma = /akkoma/i; +const containGTS = /gotosocial/i; const platformFeatures = { '@mastodon/lists': notContainPixelfed, '@mastodon/filters': notContainPixelfed, @@ -25,11 +26,19 @@ const platformFeatures = { '@pleroma/local-visibility-post': containPleroma, '@akkoma/local-visibility-post': containAkkoma, }; + const supportsCache = {}; function supports(feature) { try { - const { version, domain } = getCurrentInstance(); + let { version, domain } = getCurrentInstance(); + let softwareName = getCurrentNodeInfo()?.software?.name || 'mastodon'; + + if (softwareName === 'hometown') { + // Hometown is a Mastodon fork and inherits its features + softwareName = 'mastodon'; + } + const key = `${domain}-${feature}`; if (supportsCache[key]) return supportsCache[key]; @@ -39,10 +48,17 @@ function supports(feature) { const range = features[feature]; if (!range) return false; - return (supportsCache[key] = satisfies(version, range, { - includePrerelease: true, - loose: true, - })); + + // '@mastodon/blah' => 'mastodon' + const featureSoftware = feature.match(/^@([a-z]+)\//)[1]; + + const doesSoftwareMatch = featureSoftware === softwareName.toLowerCase(); + return (supportsCache[key] = + doesSoftwareMatch && + satisfies(version, range, { + includePrerelease: true, + loose: true, + })); } catch (e) { return false; }