Example #1
0
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")
Example #2
0
 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,
     )
Example #3
0
    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", "/"))
Example #4
0
    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()
Example #5
0
    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")
Example #6
0
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")
Example #7
0
    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)
Example #8
0
    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
Example #9
0
    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()
Example #10
0
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")
Example #11
0
    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")
Example #12
0
 def on_live_leave(self):
     logging.goodnews("Leaving a live event")
     self.current_live = False
Example #13
0
 def on_live_enter(self):
     logging.goodnews("Entering a live event")
     self.current_live = True
     self.cued_live = False
Example #14
0
    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()
Example #15
0
        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