# # Aura Engine API (https://gitlab.servus.at/aura/engine-api) # # Copyright (C) 2020 - The Aura Engine Team. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. import datetime from sqlalchemy import create_engine, Column, DateTime, String, Integer, Boolean from sqlalchemy.event import listen from flask_sqlalchemy import SQLAlchemy from flask_marshmallow import Marshmallow db = SQLAlchemy() ma = Marshmallow() class PlayLog(db.Model): """ Table holding play-log entries. """ __tablename__ = 'playlog' # Primary Key track_start = Column(DateTime, primary_key=True) # Columns track_artist = Column(String(256)) track_album = Column(String(256)) track_title = Column(String(256)) track_duration = Column(String(256)) track_type = Column(Integer) timeslot_id = Column(Integer) show_name = Column(String(256)) log_source = Column(Integer) # The play-out source this log is coming from (e.g. engine1, engine2) is_synced = Column(Boolean) # Only relevant for main nodes, in a multi-node setup def __init__(self, data): """ Initializes a trackservice entry """ self.track_start = data.track_start self.track_artist = data.track_artist self.track_album = data.track_album self.track_title = data.track_title self.track_duration = data.track_duration self.track_type = data.track_type self.timeslot_id = data.timeslot_id self.show_name = data.show_name self.log_source = data.log_source self.is_synced = False def save(self): db.session.add(self) db.session.commit() @staticmethod def select_current(): """ Selects the currently playing track. """ db.session.commit() now = datetime.datetime.now() track = db.session.query(PlayLog).\ filter(PlayLog.track_start <= str(now)).\ order_by(PlayLog.track_start.desc()).first() return track @staticmethod def paginate(page, page_size, since_time=None): """ Returns a list of entries for a given page and an start time (optional). """ def q(page=0, page_size=None): query = db.session.query(PlayLog).order_by(PlayLog.track_start.desc()) if isinstance(since_time, datetime.datetime): query = query.filter(PlayLog.track_start >= since_time) listen(query, 'before_compile', apply_limit(page, page_size), retval=True) return query def apply_limit(page, page_size): def wrapped(query): if page_size: query = query.limit(page_size) if page: query = query.offset(page * page_size) return query return wrapped return q(page, page_size) @staticmethod def select_last_hours(n): """ Selects the tracks playing in the past (`n`) hours. """ db.session.commit() last_hours = datetime.datetime.today() - datetime.timedelta(hours=n) tracks = db.session.query(PlayLog).filter(PlayLog.track_start >= str(last_hours)).\ order_by(PlayLog.track_start.desc()).all() return tracks @staticmethod def select_by_day(day): """ Select the track-service items for a day. """ db.session.commit() day_plus_one = day + datetime.timedelta(days=1) tracks = db.session.query(PlayLog).\ filter(PlayLog.track_start >= str(day), PlayLog.track_start < str(day_plus_one)).\ order_by(PlayLog.track_start.desc()).all() return tracks @staticmethod def select_by_range(from_day, to_day): """ Selects the track-service items for a day range. """ db.session.commit() tracks = db.session.query(PlayLog).filter(PlayLog.track_start >= str(from_day),\ PlayLog.track_start < str(to_day)).order_by(PlayLog.track_start.desc()).all() return tracks def __str__(self): return "Track [track_start: %s, track_title: %s]" % (str(self.track_start), str(self.track_title)) class PlayLogSchema(ma.SQLAlchemyAutoSchema): """ Schema for playlog entries. """ class Meta: model = PlayLog sqla_session = db.session class TrackSchema(ma.SQLAlchemySchema): """ Schema for trackservice entries. """ class Meta: model = PlayLog sqla_session = db.session fields = ( "track_start", "track_artist", "track_album", "track_title" ) class ActivityLog(db.Model): """ Table holding a log of play-out source activity and their sync states. Only used in "SYNC" deployment mode. """ __tablename__ = 'activity_log' # Primary Key log_time = Column(DateTime, primary_key=True) # Columns source_number = Column(Integer) is_synced = Column(Boolean) def __init__(self, source_number): """ Initializes an activity entry """ self.log_time = datetime.datetime.now() self.source_number = source_number self.is_synced = False def get_active_source(): """ Retrieves the currently active source. """ db.session.commit() source = db.session.query(ActivityLog).\ order_by(ActivityLog.log_time.desc()).first() return source def save(self): db.session.add(self) db.session.commit() class HealthHistoryEntry(db.Model): """ Table holding an history of health information for sources. """ __tablename__ = 'health_history' # Primary Key log_time = Column(DateTime, primary_key=True) # Columns source_number = Column(Integer) is_healthy = Column(Boolean) is_synced = Column(Boolean) # Only relevant for main nodes, in a multi-node setup health_info = Column(String(2048)) def __init__(self, source_number, is_healthy, health_info): """ Initializes an health entry. """ self.log_time = datetime.datetime.now() self.source_number = source_number self.is_healthy = is_healthy self.is_synced = False self.health_info = health_info def save(self): db.session.add(self) db.session.commit()