Compare commits

...

6 Commits

116 changed files with 203 additions and 17767 deletions
+27
View File
@@ -11,6 +11,8 @@ jobs:
permissions:
contents: write
packages: write
id-token: write
attestations: write
steps:
- name: Checkout code
uses: actions/checkout@v4
@@ -35,6 +37,7 @@ jobs:
type=ref,event=tag
- name: Build and push Docker image
id: build
uses: docker/build-push-action@v5
with:
context: .
@@ -44,10 +47,19 @@ jobs:
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- name: Generate artifact attestation
uses: actions/attest@v4
with:
subject-name: ghcr.io/${{ github.repository }}
subject-digest: ${{ steps.build.outputs.digest }}
push-to-registry: true
release-extension:
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
attestations: write
steps:
- name: Checkout code
uses: actions/checkout@v4
@@ -103,6 +115,21 @@ jobs:
npm install
npm run build:extension
- name: Generate artifact attestation for extensions
uses: actions/attest@v4
with:
subject-path: dist/koalasync-*.zip
- name: Build Website
run: node website/build.js
- name: Upload Website Artifacts
uses: actions/upload-artifact@v4
with:
name: website-www
path: website/www/
if-no-files-found: error
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
+3
View File
@@ -40,5 +40,8 @@ coverage/
# the root 'shared/' remains the Single Source of Truth.
extension/shared/
# Auto-generated website build output
website/www/
# Temporary scratch files
scratch/
+23 -7
View File
@@ -14,7 +14,7 @@
<p align="center"><i>KoalaSync is a lightweight Browser Extension and Relay Server for synchronized video playback on almost any website with a video element—YouTube, Twitch, Netflix, Emby, Jellyfin, and beyond. Built with a focus on <b>Data Sovereignty</b> and <b>Performance</b>.</i></p>
<p align="center"><a href="docs/CHANGELOG.md"><b>New v2.2.1 Release!</b> — See what's changed</a></p>
<p align="center"><a href="docs/CHANGELOG.md"><b>New v2.2.2 Release!</b> — See what's changed</a></p>
### 🌟 Why KoalaSync?
@@ -54,6 +54,16 @@ The easiest and safest way to install KoalaSync is directly through the official
2. **Invite Friends:** Share the auto-copied invite link. Once they click it, they automatically join.
3. **Pick a Video:** Navigate to the Sync Tab, select the tab playing your video, and grab some popcorn! 🍿
---
### 🌐 Localization & Translations
Both the official KoalaSync website and the **v2.0 Browser Extension** feature full dynamic localization:
- **Available Languages**: Support is included for 13 languages: English (`en`), German (`de`), French (`fr`), Spanish (`es`), Portuguese (Brazil) (`pt-BR`), Russian (`ru`), Italian (`it`), Polish (`pl`), Turkish (`tr`), Dutch (`nl`), Japanese (`ja`), Korean (`ko`), and European Portuguese (`pt`).
- **Real-Time Extension Localization**: Inside the extension Settings panel, users can swap languages instantly. The entire interface, notifications, Empty States, and onboarding guides re-translate dynamically in real-time.
- **Contributing**: We welcome community translations for both the website and the extension! Please refer directly to the [TRANSLATION.md](website/TRANSLATION.md) guide for step-by-step instructions on how to audit, refine, or add new languages.
---
### 🛠️ For Developers & Self-Hosters
@@ -93,15 +103,21 @@ To connect your extension to a self-hosted server, open the popup → **Room** t
To verify your relay is reachable from outside, visit `https://your-domain.com` in a browser — it should return `{"status":"online","service":"KoalaSync Relay"}`.
---
#### Supply Chain Security (v2.2.2+)
### 🌐 Localization & Translations
All official release artifacts (Docker images and extension binaries) are published with signed [artifact attestations](https://docs.github.com/en/actions/how-tos/secure-your-work/use-artifact-attestations) to prove they were built from this repository's source code.
Both the official KoalaSync website and the **v2.0 Browser Extension** feature full dynamic localization:
- **Available Languages**: Support is included for 13 languages: English (`en`), German (`de`), French (`fr`), Spanish (`es`), Portuguese (Brazil) (`pt-BR`), Russian (`ru`), Italian (`it`), Polish (`pl`), Turkish (`tr`), Dutch (`nl`), Japanese (`ja`), Korean (`ko`), and European Portuguese (`pt`).
- **Real-Time Extension Localization**: Inside the extension Settings panel, users can swap languages instantly. The entire interface, notifications, Empty States, and onboarding guides re-translate dynamically in real-time.
- **Contributing**: We welcome community translations for both the website and the extension! Please refer directly to the [TRANSLATION.md](website/TRANSLATION.md) guide for step-by-step instructions on how to audit, refine, or add new languages.
**Verify a Docker image:**
```bash
gh attestation verify oci://ghcr.io/shik3i/koalasync:latest \
-R Shik3i/KoalaSync
```
**Verify an extension binary:**
```bash
gh attestation verify dist/koalasync-chrome.zip \
-R Shik3i/KoalaSync
```
---
+25
View File
@@ -4,6 +4,31 @@ All notable changes to the KoalaSync browser extension and relay server.
---
## [v2.2.3] — 2026-06-10
### Added
- **Artifact Attestations (Supply Chain Security)**: All release artifacts (Docker images, extension ZIPs) are now published with signed [SLSA provenance attestations](https://docs.github.com/en/actions/how-tos/secure-your-work/use-artifact-attestations) via `actions/attest@v4`. Anyone can verify that an artifact was built from this repository using `gh attestation verify`.
- **Admin health: `rateLimits.denied` counters**: New rolling counters track actual rate-limit denials (429 responses), separate from `rateLimits.trackedClients` which reports unique IPs in the tracking window.
- **Docker HEALTHCHECK**: Container health is now checked every 30s via `GET /health`.
- **`npm start` script**: Server can now be started with `npm start`.
### Fixed
- **Server: `activeLobby` no longer silently overwritten**: If a second peer sends `EPISODE_LOBBY` while a lobby is already active, the request is now ignored instead of destroying the first peer's lobby.
- **CORS log sanitization**: Rejected origin headers are sanitized (`\r\n` stripped) to prevent log injection.
- **Extension: pagehide resource leak**: `keepAlivePort`, `lobbyPollTimer`, heartbeats, and `MutationObserver` are now properly cleaned up when a tab is hidden or enters bfcache.
- **Extension: unhandled storage rejections**: `chrome.storage.session.set()` calls in the disconnect handler now have `.catch(() => {})`.
- **`'Pixel'` duplicate in name generator**: Second occurrence replaced with `'Nitro'` for better name diversity.
- **`'opposum'` typo**: Corrected to `'opossum'` in the emoji map and added `'Opossum'` to `USERNAME_NOUNS`.
- **Test reliability**: `test-server-routes.mjs` now sets `ADMIN_METRICS_TOKEN` before importing the server module, fixing standalone test execution.
- **`MAX_PEERS_PER_ROOM` konsistent**: `.env` auf 25 gesetzt (wie `.env.example`).
- **pt-BR.json duplicate removed**: Duplicate `FOOTER_DISCLAIMER` key removed from website locale.
### Changed
- **Admin health: `rateLimitEntries` renamed to `rateLimits.trackedClients`**: The field now accurately describes that it tracks unique clients in the rate-limit window, not denial counts. Update your json_exporter/Grafana config accordingly.
- **README restructured**: Sections reordered by progressive technical depth. New "Supply Chain Security" subsection under "For Developers & Self-Hosters" with verification commands.
---
## [v2.2.2] — 2026-06-09
### Added
+37 -12
View File
@@ -54,26 +54,51 @@ modules:
path: '{.memory.heapTotal}'
help: "V8 engine heap total in bytes"
# Rate limiter tracking — unique clients currently in each tracking window
# (not rate-limit denials; these include legitimate traffic too)
- name: koalasync_rate_limit_connections
path: '{.rateLimitEntries.connections}'
help: "Number of entries tracked in the connection rate limiter"
path: '{.rateLimits.trackedClients.connections}'
help: "Unique clients tracked in the connection rate limiter window"
- name: koalasync_rate_limit_events
path: '{.rateLimitEntries.events}'
help: "Number of entries in the event rate limiter"
path: '{.rateLimits.trackedClients.events}'
help: "Unique sockets tracked in the event rate limiter window"
- name: koalasync_rate_limit_health
path: '{.rateLimitEntries.health}'
help: "Number of entries in the health rate limiter"
path: '{.rateLimits.trackedClients.health}'
help: "Unique IPs tracked in the health endpoint rate limiter window"
- name: koalasync_rate_limit_admin_metrics_auth
path: '{.rateLimitEntries.adminMetricsAuth}'
help: "Number of entries in the admin metrics auth rate limiter"
path: '{.rateLimits.trackedClients.adminMetricsAuth}'
help: "Unique IPs tracked in the admin metrics auth rate limiter window"
- name: koalasync_rate_limit_auth_failures
path: '{.rateLimitEntries.authFailures}'
help: "Number of entries in the authentication failures cache"
path: '{.rateLimits.trackedClients.authFailures}'
help: "Unique IPs tracked in the authentication failures cache"
- name: koalasync_rate_limit_room_list
path: '{.rateLimitEntries.roomList}'
help: "Number of entries in the room list cooldown cache"
path: '{.rateLimits.trackedClients.roomList}'
help: "Unique sockets in the room list cooldown cache"
# Actual rate-limit denials — incremented only when a 429 is served
- name: koalasync_rate_limit_denied_connections
path: '{.rateLimits.denied.connections}'
help: "Total connection attempts denied by rate limiter"
- name: koalasync_rate_limit_denied_events
path: '{.rateLimits.denied.events}'
help: "Total socket events denied by rate limiter"
- name: koalasync_rate_limit_denied_health
path: '{.rateLimits.denied.health}'
help: "Total health endpoint requests denied by rate limiter"
- name: koalasync_rate_limit_denied_admin_metrics_auth
path: '{.rateLimits.denied.adminMetricsAuth}'
help: "Total admin metrics auth attempts denied by rate limiter"
- name: koalasync_rate_limit_denied_room_list
path: '{.rateLimits.denied.roomList}'
help: "Total room list refresh requests denied by rate limiter"
+2 -2
View File
@@ -544,12 +544,12 @@ async function connect() {
isForceSyncInitiator: false,
forceSyncAcks: [],
forceSyncDeadline: null
});
}).catch(() => {});
if (currentRoom) {
currentRoom.peers = [];
if (storageInitialized) chrome.storage.session.set({ currentRoom });
if (storageInitialized) chrome.storage.session.set({ currentRoom }).catch(() => {});
chrome.runtime.sendMessage({ type: 'PEER_UPDATE', peers: [] }).catch(() => {});
}
broadcastConnectionStatus('disconnected');
+5
View File
@@ -837,6 +837,11 @@
window.addEventListener('pagehide', () => {
pageVisible = false;
closeAudioContext();
if (keepAlivePort) { try { keepAlivePort.disconnect(); } catch (_e) { /* ignore */ } keepAlivePort = null; }
if (lobbyPollTimer) { clearInterval(lobbyPollTimer); lobbyPollTimer = null; }
if (heartbeatTimeout) { clearTimeout(heartbeatTimeout); heartbeatTimeout = null; }
if (proactiveHeartbeatTimeout) { clearTimeout(proactiveHeartbeatTimeout); proactiveHeartbeatTimeout = null; }
observer.disconnect();
});
window.addEventListener('pageshow', (event) => {
// event.persisted is true ONLY when restored from bfcache, not on initial load
+1 -1
View File
@@ -2,7 +2,7 @@
"manifest_version": 3,
"default_locale": "en",
"name": "KoalaSync",
"version": "2.2.1",
"version": "2.2.2",
"description": "Synchronize video playback on YouTube, Netflix, Emby, Jellyfin, and any HTML5 site in real-time with friends.",
"permissions": [
"storage",
+5 -2
View File
@@ -1,12 +1,12 @@
{
"name": "koalasync",
"version": "2.1.3",
"version": "2.2.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "koalasync",
"version": "2.1.3",
"version": "2.2.2",
"devDependencies": {
"archiver": "^7.0.1",
"esbuild": "^0.28.0",
@@ -1240,6 +1240,7 @@
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -1373,6 +1374,7 @@
"integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
"peerDependencies": {
"bare-abort-controller": "*"
},
@@ -1895,6 +1897,7 @@
"integrity": "sha512-loXy6bWOoP3EP6JA7jo6p5jMpBJmHmsNZM5SFRHLdh1MGOPurMnNBj4ZlAbaqUAaQWbCr7jHV4P7gzAyryZWkQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.2",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "koalasync",
"version": "2.2.1",
"version": "2.2.2",
"description": "KoalaSync Build Scripts",
"private": true,
"scripts": {
+6 -3
View File
@@ -77,9 +77,12 @@ assert.equal(adminHealth.avgPeersPerRoom, 2.5, 'admin metrics should include ave
assert.equal(adminHealth.maxPeersInRoom, 3, 'admin metrics should include max room size');
assert.deepEqual(adminHealth.memory, { rss: 10, heapUsed: 5, heapTotal: 8 }, 'admin metrics should expose process memory');
assert.deepEqual(
adminHealth.rateLimitEntries,
{ connections: 1, events: 2, health: 3, adminMetricsAuth: 4, authFailures: 5, roomList: 6 },
'admin metrics should expose aggregate rate-limit map sizes'
adminHealth.rateLimits,
{
trackedClients: { connections: 1, events: 2, health: 3, adminMetricsAuth: 4, authFailures: 5, roomList: 6 },
denied: { connections: 0, events: 0, health: 0, adminMetricsAuth: 0, roomList: 0 }
},
'admin metrics should expose rate-limit tracking and denial counts'
);
console.log('server ops tests passed');
+6 -3
View File
@@ -1,5 +1,8 @@
import assert from 'node:assert/strict';
import {
// Must set env before dynamic import — ESM hoists static imports
process.env.ADMIN_METRICS_TOKEN = process.env.ADMIN_METRICS_TOKEN || 'test-admin-token-with-more-than-32-chars';
const {
ADMIN_METRICS_AUTH_RATE_LIMIT_PER_MINUTE,
HEALTH_RATE_LIMIT_PER_MINUTE,
healthCounts,
@@ -9,9 +12,9 @@ import {
rooms,
startServer,
stopServerForTests
} from '../server/index.js';
} = await import('../server/index.js');
const adminToken = process.env.ADMIN_METRICS_TOKEN || 'test-admin-token-with-more-than-32-chars';
const adminToken = process.env.ADMIN_METRICS_TOKEN;
const baseHeaders = { 'x-forwarded-for': '203.0.113.10' };
function url(path) {
+3
View File
@@ -10,4 +10,7 @@ RUN cd server && npm install --production
COPY server/ ./server/
WORKDIR /app/server
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
CMD ["node", "index.js"]
+26 -7
View File
@@ -82,7 +82,8 @@ app.get('/health', (req, res) => {
adminMetricsAuth: adminMetricsAuthCounts.size,
authFailures: failedAuthAttempts.size,
roomList: roomListCooldowns.size
}
},
rateLimitDenied
})
));
});
@@ -96,7 +97,7 @@ export const io = new Server(httpServer, {
if (!origin || origin === 'https://sync.koalastuff.net' || origin.startsWith('chrome-extension://') || origin.startsWith('moz-extension://')) {
callback(null, true);
} else {
log('CORS', `Rejected origin: ${origin}`);
log('CORS', `Rejected origin: ${(origin || '').replace(/[\r\n]/g, '')}`);
callback(new Error('Not allowed by CORS'));
}
},
@@ -192,6 +193,15 @@ export const healthCounts = new Map(); // ip -> { count, resetTime }
export const adminMetricsAuthCounts = new Map(); // ip -> { count, resetTime }
const roomListCooldowns = new Map(); // socketId -> last allowed timestamp
// Actual rate-limit denial counters (incremented only when a request is denied)
const rateLimitDenied = {
connections: 0,
events: 0,
health: 0,
adminMetricsAuth: 0,
roomList: 0
};
// Clean up connection counts and event counts to prevent memory leak
const rateLimitCleanupInterval = setInterval(() => {
const now = Date.now();
@@ -228,7 +238,9 @@ function checkConnectionRate(ip) {
if (now > entry.resetTime) { entry.count = 0; entry.resetTime = now + 60000; }
entry.count++;
connectionCounts.set(ip, entry);
return entry.count <= 10;
if (entry.count <= 10) return true;
rateLimitDenied.connections++;
return false;
}
function checkEventRate(socketId) {
@@ -237,7 +249,9 @@ function checkEventRate(socketId) {
if (now > entry.resetTime) { entry.count = 0; entry.resetTime = now + 10000; }
entry.count++;
eventCounts.set(socketId, entry);
return entry.count <= 30;
if (entry.count <= 30) return true;
rateLimitDenied.events++;
return false;
}
function checkHealthRate(ip) {
@@ -246,7 +260,9 @@ function checkHealthRate(ip) {
if (now > entry.resetTime) { entry.count = 0; entry.resetTime = now + 60000; }
entry.count++;
healthCounts.set(ip, entry);
return entry.count <= HEALTH_RATE_LIMIT_PER_MINUTE;
if (entry.count <= HEALTH_RATE_LIMIT_PER_MINUTE) return true;
rateLimitDenied.health++;
return false;
}
function checkAdminMetricsAuthRate(ip) {
@@ -255,7 +271,9 @@ function checkAdminMetricsAuthRate(ip) {
if (now > entry.resetTime) { entry.count = 0; entry.resetTime = now + 60000; }
entry.count++;
adminMetricsAuthCounts.set(ip, entry);
return entry.count <= ADMIN_METRICS_AUTH_RATE_LIMIT_PER_MINUTE;
if (entry.count <= ADMIN_METRICS_AUTH_RATE_LIMIT_PER_MINUTE) return true;
rateLimitDenied.adminMetricsAuth++;
return false;
}
/**
@@ -585,7 +603,7 @@ io.on('connection', (socket) => {
socket.to(mapping.roomId).emit(eventName, relayPayload);
// --- Side-effects: Server-side Episode Lobby Tracking ---
if (eventName === EVENTS.EPISODE_LOBBY && relayPayload.expectedTitle) {
if (eventName === EVENTS.EPISODE_LOBBY && relayPayload.expectedTitle && !room.activeLobby) {
room.activeLobby = {
expectedTitle: relayPayload.expectedTitle,
initiatorPeerId: mapping.peerId,
@@ -613,6 +631,7 @@ io.on('connection', (socket) => {
return;
}
if (!checkCooldown(roomListCooldowns, socket.id, ROOM_LIST_COOLDOWN_MS)) {
rateLimitDenied.roomList++;
socket.emit(EVENTS.ERROR, { message: 'Room list refresh is rate limited. Try again in a few seconds.' });
return;
}
+18 -8
View File
@@ -48,7 +48,8 @@ export function buildHealthPayload({
now = Date.now(),
uptime = 0,
memoryUsage = () => process.memoryUsage(),
rateLimitSizes = {}
rateLimitSizes = {},
rateLimitDenied = {}
}) {
const payload = {
status: 'ok',
@@ -75,13 +76,22 @@ export function buildHealthPayload({
roomsWithLobby: roomValues.filter(room => !!room.activeLobby).length,
avgPeersPerRoom,
maxPeersInRoom,
rateLimitEntries: {
connections: rateLimitSizes.connections || 0,
events: rateLimitSizes.events || 0,
health: rateLimitSizes.health || 0,
adminMetricsAuth: rateLimitSizes.adminMetricsAuth || 0,
authFailures: rateLimitSizes.authFailures || 0,
roomList: rateLimitSizes.roomList || 0
rateLimits: {
trackedClients: {
connections: rateLimitSizes.connections || 0,
events: rateLimitSizes.events || 0,
health: rateLimitSizes.health || 0,
adminMetricsAuth: rateLimitSizes.adminMetricsAuth || 0,
authFailures: rateLimitSizes.authFailures || 0,
roomList: rateLimitSizes.roomList || 0
},
denied: {
connections: rateLimitDenied.connections || 0,
events: rateLimitDenied.events || 0,
health: rateLimitDenied.health || 0,
adminMetricsAuth: rateLimitDenied.adminMetricsAuth || 0,
roomList: rateLimitDenied.roomList || 0
}
},
memory: {
rss: mem.rss,
+1
View File
@@ -4,6 +4,7 @@
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
+3 -3
View File
@@ -21,7 +21,7 @@ export const USERNAME_ADJECTIVES = [
'Cosmic', 'Neon', 'Shadow', 'Crystal', 'Thunder', 'Silent', 'Golden',
'Fierce', 'Noble', 'Mystic', 'Frozen', 'Blazing', 'Sapphire', 'Iron', 'Crimson',
'Turbo', 'Zen', 'Pixel', 'Cyber', 'Solar', 'Lunar', 'Astro', 'Hyper',
'Steel', 'Rogue', 'Alpha', 'Omega', 'Royal', 'Pixel', 'Warp', 'Frost',
'Steel', 'Rogue', 'Alpha', 'Omega', 'Royal', 'Nitro', 'Warp', 'Frost',
];
export const USERNAME_NOUNS = [
@@ -39,7 +39,7 @@ export const USERNAME_NOUNS = [
'Mouse', 'Pig', 'Boar', 'Polar', 'Orangutan', 'Mammoth',
'Crow', 'Duck', 'Swan', 'Penguin', 'Parrot', 'Peacock',
'Dove', 'Dodo', 'Turkey', 'Flamingo', 'Chicken', 'Rooster', 'Goose',
'Dolphin', 'Whale', 'Crab', 'Lobster', 'Octopus', 'Squid',
'Dolphin', 'Whale', 'Crab', 'Lobster', 'Octopus', 'Opossum', 'Squid',
'Jellyfish', 'Turtle',
'Crocodile', 'Lizard', 'Snake', 'Frog', 'Toad', 'Gecko',
'Bee', 'Ant', 'Spider', 'Scorpion', 'Butterfly', 'Ladybug',
@@ -102,7 +102,7 @@ export const ANIMAL_EMOJI_MAP = {
'mammoth': '🦣',
'meerkat': '🦦',
'octopus': '🐙',
'opposum': '🐭',
'opossum': '🐭',
'ostrich': '🐦',
'panther': '🐆',
'pelican': '🦩',
+8
View File
@@ -241,6 +241,14 @@ async function compile() {
console.log(' Assets copied.');
}
// Copy apple-touch-icon to www root (browsers/iOS request these at /)
const appleTouchSrc = path.join(destAssets, 'apple-touch-icon.png');
if (fs.existsSync(appleTouchSrc)) {
fs.copyFileSync(appleTouchSrc, path.join(wwwDir, 'apple-touch-icon.png'));
fs.copyFileSync(appleTouchSrc, path.join(wwwDir, 'apple-touch-icon-precomposed.png'));
console.log(' ✓ Apple touch icons copied to www root.');
}
// ── 7. Convert all WebP to AVIF (quality 70) ──
console.log('Converting WebP → AVIF...');
let avifCount = 0;
-1
View File
@@ -175,6 +175,5 @@
"FOOTER_LEGAL_LINK": "imprint",
"FOOTER_PRIVACY_LINK": "privacy",
"FOOTER_DISCLAIMER": "KoalaSync não é afiliado, endossado ou associado à Netflix, Disney+, Amazon, YouTube, Twitch ou qualquer outra plataforma de streaming. Todas as marcas registradas são propriedade de seus respectivos titulares.",
"FOOTER_DISCLAIMER": "KoalaSync não é afiliado, endossado ou associado à Netflix, Disney+, Amazon, YouTube, Twitch ou qualquer outra plataforma de streaming. Todas as marcas registradas são propriedade de seus respectivos titulares.",
"FOOTER_SUPPORT": "Me pague um café no Ko-Fi"
}
+1 -1
View File
@@ -102,7 +102,7 @@
"priceCurrency": "EUR"
},
"description": "Watch Netflix, YouTube, Twitch, Jellyfin, Emby and almost any HTML5 video in perfect sync with friends. Open source, privacy-first, free.",
"softwareVersion": "2.2.1",
"softwareVersion": "2.2.2",
"license": "https://opensource.org/licenses/MIT",
"sameAs": "https://github.com/Shik3i/KoalaSync",
"image": "https://sync.koalastuff.net/assets/NewLogoIcon.webp",
+2 -2
View File
@@ -1,4 +1,4 @@
{
"version": "2.2.1",
"date": "2026-06-09T05:08:31Z"
"version": "2.2.2",
"date": "2026-06-09T19:16:14Z"
}
-8
View File
@@ -1,8 +0,0 @@
# Auto-Generated Output — Do Not Edit
This directory is **fully auto-generated** by `node website/build.js`.
- Edit source files in `../` (`template.html`, `style.css`, `app.js`, `lang-init.js`, `locales/*.json`)
- Run `node website/build.js` to regenerate
Never edit files here directly — changes will be lost on the next build.
-59
View File
File diff suppressed because one or more lines are too long
Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

-1
View File
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 48 48" height="48" width="48"><defs><linearGradient id="a" x1="3.2173" y1="15" x2="44.7812" y2="15" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#d93025"/><stop offset="1" stop-color="#ea4335"/></linearGradient><linearGradient id="b" x1="20.7219" y1="47.6791" x2="41.5039" y2="11.6837" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fcc934"/><stop offset="1" stop-color="#fbbc04"/></linearGradient><linearGradient id="c" x1="26.5981" y1="46.5015" x2="5.8161" y2="10.506" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1e8e3e"/><stop offset="1" stop-color="#34a853"/></linearGradient></defs><circle cx="24" cy="23.9947" r="12" style="fill:#fff"/><path d="M3.2154,36A24,24,0,1,0,12,3.2154,24,24,0,0,0,3.2154,36ZM34.3923,18A12,12,0,1,1,18,13.6077,12,12,0,0,1,34.3923,18Z" style="fill:none"/><path d="M24,12H44.7812a23.9939,23.9939,0,0,0-41.5639.0029L13.6079,30l.0093-.0024A11.9852,11.9852,0,0,1,24,12Z" style="fill:url(#a)"/><circle cx="24" cy="24" r="9.5" style="fill:#1a73e8"/><path d="M34.3913,30.0029,24.0007,48A23.994,23.994,0,0,0,44.78,12.0031H23.9989l-.0025.0093A11.985,11.985,0,0,1,34.3913,30.0029Z" style="fill:url(#b)"/><path d="M13.6086,30.0031,3.218,12.006A23.994,23.994,0,0,0,24.0025,48L34.3931,30.0029l-.0067-.0068a11.9852,11.9852,0,0,1-20.7778.007Z" style="fill:url(#c)"/></svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

-3
View File
@@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#52b54b">
<path d="M11.041 0c-.007 0-1.456 1.43-3.219 3.176L4.615 6.352l.512.513.512.512-2.819 2.791L0 12.961l1.83 1.848c1.006 1.016 2.438 2.46 3.182 3.209l1.351 1.359.508-.496c.28-.273.515-.498.524-.498.008 0 1.266 1.264 2.794 2.808L12.97 24l.187-.182c.23-.225 5.007-4.95 5.717-5.656l.52-.516-.502-.513c-.276-.282-.5-.52-.496-.53.003-.009 1.264-1.26 2.802-2.783 1.538-1.522 2.8-2.776 2.803-2.785.005-.012-3.617-3.684-6.107-6.193L17.65 4.6l-.505.505c-.279.278-.517.501-.53.497-.013-.005-1.27-1.267-2.793-2.805A449.655 449.655 0 0011.041 0zM9.223 7.367c.091.038 7.951 4.608 7.957 4.627.003.013-1.781 1.056-3.965 2.32a999.898 999.898 0 01-3.996 2.307c-.019.006-.026-1.266-.026-4.629 0-3.7.007-4.634.03-4.625z"/>
</svg>

Before

Width:  |  Height:  |  Size: 785 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

-1
View File
@@ -1 +0,0 @@
<svg role="img" viewBox="0 0 24 24" fill="#ffffff" xmlns="http://www.w3.org/2000/svg"><title>Firefox Browser</title><path d="M8.824 7.287c.008 0 .004 0 0 0zm-2.8-1.4c.006 0 .003 0 0 0zm16.754 2.161c-.505-1.215-1.53-2.528-2.333-2.943.654 1.283 1.033 2.57 1.177 3.53l.002.02c-1.314-3.278-3.544-4.6-5.366-7.477-.091-.147-.184-.292-.273-.446a3.545 3.545 0 01-.13-.24 2.118 2.118 0 01-.172-.46.03.03 0 00-.027-.03.038.038 0 00-.021 0l-.006.001a.037.037 0 00-.01.005L15.624 0c-2.585 1.515-3.657 4.168-3.932 5.856a6.197 6.197 0 00-2.305.587.297.297 0 00-.147.37c.057.162.24.24.396.17a5.622 5.622 0 012.008-.523l.067-.005a5.847 5.847 0 011.957.222l.095.03a5.816 5.816 0 01.616.228c.08.036.16.073.238.112l.107.055a5.835 5.835 0 01.368.211 5.953 5.953 0 012.034 2.104c-.62-.437-1.733-.868-2.803-.681 4.183 2.09 3.06 9.292-2.737 9.02a5.164 5.164 0 01-1.513-.292 4.42 4.42 0 01-.538-.232c-1.42-.735-2.593-2.121-2.74-3.806 0 0 .537-2 3.845-2 .357 0 1.38-.998 1.398-1.287-.005-.095-2.029-.9-2.817-1.677-.422-.416-.622-.616-.8-.767a3.47 3.47 0 00-.301-.227 5.388 5.388 0 01-.032-2.842c-1.195.544-2.124 1.403-2.8 2.163h-.006c-.46-.584-.428-2.51-.402-2.913-.006-.025-.343.176-.389.206-.406.29-.787.616-1.136.974-.397.403-.76.839-1.085 1.303a9.816 9.816 0 00-1.562 3.52c-.003.013-.11.487-.19 1.073-.013.09-.026.181-.037.272a7.8 7.8 0 00-.069.667l-.002.034-.023.387-.001.06C.386 18.795 5.593 24 12.016 24c5.752 0 10.527-4.176 11.463-9.661.02-.149.035-.298.052-.448.232-1.994-.025-4.09-.753-5.844z"/></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

-1
View File
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" width="24" height="24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>

Before

Width:  |  Height:  |  Size: 835 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

-3
View File
@@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#00a4dc">
<path d="M12 .002C8.826.002-1.398 18.537.16 21.666c1.56 3.129 22.14 3.094 23.682 0C25.384 18.573 15.177 0 12 0zm7.76 18.949c-1.008 2.028-14.493 2.05-15.514 0C3.224 16.9 9.92 4.755 12.003 4.755c2.081 0 8.77 12.166 7.759 14.196zM12 9.198c-1.054 0-4.446 6.15-3.93 7.189.518 1.04 7.348 1.027 7.86 0 .511-1.027-2.874-7.19-3.93-7.19z"/>
</svg>

Before

Width:  |  Height:  |  Size: 416 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

-3
View File
@@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#e50914">
<path d="M5.398 0 13.746 23.602c2.346.059 4.856.398 4.856.398L10.113 0H5.398zm8.489 0v9.172l4.715 13.33V0h-4.715zM5.398 1.5V24c1.873-.225 2.81-.312 4.715-.398V14.83L5.398 1.5z"/>
</svg>

Before

Width:  |  Height:  |  Size: 264 B

-5
View File
@@ -1,5 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#00a8e1">
<text x="12" y="7.2" text-anchor="middle" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif" font-size="7.5" font-weight="900" letter-spacing="-0.1px">prime</text>
<text x="12" y="14.8" text-anchor="middle" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif" font-size="7.5" font-weight="900" letter-spacing="-0.1px">video</text>
<path d="M.045 18.02c.072-.116.187-.124.348-.022 3.636 2.11 7.594 3.166 11.87 3.166 2.852 0 5.668-.533 8.447-1.595l.315-.14c.138-.06.234-.1.293-.13.226-.088.39-.046.525.13.12.174.09.336-.12.48-.256.19-.6.41-1.006.654-1.244.743-2.64 1.316-4.185 1.726a17.617 17.617 0 01-10.951-.577 17.88 17.88 0 01-5.43-3.35c-.1-.074-.151-.15-.151-.22 0-.047.021-.09.051-.13z"/>
</svg>

Before

Width:  |  Height:  |  Size: 887 B

-3
View File
@@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#9146ff">
<path d="M11.571 4.714h1.715v5.143H11.57zm4.715 0H18v5.143h-1.714zM6 0L1.714 4.286v15.428h5.143V24l4.286-4.286h3.428L22.286 12V0zm14.571 11.143l-3.428 3.428h-3.429l-3 3v-3H6.857V1.714h13.714Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 280 B

-3
View File
@@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#ff0000">
<path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"/>
</svg>

Before

Width:  |  Height:  |  Size: 446 B

-24
View File
@@ -1,24 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Redirecting...</title>
<script>
(function() {
var savedLang = localStorage.getItem('koala_lang');
var browserLang = (navigator.language || navigator.userLanguage || '').toLowerCase();
var isDe = (savedLang === 'de') || (!savedLang && browserLang.indexOf('de') === 0);
var path = window.location.pathname;
var hasHtml = path.endsWith('.html');
if (isDe) {
window.location.replace(hasHtml ? 'de/datenschutz.html' : 'de/datenschutz');
} else {
window.location.replace(hasHtml ? 'privacy.html' : 'privacy');
}
})();
</script>
</head>
<body>
<p>Redirecting / Weiterleitung...</p>
</body>
</html>
-168
View File
@@ -1,168 +0,0 @@
<!DOCTYPE html>
<html lang="de" class="lang-de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Datenschutz | KoalaSync</title>
<link rel="preload" href="../style.49e7653a.min.css" as="style">
<link rel="stylesheet" href="../style.49e7653a.min.css">
<link rel="icon" type="image/webp" href="../assets/NewLogoIcon_64.webp">
<meta name="robots" content="index, follow">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{ "@type": "ListItem", "position": 1, "name": "Startseite", "item": "https://sync.koalastuff.net/de/" },
{ "@type": "ListItem", "position": 2, "name": "Datenschutz", "item": "https://sync.koalastuff.net/de/datenschutz" }
]
}
</script>
<!-- Mobile Browser Theme Styling -->
<meta name="theme-color" content="#0f172a">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<script src="../lang-init.1b13bbf2.min.js"></script>
</head>
<body>
<div class="bg-blobs">
<div class="blob blob-1"></div>
<div class="blob blob-2"></div>
<div class="blob blob-3"></div>
</div>
<nav>
<div class="container nav-content">
<a href="./" class="logo-area" style="text-decoration: none;">
<picture><source srcset="../assets/NewLogoIcon.avif" type="image/avif"><img src="../assets/NewLogoIcon.webp" alt="KoalaSync Logo" width="40" height="40"></picture>
<span>KoalaSync</span>
</a>
<div class="nav-links">
<a href="./" style="display: inline-flex; align-items: center; gap: 6px;">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" aria-hidden="true" style="width:16px;height:16px;display:block" viewBox="0 0 24 24"><path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><path d="M9 22V12h6v10"/></svg>
<span>Startseite</span>
</a>
<a href="https://github.com/Shik3i/KoalaSync" target="_blank" rel="noopener" style="display: inline-flex; align-items: center; gap: 6px;">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" aria-hidden="true" style="display:block" viewBox="0 0 24 24"><path d="M12 0C5.374 0 0 5.373 0 12c0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23A11.5 11.5 0 0 1 12 5.803c1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576C20.566 21.797 24 17.3 24 12c0-6.627-5.373-12-12-12"/></svg>
GitHub
</a>
</div>
<div class="nav-right">
<div class="lang-select-container">
<select class="lang-dropdown" aria-label="Select Language">
<option value="en">🇬🇧 English</option>
<option value="de">🇩🇪 Deutsch</option>
<option value="fr">🇫🇷 Français</option>
<option value="es">🇪🇸 Español</option>
<option value="pt-BR">🇧🇷 Português (Brasil)</option>
<option value="ru">🇷🇺 Русский</option>
<option value="it">🇮🇹 Italiano</option>
<option value="pl">🇵🇱 Polski</option>
<option value="tr">🇹🇷 Türkçe</option>
<option value="nl">🇳🇱 Nederlands</option>
<option value="ja">🇯🇵 日本語</option>
<option value="ko">🇰🇷 한국어</option>
<option value="pt">🇵🇹 Português (Portugal)</option>
</select>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" aria-hidden="true" class="chevron-icon" viewBox="0 0 24 24"><path d="m6 9 6 6 6-6"/></svg>
</div>
<button class="hamburger" aria-label="Menu" aria-expanded="false"></button>
</div>
</div>
</nav>
<main class="legal-content">
<div class="legal-card" data-reveal style="padding: 2rem;">
<div style="display: flex; justify-content: center;">
<picture><source srcset="../assets/KoalaPrivacy.avif" type="image/avif"><img src="../assets/KoalaPrivacy.webp" alt="Niedlicher Koala, der den Datenschutz repräsentiert" class="legal-mascot" width="180" height="180"></picture>
</div>
<h1>Datenschutz</h1>
<p style="text-align: center; text-transform: uppercase; letter-spacing: 0.1em; font-size: 0.8rem; border-bottom: 1px solid var(--glass-border); padding-bottom: 1.5rem; margin-bottom: 2rem;">
Sicherheit & Privatsphäre
</p>
<section>
<h2>1. Hosting & Logfiles</h2>
<p>
Diese Seite wird auf einem privaten Server gehostet. Zur Gewährleistung der Stabilität werden standardmäßige Server-Logs (IP, Browser, Zeit) erhoben, aber nicht mit Personen verknüpft und nach 7 Tagen automatisch gelöscht.
</p>
</section>
<section>
<h2>2. Keine Drittanbieter & Open Source</h2>
<p>
KoalaSync verzichtet bewusst auf Analyse-Tools, Tracking-Cookies oder Werbenetzwerke. Wir laden keine Ressourcen von Drittanbietern (wie Google Fonts) nach, um Ihre Privatsphäre maximal zu schützen.
</p>
<p style="margin-top: 0.5rem;">
Da KoalaSync vollständig Open Source ist, kann zudem jede Zeile Code auf unserem <a href="https://github.com/shik3i/KoalaSync" target="_blank" rel="noopener" style="color: var(--accent);">GitHub-Repository</a> öffentlich eingesehen und auf Sicherheit geprüft werden.
</p>
</section>
<section>
<h2>3. Relay-Server Architektur</h2>
<p>
Unser Relay-Server arbeitet ausschließlich im Arbeitsspeicher (RAM). Nachrichten zwischen Teilnehmern werden nicht auf Festplatten gespeichert und sind flüchtig. Sobald ein Raum geschlossen wird, werden alle zugehörigen Metadaten sofort gelöscht. Wir tracken Sie nicht. Wir überwachen lediglich unseren Server auf Basis von aggregierten, anonymen, nicht-personenbezogenen System-Leistungsmetriken.
</p>
</section>
<section>
<h2>4. Browser-Erweiterung (Extension)</h2>
<p>
Um die geräteübergreifende Synchronisation zu ermöglichen, erfasst die KoalaSync Browser-Erweiterung temporär Daten des aktuell aktiven Video-Tabs (z. B. Tab-Titel, Medien-Metadaten wie den Videotitel sowie den Wiedergabestatus). Diese Daten werden ausschließlich zur Synchronisation an die anderen Teilnehmer in Ihrem Raum gesendet. Es wird ausdrücklich <strong>kein allgemeiner Browserverlauf (Browsing History)</strong> ausgelesen, gespeichert oder übermittelt.
</p>
</section>
<section>
<h2>5. Berechtigungen der Erweiterung</h2>
<p>
Um ihre technischen Zweck zu erfüllen, benötigt die Browser-Erweiterung bestimmte Berechtigungen. Jede Berechtigung wird ausschließlich für die Kernfunktionalität genutzt:
</p>
<ul style="margin-left: 1.5rem; margin-top: 0.5rem; color: var(--text-muted); font-size: 0.9rem; list-style-type: disc; display: flex; flex-direction: column; gap: 0.35rem;">
<li><strong>storage</strong>: Erlaubt das lokale Speichern von Benutzernamen, Server-URLs und Raum-Zugangsdaten im Browser, damit Sie sich nicht jedes Mal neu anmelden müssen.</li>
<li><strong>tabs</strong>: Wird benötigt, um geöffnete Tabs im Dropdown der Erweiterung aufzulisten und deren Titel auszulesen, damit Sie bequem den richtigen Video-Tab auswählen können.</li>
<li><strong>scripting</strong>: Erforderlich, um das Synchronisationsskript (content.js) sicher in den von Ihnen ausgewählten Videotab zu injizieren.</li>
<li><strong>alarms</strong>: Verhindert, dass der Hintergrunddienst der Erweiterung (Service Worker) während einer aktiven Synchronisationssitzung vom Browser in den Ruhezustand versetzt wird.</li>
<li><strong>activeTab</strong>: Ermöglicht eine sichere, temporäre Interaktion mit dem momentan aktiven Tab für direkte Steuerungsbefehle.</li>
<li><strong>notifications</strong>: Ermöglicht optionale Desktop-Benachrichtigungen, wenn beispielsweise ein neuer Freund dem Raum beitritt.</li>
<li><strong>&lt;all_urls&gt; (Host-Berechtigung)</strong>: Ermöglicht der Erweiterung, auf beliebigen Webseiten nach HTML5-Videoelementen zu suchen, damit die Synchronisation plattformübergreifend (z. B. auf YouTube, Netflix, Jellyfin etc.) funktioniert.</li>
</ul>
</section>
<section>
<h2>6. Brute-Force Schutz</h2>
<p>
Zur Sicherheit unserer Nutzer speichern wir fehlgeschlagene Login-Versuche (IP-Adresse und Raum-ID) für maximal 15 Minuten im RAM, um automatisierte Angriffe zu verhindern. Diese Daten werden danach rückstandslos gelöscht.
</p>
</section>
<section>
<h2>7. Ihre Rechte</h2>
<p>
Sie haben das Recht auf Auskunft, Berichtigung oder Löschung Ihrer Daten. Da wir jedoch keine personenbezogenen Daten dauerhaft speichern, ist eine Zuordnung zu Ihrer Person in der Regel technisch nicht möglich.
</p>
<p>Kontakt bei Fragen: <span class="email-reveal" data-user="koalasync_datenschutz" data-domain="koalamail.rocks" style="color: var(--accent); cursor: pointer; text-decoration: underline;">[E-Mail anzeigen]</span></p>
</section>
</div>
</main>
<footer>
<div class="container">
<p>&copy; 2026 KoalaSync. Open Source unter der MIT-Lizenz.</p>
<p style="font-size: 0.8rem; margin-top: 0.5rem;">Keine Daten werden auf unseren Servern gespeichert. Reines RAM-basiertes Relay.</p>
<div style="margin-top: 1.5rem; font-size: 0.8rem; display: flex; justify-content: center; align-items: center; gap: 1.5rem; flex-wrap: wrap;">
<a href="impressum" style="color: var(--text-muted); text-decoration: none;">Impressum</a>
<a href="datenschutz" style="color: var(--text-muted); text-decoration: none;">Datenschutz</a>
<a href="https://mastodon.social/@koalastuff" rel="me noopener" target="_blank" style="color: var(--text-muted); text-decoration: none; display: inline-flex; align-items: center; gap: 4px;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" aria-hidden="true" style="display:block" viewBox="0 0 24 24"><path d="M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38q.398-.092.786-.213c.585-.184 1.27-.39 1.774-.753a.06.06 0 0 0 .023-.043v-1.809a.05.05 0 0 0-.02-.041.05.05 0 0 0-.046-.01 20.3 20.3 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.6 5.6 0 0 1-.319-1.433.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546.376 0 .75 0 1.125-.01 1.57-.044 3.224-.124 4.768-.422q.059-.011.11-.024c2.435-.464 4.753-1.92 4.989-5.604.008-.145.03-1.52.03-1.67.002-.512.167-3.63-.024-5.545m-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102q0-1.965 1.011-3.12c.696-.77 1.608-1.164 2.74-1.164 1.311 0 2.302.5 2.962 1.498l.638 1.06.638-1.06c.66-.999 1.65-1.498 2.96-1.498 1.13 0 2.043.395 2.74 1.164q1.012 1.155 1.012 3.12z"/></svg>
Mastodon
</a>
</div>
</div>
</footer>
<script src="../app.49c86a28.min.js"></script>
</body>
</html>
-155
View File
@@ -1,155 +0,0 @@
<!DOCTYPE html>
<html lang="de" class="lang-de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Impressum | KoalaSync</title>
<link rel="preload" href="../style.49e7653a.min.css" as="style">
<link rel="stylesheet" href="../style.49e7653a.min.css">
<link rel="icon" type="image/webp" href="../assets/NewLogoIcon_64.webp">
<meta name="robots" content="index, follow">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{ "@type": "ListItem", "position": 1, "name": "Startseite", "item": "https://sync.koalastuff.net/de/" },
{ "@type": "ListItem", "position": 2, "name": "Impressum", "item": "https://sync.koalastuff.net/de/impressum" }
]
}
</script>
<!-- Mobile Browser Theme Styling -->
<meta name="theme-color" content="#0f172a">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<script src="../lang-init.1b13bbf2.min.js"></script>
</head>
<body>
<div class="bg-blobs">
<div class="blob blob-1"></div>
<div class="blob blob-2"></div>
<div class="blob blob-3"></div>
</div>
<nav>
<div class="container nav-content">
<a href="./" class="logo-area" style="text-decoration: none;">
<picture><source srcset="../assets/NewLogoIcon.avif" type="image/avif"><img src="../assets/NewLogoIcon.webp" alt="KoalaSync Logo" width="40" height="40"></picture>
<span>KoalaSync</span>
</a>
<div class="nav-links">
<a href="./" style="display: inline-flex; align-items: center; gap: 6px;">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" aria-hidden="true" style="width:16px;height:16px;display:block" viewBox="0 0 24 24"><path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><path d="M9 22V12h6v10"/></svg>
<span>Startseite</span>
</a>
<a href="https://github.com/Shik3i/KoalaSync" target="_blank" rel="noopener" style="display: inline-flex; align-items: center; gap: 6px;">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" aria-hidden="true" style="display:block" viewBox="0 0 24 24"><path d="M12 0C5.374 0 0 5.373 0 12c0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23A11.5 11.5 0 0 1 12 5.803c1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576C20.566 21.797 24 17.3 24 12c0-6.627-5.373-12-12-12"/></svg>
GitHub
</a>
</div>
<div class="nav-right">
<div class="lang-select-container">
<select class="lang-dropdown" aria-label="Select Language">
<option value="en">🇬🇧 English</option>
<option value="de">🇩🇪 Deutsch</option>
<option value="fr">🇫🇷 Français</option>
<option value="es">🇪🇸 Español</option>
<option value="pt-BR">🇧🇷 Português (Brasil)</option>
<option value="ru">🇷🇺 Русский</option>
<option value="it">🇮🇹 Italiano</option>
<option value="pl">🇵🇱 Polski</option>
<option value="tr">🇹🇷 Türkçe</option>
<option value="nl">🇳🇱 Nederlands</option>
<option value="ja">🇯🇵 日本語</option>
<option value="ko">🇰🇷 한국어</option>
<option value="pt">🇵🇹 Português (Portugal)</option>
</select>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" aria-hidden="true" class="chevron-icon" viewBox="0 0 24 24"><path d="m6 9 6 6 6-6"/></svg>
</div>
<button class="hamburger" aria-label="Menu" aria-expanded="false"></button>
</div>
</div>
</nav>
<main class="legal-content">
<div class="legal-card" data-reveal style="padding: 2rem;">
<div style="display: flex; justify-content: center;">
<picture><source srcset="../assets/KoalaImprintl.avif" type="image/avif"><img src="../assets/KoalaImprintl.webp" alt="Niedlicher Koala, der das Impressum repräsentiert" class="legal-mascot" width="180" height="180"></picture>
</div>
<h1>Impressum</h1>
<p style="text-align: center; text-transform: uppercase; letter-spacing: 0.1em; font-size: 0.8rem; border-bottom: 1px solid var(--glass-border); padding-bottom: 1.5rem; margin-bottom: 2rem;">
Transparenz & Identifikation
</p>
<section>
<h2>Betreiber & Kontakt</h2>
<p>Timo (KoalaDev) Privatperson</p>
<p style="margin-top: 0.5rem;">
E-Mail: <span class="email-reveal" data-user="koalasync_admin" data-domain="koalamail.rocks" style="color: var(--accent); cursor: pointer; text-decoration: underline;">[E-Mail anzeigen]</span>
</p>
<p style="margin-top: 0.75rem;">
<span style="opacity: 0.6;">🔒 Private Nachricht:</span>
<a href="https://mastodon.social/@koalastuff" rel="me noopener" target="_blank" style="color: var(--accent); text-decoration: none;">@koalastuff auf Mastodon</a>
</p>
<p style="margin-top: 0.5rem;">
<span style="opacity: 0.6;">🐛 Active Bedenken / Bug Reports:</span>
<a href="https://github.com/Shik3i/KoalaSync/issues" target="_blank" rel="noopener" style="color: var(--accent); text-decoration: none;">GitHub Issues</a>
</p>
</section>
<section style="opacity: 0.8;">
<h2>Privatprojekt-Hinweis</h2>
<p>
Diese Website ist ein rein privates Hobby-Projekt und dient keinen geschäftsmäßigen Zwecken.
Eine Impressumspflicht nach § 5 DDG (ehemals TMG) besteht daher nicht.
Diese Angaben erfolgen rein freiwillig zur Transparenz gegenüber der Community.
</p>
</section>
<section>
<h2>Haftung für Inhalte</h2>
<p>
Gemäß § 7 Abs.1 DDG sind wir für eigene Inhalte verantwortlich. Nach §§ 8 bis 10 DDG sind wir jedoch nicht verpflichtet,
übermittelte oder gespeicherte fremde Informationen zu überwachen.
</p>
</section>
<section>
<h2>Haftung für Links</h2>
<p>
Unser Angebot enthält Links zu externen Websites Dritter. Auf deren Inhalte haben wir keinen Einfluss und
können daher keine Gewähr für diese fremden Inhalte übernehmen.
</p>
</section>
<section>
<h2>Urheberrecht</h2>
<p>
Die durch die Seitenbetreiber erstellten Inhalte auf diesen Seiten unterliegen dem deutschen Urheberrecht.
Vervielfältigung, Bearbeitung und jede Art der Verwertung außerhalb der Grenzen des Urheberrechtes bedürfen der schriftlichen Zustimmung.
</p>
</section>
</div>
</main>
<footer>
<div class="container">
<p>&copy; 2026 KoalaSync. Open Source unter der MIT-Lizenz.</p>
<p style="font-size: 0.8rem; margin-top: 0.5rem;">Keine Daten werden auf unseren Servern gespeichert. Reines RAM-basiertes Relay.</p>
<div style="margin-top: 1.5rem; font-size: 0.8rem; display: flex; justify-content: center; align-items: center; gap: 1.5rem; flex-wrap: wrap;">
<a href="impressum" style="color: var(--text-muted); text-decoration: none;">Impressum</a>
<a href="datenschutz" style="color: var(--text-muted); text-decoration: none;">Datenschutz</a>
<a href="https://mastodon.social/@koalastuff" rel="me noopener" target="_blank" style="color: var(--text-muted); text-decoration: none; display: inline-flex; align-items: center; gap: 4px;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" aria-hidden="true" style="display:block" viewBox="0 0 24 24"><path d="M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38q.398-.092.786-.213c.585-.184 1.27-.39 1.774-.753a.06.06 0 0 0 .023-.043v-1.809a.05.05 0 0 0-.02-.041.05.05 0 0 0-.046-.01 20.3 20.3 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.6 5.6 0 0 1-.319-1.433.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546.376 0 .75 0 1.125-.01 1.57-.044 3.224-.124 4.768-.422q.059-.011.11-.024c2.435-.464 4.753-1.92 4.989-5.604.008-.145.03-1.52.03-1.67.002-.512.167-3.63-.024-5.545m-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102q0-1.965 1.011-3.12c.696-.77 1.608-1.164 2.74-1.164 1.311 0 2.302.5 2.962 1.498l.638 1.06.638-1.06c.66-.999 1.65-1.498 2.96-1.498 1.13 0 2.043.395 2.74 1.164q1.012 1.155 1.012 3.12z"/></svg>
Mastodon
</a>
</div>
</div>
</footer>
<script src="../app.49c86a28.min.js"></script>
</body>
</html>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-24
View File
@@ -1,24 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Redirecting...</title>
<script>
(function() {
var savedLang = localStorage.getItem('koala_lang');
var browserLang = (navigator.language || navigator.userLanguage || '').toLowerCase();
var isDe = (savedLang === 'de') || (!savedLang && browserLang.indexOf('de') === 0);
var path = window.location.pathname;
var hasHtml = path.endsWith('.html');
if (isDe) {
window.location.replace(hasHtml ? 'de/impressum.html' : 'de/impressum');
} else {
window.location.replace(hasHtml ? 'imprint.html' : 'imprint');
}
})();
</script>
</head>
<body>
<p>Redirecting / Weiterleitung...</p>
</body>
</html>
-153
View File
@@ -1,153 +0,0 @@
<!DOCTYPE html>
<html lang="en" class="lang-en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Legal Notice | KoalaSync</title>
<link rel="preload" href="style.49e7653a.min.css" as="style">
<link rel="stylesheet" href="style.49e7653a.min.css">
<link rel="icon" type="image/webp" href="assets/NewLogoIcon_64.webp">
<meta name="robots" content="index, follow">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{ "@type": "ListItem", "position": 1, "name": "Home", "item": "https://sync.koalastuff.net/" },
{ "@type": "ListItem", "position": 2, "name": "Legal Notice", "item": "https://sync.koalastuff.net/imprint" }
]
}
</script>
<!-- Mobile Browser Theme Styling -->
<meta name="theme-color" content="#0f172a">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<script src="lang-init.1b13bbf2.min.js"></script>
</head>
<body>
<div class="bg-blobs">
<div class="blob blob-1"></div>
<div class="blob blob-2"></div>
<div class="blob blob-3"></div>
</div>
<nav>
<div class="container nav-content">
<a href="./" class="logo-area" style="text-decoration: none;">
<picture><source srcset="assets/NewLogoIcon.avif" type="image/avif"><img src="assets/NewLogoIcon.webp" alt="KoalaSync Logo" width="40" height="40"></picture>
<span>KoalaSync</span>
</a>
<div class="nav-links">
<a href="./" style="display: inline-flex; align-items: center; gap: 6px;">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" aria-hidden="true" style="width:16px;height:16px;display:block" viewBox="0 0 24 24"><path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><path d="M9 22V12h6v10"/></svg>
<span>Home</span>
</a>
<a href="https://github.com/Shik3i/KoalaSync" target="_blank" rel="noopener" style="display: inline-flex; align-items: center; gap: 6px;">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" aria-hidden="true" style="display:block" viewBox="0 0 24 24"><path d="M12 0C5.374 0 0 5.373 0 12c0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23A11.5 11.5 0 0 1 12 5.803c1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576C20.566 21.797 24 17.3 24 12c0-6.627-5.373-12-12-12"/></svg>
GitHub
</a>
</div>
<div class="nav-right">
<div class="lang-select-container">
<select class="lang-dropdown" aria-label="Select Language">
<option value="en">🇬🇧 English</option>
<option value="de">🇩🇪 Deutsch</option>
<option value="fr">🇫🇷 Français</option>
<option value="es">🇪🇸 Español</option>
<option value="pt-BR">🇧🇷 Português (Brasil)</option>
<option value="ru">🇷🇺 Русский</option>
<option value="it">🇮🇹 Italiano</option>
<option value="pl">🇵🇱 Polski</option>
<option value="tr">🇹🇷 Türkçe</option>
<option value="nl">🇳🇱 Nederlands</option>
<option value="ja">🇯🇵 日本語</option>
<option value="ko">🇰🇷 한국어</option>
<option value="pt">🇵🇹 Português (Portugal)</option>
</select>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" aria-hidden="true" class="chevron-icon" viewBox="0 0 24 24"><path d="m6 9 6 6 6-6"/></svg>
</div>
<button class="hamburger" aria-label="Menu" aria-expanded="false"></button>
</div>
</div>
</nav>
<main class="legal-content">
<div class="legal-card" data-reveal style="padding: 2rem;">
<div style="display: flex; justify-content: center;">
<picture><source srcset="assets/KoalaImprintl.avif" type="image/avif"><img src="assets/KoalaImprintl.webp" alt="Cute Koala representing the legal notice page" class="legal-mascot" width="180" height="180"></picture>
</div>
<h1>Legal Notice</h1>
<p style="text-align: center; text-transform: uppercase; letter-spacing: 0.1em; font-size: 0.8rem; border-bottom: 1px solid var(--glass-border); padding-bottom: 1.5rem; margin-bottom: 2rem;">
Transparency & Identification
</p>
<section>
<h2>Operator & Contact</h2>
<p>Timo (KoalaDev) Private Individual</p>
<p style="margin-top: 0.5rem;">
E-Mail: <span class="email-reveal" data-user="koalasync_admin" data-domain="koalamail.rocks" style="color: var(--accent); cursor: pointer; text-decoration: underline;">[Show Email]</span>
</p>
<p style="margin-top: 0.75rem;">
<span style="opacity: 0.6;">🔒 Private message:</span>
<a href="https://mastodon.social/@koalastuff" rel="me noopener" target="_blank" style="color: var(--accent); text-decoration: none;">@koalastuff on Mastodon</a>
</p>
<p style="margin-top: 0.5rem;">
<span style="opacity: 0.6;">🐛 Active concerns / Bug reports:</span>
<a href="https://github.com/Shik3i/KoalaSync/issues" target="_blank" rel="noopener" style="color: var(--accent); text-decoration: none;">GitHub Issues</a>
</p>
</section>
<section style="opacity: 0.8;">
<h2>Private Project Notice</h2>
<p>
This website is a purely private hobby project and does not serve any commercial purposes.
Therefore, there is no obligation to provide a legal notice according to § 5 DDG (formerly TMG).
This information is provided voluntarily for transparency towards the community.
</p>
</section>
<section>
<h2>Liability for Content</h2>
<p>
According to § 7 Abs.1 DDG we are responsible for our own content. According to §§ 8 to 10 DDG, however, we are not obligated to monitor transmitted or stored third-party information.
</p>
</section>
<section>
<h2>Liability for Links</h2>
<p>
Our offer contains links to external third-party websites. We have no influence on their content and therefore cannot assume any liability for these external contents.
</p>
</section>
<section>
<h2>Copyright</h2>
<p>
The content and works created by the site operators on these pages are subject to German copyright law.
Duplication, processing, and any kind of exploitation outside the limits of copyright require written consent.
</p>
</section>
</div>
</main>
<footer>
<div class="container">
<p>&copy; 2026 KoalaSync. Open source under the MIT License.</p>
<p style="font-size: 0.8rem; margin-top: 0.5rem;">No data is stored on our servers. Pure RAM-based relay.</p>
<div style="margin-top: 1.5rem; font-size: 0.8rem; display: flex; justify-content: center; align-items: center; gap: 1.5rem; flex-wrap: wrap;">
<a href="imprint" style="color: var(--text-muted); text-decoration: none;">Legal Notice</a>
<a href="privacy" style="color: var(--text-muted); text-decoration: none;">Privacy Policy</a>
<a href="https://mastodon.social/@koalastuff" rel="me noopener" target="_blank" style="color: var(--text-muted); text-decoration: none; display: inline-flex; align-items: center; gap: 4px;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" aria-hidden="true" style="display:block" viewBox="0 0 24 24"><path d="M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38q.398-.092.786-.213c.585-.184 1.27-.39 1.774-.753a.06.06 0 0 0 .023-.043v-1.809a.05.05 0 0 0-.02-.041.05.05 0 0 0-.046-.01 20.3 20.3 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.6 5.6 0 0 1-.319-1.433.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546.376 0 .75 0 1.125-.01 1.57-.044 3.224-.124 4.768-.422q.059-.011.11-.024c2.435-.464 4.753-1.92 4.989-5.604.008-.145.03-1.52.03-1.67.002-.512.167-3.63-.024-5.545m-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102q0-1.965 1.011-3.12c.696-.77 1.608-1.164 2.74-1.164 1.311 0 2.302.5 2.962 1.498l.638 1.06.638-1.06c.66-.999 1.65-1.498 2.96-1.498 1.13 0 2.043.395 2.74 1.164q1.012 1.155 1.012 3.12z"/></svg>
Mastodon
</a>
</div>
</div>
</footer>
<script src="app.49c86a28.min.js"></script>
</body>
</html>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More