last.fm-to-mastodon.js
· 4.1 KiB · JavaScript
Исходник
// Variables used by Scriptable.
// These must be at the very top of the file. Do not edit.
// icon-color: pink; icon-glyph: headphones-alt;
// Last.fm to Mastodon
// by @zicklepop@nyan.lol
//
// Set a profile field to your currently playing track
//
// Requirements:
// - API Key from Last.fm: https://www.last.fm/api
// - Token from Mastodon with permission scopes for:
// `read:account` and `write:account`
// - Find it on your Mastodon instance website under
// Settings -> Development -> New Application
// Script Constants
// - Ignore, just defining before use
// Continue down to config
const LASTFM_URL_IN_VALUE = 'LASTFM_URL_IN_VALUE'
const LASTFM_IN_NAME = 'LASTFM_IN_NAME'
// Config
// - Put in your details below
// - Find Field By:
// - When set to LASTFM_URL_IN_VALUE the script will
// look for a last.fm url in a field value and set
// the title of the field to the current track
// - When set to LASTFM_IN_NAME the script will look
// for a field title that is `last.fm` (case-insenstive)
// and set the value to the current track
const LASTFM_USERNAME = ''
const LASTFM_API_KEY = ''
const MASTODON_INSTANCE = '' // ie: social.lol
const MASTODON_TOKEN = ''
const FIND_FIELD_BY = LASTFM_URL_IN_VALUE // or LASTFM_IN_NAME
// More Script Constants
// - You can ignore this too
const LASTFM_API = `http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=${LASTFM_USERNAME}&api_key=${LASTFM_API_KEY}&format=json&limit=1`
const MASTODON_GET_ACCOUNT_API = `https://${MASTODON_INSTANCE}/api/v1/accounts/verify_credentials`
const MASTODON_UPDATE_FIELDS_API = `https://${MASTODON_INSTANCE}/api/v1/accounts/update_credentials`
const MASTODON_HEADERS = {
'Content-Type': 'application/json',
Authorization: `Bearer ${MASTODON_TOKEN}`,
}
// Last FM Related Functions
function formatTrackString(track) {
const { artist, album, name } = track
const albumName = album['#text']
const artistName = artist['#text']
// If you want to change the format of the track
// value, you would do it here.
return `${artistName} - ${albumName} - ${name}`
}
async function getLatestTrack() {
const res = new Request(LASTFM_API)
const data = await res.loadJSON()
const track = data.recenttracks.track[0]
return formatTrackString(track)
}
// Mastodon Related Functions
function findProfileField(el, i) {
const { name, value } = el
if (FIND_FIELD_BY === LASTFM_URL_IN_VALUE) {
return value.toLowerCase().indexOf('last.fm/user/') >= 0
}
if (FIND_FIELD_BY === LASTFM_IN_NAME) {
return name.toLowerCase().indexOf('last.fm') >= 0
}
return false
}
function buildFieldParams(fields) {
return fields.reduce((out, { name, value }, index) => {
const prefix = index === 0 ? '?' : '&'
return `${out}${prefix}fields_attributes[${index}][name]=${encodeURIComponent(
name
)}&fields_attributes[${index}][value]=${encodeURIComponent(value)}`
}, '')
}
async function getFields() {
const res = new Request(MASTODON_GET_ACCOUNT_API)
res.headers = MASTODON_HEADERS
const data = await res.loadJSON()
const { source } = data
const { fields } = source
const targetField = fields.find(findProfileField)
const index = fields.indexOf(targetField)
return { index, fields }
}
async function updateMastodonField() {
const latestTrack = await getLatestTrack()
const { fields, index } = await getFields()
let hasChange = false
if (FIND_FIELD_BY === LASTFM_URL_IN_VALUE) {
if (fields[index].name !== latestTrack) {
hasChange = true
fields[index].name = latestTrack
}
}
if (FIND_FIELD_BY === LASTFM_IN_NAME) {
if (fields[index].value !== latestTrack) {
hasChange = true
fields[index].value = latestTrack
}
}
if (hasChange) {
const apiUrl = `${MASTODON_UPDATE_FIELDS_API}${buildFieldParams(fields)}`
const res = new Request(apiUrl)
res.headers = MASTODON_HEADERS
res.method = 'PATCH'
const data = await res.loadJSON()
if (data.error) {
console.log(`Error: ${data.error}`)
} else {
console.log('Updated')
}
} else {
console.log('No change')
}
}
await updateMastodonField()
1 | // Variables used by Scriptable. |
2 | // These must be at the very top of the file. Do not edit. |
3 | // icon-color: pink; icon-glyph: headphones-alt; |
4 | // Last.fm to Mastodon |
5 | // by @zicklepop@nyan.lol |
6 | // |
7 | // Set a profile field to your currently playing track |
8 | // |
9 | // Requirements: |
10 | // - API Key from Last.fm: https://www.last.fm/api |
11 | // - Token from Mastodon with permission scopes for: |
12 | // `read:account` and `write:account` |
13 | // - Find it on your Mastodon instance website under |
14 | // Settings -> Development -> New Application |
15 | |
16 | // Script Constants |
17 | // - Ignore, just defining before use |
18 | // Continue down to config |
19 | |
20 | const LASTFM_URL_IN_VALUE = 'LASTFM_URL_IN_VALUE' |
21 | const LASTFM_IN_NAME = 'LASTFM_IN_NAME' |
22 | |
23 | // Config |
24 | // - Put in your details below |
25 | // - Find Field By: |
26 | // - When set to LASTFM_URL_IN_VALUE the script will |
27 | // look for a last.fm url in a field value and set |
28 | // the title of the field to the current track |
29 | // - When set to LASTFM_IN_NAME the script will look |
30 | // for a field title that is `last.fm` (case-insenstive) |
31 | // and set the value to the current track |
32 | |
33 | const LASTFM_USERNAME = '' |
34 | const LASTFM_API_KEY = '' |
35 | const MASTODON_INSTANCE = '' // ie: social.lol |
36 | const MASTODON_TOKEN = '' |
37 | const FIND_FIELD_BY = LASTFM_URL_IN_VALUE // or LASTFM_IN_NAME |
38 | |
39 | // More Script Constants |
40 | // - You can ignore this too |
41 | |
42 | const LASTFM_API = `http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=${LASTFM_USERNAME}&api_key=${LASTFM_API_KEY}&format=json&limit=1` |
43 | const MASTODON_GET_ACCOUNT_API = `https://${MASTODON_INSTANCE}/api/v1/accounts/verify_credentials` |
44 | const MASTODON_UPDATE_FIELDS_API = `https://${MASTODON_INSTANCE}/api/v1/accounts/update_credentials` |
45 | const MASTODON_HEADERS = { |
46 | 'Content-Type': 'application/json', |
47 | Authorization: `Bearer ${MASTODON_TOKEN}`, |
48 | } |
49 | |
50 | // Last FM Related Functions |
51 | |
52 | function formatTrackString(track) { |
53 | const { artist, album, name } = track |
54 | const albumName = album['#text'] |
55 | const artistName = artist['#text'] |
56 | |
57 | // If you want to change the format of the track |
58 | // value, you would do it here. |
59 | return `${artistName} - ${albumName} - ${name}` |
60 | } |
61 | |
62 | async function getLatestTrack() { |
63 | const res = new Request(LASTFM_API) |
64 | const data = await res.loadJSON() |
65 | const track = data.recenttracks.track[0] |
66 | return formatTrackString(track) |
67 | } |
68 | |
69 | // Mastodon Related Functions |
70 | |
71 | function findProfileField(el, i) { |
72 | const { name, value } = el |
73 | if (FIND_FIELD_BY === LASTFM_URL_IN_VALUE) { |
74 | return value.toLowerCase().indexOf('last.fm/user/') >= 0 |
75 | } |
76 | if (FIND_FIELD_BY === LASTFM_IN_NAME) { |
77 | return name.toLowerCase().indexOf('last.fm') >= 0 |
78 | } |
79 | return false |
80 | } |
81 | |
82 | function buildFieldParams(fields) { |
83 | return fields.reduce((out, { name, value }, index) => { |
84 | const prefix = index === 0 ? '?' : '&' |
85 | return `${out}${prefix}fields_attributes[${index}][name]=${encodeURIComponent( |
86 | name |
87 | )}&fields_attributes[${index}][value]=${encodeURIComponent(value)}` |
88 | }, '') |
89 | } |
90 | |
91 | async function getFields() { |
92 | const res = new Request(MASTODON_GET_ACCOUNT_API) |
93 | res.headers = MASTODON_HEADERS |
94 | const data = await res.loadJSON() |
95 | const { source } = data |
96 | const { fields } = source |
97 | const targetField = fields.find(findProfileField) |
98 | const index = fields.indexOf(targetField) |
99 | return { index, fields } |
100 | } |
101 | |
102 | async function updateMastodonField() { |
103 | const latestTrack = await getLatestTrack() |
104 | const { fields, index } = await getFields() |
105 | let hasChange = false |
106 | |
107 | if (FIND_FIELD_BY === LASTFM_URL_IN_VALUE) { |
108 | if (fields[index].name !== latestTrack) { |
109 | hasChange = true |
110 | fields[index].name = latestTrack |
111 | } |
112 | } |
113 | if (FIND_FIELD_BY === LASTFM_IN_NAME) { |
114 | if (fields[index].value !== latestTrack) { |
115 | hasChange = true |
116 | fields[index].value = latestTrack |
117 | } |
118 | } |
119 | |
120 | if (hasChange) { |
121 | const apiUrl = `${MASTODON_UPDATE_FIELDS_API}${buildFieldParams(fields)}` |
122 | const res = new Request(apiUrl) |
123 | res.headers = MASTODON_HEADERS |
124 | res.method = 'PATCH' |
125 | const data = await res.loadJSON() |
126 | |
127 | if (data.error) { |
128 | console.log(`Error: ${data.error}`) |
129 | } else { |
130 | console.log('Updated') |
131 | } |
132 | } else { |
133 | console.log('No change') |
134 | } |
135 | } |
136 | |
137 | await updateMastodonField() |
138 |