-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request automatic-ripping-machine#977 from shitwolfymakes/…
…models-refactor Models Refactor
- Loading branch information
Showing
28 changed files
with
791 additions
and
751 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
2.6.60 | ||
2.6.67 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
from arm.ui import db | ||
|
||
|
||
class AlembicVersion(db.Model): | ||
""" | ||
Class to hold the A.R.M db version | ||
""" | ||
version_num = db.Column(db.String(36), autoincrement=False, primary_key=True) | ||
|
||
def __init__(self, version=None): | ||
self.version_num = version | ||
|
||
def __repr__(self): | ||
return f'<AlembicVersion: {self.version_num}>' | ||
|
||
def __str__(self): | ||
"""Returns a string of the object""" | ||
return self.__class__.__name__ + ": " + self.version_num |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
from prettytable import PrettyTable | ||
|
||
from arm.ui import db | ||
|
||
|
||
hidden_attribs = ("OMDB_API_KEY", "EMBY_USERID", "EMBY_PASSWORD", | ||
"EMBY_API_KEY", "PB_KEY", "IFTTT_KEY", "PO_KEY", | ||
"PO_USER_KEY", "PO_APP_KEY", "ARM_API_KEY", | ||
"TMDB_API_KEY", "_sa_instance_state") | ||
HIDDEN_VALUE = "<hidden>" | ||
|
||
|
||
class Config(db.Model): | ||
""" Holds all the config settings for each job | ||
as these may change between each job """ | ||
CONFIG_ID = db.Column(db.Integer, primary_key=True) | ||
job_id = db.Column(db.Integer, db.ForeignKey('job.job_id')) | ||
ARM_CHECK_UDF = db.Column(db.Boolean) | ||
GET_VIDEO_TITLE = db.Column(db.Boolean) | ||
SKIP_TRANSCODE = db.Column(db.Boolean) | ||
VIDEOTYPE = db.Column(db.String(25)) | ||
MINLENGTH = db.Column(db.String(6)) | ||
MAXLENGTH = db.Column(db.String(6)) | ||
MANUAL_WAIT = db.Column(db.Boolean) | ||
MANUAL_WAIT_TIME = db.Column(db.Integer) | ||
RAW_PATH = db.Column(db.String(255)) | ||
TRANSCODE_PATH = db.Column(db.String(255)) | ||
COMPLETED_PATH = db.Column(db.String(255)) | ||
EXTRAS_SUB = db.Column(db.String(255)) | ||
INSTALLPATH = db.Column(db.String(255)) | ||
LOGPATH = db.Column(db.String(255)) | ||
LOGLEVEL = db.Column(db.String(255)) | ||
LOGLIFE = db.Column(db.Integer) | ||
DBFILE = db.Column(db.String(255)) | ||
WEBSERVER_IP = db.Column(db.String(25)) | ||
WEBSERVER_PORT = db.Column(db.Integer) | ||
SET_MEDIA_PERMISSIONS = db.Column(db.Boolean) | ||
CHMOD_VALUE = db.Column(db.Integer) | ||
SET_MEDIA_OWNER = db.Column(db.Boolean) | ||
CHOWN_USER = db.Column(db.String(50)) | ||
CHOWN_GROUP = db.Column(db.String(50)) | ||
RIPMETHOD = db.Column(db.String(25)) | ||
MKV_ARGS = db.Column(db.String(25)) | ||
DELRAWFILES = db.Column(db.Boolean) | ||
HASHEDKEYS = db.Column(db.Boolean) | ||
HB_PRESET_DVD = db.Column(db.String(256)) | ||
HB_PRESET_BD = db.Column(db.String(256)) | ||
DEST_EXT = db.Column(db.String(10)) | ||
HANDBRAKE_CLI = db.Column(db.String(25)) | ||
MAINFEATURE = db.Column(db.Boolean) | ||
HB_ARGS_DVD = db.Column(db.String(256)) | ||
HB_ARGS_BD = db.Column(db.String(256)) | ||
EMBY_REFRESH = db.Column(db.Boolean) | ||
EMBY_SERVER = db.Column(db.String(25)) | ||
EMBY_PORT = db.Column(db.String(6)) | ||
EMBY_CLIENT = db.Column(db.String(25)) | ||
EMBY_DEVICE = db.Column(db.String(50)) | ||
EMBY_DEVICEID = db.Column(db.String(128)) | ||
EMBY_USERNAME = db.Column(db.String(50)) | ||
EMBY_USERID = db.Column(db.String(128)) | ||
EMBY_PASSWORD = db.Column(db.String(128)) | ||
EMBY_API_KEY = db.Column(db.String(64)) | ||
NOTIFY_RIP = db.Column(db.Boolean) | ||
NOTIFY_TRANSCODE = db.Column(db.Boolean) | ||
PB_KEY = db.Column(db.String(64)) | ||
IFTTT_KEY = db.Column(db.String(64)) | ||
IFTTT_EVENT = db.Column(db.String(25)) | ||
PO_USER_KEY = db.Column(db.String(64)) | ||
PO_APP_KEY = db.Column(db.String(64)) | ||
OMDB_API_KEY = db.Column(db.String(64)) | ||
|
||
def __init__(self, c, job_id): | ||
self.__dict__.update(c) | ||
self.job_id = job_id | ||
|
||
def __str__(self): | ||
"""Returns a string of the object""" | ||
return_string = self.__class__.__name__ + ": " | ||
for attr, value in self.__dict__.items(): | ||
if str(attr) in hidden_attribs and value: | ||
value = HIDDEN_VALUE | ||
return_string = return_string + "(" + str(attr) + "=" + str(value) + ") " | ||
|
||
return return_string | ||
|
||
def list_params(self): | ||
"""Returns a string of the object""" | ||
return_string = self.__class__.__name__ + ": " | ||
for attr, value in self.__dict__.items(): | ||
if return_string: | ||
return_string = return_string + "\n" | ||
if str(attr) in hidden_attribs and value: | ||
value = HIDDEN_VALUE | ||
return_string = return_string + str(attr) + ":" + str(value) | ||
|
||
return return_string | ||
|
||
def pretty_table(self): | ||
"""Returns a string of the PrettyTable""" | ||
pretty_table = PrettyTable() | ||
pretty_table.field_names = ["Config", "Value"] | ||
pretty_table._max_width = {"Config": 20, "Value": 30} | ||
for attr, value in self.__dict__.items(): | ||
if str(attr) in hidden_attribs and value: | ||
value = HIDDEN_VALUE | ||
pretty_table.add_row([str(attr), str(value)]) | ||
return str(pretty_table.get_string()) | ||
|
||
def get_d(self): | ||
""" | ||
Return a dict of class - exclude any sensitive info | ||
:return: dict containing all attribs from class | ||
""" | ||
return_dict = {} | ||
for key, value in self.__dict__.items(): | ||
if str(key) not in hidden_attribs: | ||
return_dict[str(key)] = str(value) | ||
return return_dict |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,217 @@ | ||
import logging | ||
import os | ||
import psutil | ||
import pyudev | ||
import subprocess | ||
import time | ||
|
||
from prettytable import PrettyTable | ||
from arm.ripper import music_brainz | ||
from arm.ui import db | ||
import arm.config.config as cfg | ||
|
||
# THESE IMPORTS ARE REQUIRED FOR THE db.Relationships to work | ||
from arm.models.track import Track # noqa: F401 | ||
from arm.models.config import Config # noqa: F401 | ||
|
||
|
||
class Job(db.Model): | ||
""" | ||
Job Class hold most of the details for each job | ||
connects to track, config | ||
""" | ||
job_id = db.Column(db.Integer, primary_key=True) | ||
arm_version = db.Column(db.String(20)) | ||
crc_id = db.Column(db.String(63)) | ||
logfile = db.Column(db.String(256)) | ||
start_time = db.Column(db.DateTime) | ||
stop_time = db.Column(db.DateTime) | ||
job_length = db.Column(db.String(12)) | ||
status = db.Column(db.String(32)) | ||
stage = db.Column(db.String(63)) | ||
no_of_titles = db.Column(db.Integer) | ||
title = db.Column(db.String(256)) | ||
title_auto = db.Column(db.String(256)) | ||
title_manual = db.Column(db.String(256)) | ||
year = db.Column(db.String(4)) | ||
year_auto = db.Column(db.String(4)) | ||
year_manual = db.Column(db.String(4)) | ||
video_type = db.Column(db.String(20)) | ||
video_type_auto = db.Column(db.String(20)) | ||
video_type_manual = db.Column(db.String(20)) | ||
imdb_id = db.Column(db.String(15)) | ||
imdb_id_auto = db.Column(db.String(15)) | ||
imdb_id_manual = db.Column(db.String(15)) | ||
poster_url = db.Column(db.String(256)) | ||
poster_url_auto = db.Column(db.String(256)) | ||
poster_url_manual = db.Column(db.String(256)) | ||
devpath = db.Column(db.String(15)) | ||
mountpoint = db.Column(db.String(20)) | ||
hasnicetitle = db.Column(db.Boolean) | ||
errors = db.Column(db.Text) | ||
disctype = db.Column(db.String(20)) # dvd/bluray/data/music/unknown | ||
label = db.Column(db.String(256)) | ||
path = db.Column(db.String(256)) | ||
ejected = db.Column(db.Boolean) | ||
updated = db.Column(db.Boolean) | ||
pid = db.Column(db.Integer) | ||
pid_hash = db.Column(db.Integer) | ||
tracks = db.relationship('Track', backref='job', lazy='dynamic') | ||
config = db.relationship('Config', uselist=False, backref="job") | ||
|
||
def __init__(self, devpath): | ||
"""Return a disc object""" | ||
self.devpath = devpath | ||
self.mountpoint = "/mnt" + devpath | ||
self.hasnicetitle = False | ||
self.video_type = "unknown" | ||
self.ejected = False | ||
self.updated = False | ||
if cfg.arm_config['VIDEOTYPE'] != "auto": | ||
self.video_type = cfg.arm_config['VIDEOTYPE'] | ||
self.parse_udev() | ||
self.get_pid() | ||
self.stage = str(round(time.time() * 100)) | ||
|
||
if self.disctype == "dvd" and not self.label: | ||
logging.info("No disk label Available. Trying lsdvd") | ||
command = f"lsdvd {devpath} | grep 'Disc Title' | cut -d ' ' -f 3-" | ||
lsdvdlbl = str(subprocess.check_output(command, shell=True).strip(), 'utf-8') | ||
self.label = lsdvdlbl | ||
|
||
def __str__(self): | ||
"""Returns a string of the object""" | ||
|
||
return_string = self.__class__.__name__ + ": " | ||
for attr, value in self.__dict__.items(): | ||
return_string = return_string + "(" + str(attr) + "=" + str(value) + ") " | ||
|
||
return return_string | ||
|
||
def __repr__(self): | ||
return f'<Job {self.label}>' | ||
|
||
def parse_udev(self): | ||
"""Parse udev for properties of current disc""" | ||
context = pyudev.Context() | ||
device = pyudev.Devices.from_device_file(context, self.devpath) | ||
self.disctype = "unknown" | ||
|
||
for key, value in device.items(): | ||
logging.debug(f"pyudev: {key}: {value}") | ||
if key == "ID_FS_LABEL": | ||
self.label = value | ||
if value == "iso9660": | ||
self.disctype = "data" | ||
elif key == "ID_CDROM_MEDIA_BD": | ||
self.disctype = "bluray" | ||
elif key == "ID_CDROM_MEDIA_DVD": | ||
self.disctype = "dvd" | ||
elif key == "ID_CDROM_MEDIA_TRACK_COUNT_AUDIO": | ||
self.disctype = "music" | ||
else: | ||
continue | ||
|
||
def get_pid(self): | ||
""" | ||
Get the jobs process id | ||
:return: None | ||
""" | ||
pid = os.getpid() | ||
process_id = psutil.Process(pid) | ||
self.pid = pid | ||
self.pid_hash = hash(process_id) | ||
|
||
def get_disc_type(self, found_hvdvd_ts): | ||
""" | ||
Checks/corrects the current disc-type | ||
:param found_hvdvd_ts: gets pushed in from utils - saves importing utils | ||
:return: None | ||
""" | ||
if self.disctype == "music": | ||
logging.debug("Disc is music.") | ||
self.label = music_brainz.main(self) | ||
elif os.path.isdir(self.mountpoint + "/VIDEO_TS"): | ||
logging.debug(f"Found: {self.mountpoint}/VIDEO_TS") | ||
self.disctype = "dvd" | ||
elif os.path.isdir(self.mountpoint + "/video_ts"): | ||
logging.debug(f"Found: {self.mountpoint}/video_ts") | ||
self.disctype = "dvd" | ||
elif os.path.isdir(self.mountpoint + "/BDMV"): | ||
logging.debug(f"Found: {self.mountpoint}/BDMV") | ||
self.disctype = "bluray" | ||
elif os.path.isdir(self.mountpoint + "/HVDVD_TS"): | ||
logging.debug(f"Found: {self.mountpoint}/HVDVD_TS") | ||
# do something here | ||
elif found_hvdvd_ts: | ||
logging.debug("Found file: HVDVD_TS") | ||
# do something here too | ||
else: | ||
logging.debug("Did not find valid dvd/bd files. Changing disc-type to 'data'") | ||
self.disctype = "data" | ||
|
||
def identify_audio_cd(self): | ||
""" | ||
Get the title for audio cds to use for the logfile name. | ||
Needs the job class passed into it so it can be forwarded to mb | ||
return - only the logfile - setup_logging() adds the full path | ||
""" | ||
# Use the music label if we can find it - defaults to music_cd.log | ||
disc_id = music_brainz.get_disc_id(self) | ||
logging.debug(f"music_id: {disc_id}") | ||
mb_title = music_brainz.get_title(disc_id, self) | ||
logging.debug(f"mm_title: {mb_title}") | ||
|
||
if mb_title == "not identified": | ||
self.label = self.title = "not identified" | ||
logfile = "music_cd.log" | ||
new_log_file = f"music_cd_{round(time.time() * 100)}.log" | ||
else: | ||
logfile = f"{mb_title}.log" | ||
new_log_file = f"{mb_title}_{round(time.time() * 100)}.log" | ||
|
||
temp_log_full = os.path.join(cfg.arm_config['LOGPATH'], logfile) | ||
logfile = new_log_file if os.path.isfile(temp_log_full) else logfile | ||
return logfile | ||
|
||
def pretty_table(self): | ||
"""Returns a string of the prettytable""" | ||
pretty_table = PrettyTable() | ||
pretty_table.field_names = ["Config", "Value"] | ||
pretty_table._max_width = {"Config": 50, "Value": 60} | ||
for attr, value in self.__dict__.items(): | ||
if attr == "config": | ||
pretty_table.add_row([str(attr), str(value.pretty_table())]) | ||
else: | ||
pretty_table.add_row([str(attr), str(value)]) | ||
return str(pretty_table.get_string()) | ||
|
||
def get_d(self): | ||
""" | ||
Return a dict of class - exclude the _sa_instance_state | ||
:return: dict containing all attribs from class | ||
""" | ||
return_dict = {} | ||
for key, value in self.__dict__.items(): | ||
if '_sa_instance_state' not in key: | ||
return_dict[str(key)] = str(value) | ||
return return_dict | ||
|
||
def eject(self): | ||
"""Eject disc if it hasn't previously been ejected""" | ||
if not self.ejected: | ||
self.ejected = True | ||
try: | ||
# This might always return true | ||
if bool(os.system("umount " + self.devpath)): | ||
logging.debug(f"Unmounted disc {self.devpath}") | ||
else: | ||
logging.debug(f"Failed to unmount {self.devpath}") | ||
if bool(os.system("eject -sv " + self.devpath)): | ||
logging.debug(f"Ejected disc {self.devpath}") | ||
else: | ||
logging.debug(f"Failed to eject {self.devpath}") | ||
except Exception as error: | ||
logging.debug(f"{self.devpath} couldn't be ejected {error}") |
Oops, something went wrong.