Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit fc7c6c55 authored by Sebastiano Barezzi's avatar Sebastiano Barezzi
Browse files

Twelve: SubsonicDataSource: Implement lyrics fetching

Change-Id: I08af7207345a09bc5e558730b1c4470287f579d9
parent 85bd87ef
Loading
Loading
Loading
Loading
+34 −3
Original line number Diff line number Diff line
@@ -375,9 +375,22 @@ class SubsonicDataSource(
            uri?.let(this::audio) ?: flowOf(RequestStatus.Error(MediaError.NOT_FOUND))
        }

    override fun lyrics(audioUri: Uri) = flowOf(
        RequestStatus.Error<Lyrics, _>(MediaError.NOT_IMPLEMENTED)
    )
    override fun lyrics(audioUri: Uri) = suspend {
        val audioId = audioUri.lastPathSegment!!

        subsonicClient.getLyricsBySongId(audioId).toRequestStatus {
            toModel()
        }.let {
            when (it) {
                is RequestStatus.Loading -> RequestStatus.Loading(it.progress)
                is RequestStatus.Success -> it.data?.let { lyrics ->
                    RequestStatus.Success<_, MediaError>(lyrics)
                } ?: RequestStatus.Error(MediaError.NOT_FOUND)

                is RequestStatus.Error -> RequestStatus.Error(it.error, it.throwable)
            }
        }
    }.asFlow()

    override suspend fun createPlaylist(name: String) = subsonicClient.createPlaylist(
        null, name, listOf()
@@ -502,6 +515,24 @@ class SubsonicDataSource(
        else -> Audio.Type.MUSIC
    }

    private fun org.lineageos.twelve.datasources.subsonic.models.LyricsList.toModel() =
        structuredLyrics.firstOrNull()?.let { structuredLyrics ->
            val offset = structuredLyrics.offset ?: 0

            Lyrics.Builder()
                .apply {
                    structuredLyrics.line.forEach { line ->
                        val startMs = line.start?.let { start -> start + offset }

                        addLine(
                            text = line.value,
                            startMs = startMs
                        )
                    }
                }
                .build()
        }

    private fun Error.Code.toRequestStatusType() = when (this) {
        Error.Code.GENERIC_ERROR -> MediaError.IO
        Error.Code.REQUIRED_PARAMETER_MISSING -> MediaError.IO
+22 −0
Original line number Diff line number Diff line
@@ -1217,6 +1217,28 @@ class SubsonicClient(

    // TODO

    // OpenSubsonic extensions

    /**
     * Retrieves all structured lyrics from the server for a given song. The lyrics can come from
     * embedded tags (SYLT/USLT), LRC file/text file, or any other external source.
     *
     * Note: OpenSubsonic only.
     *
     * @since OpenSubsonic version 1
     * @param id The track ID
     */
    suspend fun getLyricsBySongId(
        id: String,
    ) = ApiRequest.get<ResponseRoot>(
        listOf("getLyricsBySongId"),
        queryParameters = listOf(
            "id" to id,
        )
    ).execute(api).mapResponse(SubsonicResponse::lyricsList)

    // TODO

    private inline fun <T> MethodResult<ResponseRoot>.mapResponse(
        methodValue: SubsonicResponse.() -> T,
    ) = when (this) {
+24 −0
Original line number Diff line number Diff line
/*
 * SPDX-FileCopyrightText: 2025 The LineageOS Project
 * SPDX-License-Identifier: Apache-2.0
 */

package org.lineageos.twelve.datasources.subsonic.models

import kotlinx.serialization.Serializable

/**
 * One line of a song lyric.
 *
 * Note: OpenSubsonic only.
 *
 * @param value The actual text of this line
 * @param start The start time of the lyrics, relative to the start time of the track, in
 *   milliseconds. If this is not part of synced lyrics, start must be omitted
 */
@Suppress("PROVIDED_RUNTIME_TOO_LOW")
@Serializable
data class Line(
    val value: String,
    val start: Long? = null,
)
+19 −0
Original line number Diff line number Diff line
/*
 * SPDX-FileCopyrightText: 2025 The LineageOS Project
 * SPDX-License-Identifier: Apache-2.0
 */

package org.lineageos.twelve.datasources.subsonic.models

import kotlinx.serialization.Serializable

/**
 * Lyrics.
 */
@Suppress("PROVIDED_RUNTIME_TOO_LOW")
@Serializable
data class Lyrics(
    val value: String,
    val artist: String? = null,
    val title: String? = null,
)
+22 −0
Original line number Diff line number Diff line
/*
 * SPDX-FileCopyrightText: 2025 The LineageOS Project
 * SPDX-License-Identifier: Apache-2.0
 */

package org.lineageos.twelve.datasources.subsonic.models

import kotlinx.serialization.Serializable

/**
 * List of structured lyrics.
 *
 * Note: OpenSubsonic only.
 *
 * @param structuredLyrics Structured lyrics. There can be multiple lyrics of the same type with the
 *   same language
 */
@Suppress("PROVIDED_RUNTIME_TOO_LOW")
@Serializable
data class LyricsList(
    val structuredLyrics: List<StructuredLyrics>,
)
Loading