mirror of
https://github.com/Shik3i/KoalaSync.git
synced 2026-07-26 20:18:14 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 82c09a5328 | |||
| 2fbeafeb3f | |||
| 80f8c821cb | |||
| 7d3965a9fd | |||
| 1aca6c37d4 | |||
| aa740592dd | |||
| 6f8bcf8478 | |||
| 807a620fe9 | |||
| 6e138f51d3 | |||
| ed50e354ab | |||
| 48bd503b5c |
@@ -107,9 +107,18 @@ Before starting any task, committing, or pushing, you **MUST** run `git pull --r
|
||||
- **ESLint Validation**: Run `npm run lint` (or `npx eslint .`). The output must show **zero errors and zero warnings**. ESLint is configured to catch undefined variables, unused vars, unreachable code, and other semantic issues. **NEVER** commit or push code that fails this check.
|
||||
2. Commit all verified code changes and push to `main`.
|
||||
3. Create and push a new tag. **MANDATORY**: Tags MUST start with a `v` (e.g., `v1.4.0`). The GitHub Actions release workflow is strictly configured to ignore any tags without the `v` prefix.
|
||||
- **🚫 TAG IMMUTABILITY**: Once a tag is pushed to `origin`, it is **PERMANENT**. You MUST **NEVER** reuse, move, or force-push an existing tag — not even to "fix" a mistake. If a release is missing a fix, increment the version and create a **new** tag (e.g., `v1.7.0` → `v1.7.1`). Tags are immutable identifiers; moving them breaks CI pipelines, corrupts the release history, and causes unreproducible builds.
|
||||
- **🚫 WHEN NOT TO TAG**: Do NOT create a release tag for changes that do NOT affect the shipped extension or server artifacts. Website text changes, documentation updates (`.md` files), and landing page content do NOT require a version tag. Tags trigger the full CI pipeline (Docker build, extension packaging, GitHub Release) — running this for a typo fix wastes CI resources and creates meaningless releases. Only tag when extension code (`extension/`), server code (`server/`), or shared protocol constants (`shared/`) have changed.
|
||||
4. The CI will extract the version from the tag (e.g., `v1.4.0` → `1.4.0`), inject it into all source files, build the extension artifacts, publish the Docker image, and create a GitHub Release.
|
||||
5. Verify the release builds on GitHub Actions.
|
||||
|
||||
### 🚫 Force Push Policy
|
||||
> [!CAUTION]
|
||||
> **Force pushing (`git push --force` or `git push -f`) is FORBIDDEN without explicit user confirmation.**
|
||||
> - If a push is rejected due to a non-fast-forward conflict, you **MUST** run `git pull --rebase` first.
|
||||
> - If a force push is absolutely required (e.g., squashed history, amended commits), you **MUST** ask the user for explicit permission with a clear explanation of why it's necessary. Never force-push autonomously.
|
||||
> - This applies to both branches (`main`) and **tags** (see Tag Immutability above). Force-pushing tags is doubly destructive. Never do it.
|
||||
|
||||
### Adding a Protocol Event
|
||||
1. Add the event name to `shared/constants.js`.
|
||||
2. Run the build script (`node scripts/build-extension.js`).
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "KoalaSync",
|
||||
"version": "1.7.0",
|
||||
"version": "1.7.5",
|
||||
"description": "Watch party extension to synchronize video playback on YouTube, Twitch, Netflix, and HTML5 sites in real-time with friends.",
|
||||
"permissions": [
|
||||
"storage",
|
||||
|
||||
+41
-13
@@ -109,6 +109,7 @@ async function init() {
|
||||
localPeerId = res.peerId;
|
||||
applyConnectionStatus(res.status);
|
||||
updatePeerList(res.peers);
|
||||
lastKnownPeers = res.peers || [];
|
||||
if (res.lastActionState) updateLastActionUI(res.lastActionState, res.peers);
|
||||
|
||||
// Populate Tabs using the background's targetTabId
|
||||
@@ -170,7 +171,11 @@ function updateUI(roomId, password, useCustomServer = false, serverUrl = '') {
|
||||
|
||||
function updateLastActionUI(state, peers) {
|
||||
if (!state || !state.action) {
|
||||
elements.lastActionCard.innerHTML = '<div style="text-align:center; color: var(--text-muted); font-size: 10px;">No recent commands</div>';
|
||||
elements.lastActionCard.replaceChildren();
|
||||
const el = document.createElement('div');
|
||||
el.style.cssText = 'text-align:center; color: var(--text-muted); font-size: 10px;';
|
||||
el.textContent = 'No recent commands';
|
||||
elements.lastActionCard.appendChild(el);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -303,13 +308,21 @@ function renderEmpty(container, type) {
|
||||
rooms: { icon: '\u{1F50D}', title: 'No active rooms', hint: 'Create a room or refresh to find public ones' }
|
||||
};
|
||||
const state = states[type] || { icon: '', title: '', hint: '' };
|
||||
container.innerHTML = `
|
||||
<div style="text-align:center; padding:16px 8px; color:var(--text-muted);">
|
||||
<div style="font-size:24px; margin-bottom:6px;">${state.icon}</div>
|
||||
<div style="font-size:12px; font-weight:600; margin-bottom:4px;">${state.title}</div>
|
||||
<div style="font-size:10px; opacity:0.7;">${state.hint}</div>
|
||||
</div>
|
||||
`;
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.style.cssText = 'text-align:center; padding:16px 8px; color:var(--text-muted);';
|
||||
const iconDiv = document.createElement('div');
|
||||
iconDiv.style.cssText = 'font-size:24px; margin-bottom:6px;';
|
||||
iconDiv.textContent = state.icon;
|
||||
const titleDiv = document.createElement('div');
|
||||
titleDiv.style.cssText = 'font-size:12px; font-weight:600; margin-bottom:4px;';
|
||||
titleDiv.textContent = state.title;
|
||||
const hintDiv = document.createElement('div');
|
||||
hintDiv.style.cssText = 'font-size:10px; opacity:0.7;';
|
||||
hintDiv.textContent = state.hint;
|
||||
wrapper.appendChild(iconDiv);
|
||||
wrapper.appendChild(titleDiv);
|
||||
wrapper.appendChild(hintDiv);
|
||||
container.replaceChildren(wrapper);
|
||||
}
|
||||
|
||||
function updatePeerList(peers) {
|
||||
@@ -518,7 +531,15 @@ async function populateTabs(providedPeers = null, providedTargetTabId = null) {
|
||||
if (!tab.url || tab.url.startsWith('chrome://')) return false;
|
||||
if (isFilterActive && tab.id !== parseInt(currentTargetTabId)) {
|
||||
const urlStr = tab.url.toLowerCase();
|
||||
if (BLACKLIST_DOMAINS.some(d => urlStr.includes(d.toLowerCase()))) return false;
|
||||
if (BLACKLIST_DOMAINS.some(d => {
|
||||
const domain = d.toLowerCase();
|
||||
try {
|
||||
const hostname = new URL(tab.url).hostname.toLowerCase();
|
||||
if (domain.endsWith('.')) return hostname.startsWith(domain) || hostname.includes('.' + domain);
|
||||
if (domain.includes('.')) return hostname === domain || hostname.endsWith('.' + domain);
|
||||
} catch {}
|
||||
return urlStr.includes(domain);
|
||||
})) return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
@@ -924,7 +945,11 @@ elements.createRoomBtn.addEventListener('click', () => {
|
||||
});
|
||||
|
||||
elements.refreshRooms.addEventListener('click', () => {
|
||||
elements.publicRooms.innerHTML = '<div style="text-align:center; padding: 10px; color:var(--text-muted);">Refreshing...</div>';
|
||||
elements.publicRooms.replaceChildren();
|
||||
const el = document.createElement('div');
|
||||
el.style.cssText = 'text-align:center; padding: 10px; color:var(--text-muted);';
|
||||
el.textContent = 'Refreshing...';
|
||||
elements.publicRooms.appendChild(el);
|
||||
chrome.runtime.sendMessage({ type: 'GET_ROOM_LIST' });
|
||||
});
|
||||
|
||||
@@ -1343,9 +1368,12 @@ function renderOnboardingStep() {
|
||||
title.textContent = step.title;
|
||||
text.textContent = step.text;
|
||||
|
||||
dots.innerHTML = onboardingSteps.map((_, i) =>
|
||||
`<div style="width:8px; height:8px; border-radius:50%; background:${i === onboardingStep ? 'var(--accent)' : '#475569'};"></div>`
|
||||
).join('');
|
||||
dots.replaceChildren();
|
||||
onboardingSteps.forEach((_, i) => {
|
||||
const dot = document.createElement('div');
|
||||
dot.style.cssText = `width:8px; height:8px; border-radius:50%; background:${i === onboardingStep ? 'var(--accent)' : '#475569'};`;
|
||||
dots.appendChild(dot);
|
||||
});
|
||||
|
||||
nextBtn.textContent = onboardingStep === onboardingSteps.length - 1 ? 'Done!' : 'Next';
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "koalasync",
|
||||
"version": "1.7.0",
|
||||
"version": "1.7.5",
|
||||
"description": "KoalaSync Build Scripts",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
+2
-2
@@ -54,8 +54,8 @@
|
||||
<span lang="de">Gemeinsam schauen.<br>Perfekt synchron.</span>
|
||||
</h1>
|
||||
<h2 class="hero-subtitle" data-reveal>
|
||||
<span lang="en">A free, open-source watch party extension for YouTube, Twitch, and local MP4s. Built for reliable synchronization and data sovereignty.</span>
|
||||
<span lang="de">Eine kostenlose, quelloffene Watch-Party-Erweiterung für YouTube, Twitch und lokale MP4s. Entwickelt für zuverlässige Synchronisation und Datenhoheit.</span>
|
||||
<span lang="en">A free, open-source watch party extension for YouTube, Twitch, Netflix, and almost any website with a video player. Built for reliable synchronization and data sovereignty.</span>
|
||||
<span lang="de">Eine kostenlose, quelloffene Watch-Party-Erweiterung für YouTube, Twitch, Netflix und fast jede Webseite mit einem Videoplayer. Entwickelt für zuverlässige Synchronisation und Datenhoheit.</span>
|
||||
</h2>
|
||||
<div class="cta-group" data-reveal>
|
||||
<a href="https://chromewebstore.google.com/detail/koalasync/obbnmkmlaaddodakcbdljknjpagklifc" class="btn btn-primary">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"version": "1.7.0",
|
||||
"date": "2026-05-25T10:30:48Z"
|
||||
"version": "1.7.5",
|
||||
"date": "2026-05-25T14:00:00Z"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user