|
|
@ -1,11 +1,120 @@ |
|
|
|
import axios, { AxiosInstance } from 'axios'; |
|
|
|
|
|
|
|
export interface IAnkiConnectActions |
|
|
|
extends Record< |
|
|
|
string, |
|
|
|
{ |
|
|
|
params?: Record<string, unknown>; |
|
|
|
result: unknown; |
|
|
|
} |
|
|
|
> { |
|
|
|
// Deck Actions
|
|
|
|
deckNames: { |
|
|
|
result: string[]; |
|
|
|
}; |
|
|
|
getDecks: { |
|
|
|
params: { |
|
|
|
cards: number[]; |
|
|
|
}; |
|
|
|
result: { |
|
|
|
[deckName: string]: number[]; |
|
|
|
}; |
|
|
|
}; |
|
|
|
changeDeck: { |
|
|
|
params: { |
|
|
|
cards: number[]; |
|
|
|
deck: string; |
|
|
|
}; |
|
|
|
result: null; |
|
|
|
}; |
|
|
|
|
|
|
|
// Media Actions
|
|
|
|
storeMediaFile: { |
|
|
|
params: ( |
|
|
|
| { |
|
|
|
/** |
|
|
|
* Specified base64-encoded contents |
|
|
|
*/ |
|
|
|
data: string; |
|
|
|
} |
|
|
|
| { |
|
|
|
path: string; |
|
|
|
} |
|
|
|
| { |
|
|
|
url: string; |
|
|
|
} |
|
|
|
) & { |
|
|
|
/** |
|
|
|
* To prevent Anki from removing files not used by any cards (e.g. for configuration files), |
|
|
|
* prefix the filename with an underscore. |
|
|
|
*/ |
|
|
|
filename: string; |
|
|
|
/** |
|
|
|
* Any existing file with the same name is deleted by default. |
|
|
|
* Set `deleteExisting` to `false` to prevent that by letting Anki give the new file a non-conflicting name. |
|
|
|
*/ |
|
|
|
deleteExisting?: boolean; |
|
|
|
}; |
|
|
|
result: string; |
|
|
|
}; |
|
|
|
retrieveMediaFile: { |
|
|
|
/** |
|
|
|
* Retrieves the base64-encoded contents of the specified file, returning `false` if the file does not exist. |
|
|
|
*/ |
|
|
|
params: { |
|
|
|
filename: string; |
|
|
|
}; |
|
|
|
result: string | false; |
|
|
|
}; |
|
|
|
getMediaFilesNames: { |
|
|
|
/** |
|
|
|
* Gets the names of media files matched the pattern. Returning all names by default. |
|
|
|
*/ |
|
|
|
params: { |
|
|
|
pattern: string; |
|
|
|
}; |
|
|
|
result: string[]; |
|
|
|
}; |
|
|
|
deleteMediaFile: { |
|
|
|
params: { |
|
|
|
filename: string; |
|
|
|
}; |
|
|
|
result: null; |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
export class AnkiConnect { |
|
|
|
$axios: AxiosInstance; |
|
|
|
|
|
|
|
constructor(public url = 'http://localhost:8765') { |
|
|
|
constructor(public url = 'http://localhost:8765', public version = 6) { |
|
|
|
this.$axios = axios.create({ |
|
|
|
baseURL: url, |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
async api<A extends keyof IAnkiConnectActions>( |
|
|
|
action: A, |
|
|
|
params: IAnkiConnectActions[A]['params'], |
|
|
|
version = this.version, |
|
|
|
): Promise<IAnkiConnectActions[A]['result']> { |
|
|
|
const { data: response } = await this.$axios.post<{ |
|
|
|
result: any; |
|
|
|
error: string | null; |
|
|
|
}>('/', { action, params, version }); |
|
|
|
|
|
|
|
if (Object.getOwnPropertyNames(response).length != 2) { |
|
|
|
throw 'response has an unexpected number of fields'; |
|
|
|
} |
|
|
|
if (!response.hasOwnProperty('error')) { |
|
|
|
throw 'response is missing required error field'; |
|
|
|
} |
|
|
|
if (!response.hasOwnProperty('result')) { |
|
|
|
throw 'response is missing required result field'; |
|
|
|
} |
|
|
|
if (response.error) { |
|
|
|
throw response.error; |
|
|
|
} |
|
|
|
|
|
|
|
return response.result; |
|
|
|
} |
|
|
|
} |