diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index d01a9eb..0df0088 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -3,6 +3,9 @@ name: Build and Publish Container Image on: push: branches: [ main ] + tags: [ 'v*' ] + release: + types: [ published ] workflow_dispatch: jobs: @@ -32,9 +35,11 @@ jobs: with: images: ghcr.io/${{ github.repository_owner }}/nodecast-tv tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} type=sha type=ref,event=branch - type=raw,value=latest + type=raw,value=latest,enable={{is_default_branch}} - name: Build and push Container image uses: docker/build-push-action@v5 diff --git a/server/db.js b/server/db.js index ba6c817..0f5648c 100644 --- a/server/db.js +++ b/server/db.js @@ -144,8 +144,9 @@ const sources = { async delete(id) { const db = await loadDb(); db.sources = db.sources.filter(s => s.id !== parseInt(id)); - // Also delete related hidden items + // Also delete related hidden items and favorites db.hiddenItems = db.hiddenItems.filter(h => h.source_id !== parseInt(id)); + db.favorites = db.favorites.filter(f => f.source_id !== parseInt(id)); await saveDb(db); }, diff --git a/server/routes/sources.js b/server/routes/sources.js index 72c1352..615b4fb 100644 --- a/server/routes/sources.js +++ b/server/routes/sources.js @@ -1,6 +1,7 @@ const express = require('express'); const router = express.Router(); const { sources } = require('../db'); +const { getDb } = require('../db/sqlite'); const xtreamApi = require('../services/xtreamApi'); const syncService = require('../services/syncService'); @@ -108,11 +109,29 @@ router.put('/:id', async (req, res) => { // Delete source router.delete('/:id', async (req, res) => { try { - const existing = await sources.getById(req.params.id); + const sourceId = parseInt(req.params.id); + const existing = await sources.getById(sourceId); if (!existing) { return res.status(404).json({ error: 'Source not found' }); } - await sources.delete(req.params.id); + + // Cascade delete: Clean up SQLite data for this source + const db = getDb(); + const deleteCategories = db.prepare('DELETE FROM categories WHERE source_id = ?'); + const deleteItems = db.prepare('DELETE FROM playlist_items WHERE source_id = ?'); + const deleteEpg = db.prepare('DELETE FROM epg_programs WHERE source_id = ?'); + const deleteSyncStatus = db.prepare('DELETE FROM sync_status WHERE source_id = ?'); + + const catResult = deleteCategories.run(sourceId); + const itemResult = deleteItems.run(sourceId); + const epgResult = deleteEpg.run(sourceId); + deleteSyncStatus.run(sourceId); + + console.log(`[Source] Cascade delete for source ${sourceId}: ${catResult.changes} categories, ${itemResult.changes} items, ${epgResult.changes} EPG programs`); + + // Delete source config and related hidden items (favorites handled by db.js) + await sources.delete(sourceId); + res.json({ success: true }); } catch (err) { console.error('Error deleting source:', err);