LyricsKit

repository·master·Indexed 41 days ago

https://github.com/ddddxxx/lyricskit

A Swift-based lyrics submodule for LyricsX that provides tools to search for lyrics across services including NetEase Music, QQ Music, Kugou Music, TTPod, Gecimi, and Syair. It includes a Combine-based search API and implements the LRCX file format specification, supporting ID tags, timestamped lyric lines, and attachments for translations, furigana, and romaji.

Tokens
1.5K
Snippets
4
Records
5
Agent score
50%

What's inside LyricsKit

  1. Search lyrics from the internet using LyricsKit

    master

    To search for lyrics, create a LyricsSearchRequest containing the song information and duration. You can then use a specific provider from LyricsProviders or a LyricsProviders.Group to search across multiple sources simultaneously. Use the lyricsPublisher(request:) method to receive the lyrics via a Combine publisher.

    import LyricsService
    
    // create a search request
    let song = "Tranquilize"
    let artist = "The Killers"
    let duration = 225.2
    let searchReq = LyricsSearchRequest(
        searchTerm: .info(title: song, artist: artist),
        duration: duration
    )
    
    // choose a lyrics service provider
    let provider = LyricsProviders.Kugou()
    // or search from multiple sources
    let provider = LyricsProviders.Group(service: [.kugou, .netease, .qq])
    
    // search
    provider.lyricsPublisher(request: searchReq).sink { lyrics in
        print(lyrics)
    }
  2. LRCX Predefined ID tags

    master

    LRCX supports predefined ID tags for metadata. These are used to identify song information within the file.

    TagKeyValue TypeDescription
    titletistring
    albumalstring
    artistarstring
    offsetoffsetinteger
    lengthlengthdecimal
    | Tag | Key | Value Type | Description |
    | --- | --- | --- | --- |
    | title | ti | string | |
    | album | al | string | |
    | artist | ar | string | |
    | offset | offset | integer | |
    | length | length | decimal | |
  3. LRCX Predefined attachment tags

    master

    LRCX supports predefined attachment tags to provide additional information like translations or pronunciation guides.

    TagKeyValue TypeAttachment typeDescription
    translationtrRFC 4646plain text
    word time tagttno valueindex based (with timestamp in millisecond)
    furiganafuno valuerange based
    romajirono valuerange based
    | Tag | Key | Value Type | Attachment type | Description |
    | --- | --- | --- | --- | --- |
    | translation | tr | [RFC 4646](https://www.ietf.org/rfc/rfc4646.txt) | plain text | |
    | word time tag | tt | no value | index based (with timestamp in millisecond) | |
    | furigana | fu | no value | range based | |
    | romaji | ro | no value | range based | |
  4. LRCX file specification

    master

    The LRCX format is a structured lyric format defined by a grammar that supports ID tags, lyric lines with timestamps, and lyric attachments.

    Key components include:

    • <id tag>: Metadata tags in the format [key] or [key:value].
    • <lyric line>: A timestamp followed by text: [mm:ss.SSS] lyric text.
    • <lyric attachment>: Timestamps paired with attachment tags and bodies (plain text, index-based, or range-based).

    Full EBNF grammar:

    <lrcx>              ::= <line> (NEWLINE <line>)*
    <line>              ::= <id tag>
                          | <lyric line>
                          | <lyric attachment>
                          | ""
    
    <id tag>            ::= <tag>
    <tag>               ::= "[" <tag content> "]"
    <tag content>       ::= <tag key>
                          | <tag key> ":" <tag value>
    <tag key>           ::= [0-9a-zA-Z_-]+
    <tag value>         ::= <character except NEWLINE or "]"+>
    
    <lyric line>        ::= <time tag> <character except NEWLINE>*
    <lyric attachment>  ::= <time tag> <attachment tag> <attachment body>
    
    <time tag>          ::= "[" (<minute> ":")* <second> ("." <millisecond>)* "]"
    
    <attachment tag>    ::= <tag>
    <attachment body>   ::= <plain text attachment>
                          | <index based attachment>
                          | <range based attachment>
    <plain text attachment>     ::= <character except NEWLINE>+
    <index based attachment>    ::= <index based segment>+
    <range based attachment>    ::= <range based segment>+
    <index based segment>       ::= "<" <segment value> "," <segment index> ">
    <range based segment>       ::= "<" <segment value> "," <segment range> ">
    <segment value>             ::= <characters except NEWLINE, "," or ">">
    <segment index>             ::= <number>
    <segment range>             ::= <lowerBound> "," <upperBound>
    <lrcx>              ::= <line> (NEWLINE <line>)*
    <line>              ::= <id tag>
                          | <lyric line>
                          | <lyric attachment>
                          | ""
    
    <id tag>            ::= <tag>
    <tag>               ::= "[" <tag content> "]"
    <tag content>       ::= <tag key>
                          | <tag key> ":" <tag value>
    <tag key>           ::= [0-9a-zA-Z_-]+
    <tag value>         ::= <character except NEWLINE or "]"+>
    
    <lyric line>        ::= <time tag> <character except NEWLINE>*
    <lyric attachment>  ::= <time tag> <attachment tag> <attachment body>
    
    <time tag>          ::= "[" (<minute> ":")* <second> ("." <millisecond>)* "]"
    
    <attachment tag>    ::= <tag>
    <attachment body>   ::= <plain text attachment>
                          | <index based attachment>
                          | <range based attachment>
    <plain text attachment>     ::= <character except NEWLINE>+
    <index based attachment>    ::= <index based segment>+
    <range based attachment>    ::= <range based segment>+
    <index based segment>       ::= "<" <segment value> "," <segment index> ">
    <range based segment>       ::= "<" <segment value> "," <segment range> ">
    <segment value>             ::= <characters except NEWLINE, "," or ">">
    <segment index>             ::= <number>
    <segment range>             ::= <lowerBound> "," <upperBound>