gonzopiserver.py (18953B)
1 #!/usr/bin/env python3 2 3 import web 4 import os 5 import socket 6 import ifaddr 7 import sys 8 import time 9 import random 10 import hashlib 11 import configparser 12 from pymediainfo import MediaInfo 13 14 # Get path of the current dir, then use it as working directory: 15 rundir = os.path.dirname(__file__) 16 if rundir != '': 17 os.chdir(rundir) 18 19 urls = ( 20 '/','intro', 21 '/c/?', 'index', 22 '/f/(.*)?', 'films', 23 '/p/(.*)?', 'player', 24 '/api','api' 25 ) 26 27 #--------------USB filmfolder------------------- 28 29 def usbfilmfolder(): 30 usbmount = 0 31 while True: 32 usbconnected = os.path.ismount('/media/usb'+str(usbmount)) 33 time.sleep(0.02) 34 if usbconnected == True: 35 try: 36 os.makedirs('/media/usb'+str(usbmount)+'/gonzopifilms/') 37 except: 38 pass 39 try: 40 p = subprocess.check_output('stat -f -c %T /media/usb'+str(usbmount), shell=True) 41 filesystem = p.decode() 42 print('filesystem info: ' + filesystem) 43 except: 44 print('Oh-no! dont know your filesystem') 45 filmfolder = '/media/usb'+str(usbmount)+'/gonzopifilms/' 46 return filmfolder 47 else: 48 usbmount = usbmount + 1 49 if usbmount > 20: 50 break 51 52 home = os.path.expanduser('~') 53 menuold = [] 54 vumeterold = '' 55 #configfile = home + '/.gonzopi/config.ini' 56 #configdir = os.path.dirname(configfile) 57 #config = configparser.ConfigParser() 58 #if config.read(configfile): 59 # filmfolder = config['USER']['filmfolder']+'/' 60 filmfolder = '/home/pi/gonzopifilms/' 61 real_filmfolder=filmfolder 62 63 os.system("unlink static/*") 64 #CHECK IF FILMING TO USB STORAGE 65 filmfolderusb=usbfilmfolder() 66 if filmfolderusb: 67 filmfolder=filmfolderusb 68 real_filmfolder=filmfolder 69 # Link video directory to static dir 70 os.system("ln -s -t static/ " + filmfolder) 71 filmfolder='static/gonzopifilms/' 72 else: 73 os.system("ln -s -t static/ " + filmfolder) 74 filmfolder='static/gonzopifilms/' 75 #fix filmfolder root to Videos/gonzopifilms 76 77 basedir = os.path.dirname(os.path.realpath(__file__)) 78 sys.path.append(basedir) 79 80 films = [] 81 82 #NETWORKS 83 84 networks=[] 85 adapters = ifaddr.get_adapters() 86 for adapter in adapters: 87 print("IPs of network adapter " + adapter.nice_name) 88 for ip in adapter.ips: 89 if '::' not in ip.ip[0] and '127.0.0.1' != ip.ip: 90 print(ip.ip) 91 networks.append(ip.ip) 92 network=networks[0] 93 94 app = web.application(urls, globals()) 95 render = web.template.render('templates/', base="base") 96 web.config.debug=False 97 os.system('rm '+basedir+'/sessions/*') 98 store = web.session.DiskStore(basedir + '/sessions/') 99 session = web.session.Session(app,store,initializer={'login': 0, 'user': '', 'backurl': '', 'bildsida': 0, 'cameras': [], 'reload': 0, 'randhash':'', 'menu':[]}) 100 101 port=55555 102 ip='0.0.0.0' 103 cameras=[] 104 recording = False 105 106 session.randhash = hashlib.md5(str(random.getrandbits(256)).encode('utf-8')).hexdigest() 107 108 ##---------------Connection---------------------------------------------- 109 110 def pingtocamera(host, port, data): 111 #print("Sending to "+host+" on port "+str(port)+" DATA:"+data) 112 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 113 s.settimeout(0.01) 114 try: 115 while True: 116 s.connect((host, port)) 117 s.send(str.encode(data)) 118 if host not in cameras and host not in networks: 119 session.cameras.append(host) 120 print("Found camera! "+host) 121 print("Sent to server..") 122 break 123 except: 124 ('did not connect') 125 s.close() 126 127 def sendtocamera(host, port, data): 128 print("Sending to "+host+" on port "+str(port)+" DATA:"+data) 129 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 130 s.settimeout(0.1) 131 try: 132 while True: 133 s.connect((host, port)) 134 s.send(str.encode(data)) 135 print("Sent to server..") 136 break 137 except: 138 ('did not connect') 139 s.close() 140 141 142 def getfilms(filmfolder): 143 #get a list of films, in order of settings.p file last modified 144 films_sorted = [] 145 #print(filmfolder) 146 films = next(os.walk(filmfolder))[1] 147 for i in films: 148 if os.path.isfile(filmfolder + i + '/settings.p') == True: 149 lastupdate = os.path.getmtime(filmfolder + i + '/' + 'settings.p') 150 films_sorted.append((i,lastupdate)) 151 films_sorted = sorted(films_sorted, key=lambda tup: tup[1], reverse=True) 152 #print(films_sorted) 153 return films_sorted 154 155 #------------Count scenes-------- 156 157 def countscenes(filmfolder, filmname): 158 scenes = 0 159 try: 160 allfiles = os.listdir(filmfolder + filmname) 161 except: 162 allfiles = [] 163 scenes = 0 164 for a in allfiles: 165 if 'scene' in a: 166 scenes = scenes + 1 167 return scenes 168 169 #------------Count shots-------- 170 171 def countshots(filmname, filmfolder, scene): 172 shots = 0 173 try: 174 allfiles = os.listdir(filmfolder + filmname + '/scene' + str(scene).zfill(3)) 175 except: 176 allfiles = [] 177 shots = 0 178 for a in allfiles: 179 if 'shot' in a: 180 shots = shots + 1 181 return shots 182 183 #------------Count takes-------- 184 185 def counttakes(filmname, filmfolder, scene, shot): 186 takes = 0 187 try: 188 allfiles = os.listdir(filmfolder + filmname + '/scene' + str(scene).zfill(3) + '/shot' + str(shot).zfill(3)) 189 except: 190 allfiles = [] 191 return takes 192 for a in allfiles: 193 if '.mp4' in a or '.h264' in a: 194 takes = takes + 1 195 return takes 196 197 def checkpicture(thumbdir,scene,shot,take): 198 if os.path.isfile(thumbdir) == False: 199 return "/"+filmfolder+name+"/scene"+str(scene).zfill(3)+"/shot"+str(shot).zfill(3)+"/picture"+str(take).zfill(3)+".jpeg" 200 else: 201 return '' 202 203 def countsize(filename): 204 size = 0 205 if type(filename) is str: 206 size = os.stat(filename).st_size 207 else: 208 return 0 209 return size/1024 210 211 def checkvideo(video,filmfolder,film,scene,shot,take): 212 if take==None: 213 take=1 214 #print(basedir+video) 215 p = "/"+filmfolder+film+"/scene"+str(scene).zfill(3)+"/shot"+str(shot).zfill(3)+ "/picture"+str(take).zfill(3)+".jpeg" 216 #print(p) 217 v = '' 218 if video != '': 219 try: 220 if os.stat(basedir+video).st_size == 0: 221 v = '' 222 else: 223 v='video' 224 except: 225 v = '' 226 if os.path.isfile(basedir+p) == True: 227 return p, v 228 return '', v 229 230 def has_audio_track(file_path): 231 try: 232 # Parse the media file 233 media_info = MediaInfo.parse(file_path) 234 235 # Check for audio tracks 236 for track in media_info.tracks: 237 if track.track_type == "Audio": 238 return True 239 return False 240 241 except Exception as e: 242 print(f"Error parsing {file_path}: {e}") 243 return None 244 245 class intro: 246 def GET(self): 247 return render.intro() 248 249 class index: 250 def GET(self): 251 global recording 252 films = getfilms(filmfolder) 253 renderedfilms = [] 254 unrenderedfilms = [] 255 allfilms = [] 256 for f in films: 257 if os.path.isfile(filmfolder + f[0] + '/' + f[0] + '.mp4') == True: 258 renderedfilms.append(f[0]) 259 allfilms.append(f[0]) 260 else: 261 unrenderedfilms.append(f[0]) 262 allfilms.append(f[0]) 263 i=web.input(func=None,selected=None) 264 if i.selected != None: 265 sendtocamera(ip,port,'SELECTED:'+i.selected) 266 if i.func == 'search': 267 session.cameras=[] 268 # ping ip every 10 sec while not recording to connect cameras 269 pingip=0 270 while pingip < 255 : 271 pingip+=1 272 pingtocamera(network[:-3]+str(pingip),port,'PING') 273 elif i.func == 'record': 274 sendtocamera(ip,port,'RECORD') 275 elif i.func == 'retake': 276 print('retake') 277 elif i.func == 'up': 278 sendtocamera(ip,port,'UP') 279 elif i.func == 'down': 280 sendtocamera(ip,port,'DOWN') 281 elif i.func == 'left': 282 sendtocamera(ip,port,'LEFT') 283 elif i.func == 'right': 284 sendtocamera(ip,port,'RIGHT') 285 elif i.func == 'view': 286 sendtocamera(ip,port,'VIEW') 287 elif i.func == 'middle': 288 sendtocamera(ip,port,'MIDDLE') 289 elif i.func == 'delete': 290 sendtocamera(ip,port,'DELETE') 291 elif i.func == 'picture': 292 sendtocamera(ip,port,'PICTURE') 293 session.randhash = hashlib.md5(str(random.getrandbits(256)).encode('utf-8')).hexdigest() 294 session.reload = 1 295 elif i.func == 'camera0': 296 sendtocamera(ip,port,'CAMERA:0') 297 elif i.func == 'camera1': 298 sendtocamera(ip,port,'CAMERA:1') 299 elif i.func == 'camera2': 300 sendtocamera(ip,port,'CAMERA:2') 301 elif i.func == 'camera3': 302 sendtocamera(ip,port,'CAMERA:3') 303 elif i.func == 'camera4': 304 sendtocamera(ip,port,'CAMERA:4') 305 elif i.func == 'camera5': 306 sendtocamera(ip,port,'CAMERA:5') 307 elif i.func == 'camera6': 308 sendtocamera(ip,port,'CAMERA:6') 309 elif i.func == 'camera7': 310 sendtocamera(ip,port,'CAMERA:7') 311 elif i.func == 'camera8': 312 sendtocamera(ip,port,'CAMERA:8') 313 elif i.func == 'move': 314 sendtocamera(ip,port,'move') 315 elif i.func == 'copy': 316 sendtocamera(ip,port,'copy') 317 elif i.func == 'paste': 318 sendtocamera(ip,port,'paste') 319 interface=open('/dev/shm/interface','r') 320 vumeter=open('/dev/shm/vumeter','r') 321 menu=interface.readlines() 322 vumetermessage=vumeter.readlines()[0].rstrip('\n') 323 try: 324 selected=int(menu[0]) 325 except: 326 selected=0 327 try: 328 name=menu[3].split(':')[1] 329 name=name.rstrip('\n') 330 except: 331 name='' 332 try: 333 scene=menu[4].split(':')[1].split('/')[0] 334 except: 335 scene=1 336 try: 337 shot=menu[5].split(':')[1].split('/')[0] 338 except: 339 shot=1 340 try: 341 take=menu[6].split(':')[1].split('/')[0] 342 except: 343 take=1 344 session.reload = 0 345 if i.func == 'retake': 346 print(i.func) 347 if recording == False: 348 sendtocamera(ip,port,'RETAKE:'+shot) 349 recording = True 350 else: 351 sendtocamera(ip,port,'STOPRETAKE') 352 recording = False 353 if i.func != None: 354 time.sleep(1) 355 session.reload = 1 356 raise web.seeother('/c/') 357 thumb="/"+filmfolder+name+"/scene"+str(scene).zfill(3)+"/shot"+str(shot).zfill(3)+"/picture"+str(take).zfill(3)+".jpeg" 358 #print(thumb) 359 if os.path.isfile(basedir+thumb) == False: 360 print(basedir+thumb) 361 thumb='' 362 return render.index(allfilms, session.cameras, menu, selected,name,scene,shot,take,str,session.randhash,thumb,vumetermessage,i.func,filmfolder) 363 364 class films: 365 def GET(self, film): 366 shots = 0 367 takes = 0 368 gonzopifilms = getfilms(filmfolder) 369 renderedfilms = [] 370 unrenderedfilms = [] 371 allfilms = [] 372 for f in gonzopifilms: 373 if os.path.isfile(filmfolder + f[0] + '/' + f[0] + '.mp4') == True: 374 renderedfilms.append(f[0]) 375 allfilms.append(f[0]) 376 else: 377 unrenderedfilms.append(f[0]) 378 allfilms.append(f[0]) 379 i = web.input(page=None, scene=None, shot=None, take=None, film=None, randhash=None) 380 if i.scene != None: 381 shots = countshots(film, filmfolder, i.scene) 382 takes = counttakes(film, filmfolder, i.scene, i.shot) 383 if i.scene != None and i.shot != None: 384 shots = countshots(film, filmfolder, i.scene) 385 if i.randhash == None: 386 randhash = hashlib.md5(str(random.getrandbits(256)).encode('utf-8')).hexdigest() 387 scenes = countscenes(filmfolder, film) 388 return render.filmpage(allfilms, film, scenes, str, filmfolder, counttakes, countshots, shots, i.scene, takes, i.shot, i.take, checkvideo, randhash) 389 390 class player: 391 def GET(self, film): 392 i=web.input(scene=None,shot=None,take=None) 393 randhash = hashlib.md5(str(random.getrandbits(256)).encode('utf-8')).hexdigest() 394 return render.player(real_filmfolder,filmfolder,film,i.scene,i.shot,i.take,str,randhash,has_audio_track) 395 396 class api: 397 def GET(self): 398 global menuold, vumeterold 399 i=web.input(func=None,selected=None) 400 if i.func == 'record': 401 sendtocamera(ip,port,'RECORD') 402 elif i.func == 'retake': 403 sendtocamera(ip,port,'RETAKE') 404 elif i.func == 'up': 405 sendtocamera(ip,port,'UP') 406 elif i.func == 'down': 407 sendtocamera(ip,port,'DOWN') 408 elif i.func == 'left': 409 sendtocamera(ip,port,'LEFT') 410 elif i.func == 'right': 411 sendtocamera(ip,port,'RIGHT') 412 elif i.func == 'view': 413 sendtocamera(ip,port,'VIEW') 414 elif i.func == 'middle': 415 sendtocamera(ip,port,'MIDDLE') 416 elif i.func == 'delete': 417 sendtocamera(ip,port,'DELETE') 418 elif i.func == 'picture': 419 sendtocamera(ip,port,'PICTURE') 420 elif i.func == 'camera0': 421 sendtocamera(ip,port,'CAMERA:0') 422 elif i.func == 'camera1': 423 sendtocamera(ip,port,'CAMERA:1') 424 elif i.func == 'camera2': 425 sendtocamera(ip,port,'CAMERA:2') 426 elif i.func == 'camera3': 427 sendtocamera(ip,port,'CAMERA:3') 428 elif i.func == 'camera4': 429 sendtocamera(ip,port,'CAMERA:4') 430 elif i.func == 'camera5': 431 sendtocamera(ip,port,'CAMERA:5') 432 elif i.func == 'camera6': 433 sendtocamera(ip,port,'CAMERA:6') 434 elif i.func == 'camera7': 435 sendtocamera(ip,port,'CAMERA:7') 436 elif i.func == 'camera8': 437 sendtocamera(ip,port,'CAMERA:8') 438 elif i.func == 'move': 439 sendtocamera(ip,port,'move') 440 elif i.func == 'copy': 441 sendtocamera(ip,port,'copy') 442 elif i.func == 'paste': 443 sendtocamera(ip,port,'paste') 444 interface=open('/dev/shm/interface','r') 445 menu=interface.readlines() 446 vumeter=open('/dev/shm/vumeter','r') 447 vumetermessage=vumeter.readlines()[0].rstrip('\n') 448 if menu != menuold or vumetermessage != vumeterold: 449 menuold=menu 450 vumeterold=vumetermessage 451 #print(menu) 452 menudone='' 453 p=0 454 film=None 455 selectfilm=False 456 if menu != '': 457 scene=1 458 shot=1 459 take=1 460 for i in menu: 461 if p == 0: 462 selected=int(i)+3 463 if p > 1: 464 if selected == p: 465 #menudone=menudone+'<b> '+i.rstrip('\n')+' </b> | ' 466 menudone=menudone+'<ka style="text-decoration:none; font-size:20px;" color:fff;" href="">'+i+'</ka>' 467 else: 468 #menudone=menudone+i.rstrip('\n')+' | ' 469 menudone=menudone+'<a style="text-decoration:none; font-size:20px;" href="?selected='+str(p-3)+'"> '+i+' </a>' 470 #if p == 7: 471 # menudone=menudone+'<br>' 472 #if p == 13: 473 # menudone=menudone+'<br>' 474 #if p == 21: 475 # menudone=menudone+'<br>' 476 #if p == 30: 477 # menudone=menudone+'<br>' 478 if p == 2 and i.rstrip('\n') == 'Up and down to select and load film': 479 selectfilm=True 480 if p == 3 and selectfilm==True: 481 try: 482 film=i.split(':')[1].rstrip('\n') 483 except: 484 film=None 485 if p == 4 and selectfilm == False: 486 try: 487 film=i.split(':')[1].rstrip('\n') 488 except: 489 film=None 490 if p == 5 and film != None: 491 try: 492 scene=int(i.split(':')[1].split('/')[0]) 493 except: 494 scene=1 495 if p == 6 and film != None: 496 try: 497 shot=int(i.split(':')[1].split('/')[0]) 498 except: 499 shot=1 500 if p == 7 and film != None: 501 try: 502 take=int(i.split(':')[1].split('/')[0]) 503 except: 504 take=1 505 if p > 0 and selected == 423: 506 menudone=menudone+'<ka style="text-decoration:none; font-size:20px;" color:fff;" href="">'+i+'</ka>' 507 #if p > 2 and film == None: 508 #menudone=menudone+'<ka style="text-decoration:none; font-size:20px;" color:fff;" href="">'+i+'</ka>' 509 p = p + 1 510 thumb = '' 511 video = '' 512 if film != None: 513 if selected == 0: 514 video = '/p/'+film 515 menudone+=menudone+'video' 516 if selected == 4: 517 video = '/p/'+film 518 elif selected == 5: 519 video = '/p/'+film+'?scene=' + str(scene) 520 elif selected == 6: 521 video = '/p/'+film+'?scene='+str(scene)+'&shot='+str(shot)+'&take='+str(take) 522 elif selected == 7: 523 video = '/p/'+film+'?scene='+str(scene)+'&shot='+str(shot)+'&take='+str(take) 524 else: 525 video = '/p/'+film+'?scene='+str(scene)+'&shot='+str(shot)+'&take='+str(take) 526 thumb = '/'+filmfolder + film + "/scene" + str(scene).zfill(3) + "/shot" + str(shot).zfill(3) + "/take" + str(take).zfill(3) + ".jpeg" 527 if os.path.isfile(basedir+thumb) == True: 528 randhashimg = '?'+hashlib.md5(str(random.getrandbits(256)).encode('utf-8')).hexdigest() 529 writemenu=menudone+'<br><br>'+vumetermessage+'<br><a href="'+video+'"><img src="'+thumb+randhashimg+'"></a>' 530 #writemenu=menudone+render.player(filmfolder,film,scene,shot,take,str) 531 else: 532 writemenu=menudone+'<br><br>'+vumetermessage+'<br>' 533 f = open(basedir+'/static/menu.html', 'w') 534 f.write(writemenu) 535 f.close() 536 537 application = app.wsgifunc() 538