Skip to content

Commit

Permalink
feat: 解除海外限制
Browse files Browse the repository at this point in the history
  • Loading branch information
sigoden committed Nov 6, 2021
1 parent c9158b9 commit 3ad49e6
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 25 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- 每日推荐
- 精选歌单
- 私人歌单
- 海外正常使用

> VIP歌曲(仅限非会员)、无版权(变灰)歌曲来自咪咕、酷我的公开曲库。
Expand Down
4 changes: 3 additions & 1 deletion src/background/chrome.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,9 @@ function initRequestHook () {
}
}
}
logger.verbose('requestHook.163', details.requestHeaders)
if (store.chinaIp) details.requestHeaders.push({ name: 'X-Real-Ip', value: store.chinaIp })
details.requestHeaders.push({ name: 'Referer', value: DOMAIN })
logger.verbose('requestHook.163', details.requestHeaders)
} else if (details.url.startsWith(KUWO_DOMAIN)) {
let token = ''
for (let i = 0; i < details.requestHeaders.length; ++i) {
Expand All @@ -147,6 +148,7 @@ function initRequestHook () {
}
}
if (token) details.requestHeaders.push({ name: 'csrf', value: token })
if (store.chinaIp) details.requestHeaders.push({ name: 'X-Real-Ip', value: store.chinaIp })
details.requestHeaders.push({ name: 'Referer', value: KUWO_DOMAIN })
logger.verbose('requestHook.kuwo', details.requestHeaders)
} else if (details.url.startsWith(KUWO_MOBI_DOMAIN)) {
Expand Down
83 changes: 60 additions & 23 deletions src/background/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@ import {
chunkArr,
shuffleArr,
race,
randChinaIp,
} from '../utils'

// 缓存歌单
const playlistDetailStore = {}
// 缓存歌单内歌曲
const songsStore = {}
const songsMapStore = {}

// 播放器
let audio
Expand All @@ -34,19 +35,15 @@ let audioState = { ...EMPTY_AUDIO_STATE, volumeMute: null }
let isForcePlay = false
// 持久化缓存信息
let persistData = null
// 上次重启时间
let rebootAt = 0
// 上次刷新时间
let refreshAt = 0

const store = proxy({ ...COMMON_PROPS, dir: 1, songUrl: '' })
const store = proxy({ ...COMMON_PROPS, dir: 1, songUrl: '', chinaIp: null })

export async function bootstrap () {
await Promise.all([
persistLoad(),
refreshLogin(),
])
await refreshPlaylists()
rebootAt = Date.now()
logger.info('bootstrap', store)
await persistLoad()
await refreshStore()
await detectOversea()
}

export function updateAudioTime (currentTime) {
Expand Down Expand Up @@ -130,13 +127,13 @@ export async function changePlaylist (playlistId) {
export async function loadSongsMap () {
const { selectedPlaylist } = store
if (!selectedPlaylist?.id) return {}
let songsMap = songsStore[selectedPlaylist.id]
let songsMap = songsMapStore[selectedPlaylist.id]
if (songsMap) {
return songsMap
}
const tracks = await loadTracks(selectedPlaylist.normalIndexes)
songsMap = tracksToSongsMap(tracks)
songsStore[selectedPlaylist.id] = songsMap
songsMapStore[selectedPlaylist.id] = songsMap
return songsMap
}

Expand Down Expand Up @@ -216,7 +213,7 @@ export async function refreshPlaylists () {
const newPlaylists = store.playlists
for (const playlistId of oldPlaylistIds) {
if (newPlaylists.findIndex(v => v.id === playlistId) === -1) {
delete songsStore[playlistId]
delete songsMapStore[playlistId]
delete playlistDetailStore[playlistId]
}
}
Expand All @@ -228,10 +225,11 @@ export function popupInit () {
}

function persistSave () {
const { volume, playMode, selectedPlaylist, selectedSong } = store
const { volume, playMode, selectedPlaylist, selectedSong, chinaIp } = store
const data = {
volume,
playMode,
chinaIp,
playlistId: selectedPlaylist?.id || null,
songId: selectedSong?.id || null,
}
Expand All @@ -244,6 +242,7 @@ async function persistLoad () {
const {
volume = COMMON_PROPS.volume,
playMode = COMMON_PROPS.playMode,
chinaIp = null,
playlistId,
songId,
} = data
Expand All @@ -252,7 +251,7 @@ async function persistLoad () {
persistData = { playlistId }
if (songId) persistData.songId = songId
}
Object.assign(store, { volume, playMode })
Object.assign(store, { volume, playMode, chinaIp })
}
}

Expand All @@ -261,6 +260,13 @@ function getPopupData () {
return { userId, playing, volume, playMode, playlists, selectedPlaylist, selectedSong, audioState }
}

async function refreshStore () {
await refreshLogin()
await refreshPlaylists()
refreshAt = Date.now()
logger.debug('refreshStore')
}

async function refreshLogin () {
const res = await api.loginRefresh()
if (res.code !== 200) {
Expand Down Expand Up @@ -339,7 +345,7 @@ async function loadPlaylistDetails (playlist) {
})
const songsMap = tracksToSongsMap(tracks)
normalIndexes = tracks.map(v => v.id)
songsStore[playlist.id] = songsMap
songsMapStore[playlist.id] = songsMap
}
if (playlist.id === PLAYLIST_REC_SONGS.id) {
const res = await api.getRecommendSongs()
Expand All @@ -360,7 +366,7 @@ async function loadPlaylistDetails (playlist) {
} else {
const res = await api.getPlaylistDetail(playlist.id)
if (res.code === 200) {
delete songsStore[playlist.id]
delete songsMapStore[playlist.id]
normalIndexes = res.playlist.trackIds.map(v => v.id)
} else {
logger.error('getPlaylistDetail.error', playlist.id, res.message)
Expand Down Expand Up @@ -394,7 +400,7 @@ async function refreshPlaylistDetails (playlistId) {

async function loadSongDetails (playlistDetail, songId, retry) {
const { normalIndexes, invalidIndexes } = playlistDetail
let songsMap = songsStore[playlistDetail.id]
let songsMap = songsMapStore[playlistDetail.id]
if (!songsMap || !songsMap[songId]) {
const tracks = await loadTracks([songId])
songsMap = tracksToSongsMap(tracks)
Expand All @@ -404,7 +410,7 @@ async function loadSongDetails (playlistDetail, songId, retry) {
try {
if (!song || !song.valid) {
throw new Error('歌曲无法播放')
} else if (song.miss || (song.vip && !store.vip)) {
} else if (song.st < 0 || (song.vip && !store.vip)) {
try {
url = await race([
getKuWoSong(song.name, song.artists),
Expand All @@ -422,6 +428,9 @@ async function loadSongDetails (playlistDetail, songId, retry) {
if (!url) {
throw new Error('获取资源失败')
}
if (store.chinaIp) {
url = url.replace(/(m\d+?)(?!c)\.music\.126\.net/, '$1c.music.126.net')
}
}
} catch (err) {
logger.error('loadSongDetail.err', err)
Expand Down Expand Up @@ -494,8 +503,31 @@ function getNextSongId (playlistDetail, songId) {
return songsIndex[nextIndex]
}

async function detectOversea () {
const selectedPlaylistId = store.selectedPlaylist.id
if (PLAYLIST_TOP[0].id !== selectedPlaylistId) {
return
}
const songsMap = await loadSongsMap()
const ids = Object.keys(songsMap)
const ids2 = ids.filter(id => songsMap[id].st === -100)
if (ids2.length / ids.length < 0.25) {
if (!store.chinaIp) return
logger.info('Oversea removed')
store.chinaIp = null
} else {
logger.info('Oversea detected')
store.chinaIp = randChinaIp()
}
delete songsMapStore[selectedPlaylistId]
await persistSave()
await refreshStore()
}

function createAudio (url) {
const audio = new Audio(url)
globalThis.audio = audio

audio.volume = store.volume
audio.onprogress = () => {
if (audio.buffered.length) {
Expand Down Expand Up @@ -554,7 +586,7 @@ function tracksToSongsMap (tracks) {
id,
name,
valid: true,
miss: st < 0,
st,
vip: !(fee === 0 || fee === 8),
picUrl: picUrl + IMAGE_CLIP,
artists: ar.map(v => v.name).join(' & '),
Expand Down Expand Up @@ -596,11 +628,16 @@ subscribeKey(store, 'playing', playing => {

setInterval(async () => {
await refreshLogin()
if (Date.now() - rebootAt > 13 * 60 * 60 * 1000) {
await bootstrap()
if (Date.now() - refreshAt > 13 * 60 * 60 * 1000) {
await refreshStore()
}
}, 33 * 60 * 1000)

api.code301 = reset

globalThis.store = store
globalThis.songsMapStore = songsMapStore
globalThis.playlistDetailStore = playlistDetailStore
globalThis.refreshStore = refreshStore

export default store
2 changes: 1 addition & 1 deletion src/popup/PlayList.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ export default function PlayList ({ maxHeight }) {
<TableCell
component='th'
scope='row'
sx={{ maxWidth: 200, py: '4px', pl: '16px', ...(song.miss ? { filter: 'opacity(0.5)' } : {}) }}
sx={{ maxWidth: 200, py: '4px', pl: '16px', ...(song.st < 0 ? { filter: 'opacity(0.5)' } : {}) }}
>
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<IconButton disabled={!song.valid} onClick={() => storeUtils.playSong(song.id)}>
Expand Down
1 change: 1 addition & 0 deletions src/popup/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const store = proxy({
audioState: { ...EMPTY_AUDIO_STATE },
...COMMON_PROPS,
})
globalThis.store = store

export function updateAudioTime (currentTime) {
return doAction('updateAudioTime', [currentTime])
Expand Down
5 changes: 5 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,11 @@ export async function sleep (ms) {
})
}

export function randChinaIp () {
const rand = () => Math.floor(Math.random() * 256)
return `113.88.${rand()}.${rand()}`
}

export function race (values) {
return new Promise((resolve, reject) => {
let rejected = 0
Expand Down

0 comments on commit 3ad49e6

Please sign in to comment.