Initial commit

This commit is contained in:
2026-06-30 17:06:06 +02:00
commit d0bb893522
19 changed files with 1333 additions and 0 deletions

1
ts/constants.ts Normal file
View File

@@ -0,0 +1 @@
export const BambuddyAddress = 'https://print.morphix.nl';

44
ts/login.ts Normal file
View File

@@ -0,0 +1,44 @@
import { BambuddyAddress } from './constants';
export async function login(
username: string,
password: string,
): Promise<LoginResponse | null> {
const request = await fetch(`${BambuddyAddress}/api/v1/auth/login`, {
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
username: username,
password: password,
}),
method: 'POST',
});
const response = await request.json();
if (response?.detail != null) {
console.error(`Login failed: ${response.detail}`);
return null;
}
return response as LoginResponse;
}
export interface LoginResponse {
access_token: string;
token_type: string;
user: {
auth_source: string;
created_at: string;
email: string;
groups: { id: number; name: string }[];
id: number;
is_active: boolean;
is_admin: boolean;
permissions: string[];
role: string;
username: string;
};
}

38
ts/main.ts Normal file
View File

@@ -0,0 +1,38 @@
import { BambuddyAddress } from './constants';
import { login } from './login';
import { getPrinterDetails } from './printer';
import { getStreamToken } from './streamToken';
import * as express from 'express';
import { Request, Response } from 'express';
async function getToken() {
const loginResponse = await login('screen', 'e8$o$u@F8XtHt#');
console.log('Login response:', loginResponse);
const streamToken = await getStreamToken(
loginResponse?.access_token as string,
);
return streamToken?.token;
}
const app = express();
app.get('/', async (req: Request, res: Response) => {
res.send(
'Bambuddy Camera Bridge is running. Use /:printerId to access the camera stream.',
);
});
app.get('/:printerId', async (req: Request, res: Response) => {
const token = await getToken();
res.redirect(
`${BambuddyAddress}/api/v1/printers/${req.params.printerId}/camera/stream?fps=15&t=${Date.now()}&token=${token}`,
);
});
app.listen(3838, () => {
console.log('Server is running on port 3838');
});

44
ts/printer.ts Normal file
View File

@@ -0,0 +1,44 @@
import { BambuddyAddress } from './constants';
export async function getPrinterDetails(
bearerToken: string,
printerId: number,
): Promise<PrinterDetails | null> {
const request = await fetch(
`${BambuddyAddress}/api/v1/printers/${printerId}`,
{
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${bearerToken}`,
},
method: 'GET',
},
);
const response = await request.json();
return response as PrinterDetails;
}
export interface PrinterDetails {
name: string;
serial_number: string;
ip_address: string;
access_code: string;
model: string;
location: string;
auto_archive: boolean;
external_camera_url: string;
external_camera_type: string;
external_camera_enabled: boolean;
external_camera_snapshot_url: string | null;
camera_rotation: number;
id: number;
is_active: boolean;
nozzle_count: number;
print_hours_offset: number;
plate_detection_enabled: boolean;
plate_detection_roi: any;
created_at: string;
updated_at: string;
}

24
ts/streamToken.ts Normal file
View File

@@ -0,0 +1,24 @@
import { BambuddyAddress } from './constants';
export async function getStreamToken(
bearerToken: string,
): Promise<PrinterDetails | null> {
const request = await fetch(
`${BambuddyAddress}/api/v1/printers/camera/stream-token`,
{
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${bearerToken}`,
},
method: 'POST',
},
);
const response = await request.json();
return response as PrinterDetails;
}
export interface PrinterDetails {
token: string;
}