summaryrefslogtreecommitdiffstats
path: root/linhes/linhes-system/idle.py
blob: 3f4b3bc183b4a88b2e851c29416f243e553e776f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
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
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
#!/usr/bin/python

import argparse, os, re, subprocess, sys, time
from datetime import datetime, date, timedelta

def msg(cmdargs,msg):
    if cmdargs.silent is False:
        print("%s" %msg)

def mythshutdownlock_check(cmdargs,cursor):
    if (cmdargs.lock):
        msg(cmdargs,"    Checking mythshutdown for lock...")
        try:
            cursor.execute("select data from settings where value = 'MythShutdownLock'")
            results=cursor.fetchone()
        except:
            return True
        lock=results[0]
        if int(lock) == 0 :
            msg(cmdargs,"        mythshutdown is NOT locked.")
            return True
        else:
            msg(cmdargs,"        mythshutdown is locked.")
            return False
    else:
        return True

def dailywake_check(cmdargs,cursor):
    if (cmdargs.daily):
        msg(cmdargs,"    Checking if in a daily wake period...")
        dailyWake=False
        today = date.today()
        now = datetime.now()
        try:
            cursor.execute("select data from settings where value = 'DailyWakeupStartPeriod1'")
            results=cursor.fetchone()
            p1Start=datetime.strptime(' '.join([str(today), results[0]]), "%Y-%m-%d %H:%M")
            cursor.execute("select data from settings where value = 'DailyWakeupEndPeriod1'")
            results=cursor.fetchone()
            p1End=datetime.strptime(' '.join([str(today), results[0]]), "%Y-%m-%d %H:%M")
            cursor.execute("select data from settings where value = 'DailyWakeupStartPeriod2'")
            results=cursor.fetchone()
            p2Start=datetime.strptime(' '.join([str(today), results[0]]), "%Y-%m-%d %H:%M")
            cursor.execute("select data from settings where value = 'DailyWakeupEndPeriod2'")
            results=cursor.fetchone()
            p2End=datetime.strptime(' '.join([str(today), results[0]]), "%Y-%m-%d %H:%M")
        except:
            print("error")
            return True

        # Check for time periods that cross midnight
        if (p1End < p1Start):
            if (now > p1End):
                p1End = p1End + timedelta(days=1)
            else:
                p1Start = p1Start + timedelta(days=-1)
        if (p2End < p2Start):
            if (now > p2End):
                p2End = p2End + timedelta(days=1)
            else:
                p2Start = p2Start + timedelta(days=-1)

        #Check for one of the daily wakeup periods
        if (p1Start != p1End):
            if (now >= p1Start and now <= p1End):
                msg(cmdargs,"        Currently in daily wake period 1.")
                return False
        if (p2Start != p2End):
            if (now >= p2Start and now <= p2End):
                msg(cmdargs,"        Currently in daily wake period 2.")
                return False

        #Are we about to start a daily wakeup period using the -t TIME var
        if (p1Start != p1End):
            delta=p1Start-now
            if (delta.seconds >= 0 and delta.seconds <= cmdargs.time * 60):
                msg(cmdargs,"        Daily wake period 1 will start in less than %s minutes." %cmdargs.time)
                return False
        if (p2Start != p2End):
            delta=p2Start-now
            if (delta.seconds >= 0 and delta.seconds <= cmdargs.time * 60):
                msg(cmdargs,"        Daily wake period 2 will start in less than %s minutes." %cmdargs.time)
                return False

        msg(cmdargs,"        Currently NOT in a daily wake period.")
        return True
    else:
        return True

def schemalock_check(cmdargs,cursor):
    msg(cmdargs,"    Checking if the schema is locked...")
    try:
        cursor.execute("select count(*) from schemalock")
        results=cursor.fetchone()
    except:
        return True
    schemalock=results[0]
    if schemalock == 0:
        msg(cmdargs,"        The schema is NOT locked.")
        return True
    else:
        msg(cmdargs,"        The schema is locked.")
        return False

def in_use(cmdargs,cursor):
    msg(cmdargs,"    Checking if programs are in use...")
    try:
        cursor.execute("select count(*) from inuseprograms")
        results=cursor.fetchone()
    except:
        return True
    prginuse=results[0]
    if prginuse == 0 :
        msg(cmdargs,"        Programs are NOT in use.")
        return True
    else:
        msg(cmdargs,"        %s programs are in use." %prginuse)
        cursor.execute("select recusage,chanid,lastupdatetime from inuseprograms")
        results=cursor.fetchall()
        for i in results:
            msg(cmdargs,"            %s - %s - %s" %(i[0],i[1],i[2]))
        return False

def job_check(cmdargs,cursor):
    msg(cmdargs,"    Checking jobqueue for active jobs...")
    try:
        cursor.execute("select count(*) from jobqueue where status between 2 and 5")
        results=cursor.fetchone()
    except:
        return True
    jobs=results[0]
    if jobs == 0 :
        msg(cmdargs,"        No jobs are active.")
        return True
    else:
        msg(cmdargs,"        Jobs are active.")
        return False

def upcoming_check(cmdargs,mythBE):
    msg(cmdargs,"    Checking for recordings in the next %s minutes..." %cmdargs.time)
    try:
        upcoming = mythBE.getUpcomingRecordings()
    except:
        msg(cmdargs,"        Could not get upcoming recordings.")
        return True
    time_diff=10000
    r=0
    for i in upcoming:
        r += 1
        if r > 1:
            break
        show=str(i)
        show=show.strip()
        showtime=re.split("[-+]\\d\\d:\\d\\d",str(i.starttime))[0]
        now=time.time()
        rec_time=time.strptime( showtime ,"%Y-%m-%d %H:%M:%S" )
        r=time.mktime(rec_time)
        time_diff = ( r - now ) / 60

    if ( time_diff > cmdargs.time) :
        msg(cmdargs,"        No recordings starting in %s minutes." %cmdargs.time)
        return True
    else:
        msg(cmdargs,"        A recording is starting in %s minutes." %int(time_diff))
        return False

def mfd_check(cmdargs):
    msg(cmdargs,"    Checking if mythfilldatabase is running...")
    with open(os.devnull, "w") as fnull:
        mythfilldatabase_ret = subprocess.call(["pidof", "mythfilldatabase"], stdout=fnull)
    if mythfilldatabase_ret == 0 :
        msg(cmdargs,"        mythfilldatabase is running.")
        return False
    else:
        msg(cmdargs,"        mythfilldatabase is NOT running.")
        return True

def mythtvsetup_check(cmdargs):
    msg(cmdargs,"    Checking if mythtv-setup is running...")
    with open(os.devnull, "w") as fnull:
        mythsetup_ret = subprocess.call(["pidof", "mythtv-setup"], stdout=fnull)
    if mythsetup_ret == 0 :
        msg(cmdargs,"        mythtv-setup is running.")
        return False
    else:
        msg(cmdargs,"        mythtv-setup is NOT running.")
        return True

def userlogins_check(cmdargs):
    if (cmdargs.logins):
        u=False
        msg(cmdargs,"    Checking for users logged in...")
        users=subprocess.check_output("who")
        names=([x.split() for x in users.splitlines()])
        for i in names:
            if (i[0] == "mythtv" and i[4] == "(:0)"):
                msg(cmdargs,"        Ignoring %s %s" %(i[0],i[4]))
            else:
                msg(cmdargs,"        User logged in: %s %s" %(i[0],i[4]))
                u=True
        if u:
            return False
        else:
            return True
    else:
        return True

def sambafiles_check(cmdargs):
    if (cmdargs.sambafiles):
        msg(cmdargs,"    Checking if Samba files are in use...")
        try:
            smbstatus=subprocess.check_output(["smbstatus", "-L"])
        except:
            smbstatus="No locked files"
        if "No locked files" in smbstatus:
            msg(cmdargs,"        Samba files are NOT in use.")
            return True
        else:
            msg(cmdargs,"        Samba files are in use.")
            return False
    else:
        return True

def mythfe_check(cmdargs,cursor,mythDB):
    #checks to see if a frontend is considered idle
    # True means FE is idle

    if ( cmdargs.runningfe ):
        msg(cmdargs,"    Checking for running and playing mythfrontends...")
    else:
        msg(cmdargs,"    Checking for playing mythfrontends...")
    try:
        cursor.execute("select distinct hostname from settings where hostname is not null;")
        frontends=cursor.fetchall()
    except:
        return True

    for i in frontends:
        try:
            msg(cmdargs,"        Checking %s's mythfrontend status..." %i)
            frontend = mythDB.getFrontend(''.join(i))
            if ( cmdargs.runningfe ):
                msg(cmdargs,"            %s's mythfrontend is RUNNING." %i)
                return False
            location = frontend.sendQuery('Location')

            if location == "standbymode":
                msg(cmdargs,"            %s's mythfrontend is in Standby Mode." %i)
                continue

            if ( location.startswith('Playback ') ):
                msg(cmdargs,"            %s's mythfrontend is PLAYING." %i)
                return False
            else:
                msg(cmdargs,"            %s's mythfrontend is NOT playing." %i)

            if '.xml' in location or 'mainmenu' in location:
                msg(cmdargs,"            %s's mythfrontend is in MENUS." %i)
            else:
                #FE is not in menus, so it must be active in a plugin
                msg(cmdargs,"            %s's mythfrontend is NOT in menus." %i)
                return False
        except:
            msg(cmdargs,"            Could not connect to %s's mythfrontend." %i)

    if ( cmdargs.runningfe ):
        msg(cmdargs,"        mythfrontends are not running or playing or are in menus.")
    else:
        msg(cmdargs,"        mythfrontends are not playing or are in menus.")

    return True

def usage():
    line = '''
    idle.py checks if the system is idle.
    Use idle.py -h to see options.

    idle.py checks these parts of the system in this order to
    determine if it is idle:
    - (option -g) users are logged in return busy
        ignores mythtv (:0) for busy
    - (option -f) Samba files are in use return busy
    - (option -l) mythshutdown is locked return busy
    - (option -d) in a daily wake period or
        about to start a daily wake period return busy
        checks the next 15 minutes. -t TIME changes time
    - schema is locked return busy
    - there are in use programs return busy
    - there are active jobs in the job queue return busy
    - mythfilldatabase is running return busy
    - mythtv-setup is running return busy
    - there are upcoming recordings return busy
        checks the next 15 minutes. -t TIME changes time
    - (option -r) mythfrontends running return busy
    - mythfrontends playing back a recording or video return busy
    - mythfrontends not in menus return busy

    idle.py stops checking and returns false (busy) when the first busy is found.
    '''
    print(line)
    sys.exit(0)

def main(args=[False]):
    parser = argparse.ArgumentParser()
    parser.add_argument('-d', '--daily', action='store_true', help='Include daily wake & about to start wake in system busy. (default: daily wake & about to start wake is system idle)')
    parser.add_argument('-g', '--logins', action='store_true', help='Include user logins in system busy. Ignores mythtv (:0) in system busy.')
    parser.add_argument('-f', '--sambafiles', action='store_true', help='Include Samba files in use in system busy.')
    parser.add_argument('-l', '--lock', action='store_true', help='Include mythshutdown lock in system busy. (default: mythshutdown lock is system idle)')
    parser.add_argument('-r', '--runningfe', action='store_true', help='Include running mythfrontends in system busy. (default: running mythfrontends are system idle)')
    parser.add_argument('-s', '--silent', action='store_true', help='Run without printing output. Recommended for use in cron jobs or scripts.')
    parser.add_argument('-t', '--time', type=int, default=15, help='Minutes of idle time needed to return idle for upcoming recordings and daily wake.')
    parser.add_argument('-u', '--usage', action='store_true', help='Print usage instructions.')
    if args[0] is False:
        cmdargs = parser.parse_args()
    else:
        cmdargs = parser.parse_args(args)

    if cmdargs.usage:
        usage()
    idle=True
    msg(cmdargs,"Checking system idle...")

    if (userlogins_check(cmdargs)):
        idle = True
    else:
        idle = False

    if (idle and sambafiles_check(cmdargs)):
        idle = True
    else:
        idle = False

    try:
        from MythTV import MythDB
        mythDB = MythDB()
        cursor = mythDB.cursor()
        db_conn=True
    except:
        msg(cmdargs,"Couldn't connect to MythTV database.")
        db_conn=False

    try:
        from MythTV import MythBE
        mythBE = MythBE()
        be_conn=True
    except:
        msg(cmdargs,"Couldn't connect to MythTV backend.")
        be_conn=False

    if ( db_conn and idle ):
        if (mythshutdownlock_check(cmdargs,cursor) and dailywake_check(cmdargs,cursor) and schemalock_check(cmdargs,cursor) and in_use(cmdargs,cursor) and job_check(cmdargs,cursor)):
            idle=True
        else:
            idle=False

    if ( be_conn and idle ):
        if (mfd_check(cmdargs) and mythtvsetup_check(cmdargs) and upcoming_check(cmdargs,mythBE)):
            idle=True
        else:
            idle=False

    if ( db_conn and idle ):
        if (mythfe_check(cmdargs,cursor,mythDB)):
            idle=True
        else:
            idle=False

    if ( idle ):
        msg(cmdargs,"System is idle.")
    else:
        msg(cmdargs,"System is busy.")
    return idle

if __name__ == "__main__":
    idle=main()
    if ( idle ):
        exit(0)
    else:
        exit(1)