#! /usr/bin/python3 import os import subprocess import time import re import fcntl 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 SECOND = 1 MINUTE = 60 * SECOND HOUR = 60 * MINUTE class Reader(worker.Worker): def __init__(self, device, directory): super().__init__(directory) self.device = device self.staleness = 0 self.drive = None logging.info("Starting reader on %s" % self.device) def reopen(self): if self.drive and (self.staleness < 15): self.staleness += 1 return True self.staleness = 0 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) return True except FileNotFoundError: return False def once(self): self.status["type"] = "reader" self.status["device"] = self.device if not self.reopen(): time.sleep(10 * SECOND) return rv = fcntl.ioctl(self.drive, CDROM_DRIVE_STATUS) if rv == CDS_DISC_OK: rv = fcntl.ioctl(self.drive, CDROM_DISC_STATUS) 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) self.eject() elif rv in (CDS_TRAY_OPEN, CDS_NO_DISC, CDS_DRIVE_NOT_READ): time.sleep(3 * SECOND) else: logging.info("CDROM_DRIVE_STATUS: %d (%s)" % (rv, CDS_STR[rv])) time.sleep(3 * SECOND) def eject(self): 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): logging.info("Handling media, video=%r" % video) self.status["video"] = video self.status["state"] = "reading" state = {} state["video"] = video if video: media = dvd else: media = cd media.scan(state, self.device) self.status["title"] = state["title"] subdir = slugify.slugify(state["title"]) workdir = self.workdir(subdir) os.makedirs(workdir, exist_ok=True) self.status["state"] = "copying" for pct in media.copy(state, self.device, workdir): self.status["complete"] = pct self.write_state(subdir, state) # vi: sw=4 ts=4 et ai