Skip to content

Commit

Permalink
Merge pull request #96 from Eithoo/fix-for-new-embed
Browse files Browse the repository at this point in the history
fix: changes in Spotify embeds
  • Loading branch information
Kikobeats committed Sep 2, 2022
2 parents b5973d1 + 57908c8 commit 1cbee73
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 57 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v3
with:
token: ${{ secrets.GH_TOKEN }}
token: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }}
- name: Setup Node.js
uses: actions/setup-node@v3
with:
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
],
"dependencies": {
"himalaya": "~1.1.0",
"spotify-uri": "~3.0.1"
"spotify-uri": "~3.0.3"
},
"devDependencies": {
"@commitlint/cli": "latest",
Expand Down
63 changes: 25 additions & 38 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,45 +22,35 @@ const createGetData = fetch => async (url, opts) => {
const embed = parse(text)

const scripts = embed
.filter(e => e.tagName === 'html')[0]
.children.filter(e => e.tagName === 'body')[0]
.children.filter(e => e.tagName === 'script')
.find(el => el.tagName === 'html')
.children.find(el => el.tagName === 'body')
.children.filter(({ tagName }) => tagName === 'script')

const resourceScript = scripts.filter(
e => e.attributes.findIndex(a => a.value === 'resource') !== -1
let script = scripts.find(script =>
script.attributes.some(({ value }) => value === 'resource')
)

if (resourceScript.length > 0) {
if (script !== undefined) {
// found data in the older embed style
return JSON.parse(decodeURIComponent(resourceScript[0].children[0].content))
return normalizeData({
data: JSON.parse(decodeURIComponent(script.children[0].content))
})
}

const hydrateScript = scripts.filter(
e => e.children[0] && /%22data%22%|"data":/.test(e.children[0].content)
script = scripts.find(script =>
script.attributes.some(({ value }) => value === 'initial-state')
)

if (hydrateScript.length > 0) {
// found hydration data
// parsing via looking for { to be a little bit resistant to code changes
const scriptContent = hydrateScript[0].children[0].content.includes(
'%22data%22%'
)
? decodeURIComponent(hydrateScript[0].children[0].content)
: hydrateScript[0].children[0].content
return normalizeData(
JSON.parse(
'{' +
scriptContent
.split('{')
.slice(1)
.join('{')
.trim()
)
)
if (script !== undefined) {
// found data in the new embed style
const data = JSON.parse(
Buffer.from(decodeURIComponent(script.children[0].content), 'base64')
).data.entity
return normalizeData({ data })
}

throw new Error(
"Couldn't find any data in embed page that we know how to parse"
"Couldn't find any data in embed page that we know how to parse.\nPlease report the problem at https://github.com/microlinkhq/spotify-url-info/issues."
)
}

Expand All @@ -77,7 +67,6 @@ function getParsedUrl (url) {
function getImages (data) {
switch (data.type) {
case TYPE.TRACK:
return data.album.images
case TYPE.EPISODE:
return data.coverArt.sources
default:
Expand All @@ -88,7 +77,6 @@ function getImages (data) {
function getDate (data) {
switch (data.type) {
case TYPE.TRACK:
return data.album.release_date
case TYPE.EPISODE:
return data.releaseDate.isoString
default:
Expand Down Expand Up @@ -127,7 +115,8 @@ function getPreview (data) {
description: data.description || track.description,
artist: getArtistTrack(track) || track.artist,
image: getImages(data).reduce((a, b) => (a.width > b.width ? a : b)).url,
audio: track.audio_preview_url || track.preview_url,
audio:
track.audio_preview_url || track.audioPreview?.url || track.preview_url,
link: getLink(data),
embed: `https://embed.spotify.com/?uri=${data.uri}`
}
Expand Down Expand Up @@ -170,13 +159,6 @@ function getFirstTrack (data) {
}

function normalizeData ({ data }) {
data = data.entity ? data.entity : data

if (data.episode) {
data = data.episode
data.type = TYPE.EPISODE
}

if (!data || !data.type || !data.name) {
throw new Error("Data doesn't seem to be of the right shape to parse")
}
Expand All @@ -187,12 +169,17 @@ function normalizeData ({ data }) {
)
}

if (data.type === TYPE.TRACK) {
data.external_urls = { spotify: spotifyURI.formatOpenURL(data.uri) }
}

return data
}

function spotifyUrlInfo (fetch) {
const getData = createGetData(fetch)
return {
getLink,
getData,
getPreview: (url, opts) => getData(url, opts).then(getPreview),
getTracks: (url, opts) => getData(url, opts).then(getTracks),
Expand Down
28 changes: 14 additions & 14 deletions test/get-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
const fetch = require('isomorphic-unfetch')
const test = require('ava')

const { getData } = require('..')(fetch)
const { getLink, getData } = require('..')(fetch)

test('getting data for empty url should return rejection', async t => {
const error = await t.throwsAsync(() => getData(''), {
Expand Down Expand Up @@ -39,33 +39,30 @@ test('getting data for non spotify url string should return rejection', async t
})

test('get data for spotify track', async t => {
const data = await getData(
'https://open.spotify.com/track/5nTtCOCds6I0PHMNtqelas'
)
const url = 'https://open.spotify.com/track/5nTtCOCds6I0PHMNtqelas'
const data = await getData(url)

t.is(data.type, 'track')
t.is(data.name, 'Immaterial')
t.true(data.external_urls.spotify?.includes('open.spotify.com/track'))
t.is(getLink(data), url)
})

test('get data for spotify artist', async t => {
const data = await getData(
'https://open.spotify.com/artist/5a2w2tgpLwv26BYJf2qYwu'
)
const url = 'https://open.spotify.com/artist/5a2w2tgpLwv26BYJf2qYwu'
const data = await getData(url)

t.is(data.type, 'artist')
t.is(data.name, 'SOPHIE')
t.true(data.external_urls.spotify?.includes('open.spotify.com/artist'))
t.is(getLink(data), url)
})

test('get data for spotify album', async t => {
const data = await getData(
'https://open.spotify.com/album/4tDBsfbHRJ9OdcMO9bmnai'
)
const url = 'https://open.spotify.com/album/4tDBsfbHRJ9OdcMO9bmnai'
const data = await getData(url)

t.is(data.type, 'album')
t.is(data.name, 'PRODUCT')
t.true(data.external_urls.spotify?.includes('open.spotify.com/album'))
t.is(getLink(data), url)
})

test('get data for spotify playlist', async t => {
Expand All @@ -75,7 +72,10 @@ test('get data for spotify playlist', async t => {

t.is(data.type, 'playlist')
t.is(data.name, 'SOPHIE – PRODUCT')
t.true(data.external_urls.spotify?.includes('/playlist/'))
t.is(
getLink(data),
'https://open.spotify.com/playlist/3Q4cPwMHY95ZHXtmcU2xvH'
)
})

test('get data for spotify episode', async t => {
Expand Down
5 changes: 2 additions & 3 deletions test/get-tracks.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,8 @@ test('getting data for non spotify url string should return rejection', async t
})

test('get tracks for spotify track', async t => {
const tracks = await getTracks(
'https://open.spotify.com/track/5nTtCOCds6I0PHMNtqelas'
)
const url = 'https://open.spotify.com/track/5nTtCOCds6I0PHMNtqelas'
const tracks = await getTracks(url)
t.true(Array.isArray(tracks))
t.is(tracks[0].name, 'Immaterial')
t.true(tracks[0].external_urls.spotify?.includes('/track/'))
Expand Down

0 comments on commit 1cbee73

Please sign in to comment.