Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5780b614cc | |||
| 9f0c4a6091 | |||
| 3db4341ab2 | |||
| b477677732 | |||
| 70eacd51cc | |||
| dab7e2c2ac | |||
| 8b998b2286 | |||
| 52fe86b1ab | |||
| 58a67a1a75 | |||
| e1e6008a8f | |||
| 34295dd142 | |||
| 95c84c0738 | |||
| 6ec827aa76 | |||
| af162b0148 | |||
| 363e43c87a | |||
| 34082db990 | |||
| 78a1e4af6e | |||
| 030165875c | |||
| b6a79d41f7 | |||
| 2d913311bb | |||
| bdc5faf491 |
@@ -1,11 +1,10 @@
|
||||
# videogrep
|
||||
# Playphrase
|
||||
Search for specific words in srt files and watch with mpv.
|
||||
Inspired by [videogrep](http://lav.io/2014/06/videogrep-automatic-supercuts-with-python/) and [playphrase.me](http://playphrase.me/).
|
||||
|
||||
# Download
|
||||
|
||||
* Windows - [https://github.com/kelciour/playphrase/releases](https://github.com/kelciour/playphrase/releases)
|
||||
* Linux and MacOS - [playphrase-master.zip](https://github.com/kelciour/playphrase/archive/master.zip)
|
||||
See [https://github.com/kelciour/playphrase/releases](https://github.com/kelciour/playphrase/releases)
|
||||
|
||||
# Requirements
|
||||
|
||||
@@ -15,17 +14,22 @@ Inspired by [videogrep](http://lav.io/2014/06/videogrep-automatic-supercuts-with
|
||||
|
||||
# Usage
|
||||
|
||||
Run ```python videogrep.py -i <media_dir> _init_``` to generate txt files from srt files that will be used for search (only the first time or when you add new movies in your folder).
|
||||
Run ```python playphrase.py -i <media_dir> _init_``` to generate txt files from srt files that will be used for search (only the first time or when you add new movies in your folder).
|
||||
|
||||
After that use
|
||||
```python videogrep.py -i <media_dir> <phrase>```
|
||||
```python playphrase.py -i <media_dir> <phrase>```
|
||||
|
||||
### Keyboard Shortcuts
|
||||
Use ```Enter``` to move to the next clip or ```Shift + <``` and ```Shift + >``` to switch between clips, ```q``` to close player and ```f``` to toggle fullscreen.
|
||||
Use ```Enter``` to move to the next clip or ```Shift + <``` and ```Shift + >``` to switch between clips, ```q``` to close player.
|
||||
|
||||
More info: [https://mpv.io/manual/master/#keyboard-control](https://mpv.io/manual/master/#keyboard-control)
|
||||
|
||||
###Additional options:
|
||||
### Batch Scripts
|
||||
|
||||
There's ```.bat``` (Windows) and ```.sh``` (Linux) files to simplify user input. First time before running edit them and update ```media_dir``` path.
|
||||
Use ```quit```, ```exit``` or ```q```, ```x``` to exit from batch script.
|
||||
|
||||
### Additional options:
|
||||
* ```-ph, --phrases GAP_BETWEEN_PHRASES```
|
||||
move start time of the clip to the beginning of the current phrase. Value is optional (default=1.75 seconds)
|
||||
* ```-l, --limit```
|
||||
@@ -43,5 +47,5 @@ only show grep results
|
||||
|
||||
# Note
|
||||
|
||||
* videogrep requires the subtitle track and the video file to have the exact same name, up to the extension.
|
||||
* just re-run your command if there was an error with pipe
|
||||
* playphrase requires the subtitle track and the video file to have the exact same name, up to the extension.
|
||||
* just re-run your command if there was an error with pipe
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
@echo off
|
||||
setlocal EnableDelayedExpansion
|
||||
|
||||
set media_dir="J:\English AudioBooks"
|
||||
|
||||
for /L %%n in (1,0,1) do (
|
||||
set /p phrase="Phrase: "
|
||||
|
||||
if /I "!phrase!"=="q" call :stop
|
||||
if /I "!phrase!"=="x" call :stop
|
||||
if /I "!phrase!"=="quit" call :stop
|
||||
if /I "!phrase!"=="exit" call :stop
|
||||
|
||||
rem Disable album cover art and create a window even if there is no album cover art.
|
||||
rem python playphrase.py --mpv-options "--video=no --force-window=yes --osc=no --title=${filename}" --input %media_dir% "!phrase!"
|
||||
|
||||
python playphrase.py --mpv-options "--sub-font-size=37 --sub-back-color=0.05/0.95 --sub-scale-by-window=no --sub-scale-with-window=no --autofit=620 --osc=no --title=${filename}" --input %media_dir% "!phrase!"
|
||||
)
|
||||
|
||||
:stop
|
||||
call :__stop 2>nul
|
||||
|
||||
:__stop
|
||||
() creates a syntax error, quits the batch
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
media_dir="/media/nickolay/9A043D5E043D3F17/English AudioBooks"
|
||||
|
||||
while true
|
||||
do
|
||||
read -p "Phrase: " -r phrase
|
||||
if [ "$phrase" = "q" ]; then
|
||||
exit 0
|
||||
elif [ "$phrase" = "x" ]; then
|
||||
exit 0
|
||||
elif [ "$phrase" = "quit" ]; then
|
||||
exit 0
|
||||
elif [ "$phrase" = "exit" ]; then
|
||||
exit 0
|
||||
else
|
||||
# Disable album cover art and create a window even if there is no album cover art.
|
||||
# python "playphrase.py" --mpv-options "--video=no --force-window=yes --osc=no --title=${filename}" --input "$media_dir" "$phrase"
|
||||
|
||||
python "playphrase.py" --mpv-options "--sub-font-size=37 --sub-back-color=0.05/0.9 --sub-scale-by-window=no --sub-scale-with-window=no --autofit=620 --osc=no --title=${filename}" --input "$media_dir" "$phrase"
|
||||
fi
|
||||
done
|
||||
@@ -10,7 +10,7 @@ import time
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
movie_extensions = ['mp4', 'avi', 'mkv']
|
||||
movie_extensions = ['mp4', 'avi', 'mkv', 'mp3']
|
||||
srt_encodings = ["utf-8", "cp1251"]
|
||||
|
||||
def srt_time_to_seconds(time):
|
||||
@@ -75,6 +75,7 @@ def convert_into_sentences(en_subs, limit):
|
||||
prev_sub_content[-1] != ']' and
|
||||
prev_sub_content[-1] != ')' and
|
||||
prev_sub_content[-1] != u'♪' and
|
||||
prev_sub_content[-1] != u'”' and
|
||||
prev_sub_content[-1] != '"'):
|
||||
|
||||
subs[-1] = (prev_sub_start, sub_end, prev_sub_content + " " + sub_content)
|
||||
@@ -96,40 +97,63 @@ def write_subtitles(filename, subs):
|
||||
|
||||
f.close()
|
||||
|
||||
def play_clips(clips, ending_mode):
|
||||
def update_mpv_player_cmd(cmd_options, mpv_options):
|
||||
for opt in mpv_options.split():
|
||||
if "=" in opt:
|
||||
key, value = opt.split("=", 1)
|
||||
cmd_options[key] = value
|
||||
else:
|
||||
cmd_options[opt] = True
|
||||
|
||||
cmd = ["mpv"]
|
||||
for opt in cmd_options:
|
||||
if cmd_options[opt] == True:
|
||||
cmd.append(opt)
|
||||
else:
|
||||
cmd.append(opt + "=" + cmd_options[opt])
|
||||
|
||||
return cmd
|
||||
|
||||
def play_clips(clips, ending_mode, mpv_options):
|
||||
if len(clips) != 0:
|
||||
clip_filename, clip_start, clip_end = clips[0]
|
||||
|
||||
pipe_name = "\\\\.\pipe\mpv-pipe"
|
||||
cmd = ["mpv", "--idle=once", "--force-window=no", "--input-ipc-server=%s" % pipe_name]
|
||||
p = subprocess.Popen(cmd, shell=False)
|
||||
pipe_name = "mpv-pipe"
|
||||
|
||||
time.sleep(0.5) # wait 0.5 seconds for pipe has been created
|
||||
mpv_default_options = { "--idle":"once", "--no-terminal":True, "--force-window":"no", "--input-file":pipe_name }
|
||||
|
||||
cmd = update_mpv_player_cmd(mpv_default_options, mpv_options)
|
||||
|
||||
with open(pipe_name, 'w'): # create pipe
|
||||
pass
|
||||
|
||||
p = subprocess.Popen(cmd, shell=False) # start mpv player in idle mode
|
||||
|
||||
if not os.path.isfile(pipe_name):
|
||||
print "Can't open '%s'" % pipe_name
|
||||
return
|
||||
else:
|
||||
with open(pipe_name, "wb", 0) as f_pipe:
|
||||
for clip_filename, clip_start, clip_end in clips:
|
||||
clip_filename = clip_filename.replace("\\","/")
|
||||
|
||||
cmd = ["echo", "loadfile", '"' + clip_filename + '"']
|
||||
cmd = ["loadfile", '"' + clip_filename + '"']
|
||||
if ending_mode:
|
||||
cmd.append("append-play start=%s,end=%s" % (clip_start, clip_end))
|
||||
else:
|
||||
cmd.append("append-play start=%s" % clip_start)
|
||||
|
||||
try:
|
||||
with open(pipe_name, "w") as mpv_pipe:
|
||||
subprocess.call(cmd, stdout=mpv_pipe)
|
||||
if p.poll() == None:
|
||||
f_pipe.write(" ".join(cmd) + "\n")
|
||||
else:
|
||||
break
|
||||
except IOError as ex:
|
||||
print ex
|
||||
p.kill()
|
||||
if ex.errno != 32:
|
||||
print ex
|
||||
if p != None:
|
||||
p.kill()
|
||||
return
|
||||
|
||||
def main(media_dir, search_phrase, phrase_mode, phrases_gap, padding, limit, output_file, ending_mode, randomize_mode, demo_mode):
|
||||
def main(media_dir, search_phrase, phrase_mode, phrases_gap, padding, limit, output_file, ending_mode, randomize_mode, demo_mode, mpv_options):
|
||||
cmd = " ".join(["grep", "-r", "-n", "-i", "--include", "\*.txt", "-P", '"' + search_phrase + '"', '"' + media_dir + '"'])
|
||||
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, bufsize=-1)
|
||||
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True, bufsize=-1)
|
||||
output, error = p.communicate()
|
||||
|
||||
if p.returncode == 0:
|
||||
@@ -228,7 +252,7 @@ def main(media_dir, search_phrase, phrase_mode, phrases_gap, padding, limit, out
|
||||
random.shuffle(clips)
|
||||
|
||||
if not demo_mode:
|
||||
play_clips(clips, ending_mode)
|
||||
play_clips(clips, ending_mode, mpv_options)
|
||||
|
||||
elif p.returncode == 1:
|
||||
print "'%s' is not found in '%s'" % (search_phrase, media_dir)
|
||||
@@ -261,7 +285,7 @@ def convert_to_unicode(file_content):
|
||||
print "ERROR: Unknown encoding. Use srt file with 'utf-8' encoding."
|
||||
return (False, file_content)
|
||||
|
||||
def init(media_dir):
|
||||
def init(media_dir, limit):
|
||||
for root, dirs, files in os.walk(media_dir):
|
||||
for file in files:
|
||||
file_ext = file.split('.')[-1]
|
||||
@@ -279,7 +303,7 @@ def init(media_dir):
|
||||
sys.exit(1)
|
||||
|
||||
subs = read_subtitles(content)
|
||||
subs = convert_into_sentences(subs, 20)
|
||||
subs = convert_into_sentences(subs, limit)
|
||||
|
||||
write_subtitles(file_path[:-4] + ".txt", subs)
|
||||
|
||||
@@ -292,7 +316,7 @@ def parse_args(argv):
|
||||
print "Search phrase can't be empty"
|
||||
sys.exit()
|
||||
|
||||
args = {"padding": 0, "limit": 30, "output_file": None, "phrase_mode": False, "phrases_gap":1.75, "search_phrase":search_phrase, "ending_mode":False, "randomize_mode":False, "demo_mode":False}
|
||||
args = {"padding": 0, "limit": 15, "output_file": None, "phrase_mode": False, "phrases_gap":1.75, "search_phrase":search_phrase, "ending_mode":False, "randomize_mode":False, "demo_mode":False, "mpv_options":""}
|
||||
|
||||
argv = argv[:-1]
|
||||
idx = 0
|
||||
@@ -332,6 +356,11 @@ def parse_args(argv):
|
||||
idx += 1
|
||||
except ValueError:
|
||||
pass
|
||||
elif argv[idx] == "--mpv-options" or argv[idx] == "-m":
|
||||
if idx + 1 >= len(argv):
|
||||
return False
|
||||
args["mpv_options"] = argv[idx + 1]
|
||||
idx += 1
|
||||
else:
|
||||
return False
|
||||
|
||||
@@ -354,6 +383,7 @@ def usage():
|
||||
print "-r, --randomize", "\t", "randomize the clips"
|
||||
print "-o, --output", "\t", "name of the file in which output of \'grep\' command will be written"
|
||||
print "-d, --demo", "\t", "only show grep results"
|
||||
print "-m, --mpv-options OPTIONS", "\t", "mpv player options"
|
||||
|
||||
if __name__ == '__main__':
|
||||
os.environ["PATH"] += os.pathsep + "." + os.sep + "utils" + os.sep + "grep"
|
||||
@@ -362,11 +392,11 @@ if __name__ == '__main__':
|
||||
args = parse_args(sys.argv[1:])
|
||||
if args != False:
|
||||
if args["search_phrase"] == "_init_":
|
||||
init(args["media_dir"])
|
||||
init(args["media_dir"], args["limit"])
|
||||
else:
|
||||
if need_update(args["media_dir"]):
|
||||
print "WARNING: number of '.srt' and '.txt' files doesn't match. Maybe you need to use 'videogrep <media_dir> _init_'."
|
||||
|
||||
main(args["media_dir"], args["search_phrase"], args["phrase_mode"], args["phrases_gap"], args["padding"], args["limit"], args["output_file"], args["ending_mode"], args["randomize_mode"], args["demo_mode"])
|
||||
main(args["media_dir"], args["search_phrase"], args["phrase_mode"], args["phrases_gap"], args["padding"], args["limit"], args["output_file"], args["ending_mode"], args["randomize_mode"], args["demo_mode"], args["mpv_options"])
|
||||
else:
|
||||
usage()
|
||||
@@ -0,0 +1,21 @@
|
||||
@echo off
|
||||
setlocal EnableDelayedExpansion
|
||||
|
||||
set media_dir="J:\English Movies"
|
||||
|
||||
for /L %%n in (1,0,1) do (
|
||||
set /p phrase="Phrase: "
|
||||
|
||||
if /I "!phrase!"=="q" call :stop
|
||||
if /I "!phrase!"=="x" call :stop
|
||||
if /I "!phrase!"=="quit" call :stop
|
||||
if /I "!phrase!"=="exit" call :stop
|
||||
|
||||
python playphrase.py --input %media_dir% "!phrase!"
|
||||
)
|
||||
|
||||
:stop
|
||||
call :__stop 2>nul
|
||||
|
||||
:__stop
|
||||
() creates a syntax error, quits the batch
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
media_dir="/media/nickolay/9A043D5E043D3F17/English Movies"
|
||||
|
||||
while true
|
||||
do
|
||||
read -p "Phrase: " -r phrase
|
||||
if [ "$phrase" = "q" ]; then
|
||||
exit 0
|
||||
elif [ "$phrase" = "x" ]; then
|
||||
exit 0
|
||||
elif [ "$phrase" = "quit" ]; then
|
||||
exit 0
|
||||
elif [ "$phrase" = "exit" ]; then
|
||||
exit 0
|
||||
else
|
||||
python "playphrase.py" --input "$media_dir" "$phrase"
|
||||
fi
|
||||
done
|
||||
Reference in New Issue
Block a user