def clkSpartaUploadClear(self, widget, event, data=None): for list_row in ListStore.projShotStore: row_selected = list_row[const.COLUMN_CHOICE] row_register = list_row[const.COLUMN_REGISTER] if row_selected and 'Y' == row_register: shot_name = list_row[const.COLUMN_SHOTLIST] db_shot_record = self.datastore.getShotFromName(shot_name).first() # 업로드 여부 지움 db_shot_record.isregister = u'N' self.datastore.shotSave(db_shot_record) gui_util.updateProjectShots(self.datastore)
def clkInfoXlsLoad(self, widget, event, data=None): # infoXLS 불러오기 클릭시 # 다이얼로그 오픈 --------------------- FileDialog = gtk.FileChooserDialog("Open info.xls Path", self.parentWindow, gtk.FILE_CHOOSER_ACTION_OPEN, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK ), None) FileDialog.set_default_response(gtk.RESPONSE_OK) filter = gtk.FileFilter() filter.set_name("info.xls") filter.add_pattern("*.xls") FileDialog.add_filter(filter) FileDialog.show() response = FileDialog.run() if response == gtk.RESPONSE_OK: filename = FileDialog.get_filename() FileDialog.destroy() else: FileDialog.destroy() return # ------------------------------------ # 엑셀에서 셀값을 가져와 딕셔너리에 저장 ---------------- book = xlrd.open_workbook( filename ) sh = book.sheet_by_index(0) ShotMatchDict = dict() for record_index in range( 1, sh.nrows ): # 2번재 줄부터 읽음 DirName = str(sh.cell_value(record_index, 0)) SeqName = str(sh.cell_value(record_index, 1)) SeqNumber = str(sh.cell_value(record_index, 2)) ShotType = str(sh.cell_value(record_index, 3)) ShotStereo = str(sh.cell_value(record_index, 4)) if len(re.findall("\.[0-9]+$",DirName)) > 0: # Add By Sabzil DirName = DirName.split(".")[0] ShotMatchDict[DirName] = { "SeqName" : SeqName, "SeqNumber" : SeqNumber, "ShotType" : ShotType, "ShotStereo" : ShotStereo } # ------------------------------------------------------- # ShotName이 중복해서 있는 경우는 뒤에 _를 붙여주어야 한다. # 이 요구사항은 코디네이터 김희경님의 요청사항이다(마이웨이 하나 때문에 이것저것 처리해둔다) # Rule Name : 김희경_110804_Rule #print ShotMatchDict ShotNameDuplicate = {} ShotNumber = "" # 엑셀에 표기된 SeqName, SeqNum 대로 찾아서, 뒷부분에 숫자가 있을경우 그 숫자를 Duplicate에 기록한다. # [WARNNING] 전 개발자가, SeqNumber라고 표현 했지만, 원래는 샷이름임 for (key, value) in ShotMatchDict.items(): # /show/myWay/seq/SeqNAME/SeqNUM dir_list = glob("%s*" % path_join("/", "show", const.PROJECT, "seq", value["SeqName"], value["SeqNumber"])) dir_list.sort() if len(dir_list) > 0: numTail = re.findall("([0-9]+)$", dir_list[-1] ) if len(numTail) > 0: ShotNameDuplicate[ value.get("SeqNumber") ] = numTail[0] # 다시 채킹필요 elif exists( dir_list[-1] ): ShotNameDuplicate[ value.get("SeqNumber") ] = 0 #[sz] ListStore는 GTK용 오브젝트, ListData를 가지는 컨테이너 # ListStore Update(from ShotMatchDict) for row in ListStore.projShotStore: # ShotName은 디렉터리 이름을 완전하게 매치해야 한다. ShotName = row[ const.COLUMN_SHOTLIST ] # DB정보를 가져온다. db_shot_record = self.datastore.getShotFromName(ShotName).first() if (None == db_shot_record): self.Alert("영상소스 파일 수와 키코드 계산 결과 프레임이 일치하지 않습니다. 데이터를 확인하여 주십시오.\n문제가 발생한 디렉터리는 %s 입니다." % ShotName) continue # DB의 정보를 가져온다. List_Seq = db_shot_record.seq List_SeqNumber = db_shot_record.shotnumber List_Type = db_shot_record.type List_Stereo = db_shot_record.isstereo # 먼저 정보를 불러온다. XlsMatchDict = ShotMatchDict.get(ShotName, None) if XlsMatchDict == None: if ShotName.isdigit(): XlsMatchDict = ShotMatchDict.get( str(int(ShotName)) , None ) if XlsMatchDict == None: print "Not Found in Excel:", ShotName continue # 정보 갱신을 위해 기존 값이 길이 0인지 확인한다.(0인 경우에만 정보를 갱신한다.) if (None == List_Seq) or (0 == len(List_Seq)): # SeqName이 숫자로만 구성되어 있는 경우 소수점으로 들어갈 수 있는 문제가 있다. re_search_result = re.search("^([0-9]+)\.[0-9]+$", str(XlsMatchDict["SeqName"])) if re_search_result: XlsMatchDict["SeqName"] = re_search_result.group(1) db_shot_record.seq = XlsMatchDict["SeqName"] if (None == List_SeqNumber) or (0 == len(List_SeqNumber)): # 먼저 중복된 SeqNumbner가 ShotNameDuplicate 에 있는지 확인한다.(내가 무슨 잘못을...) # 먼저 엑셀의 데이터를 기준으로 마이웨이 프로젝트에 한해서 디렉터리가 이미 존재하는지 확인한다. if XlsMatchDict["SeqNumber"] in ShotNameDuplicate: ShotNameDuplicate[XlsMatchDict.get("SeqNumber")] += 1 ShotNumber = "%s_%d" % ( XlsMatchDict["SeqNumber"], ShotNameDuplicate[XlsMatchDict.get("SeqNumber")] ) else: ShotNameDuplicate[XlsMatchDict.get("SeqNumber")] = 0 ShotNumber = XlsMatchDict["SeqNumber"] # 2011/08/12일 기존 경로인 138 디렉터리 아래 동일한 샷네임이 있을 경우 MOV영상을 덮어 써버리는 문제가 있어서 # 기존 경로도 조사하게 한다.(단, 이 루틴은 마이웨이에 한정한다.) if "myWay" == const.PROJECT: dir_list = glob("%s*" % path_join("/", "show", const.PROJECT, "seq", XlsMatchDict["SeqName"], XlsMatchDict["SeqNumber"])) dir_list.sort() if len(dir_list) > 0: search = re.search(".+_([0-9]+)$", dir_list[-1]) if search: # 기존 경로가 존재하면.. ShotNameDuplicate[XlsMatchDict.get("SeqNumber")] = int(search.group(1)) ShotNumber = "%s_%d" % ( XlsMatchDict["SeqNumber"], ShotNameDuplicate[XlsMatchDict.get("SeqNumber")] ) db_shot_record.shotnumber = ShotNumber if None == List_Type or 0 == len(List_Type): db_shot_record.type = XlsMatchDict["ShotType"] if None == List_Stereo or 0 == len(List_Stereo): db_shot_record.isstereo = XlsMatchDict["ShotStereo"] # DB 갱신 self.datastore.shotSave(db_shot_record) # ListStore 갱신 gui_util.updateProjectShots( self.datastore ) return
def clkPublish(self, widget, event, data=None): tmp_path = path_join(const.SCAN_ROOT, "tmp") # tmp_path exists if not exists(tmp_path): makedirs(tmp_path) # 물론 projectShot에서 체크된 된것만 수행한다) for row in ListStore.projShotStore: if not row[const.COLUMN_CHOICE]: continue # Choice가 선택되어진 경우만 수행한다. # Publish 단계에선 DB정보가 완성되어 있다(ScanInfo.py에서 이미 데이터를 넣는다) ################################################################ # shotname을 기준으로 데이터베이스에 질의해서 db_shot_record에 값을 담는다. ################################################################ db_shot_record = self.datastore.getShotFromName(row[const.COLUMN_SHOTLIST]).first() if db_shot_record == None: # 데이터가 없음을 알리고 루프를 반복한다. 물론 그럴리는 없겠지만... # 별도의 처리를 하기 전까지는 그냥 루프만 반복한다. continue # 새로운 Seq Name이나 새 Seq Number가 없으면 작업 하나 마나다. 에러 메시지 출력해주게 한다.(미정) if (None == db_shot_record.seq) or (None == db_shot_record.shotnumber): return False tmp_shot_directory = path_join(tmp_path, db_shot_record.shotname) # Dpx Size ShotMaxWidth = int(db_shot_record.width) ShotMaxHeight = int(db_shot_record.height) # Thumbnail은 항상 300으로 고정한다. thumbnail_width = 300 thumbnail_height = int(float(ShotMaxHeight) / float(ShotMaxWidth) * thumbnail_width) # Half Size half_width = ShotMaxWidth / 2 half_height = ShotMaxHeight / 2 tmp_resolution_dir = path_join(tmp_shot_directory, "%dx%d" % (ShotMaxWidth, ShotMaxHeight)) if not exists(tmp_resolution_dir): makedirs(tmp_resolution_dir) # dpx, tga, cin 등의 파일을 resolution_dir에 복사 dpx_files = glob("%s/%s/*" % (const.SCAN_ROOT, db_shot_record.shotname)) # 임시 디렉터리에 파일이 존재하면 복사하지 않게 한다. new_resolution_files = glob("%s/*" % tmp_resolution_dir) # 이미 수행되어 있는 경우 다시 복사하지 않게 한다.(퍼블리시 여부로 대체한다.) if len(dpx_files) == len(new_resolution_files): # 하나라도 값이 다르면 수행하지 않게 한다. self.Alert(u"디렉터리 %s는 이미 임시 파일이 있습니다. tmp 디렉터리를 먼저 삭제하셔야 합니다" % db_shot_record.shotname) continue #return False util.fileCopy(dpx_files, tmp_resolution_dir) # 임시 디렉터리로 복사가 완료되었으면 이름을 변경후 Nuke를 사용하여 # 썸네일 및 MOV파일을 만들어넣고 seq 폴더로 데이터를 옮긴다. if 0 == len(db_shot_record.type.strip()): # Type이 비어있는 값이면... util.changesetRecord(db_shot_record, "type", "org") newShotStereo = db_shot_record.isstereo.strip().lower() publish_dir = path_join("/", "show", const.PROJECT, "seq") # Seq, SeqNumDir, TypeDirectory, ResolutionDir, ResolutionHalfDir, ThumbnailDir SeqDir = path_join(publish_dir, db_shot_record.seq) SeqNumDir = path_join(SeqDir, "%s_%s" % (db_shot_record.seq, db_shot_record.shotnumber)) # Rule : 김희경_110804_Rule if "myWay" == const.PROJECT: SeqNumDir = path_join(SeqDir, db_shot_record.shotnumber) TypeDirectory = path_join(SeqNumDir, "plate", db_shot_record.type) # Resolution Dir Create ResolutionDir = path_join(TypeDirectory, "%dx%d" % (ShotMaxWidth, ShotMaxHeight)) ResolutionHalfDir = path_join(TypeDirectory, "%dx%d" % (ShotMaxWidth / 2, ShotMaxHeight / 2)) ThumbnailDir = path_join(TypeDirectory, "thumbnail") # 비어있는 디렉터리가 있으면 생성시킨다. for item in (SeqDir, SeqNumDir, TypeDirectory, ResolutionDir, ResolutionHalfDir, ThumbnailDir): if not exists(item): makedirs(item) ################################################################ # File Renaming Rules Define # # (선결조건 : 이름이 먼저 변경되어 있어야 함)여기에서 우선 tmp/샷네임 # 디렉터리 안에서 이름을 교체하고 썸네일과 하프 사이즈를 생성할 수 있는 # .nk, .alf 파일을 각각 만들고 os.system 메소드로 실행한다. ################################################################ stereo_type = {"l" : "_left", "r" : "_right"} dpx_files = glob("%s/*" % tmp_resolution_dir) dpx_files.sort() # 정상적인 썸네일 및 영상 파일을 만들기 위해서... start_frame_number = 101 movie_src_rename_files = dict() for dpx_item in dpx_files: movie_src_file_ext = splitext(dpx_item) # 다양한 영상 소스에 대한 대응을 하기 위해서임 # New Fille Name Dictionaries new_file_name = util.NewShotNameDict() new_file_name["SEQ"] = "%s_" % db_shot_record.seq new_file_name["SHOT_NUMBER"] = "%s_" % db_shot_record.shotnumber new_file_name["TYPE"] = "plate_%s_" % db_shot_record.type new_file_name["WIDTH"] = "%dx" % ShotMaxWidth new_file_name["HEIGHT"] = "%d" % ShotMaxHeight new_file_name["STEREO"] = "%s." % stereo_type.get(db_shot_record.isstereo, '') new_file_name["FRAME"] = "%s." % str(start_frame_number).zfill(4) new_file_name["EXT"] = "%s" % movie_src_file_ext[1][1:] # 샷 타입이 org인 경우 _plate_org를 파일 이름과 스파르타 등록네임에서 빼달라는 박성진 코디 요청 있었음 # 메일을 받았을 당시 참조 메일 없었으니 이것으로 생기는 혼선에 대해선 박성진 코디네이터에게 책임이 있음 # 2012.2.20 19:32 이상호([email protected]) if db_shot_record.type == "org": del new_file_name["TYPE"] new_file_name = "".join(new_file_name.values()) # Myway Rule # Rule Name : 김희경_110804_Rule if "myWay" == const.PROJECT: del new_file_name["SEQ"] new_file_name = "".join(new_file_name.values()) # 영상 소스 파일 이름 변경 util.fileRename(dpx_item, path_join(tmp_resolution_dir, new_file_name)) start_frame_number += 1 del new_file_name # Thumbnail 파일 생성을 위해서 tmp_resolution_dir의 내용을 리스트로 담아두고 썸네일을 생성할 때 # 사용하게 한다.(디렉토리 경로는 미리 변경해두어야 한다.) dpx_files = glob("%s/*" % tmp_resolution_dir) dpx_files.sort() # 정상적인 썸네일 및 영상 파일을 만들기 위해서... ################################################################ # 이제 파일을 복사한다. ################################################################ new_shot_name = util.NewShotNameDict() new_shot_name["SEQ"] = "%s_" % db_shot_record.seq new_shot_name["SHOT_NUMBER"] = "%s_" % db_shot_record.shotnumber new_shot_name["TYPE"] = "plate_%s_" % db_shot_record.type new_shot_name["WIDTH"] = "%dx" % int(db_shot_record.width) new_shot_name["HEIGHT"] = "%d" % int(db_shot_record.height) new_shot_name["STEREO"] = "%s" % stereo_type.get(db_shot_record.isstereo, '') # New Shot Name # 마이웨이 프로젝트인 경우 newShotName도 형식이 달라져야 한다. # Rule Name : 김희경_110804_Rule if db_shot_record.type == "org": # (박성진 코디네이터 요청. 2012/02/20) del new_shot_name["TYPE"] # 기본 모드 newShotName = "".join(new_shot_name.values()) if "myWay" == const.PROJECT: del new_shot_name["SEQ"] newShotName = "".join(new_shot_name.values()) util.tmpPathToDestPath.tmp_path = tmp_shot_directory util.tmpPathToDestPath.dst_path = TypeDirectory # 디렉터리 경로를 임시 변환하게 하기 위하여 map을 호출하여 임시 경로를 새 경로로 # 변경하게 한다. dpx_files = map(util.tmpPathToDestPath, dpx_files) middle_frame = len(dpx_files) / 2 # Thumbnail File Name(Half, Thumbnail) Thumbnail_FileName = "%s.jpg" % splitext(basename(dpx_files[middle_frame]))[0] newFrameInfo = util.getNewFrame(tmp_resolution_dir) if exists(tmp_shot_directory): # 이동할 리스트를 생성한다. copy_list = glob("%s/*/*" % tmp_shot_directory) # 실제 파일을 move 시킨다. util.fileMove(copy_list, TypeDirectory) self.writePublishInfo( path_join(TypeDirectory, "%s.mov" % newShotName), path_join(ThumbnailDir, Thumbnail_FileName), ResolutionDir, newFrameInfo, db_shot_record ) # DB에도 정보가 기록이 완료되면 tmp 디렉터리도 삭제한다. rmtree(tmp_shot_directory) ################################################################ # 썸네일과 MOV 생성(MOV는 Nuke Run) ################################################################ # nuke, alfredo 스크립트 파일과 임시 MOV를 생성하게 위한 디렉터리를 생성한다. # alf, nk 파일 보관용 tmp_mov_directory = path_join(TypeDirectory, ".%.2f" % time.time()) if not exists(tmp_mov_directory): makedirs(tmp_mov_directory) # Half Image, Thumbnail Image # (스테레오 샷은 스파르타 업로드 시 걸러지므로 여기에선 스테레오 여부를 무시하고 썸네일을 생성하게 한다) JpegNuke = path_join(tmp_mov_directory, "%s_jpeg.nk" % newShotName) MovNuke = path_join(tmp_mov_directory, "%s_mov.nk" % newShotName) thumb_fd = open(const.watch_thumb_file, "a") thumb_fd.write("%s\t%s\t%s\t%s\n" % (thumbnail_width, thumbnail_height, dpx_files[middle_frame], path_join(ThumbnailDir, Thumbnail_FileName))) thumb_fd.close() time.sleep(1) # 영상 소스의 확장자 얻어오기 movie_src_ext = splitext(dpx_files[0])[1] # [MOV] 생성하기(Jpeg 생성, MOV 생성) nuke_helper.nuke_run( path_join(ResolutionDir, "%s.%%04d%s" % (newShotName, movie_src_ext)), db_shot_record.clipname, newShotName, 1024, # 확인용 720, # 확인용 '%d-%d' % (newFrameInfo["START"], newFrameInfo["END"]), path_join(tmp_mov_directory, "%s.%%04d.jpg" % newShotName), JpegNuke, path_join("/local", "%s.mov" % newShotName), True, MovNuke ) MovAlfred = tractor_script.tractorSubmission( ( '<ScanDataTransfer> MOV - %s' % newShotName, newFrameInfo["START"], newFrameInfo["END"], JpegNuke, '/bin/mv %s %s' % ( path_join("/local", "%s.mov" % newShotName), path_join(TypeDirectory, "%s.mov" % newShotName) ), MovNuke, tmp_mov_directory, path_join(TypeDirectory, "._%s.mov" % newShotName) ), True) open(path_join(tmp_mov_directory, "%s.alf" % newShotName), "w").write(MovAlfred) # AlfredRunning tractor_script.tractor_running(path_join(tmp_mov_directory, "%s.alf" % newShotName)) self.datastore.shotSave(db_shot_record) gui_util.updateProjectShots(self.datastore) self.Alert("Publish가 모두 완료되었습니다.")
def cbPrjDateChange(self, combobox, user_param1): if combobox.get_active_text() == u"스캔 데이터가 없습니다": return False scan_root_path = path_join("/", "show", const.PROJECT, "product", "scan", combobox.get_active_text()) const.SCAN_DATE = combobox.get_active_text() const.SCAN_ROOT = scan_root_path ListStore.projShotStore.clear() # Scan Shot List Output if self.projScanRootDirs == None: shot_lists = glob( path_join(const.SCAN_ROOT, "*") ) shot_lists.sort() self.projScanRootDirs = shot_lists # Djv Info 객체 생성 djv_info = DjvInfo( const.SCAN_ROOT ) for item in self.projScanRootDirs: if isdir(item) and basename(item) not in ("tmp", "mov"): print "item", item # ScanRoot안에 0개의 파일을 가진 디렉터리가 존재하면 리스트에 추가할 수 없으므로 루프를 반복시킨다. if 0 == len( glob("%s/*" % item) ): continue # 디렉터리 안에 unknown.txt가 있으면 작업하지 않게 한다. if exists(path_join(item, "unknown.txt")): continue djv_information = {} djv_files_size = None orginalFrameInfo = {} seq_count = 0 # 샷의 정보가 DB에 있는지 먼저 확인해서 있으면 아래 과정을 반복하게 하지 않는다.(정말 오래 걸린다. 용량을 산정하기 때문에..) db_shot_record = self.store.getShotFromName(basename(item)).first() if None == db_shot_record: djv_information = djv_info.retrieveInfo(item) djv_files_size = util.approximate_size(djv_info.total_size(item), False) orginalFrameInfo = util.getOriginalFrame(basename(item)) seq_count = len(glob(path_join(const.SCAN_ROOT, item, "*"))) else: djv_information['Start'] = db_shot_record.starttime or '' djv_information['End'] = db_shot_record.endtime or '' djv_information['Duration'] = db_shot_record.duration or '' djv_information['Speed'] = db_shot_record.fps or '' djv_information['Width'] = db_shot_record.width or '' djv_information['Height'] = db_shot_record.height or '' djv_information['Aspect'] = db_shot_record.ratio or '' orginalFrameInfo['START'] = db_shot_record.originalstartframe or '' orginalFrameInfo['END'] = db_shot_record.originalendframe or '' orginalFrameInfo['EXT'] = db_shot_record.fileformat or '' seq_count = db_shot_record.seqcount or 0 print "djv:", djv_information ListStore.projShotStore.append( row=[ None, basename(item), '', # new seq '', # new seq num '', # type '', # stereo False, # publish int(orginalFrameInfo["START"]), # original start frame int(orginalFrameInfo["END"]), # original end frame 0, # start handle 0, # end handle 0, # new start frmae 0, # new end frame djv_information['Start'], djv_information['End'], djv_information['Duration'], djv_information['Speed'], int(djv_information['Width']), int(djv_information['Height']), djv_information['Aspect'], orginalFrameInfo["EXT"], # format djv_files_size, int(seq_count), 'N' ] ) gui_util.makeDBList(self.store) ## XML File이 있을 경우 Migration xml_file = path_join(scan_root_path, "scan_%s_list.xml" % const.SCAN_DATE) if exists(xml_file): self.ExcelMigration(xml_file) gui_util.updateProjectShots(self.store)