mirror of
https://github.com/FoxxMD/multi-scrobbler.git
synced 2026-07-09 17:28:28 +00:00
refactor(teal): Generate and use real lexicon definitions for tealfm implementation
Removes hand-rolled interfaces and generates interfaces+validation for official lexicon definitions
This commit is contained in:
parent
18c520ce2f
commit
95d7d276d7
22 changed files with 1069 additions and 81 deletions
|
|
@ -31,4 +31,5 @@ tmp-*
|
|||
.env
|
||||
*.env
|
||||
.storybook
|
||||
.stories
|
||||
.stories
|
||||
**/lexicons/**/*.json
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -153,4 +153,6 @@ tmp-*
|
|||
storybook-static
|
||||
|
||||
*.db
|
||||
*.db*
|
||||
*.db*
|
||||
|
||||
**/lexicons/**/*.json
|
||||
260
package-lock.json
generated
260
package-lock.json
generated
|
|
@ -11,7 +11,9 @@
|
|||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@astronautlabs/mdns": "^1.0.7",
|
||||
"@atcute/bluesky": "^4.0.5",
|
||||
"@atcute/identity-resolver-node": "^1.0.3",
|
||||
"@atcute/lexicons": "^2.0.0",
|
||||
"@atcute/repo": "^1.0.0",
|
||||
"@atproto/api": "^0.18.0",
|
||||
"@atproto/oauth-client-node": "^0.3.10",
|
||||
|
|
@ -103,6 +105,7 @@
|
|||
"youtubei.js": "^15.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@atcute/lex-cli": "^3.1.0",
|
||||
"@chakra-ui/react": "^3.34.0",
|
||||
"@chromatic-com/storybook": "^5.1.2",
|
||||
"@dbus-types/notifications": "^0.0.5",
|
||||
|
|
@ -277,6 +280,31 @@
|
|||
"integrity": "sha512-9bVdQ15Tbzpor1z/bteaemC9NvRDZgMD4Cfbu1/r/6Zv6fCBXvIJJoJ6Dh/BMvTlAiT2Xewm36i0VWRnZ4yw6A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@atcute/atproto": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@atcute/atproto/-/atproto-4.0.2.tgz",
|
||||
"integrity": "sha512-hLnvjiIOStpdUm0cEN+R5YydvbV0d6ap17Iv+t7i/nhSCN3TGMya7M0ftCWtCo+xoQ1EU6HK74R8jqXWlyrM0w==",
|
||||
"license": "0BSD",
|
||||
"dependencies": {
|
||||
"@atcute/lexicons": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@atcute/lexicons": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@atcute/bluesky": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@atcute/bluesky/-/bluesky-4.0.5.tgz",
|
||||
"integrity": "sha512-kw+kc41cNXBFUyFU9oPDKhltB9JTEKNDTiNoSbtOvonwg2Wej9Zg8vt0UhLvb6958rSwLvG0xX+SuQbZ0O8k2Q==",
|
||||
"license": "0BSD",
|
||||
"dependencies": {
|
||||
"@atcute/atproto": "^4.0.2",
|
||||
"@atcute/lexicons": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@atcute/lexicons": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@atcute/car": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@atcute/car/-/car-6.0.0.tgz",
|
||||
|
|
@ -372,7 +400,7 @@
|
|||
"@atcute/lexicons": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@atcute/lexicons": {
|
||||
"node_modules/@atcute/identity-resolver-node/node_modules/@atcute/lexicons": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@atcute/lexicons/-/lexicons-1.3.1.tgz",
|
||||
"integrity": "sha512-2JVxDmHt+QwsUoPyVYWIN7ZLRLfLx4GeJxKFjA9ofStuby9hCMv7Q4GAPIXuJD8wPv8vrnhr1yRNQhiJX+bthw==",
|
||||
|
|
@ -384,6 +412,158 @@
|
|||
"esm-env": "^1.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@atcute/identity-resolver/node_modules/@atcute/lexicons": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@atcute/lexicons/-/lexicons-1.3.1.tgz",
|
||||
"integrity": "sha512-2JVxDmHt+QwsUoPyVYWIN7ZLRLfLx4GeJxKFjA9ofStuby9hCMv7Q4GAPIXuJD8wPv8vrnhr1yRNQhiJX+bthw==",
|
||||
"license": "0BSD",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@atcute/uint8array": "^1.1.1",
|
||||
"@atcute/util-text": "^1.3.1",
|
||||
"@standard-schema/spec": "^1.1.0",
|
||||
"esm-env": "^1.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@atcute/identity/node_modules/@atcute/lexicons": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@atcute/lexicons/-/lexicons-1.3.1.tgz",
|
||||
"integrity": "sha512-2JVxDmHt+QwsUoPyVYWIN7ZLRLfLx4GeJxKFjA9ofStuby9hCMv7Q4GAPIXuJD8wPv8vrnhr1yRNQhiJX+bthw==",
|
||||
"license": "0BSD",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@atcute/uint8array": "^1.1.1",
|
||||
"@atcute/util-text": "^1.3.1",
|
||||
"@standard-schema/spec": "^1.1.0",
|
||||
"esm-env": "^1.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@atcute/lex-cli": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@atcute/lex-cli/-/lex-cli-3.1.0.tgz",
|
||||
"integrity": "sha512-Mba7y12ENIbdj+cr+gt5mJTalpuz/UbS4ykm/wT7t9ipoJtidXMSeuQFfeoyBvvidW77Vg4G6zxZkoDxtlr6Mg==",
|
||||
"dev": true,
|
||||
"license": "0BSD",
|
||||
"dependencies": {
|
||||
"@atcute/identity": "^2.0.0",
|
||||
"@atcute/identity-resolver": "^2.0.0",
|
||||
"@atcute/lexicon-doc": "^3.0.0",
|
||||
"@atcute/lexicon-resolver": "^1.0.0",
|
||||
"@atcute/lexicons": "^2.0.0",
|
||||
"@optique/core": "^1.0.2",
|
||||
"@optique/run": "^1.0.2",
|
||||
"picocolors": "^1.1.1",
|
||||
"prettier": "^3.8.3",
|
||||
"valibot": "^1.4.0"
|
||||
},
|
||||
"bin": {
|
||||
"lex-cli": "cli.mjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@atcute/lex-cli/node_modules/@atcute/identity": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@atcute/identity/-/identity-2.0.0.tgz",
|
||||
"integrity": "sha512-YXFsggO7eJYifqkN85+kUXJE2a1iI9AyuzPTDjtS/4WE1Zs1/XiPkWmwZlAgtp+pYhVtjm3mJqy/h/mZ0OnIVw==",
|
||||
"dev": true,
|
||||
"license": "0BSD",
|
||||
"dependencies": {
|
||||
"@atcute/lexicons": "^2.0.0",
|
||||
"valibot": "^1.4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@atcute/lexicons": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@atcute/lex-cli/node_modules/@atcute/identity-resolver": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@atcute/identity-resolver/-/identity-resolver-2.0.0.tgz",
|
||||
"integrity": "sha512-IKg1BDQAF2bIdN10DL6KAXmTjK+3enTU2IRbuani9TsFahBwGZ7O5FiVmTiL6QlGfauGNW5S0xNCOxWXWMoR2Q==",
|
||||
"dev": true,
|
||||
"license": "0BSD",
|
||||
"dependencies": {
|
||||
"@atcute/lexicons": "^2.0.0",
|
||||
"@atcute/util-fetch": "^2.0.0",
|
||||
"valibot": "^1.4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@atcute/identity": "^2.0.0",
|
||||
"@atcute/lexicons": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@atcute/lex-cli/node_modules/@atcute/lexicon-resolver": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@atcute/lexicon-resolver/-/lexicon-resolver-1.0.0.tgz",
|
||||
"integrity": "sha512-4v3oSijgd3w9JS2BMsV1dfD+GD1ClQeuEJatM9b7rNffi1kMTSn/3nOQbJ1aNeXfqZbCkn3ATDRdvgki1xIAZw==",
|
||||
"dev": true,
|
||||
"license": "0BSD",
|
||||
"dependencies": {
|
||||
"@atcute/crypto": "^2.4.1",
|
||||
"@atcute/lexicon-doc": "^3.0.0",
|
||||
"@atcute/lexicons": "^2.0.0",
|
||||
"@atcute/repo": "^1.0.0",
|
||||
"@atcute/util-fetch": "^2.0.0",
|
||||
"valibot": "^1.4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@atcute/identity": "^2.0.0",
|
||||
"@atcute/identity-resolver": "^2.0.0",
|
||||
"@atcute/lexicon-doc": "^3.0.0",
|
||||
"@atcute/lexicons": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@atcute/lex-cli/node_modules/@atcute/util-fetch": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@atcute/util-fetch/-/util-fetch-2.0.0.tgz",
|
||||
"integrity": "sha512-v+4aFQ/tuBqTV+URDJaFgm3mASWdglKXiPaGutJ1bs7QtQKmPZeesPY5MzW/a+MtI8GWCEJk8X9wOfalPOFSlg==",
|
||||
"dev": true,
|
||||
"license": "0BSD",
|
||||
"dependencies": {
|
||||
"valibot": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@atcute/lexicon-doc": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@atcute/lexicon-doc/-/lexicon-doc-3.0.0.tgz",
|
||||
"integrity": "sha512-hxBTEvO78X4j/HsGgcH8GKgMA9hP9FM6jtwQL8Yd6MIHtGXdB8QygvBmOAJEqm1oE9ckU1SSU3cwa2t4tbZZNw==",
|
||||
"dev": true,
|
||||
"license": "0BSD",
|
||||
"dependencies": {
|
||||
"@atcute/identity": "^2.0.0",
|
||||
"@atcute/lexicons": "^2.0.0",
|
||||
"@atcute/uint8array": "^1.1.1",
|
||||
"@atcute/util-text": "^1.3.1",
|
||||
"valibot": "^1.4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@atcute/lexicons": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@atcute/lexicon-doc/node_modules/@atcute/identity": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@atcute/identity/-/identity-2.0.0.tgz",
|
||||
"integrity": "sha512-YXFsggO7eJYifqkN85+kUXJE2a1iI9AyuzPTDjtS/4WE1Zs1/XiPkWmwZlAgtp+pYhVtjm3mJqy/h/mZ0OnIVw==",
|
||||
"dev": true,
|
||||
"license": "0BSD",
|
||||
"dependencies": {
|
||||
"@atcute/lexicons": "^2.0.0",
|
||||
"valibot": "^1.4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@atcute/lexicons": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@atcute/lexicons": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@atcute/lexicons/-/lexicons-2.0.0.tgz",
|
||||
"integrity": "sha512-fIlwP+TPEAGoF5aU5s+f8N5sOjOu8Mww/sQL1B57Dp2hj3G/EWG9XwOHPokzycBCgXx+UxIIrzZCGy8whsVDZw==",
|
||||
"license": "0BSD",
|
||||
"dependencies": {
|
||||
"@atcute/uint8array": "^1.1.1",
|
||||
"@atcute/util-text": "^1.3.1",
|
||||
"@standard-schema/spec": "^1.1.0",
|
||||
"esm-env": "^1.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@atcute/mst": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@atcute/mst/-/mst-1.0.1.tgz",
|
||||
|
|
@ -428,18 +608,6 @@
|
|||
"@atcute/lexicons": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@atcute/repo/node_modules/@atcute/lexicons": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@atcute/lexicons/-/lexicons-2.0.0.tgz",
|
||||
"integrity": "sha512-fIlwP+TPEAGoF5aU5s+f8N5sOjOu8Mww/sQL1B57Dp2hj3G/EWG9XwOHPokzycBCgXx+UxIIrzZCGy8whsVDZw==",
|
||||
"license": "0BSD",
|
||||
"dependencies": {
|
||||
"@atcute/uint8array": "^1.1.1",
|
||||
"@atcute/util-text": "^1.3.1",
|
||||
"@standard-schema/spec": "^1.1.0",
|
||||
"esm-env": "^1.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@atcute/uint8array": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@atcute/uint8array/-/uint8array-1.1.2.tgz",
|
||||
|
|
@ -2712,6 +2880,39 @@
|
|||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@optique/core": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@optique/core/-/core-1.0.2.tgz",
|
||||
"integrity": "sha512-znsqMmjAdeOgSJzdJlpZpgAscojwQmeQYXzYnuEKllz5VCj6WyEkdzU4QuvJQtWQY3ve2taXwudEBRur0VHBOQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
"https://github.com/sponsors/dahlia"
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"bun": ">=1.2.0",
|
||||
"deno": ">=2.3.0",
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@optique/run": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@optique/run/-/run-1.0.2.tgz",
|
||||
"integrity": "sha512-0Wc+zC8SLGV8zXQX+pk+o0c6wE/ddx/36CHZ0toTh5lApsjruUuGhqbxvljerAAG5un1xQbOLxzksBVC6UPgSg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
"https://github.com/sponsors/dahlia"
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@optique/core": "1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"bun": ">=1.2.0",
|
||||
"deno": ">=2.3.0",
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxc-parser/binding-android-arm-eabi": {
|
||||
"version": "0.127.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm-eabi/-/binding-android-arm-eabi-0.127.0.tgz",
|
||||
|
|
@ -14751,6 +14952,22 @@
|
|||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "3.8.3",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz",
|
||||
"integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/pretty-format": {
|
||||
"version": "27.5.1",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
|
||||
|
|
@ -17631,7 +17848,7 @@
|
|||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz",
|
||||
"integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
|
|
@ -18024,6 +18241,21 @@
|
|||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/valibot": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/valibot/-/valibot-1.4.1.tgz",
|
||||
"integrity": "sha512-klCmFTz2jeDluy9RwX+F884TCiogtdBJ/YaxSx1EOBYXa3NXNWj8kR1jjN8rzluwojJVWWaHJ4r1U5LfICnM3g==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"typescript": ">=5"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
|
|
|
|||
|
|
@ -24,7 +24,8 @@
|
|||
"install:parallel": "concurrently --kill-others-on-fail --names app,docs \"npm ci --no-audit\" \"npm run docs:install\"",
|
||||
"cliff": "git-cliff --unreleased",
|
||||
"storybook": "storybook dev -p 6006",
|
||||
"build-storybook": "storybook build"
|
||||
"build-storybook": "storybook build",
|
||||
"atproto:lex:tealfm": "npm exec -- lex-cli pull -c src/backend/common/vendor/teal/lex.config.ts && npm exec -- lex-cli generate -c src/backend/common/vendor/teal/lex.config.ts"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
|
|
@ -49,7 +50,9 @@
|
|||
"homepage": ".",
|
||||
"dependencies": {
|
||||
"@astronautlabs/mdns": "^1.0.7",
|
||||
"@atcute/bluesky": "^4.0.5",
|
||||
"@atcute/identity-resolver-node": "^1.0.3",
|
||||
"@atcute/lexicons": "^2.0.0",
|
||||
"@atcute/repo": "^1.0.0",
|
||||
"@atproto/api": "^0.18.0",
|
||||
"@atproto/oauth-client-node": "^0.3.10",
|
||||
|
|
@ -141,6 +144,7 @@
|
|||
"youtubei.js": "^15.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@atcute/lex-cli": "^3.1.0",
|
||||
"@chakra-ui/react": "^3.34.0",
|
||||
"@chromatic-com/storybook": "^5.1.2",
|
||||
"@dbus-types/notifications": "^0.0.5",
|
||||
|
|
|
|||
|
|
@ -51,50 +51,6 @@ export interface TealClientOptions extends TealOptions,CommonClientOptions {
|
|||
export interface TealClientAIOConfig extends TealClientConfig {
|
||||
type: 'tealfm'
|
||||
}
|
||||
export interface TealArtistCredit {
|
||||
artistName?: string,
|
||||
/** The MusicBrainz artist ID URI, formatted as mbid:<uuid> */
|
||||
artistMbId?: string
|
||||
}
|
||||
/**
|
||||
* https://github.com/teal-fm/teal/blob/main/lexicons/fm.teal.alpha/feed/play.json
|
||||
* https://github.com/teal-fm/teal/blob/main/lexicons/fm.teal.alpha/feed/defs.json
|
||||
* */
|
||||
export interface ScrobbleRecord {
|
||||
$type: "fm.teal.alpha.feed.play",
|
||||
trackName: string,
|
||||
playedTime: string,
|
||||
duration?: number
|
||||
artists?: TealArtistCredit[]
|
||||
/** Album name */
|
||||
releaseName?: string
|
||||
/** A metadata string specifying the user agent where the format is `<app-identifier>/<version> (<kernel/OS-base>; <platform/OS-version>; <device-model>)` */
|
||||
submissionClientAgent: string,
|
||||
musicServiceBaseDomain?: string
|
||||
/** The MusicBrainz ID URI of the track, formatted as mbid:<uuid> */
|
||||
trackMbId?: string
|
||||
/** The MusicBrainz recording ID URI of the track, formatted as mbid:<uuid> */
|
||||
recordingMbId?: string
|
||||
/** The MusicBrainz release ID URI, formatted as mbid:<uuid> */
|
||||
releaseMbId?: string
|
||||
isrc?: string,
|
||||
/** The URL associated with this track */
|
||||
originUrl?: string
|
||||
/** Distinguishing information for track variants (e.g. 'Acoustic Version', 'Live at Wembley', 'Radio Edit', 'Demo'). Used to differentiate between different versions of the same base track while maintaining grouping capabilities. */
|
||||
trackDiscriminant?: string;
|
||||
/** Distinguishing information for release variants (e.g. 'Deluxe Edition', 'Remastered', '2023 Remaster', 'Special Edition'). Used to differentiate between different versions of the same base release while maintaining grouping capabilities. */
|
||||
releaseDiscriminant?: string;
|
||||
[x: string]: unknown
|
||||
}
|
||||
|
||||
export interface StatusRecord {
|
||||
$type: "fm.teal.alpha.actor.status",
|
||||
/** item is just ScrobbleRecord, but without $type */
|
||||
item: Omit<ScrobbleRecord, '$type'>,
|
||||
time: string,
|
||||
expiry: string,
|
||||
[x: string]: unknown
|
||||
}
|
||||
|
||||
export interface ListRecord<T> {
|
||||
uri: string;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { getRoot } from "../../../ioc.js";
|
||||
import { AbstractApiOptions, PagelessListensTimeRangeOptions, PagelessTimeRangeListens, PagelessTimeRangeListensResult } from "../../infrastructure/Atomic.js";
|
||||
import { ListRecord, ScrobbleRecord, StatusRecord, TealClientData } from "../../infrastructure/config/client/tealfm.js";
|
||||
import { ListRecord, TealClientData } from "../../infrastructure/config/client/tealfm.js";
|
||||
import AbstractApiClient from "../AbstractApiClient.js";
|
||||
import { Agent, ComAtprotoRepoCreateRecord, ComAtprotoRepoListRecords, ComAtprotoRepoPutRecord } from "@atproto/api";
|
||||
import { MSCache } from "../../Cache.js";
|
||||
import { BrainzMeta, PlayObject, PlayObjectLifecycleless, ScrobbleActionResult, UnixTimestamp, MBID, NowPlayingUpdateThreshold, SourcePlayerObj, Second } from "../../../../core/Atomic.js";
|
||||
import { BrainzMeta, PlayObject, PlayObjectLifecycleless, ScrobbleActionResult, UnixTimestamp, MBID, SourcePlayerObj } from "../../../../core/Atomic.js";
|
||||
import { musicServiceToCononical } from '../listenbrainz/lzUtils.js';
|
||||
import { parseRegexSingle } from "@foxxmd/regex-buddy-core";
|
||||
import { RecordOptions } from "../../infrastructure/config/client/tealfm.js";
|
||||
|
|
@ -17,6 +17,7 @@ import { UpstreamError } from "../../errors/UpstreamError.js";
|
|||
import { decodeTid, generateTID } from '@ewanc26/tid';
|
||||
import { Duration } from "dayjs/plugin/duration.js";
|
||||
import { streamBodyProgress } from "../../../utils/NetworkUtils.js";
|
||||
import { FmTealAlphaActorStatus, FmTealAlphaFeedPlay } from "../teal/lexicons/index.js";
|
||||
|
||||
export abstract class AbstractBlueSkyApiClient extends AbstractApiClient implements PagelessTimeRangeListens {
|
||||
|
||||
|
|
@ -36,7 +37,7 @@ export abstract class AbstractBlueSkyApiClient extends AbstractApiClient impleme
|
|||
|
||||
abstract restoreSession(): Promise<boolean>;
|
||||
|
||||
async createScrobbleRecord(record: ScrobbleRecord): Promise<ScrobbleActionResult> {
|
||||
async createScrobbleRecord(record: FmTealAlphaFeedPlay.Main): Promise<ScrobbleActionResult> {
|
||||
const input: ComAtprotoRepoCreateRecord.InputSchema = {
|
||||
repo: this.agent.sessionManager.did,
|
||||
collection: "fm.teal.alpha.feed.play",
|
||||
|
|
@ -50,7 +51,7 @@ export abstract class AbstractBlueSkyApiClient extends AbstractApiClient impleme
|
|||
}
|
||||
}
|
||||
|
||||
async updateStatusRecord(record: StatusRecord): Promise<ScrobbleActionResult> {
|
||||
async updateStatusRecord(record: FmTealAlphaActorStatus.Main): Promise<ScrobbleActionResult> {
|
||||
const input: ComAtprotoRepoPutRecord.InputSchema = {
|
||||
repo: this.agent.sessionManager.did,
|
||||
collection: "fm.teal.alpha.actor.status",
|
||||
|
|
@ -118,7 +119,7 @@ export abstract class AbstractBlueSkyApiClient extends AbstractApiClient impleme
|
|||
fromTS = usecToUnix(timestampUs);
|
||||
}
|
||||
|
||||
const plays = (resp.data.records as unknown as ListRecord<ScrobbleRecord>[]).map(x => listRecordToPlay(x));
|
||||
const plays = (resp.data.records as unknown as ListRecord<FmTealAlphaFeedPlay.Main>[]).map(x => listRecordToPlay(x));
|
||||
|
||||
return {data: plays, meta: {to, from: fromTS, limit}};
|
||||
}
|
||||
|
|
@ -128,9 +129,9 @@ export abstract class AbstractBlueSkyApiClient extends AbstractApiClient impleme
|
|||
}
|
||||
}
|
||||
|
||||
export const playToRecord = (play: PlayObject): ScrobbleRecord => {
|
||||
export const playToRecord = (play: PlayObject): FmTealAlphaFeedPlay.Main => {
|
||||
|
||||
const record: ScrobbleRecord = {
|
||||
const record: FmTealAlphaFeedPlay.Main = {
|
||||
$type: "fm.teal.alpha.feed.play",
|
||||
trackName: play.data.track,
|
||||
artists: play.data.artists.map(x => removeUndefinedKeys({ artistName: x.name, artistMbId: mbidUriOrUndefined(x.mbid as MBID) })),
|
||||
|
|
@ -160,7 +161,7 @@ export const mbidToUri = (mbid: MBID): MBIDURI => {
|
|||
return `mbid:${mbid}`;
|
||||
}
|
||||
|
||||
export const playToStatusRecord = (play: PlayObject, notPlaying: boolean, position?: number): StatusRecord => {
|
||||
export const playToStatusRecord = (play: PlayObject, notPlaying: boolean, position?: number): FmTealAlphaActorStatus.Main => {
|
||||
const { $type, ...item } = notPlaying
|
||||
? { trackName: "", artists: [] }
|
||||
: playToRecord(play);
|
||||
|
|
@ -177,7 +178,10 @@ export const playToStatusRecord = (play: PlayObject, notPlaying: boolean, positi
|
|||
$type: "fm.teal.alpha.actor.status",
|
||||
time: dayjs().toISOString(),
|
||||
expiry: expiry.toISOString(),
|
||||
item
|
||||
item: {
|
||||
artists: [],
|
||||
...item
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -201,7 +205,7 @@ export const nowPlayingExpirationDuration = (data: Pick<SourcePlayerObj, 'play'
|
|||
return dayjs.duration(expiry.diff(dayjs(), 'ms'));
|
||||
}
|
||||
|
||||
export const listRecordToPlay = (listRecord: ListRecord<ScrobbleRecord>): PlayObject => {
|
||||
export const listRecordToPlay = (listRecord: ListRecord<FmTealAlphaFeedPlay.Main>): PlayObject => {
|
||||
const opts: RecordOptions = {};
|
||||
const uriRes = parseRegexSingle(ATPROTO_URI_REGEX, listRecord.uri);
|
||||
if (uriRes !== undefined) {
|
||||
|
|
@ -212,7 +216,7 @@ export const listRecordToPlay = (listRecord: ListRecord<ScrobbleRecord>): PlayOb
|
|||
return recordToPlay(listRecord.value, opts);
|
||||
}
|
||||
|
||||
export const recordToPlay = (record: ScrobbleRecord, options: RecordOptions = {}): PlayObject => {
|
||||
export const recordToPlay = (record: FmTealAlphaFeedPlay.Main, options: RecordOptions = {}): PlayObject => {
|
||||
|
||||
const play: PlayObjectLifecycleless = {
|
||||
data: {
|
||||
|
|
|
|||
26
src/backend/common/vendor/teal/lex.config.ts
vendored
Normal file
26
src/backend/common/vendor/teal/lex.config.ts
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { defineLexiconConfig } from '@atcute/lex-cli';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname } from 'path';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
export default defineLexiconConfig({
|
||||
generate: {
|
||||
files: ['lexicons/**/*.json'],
|
||||
outdir: 'lexicons/',
|
||||
imports: ['@atcute/bluesky'],
|
||||
},
|
||||
pull: {
|
||||
outdir: path.resolve(__dirname, 'lexicons/'),
|
||||
sources: [
|
||||
{
|
||||
type: 'git',
|
||||
remote: 'https://github.com/teal-fm/teal.git',
|
||||
ref: 'main',
|
||||
pattern: ['lexicons/fm.teal.alpha/feed/*.json','lexicons/fm.teal.alpha/actor/*.json'],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
6
src/backend/common/vendor/teal/lexicons/README.md
vendored
Normal file
6
src/backend/common/vendor/teal/lexicons/README.md
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# lexicon sources
|
||||
|
||||
this directory contains lexicon documents pulled from the following sources:
|
||||
|
||||
- https://github.com/teal-fm/teal.git (ref: main)
|
||||
- commit: f661868af2a56199f1b3cae1ad20cd5831ec4212
|
||||
11
src/backend/common/vendor/teal/lexicons/index.ts
vendored
Normal file
11
src/backend/common/vendor/teal/lexicons/index.ts
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
export * as FmTealAlphaActorDefs from "./types/fm/teal/alpha/actor/defs.js";
|
||||
export * as FmTealAlphaActorGetProfile from "./types/fm/teal/alpha/actor/getProfile.js";
|
||||
export * as FmTealAlphaActorGetProfiles from "./types/fm/teal/alpha/actor/getProfiles.js";
|
||||
export * as FmTealAlphaActorProfile from "./types/fm/teal/alpha/actor/profile.js";
|
||||
export * as FmTealAlphaActorProfileStatus from "./types/fm/teal/alpha/actor/profileStatus.js";
|
||||
export * as FmTealAlphaActorSearchActors from "./types/fm/teal/alpha/actor/searchActors.js";
|
||||
export * as FmTealAlphaActorStatus from "./types/fm/teal/alpha/actor/status.js";
|
||||
export * as FmTealAlphaFeedDefs from "./types/fm/teal/alpha/feed/defs.js";
|
||||
export * as FmTealAlphaFeedGetActorFeed from "./types/fm/teal/alpha/feed/getActorFeed.js";
|
||||
export * as FmTealAlphaFeedGetPlay from "./types/fm/teal/alpha/feed/getPlay.js";
|
||||
export * as FmTealAlphaFeedPlay from "./types/fm/teal/alpha/feed/play.js";
|
||||
96
src/backend/common/vendor/teal/lexicons/types/fm/teal/alpha/actor/defs.ts
vendored
Normal file
96
src/backend/common/vendor/teal/lexicons/types/fm/teal/alpha/actor/defs.ts
vendored
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
import type {} from "@atcute/lexicons";
|
||||
import * as v from "@atcute/lexicons/validations";
|
||||
import * as AppBskyRichtextFacet from "@atcute/bluesky/types/app/richtext/facet";
|
||||
import * as FmTealAlphaActorProfile from "./profile.js";
|
||||
import * as FmTealAlphaFeedDefs from "../feed/defs.js";
|
||||
|
||||
const _miniProfileViewSchema = /*#__PURE__*/ v.object({
|
||||
$type: /*#__PURE__*/ v.optional(
|
||||
/*#__PURE__*/ v.literal("fm.teal.alpha.actor.defs#miniProfileView"),
|
||||
),
|
||||
/**
|
||||
* IPLD of the avatar
|
||||
*/
|
||||
avatar: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
|
||||
/**
|
||||
* The decentralized identifier of the actor
|
||||
*/
|
||||
did: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
|
||||
displayName: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
|
||||
handle: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
|
||||
});
|
||||
const _profileViewSchema = /*#__PURE__*/ v.object({
|
||||
$type: /*#__PURE__*/ v.optional(
|
||||
/*#__PURE__*/ v.literal("fm.teal.alpha.actor.defs#profileView"),
|
||||
),
|
||||
/**
|
||||
* IPLD of the avatar
|
||||
*/
|
||||
avatar: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
|
||||
/**
|
||||
* IPLD of the banner image
|
||||
*/
|
||||
banner: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
|
||||
createdAt: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.datetimeString()),
|
||||
/**
|
||||
* Free-form profile description text.
|
||||
*/
|
||||
description: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
|
||||
/**
|
||||
* Annotations of text in the profile description (mentions, URLs, hashtags, etc). May be changed to another (backwards compatible) lexicon.
|
||||
*/
|
||||
get descriptionFacets() {
|
||||
return /*#__PURE__*/ v.optional(
|
||||
/*#__PURE__*/ v.array(AppBskyRichtextFacet.mainSchema),
|
||||
);
|
||||
},
|
||||
/**
|
||||
* The decentralized identifier of the actor
|
||||
*/
|
||||
did: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
|
||||
displayName: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
|
||||
/**
|
||||
* The user's most recent item featured on their profile.
|
||||
*/
|
||||
get featuredItem() {
|
||||
return /*#__PURE__*/ v.optional(FmTealAlphaActorProfile.featuredItemSchema);
|
||||
},
|
||||
get status() {
|
||||
return /*#__PURE__*/ v.optional(statusViewSchema);
|
||||
},
|
||||
});
|
||||
const _statusViewSchema = /*#__PURE__*/ v.object({
|
||||
$type: /*#__PURE__*/ v.optional(
|
||||
/*#__PURE__*/ v.literal("fm.teal.alpha.actor.defs#statusView"),
|
||||
),
|
||||
/**
|
||||
* The unix timestamp of the expiry time of the item. If unavailable, default to 10 minutes past the start time.
|
||||
*/
|
||||
expiry: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.datetimeString()),
|
||||
get item() {
|
||||
return /*#__PURE__*/ v.optional(FmTealAlphaFeedDefs.playViewSchema);
|
||||
},
|
||||
/**
|
||||
* The unix timestamp of when the item was recorded
|
||||
*/
|
||||
time: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.datetimeString()),
|
||||
});
|
||||
|
||||
type miniProfileView$schematype = typeof _miniProfileViewSchema;
|
||||
type profileView$schematype = typeof _profileViewSchema;
|
||||
type statusView$schematype = typeof _statusViewSchema;
|
||||
|
||||
export interface miniProfileViewSchema extends miniProfileView$schematype {}
|
||||
export interface profileViewSchema extends profileView$schematype {}
|
||||
export interface statusViewSchema extends statusView$schematype {}
|
||||
|
||||
export const miniProfileViewSchema =
|
||||
_miniProfileViewSchema as miniProfileViewSchema;
|
||||
export const profileViewSchema = _profileViewSchema as profileViewSchema;
|
||||
export const statusViewSchema = _statusViewSchema as statusViewSchema;
|
||||
|
||||
export interface MiniProfileView extends v.InferInput<
|
||||
typeof miniProfileViewSchema
|
||||
> {}
|
||||
export interface ProfileView extends v.InferInput<typeof profileViewSchema> {}
|
||||
export interface StatusView extends v.InferInput<typeof statusViewSchema> {}
|
||||
36
src/backend/common/vendor/teal/lexicons/types/fm/teal/alpha/actor/getProfile.ts
vendored
Normal file
36
src/backend/common/vendor/teal/lexicons/types/fm/teal/alpha/actor/getProfile.ts
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import type {} from "@atcute/lexicons";
|
||||
import * as v from "@atcute/lexicons/validations";
|
||||
import type {} from "@atcute/lexicons/ambient";
|
||||
import * as FmTealAlphaActorDefs from "./defs.js";
|
||||
|
||||
const _mainSchema = /*#__PURE__*/ v.query("fm.teal.alpha.actor.getProfile", {
|
||||
params: /*#__PURE__*/ v.object({
|
||||
/**
|
||||
* The author's DID
|
||||
*/
|
||||
actor: /*#__PURE__*/ v.actorIdentifierString(),
|
||||
}),
|
||||
output: {
|
||||
type: "lex",
|
||||
schema: /*#__PURE__*/ v.object({
|
||||
get actor() {
|
||||
return FmTealAlphaActorDefs.profileViewSchema;
|
||||
},
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
type main$schematype = typeof _mainSchema;
|
||||
|
||||
export interface mainSchema extends main$schematype {}
|
||||
|
||||
export const mainSchema = _mainSchema as mainSchema;
|
||||
|
||||
export interface $params extends v.InferInput<mainSchema["params"]> {}
|
||||
export interface $output extends v.InferXRPCBodyInput<mainSchema["output"]> {}
|
||||
|
||||
declare module "@atcute/lexicons/ambient" {
|
||||
interface XRPCQueries {
|
||||
"fm.teal.alpha.actor.getProfile": mainSchema;
|
||||
}
|
||||
}
|
||||
42
src/backend/common/vendor/teal/lexicons/types/fm/teal/alpha/actor/getProfiles.ts
vendored
Normal file
42
src/backend/common/vendor/teal/lexicons/types/fm/teal/alpha/actor/getProfiles.ts
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import type {} from "@atcute/lexicons";
|
||||
import * as v from "@atcute/lexicons/validations";
|
||||
import type {} from "@atcute/lexicons/ambient";
|
||||
import * as FmTealAlphaActorDefs from "./defs.js";
|
||||
|
||||
const _mainSchema = /*#__PURE__*/ v.query("fm.teal.alpha.actor.getProfiles", {
|
||||
params: /*#__PURE__*/ v.object({
|
||||
/**
|
||||
* Array of actor DIDs
|
||||
* @minLength 1
|
||||
*/
|
||||
actors: /*#__PURE__*/ v.constrain(
|
||||
/*#__PURE__*/ v.array(/*#__PURE__*/ v.actorIdentifierString()),
|
||||
[/*#__PURE__*/ v.arrayLength(1)],
|
||||
),
|
||||
}),
|
||||
output: {
|
||||
type: "lex",
|
||||
schema: /*#__PURE__*/ v.object({
|
||||
get actors() {
|
||||
return /*#__PURE__*/ v.array(
|
||||
FmTealAlphaActorDefs.miniProfileViewSchema,
|
||||
);
|
||||
},
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
type main$schematype = typeof _mainSchema;
|
||||
|
||||
export interface mainSchema extends main$schematype {}
|
||||
|
||||
export const mainSchema = _mainSchema as mainSchema;
|
||||
|
||||
export interface $params extends v.InferInput<mainSchema["params"]> {}
|
||||
export interface $output extends v.InferXRPCBodyInput<mainSchema["output"]> {}
|
||||
|
||||
declare module "@atcute/lexicons/ambient" {
|
||||
interface XRPCQueries {
|
||||
"fm.teal.alpha.actor.getProfiles": mainSchema;
|
||||
}
|
||||
}
|
||||
100
src/backend/common/vendor/teal/lexicons/types/fm/teal/alpha/actor/profile.ts
vendored
Normal file
100
src/backend/common/vendor/teal/lexicons/types/fm/teal/alpha/actor/profile.ts
vendored
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
import type {} from "@atcute/lexicons";
|
||||
import * as v from "@atcute/lexicons/validations";
|
||||
import type {} from "@atcute/lexicons/ambient";
|
||||
import * as AppBskyRichtextFacet from "@atcute/bluesky/types/app/richtext/facet";
|
||||
|
||||
const _featuredItemSchema = /*#__PURE__*/ v.object({
|
||||
$type: /*#__PURE__*/ v.optional(
|
||||
/*#__PURE__*/ v.literal("fm.teal.alpha.actor.profile#featuredItem"),
|
||||
),
|
||||
/**
|
||||
* The MusicBrainz ID URI of the item, formatted as mbid:<uuid>
|
||||
*/
|
||||
mbid: /*#__PURE__*/ v.genericUriString(),
|
||||
/**
|
||||
* The type of the item. Must be a valid Musicbrainz type, e.g. album, track, recording, etc.
|
||||
*/
|
||||
type: /*#__PURE__*/ v.string(),
|
||||
});
|
||||
const _mainSchema = /*#__PURE__*/ v.record(
|
||||
/*#__PURE__*/ v.literal("self"),
|
||||
/*#__PURE__*/ v.object({
|
||||
$type: /*#__PURE__*/ v.literal("fm.teal.alpha.actor.profile"),
|
||||
/**
|
||||
* Small image to be displayed next to posts from account. AKA, 'profile picture'
|
||||
* @accept image/jpeg, image/png
|
||||
* @maxSize 1000000
|
||||
*/
|
||||
avatar: /*#__PURE__*/ v.optional(
|
||||
/*#__PURE__*/ v.constrain(/*#__PURE__*/ v.blob(), [
|
||||
/*#__PURE__*/ v.blobSize(1000000),
|
||||
/*#__PURE__*/ v.blobAccept(["image/jpeg", "image/png"]),
|
||||
]),
|
||||
),
|
||||
/**
|
||||
* Larger horizontal image to display behind profile view.
|
||||
* @accept image/jpeg, image/png
|
||||
* @maxSize 1000000
|
||||
*/
|
||||
banner: /*#__PURE__*/ v.optional(
|
||||
/*#__PURE__*/ v.constrain(/*#__PURE__*/ v.blob(), [
|
||||
/*#__PURE__*/ v.blobSize(1000000),
|
||||
/*#__PURE__*/ v.blobAccept(["image/jpeg", "image/png"]),
|
||||
]),
|
||||
),
|
||||
createdAt: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.datetimeString()),
|
||||
/**
|
||||
* Free-form profile description text.
|
||||
* @maxLength 2560
|
||||
* @maxGraphemes 256
|
||||
*/
|
||||
description: /*#__PURE__*/ v.optional(
|
||||
/*#__PURE__*/ v.constrain(/*#__PURE__*/ v.string(), [
|
||||
/*#__PURE__*/ v.stringLength(0, 2560),
|
||||
/*#__PURE__*/ v.stringGraphemes(0, 256),
|
||||
]),
|
||||
),
|
||||
/**
|
||||
* Annotations of text in the profile description (mentions, URLs, hashtags, etc).
|
||||
*/
|
||||
get descriptionFacets() {
|
||||
return /*#__PURE__*/ v.optional(
|
||||
/*#__PURE__*/ v.array(AppBskyRichtextFacet.mainSchema),
|
||||
);
|
||||
},
|
||||
/**
|
||||
* @maxLength 640
|
||||
* @maxGraphemes 64
|
||||
*/
|
||||
displayName: /*#__PURE__*/ v.optional(
|
||||
/*#__PURE__*/ v.constrain(/*#__PURE__*/ v.string(), [
|
||||
/*#__PURE__*/ v.stringLength(0, 640),
|
||||
/*#__PURE__*/ v.stringGraphemes(0, 64),
|
||||
]),
|
||||
),
|
||||
/**
|
||||
* The user's most recent item featured on their profile.
|
||||
*/
|
||||
get featuredItem() {
|
||||
return /*#__PURE__*/ v.optional(featuredItemSchema);
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
type featuredItem$schematype = typeof _featuredItemSchema;
|
||||
type main$schematype = typeof _mainSchema;
|
||||
|
||||
export interface featuredItemSchema extends featuredItem$schematype {}
|
||||
export interface mainSchema extends main$schematype {}
|
||||
|
||||
export const featuredItemSchema = _featuredItemSchema as featuredItemSchema;
|
||||
export const mainSchema = _mainSchema as mainSchema;
|
||||
|
||||
export interface FeaturedItem extends v.InferInput<typeof featuredItemSchema> {}
|
||||
export interface Main extends v.InferInput<typeof mainSchema> {}
|
||||
|
||||
declare module "@atcute/lexicons/ambient" {
|
||||
interface Records {
|
||||
"fm.teal.alpha.actor.profile": mainSchema;
|
||||
}
|
||||
}
|
||||
42
src/backend/common/vendor/teal/lexicons/types/fm/teal/alpha/actor/profileStatus.ts
vendored
Normal file
42
src/backend/common/vendor/teal/lexicons/types/fm/teal/alpha/actor/profileStatus.ts
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import type {} from "@atcute/lexicons";
|
||||
import * as v from "@atcute/lexicons/validations";
|
||||
import type {} from "@atcute/lexicons/ambient";
|
||||
|
||||
const _mainSchema = /*#__PURE__*/ v.record(
|
||||
/*#__PURE__*/ v.literal("self"),
|
||||
/*#__PURE__*/ v.object({
|
||||
$type: /*#__PURE__*/ v.literal("fm.teal.alpha.actor.profileStatus"),
|
||||
/**
|
||||
* The onboarding completion status
|
||||
*/
|
||||
completedOnboarding: /*#__PURE__*/ v.string<
|
||||
| "complete"
|
||||
| "none"
|
||||
| "playOnboarding"
|
||||
| "profileOnboarding"
|
||||
| (string & {})
|
||||
>(),
|
||||
/**
|
||||
* The timestamp when this status was created
|
||||
*/
|
||||
createdAt: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.datetimeString()),
|
||||
/**
|
||||
* The timestamp when this status was last updated
|
||||
*/
|
||||
updatedAt: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.datetimeString()),
|
||||
}),
|
||||
);
|
||||
|
||||
type main$schematype = typeof _mainSchema;
|
||||
|
||||
export interface mainSchema extends main$schematype {}
|
||||
|
||||
export const mainSchema = _mainSchema as mainSchema;
|
||||
|
||||
export interface Main extends v.InferInput<typeof mainSchema> {}
|
||||
|
||||
declare module "@atcute/lexicons/ambient" {
|
||||
interface Records {
|
||||
"fm.teal.alpha.actor.profileStatus": mainSchema;
|
||||
}
|
||||
}
|
||||
61
src/backend/common/vendor/teal/lexicons/types/fm/teal/alpha/actor/searchActors.ts
vendored
Normal file
61
src/backend/common/vendor/teal/lexicons/types/fm/teal/alpha/actor/searchActors.ts
vendored
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
import type {} from "@atcute/lexicons";
|
||||
import * as v from "@atcute/lexicons/validations";
|
||||
import type {} from "@atcute/lexicons/ambient";
|
||||
import * as FmTealAlphaActorDefs from "./defs.js";
|
||||
|
||||
const _mainSchema = /*#__PURE__*/ v.query("fm.teal.alpha.actor.searchActors", {
|
||||
params: /*#__PURE__*/ v.object({
|
||||
/**
|
||||
* Cursor for pagination
|
||||
*/
|
||||
cursor: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
|
||||
/**
|
||||
* The maximum number of actors to return
|
||||
* @minimum 1
|
||||
* @maximum 25
|
||||
*/
|
||||
limit: /*#__PURE__*/ v.optional(
|
||||
/*#__PURE__*/ v.constrain(/*#__PURE__*/ v.integer(), [
|
||||
/*#__PURE__*/ v.integerRange(1, 25),
|
||||
]),
|
||||
),
|
||||
/**
|
||||
* The search query
|
||||
* @maxLength 640
|
||||
* @maxGraphemes 128
|
||||
*/
|
||||
q: /*#__PURE__*/ v.constrain(/*#__PURE__*/ v.string(), [
|
||||
/*#__PURE__*/ v.stringLength(0, 640),
|
||||
/*#__PURE__*/ v.stringGraphemes(0, 128),
|
||||
]),
|
||||
}),
|
||||
output: {
|
||||
type: "lex",
|
||||
schema: /*#__PURE__*/ v.object({
|
||||
get actors() {
|
||||
return /*#__PURE__*/ v.array(
|
||||
FmTealAlphaActorDefs.miniProfileViewSchema,
|
||||
);
|
||||
},
|
||||
/**
|
||||
* Cursor for pagination
|
||||
*/
|
||||
cursor: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
type main$schematype = typeof _mainSchema;
|
||||
|
||||
export interface mainSchema extends main$schematype {}
|
||||
|
||||
export const mainSchema = _mainSchema as mainSchema;
|
||||
|
||||
export interface $params extends v.InferInput<mainSchema["params"]> {}
|
||||
export interface $output extends v.InferXRPCBodyInput<mainSchema["output"]> {}
|
||||
|
||||
declare module "@atcute/lexicons/ambient" {
|
||||
interface XRPCQueries {
|
||||
"fm.teal.alpha.actor.searchActors": mainSchema;
|
||||
}
|
||||
}
|
||||
36
src/backend/common/vendor/teal/lexicons/types/fm/teal/alpha/actor/status.ts
vendored
Normal file
36
src/backend/common/vendor/teal/lexicons/types/fm/teal/alpha/actor/status.ts
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import type {} from "@atcute/lexicons";
|
||||
import * as v from "@atcute/lexicons/validations";
|
||||
import type {} from "@atcute/lexicons/ambient";
|
||||
import * as FmTealAlphaFeedDefs from "../feed/defs.js";
|
||||
|
||||
const _mainSchema = /*#__PURE__*/ v.record(
|
||||
/*#__PURE__*/ v.literal("self"),
|
||||
/*#__PURE__*/ v.object({
|
||||
$type: /*#__PURE__*/ v.literal("fm.teal.alpha.actor.status"),
|
||||
/**
|
||||
* The RFC 3339 formatted time of the expiry time of the item. If unavailable, default to 10 minutes past the start time.
|
||||
*/
|
||||
expiry: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.datetimeString()),
|
||||
get item() {
|
||||
return FmTealAlphaFeedDefs.playViewSchema;
|
||||
},
|
||||
/**
|
||||
* The RFC 3339 formatted time of when the item was recorded
|
||||
*/
|
||||
time: /*#__PURE__*/ v.datetimeString(),
|
||||
}),
|
||||
);
|
||||
|
||||
type main$schematype = typeof _mainSchema;
|
||||
|
||||
export interface mainSchema extends main$schematype {}
|
||||
|
||||
export const mainSchema = _mainSchema as mainSchema;
|
||||
|
||||
export interface Main extends v.InferInput<typeof mainSchema> {}
|
||||
|
||||
declare module "@atcute/lexicons/ambient" {
|
||||
interface Records {
|
||||
"fm.teal.alpha.actor.status": mainSchema;
|
||||
}
|
||||
}
|
||||
109
src/backend/common/vendor/teal/lexicons/types/fm/teal/alpha/feed/defs.ts
vendored
Normal file
109
src/backend/common/vendor/teal/lexicons/types/fm/teal/alpha/feed/defs.ts
vendored
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
import type {} from "@atcute/lexicons";
|
||||
import * as v from "@atcute/lexicons/validations";
|
||||
|
||||
const _artistSchema = /*#__PURE__*/ v.object({
|
||||
$type: /*#__PURE__*/ v.optional(
|
||||
/*#__PURE__*/ v.literal("fm.teal.alpha.feed.defs#artist"),
|
||||
),
|
||||
/**
|
||||
* The MusicBrainz artist ID URI, formatted as mbid:<uuid>
|
||||
*/
|
||||
artistMbId: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.genericUriString()),
|
||||
/**
|
||||
* The name of the artist
|
||||
* @minLength 1
|
||||
* @maxLength 256
|
||||
* @maxGraphemes 2560
|
||||
*/
|
||||
artistName: /*#__PURE__*/ v.constrain(/*#__PURE__*/ v.string(), [
|
||||
/*#__PURE__*/ v.stringLength(1, 256),
|
||||
/*#__PURE__*/ v.stringGraphemes(0, 2560),
|
||||
]),
|
||||
});
|
||||
const _playViewSchema = /*#__PURE__*/ v.object({
|
||||
$type: /*#__PURE__*/ v.optional(
|
||||
/*#__PURE__*/ v.literal("fm.teal.alpha.feed.defs#playView"),
|
||||
),
|
||||
/**
|
||||
* Array of artists in order of original appearance.
|
||||
*/
|
||||
get artists() {
|
||||
return /*#__PURE__*/ v.array(artistSchema);
|
||||
},
|
||||
/**
|
||||
* The length of the track in seconds
|
||||
*/
|
||||
duration: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.integer()),
|
||||
/**
|
||||
* The ISRC code associated with the recording
|
||||
*/
|
||||
isrc: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
|
||||
/**
|
||||
* The base domain of the music service. e.g. music.apple.com, tidal.com, spotify.com. Defaults to 'local' if not provided.
|
||||
*/
|
||||
musicServiceBaseDomain: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
|
||||
/**
|
||||
* The URL associated with this track
|
||||
*/
|
||||
originUrl: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
|
||||
/**
|
||||
* The unix timestamp of when the track was played
|
||||
*/
|
||||
playedTime: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.datetimeString()),
|
||||
/**
|
||||
* The MusicBrainz recording ID URI of the track, formatted as mbid:<uuid>
|
||||
*/
|
||||
recordingMbId: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.genericUriString()),
|
||||
/**
|
||||
* The MusicBrainz release ID URI, formatted as mbid:<uuid>
|
||||
*/
|
||||
releaseMbId: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.genericUriString()),
|
||||
/**
|
||||
* The name of the release/album
|
||||
* @maxLength 256
|
||||
* @maxGraphemes 2560
|
||||
*/
|
||||
releaseName: /*#__PURE__*/ v.optional(
|
||||
/*#__PURE__*/ v.constrain(/*#__PURE__*/ v.string(), [
|
||||
/*#__PURE__*/ v.stringLength(0, 256),
|
||||
/*#__PURE__*/ v.stringGraphemes(0, 2560),
|
||||
]),
|
||||
),
|
||||
/**
|
||||
* A user-agent style string specifying the user agent. e.g. tealtracker/0.0.1b (Linux; Android 13; SM-A715F). Defaults to 'manual/unknown' if not provided.
|
||||
* @maxLength 256
|
||||
* @maxGraphemes 2560
|
||||
*/
|
||||
submissionClientAgent: /*#__PURE__*/ v.optional(
|
||||
/*#__PURE__*/ v.constrain(/*#__PURE__*/ v.string(), [
|
||||
/*#__PURE__*/ v.stringLength(0, 256),
|
||||
/*#__PURE__*/ v.stringGraphemes(0, 2560),
|
||||
]),
|
||||
),
|
||||
/**
|
||||
* The MusicBrainz ID URI of the track, formatted as mbid:<uuid>
|
||||
*/
|
||||
trackMbId: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.genericUriString()),
|
||||
/**
|
||||
* The name of the track
|
||||
* @minLength 1
|
||||
* @maxLength 256
|
||||
* @maxGraphemes 2560
|
||||
*/
|
||||
trackName: /*#__PURE__*/ v.constrain(/*#__PURE__*/ v.string(), [
|
||||
/*#__PURE__*/ v.stringLength(1, 256),
|
||||
/*#__PURE__*/ v.stringGraphemes(0, 2560),
|
||||
]),
|
||||
});
|
||||
|
||||
type artist$schematype = typeof _artistSchema;
|
||||
type playView$schematype = typeof _playViewSchema;
|
||||
|
||||
export interface artistSchema extends artist$schematype {}
|
||||
export interface playViewSchema extends playView$schematype {}
|
||||
|
||||
export const artistSchema = _artistSchema as artistSchema;
|
||||
export const playViewSchema = _playViewSchema as playViewSchema;
|
||||
|
||||
export interface Artist extends v.InferInput<typeof artistSchema> {}
|
||||
export interface PlayView extends v.InferInput<typeof playViewSchema> {}
|
||||
44
src/backend/common/vendor/teal/lexicons/types/fm/teal/alpha/feed/getActorFeed.ts
vendored
Normal file
44
src/backend/common/vendor/teal/lexicons/types/fm/teal/alpha/feed/getActorFeed.ts
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import type {} from "@atcute/lexicons";
|
||||
import * as v from "@atcute/lexicons/validations";
|
||||
import type {} from "@atcute/lexicons/ambient";
|
||||
import * as FmTealAlphaFeedDefs from "./defs.js";
|
||||
|
||||
const _mainSchema = /*#__PURE__*/ v.query("fm.teal.alpha.feed.getActorFeed", {
|
||||
params: /*#__PURE__*/ v.object({
|
||||
/**
|
||||
* The author's DID for the play
|
||||
*/
|
||||
authorDID: /*#__PURE__*/ v.actorIdentifierString(),
|
||||
/**
|
||||
* The cursor to start the query from
|
||||
*/
|
||||
cursor: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
|
||||
/**
|
||||
* The upper limit of tracks to get per request. Default is 20, max is 50.
|
||||
*/
|
||||
limit: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.integer()),
|
||||
}),
|
||||
output: {
|
||||
type: "lex",
|
||||
schema: /*#__PURE__*/ v.object({
|
||||
get plays() {
|
||||
return /*#__PURE__*/ v.array(FmTealAlphaFeedDefs.playViewSchema);
|
||||
},
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
type main$schematype = typeof _mainSchema;
|
||||
|
||||
export interface mainSchema extends main$schematype {}
|
||||
|
||||
export const mainSchema = _mainSchema as mainSchema;
|
||||
|
||||
export interface $params extends v.InferInput<mainSchema["params"]> {}
|
||||
export interface $output extends v.InferXRPCBodyInput<mainSchema["output"]> {}
|
||||
|
||||
declare module "@atcute/lexicons/ambient" {
|
||||
interface XRPCQueries {
|
||||
"fm.teal.alpha.feed.getActorFeed": mainSchema;
|
||||
}
|
||||
}
|
||||
40
src/backend/common/vendor/teal/lexicons/types/fm/teal/alpha/feed/getPlay.ts
vendored
Normal file
40
src/backend/common/vendor/teal/lexicons/types/fm/teal/alpha/feed/getPlay.ts
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import type {} from "@atcute/lexicons";
|
||||
import * as v from "@atcute/lexicons/validations";
|
||||
import type {} from "@atcute/lexicons/ambient";
|
||||
import * as FmTealAlphaFeedDefs from "./defs.js";
|
||||
|
||||
const _mainSchema = /*#__PURE__*/ v.query("fm.teal.alpha.feed.getPlay", {
|
||||
params: /*#__PURE__*/ v.object({
|
||||
/**
|
||||
* The author's DID for the play
|
||||
*/
|
||||
authorDID: /*#__PURE__*/ v.actorIdentifierString(),
|
||||
/**
|
||||
* The record key of the play
|
||||
*/
|
||||
rkey: /*#__PURE__*/ v.string(),
|
||||
}),
|
||||
output: {
|
||||
type: "lex",
|
||||
schema: /*#__PURE__*/ v.object({
|
||||
get play() {
|
||||
return FmTealAlphaFeedDefs.playViewSchema;
|
||||
},
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
type main$schematype = typeof _mainSchema;
|
||||
|
||||
export interface mainSchema extends main$schematype {}
|
||||
|
||||
export const mainSchema = _mainSchema as mainSchema;
|
||||
|
||||
export interface $params extends v.InferInput<mainSchema["params"]> {}
|
||||
export interface $output extends v.InferXRPCBodyInput<mainSchema["output"]> {}
|
||||
|
||||
declare module "@atcute/lexicons/ambient" {
|
||||
interface XRPCQueries {
|
||||
"fm.teal.alpha.feed.getPlay": mainSchema;
|
||||
}
|
||||
}
|
||||
138
src/backend/common/vendor/teal/lexicons/types/fm/teal/alpha/feed/play.ts
vendored
Normal file
138
src/backend/common/vendor/teal/lexicons/types/fm/teal/alpha/feed/play.ts
vendored
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
import type {} from "@atcute/lexicons";
|
||||
import * as v from "@atcute/lexicons/validations";
|
||||
import type {} from "@atcute/lexicons/ambient";
|
||||
import * as FmTealAlphaFeedDefs from "./defs.js";
|
||||
|
||||
const _mainSchema = /*#__PURE__*/ v.record(
|
||||
/*#__PURE__*/ v.tidString(),
|
||||
/*#__PURE__*/ v.object({
|
||||
$type: /*#__PURE__*/ v.literal("fm.teal.alpha.feed.play"),
|
||||
/**
|
||||
* DEPRECATED: USE 'artists' INSTEAD. Array of Musicbrainz artist IDs.
|
||||
* @deprecated
|
||||
*/
|
||||
artistMbIds: /*#__PURE__*/ v.optional(
|
||||
/*#__PURE__*/ v.array(/*#__PURE__*/ v.string()),
|
||||
),
|
||||
/**
|
||||
* DEPRECATED: USE 'artists' INSTEAD. Array of artist names in order of original appearance.
|
||||
* @deprecated
|
||||
*/
|
||||
artistNames: /*#__PURE__*/ v.optional(
|
||||
/*#__PURE__*/ v.array(
|
||||
/*#__PURE__*/ v.constrain(/*#__PURE__*/ v.string(), [
|
||||
/*#__PURE__*/ v.stringLength(1, 256),
|
||||
/*#__PURE__*/ v.stringGraphemes(0, 2560),
|
||||
]),
|
||||
),
|
||||
),
|
||||
/**
|
||||
* Array of artists in order of original appearance.
|
||||
*/
|
||||
get artists() {
|
||||
return /*#__PURE__*/ v.optional(
|
||||
/*#__PURE__*/ v.array(FmTealAlphaFeedDefs.artistSchema),
|
||||
);
|
||||
},
|
||||
/**
|
||||
* The length of the track in seconds
|
||||
*/
|
||||
duration: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.integer()),
|
||||
/**
|
||||
* The ISRC code associated with the recording
|
||||
*/
|
||||
isrc: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
|
||||
/**
|
||||
* The base domain of the music service. e.g. music.apple.com, tidal.com, spotify.com. Defaults to 'local' if unavailable or not provided.
|
||||
*/
|
||||
musicServiceBaseDomain: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
|
||||
/**
|
||||
* The URL associated with this track
|
||||
*/
|
||||
originUrl: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
|
||||
/**
|
||||
* The unix timestamp of when the track was played
|
||||
*/
|
||||
playedTime: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.datetimeString()),
|
||||
/**
|
||||
* The MusicBrainz recording ID URI of the track, formatted as mbid:<uuid>
|
||||
*/
|
||||
recordingMbId: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.genericUriString()),
|
||||
/**
|
||||
* Distinguishing information for release variants (e.g. 'Deluxe Edition', 'Remastered', '2023 Remaster', 'Special Edition'). Used to differentiate between different versions of the same base release while maintaining grouping capabilities.
|
||||
* @maxLength 128
|
||||
* @maxGraphemes 1280
|
||||
*/
|
||||
releaseDiscriminant: /*#__PURE__*/ v.optional(
|
||||
/*#__PURE__*/ v.constrain(/*#__PURE__*/ v.string(), [
|
||||
/*#__PURE__*/ v.stringLength(0, 128),
|
||||
/*#__PURE__*/ v.stringGraphemes(0, 1280),
|
||||
]),
|
||||
),
|
||||
/**
|
||||
* The MusicBrainz release ID URI, formatted as mbid:<uuid>
|
||||
*/
|
||||
releaseMbId: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.genericUriString()),
|
||||
/**
|
||||
* The name of the release/album
|
||||
* @maxLength 256
|
||||
* @maxGraphemes 2560
|
||||
*/
|
||||
releaseName: /*#__PURE__*/ v.optional(
|
||||
/*#__PURE__*/ v.constrain(/*#__PURE__*/ v.string(), [
|
||||
/*#__PURE__*/ v.stringLength(0, 256),
|
||||
/*#__PURE__*/ v.stringGraphemes(0, 2560),
|
||||
]),
|
||||
),
|
||||
/**
|
||||
* A metadata string specifying the user agent where the format is `<app-identifier>/<version> (<kernel/OS-base>; <platform/OS-version>; <device-model>)`. If string is provided, only `app-identifier` and `version` are required. `app-identifier` is recommended to be in reverse dns format. Defaults to 'manual/unknown' if unavailable or not provided.
|
||||
* @maxLength 256
|
||||
* @maxGraphemes 2560
|
||||
*/
|
||||
submissionClientAgent: /*#__PURE__*/ v.optional(
|
||||
/*#__PURE__*/ v.constrain(/*#__PURE__*/ v.string(), [
|
||||
/*#__PURE__*/ v.stringLength(0, 256),
|
||||
/*#__PURE__*/ v.stringGraphemes(0, 2560),
|
||||
]),
|
||||
),
|
||||
/**
|
||||
* Distinguishing information for track variants (e.g. 'Acoustic Version', 'Live at Wembley', 'Radio Edit', 'Demo'). Used to differentiate between different versions of the same base track while maintaining grouping capabilities.
|
||||
* @maxLength 128
|
||||
* @maxGraphemes 1280
|
||||
*/
|
||||
trackDiscriminant: /*#__PURE__*/ v.optional(
|
||||
/*#__PURE__*/ v.constrain(/*#__PURE__*/ v.string(), [
|
||||
/*#__PURE__*/ v.stringLength(0, 128),
|
||||
/*#__PURE__*/ v.stringGraphemes(0, 1280),
|
||||
]),
|
||||
),
|
||||
/**
|
||||
* The MusicBrainz ID URI of the track, formatted as mbid:<uuid>
|
||||
*/
|
||||
trackMbId: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.genericUriString()),
|
||||
/**
|
||||
* The name of the track
|
||||
* @minLength 1
|
||||
* @maxLength 256
|
||||
* @maxGraphemes 2560
|
||||
*/
|
||||
trackName: /*#__PURE__*/ v.constrain(/*#__PURE__*/ v.string(), [
|
||||
/*#__PURE__*/ v.stringLength(1, 256),
|
||||
/*#__PURE__*/ v.stringGraphemes(0, 2560),
|
||||
]),
|
||||
}),
|
||||
);
|
||||
|
||||
type main$schematype = typeof _mainSchema;
|
||||
|
||||
export interface mainSchema extends main$schematype {}
|
||||
|
||||
export const mainSchema = _mainSchema as mainSchema;
|
||||
|
||||
export interface Main extends v.InferInput<typeof mainSchema> {}
|
||||
|
||||
declare module "@atcute/lexicons/ambient" {
|
||||
interface Records {
|
||||
"fm.teal.alpha.feed.play": mainSchema;
|
||||
}
|
||||
}
|
||||
|
|
@ -12,8 +12,8 @@ import { FormatPlayObjectOptions, CALCULATED_PLAYER_STATUSES, ReportedPlayerStat
|
|||
import { playToListenPayload } from '../common/vendor/listenbrainz/lzUtils.js';
|
||||
import { Notifiers } from "../notifier/Notifiers.js";
|
||||
|
||||
import AbstractScrobbleClient, { nowPlayingUpdateByPlayDuration, shouldClearNPStatus } from "./AbstractScrobbleClient.js";
|
||||
import { ScrobbleRecord, TealClientConfig } from "../common/infrastructure/config/client/tealfm.js";
|
||||
import { nowPlayingUpdateByPlayDuration, shouldClearNPStatus } from "./AbstractScrobbleClient.js";
|
||||
import { TealClientConfig } from "../common/infrastructure/config/client/tealfm.js";
|
||||
import { BlueSkyAppApiClient } from "../common/vendor/bluesky/BlueSkyAppApiClient.js";
|
||||
import { BlueSkyOauthApiClient } from "../common/vendor/bluesky/BlueSkyOauthApiClient.js";
|
||||
import { AbstractBlueSkyApiClient, nowPlayingExpirationDuration, playToRecord, playToStatusRecord, recordToPlay } from "../common/vendor/bluesky/AbstractBlueSkyApiClient.js";
|
||||
|
|
@ -23,6 +23,7 @@ import AbstractHistoricalScrobbleClient from "./AbstractHistoricalScrobbleClient
|
|||
import { fromStream } from '@atcute/repo';
|
||||
import { playToRepositoryCreatePlayHistoricalOpts, RepositoryCreatePlayHistoricalOpts } from "../common/database/drizzle/repositories/PlayHistoricalRepository.js";
|
||||
import { isAbortError } from "abort-controller-x";
|
||||
import { FmTealAlphaFeedPlay } from "../common/vendor/teal/lexicons/index.js";
|
||||
|
||||
export default class TealScrobbler extends AbstractHistoricalScrobbleClient {
|
||||
|
||||
|
|
@ -234,7 +235,7 @@ export default class TealScrobbler extends AbstractHistoricalScrobbleClient {
|
|||
if(entry.collection === 'fm.teal.alpha.feed.play') {
|
||||
let play: PlayObject;
|
||||
try {
|
||||
play = recordToPlay(entry.record as ScrobbleRecord, {
|
||||
play = recordToPlay(entry.record as FmTealAlphaFeedPlay.Main, {
|
||||
web: did !== undefined ? `at://did:plc:${did}/fm.teal.alpha.feed.play/${entry.rkey}` : undefined,
|
||||
playId: entry.rkey,
|
||||
user: did
|
||||
|
|
|
|||
|
|
@ -11,13 +11,14 @@ import { sortByNewestPlayDate } from './PlayUtils.js';
|
|||
import { CALCULATED_PLAYER_STATUSES, NO_DEVICE, NO_USER, PlayerStateDataMaybePlay, PlayPlatformId, REPORTED_PLAYER_STATUSES, SINGLE_USER_PLATFORM_ID } from '../backend/common/infrastructure/Atomic.js';
|
||||
import { arrayListAnd, artistNamesToCredits } from './StringUtils.js';
|
||||
import { findDelimiters } from "./StringUtils.js";
|
||||
import { ListRecord, ScrobbleRecord } from '../backend/common/infrastructure/config/client/tealfm.js';
|
||||
import { ListRecord } from '../backend/common/infrastructure/config/client/tealfm.js';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { LastFMTrackObject } from '../backend/common/vendor/LastfmApiClient.js';
|
||||
import { MarkOptional } from 'ts-essentials';
|
||||
import { defaultLifecycle } from '../backend/utils/PlayTransformUtils.js';
|
||||
import clone from 'clone';
|
||||
import { removeUndefinedKeys } from '../backend/utils.js';
|
||||
import { FmTealAlphaFeedPlay } from '../backend/common/vendor/teal/lexicons/index.js';
|
||||
|
||||
dayjs.extend(utc)
|
||||
dayjs.extend(isBetween);
|
||||
|
|
@ -476,7 +477,7 @@ export const generateMbid = (): MBID => {
|
|||
export const generateTealPlayRecord = (opts: {
|
||||
withMbids?: boolean,
|
||||
withIsrc?: boolean
|
||||
} = {}): [ListRecord<ScrobbleRecord>, { did: string, tid: string }] => {
|
||||
} = {}): [ListRecord<FmTealAlphaFeedPlay.Main>, { did: string, tid: string }] => {
|
||||
const {
|
||||
withMbids = true,
|
||||
withIsrc = true,
|
||||
|
|
@ -488,12 +489,12 @@ export const generateTealPlayRecord = (opts: {
|
|||
const did = nanoid(12);
|
||||
const tid = nanoid(10);
|
||||
|
||||
const rec: ListRecord<ScrobbleRecord> = {
|
||||
const rec: ListRecord<FmTealAlphaFeedPlay.Main> = {
|
||||
uri: `at://did:plc:${did}/fm.teal.alpha.feed.play/${tid}`,
|
||||
cid: nanoid(12),
|
||||
value: {
|
||||
'$type': 'fm.teal.alpha.feed.play',
|
||||
artists: artists.map(x => withMbids ? { artistName: x, artistMbId: generateMbid() } : { artistName: x }),
|
||||
artists: artists.map(x => withMbids ? { artistName: x, artistMbId: `mbid:${generateMbid()}` } : { artistName: x }),
|
||||
releaseName: faker.music.album(),
|
||||
trackName: faker.music.songName(),
|
||||
playedTime: now.toISOString(),
|
||||
|
|
@ -503,8 +504,8 @@ export const generateTealPlayRecord = (opts: {
|
|||
}
|
||||
|
||||
if (withMbids) {
|
||||
rec.value.releaseMbId = generateMbid();
|
||||
rec.value.recordingMbId = generateMbid();
|
||||
rec.value.releaseMbId = `mbid:${generateMbid()}`;
|
||||
rec.value.recordingMbId = `mbid:${generateMbid()}`;
|
||||
}
|
||||
|
||||
if (withIsrc) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue