From ce05ff2de1ac70fcd831f0fd09419d1ee95334f0 Mon Sep 17 00:00:00 2001 From: Pedro Pombeiro Date: Wed, 25 Sep 2024 21:50:18 +0200 Subject: [PATCH 01/19] Clean up Dockerfile --- Dockerfile | 95 +++++++++++++++++++++++++----------------------------- 1 file changed, 44 insertions(+), 51 deletions(-) diff --git a/Dockerfile b/Dockerfile index f31ad4c..99432fe 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,53 +1,51 @@ -#FROM ubuntu:16.04 -FROM ubuntu:22.04 +FROM python:slim-bullseye -RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get -y install tzdata && apt-get -y clean - -RUN apt-get update && apt-get install -y --no-install-recommends apt-utils && apt-get -y clean - -RUN apt-get -y update && apt-get -y upgrade && apt-get -y clean -RUN apt-get -y install \ - sane \ - sane-utils \ +RUN <> /etc/sudoers +RUN <> /etc/sudoers +EOF ENV NAME="Scanner" ENV MODEL="MFC-L2700DW" @@ -55,28 +53,24 @@ ENV IPADDRESS="192.168.1.123" ENV USERNAME="NAS" ENV REMOVE_BLANK_THRESHOLD="0.3" -#only set these variables in the compose file, if inotify needs to be triggered (e.g., for Synology Drive): +# Only set these variables in the compose file, if inotify needs to be triggered (e.g., for Synology Drive): ENV SSH_USER="" ENV SSH_PASSWORD="" ENV SSH_HOST="" ENV SSH_PATH="" -#only set these variables in the compose file, if you need FTP upload: +# Only set these variables in the compose file, if you need FTP upload: ENV FTP_USER="" ENV FTP_PASSWORD="" ENV FTP_HOST="" -#only set these variables in the compose file, if you need Telegram notifications: +# Only set these variables in the compose file, if you need Telegram notifications: ENV TELEGRAM_TOKEN="" ENV TELEGRAM_CHATID="" # Make sure this ends in a slash. ENV FTP_PATH="/scans/" -EXPOSE 54925 -EXPOSE 54921 -EXPOSE 80 - #ADD files/gui/index.php /var/www/html #ADD files/gui/main.css /var/www/html #ADD files/api/scan.php /var/www/html @@ -85,9 +79,8 @@ EXPOSE 80 #ADD files/api/download.php /var/www/html COPY html /var/www/html RUN chown -R www-data /var/www/ + #directory for scans: VOLUME /scans -CMD /opt/brother/runScanner.sh - - +CMD ["bash", "-c", "/opt/brother/runScanner.sh"] From a4d068c7317e25ea0980ebb66d5d62ab4b295f28 Mon Sep 17 00:00:00 2001 From: Pedro Pombeiro Date: Wed, 25 Sep 2024 00:10:02 +0200 Subject: [PATCH 02/19] Convert shell scripts to single Python script # Conflicts: # script/scanRear.sh # script/scantofile-0.2.4-1.sh # script/trigger_telegram.sh --- script/remove_blank.sh | 32 --- script/scanRear.sh | 126 --------- script/scanner.py | 493 ++++++++++++++++++++++++++++++++++ script/scantoemail-0.2.4-1.py | 18 ++ script/scantoemail-0.2.4-1.sh | 16 +- script/scantoemail.py | 1 + script/scantofile-0.2.4-1.py | 18 ++ script/scantofile-0.2.4-1.sh | 105 +------- script/scantofile.py | 1 + script/scantoocr-0.2.4-1.py | 18 ++ script/scantoocr-0.2.4-1.sh | 12 +- script/scantoocr.py | 1 + script/sendtoftps.py | 36 +++ script/sendtoftps.sh | 28 -- script/trigger_inotify.py | 40 +++ script/trigger_inotify.sh | 16 -- script/trigger_telegram.py | 40 +++ script/trigger_telegram.sh | 19 -- 18 files changed, 681 insertions(+), 339 deletions(-) delete mode 100755 script/remove_blank.sh delete mode 100755 script/scanRear.sh create mode 100755 script/scanner.py create mode 100755 script/scantoemail-0.2.4-1.py create mode 120000 script/scantoemail.py create mode 100755 script/scantofile-0.2.4-1.py create mode 120000 script/scantofile.py create mode 100755 script/scantoocr-0.2.4-1.py create mode 120000 script/scantoocr.py create mode 100755 script/sendtoftps.py delete mode 100755 script/sendtoftps.sh create mode 100755 script/trigger_inotify.py delete mode 100755 script/trigger_inotify.sh create mode 100755 script/trigger_telegram.py delete mode 100755 script/trigger_telegram.sh diff --git a/script/remove_blank.sh b/script/remove_blank.sh deleted file mode 100755 index 9a25c1b..0000000 --- a/script/remove_blank.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash -# remove_blank - git.waldenlabs.net/calvinrw/brother-paperless-workflow -# Heavily based on from Anthony Street's (and other contributors') -# StackExchange answer: https://superuser.com/a/1307895 - -if [ -n "$REMOVE_BLANK_THRESHOLD" ]; then - IN="$1" - FILENAME="$(basename "${IN}")" - FILENAME="${FILENAME%.*}" - SCRIPTNAME="remove_blank.sh" - PAGES="$(pdfinfo "$IN" | grep ^Pages: | tr -dc '0-9')" - echo "$SCRIPTNAME: threshold=$REMOVE_BLANK_THRESHOLD; analyzing $PAGES pages" - - cd "$(dirname "$IN")" || exit - pwd - - function non_blank() { - for i in $(seq 1 "$PAGES"); do - PERCENT=$(gs -o - -dFirstPage="${i}" -dLastPage="${i}" -sDEVICE=ink_cov "$IN" | grep CMYK | nawk 'BEGIN { sum=0; } {sum += $1 + $2 + $3 + $4;} END { printf "%.5f\n", sum } ') - if [ $(echo "$PERCENT > $REMOVE_BLANK_THRESHOLD" | bc) -eq 1 ]; then - echo "$i" - echo "Page $i: keep" 1>&2 - else - echo "Page $i: delete" 1>&2 - fi - done | tee "$FILENAME.tmp" - } - - set +x - pdftk "${IN}" cat $(non_blank) output "${FILENAME}_noblank.pdf" && - mv "${FILENAME}_noblank.pdf" "$IN" -fi diff --git a/script/scanRear.sh b/script/scanRear.sh deleted file mode 100755 index 3fa0180..0000000 --- a/script/scanRear.sh +++ /dev/null @@ -1,126 +0,0 @@ -#!/bin/bash -# $1 = scanner device -# $2 = friendly name - -#override environment, as brscan is screwing it up: -export $(grep -v '^#' /opt/brother/scanner/env.txt | xargs) - -resolution="${RESOLUTION:-300}" - -gm_opts=(-page A4+0+0) -if [ "$USE_JPEG_COMPRESSION" = "true" ]; then - gm_opts+=(-compress JPEG -quality 80) -fi - -device="$1" -script_dir="/opt/brother/scanner/brscan-skey/script" -remove_blank="${script_dir}/remove_blank.sh" - -set -e # Exit on error - -mkdir -p /tmp -cd /tmp -date=$(ls -rd */ | grep "$(date +"%Y-%m-%d")" | head -1) -date=${date%/} -tmp_dir="/tmp/${date}" -filename_base="${tmp_dir}/${date}-back-page" -tmp_output_file="${filename_base}%04d.pnm" -tmp_output_pdf_file="${tmp_dir}/${date}.pdf" -output_pdf_file="/scans/${date}.pdf" - -cd "$tmp_dir" - -kill -9 "$(cat scan_pid)" -rm scan_pid - -function scan_cmd() { - # `brother4:net1;dev0` device name gets passed to scanimage, which it refuses as an invalid device name for some reason. - # Let's use the default scanner for now - # scanimage -l 0 -t 0 -x 215 -y 297 --device-name="$1" --resolution="$2" --batch="$3" - scanimage -l 0 -t 0 -x 215 -y 297 --format=pnm --resolution="$2" --batch="$3" -} - -if [ "$(which usleep 2>/dev/null)" != '' ]; then - usleep 100000 -else - sleep 0.1 -fi -scan_cmd "$device" "$resolution" "$tmp_output_file" -if [ ! -s "${filename_base}0001.pnm" ]; then - if [ "$(which usleep 2>/dev/null)" != '' ]; then - usleep 1000000 - else - sleep 1 - fi - scan_cmd "$device" "$resolution" "$tmp_output_file" -fi - -( - - #rename pages: - numberOfPages=$(find . -maxdepth 1 -name "*front-page*" | wc -l) - echo "number of pages scanned: $numberOfPages" - - cnt=0 - for filename in *front*.pnm; do - cnt=$((cnt + 1)) - cntFormatted=$(printf "%03d" $cnt) - if [[ $filename = *"front"* ]]; then - mv "$filename" "index${cntFormatted}-1-${filename}" - fi - done - cnt=0 - for filename in *back*.pnm; do - cnt=$((cnt + 1)) - if [[ $filename = *"back"* ]]; then - rearIndex=$((numberOfPages - cnt + 1)) - rearIndexFormatted=$(printf "%03d" $rearIndex) - mv "$filename" "index${rearIndexFormatted}-2-${filename}" - fi - done - - ( - echo "converting to PDF for $date..." - gm convert ${gm_opts[@]} ./*.pnm "$tmp_output_pdf_file" - ${script_dir}/trigger_inotify.sh "${SSH_USER}" "${SSH_PASSWORD}" "${SSH_HOST}" "${SSH_PATH}" "${output_pdf_file}" - ${script_dir}/trigger_telegram.sh "${date}.pdf (rear) scanned" - ${script_dir}/sendtoftps.sh \ - "${FTP_USER}" \ - "${FTP_PASSWORD}" \ - "${FTP_HOST}" \ - "${FTP_PATH}" \ - "${output_pdf_file}" - - $remove_blank "$tmp_output_pdf_file" - mv "$tmp_output_pdf_file" "$output_pdf_file" - - $script_dir/trigger_inotify.sh "${SSH_USER}" "${SSH_PASSWORD}" "${SSH_HOST}" "${SSH_PATH}" "${output_pdf_file}" - - echo "cleaning up for $date..." - cd /scans || exit - rm -rf "$tmp_dir" - - if [ -z "${OCR_SERVER}" ] || [ -z "${OCR_PORT}" ] || [ -z "${OCR_PATH}" ]; then - echo "OCR environment variables not set, skipping OCR." - else - echo "starting OCR for $date..." - ( - curl -F "userfile=@${output_pdf_file}" -H "Expect:" -o "/scans/${date}-ocr.pdf" "${OCR_SERVER}":"${OCR_PORT}"/"${OCR_PATH}" - ${script_dir}/trigger_inotify.sh "${SSH_USER}" "${SSH_PASSWORD}" "${SSH_HOST}" "${SSH_PATH}" "${date}-ocr.pdf" - ${script_dir}/trigger_telegram.sh "${date}-ocr.pdf (rear) OCR finished" - ${script_dir}/sendtoftps.sh \ - "${FTP_USER}" \ - "${FTP_PASSWORD}" \ - "${FTP_HOST}" \ - "${FTP_PATH}" \ - "/scans/${date}-ocr.pdf" - - if [ "${REMOVE_ORIGINAL_AFTER_OCR}" == "true" ]; then - if [ -f "/scans/${date}-ocr.pdf" ]; then - rm ${output_pdf_file} - fi - fi - ) & - fi - ) & -) & diff --git a/script/scanner.py b/script/scanner.py new file mode 100755 index 0000000..58a1f79 --- /dev/null +++ b/script/scanner.py @@ -0,0 +1,493 @@ +#!/usr/bin/python3 +# $1 = scanner device +# $2 = friendly name + +import glob +import os +import re +import shutil +import signal +import subprocess +import sys +import tempfile +import time +from datetime import datetime +from typing import List, TextIO + +from sendtoftps import sendtoftps +from trigger_inotify import trigger_inotify +from trigger_telegram import trigger_telegram + +ENVIRONMENT_FILE_PATH = "/opt/brother/scanner/env.txt" +SCRIPT_DIR = "/opt/brother/scanner/brscan-skey/script" +SCAN_DIR = "/scans" +GM_COMPRESSED_JPEG_SETTINGS = ["-compress", "JPEG", "-quality", "80"] + + +# +# Utility methods +# + + +def read_environment() -> None: + # Read the environment variables from the file, + # as brscan is screwing it up + with open(ENVIRONMENT_FILE_PATH, "r") as f: + for line in f: + if not line.startswith("#"): # Skip comments + key, value = line.strip().split("=") + os.environ[key] = value + + +def execute_command(log: TextIO, command: List[str], **kwargs) -> None: + log.flush() + print(f" DEBUG: Executing command: {command}, kwargs={kwargs}") + log.flush() + + subprocess.run(command, text=True, stdout=log, stderr=log, **kwargs) + + +def execute_command_pid(log: TextIO, command: List[str], **kwargs) -> int: + log.flush() + print(f" DEBUG: Executing command: {command}, kwargs={kwargs}") + log.flush() + + process = subprocess.Popen( + command, start_new_session=True, text=True, stdout=log, stderr=log, **kwargs + ) + return process.pid + + +def scan_cmd( + log: TextIO, device: str, output_batch: str, scanimage_args: List[str] +) -> None: + log.flush() # Required, otherwise scanimage output will appear before the already printed output + + resolution = os.environ.get("RESOLUTION", 300) + # `brother4:net1;dev0` device name gets passed to scanimage, which it refuses as an invalid device name for some reason. + # Let's use the default scanner for now + # fmt: off + scan_command = [ + "scanimage", + "-l", "0", "-t", "0", "-x", "215", "-y", "297", + "--format=pnm", + *scanimage_args, + f"--resolution={resolution}", + f"--batch={output_batch}", + ] + # fmt: on + execute_command(log, scan_command, check=True) + + +def notify(log: TextIO, file_path: str, message: str) -> None: + trigger_inotify( + log, + os.getenv("SSH_USER"), + os.getenv("SSH_PASSWORD"), + os.getenv("SSH_HOST"), + os.getenv("SSH_PATH"), + file_path, + ) + trigger_telegram( + log, + os.getenv("TELEGRAM_TOKEN"), + os.getenv("TELEGRAM_CHATID"), + f"Scanner: {message}", + ) + + +def latest_batch_dir() -> str: + prefix = datetime.today().strftime("%Y-%m-%d") + dir_entries = glob.glob(os.path.join(tempfile.gettempdir(), f"{prefix}*")) + dirs = filter(os.path.isdir, dir_entries) + sorted_dirs = sorted(dirs, key=os.path.getctime) + if len(sorted_dirs) == 0: + return None + return os.path.basename(sorted_dirs[-1]) + + +def move_across_mounts(source: str, destination: str) -> None: + """Moves a file across mounts. + + Args: + source (str): The source path. + destination (str): The destination path. + """ + + try: + print(f" DEBUG: Moving {source} to {destination}") + shutil.copy2(source, destination) + os.remove(source) + except Exception as e: + print(f" ERROR: moving file - {e}") + + +# +# PDF manipulation methods +# +def remove_blank_pages( + log: TextIO, input_file: str, remove_blank_threshold: float +) -> None: + """Removes blank pages from a PDF file based on a threshold. + + remove_blank - git.waldenlabs.net/calvinrw/brother-paperless-workflow + Heavily based on from Anthony Street's (and other contributors') + StackExchange answer: https://superuser.com/a/1307895 + + Args: + input_file (str): The path to the input PDF file. + remove_blank_threshold (float): The threshold for ink coverage to consider a page non-blank. + """ + + filename = os.path.splitext(os.path.basename(input_file))[0] + dirname = os.path.dirname(input_file) + + # Get the number of pages in the PDF + process = subprocess.Popen( + ["pdfinfo", input_file], stdout=subprocess.PIPE, stderr=log + ) + output, _ = process.communicate() + if process.returncode != 0: + print(f" ERROR: getting number of pages from {input_file}: {output}") + return + pages_line = re.search(r"^Pages:\s*(\d+)", output.decode(), re.MULTILINE) + page_count = int(pages_line.group(1)) + + print( + f" Analyzing {page_count} pages in {input_file} with threshold {remove_blank_threshold}%" + ) + os.chdir(dirname) + + def non_blank_pages() -> List[str]: + picked_pages = [] + for page in range(1, page_count + 1): + # Use subprocess to run gs and get ink coverage + process = subprocess.Popen( + [ + "gs", + "-o", + "-", + f"-dFirstPage={page}", + f"-dLastPage={page}", + "-sDEVICE=ink_cov", + input_file, + ], + stdout=subprocess.PIPE, + stderr=log, + ) + output, _ = process.communicate() + ink_coverage_line = re.search( + r"^\s*([\d\.]+)\s+([\d\.]+)\s+([\d\.]+)\s+([\d\.]+)\s+CMYK", + output.decode(), + re.MULTILINE, + ) + ink_coverage = sum(map(float, ink_coverage_line.groups())) + + if ink_coverage < remove_blank_threshold: + print(f" Page {page}: delete (ink coverage: {ink_coverage:.2f}%)") + else: + picked_pages += str(page) + print(f" Page {page}: keep (ink coverage: {ink_coverage:.2f}%)") + + return picked_pages + + # Use pdftk to remove pages + try: + output_file = os.path.join(dirname, f"{filename}_noblank.pdf") + selected_pages = non_blank_pages() + command = [ + "/usr/bin/pdftk", + input_file, + "cat", + *selected_pages, + "output", + output_file, + ] + execute_command(log, command, check=True) + + removed_pages = page_count - len(selected_pages) + if removed_pages == 0: + print(f" No blank pages detected in {input_file}") + else: + os.replace(output_file, input_file) + print(f" Removed {removed_pages} blank pages and saved as {input_file}") + except FileNotFoundError: + print( + f" WARNING: '{command[0]}' executable not found. Skipping PDF manipulation." + ) + except subprocess.CalledProcessError: + print(f" ERROR: manipulating {input_file}. Skipping PDF manipulation.") + + +# +# Async job methods +# +def convert_and_post_process( + job_name: str, side: str, remove_blank_threshold: float +) -> None: + log = sys.stdout + log.flush() + + print(f" {side} side: converting to PDF for {job_name}...") + + # Find job pages, sorted in the correct order + job_dir = os.path.join(tempfile.gettempdir(), job_name) + tmp_output_pdf_file = os.path.join(job_dir, f"{job_name}.pdf") + output_pdf_file = os.path.join(SCAN_DIR, f"{job_name}.pdf") + if side == "front": + filepath_base = os.path.join(job_dir, f"{job_name}-{side}-page") + input_files = glob.glob(f"{filepath_base}*.pnm") + else: + input_files = glob.glob(os.path.join(job_dir, "*.pnm")) + input_files.sort() + + # Convert pages to single PDF with optional JPEG compression + gm_opts = [] + if os.environ.get("USE_JPEG_COMPRESSION", "false") == "true": + gm_opts += GM_COMPRESSED_JPEG_SETTINGS + execute_command( + log, ["gm", "convert", *gm_opts, *input_files, tmp_output_pdf_file], check=True + ) + + if remove_blank_threshold: + remove_blank_pages(log, tmp_output_pdf_file, remove_blank_threshold) + + move_across_mounts(tmp_output_pdf_file, output_pdf_file) + + notify(log, output_pdf_file, f"{job_name}.pdf ({side}) scanned") + + # Cleanup temporary files + print(f" {side} side: cleaning up for {job_name}...") + subprocess.run( + f"rm -rf '{job_dir}' {tempfile.gettempdir()}/brscan_jpeg_*", + shell=True, + check=True, + stdout=log, + stderr=log, + ) + + # Check for OCR environment variables + ocr_server = os.getenv("OCR_SERVER") + ocr_port = os.getenv("OCR_PORT") + ocr_path = os.getenv("OCR_PATH") + + if not any([ocr_server, ocr_port, ocr_path]): + print(f" {side} side: OCR environment variables not set, skipping OCR.") + else: + ocr_pdf_name = f"{job_name}-ocr.pdf" + ocr_pdf_path = os.path.join(SCAN_DIR, ocr_pdf_name) + + # Perform OCR in the background + print(f" {side} side: starting OCR for {job_name}...") + execute_command( + log, + [ + "curl", + "-F", + "userfile=@${output_pdf_file}", + "-H", + "Expect:", + "-o", + ocr_pdf_path, + f"{ocr_server}:{ocr_port}/{ocr_path}", + ], + check=True, + ) + + notify(log, ocr_pdf_name, f"{ocr_pdf_name} ({side}) OCR finished") + sendtoftps( + log, + os.getenv("FTP_USER"), + os.getenv("FTP_PASSWORD"), + os.getenv("FTP_HOST"), + os.getenv("FTP_PATH"), + ocr_pdf_path, + ) + + if os.getenv("REMOVE_ORIGINAL_AFTER_OCR") == "true" and os.path.isfile( + ocf_pdf_path + ): + os.remove(output_pdf_file) + + print(f" {side} side: Conversion and post-processing for finished.") + print("-----------------------------------") + + +def wait_for_rear_pages_or_convert(job_name: str) -> None: + # Wait for 2 minutes in case there is a rear side scan + print( + f" front side: Waiting for 2 minutes before starting file conversion for {job_name}" + ) + time.sleep(120) + + convert_and_post_process(job_name, "front", None) + + +# +# Reading/writing of temp state files +# + + +def scanimage_args_path(job_dir: str) -> str: + # File where the arguments to scanimage are saved across steps in the job + return os.path.join(job_dir, ".scanimage_args") + + +def save_scanimage_args(job_dir: str, scanimage_args: List[str]) -> None: + # Save scanimage_args in a file for use with future rear side scans + path = scanimage_args_path(job_dir) + with open(path, "w") as scanimage_args_file: + for arg in scanimage_args: + scanimage_args_file.write(arg + "\n") + + +def read_scanimage_args(job_dir: str) -> List[str]: + # Read scanimage_args used for front scanning + path = scanimage_args_path(job_dir) + scanimage_args = [] + try: + with open(path, "r") as scanimage_args_file: + scanimage_args = [line.rstrip() for line in scanimage_args_file] + + os.remove(path) + except FileNotFoundError: + print(f" ERROR: scanimage_args file {path} not found.") + + return scanimage_args + + +def scan_pid_path(job_dir: str) -> str: + return os.path.join(job_dir, ".scan_pid") + + +def save_front_processing_pid(job_dir: str, pid: int) -> None: + with open(scan_pid_path(job_dir), "w") as pid_file: + pid_file.write(str(pid)) + + +def kill_front_processing_from_pid(job_dir: str) -> int: + path = scan_pid_path(job_dir) + pid = None + try: + with open(path, "r") as scan_pid_file: + pid = int(scan_pid_file.read().strip()) + print( + f" rear side: Read pid from {path}, killing front processing job {pid}" + ) + os.kill(pid, signal.SIGKILL) + except FileNotFoundError: + print(" rear side: ERROR: scan_pid file {path} not found.") + except ProcessLookupError: + print(" rear side: ERROR: process with pid {pid} not found.") + else: + os.remove(path) + return pid + + return None + + +# +# Scan entry points +# +def scan_front(log: TextIO, device: str, scanimage_args=[]) -> None: + job_name = datetime.now().strftime("%Y-%m-%d-%H-%M-%S") # Generate unique timestamp + job_dir = os.path.join(tempfile.gettempdir(), job_name) + filepath_base = os.path.join(job_dir, f"{job_name}-front-page") + tmp_output_batch = f"{filepath_base}%04d.pnm" + + # Create temporary directory + os.makedirs(job_dir, exist_ok=True) + os.chdir(job_dir) + print(f"- Scanning front to batch {tmp_output_batch}") + + # Save scanimage_args in a file for use with future rear side scans + save_scanimage_args(job_dir, scanimage_args) + + # Perform scan with retry + time.sleep(0.1) + scan_cmd(log, device, tmp_output_batch, scanimage_args) + if not os.path.exists(f"{filepath_base}0001.pnm"): + time.sleep(1) # Short delay before retry + scan_cmd(log, device, tmp_output_batch, scanimage_args) + + # Run conversion process in the background + pid = os.fork() + if pid == 0: # Child process + wait_for_rear_pages_or_convert(job_name) + os._exit(0) # Exit child process cleanly + elif pid > 0: + save_front_processing_pid(job_dir, pid) + print( + f" front side: INFO: Waiting to start conversion process for {job_name} in process with PID {pid}" + ) + else: + print(f" front side: ERROR: Fork failed ({pid}).") + + +def scan_rear(log: TextIO, device: str, scanimage_args=None) -> None: + # Find latest directory in temp directory + job_name = latest_batch_dir() + print(f"- Scanning rear to latest batch {job_name}") + if job_name is None: + print(" rear side: ERROR: Could not find front scan directory") + return + + print(f" rear side: Found front-side batch: {job_name}") + job_dir = os.path.join(tempfile.gettempdir(), job_name) + filepath_base = os.path.join(job_dir, f"{job_name}-back-page") + tmp_output_batch = f"{filepath_base}%04d.pnm" + + os.chdir(job_dir) + + # Interrupt front scanning process which is waiting from a rear side scan + if kill_front_processing_from_pid(job_dir) is None: + return + + if scanimage_args is None: + # Read scanimage_args used for front scanning + scanimage_args = read_scanimage_args(job_dir) + + # Perform scan with retry + time.sleep(0.1) + scan_cmd(log, device, tmp_output_batch, scanimage_args) + if not os.path.exists(f"{filepath_base}0001.pnm"): + time.sleep(1) # Short delay before retry + scan_cmd(log, device, tmp_output_batch, scanimage_args) + + # Rename pages + number_of_pages = len( + [f for f in os.listdir(".") if (os.path.isfile(f) and "front-page" in f)] + ) + print(f" rear side: INFO: number of pages scanned: {number_of_pages}") + + cnt = 0 + for filename in glob.glob("*front*.pnm"): + cnt += 1 + cnt_formatted = f"{cnt:03d}" + os.rename(filename, f"index{cnt_formatted}-1-{filename}") + print( + f" rear side: DEBUG: renamed {filename} to index{cnt_formatted}-1-{filename}" + ) + + cnt = 0 + for filename in glob.glob("*back*.pnm"): + cnt += 1 + rear_index = number_of_pages - cnt + 1 + rear_index_formatted = f"{rear_index:03d}" + os.rename(filename, f"index{rear_index_formatted}-2-{filename}") + print( + f" rear side: DEBUG: renamed {filename} to index{rear_index_formatted}-2-{filename}" + ) + + # Convert to PDF + remove_blank_threshold = os.getenv("REMOVE_BLANK_THRESHOLD") + if remove_blank_threshold: + remove_blank_threshold = float(remove_blank_threshold) + + pid = os.fork() + if pid == 0: # Child process + convert_and_post_process(job_name, "rear", remove_blank_threshold) + os._exit(0) # Exit child process cleanly + + elif pid < 0: + print(f" rear side: ERROR: Fork failed ({pid}).") diff --git a/script/scantoemail-0.2.4-1.py b/script/scantoemail-0.2.4-1.py new file mode 100755 index 0000000..dcdecdb --- /dev/null +++ b/script/scantoemail-0.2.4-1.py @@ -0,0 +1,18 @@ +#!/usr/bin/python3 +# $1 = scanner device +# $2 = friendly name + +import sys + +from scanner import read_environment, scan_rear + +if __name__ == "__main__": + # Open the log file in append mode + with open("/var/log/scanner.log", "a") as f: + # Redirect stdout to the log file + sys.stdout = f + + read_environment() + + device = sys.argv[1] + scan_rear(f, device) diff --git a/script/scantoemail-0.2.4-1.sh b/script/scantoemail-0.2.4-1.sh index 2090633..003ce1d 100755 --- a/script/scantoemail-0.2.4-1.sh +++ b/script/scantoemail-0.2.4-1.sh @@ -2,15 +2,9 @@ # $1 = scanner device # $2 = friendly name -{ - echo "scantoemail.sh triggered" - #override environment, as brscan is screwing it up: - export $(grep -v '^#' /opt/brother/scanner/env.txt | xargs) +SCRIPTPATH="$( + cd "$(dirname "$0")" || exit + pwd -P +)" - SCRIPTPATH="$( - cd "$(dirname "$0")" || exit - pwd -P - )" - /bin/bash "$SCRIPTPATH"/scanRear.sh $@ - -} >>/var/log/scanner.log 2>&1 +"$SCRIPTPATH"/scantoemail.py $@ diff --git a/script/scantoemail.py b/script/scantoemail.py new file mode 120000 index 0000000..672e1fb --- /dev/null +++ b/script/scantoemail.py @@ -0,0 +1 @@ +scantoemail-0.2.4-1.py \ No newline at end of file diff --git a/script/scantofile-0.2.4-1.py b/script/scantofile-0.2.4-1.py new file mode 100755 index 0000000..056fac9 --- /dev/null +++ b/script/scantofile-0.2.4-1.py @@ -0,0 +1,18 @@ +#!/usr/bin/python3 +# $1 = scanner device +# $2 = friendly name + +import sys + +from scanner import read_environment, scan_front + +if __name__ == "__main__": + # Open the log file in append mode + with open("/var/log/scanner.log", "a") as f: + # Redirect stdout to the log file + sys.stdout = f + + read_environment() + + device = sys.argv[1] + scan_front(f, device) diff --git a/script/scantofile-0.2.4-1.sh b/script/scantofile-0.2.4-1.sh index 4e8c770..745b9f4 100755 --- a/script/scantofile-0.2.4-1.sh +++ b/script/scantofile-0.2.4-1.sh @@ -2,104 +2,9 @@ # $1 = scanner device # $2 = friendly name -{ - #override environment, as brscan is screwing it up: - export $(grep -v '^#' /opt/brother/scanner/env.txt | xargs) +SCRIPTPATH="$( + cd "$(dirname "$0")" || exit + pwd -P +)" - resolution="${RESOLUTION:-300}" - - gm_opts=(-page A4+0+0) - if [ "$USE_JPEG_COMPRESSION" = "true" ]; then - gm_opts+=(-compress JPEG -quality 80) - fi - - device="$1" - date=$(date +%Y-%m-%d-%H-%M-%S) - script_dir="/opt/brother/scanner/brscan-skey/script" - tmp_dir="/tmp/$date" - filename_base="${tmp_dir}/${date}-front-page" - tmp_output_file="${filename_base}%04d.pnm" - output_pdf_file="/scans/${date}.pdf" - - set -e # Exit on error - - mkdir -p "$tmp_dir" - cd "$tmp_dir" - filename_base="/tmp/${date}/${date}-front-page" - output_file="${filename_base}%04d.pnm" - echo "filename: $tmp_output_file" - - function scan_cmd() { - # `brother4:net1;dev0` device name gets passed to scanimage, which it refuses as an invalid device name for some reason. - # Let's use the default scanner for now - # scanimage -l 0 -t 0 -x 215 -y 297 --device-name="$1" --resolution="$2" --batch="$3" - scanimage -l 0 -t 0 -x 215 -y 297 --format=pnm --resolution="$2" --batch="$3" - } - - if [ "$(which usleep 2>/dev/null)" != '' ]; then - usleep 100000 - else - sleep 0.1 - fi - scan_cmd "$device" "$resolution" "$tmp_output_file" - if [ ! -s "${filename_base}0001.pnm" ]; then - if [ "$(which usleep 2>/dev/null)" != '' ]; then - usleep 1000000 - else - sleep 1 - fi - scan_cmd "$device" "$resolution" "$tmp_output_file" - fi - - #only convert when no back pages are being scanned: - ( - if [ "$(which usleep 2>/dev/null)" != '' ]; then - usleep 120000000 - else - sleep 120 - fi - - ( - echo "converting to PDF for $date..." - gm convert ${gm_opts[@]} "$filename_base"*.pnm "$output_pdf_file" - ${script_dir}/trigger_inotify.sh "${SSH_USER}" "${SSH_PASSWORD}" "${SSH_HOST}" "${SSH_PATH}" "${output_pdf_file}" - ${script_dir}/trigger_telegram.sh "${date}.pdf (front) scanned" - ${script_dir}/sendtoftps.sh \ - "${FTP_USER}" \ - "${FTP_PASSWORD}" \ - "${FTP_HOST}" \ - "${FTP_PATH}" \ - "${output_pdf_file}" - - echo "cleaning up for $date..." - cd /scans || exit - rm -rf "$tmp_dir" - - if [ -z "${OCR_SERVER}" ] || [ -z "${OCR_PORT}" ] || [ -z "${OCR_PATH}" ]; then - echo "OCR environment variables not set, skipping OCR." - else - echo "starting OCR for $date..." - ( - curl -F "userfile=@${output_pdf_file}" -H "Expect:" -o "/scans/${date}-ocr.pdf" "${OCR_SERVER}":"${OCR_PORT}"/"${OCR_PATH}" - ${script_dir}/trigger_inotify.sh "${SSH_USER}" "${SSH_PASSWORD}" "${SSH_HOST}" "${SSH_PATH}" "${date}-ocr.pdf" - ${script_dir}/trigger_telegram.sh "${date}-ocr.pdf (front) OCR finished" - ${script_dir}/sendtoftps.sh \ - "${FTP_USER}" \ - "${FTP_PASSWORD}" \ - "${FTP_HOST}" \ - "${FTP_PATH}" \ - "/scans/${date}-ocr.pdf" - - if [ "${REMOVE_ORIGINAL_AFTER_OCR}" == "true" ]; then - if [ -f "/scans/${date}-ocr.pdf" ]; then - rm ${output_pdf_file} - fi - fi - ) & - fi - ) & - ) & - echo $! >scan_pid - echo "conversion process for $date is running in PID: $(cat scan_pid)" - -} >>/var/log/scanner.log 2>&1 +"$SCRIPTPATH"/scantofile.py $@ diff --git a/script/scantofile.py b/script/scantofile.py new file mode 120000 index 0000000..64bff2a --- /dev/null +++ b/script/scantofile.py @@ -0,0 +1 @@ +scantofile-0.2.4-1.py \ No newline at end of file diff --git a/script/scantoocr-0.2.4-1.py b/script/scantoocr-0.2.4-1.py new file mode 100755 index 0000000..faa6508 --- /dev/null +++ b/script/scantoocr-0.2.4-1.py @@ -0,0 +1,18 @@ +#!/usr/bin/python3 +# $1 = scanner device +# $2 = friendly name + +import sys + +from scanner import read_environment, scan_front + +if __name__ == "__main__": + # Open the log file in append mode + with open("/var/log/scanner.log", "a") as f: + # Redirect stdout to the log file + sys.stdout = f + + read_environment() + + device = sys.argv[1] + scan_front(f, device, ["--mode=True Gray"]) diff --git a/script/scantoocr-0.2.4-1.sh b/script/scantoocr-0.2.4-1.sh index fc86ca2..f918b8c 100755 --- a/script/scantoocr-0.2.4-1.sh +++ b/script/scantoocr-0.2.4-1.sh @@ -2,11 +2,9 @@ # $1 = scanner device # $2 = friendly name -{ +SCRIPTPATH="$( + cd "$(dirname "$0")" || exit + pwd -P +)" - echo "ERROR!" - echo "This function is not implemented." - echo "You may implement your own script and mount under $0." - echo "Check out scripts in same folder or https://github.com/PhilippMundhenk/BrotherScannerDocker for examples." - -} >>/var/log/scanner.log 2>&1 +"$SCRIPTPATH"/scantoocr.py $@ diff --git a/script/scantoocr.py b/script/scantoocr.py new file mode 120000 index 0000000..ccdc918 --- /dev/null +++ b/script/scantoocr.py @@ -0,0 +1 @@ +scantoocr-0.2.4-1.py \ No newline at end of file diff --git a/script/sendtoftps.py b/script/sendtoftps.py new file mode 100755 index 0000000..b13a834 --- /dev/null +++ b/script/sendtoftps.py @@ -0,0 +1,36 @@ +#!/usr/bin/python3 + + +def sendtoftps(log, user, password, address, filepath, file): + """Uploads a file to an FTP server. + + Args: + user (str): The FTP username. + password (str): The FTP password. + address (str): The FTP address. + filepath (str): The file path on the FTP server. + file (str): The file to upload. + """ + + command = [ + "curl", + "--silent", + "--show-error", + "--ssl-reqd", + "--user", + f"{user}:{password}", + "--upload-file", + file, + f"ftp://{address}{filepath}", + ] + + try: + subprocess.run(command, check=True, stdout=log, stderr=log) + print(f"Uploading to FTP server {address} successful.") + except subprocess.CalledProcessError: + print("Uploading to FTP failed while using curl") + print(f"user: {user}") + print(f"address: {address}") + print(f"filepath: {filepath}") + print(f"file: {file}") + exit(1) diff --git a/script/sendtoftps.sh b/script/sendtoftps.sh deleted file mode 100755 index f2106ec..0000000 --- a/script/sendtoftps.sh +++ /dev/null @@ -1,28 +0,0 @@ -user=$1 -password=$2 -address=$3 -filepath=$4 -file=$5 - -cd /scans - -if [ -z "${user}" ] || [ -z "${password}" ] || [ -z "${address}" ] || [ -z "${filepath}" ] || [ -z "${file}" ]; then - echo "FTP environment variables not set, skipping inotify trigger." -else - if curl --silent \ - --show-error \ - --ssl-reqd \ - --user "${user}:${password}" \ - --upload-file "${file}" \ - "ftp://${address}${filepath}" ; then - echo "Uploading to ftp server ${address} successful." - else - echo "Uploading to ftp failed while using curl" - echo "user: ${user}" - echo "address: ${address}" - echo "filepath: ${filepath}" - echo "file: ${file}" - exit 1 - fi -fi - diff --git a/script/trigger_inotify.py b/script/trigger_inotify.py new file mode 100755 index 0000000..ad5897c --- /dev/null +++ b/script/trigger_inotify.py @@ -0,0 +1,40 @@ +#!/usr/bin/python3 + +import subprocess +from typing import TextIO + + +def trigger_inotify( + log: TextIO, user: str, password: str, address: str, filepath: str, file: str +) -> None: + """Triggers inotify for a file. + + Args: + user (str): The SSH username. + password (str): The SSH password. + address (str): The SSH address. + filepath (str): The file path. + file (str): The file name. + """ + + if not user or not password or not address or not filepath: + print(" INFO: SSH environment variables not set, skipping inotify trigger.") + return + + command = [ + "sshpass", + "-p", + password, + "ssh", + "-o", + "StrictHostKeyChecking=no", + f"{user}@{address}", + f'sed "" -i {filepath}/{file}', + ] + + try: + subprocess.run(command, check=True, stdout=log, stderr=log) + print("Trigger inotify successful") + except subprocess.CalledProcessError: + print("Trigger inotify failed") + exit(1) diff --git a/script/trigger_inotify.sh b/script/trigger_inotify.sh deleted file mode 100755 index 4077b22..0000000 --- a/script/trigger_inotify.sh +++ /dev/null @@ -1,16 +0,0 @@ -user=$1 -password=$2 -address=$3 -filepath=$4 -file=$5 - -if [ -z "${user}" ] || [ -z "${password}" ] || [ -z "${address}" ] || [ -z "${filepath}" ]; then - echo "SSH environment variables not set, skipping inotify trigger." -else - if sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$user"@"$address" "sed \"\" -i $filepath/$file"; then - echo "trigger inotify successful" - else - echo "trigger inotify failed" - exit 1 - fi -fi diff --git a/script/trigger_telegram.py b/script/trigger_telegram.py new file mode 100755 index 0000000..494d75e --- /dev/null +++ b/script/trigger_telegram.py @@ -0,0 +1,40 @@ +#!/usr/bin/python3 + +import os +import urllib.parse +from typing import TextIO + + +def trigger_telegram(log: TextIO, token: str, chat_id: str, message: str) -> None: + """Sends a Telegram message using the provided token and chat ID.""" + + if not token or not chat_id: + print( + " INFO: TELEGRAM_TOKEN or TELEGRAM_CHATID environment variables not set, skipping Telegram trigger." + ) + exit(1) + + # URL encode the message + encoded_message = urllib.parse.quote(message, safe="") + + # Build the URL + url = f"https://api.telegram.org/{token}/sendMessage" + + # Prepare data payload + payload = {"chat_id": chat_id, "text": encoded_message} + + # Use requests library for a more robust solution (install with 'pip install requests') + try: + import requests + + response = requests.post(url, json=payload) + response.raise_for_status() # Raise an exception for non-200 response + print(" Telegram message sent successfully.") + except ModuleNotFoundError: + print(" WARNING: 'requests' library not found. Using wget fallback.") + # Fallback using wget (not recommended for production due to limited feedback) + os.system( + f"wget -qO- --post-data='chat_id={chat_id}&text={encoded_message}' '{url}' >/dev/null" + ) + except requests.exceptions.RequestException as e: + print(f" ERROR: sending Telegram message: {e}") diff --git a/script/trigger_telegram.sh b/script/trigger_telegram.sh deleted file mode 100755 index ea4e3c2..0000000 --- a/script/trigger_telegram.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -# Check if TELEGRAM_TOKEN and TELEGRAM_CHATID are both set -if [ -z "${TELEGRAM_TOKEN}" ] || [ -z "${TELEGRAM_CHATID}" ]; then - echo "TELEGRAM_TOKEN or TELEGRAM_CHATID environment variables not set, skipping Telegram trigger." -else - # Use the environment variables TELEGRAM_TOKEN and TELEGRAM_CHATID - TOKEN="$TELEGRAM_TOKEN" - CHAT_ID="$TELEGRAM_CHATID" - - # The message is passed as a parameter - MESSAGE="Scanner: $1" - - # URL encode the message to handle spaces and special characters - ENCODED_MESSAGE=$(echo "$MESSAGE" | jq -sRr @uri) - - # Send the message using wget - wget -qO- --post-data="chat_id=$CHAT_ID&text=$ENCODED_MESSAGE" "https://api.telegram.org/$TOKEN/sendMessage" >/dev/null -fi From 83664c07bf9ddb7dbcf863dd6524fdbd06744dd0 Mon Sep 17 00:00:00 2001 From: Pedro Pombeiro Date: Wed, 25 Sep 2024 21:57:18 +0200 Subject: [PATCH 03/19] Add possibility to override brscan-skey.config --- files/brscan-skey.config | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 files/brscan-skey.config diff --git a/files/brscan-skey.config b/files/brscan-skey.config new file mode 100644 index 0000000..ec298ea --- /dev/null +++ b/files/brscan-skey.config @@ -0,0 +1,8 @@ +password= +IMAGE="bash /opt/brother/scanner/brscan-skey/script/scantoimage.sh" +OCR="bash /opt/brother/scanner/brscan-skey/script/scantoocr.sh" +EMAIL="bash /opt/brother/scanner/brscan-skey/script/scantoemail.sh" +FILE="bash /opt/brother/scanner/brscan-skey/script/scantofile.sh" +SEMID=b +eth= +ip_address= From d136280a711949307535fbe951face966b759805 Mon Sep 17 00:00:00 2001 From: Pedro Pombeiro Date: Sun, 29 Sep 2024 11:41:18 +0200 Subject: [PATCH 04/19] Completely remove shell scripts --- files/brscan-skey.config | 8 ++++---- html/scan.php | 6 +++--- script/scantoemail-0.2.4-1.py | 18 ------------------ script/scantoemail-0.2.4-1.sh | 10 ---------- script/scantoemail.py | 22 +++++++++++++++++++++- script/scantoemail.sh | 1 - script/scantofile-0.2.4-1.py | 18 ------------------ script/scantofile-0.2.4-1.sh | 10 ---------- script/scantofile.py | 22 +++++++++++++++++++++- script/scantofile.sh | 1 - script/scantoimage-0.2.4-1.sh | 12 ------------ script/scantoimage.py | 19 +++++++++++++++++++ script/scantoimage.sh | 1 - script/scantoocr-0.2.4-1.py | 18 ------------------ script/scantoocr-0.2.4-1.sh | 10 ---------- script/scantoocr.py | 22 +++++++++++++++++++++- script/scantoocr.sh | 1 - 17 files changed, 89 insertions(+), 110 deletions(-) delete mode 100755 script/scantoemail-0.2.4-1.py delete mode 100755 script/scantoemail-0.2.4-1.sh mode change 120000 => 100755 script/scantoemail.py delete mode 120000 script/scantoemail.sh delete mode 100755 script/scantofile-0.2.4-1.py delete mode 100755 script/scantofile-0.2.4-1.sh mode change 120000 => 100755 script/scantofile.py delete mode 120000 script/scantofile.sh delete mode 100755 script/scantoimage-0.2.4-1.sh create mode 100755 script/scantoimage.py delete mode 120000 script/scantoimage.sh delete mode 100755 script/scantoocr-0.2.4-1.py delete mode 100755 script/scantoocr-0.2.4-1.sh mode change 120000 => 100755 script/scantoocr.py delete mode 120000 script/scantoocr.sh diff --git a/files/brscan-skey.config b/files/brscan-skey.config index ec298ea..02029c1 100644 --- a/files/brscan-skey.config +++ b/files/brscan-skey.config @@ -1,8 +1,8 @@ password= -IMAGE="bash /opt/brother/scanner/brscan-skey/script/scantoimage.sh" -OCR="bash /opt/brother/scanner/brscan-skey/script/scantoocr.sh" -EMAIL="bash /opt/brother/scanner/brscan-skey/script/scantoemail.sh" -FILE="bash /opt/brother/scanner/brscan-skey/script/scantofile.sh" +IMAGE="python3 /opt/brother/scanner/brscan-skey/script/scantoimage.py" +OCR="python3 /opt/brother/scanner/brscan-skey/script/scantoocr.py" +EMAIL="python3 /opt/brother/scanner/brscan-skey/script/scantoemail.py" +FILE="python3 /opt/brother/scanner/brscan-skey/script/scantofile.py" SEMID=b eth= ip_address= diff --git a/html/scan.php b/html/scan.php index ddfa94e..12a3342 100644 --- a/html/scan.php +++ b/html/scan.php @@ -18,10 +18,10 @@ if (in_array($target, array('file','email','image','ocr'))) { if ($_SERVER['REQUEST_METHOD'] == 'POST') { //return immediately - $handle = popen('sudo -b -u \#'.$UID.' /opt/brother/scanner/brscan-skey/script/scanto'.$target.'.sh', 'r'); + $handle = popen('sudo -b -u \#'.$UID.' /opt/brother/scanner/brscan-skey/script/scanto'.$target.'.py', 'r'); } else if ($_SERVER['REQUEST_METHOD'] == 'GET') { //wait for completion - $output=shell_exec('sudo -u \#'.$UID.' /opt/brother/scanner/brscan-skey/script/scanto'.$target.'.sh'); + $output=shell_exec('sudo -u \#'.$UID.' /opt/brother/scanner/brscan-skey/script/scanto'.$target.'.py'); } } else @@ -43,4 +43,4 @@ // die(); //} -?> \ No newline at end of file +?> diff --git a/script/scantoemail-0.2.4-1.py b/script/scantoemail-0.2.4-1.py deleted file mode 100755 index dcdecdb..0000000 --- a/script/scantoemail-0.2.4-1.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/python3 -# $1 = scanner device -# $2 = friendly name - -import sys - -from scanner import read_environment, scan_rear - -if __name__ == "__main__": - # Open the log file in append mode - with open("/var/log/scanner.log", "a") as f: - # Redirect stdout to the log file - sys.stdout = f - - read_environment() - - device = sys.argv[1] - scan_rear(f, device) diff --git a/script/scantoemail-0.2.4-1.sh b/script/scantoemail-0.2.4-1.sh deleted file mode 100755 index 003ce1d..0000000 --- a/script/scantoemail-0.2.4-1.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -# $1 = scanner device -# $2 = friendly name - -SCRIPTPATH="$( - cd "$(dirname "$0")" || exit - pwd -P -)" - -"$SCRIPTPATH"/scantoemail.py $@ diff --git a/script/scantoemail.py b/script/scantoemail.py deleted file mode 120000 index 672e1fb..0000000 --- a/script/scantoemail.py +++ /dev/null @@ -1 +0,0 @@ -scantoemail-0.2.4-1.py \ No newline at end of file diff --git a/script/scantoemail.py b/script/scantoemail.py new file mode 100755 index 0000000..e5dcd1c --- /dev/null +++ b/script/scantoemail.py @@ -0,0 +1,21 @@ +#!/usr/bin/python3 +# $1 = scanner device +# $2 = friendly name + +import sys + +from scanner import read_environment, scan_rear + +if __name__ == "__main__": + # Open the log file in append mode + with open("/var/log/scanner.log", "a") as log: + # Redirect stdout to the log file + sys.stdout = log + sys.stderr = log + + read_environment() + + device = None + if len(sys.argv) > 1: + device = sys.argv[1] + scan_rear(log, device) diff --git a/script/scantoemail.sh b/script/scantoemail.sh deleted file mode 120000 index 36826b0..0000000 --- a/script/scantoemail.sh +++ /dev/null @@ -1 +0,0 @@ -scantoemail-0.2.4-1.sh \ No newline at end of file diff --git a/script/scantofile-0.2.4-1.py b/script/scantofile-0.2.4-1.py deleted file mode 100755 index 056fac9..0000000 --- a/script/scantofile-0.2.4-1.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/python3 -# $1 = scanner device -# $2 = friendly name - -import sys - -from scanner import read_environment, scan_front - -if __name__ == "__main__": - # Open the log file in append mode - with open("/var/log/scanner.log", "a") as f: - # Redirect stdout to the log file - sys.stdout = f - - read_environment() - - device = sys.argv[1] - scan_front(f, device) diff --git a/script/scantofile-0.2.4-1.sh b/script/scantofile-0.2.4-1.sh deleted file mode 100755 index 745b9f4..0000000 --- a/script/scantofile-0.2.4-1.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -# $1 = scanner device -# $2 = friendly name - -SCRIPTPATH="$( - cd "$(dirname "$0")" || exit - pwd -P -)" - -"$SCRIPTPATH"/scantofile.py $@ diff --git a/script/scantofile.py b/script/scantofile.py deleted file mode 120000 index 64bff2a..0000000 --- a/script/scantofile.py +++ /dev/null @@ -1 +0,0 @@ -scantofile-0.2.4-1.py \ No newline at end of file diff --git a/script/scantofile.py b/script/scantofile.py new file mode 100755 index 0000000..a39105e --- /dev/null +++ b/script/scantofile.py @@ -0,0 +1,21 @@ +#!/usr/bin/python3 +# $1 = scanner device +# $2 = friendly name + +import sys + +from scanner import read_environment, scan_front + +if __name__ == "__main__": + # Open the log file in append mode + with open("/var/log/scanner.log", "a") as log: + # Redirect stdout to the log file + sys.stdout = log + sys.stderr = log + + read_environment() + + device = None + if len(sys.argv) > 1: + device = sys.argv[1] + scan_front(log, device) diff --git a/script/scantofile.sh b/script/scantofile.sh deleted file mode 120000 index 33f00b8..0000000 --- a/script/scantofile.sh +++ /dev/null @@ -1 +0,0 @@ -scantofile-0.2.4-1.sh \ No newline at end of file diff --git a/script/scantoimage-0.2.4-1.sh b/script/scantoimage-0.2.4-1.sh deleted file mode 100755 index fc86ca2..0000000 --- a/script/scantoimage-0.2.4-1.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -# $1 = scanner device -# $2 = friendly name - -{ - - echo "ERROR!" - echo "This function is not implemented." - echo "You may implement your own script and mount under $0." - echo "Check out scripts in same folder or https://github.com/PhilippMundhenk/BrotherScannerDocker for examples." - -} >>/var/log/scanner.log 2>&1 diff --git a/script/scantoimage.py b/script/scantoimage.py new file mode 100755 index 0000000..bf43619 --- /dev/null +++ b/script/scantoimage.py @@ -0,0 +1,19 @@ +#!/usr/bin/python3 +# $1 = scanner device +# $2 = friendly name + +import sys + +if __name__ == "__main__": + # Open the log file in append mode + with open("/var/log/scanner.log", "a") as log: + # Redirect stdout to the log file + sys.stdout = log + sys.stderr = log + + print("ERROR!") + print("This function is not implemented.") + print("You may implement your own script and mount under $0.") + print( + "Check out scripts in same folder or https://github.com/PhilippMundhenk/BrotherScannerDocker for examples." + ) diff --git a/script/scantoimage.sh b/script/scantoimage.sh deleted file mode 120000 index bfe2ea3..0000000 --- a/script/scantoimage.sh +++ /dev/null @@ -1 +0,0 @@ -scantoimage-0.2.4-1.sh \ No newline at end of file diff --git a/script/scantoocr-0.2.4-1.py b/script/scantoocr-0.2.4-1.py deleted file mode 100755 index faa6508..0000000 --- a/script/scantoocr-0.2.4-1.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/python3 -# $1 = scanner device -# $2 = friendly name - -import sys - -from scanner import read_environment, scan_front - -if __name__ == "__main__": - # Open the log file in append mode - with open("/var/log/scanner.log", "a") as f: - # Redirect stdout to the log file - sys.stdout = f - - read_environment() - - device = sys.argv[1] - scan_front(f, device, ["--mode=True Gray"]) diff --git a/script/scantoocr-0.2.4-1.sh b/script/scantoocr-0.2.4-1.sh deleted file mode 100755 index f918b8c..0000000 --- a/script/scantoocr-0.2.4-1.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -# $1 = scanner device -# $2 = friendly name - -SCRIPTPATH="$( - cd "$(dirname "$0")" || exit - pwd -P -)" - -"$SCRIPTPATH"/scantoocr.py $@ diff --git a/script/scantoocr.py b/script/scantoocr.py deleted file mode 120000 index ccdc918..0000000 --- a/script/scantoocr.py +++ /dev/null @@ -1 +0,0 @@ -scantoocr-0.2.4-1.py \ No newline at end of file diff --git a/script/scantoocr.py b/script/scantoocr.py new file mode 100755 index 0000000..321bb86 --- /dev/null +++ b/script/scantoocr.py @@ -0,0 +1,21 @@ +#!/usr/bin/python3 +# $1 = scanner device +# $2 = friendly name + +import sys + +from scanner import read_environment, scan_front + +if __name__ == "__main__": + # Open the log file in append mode + with open("/var/log/scanner.log", "a") as log: + # Redirect stdout to the log file + sys.stdout = log + sys.stderr = log + + read_environment() + + device = None + if len(sys.argv) > 1: + device = sys.argv[1] + scan_front(log, device, ["--mode=True Gray"]) diff --git a/script/scantoocr.sh b/script/scantoocr.sh deleted file mode 120000 index 105eb99..0000000 --- a/script/scantoocr.sh +++ /dev/null @@ -1 +0,0 @@ -scantoocr-0.2.4-1.sh \ No newline at end of file From e92f98f6e31bf8d9dfc748eef57e861c64262195 Mon Sep 17 00:00:00 2001 From: Pedro Pombeiro Date: Tue, 1 Oct 2024 22:19:31 +0200 Subject: [PATCH 05/19] Lint with mypy --- script/scanner.py | 108 +++++++++++++++++++++++-------------- script/scantoemail.py | 2 +- script/scantofile.py | 2 +- script/scantoimage.py | 2 +- script/scantoocr.py | 2 +- script/sendtoftps.py | 21 ++++++-- script/trigger_inotify.py | 11 ++-- script/trigger_telegram.py | 20 +++---- 8 files changed, 103 insertions(+), 65 deletions(-) diff --git a/script/scanner.py b/script/scanner.py index 58a1f79..8afabd5 100755 --- a/script/scanner.py +++ b/script/scanner.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # $1 = scanner device # $2 = friendly name @@ -12,7 +12,7 @@ import tempfile import time from datetime import datetime -from typing import List, TextIO +from typing import List, Optional, TextIO from sendtoftps import sendtoftps from trigger_inotify import trigger_inotify @@ -59,12 +59,13 @@ def execute_command_pid(log: TextIO, command: List[str], **kwargs) -> int: def scan_cmd( - log: TextIO, device: str, output_batch: str, scanimage_args: List[str] + log: TextIO, device: Optional[str], output_batch: str, scanimage_args: List[str] ) -> None: log.flush() # Required, otherwise scanimage output will appear before the already printed output resolution = os.environ.get("RESOLUTION", 300) - # `brother4:net1;dev0` device name gets passed to scanimage, which it refuses as an invalid device name for some reason. + # `brother4:net1;dev0` device name gets passed to scanimage, which it refuses as an invalid device name + # for some reason. # Let's use the default scanner for now # fmt: off scan_command = [ @@ -90,13 +91,13 @@ def notify(log: TextIO, file_path: str, message: str) -> None: ) trigger_telegram( log, + f"Scanner: {message}", os.getenv("TELEGRAM_TOKEN"), os.getenv("TELEGRAM_CHATID"), - f"Scanner: {message}", ) -def latest_batch_dir() -> str: +def latest_batch_dir() -> Optional[str]: prefix = datetime.today().strftime("%Y-%m-%d") dir_entries = glob.glob(os.path.join(tempfile.gettempdir(), f"{prefix}*")) dirs = filter(os.path.isdir, dir_entries) @@ -148,9 +149,13 @@ def remove_blank_pages( ) output, _ = process.communicate() if process.returncode != 0: - print(f" ERROR: getting number of pages from {input_file}: {output}") + print(f" ERROR: getting number of pages from {input_file}") + return + info = output.decode() + pages_line = re.search(r"^Pages:\s*(\d+)", info, re.MULTILINE) + if pages_line is None: + print(f" ERROR: finding number of pages in {info}") return - pages_line = re.search(r"^Pages:\s*(\d+)", output.decode(), re.MULTILINE) page_count = int(pages_line.group(1)) print( @@ -159,7 +164,7 @@ def remove_blank_pages( os.chdir(dirname) def non_blank_pages() -> List[str]: - picked_pages = [] + picked_pages: List[str] = [] for page in range(1, page_count + 1): # Use subprocess to run gs and get ink coverage process = subprocess.Popen( @@ -181,13 +186,22 @@ def non_blank_pages() -> List[str]: output.decode(), re.MULTILINE, ) - ink_coverage = sum(map(float, ink_coverage_line.groups())) + if ink_coverage_line is None: + ink_coverage = None + else: + ink_coverage = sum(map(float, ink_coverage_line.groups())) - if ink_coverage < remove_blank_threshold: - print(f" Page {page}: delete (ink coverage: {ink_coverage:.2f}%)") + if ink_coverage is not None and ink_coverage < remove_blank_threshold: + print( + f" Page { + page}: delete (ink coverage: {ink_coverage:.2f}%)" + ) else: picked_pages += str(page) - print(f" Page {page}: keep (ink coverage: {ink_coverage:.2f}%)") + print( + f" Page { + page}: keep (ink coverage: {ink_coverage:.2f}%)" + ) return picked_pages @@ -210,20 +224,27 @@ def non_blank_pages() -> List[str]: print(f" No blank pages detected in {input_file}") else: os.replace(output_file, input_file) - print(f" Removed {removed_pages} blank pages and saved as {input_file}") + print( + f" Removed { + removed_pages} blank pages and saved as {input_file}" + ) except FileNotFoundError: print( - f" WARNING: '{command[0]}' executable not found. Skipping PDF manipulation." + f" WARNING: '{ + command[0]}' executable not found. Skipping PDF manipulation." ) except subprocess.CalledProcessError: - print(f" ERROR: manipulating {input_file}. Skipping PDF manipulation.") + print( + f" ERROR: manipulating { + input_file}. Skipping PDF manipulation." + ) # # Async job methods # def convert_and_post_process( - job_name: str, side: str, remove_blank_threshold: float + job_name: str, side: str, remove_blank_threshold: Optional[float] ) -> None: log = sys.stdout log.flush() @@ -295,19 +316,17 @@ def convert_and_post_process( ) notify(log, ocr_pdf_name, f"{ocr_pdf_name} ({side}) OCR finished") - sendtoftps( - log, - os.getenv("FTP_USER"), - os.getenv("FTP_PASSWORD"), - os.getenv("FTP_HOST"), - os.getenv("FTP_PATH"), - ocr_pdf_path, - ) - if os.getenv("REMOVE_ORIGINAL_AFTER_OCR") == "true" and os.path.isfile( - ocf_pdf_path - ): - os.remove(output_pdf_file) + ftp_user = os.getenv("FTP_USER") + ftp_password = os.getenv("FTP_PASSWORD") + ftp_host = os.getenv("FTP_HOST") + ftp_path = os.getenv("FTP_PATH") + sendtoftps(log, ftp_user, ftp_password, ftp_host, ftp_path, ocr_pdf_path) + + if os.getenv("REMOVE_ORIGINAL_AFTER_OCR") == "true" and os.path.isfile( + ocr_pdf_path + ): + os.remove(output_pdf_file) print(f" {side} side: Conversion and post-processing for finished.") print("-----------------------------------") @@ -316,7 +335,8 @@ def convert_and_post_process( def wait_for_rear_pages_or_convert(job_name: str) -> None: # Wait for 2 minutes in case there is a rear side scan print( - f" front side: Waiting for 2 minutes before starting file conversion for {job_name}" + f" front side: Waiting for 2 minutes before starting file conversion for { + job_name}" ) time.sleep(120) @@ -365,14 +385,15 @@ def save_front_processing_pid(job_dir: str, pid: int) -> None: pid_file.write(str(pid)) -def kill_front_processing_from_pid(job_dir: str) -> int: +def kill_front_processing_from_pid(job_dir: str) -> Optional[int]: path = scan_pid_path(job_dir) pid = None try: with open(path, "r") as scan_pid_file: pid = int(scan_pid_file.read().strip()) print( - f" rear side: Read pid from {path}, killing front processing job {pid}" + f" rear side: Read pid from { + path}, killing front processing job {pid}" ) os.kill(pid, signal.SIGKILL) except FileNotFoundError: @@ -389,8 +410,9 @@ def kill_front_processing_from_pid(job_dir: str) -> int: # # Scan entry points # -def scan_front(log: TextIO, device: str, scanimage_args=[]) -> None: - job_name = datetime.now().strftime("%Y-%m-%d-%H-%M-%S") # Generate unique timestamp +def scan_front(log: TextIO, device: Optional[str], scanimage_args=[]) -> None: + # Generate unique timestamp + job_name = datetime.now().strftime("%Y-%m-%d-%H-%M-%S") job_dir = os.path.join(tempfile.gettempdir(), job_name) filepath_base = os.path.join(job_dir, f"{job_name}-front-page") tmp_output_batch = f"{filepath_base}%04d.pnm" @@ -418,13 +440,14 @@ def scan_front(log: TextIO, device: str, scanimage_args=[]) -> None: elif pid > 0: save_front_processing_pid(job_dir, pid) print( - f" front side: INFO: Waiting to start conversion process for {job_name} in process with PID {pid}" + f" front side: INFO: Waiting to start conversion process for { + job_name} in process with PID {pid}" ) else: print(f" front side: ERROR: Fork failed ({pid}).") -def scan_rear(log: TextIO, device: str, scanimage_args=None) -> None: +def scan_rear(log: TextIO, device: Optional[str], scanimage_args=None) -> None: # Find latest directory in temp directory job_name = latest_batch_dir() print(f"- Scanning rear to latest batch {job_name}") @@ -466,7 +489,8 @@ def scan_rear(log: TextIO, device: str, scanimage_args=None) -> None: cnt_formatted = f"{cnt:03d}" os.rename(filename, f"index{cnt_formatted}-1-{filename}") print( - f" rear side: DEBUG: renamed {filename} to index{cnt_formatted}-1-{filename}" + f" rear side: DEBUG: renamed {filename} to index{ + cnt_formatted}-1-{filename}" ) cnt = 0 @@ -476,13 +500,15 @@ def scan_rear(log: TextIO, device: str, scanimage_args=None) -> None: rear_index_formatted = f"{rear_index:03d}" os.rename(filename, f"index{rear_index_formatted}-2-{filename}") print( - f" rear side: DEBUG: renamed {filename} to index{rear_index_formatted}-2-{filename}" + f" rear side: DEBUG: renamed {filename} to index{ + rear_index_formatted}-2-{filename}" ) # Convert to PDF - remove_blank_threshold = os.getenv("REMOVE_BLANK_THRESHOLD") - if remove_blank_threshold: - remove_blank_threshold = float(remove_blank_threshold) + remove_blank_threshold_str = os.getenv("REMOVE_BLANK_THRESHOLD") + remove_blank_threshold = None + if remove_blank_threshold_str is not None: + remove_blank_threshold = float(remove_blank_threshold_str) pid = os.fork() if pid == 0: # Child process diff --git a/script/scantoemail.py b/script/scantoemail.py index e5dcd1c..16e5325 100755 --- a/script/scantoemail.py +++ b/script/scantoemail.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # $1 = scanner device # $2 = friendly name diff --git a/script/scantofile.py b/script/scantofile.py index a39105e..2dd1105 100755 --- a/script/scantofile.py +++ b/script/scantofile.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # $1 = scanner device # $2 = friendly name diff --git a/script/scantoimage.py b/script/scantoimage.py index bf43619..37649c7 100755 --- a/script/scantoimage.py +++ b/script/scantoimage.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # $1 = scanner device # $2 = friendly name diff --git a/script/scantoocr.py b/script/scantoocr.py index 321bb86..652110e 100755 --- a/script/scantoocr.py +++ b/script/scantoocr.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # $1 = scanner device # $2 = friendly name diff --git a/script/sendtoftps.py b/script/sendtoftps.py index b13a834..beb27b1 100755 --- a/script/sendtoftps.py +++ b/script/sendtoftps.py @@ -1,7 +1,17 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 +import subprocess +from typing import List, Optional, TextIO -def sendtoftps(log, user, password, address, filepath, file): + +def sendtoftps( + log: TextIO, + user: Optional[str], + password: Optional[str], + address: Optional[str], + filepath: Optional[str], + file: Optional[str], +) -> None: """Uploads a file to an FTP server. Args: @@ -12,7 +22,10 @@ def sendtoftps(log, user, password, address, filepath, file): file (str): The file to upload. """ - command = [ + if not any([user, password, address, filepath, file]): + return + + command: List[str] = [ "curl", "--silent", "--show-error", @@ -20,7 +33,7 @@ def sendtoftps(log, user, password, address, filepath, file): "--user", f"{user}:{password}", "--upload-file", - file, + str(file), f"ftp://{address}{filepath}", ] diff --git a/script/trigger_inotify.py b/script/trigger_inotify.py index ad5897c..c630201 100755 --- a/script/trigger_inotify.py +++ b/script/trigger_inotify.py @@ -1,11 +1,16 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 import subprocess -from typing import TextIO +from typing import Optional, TextIO def trigger_inotify( - log: TextIO, user: str, password: str, address: str, filepath: str, file: str + log: TextIO, + user: Optional[str], + password: Optional[str], + address: Optional[str], + filepath: Optional[str], + file: Optional[str], ) -> None: """Triggers inotify for a file. diff --git a/script/trigger_telegram.py b/script/trigger_telegram.py index 494d75e..591e7f0 100755 --- a/script/trigger_telegram.py +++ b/script/trigger_telegram.py @@ -1,11 +1,14 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 -import os import urllib.parse -from typing import TextIO +from typing import Optional, TextIO +import requests -def trigger_telegram(log: TextIO, token: str, chat_id: str, message: str) -> None: + +def trigger_telegram( + log: TextIO, message: str, token: Optional[str], chat_id: Optional[str] +) -> None: """Sends a Telegram message using the provided token and chat ID.""" if not token or not chat_id: @@ -23,18 +26,9 @@ def trigger_telegram(log: TextIO, token: str, chat_id: str, message: str) -> Non # Prepare data payload payload = {"chat_id": chat_id, "text": encoded_message} - # Use requests library for a more robust solution (install with 'pip install requests') try: - import requests - response = requests.post(url, json=payload) response.raise_for_status() # Raise an exception for non-200 response print(" Telegram message sent successfully.") - except ModuleNotFoundError: - print(" WARNING: 'requests' library not found. Using wget fallback.") - # Fallback using wget (not recommended for production due to limited feedback) - os.system( - f"wget -qO- --post-data='chat_id={chat_id}&text={encoded_message}' '{url}' >/dev/null" - ) except requests.exceptions.RequestException as e: print(f" ERROR: sending Telegram message: {e}") From 729851ca9398d5c5b95a3e254a8ca62046cb799d Mon Sep 17 00:00:00 2001 From: Pedro Pombeiro Date: Tue, 1 Oct 2024 22:46:46 +0200 Subject: [PATCH 06/19] Add linters to CI pipeline --- .github/workflows/publishBranchesPRs.yml | 8 ++-- .github/workflows/publishMaster.yml | 6 +-- .github/workflows/publishTags.yml | 8 ++-- .github/workflows/superLinter.yml | 47 ++++++++++++++++++ .hadolint.yml | 3 ++ .yamllint.yml | 11 +++++ html/active.php | 34 ++++++------- html/download.php | 38 ++++++++------- html/index.php | 61 +++++++++++------------- html/list.php | 5 +- html/scan.php | 29 +++++------ 11 files changed, 155 insertions(+), 95 deletions(-) create mode 100644 .github/workflows/superLinter.yml create mode 100644 .hadolint.yml create mode 100644 .yamllint.yml diff --git a/.github/workflows/publishBranchesPRs.yml b/.github/workflows/publishBranchesPRs.yml index 09148d8..31d41e7 100644 --- a/.github/workflows/publishBranchesPRs.yml +++ b/.github/workflows/publishBranchesPRs.yml @@ -5,7 +5,7 @@ name: PR - Create and publish a Docker image on: pull_request: #push: - # branches: + # branches: # - '*' # - '!master' @@ -22,10 +22,10 @@ jobs: permissions: contents: read packages: write - # + # steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here. - name: Log in to the Container registry uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 @@ -36,7 +36,7 @@ jobs: # This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels. - name: Extract branch name shell: bash - run: echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_OUTPUT + run: echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> "$GITHUB_OUTPUT" id: extract_branch - name: Extract metadata (tags, labels) for Docker id: meta diff --git a/.github/workflows/publishMaster.yml b/.github/workflows/publishMaster.yml index 8abddac..1a0b6c5 100644 --- a/.github/workflows/publishMaster.yml +++ b/.github/workflows/publishMaster.yml @@ -4,7 +4,7 @@ name: Master - Create and publish a Docker image # Configures this workflow to run every time a change is pushed to the branch called `master`. on: push: - branches: ['master'] + branches: ["master"] # Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds. env: @@ -19,10 +19,10 @@ jobs: permissions: contents: read packages: write - # + # steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here. - name: Log in to the Container registry uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 diff --git a/.github/workflows/publishTags.yml b/.github/workflows/publishTags.yml index 4dd9245..903c491 100644 --- a/.github/workflows/publishTags.yml +++ b/.github/workflows/publishTags.yml @@ -4,8 +4,8 @@ name: Tags - Create and publish a Docker image # Build when a tag is created on: push: - tags: - - '**' + tags: + - "**" # Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds. env: @@ -20,10 +20,10 @@ jobs: permissions: contents: read packages: write - # + # steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here. - name: Log in to the Container registry uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 diff --git a/.github/workflows/superLinter.yml b/.github/workflows/superLinter.yml new file mode 100644 index 0000000..24a4e56 --- /dev/null +++ b/.github/workflows/superLinter.yml @@ -0,0 +1,47 @@ +--- +# This workflow executes several linters on changed files based on languages used in your code base whenever +# you push a code or open a pull request. +# +# You can adjust the behavior by modifying this file. +# For more information, see: +# https://github.com/github/super-linter +name: Lint Code Base + +on: # yamllint disable-line rule:truthy + push: + branches: ["master"] + pull_request: + branches: ["master"] + +permissions: + contents: read + +jobs: + run-lint: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + # Full git history is needed to get a proper list of changed files within `super-linter` + fetch-depth: 0 + + - name: Lint Code Base + uses: github/super-linter/slim@v7 + env: + DISABLE_ERRORS: true + VALIDATE_ALL_CODEBASE: false + VALIDATE_CHECKOV: false + VALIDATE_EDITORCONFIG: false + VALIDATE_JSCPD: false + VALIDATE_MARKDOWN: false + VALIDATE_PYTHON: true + VALIDATE_PYTHON_PYLINT: false + VALIDATE_YAML: false + VALIDATE_YAML_PRETTIER: false + DEFAULT_BRANCH: master + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + LINTER_RULES_PATH: / + DOCKERFILE_HADOLINT_FILE_NAME: .hadolint.yml + MARKDOWN_CONFIG_FILE: .markdown-lint.yml + YAML_CONFIG_FILE: .yamllint.yml diff --git a/.hadolint.yml b/.hadolint.yml new file mode 100644 index 0000000..c390dfb --- /dev/null +++ b/.hadolint.yml @@ -0,0 +1,3 @@ +ignored: + - DL3008 # Pin versions in apt get install. Instead of `apt-get install ` use `apt-get install =` + - DL3018 # Pin versions in apk add. Instead of `apk add ` use `apk add =` diff --git a/.yamllint.yml b/.yamllint.yml new file mode 100644 index 0000000..fb06ff6 --- /dev/null +++ b/.yamllint.yml @@ -0,0 +1,11 @@ +extends: default + +rules: + document-start: disable + line-length: + max: 180 + level: warning + comments: + # Changed this to stop a mess between linters from Prettier (vscode) to yamllint + # - https://github.com/prettier/prettier/pull/10926 + min-spaces-from-content: 1 diff --git a/html/active.php b/html/active.php index 2b3e4d5..a88f1cd 100644 --- a/html/active.php +++ b/html/active.php @@ -1,25 +1,25 @@ isProcessRunning('scanimage'), - 'waiting' => isProcessRunning('sleep'), - 'ocr' => isProcessRunning('curl') + 'scan' => isProcessRunning('scanimage'), + 'waiting' => isProcessRunning('sleep'), + 'ocr' => isProcessRunning('curl') ); @@ -27,4 +27,4 @@ function isProcessRunning($processName) { header('Content-Type: application/json; charset=utf-8'); echo json_encode($result); -?> \ No newline at end of file +?> diff --git a/html/download.php b/html/download.php index 45da56a..d2c8c68 100644 --- a/html/download.php +++ b/html/download.php @@ -1,23 +1,25 @@ \ No newline at end of file + +?> diff --git a/html/index.php b/html/index.php index ee283af..5e58710 100644 --- a/html/index.php +++ b/html/index.php @@ -1,5 +1,5 @@ - - +