mirror of
https://github.com/austinried/subtracks.git
synced 2025-12-27 00:59:28 +01:00
first pass api client
This commit is contained in:
parent
1b78acd5fa
commit
b51d0eb685
12
App.tsx
12
App.tsx
@ -11,3 +11,15 @@ const App = () => {
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
||||
import { SubsonicApiClient } from './src/subsonic/api';
|
||||
import md5 from 'md5';
|
||||
|
||||
const password = 'test';
|
||||
const salt = 'salty';
|
||||
const token = md5(password + salt);
|
||||
|
||||
const client = new SubsonicApiClient('http://navidrome.home', 'austin', token, salt);
|
||||
|
||||
client.ping();
|
||||
client.getArtists();
|
||||
|
||||
82
package-lock.json
generated
82
package-lock.json
generated
@ -8,17 +8,21 @@
|
||||
"name": "subsonify",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"md5": "^2.3.0",
|
||||
"react": "17.0.1",
|
||||
"react-native": "0.64.1",
|
||||
"recoil": "^0.3.1"
|
||||
"recoil": "^0.3.1",
|
||||
"xmldom": "^0.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.12.9",
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@react-native-community/eslint-config": "^2.0.0",
|
||||
"@types/jest": "^26.0.23",
|
||||
"@types/md5": "^2.3.0",
|
||||
"@types/react-native": "^0.64.5",
|
||||
"@types/react-test-renderer": "^16.9.2",
|
||||
"@types/xmldom": "^0.1.30",
|
||||
"babel-jest": "^26.6.3",
|
||||
"eslint": "^7.14.0",
|
||||
"jest": "^26.6.3",
|
||||
@ -3071,6 +3075,15 @@
|
||||
"integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/md5": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/md5/-/md5-2.3.0.tgz",
|
||||
"integrity": "sha512-556YJ7ejzxIqSSxzyGGpctuZOarNZJt/zlEkhmmDc1f/slOEANHuwu2ZX7YaZ40rMiWoxt8GvAhoDpW1cmSy6A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "15.12.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.2.tgz",
|
||||
@ -3146,6 +3159,12 @@
|
||||
"integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/xmldom": {
|
||||
"version": "0.1.30",
|
||||
"resolved": "https://registry.npmjs.org/@types/xmldom/-/xmldom-0.1.30.tgz",
|
||||
"integrity": "sha512-edqgAFXMEtVvaBZ3YnhamvmrHjoYpuxETmnb0lbTZmf/dXpAsO9ZKotUO4K2rn2SIZBDFCMOuA7fOe0H6dRZcA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/yargs": {
|
||||
"version": "15.0.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz",
|
||||
@ -4222,6 +4241,14 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/charenc": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
|
||||
"integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/ci-info": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
|
||||
@ -4625,6 +4652,14 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/crypt": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
|
||||
"integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/cssom": {
|
||||
"version": "0.4.4",
|
||||
"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz",
|
||||
@ -9108,6 +9143,16 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/md5": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
|
||||
"integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==",
|
||||
"dependencies": {
|
||||
"charenc": "0.0.2",
|
||||
"crypt": "0.0.2",
|
||||
"is-buffer": "~1.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/merge-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||
@ -15576,6 +15621,15 @@
|
||||
"integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/md5": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/md5/-/md5-2.3.0.tgz",
|
||||
"integrity": "sha512-556YJ7ejzxIqSSxzyGGpctuZOarNZJt/zlEkhmmDc1f/slOEANHuwu2ZX7YaZ40rMiWoxt8GvAhoDpW1cmSy6A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "15.12.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.2.tgz",
|
||||
@ -15653,6 +15707,12 @@
|
||||
"integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/xmldom": {
|
||||
"version": "0.1.30",
|
||||
"resolved": "https://registry.npmjs.org/@types/xmldom/-/xmldom-0.1.30.tgz",
|
||||
"integrity": "sha512-edqgAFXMEtVvaBZ3YnhamvmrHjoYpuxETmnb0lbTZmf/dXpAsO9ZKotUO4K2rn2SIZBDFCMOuA7fOe0H6dRZcA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/yargs": {
|
||||
"version": "15.0.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz",
|
||||
@ -16436,6 +16496,11 @@
|
||||
"integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==",
|
||||
"dev": true
|
||||
},
|
||||
"charenc": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
|
||||
"integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc="
|
||||
},
|
||||
"ci-info": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
|
||||
@ -16770,6 +16835,11 @@
|
||||
"which": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"crypt": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
|
||||
"integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs="
|
||||
},
|
||||
"cssom": {
|
||||
"version": "0.4.4",
|
||||
"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz",
|
||||
@ -20135,6 +20205,16 @@
|
||||
"object-visit": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"md5": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
|
||||
"integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==",
|
||||
"requires": {
|
||||
"charenc": "0.0.2",
|
||||
"crypt": "0.0.2",
|
||||
"is-buffer": "~1.1.6"
|
||||
}
|
||||
},
|
||||
"merge-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||
|
||||
@ -10,17 +10,21 @@
|
||||
"lint": "eslint . --ext .js,.jsx,.ts,.tsx"
|
||||
},
|
||||
"dependencies": {
|
||||
"md5": "^2.3.0",
|
||||
"react": "17.0.1",
|
||||
"react-native": "0.64.1",
|
||||
"recoil": "^0.3.1"
|
||||
"recoil": "^0.3.1",
|
||||
"xmldom": "^0.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.12.9",
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@react-native-community/eslint-config": "^2.0.0",
|
||||
"@types/jest": "^26.0.23",
|
||||
"@types/md5": "^2.3.0",
|
||||
"@types/react-native": "^0.64.5",
|
||||
"@types/react-test-renderer": "^16.9.2",
|
||||
"@types/xmldom": "^0.1.30",
|
||||
"babel-jest": "^26.6.3",
|
||||
"eslint": "^7.14.0",
|
||||
"jest": "^26.6.3",
|
||||
|
||||
106
src/subsonic/api.ts
Normal file
106
src/subsonic/api.ts
Normal file
@ -0,0 +1,106 @@
|
||||
import { DOMParser } from 'xmldom';
|
||||
|
||||
export class SubsonicApiClient {
|
||||
public address: string;
|
||||
public username: string;
|
||||
|
||||
private params: URLSearchParams
|
||||
|
||||
constructor(address: string, username: string, token: string, salt: string) {
|
||||
this.address = address;
|
||||
this.username = username;
|
||||
|
||||
this.params = new URLSearchParams();
|
||||
this.params.append('u', username);
|
||||
this.params.append('t', token);
|
||||
this.params.append('s', salt);
|
||||
this.params.append('v', '1.15.0');
|
||||
this.params.append('c', 'subsonify-cool-unique-app-string')
|
||||
}
|
||||
|
||||
private async apiRequest(method: string, params?: URLSearchParams): Promise<Document> {
|
||||
const url = `${this.address}/rest/${method}?${(params || this.params).toString()}`;
|
||||
|
||||
const response = await fetch(url);
|
||||
const text = await response.text();
|
||||
|
||||
console.log(text);
|
||||
|
||||
const xml = new DOMParser().parseFromString(text);
|
||||
if (xml.documentElement.getAttribute('status') !== 'ok') {
|
||||
throw new SubsonicApiException();
|
||||
}
|
||||
|
||||
return xml;
|
||||
}
|
||||
|
||||
public async ping(): Promise<SubsonicResponse<null>> {
|
||||
const xml = await this.apiRequest('ping');
|
||||
const response = new SubsonicResponse<null>(xml, null);
|
||||
|
||||
console.log(response.status);
|
||||
console.log(response.version);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public async getArtists(): Promise<SubsonicResponse<ArtistID3Response>> {
|
||||
const xml = await this.apiRequest('getArtists');
|
||||
const data = new ArtistID3Response(xml);
|
||||
const response = new SubsonicResponse<ArtistID3Response>(xml, data);
|
||||
|
||||
console.log(response.status);
|
||||
console.log(response.version);
|
||||
console.log(response.data.artists);
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
class SubsonicApiException {
|
||||
|
||||
}
|
||||
|
||||
type ResponseStatus = 'ok' | 'failed';
|
||||
|
||||
class SubsonicResponse<T> {
|
||||
public status: ResponseStatus;
|
||||
public version: string;
|
||||
public data: T;
|
||||
|
||||
constructor(xml: Document, data: T) {
|
||||
this.data = data;
|
||||
this.status = xml.documentElement.getAttribute('status') as ResponseStatus;
|
||||
this.version = xml.documentElement.getAttribute('version') as string;
|
||||
}
|
||||
}
|
||||
|
||||
interface ArtistID3 {
|
||||
id: string;
|
||||
name: string;
|
||||
coverArt?: string;
|
||||
albumCount: number;
|
||||
starred?: Date;
|
||||
}
|
||||
|
||||
class ArtistID3Response {
|
||||
public ignoredArticles: string;
|
||||
public artists: ArtistID3[] = [];
|
||||
|
||||
constructor(xml: Document) {
|
||||
this.ignoredArticles = xml.getElementsByTagName('artists')[0].getAttribute('ignoredArticles') as string;
|
||||
|
||||
const artistElements = xml.getElementsByTagName('artist');
|
||||
for (let i = 0; i < artistElements.length; i++) {
|
||||
const a = artistElements[i];
|
||||
|
||||
this.artists.push({
|
||||
id: a.getAttribute('id') as string,
|
||||
name: a.getAttribute('name') as string,
|
||||
coverArt: a.getAttribute('coverArt') || undefined,
|
||||
albumCount: parseInt(a.getAttribute('albumCount') as string),
|
||||
starred: a.getAttribute('starred') ? new Date(a.getAttribute('starred') as string) : undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user