jacquesh / foo_openlyrics

An open-source lyric display panel for foobar2000
MIT License
432 stars 24 forks source link

Circumvent netease source geolocation restriction #291

Closed HarukaMa closed 11 months ago

HarukaMa commented 1 year ago

The NetEase API cannot be used outside of China - normal search API searches for strange things and the web API variant is encrypted. Adding a header could trick NetEase's server to think we are in China.

In theory we can use the web API instead and decrypt the response if we are abroad, but we certainly don't want to check in the decryption key here, and normal users obviously don't know how to acquire that.

jacquesh commented 1 year ago

The NetEase API cannot be used outside of China

Do you have any evidence of that? Can you post the exact debug console output you're receiving when you try? It works fine for me (from outside China). Where are you making requests from?

Adding a header could trick NetEase's server to think we are in China.

"Could" does not instill confidence that this will work. I assume you have tested it?

In theory we can use the web API instead and decrypt the response if we are abroad, but we certainly don't want to check in the decryption key here, and normal users obviously don't know how to acquire that.

I don't understand what you mean here. What web API? What decryption? Please elaborate.

HarukaMa commented 1 year ago

Do you have any evidence of that? Can you post the exact debug console output you're receiving when you try? It works fine for me (from outside China). Where are you making requests from?

Making requests from Japan. An example request: http://music.163.com/api/search/get?s=A+World+Beyond+The+Sky&type=1&offset=0&total=true&limit=1

Result when I request without the X-Real-IP header:

{
    "code": 200,
    "result": {
        "hasMore": true,
        "songCount": 303,
        "songs": [
            {
                "album": {
                    "artist": {
                        "albumSize": 0,
                        "alias": [],
                        "fansGroup": null,
                        "id": 0,
                        "img1v1": 0,
                        "img1v1Url": "http://p2.music.126.net/6y-UleORITEDbvrOLV0Q8A==/5639395138885805.jpg",
                        "name": "",
                        "picId": 0,
                        "picUrl": null,
                        "trans": null
                    },
                    "copyrightId": 0,
                    "id": 44464,
                    "mark": 0,
                    "name": "RANDOM",
                    "picId": 6040716883333198,
                    "publishTime": 1104508800000,
                    "size": 99,
                    "status": 1
                },
                "alias": [],
                "artists": [
                    {
                        "albumSize": 0,
                        "alias": [],
                        "fansGroup": null,
                        "id": 14598,
                        "img1v1": 0,
                        "img1v1Url": "http://p2.music.126.net/6y-UleORITEDbvrOLV0Q8A==/5639395138885805.jpg",
                        "name": "岡本光市",
                        "picId": 0,
                        "picUrl": null,
                        "trans": null
                    }
                ],
                "copyrightId": 663018,
                "duration": 5000,
                "fee": 0,
                "ftype": 0,
                "id": 459457,
                "mark": 9007199254872064,
                "mvid": 0,
                "name": "98",
                "rUrl": null,
                "rtype": 0,
                "status": -1
            }
        ]
    }
}

Note the returned result makes no sense; it seems the backend is searching for some random numbers (use a larger limit and observe the song's name) and the result has no relation to the query string ("A World Beyond The Sky").

When I add the header, the response is:

{
    "code": 200,
    "result": {
        "hasMore": true,
        "songCount": 318,
        "songs": [
            {
                "album": {
                    "artist": {
                        "albumSize": 0,
                        "alias": [],
                        "fansGroup": null,
                        "id": 0,
                        "img1v1": 0,
                        "img1v1Url": "http://p2.music.126.net/6y-UleORITEDbvrOLV0Q8A==/5639395138885805.jpg",
                        "name": "",
                        "picId": 0,
                        "picUrl": null,
                        "trans": null
                    },
                    "copyrightId": 1418220,
                    "id": 149061128,
                    "mark": 0,
                    "name": "PSO2 NEW GENESIS Original Sound Track Vol.1 1",
                    "picId": 109951167739333020,
                    "publishTime": 1658246400000,
                    "size": 22,
                    "status": 1
                },
                "alias": [],
                "artists": [
                    {
                        "albumSize": 0,
                        "alias": [],
                        "fansGroup": null,
                        "id": 0,
                        "img1v1": 0,
                        "img1v1Url": "http://p2.music.126.net/6y-UleORITEDbvrOLV0Q8A==/5639395138885805.jpg",
                        "name": "SEGA",
                        "picId": 0,
                        "picUrl": null,
                        "trans": null
                    },
                    {
                        "albumSize": 0,
                        "alias": [],
                        "fansGroup": null,
                        "id": 35944588,
                        "img1v1": 0,
                        "img1v1Url": "http://p2.music.126.net/6y-UleORITEDbvrOLV0Q8A==/5639395138885805.jpg",
                        "name": "Kristen Watts",
                        "picId": 0,
                        "picUrl": null,
                        "trans": null
                    }
                ],
                "copyrightId": 1418220,
                "duration": 252466,
                "fee": 8,
                "ftype": 0,
                "id": 1968994910,
                "mark": 270336,
                "mvid": 0,
                "name": "A World Beyond The Sky",
                "rUrl": null,
                "rtype": 0,
                "status": -1
            }
        ]
    }
}

Which is exactly what I was looking for.

"Could" does not instill confidence that this will work. I assume you have tested it?

The above results should indicate that this works.

I don't understand what you mean here. What web API? What decryption? Please elaborate.

There is an endpoint http://music.163.com/api/search/get/web which returns encrypted results when the requesting IP is deemed "abroad", while returns plain JSON when I add the header. You can try accessing http://music.163.com/api/search/get/web?s=A+World+Beyond+The+Sky&type=1&offset=0&total=true&limit=1 to see the response.

Actually, I haven't really tested this in too many regions - I've only tested with my native Japan IP and a US IP, and the netease API behaves differently with the HTTP header.

jacquesh commented 12 months ago

I know this has been open for ages, I haven't forgotten about it and I expect I will merge it. I just want to finish the other outstanding changes for the next release and then test this out myself.

jacquesh commented 11 months ago

I tested it and I do actually see the behaviour you describe, it just only seems to happen with some tracks and not others (your example was super helpful in that regard, thanks!)

I'm going to close this instead of merging because I made an equivalent change (referencing this PR in the commit message). This is for 2 reasons: 1) I wanted a slightly different IP, it took me a second to verify that the given IP is in China's IP range so I preferred to use on where that's more obvious (namely by using the start of one of their ranges) and 2) You didn't add a changelog entry in main.cpp

Of course we could have gone back and forth on it with me requesting changes and you making them etc before merging the PR but for a one-line change it seemed simpler to just make the changes myself. As I say, your contribution is at the very least called out in the commit message and you get your fix regardless. Thanks!