broadcasts.py 11 KB
Newer Older
1
__author__ = 'gg'
2
3
# -*- coding: utf-8 -*-

4
import datetime, os, urllib, sys
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
5
import time
6
import decimal
7

8
from sqlalchemy import orm, func, Boolean, Column, Date, DateTime, Float, Integer, String, Text, Time, ForeignKey, ForeignKeyConstraint
9
from sqlalchemy.orm import relationship
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
10
from sqlalchemy.sql.expression import false
11
from libraries.database.database import db
12
from libraries.enum.scheduleentrytype import ScheduleEntryType
13

14

Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
15
class AuraDatabaseModel:
16
17
18
    def store(self, add=False, commit=False):
        if add:
            db.session.add(self)
19
20
        if commit:
            db.session.commit()
21
22

    def delete(self, commit=False):
23
24
25
        db.session.delete(self)
        if commit:
            db.session.commit()
26

27
28
    def _asdict(self):
        return self.__dict__
29

30
    @staticmethod
31
32
33
    def recreate_db(systemexit = False):
        manualschedule = Schedule()
        manualschedule.schedule_id = 0
34
        manualschedule.show_name = "Manual Show"
35

36
37
38
39
        print("Recreating Database...")
        db.drop_all()
        print("all dropped. creating...")
        db.create_all()
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
40
        print("inserting manual scheduling possibility and fallback trackservice schedule")
41
        db.session.add(manualschedule)
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
42
#        db.session.add(fallback_trackservice_schedule)
43
44
45
        print("all created. commiting...")
        db.session.commit()
        print("Database recreated!")
46

47
48
        if systemexit:
            sys.exit(0)
49

50

51
# ------------------------------------------------------------------------------------------ #
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
52
class Schedule(db.Model, AuraDatabaseModel):
53
    """
54
    One specific Schedule for a show on a timeslot
55
    """
56
    __tablename__ = 'schedule'
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
57
58

    # primary and foreign keys
59
    schedule_id = Column(Integer, primary_key=True, autoincrement=False)
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
60
    show_id = Column(Integer) # well, not needed..
61

62
63
    schedule_start = Column(DateTime) # can be null due to manual entries
    schedule_end = Column(DateTime) # can be null due to manual entries
64
65
66
67
68
69
70
71
72
    show_name = Column(String(256))
    show_hosts = Column(String(256))
    rtr_category = Column(String(256))
    comment = Column(String(512))
    languages = Column(String(256))
    type = Column(String(256))
    category = Column(String(256))
    topic = Column(String(256))
    musicfocus = Column(String(256))
73
74
75

    is_repetition = Column(Boolean())

76
77
78
79
80
    playlist_id = Column(Integer)
    timeslot_fallback_id = Column(Integer)
    show_fallback_id = Column(Integer)
    station_fallback_id = Column(Integer)

81
82
83
84
85
86
    def get_length(self):
        sec1 = int(datetime.datetime.strptime(self.start[0:16].replace(" ", "T"), "%Y-%m-%dT%H:%M").strftime("%s"))
        sec2 = int(datetime.datetime.strptime(self.end[0:16].replace(" ", "T"), "%Y-%m-%dT%H:%M").strftime("%s"))
        len = sec2 - sec1
        return len

87

88
# ------------------------------------------------------------------------------------------ #
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
89
class ScheduleEntry(db.Model, AuraDatabaseModel):
90
    """
91
    One schedule can have multiple entries
92
    """
93
94
    __tablename__ = 'schedule_entry'

Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
95
    # primary and foreign keys
96
97
98
    playlist_id = Column(Integer, primary_key=True, nullable=False, autoincrement=False)
    entry_num = Column(Integer, primary_key=True, nullable=False, autoincrement=False)
    schedule_id = Column(Integer, ForeignKey("schedule.schedule_id"))
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
99

100
    entry_start = Column(DateTime)
101
    source = Column(String(256))
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
102
    volume = Column(Integer, default=100)
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
103
    is_fallback = Column(Boolean, default=False)
104
    cleansource = ""
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
105
    entry_start_unix = 0
106
    programme_index = -1
107
    type = None
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
108

109
    schedule = relationship("Schedule", foreign_keys=[schedule_id], lazy="joined")
110

111
    # normal constructor
112
113
    def __init__(self, **kwargs):
        super(ScheduleEntry, self).__init__(**kwargs)
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
114
        self.calc_unix_times()
115

116
    # constructor like - called from sqlalchemy
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
117
    @orm.reconstructor
118
119
120
121
    def reconstructor(self):
        self.calc_unix_times()
        self.set_entry_type()

122
123
124
125
126
127
128
129
    def define_clean_source(self):
        if self.source.startswith("http") or self.source.startswith("live") or self.source.startswith("linein"):
            self.cleansource = self.source
        if self.source.startswith("pool") or self.source.startswith("file"):
            self.cleansource = self.source[7:]
        if self.source.startswith("playlist"):
            self.cleansource = self.source[11:]

130
    def calc_unix_times(self):
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
131
132
        if self.entry_start is not None:
            self.entry_start_unix = time.mktime(self.entry_start.timetuple())
133

134
135
    def set_entry_type(self):
        if self.source.startswith("http"):
136
137
138
139
140
            self.type = ScheduleEntryType.STREAM
        if self.source.startswith("pool") or self.source.startswith("playlist") or self.source.startswith("file"):
            self.type = ScheduleEntryType.FILESYSTEM
        if self.source.startswith("live") or self.source.startswith("linein"):
            self.type = ScheduleEntryType.LIVE
141

142
143
144
145
146
147
    # ------------------------------------------------------------------------------------------ #
    @staticmethod
    def select_all():
        # when deleting all entries, and fetching new programmes, the entries are stored and commited in the code.
        # but sqlalchemy thinks somehow it is not commit and returns an empty set

148
149
        #print("WARNING: broadcasts.py This commit before SELECT is a BAND-AID & UGLY-HACK. Why the hell is there a transaction pending and not commited?")
        #db.session.commit()
150
        # fetching all entries
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
151
        all_entries = db.session.query(ScheduleEntry).filter(ScheduleEntry.is_fallback == false()).order_by(ScheduleEntry.entry_start).all()
152
153

        # BAND-AID debug output. The model and db session are different. crap
154
155
156
157
        #print("broadcasts.py SELECT ALL ScheduleEntry.q.session == db.session?")
        #print(ScheduleEntry.query.session == db.session)
        #print("broadcasts.py SELECT ALL ScheduleEntry.q.s.conn == db.s.conn?")
        #print(ScheduleEntry.query.session.connection() == db.session.connection())
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
        cnt = 0
        for entry in all_entries:
            entry.programme_index = cnt
            cnt = cnt + 1

        return all_entries

    @staticmethod
    def select_next_manual_entry_num():

        max_manual_entry_num = db.session.query(func.max(ScheduleEntry.entry_num)).filter(ScheduleEntry.schedule_id == 0).first()
        print(max_manual_entry_num)

        if max_manual_entry_num[0] is None:
            return 0
        else:
            return int(max_manual_entry_num[0])+1

#        print("returning", res)

#        return res

    # ------------------------------------------------------------------------------------------ #
    @staticmethod
    def upcoming(datefrom=datetime.datetime.now()):
        # damn BAND-AID
184
        # db.session.commit()
185
186
187
188
189
190
191
192

        upcomingtracks = db.session.query(ScheduleEntry).filter(ScheduleEntry.start > datefrom).all()
        #upcomingtracks = ScheduleEntry.query.filter(ScheduleEntry.start > datefrom).all()
        return upcomingtracks

    # ------------------------------------------------------------------------------------------ #
    @staticmethod
    def select_one(playlist_id, entry_num):
193
        return db.session.query(ScheduleEntry).filter(ScheduleEntry.playlist_id == playlist_id, ScheduleEntry.entry_num == entry_num).first()
194
195
196
197
198

    # ------------------------------------------------------------------------------------------ #
    def __str__(self):
        return "ScheduleEntry starts @ " + ScheduleEntry.entry_start + " and ends @ " + ScheduleEntry.entry_end + " and plays " + ScheduleEntry.source

199

200
# ------------------------------------------------------------------------------------------ #
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
201
202
class TrackService(db.Model, AuraDatabaseModel):
    __tablename__ = 'trackservice'
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
203

Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
204
205
206
    trackservice_id = Column(Integer, primary_key=True, autoincrement=True)
    playlist_id = Column(Integer, nullable=False)
    entry_num = Column(Integer, nullable=False)
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
207

Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
208
    source = Column(String(255), nullable=False)
209
    start = Column(DateTime, nullable=False, default=func.now())
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
210

211
212
213
    __table_args__ = (
        ForeignKeyConstraint(['playlist_id', 'entry_num'], ['schedule_entry.playlist_id', 'schedule_entry.entry_num']),
    )
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
214

215
    #schedule = relationship("Schedule", foreign_keys=[schedule_id], lazy="joined")
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
216
217
    # trackservice_entry = relationship("ScheduleEntry", foreign_keys=[playlist_id, entry_num], lazy="joined")
    schedule_entry = relationship("ScheduleEntry", primaryjoin="and_(TrackService.playlist_id==ScheduleEntry.playlist_id, TrackService.entry_num==ScheduleEntry.entry_num)", lazy="joined")
218

219
220
221
    @staticmethod
    def select_one(trackservice_id):
        return db.session.query(TrackService).filter(TrackService.trackservice_id == trackservice_id).first()
222

Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
# ------------------------------------------------------------------------------------------ #
# class TrackServiceSchedule(db.Model, AuraDatabaseModel):
#     """
#     Trackservice is tracking every schedule.
#     """
#     __tablename__ = 'trackservice_schedule'
#
#     # primary and foreign keys
#     ts_schedule_id = Column(Integer, primary_key=True, autoincrement=True)
#     schedule_id = Column(Integer, ForeignKey("schedule.schedule_id"))
#
#     schedule = relationship("Schedule", foreign_keys=[schedule_id], lazy="joined")
#
#     # ------------------------------------------------------------------------------------------ #
#     @staticmethod
#     def select_one(schedule_id):
#         # damn BAND-AID
#         # db.session.commit()
#
#         return db.session.query(ScheduleEntry).filter(TrackServiceSchedule.schedule_id == schedule_id).first()
#
# # ------------------------------------------------------------------------------------------ #
# class TrackServiceScheduleEntry(db.Model, AuraDatabaseModel):
#     """
#     And a schedule can have multiple entries
#     """
#     __tablename__ = 'trackservice_entry'
#
#     # primary and foreign keys. the foreign keys here can be null, because of fallback stuff
#     ts_entry_id = Column(Integer, primary_key=True, autoincrement=True)
#     ts_schedule_id = Column(Integer, ForeignKey("trackservice_schedule.ts_schedule_id"), nullable=True)
#     playlist_id = Column(Integer, nullable=True)
#     entry_num = Column(Integer, nullable=True)
#
#     fallback = Column(Boolean, default=False)
#     fallback_start = Column(DateTime, nullable=True, default=None)
#     source = Column(String(256), nullable=True, default=None)
#
#     # foreign key definitions
#     __table_args__ = (
#         ForeignKeyConstraint(['playlist_id', 'entry_num'], ['schedule_entry.playlist_id', 'schedule_entry.entry_num']),
#     )
#
#     trackservice_schedule = relationship("TrackServiceSchedule", foreign_keys=[ts_schedule_id], lazy="joined")
#     #trackservice_entry = relationship("ScheduleEntry", foreign_keys=[playlist_id, entry_num], lazy="joined")
#     trackservice_entry = relationship("ScheduleEntry", primaryjoin="and_(TrackServiceScheduleEntry.playlist_id==ScheduleEntry.playlist_id, TrackServiceScheduleEntry.entry_num==ScheduleEntry.entry_num)" , lazy="joined")
#
#     @staticmethod
#     def select_all():
#         return db.session.query(TrackServiceScheduleEntry).filter().all()

274
#AuraDatabaseModel.recreate_db(True)