def passwd(*args): print() try: login = input("Login: "******"Password (will be echoed): ").strip() is_admin = input("Admin (yes/no): ").strip() except KeyboardInterrupt: print() logging.warning("Interrupted by user") sys.exit(0) db = DB() db.query("SELECT id FROM users WHERE login=%s", [login]) res = db.fetchall() if not res: critical_error("Unable to set password: no such user") u = User(res[0][0], db=db) if login: u["login"] = u["full_name"] = login u["is_admin"] = 1 if is_admin == "yes" else 0 u.set_password(password) u.save() print() logging.goodnews("Password changed")
def done(self, message="Completed"): now = time.time() self.db.query( """ UPDATE jobs SET status=2, progress=100, end_time=%s, message=%s WHERE id=%s """, [now, message, self.id], ) self.db.commit() self.status = JobState.COMPLETED logging.goodnews(f"{self}: {message}") messaging.send( "job_progress", id=self.id, id_asset=self.asset.id, id_action=self.action.id, status=JobState.COMPLETED, etime=now, progress=100, message=message, )
def login(self, *args, **kwargs): if args: return self.render_error(400, "Bad request") if cherrypy.request.method != "POST": return self.render_error(400, "Bad request") request = parse_request(**kwargs) login = request.get("login", "-") password = request.get("password", "-") user_data = self.parent["login_helper"](login, password) if not user_data: logging.error(f"Incorrect login ({login})") if kwargs.get("api", False): return json_response( 401, "Invalid user name / password combination") return self.default(error="Invalid login/password combination") if "password" in user_data: del (user_data["password"]) client_info = get_client_info() logging.goodnews("User {} logged in".format(login)) session_id = self.sessions.create(user_data, **client_info) save_session_cookie(self, session_id) if request.get("api", False): return json_response(200, data=user_data, session_id=session_id) raise cherrypy.HTTPRedirect(request.get("from_page", "/"))
def load_callback(self, response): self.parent().setCursor(Qt.ArrowCursor) if not response: logging.error(response.message) return QApplication.processEvents() self.parent().setCursor(Qt.WaitCursor) self.beginResetModel() logging.info("Loading rundown. Please wait...") required_assets = [] self.header_data = config["playout_channels"][self.id_channel].get( "rundown_columns", DEFAULT_COLUMNS) self.object_data = [] self.event_ids = [] i = 0 for row in response.data: row["rundown_row"] = i if row["object_type"] == "event": self.object_data.append(Event(meta=row)) i += 1 self.event_ids.append(row["id"]) if row["is_empty"]: self.object_data.append( Item(meta={ "title": "(Empty event)", "id_bin": row["id_bin"] })) i += 1 elif row["object_type"] == "item": item = Item(meta=row) item.id_channel = self.id_channel if row["id_asset"]: item._asset = asset_cache.get(row["id_asset"]) required_assets.append( [row["id_asset"], row["asset_mtime"]]) else: item._asset = False self.object_data.append(item) i += 1 else: continue asset_cache.request(required_assets) self.endResetModel() self.parent().setCursor(Qt.ArrowCursor) logging.goodnews( "Rundown loaded in {:.03f}s".format(time.time() - self.load_start_time)) if self.current_callback: self.current_callback()
def __init__(self, id_service, settings=False): logging.debug(f"Initializing service ID {id_service}") self.id_service = id_service self.settings = settings config["id_service"] = id_service try: self.on_init() except SystemExit: sys.exit(1) except Exception: log_traceback(f"Unable to initialize service ID {id_service}") self.shutdown() else: db = DB() db.query( "UPDATE services SET last_seen = %s, state=1 WHERE id=%s", [time.time(), self.id_service], ) db.commit() logging.goodnews("Service started")
def adduser(*args): print() try: login = input("Login: "******"Password (will be echoed): ").strip() is_admin = input("Admin (yes/no): ").strip() full_name = input(f"Full name (default: {login}): ").strip() or login email = input("Email: ").strip() except KeyboardInterrupt: print() logging.warning("Interrupted by user") sys.exit(0) user = User() user["login"] = login user["full_name"] = full_name user["email"] = email user["is_admin"] = 1 if is_admin == "yes" else 0 user.set_password(password) user.save() print() logging.goodnews("User created")
def on_message(self, *args): data = args[-1] if not self.active: logging.goodnews("[LISTENER] connected", handlers=False) self.active = True try: message = SeismicMessage(json.loads(data)) except Exception: log_traceback(handlers=False) logging.debug(f"[LISTENER] Malformed message: {data}", handlers=False) return if message.site_name != self.site_name: return self.last_msg = time.time() if message.data and message.data.get("initiator", None) == CLIENT_ID: return self.queue.put(message)
def main(self): info = self.parser.get_info(self.caspar_feed_layer) if not info: logging.warning("Channel {} update stat failed".format(self.id_channel)) self.bad_requests += 1 if self.bad_requests > 10: logging.error("Connection lost. Reconnecting...") if self.connect(): logging.goodnews("Connection estabilished") else: logging.error("Connection call failed") time.sleep(2) time.sleep(0.3) return else: self.request_time = time.time() self.bad_requests = 0 current_fname = info["current"] cued_fname = info["cued"] # # # Auto recovery # # if not current_fname and time.time() - self.recovery_time > 20: # self.parent.channel_recover() # return # self.recovery_time = time.time() if ( cued_fname and (not self.paused) and (info["pos"] == self.fpos) and not self.parent.current_live and self.cued_item and (not self.cued_item["run_mode"]) ): if self.stalled and self.stalled < time.time() - 5: logging.warning("Stalled for a long time") logging.warning("Taking stalled clip (pos: {})".format(self.fpos)) self.take() elif not self.stalled: logging.debug("Playback is stalled") self.stalled = time.time() elif self.stalled: logging.debug("No longer stalled") self.stalled = False self.fpos = info["pos"] self.fdur = info["dur"] # # Playlist advancing # advanced = False if ( self.cueing and self.cueing == current_fname and not cued_fname and not self.parent.cued_live ): logging.warning("Using short clip workaround") self.current_item = self.cued_item self.current_fname = current_fname self.current_in = self.cued_in self.current_out = self.cued_out self.cued_in = self.cued_out = 0 advanced = True self.cued_item = False self.cueing = False self.cued_fname = False elif (not cued_fname) and (current_fname) and not self.parent.cued_live: if current_fname == self.cued_fname: self.current_item = self.cued_item self.current_fname = self.cued_fname self.current_in = self.cued_in self.current_out = self.cued_out self.cued_in = self.cued_out = 0 advanced = True self.cued_item = False elif (not current_fname) and (not cued_fname) and self.parent.cued_live: self.current_item = self.cued_item self.current_fname = "LIVE" self.current_in = 0 self.current_out = 0 self.cued_in = self.cued_out = 0 advanced = True self.cued_item = False self.parent.on_live_enter() if advanced: try: self.parent.on_change() except Exception: log_traceback("Playout on_change failed") if self.current_item and not self.cued_item and not self.cueing: self.parent.cue_next() elif self.force_cue: logging.info("Forcing cue next") self.parent.cue_next() self.force_cue = False if self.cueing: if cued_fname == self.cued_fname: logging.debug("Cued", self.cueing) self.cueing = False else: logging.debug("Cueing", self.cueing) if ( self.cued_item and cued_fname and cued_fname != self.cued_fname and not self.cueing ): logging.warning( "Cue mismatch: IS: {} SHOULDBE: {}".format(cued_fname, self.cued_fname) ) self.cued_item = False try: self.parent.on_progress() except Exception: log_traceback("Playout on_main failed") self.current_fname = current_fname self.cued_fname = cued_fname
def __init__(self, **kwargs): """CherryAdmin class constructor. host: IP Address the server will listen for HTTP connections port: Port the server will listen for HTTP connection blocking: templates_dir: static_dir: sessions_dir: sessions_timeout: Minutes after which inactive session expires hash_salt: minify_html: log_screen: """ self.settings = default_settings self.settings.update(kwargs) self.is_running = False self.handler = CherryAdminHandler(self) self.sessions = CherryAdminSessions( self["sessions_dir"], self["sessions_timeout"] * 60, self["hash_salt"] ) static_root, static_dir = os.path.split( os.path.abspath(self["static_dir"]) ) self.config = { '/': { 'tools.proxy.on': True, 'tools.proxy.local': 'Referer', 'tools.staticdir.root': static_root, 'tools.trailing_slash.on': False, 'error_page.default': self.handler.cherrypy_error, }, '/static': { 'tools.staticdir.on': True, 'tools.staticdir.dir': static_dir }, '/favicon.ico': { 'tools.staticfile.on': True, 'tools.staticfile.filename': os.path.join( static_root, static_dir, "img", "favicon.ico" ) }, } cherrypy.config.update({ "server.socket_host": str(self["host"]), "server.socket_port": int(self["port"]), "log.screen": self["log_screen"] }) cherrypy.tree.mount(self.handler, "/", self.config) if kwargs.get("start_engine", True): cherrypy.engine.subscribe('start', self.start) cherrypy.engine.subscribe('stop', self.stop) cherrypy.engine.start() logging.goodnews("Web service started") if self["blocking"]: cherrypy.engine.block()
def do_import(parent, import_file, asset): probe = mediaprobe(import_file) match = True for condition in parent.conditions: value = parent.conditions[condition] if value != probe.get(condition, None): match = False break if match: logging.info(f"Fast importing {import_file} to {asset}") try: os.rename(import_file.path, asset.file_path) except Exception: log_traceback() mk_error(import_file, "Unable to fast import. See logs.") return False else: logging.info(f"Importing {import_file} to {asset}") try: themis = Themis( import_file, use_temp_file=False, ) except Exception: mk_error(import_file, "Import failed (Unable to read source file)") return False themis.add_output(asset.file_path, **parent.profile) if themis.start(): backup_dir = os.path.join( storages[parent.import_storage].local_path, parent.backup_dir, ) try: if not os.path.isdir(backup_dir): os.makedirs(backup_dir) except Exception: logging.error("Unable to create backup directory") os.remove(import_file.path) else: backup_path = os.path.join(backup_dir, os.path.basename(asset.file_path)) logging.debug(f"Creating backup of {asset} to {backup_path}") if os.path.exists(backup_path): os.remove(backup_path) os.rename(import_file.path, backup_path) logging.goodnews(f"{asset} imported") else: logging.error(f"{asset} import failed") mk_error(import_file, "Import failed") allkeys = list(asset.meta) for key in allkeys: if meta_types[key]["ns"] in ["q", "f"]: del asset.meta[key] asset["status"] = ObjectStatus.CREATING asset.save() logging.goodnews(f"Import {asset} finished")
def main(self): channel = self.caspar_data[self.caspar_channel] if not channel: return layer = channel[self.caspar_feed_layer] if not layer: return foreground = layer["foreground"] background = layer["background"] current_fname = os.path.splitext(foreground.name)[0] cued_fname = os.path.splitext(background.name)[0] pos = foreground.position dur = foreground.duration self.channel_fps = channel.fps self.paused = foreground.paused self.loop = foreground.loop # if cued_fname and (not self.paused) and (pos == self.pos) and (not self.parent.current_live) and self.cued_item and (not self.cued_item["run_mode"]): # if self.stalled and self.stalled < time.time() - 5: # logging.warning("Stalled for a long time") # logging.warning("Taking stalled clip (pos: {})".format(self.pos)) # self.take() # elif not self.stalled: # logging.debug("Playback is stalled") # self.stalled = time.time() # elif self.stalled: # logging.debug("No longer stalled") # self.stalled = False self.pos = pos self.dur = dur # # Playlist advancing # advanced = False if self.parent.cued_live: if ((background.producer == "empty") and (foreground.producer != "empty") and not self.cueing): self.current_item = self.cued_item self.current_fname = "LIVE" advanced = True self.cued_item = False self.parent.on_live_enter() else: if (not cued_fname) and (current_fname): if current_fname == self.cued_fname: self.current_item = self.cued_item self.current_fname = self.cued_fname advanced = True self.cued_item = False if advanced and not self.cueing: try: self.parent.on_change() except Exception: log_traceback("Playout on_change failed") if self.current_item and not self.cued_item and not self.cueing: self.cueing = True if not self.parent.cue_next(): self.cueing = False if self.cueing: if cued_fname == self.cueing: logging.goodnews(f"Cued {self.cueing}") self.cued_item = self.cueing_item self.cueing_item = False self.cueing = False elif self.parent.cued_live: if background.producer != "empty": logging.goodnews(f"Cued {self.cueing}") self.cued_item = self.cueing_item self.cueing_item = False self.cueing = False else: logging.debug( f"Waiting for cue {self.cueing} (is {cued_fname})") if time.time() - self.cueing_time > 5 and self.current_item: logging.warning("Cueing again") self.cueing = False self.parent.cue_next() elif (not self.cueing and self.cued_item and cued_fname and cued_fname != self.cued_fname and not self.parent.cued_live): logging.error( f"Cue mismatch: IS: {cued_fname} SHOULDBE: {self.cued_fname}") self.cued_item = False self.current_fname = current_fname self.cued_fname = cued_fname try: self.parent.on_progress() except Exception: log_traceback("Playout on_progress failed")
def on_live_leave(self): logging.goodnews("Leaving a live event") self.current_live = False
def on_live_enter(self): logging.goodnews("Entering a live event") self.current_live = True self.cued_live = False
def main(self): storages_conf = config.get("storages", "all") db = DB() db.query("SELECT id, settings FROM storages") for id_storage, storage_settings in db.fetchall(): if type(storages_conf) == list and id_storage not in storages_conf: continue storage = Storage(id_storage, **storage_settings) if storage: storage_string = f"{config['site_name']}:{storage.id}" storage_ident_path = os.path.join(storage.local_path, ".nebula_root") if not ( os.path.exists(storage_ident_path) and storage_string in [line.strip() for line in open(storage_ident_path).readlines()] ): try: with open(storage_ident_path, "a") as f: f.write(storage_string + "\n") except Exception: if self.first_run: logging.warning(f"{storage} is mounted, but read only") else: if self.first_run: logging.info(f"{storage} is mounted and root is writable") continue s, i, lcheck = storage_status.get(id_storage, [True, 2, 0]) if not s and time.time() - lcheck < i: continue if s: logging.info(f"{storage} is not mounted. Mounting...") if not os.path.exists(storage.local_path): try: os.mkdir(storage.local_path) except Exception: if s: logging.error(f"Unable to create mountpoint for {storage}") storage_status[id_storage] = [False, 240, time.time()] continue self.mount(storage) if ismount(storage.local_path): logging.goodnews(f"{storage} mounted successfully") if id_storage not in storage_status: storage_status[id_storage] = [True, 2, 0] storage_status[id_storage][0] = True storage_status[id_storage][1] = 2 else: if s: logging.error(f"{storage} mounting failed") storage_status[id_storage][0] = False check_interval = storage_status[id_storage][1] storage_status[id_storage][1] = min(240, check_interval * 2) storage_status[id_storage][2] = time.time()
try: sync_cron() or del_cron() time.sleep(10) except KeyboardInterrupt: break except Exception: log_traceback() time.sleep(10) # Shutdown (CTRL+C) print() try: logging.warning("Shutting down nebula. Please wait...") shutdown(agents) logging.goodnews("Exiting gracefully") sys.exit(0) except KeyboardInterrupt: print() logging.warning("Immediate shutdown enforced. This may cause problems") sys.exit(1) else: # This is a very dirty hack to keep old plugins working. import os # noqa import sys # noqa import json # noqa import time # noqa from nxtools import * # noqa