Changeset 48e5447199435cb9695489516056d65842b74acc
- Timestamp:
- 03/01/08 17:37:53 (10 months ago)
- git-parent:
[f1e76d8061669097cf6aae05d118690c87853181], [13846522caa6199e6c12e614475b80438432e08d]
- Files:
-
- debug.py (added)
- httpserver.py (modified) (2 diffs)
- plugins/video/transcode.py (modified) (23 diffs)
- plugins/video/video.py (modified) (15 diffs)
- pyTivo.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
httpserver.py
rdcebed3 r48e5447 7 7 import config 8 8 from xml.sax.saxutils import escape 9 from debug import debug_write, fn_attr 9 10 10 11 SCRIPTDIR = os.path.dirname(__file__) 11 12 12 debug = config.getDebug()13 13 hack83 = config.getHack83() 14 15 def debug_write(data):16 if debug:17 debug_out = []18 debug_out.append('httpserver.py - ')19 for x in data:20 debug_out.append(str(x))21 fdebug = open('debug.txt', 'a')22 fdebug.write(' '.join(debug_out))23 fdebug.close()24 14 25 15 class TivoHTTPServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer): … … 134 124 def unsupported(self, query): 135 125 if hack83 and 'Command' in query and 'Filter' in query: 136 debug_write( ['Unsupported request,',137 'checking to see if it is video. \n'])126 debug_write(__name__, fn_attr(), ['Unsupported request,', 127 'checking to see if it is video.']) 138 128 command = query['Command'][0] 139 129 plugin = GetPlugin('video') 140 130 if ''.join(query['Filter']).find('video') >= 0 and \ 141 131 hasattr(plugin, command): 142 debug_write( ['Unsupported request,',132 debug_write(__name__, fn_attr(), ['Unsupported request,', 143 133 'yup it is video', 144 'send to video plugin for it to sort out. \n'])134 'send to video plugin for it to sort out.']) 145 135 method = getattr(plugin, command) 146 136 method(self, query) plugins/video/transcode.py
rf1e76d8 r48e5447 1 1 import subprocess, shutil, os, re, sys, ConfigParser, time, lrucache 2 2 import config 3 from debug import debug_write, fn_attr 3 4 4 5 info_cache = lrucache.LRUCache(1000) 6 videotest = os.path.join(os.path.dirname(__file__), 'videotest.mpg') 5 7 6 8 def ffmpeg_path(): 7 9 return config.get('Server', 'ffmpeg') 8 9 videotest = os.path.join(os.path.dirname(__file__), 'videotest.mpg')10 11 def debug_write(data):12 if config.getDebug():13 debug_out = []14 for x in data:15 debug_out.append(str(x))16 fdebug = open('debug.txt', 'a')17 fdebug.write(' '.join(debug_out))18 fdebug.close()19 10 20 11 # XXX BIG HACK … … 34 25 def output_video(inFile, outFile, tsn=''): 35 26 if tivo_compatable(inFile, tsn): 36 debug_write( ['output_video: ', inFile, ' is tivo compatible\n'])27 debug_write(__name__, fn_attr(), [inFile, ' is tivo compatible']) 37 28 f = file(inFile, 'rb') 38 29 shutil.copyfileobj(f, outFile) 39 30 f.close() 40 31 else: 41 debug_write( ['output_video: ', inFile, ' is not tivo compatible\n'])32 debug_write(__name__, fn_attr(), [inFile, ' is not tivo compatible']) 42 33 transcode(inFile, outFile, tsn) 43 34 … … 56 47 57 48 cmd = [ffmpeg_path(), '-i', inFile] + cmd_string.split() 49 print 'transcoding to tivo model '+tsn[:3]+' using ffmpeg command:' 58 50 print cmd 59 debug_write( ['transcode: ffmpeg command is ', ' '.join(cmd), '\n'])51 debug_write(__name__, fn_attr(), ['ffmpeg command is ', ' '.join(cmd)]) 60 52 ffmpeg = subprocess.Popen(cmd, stdout=subprocess.PIPE) 61 53 try: … … 99 91 type, width, height, fps, millisecs, kbps, akbps, acodec, afreq = video_info(inFile) 100 92 101 debug_write( ['tsn:', tsn, '\n'])93 debug_write(__name__, fn_attr(), ['tsn:', tsn]) 102 94 103 95 aspect169 = config.get169Setting(tsn) 104 96 105 debug_write( ['aspect169:', aspect169, '\n'])97 debug_write(__name__, fn_attr(), ['aspect169:', aspect169]) 106 98 107 99 optres = config.getOptres() 108 100 109 debug_write( ['optres:', optres, '\n'])101 debug_write(__name__, fn_attr(), ['optres:', optres]) 110 102 111 103 if optres: … … 121 113 rheight, rwidth = height/d, width/d 122 114 123 debug_write( ['select_aspect: File=', inFile, ' Type=', type, ' width=', width, ' height=', height, ' fps=', fps, ' millisecs=', millisecs, ' ratio=', ratio, ' rheight=', rheight, ' rwidth=', rwidth, ' TIVO_HEIGHT=', TIVO_HEIGHT, 'TIVO_WIDTH=', TIVO_WIDTH, '\n'])115 debug_write(__name__, fn_attr(), ['File=', inFile, ' Type=', type, ' width=', width, ' height=', height, ' fps=', fps, ' millisecs=', millisecs, ' ratio=', ratio, ' rheight=', rheight, ' rwidth=', rwidth, ' TIVO_HEIGHT=', TIVO_HEIGHT, 'TIVO_WIDTH=', TIVO_WIDTH]) 124 116 125 117 multiplier16by9 = (16.0 * TIVO_HEIGHT) / (9.0 * TIVO_WIDTH) … … 130 122 # else, optres is enabled and resizes SD video to the "S2" standard on S3/HD. 131 123 elif (rwidth, rheight) in [(4, 3), (10, 11), (15, 11), (59, 54), (59, 72), (59, 36), (59, 54)]: 132 debug_write( ['select_aspect: File is within 4:3 list.\n'])124 debug_write(__name__, fn_attr(), ['File is within 4:3 list.']) 133 125 return ['-aspect', '4:3', '-s', str(TIVO_WIDTH) + 'x' + str(TIVO_HEIGHT)] 134 126 elif ((rwidth, rheight) in [(16, 9), (20, 11), (40, 33), (118, 81), (59, 27)]) and aspect169: 135 debug_write( ['select_aspect: File is within 16:9 list and 16:9 allowed.\n'])127 debug_write(__name__, fn_attr(), ['File is within 16:9 list and 16:9 allowed.']) 136 128 return ['-aspect', '16:9', '-s', str(TIVO_WIDTH) + 'x' + str(TIVO_HEIGHT)] 137 129 else: … … 162 154 settings.append('-s') 163 155 settings.append(str(TIVO_WIDTH) + 'x' + str(TIVO_HEIGHT)) 164 debug_write( ['select_aspect: 16:9 aspect allowed, file is wider than 16:9 padding top and bottom\n', ' '.join(settings), '\n'])156 debug_write(__name__, fn_attr(), ['16:9 aspect allowed, file is wider than 16:9 padding top and bottom', ' '.join(settings)]) 165 157 else: #too skinny needs padding on left and right. 166 158 endWidth = int((TIVO_HEIGHT*width)/(height*multiplier16by9)) … … 185 177 settings.append('-s') 186 178 settings.append(str(TIVO_WIDTH) + 'x' + str(TIVO_HEIGHT)) 187 debug_write( ['select_aspect: 16:9 aspect allowed, file is narrower than 16:9 padding left and right\n', ' '.join(settings), '\n'])179 debug_write(__name__, fn_attr(), ['16:9 aspect allowed, file is narrower than 16:9 padding left and right\n', ' '.join(settings)]) 188 180 else: #this is a 4:3 file or 16:9 output not allowed 189 181 settings.append('-aspect') … … 208 200 settings.append('-s') 209 201 settings.append(str(TIVO_WIDTH) + 'x' + str(TIVO_HEIGHT)) 210 debug_write( ['select_aspect: File is wider than 4:3 padding top and bottom\n', ' '.join(settings), '\n'])202 debug_write(__name__, fn_attr(), ['File is wider than 4:3 padding top and bottom\n', ' '.join(settings)]) 211 203 212 204 return settings … … 236 228 settings.append(str(TIVO_WIDTH) + 'x' + str(TIVO_HEIGHT)) 237 229 238 debug_write( ['select_aspect: File is taller than 4:3 padding left and right\n', ' '.join(settings), '\n'])230 debug_write(__name__, fn_attr(), ['File is taller than 4:3 padding left and right\n', ' '.join(settings)]) 239 231 240 232 return settings … … 246 238 247 239 if (inFile[-5:]).lower() == '.tivo': 248 debug_write( ['tivo_compatible: ', inFile, ' ends with .tivo\n'])240 debug_write(__name__, fn_attr(), ['TRUE, ends with .tivo.', inFile]) 249 241 return True 250 242 251 243 if not type == 'mpeg2video': 252 244 #print 'Not Tivo Codec' 253 debug_write( ['tivo_compatible: ', inFile, ' is not mpeg2video it is ', type, '\n'])245 debug_write(__name__, fn_attr(), ['FALSE, type', type, 'not mpeg2video.', inFile]) 254 246 return False 255 247 256 248 if (inFile[-3:]).lower() == '.ts': 257 debug_write( ['tivo_compatible: ', inFile, ' transport stream not supported ', '\n'])249 debug_write(__name__, fn_attr(), ['FALSE, transport stream not supported.', inFile]) 258 250 return False 259 251 260 252 if not akbps or int(akbps) > config.getMaxAudioBR(tsn): 261 debug_write( ['tivo_compatible: ', inFile, ' max audio bitrate exceeded it is ', akbps, '\n'])253 debug_write(__name__, fn_attr(), ['FALSE,', akbps, 'kbps exceeds max audio bitrate.', inFile]) 262 254 return False 263 255 264 256 if not kbps or int(kbps)-int(akbps) > config.strtod(config.getMaxVideoBR())/1000: 265 debug_write( ['tivo_compatible: ', inFile, ' max video bitrate exceeded it is ', kbps, '\n'])257 debug_write(__name__, fn_attr(), ['FALSE,', kbps, 'kbps exceeds max video bitrate.', inFile]) 266 258 return False 267 259 268 260 if config.isHDtivo(tsn): 269 debug_write( ['tivo_compatible: ', inFile, ' you have a S3 skiping the rest of the tests', '\n'])261 debug_write(__name__, fn_attr(), ['TRUE, HD Tivo detected, skipping remaining tests', inFile]) 270 262 return True 271 263 272 264 if not fps == '29.97': 273 265 #print 'Not Tivo fps' 274 debug_write( ['tivo_compatible: ', inFile, ' is not correct fps it is ', fps, '\n'])266 debug_write(__name__, fn_attr(), ['FALSE,', fps, 'fps, should be 29.97.', inFile]) 275 267 return False 276 268 … … 278 270 if (mode[0], mode[1]) == (width, height): 279 271 #print 'Is TiVo!' 280 debug_write( ['tivo_compatible: ', inFile, ' has correct width of ', width, ' and height of ', height, '\n'])272 debug_write(__name__, fn_attr(), ['TRUE,', width, 'x', height, 'is valid.', inFile]) 281 273 return True 282 274 #print 'Not Tivo dimensions' … … 287 279 if inFile != videotest: 288 280 if inFile in info_cache and info_cache[inFile][0] == mtime: 289 debug_write( ['video_info: ', inFile, ' cache hit!', '\n'])281 debug_write(__name__, fn_attr(), ['CACHE HIT!', inFile]) 290 282 return info_cache[inFile][1] 291 283 292 284 if (inFile[-5:]).lower() == '.tivo': 293 285 info_cache[inFile] = (mtime, (True, True, True, True, True, True, True, True, True)) 294 debug_write( ['video_info: ', inFile, ' ends in .tivo.\n'])286 debug_write(__name__, fn_attr(), ['VALID, ends in .tivo.', inFile]) 295 287 return True, True, True, True, True, True, True, True, True 296 288 … … 310 302 311 303 output = ffmpeg.stderr.read() 312 debug_write( ['video_info: ffmpeg output=', output, '\n'])304 debug_write(__name__, fn_attr(), ['ffmpeg output=', output]) 313 305 314 306 rezre = re.compile(r'.*Video: ([^,]+),.*') … … 318 310 else: 319 311 info_cache[inFile] = (mtime, (None, None, None, None, None, None, None, None, None)) 320 debug_write( ['video_info: failed at codec\n'])312 debug_write(__name__, fn_attr(), ['failed at video codec']) 321 313 return None, None, None, None, None, None, None, None, None 322 314 … … 328 320 else: 329 321 info_cache[inFile] = (mtime, (None, None, None, None, None, None, None, None, None)) 330 debug_write( ['video_info: failed at width/height\n'])322 debug_write(__name__, fn_attr(), ['failed at width/height']) 331 323 return None, None, None, None, None, None, None, None, None 332 324 … … 337 329 else: 338 330 info_cache[inFile] = (mtime, (None, None, None, None, None, None, None, None, None)) 339 debug_write( ['video_info: failed at fps\n'])331 debug_write(__name__, fn_attr(), ['failed at fps']) 340 332 return None, None, None, None, None, None, None, None, None 341 333 … … 346 338 x = rezre.search(output.lower() ) 347 339 if x: 348 debug_write( ['video_info: film source: 29.97 setting fps to 29.97\n'])340 debug_write(__name__, fn_attr(), ['film source: 29.97 setting fps to 29.97']) 349 341 fps = '29.97' 350 342 else: 351 343 # for build 8047: 352 344 rezre = re.compile(r'.*frame rate differs from container frame rate: 29.97.*') 353 debug_write( ['video_info: Bug in VideoReDo\n'])345 debug_write(__name__, fn_attr(), ['Bug in VideoReDo']) 354 346 x = rezre.search(output.lower() ) 355 347 if x: … … 370 362 else: 371 363 kbps = None 372 debug_write( ['video_info: failed at kbps\n'])364 debug_write(__name__, fn_attr(), ['failed at kbps']) 373 365 374 366 #get audio bitrate of source for tivo compatibility test. … … 379 371 else: 380 372 akbps = None 381 debug_write( ['video_info: failed at akbps\n'])373 debug_write(__name__, fn_attr(), ['failed at akbps']) 382 374 383 375 #get audio codec of source for tivo compatibility test. … … 388 380 else: 389 381 acodec = None 390 debug_write( ['video_info: failed at acodec\n'])382 debug_write(__name__, fn_attr(), ['failed at acodec']) 391 383 392 384 #get audio frequency of source for tivo compatibility test. … … 397 389 else: 398 390 afreq = None 399 debug_write( ['video_info: failed at afreq\n'])391 debug_write(__name__, fn_attr(), ['failed at afreq']) 400 392 401 393 info_cache[inFile] = (mtime, (codec, width, height, fps, millisecs, kbps, akbps, acodec, afreq)) 402 debug_write( ['video_info: Codec=', codec, ' width=', width, ' height=', height, ' fps=', fps, ' millisecs=', millisecs, ' kbps=', kbps, ' akbps=', akbps, ' acodec=', acodec, ' afreq=', afreq, '\n'])394 debug_write(__name__, fn_attr(), ['Codec=', codec, ' width=', width, ' height=', height, ' fps=', fps, ' millisecs=', millisecs, ' kbps=', kbps, ' akbps=', akbps, ' acodec=', acodec, ' afreq=', afreq]) 403 395 return codec, width, height, fps, millisecs, kbps, akbps, acodec, afreq 404 396 … … 417 409 return True 418 410 else: 419 debug_write( ['supported_format: ', inFile, ' is not supported\n'])411 debug_write(__name__, fn_attr(), ['FALSE, file not supported', inFile]) 420 412 return False 421 413 422 414 def kill(pid): 423 debug_write( ['kill: killing pid=', str(pid), '\n'])415 debug_write(__name__, fn_attr(), ['killing pid=', str(pid)]) 424 416 if mswindows: 425 417 win32kill(pid) plugins/video/video.py
rf1e76d8 r48e5447 9 9 import config 10 10 import time 11 from debug import debug_write, fn_attr 11 12 12 13 SCRIPTDIR = os.path.dirname(__file__) … … 20 21 extensions = None 21 22 22 def debug_write(data): 23 if config.getDebug(): 24 debug_out = [] 25 debug_out.append('Video.py - ') 26 for x in data: 27 debug_out.append(str(x)) 28 fdebug = open('debug.txt', 'a') 29 fdebug.write(' '.join(debug_out)) 30 fdebug.close() 23 if config.getHack83(): 24 debug_write(__name__, fn_attr(), ['Hack83 is enabled.']) 31 25 32 26 class Video(Plugin): … … 51 45 52 46 def hack(self, handler, query, subcname): 53 debug_write( ['Hack new request ------------------------\n'])54 debug_write( ['Hack TiVo request is: \n', query, '\n'])47 debug_write(__name__, fn_attr(), ['new request ------------------------']) 48 debug_write(__name__, fn_attr(), ['TiVo request is: \n', query]) 55 49 queryAnchor = '' 56 50 rightAnchor = '' … … 60 54 # not a tivo 61 55 if not tsn: 62 debug_write( ['Hackthis was not a TiVo request.',63 'Using default tsn. \n'])56 debug_write(__name__, fn_attr(), ['this was not a TiVo request.', 57 'Using default tsn.']) 64 58 tsn = '123456789' 65 59 … … 74 68 queryAnchor = queryAnchor.split('/', 1)[-1] 75 69 leftAnchor, rightAnchor = queryAnchor.rsplit('/', 1) 76 debug_write( ['HackqueryAnchor: ', queryAnchor,70 debug_write(__name__, fn_attr(), ['queryAnchor: ', queryAnchor, 77 71 ' leftAnchor: ', leftAnchor, 78 ' rightAnchor: ', rightAnchor , '\n'])72 ' rightAnchor: ', rightAnchor]) 79 73 try: 80 74 path, state = self.request_history[tsn] 81 75 except KeyError: 82 76 # Never seen this tsn, starting new history 83 debug_write( ['New TSN.\n'])77 debug_write(__name__, fn_attr(), ['New TSN.']) 84 78 path = [] 85 79 state = {} … … 89 83 state['time'] = int(time.time()) + 1000 90 84 91 debug_write( ['Hack our saved request is: \n', state['query'], '\n'])85 debug_write(__name__, fn_attr(), ['our saved request is: \n', state['query']]) 92 86 93 87 current_folder = subcname.split('/')[-1] … … 98 92 # 1. at the root - This request is always accurate 99 93 if len(subcname.split('/')) == 1: 100 debug_write( ['Hackwe are at the root.',101 'Saving query, Clearing state[page]. \n'])94 debug_write(__name__, fn_attr(), ['we are at the root.', 95 'Saving query, Clearing state[page].']) 102 96 path[:] = [current_folder] 103 97 state['query'] = query … … 109 103 # entering a new folder. 110 104 if 'AnchorItem' not in query: 111 debug_write( ['Hackwe are entering a new folder.',112 'Saving query, setting time, setting state[page]. \n'])105 debug_write(__name__, fn_attr(), ['we are entering a new folder.', 106 'Saving query, setting time, setting state[page].']) 113 107 path[:] = subcname.split('/') 114 108 state['query'] = query … … 125 119 # we know this is the proper page 126 120 if ''.join(query['AnchorItem']) == 'Hack8.3': 127 debug_write( ['Hackrequested page from 302 code.',128 'Returning saved query ,\n'])121 debug_write(__name__, fn_attr(), ['requested page from 302 code.', 122 'Returning saved query.']) 129 123 return state['query'], path 130 124 131 125 # 4. this is a request for a file 132 126 if 'ItemCount' in query and int(''.join(query['ItemCount'])) == 1: 133 debug_write( ['Hack requested a file', '\n'])127 debug_write(__name__, fn_attr(), ['requested a file']) 134 128 # Everything in this request is right except the container 135 129 query['Container'] = ['/'.join(path)] … … 143 137 # Sleep just in case the erroneous request came first this 144 138 # allows a proper request to be processed first 145 debug_write( ['Hack maybe erroneous request, sleeping.\n'])139 debug_write(__name__, fn_attr(), ['maybe erroneous request, sleeping.']) 146 140 time.sleep(.25) 147 141 … … 151 145 # First we have to figure out if we are scrolling 152 146 if 'AnchorOffset' in query: 153 debug_write( ['HackAnchor offset was in query.',154 'leftAnchor needs to match ', '/'.join(path) , '\n'])147 debug_write(__name__, fn_attr(), ['Anchor offset was in query.', 148 'leftAnchor needs to match ', '/'.join(path)]) 155 149 if leftAnchor == str('/'.join(path)): 156 debug_write( ['Hack leftAnchor matched.', '\n'])150 debug_write(__name__, fn_attr(), ['leftAnchor matched.']) 157 151 query['Container'] = ['/'.join(path)] 158 152 files, total, start = self.get_files(handler, query, 159 153 self.video_file_filter) 160 debug_write( ['Hacksaved page is= ', state['page'],161 ' top returned file is= ', files[0] , '\n'])154 debug_write(__name__, fn_attr(), ['saved page is= ', state['page'], 155 ' top returned file is= ', files[0]]) 162 156 # If the first file returned equals the top of the page 163 157 # then we haven't scrolled pages 164 158 if files[0] != str(state['page']): 165 debug_write( ['Hack this is scrolling within a folder.\n'])159 debug_write(__name__, fn_attr(), ['this is scrolling within a folder.']) 166 160 state['page'] = files[0] 167 161 return query, path … … 174 168 # request. 175 169 if (int(time.time()) - state['time']) <= 1: 176 debug_write( ['Hack erroneous request, send a 302 error', '\n'])170 debug_write(__name__, fn_attr(), ['erroneous request, send a 302 error']) 177 171 return None, path 178 172 … … 180 174 # this request came by itself; it must be to exit a folder 181 175 else: 182 debug_write( ['Hackover 1 second,',183 'must be request to exit folder \n'])176 debug_write(__name__, fn_attr(), ['over 1 second,', 177 'must be request to exit folder']) 184 178 path.pop() 185 179 state['query'] = {'Command': query['Command'], … … 191 185 192 186 # just in case we missed something. 193 debug_write( ['HackERROR, should not have made it here. ',194 'Trying to recover. \n'])187 debug_write(__name__, fn_attr(), ['ERROR, should not have made it here. ', 188 'Trying to recover.']) 195 189 return state['query'], path 196 190 … … 337 331 hackPath = '/'.join(hackPath) 338 332 print 'Tivo said:', subcname, '|| Hack said:', hackPath 339 debug_write( ['HackTivo said: ', subcname, ' || Hack said: ',340 hackPath , '\n'])333 debug_write(__name__, fn_attr(), ['Tivo said: ', subcname, ' || Hack said: ', 334 hackPath]) 341 335 subcname = hackPath 342 336 343 337 if not query: 344 debug_write( ['Hack sending 302 redirect page', '\n'])338 debug_write(__name__, fn_attr(), ['sending 302 redirect page']) 345 339 handler.send_response(302) 346 340 handler.send_header('Location ', 'http://' + pyTivo.py
r7018122 r75822c9 3 3 import beacon, httpserver, os, sys 4 4 import config 5 from debug import print_conf, fn_attr 5 6 from plugin import GetPlugin 6 7 … … 34 35 b.listen() 35 36 37 print_conf(__name__, fn_attr()) 36 38 print 'pyTivo is ready.' 37 39 try:
