aeidon/agents/preview.py¶
Source code for module aeidon.agents.preview from file aeidon/agents/preview.py.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | # -*- coding: utf-8 -*-
# Copyright (C) 2005 Osmo Salomaa
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Previewing subtitles with a video player."""
import aeidon
import mimetypes
import os
import string
class PreviewAgent(aeidon.Delegate):
"""Previewing subtitles with a video player."""
def __init__(self, master):
"""Initialize a :class:`aeidon.PreviewAgent` instance."""
aeidon.Delegate.__init__(self, master)
aeidon.util.connect(self, self, "notify::main_file")
@aeidon.deco.export
def find_video(self):
"""
Find and return the video file path based on main file's path.
The video file is searched for in the same directory as the subtitle
file. The subtitle file's filename without extension is assumed to
start with or match the video file's filename without extension,
e.g. 'movie.avi' for 'movie.en.srt'.
"""
if self.main_file is None: return None
dirname = os.path.dirname(self.main_file.path)
subname = os.path.basename(self.main_file.path)
for name in os.listdir(dirname):
path = os.path.join(dirname, name)
root = os.path.splitext(name)[0]
if not subname.startswith(root): continue
type, encoding = mimetypes.guess_type(path)
if type and type.startswith("video/"):
self.video_path = path
return self.video_path
return None
def _get_subtitle_path(self, doc, encoding=None, temp=False):
"""
Return path to a file to preview, either real or temporary.
Raise :exc:`IOError` if writing to temporary file fails.
Raise :exc:`UnicodeError` if encoding temporary file fails.
"""
file = self.get_file(doc)
if file is None or encoding != file.encoding:
return self.new_temp_file(doc)
if doc == aeidon.documents.MAIN:
if not self.main_changed and not temp:
return self.main_file.path
if doc == aeidon.documents.TRAN:
if not self.tran_changed and not temp:
return self.tran_file.path
return self.new_temp_file(doc)
def _on_notify_main_file(self, *args):
"""Try to find the video file path if unset."""
if not self.video_path:
self.find_video()
@aeidon.deco.export
def preview(self, position, doc, command, offset, encoding=None, temp=False):
"""
Start video player with `command` from `position`.
`command` can have variables ``$MILLISECONDS``, ``$SECONDS``,
``$SUBFILE`` and ``$VIDEOFILE``. `offset` should be the amount
of seconds before `position` to start. `encoding` can be specified
if different from `doc` file encoding. Use ``True`` for `temp` to
always use a temporary file for preview regardless of whether
the file is changed or not.
Return a three tuple of :class:`subprocess.POpen` instance, command
with variables expanded and a file object to which process standard
output and standard error are directed.
Raise :exc:`IOError` if writing to temporary file fails.
Raise :exc:`UnicodeError` if encoding temporary file fails.
Raise :exc:`aeidon.ProcessError` if unable to start process.
"""
sub_path = self._get_subtitle_path(doc, encoding, temp=temp)
output_path = aeidon.temp.create(".output")
fout = open(output_path, "w")
seconds = max(0, self.calc.to_seconds(position) - offset)
command = string.Template(command).safe_substitute(
MILLISECONDS=("{:.0f}".format(seconds*1000)),
SECONDS=("{:.3f}".format(seconds)),
SUBFILE=aeidon.util.shell_quote(sub_path),
VIDEOFILE=aeidon.util.shell_quote(self.video_path))
process = aeidon.util.start_process(command, stderr=fout, stdout=fout)
return process, command, fout
|