4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Expand Up @@ -14,7 +14,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v4
with:
go-version: 1.19
go-version-file: "go.mod"

- name: Build
run: go build .
Expand Down Expand Up @@ -50,7 +50,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v4
with:
go-version: 1.19
go-version-file: "go.mod"

- name: Build
if: env.IS_UNIX == 'true' || env.IS_WIN == 'true'
Expand Down
81 changes: 16 additions & 65 deletions CustomApps/lyrics-plus/ProviderNetease.js
@@ -1,77 +1,28 @@
/**
* @typedef {{
* result: {
* songs: {
* name: string,
* id: number,
* dt: number, // duration in ms
* al: { // album
* name: string,
* },
* }[],
* },
* }} SearchResponse
*
* @typedef {{
* title: string,
* artist: string,
* album: string,
* duration: number,
* }} Info
*/

const ProviderNetease = (function () {
/**
* Search with PyNCM api.
*
* @param {Info} info
* @throw "Cannot find track"
*/
async function search(info) {
const searchURL = "https://pyncmd.apis.imouto.in/api/pyncm?module=cloudsearch&method=GetSearchResult&keyword=";
const requestHeader = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0"
};

async function findLyrics(info) {
const searchURL = "https://music.xianqiao.wang/neteaseapiv2/search?limit=10&type=1&keywords=";
const lyricURL = "https://music.xianqiao.wang/neteaseapiv2/lyric?id=";

const cleanTitle = Utils.removeExtraInfo(Utils.removeSongFeat(Utils.normalize(info.title)));
const finalURL = searchURL + encodeURIComponent(`${cleanTitle} ${info.artist}`);

/** @type {SearchResponse} */
const searchResults = await Spicetify.CosmosAsync.get(finalURL);
const searchResults = await CosmosAsync.get(finalURL, null, requestHeader);
const items = searchResults.result.songs;

// Find the best match.
for (const song of items) {
const expectedDuration = info.duration;
const actualDuration = song.dt;

// normalized expected album name
const neAlbumName = Utils.normalize(info.album);
const expectedAlbumName = Utils.containsHanCharacter(neAlbumName) ? await Utils.toSimplifiedChinese(neAlbumName) : neAlbumName;
const actualAlbumName = Utils.normalize(song.al.name); // usually in Simplified Chinese

if (actualAlbumName == expectedAlbumName || Math.abs(expectedDuration - actualDuration) < 1000) {
return song;
}
if (!items?.length) {
throw "Cannot find track";
}

throw "Cannot find track";
}

/**
* @param {Info} info
*
* @returns {{
* lrc: {
* lyric: string,
* klyric: undefined, // unimplemented
* },
* }}
*/
async function findLyrics(info) {
const lyricURL = "https://pyncmd.apis.imouto.in/api/pyncm?module=track&method=GetTrackLyrics&song_id=";

const searchResponse = await search(info);
const songID = searchResponse.id;
// normalized expected album name
const neAlbumName = Utils.normalize(info.album);
const expectedAlbumName = Utils.containsHanCharacter(neAlbumName) ? await Utils.toSimplifiedChinese(neAlbumName) : neAlbumName;
let itemId = items.findIndex(val => Utils.normalize(val.album.name) === expectedAlbumName || Math.abs(info.duration - val.duration) < 1000);
if (itemId === -1) throw "Cannot find track";

return CosmosAsync.get(lyricURL + songID);
return await CosmosAsync.get(lyricURL + items[itemId].id, null, requestHeader);
}

const creditInfo = [
Expand Down
49 changes: 9 additions & 40 deletions Extensions/popupLyrics.js
Expand Up @@ -78,36 +78,6 @@ function PopupLyrics() {
}

class LyricProviders {
/** Netease PyNCM API
*
* @typedef {{
* result: {
* songs: {
* name: string,
* id: number,
* dt: number, // duration in ms
* al: { // album
* name: string,
* },
* }[],
* },
* }} SearchResponse
*
* @typedef {{
* title: string,
* artist: string,
* album: string,
* duration: number,
* }} Info
*
* @typedef {{
* lrc: {
* lyric: string,
* klyric: undefined, // unimplemented
* },
* }} NeteaseLyric
*/

static async fetchSpotify(info) {
const baseURL = "wg://lyrics/v1/track/";
const id = info.uri.split(":")[2];
Expand Down Expand Up @@ -189,27 +159,26 @@ function PopupLyrics() {
}

static async fetchNetease(info) {
const searchURL = "https://pyncmd.apis.imouto.in/api/pyncm?module=cloudsearch&method=GetSearchResult&keyword=";
const lyricURL = "https://pyncmd.apis.imouto.in/api/pyncm?module=track&method=GetTrackLyrics&song_id=";
const searchURL = "https://music.xianqiao.wang/neteaseapiv2/search?limit=10&type=1&keywords=";
const lyricURL = "https://music.xianqiao.wang/neteaseapiv2/lyric?id=";
const requestHeader = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0"
};

const cleanTitle = LyricUtils.removeExtraInfo(LyricUtils.normalize(info.title));
const finalURL = searchURL + encodeURIComponent(`${cleanTitle} ${info.artist}`);

/** @type {SearchResponse} */
const searchResults = await CosmosAsync.get(finalURL);
const searchResults = await CosmosAsync.get(finalURL, null, requestHeader);
const items = searchResults.result.songs;

if (!items) {
if (!items || !items.length) {
return { error: "Cannot find track" };
}

const album = LyricUtils.capitalize(info.album);

let itemId = items.findIndex(val => LyricUtils.capitalize(val.al.name) === album || Math.abs(info.duration - val.dt) < 1000);
let itemId = items.findIndex(val => LyricUtils.capitalize(val.album.name) === album || Math.abs(info.duration - val.duration) < 1000);
if (itemId === -1) return { error: "Cannot find track" };

/** @type {NeteaseLyric} */
const meta = await CosmosAsync.get(lyricURL + items[itemId].id);
const meta = await CosmosAsync.get(lyricURL + items[itemId].id, null, requestHeader);
let lyricStr = meta.lrc;

if (!lyricStr || !lyricStr.lyric) {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
@@ -1,6 +1,6 @@
module github.com/spicetify/spicetify-cli

go 1.19
go 1.21

require (
github.com/go-ini/ini v1.67.0
Expand Down
14 changes: 7 additions & 7 deletions jsHelper/spicetifyWrapper.js
Expand Up @@ -705,7 +705,8 @@ Spicetify._getStyledClassName = (args, component) => {
"iconSize",
"position",
"data-encore-id",
"$size" // >= 1.2.23
"$size",
"$iconColor"
];
const customKeys = ["padding", "blocksize"];

Expand Down Expand Up @@ -2286,9 +2287,9 @@ Spicetify.Playbar = (function () {
setTimeout(checkForUpdate, 300);
return;
}
const { check_spicetify_upgrade, version } = Spicetify.Config;
const { check_spicetify_update, version } = Spicetify.Config;
// Skip checking if upgrade check is disabled, or version is Dev/version is not set
if (!check_spicetify_upgrade || !version || version === "Dev") {
if (!check_spicetify_update || !version || version === "Dev") {
return;
}
// Fetch latest version from GitHub
Expand Down Expand Up @@ -2367,10 +2368,9 @@ Spicetify.Playbar = (function () {
<p>Run these commands in the terminal:</p>
<ol>
<li>Update Spicetify CLI</li>
<pre class="spicetify-update-little-space">spicetify upgrade</pre>
<p class="spicetify-update-space">If you installed Spicetify via a package manager, update using said package manager.</p>
<li>Apply changes to Spotify</li>
<pre>spicetify restore backup apply</pre>
<pre class="spicetify-update-little-space">spicetify update</pre>
<p>Spicetify will automatically apply changes to Spotify after upgrading to the latest version.</p>
<p>If you installed Spicetify via a package manager, update using said package manager.</p>
</ol>
`;

Expand Down