示例#1
0
    def generate_vod_recording_playlist_m3u8(cls, client_uuid, recording_id,
                                             http_token):
        db_session = Database.create_session()

        try:
            vod_playlist_m3u8_object = M3U8()
            vod_playlist_m3u8_object.media_sequence = 0
            vod_playlist_m3u8_object.version = '3'
            vod_playlist_m3u8_object.target_duration = 0
            vod_playlist_m3u8_object.playlist_type = 'VOD'

            for segment_row in DatabaseAccess.query_segment_pickle(
                    db_session, recording_id):
                segment = pickle.loads(segment_row.pickle)

                if segment.duration > vod_playlist_m3u8_object.target_duration:
                    vod_playlist_m3u8_object.target_duration = math.ceil(
                        segment.duration)

                vod_playlist_m3u8_object.add_segment(segment)

            return re.sub(
                r'(\.ts\?)(.*)', r'\1client_uuid={0}&http_token={1}&\2'.format(
                    client_uuid,
                    urllib.parse.quote(http_token) if http_token else ''),
                '{0}\n'
                '{1}'.format(vod_playlist_m3u8_object.dumps(),
                             '#EXT-X-ENDLIST'))
        finally:
            db_session.close()
示例#2
0
    def get_recording(cls, db_session, recording_id):
        recording = DatabaseAccess.query_recording(db_session, recording_id)

        if recording is not None:
            return recording

        raise RecordingNotFoundError
示例#3
0
    def _start_recording(cls):
        current_date_time_in_utc = datetime.now(pytz.utc)

        with Database.get_write_lock():
            db_session = Database.create_session()

            try:
                for scheduled_recording in DatabaseAccess.query_scheduled_recordings(
                        db_session):
                    scheduled_recording_start_date_time_in_utc = scheduled_recording.start_date_time_in_utc

                    if current_date_time_in_utc > scheduled_recording_start_date_time_in_utc:
                        scheduled_recording.status = RecordingStatus.LIVE.value

                        with cls._live_recordings_to_recording_thread_lock:
                            cls._live_recordings_to_recording_thread[
                                scheduled_recording.id] = RecordingThread(
                                    scheduled_recording)
                            cls._live_recordings_to_recording_thread[
                                scheduled_recording.id].start()

                db_session.commit()

                cls._set_start_recording_timer(db_session)
            except Exception:
                (type_, value_, traceback_) = sys.exc_info()
                logger.error('\n'.join(
                    traceback.format_exception(type_, value_, traceback_)))

                db_session.rollback()
            finally:
                db_session.close()
示例#4
0
    def delete_recording(cls, db_session, recording):
        DatabaseAccess.delete_recording(db_session, recording.id)

        for segment_row in DatabaseAccess.query_segments_directory_path(
                db_session, recording.id):
            try:
                shutil.rmtree(segment_row.directory_path)
            except OSError:
                pass

        DatabaseAccess.delete_segments(db_session, recording.id)
        db_session.flush()

        if not db_session.deleted:
            if recording.status == RecordingStatus.SCHEDULED.value:
                cls._set_start_recording_timer(db_session)
        else:
            raise RecordingNotFoundError
示例#5
0
    def stop_live_recording(cls, db_session, recording):
        with cls._live_recordings_to_recording_thread_lock:
            try:
                cls._live_recordings_to_recording_thread[
                    recording.id].force_stop()

                del cls._live_recordings_to_recording_thread[recording.id]
            except KeyError:
                recording = DatabaseAccess.query_recording(
                    db_session, recording.id)

                if recording is not None:
                    if recording.status == RecordingStatus.LIVE.value:
                        segment_row = DatabaseAccess.query_segments_count(
                            db_session, recording.id)

                        if segment_row is not None and segment_row.count > 0:
                            recording.status = RecordingStatus.PERSISTED.value
                else:
                    raise RecordingNotFoundError
示例#6
0
    def get_recordings(cls):
        recordings = []

        db_session = Database.create_session()

        try:
            for recording in DatabaseAccess.query_recordings(db_session):
                recordings.append(recording)
        finally:
            db_session.close()

        return recordings
示例#7
0
    def _initialize_fernet_key(cls):
        db_session = Database.create_session()

        try:
            password_encryption_key_setting = DatabaseAccess.query_setting(
                db_session, 'password_encryption_key')

            if password_encryption_key_setting is not None:
                fernet_key = password_encryption_key_setting.value.encode()
                cls._fernet = Fernet(fernet_key)
        finally:
            db_session.close()
示例#8
0
    def _restart_live_recordings(cls, db_session):
        current_date_time_in_utc = datetime.now(pytz.utc)

        live_recordings_to_recording_thread = {}

        for live_recording in DatabaseAccess.query_live_recordings(db_session):
            if live_recording.end_date_time_in_utc > current_date_time_in_utc:
                live_recordings_to_recording_thread[
                    live_recording.id] = RecordingThread(live_recording)
                live_recordings_to_recording_thread[live_recording.id].start()

        cls._set_live_recordings_to_recording_thread(
            live_recordings_to_recording_thread)
示例#9
0
    def generate_vod_index_playlist_m3u8(cls, is_server_secure,
                                         client_ip_address, client_uuid,
                                         http_token):
        playlist_m3u8 = []

        client_ip_address_type = Utility.determine_ip_address_type(
            client_ip_address)
        server_hostname = Configuration.get_configuration_parameter(
            'SERVER_HOSTNAME_{0}'.format(client_ip_address_type.value))
        server_port = Configuration.get_configuration_parameter(
            'SERVER_HTTP{0}_PORT'.format('S' if is_server_secure else ''))

        db_session = Database.create_session()

        try:
            for persistent_recording in DatabaseAccess.query_persisted_recordings(
                    db_session):
                playlist_m3u8.append(
                    '#EXTINF:-1,{0} - [{1} - {2}]\n'
                    '{3}\n'.format(
                        persistent_recording.program_title,
                        persistent_recording.start_date_time_in_utc.astimezone(
                            tzlocal.get_localzone()).strftime(
                                '%Y-%m-%d %H:%M:%S%z'),
                        persistent_recording.end_date_time_in_utc.astimezone(
                            tzlocal.get_localzone()).strftime(
                                '%Y-%m-%d %H:%M:%S%z'),
                        cls.generate_vod_recording_playlist_url(
                            is_server_secure,
                            server_hostname,
                            server_port,
                            client_uuid,
                            persistent_recording.id,
                            http_token,
                        ),
                    ))
        finally:
            db_session.close()

        if playlist_m3u8:
            playlist_m3u8 = '#EXTM3U\n{0}'.format(''.join(playlist_m3u8))

            logger.debug('Generated VOD playlist.m3u8')
        else:
            logger.debug(
                'No persistent recordings found. VOD playlist.m3u8 will not be generated'
            )

        return playlist_m3u8
示例#10
0
    def get_recording_program_title(cls, recording_id):
        db_session = Database.create_session()

        try:
            recording = DatabaseAccess.query_recording(db_session,
                                                       recording_id)

            if recording is not None:
                program_title = recording.program_title
            else:
                program_title = 'Recording {0}'.format(recording_id)

            return program_title
        finally:
            db_session.close()
示例#11
0
    def load_ts_file(cls, path, recording_id):
        db_session = Database.create_session()

        try:
            segment_name = re.sub(r'/vod/(.*)\?.*', r'\1', path)

            segment_row = DatabaseAccess.query_segment_directory_path(
                db_session, segment_name, recording_id)

            if segment_row is not None:
                return Utility.read_file(os.path.join(
                    segment_row.directory_path, segment_name),
                                         in_binary=True)
            else:
                raise SegmentNotFoundError
        finally:
            db_session.close()
示例#12
0
    def _set_start_recording_timer(cls, db_session):
        with cls._start_recording_timer_lock:
            if cls._start_recording_timer:
                cls._start_recording_timer.cancel()

            soonest_scheduled_recording_start_date_time_in_utc = None
            current_date_time_in_utc = datetime.now(pytz.utc)

            for scheduled_recording in DatabaseAccess.query_scheduled_recordings(
                    db_session):
                scheduled_recording_start_date_time_in_utc = (
                    scheduled_recording.start_date_time_in_utc)

                if (current_date_time_in_utc >
                        scheduled_recording_start_date_time_in_utc):
                    scheduled_recording.status = RecordingStatus.LIVE.value

                    with cls._live_recordings_to_recording_thread_lock:
                        cls._live_recordings_to_recording_thread[
                            scheduled_recording.id] = RecordingThread(
                                scheduled_recording)
                        cls._live_recordings_to_recording_thread[
                            scheduled_recording.id].start()
                elif not soonest_scheduled_recording_start_date_time_in_utc:
                    soonest_scheduled_recording_start_date_time_in_utc = (
                        scheduled_recording_start_date_time_in_utc)
                elif (soonest_scheduled_recording_start_date_time_in_utc >
                      scheduled_recording_start_date_time_in_utc):
                    soonest_scheduled_recording_start_date_time_in_utc = (
                        scheduled_recording_start_date_time_in_utc)

            if soonest_scheduled_recording_start_date_time_in_utc:
                interval = (
                    soonest_scheduled_recording_start_date_time_in_utc -
                    datetime.now(pytz.utc)).total_seconds()
                cls._start_recording_timer = Timer(interval,
                                                   cls._start_recording)
                cls._start_recording_timer.daemon = True
                cls._start_recording_timer.start()

                logger.debug(
                    'Starting recording timer\nInterval => %s seconds',
                    interval)
示例#13
0
    def _initialize_recordings(cls, db_session):
        deleted_recordings_log_message = []
        loaded_recordings_log_message = []

        unformatted_message_to_log = 'Provider          => {0}\n' \
                                     'Channel number    => {1}\n' \
                                     'Channel name      => {2}\n' \
                                     'Program title     => {3}\n' \
                                     'Start date & time => {4}\n' \
                                     'End date & time   => {5}\n' \
                                     'Status            => {6}\n'

        for recording in DatabaseAccess.query_recordings(db_session):
            current_date_time_in_utc = datetime.now(pytz.utc)

            formatted_message_to_log = unformatted_message_to_log.format(
                recording.provider, recording.channel_number,
                recording.channel_name, recording.program_title,
                recording.start_date_time_in_utc.astimezone(
                    tzlocal.get_localzone()).strftime('%Y-%m-%d %H:%M:%S%z'),
                recording.end_date_time_in_utc.astimezone(
                    tzlocal.get_localzone()).strftime('%Y-%m-%d %H:%M:%S%z'),
                recording.status)

            if current_date_time_in_utc >= recording.end_date_time_in_utc:
                if recording.status == RecordingStatus.LIVE.value:
                    segment_row = DatabaseAccess.query_segments_count(
                        db_session, recording.id)

                    if segment_row is not None and segment_row.count > 0:
                        recording.status = RecordingStatus.PERSISTED.value

                        loaded_recordings_log_message.append(
                            formatted_message_to_log)
                    else:
                        DatabaseAccess.delete_recording(
                            db_session, recording.id)

                        deleted_recordings_log_message.append(
                            formatted_message_to_log)
                elif recording.status == RecordingStatus.SCHEDULED.value:
                    DatabaseAccess.delete_recording(db_session, recording.id)

                    deleted_recordings_log_message.append(
                        formatted_message_to_log)
            else:
                loaded_recordings_log_message.append(formatted_message_to_log)

        if deleted_recordings_log_message:
            deleted_recordings_log_message.insert(
                0, 'Deleted expired recording{0}\n'.format(
                    's' if len(deleted_recordings_log_message) > 1 else ''))

            logger.debug('\n'.join(deleted_recordings_log_message).strip())

        if loaded_recordings_log_message:
            loaded_recordings_log_message.insert(
                0, 'Loaded recording{0}\n'.format(
                    's' if len(loaded_recordings_log_message) > 1 else ''))

            logger.debug('\n'.join(loaded_recordings_log_message).strip())
示例#14
0
 def delete_setting(cls, db_session, setting_name):
     DatabaseAccess.delete_setting(db_session, setting_name)
示例#15
0
 def query_settings(cls, db_session):
     return DatabaseAccess.query_settings(db_session)
示例#16
0
 def query_setting(cls, db_session, setting_name):
     return DatabaseAccess.query_setting(db_session, setting_name)