/usr/lib/python3/dist-packages/aeidon/agents/preview.py is in python3-aeidon 0.24.3-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | # -*- coding: utf-8 -*-
# Copyright (C) 2005-2010 Osmo Salomaa
#
# This file is part of Gaupol.
#
# Gaupol 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.
#
# Gaupol 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
# Gaupol. If not, see <http://www.gnu.org/licenses/>.
"""Previewing subtitles with a video player."""
import aeidon
import os
import string
import subprocess
class PreviewAgent(aeidon.Delegate, metaclass=aeidon.Contractual):
"""Previewing subtitles with a video player."""
def __init__(self, master):
"""Initialize a :class:`aeidon.PreviewAgent` object."""
aeidon.Delegate.__init__(self, master)
aeidon.util.connect(self, self, "notify::main_file")
def _get_subtitle_path_require(self, doc, encoding=None, temp=False):
if encoding is not None:
assert aeidon.encodings.is_valid_code(encoding)
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 find_video(self, extensions=None):
"""
Find and return the video file path based on main file's path.
`extensions` should be a sequence of video filename extensions or
``None`` for defaults. 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.
"""
if self.main_file is None: return None
extensions = list(extensions or (
".3ivx", ".asf", ".avi", ".divx", ".flv", ".m2v", ".mkv",
".mov", ".mp4", ".mpeg", ".mpg", ".ogm", ".ogv", ".qt", ".rm",
".rmvb", ".swf", ".vob", ".wmv",
# Keep extensions used by other file types than video at the
# end of the list, so that if there are multiple matches,
# ambiguous extensions would not be the ones chosen.
".ogg", ".dat"))
# Add upper-case versions of all extensions.
extensions = aeidon.util.flatten([[x, x.upper()] for x in extensions])
dirname = os.path.dirname(self.main_file.path)
basename_sub = os.path.basename(self.main_file.path)
rootname_sub = os.path.splitext(basename_sub)[0]
for extension in extensions:
for video_path in os.listdir(dirname):
if not video_path.endswith(extension): continue
basename_video = os.path.basename(video_path)
rootname_video = os.path.splitext(basename_video)[0]
if not rootname_sub.startswith(rootname_video): continue
self.video_path = os.path.join(dirname, basename_video)
return self.video_path
return None
def preview_require(self, *args, **kwargs):
assert self.video_path is not None
def preview_ensure(self, value, *args, **kwargs):
assert os.path.isfile(value[2])
@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, which can be used to take into
account that video players can usually seek only to keyframes, which
exist maybe ten seconds or so apart. `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 process standard output and error path.
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")
output_fd = aeidon.temp.get_handle(output_path)
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=subprocess.STDOUT,
stdout=output_fd)
return process, command, output_path
|