Skip to content

Commit

Permalink
Merge pull request #817 from graue/feature-detect
Browse files Browse the repository at this point in the history
Support exclusive lists with GoToSocial 0.17
  • Loading branch information
cheeaun authored Nov 12, 2024
2 parents 62dc2ca + 7b926f7 commit b70e31a
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 22 deletions.
4 changes: 3 additions & 1 deletion src/components/list-add-edit.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<div class="sheet">
Expand Down
1 change: 1 addition & 0 deletions src/data/features.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
30 changes: 15 additions & 15 deletions src/locales/en.po

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 29 additions & 0 deletions src/utils/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -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[
Expand All @@ -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;
Expand Down
14 changes: 14 additions & 0 deletions src/utils/store-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
28 changes: 22 additions & 6 deletions src/utils/supports.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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];

Expand All @@ -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;
}
Expand Down

0 comments on commit b70e31a

Please sign in to comment.