Keep cwd and pass dir to player subprocess instead (#1656)

This commit is contained in:
RumovZ 2022-02-11 01:35:48 +01:00 committed by GitHub
parent cc91017bf1
commit 6c8cdc0a0c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 29 additions and 53 deletions

View file

@ -245,7 +245,6 @@ class Collection(DeprecatedNamesMixin):
self._clear_caches() self._clear_caches()
self._backend.close_collection(downgrade_to_schema11=downgrade) self._backend.close_collection(downgrade_to_schema11=downgrade)
self.db = None self.db = None
self.media.close()
def close_for_full_sync(self) -> None: def close_for_full_sync(self) -> None:
# save and cleanup, but backend will take care of collection close # save and cleanup, but backend will take care of collection close
@ -253,7 +252,6 @@ class Collection(DeprecatedNamesMixin):
self.save(trx=False) self.save(trx=False)
self._clear_caches() self._clear_caches()
self.db = None self.db = None
self.media.close()
def rollback(self) -> None: def rollback(self) -> None:
self._clear_caches() self._clear_caches()
@ -285,8 +283,6 @@ class Collection(DeprecatedNamesMixin):
media_db_path=media_db, media_db_path=media_db,
log_path=log_path, log_path=log_path,
) )
else:
self.media.connect()
self.db = DBProxy(weakref.proxy(self._backend)) self.db = DBProxy(weakref.proxy(self._backend))
self.db.begin() self.db.begin()

View file

@ -29,11 +29,6 @@ def media_paths_from_col_path(col_path: str) -> tuple[str, str]:
CheckMediaResponse = media_pb2.CheckMediaResponse CheckMediaResponse = media_pb2.CheckMediaResponse
# fixme: look into whether we can drop chdir() below
# - need to check aa89d06304fecd3597da4565330a3e55bdbb91fe
# - and audio handling code
class MediaManager(DeprecatedNamesMixin): class MediaManager(DeprecatedNamesMixin):
sound_regexps = [r"(?i)(\[sound:(?P<fname>[^]]+)\])"] sound_regexps = [r"(?i)(\[sound:(?P<fname>[^]]+)\])"]
@ -51,45 +46,19 @@ class MediaManager(DeprecatedNamesMixin):
def __init__(self, col: anki.collection.Collection, server: bool) -> None: def __init__(self, col: anki.collection.Collection, server: bool) -> None:
self.col = col.weakref() self.col = col.weakref()
self._dir: str | None = None
if server: if server:
return return
# media directory # media directory
self._dir = media_paths_from_col_path(self.col.path)[0] self._dir = media_paths_from_col_path(self.col.path)[0]
if not os.path.exists(self._dir): if not os.path.exists(self._dir):
os.makedirs(self._dir) os.makedirs(self._dir)
try:
self._oldcwd = os.getcwd()
except OSError:
# cwd doesn't exist
self._oldcwd = None
try:
os.chdir(self._dir)
except OSError as exc:
raise Exception("invalidTempFolder") from exc
def __repr__(self) -> str: def __repr__(self) -> str:
dict_ = dict(self.__dict__) dict_ = dict(self.__dict__)
del dict_["col"] del dict_["col"]
return f"{super().__repr__()} {pprint.pformat(dict_, width=300)}" return f"{super().__repr__()} {pprint.pformat(dict_, width=300)}"
def connect(self) -> None: def dir(self) -> str:
if self.col.server:
return
os.chdir(self._dir)
def close(self) -> None:
if self.col.server:
return
# change cwd back to old location
if self._oldcwd:
try:
os.chdir(self._oldcwd)
except:
# may have been deleted
pass
def dir(self) -> str | None:
return self._dir return self._dir
def force_resync(self) -> None: def force_resync(self) -> None:

View file

@ -192,7 +192,6 @@ class AnkiQt(QMainWindow):
self.setupKeys() self.setupKeys()
self.setupThreads() self.setupThreads()
self.setupMediaServer() self.setupMediaServer()
self.setupSound()
self.setupSpellCheck() self.setupSpellCheck()
self.setupProgress() self.setupProgress()
self.setupStyle() self.setupStyle()
@ -449,6 +448,7 @@ class AnkiQt(QMainWindow):
if not self.loadCollection(): if not self.loadCollection():
return return
self.setup_sound()
self.flags = FlagManager(self) self.flags = FlagManager(self)
# show main window # show main window
if self.pm.profile["mainWindowState"]: if self.pm.profile["mainWindowState"]:
@ -486,6 +486,7 @@ class AnkiQt(QMainWindow):
self.unloadCollection(callback) self.unloadCollection(callback)
def _unloadProfile(self) -> None: def _unloadProfile(self) -> None:
self.cleanup_sound()
saveGeom(self, "mainWindow") saveGeom(self, "mainWindow")
saveState(self, "mainWindow") saveState(self, "mainWindow")
self.pm.save() self.pm.save()
@ -519,8 +520,11 @@ class AnkiQt(QMainWindow):
# Sound/video # Sound/video
########################################################################## ##########################################################################
def setupSound(self) -> None: def setup_sound(self) -> None:
aqt.sound.setup_audio(self.taskman, self.pm.base) aqt.sound.setup_audio(self.taskman, self.pm.base, self.col.media.dir())
def cleanup_sound(self) -> None:
aqt.sound.cleanup_audio()
def _add_play_buttons(self, text: str) -> str: def _add_play_buttons(self, text: str) -> str:
"Return card text with play buttons added, or stripped." "Return card text with play buttons added, or stripped."

View file

@ -3,7 +3,6 @@
from __future__ import annotations from __future__ import annotations
import atexit
import os import os
import platform import platform
import re import re
@ -271,8 +270,9 @@ class SimpleProcessPlayer(Player): # pylint: disable=abstract-method
args: list[str] = [] args: list[str] = []
env: dict[str, str] | None = None env: dict[str, str] | None = None
def __init__(self, taskman: TaskManager) -> None: def __init__(self, taskman: TaskManager, media_folder: str | None = None) -> None:
self._taskman = taskman self._taskman = taskman
self._media_folder = media_folder
self._terminate_flag = False self._terminate_flag = False
self._process: subprocess.Popen | None = None self._process: subprocess.Popen | None = None
self._warned_about_missing_player = False self._warned_about_missing_player = False
@ -292,6 +292,7 @@ class SimpleProcessPlayer(Player): # pylint: disable=abstract-method
self._process = subprocess.Popen( self._process = subprocess.Popen(
self.args + [tag.filename], self.args + [tag.filename],
env=self.env, env=self.env,
cwd=self._media_folder,
stdout=subprocess.DEVNULL, stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
) )
@ -359,8 +360,10 @@ class SimpleMpvPlayer(SimpleProcessPlayer, VideoPlayer):
] ]
) )
def __init__(self, taskman: TaskManager, base_folder: str) -> None: def __init__(
super().__init__(taskman) self, taskman: TaskManager, base_folder: str, media_folder: str
) -> None:
super().__init__(taskman, media_folder)
self.args += [f"--config-dir={base_folder}"] self.args += [f"--config-dir={base_folder}"]
@ -381,7 +384,8 @@ class MpvManager(MPV, SoundOrVideoPlayer):
"--input-media-keys=no", "--input-media-keys=no",
] ]
def __init__(self, base_path: str) -> None: def __init__(self, base_path: str, media_folder: str) -> None:
self.media_folder = media_folder
mpvPath, self.popenEnv = _packagedCmd(["mpv"]) mpvPath, self.popenEnv = _packagedCmd(["mpv"])
self.executable = mpvPath[0] self.executable = mpvPath[0]
self._on_done: OnDoneCallback | None = None self._on_done: OnDoneCallback | None = None
@ -407,7 +411,7 @@ class MpvManager(MPV, SoundOrVideoPlayer):
assert isinstance(tag, SoundOrVideoTag) assert isinstance(tag, SoundOrVideoTag)
self._on_done = on_done self._on_done = on_done
filename = hooks.media_file_filter(tag.filename) filename = hooks.media_file_filter(tag.filename)
path = os.path.join(os.getcwd(), filename) path = os.path.join(self.media_folder, filename)
self.command("loadfile", path, "replace", "pause=no") self.command("loadfile", path, "replace", "pause=no")
gui_hooks.av_player_did_begin_playing(self, tag) gui_hooks.av_player_did_begin_playing(self, tag)
@ -446,8 +450,9 @@ class MpvManager(MPV, SoundOrVideoPlayer):
class SimpleMplayerSlaveModePlayer(SimpleMplayerPlayer): class SimpleMplayerSlaveModePlayer(SimpleMplayerPlayer):
def __init__(self, taskman: TaskManager) -> None: def __init__(self, taskman: TaskManager, media_folder: str) -> None:
super().__init__(taskman) self.media_folder = media_folder
super().__init__(taskman, media_folder)
self.args.append("-slave") self.args.append("-slave")
def _play(self, tag: AVTag) -> None: def _play(self, tag: AVTag) -> None:
@ -458,6 +463,7 @@ class SimpleMplayerSlaveModePlayer(SimpleMplayerPlayer):
self._process = subprocess.Popen( self._process = subprocess.Popen(
self.args + [filename], self.args + [filename],
env=self.env, env=self.env,
cwd=self.media_folder,
stdin=subprocess.PIPE, stdin=subprocess.PIPE,
stdout=subprocess.DEVNULL, stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
@ -819,12 +825,12 @@ def play_clicked_audio(pycmd: str, card: Card) -> None:
########################################################################## ##########################################################################
def setup_audio(taskman: TaskManager, base_folder: str) -> None: def setup_audio(taskman: TaskManager, base_folder: str, media_folder: str) -> None:
# legacy global var # legacy global var
global mpvManager global mpvManager
try: try:
mpvManager = MpvManager(base_folder) mpvManager = MpvManager(base_folder, media_folder)
except FileNotFoundError: except FileNotFoundError:
print("mpv not found, reverting to mplayer") print("mpv not found, reverting to mplayer")
except aqt.mpv.MPVProcessError: except aqt.mpv.MPVProcessError:
@ -834,10 +840,10 @@ def setup_audio(taskman: TaskManager, base_folder: str) -> None:
av_player.players.append(mpvManager) av_player.players.append(mpvManager)
if is_win: if is_win:
mpvPlayer = SimpleMpvPlayer(taskman, base_folder) mpvPlayer = SimpleMpvPlayer(taskman, base_folder, media_folder)
av_player.players.append(mpvPlayer) av_player.players.append(mpvPlayer)
else: else:
mplayer = SimpleMplayerSlaveModePlayer(taskman) mplayer = SimpleMplayerSlaveModePlayer(taskman, media_folder)
av_player.players.append(mplayer) av_player.players.append(mplayer)
# tts support # tts support
@ -857,5 +863,6 @@ def setup_audio(taskman: TaskManager, base_folder: str) -> None:
if int(platform.version().split(".")[-1]) >= 17763: if int(platform.version().split(".")[-1]) >= 17763:
av_player.players.append(WindowsRTTTSFilePlayer(taskman)) av_player.players.append(WindowsRTTTSFilePlayer(taskman))
# cleanup at shutdown
atexit.register(av_player.shutdown) def cleanup_audio() -> None:
av_player.shutdown()