~bcmathis/xibo/pyclient-installer

« back to all changes in this revision

Viewing changes to client/python/XiboClient.py

  • Committer: Alex Harrington
  • Date: 2011-02-10 22:22:34 UTC
  • mfrom: (194.8.40 pyclient-1.2.1a1)
  • Revision ID: alex@longhill.org.uk-20110210222234-5ubnfn6wzqh6upzo
[pyclient][offline] Merged in Client and Offline Client 1.2.1a1

Show diffs side-by-side

added added

removed removed

Lines of Context:
37
37
import os
38
38
import fnmatch
39
39
import re
40
 
import time
41
40
import datetime
42
41
import sys
43
42
import socket
49
48
import PIL.Image
50
49
import math
51
50
 
52
 
version = "1.2.0a3"
 
51
version = "1.2.1a1"
53
52
 
54
53
# What layout schema version is supported
55
54
schemaVersion = 1
57
56
#### Abstract Classes
58
57
class XiboLog:
59
58
    "Abstract Class - Interface for Loggers"
60
 
    level=0
61
 
    def __init__(self,level): abstract
62
 
    def log(self,level,category,message,osd=False): abstract
63
 
    def stat(self,statType, fromDT, toDT, tag, layoutID, scheduleID, mediaID): abstract
64
 
    def setXmds(self,xmds):
 
59
    level = 0
 
60
    def __init__(self, level): abstract
 
61
    def log(self, level, category, message, osd = False): abstract
 
62
    def stat(self, statType, fromDT, toDT, tag, layoutID, scheduleID, mediaID): abstract
 
63
    def setXmds(self, xmds):
65
64
        pass
66
65
    def flush(self):
67
66
        pass
68
 
    def setupInfo(self,p):
 
67
    def setupInfo(self, p):
69
68
        self.p = p
70
69
        
71
70
        try:
72
 
            self.liftEnabled = config.get('Lift','enabled')
 
71
            self.liftEnabled = config.get('Lift', 'enabled')
73
72
            if self.liftEnabled == "false":
74
73
                self.liftEnabled = False
75
 
                log.log(3,"audit",_("Disabling lift functionality in Logger"))
 
74
                log.log(3, "audit", _("Disabling lift functionality in Logger"))
76
75
            else:
77
76
                self.liftEnabled = True
78
 
                log.log(3,"audit",_("Enabling lift functionality in Logger"))
 
77
                log.log(3, "audit", _("Enabling lift functionality in Logger"))
79
78
        except:
80
79
            self.liftEnabled = False
81
 
            log.log(3,"error",_("Lift->enabled not defined in configuration. Disabling lift functionality in Logger"))
 
80
            log.log(3, "error", _("Lift->enabled not defined in configuration. Disabling lift functionality in Logger"))
82
81
        
83
82
        # Populate the info screen
84
83
        # Background.
85
84
        tmpXML = '<rect fillcolor="ffffff" id="infoBG" fillopacity="0.75" size="(400,300)" />'
86
 
        self.p.enqueue('add',(tmpXML,'info'))
 
85
        self.p.enqueue('add', (tmpXML, 'info'))
87
86
        
88
87
        # Logo + version bottom right
89
88
        tmpXML = '<image href="resources/logo.png" id="infoLOGO" opacity="1" width="50" height="18" x="345" y="276" />'
90
 
        self.p.enqueue('add',(tmpXML,'info'))
 
89
        self.p.enqueue('add', (tmpXML, 'info'))
91
90
        tmpXML = '<words x="290" y="280" opacity="1" text="v' + version + '" font="Arial" color="000000" fontsize="12" />'
92
 
        self.p.enqueue('add',(tmpXML,'info'))
 
91
        self.p.enqueue('add', (tmpXML, 'info'))
93
92
        
94
93
        # Required Files Traffic Light
95
94
        tmpXML = '<image href="resources/dotgrey.png" id="infoRFGrey" opacity="1" width="20" height="20" x="5" y="275" />'
96
 
        self.p.enqueue('add',(tmpXML,'info'))
 
95
        self.p.enqueue('add', (tmpXML, 'info'))
97
96
        tmpXML = '<image href="resources/dotred.png" id="infoRFRed" opacity="0" width="20" height="20" x="5" y="275" />'
98
 
        self.p.enqueue('add',(tmpXML,'info'))
 
97
        self.p.enqueue('add', (tmpXML, 'info'))
99
98
        tmpXML = '<image href="resources/dotamber.png" id="infoRFAmber" opacity="0" width="20" height="20" x="5" y="275" />'
100
 
        self.p.enqueue('add',(tmpXML,'info'))
 
99
        self.p.enqueue('add', (tmpXML, 'info'))
101
100
        tmpXML = '<image href="resources/dotgreen.png" id="infoRFGreen" opacity="0" width="20" height="20" x="5" y="275" />'
102
 
        self.p.enqueue('add',(tmpXML,'info'))
 
101
        self.p.enqueue('add', (tmpXML, 'info'))
103
102
        tmpXML = '<words x="10" y="270" opacity="1" text="Required Files" font="Arial" color="000000" fontsize="10" angle="-1.57079633" pivot="(0,0)"/>'
104
 
        self.p.enqueue('add',(tmpXML,'info'))
 
103
        self.p.enqueue('add' ,(tmpXML, 'info'))
105
104
        
106
105
        # GetFile Traffic Light
107
106
        tmpXML = '<image href="resources/dotgrey.png" id="infoGFGrey" opacity="1" width="20" height="20" x="30" y="275" />'
108
 
        self.p.enqueue('add',(tmpXML,'info'))
 
107
        self.p.enqueue('add', (tmpXML, 'info'))
109
108
        tmpXML = '<image href="resources/dotred.png" id="infoGFRed" opacity="0" width="20" height="20" x="30" y="275" />'
110
 
        self.p.enqueue('add',(tmpXML,'info'))
 
109
        self.p.enqueue('add', (tmpXML, 'info'))
111
110
        tmpXML = '<image href="resources/dotamber.png" id="infoGFAmber" opacity="0" width="20" height="20" x="30" y="275" />'
112
 
        self.p.enqueue('add',(tmpXML,'info'))
 
111
        self.p.enqueue('add', (tmpXML, 'info'))
113
112
        tmpXML = '<image href="resources/dotgreen.png" id="infoGFGreen" opacity="0" width="20" height="20" x="30" y="275" />'
114
 
        self.p.enqueue('add',(tmpXML,'info'))
 
113
        self.p.enqueue('add', (tmpXML, 'info'))
115
114
        tmpXML = '<words x="35" y="270" opacity="1" text="Get File" font="Arial" color="000000" fontsize="10" angle="-1.57079633" pivot="(0,0)"/>'
116
 
        self.p.enqueue('add',(tmpXML,'info'))
 
115
        self.p.enqueue('add', (tmpXML, 'info'))
117
116
        tmpXML = '<words id="infoRunningDownloads" x="37" y="278" opacity="1" text="0" font="Arial" color="000000" fontsize="10" />'
118
 
        self.p.enqueue('add',(tmpXML,'info'))
 
117
        self.p.enqueue('add', (tmpXML, 'info'))
119
118
        
120
119
        # Schedule Traffic Light
121
120
        tmpXML = '<image href="resources/dotgrey.png" id="infoSGrey" opacity="1" width="20" height="20" x="55" y="275" />'
122
 
        self.p.enqueue('add',(tmpXML,'info'))
 
121
        self.p.enqueue('add', (tmpXML, 'info'))
123
122
        tmpXML = '<image href="resources/dotred.png" id="infoSRed" opacity="0" width="20" height="20" x="55" y="275" />'
124
 
        self.p.enqueue('add',(tmpXML,'info'))
 
123
        self.p.enqueue('add', (tmpXML, 'info'))
125
124
        tmpXML = '<image href="resources/dotamber.png" id="infoSAmber" opacity="0" width="20" height="20" x="55" y="275" />'
126
 
        self.p.enqueue('add',(tmpXML,'info'))
 
125
        self.p.enqueue('add', (tmpXML, 'info'))
127
126
        tmpXML = '<image href="resources/dotgreen.png" id="infoSGreen" opacity="0" width="20" height="20" x="55" y="275" />'
128
 
        self.p.enqueue('add',(tmpXML,'info'))
 
127
        self.p.enqueue('add', (tmpXML, 'info'))
129
128
        tmpXML = '<words x="60" y="270" opacity="1" text="Schedule" font="Arial" color="000000" fontsize="10" angle="-1.57079633" pivot="(0,0)"/>'
130
 
        self.p.enqueue('add',(tmpXML,'info'))
 
129
        self.p.enqueue('add', (tmpXML, 'info'))
131
130
        
132
131
        # RegisterDisplay Traffic Light
133
132
        tmpXML = '<image href="resources/dotgrey.png" id="infoRDGrey" opacity="1" width="20" height="20" x="80" y="275" />'
134
 
        self.p.enqueue('add',(tmpXML,'info'))
 
133
        self.p.enqueue('add', (tmpXML, 'info'))
135
134
        tmpXML = '<image href="resources/dotred.png" id="infoRDRed" opacity="0" width="20" height="20" x="80" y="275" />'
136
 
        self.p.enqueue('add',(tmpXML,'info'))
 
135
        self.p.enqueue('add', (tmpXML, 'info'))
137
136
        tmpXML = '<image href="resources/dotamber.png" id="infoRDAmber" opacity="0" width="20" height="20" x="80" y="275" />'
138
 
        self.p.enqueue('add',(tmpXML,'info'))
 
137
        self.p.enqueue('add', (tmpXML, 'info'))
139
138
        tmpXML = '<image href="resources/dotgreen.png" id="infoRDGreen" opacity="0" width="20" height="20" x="80" y="275" />'
140
 
        self.p.enqueue('add',(tmpXML,'info'))
 
139
        self.p.enqueue('add', (tmpXML, 'info'))
141
140
        tmpXML = '<words x="85" y="270" opacity="1" text="Register Display" font="Arial" color="000000" fontsize="10" angle="-1.57079633" pivot="(0,0)"/>'
142
 
        self.p.enqueue('add',(tmpXML,'info'))
 
141
        self.p.enqueue('add', (tmpXML, 'info'))
143
142
        
144
143
        # Logs Traffic Light
145
144
        tmpXML = '<image href="resources/dotgrey.png" id="infoLogGrey" opacity="1" width="20" height="20" x="105" y="275" />'
146
 
        self.p.enqueue('add',(tmpXML,'info'))
 
145
        self.p.enqueue('add', (tmpXML, 'info'))
147
146
        tmpXML = '<image href="resources/dotred.png" id="infoLogRed" opacity="0" width="20" height="20" x="105" y="275" />'
148
 
        self.p.enqueue('add',(tmpXML,'info'))
 
147
        self.p.enqueue('add', (tmpXML, 'info'))
149
148
        tmpXML = '<image href="resources/dotamber.png" id="infoLogAmber" opacity="0" width="20" height="20" x="105" y="275" />'
150
 
        self.p.enqueue('add',(tmpXML,'info'))
 
149
        self.p.enqueue('add', (tmpXML, 'info'))
151
150
        tmpXML = '<image href="resources/dotgreen.png" id="infoLogGreen" opacity="0" width="20" height="20" x="105" y="275" />'
152
 
        self.p.enqueue('add',(tmpXML,'info'))
 
151
        self.p.enqueue('add', (tmpXML, 'info'))
153
152
        tmpXML = '<words x="110" y="270" opacity="1" text="Log" font="Arial" color="000000" fontsize="10" angle="-1.57079633" pivot="(0,0)"/>'
154
 
        self.p.enqueue('add',(tmpXML,'info'))
 
153
        self.p.enqueue('add', (tmpXML, 'info'))
155
154
        
156
155
        # Stats Traffic Light
157
156
        tmpXML = '<image href="resources/dotgrey.png" id="infoStatGrey" opacity="1" width="20" height="20" x="130" y="275" />'
158
 
        self.p.enqueue('add',(tmpXML,'info'))
 
157
        self.p.enqueue('add', (tmpXML, 'info'))
159
158
        tmpXML = '<image href="resources/dotred.png" id="infoStatRed" opacity="0" width="20" height="20" x="130" y="275" />'
160
 
        self.p.enqueue('add',(tmpXML,'info'))
 
159
        self.p.enqueue('add', (tmpXML, 'info'))
161
160
        tmpXML = '<image href="resources/dotamber.png" id="infoStatAmber" opacity="0" width="20" height="20" x="130" y="275" />'
162
 
        self.p.enqueue('add',(tmpXML,'info'))
 
161
        self.p.enqueue('add', (tmpXML, 'info'))
163
162
        tmpXML = '<image href="resources/dotgreen.png" id="infoStatGreen" opacity="0" width="20" height="20" x="130" y="275" />'
164
 
        self.p.enqueue('add',(tmpXML,'info'))
 
163
        self.p.enqueue('add', (tmpXML, 'info'))
165
164
        tmpXML = '<words x="135" y="270" opacity="1" text="Stats" font="Arial" color="000000" fontsize="10" angle="-1.57079633" pivot="(0,0)"/>'
166
 
        self.p.enqueue('add',(tmpXML,'info'))
 
165
        self.p.enqueue('add', (tmpXML, 'info'))
 
166
 
 
167
        # Offline Update traffic light
 
168
        tmpXML = '<image href="resources/dotamber.png" id="offlineUpdateAmber" opacity="0" width="20" height="20" x="20" y="20" />'
 
169
        self.p.enqueue('add', (tmpXML, 'offlineUpdate'))
 
170
        tmpXML = '<image href="resources/dotgreen.png" id="offlineUpdateGreen" opacity="0" width="20" height="20" x="20" y="20" />'
 
171
        self.p.enqueue('add', (tmpXML, 'offlineUpdate'))
167
172
        
168
173
        # IP Address
169
174
        tmpXML = '<words x="5" y="5" opacity="1" text="IP Address: " font="Arial" color="000000" fontsize="11" />'
170
 
        self.p.enqueue('add',(tmpXML,'info'))
 
175
        self.p.enqueue('add', (tmpXML, 'info'))
171
176
        tmpXML = '<words id="infoIP" x="75" y="5" opacity="1" text="" font="Arial" color="000000" fontsize="11" width="180" linespacing="10" alignment="left" />'
172
 
        self.p.enqueue('add',(tmpXML,'info'))
 
177
        self.p.enqueue('add', (tmpXML, 'info'))
173
178
        
174
179
        # Disk Space
175
180
        tmpXML = '<words x="5" y="18" opacity="1" text="Disk Space: " font="Arial" color="000000" fontsize="11" />'
176
 
        self.p.enqueue('add',(tmpXML,'info'))
 
181
        self.p.enqueue('add', (tmpXML, 'info'))
177
182
        tmpXML = '<words id="infoDisk" x="75" y="18" opacity="1" text="" font="Arial" color="000000" fontsize="11" width="180" linespacing="10" alignment="left" />'
178
 
        self.p.enqueue('add',(tmpXML,'info'))
 
183
        self.p.enqueue('add', (tmpXML, 'info'))
179
184
 
180
185
        # Lift Traffic Lights
181
186
        if self.liftEnabled:
182
187
            tmpXML = '<image href="resources/dotgrey.png" id="infoLift1Grey" opacity="1" width="10" height="10" x="165" y="285" />'
183
 
            self.p.enqueue('add',(tmpXML,'info'))
 
188
            self.p.enqueue('add', (tmpXML, 'info'))
184
189
            tmpXML = '<image href="resources/dotred.png" id="infoLift1Red" opacity="0" width="10" height="10" x="165" y="285" />'
185
 
            self.p.enqueue('add',(tmpXML,'info'))
 
190
            self.p.enqueue('add', (tmpXML, 'info'))
186
191
            tmpXML = '<image href="resources/dotamber.png" id="infoLift1Amber" opacity="0" width="10" height="10" x="165" y="285" />'
187
 
            self.p.enqueue('add',(tmpXML,'info'))
 
192
            self.p.enqueue('add', (tmpXML, 'info'))
188
193
            tmpXML = '<image href="resources/dotgreen.png" id="infoLift1Green" opacity="0" width="10" height="10" x="165" y="285" />'
189
 
            self.p.enqueue('add',(tmpXML,'info'))
 
194
            self.p.enqueue('add', (tmpXML, 'info'))
190
195
            
191
196
            tmpXML = '<image href="resources/dotgrey.png" id="infoLift2Grey" opacity="1" width="10" height="10" x="180" y="285" />'
192
 
            self.p.enqueue('add',(tmpXML,'info'))
 
197
            self.p.enqueue('add', (tmpXML, 'info'))
193
198
            tmpXML = '<image href="resources/dotred.png" id="infoLift2Red" opacity="0" width="10" height="10" x="180" y="285" />'
194
 
            self.p.enqueue('add',(tmpXML,'info'))
 
199
            self.p.enqueue('add', (tmpXML, 'info'))
195
200
            tmpXML = '<image href="resources/dotamber.png" id="infoLift2Amber" opacity="0" width="10" height="10" x="180" y="285" />'
196
 
            self.p.enqueue('add',(tmpXML,'info'))
 
201
            self.p.enqueue('add', (tmpXML, 'info'))
197
202
            tmpXML = '<image href="resources/dotgreen.png" id="infoLift2Green" opacity="0" width="10" height="10" x="180" y="285" />'
198
 
            self.p.enqueue('add',(tmpXML,'info'))
 
203
            self.p.enqueue('add', (tmpXML, 'info'))
199
204
            
200
205
            tmpXML = '<image href="resources/dotgrey.png" id="infoLift3Grey" opacity="1" width="10" height="10" x="195" y="285" />'
201
 
            self.p.enqueue('add',(tmpXML,'info'))
 
206
            self.p.enqueue('add', (tmpXML, 'info'))
202
207
            tmpXML = '<image href="resources/dotred.png" id="infoLift3Red" opacity="0" width="10" height="10" x="195" y="285" />'
203
 
            self.p.enqueue('add',(tmpXML,'info'))
 
208
            self.p.enqueue('add', (tmpXML, 'info'))
204
209
            tmpXML = '<image href="resources/dotamber.png" id="infoLift3Amber" opacity="0" width="10" height="10" x="195" y="285" />'
205
 
            self.p.enqueue('add',(tmpXML,'info'))
 
210
            self.p.enqueue('add', (tmpXML, 'info'))
206
211
            tmpXML = '<image href="resources/dotgreen.png" id="infoLift3Green" opacity="0" width="10" height="10" x="195" y="285" />'
207
 
            self.p.enqueue('add',(tmpXML,'info'))
 
212
            self.p.enqueue('add', (tmpXML, 'info'))
208
213
 
209
214
            tmpXML = '<image href="resources/dotgrey.png" id="infoLift4Grey" opacity="1" width="10" height="10" x="210" y="285" />'
210
 
            self.p.enqueue('add',(tmpXML,'info'))
 
215
            self.p.enqueue('add', (tmpXML, 'info'))
211
216
            tmpXML = '<image href="resources/dotred.png" id="infoLift4Red" opacity="0" width="10" height="10" x="210" y="285" />'
212
 
            self.p.enqueue('add',(tmpXML,'info'))
 
217
            self.p.enqueue('add', (tmpXML, 'info'))
213
218
            tmpXML = '<image href="resources/dotamber.png" id="infoLift4Amber" opacity="0" width="10" height="10" x="210" y="285" />'
214
 
            self.p.enqueue('add',(tmpXML,'info'))
 
219
            self.p.enqueue('add', (tmpXML, 'info'))
215
220
            tmpXML = '<image href="resources/dotgreen.png" id="infoLift4Green" opacity="0" width="10" height="10" x="210" y="285" />'
216
 
            self.p.enqueue('add',(tmpXML,'info'))
 
221
            self.p.enqueue('add', (tmpXML, 'info'))
217
222
            
218
223
            tmpXML = '<image href="resources/dotgrey.png" id="infoLift5Grey" opacity="1" width="10" height="10" x="225" y="285" />'
219
 
            self.p.enqueue('add',(tmpXML,'info'))
 
224
            self.p.enqueue('add', (tmpXML, 'info'))
220
225
            tmpXML = '<image href="resources/dotred.png" id="infoLift5Red" opacity="0" width="10" height="10" x="225" y="285" />'
221
 
            self.p.enqueue('add',(tmpXML,'info'))
 
226
            self.p.enqueue('add', (tmpXML, 'info'))
222
227
            tmpXML = '<image href="resources/dotamber.png" id="infoLift5Amber" opacity="0" width="10" height="10" x="225" y="285" />'
223
 
            self.p.enqueue('add',(tmpXML,'info'))
 
228
            self.p.enqueue('add', (tmpXML, 'info'))
224
229
            tmpXML = '<image href="resources/dotgreen.png" id="infoLift5Green" opacity="0" width="10" height="10" x="225" y="285" />'
225
 
            self.p.enqueue('add',(tmpXML,'info'))
 
230
            self.p.enqueue('add', (tmpXML, 'info'))
226
231
            
227
232
            tmpXML = '<image href="resources/dotgrey.png" id="infoLift6Grey" opacity="1" width="10" height="10" x="240" y="285" />'
228
 
            self.p.enqueue('add',(tmpXML,'info'))
 
233
            self.p.enqueue('add', (tmpXML, 'info'))
229
234
            tmpXML = '<image href="resources/dotred.png" id="infoLift6Red" opacity="0" width="10" height="10" x="240" y="285" />'
230
 
            self.p.enqueue('add',(tmpXML,'info'))
 
235
            self.p.enqueue('add', (tmpXML, 'info'))
231
236
            tmpXML = '<image href="resources/dotamber.png" id="infoLift6Amber" opacity="0" width="10" height="10" x="240" y="285" />'
232
 
            self.p.enqueue('add',(tmpXML,'info'))
 
237
            self.p.enqueue('add', (tmpXML, 'info'))
233
238
            tmpXML = '<image href="resources/dotgreen.png" id="infoLift6Green" opacity="0" width="10" height="10" x="240" y="285" />'
234
 
            self.p.enqueue('add',(tmpXML,'info'))
 
239
            self.p.enqueue('add', (tmpXML, 'info'))
235
240
            
236
241
            tmpXML = '<image href="resources/dotgrey.png" id="infoLift7Grey" opacity="1" width="10" height="10" x="255" y="285" />'
237
 
            self.p.enqueue('add',(tmpXML,'info'))
 
242
            self.p.enqueue('add', (tmpXML, 'info'))
238
243
            tmpXML = '<image href="resources/dotred.png" id="infoLift7Red" opacity="0" width="10" height="10" x="255" y="285" />'
239
 
            self.p.enqueue('add',(tmpXML,'info'))
 
244
            self.p.enqueue('add', (tmpXML, 'info'))
240
245
            tmpXML = '<image href="resources/dotamber.png" id="infoLift7Amber" opacity="0" width="10" height="10" x="255" y="285" />'
241
 
            self.p.enqueue('add',(tmpXML,'info'))
 
246
            self.p.enqueue('add', (tmpXML, 'info'))
242
247
            tmpXML = '<image href="resources/dotgreen.png" id="infoLift7Green" opacity="0" width="10" height="10" x="255" y="285" />'
243
 
            self.p.enqueue('add',(tmpXML,'info'))
 
248
            self.p.enqueue('add', (tmpXML, 'info'))
244
249
            
245
250
            tmpXML = '<image href="resources/dotgrey.png" id="infoLift8Grey" opacity="1" width="10" height="10" x="270" y="285" />'
246
 
            self.p.enqueue('add',(tmpXML,'info'))
 
251
            self.p.enqueue('add', (tmpXML, 'info'))
247
252
            tmpXML = '<image href="resources/dotred.png" id="infoLift8Red" opacity="0" width="10" height="10" x="270" y="285" />'
248
 
            self.p.enqueue('add',(tmpXML,'info'))
 
253
            self.p.enqueue('add', (tmpXML, 'info'))
249
254
            tmpXML = '<image href="resources/dotamber.png" id="infoLift8Amber" opacity="0" width="10" height="10" x="270" y="285" />'
250
 
            self.p.enqueue('add',(tmpXML,'info'))
 
255
            self.p.enqueue('add', (tmpXML, 'info'))
251
256
            tmpXML = '<image href="resources/dotgreen.png" id="infoLift8Green" opacity="0" width="10" height="10" x="270" y="285" />'
252
 
            self.p.enqueue('add',(tmpXML,'info'))
 
257
            self.p.enqueue('add', (tmpXML, 'info'))
253
258
 
254
259
            # Lift Tag
255
260
            tmpXML = '<words id="infoLiftTag" x="165" y="265" opacity="1" text="Current Tag: default" font="Arial" color="000000" fontsize="11" />'
256
 
            self.p.enqueue('add',(tmpXML,'info'))
 
261
            self.p.enqueue('add', (tmpXML, 'info'))
257
262
        
258
263
        # Schedule
259
264
        tmpXML = '<words x="5" y="75" opacity="1" text="Schedule" font="Arial" color="000000" fontsize="14" />'
260
 
        self.p.enqueue('add',(tmpXML,'info'))
 
265
        self.p.enqueue('add', (tmpXML, 'info'))
261
266
        tmpXML = '<words id="infoCurrentSchedule" x="5" y="90" opacity="1" text="" font="Arial" color="000000" fontsize="11" width="180" linespacing="10" alignment="left" />'
262
 
        self.p.enqueue('add',(tmpXML,'info'))
 
267
        self.p.enqueue('add', (tmpXML, 'info'))
263
268
        
264
269
        # Now Playing
265
270
        tmpXML = '<words x="5" y="40" opacity="1" text="Now Playing" font="Arial" color="000000" fontsize="14" />'
266
 
        self.p.enqueue('add',(tmpXML,'info'))
 
271
        self.p.enqueue('add', (tmpXML, 'info'))
267
272
        tmpXML = '<words id="infoNowPlaying" x="5" y="55" opacity="1" text="" font="Arial" color="000000" fontsize="11" />'
268
 
        self.p.enqueue('add',(tmpXML,'info'))
 
273
        self.p.enqueue('add', (tmpXML, 'info'))
269
274
        
270
275
        # Media
271
276
        tmpXML = '<words x="205" y="5" opacity="1" text="Media" font="Arial" color="000000" fontsize="14" />'
272
 
        self.p.enqueue('add',(tmpXML,'info'))
 
277
        self.p.enqueue('add', (tmpXML, 'info'))
273
278
        tmpXML = '<words id="infoMedia" x="205" y="20" opacity="1" text="" font="Arial" color="000000" fontsize="11" />'
274
 
        self.p.enqueue('add',(tmpXML,'info'))
 
279
        self.p.enqueue('add', (tmpXML, 'info'))
275
280
 
276
281
        # On Screen Logging
277
282
        tmpXML = '<rect fillcolor="ffffff" id="osLogBG" fillopacity="0.75" size="(%d,%d)" />' % (self.p.osLogX, 20)
278
 
        self.p.enqueue('add',(tmpXML,'osLog'))
 
283
        self.p.enqueue('add', (tmpXML, 'osLog'))
279
284
        tmpXML = '<words id="osLogText" x="5" y="3" opacity="1" text="Xibo Client v%s" font="Arial" color="000000" fontsize="11" />' % version
280
 
        self.p.enqueue('add',(tmpXML,'osLog'))
 
285
        self.p.enqueue('add', (tmpXML, 'osLog'))
281
286
    
282
 
    def lights(self,field,value):
 
287
    def lights(self, field, value):
283
288
        if value == "green":
284
 
            self.p.enqueue('setOpacity',("info" + field + "Green", 1))
285
 
            self.p.enqueue('setOpacity',("info" + field + "Grey", 0))
286
 
            self.p.enqueue('setOpacity',("info" + field + "Amber", 0))
287
 
            self.p.enqueue('setOpacity',("info" + field + "Red", 0))
 
289
            self.p.enqueue('setOpacity', ("info" + field + "Green", 1))
 
290
            self.p.enqueue('setOpacity', ("info" + field + "Grey", 0))
 
291
            self.p.enqueue('setOpacity', ("info" + field + "Amber", 0))
 
292
            self.p.enqueue('setOpacity', ("info" + field + "Red", 0))
288
293
        if value == "red":
289
 
            self.p.enqueue('setOpacity',("info" + field + "Green", 0))
290
 
            self.p.enqueue('setOpacity',("info" + field + "Grey", 0))
291
 
            self.p.enqueue('setOpacity',("info" + field + "Amber", 0))
292
 
            self.p.enqueue('setOpacity',("info" + field + "Red", 1))
 
294
            self.p.enqueue('setOpacity', ("info" + field + "Green", 0))
 
295
            self.p.enqueue('setOpacity', ("info" + field + "Grey", 0))
 
296
            self.p.enqueue('setOpacity', ("info" + field + "Amber", 0))
 
297
            self.p.enqueue('setOpacity', ("info" + field + "Red", 1))
293
298
        if value == "amber":
294
 
            self.p.enqueue('setOpacity',("info" + field + "Green", 0))
295
 
            self.p.enqueue('setOpacity',("info" + field + "Grey", 0))
296
 
            self.p.enqueue('setOpacity',("info" + field + "Amber", 1))
297
 
            self.p.enqueue('setOpacity',("info" + field + "Red", 0))
 
299
            self.p.enqueue('setOpacity', ("info" + field + "Green", 0))
 
300
            self.p.enqueue('setOpacity', ("info" + field + "Grey", 0))
 
301
            self.p.enqueue('setOpacity', ("info" + field + "Amber", 1))
 
302
            self.p.enqueue('setOpacity', ("info" + field + "Red", 0))
298
303
        if value == "grey":
299
 
            self.p.enqueue('setOpacity',("info" + field + "Green", 0))
300
 
            self.p.enqueue('setOpacity',("info" + field + "Grey", 1))
301
 
            self.p.enqueue('setOpacity',("info" + field + "Amber", 0))
302
 
            self.p.enqueue('setOpacity',("info" + field + "Red", 0))
 
304
            self.p.enqueue('setOpacity', ("info" + field + "Green", 0))
 
305
            self.p.enqueue('setOpacity', ("info" + field + "Grey", 1))
 
306
            self.p.enqueue('setOpacity', ("info" + field + "Amber", 0))
 
307
            self.p.enqueue('setOpacity', ("info" + field + "Red", 0))
 
308
        if value == "start":
 
309
            self.p.enqueue('setOpacity', ("%sAmber" % field, 1))
 
310
            self.p.enqueue('setOpacity', ("%sGreen" % field, 0))
 
311
        if value == "finish":
 
312
            self.p.enqueue('setOpacity', ("%sAmber" % field, 0))
 
313
            self.p.enqueue('setOpacity', ("%sGreen" % field, 1))
 
314
            self.p.enqueue('anim', ('fadeOut', '%sGreen' % field, 3000, None))
303
315
 
304
 
    def updateSchedule(self,schedule):
305
 
        self.p.enqueue('del','infoCurrentSchedule')
 
316
    def updateSchedule(self, schedule):
 
317
        self.p.enqueue('del', 'infoCurrentSchedule')
306
318
        tmpXML = '<words id="infoCurrentSchedule" x="5" y="90" opacity="1" text="' + schedule + '" font="Arial" color="000000" fontsize="11" width="180" linespacing="10" alignment="left" />'
307
 
        self.p.enqueue('add',(tmpXML,'info'))
 
319
        self.p.enqueue('add', (tmpXML, 'info'))
308
320
 
309
 
    def updateNowPlaying(self,now):
310
 
        self.p.enqueue('del','infoNowPlaying')
 
321
    def updateNowPlaying(self, now):
 
322
        self.p.enqueue('del', 'infoNowPlaying')
311
323
        tmpXML = '<words id="infoNowPlaying" x="5" y="55" opacity="1" text="' + now + '" font="Arial" color="000000" fontsize="11" />'
312
 
        self.p.enqueue('add',(tmpXML,'info'))
 
324
        self.p.enqueue('add', (tmpXML, 'info'))
313
325
 
314
 
    def updateMedia(self,media):
315
 
        self.p.enqueue('del','infoMedia')
 
326
    def updateMedia(self, media):
 
327
        self.p.enqueue('del', 'infoMedia')
316
328
        tmpXML = '<words id="infoMedia" x="205" y="20" opacity="1" font="Arial" color="000000" fontsize="11" width="180">' + media + '</words>'
317
 
        self.p.enqueue('add',(tmpXML,'info'))
 
329
        self.p.enqueue('add', (tmpXML, 'info'))
318
330
    
319
 
    def updateRunningDownloads(self,num):
320
 
        self.p.enqueue('del','infoRunningDownloads')
 
331
    def updateRunningDownloads(self, num):
 
332
        self.p.enqueue('del', 'infoRunningDownloads')
321
333
        tmpXML = '<words id="infoRunningDownloads" x="37" y="278" opacity="1" text="' + str(num) + '" font="Arial" color="000000" fontsize="10" />'
322
 
        self.p.enqueue('add',(tmpXML,'info'))
 
334
        self.p.enqueue('add', (tmpXML, 'info'))
323
335
    
324
 
    def updateIP(self,serverIP):
325
 
        self.p.enqueue('del','infoIP')
 
336
    def updateIP(self, serverIP):
 
337
        self.p.enqueue('del', 'infoIP')
326
338
        tmpXML = '<words id="infoIP" x="75" y="5" opacity="1" text="' + str(serverIP) + '" font="Arial" color="000000" fontsize="10" />'
327
 
        self.p.enqueue('add',(tmpXML,'info'))
 
339
        self.p.enqueue('add', (tmpXML, 'info'))
328
340
 
329
 
    def updateFreeSpace(self,tup):
 
341
    def updateFreeSpace(self, tup):
330
342
        perc = int((tup[1] * 1.0 / tup[0]) * 100)
331
 
        self.p.enqueue('del','infoDisk')
 
343
        self.p.enqueue('del', 'infoDisk')
332
344
        tmpXML = '<words id="infoDisk" x="75" y="18" opacity="1" text="' + self.bytestr(tup[1]) + ' (' + str(perc) + '%) free" font="Arial" color="000000" fontsize="10" />'
333
 
        self.p.enqueue('add',(tmpXML,'info'))
 
345
        self.p.enqueue('add', (tmpXML, 'info'))
334
346
        
335
347
    # Convert a value in bytes to human readable format
336
348
    # Taken from http://stackoverflow.com/questions/1094841/reusable-library-to-get-human-readable-version-of-file-size
337
349
    # By Sridhar Ratnakumar
338
350
    # Assumed Public Domain
339
 
    def bytestr(self,size):
340
 
        for x in ['bytes','KB','MB','GB','TB']:
 
351
    def bytestr(self, size):
 
352
        for x in ['bytes', 'KB', 'MB', 'GB', 'TB']:
341
353
            if size < 1024.0:
342
354
                return "%3.1f %s" % (size, x)
343
355
            size /= 1024.0
344
356
            
345
 
    def updateLift(self,tag):
 
357
    def updateLift(self, tag):
346
358
        # Break out if lift is disabled
347
359
        if not self.liftEnabled:
348
360
            return
349
361
        
350
 
        self.p.enqueue('del','infoLiftTag')
 
362
        self.p.enqueue('del', 'infoLiftTag')
351
363
        tmpXML = '<words id="infoLiftTag" x="165" y="265" opacity="1" text="Current Tag: ' + tag + '" font="Arial" color="000000" fontsize="11" />'
352
 
        self.p.enqueue('add',(tmpXML,'info'))
 
364
        self.p.enqueue('add', (tmpXML, 'info'))
353
365
 
354
 
    def osLog(self,message):
355
 
        self.p.enqueue('del','osLogText')
 
366
    def osLog(self, message):
 
367
        self.p.enqueue('del', 'osLogText')
356
368
        tmpXML = '<words id="osLogText" x="5" y="3" opacity="1" text="%s" font="Arial" color="000000" fontsize="11" />' % message
357
 
        self.p.enqueue('add',(tmpXML,'osLog'))
 
369
        self.p.enqueue('add', (tmpXML, 'osLog'))
358
370
 
359
371
class XiboScheduler(Thread):
360
372
    "Abstract Class - Interface for Schedulers"
811
823
        self.p = player
812
824
        self.__lock = Semaphore()
813
825
        self.__lock.acquire()
 
826
        self.offline = config.getboolean('Main','manualUpdate')
814
827
 
815
828
        # Store a dictionary of XiboDownloadThread objects so we know
816
829
        # which files are downloading and how many download slots
888
901
                        try:
889
902
                            tmpPath = os.path.join(config.get('Main','libraryDir'),str(f.attributes['path'].value))
890
903
                            tmpFileName = str(f.attributes['path'].value)
891
 
                            tmpSize = int(f.attributes['size'].value)
 
904
                            tmpSize = long(f.attributes['size'].value)
892
905
                            tmpHash = str(f.attributes['md5'].value)
893
906
                            tmpType = str(f.attributes['type'].value)
894
907
                            self.updateInfo()
984
997
                while True:
985
998
                    tmpType, tmpFileName, tmpSize, tmpHash = self.dlQueue.get(False)
986
999
 
 
1000
                    if config.get('Main','manualUpdate') == 'true':
 
1001
                        log.lights('offlineUpdate','start')
 
1002
 
987
1003
                    # Check if the file is downloading already
988
1004
                    if not tmpFileName in self.runningDownloads:
989
1005
                        # Make a download thread and actually download the file.
990
1006
                        # Add the running thread to the self.runningDownloads dictionary
991
1007
                        self.runningDownloads[tmpFileName] = XiboDownloadThread(self,tmpType,tmpFileName,tmpSize,tmpHash)
992
 
                        self.runningDownloads[tmpFileName].start()
993
1008
                        log.updateRunningDownloads(len(self.runningDownloads))
994
1009
 
 
1010
                        if self.offline:
 
1011
                            # If we're running offline, block until completed.
 
1012
                            self.runningDownloads[tmpFileName].run()
 
1013
                        else:
 
1014
                            self.runningDownloads[tmpFileName].start()
 
1015
 
995
1016
                    while len(self.runningDownloads) >= (self.maxDownloads - 1):
996
1017
                        # There are no download thread slots free
997
1018
                        # Sleep for 5 seconds and try again.
1041
1062
            self.updateInfo()
1042
1063
            
1043
1064
            log.log(5,"audit",_("There are ") + str(threading.activeCount()) + _(" running threads."))
1044
 
            log.log(3,"audit",_("XiboDownloadManager: Sleeping") + " " + str(self.interval) + " " + _("seconds"))
1045
 
            self.p.enqueue('timer',(int(self.interval) * 1000,self.collect))
 
1065
 
 
1066
            if config.getboolean('Main','manualUpdate'):
 
1067
                time.sleep(5)
 
1068
                log.lights('offlineUpdate','finish')
 
1069
            else:
 
1070
                log.log(3,"audit",_("XiboDownloadManager: Sleeping") + " " + str(self.interval) + " " + _("seconds"))
 
1071
                self.p.enqueue('timer',(int(self.interval) * 1000,self.collect))
 
1072
 
1046
1073
            self.__lock.acquire()
1047
1074
        # End While
1048
1075
    
1049
1076
    def collect(self):
1050
 
        self.__lock.release()
 
1077
        if len(self.runningDownloads) == 0:
 
1078
            self.__lock.release()
1051
1079
 
1052
1080
    def dlThreadCompleteNotify(self,tmpFileName):
1053
1081
        # Download thread completed. Log and remove from
1081
1109
        self.tmpSize = tmpSize
1082
1110
        self.tmpHash = tmpHash
1083
1111
        self.parent = parent
1084
 
        self.offset = 0
 
1112
        self.offset = long(0)
1085
1113
        self.chunk = 512000
1086
1114
        
1087
1115
        # Server versions prior to 1.0.5 send an invalid md5sum for layouts that require
1254
1282
        # Add a ColorNode and maybe ImageNode to the layout div to draw the background
1255
1283
 
1256
1284
        # This code will work with libavg > 0.8.x
1257
 
        tmpXML = '<rect fillopacity="1" fillcolor="%s" color="%s" size="(%d,%d)" id="bgColor%s" />' % (self.l.backgroundColour.strip("#"),self.l.backgroundColour.strip("#"),self.l.sWidth,self.l.sHeight,self.layoutNodeNameExt)
1258
 
        self.p.enqueue('add',(tmpXML,self.layoutNodeName))
 
1285
        try:
 
1286
            tmpXML = '<rect fillopacity="1" fillcolor="%s" color="%s" size="(%d,%d)" id="bgColor%s" />' % (self.l.backgroundColour.strip("#"),self.l.backgroundColour.strip("#"),self.l.sWidth,self.l.sHeight,self.layoutNodeNameExt)
 
1287
            self.p.enqueue('add',(tmpXML,self.layoutNodeName))
 
1288
        except AttributeError:
 
1289
            # The background colour isn't set for the layout.
 
1290
            # This is likely to be bad news as the XLF is already invalid.
 
1291
            # Log this, sleep and then load a different layout.
 
1292
            log.log(0,'error',_("Layout %s is invalid or corrupt. No background colour specified in the XLF. Skipping.") % self.l.layoutID)
 
1293
            time.sleep(5)
 
1294
            self.parent.nextLayout()
 
1295
            return
1259
1296
 
1260
1297
        if self.l.backgroundImage != None:
1261
1298
            
1870
1907
 
1871
1908
        # See if the item is in a scheduled window to run
1872
1909
        for sc in self.schedule:
1873
 
            fromDt = time.mktime(time.strptime(sc[0], "%Y-%m-%d %H:%M:%S"))
1874
 
            toDt = time.mktime(time.strptime(sc[1], "%Y-%m-%d %H:%M:%S"))
 
1910
            try:
 
1911
                fromDt = time.mktime(time.strptime(sc[0], "%Y-%m-%d %H:%M:%S"))
 
1912
            except OverflowError:
 
1913
                log.log(0, 'error', _("Layout %s has an invalid schedule start time. Using 00:00:00 UTC on 1 January 1970") % self.layoutID)
 
1914
                fromtDt = 0
 
1915
            except ValueError:
 
1916
                log.log(0, 'error', _("Layout %s has an invalid schedule start time. Using 00:00:00 UTC on 1 January 1970") % self.layoutID)
 
1917
                fromtDt = 0
 
1918
 
 
1919
            try:
 
1920
                toDt = time.mktime(time.strptime(sc[1], "%Y-%m-%d %H:%M:%S"))
 
1921
            except OverflowError:
 
1922
                log.log(0, 'error', _("Layout %s has an invalid schedule finish time. Using 00:00:00 UTC on 19 January 2038") % self.layoutID)
 
1923
                toDt = 2147472000
 
1924
            except ValueError:
 
1925
                log.log(0, 'error', _("Layout %s has an invalid schedule finish time. Using 00:00:00 UTC on 19 January 2038") % self.layoutID)
 
1926
                toDt = 2147472000
 
1927
 
1875
1928
            priority = sc[2]
1876
1929
            now = time.time()
1877
1930
            
1894
1947
    def isPriority(self):
1895
1948
        # Check through the schedule and see if we're priority at the moment.
1896
1949
        for sc in self.schedule:
1897
 
            fromDt = time.mktime(time.strptime(sc[0], "%Y-%m-%d %H:%M:%S"))
1898
 
            toDt = time.mktime(time.strptime(sc[1], "%Y-%m-%d %H:%M:%S"))
 
1950
            try:
 
1951
                fromDt = time.mktime(time.strptime(sc[0], "%Y-%m-%d %H:%M:%S"))
 
1952
            except OverflowError:
 
1953
                log.log(0, 'error', _("Layout %s has an invalid schedule start time. Using 00:00:00 UTC on 1 January 1970") % self.layoutID)
 
1954
                fromtDt = 0
 
1955
            except ValueError:
 
1956
                log.log(0, 'error', _("Layout %s has an invalid schedule start time. Using 00:00:00 UTC on 1 January 1970") % self.layoutID)
 
1957
                fromtDt = 0
 
1958
 
 
1959
            try:
 
1960
                toDt = time.mktime(time.strptime(sc[1], "%Y-%m-%d %H:%M:%S"))
 
1961
            except OverflowError:
 
1962
                log.log(0, 'error', _("Layout %s has an invalid schedule finish time. Using 00:00:00 UTC on 19 January 2038") % self.layoutID)
 
1963
                toDt = 2147472000
 
1964
            except ValueError:
 
1965
                log.log(0, 'error', _("Layout %s has an invalid schedule finish time. Using 00:00:00 UTC on 19 January 2038") % self.layoutID)
 
1966
                toDt = 2147472000
 
1967
 
1899
1968
            priority = sc[2]
1900
1969
            now = time.time()
1901
1970
            
2028
2097
 
2029
2098
                    try:
2030
2099
                        if self.__defaultLayout.layoutID != layoutID:
2031
 
                           self.__defaultLayout = XiboLayout(layoutID,True)
 
2100
                            self.__defaultLayout = XiboLayout(layoutID,True)
2032
2101
                    except:
2033
2102
                        self.__defaultLayout = XiboLayout(layoutID,True)
2034
2103
            
2053
2122
                        tmpLayout.addSchedule(layoutFromDT,layoutToDT,layoutPriority)
2054
2123
                        newLayouts.append(tmpLayout)
2055
2124
                        scheduleText += str(layoutID) + ', '
 
2125
                # End for l in tmpLayouts
2056
2126
                        
2057
 
                    # Swap the newLayouts array in to the live scheduler
2058
 
                    self.__lock.acquire()
2059
 
                    self.__layouts = newLayouts
2060
 
                    self.__lock.release()
 
2127
                # Swap the newLayouts array in to the live scheduler
 
2128
                self.__lock.acquire()
 
2129
                self.__layouts = newLayouts
 
2130
                self.__lock.release()
2061
2131
                    
2062
 
                    log.updateSchedule(scheduleText)
 
2132
                log.updateSchedule(scheduleText)
2063
2133
            # End if previousSchedule != schedule
2064
2134
            
2065
 
            log.log(3,"info",_("XmdsScheduler: Sleeping") + " " + str(self.interval) + " " + _("seconds"))
2066
 
            self.p.enqueue('timer',(int(self.interval) * 1000,self.collect))
 
2135
            if config.getboolean('Main','manualUpdate'):
 
2136
                pass
 
2137
            else:
 
2138
                log.log(3,"info",_("XmdsScheduler: Sleeping") + " " + str(self.interval) + " " + _("seconds"))
 
2139
                self.p.enqueue('timer',(int(self.interval) * 1000,self.collect))
 
2140
 
2067
2141
            self.__collectLock.acquire()
2068
2142
        # End while self.running
2069
2143
    
2071
2145
        self.__collectLock.release()
2072
2146
 
2073
2147
    def __len__(self):
 
2148
        log.log(8,'audit',_('There are %s layouts in the scheduler.') % len(self.__layouts))
2074
2149
        return len(self.__layouts)
2075
2150
 
2076
2151
    def nextLayout(self):
2077
2152
        "Return the next valid layout"
2078
 
        
 
2153
 
 
2154
        log.log(8,'audit',_('nextLayout: IN'))        
2079
2155
        # If there are no possible layouts then return the default or splash screen straight away.
2080
2156
        if len(self) == 0:
 
2157
            log.log(8,'audit',_('No layouts available.'))
2081
2158
            try:
2082
2159
                if self.__defaultLayout.canRun():
 
2160
                    log.log(8,'audit',_('Default layout can run.'))
2083
2161
                    log.updateNowPlaying(str(self.__defaultLayout.layoutID) + " (Default)")
2084
2162
                    return self.__defaultLayout
2085
2163
                else:
 
2164
                    log.log(8,'audit',_('Default layout cannot run and there are no other layouts. Loading Splash Screen'))
2086
2165
                    log.updateNowPlaying("Splash Screen")
2087
2166
                    return XiboLayout('0',False)
2088
2167
            except:
 
2168
                log.log(8,'audit',_('Exception thrown checking default layout. Loading Splash Screen.'))
2089
2169
                log.updateNowPlaying("Splash Screen")
2090
2170
                return XiboLayout('0',False)
2091
2171
        
2092
2172
        # Consider each possible layout and see if it can run
2093
2173
        # Lock out the scheduler while we do this so that the
2094
2174
        # maths doesn't go horribly wrong!
 
2175
        log.log(8,'audit',_('Attempting to acquire scheduler layout lock.'))
2095
2176
        self.__lock.acquire()
 
2177
        log.log(8,'audit',_('Scheduler layout lock acquired.'))
2096
2178
 
2097
2179
        # Check if any layout is a priorty.
2098
2180
        thereIsPriority = False
2099
2181
        for l in self.__layouts:
2100
2182
            if l.isPriority():
 
2183
                log.log(8,'audit',_('There are layouts with priority.'))
2101
2184
                thereIsPriority = True
2102
2185
 
2103
2186
        count = 0
2104
2187
        while count < len(self):
2105
2188
            self.__pointer = (self.__pointer + 1) % len(self)
2106
2189
            tmpLayout = self.__layouts[self.__pointer]
 
2190
 
 
2191
            log.log(8,'audit',_('Checking layout schedule ID %s.') % self.__pointer)
2107
2192
            
2108
2193
            if self.liftEnabled:
2109
2194
                if thereIsPriority:
 
2195
                    log.log(8,'audit',_('Lift is enabled and there is a priority layout.'))
2110
2196
                    if tmpLayout.canRun() and tmpLayout.isPriority() and self.validTag in tmpLayout.tags:
2111
2197
                        log.updateNowPlaying(str(tmpLayout.layoutID) + " (P)")
 
2198
                        log.log(8,'audit',_('Releasing scheduler layout lock.'))
2112
2199
                        self.__lock.release()
2113
2200
                        return tmpLayout
2114
2201
                    else:
 
2202
                        log.log(8,'audit',_('Trying next layout.'))
2115
2203
                        count = count + 1
2116
2204
                else:
 
2205
                    log.log(8,'audit',_('Lift is enabled and there are no priority layouts.'))
2117
2206
                    if tmpLayout.canRun() and self.validTag in tmpLayout.tags:
2118
2207
                        log.updateNowPlaying(str(tmpLayout.layoutID))
 
2208
                        log.log(8,'audit',_('Releasing scheduler layout lock.'))
2119
2209
                        self.__lock.release()
2120
2210
                        return tmpLayout
2121
2211
                    else:
 
2212
                        log.log(8,'audit',_('Trying next layout.'))
2122
2213
                        count = count + 1
2123
2214
            else:
2124
2215
                if thereIsPriority:
2125
2216
                    if tmpLayout.canRun() and tmpLayout.isPriority():
2126
2217
                        log.updateNowPlaying(str(tmpLayout.layoutID) + " (P)")
 
2218
                        log.log(8,'audit',_('Releasing scheduler layout lock.'))
2127
2219
                        self.__lock.release()
2128
2220
                        return tmpLayout
2129
2221
                    else:
 
2222
                        log.log(8,'audit',_('Trying next layout.'))
2130
2223
                        count = count + 1
2131
2224
                else:
2132
2225
                    if tmpLayout.canRun():
2133
2226
                        log.updateNowPlaying(str(tmpLayout.layoutID))
 
2227
                        log.log(8,'audit',_('Releasing scheduler layout lock.'))
2134
2228
                        self.__lock.release()
2135
2229
                        return tmpLayout
2136
2230
                    else:
 
2231
                        log.log(8,'audit',_('Trying next layout.'))
2137
2232
                        count = count + 1
2138
2233
        
 
2234
        log.log(8,'info',_('Tried all layouts and none could run.'))
2139
2235
        try:
2140
2236
            if self.__defaultLayout.canRun():
2141
2237
                log.updateNowPlaying(str(self.__defaultLayout.layoutID) + " (Default)")
 
2238
                log.log(8,'audit',_('Releasing scheduler layout lock.'))
2142
2239
                self.__lock.release()
2143
2240
                return self.__defaultLayout
2144
2241
            else:
2145
2242
                log.updateNowPlaying("Splash Screen")
 
2243
                log.log(8,'audit',_('Releasing scheduler layout lock.'))
2146
2244
                self.__lock.release()
2147
2245
                return XiboLayout('0',False)
2148
2246
        except:
 
2247
            log.log(8,'info',_('Exception thrown checking default layout. Falling back to Splash Screen.'))
2149
2248
            log.updateNowPlaying("Splash Screen")
 
2249
            log.log(8,'audit',_('Releasing scheduler layout lock.'))
2150
2250
            self.__lock.release()
2151
2251
            return XiboLayout('0',False)
2152
2252
 
2379
2479
 
2380
2480
class XMDS:
2381
2481
    def __init__(self):
2382
 
        self.__schemaVersion__ = "2";
 
2482
        self.__schemaVersion__ = "2"
2383
2483
 
2384
2484
        # Semaphore to allow only one XMDS call to run check simultaneously
2385
2485
        self.checkLock = Semaphore()
2398
2498
        # Convert the UUID in to a SHA1 hash
2399
2499
        self.uuid = hashlib.sha1(str(self.uuid)).hexdigest()
2400
2500
 
 
2501
        licenseKey = ''
 
2502
        try:
 
2503
            licenseKey = config.get('Main','xmdsLicenseKey')
 
2504
        except:
 
2505
            pass
 
2506
 
 
2507
        if licenseKey != '':
 
2508
            self.uuid = licenseKey
 
2509
 
2401
2510
        self.name = None
2402
2511
        try:
2403
2512
            self.name = config.get('Main','xmdsClientName')
2511
2620
                req = self.server.RequiredFiles(self.getKey(),self.getUUID(),self.__schemaVersion__)
2512
2621
            except SOAPpy.Types.faultType, err:
2513
2622
                log.lights('RF','red')
2514
 
                log.lights('RF','red')
2515
2623
                raise XMDSException("RequiredFiles: Incorrect arguments passed to XMDS.")
2516
2624
            except SOAPpy.Errors.HTTPError, err:
2517
2625
                log.lights('RF','red')
2786
2894
                    log.log(0,"error",str(err))
2787
2895
                    self.hasInitialised = False
2788
2896
 
2789
 
#### Finish Websevrvice
 
2897
class XMDSOffline(Thread):
 
2898
    def __init__(self,displayManager):
 
2899
        Thread.__init__(self)
 
2900
        self.__schemaVersion__ = "2"
 
2901
        self.displayManager = displayManager
 
2902
        self.updatePath = ""
 
2903
        self.__running__ = True
 
2904
        self.__scanPath__ = '/media'
 
2905
 
 
2906
        # Semaphore to allow only one XMDS call to run check simultaneously
 
2907
        self.checkLock = Semaphore()
 
2908
 
 
2909
        self.hasInitialised = False
 
2910
 
 
2911
        salt = None
 
2912
        try:
 
2913
            salt = config.get('Main','xmdsClientID')
 
2914
        except:
 
2915
            log.log(0,"error",_("No XMDS Client ID specified in your configuration"))
 
2916
            log.log(0,"error",_("Please check your xmdsClientID configuration option"))
 
2917
            exit(1)
 
2918
 
 
2919
        self.uuid = uuid.uuid5(uuid.NAMESPACE_DNS, salt)
 
2920
        # Convert the UUID in to a SHA1 hash
 
2921
        self.uuid = hashlib.sha1(str(self.uuid)).hexdigest()
 
2922
 
 
2923
        licenseKey = ''
 
2924
        try:
 
2925
            licenseKey = config.get('Main','xmdsLicenseKey')
 
2926
        except:
 
2927
            pass
 
2928
 
 
2929
        if licenseKey != '':
 
2930
            self.uuid = licenseKey
 
2931
 
 
2932
        self.name = None
 
2933
        try:
 
2934
            self.name = config.get('Main','xmdsClientName')
 
2935
        except:
 
2936
            pass
 
2937
 
 
2938
        if self.name == None or self.name == "":
 
2939
            import platform
 
2940
            self.name = platform.node()
 
2941
 
 
2942
        self.start()
 
2943
 
 
2944
    def run(self):
 
2945
        # Sleep for 10 seconds to allow the client time to start and settle.
 
2946
        time.sleep(10)
 
2947
 
 
2948
        # Startup a loop listening scanning for new mounts
 
2949
        log.log(5,'info','Offline Update: Scanning.',True)
 
2950
        while self.__running__:
 
2951
            for folder in os.listdir(self.__scanPath__):
 
2952
                log.log(5,'info','Offline Update: Checking %s for new content.' % os.path.join(self.__scanPath__,folder),True)
 
2953
                log.log(5,'info','Offline Update: Client License Key: %s' % self.uuid,True)
 
2954
                if os.path.isdir(os.path.join(self.__scanPath__,folder,self.uuid)):
 
2955
                    log.log(5,'info','Offline Update: Starting update from %s.' % os.path.join(self.__scanPath__,folder,self.uuid),True)
 
2956
                    self.updatePath = os.path.join(self.__scanPath__,folder)
 
2957
                    self.displayManager.scheduler.collect()
 
2958
                    time.sleep(5)
 
2959
                    self.displayManager.downloader.collect()
 
2960
            log.log(5,'info','Offline Update: Sleeping 30 seconds.',True)
 
2961
            time.sleep(30)
 
2962
       
 
2963
    def getIP(self):
 
2964
        return 'Offline Mode'
 
2965
    
 
2966
    def getDisk(self):
 
2967
        s = os.statvfs(config.get('Main','libraryDir'))
 
2968
        return (s.f_bsize * s.f_blocks,s.f_bsize * s.f_bavail)
 
2969
 
 
2970
    def getUUID(self):
 
2971
        return str(self.uuid)
 
2972
 
 
2973
    def getName(self):
 
2974
        return str(self.name)
 
2975
 
 
2976
    def getKey(self):
 
2977
        return 'Offline'
 
2978
 
 
2979
    def check(self):
 
2980
        return True
 
2981
 
 
2982
    def RequiredFiles(self):
 
2983
        """Connect to XMDS and get a list of required files"""
 
2984
        log.lights('RF','amber')
 
2985
        req = None
 
2986
        if self.check():
 
2987
            try:
 
2988
                # Update the IP Address shown on the infoScreen
 
2989
                log.updateIP(self.getIP())
 
2990
            except:
 
2991
                pass
 
2992
 
 
2993
            log.updateFreeSpace(self.getDisk())
 
2994
            
 
2995
            try:
 
2996
                fh = open(os.path.join(self.updatePath,self.uuid,'rf.xml'), 'r')
 
2997
                req = fh.read()
 
2998
                fh.close()
 
2999
            except IOError:
 
3000
                log.lights('RF','red')
 
3001
                raise XMDSException("XMDS could not be initialised")
 
3002
 
 
3003
        else:
 
3004
            log.log(0,"error","XMDS could not be initialised")
 
3005
            log.lights('RF','grey')
 
3006
            raise XMDSException("XMDS could not be initialised")
 
3007
 
 
3008
        log.lights('RF','green')
 
3009
        return req
 
3010
    
 
3011
    def SubmitLog(self,logXml):
 
3012
        pass
 
3013
    
 
3014
    def SubmitStats(self,statXml):
 
3015
        pass
 
3016
 
 
3017
    def Schedule(self):
 
3018
        """Connect to XMDS and get the current schedule"""
 
3019
        log.lights('S','amber')
 
3020
        req = None
 
3021
        if self.check():
 
3022
            try:
 
3023
                fh = open(os.path.join(self.updatePath,self.uuid,'schedule.xml'), 'r')
 
3024
                req = fh.read()
 
3025
                fh.close()
 
3026
            except IOError:
 
3027
                log.lights('S','red')
 
3028
                raise XMDSException("XMDS could not be initialised")
 
3029
        else:
 
3030
            log.log(0,"error","XMDS could not be initialised")
 
3031
            log.lights('S','grey')
 
3032
            raise XMDSException("XMDS could not be initialised")
 
3033
 
 
3034
        log.lights('S','green')
 
3035
        return req
 
3036
 
 
3037
    def GetFile(self,tmpPath,tmpType,tmpOffset,tmpChunk):
 
3038
        """Connect to XMDS and download a file"""
 
3039
        response = None
 
3040
        log.lights('GF','amber')
 
3041
        if self.check():
 
3042
            if tmpType == 'media':
 
3043
                try:
 
3044
                    fh = open(os.path.join(self.updatePath,self.uuid,tmpPath), 'r')
 
3045
                    fh.seek(tmpOffset)
 
3046
                    response = fh.read(tmpChunk)
 
3047
                    fh.close()
 
3048
                except:
 
3049
                    log.lights('GF','red')
 
3050
                    raise XMDSException("XMDS could not be initialised")
 
3051
            if tmpType == 'layout':
 
3052
                try:
 
3053
                    fh = open(os.path.join(self.updatePath,self.uuid,tmpPath), 'r')
 
3054
                    response = fh.read()
 
3055
                    fh.close()
 
3056
                except:
 
3057
                    log.lights('GF','red')
 
3058
                    raise XMDSException("XMDS could not be initialised")
 
3059
            if tmpType == 'blacklist':
 
3060
                response = ""
 
3061
        else:
 
3062
            log.log(0,"error","XMDS could not be initialised")
 
3063
            log.lights('GF','grey')
 
3064
            raise XMDSException("XMDS could not be initialised")
 
3065
 
 
3066
        log.lights('GF','green')
 
3067
        return response
 
3068
 
 
3069
    def RegisterDisplay(self):
 
3070
        log.lights('RD','amber')
 
3071
        time.sleep(5)
 
3072
        log.lights('RD','green')
 
3073
 
 
3074
#### Finish Webservice
2790
3075
 
2791
3076
class XiboDisplayManager:
2792
3077
    def __init__(self):
2795
3080
    def run(self):
2796
3081
        # Run up a XiboLogScreen temporarily until XMDS is initialised.
2797
3082
        global log
2798
 
        logLevel = config.get('Logging','logLevel');
 
3083
        logLevel = config.get('Logging','logLevel')
2799
3084
        log = XiboLogScreen(logLevel)
2800
3085
        
2801
 
        self.xmds = XMDS()
 
3086
        if config.get('Main','manualUpdate') == 'true':
 
3087
            self.xmds = XMDSOffline(self)
 
3088
        else:
 
3089
            self.xmds = XMDS()
2802
3090
        
2803
3091
        # Check data directory exists
2804
3092
        try:
2812
3100
            log.log(0,"error",_("No libraryDir specified in your configuration"))
2813
3101
            exit(1)            
2814
3102
                
2815
 
        print _("Log Level is: ") + logLevel;
 
3103
        print _("Log Level is: ") + logLevel
2816
3104
        print _("Logging will be handled by: ") + config.get('Logging','logWriter')
2817
3105
        print _("Switching to new logger")
2818
3106
 
2927
3215
    def __init__(self,parent):
2928
3216
        self.__lock = Semaphore()
2929
3217
 
2930
 
        # Acquire the lock so that nothing can enqueue stuff until this thread starts
 
3218
        # Acquire the lock so that nothing can enqueue stuff until this thread
 
3219
        # starts
2931
3220
        self.__lock.acquire()
2932
3221
 
2933
 
        global AVG_080
2934
 
        global AVG_090
2935
 
        global AVG_090SVN4277
2936
 
        global libavgVersion
2937
 
 
2938
3222
        Thread.__init__(self)
2939
3223
        self.info = False
2940
3224
        self.osLog = False
2942
3226
        self.osLogY = 0
2943
3227
        self.q = Queue.Queue(0)
2944
3228
        self.uniqueId = 0
2945
 
        self.dim = (int(config.get('Main','width')),int(config.get('Main','height')))
 
3229
        self.dim = (int(config.get('Main', 'width')),
 
3230
                    int(config.get('Main', 'height')))
2946
3231
        self.currentFH = None
2947
3232
        self.parent = parent
2948
3233
 
2949
3234
    def getDimensions(self):
2950
 
        # TODO: I don't think this is ever used.
 
3235
        # NB: I don't think this is ever used.
2951
3236
        return self.dim
2952
3237
 
2953
3238
    def getElementByID(self,id):
2964
3249
        return self.uniqueId
2965
3250
 
2966
3251
    def run(self):
2967
 
        log.log(1,"info",_("New XiboPlayer running"))
 
3252
        log.log(1, 'info', _("New XiboPlayer running"))
2968
3253
        self.player = avg.Player.get()
2969
3254
        
2970
 
        if config.get('Main','fullscreen') == "true":
2971
 
            self.player.setResolution(True,int(config.get('Main','width')),int(config.get('Main','height')),int(config.get('Main','bpp')))
 
3255
        if config.get('Main', 'fullscreen') == "true":
 
3256
            self.player.setResolution(
 
3257
                True,
 
3258
                int(config.get('Main', 'width')),
 
3259
                int(config.get('Main', 'height')),
 
3260
                int(config.get('Main', 'bpp'))
 
3261
            )
2972
3262
        else:
2973
 
            self.player.setResolution(False,int(config.get('Main','width')),int(config.get('Main','height')),int(config.get('Main','bpp')))
 
3263
            self.player.setResolution(
 
3264
                False,
 
3265
                int(config.get('Main', 'width')),
 
3266
                int(config.get('Main', 'height')),
 
3267
                int(config.get('Main', 'bpp'))
 
3268
            )
2974
3269
 
2975
3270
        try:
2976
 
            if int(config.get('Main','fps')) > 0:
2977
 
                fps = int(config.get('Main','fps'))
 
3271
            if int(config.get('Main', 'fps')) > 0:
 
3272
                fps = int(config.get('Main', 'fps'))
2978
3273
                self.player.setFramerate(fps)
2979
3274
        except ValueError:
2980
 
            log.log(0,"error",_("Your configuration for fps is incorrect. Main->FPS should be an integer value."))
2981
 
            log.log(0,"error",_("Using 60fps as a default."))            
 
3275
            log.log(0, 'error', _('Your configuration for fps is incorrect.'
 
3276
                                  ' Main->FPS should be an integer value.'))
 
3277
            log.log(0, 'error', _('Using 60fps as a default.'))            
2982
3278
            fps = 60
2983
3279
            self.player.setFramerate(fps)
2984
3280
        except ConfigParser.NoOptionError:
2992
3288
        self.player.volume = 1
2993
3289
        self.player.stopOnEscape(False)
2994
3290
        
2995
 
        useRotation = bool(not int(config.get('Main','vwidth')) == 0)
 
3291
        useRotation = bool(not int(config.get('Main', 'vwidth')) == 0)
2996
3292
        
2997
3293
        # Calculate the information window
2998
3294
        if useRotation:
2999
 
            infoX = (int(config.get('Main','vwidth')) - 400) / 2
3000
 
            infoY = (int(config.get('Main','vheight')) - 300) / 2
3001
 
            self.osLogX = int(config.get('Main','vwidth'))
3002
 
            self.osLogY = int(config.get('Main','vheight')) - 20
 
3295
            infoX = (int(config.get('Main', 'vwidth')) - 400) / 2
 
3296
            infoY = (int(config.get('Main', 'vheight')) - 300) / 2
 
3297
            self.osLogX = int(config.get('Main', 'vwidth'))
 
3298
            self.osLogY = int(config.get('Main', 'vheight')) - 20
3003
3299
        else:
3004
 
            infoX = (int(config.get('Main','width')) - 400) / 2
3005
 
            infoY = (int(config.get('Main','height')) - 300) / 2
3006
 
            self.osLogX = int(config.get('Main','width'))
3007
 
            self.osLogY = int(config.get('Main','height')) - 20
 
3300
            infoX = (int(config.get('Main', 'width')) - 400) / 2
 
3301
            infoY = (int(config.get('Main', 'height')) - 300) / 2
 
3302
            self.osLogX = int(config.get('Main', 'width'))
 
3303
            self.osLogY = int(config.get('Main', 'height')) - 20
3008
3304
        
3009
 
        # If the info window is bigger than the client, stick it in the top left corner.
 
3305
        # If the info window is bigger than the client, stick it in the top
 
3306
        # left corner.
3010
3307
        if infoX < 0:
3011
3308
            infoX = 0
3012
3309
        if infoY < 0:
3028
3325
        avgContent += '<div id="screen" pos="(0,0)" crop="False" />'
3029
3326
        avgContent += '<div id="osLog" pos="(0,%d)" width="%d" height="20" opacity="0" />' % (self.osLogY,self.osLogX)
3030
3327
        avgContent += '<div id="info" width="400" height="300" x="%d" y="%d" opacity="0" crop="False" />' % (infoX,infoY)
 
3328
        avgContent += '<div id="offlineUpdate" width="100" height="100" x="0" y="0" opacity="1" crop="False" />'
3031
3329
        if useRotation:
3032
3330
            avgContent += '</div>'
3033
3331
        avgContent += '</avg>'
3194
3492
                    currentNode.setBitmap(data[1])
3195
3493
                self.q.task_done()
3196
3494
                # Call ourselves again to action any remaining queued items
3197
 
                # This does not make an infinite loop since when all queued items are processed
 
3495
                # This does not make an infinite loop since when all queued
 
3496
                # items are processed.
3198
3497
                # A Queue.Empty exception is thrown and this whole block is skipped.
3199
3498
                self.__lock.release()
3200
3499
                self.frameHandle()
3205
3504
            except RuntimeError as detail:
3206
3505
                log.log(1,"error",_("A runtime error occured: ") + str(detail))
3207
3506
                self.__lock.release()
3208
 
            # TODO: Put this catchall back when finished debugging.
 
3507
            # Generic catchall to prevent unhandled player exceptions bringing
 
3508
            # us down.
3209
3509
            except:
3210
 
                   # log.log(0,"error",_("An unspecified error occured: ") + str(sys.exc_info()[0]))
3211
 
                   self.__lock.release()
3212
 
                   log.log(0,"audit",str(cmd) + " : " + str(data))
 
3510
                # log.log(0,"error",_("An unspecified error occured: ") + str(sys.exc_info()[0]))
 
3511
                self.__lock.release()
 
3512
                log.log(0,"audit",str(cmd) + " : " + str(data))
3213
3513
        except AttributeError:
3214
3514
            log.log(0,"error","Caught that thing that makes the player crash on startup!")
3215
3515