@unavatar/core 3.22.0 → 3.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@unavatar/core",
|
|
3
3
|
"description": "Get unified user avatar from social networks, including Instagram, SoundCloud, Telegram, Twitter, YouTube & more.",
|
|
4
4
|
"homepage": "https://unavatar.io",
|
|
5
|
-
"version": "3.
|
|
5
|
+
"version": "3.24.0",
|
|
6
6
|
"main": "src/index.js",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": "./src/index.js",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { $jsonld } = require('@metascraper/helpers')
|
|
4
|
-
const
|
|
4
|
+
const { createGetSearchResults } = require('../util/itunes-search')
|
|
5
5
|
|
|
6
6
|
const APPLE_MUSIC_ID_REGEX = /^\d+$/
|
|
7
7
|
const APPLE_MUSIC_STOREFRONT = 'us'
|
|
@@ -36,26 +36,19 @@ const parseInput = input => {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
module.exports = ({ createHtmlProvider, itunesSearchCache, got }) => {
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
)}&entity=${entity}&limit=1`
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const entityId = body?.results?.[0]?.[idKey]
|
|
54
|
-
return isNumericId(entityId) ? String(entityId) : null
|
|
55
|
-
},
|
|
56
|
-
itunesSearchCache,
|
|
57
|
-
{ key: ({ query, type }) => `${type}:${query.trim().toLowerCase()}` }
|
|
58
|
-
)
|
|
39
|
+
const getSearchResults = createGetSearchResults({ got, itunesSearchCache })
|
|
40
|
+
|
|
41
|
+
const searchEntityId = async ({ query, type }) => {
|
|
42
|
+
const entityConfig = APPLE_MUSIC_ENTITY_TYPES[type]
|
|
43
|
+
if (!entityConfig) return
|
|
44
|
+
const { entity, idKey } = entityConfig
|
|
45
|
+
|
|
46
|
+
const [result] = await getSearchResults(
|
|
47
|
+
`term=${encodeURIComponent(query)}&entity=${entity}&limit=1`
|
|
48
|
+
)
|
|
49
|
+
const entityId = result?.[idKey]
|
|
50
|
+
return isNumericId(entityId) ? String(entityId) : null
|
|
51
|
+
}
|
|
59
52
|
|
|
60
53
|
const appleMusicURI = async input => {
|
|
61
54
|
const { hasExplicitType, type, id } = parseInput(input)
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { createGetSearchResults } = require('../util/itunes-search')
|
|
4
|
+
|
|
5
|
+
const ITUNES_LOOKUP_URL = 'https://itunes.apple.com/lookup'
|
|
6
|
+
const COUNTRY_CODE_REGEX = /^[a-z]{2}$/i
|
|
7
|
+
|
|
8
|
+
const getArtworkUrl = result =>
|
|
9
|
+
result?.artworkUrl512 || result?.artworkUrl100 || result?.artworkUrl60
|
|
10
|
+
|
|
11
|
+
const withCountry = ({ query, country }) =>
|
|
12
|
+
country ? `${query}&country=${encodeURIComponent(country)}` : query
|
|
13
|
+
|
|
14
|
+
const parseInput = input => {
|
|
15
|
+
const separatorIndex = input.indexOf(':')
|
|
16
|
+
if (separatorIndex === -1) return { type: 'app', value: input }
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
type: input.slice(0, separatorIndex),
|
|
20
|
+
value: input.slice(separatorIndex + 1)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const parseCountry = value => {
|
|
25
|
+
const separatorIndex = value.lastIndexOf('@')
|
|
26
|
+
if (separatorIndex === -1) return { value, country: undefined }
|
|
27
|
+
|
|
28
|
+
const country = value.slice(separatorIndex + 1)
|
|
29
|
+
if (!COUNTRY_CODE_REGEX.test(country)) return { value, country: undefined }
|
|
30
|
+
|
|
31
|
+
const nextValue = value.slice(0, separatorIndex)
|
|
32
|
+
if (!nextValue) return { value, country: undefined }
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
value: nextValue,
|
|
36
|
+
country: country.toLowerCase()
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const getLookupResults = async ({ got, query }) => {
|
|
41
|
+
const body = await got(`${ITUNES_LOOKUP_URL}?${query}`, {
|
|
42
|
+
responseType: 'json',
|
|
43
|
+
resolveBodyOnly: true
|
|
44
|
+
})
|
|
45
|
+
return body?.results ?? []
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const getAppAvatar = async ({ got, id, country }) => {
|
|
49
|
+
const query = withCountry({
|
|
50
|
+
query: `id=${encodeURIComponent(id)}&entity=software&limit=1`,
|
|
51
|
+
country
|
|
52
|
+
})
|
|
53
|
+
const [result] = await getLookupResults({ got, query })
|
|
54
|
+
return getArtworkUrl(result)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const getDeveloperAvatar = async ({ got, id, country }) => {
|
|
58
|
+
const query = withCountry({
|
|
59
|
+
query: `id=${encodeURIComponent(id)}&entity=software&limit=200`,
|
|
60
|
+
country
|
|
61
|
+
})
|
|
62
|
+
const results = await getLookupResults({ got, query })
|
|
63
|
+
const softwareResult = results.find(result => result?.kind === 'software')
|
|
64
|
+
return getArtworkUrl(softwareResult)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const getBundleAvatar = async ({ got, bundleId, country }) => {
|
|
68
|
+
const query = withCountry({
|
|
69
|
+
query: `bundleId=${encodeURIComponent(bundleId)}&entity=software&limit=1`,
|
|
70
|
+
country
|
|
71
|
+
})
|
|
72
|
+
const [result] = await getLookupResults({ got, query })
|
|
73
|
+
return getArtworkUrl(result)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const getAppNameAvatar = async ({ got, name, country, searchResults }) => {
|
|
77
|
+
const getSearchResults = searchResults || createGetSearchResults({ got })
|
|
78
|
+
const query = withCountry({
|
|
79
|
+
query: `term=${encodeURIComponent(name)}&entity=software&limit=1`,
|
|
80
|
+
country
|
|
81
|
+
})
|
|
82
|
+
const [result] = await getSearchResults(query)
|
|
83
|
+
return getArtworkUrl(result)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const getDeveloperNameAvatar = async ({ got, name, country, searchResults }) => {
|
|
87
|
+
const getSearchResults = searchResults || createGetSearchResults({ got })
|
|
88
|
+
const query = withCountry({
|
|
89
|
+
query: `term=${encodeURIComponent(
|
|
90
|
+
name
|
|
91
|
+
)}&entity=software&attribute=softwareDeveloper&limit=1`,
|
|
92
|
+
country
|
|
93
|
+
})
|
|
94
|
+
const [result] = await getSearchResults(query)
|
|
95
|
+
return getArtworkUrl(result)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
module.exports = ({ got, itunesSearchCache }) => {
|
|
99
|
+
const searchResults = createGetSearchResults({ got, itunesSearchCache })
|
|
100
|
+
|
|
101
|
+
return async function appleStore (input) {
|
|
102
|
+
const { type, value: rawValue } = parseInput(input)
|
|
103
|
+
const { value, country } = parseCountry(rawValue)
|
|
104
|
+
|
|
105
|
+
switch (type) {
|
|
106
|
+
case 'app':
|
|
107
|
+
return getAppAvatar({ got, id: value, country })
|
|
108
|
+
case 'dev':
|
|
109
|
+
return getDeveloperAvatar({ got, id: value, country })
|
|
110
|
+
case 'bundle':
|
|
111
|
+
return getBundleAvatar({ got, bundleId: value, country })
|
|
112
|
+
case 'app-name':
|
|
113
|
+
return getAppNameAvatar({ got, name: value, country, searchResults })
|
|
114
|
+
case 'dev-name':
|
|
115
|
+
return getDeveloperNameAvatar({ got, name: value, country, searchResults })
|
|
116
|
+
default:
|
|
117
|
+
throw new Error(`Unsupported Apple Store type: ${type}`)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
module.exports.getAppAvatar = getAppAvatar
|
|
123
|
+
module.exports.getDeveloperAvatar = getDeveloperAvatar
|
|
124
|
+
module.exports.getBundleAvatar = getBundleAvatar
|
|
125
|
+
module.exports.getAppNameAvatar = getAppNameAvatar
|
|
126
|
+
module.exports.getDeveloperNameAvatar = getDeveloperNameAvatar
|
package/src/providers/flickr.js
CHANGED
|
@@ -4,24 +4,33 @@ const BUDDY_ICON_URL_PATTERN = /(?:https?:)?\/\/[^"'()\s]*\/buddyicons\/[^"'()\s
|
|
|
4
4
|
const CSS_URL_PATTERN = /url\((['"]?)([^)'"]+)\1\)/i
|
|
5
5
|
const unescapePathSlashes = value => value?.replace(/\\\//g, '/')
|
|
6
6
|
|
|
7
|
+
const parseInput = input => {
|
|
8
|
+
const [first, second] = input.split(':')
|
|
9
|
+
return {
|
|
10
|
+
type: second ? first : 'user',
|
|
11
|
+
id: second ?? first
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
7
15
|
const getBuddyIconFromText = value => {
|
|
8
16
|
const normalizedValue = unescapePathSlashes(value)
|
|
9
17
|
if (typeof normalizedValue !== 'string') return
|
|
10
18
|
return normalizedValue.match(BUDDY_ICON_URL_PATTERN)?.[0]
|
|
11
19
|
}
|
|
12
20
|
|
|
21
|
+
const getUserProfileUrl = userId => `https://www.flickr.com/photos/${userId}/`
|
|
22
|
+
const getGroupProfileUrl = groupId => `https://www.flickr.com/groups/${groupId}/`
|
|
23
|
+
|
|
13
24
|
const getAvatarUrl = input => {
|
|
14
|
-
const
|
|
15
|
-
const type = second ? first : 'user'
|
|
16
|
-
const id = second ?? first
|
|
25
|
+
const { type, id } = parseInput(input)
|
|
17
26
|
|
|
18
27
|
switch (type) {
|
|
19
28
|
case 'user':
|
|
20
29
|
case 'photos':
|
|
21
|
-
return
|
|
30
|
+
return getUserProfileUrl(id)
|
|
22
31
|
case 'group':
|
|
23
32
|
case 'groups':
|
|
24
|
-
return
|
|
33
|
+
return getGroupProfileUrl(id)
|
|
25
34
|
default:
|
|
26
35
|
throw new Error(`Unsupported Flickr type: ${type}`)
|
|
27
36
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const getAvatarUrl = input => {
|
|
4
|
+
const [first, second] = input.split(':')
|
|
5
|
+
const type = second ? first : 'app'
|
|
6
|
+
const id = encodeURIComponent(second ?? first)
|
|
7
|
+
|
|
8
|
+
switch (type) {
|
|
9
|
+
case 'app':
|
|
10
|
+
return `https://play.google.com/store/apps/details?id=${id}`
|
|
11
|
+
case 'dev':
|
|
12
|
+
return `https://play.google.com/store/apps/dev?id=${id}`
|
|
13
|
+
default:
|
|
14
|
+
throw new Error(`Unsupported Google Play type: ${type}`)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
module.exports = ({ createHtmlProvider, getOgImage }) =>
|
|
19
|
+
createHtmlProvider({
|
|
20
|
+
name: 'google-play',
|
|
21
|
+
url: getAvatarUrl,
|
|
22
|
+
getter: getOgImage
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
module.exports.getAvatarUrl = getAvatarUrl
|
package/src/providers/index.js
CHANGED
|
@@ -4,6 +4,7 @@ const providersBy = {
|
|
|
4
4
|
email: ['gravatar', 'github'],
|
|
5
5
|
username: [
|
|
6
6
|
'apple-music',
|
|
7
|
+
'apple-store',
|
|
7
8
|
'behance',
|
|
8
9
|
'bluesky',
|
|
9
10
|
'buymeacoffee',
|
|
@@ -14,6 +15,7 @@ const providersBy = {
|
|
|
14
15
|
'flickr',
|
|
15
16
|
'github',
|
|
16
17
|
'gitlab',
|
|
18
|
+
'google-play',
|
|
17
19
|
'instagram',
|
|
18
20
|
'ko-fi',
|
|
19
21
|
'linkedin',
|
|
@@ -48,6 +50,7 @@ const providersBy = {
|
|
|
48
50
|
module.exports = ctx => {
|
|
49
51
|
const providers = {
|
|
50
52
|
'apple-music': require('./apple-music')(ctx),
|
|
53
|
+
'apple-store': require('./apple-store')(ctx),
|
|
51
54
|
behance: require('./behance')(ctx),
|
|
52
55
|
bluesky: require('./bluesky')(ctx),
|
|
53
56
|
buymeacoffee: require('./buymeacoffee')(ctx),
|
|
@@ -60,6 +63,7 @@ module.exports = ctx => {
|
|
|
60
63
|
github: require('./github')(ctx),
|
|
61
64
|
gitlab: require('./gitlab')(ctx),
|
|
62
65
|
google: require('./google')(ctx),
|
|
66
|
+
'google-play': require('./google-play')(ctx),
|
|
63
67
|
gravatar: require('./gravatar')(ctx),
|
|
64
68
|
instagram: require('./instagram')(ctx),
|
|
65
69
|
'ko-fi': require('./ko-fi')(ctx),
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const memoize = require('@keyvhq/memoize')
|
|
4
|
+
|
|
5
|
+
const ITUNES_SEARCH_URL = 'https://itunes.apple.com/search'
|
|
6
|
+
|
|
7
|
+
const getSearchResults = async ({ got, query }) => {
|
|
8
|
+
const body = await got(`${ITUNES_SEARCH_URL}?${query}`, {
|
|
9
|
+
responseType: 'json',
|
|
10
|
+
resolveBodyOnly: true
|
|
11
|
+
})
|
|
12
|
+
return body?.results ?? []
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const createGetSearchResults = ({ got, itunesSearchCache }) => {
|
|
16
|
+
const searchResults = query => getSearchResults({ got, query })
|
|
17
|
+
if (!itunesSearchCache) return searchResults
|
|
18
|
+
|
|
19
|
+
return memoize(searchResults, itunesSearchCache, {
|
|
20
|
+
key: query => query.trim().toLowerCase()
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
module.exports = { createGetSearchResults }
|