correct application of playlists rules
This commit is contained in:
@@ -1,136 +1,244 @@
|
||||
CREATE TABLE IF NOT EXISTS video_summary AS
|
||||
SELECT
|
||||
v.file_name,
|
||||
v.raw_file,
|
||||
v.mp4_file,
|
||||
v.record_datetime,
|
||||
v.day_of_week,
|
||||
v.difficulty_level,
|
||||
v.address,
|
||||
GROUP_CONCAT(DISTINCT l.name) AS labels,
|
||||
GROUP_CONCAT(DISTINCT p.name) AS playlists
|
||||
FROM videos v
|
||||
LEFT JOIN video_labels vl ON vl.video_file_name = v.file_name
|
||||
LEFT JOIN labels l ON l.id = vl.label_id
|
||||
LEFT JOIN video_playlists vp ON vp.video_file_name = v.file_name
|
||||
LEFT JOIN playlists p ON p.id = vp.playlist_id
|
||||
GROUP BY v.file_name;
|
||||
-- ============================================================================
|
||||
-- VIEW : playlist_videos
|
||||
-- ============================================================================
|
||||
DROP VIEW IF EXISTS playlist_videos;
|
||||
|
||||
DROP VIEW playlist_videos;
|
||||
CREATE VIEW playlist_videos AS
|
||||
WITH
|
||||
-- Sous-requête pour les playlists manuelles
|
||||
manual_playlist_videos AS (
|
||||
-- 1️⃣ Playlists manuelles
|
||||
manual_playlists_videos AS (
|
||||
SELECT
|
||||
p.id AS playlist_id,
|
||||
p.name AS playlist_name,
|
||||
vp.video_file_name,
|
||||
v.*,
|
||||
'manual' AS playlist_type
|
||||
'manual' AS playlist_type,
|
||||
vp.video_file_name
|
||||
FROM playlists p
|
||||
JOIN video_playlists vp ON p.id = vp.playlist_id
|
||||
JOIN videos v ON vp.video_file_name = v.file_name
|
||||
WHERE p.type = 'manual'
|
||||
),
|
||||
|
||||
-- Sous-requête pour les playlists dynamiques
|
||||
dynamic_playlist_videos AS (
|
||||
-- 2️⃣ Dynamiques sans include/exclude
|
||||
dynamic_playlist_videos_base AS (
|
||||
SELECT DISTINCT
|
||||
p.id AS playlist_id,
|
||||
p.name AS playlist_name,
|
||||
v.file_name AS video_file_name,
|
||||
v.*,
|
||||
'dynamic' AS playlist_type
|
||||
'dynamic' AS playlist_type,
|
||||
v.file_name AS video_file_name
|
||||
FROM playlists p
|
||||
JOIN videos v
|
||||
WHERE p.type = 'dynamic'
|
||||
-- Inclure les vidéos qui ont les labels requis
|
||||
-- Labels inclus (AND/OR)
|
||||
AND (
|
||||
json_array_length(json_extract(p.rules_json, '$.include_labels')) = 0
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM labels l
|
||||
JOIN video_labels vl ON l.id = vl.label_id
|
||||
WHERE vl.video_file_name = v.file_name
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM (
|
||||
SELECT 0 AS n UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4
|
||||
-- Ajoute plus de lignes si tes tableaux JSON ont plus de 5 éléments
|
||||
) n
|
||||
WHERE n.n < json_array_length(json_extract(p.rules_json, '$.include_labels'))
|
||||
AND l.name = json_extract(
|
||||
json_extract(p.rules_json, '$.include_labels'),
|
||||
'$[' || n.n || ']'
|
||||
)
|
||||
OR (
|
||||
json_extract(p.rules_json, '$.label_logic') = 'OR'
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM json_each(json_extract(p.rules_json, '$.include_labels')) jl
|
||||
JOIN labels l ON l.name = jl.value
|
||||
JOIN video_labels vl ON vl.label_id = l.id AND vl.video_file_name = v.file_name
|
||||
)
|
||||
)
|
||||
OR (
|
||||
json_extract(p.rules_json, '$.label_logic') = 'AND'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM json_each(json_extract(p.rules_json, '$.include_labels')) jl
|
||||
WHERE jl.value NOT IN (
|
||||
SELECT l2.name
|
||||
FROM labels l2
|
||||
JOIN video_labels vl2 ON l2.id = vl2.label_id
|
||||
WHERE vl2.video_file_name = v.file_name
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
-- Exclure les vidéos qui ont les labels exclus
|
||||
-- Labels exclus
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM labels l
|
||||
JOIN video_labels vl ON l.id = vl.label_id
|
||||
WHERE vl.video_file_name = v.file_name
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM (
|
||||
SELECT 0 AS n UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4
|
||||
) n
|
||||
WHERE n.n < json_array_length(json_extract(p.rules_json, '$.exclude_labels'))
|
||||
AND l.name = json_extract(
|
||||
json_extract(p.rules_json, '$.exclude_labels'),
|
||||
'$[' || n.n || ']'
|
||||
)
|
||||
)
|
||||
SELECT 1 FROM json_each(json_extract(p.rules_json, '$.exclude_labels')) je
|
||||
JOIN labels lx ON lx.name = je.value
|
||||
JOIN video_labels vlx ON vlx.label_id = lx.id AND vlx.video_file_name = v.file_name
|
||||
)
|
||||
-- Inclure les vidéos qui sont dans les playlists requises
|
||||
AND (
|
||||
json_array_length(json_extract(p.rules_json, '$.include_playlists')) = 0
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM playlists pl
|
||||
JOIN video_playlists vp ON pl.id = vp.playlist_id
|
||||
WHERE vp.video_file_name = v.file_name
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM (
|
||||
SELECT 0 AS n UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4
|
||||
) n
|
||||
WHERE n.n < json_array_length(json_extract(p.rules_json, '$.include_playlists'))
|
||||
AND pl.name = json_extract(
|
||||
json_extract(p.rules_json, '$.include_playlists'),
|
||||
'$[' || n.n || ']'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
-- Exclure les vidéos qui sont dans les playlists exclues
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM playlists pl
|
||||
JOIN video_playlists vp ON pl.id = vp.playlist_id
|
||||
WHERE vp.video_file_name = v.file_name
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM (
|
||||
SELECT 0 AS n UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4
|
||||
) n
|
||||
WHERE n.n < json_array_length(json_extract(p.rules_json, '$.exclude_playlists'))
|
||||
AND pl.name = json_extract(
|
||||
json_extract(p.rules_json, '$.exclude_playlists'),
|
||||
'$[' || n.n || ']'
|
||||
)
|
||||
)
|
||||
)
|
||||
-- Filtrer par date si nécessaire
|
||||
-- Dates
|
||||
AND (
|
||||
json_extract(p.rules_json, '$.date_after') IS NULL
|
||||
OR v.record_datetime >= json_extract(p.rules_json, '$.date_after')
|
||||
OR (
|
||||
json_extract(p.rules_json, '$.date_delta_days') IS NOT NULL
|
||||
AND v.record_datetime >= date('now', (json_extract(p.rules_json, '$.date_delta_days') || ' days'))
|
||||
)
|
||||
)
|
||||
AND (
|
||||
json_extract(p.rules_json, '$.date_before') IS NULL
|
||||
OR v.record_datetime <= json_extract(p.rules_json, '$.date_before')
|
||||
)
|
||||
-- Difficulty / day / address
|
||||
AND (
|
||||
json_extract(p.rules_json, '$.difficulty') IS NULL
|
||||
OR v.difficulty_level = json_extract(p.rules_json, '$.difficulty')
|
||||
)
|
||||
AND (
|
||||
json_extract(p.rules_json, '$.day_of_week') IS NULL
|
||||
OR v.day_of_week = json_extract(p.rules_json, '$.day_of_week')
|
||||
)
|
||||
AND (
|
||||
json_extract(p.rules_json, '$.address_keyword') IS NULL
|
||||
OR (
|
||||
v.address NOT LIKE '%unknown%'
|
||||
AND v.address LIKE '%' || json_extract(p.rules_json, '$.address_keyword') || '%'
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
-- 3️⃣ Inclusions directes (parent → enfant)
|
||||
playlist_direct_includes AS (
|
||||
SELECT
|
||||
p.id AS parent_playlist_id,
|
||||
CAST(inc.value AS INTEGER) AS child_playlist_id
|
||||
FROM playlists p
|
||||
JOIN json_each(json_extract(p.rules_json, '$.include_playlists')) inc
|
||||
ON json_type(inc.value) IN ('integer', 'text')
|
||||
WHERE json_array_length(json_extract(p.rules_json, '$.include_playlists')) > 0
|
||||
),
|
||||
|
||||
-- 4️⃣ Récursion : parent → descendant (transitif)
|
||||
playlist_includes_recursive AS (
|
||||
WITH RECURSIVE rec(parent_playlist_id, child_playlist_id) AS (
|
||||
SELECT parent_playlist_id, child_playlist_id FROM playlist_direct_includes
|
||||
UNION ALL
|
||||
SELECT d.parent_playlist_id, di.child_playlist_id
|
||||
FROM playlist_direct_includes d
|
||||
JOIN rec di ON di.parent_playlist_id = d.child_playlist_id
|
||||
)
|
||||
SELECT DISTINCT parent_playlist_id AS parent_id, child_playlist_id AS child_id FROM rec
|
||||
),
|
||||
|
||||
-- 5️⃣ Exclusions directes et récursives
|
||||
playlist_direct_excludes AS (
|
||||
SELECT
|
||||
p.id AS parent_playlist_id,
|
||||
CAST(exc.value AS INTEGER) AS child_playlist_id
|
||||
FROM playlists p
|
||||
JOIN json_each(json_extract(p.rules_json, '$.exclude_playlists')) exc
|
||||
ON json_type(exc.value) IN ('integer', 'text')
|
||||
WHERE json_array_length(json_extract(p.rules_json, '$.exclude_playlists')) > 0
|
||||
),
|
||||
playlist_excludes_recursive AS (
|
||||
WITH RECURSIVE rec_ex(parent_playlist_id, child_playlist_id) AS (
|
||||
SELECT parent_playlist_id, child_playlist_id FROM playlist_direct_excludes
|
||||
UNION ALL
|
||||
SELECT d.parent_playlist_id, di.child_playlist_id
|
||||
FROM playlist_direct_excludes d
|
||||
JOIN rec_ex di ON di.parent_playlist_id = d.child_playlist_id
|
||||
)
|
||||
SELECT DISTINCT parent_playlist_id AS parent_id, child_playlist_id AS child_id FROM rec_ex
|
||||
),
|
||||
|
||||
-- 6️⃣ Vidéos issues des playlists incluses
|
||||
playlist_included_videos AS (
|
||||
SELECT pir.parent_id AS parent_playlist_id, mpv.video_file_name
|
||||
FROM playlist_includes_recursive pir
|
||||
JOIN manual_playlists_videos mpv ON mpv.playlist_id = pir.child_id
|
||||
UNION
|
||||
SELECT pir.parent_id AS parent_playlist_id, dpb.video_file_name
|
||||
FROM playlist_includes_recursive pir
|
||||
JOIN dynamic_playlist_videos_base dpb ON dpb.playlist_id = pir.child_id
|
||||
),
|
||||
|
||||
-- 7️⃣ Inclusion logique OR
|
||||
playlist_includes_union AS (
|
||||
SELECT DISTINCT db.playlist_id, db.playlist_name, db.playlist_type, db.video_file_name
|
||||
FROM dynamic_playlist_videos_base db
|
||||
JOIN playlists p ON p.id = db.playlist_id
|
||||
WHERE json_extract(p.rules_json, '$.logic') = 'OR'
|
||||
UNION
|
||||
SELECT DISTINCT iv.parent_playlist_id AS playlist_id,
|
||||
(SELECT name FROM playlists WHERE id = iv.parent_playlist_id) AS playlist_name,
|
||||
'dynamic' AS playlist_type,
|
||||
iv.video_file_name
|
||||
FROM playlist_included_videos iv
|
||||
JOIN playlists p ON p.id = iv.parent_playlist_id
|
||||
WHERE json_extract(p.rules_json, '$.logic') = 'OR'
|
||||
),
|
||||
|
||||
-- 8️⃣ Inclusion logique AND (+ fallback si 0 include)
|
||||
playlist_includes_intersection AS (
|
||||
SELECT DISTINCT db.playlist_id, db.playlist_name, db.playlist_type, db.video_file_name
|
||||
FROM dynamic_playlist_videos_base db
|
||||
JOIN playlists p ON p.id = db.playlist_id
|
||||
WHERE json_extract(p.rules_json, '$.logic') = 'AND'
|
||||
AND json_array_length(json_extract(p.rules_json, '$.include_playlists')) > 0
|
||||
AND db.video_file_name IN (
|
||||
SELECT iv.video_file_name
|
||||
FROM playlist_included_videos iv
|
||||
WHERE iv.parent_playlist_id = db.playlist_id
|
||||
)
|
||||
UNION ALL
|
||||
SELECT DISTINCT db.playlist_id, db.playlist_name, db.playlist_type, db.video_file_name
|
||||
FROM dynamic_playlist_videos_base db
|
||||
JOIN playlists p ON p.id = db.playlist_id
|
||||
WHERE json_extract(p.rules_json, '$.logic') = 'AND'
|
||||
AND (
|
||||
json_array_length(json_extract(p.rules_json, '$.include_playlists')) IS NULL
|
||||
OR json_array_length(json_extract(p.rules_json, '$.include_playlists')) = 0
|
||||
)
|
||||
),
|
||||
|
||||
-- 9️⃣ Fusion des deux logiques d’inclusion
|
||||
playlist_after_includes AS (
|
||||
SELECT * FROM playlist_includes_union
|
||||
UNION ALL
|
||||
SELECT * FROM playlist_includes_intersection
|
||||
),
|
||||
|
||||
-- 🔟 Vidéos exclues (via exclude_playlists récursif)
|
||||
playlist_excluded_videos AS (
|
||||
SELECT per.parent_id AS parent_playlist_id, mpv.video_file_name
|
||||
FROM playlist_excludes_recursive per
|
||||
JOIN manual_playlists_videos mpv ON mpv.playlist_id = per.child_id
|
||||
UNION
|
||||
SELECT per.parent_id AS parent_playlist_id, dpb.video_file_name
|
||||
FROM playlist_excludes_recursive per
|
||||
JOIN dynamic_playlist_videos_base dpb ON dpb.playlist_id = per.child_id
|
||||
),
|
||||
|
||||
-- 1️⃣1️⃣ Application des exclusions
|
||||
playlist_after_excludes AS (
|
||||
SELECT pai.playlist_id, pai.playlist_name, pai.playlist_type, pai.video_file_name
|
||||
FROM playlist_after_includes pai
|
||||
LEFT JOIN playlist_excluded_videos pev
|
||||
ON pev.parent_playlist_id = pai.playlist_id AND pev.video_file_name = pai.video_file_name
|
||||
WHERE pev.parent_playlist_id IS NULL
|
||||
)
|
||||
|
||||
-- Union des deux types de playlists
|
||||
SELECT * FROM manual_playlist_videos
|
||||
-- 1️⃣2️⃣ Résultat final : union manuelles + dynamiques
|
||||
SELECT playlist_id, playlist_name, playlist_type, video_file_name
|
||||
FROM manual_playlists_videos
|
||||
UNION ALL
|
||||
SELECT * FROM dynamic_playlist_videos;
|
||||
SELECT playlist_id, playlist_name, playlist_type, video_file_name
|
||||
FROM playlist_after_excludes;
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- TABLE AGRÉGÉE : video_summary
|
||||
-- ============================================================================
|
||||
DROP VIEW IF EXISTS video_summary;
|
||||
|
||||
CREATE VIEW video_summary AS
|
||||
SELECT
|
||||
v.file_name,
|
||||
v.raw_file,
|
||||
v.mp4_file,
|
||||
v.record_datetime,
|
||||
v.day_of_week,
|
||||
v.difficulty_level,
|
||||
v.address,
|
||||
GROUP_CONCAT(DISTINCT l.name) AS labels,
|
||||
GROUP_CONCAT(DISTINCT pv.playlist_name) AS playlists
|
||||
FROM videos v
|
||||
LEFT JOIN video_labels vl ON vl.video_file_name = v.file_name
|
||||
LEFT JOIN labels l ON l.id = vl.label_id
|
||||
LEFT JOIN playlist_videos pv ON pv.video_file_name = v.file_name
|
||||
GROUP BY v.file_name;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS video_summary_materialized AS
|
||||
SELECT * FROM video_summary;
|
||||
Reference in New Issue
Block a user