@souptik/immich
Version:
705 lines (704 loc) • 32.9 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const axios_1 = __importDefault(require("axios"));
const cliProgress = __importStar(require("cli-progress"));
const commander_1 = require("commander");
const fdir_1 = require("fdir");
const form_data_1 = __importDefault(require("form-data"));
const fs = __importStar(require("fs"));
const promises_1 = require("fs/promises");
const path = __importStar(require("path"));
const readline = __importStar(require("readline"));
const si = __importStar(require("systeminformation"));
// GLOBAL
const chalk_1 = __importDefault(require("chalk"));
const mime = __importStar(require("mime-types"));
const moment_1 = __importDefault(require("moment"));
const p_limit_1 = __importDefault(require("p-limit"));
const package_json_1 = __importDefault(require("../package.json"));
const log = console.log;
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
let errorAssets = [];
const SUPPORTED_MIME = [
// IMAGES
'image/heif',
'image/heic',
'image/jpeg',
'image/png',
'image/jpg',
'image/gif',
'image/heic',
'image/heif',
'image/dng',
'image/x-adobe-dng',
'image/webp',
'image/tiff',
'image/nef',
'image/x-nikon-nef',
// VIDEO
'video/mp4',
'video/webm',
'video/quicktime',
'video/x-msvideo',
'video/3gpp',
];
commander_1.program.name('immich').description('Immich command line interface').version(package_json_1.default.version);
commander_1.program
.command('upload')
.description('Upload assets to an Immich instance')
.usage('upload [options] <paths...>')
.addOption(new commander_1.Option('-k, --key <value>', 'API Key').env('IMMICH_API_KEY'))
.addOption(new commander_1.Option('-s, --server <value>', 'Immich server address (http://<your-ip>:2283/api or https://<your-domain>/api)').env('IMMICH_SERVER_ADDRESS'))
.addOption(new commander_1.Option('-r, --recursive', 'Recursive').env('IMMICH_RECURSIVE').default(false))
.addOption(new commander_1.Option('-y, --yes', 'Assume yes on all interactive prompts').env('IMMICH_ASSUME_YES'))
.addOption(new commander_1.Option('-da, --delete', 'Delete local assets after upload').env('IMMICH_DELETE_ASSETS'))
.addOption(new commander_1.Option('-t, --threads <num>', 'Amount of concurrent upload threads (default=5)').env('IMMICH_UPLOAD_THREADS'))
.addOption(new commander_1.Option('-al, --album [album]', 'Create albums for assets based on the parent folder or a given name').env('IMMICH_CREATE_ALBUMS'))
.addOption(new commander_1.Option('-i, --import', 'Import instead of upload').env('IMMICH_IMPORT').default(false))
.addOption(new commander_1.Option('-id, --device-uuid <value>', 'Set a device UUID').env('IMMICH_DEVICE_UUID'))
.addOption(new commander_1.Option('-d, --directory <value>', 'Upload assets recursively from the specified directory (DEPRECATED, use path argument with --recursive instead)').env('IMMICH_TARGET_DIRECTORY'))
.argument('[paths...]', 'One or more paths to assets to be uploaded')
.action((paths, options) => {
if (options.directory) {
if (paths.length > 0) {
log(chalk_1.default.red("Error: Can't use deprecated --directory option when specifying paths"));
process.exit(1);
}
if (options.recursive) {
log(chalk_1.default.red("Error: Can't use deprecated --directory option together with --recursive"));
process.exit(1);
}
log(chalk_1.default.yellow('Warning: deprecated option --directory used, this will be removed in a future release. Please specify paths with --recursive instead'));
paths.push(options.directory);
options.recursive = true;
}
else {
if (paths.length === 0) {
// If no path argument is given, check if an env variable is set
const envPath = process.env.IMMICH_ASSET_PATH;
if (!envPath) {
log(chalk_1.default.red('Error: Must specify at least one path'));
process.exit(1);
}
else {
paths = [envPath];
}
}
}
upload(paths, options);
});
commander_1.program
.command('delete')
.description('Delete assets from an Immich instance')
.usage('delete [options] <paths...>')
.addOption(new commander_1.Option('-k, --key <value>', 'API Key').env('IMMICH_API_KEY'))
.addOption(new commander_1.Option('-s, --server <value>', 'Immich server address (http://<your-ip>:2283/api or https://<your-domain>/api)').env('IMMICH_SERVER_ADDRESS'))
.addOption(new commander_1.Option('-y, --yes', 'Assume yes on all interactive prompts').env('IMMICH_ASSUME_YES'))
.addOption(new commander_1.Option('-t, --threads <num>', 'Amount of concurrent upload threads (default=5)').env('IMMICH_UPLOAD_THREADS'))
.addOption(new commander_1.Option('-al, --album [album]', 'Album\'s image to delete. This will delete images in the specified album only.').env('IMMICH_DELETE_ALBUMS_IMAGE'))
.addOption(new commander_1.Option('-d, --date [date]', 'Images of this date will be deleted. If you provided time with the date then 24 hours from that time will be considered.').env('IMMICH_DELETE_DATE'))
.addOption(new commander_1.Option('-dll, --date_lower_limit [date_lower_limit]', 'Time bucket\'s lower limit').env('IMMICH_DELETE_DATE_LOWER_LIMIT'))
.addOption(new commander_1.Option('-dul, --date_upper_limit [date_upper_limit]', 'Time bucket\'s upper limit.').env('IMMICH_DELETE_DATE_UPPER_LIMIT'))
.addOption(new commander_1.Option('-id, --device-uuid <value>', 'Set a device UUID').env('IMMICH_DEVICE_UUID'))
.action((options) => {
if ((options === null || options === void 0 ? void 0 : options.album) == undefined && (options === null || options === void 0 ? void 0 : options.date_lower_limit) == undefined && (options === null || options === void 0 ? void 0 : options.date_upper_limit) == undefined && (options === null || options === void 0 ? void 0 : options.date) == undefined) {
log(chalk_1.default.red("Error: Either specify --all option to delete all assets, or provide one of the following asset: --album, -date, --date_lower_limit, --date_upper_limit"));
process.exit(1);
}
delete_assets(options);
});
commander_1.program.parse(process.argv);
function delete_assets({ key, server, recursive, yes: assumeYes, threads: uploadThreads, album, date: deleteDate, date_lower_limit: dateLowerLimit, date_upper_limit: dateUpperLimit, deviceUuid: deviceUuid, }) {
return __awaiter(this, void 0, void 0, function* () {
const endpoint = server;
const deviceId = deviceUuid || (yield si.uuid()).os || 'CLI';
const osInfo = (yield si.osInfo()).distro;
let timeLowerLimitEpoch = (dateLowerLimit == undefined) ? undefined : Date.parse(dateLowerLimit);
let timeUpperLimitEpoch = (dateUpperLimit == undefined) ? undefined : Date.parse(dateUpperLimit);
if (deleteDate != undefined) {
dateLowerLimit = deleteDate;
dateUpperLimit = deleteDate;
timeLowerLimitEpoch = Date.parse(deleteDate);
timeUpperLimitEpoch = new Date(deleteDate);
timeUpperLimitEpoch.setUTCHours(timeUpperLimitEpoch.getUTCHours() + 23, timeUpperLimitEpoch.getUTCMinutes() + 59, timeUpperLimitEpoch.getUTCSeconds() + 59);
}
if (Number.isNaN(timeLowerLimitEpoch) || Number.isNaN(timeUpperLimitEpoch)) {
log(chalk_1.default.red(`Invalid date format.`));
process.exit(1);
}
// Ping server
log('Checking connectivity with Immich instance...');
yield pingServer(endpoint);
// Login
log('Checking credentials...');
const user = yield validateConnection(endpoint, key);
log(chalk_1.default.green(`Successful authentication for user ${user.email}`));
const assetsToDelete = [];
// Get the assets to be deleted.
if (album) {
const album_info = yield get_album_info(key, server, album);
album_info === null || album_info === void 0 ? void 0 : album_info.assets.forEach((el) => {
// Check if the asset is within the desired time bucket.
if (timeLowerLimitEpoch != undefined && timeLowerLimitEpoch > new Date(el.fileCreatedAt).getTime()) {
return;
}
if (timeUpperLimitEpoch != undefined && timeUpperLimitEpoch < new Date(el.fileCreatedAt).getTime()) {
return;
}
assetsToDelete.push(el.id);
});
}
else {
const assets_by_time_bucket = yield get_assets_by_time_bucket(key, server, dateLowerLimit, dateUpperLimit);
assets_by_time_bucket.forEach((el) => {
// Check if the asset is within the desired time bucket.
if (timeLowerLimitEpoch != undefined && timeLowerLimitEpoch > new Date(el.fileCreatedAt).getTime()) {
return;
}
if (timeUpperLimitEpoch != undefined && timeUpperLimitEpoch < new Date(el.fileCreatedAt).getTime()) {
return;
}
assetsToDelete.push(el.id);
});
}
log(chalk_1.default.green(`A total of ${assetsToDelete.length} assets found to be deleted.`));
if (assetsToDelete.length == 0) {
process.exit(0);
}
// Ask user
try {
//There is a promise API for readline, but it's currently experimental
//https://nodejs.org/api/readline.html#promises-api
const answer = assumeYes
? 'y'
: yield new Promise((resolve) => {
rl.question('Do you want to start deletion now? (y/n) ', resolve);
});
if (answer == 'n') {
log(chalk_1.default.yellow('Abort Delete Process'));
process.exit(1);
}
if (answer == 'y') {
log(chalk_1.default.green('Start deleting...'));
const progressBar = new cliProgress.SingleBar({
format: 'Delete Progress | {bar} | {percentage}% || {value}/{total}',
}, cliProgress.Presets.shades_classic);
progressBar.start(Math.ceil(assetsToDelete.length / 20), 0);
const deleteQueue = [];
const limit = (0, p_limit_1.default)(uploadThreads !== null && uploadThreads !== void 0 ? uploadThreads : 5);
var deletePayload = [];
assetsToDelete.forEach((asset, index) => {
deletePayload.push(asset);
if (deletePayload.length >= 20 || index >= assetsToDelete.length - 1) {
const deletePayloadBatch = deletePayload;
deleteQueue.push(limit(() => __awaiter(this, void 0, void 0, function* () {
try {
const config = {
method: 'delete',
maxRedirects: 0,
url: `${server}/asset`,
headers: {
'x-api-key': key,
'Content-Type': 'application/json',
'Accept': 'application/json'
},
data: JSON.stringify({
ids: deletePayloadBatch
}),
maxContentLength: Infinity,
maxBodyLength: Infinity,
};
yield (0, axios_1.default)(config);
progressBar.increment(1);
}
catch (err) {
log(chalk_1.default.red(err.message));
}
})));
deletePayload = [];
}
});
yield Promise.all(deleteQueue);
progressBar.stop();
for (const error of errorAssets) {
log("Error asset: ", error);
}
if (errorAssets.length > 0) {
process.exit(1);
}
process.exit(0);
}
}
catch (e) {
log(chalk_1.default.red('Error reading input from user '), e);
process.exit(1);
}
});
}
function get_assets_by_time_bucket(key, server, timeLowerLimit, timeUpperLimit) {
return __awaiter(this, void 0, void 0, function* () {
const timeBucket = dateRange(timeLowerLimit, timeUpperLimit);
let payload = {
timeBucket,
withoutThumbs: false
};
try {
const config = {
method: 'post',
maxRedirects: 0,
url: `${server}/asset/time-bucket`,
headers: {
'x-api-key': key,
'Content-Type': 'application/json',
'Accept': 'application/json'
},
data: JSON.stringify(payload),
maxContentLength: Infinity,
maxBodyLength: Infinity,
};
const res = yield (0, axios_1.default)(config);
return res.data;
}
catch (error) {
log(chalk_1.default.red('Error: Fetching assets by time bucket.'));
process.exit(1);
}
});
}
function get_album_info(key, server, album) {
return __awaiter(this, void 0, void 0, function* () {
try {
const config = {
method: 'get',
maxRedirects: 0,
url: `${server}/album/${album}`,
headers: {
'x-api-key': key,
'Accept': 'application/json'
},
maxContentLength: Infinity,
maxBodyLength: Infinity,
};
const res = yield (0, axios_1.default)(config);
return res.data;
}
catch (error) {
log(chalk_1.default.red('Error: Fetching assets by album.'));
process.exit(1);
}
});
}
function dateRange(startDate, endDate) {
const startDateEpoch = (startDate == undefined) ? Date.now() : Date.parse(startDate);
const endDateEpoch = (endDate == undefined) ? Date.now() : Date.parse(endDate);
if (Number.isNaN(startDateEpoch) || Number.isNaN(endDateEpoch)) {
log(chalk_1.default.red(`Invalid date format.`));
process.exit(1);
}
let startDateParsed = (0, moment_1.default)(startDateEpoch);
let endDateParsed = (0, moment_1.default)(endDateEpoch);
var dates = [];
var month = (0, moment_1.default)(startDateParsed);
if (month > endDateParsed) {
log(chalk_1.default.red('Error: Upper limit can\'t be less than lower limit.'));
process.exit(1);
}
while (month <= endDateParsed) {
dates.push(new Date(month.format('YYYY-MM-01')).toISOString());
month.add(1, "month");
}
return dates;
}
function upload(paths, { key, server, recursive, yes: assumeYes, delete: deleteAssets, uploadThreads, album: createAlbums, deviceUuid: deviceUuid, import: doImport, }) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const endpoint = server;
const deviceId = deviceUuid || (yield si.uuid()).os || 'CLI';
const osInfo = (yield si.osInfo()).distro;
const localAssets = [];
// Ping server
log('Checking connectivity with Immich instance...');
yield pingServer(endpoint);
// Login
log('Checking credentials...');
const user = yield validateConnection(endpoint, key);
log(chalk_1.default.green(`Successful authentication for user ${user.email}`));
// Index provided directory
log('Indexing local assets...');
let crawler = new fdir_1.fdir().withFullPaths();
if (!recursive) {
// Don't go into subfolders
crawler = crawler.withMaxDepth(0);
}
const files = [];
for (const newPath of paths) {
try {
// Check if the path can be accessed
fs.accessSync(newPath);
}
catch (e) {
log(chalk_1.default.red(e));
process.exit(1);
}
const stats = fs.lstatSync(newPath);
if (stats.isDirectory()) {
// Path is a directory so use the crawler to crawl it (potentially very large list)
const children = crawler.crawl(newPath).sync();
for (const child of children) {
files.push(child);
}
}
else {
// Path is a single file
files.push(path.resolve(newPath));
}
}
// Ensure that list of files only has unique entries
const uniqueFiles = new Set(files);
for (const filePath of uniqueFiles) {
const mimeType = mime.lookup(filePath);
if (SUPPORTED_MIME.includes(mimeType)) {
try {
const fileStat = fs.statSync(filePath);
localAssets.push({
id: `${path.basename(filePath)}-${fileStat.size}`.replace(/\s+/g, ''),
filePath,
});
}
catch (e) {
errorAssets.push({
file: filePath,
reason: e,
response: (_a = e.response) === null || _a === void 0 ? void 0 : _a.data,
});
continue;
}
}
}
if (localAssets.length == 0) {
log('No local assets found, exiting');
process.exit(0);
}
log(`Indexing complete, found ${localAssets.length} local assets`);
log('Comparing local assets with those on the Immich instance...');
const backupAsset = yield getAssetInfoFromServer(endpoint, key, deviceId);
const newAssets = localAssets.filter((a) => !backupAsset.includes(a.id));
if (localAssets.length == 0 || (newAssets.length == 0 && !createAlbums)) {
log(chalk_1.default.green('All assets have been backed up to the server'));
process.exit(0);
}
else {
log(chalk_1.default.green(`A total of ${newAssets.length} assets will be uploaded to the server`));
}
if (createAlbums) {
log(chalk_1.default.green(`A total of ${localAssets.length} assets will be added to album(s).\n` +
'NOTE: some assets may already be associated with the album, this will not create duplicates.'));
}
// Ask user
try {
//There is a promise API for readline, but it's currently experimental
//https://nodejs.org/api/readline.html#promises-api
const answer = assumeYes
? 'y'
: yield new Promise((resolve) => {
rl.question('Do you want to start upload now? (y/n) ', resolve);
});
const deleteLocalAsset = deleteAssets ? 'y' : 'n';
if (answer == 'n') {
log(chalk_1.default.yellow('Abort Upload Process'));
process.exit(1);
}
if (answer == 'y') {
log(chalk_1.default.green('Start uploading...'));
const progressBar = new cliProgress.SingleBar({
format: 'Upload Progress | {bar} | {percentage}% || {value}/{total} || Current file [{filepath}]',
}, cliProgress.Presets.shades_classic);
progressBar.start(localAssets.length, 0, { filepath: '' });
const assetDirectoryMap = new Map();
const uploadQueue = [];
const limit = (0, p_limit_1.default)(uploadThreads !== null && uploadThreads !== void 0 ? uploadThreads : 5);
for (const asset of localAssets) {
const album = asset.filePath.split(path.sep).slice(-2)[0];
if (!assetDirectoryMap.has(album)) {
assetDirectoryMap.set(album, []);
}
if (!backupAsset.includes(asset.id)) {
// New file, lets upload it!
uploadQueue.push(limit(() => __awaiter(this, void 0, void 0, function* () {
try {
const res = yield startUpload(endpoint, key, asset, deviceId, doImport);
progressBar.increment(1, { filepath: asset.filePath });
if (res && (res.status == 201 || res.status == 200)) {
if (deleteLocalAsset == 'y') {
fs.unlink(asset.filePath, (err) => {
if (err) {
log(err);
return;
}
});
}
backupAsset.push(asset.id);
assetDirectoryMap.get(album).push(res.data.id);
}
}
catch (err) {
log(chalk_1.default.red(err.message));
}
})));
}
else if (createAlbums) {
// Existing file. No need to upload it BUT lets still add to Album.
uploadQueue.push(limit(() => __awaiter(this, void 0, void 0, function* () {
try {
// Fetch existing asset from server
const res = yield axios_1.default.post(`${endpoint}/asset/check`, {
deviceAssetId: asset.id,
deviceId,
}, {
headers: { 'x-api-key': key },
});
assetDirectoryMap.get(album).push(res.data.id);
}
catch (err) {
log(chalk_1.default.red(err.message));
}
})));
}
}
const uploads = yield Promise.all(uploadQueue);
progressBar.stop();
if (createAlbums) {
log(chalk_1.default.green('Creating albums...'));
const serverAlbums = yield getAlbumsFromServer(endpoint, key);
if (typeof createAlbums === 'boolean') {
progressBar.start(assetDirectoryMap.size, 0);
for (const localAlbum of assetDirectoryMap.keys()) {
const serverAlbumIndex = serverAlbums.findIndex((album) => album.albumName === localAlbum);
let albumId;
if (serverAlbumIndex > -1) {
albumId = serverAlbums[serverAlbumIndex].id;
}
else {
albumId = yield createAlbum(endpoint, key, localAlbum);
}
if (albumId) {
yield addAssetsToAlbum(endpoint, key, albumId, assetDirectoryMap.get(localAlbum));
}
progressBar.increment();
}
progressBar.stop();
}
else {
const serverAlbumIndex = serverAlbums.findIndex((album) => album.albumName === createAlbums);
let albumId;
if (serverAlbumIndex > -1) {
albumId = serverAlbums[serverAlbumIndex].id;
}
else {
albumId = yield createAlbum(endpoint, key, createAlbums);
}
yield addAssetsToAlbum(endpoint, key, albumId, Array.from(assetDirectoryMap.values()).flat());
}
}
// log(chalk.yellow(`Failed to upload ${errorAssets.length} files `), errorAssets);
for (const error of errorAssets) {
console.log("Error asset: ", error);
}
if (errorAssets.length > 0) {
process.exit(1);
}
process.exit(0);
}
}
catch (e) {
log(chalk_1.default.red('Error reading input from user '), e);
process.exit(1);
}
});
}
function startUpload(endpoint, key, asset, deviceId, doImport) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
try {
const assetType = getAssetType(asset.filePath);
const fileStat = yield (0, promises_1.stat)(asset.filePath);
const data = {
deviceAssetId: asset.id,
deviceId,
assetType,
fileCreatedAt: fileStat.mtime.toISOString(),
fileModifiedAt: fileStat.mtime.toISOString(),
isFavorite: String(false),
fileExtension: path.extname(asset.filePath),
duration: '0:00:00.000000',
isReadOnly: doImport ? String(true) : String(false),
};
const formData = new form_data_1.default();
if (!doImport) {
for (const prop in data) {
formData.append(prop, data[prop]);
}
formData.append("assetData", fs.createReadStream(asset.filePath));
}
else {
data.assetPath = asset.filePath;
}
try {
yield fs.promises.access(`${asset.filePath}.xmp`, fs.constants.W_OK);
if (doImport) {
data.sidecarPath = path.resolve(`${asset.filePath}.xmp`);
}
else {
formData.append("sidecarData", fs.createReadStream(path.resolve(`${asset.filePath}.xmp`)), { contentType: 'application/xml' });
}
}
catch (e) { }
const config = {
method: 'post',
maxRedirects: 0,
url: doImport == true ? `${endpoint}/asset/import` : `${endpoint}/asset/upload`,
headers: Object.assign({ 'x-api-key': key }, (doImport == false && formData.getHeaders())),
maxContentLength: Infinity,
maxBodyLength: Infinity,
data: doImport ? data : formData,
};
const res = yield (0, axios_1.default)(config);
return res;
}
catch (e) {
errorAssets.push({
file: asset.filePath,
reason: e,
response: (_a = e.response) === null || _a === void 0 ? void 0 : _a.data,
});
return null;
}
});
}
function getAlbumsFromServer(endpoint, key) {
return __awaiter(this, void 0, void 0, function* () {
try {
const res = yield axios_1.default.get(`${endpoint}/album`, {
headers: { 'x-api-key': key },
});
return res.data;
}
catch (e) {
log(chalk_1.default.red('Error getting albums'), e);
process.exit(1);
}
});
}
function createAlbum(endpoint, key, albumName) {
return __awaiter(this, void 0, void 0, function* () {
try {
const res = yield axios_1.default.post(`${endpoint}/album`, { albumName }, {
headers: { 'x-api-key': key },
});
return res.data.id;
}
catch (e) {
log(chalk_1.default.red(`Error creating album '${albumName}'`), e);
}
});
}
function addAssetsToAlbum(endpoint, key, albumId, assetIds) {
return __awaiter(this, void 0, void 0, function* () {
try {
yield axios_1.default.put(`${endpoint}/album/${albumId}/assets`, { assetIds: [...new Set(assetIds)] }, {
headers: { 'x-api-key': key },
});
}
catch (e) {
log(chalk_1.default.red('Error adding asset to album'), e);
}
});
}
function getAssetInfoFromServer(endpoint, key, deviceId) {
return __awaiter(this, void 0, void 0, function* () {
try {
const res = yield axios_1.default.get(`${endpoint}/asset/${deviceId}`, {
headers: { 'x-api-key': key },
});
return res.data;
}
catch (e) {
log(chalk_1.default.red("Error getting device's uploaded assets"));
process.exit(1);
}
});
}
function pingServer(endpoint) {
return __awaiter(this, void 0, void 0, function* () {
try {
const res = yield axios_1.default.get(`${endpoint}/server-info/ping`);
if (res.data['res'] == 'pong') {
log(chalk_1.default.green('Server status: OK'));
}
}
catch (e) {
log(chalk_1.default.red('Error connecting to server - check server address and port'));
process.exit(1);
}
});
}
function validateConnection(endpoint, key) {
return __awaiter(this, void 0, void 0, function* () {
try {
const res = yield axios_1.default.get(`${endpoint}/user/me`, {
headers: { 'x-api-key': key },
});
if (res.status == 200) {
log(chalk_1.default.green('Login status: OK'));
return res.data;
}
}
catch (e) {
log(chalk_1.default.red('Error logging in - check api key'));
process.exit(1);
}
});
}
function getAssetType(filePath) {
const mimeType = mime.lookup(filePath);
return mimeType.split('/')[0].toUpperCase();
}