2026-03-17 16:54:31 +01:00
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<html lang="en">
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
|
|
|
|
<title>Pay2Play! — The Worst Music Player</title>
|
|
|
|
|
<meta name="description" content="Every feature costs money. Every button is a paywall. Welcome to Pay2Play!.">
|
|
|
|
|
<meta property="og:title" content="Pay2Play! — The Worst Music Player">
|
|
|
|
|
<meta property="og:description" content="A music player where pause costs $0.01, resume is a separate charge, and you only get 3 seconds free.">
|
|
|
|
|
<meta property="og:type" content="website">
|
2026-03-18 09:02:51 +01:00
|
|
|
<meta property="og:image" content="https://donothireus.com/pay2play/og-card.png">
|
2026-03-18 08:55:07 +01:00
|
|
|
<meta name="twitter:card" content="summary_large_image">
|
2026-03-18 09:02:51 +01:00
|
|
|
<meta name="twitter:image" content="https://donothireus.com/pay2play/og-card.png">
|
2026-03-17 16:54:31 +01:00
|
|
|
<meta name="twitter:title" content="Pay2Play! — The Worst Music Player">
|
|
|
|
|
<meta name="twitter:description" content="Every feature costs money. Even closing the app shows an unskippable ad.">
|
2026-03-18 09:06:36 +01:00
|
|
|
<link rel="icon" href="favicon.ico">
|
2026-03-17 16:54:31 +01:00
|
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
|
|
|
<link href="https://fonts.googleapis.com/css2?family=Anybody:wght@400;700;900&family=IBM+Plex+Mono:wght@400;600&display=swap" rel="stylesheet">
|
2026-03-18 09:16:20 +01:00
|
|
|
<link rel="stylesheet" id="app-css" href="style.css">
|
2026-03-18 09:09:39 +01:00
|
|
|
<!-- Privacy-friendly analytics by Plausible (proxied via /implausibly/) -->
|
2026-03-18 09:46:47 +01:00
|
|
|
<script async src="/implausibly/js/script.js"></script>
|
2026-03-18 09:09:39 +01:00
|
|
|
<script>
|
|
|
|
|
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
2026-03-18 09:46:47 +01:00
|
|
|
plausible.init({
|
|
|
|
|
endpoint: "/implausibly/api/event"
|
|
|
|
|
})
|
2026-03-18 09:09:39 +01:00
|
|
|
</script>
|
2026-03-17 16:54:31 +01:00
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
<div id="root"></div>
|
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.production.min.js"></script>
|
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.production.min.js"></script>
|
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.49/Tone.js"></script>
|
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.9/babel.min.js"></script>
|
2026-03-18 09:16:20 +01:00
|
|
|
<script>
|
|
|
|
|
// Cache-bust local assets using their Last-Modified header
|
|
|
|
|
(async () => {
|
|
|
|
|
const bust = async (url) => {
|
|
|
|
|
try {
|
|
|
|
|
const r = await fetch(url, { method: "HEAD" });
|
|
|
|
|
const lm = r.headers.get("Last-Modified");
|
|
|
|
|
return lm ? url + "?v=" + new Date(lm).getTime() : url;
|
|
|
|
|
} catch(e) { return url; }
|
|
|
|
|
};
|
|
|
|
|
document.getElementById("app-css").href = await bust("style.css");
|
|
|
|
|
const s = document.createElement("script");
|
|
|
|
|
s.type = "text/babel";
|
|
|
|
|
s.src = await bust("app.js");
|
|
|
|
|
s.setAttribute("data-type", "module");
|
|
|
|
|
document.body.appendChild(s);
|
|
|
|
|
Babel.transformScriptTags();
|
|
|
|
|
})();
|
|
|
|
|
</script>
|
2026-03-17 16:54:31 +01:00
|
|
|
</body>
|
|
|
|
|
</html>
|