-
Notifications
You must be signed in to change notification settings - Fork 37
Expand file tree
/
Copy pathAbstractBlueSkyApiClient.ts
More file actions
123 lines (107 loc) · 4.51 KB
/
AbstractBlueSkyApiClient.ts
File metadata and controls
123 lines (107 loc) · 4.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import { getRoot } from "../../../ioc.js";
import { AbstractApiOptions } from "../../infrastructure/Atomic.js";
import { ListRecord, ScrobbleRecord, TealClientData } from "../../infrastructure/config/client/tealfm.js";
import AbstractApiClient from "../AbstractApiClient.js";
import { Agent } from "@atproto/api";
import { MSCache } from "../../Cache.js";
import { PlayObject } from "../../../../core/Atomic.js";
import { musicServiceToCononical } from "../ListenbrainzApiClient.js";
import { parseRegexSingle } from "@foxxmd/regex-buddy-core";
import { RecordOptions } from "../../infrastructure/config/client/tealfm.js";
import dayjs from "dayjs";
import { getScrobbleTsSOCDateWithContext } from "../../../utils/TimeUtils.js";
export abstract class AbstractBlueSkyApiClient extends AbstractApiClient {
declare config: TealClientData;
agent!: Agent;
cache: MSCache;
constructor(name: any, config: TealClientData, options: AbstractApiOptions) {
super('blueSky', name, config, options);
this.cache = getRoot().items.cache();
}
abstract initClient(): Promise<void>;
abstract restoreSession(): Promise<boolean>;
async createScrobbleRecord(record: ScrobbleRecord): Promise<void> {
try {
await this.agent.com.atproto.repo.createRecord({
repo: this.agent.sessionManager.did,
collection: "fm.teal.alpha.feed.play",
record
});
} catch (e) {
throw new Error(`Failed to create record`, { cause: e });
}
}
async listScrobbleRecord(limit: number = 20): Promise<ListRecord<ScrobbleRecord>[]> {
try {
const response = await this.agent.com.atproto.repo.listRecords({
repo: this.agent.sessionManager.did,
collection: "fm.teal.alpha.feed.play",
limit
});
return response.data.records as unknown as ListRecord<ScrobbleRecord>[];
} catch (e) {
throw new Error(`Failed to create record`, { cause: e });
}
}
}
export const playToRecord = (play: PlayObject): ScrobbleRecord => {
const record: ScrobbleRecord = {
$type: "fm.teal.alpha.feed.play",
trackName: play.data.track,
artists: play.data.artists.map((x, i) => ({
artistName: x,
...(play.data.meta?.brainz?.artist?.[i]
? { artistMbId: play.data.meta.brainz.artist[i] }
: {})
})),
duration: Math.round(play.data.duration),
playedTime: getScrobbleTsSOCDateWithContext(play)[0].toISOString(),
releaseName: play.data.album,
submissionClientAgent: `multi-scrobbler/${getRoot().items.version}`,
musicServiceBaseDomain: musicServiceToCononical(play.meta.musicService) ?? play.meta.musicService,
isrc: play.data.isrc,
recordingMbId: play.data.meta?.brainz?.track,
releaseMbId: play.data.meta?.brainz?.album
};
return record;
};export const listRecordToPlay = (listRecord: ListRecord<ScrobbleRecord>): PlayObject => {
const opts: RecordOptions = {};
const uriRes = parseRegexSingle(ATPROTO_URI_REGEX, listRecord.uri);
if (uriRes !== undefined) {
opts.web = `https://atproto.at/viewer?uri=${uriRes.named.resource}`;
opts.playId = uriRes.named.tid;
opts.user = uriRes.named.did;
}
return recordToPlay(listRecord.value, opts);
};
export const recordToPlay = (record: ScrobbleRecord, options: RecordOptions = {}): PlayObject => {
const play: PlayObject = {
data: {
track: record.trackName,
artists: record.artists.filter(x => x.artistName !== undefined).map(x => x.artistName),
duration: record.duration,
playDate: dayjs(record.playedTime),
album: record.releaseName,
isrc: record.isrc,
meta: {
brainz: {
track: record.recordingMbId,
album: record.releaseMbId,
artist: record.artists.filter(x => x.artistMbId !== undefined).map(x => x.artistMbId)
}
}
},
meta: {
source: 'tealfm',
parsedFrom: 'history',
musicService: record.musicServiceBaseDomain,
playId: options.playId,
url: {
web: options.web
},
user: options.user
}
};
return play;
};
export const ATPROTO_URI_REGEX = new RegExp(/at:\/\/(?<resource>(?<did>did.*?)\/fm.teal.alpha.feed.play\/(?<tid>.*))/);