fuck shit fuck fuck fuck fuck fuck
This commit is contained in:
parent
84868aba45
commit
ec7f9cf1a7
|
|
@ -38,6 +38,17 @@
|
|||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="Cool People | Clove Twilight">
|
||||
<meta name="twitter:description" content="Cool people Clove knows!">
|
||||
<style>
|
||||
.friends-disclaimer {
|
||||
margin: 2.5rem auto 0;
|
||||
max-width: 60ch;
|
||||
text-align: center;
|
||||
font-size: .8rem;
|
||||
line-height: 1.5;
|
||||
opacity: .6;
|
||||
}
|
||||
.friends-disclaimer a { color: inherit; text-decoration: underline; }
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
|
@ -64,6 +75,12 @@
|
|||
|
||||
<!-- Cards are rendered by friends.js from the FRIENDS config -->
|
||||
<div id="friends-root"></div>
|
||||
|
||||
<p class="friends-disclaimer">
|
||||
Presence data is served by
|
||||
<a href="https://restful.doughmination.uk" target="_blank" rel="noopener">Doughmination Restful</a>
|
||||
by default, falling back to Lanyard and Dustin’s API.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<script src="/js/core.js" data-cat="/assets/oneko/classics/classic.png"></script>
|
||||
|
|
|
|||
100
js/discord.js
100
js/discord.js
|
|
@ -648,8 +648,108 @@
|
|||
ws.addEventListener("error", () => { try { ws.close(); } catch (e) {} });
|
||||
}
|
||||
|
||||
// ---- data source: self-hosted API primary, Lanyard + dstn fallback ------
|
||||
// The Doughmination Restful API returns presence + full profile in one call,
|
||||
// so it drives the card on its own. We poll it; only if it can't serve us
|
||||
// (network error, or no live presence) do we fail over to the Lanyard
|
||||
// websocket + dstn.to, the same chain the friends grid uses.
|
||||
const SELF_BASE = "https://restful.doughmination.uk/v1/users/";
|
||||
const SELF_POLL_MS = 20000; // own-presence refresh cadence
|
||||
const SELF_GIVE_UP = 3; // consecutive misses before failing over
|
||||
let selfTimer = null;
|
||||
let selfMisses = 0;
|
||||
let lanyardActive = false;
|
||||
|
||||
// self-host shape -> the Lanyard-shaped object render() already understands
|
||||
function mapSelfHostToLanyard(j) {
|
||||
const u = (j.data && j.data.user) || {};
|
||||
const p = (j.data && j.data.presence) || {};
|
||||
const plat = p.platform || {};
|
||||
const dec = u.avatar_decoration;
|
||||
const clan = u.clan;
|
||||
return {
|
||||
discord_user: {
|
||||
id: u.id || DISCORD_USER_ID,
|
||||
username: u.username,
|
||||
global_name: u.global_name,
|
||||
display_name: u.display_name,
|
||||
avatar: u.avatar,
|
||||
avatar_decoration_data: (dec && dec.asset) ? { asset: dec.asset } : null,
|
||||
primary_guild: (clan && clan.tag)
|
||||
? { tag: clan.tag, identity_enabled: true, badge: clan.badge, identity_guild_id: clan.guild_id }
|
||||
: null,
|
||||
public_flags: 0
|
||||
},
|
||||
discord_status: p.status || (p.online ? "online" : "offline"),
|
||||
activities: p.activities || [],
|
||||
listening_to_spotify: !!p.listening_to_spotify,
|
||||
spotify: p.spotify || null,
|
||||
active_on_discord_desktop: !!plat.desktop,
|
||||
active_on_discord_mobile: !!plat.mobile,
|
||||
active_on_discord_web: !!plat.web,
|
||||
kv: {}
|
||||
};
|
||||
}
|
||||
|
||||
function renderFromSelfHost(j) {
|
||||
const u = (j.data && j.data.user) || {};
|
||||
render(mapSelfHostToLanyard(j));
|
||||
// badges arrive pre-resolved (same consumer as dstn badges)
|
||||
if (Array.isArray(j.data.badges) && j.data.badges.length) {
|
||||
dstnBadges = j.data.badges;
|
||||
paintBadges();
|
||||
}
|
||||
// profile extras: banner rebuilt from the raw hash (dodges the animated
|
||||
// .gif 415), plus bio / connections / pronouns straight from the API
|
||||
applyBanner(
|
||||
bannerUrl(u.id || DISCORD_USER_ID, u.banner),
|
||||
(typeof u.accent_color === "number") ? intToHex(u.accent_color) : null
|
||||
);
|
||||
renderBio(u.bio);
|
||||
renderConnections(j.data.connected_accounts);
|
||||
if (pronounsEl) {
|
||||
if (u.pronouns) { pronounsEl.textContent = u.pronouns; pronounsEl.hidden = false; }
|
||||
else pronounsEl.hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
function loadSelfHosted() {
|
||||
return fetch(SELF_BASE + DISCORD_USER_ID, { cache: "no-store" })
|
||||
.then(function (r) { return r.ok ? r.json().catch(function () { return null; }) : null; })
|
||||
.then(function (j) {
|
||||
// need a live presence object to drive the card; else fall back
|
||||
if (!j || !j.success || !j.data || !j.data.user || !j.data.presence) return false;
|
||||
renderFromSelfHost(j);
|
||||
return true;
|
||||
})
|
||||
.catch(function () { return false; });
|
||||
}
|
||||
|
||||
function startLanyardFallback() {
|
||||
if (lanyardActive) return;
|
||||
lanyardActive = true;
|
||||
if (selfTimer) { clearInterval(selfTimer); selfTimer = null; }
|
||||
connect();
|
||||
loadDstn();
|
||||
}
|
||||
|
||||
function pollSelfHost() {
|
||||
if (document.hidden) return;
|
||||
loadSelfHosted().then(function (ok) {
|
||||
if (ok) { selfMisses = 0; return; }
|
||||
if (++selfMisses >= SELF_GIVE_UP) startLanyardFallback();
|
||||
});
|
||||
}
|
||||
|
||||
// boot: Doughmination first; Lanyard/dstn only if it can't serve us
|
||||
loadSelfHosted().then(function (ok) {
|
||||
if (ok) {
|
||||
selfMisses = 0;
|
||||
selfTimer = setInterval(pollSelfHost, SELF_POLL_MS);
|
||||
} else {
|
||||
startLanyardFallback();
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("visibilitychange", () => {
|
||||
if (!document.hidden && latest) updateTimes();
|
||||
|
|
|
|||
|
|
@ -419,8 +419,9 @@
|
|||
group.members.forEach(function (m) {
|
||||
var refs = buildCard(m);
|
||||
grid.appendChild(refs.el);
|
||||
// dead alts are banned/retired — never pull live data for them
|
||||
if (m.discordId && m.tier !== "dead-alt") {
|
||||
// poll anyone with an ID — even "dead" alts can be semi-alive. Accounts
|
||||
// that 404 everywhere are dropped automatically by the give-up logic.
|
||||
if (m.discordId) {
|
||||
var entry = { m: m, refs: refs, misses: 0, stop: false };
|
||||
liveMembers.push(entry);
|
||||
pollEntry(entry);
|
||||
|
|
|
|||
Loading…
Reference in New Issue