Track version

pull/253/head
Broque Thomas 3 months ago
parent 1bec9320b4
commit 114af496c7

@ -36,6 +36,8 @@ jobs:
push: true
no-cache: true
pull: true
build-args: |
COMMIT_SHA=${{ github.sha }}
tags: |
boulderbadgedad/soulsync:latest
boulderbadgedad/soulsync:${{ inputs.version_tag }}

@ -3,6 +3,10 @@
FROM python:3.11-slim
# Build-time commit SHA for update detection
ARG COMMIT_SHA=""
ENV SOULSYNC_COMMIT_SHA=${COMMIT_SHA}
# Set working directory
WORKDIR /app

@ -11925,6 +11925,64 @@ def _automatic_wishlist_cleanup_after_db_update():
import traceback
traceback.print_exc()
# ── Update detection ─────────────────────────────────────────────
_GITHUB_REPO = "Nezreka/SoulSync"
_update_cache = {'latest_sha': None, 'last_check': 0, 'error': None}
_UPDATE_CHECK_INTERVAL = 3600 # 1 hour
def _get_current_commit_sha():
"""Get the commit SHA of the running instance (env var for Docker, git for local)."""
# Docker: baked in at build time via COMMIT_SHA build arg
sha = os.environ.get('SOULSYNC_COMMIT_SHA', '').strip()
if sha:
return sha
# Local dev: read from git
try:
import subprocess
result = subprocess.run(['git', 'rev-parse', 'HEAD'], capture_output=True, text=True, cwd=os.path.dirname(__file__) or '.')
if result.returncode == 0:
return result.stdout.strip()
except Exception:
pass
return None
_current_commit_sha = _get_current_commit_sha()
def _check_for_updates():
"""Check GitHub for the latest commit SHA on main branch."""
import time as _time
now = _time.time()
if now - _update_cache['last_check'] < _UPDATE_CHECK_INTERVAL:
return # Still fresh
_update_cache['last_check'] = now
try:
import urllib.request
import json as _json
req = urllib.request.Request(
f"https://api.github.com/repos/{_GITHUB_REPO}/commits/main",
headers={'Accept': 'application/vnd.github.v3+json', 'User-Agent': 'SoulSync-UpdateCheck'}
)
with urllib.request.urlopen(req, timeout=10) as resp:
data = _json.loads(resp.read().decode())
_update_cache['latest_sha'] = data.get('sha')
_update_cache['error'] = None
except Exception as e:
_update_cache['error'] = str(e)
logger.debug(f"Update check failed: {e}")
@app.route('/api/update-check', methods=['GET'])
def check_for_update():
"""Check if a newer version is available on GitHub."""
_check_for_updates()
current = _current_commit_sha
latest = _update_cache.get('latest_sha')
update_available = bool(current and latest and current != latest)
return jsonify({
'update_available': update_available,
'current_sha': current[:8] if current else None,
'latest_sha': latest[:8] if latest else None,
})
@app.route('/api/version-info', methods=['GET'])
def get_version_info():
"""

@ -1241,6 +1241,10 @@ function initApp() {
fetchAndUpdateServiceStatus();
setInterval(fetchAndUpdateServiceStatus, 10000); // Every 10 seconds (no-op when WebSocket active)
// Check for updates on load and every hour
checkForUpdates();
setInterval(checkForUpdates, 3600000);
// Refresh key data immediately when user returns to this tab
document.addEventListener('visibilitychange', () => {
if (!document.hidden) {
@ -12076,7 +12080,36 @@ function formatArtists(artists) {
return artistNames.join(', ') || 'Unknown Artist';
}
async function checkForUpdates() {
try {
const res = await fetch('/api/update-check');
if (!res.ok) return;
const data = await res.json();
const btn = document.querySelector('.version-button');
if (!btn) return;
if (data.update_available) {
const dismissed = localStorage.getItem('soulsync-update-dismissed');
if (dismissed !== data.latest_sha) {
btn.classList.add('update-available');
}
} else {
btn.classList.remove('update-available');
}
} catch (e) {
console.debug('Update check failed:', e);
}
}
async function showVersionInfo() {
// Dismiss update glow when user opens the modal (fire-and-forget, don't block modal)
const btn = document.querySelector('.version-button');
if (btn && btn.classList.contains('update-available')) {
btn.classList.remove('update-available');
fetch('/api/update-check').then(r => r.json()).then(data => {
if (data.latest_sha) localStorage.setItem('soulsync-update-dismissed', data.latest_sha);
}).catch(() => {});
}
try {
console.log('Fetching version info...');

@ -868,6 +868,23 @@ body {
transform: scale(0.97);
}
.version-button.update-available {
color: rgb(var(--accent-light-rgb));
border-color: rgba(var(--accent-rgb), 0.4);
animation: version-glow 2s ease-in-out infinite;
}
@keyframes version-glow {
0%, 100% {
box-shadow: 0 0 4px rgba(var(--accent-rgb), 0.2), 0 0 8px rgba(var(--accent-rgb), 0.1);
border-color: rgba(var(--accent-rgb), 0.3);
}
50% {
box-shadow: 0 0 8px rgba(var(--accent-rgb), 0.5), 0 0 20px rgba(var(--accent-rgb), 0.3), 0 0 30px rgba(var(--accent-rgb), 0.1);
border-color: rgba(var(--accent-rgb), 0.6);
}
}
/* Status Section - Premium Glassmorphic Design */
.status-section {
height: fit-content;

Loading…
Cancel
Save