mirror of
https://github.com/Shik3i/KoalaSync.git
synced 2026-07-26 20:18:14 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cb84709358 | |||
| 43a7bb0d57 | |||
| e1e86307b1 | |||
| e934fcf484 | |||
| d4181b2eaf |
@@ -6,7 +6,7 @@
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/Shik3i/KoalaSync/actions/workflows/release.yml"><img src="https://github.com/Shik3i/KoalaSync/actions/workflows/release.yml/badge.svg" alt="Release Status"></a>
|
||||
<a href="https://github.com/Shik3i/KoalaSync/releases"><img src="https://img.shields.io/badge/Release-v2.5.4-blue?logo=github" alt="GitHub release"></a>
|
||||
<a href="https://github.com/Shik3i/KoalaSync/releases"><img src="https://img.shields.io/badge/Release-v2.6.0-blue?logo=github" alt="GitHub release"></a>
|
||||
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue" alt="License"></a>
|
||||
<a href="https://addons.mozilla.org/de/firefox/addon/koalasync/"><img src="https://img.shields.io/badge/Firefox-Download-orange?logo=firefoxbrowser&logoColor=white" alt="Firefox Add-on"></a>
|
||||
<a href="https://chromewebstore.google.com/detail/koalasync/obbnmkmlaaddodakcbdljknjpagklifc"><img src="https://img.shields.io/badge/Chrome-Download-blue?logo=googlechrome&logoColor=white" alt="Chrome Extension"></a>
|
||||
@@ -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.5.4 Release!</b> — See what's changed</a></p>
|
||||
<p align="center"><a href="docs/CHANGELOG.md"><b>New v2.6.0 Release!</b> — See what's changed</a></p>
|
||||
|
||||
### 🌟 Why KoalaSync?
|
||||
|
||||
|
||||
+11
-10
@@ -1,29 +1,30 @@
|
||||
# KoalaSync Changelog
|
||||
|
||||
All notable changes to the KoalaSync browser extension, relay server, website, and release tooling.
|
||||
All notable changes to the KoalaSync browser extension and relay server.
|
||||
|
||||
---
|
||||
|
||||
## [v2.6.1] — 2026-07-15
|
||||
|
||||
### Fixed
|
||||
- **Extension: Episode Lobby peer list** — Peer names in the lobby are now rendered as text instead of markup. A peer could previously put HTML in their username and have it rendered in everyone else's popup, which allowed loading remote images (leaking viewer IP addresses) and spoofing the readiness badges. Scripts were already blocked by the extension's content security policy.
|
||||
|
||||
### Changed
|
||||
- **Release checks: AMO validation** — `npm run verify` now runs Mozilla's `addons-linter` against the built Firefox artifact with `--warnings-as-errors`, and ESLint enforces `no-unsanitized`, so upload-blocking issues surface locally instead of at submission time.
|
||||
|
||||
---
|
||||
|
||||
## [v2.6.0] — 2026-07-15
|
||||
|
||||
### Added
|
||||
- **Website: Expanded comparison guides** — Added fully localized comparison pages for Kosmi, Scener, and TwoSeven, plus improved existing alternatives pages and navigation.
|
||||
- **Website: AI-readable product profile** — Expanded `llms.txt` with fit guidance, limitations, architecture, privacy, installation, self-hosting, and support information, and linked it from every localized landing-page head.
|
||||
- **Website: Accessibility regression coverage** — Added automated checks for light-theme step numbers, legal-link cues, heading hierarchy, readable self-hosting surfaces, and reduced-motion behavior.
|
||||
- **Extension: Appearance controls** — Added localized system, light, and dark theme options with an early theme initializer to avoid flashes during popup startup.
|
||||
|
||||
### Changed
|
||||
- **Website: Koala nature redesign** — Rebuilt the landing page around a responsive day/night forest theme with richer motion, an improved interactive demo, clearer onboarding, polished legal/join/error pages, and stronger mobile behavior.
|
||||
- **Extension: Popup and settings redesign** — Unified controls, status surfaces, colors, icons, badges, and accessibility behavior; settings are now organized into mutually exclusive accordion groups.
|
||||
- **Website: Faster rendering and builds** — Split page CSS by responsibility, removed startup forced reflows, added responsive mascot assets, cached AVIF generation, subset the flag font, minified generated HTML, and added integrity metadata for scripts and styles.
|
||||
- **Website: SEO and localization** — Added richer structured metadata, AI-crawler guidance, dynamic sitemap generation, and complete translations for the expanded alternatives content.
|
||||
- **Website: Safer self-hosting example** — Added an explicit `SERVER_SALT` replacement value, optional admin-metrics configuration, loopback-only relay publishing, and consistent host-Caddy proxy targets without requiring a separate `.env` file.
|
||||
|
||||
### Fixed
|
||||
- **Extension: Episode Lobby reliability** — Prevented the lobby from remaining stuck in a loading state and stopped episode transitions from triggering on non-episodic media.
|
||||
- **Extension: Tab-title normalization** — Notification counters such as `(14)`, `[7]`, and `(99+)` are removed reliably without stripping legitimate large numeric titles.
|
||||
- **Website and extension: Theme contrast and navigation** — Fixed light-theme contrast, language highlighting, mobile join navigation, and several control-label and tooltip inconsistencies.
|
||||
- **Website: Build and accessibility correctness** — Replaced the regex HTML minifier with conservative parser-based `htmlnano`, stopped tracking generated sitemap output, restored readable light-theme step numbers, fixed legal-page and comparison-card contrast, repaired heading order, and disabled all film motion when reduced motion is requested.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import noUnsanitized from "eslint-plugin-no-unsanitized";
|
||||
|
||||
export default [
|
||||
{
|
||||
ignores: ["coverage/**", "dist/**", "node_modules/**", "scratch/**", "website/www/**"]
|
||||
@@ -45,7 +47,14 @@ export default [
|
||||
process: "readonly",
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
"no-unsanitized": noUnsanitized
|
||||
},
|
||||
rules: {
|
||||
// Mirrors the AMO validator's "Unsafe assignment to innerHTML" check, so a
|
||||
// rejection at upload time surfaces here instead.
|
||||
"no-unsanitized/property": "error",
|
||||
"no-unsanitized/method": "error",
|
||||
"no-undef": "error",
|
||||
"no-unused-vars": ["error", { "argsIgnorePattern": "^_", "varsIgnorePattern": "^_", "caughtErrorsIgnorePattern": "^_" }],
|
||||
"no-unreachable": "error",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"manifest_version": 3,
|
||||
"default_locale": "en",
|
||||
"name": "KoalaSync",
|
||||
"version": "2.5.4",
|
||||
"version": "2.6.0",
|
||||
"description": "Synchronize video playback on YouTube, Netflix, Emby, Jellyfin, and any HTML5 site in real-time with friends.",
|
||||
"permissions": [
|
||||
"storage",
|
||||
|
||||
+20
-5
@@ -2603,9 +2603,10 @@ function updateLobbyUI(lobby, peers) {
|
||||
elements.episodeLobbyCard.style.display = 'block';
|
||||
elements.lobbyTitle.textContent = getMessage('LOBBY_WAITING_FOR', { title: lobby.expectedTitle });
|
||||
|
||||
// Build peer readiness list
|
||||
// Build peer readiness list. Peer usernames are remote-controlled input, so
|
||||
// every node is built with the DOM API and filled via textContent.
|
||||
const readySet = new Set(lobby.readyPeers || []);
|
||||
const peerHtmls = [];
|
||||
const peerItems = [];
|
||||
|
||||
if (peers && peers.length > 0) {
|
||||
peers.forEach(p => {
|
||||
@@ -2616,12 +2617,26 @@ function updateLobbyUI(lobby, peers) {
|
||||
const icon = isReady ? '✅' : '⏳';
|
||||
const label = isReady ? getMessage('LABEL_LOBBY_PEER_READY') : getMessage('LABEL_LOBBY_PEER_LOADING');
|
||||
const badgeClass = isReady ? 'badge-ready' : 'badge-loading';
|
||||
peerHtmls.push(`<span class="lobby-peer-item">${icon} ${avatar} ${pName} <span class="badge ${badgeClass}">${label}</span></span>`);
|
||||
|
||||
const item = document.createElement('span');
|
||||
item.className = 'lobby-peer-item';
|
||||
item.appendChild(document.createTextNode(`${icon} ${avatar} ${pName} `));
|
||||
|
||||
const badge = document.createElement('span');
|
||||
badge.className = `badge ${badgeClass}`;
|
||||
badge.textContent = label;
|
||||
item.appendChild(badge);
|
||||
|
||||
peerItems.push(item);
|
||||
});
|
||||
}
|
||||
|
||||
if (peerHtmls.length > 0 && elements.lobbyPeerStatus) {
|
||||
elements.lobbyPeerStatus.innerHTML = peerHtmls.join(' ');
|
||||
if (peerItems.length > 0 && elements.lobbyPeerStatus) {
|
||||
elements.lobbyPeerStatus.textContent = '';
|
||||
peerItems.forEach((item, index) => {
|
||||
if (index > 0) elements.lobbyPeerStatus.appendChild(document.createTextNode(' '));
|
||||
elements.lobbyPeerStatus.appendChild(item);
|
||||
});
|
||||
} else if (elements.lobbyPeerStatus) {
|
||||
elements.lobbyPeerStatus.textContent = getMessage('LOBBY_WAITING_PEERS');
|
||||
}
|
||||
|
||||
Generated
+1500
-13
File diff suppressed because it is too large
Load Diff
+3
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "koalasync",
|
||||
"version": "2.5.4",
|
||||
"version": "2.6.0",
|
||||
"description": "KoalaSync Build Scripts",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
@@ -17,9 +17,11 @@
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.61.1",
|
||||
"@vitest/coverage-v8": "^4.1.9",
|
||||
"addons-linter": "^10.9.0",
|
||||
"archiver": "^7.0.1",
|
||||
"esbuild": "^0.28.1",
|
||||
"eslint": "^10.4.0",
|
||||
"eslint-plugin-no-unsanitized": "^4.1.5",
|
||||
"fs-extra": "^11.2.0",
|
||||
"htmlnano": "^3.4.0",
|
||||
"sharp": "^0.34.5",
|
||||
|
||||
@@ -33,6 +33,10 @@ const checks = [
|
||||
['root production audit', 'npm', ['audit', '--omit=dev']],
|
||||
['server production audit', 'npm', ['audit', '--omit=dev'], { cwd: path.join(repoRoot, 'server') }],
|
||||
['extension build', 'npm', ['run', 'build:extension']],
|
||||
// Must run after the build: validates the exact artifact uploaded to AMO.
|
||||
// --warnings-as-errors is required: addons-linter exits 0 on warnings, and AMO
|
||||
// rejects on them, so without it this check would pass a rejectable build.
|
||||
['AMO validation (firefox)', 'npx', ['addons-linter', '--warnings-as-errors', 'dist/koalasync-firefox.zip']],
|
||||
['website build', 'node', ['website/build.cjs']]
|
||||
];
|
||||
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
export const PROTOCOL_VERSION = "1.0.0";
|
||||
export const APP_VERSION = "2.5.4";
|
||||
export const APP_VERSION = "2.6.0";
|
||||
|
||||
export const OFFICIAL_SERVER_URL = 'wss://syncserver.koalastuff.net';
|
||||
export const OFFICIAL_LANDING_PAGE_URL = 'https://sync.koalastuff.net';
|
||||
|
||||
+6
-1
@@ -599,6 +599,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
const isDE = document.documentElement.classList.contains('lang-de');
|
||||
title.textContent = isDE ? 'Erfolgreich!' : 'Success!';
|
||||
// eslint-disable-next-line no-unsanitized/property -- both branches are hardcoded literals, no dynamic input
|
||||
desc.innerHTML = isDE
|
||||
? 'Verbunden! <br><span style="color:var(--accent); font-weight:bold;">Wähle jetzt einen Video-Tab in der Erweiterung aus.</span>'
|
||||
: 'Connected! <br><span style="color:var(--accent); font-weight:bold;">Now select a video tab in the extension.</span>';
|
||||
@@ -616,6 +617,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
setTimeout(updateCountdown, 1000);
|
||||
|
||||
const closeLabel = isDE ? 'TAB JETZT SCHLIESSEN' : 'CLOSE TAB NOW';
|
||||
// eslint-disable-next-line no-unsanitized/property -- closeLabel is a hardcoded literal, no dynamic input
|
||||
actions.innerHTML = `
|
||||
<div class="join-card-actions">
|
||||
<button class="btn btn-success" onclick="window.close()">${closeLabel}</button>
|
||||
@@ -634,6 +636,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
title.textContent = isDE ? 'Fehler' : 'Error';
|
||||
desc.textContent = isDE ? `Beitritt fehlgeschlagen: ${message}` : `Join failed: ${message}`;
|
||||
const retryLabel = isDE ? 'ERNEUT VERSUCHEN' : 'TRY AGAIN';
|
||||
// eslint-disable-next-line no-unsanitized/property -- retryLabel is a hardcoded literal, no dynamic input
|
||||
actions.innerHTML = `
|
||||
<div class="join-card-actions">
|
||||
<button class="btn btn-primary" onclick="location.reload()">${retryLabel}</button>
|
||||
@@ -1366,10 +1369,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const isDE = document.documentElement.classList.contains('lang-de');
|
||||
const originalHTML = copyBtn.innerHTML;
|
||||
|
||||
// eslint-disable-next-line no-unsanitized/property -- both branches are hardcoded literals, no dynamic input
|
||||
copyBtn.innerHTML = isDE ? '✅ Kopiert!' : '✅ Copied!';
|
||||
copyBtn.disabled = true;
|
||||
|
||||
|
||||
setTimeout(() => {
|
||||
// eslint-disable-next-line no-unsanitized/property -- restores markup captured from this same button above
|
||||
copyBtn.innerHTML = originalHTML;
|
||||
copyBtn.disabled = false;
|
||||
}, 2000);
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
"priceCurrency": "EUR"
|
||||
},
|
||||
"description": "{{SCHEMA_APP_DESC}}",
|
||||
"softwareVersion": "2.5.4",
|
||||
"softwareVersion": "2.6.0",
|
||||
"license": "https://opensource.org/licenses/MIT",
|
||||
"sameAs": "https://github.com/Shik3i/KoalaSync",
|
||||
"image": "https://sync.koalastuff.net/assets/NewLogoIcon.webp",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"version": "2.5.4",
|
||||
"date": "2026-07-08T14:25:32Z"
|
||||
"version": "2.6.0",
|
||||
"date": "2026-07-15T03:14:35Z"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user