return s.strip()
def proc_running():
- global proc
- return proc is not None
+ if 'proc' in globals():
+ global proc
+ return proc
def kill_proc(p=None):
if p is None and 'proc' in globals():
global proc
- p = proc
- if p is not None:
- eprint(1, 'killing subprocess: %s' % p.args)
- p.terminate()
+ else:
+ proc = p
+ if proc is not None:
+ eprint(1, 'killing subprocess: %s' % proc.args)
+ proc.terminate()
try:
- p.wait(timeout=3)
+ proc.wait(timeout=3)
except subprocess.TimeoutExpired:
- p.kill()
+ proc.kill()
+ proc = None
return None
def die(rc):
cdirs.append(os.path.join(os.environ.get('HOME'), '.config'))
for d in cdirs:
cf = os.path.join(d, _FFPREVIEW_CFG)
+ if not os.path.exists(cf):
+ eprint(2, 'no such file:', cf, vo=vo)
+ continue
if cls.load_cfgfile(cfg, cf, vo):
cfg['conffile'] = cf
break
for option in fconf.options('Default'):
cfg[option] = fconf.get('Default', option)
except Exception as e:
- eprint(1, str(e), '(config file', fname, 'missing or corrupt)', vo=vo)
+ eprint(1, str(e), '(config file', fname, 'corrupt?)', vo=vo)
return False
eprint(1, 'read config from', fname, vo=vo)
return cls.fixup_cfg(cfg)
for item in self.tree_widget.selectedItems():
if item.vfile:
self.loadfile = item.vfile
- eprint(1, "load file ", item.vfile)
break
super().accept()
fy = fg.y()
fw = fg.width()
fh = fg.height()
- eprint(3, 'w', wx, wy, ww, wh, 'f', fx, fy, fw, fh)
+ eprint(4, 'w', wx, wy, ww, wh, 'f', fx, fy, fw, fh)
# calculate overhead WRT to thumbnail viewport
scpol = self.scroll.verticalScrollBarPolicy()
self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
minw = gw + ow
minh = gh + oh
self.setMinimumSize(minw, minh)
- eprint(3, 'o', ow, oh, 'g', gw, gh, 'c,r', cfg['grid_columns'], cfg['grid_rows'])
+ eprint(4, 'o', ow, oh, 'g', gw, gh, 'c,r', cfg['grid_columns'], cfg['grid_rows'])
# get current available(!) screen geometry
screens = QGuiApplication.screens()
for sc in reversed(screens):
sh = scg.height()
if wx >= sx and wy >= sy and wx < sx+sw and wy < sy+sh:
break
- eprint(3, 's', sx, sy, sw, sh)
+ eprint(4, 's', sx, sy, sw, sh)
# tentative (wanted) window geometry
tx = max(wx, sx)
ty = max(wy, sy)
# available remaining screen estate (right and below)
aw = sw - (tx - sx)
ah = sh - (ty - sy)
- eprint(3, 't', tx, ty, tw, th, 'a', aw, ah)
+ eprint(4, 't', tx, ty, tw, th, 'a', aw, ah)
# try to fit the window on screen, move or resize if necessary
if tw > aw - (fw - ww):
frame_left = (fx + fw) - (wx +ww)
# round down window dimensions to thumb grid
tw = int((tw - ow) / gw) * gw + ow
th = int((th - oh) / gh) * gh + oh
- eprint(3, 't', tx, ty, tw, th)
+ eprint(4, 't', tx, ty, tw, th)
# set final size
self.setGeometry(tx, ty, tw, th)
with open(os.path.join(self.thdir, _FFPREVIEW_IDX), 'r') as idxfile:
idx = json.load(idxfile)
if cfg['verbosity'] > 3:
- eprint(4, 'idx = ' + json.dumps(idx, indent=2))
+ eprint(4, 'idx =', json.dumps(idx, indent=2))
self.show_progress(0, idx['count'])
for th in idx['th']:
if th[0] % 100 == 0:
self.vpath = os.path.dirname(self.fname)
self.thdir = os.path.abspath(os.path.join(cfg['outdir'], self.vfile))
self.setWindowTitle('ffpreview - ' + self.vfile)
+ eprint(1, "open file:", self.fname)
# clear previous view
for sd in self.statdsp:
sd.setText('')
# Helper functions
def proc_cmd(cmd):
- global proc
- if proc:
+ if proc_running():
return '', '', None
+ global proc
retval = 0
try:
- eprint(2, 'run', cmd)
+ eprint(1, 'run:', cmd)
proc = Popen(cmd, shell=False, stdout=PIPE, stderr=PIPE, env=cfg['env'])
stdout, stderr = proc.communicate()
stdout = stdout.decode()
proc = None
if retval != 0:
eprint(0, cmd, '\n returned %d' % retval)
- eprint(1, stderr)
+ eprint(2, stderr)
except Exception as e:
- eprint(0, cmd, '\n failed: ' + str(e))
+ eprint(0, cmd, '\n failed:', str(e))
proc = kill_proc(proc)
return stdout, stderr, retval
# get video meta information
def get_meta(vidfile):
meta = { 'frames': -1, 'duration':-1, 'fps':-1.0, 'nsubs': -1 }
- global proc
- if proc:
+ if proc_running():
return meta, False
# count subtitle streams
cmd = [cfg['ffprobe'], '-v', 'error', '-select_streams', 's',
out, err, rc = proc_cmd(cmd)
if rc == 0:
meta['nsubs'] = len(out.splitlines())
- eprint(2, 'number of subtitle streams:', meta['nsubs'])
+ eprint(1, 'number of subtitle streams:', meta['nsubs'])
# get frames / duration / fps
# try ffprobe fast method
cmd = [cfg['ffprobe'], '-v', 'error', '-select_streams', 'v:0',
meta['duration'] = d
meta['frames'] = f
meta['fps'] = fps
+ eprint(3, 'meta =', meta)
return meta, True
# no dice, try ffprobe slow method
cmd = [cfg['ffprobe'], '-v', 'error', '-select_streams', 'v:0', '-of', 'json', '-count_packets',
d = float(info['format']['duration'])
meta['duration'] = max(d, 0.0001)
meta['fps'] = round(meta['frames'] / meta['duration'], 2)
+ eprint(3, 'meta =', meta)
return meta, True
# ffprobe didn't cut it, try ffmpeg instead
cmd = [cfg['ffmpeg'], '-nostats', '-i', vidfile, '-c:v', 'copy',
d = hms2s(m.group(2))
meta['duration'] = max(d, 0.0001)
meta['fps'] = round(meta['frames'] / meta['duration'], 2)
+ eprint(3, 'meta =', meta)
return meta, True
# not our lucky day, eh?!
return meta, False
cmd.extend( ['-i', vidfile, '-map', '0', '-c', 'copy', '-vn', '-an', '-y', subs_file] )
out, err, rc = proc_cmd(cmd)
if rc == 0:
- eprint(2, 'copied subtitles to:', subs_file)
+ eprint(1, 'copied subtitles to:', subs_file)
return subs_file
except Exception as e:
eprint(0, str(e))
# extract thumbnails from video and collect timestamps
def make_thumbs(vidfile, thinfo, thdir, prog_cb=None):
- global proc
- rc = False
- if proc:
- return thinfo, rc
# prepare command line
pictemplate = '%08d.png'
cmd = [cfg['ffmpeg'], '-loglevel', 'info', '-hide_banner', '-y']
flt += ',subtitles=' + sf + ':si=' + str(thinfo['addss'])
# finalize command line
cmd.extend( ['-vf', flt, '-vsync', 'vfr', os.path.join(thdir, pictemplate)] )
- eprint(2, cmd)
# generate thumbnail images from video
+ rc = False
+ if proc_running():
+ return thinfo, rc
+ global proc
ebuf = ''
cnt = 0
+ eprint(1, 'run:', cmd)
try:
proc = Popen(cmd, shell=False, stderr=PIPE, env=cfg['env'])
while proc.poll() is None:
proc = None
if retval != 0:
eprint(0, cmd, '\n returned %d' % retval)
- eprint(1, ebuf)
+ eprint(2, ebuf)
thinfo['count'] = cnt
with open(os.path.join(thdir, _FFPREVIEW_IDX), 'w') as idxfile:
thinfo['date'] = int(time.time())
try:
pid = os.fork()
if pid > 0:
- eprint(2, '1st fork ok')
+ eprint(3, '1st fork ok')
status = os.waitid(os.P_PID, pid, os.WEXITED)
if status.si_status:
eprint(0, 'child exit error:', status)
else:
- eprint(2, 'child exit ok')
+ eprint(3, 'child exit ok')
return # parent: back to business
except Exception as e:
eprint(0, '1st fork failed:', str(e))
- os._exit(1)
+ return
# child
# become session leader and fork a second time
os.setsid()
try:
pid = os.fork()
if pid > 0:
- eprint(2, '2nd fork ok')
+ eprint(3, '2nd fork ok')
os._exit(0) # child done
except Exception as e:
eprint(0, '2nd fork failed:', str(e))
args = shlex.split(cmd)
for i in range(len(args)):
args[i] = args[i].replace('%t', start).replace('%f', filename)
- if cfg['verbosity'] > 0:
- cstr = ''
- for a in args:
- cstr += "'" + a + "', "
- eprint(1, 'args = [', cstr + ']')
+ eprint(1, 'run:', args)
# close all fds and redirect stdin, stdout and stderr to /dev/null
sys.stdout.flush()
sys.stderr.flush()
entry['idx'] = { 'count': cnt, 'date': int(os.path.getmtime(d)) }
flist.append(entry)
flist = sorted(flist, key=lambda k: k['tdir'])
- if cfg['verbosity'] > 2:
- eprint(3, json.dumps(flist, indent=2))
+ if cfg['verbosity'] > 3:
+ eprint(4, json.dumps(flist, indent=2))
return flist
############################################################