Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PetitLyric Source #247

Merged
merged 6 commits into from
Jul 16, 2024
Merged

Add PetitLyric Source #247

merged 6 commits into from
Jul 16, 2024

Conversation

yodaluca23
Copy link
Contributor

@yodaluca23 yodaluca23 commented Jul 15, 2024

Add PetitLyrics as a New Lyrics Source

Description

This pull request introduces a new lyrics source, PetitLyrics. The addition allows users to select PetitLyrics as their preferred lyrics provider, expanding the options available for fetching lyrics. Closes #243.

Changes Made

  1. Updated Lyrics Source Section:

    • Modified EeveeLyricsSettingsView+LyricsSourceSection.swift to include PetitLyrics in the lyrics source picker.
    • Updated the footer text to describe PetitLyrics.
  2. Implemented PetitLyrics Repository:

    • Created PetitLyricsRepository.swift in the /Sources/EeveeSpotify/Lyrics/Repositories directory.
    • Implemented the LyricsRepository protocol for PetitLyrics.
  3. Modified Lyrics Fetching Logic:

    • Updated CustomLyrics.x.swift and LyricsSource.swift to handle the new .petitLyrics case.

Affected Files

  • Sources/EeveeSpotify/Settings/Views/Sections/EeveeLyricsSettingsView+LyricsSourceSection.swift
  • Sources/EeveeSpotify/Lyrics/CustomLyrics.x.swift
  • Sources/EeveeSpotify/Lyrics/Models/Settings/LyricsSource.swift
  • Sources/EeveeSpotify/Lyrics/Repositories/PetitLyricsRepository.swift (new file)

Testing

  • Verified that the new PetitLyrics option appears in the lyrics source picker.
  • Ensured that lyrics can be fetched from PetitLyrics and displayed correctly.
  • Tested fallback mechanisms to other lyrics sources when PetitLyrics fails.

Additional Information

I had to do some hacky things because the search request sends back a full webpage, so it has to scrape it with regex, hopefully, they don't update their site often (by the looks of it they don't).
They do apparently have time synced in their app, but I couldn't get it to work with MITMProxy, to see how it's done, I may add it in the future if I can figure it out.
Please squash, if/when you merge.
Yes this is a PR description template lol.

Copy link
Owner

@whoeevee whoeevee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PetitLyrics has an API that Android app uses, so you must use it and get rid of CSRF and Regex. The API provides time-synced lyrics as well.

All requests are POST to https://p1.petitlyrics.com/api/GetPetitLyricsData.php with application/x-www-form-urlencoded Content-Type. Each request includes clientAppId = p1110417 and terminalType = 10 parameters.

To search for a song, execute the request with key_artist, key_title, and max_count:

key_artist=Kanaria&key_title=KING&clientAppId=p1110417&maxCount=5&terminalType=10

All responses are in XML. Decode them properly using a library like XMLCoder.

You will see something like this:

<response>
  <status>00000000</status>
  <songs>
    <name>プチリリ2 (android)(SDK)</name>
    <date>2024-07-15 15:12:23</date>
    <matchedCount>6</matchedCount>
    <returnedCount>5</returnedCount>
    <song>
      <order>1</order>
      <lyricsId>2893877</lyricsId>
      <title>KING</title>
      <artistId>238479</artistId>
      <artist>Kanaria</artist>
      <album>KING - Single</album>
      <jancode/>
      <isrc/>
      <writer/>
      <composer>Kanaria</composer>
      <duration>134750</duration>
      <lyricsType>0</lyricsType>
      <availableLyricsType>3</availableLyricsType>
      <prefferedLyricsType>0</prefferedLyricsType>
      <lyricsData/>
      <postUserId>anko3</postUserId>
      <postUserName>おもち</postUserName>
      <kashiMesse>0</kashiMesse>
      <viewCount>3</viewCount>
      <copyright>0</copyright>
      <isOfficial>0</isOfficial>
      <uploadDate>2020-09-03</uploadDate>
      <releaseDate/>
    </song>
  </songs>
</response>

To get the lyrics, execute the request with key_lyricsId and lyricsType = 3:

key_lyricsId=2893877&lyricsType=3&clientAppId=p1110417&terminalType=10

You will receive:

<response>
  <status>00000000</status>
  <songs>
    <name>プチリリ2 (android)(SDK)</name>
    <date>2024-07-15 15:20:18</date>
    <matchedCount>1</matchedCount>
    <returnedCount>1</returnedCount>
    <song>
      <order>1</order>
      <lyricsId>2893877</lyricsId>
      <title>KING</title>
      <artistId>238479</artistId>
      <artist>Kanaria</artist>
      <album>KING - Single</album>
      <jancode/>
      <isrc/>
      <writer/>
      <composer>Kanaria</composer>
      <duration>134750</duration>
      <lyricsType>3</lyricsType>
      <availableLyricsType>3</availableLyricsType>
      <prefferedLyricsType>3</prefferedLyricsType>
      <lyricsData>PHdzeT48bGluZW51bT40ODwvbGluZW51bT48bGluZT48bGluZXN0cmluZz7lub3plokg5Yip5Y+jIOmAneOBj
      ...

If availableLyricsType is 3, the lyrics are time-synced, and lyricsData is XML encoded in base64:

<wsy>
	<linenum>48</linenum>
	<line>
		<linestring>幽閉 利口 逝く前に</linestring>
		<wordnum>10</wordnum>
		<word>
			<starttime>14306</starttime>
			<chanum>1</chanum>
			<endtime>14357</endtime>
			<wordstring>幽</wordstring>
		</word>
	        ...

Each word is synchronized. However, you should use linestring and the first line's starttime to map it to LyricsDto.

If the lyrics are not time-synced, availableLyricsType is 1, and lyricsData is just a base64 string. Map it with .components("\n").

@yodaluca23
Copy link
Contributor Author

yodaluca23 commented Jul 16, 2024

Done, took me a bit.
I have a function that uses Foundations XMLParser (Instead of needing to make a new dependency for a specific XML library) to convert any XML to a structured dictionary.
If the responses lyricsType is 1 it treats it as non-time synced if it's 3, it treats it as time synced.
According to the website 2 is supposed to be just line syned (while three is word synced) but when decoding it base64, its just a bunch of random crap... it must be some other format, I have it just recall the API with lyricsType 1 and treat it as not time synced.
Also, you can add the lyricsType form key to the initial POST request to do the song search and get the lyrics in the same request. (which is what I did) I also limited maxCount to 1 so only the first (most likely matched) song is received.
Test:
API has Word synced (lyricsType: 3): https://open.spotify.com/track/3DamFFqW32WihKkTVlwTYQ
API has Line synced (lyricsType: 2, I don't know how to decode this so it fallsback to using lyricsType: 1): https://open.spotify.com/track/2ZrioVBvBpKZXOd8tWcmzR
API has plain text lyrics (lyricsType: 1): https://open.spotify.com/track/1uIN3VCVKzMXqF2A2Qlw5q
Is not on PetitLyrics (Testing Genius Fallback): https://open.spotify.com/track/6ASIi4DrqR0zH7e4cVm9Ya

@whoeevee whoeevee merged commit d6c5654 into whoeevee:swift Jul 16, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Feature Request] Can you add an option to set the default lyrics source for Japan?
2 participants