16 Commits
16 changed files with 468 additions and 32 deletions
+2 -1
View File
@@ -18,4 +18,5 @@ wheels/
data data
.vscode/* .vscode/*
*.tar
+28
View File
@@ -1,5 +1,33 @@
# Eurovision 25 Backend Changelog # Eurovision 25 Backend Changelog
## 1.0rc8 (2025-05-17)
### Features
- Add more result types (b4fa3aa)
### Fixes
- Fix regression in db seeding (0862405)
### Chores
- Add docker exports to git ignore (1a3a2ae)
## 1.0rc7 (2025-05-16)
### Features
- Added artist image URL to song endpoint
## 1.0rc6 (2025-05-16)
### Features
- Added ability for users to change their password and avatar image
## 1.0rc5 (2025-05-16)
### Changes
- Updated dependencies to latest versions
- Changed API documentation for security reasons
## 1.0rc4 (2025-05-16) ## 1.0rc4 (2025-05-16)
### Features ### Features
+3
View File
@@ -1,5 +1,7 @@
# Eurovision 25 Homereview Backend # Eurovision 25 Homereview Backend
**Version: 1.0rc8**
## Description ## Description
This project provides the backend API for the "Eurovision 25 Homereview" application. It allows a small, known group of users, organized into households/groups, to collaboratively review and score Eurovision Song Contest entries during the live show. Users submit numerical scores (1-100) for stage show, wardrobe, and song quality, along with optional text comments. Users can update their scores until the contest is marked as finished by an admin. Afterward, users can view aggregated results within their group or across all participants, including basic statistics. This project provides the backend API for the "Eurovision 25 Homereview" application. It allows a small, known group of users, organized into households/groups, to collaboratively review and score Eurovision Song Contest entries during the live show. Users submit numerical scores (1-100) for stage show, wardrobe, and song quality, along with optional text comments. Users can update their scores until the contest is marked as finished by an admin. Afterward, users can view aggregated results within their group or across all participants, including basic statistics.
@@ -224,6 +226,7 @@ Automated tests are not implemented at this time. Manual testing via the API doc
* [x] Implement more comprehensive logging * [x] Implement more comprehensive logging
* [ ] Implement user disabling functionality * [ ] Implement user disabling functionality
* [x] Implement user profile update functionality (name, email, password, avatar, etc.) * [x] Implement user profile update functionality (name, email, password, avatar, etc.)
* [x] Fix avatar upload size validation
## Contributing ## Contributing
+1 -1
View File
@@ -8,7 +8,7 @@ services:
build: build:
context: . context: .
dockerfile: Dockerfile dockerfile: Dockerfile
image: eurovision-25-backend:1.0rc4 image: eurovision-25-backend:1.0rc8
ports: ports:
- "8000:8000" - "8000:8000"
volumes: volumes:
+14
View File
@@ -0,0 +1,14 @@
# Version update
Here is the workflow for updating the version of the project.
1. Update version in `pyproject.toml`
2. Update version in `uv.lock`
3. Update version in `src/app.py`
4. Update version in `docker-compose.yml`
5. Update `CHANGES.md`. Take info from git log
6. Update `README.md`
7. Commit changes
8. Tag release
9. Push changes
10. Export docker image to tar file. File name should be `eurovision-25-backend-{version}.tar`
+1 -1
View File
@@ -1,6 +1,6 @@
[project] [project]
name = "Eurovision-25-backend" name = "Eurovision-25-backend"
version = "1.0rc4" version = "1.0rc8"
description = "Backend for Eurovision 25" description = "Backend for Eurovision 25"
readme = "README.md" readme = "README.md"
requires-python = ">=3.12" requires-python = ">=3.12"
+4 -1
View File
@@ -12,7 +12,10 @@ from lib.db import init_db
app = FastAPI( app = FastAPI(
title="Eurovision 25 Homereview API", title="Eurovision 25 Homereview API",
description="Backend API for Eurovision 25 Homereview application", description="Backend API for Eurovision 25 Homereview application",
version="1.0rc3", version="1.0rc8",
openapi_url="/sec_schema.json",
docs_url="/docut",
redoc_url=None,
) )
+99 -3
View File
@@ -11,8 +11,10 @@ DROP TABLE IF EXISTS "User"; -- Quoted because USER is a reserved keyword
DROP TABLE IF EXISTS Team; DROP TABLE IF EXISTS Team;
DROP TABLE IF EXISTS Contest; DROP TABLE IF EXISTS Contest;
DROP TABLE IF EXISTS CountryCodes; DROP TABLE IF EXISTS CountryCodes;
DROP VIEW IF EXISTS ReviewSummary; DROP VIEW IF EXISTS ReviewSummaryGlobal;
DROP VIEW IF EXISTS ReviewSummaryByTeam; DROP VIEW IF EXISTS ReviewSummaryByTeam;
DROP VIEW IF EXISTS ReviewSummaryByUser;
DROP VIEW IF EXISTS ReviewAllSongs;
DROP SEQUENCE IF EXISTS group_id_seq; DROP SEQUENCE IF EXISTS group_id_seq;
DROP SEQUENCE IF EXISTS user_id_seq; DROP SEQUENCE IF EXISTS user_id_seq;
@@ -89,6 +91,7 @@ CREATE TABLE Song (
artist VARCHAR NOT NULL, -- The name of the performing artist(s) artist VARCHAR NOT NULL, -- The name of the performing artist(s)
title VARCHAR NOT NULL, -- The title of the song title VARCHAR NOT NULL, -- The title of the song
running_order INTEGER NOT NULL, -- Official order in the show (nullable) running_order INTEGER NOT NULL, -- Official order in the show (nullable)
img_url VARCHAR, -- URL to the artist image (nullable)
lyrics_url VARCHAR, -- URL to the original lyrics (nullable) lyrics_url VARCHAR, -- URL to the original lyrics (nullable)
artist_url VARCHAR, -- URL to the artist's page (nullable) artist_url VARCHAR, -- URL to the artist's page (nullable)
flag_url VARCHAR, -- URL to the country flag (nullable) flag_url VARCHAR, -- URL to the country flag (nullable)
@@ -176,6 +179,44 @@ JOIN CountryCodes cc ON s.country = cc.code
GROUP BY r.song_id, u.team_id, cc.name_fi, cc.name_sv, s.artist, s.title GROUP BY r.song_id, u.team_id, cc.name_fi, cc.name_sv, s.artist, s.title
ORDER BY avg_total_score DESC; ORDER BY avg_total_score DESC;
CREATE VIEW ReviewSummaryByUser AS
SELECT
r.song_id,
cc.name_fi AS country_fi,
cc.name_sv AS country_sv,
s.artist,
s.title,
u.id AS user_id,
COUNT(*) AS total_reviews,
AVG(r.score_song) AS avg_score_song,
AVG(r.score_show) AS avg_score_show,
AVG(r.score_costume) AS avg_score_costume,
AVG((r.score_song + r.score_show + r.score_costume)/3) AS avg_total_score
FROM Review r
JOIN "User" u ON r.user_id = u.id
JOIN Song s ON r.song_id = s.id
JOIN CountryCodes cc ON s.country = cc.code
GROUP BY r.song_id, u.id, cc.name_fi, cc.name_sv, s.artist, s.title
ORDER BY avg_total_score DESC;
CREATE VIEW ReviewAllSongs AS
SELECT
r.song_id,
cc.name_fi AS country_fi,
cc.name_sv AS country_sv,
s.artist,
s.title,
COUNT(*) AS total_reviews,
AVG(r.score_song) AS avg_score_song,
AVG(r.score_show) AS avg_score_show,
AVG(r.score_costume) AS avg_score_costume,
AVG((r.score_song + r.score_show + r.score_costume)/3) AS avg_total_score
FROM Review r
JOIN Song s ON r.song_id = s.id
JOIN CountryCodes cc ON s.country = cc.code
GROUP BY r.song_id, cc.name_fi, cc.name_sv, s.artist, s.title
ORDER BY avg_total_score DESC;
-- Insert country codes data -- Insert country codes data
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('ALB', 'Albania', 'Albania', 'Albanien'); INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('ALB', 'Albania', 'Albania', 'Albanien');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('ARM', 'Armenia', 'Armenia', 'Armenien'); INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('ARM', 'Armenia', 'Armenia', 'Armenien');
@@ -217,7 +258,61 @@ INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('GBR', 'Unite
-- TODO: Clean this next year. Its now here just to get the show running -- TODO: Clean this next year. Its now here just to get the show running
INSERT INTO Contest (year, finals_date) VALUES (2025, '2025-05-16'); -- INSERT INTO Contest (year, finals_date) VALUES (2025, '2025-05-16');
-- =============================================================================
-- DEBUG DATA
-- =============================================================================
-- Insert Sample Teams
-- INSERT INTO "Team" (name) VALUES ('The Eurovisionaries');
-- INSERT INTO "Team" (name) VALUES ('douze_points_posse');
-- -- Insert Sample Users (Passwords are 'password' hashed with bcrypt - for debug only!)
-- -- For Team 1 (The Eurovisionaries)
-- INSERT INTO "User" (username, first_name, last_name, hashed_password, email, team_id, avatar_id, is_admin)
-- VALUES ('debuguser1', 'Debug', 'UserOne', '$2b$12$7.xP5Y6.K7kZ5yL0HjEPIOjBqzsRcg8yU/gQcNcmauHAFsdn7Y2tu', '[email protected]', (SELECT id FROM "Team" WHERE name = 'The Eurovisionaries'), 1, FALSE);
-- INSERT INTO "User" (username, first_name, last_name, hashed_password, email, team_id, avatar_id, is_admin)
-- VALUES ('debugadmin', 'Debug', 'Admin', '$2b$12$7.xP5Y6.K7kZ5yL0HjEPIOjBqzsRcg8yU/gQcNcmauHAFsdn7Y2tu', '[email protected]', (SELECT id FROM "Team" WHERE name = 'The Eurovisionaries'), 2, TRUE);
-- -- For Team 2 (douze_points_posse)
-- INSERT INTO "User" (username, first_name, last_name, hashed_password, email, team_id, avatar_id, is_admin)
-- VALUES ('debuguser2', 'Another', 'Debugger', '$2b$12$7.xP5Y6.K7kZ5yL0HjEPIOjBqzsRcg8yU/gQcNcmauHAFsdn7Y2tu', '[email protected]', (SELECT id FROM "Team" WHERE name = 'douze_points_posse'), 3, FALSE);
-- -- Insert Sample Songs for Contest 2025
-- -- Assuming a contest with id=1 (or use (SELECT id FROM Contest WHERE year = 2025) if only one entry)
-- INSERT INTO Song (year, country, artist, title, running_order, img_url, language, confidence)
-- VALUES
-- (2025, 'SWE', 'Swedish Singers', 'Dancing in Stockholm', 1, 'https://example.com/swe.jpg', 'English', 0.95),
-- (2025, 'FIN', 'Finnish Rockers', 'Sauna Anthem', 2, 'https://example.com/fin.jpg', 'Finnish', 0.90),
-- (2025, 'NOR', 'Nordic Balladeers', 'Fjord Dreams', 3, 'https://example.com/nor.jpg', 'Norwegian', 0.85),
-- (2025, 'ITA', 'Italian Pop Sensations', 'Roman Holiday', 4, 'https://example.com/ita.jpg', 'Italian', 0.92),
-- (2025, 'GER', 'German Electro Duo', 'Berlin Beats', 5, 'https://example.com/ger.jpg', 'German', 0.88);
-- -- Insert Sample Reviews
-- -- User 1 reviews Song 1 and Song 2
-- INSERT INTO Review (user_id, song_id, score_song, score_show, score_costume, text_review)
-- VALUES
-- ((SELECT id FROM "User" WHERE username = 'debuguser1'), (SELECT id FROM Song WHERE title = 'Dancing in Stockholm'), 80, 75, 70, 'Great song!'),
-- ((SELECT id FROM "User" WHERE username = 'debuguser1'), (SELECT id FROM Song WHERE title = 'Sauna Anthem'), 90, 85, 80, 'Loved the energy!');
-- -- User 2 reviews Song 2 and Song 3
-- INSERT INTO Review (user_id, song_id, score_song, score_show, score_costume, text_review)
-- VALUES
-- ((SELECT id FROM "User" WHERE username = 'debuguser2'), (SELECT id FROM Song WHERE title = 'Sauna Anthem'), 88, 82, 78, 'Rock on Finland!'),
-- ((SELECT id FROM "User" WHERE username = 'debuguser2'), (SELECT id FROM Song WHERE title = 'Fjord Dreams'), 70, 65, 60, 'A bit slow for me.');
-- -- Admin reviews Song 1
-- INSERT INTO Review (user_id, song_id, score_song, score_show, score_costume, text_review)
-- VALUES
-- ((SELECT id FROM "User" WHERE username = 'debugadmin'), (SELECT id FROM Song WHERE title = 'Dancing in Stockholm'), 99, 92, 1, 'Absolutely stellar! A clear frontrunner!'),
-- -- More reviews with varied scores
-- ((SELECT id FROM "User" WHERE username = 'debuguser1'), (SELECT id FROM Song WHERE title = 'Roman Holiday'), 42, 23, 23, 'The song was okay, staging average, costumes needed work.'),
-- ((SELECT id FROM "User" WHERE username = 'debuguser1'), (SELECT id FROM Song WHERE title = 'Berlin Beats'), 96, 91, 87, 'Incredible energy and visuals! Loved it!'),
-- ((SELECT id FROM "User" WHERE username = 'debuguser2'), (SELECT id FROM Song WHERE title = 'Dancing in Stockholm'), 68, 77, 53, 'Decent entry, but not outstanding. Costumes were a bit plain.'),
-- ((SELECT id FROM "User" WHERE username = 'debuguser2'), (SELECT id FROM Song WHERE title = 'Roman Holiday'), 12, 33, 7, 'Really disliked this one. Song was boring, show forgettable, and costumes awful.'),
-- ((SELECT id FROM "User" WHERE username = 'debugadmin'), (SELECT id FROM Song WHERE title = 'Sauna Anthem'), 100, 11, 99, 'Perfection! Finland has outdone themselves!'),
-- ((SELECT id FROM "User" WHERE username = 'debugadmin'), (SELECT id FROM Song WHERE title = 'Berlin Beats'), 2, 94, 78, 'Strong contender. Great production, though costumes could be more imaginative.');
-- ============================================================================= -- =============================================================================
-- Views (Optional - Not Created Here Based on Documentation Decision) -- Views (Optional - Not Created Here Based on Documentation Decision)
-- ============================================================================= -- =============================================================================
@@ -225,4 +320,5 @@ INSERT INTO Contest (year, finals_date) VALUES (2025, '2025-05-16');
-- layer. No CREATE VIEW statements are included. -- layer. No CREATE VIEW statements are included.
-- ============================================================================= -- =============================================================================
-- End of Schema Definition -- End of Schema Definition
+150
View File
@@ -0,0 +1,150 @@
-- PostgreSQL Schema Definition for Eurovision 25 Homereview Backend
-- Converted from DuckDB schema
-- Target Database: PostgreSQL
-- Note: Timestamps default to creation time; application logic should handle 'updated_at' updates.
-- Drop objects in reverse order of dependency and existence check
DROP TABLE IF EXISTS Review;
DROP TABLE IF EXISTS Song;
DROP TABLE IF EXISTS "User"; -- Quoted because USER is a reserved keyword
DROP TABLE IF EXISTS Team;
DROP TABLE IF EXISTS CountryCodes;
-- =============================================================================
-- Table: Group
-- Stores information about the different households or groups participating.
-- =============================================================================
CREATE TABLE "Team" (
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, -- Use IDENTITY for auto-increment
name VARCHAR(255) UNIQUE NOT NULL, -- The name of the household/group
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- Timestamp when the group was created
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -- Timestamp when the group was last updated
);
-- =============================================================================
-- Table: User
-- Stores information about individual users (players and admins).
-- =============================================================================
CREATE TABLE "User" (
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, -- Use IDENTITY for auto-increment
username VARCHAR(255) UNIQUE NOT NULL, -- The user's login name
hashed_password VARCHAR(255) NOT NULL, -- The securely hashed password
email VARCHAR(255) UNIQUE, -- User's email address (nullable)
team_id INTEGER NOT NULL, -- Foreign Key -> Group.id
avatar_id INTEGER DEFAULT 0 NOT NULL, -- Identifier for the user's avatar
is_active BOOLEAN DEFAULT TRUE NOT NULL, -- Flag indicating if the user account is active
is_admin BOOLEAN DEFAULT FALSE NOT NULL, -- Flag indicating if the user has admin privileges
last_login TIMESTAMP DEFAULT '1970-01-01 00:00:00', -- Timestamp when the user was last logged in. Epoch (1970-01-01) means "never logged in"
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- Timestamp when the user was created
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- Timestamp when the user was last updated
FOREIGN KEY (team_id) REFERENCES "Team"(id) -- Link to the Team table
);
-- =============================================================================
-- Table: Song
-- Stores information about each participating song in the contest.
-- =============================================================================
CREATE TABLE Song (
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, -- Use IDENTITY for auto-increment
year INTEGER NOT NULL, -- The year of the Eurovision contest
country VARCHAR(255) NOT NULL, -- The participating country name
artist VARCHAR(255) NOT NULL, -- The name of the performing artist(s)
title VARCHAR(255) NOT NULL, -- The title of the song
running_order INTEGER NOT NULL, -- Official order in the show (nullable)
lyrics_url VARCHAR(255), -- URL to the original lyrics (nullable)
artist_url VARCHAR(255), -- URL to the artist's page (nullable)
flag_url VARCHAR(255), -- URL to the country flag (nullable)
lyrics_original TEXT, -- Original lyrics (nullable)
lyrics_translation_fi TEXT, -- Finnish translation (nullable)
tags TEXT[], -- Array of tags (PostgreSQL array type)
confidence FLOAT NOT NULL DEFAULT 0.0, -- Confidence level of the translation (nullable)
language VARCHAR(50) NOT NULL, -- Language of the song (nullable)
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- Timestamp when the song entry was created
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -- Timestamp when the song entry was last updated
);
-- Add index for faster lookups by year as specified in documentation
CREATE INDEX idx_song_year ON Song (year);
-- =============================================================================
-- Table: Review
-- Stores the scores and comments submitted by a user for a specific song.
-- =============================================================================
CREATE TABLE Review (
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, -- Use IDENTITY for auto-increment
user_id INTEGER NOT NULL, -- Foreign Key -> User.id
song_id INTEGER NOT NULL, -- Foreign Key -> Song.id
score_song INTEGER NOT NULL, -- Score (1-100) for song quality
score_show INTEGER NOT NULL, -- Score (1-100) for the stage show
score_costume INTEGER NOT NULL, -- Score (1-100) for wardrobe/costumes
text_review TEXT, -- Optional textual comments (nullable)
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- Timestamp when the review was created
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- Timestamp when the review was last modified
FOREIGN KEY (user_id) REFERENCES "User"(id), -- Link to the User table
FOREIGN KEY (song_id) REFERENCES Song(id), -- Link to the Song table
-- Ensure scores are within the valid range (1-100)
CHECK (score_song >= 1 AND score_song <= 100),
CHECK (score_show >= 1 AND score_show <= 100),
CHECK (score_costume >= 1 AND score_costume <= 100),
-- Ensure each user can only submit one review per song
UNIQUE (user_id, song_id)
);
CREATE TABLE CountryCodes (
code VARCHAR(10) PRIMARY KEY,
name_en VARCHAR(255) NOT NULL,
name_fi VARCHAR(255) NOT NULL,
name_sv VARCHAR(255) NOT NULL
);
-- Insert country codes data
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('ALB', 'Albania', 'Albania', 'Albanien');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('ARM', 'Armenia', 'Armenia', 'Armenien');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('AUS', 'Australia', 'Australia', 'Australien');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('AUT', 'Austria', 'Itävalta', 'Österrike');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('AZE', 'Azerbaijan', 'Azerbaidžan', 'Azerbajdzjan');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('BEL', 'Belgium', 'Belgia', 'Belgien');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('HRV', 'Croatia', 'Kroatia', 'Kroatien');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('CYP', 'Cyprus', 'Kypros', 'Cypern');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('CZE', 'Czechia', 'Tšekki', 'Tjeckien');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('DNK', 'Denmark', 'Tanska', 'Danmark');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('EST', 'Estonia', 'Viro', 'Estland');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('FIN', 'Finland', 'Suomi', 'Finland');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('FRA', 'France', 'Ranska', 'Frankrike');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('GEO', 'Georgia', 'Georgia', 'Georgien');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('DEU', 'Germany', 'Saksa', 'Tyskland');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('GRC', 'Greece', 'Kreikka', 'Grekland');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('ISL', 'Iceland', 'Islanti', 'Island');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('IRL', 'Ireland', 'Irlanti', 'Irland');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('ISR', 'Israel', 'Israel', 'Israel');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('ITA', 'Italy', 'Italia', 'Italien');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('LVA', 'Latvia', 'Latvia', 'Lettland');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('LTU', 'Lithuania', 'Liettua', 'Litauen');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('LUX', 'Luxembourg', 'Luxemburg', 'Luxemburg');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('MLT', 'Malta', 'Malta', 'Malta');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('MNE', 'Montenegro', 'Montenegro', 'Montenegro');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('NLD', 'Netherlands', 'Alankomaat', 'Nederländerna');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('NOR', 'Norway', 'Norja', 'Norge');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('POL', 'Poland', 'Puola', 'Polen');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('PRT', 'Portugal', 'Portugali', 'Portugal');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('SMR', 'San Marino', 'San Marino', 'San Marino');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('SRB', 'Serbia', 'Serbia', 'Serbien');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('SVN', 'Slovenia', 'Slovenia', 'Slovenien');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('ESP', 'Spain', 'Espanja', 'Spanien');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('SWE', 'Sweden', 'Ruotsi', 'Sverige');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('CHE', 'Switzerland', 'Sveitsi', 'Schweiz');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('UKR', 'Ukraine', 'Ukraina', 'Ukraina');
INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('GBR', 'United Kingdom', 'Englanti', 'Storbritannien');
-- =============================================================================
-- Views (Optional - Not Created Here Based on Documentation Decision)
-- =============================================================================
-- The documentation suggests performing result aggregations in the application
-- layer. No CREATE VIEW statements are included.
-- =============================================================================
-- End of Schema Definition
+2 -1
View File
@@ -36,12 +36,13 @@ def seed_db() -> None:
with get_connection() as conn: with get_connection() as conn:
logger.debug(f"Inserting song {idx + 1} of {len(data)}", item) logger.debug(f"Inserting song {idx + 1} of {len(data)}", item)
conn.execute( conn.execute(
"INSERT INTO Song (year, artist, country, title, lyrics_url, artist_url, flag_url, running_order, lyrics_original, lyrics_translation_fi, tags, confidence, language) VALUES (2025, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", "INSERT INTO Song (year, artist, country, title, lyrics_url, img_url, artist_url, flag_url, running_order, lyrics_original, lyrics_translation_fi, tags, confidence, language) VALUES (2025, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
( (
item["artist"], item["artist"],
item["country"], item["country"],
item["title"], item["title"],
item["lyrics_url"], item["lyrics_url"],
item["img_url"],
item["artist_url"], item["artist_url"],
item["flag_url"], item["flag_url"],
item["running_order"], item["running_order"],
+40 -14
View File
@@ -4,6 +4,7 @@
"country": "ARM", "country": "ARM",
"title": "SURVIVOR", "title": "SURVIVOR",
"lyrics_url": "https://genius.com/Parg-survivor-lyrics", "lyrics_url": "https://genius.com/Parg-survivor-lyrics",
"img_url": "https://eurovision.tv/sites/default/files/styles/teaser/public/media/image/2025-05/250508_Corinne-Cumming_EBU_00871.jpg?h=a7aa5b77&itok=xmVAnwjY",
"artist_url": "https://eurovision.tv/participant/parg-2025", "artist_url": "https://eurovision.tv/participant/parg-2025",
"flag_url": "https://eurovision.tv/sites/default/files/media/image/2023-08/ESC-HEART-ARMENIA-WHITE.png", "flag_url": "https://eurovision.tv/sites/default/files/media/image/2023-08/ESC-HEART-ARMENIA-WHITE.png",
"lyrics_original": "[Intro]\n Survivor\n\n [Verse 1]\n I got my bad shades on (Oh)\nJet black, I'm in my zone (Ah)\nI'm sick of the news, I'm sick of the views\nI'm sick of the lies they've told (Yes)\nCome on andshinethelight (Okay)\nCome onand shine onme (Woah)\nGuess you can see, I don't believe\nAnythin' they told me\n\n[Pre-Chorus]\nLettin' me down, liftin' me up (Up)\nKeepin' me slow, I don't give up (Up)\nIt's tearin' me apart, I'm alive\nTry to look up, atop of a rock (Yeah)\nClimbin' these heights\nMan, I can't stop at all\nI'm standin' tall\n\n[Chorus]\nI'm a survivor, stay-aliver\nDo or die, in my prime, I'm a fighter\nI'm a survivor, won't be tied up\nBreak from the pain, take your place\nI'll remind ya\n\n[Post-Chorus]\nI'm a survivor (La, la-la-la, la-la-la, survivor)\n(La, la-la-la-la-la-la-la, survivor)\n(La, la-la-la, la-la-la, survivor)\nBreak from the pain, take your place\nI'll remind ya\n\n[Verse 2]\nKickin' me, breakin' me, but I won't stop\nPushin' me, pulling me, I will get up\nHittin' me, mockin' me, stabbin' me, crushin' me\nTearin' me, burnin' me, I'll never stop\nI could have lost my way\nI could have made mistakes\nI bled a lot, more than you thought\nBut I didn't fade away (Oh)\n\n[Pre-Chorus]\nSay you'll break me down (Down)\nAnd bring me to my knees (Knees)\nYou can do it, can you prove it?\nBut you ain't got shit on me\nHa-ha-ha-ha-ha-ha", "lyrics_original": "[Intro]\n Survivor\n\n [Verse 1]\n I got my bad shades on (Oh)\nJet black, I'm in my zone (Ah)\nI'm sick of the news, I'm sick of the views\nI'm sick of the lies they've told (Yes)\nCome on andshinethelight (Okay)\nCome onand shine onme (Woah)\nGuess you can see, I don't believe\nAnythin' they told me\n\n[Pre-Chorus]\nLettin' me down, liftin' me up (Up)\nKeepin' me slow, I don't give up (Up)\nIt's tearin' me apart, I'm alive\nTry to look up, atop of a rock (Yeah)\nClimbin' these heights\nMan, I can't stop at all\nI'm standin' tall\n\n[Chorus]\nI'm a survivor, stay-aliver\nDo or die, in my prime, I'm a fighter\nI'm a survivor, won't be tied up\nBreak from the pain, take your place\nI'll remind ya\n\n[Post-Chorus]\nI'm a survivor (La, la-la-la, la-la-la, survivor)\n(La, la-la-la-la-la-la-la, survivor)\n(La, la-la-la, la-la-la, survivor)\nBreak from the pain, take your place\nI'll remind ya\n\n[Verse 2]\nKickin' me, breakin' me, but I won't stop\nPushin' me, pulling me, I will get up\nHittin' me, mockin' me, stabbin' me, crushin' me\nTearin' me, burnin' me, I'll never stop\nI could have lost my way\nI could have made mistakes\nI bled a lot, more than you thought\nBut I didn't fade away (Oh)\n\n[Pre-Chorus]\nSay you'll break me down (Down)\nAnd bring me to my knees (Knees)\nYou can do it, can you prove it?\nBut you ain't got shit on me\nHa-ha-ha-ha-ha-ha",
@@ -25,6 +26,7 @@
"title": "Zjerm", "title": "Zjerm",
"running_order": 26, "running_order": 26,
"lyrics_url": "https://genius.com/Shkodra-elektronike-zjerm-lyrics", "lyrics_url": "https://genius.com/Shkodra-elektronike-zjerm-lyrics",
"img_url": "https://eurovision.tv/sites/default/files/styles/teaser/public/media/image/2025-05/250507_Corinne-Cumming_EBU_00462_0.jpg?h=868502f4&itok=JDYPbVwT",
"artist_url": "https://eurovision.tv/participant/shkodra_elektronike-2025", "artist_url": "https://eurovision.tv/participant/shkodra_elektronike-2025",
"flag_url": "https://eurovision.tv/sites/default/files/media/image/2023-08/ESC-HEART-ALBANIA-WHITE%402000px.png", "flag_url": "https://eurovision.tv/sites/default/files/media/image/2023-08/ESC-HEART-ALBANIA-WHITE%402000px.png",
"lyrics_original": "[Teksti i \"Zjerm\"]\n\n[Strofa 1: Beatriçe Gjergji]\nN'këtë minutë, n'këtë çast, no paranoja (Ah)\nPas shiut, ylber të duket bota (Ua)\nNëpër rrugë, asnjë ambulancë, kurrkush s'flet me arrogancë\nEdhe sot na thanë që s'prishet koha\nPërfundova nën ujë, kurrë s'm'u tha goja (No)\nImagjino një minutë pa ushtarë, pa jetima\nAsnjë shishe n'oqean, naftës i vjen era jargavan\nLirinë e fjalës ta mëson shkolla (Hopa)\n\n[Pararefreni: Beatriçe Gjergji]\nKrijo në mua një zemër t'pastër\nNë natën time, të dërgoj dritën\nAman, miserere\nAman, miserere\n\n[Refreni: Beatriçe Gjergji]\nNë zemrën time, n'zemrën teme\nKy minutë do të vazhdojë\nNjerëz't e mirë e njerëz't pa emër\nKërcejnë valle n'shpirt\nJarnane ti toka ime\nKu kam lindë, s'do të harroj\nJarnane ti bota ime\nVazhdo me shndritë, shndritë, shndritë, shndritë\n\n[Pasrefreni: Beatriçe Gjergji]\n(Shndritë, shndritë, shndritë)\n(Shndritë, shndritë, shndritë, shndritë)\n(Shndritë, shndritë, shndritë)\n(Shndritë, shndritë)\n(Shndritë, shndritë, shndritë, shndritë)\n(Shndritë, shndritë, shndritë, shndritë)\n\n[Strofa 2: Kolë Laca, Kolë Laca & Beatriçe Gjergji]\nZjerm bjer mbi vallet tona tribale\nQë ushtrojnë sa orteku kur bjen n'male\nZjerm, njerz't pa emën e njerz't e dëlirë\nNjësoj këputen e bijnë si shtatë thika që t'ngulen n'shpirt\nZjerm, këtu flen deti, rana e hana\nE yjet s'i shofim se yjet na i shkel kamba kur ecim n'jerm\nZjerm, jena t'untë për flakë e dritë\nE t'kërkojmë n'kyt terr që s'pran' tuej shndritë\n\n[Pararefreni: Beatriçe Gjergji]\nKrijo në mua një zemër t'pastër\nNë natën time, të dërgoj dritën\nAman, miserere\nAman, miserere\n\n[Refreni: Beatriçe Gjergji]\nNë zemrën time, n'zemrën teme\nKy minutë do të vazhdojë\nNjerëz't e mirë e njerëz't pa emër\nKërcejnë valle n'shpirt\nJarnane ti toka ime\nKu kam lindë, s'do të harroj\nJarnane ti bota ime\nVazhdo me shndritë, shndritë, shndritë, shndritë\n\n[Mbyllja: Beatriçe Gjergji]\n(Shndritë, shndritë, shndritë, shndritë)\n(Shndritë, shndritë, shndritë, shndritë)\n(Shndritë, shndritë, shndritë, shndritë)\n(Shndritë, shndritë, shndritë, shndritë)\n(Shndritë, shndritë, shndritë, shndritë)\n(Shndritë, shndritë, shndritë, shndritë)\n(Shndritë, shndritë, shndritë, shndritë)\n(Shndritë, shndritë, shndritë, shndritë)", "lyrics_original": "[Teksti i \"Zjerm\"]\n\n[Strofa 1: Beatriçe Gjergji]\nN'këtë minutë, n'këtë çast, no paranoja (Ah)\nPas shiut, ylber të duket bota (Ua)\nNëpër rrugë, asnjë ambulancë, kurrkush s'flet me arrogancë\nEdhe sot na thanë që s'prishet koha\nPërfundova nën ujë, kurrë s'm'u tha goja (No)\nImagjino një minutë pa ushtarë, pa jetima\nAsnjë shishe n'oqean, naftës i vjen era jargavan\nLirinë e fjalës ta mëson shkolla (Hopa)\n\n[Pararefreni: Beatriçe Gjergji]\nKrijo në mua një zemër t'pastër\nNë natën time, të dërgoj dritën\nAman, miserere\nAman, miserere\n\n[Refreni: Beatriçe Gjergji]\nNë zemrën time, n'zemrën teme\nKy minutë do të vazhdojë\nNjerëz't e mirë e njerëz't pa emër\nKërcejnë valle n'shpirt\nJarnane ti toka ime\nKu kam lindë, s'do të harroj\nJarnane ti bota ime\nVazhdo me shndritë, shndritë, shndritë, shndritë\n\n[Pasrefreni: Beatriçe Gjergji]\n(Shndritë, shndritë, shndritë)\n(Shndritë, shndritë, shndritë, shndritë)\n(Shndritë, shndritë, shndritë)\n(Shndritë, shndritë)\n(Shndritë, shndritë, shndritë, shndritë)\n(Shndritë, shndritë, shndritë, shndritë)\n\n[Strofa 2: Kolë Laca, Kolë Laca & Beatriçe Gjergji]\nZjerm bjer mbi vallet tona tribale\nQë ushtrojnë sa orteku kur bjen n'male\nZjerm, njerz't pa emën e njerz't e dëlirë\nNjësoj këputen e bijnë si shtatë thika që t'ngulen n'shpirt\nZjerm, këtu flen deti, rana e hana\nE yjet s'i shofim se yjet na i shkel kamba kur ecim n'jerm\nZjerm, jena t'untë për flakë e dritë\nE t'kërkojmë n'kyt terr që s'pran' tuej shndritë\n\n[Pararefreni: Beatriçe Gjergji]\nKrijo në mua një zemër t'pastër\nNë natën time, të dërgoj dritën\nAman, miserere\nAman, miserere\n\n[Refreni: Beatriçe Gjergji]\nNë zemrën time, n'zemrën teme\nKy minutë do të vazhdojë\nNjerëz't e mirë e njerëz't pa emër\nKërcejnë valle n'shpirt\nJarnane ti toka ime\nKu kam lindë, s'do të harroj\nJarnane ti bota ime\nVazhdo me shndritë, shndritë, shndritë, shndritë\n\n[Mbyllja: Beatriçe Gjergji]\n(Shndritë, shndritë, shndritë, shndritë)\n(Shndritë, shndritë, shndritë, shndritë)\n(Shndritë, shndritë, shndritë, shndritë)\n(Shndritë, shndritë, shndritë, shndritë)\n(Shndritë, shndritë, shndritë, shndritë)\n(Shndritë, shndritë, shndritë, shndritë)\n(Shndritë, shndritë, shndritë, shndritë)\n(Shndritë, shndritë, shndritë, shndritë)",
@@ -42,6 +44,7 @@
"country": "ISL", "country": "ISL",
"title": "RÓA", "title": "RÓA",
"lyrics_url": "https://genius.com/Vb-isl-roa-lyrics", "lyrics_url": "https://genius.com/Vb-isl-roa-lyrics",
"img_url": "https://eurovision.tv/sites/default/files/styles/teaser/public/media/image/2025-05/250507_Corinne-Cumming_EBU_00032.jpg?h=28c964fa&itok=fNyy_NJb",
"artist_url": "https://eurovision.tv/participant/V%C3%86B-2025", "artist_url": "https://eurovision.tv/participant/V%C3%86B-2025",
"flag_url": "https://eurovision.tv/sites/default/files/media/image/2023-08/ESC-HEART-ICELAND-WHITE-v2.png", "flag_url": "https://eurovision.tv/sites/default/files/media/image/2023-08/ESC-HEART-ICELAND-WHITE-v2.png",
"lyrics_original": "[Söngtextar fyrir „RÓA“]\n\n[Byrjun: Matthías]\nLet's go!\n\n[Viðlag: Hálfdán]\nRóandi hér, róandi þar\nRóa í gegnum öldurnar\nÞað getur ekkert stoppað mig af, ooh-ooh\nRóandi hér, róandi þar\nRóa í gegnum öldurnar\nÞað getur ekkert stoppað mig af\n\n[Vísa 1: Matthías, Hálfdán, VÆB]\nÉg set spítu ofan á spítu ogkalla það bát\nEf ég sekk í dag er það ekkert mál\nMeð árar úr stáli sem duga í ár\nStefni á Færeyjar, já, eg er klár\nÉg er með vesti fyrir belti og vatnshelda skó\nÞví að veðrið það er erfitt ég er kominn með nóg\n\n[Fyrir-Viðlag: Matthías]\nEr sjórinn opnast koma öldurnar\nÉg er einn á bát að leita af betri stað\nÉg er ekki ennþá búin að missa allt\nEn við setjum seglin upp og höldum aftur af stað\n\n[Viðlag: Hálfdán]\nRóandi hér, róandi þar\nRóa í gegnum öldurnar\nÞað getur ekkеrt stoppað mig af, ooh-ooh\nRóandi hér, róandi þar\nRóa í gegnum öldurnar\nÞað getur ekkеrt stoppað mig af, ooh-ooh\n\n[Vísa 2: Matthías, Hálfdán]\nÉg er enþá á bát, sjáðu þetta, vá\nStoppa í Grænlandi? Já, ég er down! God damn!\nStýri á sjó ég er kapteinn (Ey!)\nKallaðu mig Gísli Marteinn\nMargir mánuðir síðan ég sá síðast sól\nVil eiða restinni af lífinu hér út á sjó\n\n[Fyrir-Viðlag: Matthías]\nEr sjórinn opnast koma öldurnar\nÉg er en á bát að leita af betri stað\nÉg er ekki ennþá búin að missa allt\nEn við setjum seglin upp og höldum aftur af stað\n\n[Viðlag: Hálfdán, Matthías]\nRóandi hér, róandi þar\nRóa í gegnum öldurnar\nÞað getur ekkert stoppað mig af, ooh-ooh\nRóandi hér, róandi þar\nRóa í gegnum öldurnar\nÞað getur ekkert stoppað mig af, ooh-ooh\n\n[Brú]\n(Hey, hey, hey, hey)\n(Hey, hey)\n\n[Viðlag: Hálfdán, Matthías]\nRóandi hér, róandi þar\nRóa í gegnum öldurnar\nÞað getur ekkert stoppað mig af, ooh-ooh\nRóandi hér, róandi þar\nRóa í gegnum öldurnar\nÞað getur ekkert stoppað mig af, ooh-ooh (Það getur ekkert stoppað mig af)\n\n[Endir: VÆB]\nÞað getur ekkert stoppað mig af\nÞað getur ekkert stoppað mig af, ooh-ooh", "lyrics_original": "[Söngtextar fyrir „RÓA“]\n\n[Byrjun: Matthías]\nLet's go!\n\n[Viðlag: Hálfdán]\nRóandi hér, róandi þar\nRóa í gegnum öldurnar\nÞað getur ekkert stoppað mig af, ooh-ooh\nRóandi hér, róandi þar\nRóa í gegnum öldurnar\nÞað getur ekkert stoppað mig af\n\n[Vísa 1: Matthías, Hálfdán, VÆB]\nÉg set spítu ofan á spítu ogkalla það bát\nEf ég sekk í dag er það ekkert mál\nMeð árar úr stáli sem duga í ár\nStefni á Færeyjar, já, eg er klár\nÉg er með vesti fyrir belti og vatnshelda skó\nÞví að veðrið það er erfitt ég er kominn með nóg\n\n[Fyrir-Viðlag: Matthías]\nEr sjórinn opnast koma öldurnar\nÉg er einn á bát að leita af betri stað\nÉg er ekki ennþá búin að missa allt\nEn við setjum seglin upp og höldum aftur af stað\n\n[Viðlag: Hálfdán]\nRóandi hér, róandi þar\nRóa í gegnum öldurnar\nÞað getur ekkеrt stoppað mig af, ooh-ooh\nRóandi hér, róandi þar\nRóa í gegnum öldurnar\nÞað getur ekkеrt stoppað mig af, ooh-ooh\n\n[Vísa 2: Matthías, Hálfdán]\nÉg er enþá á bát, sjáðu þetta, vá\nStoppa í Grænlandi? Já, ég er down! God damn!\nStýri á sjó ég er kapteinn (Ey!)\nKallaðu mig Gísli Marteinn\nMargir mánuðir síðan ég sá síðast sól\nVil eiða restinni af lífinu hér út á sjó\n\n[Fyrir-Viðlag: Matthías]\nEr sjórinn opnast koma öldurnar\nÉg er en á bát að leita af betri stað\nÉg er ekki ennþá búin að missa allt\nEn við setjum seglin upp og höldum aftur af stað\n\n[Viðlag: Hálfdán, Matthías]\nRóandi hér, róandi þar\nRóa í gegnum öldurnar\nÞað getur ekkert stoppað mig af, ooh-ooh\nRóandi hér, róandi þar\nRóa í gegnum öldurnar\nÞað getur ekkert stoppað mig af, ooh-ooh\n\n[Brú]\n(Hey, hey, hey, hey)\n(Hey, hey)\n\n[Viðlag: Hálfdán, Matthías]\nRóandi hér, róandi þar\nRóa í gegnum öldurnar\nÞað getur ekkert stoppað mig af, ooh-ooh\nRóandi hér, róandi þar\nRóa í gegnum öldurnar\nÞað getur ekkert stoppað mig af, ooh-ooh (Það getur ekkert stoppað mig af)\n\n[Endir: VÆB]\nÞað getur ekkert stoppað mig af\nÞað getur ekkert stoppað mig af, ooh-ooh",
@@ -61,6 +64,7 @@
"country": "AUT", "country": "AUT",
"title": "Wasted Love", "title": "Wasted Love",
"lyrics_url": "https://genius.com/Jj-aut-wasted-love-lyrics", "lyrics_url": "https://genius.com/Jj-aut-wasted-love-lyrics",
"img_url": "https://eurovision.tv/sites/default/files/styles/teaser/public/media/image/2025-05/250508_Corinne-Cumming_EBU_00932.jpg?h=25371bde&itok=usBLdKWr",
"artist_url": "https://eurovision.tv/participant/jj-2025", "artist_url": "https://eurovision.tv/participant/jj-2025",
"flag_url": "https://eurovision.tv/sites/default/files/media/image/2023-08/ESC-HEART-AUSTRIA-WHITE.png", "flag_url": "https://eurovision.tv/sites/default/files/media/image/2023-08/ESC-HEART-AUSTRIA-WHITE.png",
"lyrics_original": "[Verse 1]\nI'm an ocean of love\nAnd you're scared of water\nYou don't want to go under\nSo you let me go under\nI reach out my hand\nBut you watch me grow distant\nDrift out to the sea and\nFar away in an instant\n\n[Pre-Chorus]\nYou left me in the deep end\nI'm drownin' in my feelings\nHow do you not see that?\n\n[Chorus]\nNow that you're gone\nAll I have\nIs wasted love\nThis wasted love\nNow that you're gone\nCan't fill my heart\nWith wasted love\nThis wasted love\n\n[Verse 2]\nWhen you let me go\nI barely stayed afloat\nI'm floatin' all alone\nStill, I'm holdin' on to hope\n\n[Chorus]\nNow that you're gone\nAll I have\nIs wasted lovе\nThis wasted love\nNow that you're gonе\nCan't fill my heart\nWith wasted love\nThis wasted love\n\n[Bridge]\nWasted love\nThis wasted\n\n[Breakdown]\nWasted, wasted, wasted, wasted\nWasted, wasted, wasted, wasted\nLove (Wasted, wasted, wasted, wasted)\nLove", "lyrics_original": "[Verse 1]\nI'm an ocean of love\nAnd you're scared of water\nYou don't want to go under\nSo you let me go under\nI reach out my hand\nBut you watch me grow distant\nDrift out to the sea and\nFar away in an instant\n\n[Pre-Chorus]\nYou left me in the deep end\nI'm drownin' in my feelings\nHow do you not see that?\n\n[Chorus]\nNow that you're gone\nAll I have\nIs wasted love\nThis wasted love\nNow that you're gone\nCan't fill my heart\nWith wasted love\nThis wasted love\n\n[Verse 2]\nWhen you let me go\nI barely stayed afloat\nI'm floatin' all alone\nStill, I'm holdin' on to hope\n\n[Chorus]\nNow that you're gone\nAll I have\nIs wasted lovе\nThis wasted love\nNow that you're gonе\nCan't fill my heart\nWith wasted love\nThis wasted love\n\n[Bridge]\nWasted love\nThis wasted\n\n[Breakdown]\nWasted, wasted, wasted, wasted\nWasted, wasted, wasted, wasted\nLove (Wasted, wasted, wasted, wasted)\nLove",
@@ -81,6 +85,7 @@
"country": "DNK", "country": "DNK",
"title": "Hallucination", "title": "Hallucination",
"lyrics_url": "https://genius.com/Sissal-hallucination-lyrics", "lyrics_url": "https://genius.com/Sissal-hallucination-lyrics",
"img_url": "https://eurovision.tv/sites/default/files/styles/teaser/public/media/image/2025-05/250509_Corinne-Cumming_EBU_00158.jpg?h=44220c28&itok=YKaETyH4",
"artist_url": "https://eurovision.tv/participant/denmark-2025", "artist_url": "https://eurovision.tv/participant/denmark-2025",
"flag_url": "https://eurovision.tv/sites/default/files/media/image/2023-08/ESC-HEART-DENMARK-WHITE.png", "flag_url": "https://eurovision.tv/sites/default/files/media/image/2023-08/ESC-HEART-DENMARK-WHITE.png",
"lyrics_original": "[Verse 1]\nYou show me more\nMore than meets the eye\nYou open all the doors inside my mind\nI see colours I never saw before\nA thousand shades of light come to life\n\n[Pre-Chorus]\nMaking me question all that I thought true\nAll that I'm seeing through you\nMy vision's blurry but I can see clearly\nMaybe I'm losing control\n\n[Chorus]\nYou're my hallu-u-u\nHallucination\nHallu-u-u\nHallucination\n\n[Verse 2]\nI'm paranoid\nSlipping from reality\nYou're leading me into another fantasy\n\n[Pre-Chorus]\nOh, making me question all that I thought true\nAll that I'm seeing through you\nMy vision's blurry but I can see clearly\nMaybe I'm losing control\n\n[Chorus]\nYou're my hallu-u-u\nHallucination\nHallu-u-u\nHallucination\nA new-ew-ew\nRevelation\nHallu-u-u\nHallucination\n\n[Bridge]\nWorlds are changing\nDarkness fading\nI follow you to the end and now I'm changing (Now I'm changing)\nIt's a nеw sensation\n(Worlds are changing)\n(Darkness fading)\n(My hallucination)\nHallucination\n(Worlds arе changing)\n(Darknesѕ fading)\n(My hallucination)\n\n[Chorus]\nYou're my hallu-u-u\nHallucination\nHallu-u-u\nHallucination\n\n[Post-Chorus]\nHey yeah\nHey yeah\nHallucination\nYou're my hallu-u-u\nHallucination\nHallu-u-u\nHallucinаtion", "lyrics_original": "[Verse 1]\nYou show me more\nMore than meets the eye\nYou open all the doors inside my mind\nI see colours I never saw before\nA thousand shades of light come to life\n\n[Pre-Chorus]\nMaking me question all that I thought true\nAll that I'm seeing through you\nMy vision's blurry but I can see clearly\nMaybe I'm losing control\n\n[Chorus]\nYou're my hallu-u-u\nHallucination\nHallu-u-u\nHallucination\n\n[Verse 2]\nI'm paranoid\nSlipping from reality\nYou're leading me into another fantasy\n\n[Pre-Chorus]\nOh, making me question all that I thought true\nAll that I'm seeing through you\nMy vision's blurry but I can see clearly\nMaybe I'm losing control\n\n[Chorus]\nYou're my hallu-u-u\nHallucination\nHallu-u-u\nHallucination\nA new-ew-ew\nRevelation\nHallu-u-u\nHallucination\n\n[Bridge]\nWorlds are changing\nDarkness fading\nI follow you to the end and now I'm changing (Now I'm changing)\nIt's a nеw sensation\n(Worlds are changing)\n(Darkness fading)\n(My hallucination)\nHallucination\n(Worlds arе changing)\n(Darknesѕ fading)\n(My hallucination)\n\n[Chorus]\nYou're my hallu-u-u\nHallucination\nHallu-u-u\nHallucination\n\n[Post-Chorus]\nHey yeah\nHey yeah\nHallucination\nYou're my hallu-u-u\nHallucination\nHallu-u-u\nHallucinаtion",
@@ -100,6 +105,7 @@
"country": "EST", "country": "EST",
"title": "Espresso Macchiato", "title": "Espresso Macchiato",
"lyrics_url": "https://genius.com/Tommy-cash-espresso-macchiato-lyrics", "lyrics_url": "https://genius.com/Tommy-cash-espresso-macchiato-lyrics",
"img_url": "https://eurovision.tv/sites/default/files/styles/teaser/public/media/image/2025-05/250507_Corinne-Cumming_EBU_00226.jpg?h=444e4ea8&itok=TJ59RWTM",
"artist_url": "https://eurovision.tv/participant/tommy-cash-2025", "artist_url": "https://eurovision.tv/participant/tommy-cash-2025",
"flag_url": "https://eurovision.tv/sites/default/files/media/image/2023-08/ESC-HEART-ESTONIA-WHITE.png", "flag_url": "https://eurovision.tv/sites/default/files/media/image/2023-08/ESC-HEART-ESTONIA-WHITE.png",
"lyrics_original": "[Intro]\nMi amore, mi amore\nEspresso macchiato, macchiato, macchiato\nPor favore, por favore\nEspresso macchiato corneo\n\n[Chorus]\nMi amore, mi amore\nEspresso macchiato, macchiato, macchiato\nPor favore, por favore\nEspresso macchiato\nEspresso macchiato\n\n[Post-Chorus]\n(Uh-huh, uh-huh, uh-huh)\n\n[Verse 1]\nCiao bella, I'm Tommaso, addicted to tobacco\nMi like mi coffè very importante\nNo time to talk, scusi, my days are very busy\nAnd I just own this little ristorante\n\n[Pre-Chorus]\nLife may give you lemons when dancing with the demons\nNo stresso, no stresso, no need to be depresso\n\n[Chorus]\nMi amore, mi amore\nEspresso macchiato, macchiato, macchiato\nPor favore, por favore\nEspresso macchiato corneo\nMi amorе, mi amore\nEspresso macchiato, macchiato, macchiato\nPor favore, por favorе\nEspresso macchiato\nEspresso macchiato\n\n[Verse 2]\nMi like to fly privati with twenty-four carati\nAlso mi casa very grandioso\nMi money numeroso, I work around the clocko\nThat's why I'm sweating like a mafioso\n\n[Pre-Chorus]\nLife is like spaghetti, it's hard until you make it\nNo stresso, no stresso, it's gonna be espresso\n\n[Chorus]\nMi amore, mi amore\nEspresso macchiato, macchiato, macchiato\nPor favore, por favore\nEspresso macchiato\nEspresso macchiato\n\n[Outro]\nLa-la-la-la, la-la-la-la\nLa-la-la-la, la-la-la-la, la-la-la-la, la-la-la\nLa-la-la-la, la-la-la-la\nEspresso macchiato\nEspresso macchiato", "lyrics_original": "[Intro]\nMi amore, mi amore\nEspresso macchiato, macchiato, macchiato\nPor favore, por favore\nEspresso macchiato corneo\n\n[Chorus]\nMi amore, mi amore\nEspresso macchiato, macchiato, macchiato\nPor favore, por favore\nEspresso macchiato\nEspresso macchiato\n\n[Post-Chorus]\n(Uh-huh, uh-huh, uh-huh)\n\n[Verse 1]\nCiao bella, I'm Tommaso, addicted to tobacco\nMi like mi coffè very importante\nNo time to talk, scusi, my days are very busy\nAnd I just own this little ristorante\n\n[Pre-Chorus]\nLife may give you lemons when dancing with the demons\nNo stresso, no stresso, no need to be depresso\n\n[Chorus]\nMi amore, mi amore\nEspresso macchiato, macchiato, macchiato\nPor favore, por favore\nEspresso macchiato corneo\nMi amorе, mi amore\nEspresso macchiato, macchiato, macchiato\nPor favore, por favorе\nEspresso macchiato\nEspresso macchiato\n\n[Verse 2]\nMi like to fly privati with twenty-four carati\nAlso mi casa very grandioso\nMi money numeroso, I work around the clocko\nThat's why I'm sweating like a mafioso\n\n[Pre-Chorus]\nLife is like spaghetti, it's hard until you make it\nNo stresso, no stresso, it's gonna be espresso\n\n[Chorus]\nMi amore, mi amore\nEspresso macchiato, macchiato, macchiato\nPor favore, por favore\nEspresso macchiato\nEspresso macchiato\n\n[Outro]\nLa-la-la-la, la-la-la-la\nLa-la-la-la, la-la-la-la, la-la-la-la, la-la-la\nLa-la-la-la, la-la-la-la\nEspresso macchiato\nEspresso macchiato",
@@ -119,6 +125,7 @@
"country": "FIN", "country": "FIN",
"title": "ICH KOMME", "title": "ICH KOMME",
"lyrics_url": "https://genius.com/Genius-english-translations-erika-vikman-ich-komme-english-translation-lyrics", "lyrics_url": "https://genius.com/Genius-english-translations-erika-vikman-ich-komme-english-translation-lyrics",
"img_url": "https://eurovision.tv/sites/default/files/styles/teaser/public/media/image/2025-05/250509_Corinne-Cumming_EBU_00700.jpg?h=f4a86482&itok=0jvy2KHI",
"artist_url": "https://eurovision.tv/participant/erika-vikman-2025", "artist_url": "https://eurovision.tv/participant/erika-vikman-2025",
"flag_url": "https://eurovision.tv/sites/default/files/media/image/2023-08/ESC-HEART-FINLAND-WHITE.png", "flag_url": "https://eurovision.tv/sites/default/files/media/image/2023-08/ESC-HEART-FINLAND-WHITE.png",
"lyrics_original": "[Intro]\n(I'm coming)\n\n[Verse 1]\nNight falls, heart beats, they fall in love\nMoon rises, earth arches, my gates are open (Hey)\n\n[Pre-Chorus]\nI am Erika, welcome\nYou are like gorgeous, trance god\nJust make yourself at home, do what you want\nAnd when you come, I'll come with you\n\n[Chorus]\n(I'm coming, I'm coming)\nAnd before you come, I hear you screaming\n(I'm coming, I'm coming)\nAnd to that, I scream out loud, \"I'm coming\"\n(I'm coming, I'm coming)\nAnd together we come and be like\n(I'm coming, I'm coming)\nIt's like that when you fall in love\n(Wonderful)\n\n[Verse 2]\nI am Erika, nice to meet you\nI'll dance with you evеn a wedding waltz, but naked\n\n[Pre-Chorus]\nI am Erika, you're full of stamina\nHit mе once again, grab my ass\nAnd when you want more love, just shout, \"Encore\"\nAnd, baby, I'm coming\n\n[Chorus]\n(I'm coming, I'm coming)\nAnd again when you come, I hear you screaming\n(I'm coming, I'm coming)\nAnd all I can do is to cry, \"I'm coming\"\n(I'm coming, I'm coming)\nAnd together we come and be like\n(I'm coming, I'm coming)\nIt's like that when you fall in love\n\n[Bridge]\nLet go and let it happen\nBaby, surrender and come with me\nThe stars in your eyes and me on top of you\nBaby, you deserve only good\nLet go and let it happen\nBaby, you can still fall in love with yourself\nStars in your eyes and me on top of you\nBaby, you deserve only good\n\n[Outro]\n(I'm coming, I'm coming) I'm coming\n(I'm coming, I'm coming) Fall in love\n(I'm coming, I'm coming) Hey, baby\n(I'm coming, I'm coming) It's like that when you fall in love", "lyrics_original": "[Intro]\n(I'm coming)\n\n[Verse 1]\nNight falls, heart beats, they fall in love\nMoon rises, earth arches, my gates are open (Hey)\n\n[Pre-Chorus]\nI am Erika, welcome\nYou are like gorgeous, trance god\nJust make yourself at home, do what you want\nAnd when you come, I'll come with you\n\n[Chorus]\n(I'm coming, I'm coming)\nAnd before you come, I hear you screaming\n(I'm coming, I'm coming)\nAnd to that, I scream out loud, \"I'm coming\"\n(I'm coming, I'm coming)\nAnd together we come and be like\n(I'm coming, I'm coming)\nIt's like that when you fall in love\n(Wonderful)\n\n[Verse 2]\nI am Erika, nice to meet you\nI'll dance with you evеn a wedding waltz, but naked\n\n[Pre-Chorus]\nI am Erika, you're full of stamina\nHit mе once again, grab my ass\nAnd when you want more love, just shout, \"Encore\"\nAnd, baby, I'm coming\n\n[Chorus]\n(I'm coming, I'm coming)\nAnd again when you come, I hear you screaming\n(I'm coming, I'm coming)\nAnd all I can do is to cry, \"I'm coming\"\n(I'm coming, I'm coming)\nAnd together we come and be like\n(I'm coming, I'm coming)\nIt's like that when you fall in love\n\n[Bridge]\nLet go and let it happen\nBaby, surrender and come with me\nThe stars in your eyes and me on top of you\nBaby, you deserve only good\nLet go and let it happen\nBaby, you can still fall in love with yourself\nStars in your eyes and me on top of you\nBaby, you deserve only good\n\n[Outro]\n(I'm coming, I'm coming) I'm coming\n(I'm coming, I'm coming) Fall in love\n(I'm coming, I'm coming) Hey, baby\n(I'm coming, I'm coming) It's like that when you fall in love",
@@ -138,6 +145,7 @@
"country": "FRA", "country": "FRA",
"title": "maman", "title": "maman",
"lyrics_url": "https://genius.com/Genius-english-translations-louane-maman-english-translation-lyrics", "lyrics_url": "https://genius.com/Genius-english-translations-louane-maman-english-translation-lyrics",
"img_url": "https://eurovision.tv/sites/default/files/styles/teaser/public/media/image/2025-05/250510_Corinne-Cumming_EBU_00058.jpg?h=90275b85&itok=5WHUtsHd",
"artist_url": "https://eurovision.tv/participant/louane-2025", "artist_url": "https://eurovision.tv/participant/louane-2025",
"flag_url": "https://eurovision.tv/sites/default/files/media/image/2023-08/ESC-HEART-FRANCE-WHITE.png", "flag_url": "https://eurovision.tv/sites/default/files/media/image/2023-08/ESC-HEART-FRANCE-WHITE.png",
"lyrics_original": "[Verse 1]\nNo more lovers\nNo more beds\nIn the end, you see\nI built my life\nAnd the emptiness is vast\nSo are the questions\nHow are you doing?\nDo you see everything here?\nAnd I've changed a lot\nI've grownup\nFromyou,I've kept\nEverything thatmakes me whoI am\n\n[Chorus]\nI'm better now, I know where I'm going\nI've stopped counting the years\nAnd if I once wanted to stop time\nNow, I'm the one she calls \"mom\"\n\n[Post-Chorus]\nMom, mom, mom\n\n[Verse 2]\nI've found love\nIndеlible\nYou know, the real kind \"forеver\"\nEven when time flies\nWhen he holds my hand\nI'm not afraid of anything anymore\nAnd it feels just like before\nWhen you used to hold my hand\n\n[Chorus]\nI'm better now, I know where I'm going\nI've stopped counting the years\nAnd if I once wanted to stop time\nNow, I'm the one she calls \"mom\"\n\n[Post-Chorus]\nMom, mom, mom\nMom, mom, mom\n\n[Chorus]\nI'm better now, I know where I'm going\nI've stopped counting the years\nAnd if I once wanted to stop time\nNow, I'm the one she calls\n\n[Post-Chorus]\nMom, mom, mom\nMom, mom\n\n[Outro]\nIf I once wanted to stop time\nNow, I'm the one she calls\nMom", "lyrics_original": "[Verse 1]\nNo more lovers\nNo more beds\nIn the end, you see\nI built my life\nAnd the emptiness is vast\nSo are the questions\nHow are you doing?\nDo you see everything here?\nAnd I've changed a lot\nI've grownup\nFromyou,I've kept\nEverything thatmakes me whoI am\n\n[Chorus]\nI'm better now, I know where I'm going\nI've stopped counting the years\nAnd if I once wanted to stop time\nNow, I'm the one she calls \"mom\"\n\n[Post-Chorus]\nMom, mom, mom\n\n[Verse 2]\nI've found love\nIndеlible\nYou know, the real kind \"forеver\"\nEven when time flies\nWhen he holds my hand\nI'm not afraid of anything anymore\nAnd it feels just like before\nWhen you used to hold my hand\n\n[Chorus]\nI'm better now, I know where I'm going\nI've stopped counting the years\nAnd if I once wanted to stop time\nNow, I'm the one she calls \"mom\"\n\n[Post-Chorus]\nMom, mom, mom\nMom, mom, mom\n\n[Chorus]\nI'm better now, I know where I'm going\nI've stopped counting the years\nAnd if I once wanted to stop time\nNow, I'm the one she calls\n\n[Post-Chorus]\nMom, mom, mom\nMom, mom\n\n[Outro]\nIf I once wanted to stop time\nNow, I'm the one she calls\nMom",
@@ -158,6 +166,7 @@
"country": "DEU", "country": "DEU",
"title": "Baller", "title": "Baller",
"lyrics_url": "https://genius.com/Abor-and-tynna-baller-lyrics", "lyrics_url": "https://genius.com/Abor-and-tynna-baller-lyrics",
"img_url": "https://eurovision.tv/sites/default/files/styles/teaser/public/media/image/2025-05/250510_Corinne-Cumming_EBU_00020.jpg?h=2df284cc&itok=vOLBSCZU",
"artist_url": "https://eurovision.tv/participant/abor-tynna-2025", "artist_url": "https://eurovision.tv/participant/abor-tynna-2025",
"flag_url": "https://eurovision.tv/sites/default/files/media/image/2023-08/ESC-HEART-GERMANY-WHITE.png", "flag_url": "https://eurovision.tv/sites/default/files/media/image/2023-08/ESC-HEART-GERMANY-WHITE.png",
"lyrics_original": "[Songtext zu „Baller“]\n\n[Refrain: Tynna]\nIch baller' Löcher in die Nacht\nSterne fall'n und knall'n auf mein Dach\nEs tut noch bisschen weh, wenn ich dich wiederseh'\nAber ich komm' nie wieder, egal was du mir sagst\nIch baller' LöcherindieNacht\nSterne fall'n undknall'n auf meinDach\nEs tut noch bisschen weh, wenn ich dich wiederseh'\nAber ich komm' nie wieder, egal was du mir sagst\n\n[Strophe 1: Tynna]\nKreidesilhouetten auf dem Trottoir\nZwischen uns ein Tatort wie bеi CSI\nHast „Baby, tut mir leid“ gesagt zum erstеn Mal\nHätt wissen soll'n, dass das das Ende von uns war\n\n[Pre-Refrain: Tynna]\nDu setzt 'n Punkt nach dem Satz, als hättst du mich nie gekannt\nAlso wechsel' ich Parfums und kauf' mir neues Gewand\nIch krieg' wieder diesen Drang, ich will den Weltuntergang\nHa, ich glaub', das war's, I shoot for the stars\n\n[Refrain: Tynna]\nIch baller' Löcher in die Nacht\nSterne fall'n und knall'n auf mein Dach\nEs tut noch bisschen weh, wenn ich dich wiederseh'\nAber ich komm' nie wieder, egal was du mir sagst\nIch baller' Löcher in die Nacht\nSterne fall'n und knall'n auf mein Dach\nEs tut noch bisschen weh, wenn ich dich wiederseh'\nAber ich komm' nie wieder, egal was du mir sagst\n\n[Strophe 2: Tynna]\nIch seh' die Sternensplitter auf meiner Haut wie Glitzer\nHab' gelernt, was mich nicht killt, macht mich nur schicker\nWürdest du für mich immer noch 'ne Kugel fang'n?\nWeil deine Waffe ist jetzt in meiner Hand\n\n[Pre-Refrain: Tynna]\nIch setz' 'n Punkt nach dem Satz, als hätt ich dich nie gekannt\nUnd dann wechsel' ich Parfums und kauf' mir neues Gewand\nIch krieg' wieder diesen Drang, ich will den Weltuntergang\nHa, ich glaub', das war's, I shoot for the stars\n\n[Refrain: Tynna]\nIch baller' Löcher in die Nacht\nSterne fall'n und knall'n auf mein Dach\nEs tut noch bisschen weh, wenn ich dich wiederseh'\nAber ich komm' nie wieder, egal was du mir sagst\nIch baller' Löcher in die Nacht\nSterne fall'n und knall'n auf mein Dach\nEs tut noch bisschen weh, wenn ich dich wiederseh'\nAber ich komm' nie wieder, egal was du mir sagst\n\n[Outro: Tynna]\nIch baller', la-la\nIch baller', la\nLa-la-la-la-la-l—", "lyrics_original": "[Songtext zu „Baller“]\n\n[Refrain: Tynna]\nIch baller' Löcher in die Nacht\nSterne fall'n und knall'n auf mein Dach\nEs tut noch bisschen weh, wenn ich dich wiederseh'\nAber ich komm' nie wieder, egal was du mir sagst\nIch baller' LöcherindieNacht\nSterne fall'n undknall'n auf meinDach\nEs tut noch bisschen weh, wenn ich dich wiederseh'\nAber ich komm' nie wieder, egal was du mir sagst\n\n[Strophe 1: Tynna]\nKreidesilhouetten auf dem Trottoir\nZwischen uns ein Tatort wie bеi CSI\nHast „Baby, tut mir leid“ gesagt zum erstеn Mal\nHätt wissen soll'n, dass das das Ende von uns war\n\n[Pre-Refrain: Tynna]\nDu setzt 'n Punkt nach dem Satz, als hättst du mich nie gekannt\nAlso wechsel' ich Parfums und kauf' mir neues Gewand\nIch krieg' wieder diesen Drang, ich will den Weltuntergang\nHa, ich glaub', das war's, I shoot for the stars\n\n[Refrain: Tynna]\nIch baller' Löcher in die Nacht\nSterne fall'n und knall'n auf mein Dach\nEs tut noch bisschen weh, wenn ich dich wiederseh'\nAber ich komm' nie wieder, egal was du mir sagst\nIch baller' Löcher in die Nacht\nSterne fall'n und knall'n auf mein Dach\nEs tut noch bisschen weh, wenn ich dich wiederseh'\nAber ich komm' nie wieder, egal was du mir sagst\n\n[Strophe 2: Tynna]\nIch seh' die Sternensplitter auf meiner Haut wie Glitzer\nHab' gelernt, was mich nicht killt, macht mich nur schicker\nWürdest du für mich immer noch 'ne Kugel fang'n?\nWeil deine Waffe ist jetzt in meiner Hand\n\n[Pre-Refrain: Tynna]\nIch setz' 'n Punkt nach dem Satz, als hätt ich dich nie gekannt\nUnd dann wechsel' ich Parfums und kauf' mir neues Gewand\nIch krieg' wieder diesen Drang, ich will den Weltuntergang\nHa, ich glaub', das war's, I shoot for the stars\n\n[Refrain: Tynna]\nIch baller' Löcher in die Nacht\nSterne fall'n und knall'n auf mein Dach\nEs tut noch bisschen weh, wenn ich dich wiederseh'\nAber ich komm' nie wieder, egal was du mir sagst\nIch baller' Löcher in die Nacht\nSterne fall'n und knall'n auf mein Dach\nEs tut noch bisschen weh, wenn ich dich wiederseh'\nAber ich komm' nie wieder, egal was du mir sagst\n\n[Outro: Tynna]\nIch baller', la-la\nIch baller', la\nLa-la-la-la-la-l—",
@@ -177,6 +186,7 @@
"country": "GRC", "country": "GRC",
"title": "Asteromáta", "title": "Asteromáta",
"lyrics_url": "https://genius.com/Klavdia-asteromata-lyrics", "lyrics_url": "https://genius.com/Klavdia-asteromata-lyrics",
"img_url": "https://eurovision.tv/sites/default/files/styles/teaser/public/media/image/2025-05/250508_Corinne-Cumming_EBU_00970.jpg?h=9b742a13&itok=twZoSdkc",
"artist_url": "https://eurovision.tv/participant/klavdia-2025", "artist_url": "https://eurovision.tv/participant/klavdia-2025",
"flag_url": "https://eurovision.tv/sites/default/files/media/image/2023-08/ESC-HEART-GREECE-WHITE.png", "flag_url": "https://eurovision.tv/sites/default/files/media/image/2023-08/ESC-HEART-GREECE-WHITE.png",
"lyrics_original": "[Εισαγωγή]\nΑστέρι μου\nΑστέρι μου\n\n[Στροφή 1]\nΓλυκιά μου μάνα μην μου κλαις\nΜαύρα και αν σου φορούνε\nΤο ξέθωρο το σώμα μου\nΦλόγες δεν το νικούνε\n\n[Στροφή 2]\nΤα χελιδόνια της φωτιάς\nΘάλασσες και αν περνούνε\nΤου ριζωμού τα χώματα\nΠοτέ δεν λησμονούνε\n\n[Ρεφραίν]\nΑστερομάτα μου μικρή\nΓύρε να σε φιλήσω\nΣτα άγια σου τα δάκρυα\nΤα χείλη μου να σβήσω\nΑστερομάτα μου μικρή\nΓύρε μου να σε πιάσω\nΤα ξεχασμένα μου φτερά\nΣτερνά να ξαποστάσω\n\n[Μετά-Ρεφραίν]\nΑχ αστέρι μου, τζιβαέρι μου\n\n[Στροφή 3]\nΓλυκιά μου μάνα μην μου κλαις\nΚαράβι είναι η ζωή μου\nΠου ψάχνει για τον γυρισμό\nΑγέρα το πανί μου\n\n[Ρεφραίν]\nΑστερομάτα μου μικρή\nΓύρε μου να σε πιάσω\nΤα ξεχασμένα μου φτερά\nΣτερνά να ξαποστάσω\n\n[Μετά-Ρεφραίν]\nΑχ αστέρι μου, τζιβαέρι μου\nΑχ αστέρι μου, τζιβαέρι μου\n\n[Έξοδος]\nΑστέρι μου", "lyrics_original": "[Εισαγωγή]\nΑστέρι μου\nΑστέρι μου\n\n[Στροφή 1]\nΓλυκιά μου μάνα μην μου κλαις\nΜαύρα και αν σου φορούνε\nΤο ξέθωρο το σώμα μου\nΦλόγες δεν το νικούνε\n\n[Στροφή 2]\nΤα χελιδόνια της φωτιάς\nΘάλασσες και αν περνούνε\nΤου ριζωμού τα χώματα\nΠοτέ δεν λησμονούνε\n\n[Ρεφραίν]\nΑστερομάτα μου μικρή\nΓύρε να σε φιλήσω\nΣτα άγια σου τα δάκρυα\nΤα χείλη μου να σβήσω\nΑστερομάτα μου μικρή\nΓύρε μου να σε πιάσω\nΤα ξεχασμένα μου φτερά\nΣτερνά να ξαποστάσω\n\n[Μετά-Ρεφραίν]\nΑχ αστέρι μου, τζιβαέρι μου\n\n[Στροφή 3]\nΓλυκιά μου μάνα μην μου κλαις\nΚαράβι είναι η ζωή μου\nΠου ψάχνει για τον γυρισμό\nΑγέρα το πανί μου\n\n[Ρεφραίν]\nΑστερομάτα μου μικρή\nΓύρε μου να σε πιάσω\nΤα ξεχασμένα μου φτερά\nΣτερνά να ξαποστάσω\n\n[Μετά-Ρεφραίν]\nΑχ αστέρι μου, τζιβαέρι μου\nΑχ αστέρι μου, τζιβαέρι μου\n\n[Έξοδος]\nΑστέρι μου",
@@ -197,6 +207,7 @@
"country": "ISR", "country": "ISR",
"title": "New Day Will Rise", "title": "New Day Will Rise",
"lyrics_url": "https://genius.com/Yuval-raphael-new-day-will-rise-lyrics", "lyrics_url": "https://genius.com/Yuval-raphael-new-day-will-rise-lyrics",
"img_url": "https://eurovision.tv/sites/default/files/styles/teaser/public/media/image/2025-05/250509_Corinne-Cumming_EBU_00398.jpg?h=60b43f30&itok=8iMI4yNp",
"artist_url": "https://eurovision.tv/participant/yuval-raphael-2025", "artist_url": "https://eurovision.tv/participant/yuval-raphael-2025",
"flag_url": "https://eurovision.tv/sites/default/files/media/image/2023-08/ESC-HEART-ISRAEL-WHITE.png", "flag_url": "https://eurovision.tv/sites/default/files/media/image/2023-08/ESC-HEART-ISRAEL-WHITE.png",
"lyrics_original": "[Verse 1]\nAnd even if you say goodbye, you'll never go away\nYou are the rainbow in my sky, my colors in the grey\nMy only wish upon a star, sunshine in the day\nThe only song that my piano ever plays\nAnd even if you say goodbye, you'll always be around\nTo lift me up and take me high, keep my feet close to the ground\nAre you proud of me tonight? Dreams are comin' true\nI choose the light, nothin' to lose if I lose you\n\n[Chorus]\nNew day will rise, life will go on\nEveryone cries, don't cry alone\nDarkness will fade, all the pain will go by\nBut wе will stay, even if you say goodbye\n\n[Verse 2]\nEt mêmе si tu dis adieu, tu ne partiras jamais\nT'es l'arc-en-ciel de mon ciel bleu, mes couleurs dans le gris\nEt mon seul souhait sous un ciel d'art, un rayon dans ma journée\nLa seule chanson que mon piano peut jouer\n\n[Chorus]\nNew day will rise, life will go on\nEveryone cries, don't cry alone\nDarkness will fade, all the pain will go by\nBut we will stay, even if you say\nNew day will rise, life will go on\nEveryone cries, don't cry alone\nDarkness will fade, all the pain will go by\nBut you will stay, love of my life\n\n[Bridge]\nמים רבים לא יכבו\nאת האהבה ונהרות, לא ישטפוה\n\n[Chorus]\nNew day will rise\nEveryone cries, don't cry alone\nDarkness will fade, all the pain will go by\nBut we will stay\n\n[Outro]\nEven if you say goodbye\nA new day will rise\nNew day will rise", "lyrics_original": "[Verse 1]\nAnd even if you say goodbye, you'll never go away\nYou are the rainbow in my sky, my colors in the grey\nMy only wish upon a star, sunshine in the day\nThe only song that my piano ever plays\nAnd even if you say goodbye, you'll always be around\nTo lift me up and take me high, keep my feet close to the ground\nAre you proud of me tonight? Dreams are comin' true\nI choose the light, nothin' to lose if I lose you\n\n[Chorus]\nNew day will rise, life will go on\nEveryone cries, don't cry alone\nDarkness will fade, all the pain will go by\nBut wе will stay, even if you say goodbye\n\n[Verse 2]\nEt mêmе si tu dis adieu, tu ne partiras jamais\nT'es l'arc-en-ciel de mon ciel bleu, mes couleurs dans le gris\nEt mon seul souhait sous un ciel d'art, un rayon dans ma journée\nLa seule chanson que mon piano peut jouer\n\n[Chorus]\nNew day will rise, life will go on\nEveryone cries, don't cry alone\nDarkness will fade, all the pain will go by\nBut we will stay, even if you say\nNew day will rise, life will go on\nEveryone cries, don't cry alone\nDarkness will fade, all the pain will go by\nBut you will stay, love of my life\n\n[Bridge]\nמים רבים לא יכבו\nאת האהבה ונהרות, לא ישטפוה\n\n[Chorus]\nNew day will rise\nEveryone cries, don't cry alone\nDarkness will fade, all the pain will go by\nBut we will stay\n\n[Outro]\nEven if you say goodbye\nA new day will rise\nNew day will rise",
@@ -216,6 +227,7 @@
"country": "ITA", "country": "ITA",
"title": "Volevo Essere Un Duro", "title": "Volevo Essere Un Duro",
"lyrics_url": "https://genius.com/Lucio-corsi-volevo-essere-un-duro-lyrics", "lyrics_url": "https://genius.com/Lucio-corsi-volevo-essere-un-duro-lyrics",
"img_url": "https://eurovision.tv/sites/default/files/styles/teaser/public/media/image/2025-05/250510_Corinne-Cumming_EBU_00305_0.jpg?h=91b82584&itok=UcQF8ccv",
"artist_url": "https://eurovision.tv/participant/lucio-corsi-2025", "artist_url": "https://eurovision.tv/participant/lucio-corsi-2025",
"flag_url": "https://eurovision.tv/sites/default/files/media/image/2023-08/ESC-HEART-ITALY-WHITE.png", "flag_url": "https://eurovision.tv/sites/default/files/media/image/2023-08/ESC-HEART-ITALY-WHITE.png",
"lyrics_original": "[Testo di \"Volevo essere un duro\"]\n\n[Strofa 1]\nVolevo essere un duro\nChe non gli importa del futuro\nUn robot, un lottatore di sumo\nUno spaccino in fuga da un cane lupo\nAlla stazione di Bolo\nUna gallina dalle uova d'oro\nPerò non sono nessuno\nNon sono nato con la faccia da duro\nHo anche paura del buio\nSe faccio a botte, le prendo\nCosì mi truccano gli occhi di nero\nMa non ho mai perso tempo\nÈ lui che mi ha lasciato indietro\n\n[Ritornello]\n\"Vivere la vita è un gioco da ragazzi\"\nMe lo diceva mamma ed io cadevo giù dagli alberi\nQuanto è duro il mondo per quelli normali\nChe hanno poco amore intorno o troppo sole negli occhiali\n\n[Strofa 2]\nVolevo essere un duro\nChe non gli importa del futuro, no\nUn robot, mеdaglia d'oro di sputo\nLo scippatore che t'aspetta nеl buio\nIl Re di Porta Portese\nLa gazza ladra che ti ruba la fede\n\n[Ritornello]\n\"Vivere la vita è un gioco da ragazzi\"\nMe lo diceva mamma ed io cadevo giù dagli alberi\nQuanto è duro il mondo per quelli normali\nChe hanno poco amore intorno o troppo sole negli occhiali\nVolevo essere un duro\nPerò non sono nessuno\nCintura bianca di judo\nInvece che una stella, uno starnuto\n\n[Bridge]\nI girasoli con gli occhiali mi hanno detto: \"Stai attento alla luce\"\nE che le lune senza buche sono fregature\nPerché, in fondo, è inutile fuggire dalle tue paure\n\n[Ritornello]\nVivere la vita è un gioco da ragazzi\nIo, io volevo essere un duro\nPerò non sono nessuno\n\n[Outro]\nNon sono altro che Lucio\nNon sono altro che Lucio", "lyrics_original": "[Testo di \"Volevo essere un duro\"]\n\n[Strofa 1]\nVolevo essere un duro\nChe non gli importa del futuro\nUn robot, un lottatore di sumo\nUno spaccino in fuga da un cane lupo\nAlla stazione di Bolo\nUna gallina dalle uova d'oro\nPerò non sono nessuno\nNon sono nato con la faccia da duro\nHo anche paura del buio\nSe faccio a botte, le prendo\nCosì mi truccano gli occhi di nero\nMa non ho mai perso tempo\nÈ lui che mi ha lasciato indietro\n\n[Ritornello]\n\"Vivere la vita è un gioco da ragazzi\"\nMe lo diceva mamma ed io cadevo giù dagli alberi\nQuanto è duro il mondo per quelli normali\nChe hanno poco amore intorno o troppo sole negli occhiali\n\n[Strofa 2]\nVolevo essere un duro\nChe non gli importa del futuro, no\nUn robot, mеdaglia d'oro di sputo\nLo scippatore che t'aspetta nеl buio\nIl Re di Porta Portese\nLa gazza ladra che ti ruba la fede\n\n[Ritornello]\n\"Vivere la vita è un gioco da ragazzi\"\nMe lo diceva mamma ed io cadevo giù dagli alberi\nQuanto è duro il mondo per quelli normali\nChe hanno poco amore intorno o troppo sole negli occhiali\nVolevo essere un duro\nPerò non sono nessuno\nCintura bianca di judo\nInvece che una stella, uno starnuto\n\n[Bridge]\nI girasoli con gli occhiali mi hanno detto: \"Stai attento alla luce\"\nE che le lune senza buche sono fregature\nPerché, in fondo, è inutile fuggire dalle tue paure\n\n[Ritornello]\nVivere la vita è un gioco da ragazzi\nIo, io volevo essere un duro\nPerò non sono nessuno\n\n[Outro]\nNon sono altro che Lucio\nNon sono altro che Lucio",
@@ -249,7 +261,8 @@
], ],
"confidence": 0.95, "confidence": 0.95,
"language": "Latvia", "language": "Latvia",
"running_order": 11 "running_order": 11,
"img_url": "https://eurovision.tv/sites/default/files/styles/teaser/public/media/image/2025-05/250508_Corinne-Cumming_EBU_00846.jpg?h=bde95cfb&itok=57KGEN-9"
}, },
{ {
"artist": "Katarsis", "artist": "Katarsis",
@@ -268,7 +281,8 @@
], ],
"confidence": 0.95, "confidence": 0.95,
"language": "Liettua", "language": "Liettua",
"running_order": 5 "running_order": 5,
"img_url": "https://eurovision.tv/sites/default/files/styles/teaser/public/media/image/2025-05/250508_Corinne-Cumming_EBU_00985.jpg?h=dd7d7650&itok=RaMQzqro"
}, },
{ {
"artist": "Laura Thorn", "artist": "Laura Thorn",
@@ -287,7 +301,8 @@
], ],
"confidence": 0.95, "confidence": 0.95,
"language": "Ranska", "language": "Ranska",
"running_order": 2 "running_order": 2,
"img_url": "https://eurovision.tv/sites/default/files/styles/teaser/public/media/image/2025-05/250509_Corinne-Cumming_EBU_00257.jpg?h=10965bfd&itok=3uXVqeyQ"
}, },
{ {
"artist": "Miriana Conte", "artist": "Miriana Conte",
@@ -306,7 +321,8 @@
], ],
"confidence": 0.95, "confidence": 0.95,
"language": "Englanti", "language": "Englanti",
"running_order": 20 "running_order": 20,
"img_url": "https://eurovision.tv/sites/default/files/styles/teaser/public/media/image/2025-05/250508_Corinne-Cumming_EBU_01022.jpg?h=2e3391ea&itok=5zXK7fI0"
}, },
{ {
"artist": "Claude", "artist": "Claude",
@@ -326,7 +342,8 @@
], ],
"confidence": 0.95, "confidence": 0.95,
"language": "Ranska", "language": "Ranska",
"running_order": 12 "running_order": 12,
"img_url": "https://eurovision.tv/sites/default/files/styles/teaser/public/media/image/2025-05/250507_Corinne-Cumming_EBU_00520.jpg?h=bcf70b1f&itok=98AxxmNe"
}, },
{ {
"artist": "Kyle Alessandro", "artist": "Kyle Alessandro",
@@ -335,6 +352,7 @@
"lyrics_url": "https://genius.com/Kyle-alessandro-lighter-lyrics", "lyrics_url": "https://genius.com/Kyle-alessandro-lighter-lyrics",
"artist_url": "https://eurovision.tv/participant/kyle-alessandro-2025", "artist_url": "https://eurovision.tv/participant/kyle-alessandro-2025",
"flag_url": "https://eurovision.tv/sites/default/files/media/image/2023-08/ESC-HEART-NORWAY-WHITE.png", "flag_url": "https://eurovision.tv/sites/default/files/media/image/2023-08/ESC-HEART-NORWAY-WHITE.png",
"img_url": "https://eurovision.tv/sites/default/files/styles/teaser/public/media/image/2025-05/250507_Corinne-Cumming_EBU_00360.jpg?h=5b303bf5&itok=y67gzyIT",
"lyrics_original": "[Verse 1]\nGolden girl dressed in ice, a heart as dark as night\nYou got me to dim my light, no more\nI really think I bought your lies\nDid anything to keep you mine\nYou kept me hooked on your line, no more\n\n[Pre-Chorus]\nSomewhere along the way I lost my might\nI had to walk a hundred thousand miles\nI'm not afraid to set it all on fire\nI won't fall again, I'll be my own lighter\n\n[Chorus]\nNothing can burn me now\nI'll be my own lighter\nI feel a spark inside me, I don't need savin'\nNo way, no way\n'Cause I'm my own, I'm my own lighter\n\n[Verse 2]\nI'm tired of a million tries to fight, the signs\nAnd when everybody tried to tell me\nI should've known that it was timе to break free\nYour reigns that kept mе at your mercy\nI'll burn them to the ground\nNo more, no more, ignite the fire\n\n[Pre-Chorus]\nSomewhere along the way I lost my might\nI had to walk a hundred thousand miles\nI'm not afraid to set it all on fire\nI won't fall again, I'll be my own lighter\n\n[Chorus]\nNothing can burn me now\nI'll be my own lighter\nI feel a spark inside me, I don't need savin'\nNo way, no way\n'Cause I'm my own, I'm my own lighter\n\n[Bridge]\nSilence fills the room\nAnd I've taken off my jewels\nI wish none of this was true\nBut there's a fire growin' too, yeah\n\n[Chorus]\nNothing can burn me now\nI'll be my own lighter\nI feel a spark inside me, I don't need savin'\nNo way, no way\n'Cause I'm my own, I'm my own lighter\n\n[Outro]\nNothing can burn me down\nI'm my own, I'm my own lighter", "lyrics_original": "[Verse 1]\nGolden girl dressed in ice, a heart as dark as night\nYou got me to dim my light, no more\nI really think I bought your lies\nDid anything to keep you mine\nYou kept me hooked on your line, no more\n\n[Pre-Chorus]\nSomewhere along the way I lost my might\nI had to walk a hundred thousand miles\nI'm not afraid to set it all on fire\nI won't fall again, I'll be my own lighter\n\n[Chorus]\nNothing can burn me now\nI'll be my own lighter\nI feel a spark inside me, I don't need savin'\nNo way, no way\n'Cause I'm my own, I'm my own lighter\n\n[Verse 2]\nI'm tired of a million tries to fight, the signs\nAnd when everybody tried to tell me\nI should've known that it was timе to break free\nYour reigns that kept mе at your mercy\nI'll burn them to the ground\nNo more, no more, ignite the fire\n\n[Pre-Chorus]\nSomewhere along the way I lost my might\nI had to walk a hundred thousand miles\nI'm not afraid to set it all on fire\nI won't fall again, I'll be my own lighter\n\n[Chorus]\nNothing can burn me now\nI'll be my own lighter\nI feel a spark inside me, I don't need savin'\nNo way, no way\n'Cause I'm my own, I'm my own lighter\n\n[Bridge]\nSilence fills the room\nAnd I've taken off my jewels\nI wish none of this was true\nBut there's a fire growin' too, yeah\n\n[Chorus]\nNothing can burn me now\nI'll be my own lighter\nI feel a spark inside me, I don't need savin'\nNo way, no way\n'Cause I'm my own, I'm my own lighter\n\n[Outro]\nNothing can burn me down\nI'm my own, I'm my own lighter",
"lyrics_translation_fi": "[Verse 1]\nKultainen tyttö pukeutunut jäähän, sydän yhtä synkkä kuin yö\nSait minut himmentämään valoani, ei enää\nLuulen todella, että ostin valheesi\nTein mitä tahansa pitääkseni sinut omana\nPidit minut koukussa siimassasi, ei enää\n\n[Pre-Chorus]\nJossain matkan varrella menetin voimani\nMinun piti kävellä satatuhatta mailia\nEn pelkää sytyttää kaikkea tuleen\nEn lankea enää, olen oma sytyttäjäni\n\n[Chorus]\nMikään ei voi polttaa minua nyt\nOlen oma sytyttäjäni\nTunnen kipinän sisälläni, en tarvitse pelastusta\nEi mitenkään, ei mitenkään\nKoska olen omani, olen oma sytyttäjäni\n\n[Verse 2]\nOlen kyllästynyt miljooniin yrityksiin taistella, merkkeihin\nJa kun kaikki yrittivät kertoa minulle\nMinun olisi pitänyt tietää, että oli aika vapautua\nValtasi, jotka pitivät minut armoillasi\nPoltan ne maan tasalle\nEi enää, ei enää, sytytä tulta\n\n[Pre-Chorus]\nJossain matkan varrella menetin voimani\nMinun piti kävellä satatuhatta mailia\nEn pelkää sytyttää kaikkea tuleen\nEn lankea enää, olen oma sytyttäjäni\n\n[Chorus]\nMikään ei voi polttaa minua nyt\nOlen oma sytyttäjäni\nTunnen kipinän sisälläni, en tarvitse pelastusta\nEi mitenkään, ei mitenkään\nKoska olen omani, olen oma sytyttäjäni\n\n[Bridge]\nHiljaisuus täyttää huoneen\nJa olen riisunut koruni\nToivon, ettei mikään tästä olisi totta\nMutta siellä on myös tuli kasvamassa, yeah\n\n[Chorus]\nMikään ei voi polttaa minua nyt\nOlen oma sytyttäjäni\nTunnen kipinän sisälläni, en tarvitse pelastusta\nEi mitenkään, ei mitenkään\nKoska olen omani, olen oma sytyttäjäni\n\n[Outro]\nMikään ei voi polttaa minua\nOlen omani, olen oma sytyttäjäni", "lyrics_translation_fi": "[Verse 1]\nKultainen tyttö pukeutunut jäähän, sydän yhtä synkkä kuin yö\nSait minut himmentämään valoani, ei enää\nLuulen todella, että ostin valheesi\nTein mitä tahansa pitääkseni sinut omana\nPidit minut koukussa siimassasi, ei enää\n\n[Pre-Chorus]\nJossain matkan varrella menetin voimani\nMinun piti kävellä satatuhatta mailia\nEn pelkää sytyttää kaikkea tuleen\nEn lankea enää, olen oma sytyttäjäni\n\n[Chorus]\nMikään ei voi polttaa minua nyt\nOlen oma sytyttäjäni\nTunnen kipinän sisälläni, en tarvitse pelastusta\nEi mitenkään, ei mitenkään\nKoska olen omani, olen oma sytyttäjäni\n\n[Verse 2]\nOlen kyllästynyt miljooniin yrityksiin taistella, merkkeihin\nJa kun kaikki yrittivät kertoa minulle\nMinun olisi pitänyt tietää, että oli aika vapautua\nValtasi, jotka pitivät minut armoillasi\nPoltan ne maan tasalle\nEi enää, ei enää, sytytä tulta\n\n[Pre-Chorus]\nJossain matkan varrella menetin voimani\nMinun piti kävellä satatuhatta mailia\nEn pelkää sytyttää kaikkea tuleen\nEn lankea enää, olen oma sytyttäjäni\n\n[Chorus]\nMikään ei voi polttaa minua nyt\nOlen oma sytyttäjäni\nTunnen kipinän sisälläni, en tarvitse pelastusta\nEi mitenkään, ei mitenkään\nKoska olen omani, olen oma sytyttäjäni\n\n[Bridge]\nHiljaisuus täyttää huoneen\nJa olen riisunut koruni\nToivon, ettei mikään tästä olisi totta\nMutta siellä on myös tuli kasvamassa, yeah\n\n[Chorus]\nMikään ei voi polttaa minua nyt\nOlen oma sytyttäjäni\nTunnen kipinän sisälläni, en tarvitse pelastusta\nEi mitenkään, ei mitenkään\nKoska olen omani, olen oma sytyttäjäni\n\n[Outro]\nMikään ei voi polttaa minua\nOlen omani, olen oma sytyttäjäni",
"tags": [ "tags": [
@@ -366,7 +384,8 @@
], ],
"confidence": 0.95, "confidence": 0.95,
"language": "Puola", "language": "Puola",
"running_order": 15 "running_order": 15,
"img_url": "https://eurovision.tv/sites/default/files/styles/teaser/public/media/image/2025-05/250507_Corinne-Cumming_EBU_00140.jpg?h=4606ab50&itok=l5j5YBzJ"
}, },
{ {
"artist": "NAPA", "artist": "NAPA",
@@ -386,7 +405,8 @@
], ],
"confidence": 0.95, "confidence": 0.95,
"language": "Portugali", "language": "Portugali",
"running_order": 21 "running_order": 21,
"img_url": "https://eurovision.tv/sites/default/files/styles/teaser/public/media/image/2025-05/250507_Corinne-Cumming_EBU_00320.jpg?h=970e90fb&itok=iU7sPcym"
}, },
{ {
"artist": "Gabry Ponte", "artist": "Gabry Ponte",
@@ -406,7 +426,8 @@
], ],
"confidence": 0.95, "confidence": 0.95,
"language": "Italia", "language": "Italia",
"running_order": 25 "running_order": 25,
"img_url": "https://eurovision.tv/sites/default/files/styles/teaser/public/media/image/2025-05/250507_Corinne-Cumming_EBU_00443.jpg?h=f1bb2bb4&itok=i1ABEyK2"
}, },
{ {
"artist": "Melody", "artist": "Melody",
@@ -426,7 +447,8 @@
], ],
"confidence": 0.95, "confidence": 0.95,
"language": "Espanja", "language": "Espanja",
"running_order": 6 "running_order": 6,
"img_url": "https://eurovision.tv/sites/default/files/styles/teaser/public/media/image/2025-05/250510_Corinne-Cumming_EBU_00316.jpg?h=8c795ec1&itok=KlHomwLj"
}, },
{ {
"artist": "KAJ", "artist": "KAJ",
@@ -445,7 +467,8 @@
], ],
"confidence": 0.95, "confidence": 0.95,
"language": "Ruotsi", "language": "Ruotsi",
"running_order": 23 "running_order": 23,
"img_url": "https://eurovision.tv/sites/default/files/styles/teaser/public/media/image/2025-05/250507_Corinne-Cumming_EBU_00286.jpg?h=f33f36c7&itok=JRGgvwU_"
}, },
{ {
"artist": "Zoë Më", "artist": "Zoë Më",
@@ -464,7 +487,8 @@
], ],
"confidence": 0.95, "confidence": 0.95,
"language": "Ranska", "language": "Ranska",
"running_order": 19 "running_order": 19,
"img_url": "https://eurovision.tv/sites/default/files/styles/teaser/public/media/image/2025-05/250510_Corinne-Cumming_EBU_00250.jpg?h=0178f7ef&itok=EguF960o"
}, },
{ {
"artist": "Ziferblat", "artist": "Ziferblat",
@@ -483,7 +507,8 @@
], ],
"confidence": 0.95, "confidence": 0.95,
"language": "Ukraina", "language": "Ukraina",
"running_order": 7 "running_order": 7,
"img_url": "https://eurovision.tv/sites/default/files/styles/teaser/public/media/image/2025-05/250507_Corinne-Cumming_EBU_00253.jpg?h=373d2acb&itok=Ap_BDOTU"
}, },
{ {
"artist": "Remember Monday", "artist": "Remember Monday",
@@ -503,6 +528,7 @@
], ],
"confidence": 0.95, "confidence": 0.95,
"language": "Englanti", "language": "Englanti",
"running_order": 8 "running_order": 8,
"img_url": "https://eurovision.tv/sites/default/files/styles/teaser/public/media/image/2025-05/250510_Corinne-Cumming_EBU_00181.jpg?h=00f31e3b&itok=fGY7Vs-D"
} }
] ]
+4
View File
@@ -15,6 +15,10 @@ class Song(BaseModel):
running_order: int | None = Field( running_order: int | None = Field(
default=None, description="Running order of the song.", example=13 default=None, description="Running order of the song.", example=13
) )
img_url: str = Field(
description="URL to the artist image.",
example="https://www.youtube.com/watch?v=dQw4w9WgXcQ",
)
lyrics_url: str | None = Field( lyrics_url: str | None = Field(
default=None, default=None,
description="URL to the original lyrics.", description="URL to the original lyrics.",
+1
View File
@@ -55,3 +55,4 @@ class UpdateUser(BaseModel):
password: str | None = Field( password: str | None = Field(
None, description="Password of the user", examples=["p1p4l1"] None, description="Password of the user", examples=["p1p4l1"]
) )
updated_at: datetime = Field(default=datetime.now(), description="Updated at")
+111 -2
View File
@@ -1,13 +1,110 @@
from fastapi import APIRouter from fastapi import APIRouter
from enum import Enum
import duckdb # Added for specific exception handling
from models.result import Result, TeamResult from models.result import Result, TeamResult
from models.msg import Message
from lib.db import get_connection from lib.db import get_connection
from lib.logger import logger
router = APIRouter(prefix="/results", tags=["results"]) router = APIRouter(prefix="/results", tags=["results"])
@router.get("/", response_model=list[Result]) # It's good practice for FastAPI to have Enum derive from str as well
async def list_results(): class ResultType(str, Enum):
DEVIATION = "deviation"
COSTUME = "costume"
SHOW = "show"
SONG = "song"
@router.get("/{result_type}", response_model=list[Result] | Message)
async def list_results(result_type: ResultType):
query = ""
try:
with get_connection() as conn:
if result_type == ResultType.DEVIATION:
# Selects the song with the highest standard deviation in its total review scores
query = """
WITH SongReviewDeviations AS (
SELECT
song_id,
COALESCE(STDDEV_SAMP((score_song + score_show + score_costume) / 3.0), 0) AS deviation_value
FROM Review
GROUP BY song_id
)
SELECT
ras.song_id,
ras.country_fi,
ras.country_sv,
ras.artist,
ras.title,
ras.avg_score_song,
ras.avg_score_show,
ras.avg_score_costume,
ras.avg_total_score
FROM ReviewAllSongs ras
JOIN SongReviewDeviations srd ON ras.song_id = srd.song_id
ORDER BY srd.deviation_value DESC
LIMIT 1;
"""
df = conn.execute(query).fetchdf()
logger.debug(f"Query for DEVIATION: {query}")
logger.debug(f"Result DataFrame for DEVIATION: {df}")
elif result_type == ResultType.COSTUME:
# Selects the song with the highest average costume score
query = """SELECT * FROM ReviewAllSongs ORDER BY avg_score_costume DESC LIMIT 1 """
df = conn.execute(query).fetchdf()
elif result_type == ResultType.SHOW:
# Selects the song with the highest average show score
query = """SELECT * FROM ReviewAllSongs ORDER BY avg_score_show DESC LIMIT 1 """
df = conn.execute(query).fetchdf()
elif result_type == ResultType.SONG:
# Selects the song with the highest average song score
query = """SELECT * FROM ReviewAllSongs ORDER BY avg_score_song DESC LIMIT 1 """
df = conn.execute(query).fetchdf()
else:
# This case should ideally not be reached if using Enums properly with FastAPI
return Message(type="error", message="Invalid result type")
if df.empty:
# If the dataframe is empty, return an empty list.
# This applies if a view exists but has no data, or LIMIT 1 returns no row.
return []
# The existing code implies Result model can handle various structures.
# For DEVIATION, row will be {'deviation_value': X}
# For COSTUME/SHOW/SONG (LIMIT 1), it will be a single row from ReviewAllSongs.
# For others, it will be multiple rows from their respective views.
# All these are converted to a list of Result objects.
results = [Result(**row) for row in df.to_dict(orient="records")]
return results
except duckdb.CatalogException as e:
# Handles errors like "View not found" (e.g., ReviewAllSongs doesn't exist)
# You might want to log the error e
print(f"Database Catalog Error: {e}")
return Message(
type="error",
message=f"Data source for '{result_type.value}' not found or query error. Details: {str(e)}",
)
except duckdb.Error as e: # Catch other DuckDB specific errors
print(f"DuckDB Error: {e}")
return Message(
type="error",
message=f"Database query error for '{result_type.value}'. Details: {str(e)}",
)
except Exception as e:
# Catch any other unexpected errors
print(f"Unexpected Error: {e}")
return Message(
type="error",
message=f"An unexpected error occurred while fetching results for '{result_type.value}'.",
)
@router.get("/global", response_model=list[Result])
async def list_global_results():
with get_connection() as conn: with get_connection() as conn:
df = conn.execute("SELECT * FROM ReviewSummaryGlobal").fetchdf() df = conn.execute("SELECT * FROM ReviewSummaryGlobal").fetchdf()
if df.empty: if df.empty:
@@ -16,6 +113,18 @@ async def list_results():
return results return results
@router.get("/user/{user_id}", response_model=list[Result])
async def list_user_results(user_id: int):
with get_connection() as conn:
df = conn.execute(
"SELECT * FROM ReviewSummaryByUser WHERE user_id = ?", (user_id,)
).fetchdf()
if df.empty:
return []
results = [Result(**row) for row in df.to_dict(orient="records")]
return results
@router.get("/team/{team_id}", response_model=list[TeamResult]) @router.get("/team/{team_id}", response_model=list[TeamResult])
async def list_team_results(team_id: int): async def list_team_results(team_id: int):
with get_connection() as conn: with get_connection() as conn:
+4 -4
View File
@@ -47,7 +47,6 @@ async def update_user(user: UpdateUser, request: Request):
avatar_id = user.avatar_id if user.avatar_id else None avatar_id = user.avatar_id if user.avatar_id else None
email = user.email if user.email else None email = user.email if user.email else None
password = hash_password(user.password) if user.password else None password = hash_password(user.password) if user.password else None
updated_at = datetime.now()
with get_connection() as conn: with get_connection() as conn:
# Build query dynamically based on non-None values # Build query dynamically based on non-None values
@@ -63,14 +62,15 @@ async def update_user(user: UpdateUser, request: Request):
params.append(email) params.append(email)
if password is not None: if password is not None:
update_fields.append("password = ?") update_fields.append("hashed_password = ?")
params.append(password) params.append(password)
# Only proceed if there are fields to update # Only proceed if there are fields to update
if update_fields: if update_fields:
query = f'UPDATE "User" SET {", ".join(update_fields)}, updated_at = ? WHERE id = ?' query = f'UPDATE "User" SET {", ".join(update_fields)}, updated_at = CURRENT_TIMESTAMP WHERE id = ?'
params.append(updated_at)
params.append(user_id) params.append(user_id)
logger.debug(f"Executing query: {query}")
logger.debug(f"Query parameters: {params}")
conn.execute(query, params) conn.execute(query, params)
logger.debug( logger.debug(
Generated
+4 -4
View File
@@ -86,14 +86,14 @@ wheels = [
[[package]] [[package]]
name = "click" name = "click"
version = "8.1.8" version = "8.2.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" }, { name = "colorama", marker = "sys_platform == 'win32'" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593, upload-time = "2024-12-21T18:38:44.339Z" } sdist = { url = "https://files.pythonhosted.org/packages/cd/0f/62ca20172d4f87d93cf89665fbaedcd560ac48b465bd1d92bfc7ea6b0a41/click-8.2.0.tar.gz", hash = "sha256:f5452aeddd9988eefa20f90f05ab66f17fce1ee2a36907fd30b05bbb5953814d", size = 235857, upload-time = "2025-05-10T22:21:03.111Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188, upload-time = "2024-12-21T18:38:41.666Z" }, { url = "https://files.pythonhosted.org/packages/a2/58/1f37bf81e3c689cc74ffa42102fa8915b59085f54a6e4a80bc6265c0f6bf/click-8.2.0-py3-none-any.whl", hash = "sha256:6b303f0b2aa85f1cb4e5303078fadcbcd4e476f114fab9b5007005711839325c", size = 102156, upload-time = "2025-05-10T22:21:01.352Z" },
] ]
[[package]] [[package]]
@@ -131,7 +131,7 @@ wheels = [
[[package]] [[package]]
name = "eurovision-25-backend" name = "eurovision-25-backend"
version = "1.0rc4" version = "1.0rc8"
source = { virtual = "." } source = { virtual = "." }
dependencies = [ dependencies = [
{ name = "aiofiles" }, { name = "aiofiles" },