Skip to content

Commit

Permalink
Fixed build process
Browse files Browse the repository at this point in the history
  • Loading branch information
GermanBluefox committed Sep 25, 2024
1 parent e74a77d commit f6c7ec1
Show file tree
Hide file tree
Showing 50 changed files with 1,797 additions and 176 deletions.
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,15 @@ sendTo('cameras.0', 'image', {
The result is always in `jpg` format.

Supported cameras:
- Reolink E1 Pro via RTSP (important, without `Pro` it will not work)
- Eufy via eusec adapter
- [HiKam](https://support.hikam.de/support/solutions/articles/16000070656-zugriff-auf-kameras-der-2-generation-via-onvif-f%C3%BCr-s6-q8-a7-2-generation-) of second and third generation via ONVIF (für S6, Q8, A7 2. Generation), A7 Pro, A9
- [WIWICam M1 via HiKam adapter](https://www.wiwacam.com/de/mw1-minikamera-kurzanleitung-und-faq/)
- RTSP Native - if your camera supports RTSP protocol
- `Reolink E1 Pro` via RTSP (important, without `Pro` it will not work)
- `Eufy` via eusec adapter
- [`HiKam`](https://support.hikam.de/support/solutions/articles/16000070656-zugriff-auf-kameras-der-2-generation-via-onvif-f%C3%BCr-s6-q8-a7-2-generation-) of second and third generation via ONVIF (für S6, Q8, A7 2. Generation), A7 Pro, A9
- [`WIWICam M1` via `HiKam` adapter](https://www.wiwacam.com/de/mw1-minikamera-kurzanleitung-und-faq/)
- RTSP native - if your camera supports RTSP protocol
- Screenshots via HTTP URL - if you can get the snapshot from your camera via URL

Important: the adapter starts the internal web server on `localhost:8200`, if this port is occupied on your system, you can change the port in settings.

### URL image
This is a normal URL request, where all parameters are in URL. Like `http://mycam/snapshot.jpg`

Expand Down
File renamed without changes.
1 change: 1 addition & 0 deletions admin/assets/index-BqFSCGOi.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1,543 changes: 1,543 additions & 0 deletions admin/assets/index-BqWEC3ZM.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions admin/assets/index-BqWEC3ZM.js.map

Large diffs are not rendered by default.

File renamed without changes.
File renamed without changes
30 changes: 30 additions & 0 deletions admin/index_m.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link
rel="shortcut icon"
href="./assets/favicon-CSF3NglM.ico"
/>
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<meta
name="theme-color"
content="#000000"
/>
<link
rel="manifest"
href="./assets/manifest-DQd0VAqi.json"
/>
<script type="text/javascript" onerror="setTimeout(function(){window.location.reload()}, 5000)" src="./lib/js/socket.io.js"></script>
<title>ioBroker.cameras</title>
<script type="module" crossorigin src="./assets/index-BqWEC3ZM.js"></script>
<link rel="stylesheet" crossorigin href="./assets/index-BqFSCGOi.css">
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
19 changes: 16 additions & 3 deletions build-backend/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,16 +91,29 @@ class CamerasAdapter extends adapter_core_1.Adapter {
}
async onReady() {
this.streamSubscribes = [];
if (!this.config.ffmpegPath && process.platform === 'win32' && !(0, node_fs_1.existsSync)(`${__dirname}/win-ffmpeg.exe`)) {
if (!this.config.ffmpegPath &&
process.platform === 'win32' &&
!(0, node_fs_1.existsSync)(`${__dirname}/../win-ffmpeg.exe`) &&
!(0, node_fs_1.existsSync)(`${__dirname}/win-ffmpeg.exe`)) {
this.log.info('Decompress ffmpeg.exe...');
await (0, decompress_1.default)(`${__dirname}/win-ffmpeg.zip`, __dirname);
if (__dirname.endsWith('cameras')) {
await (0, decompress_1.default)((0, node_path_1.normalize)(`${__dirname}/win-ffmpeg.zip`), __dirname);
}
else {
await (0, decompress_1.default)((0, node_path_1.normalize)(`${__dirname}/../win-ffmpeg.zip`), (0, node_path_1.normalize)(`${__dirname}/..`));
}
}
this.language = this.config.language || this.language || 'en';
this.config.tempPath = this.config.tempPath || `${__dirname}/snapshots`;
this.config.defaultCacheTimeout = parseInt(this.config.defaultCacheTimeout, 10) || 0;
if (!(0, node_fs_1.existsSync)(this.config.ffmpegPath) && !(0, node_fs_1.existsSync)(`${this.config.ffmpegPath}.exe`)) {
if (process.platform === 'win32') {
this.config.ffmpegPath = `${__dirname}/win-ffmpeg.exe`;
if (__dirname.endsWith('cameras')) {
this.config.ffmpegPath = (0, node_path_1.normalize)(`${__dirname}/win-ffmpeg.exe`);
}
else {
this.config.ffmpegPath = (0, node_path_1.normalize)(`${__dirname}/../win-ffmpeg.exe`);
}
}
else {
this.log.error(`Cannot find ffmpeg in "${this.config.ffmpegPath}"`);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"@alcalzone/release-script": "^3.8.0",
"@alcalzone/release-script-plugin-iobroker": "^3.7.2",
"@alcalzone/release-script-plugin-license": "^3.7.0",
"@iobroker/build-tools": "^1.0.3",
"@iobroker/build-tools": "^1.1.0",
"@iobroker/testing": "^5.0.0",
"@iobroker/types": "^6.0.11",
"@iobroker/vis-2-widgets-react-dev": "^4.0.3",
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion src-editor/index.html → src-admin/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
script.src =
window.location.port === '3000'
? window.location.protocol + '//' + window.location.hostname + ':8081/lib/js/socket.io.js'
: '%PUBLIC_URL%/../../lib/js/socket.io.js';
: '../../lib/js/socket.io.js';
}, 1000);

document.head.appendChild(script);
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Binary file added src-admin/public/cameras.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src-admin/public/favicon.ico
Binary file not shown.
15 changes: 15 additions & 0 deletions src-admin/public/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"short_name": "ioBroker.cameras",
"name": "ioBroker.cameras",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
File renamed without changes.
File renamed without changes.
264 changes: 132 additions & 132 deletions src-editor/src/Tabs/Options.tsx → src-admin/src/Tabs/Options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -173,141 +173,141 @@ class Options extends Component<OptionsProps, OptionsState> {
});
}

renderSettings(): JSX.Element[] {
return [
<TextField
variant="standard"
disabled={this.state.requesting}
key="port"
type="number"
slotProps={{
htmlInput: {
min: 1,
max: 0xffff,
},
}}
style={styles.port}
label={I18n.t('Local port')}
value={this.props.native.port}
onChange={e => this.props.onChange('port', e.target.value)}
/>,
<br key="br1" />,
<TextField
variant="standard"
disabled={this.state.requesting}
key="defaultTimeout"
type="number"
slotProps={{
htmlInput: {
min: 0,
max: 10000,
},
}}
style={styles.defaultTimeout}
label={I18n.t('Default timeout (ms)')}
value={this.props.native.defaultTimeout}
onChange={e => this.props.onChange('defaultTimeout', e.target.value)}
/>,
<br key="br2" />,
<FormControl
key="webInstanceSelect"
style={styles.bind}
variant="standard"
>
<InputLabel>{I18n.t('WEB Instance')}</InputLabel>
<Select
renderSettings(): JSX.Element {
return (
<>
<TextField
variant="standard"
disabled={this.state.requesting}
value={this.props.native.webInstance}
onChange={e => this.props.onChange('webInstance', e.target.value)}
key="defaultTimeout"
type="number"
slotProps={{
htmlInput: {
min: 0,
max: 10000,
},
}}
style={styles.defaultTimeout}
label={I18n.t('Default timeout (ms)')}
value={this.props.native.defaultTimeout}
onChange={e => this.props.onChange('defaultTimeout', e.target.value)}
/>
<br />
<FormControl
key="webInstanceSelect"
style={styles.bind}
variant="standard"
>
<MenuItem value="*">{I18n.t('All')}</MenuItem>
{this.state.webInstances
? this.state.webInstances.map(instance => (
<MenuItem
key={instance}
value={instance}
>
{instance}
</MenuItem>
))
: null}
</Select>
</FormControl>,
<br key="br3" />,
<TextField
variant="standard"
disabled={this.state.requesting}
key="ffmpegPath"
style={styles.ffmpegPath}
label={I18n.t('Path to ffpmeg executable')}
value={this.props.native.ffmpegPath || ''}
onChange={e => this.props.onChange('ffmpegPath', e.target.value)}
helperText={I18n.t('Like /usr/bin/ffmpeg')}
/>,
<Button
key="ffmpegPathButton"
color="grey"
variant="outlined"
onClick={() => this.onTestFfmpeg()}
disabled={!this.props.instanceAlive || this.state.requesting}
startIcon={<IconTest />}
>
{I18n.t('Test path')}
</Button>,
<br key="br4" />,
<TextField
variant="standard"
disabled={this.state.requesting}
key="tempPath"
style={styles.ffmpegPath}
label={I18n.t('Path to store temporary images')}
value={this.props.native.tempPath || ''}
onChange={e => this.props.onChange('tempPath', e.target.value)}
helperText={I18n.t('If empty then in adapter folder')}
/>,
<br key="br5" />,
<TextField
variant="standard"
disabled={this.state.requesting}
key="defaultCacheTimeout"
style={styles.ffmpegPath}
label={I18n.t('Default cache timeout (ms)')}
slotProps={{
htmlInput: {
min: 0,
max: 60000,
},
}}
type="number"
value={this.props.native.defaultCacheTimeout || ''}
onChange={e => this.props.onChange('defaultCacheTimeout', e.target.value)}
helperText={I18n.t('How often the cameras will be asked for new snapshot. If 0, then by every request')}
/>,
<br key="br6" />,
<TextField
variant="standard"
disabled={this.state.requesting}
key="dateFormat"
style={styles.ffmpegPath}
label={I18n.t('Time format')}
value={this.props.native.dateFormat || ''}
onChange={e => this.props.onChange('dateFormat', e.target.value)}
helperText={
<span>
{I18n.t('See here:')}{' '}
<a
href="https://momentjs.com/docs/#/displaying/"
rel="noreferrer"
target="_blank"
style={styles.link}
>
https://momentjs.com/
</a>
</span>
}
/>,
];
<InputLabel>{I18n.t('WEB Instance')}</InputLabel>
<Select
variant="standard"
disabled={this.state.requesting}
value={this.props.native.webInstance}
onChange={e => this.props.onChange('webInstance', e.target.value)}
>
<MenuItem value="*">{I18n.t('All')}</MenuItem>
{this.state.webInstances
? this.state.webInstances.map(instance => (
<MenuItem
key={instance}
value={instance}
>
{instance}
</MenuItem>
))
: null}
</Select>
</FormControl>
<br />
<TextField
variant="standard"
disabled={this.state.requesting}
key="ffmpegPath"
style={styles.ffmpegPath}
label={I18n.t('Path to ffpmeg executable')}
value={this.props.native.ffmpegPath || ''}
onChange={e => this.props.onChange('ffmpegPath', e.target.value)}
helperText={I18n.t('Like /usr/bin/ffmpeg')}
/>
<Button
color="grey"
variant="outlined"
onClick={() => this.onTestFfmpeg()}
disabled={!this.props.instanceAlive || this.state.requesting}
startIcon={<IconTest />}
>
{I18n.t('Test path')}
</Button>
<br />
<TextField
variant="standard"
disabled={this.state.requesting}
style={styles.ffmpegPath}
label={I18n.t('Path to store temporary images')}
value={this.props.native.tempPath || ''}
onChange={e => this.props.onChange('tempPath', e.target.value)}
helperText={I18n.t('If empty then in adapter folder')}
/>
,
<br />
<TextField
variant="standard"
disabled={this.state.requesting}
style={styles.ffmpegPath}
label={I18n.t('Default cache timeout (ms)')}
slotProps={{
htmlInput: {
min: 0,
max: 60000,
},
}}
type="number"
value={this.props.native.defaultCacheTimeout || ''}
onChange={e => this.props.onChange('defaultCacheTimeout', e.target.value)}
helperText={I18n.t(
'How often the cameras will be asked for new snapshot. If 0, then by every request',
)}
/>
<br />
<TextField
variant="standard"
disabled={this.state.requesting}
style={styles.ffmpegPath}
label={I18n.t('Time format')}
value={this.props.native.dateFormat || ''}
onChange={e => this.props.onChange('dateFormat', e.target.value)}
helperText={
<span>
{I18n.t('See here:')}{' '}
<a
href="https://momentjs.com/docs/#/displaying/"
rel="noreferrer"
target="_blank"
style={styles.link}
>
https://momentjs.com/
</a>
</span>
}
/>
<br />
<TextField
variant="standard"
disabled={this.state.requesting}
type="number"
slotProps={{
htmlInput: {
min: 1,
max: 0xffff,
},
}}
style={styles.port}
label={I18n.t('Local port')}
value={this.props.native.port}
onChange={e => this.props.onChange('port', e.target.value)}
/>
</>
);
}

renderMessage(): JSX.Element | null {
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit f6c7ec1

Please sign in to comment.