#! /usr/bin/python3 import os import subprocess import time import re import fcntl import traceback import json import logging import slugify import dvd import cd import worker CDROM_DRIVE_STATUS = 0x5326 CDS_NO_INFO = 0 CDS_NO_DISC = 1 CDS_TRAY_OPEN = 2 CDS_DRIVE_NOT_READ = 3 CDS_DISC_OK = 4 CDS_STR = ["no info", "no disc", "tray open", "drive not read", "disc ok"] CDROM_DISC_STATUS = 0x5327 CDS_AUDIO = 100 CDS_DATA_1 = 101 CDS_DATA_2 = 102 CDROM_LOCKDOOR = 0x5329 CDROM_EJECT = 0x5309 class Reader(worker.Worker): def __init__(self, device, directory): super().__init__(device) self.device = device self.status["type"] = "reader" self.status["device"] = device self.complete = 0 self.staleness = 0 self.drive = None logging.info("Starting reader on %s" % self.device) def reopen(self): if (self.staleness > 15) or not self.drive: if self.drive: os.close(self.drive) self.drive = None try: self.drive = os.open(self.device, os.O_RDONLY | os.O_NONBLOCK) logging.debug("Reopened %s" % self.device) except FileNotFoundError: pass self.staleness = 0 else: self.staleness += 1 def run(self): while True: self.status["state"] = "idle" self.reopen() if not self.drive: time.sleep(30) continue rv = fcntl.ioctl(self.drive, CDROM_DRIVE_STATUS) if rv == CDS_DISC_OK: rv = fcntl.ioctl(self.drive, CDROM_DISC_STATUS) try: if rv == CDS_AUDIO: self.handle(false) elif rv in [CDS_DATA_1, CDS_DATA_2]: self.handle(true) else: logging.info("Can't handle disc type %d" % rv) except Exception as e: logging.error("Error in disc handler: %s" % e) logging.error(traceback.format_exc()) self.eject() elif rv in (CDS_TRAY_OPEN, CDS_NO_DISC): time.sleep(3) else: logging.info("CDROM_DRIVE_STATUS: %d (%s)" % (rv, CDS_STR[rv])) time.sleep(3) def eject(self): self.status["state"] = "ejecting" for i in range(20): try: fcntl.ioctl(self.drive, CDROM_LOCKDOOR, 0) fcntl.ioctl(self.drive, CDROM_EJECT) return except Exception as e: logging.error("Ejecting: %v" % e) time.sleep(i * 5) def handle(self, video): self.status["video"] = video self.status["state"] = "reading" state = {} state["video"] = video if video: media = cd else: media = dvd media.scan(state, self.device) self.status["title"] = state["title"] subdir = slugify.slugify(state["title"]) self.status["state"] = "copying" for pct in media.copy(device, self.workdir(subdir)): self.status["complete"] = pct self.write_state(subdir, state) # vi: sw=4 ts=4 et ai