Lyrics provide text content for tracks, supporting both plain text and time-synchronized formats. You can add multiple language versions for international audiences.
Overview
The lyrics management system enables you to:
Add lyrics Attach lyrics to any track in your catalog
Time synchronization Create karaoke-style synchronized lyrics
Multi-language Support multiple language versions per track
JSONB storage Flexible structure for lyrics data
Lyrics entity structure
The Lyrics entity contains the following fields:
@ Entity ()
export class Lyrics extends AbstractEntity {
// CONTENT
@ Column ({ type: 'jsonb' })
content : { time ?: string ; text : string }[];
// TRACK ID
@ Column ({ name: 'track_id' , nullable: false , type: 'uuid' })
trackId !: UUID ;
// TRACK
@ ManyToOne (() => Track , ( track ) => track . lyrics )
@ JoinColumn ({ name: 'track_id' })
track !: Track ;
// LANGUAGE
@ Column ({
name: 'language' ,
nullable: false ,
type: 'varchar' ,
default: 'en' ,
})
language !: string ;
}
Core fields
Field Type Required Description idUUID Yes Unique identifier (inherited from AbstractEntity) contentJSONB array Yes Array of lyrics lines with optional timestamps trackIdUUID Yes Reference to the parent track languagestring Yes ISO language code (default: en) createdAttimestamp Yes Record creation time (inherited) updatedAttimestamp Yes Last update time (inherited)
Content structure
Lyrics are stored as JSONB arrays, where each element represents a line:
Plain text lyrics
Synchronized lyrics
For non-synchronized lyrics, omit the time field: [
{ "text" : "Verse one, line one" },
{ "text" : "Verse one, line two" },
{ "text" : "" },
{ "text" : "Chorus starts here" }
]
For time-synchronized lyrics, include timestamps: [
{ "time" : "00:00.00" , "text" : "Intro" },
{ "time" : "00:15.50" , "text" : "Verse one, line one" },
{ "time" : "00:20.30" , "text" : "Verse one, line two" },
{ "time" : "00:45.00" , "text" : "Chorus starts here" }
]
The time field is optional, allowing you to mix synchronized and non-synchronized content or gradually add timestamps to existing lyrics.
Relationships
Each lyrics record belongs to exactly one track. A track can have multiple lyrics records (for different languages). @ ManyToOne (() => Track , ( track ) => track . lyrics )
@ JoinColumn ({ name: 'track_id' })
track ! : Track ;
Common operations
Create lyrics
Add lyrics to a track:
POST / lyrics
{
"trackId" : "550e8400-e29b-41d4-a716-446655440000" ,
"language" : "en" ,
"content" : [
{ "time" : "00:00.00" , "text" : "[Intro]" },
{ "time" : "00:10.50" , "text" : "Walking down the street" },
{ "time" : "00:15.30" , "text" : "With a rhythm in my feet" },
{ "text" : "" },
{ "time" : "00:30.00" , "text" : "Music in the air tonight" }
]
}
Response:
{
"message" : "Lyrics created successfully" ,
"data" : {
"id" : "..." ,
"trackId" : "550e8400-e29b-41d4-a716-446655440000" ,
"language" : "en" ,
"content" : [ /* content array */ ],
"createdAt" : "2024-01-15T10:30:00Z" ,
"updatedAt" : "2024-01-15T10:30:00Z"
}
}
Fetch lyrics
Retrieve lyrics with optional filtering:
GET / lyrics ? page = 0 & size = 10 & trackId = < uuid >
Query parameters:
page - Page number (default: 0)
size - Items per page (default: 10)
trackId - Filter by track (optional)
Get paginated list of all lyrics: GET / lyrics ? page = 0 & size = 20
Get all lyrics for a specific track: GET / lyrics ? trackId = 550e8400 - e29b - 41 d4 - a716 - 446655440000
This returns all language versions for the track.
Get lyrics by ID
Retrieve a specific lyrics record:
Response:
{
"message" : "Lyrics fetched successfully" ,
"data" : {
"id" : "..." ,
"trackId" : "..." ,
"language" : "en" ,
"content" : [
{ "time" : "00:10.50" , "text" : "Walking down the street" },
{ "time" : "00:15.30" , "text" : "With a rhythm in my feet" }
]
}
}
Language support
Lyrics support multiple languages using ISO 639-1 language codes:
Adding multiple language versions
You can add lyrics in different languages for the same track:
// English version
POST / lyrics
{
"trackId" : "track-uuid" ,
"language" : "en" ,
"content" : [
{ "text" : "Hello world" }
]
}
// Spanish version
POST / lyrics
{
"trackId" : "track-uuid" ,
"language" : "es" ,
"content" : [
{ "text" : "Hola mundo" }
]
}
For synchronized lyrics, use the format MM:SS.ss or HH:MM:SS.ss:
Standard format (MM:SS.ss)
Extended format (HH:MM:SS.ss)
[
{ "time" : "00:15.50" , "text" : "First line" },
{ "time" : "00:20.30" , "text" : "Second line" },
{ "time" : "01:05.00" , "text" : "One minute later" }
]
Timestamps are stored as strings, giving you flexibility in format. Choose a format and be consistent within each lyrics record.
Use cases
Simple song lyrics
Add plain text lyrics without timestamps:
const lyrics = await fetch ( '/lyrics' , {
method: 'POST' ,
body: JSON . stringify ({
trackId: trackId ,
language: 'en' ,
content: [
{ text: 'Verse 1:' },
{ text: 'Walking through the night' },
{ text: 'Everything feels right' },
{ text: '' },
{ text: 'Chorus:' },
{ text: 'Dancing in the moonlight' },
{ text: 'Everything is alright' }
]
})
});
Karaoke-style lyrics
Create synchronized lyrics for karaoke display:
const syncedLyrics = await fetch ( '/lyrics' , {
method: 'POST' ,
body: JSON . stringify ({
trackId: trackId ,
language: 'en' ,
content: [
{ time: '00:00.00' , text: '[Intro]' },
{ time: '00:10.00' , text: 'Let me sing you a song' },
{ time: '00:15.50' , text: 'That will make you dance along' },
{ time: '00:20.30' , text: 'To the rhythm and the beat' },
{ time: '00:25.00' , text: 'Move your body and your feet' }
]
})
});
Multi-language track
Add lyrics in multiple languages:
// Original English lyrics
await createLyrics ({
trackId: trackId ,
language: 'en' ,
content: [{ text: 'Welcome to the show' }]
});
// Japanese translation
await createLyrics ({
trackId: trackId ,
language: 'ja' ,
content: [{ text: 'ショーへようこそ' }]
});
// Spanish translation
await createLyrics ({
trackId: trackId ,
language: 'es' ,
content: [{ text: 'Bienvenido al espectáculo' }]
});
Gradual timestamp addition
Start with plain text and add timestamps later:
// Initial creation without timestamps
POST / lyrics
{
"trackId" : "..." ,
"content" : [
{ "text" : "Line one" },
{ "text" : "Line two" },
{ "text" : "Line three" }
]
}
// Later, update with timestamps
PATCH / lyrics / : id
{
"content" : [
{ "time" : "00:10.00" , "text" : "Line one" },
{ "time" : "00:15.00" , "text" : "Line two" },
{ "time" : "00:20.00" , "text" : "Line three" }
]
}
JSONB advantages
Storing lyrics as JSONB provides several benefits:
Flexible schema Add custom fields without schema changes (e.g., speaker, harmony, style)
Efficient queries Query and index JSON content directly in PostgreSQL
Array operations Manipulate lyrics lines using array operations
No parsing overhead Store and retrieve structured data without serialization
Extended content structure
You can extend the content structure with additional fields:
[
{
"time" : "00:10.00" ,
"text" : "Main vocal line" ,
"harmony" : "Background vocals" ,
"speaker" : "Lead Singer"
},
{
"time" : "00:15.00" ,
"text" : "Next line" ,
"style" : "whispered"
}
]
While the entity defines the basic structure with time and text, the JSONB column accepts any valid JSON structure.
Releases Organize tracks into releases
Artists Credit songwriters and performers