diff --git a/Dockerfile b/Dockerfile index 3bb77028..76ab05e9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,15 +7,21 @@ COPY package*.json "$APP_DIR/" COPY packages/server/package*.json "$APP_DIR/packages/server/" COPY packages/client/package*.json "$APP_DIR/packages/client/" -RUN npm run docker-install +RUN npm run install COPY packages/client/ "$APP_DIR/packages/client/" COPY packages/server/ "$APP_DIR/packages/server/" -RUN npm run docker-build +RUN npm run build # production image FROM node:14-buster-slim + +# Make it possible to override the UID/GID/username of the user running scanservjs +ARG UID=2001 +ARG GID=2001 +ARG UNAME=scanservjs + ENV APP_DIR=/app WORKDIR "$APP_DIR" RUN apt-get update \ @@ -39,7 +45,8 @@ RUN apt-get update \ && npm install -g npm@7.11.2 # Create a known user -RUN useradd -u 2001 -ms /bin/bash scanservjs +RUN groupadd -g $GID -o $UNAME +RUN useradd -o -u $UID -g $GID -m -s /bin/bash $UNAME ENV \ # This goes into /etc/sane.d/net.conf @@ -63,7 +70,7 @@ COPY --from=builder "$APP_DIR/dist" "$APP_DIR/" RUN npm install --production # Change the ownership of config and data since we need to write there -RUN chown -R scanservjs:scanservjs config data /etc/sane.d/net.conf /etc/sane.d/airscan.conf -USER scanservjs +RUN chown -R $UID:$GID config data /etc/sane.d/net.conf /etc/sane.d/airscan.conf +USER $UNAME EXPOSE 8080 diff --git a/README.md b/README.md index d5bd4716..60708169 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,10 @@ Copyright 2016-2021 [Sam Strachan](https://github.com/sbs20) > an awesome web interface makes it even more brilliant! +> This is a great project! The touchscreen and buttons on my Brother scanner are +> broken, meaning the device is useless by itself because one cannot trigger +> scans, but with this project I can trigger it remotely just fine. + ## About scanservjs is a web UI frontend for your scanner. It allows you to share one or diff --git a/docs/docker.md b/docs/docker.md index 35a41520..966045a3 100644 --- a/docs/docker.md +++ b/docs/docker.md @@ -89,27 +89,33 @@ Depending on your setup you have a number of options. ## Mapping volumes -There are two volumes you may wish to map: +To access data from outside the docker container, there are two volumes you may +wish to map: * The scanned images: use `-v /local/path/scans:/app/data/output` * Configuration overrides: use `-v /local/path/cfg:/app/config` -## User and group mapping +### User and group mapping -The docker image which is created now runs under a non-privileged user account -with a UID of `2001`. If you attempt to run as a user other than `2001` or `0` -(e.g. `-u 1000`) then the process inside the container will no longer have -access to some of the things it needs to and it will fail. Most of the time you -won't care about the user, but if you're mapping volumes for either config or -data, then it may matter. +When mapping volumes, special attention must be paid to users and file systems +permissions. -The solution in most cases is either to -* change the group of the container to a known group on the host e.g. +The docker container runs under a non-privileged user with a UID and GID of `2001`. +scanservjs relies on this user for editing SANE and airscan configurations inside +the container. Changing this user's UID (e.g. by using `-u 1000` for `docker run`) +to access scans/configuration from outside docker **is not advised since it will +cause these steps to fail.** + +Your alternatives are: +1. changing the group of the container to a known group on the host e.g. `-u 2001:1000`. This will keep the user correct (`2001`) but change the group - (`1000`) -* create a corresponding user on the host e.g. + (`1000`). +2. creating a corresponding user on the host e.g. `useradd -u 2001 -ms /bin/bash scanservjs` -* change the host volume permissions e.g. `chmod 777 local-volume` +3. building a docker image with a custom UID/GID pairing: clone this repository + and run `docker build --build-arg UID=1234 --build-arg GID=5678 -t scanservjs_custom .` + (with UID and GID adjusted to your liking), then run the custom image (e.g. `docker run scanservjs_custom`). +4. as a last resort, changing the host volume permissions e.g. `chmod 777 local-volume` ## Environment variables diff --git a/package-lock.json b/package-lock.json index ef7dd320..2f79f087 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "scanservjs", - "version": "2.15.0", + "version": "2.15.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "scanservjs", - "version": "2.15.0", + "version": "2.15.1", "hasInstallScript": true, "license": "GPL-2.0" } diff --git a/package.json b/package.json index ad4b6d5a..80bc27ec 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "scanservjs", - "version": "2.15.0", + "version": "2.15.1", "description": "scanservjs is a simple web-based UI for SANE which allows you to share a scanner on a network without the need for drivers or complicated installation.", "scripts": { "clean": "rm -rf ./dist", @@ -10,9 +10,8 @@ "test": "cd packages/server && npm run test", "build": "npm run clean && cd packages/client && npm run build && cd ../server && npm run build", "package": "cd packages/server && npm run package", - "docker-install": "npm run install", - "docker-build": "npm run build", "verify": "npm run version && npm run lint && npm run test", + "docker-build": "npm run verify && docker build -t scanservjs-image .", "release": "npm run verify && npm run build && npm run package", "serve": "cd packages/client && npm run serve" }, diff --git a/packages/client/package-lock.json b/packages/client/package-lock.json index 554b4d10..275ab957 100644 --- a/packages/client/package-lock.json +++ b/packages/client/package-lock.json @@ -1,12 +1,12 @@ { "name": "scanservjs", - "version": "2.15.0", + "version": "2.15.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "scanservjs", - "version": "2.15.0", + "version": "2.15.1", "license": "GPL-2.0", "dependencies": { "@mdi/font": "^5.9.55", diff --git a/packages/client/package.json b/packages/client/package.json index 0d545ffd..ade057e5 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "scanservjs", - "version": "2.15.0", + "version": "2.15.1", "description": "scanservjs is a simple web-based UI for SANE which allows you to share a scanner on a network without the need for drivers or complicated installation.", "author": "Sam Strachan", "scripts": { diff --git a/packages/client/src/locales/cs.json b/packages/client/src/locales/cs.json index 67c6ad96..7037b716 100644 --- a/packages/client/src/locales/cs.json +++ b/packages/client/src/locales/cs.json @@ -88,6 +88,7 @@ "left-aligned": "zarovnáno vlevo", "centrally-aligned": "zarovnáno na střed", "duplex": "oboustranně", + "transparency unit": "Transparency Unit", "automatic document feeder": "@:source.adf", "automatic document feeder(left aligned)": "@:source.adf (@:source.left-aligned)", diff --git a/packages/client/src/locales/de.json b/packages/client/src/locales/de.json index 36ac7b01..56053523 100644 --- a/packages/client/src/locales/de.json +++ b/packages/client/src/locales/de.json @@ -88,6 +88,7 @@ "left-aligned": "Left Aligned", "centrally-aligned": "Centrally Aligned", "duplex": "Duplex", + "transparency unit": "Transparency Unit", "automatic document feeder": "@:source.adf", "automatic document feeder(left aligned)": "@:source.adf (@:source.left-aligned)", diff --git a/packages/client/src/locales/en.json b/packages/client/src/locales/en.json index de35f036..f9f6f0d1 100644 --- a/packages/client/src/locales/en.json +++ b/packages/client/src/locales/en.json @@ -88,6 +88,7 @@ "left-aligned": "Left Aligned", "centrally-aligned": "Centrally Aligned", "duplex": "Duplex", + "transparency unit": "Transparency Unit", "automatic document feeder": "@:source.adf", "automatic document feeder(left aligned)": "@:source.adf (@:source.left-aligned)", diff --git a/packages/client/src/locales/es.json b/packages/client/src/locales/es.json index 973da9fc..211bd319 100644 --- a/packages/client/src/locales/es.json +++ b/packages/client/src/locales/es.json @@ -88,6 +88,7 @@ "left-aligned": "Alineado a la izquierda", "centrally-aligned": "Alineado al centro", "duplex": "Dúplex", + "transparency unit": "Transparency Unit", "automatic document feeder": "@:source.adf", "automatic document feeder(left aligned)": "@:source.adf (@:source.left-aligned)", diff --git a/packages/client/src/locales/fr.json b/packages/client/src/locales/fr.json index 8c520337..ebcdad2f 100644 --- a/packages/client/src/locales/fr.json +++ b/packages/client/src/locales/fr.json @@ -10,26 +10,26 @@ }, "colors": { - "accent-4": "Default", - "red": "Red", - "pink": "Pink", - "purple": "Purple", - "deep-purple": "Deep purple", + "accent-4": "Défaut", + "red": "Rouge", + "pink": "Rose", + "purple": "Violet", + "deep-purple": "Violet foncé", "indigo": "Indigo", - "blue": "Blue", - "light-blue": "Light blue", + "blue": "Bleu", + "light-blue": "Bleu clair", "cyan": "Cyan", - "teal": "Teal", - "green": "Green", - "light-green": "Light green", - "lime": "Lime", - "yellow": "Yellow", - "amber": "Amber", + "teal": "Sarcelle", + "green": "Vert", + "light-green": "Vert clair", + "lime": "Vert citron", + "yellow": "Jaune", + "amber": "Ambre", "orange": "Orange", - "deep-orange": "Deep orange", - "brown": "Brown", - "blue-grey": "Blue grey", - "grey": "Grey" + "deep-orange": "Orange foncé", + "brown": "Brun", + "blue-grey": "Bleu gris", + "grey": "Gris" }, "batch-dialog": { @@ -69,9 +69,9 @@ }, "mode": { - "color": "Colour", - "halftone": "Halftone", - "gray": "Grey", + "color": "Couleur", + "halftone": "Noir et blanc", + "gray": "Niveau de gris", "lineart": "Lineart", "24bitcolor":"@:mode.color", @@ -82,12 +82,13 @@ }, "source": { - "flatbed": "Flatbed", - "adf": "Automatic Document Feeder", + "flatbed": "Vitre du scanner", + "adf": "ADF", "auto": "Auto", - "left-aligned": "Left Aligned", - "centrally-aligned": "Centrally Aligned", + "left-aligned": "Aligné à gauche", + "centrally-aligned": "Aligné centré", "duplex": "Duplex", + "transparency unit": "Transparency Unit", "automatic document feeder": "@:source.adf", "automatic document feeder(left aligned)": "@:source.adf (@:source.left-aligned)", @@ -97,24 +98,24 @@ }, "pipeline": { - "high-quality": "Qualité élevée", + "high-quality": "Qualité haute", "medium-quality": "Qualité moyenne", "low-quality": "Qualité basse", "uncompressed": "Décompressé", - "lzw-compressed": "Compression LZW", + "lzw-compressed": "Compressé LZW", "ocr": "OCR", "text-file": "Fichier texte" }, "scan": { - "device": "Appareil", + "device": "Scanner", "source": "Source", "resolution": "Résolution", "mode": "Mode", "dynamic-lineart": "Dynamic Lineart", "dynamic-lineart:enabled": "Activé", "dynamic-lineart:disabled": "Désactivé", - "batch": "Scan groupé", + "batch": "Batch", "filters": "Filtres", "format": "Format", "btn-preview": "Aperçu", @@ -124,32 +125,32 @@ "left": "Gauche", "width": "Largeur", "height": "Hauteur", - "paperSize": "Paper size", + "paperSize": "Taille papier", "brightness": "Luminosité", "contrast": "Contraste", "message:loading-devices": "Chargement des scanners...", "message:no-devices": "Aucun scanner trouvé", - "message:deleted-preview": "Prévisualisation effacée", - "message:turn-documents": "Tournez votre document", - "message:preview-of-page": "Prévisualisation de la page" + "message:deleted-preview": "Aperçu supprimé", + "message:turn-documents": "Tourner le document", + "message:preview-of-page": "Aperçu de la page" }, "settings": { "title": "@:navigation.settings", - "behaviour-ui": "Comportement et interface utilisateur", + "behaviour-ui": "Paramètres et interface utilisateur", "locale": "Langue", - "locale:description": "Sélection de la langue", + "locale:description": "Choisir la langue de l'application", "theme": "Thème", "theme:description": "Theme. Si vous utilisez le thème de votre système d'exploitation et que vous changez le paramètre, vous devrez recharger l'application", "theme:system": "Système", "theme:light": "Clair", - "theme:dark": "Sombre", - "color": "Colour", - "color:description": "Colour. This will change the colour of the top app bar.", - "devices": "Devices and storage", - "reset:description": "Clears stored scanner devices and forces a reload", - "reset": "Réinitialiser", - "clear-storage:description": "Clears local storage of any cached parameters", - "clear-storage": "Clear" + "theme:dark": "Foncé", + "color": "Couleur", + "color:description": "Couleur. Ce paramètre modifie la couleur de la barre supérieure", + "devices": "Scanners et mémoire locale de l'application", + "reset:description": "Efface les scanners mémorisés et force une recherche d'appareils", + "reset": "Ré-initialiser", + "clear-storage:description": "Efface les données locales des paramètres en cache", + "clear-storage": "Effacer" } } diff --git a/packages/client/src/locales/it.json b/packages/client/src/locales/it.json index 3a5dd362..992414af 100644 --- a/packages/client/src/locales/it.json +++ b/packages/client/src/locales/it.json @@ -88,6 +88,7 @@ "left-aligned": "Allineato a sinistra", "centrally-aligned": "Allineato al centro", "duplex": "Fronte/retro", + "transparency unit": "Adattatore per trasparenza", "automatic document feeder": "@:source.adf", "automatic document feeder(left aligned)": "@:source.adf (@:source.left-aligned)", diff --git a/packages/client/src/locales/pt-BR.json b/packages/client/src/locales/pt-BR.json index c54f3353..4be37ded 100644 --- a/packages/client/src/locales/pt-BR.json +++ b/packages/client/src/locales/pt-BR.json @@ -88,6 +88,7 @@ "left-aligned": "Left Aligned", "centrally-aligned": "Centrally Aligned", "duplex": "Duplex", + "transparency unit": "Transparency Unit", "automatic document feeder": "@:source.adf", "automatic document feeder(left aligned)": "@:source.adf (@:source.left-aligned)", diff --git a/packages/client/src/locales/ru.json b/packages/client/src/locales/ru.json index 5fa1ef05..3e135911 100644 --- a/packages/client/src/locales/ru.json +++ b/packages/client/src/locales/ru.json @@ -88,6 +88,7 @@ "left-aligned": "Left Aligned", "centrally-aligned": "Centrally Aligned", "duplex": "Duplex", + "transparency unit": "Transparency Unit", "automatic document feeder": "@:source.adf", "automatic document feeder(left aligned)": "@:source.adf (@:source.left-aligned)", diff --git a/packages/client/src/locales/test.json b/packages/client/src/locales/test.json index ea06e398..5030ce45 100644 --- a/packages/client/src/locales/test.json +++ b/packages/client/src/locales/test.json @@ -89,6 +89,7 @@ "left-aligned": "##LEFT", "centrally-aligned": "##CENTRAL", "duplex": "##DUPLEX", + "transparency unit": "##TRANSPARENCY", "automatic document feeder": "@:source.adf", "automatic document feeder(left aligned)": "@:source.adf (@:source.left-aligned)", diff --git a/packages/server/package-lock.json b/packages/server/package-lock.json index e5399b57..93f0e0b0 100644 --- a/packages/server/package-lock.json +++ b/packages/server/package-lock.json @@ -1,12 +1,12 @@ { "name": "scanservjs-server", - "version": "2.15.0", + "version": "2.15.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "scanservjs-server", - "version": "2.15.0", + "version": "2.15.1", "license": "GPL-2.0", "dependencies": { "adm-zip": "^0.5.5", diff --git a/packages/server/package.json b/packages/server/package.json index 716b600c..73019811 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "scanservjs-server", - "version": "2.15.0", + "version": "2.15.1", "description": "scanservjs is a simple web-based UI for SANE which allows you to share a scanner on a network without the need for drivers or complicated installation.", "scripts": { "lint": "gulp lint", diff --git a/packages/server/src/devices.js b/packages/server/src/devices.js index 60d50823..bcb32965 100644 --- a/packages/server/src/devices.js +++ b/packages/server/src/devices.js @@ -71,9 +71,13 @@ class Devices { devices = []; for (let deviceId of deviceIds) { - const data = await Process.execute(Scanimage.features(deviceId)); - log.debug('Device features: ', data); - devices.push(Device.from(data)); + try { + const data = await Process.execute(Scanimage.features(deviceId)); + log.debug('Device features: ', data); + devices.push(Device.from(data)); + } catch (error) { + log.error(`Ignoring ${deviceId}. Error: ${error}`); + } } file.save(JSON.stringify(devices, null, 2)); } diff --git a/packages/server/src/types.js b/packages/server/src/types.js index 015c9d3f..31a16478 100644 --- a/packages/server/src/types.js +++ b/packages/server/src/types.js @@ -57,7 +57,8 @@ * @typedef {Object} Configuration * @property {string} version * @property {number} port - * @property {ScanDevice} devices + * @property {string[]} devices + * @property {boolean} devicesFind * @property {string} ocrLanguage * @property {string} scanimage * @property {string} convert diff --git a/packages/server/test/resource/scanimage-a7.txt b/packages/server/test/resource/scanimage-a7.txt new file mode 100644 index 00000000..ea380922 --- /dev/null +++ b/packages/server/test/resource/scanimage-a7.txt @@ -0,0 +1,94 @@ +All options specific to device `epson:libusb:001:016': + Scan Mode: + --mode Lineart|Gray|Color [Lineart] + Selects the scan mode (e.g., lineart, monochrome, or color). + --depth 8|16 [inactive] + Number of bits per sample, typical values are 1 for "line-art" and 8 + for multibit scans. + --halftoning None|Halftone A (Hard Tone)|Halftone B (Soft Tone)|Halftone C (Net Screen)|Dither A (4x4 Bayer)|Dither B (4x4 Spiral)|Dither C (4x4 Net Screen)|Dither D (8x4 Net Screen)|Text Enhanced Technology|Download pattern A|Download pattern B [Halftone A (Hard Tone)] + Selects the halftone. + --dropout None|Red|Green|Blue [None] + Selects the dropout. + --brightness -4..3 [0] + Selects the brightness. + --sharpness -2..2 [0] + + --gamma-correction Default|User defined|High density printing|Low density printing|High contrast printing [Default] + Selects the gamma correction value from a list of pre-defined devices + or the user defined table, which can be downloaded to the scanner + --color-correction No Correction|User defined|Impact-dot printers|Thermal printers|Ink-jet printers|CRT monitors [CRT monitors] + Sets the color correction table for the selected output device. + --resolution 50|60|72|75|80|90|100|120|133|144|150|160|175|180|200|216|240|266|300|320|350|360|400|480|600|720|800|900|1200|1600|1800|2400|3200dpi [50] + Sets the resolution of the scanned image. + --threshold 0..255 [inactive] + Select minimum-brightness to get a white point + Advanced: + --mirror[=(yes|no)] [no] + Mirror the image. + --speed[=(yes|no)] [no] + Determines the speed at which the scan proceeds. + --auto-area-segmentation[=(yes|no)] [yes] + + --short-resolution[=(yes|no)] [no] + Display short resolution list + --zoom 50..200 [inactive] + Defines the zoom factor the scanner will use + --red-gamma-table 0..255,... [inactive] + Gamma-correction table for the red band. + --green-gamma-table 0..255,... [inactive] + Gamma-correction table for the green band. + --blue-gamma-table 0..255,... [inactive] + Gamma-correction table for the blue band. + --wait-for-button[=(yes|no)] [no] + After sending the scan command, wait until the button on the scanner + is pressed to actually start the scan process. + Color correction coefficients: + --cct-1 -127..127 [inactive] + Controls green level + --cct-2 -127..127 [inactive] + Adds to red based on green level + --cct-3 -127..127 [inactive] + Adds to blue based on green level + --cct-4 -127..127 [inactive] + Adds to green based on red level + --cct-5 -127..127 [inactive] + Controls red level + --cct-6 -127..127 [inactive] + Adds to blue based on red level + --cct-7 -127..127 [inactive] + Adds to green based on blue level + --cct-8 -127..127 [inactive] + Adds to red based on blue level + --cct-9 -127..127 [inactive] + Controls blue level + Preview: + --preview[=(yes|no)] [no] + Request a preview-quality scan. + --preview-speed[=(yes|no)] [no] + + Geometry: + -l 0..215.9mm [0] + Top-left x position of scan area. + -t 0..297.18mm [0] + Top-left y position of scan area. + -x 0..215.9mm [215.9] + Width of scan-area. + -y 0..297.18mm [297.18] + Height of scan-area. + --quick-format CD|A5 portrait|A5 landscape|Letter|A4|Max [Max] + + Optional equipment: + --source Flatbed|Transparency Unit [Flatbed] + Selects the scan source (such as a document-feeder). + --auto-eject[=(yes|no)] [inactive] + Eject document after scanning + --film-type Positive Film|Negative Film [inactive] + + --focus-position Focus on glass|Focus 2.5mm above glass [Focus on glass] + Sets the focus position to either the glass or 2.5mm above the glass + --bay 1 | 2 | 3 | 4 | 5 | 6 [inactive] + Select bay to scan + --eject [inactive] + Eject the sheet in the ADF + --adf_mode Simplex|Duplex [inactive] + Selects the ADF mode (simplex/duplex)