audio streaming app plyr.fm

fix: add proper privacy intro, MIT license, and email fallbacks (#764)

privacy policy:
- add smokesignal-style intro explaining what plyr.fm is
- reference canonical URL (https://plyr.fm)
- note open source under MIT, other instances not covered
- add email fallbacks so contact info always displays

terms:
- add email fallbacks for DMCA and contact sections

also:
- add MIT LICENSE file to repo root

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>

authored by zzstoatzz.io

Claude Opus 4.5 and committed by
GitHub
dd01503f 3dc4f98a

+55 -6
+21
LICENSE
··· 1 + MIT License 2 + 3 + Copyright (c) 2025 Nathan Nowack 4 + 5 + Permission is hereby granted, free of charge, to any person obtaining a copy 6 + of this software and associated documentation files (the "Software"), to deal 7 + in the Software without restriction, including without limitation the rights 8 + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 + copies of the Software, and to permit persons to whom the Software is 10 + furnished to do so, subject to the following conditions: 11 + 12 + The above copyright notice and this permission notice shall be included in all 13 + copies or substantial portions of the Software. 14 + 15 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 + SOFTWARE.
+27 -4
frontend/src/routes/privacy/+page.svelte
··· 1 1 <script lang="ts"> 2 - import { APP_NAME } from '$lib/branding'; 2 + import { APP_NAME, APP_CANONICAL_URL } from '$lib/branding'; 3 3 import type { PageData } from './$types'; 4 + 5 + const FALLBACK_EMAIL = 'plyrdotfm@proton.me'; 4 6 5 7 let { data } = $props<{ data: PageData }>(); 8 + 9 + const privacyEmail = data.privacyEmail || FALLBACK_EMAIL; 10 + const contactEmail = data.contactEmail || FALLBACK_EMAIL; 6 11 </script> 7 12 8 13 <svelte:head> ··· 16 21 <p class="last-updated">last updated: january 19, 2026</p> 17 22 18 23 <p class="intro"> 19 - this policy explains what data we collect, what's public by design on the AT Protocol, 24 + {APP_NAME} ("we", "us", or "our") is a music streaming application built on the 25 + <a href="https://atproto.com" target="_blank" rel="noopener">AT Protocol</a>. 26 + this privacy policy applies to the instance at 27 + <a href={APP_CANONICAL_URL}>{APP_CANONICAL_URL}</a> (the "site"). 28 + </p> 29 + 30 + <p class="intro"> 31 + {APP_NAME} is open source under the MIT license. other instances or derivatives 32 + hosted elsewhere are not covered by this policy. 33 + </p> 34 + 35 + <p class="intro-secondary"> 36 + this policy explains what data we collect, what's public by design on ATProto, 20 37 and your rights. 21 38 </p> 22 39 ··· 84 101 <h2>6. security</h2> 85 102 <p>we use HTTPS, encrypt sensitive data, and use HttpOnly cookies. no system is 86 103 perfectly secure—report vulnerabilities to 87 - <a href="mailto:{data.contactEmail}">{data.contactEmail}</a>.</p> 104 + <a href="mailto:{contactEmail}">{contactEmail}</a>.</p> 88 105 </section> 89 106 90 107 <section> ··· 101 118 <section class="contact"> 102 119 <h2>contact</h2> 103 120 <p> 104 - questions? <a href="mailto:{data.privacyEmail}">{data.privacyEmail}</a> 121 + questions? <a href="mailto:{privacyEmail}">{privacyEmail}</a> 105 122 </p> 106 123 </section> 107 124 ··· 135 152 } 136 153 137 154 .intro { 155 + font-size: 1.05rem; 156 + color: var(--text-secondary); 157 + margin-bottom: 1rem; 158 + } 159 + 160 + .intro-secondary { 138 161 font-size: 1.05rem; 139 162 color: var(--text-secondary); 140 163 margin-bottom: 2rem;
+7 -2
frontend/src/routes/terms/+page.svelte
··· 2 2 import { APP_NAME } from '$lib/branding'; 3 3 import type { PageData } from './$types'; 4 4 5 + const FALLBACK_EMAIL = 'plyrdotfm@proton.me'; 6 + 5 7 let { data } = $props<{ data: PageData }>(); 8 + 9 + const contactEmail = data.contactEmail || FALLBACK_EMAIL; 10 + const dmcaEmail = data.dmcaEmail || FALLBACK_EMAIL; 6 11 </script> 7 12 8 13 <svelte:head> ··· 72 77 <address class="dmca-agent"> 73 78 Nathan Nowack<br /> 74 79 DMCA Registration: {data.dmcaRegistrationNumber}<br /> 75 - Email: <a href="mailto:{data.dmcaEmail}">{data.dmcaEmail}</a> 80 + Email: <a href="mailto:{dmcaEmail}">{dmcaEmail}</a> 76 81 </address> 77 82 <p>we terminate accounts of repeat infringers.</p> 78 83 <p> ··· 106 111 <section class="contact"> 107 112 <h2>contact</h2> 108 113 <p> 109 - questions? <a href="mailto:{data.contactEmail}">{data.contactEmail}</a> 114 + questions? <a href="mailto:{contactEmail}">{contactEmail}</a> 110 115 </p> 111 116 </section> 112 117