-
Notifications
You must be signed in to change notification settings - Fork 59
/
mhwave.py
164 lines (137 loc) · 5.12 KB
/
mhwave.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
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# -*- mode: Python ; coding: utf-8 -*-
# © 2012–2016 Roland Sieker <ospalh@gmail.com>
#
# License: GNU GPL, version 3 or later;
# http://www.gnu.org/copyleft/gpl.html
u"""Anki 2 add-on that opens an audio editor."""
from PyQt5.QtCore import SIGNAL
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QAction, QMenu
import copy
import os
import re
import subprocess
import sys
from anki.hooks import addHook
from aqt import mw, utils
from aqt.editor import Editor
__version__ = "2.0.0"
sound_re = r'\[sound:(.*?)\]'
command_list = ['mhwaveedit']
sound_ending_list = ['.mp3', '.wav', '.flac', '.ogg']
def sound_ending(fname):
u"""
Return the sound-file-like ending of fname or None.
Check whether fname looks like the name of a sound file and return
the file ending if it does or None if it doesn’t.
"""
for ffts in sound_ending_list:
if fname.lower().endswith(ffts):
return ffts
return None
def edit_files(note=None, text=None):
u"""Edit files of a note or for a given text
Call the audio editor with all sounds from the note, or for a given
text"""
# First, join all fields. Use some random field delimiter. (Could
# be '', i guess.) EAFP, raise stuff when we don't have a note.
if text is None:
try:
text = '@'.join(note.fields)
except AttributeError:
# Maybe we don’t have a note
print('debug: editfiles w/o note')
return
matches = [fn for fn in re.findall(sound_re, text) if sound_ending(fn)]
if command_list and matches:
call_edit(matches)
def call_edit(files):
u"""Start the audio editor to edit files."""
# We don't do the file name fixing. The point of this is to edit
# the files in place.
tmp_edit_list = copy.copy(command_list)
tmp_edit_list.extend(files)
try:
subprocess.Popen(
tmp_edit_list, shell=False, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)
except OSError:
# On Macs, we get ‘Interruppted system call’s. Just
# ignore, like anki’s sound module does.
pass
def which(program):
"""Return path of command."""
def is_exe(fpath):
u"""Return whether fpath points to an executable file."""
return os.path.exists(fpath) and os.access(fpath, os.X_OK)
fpath, dummy_fname = os.path.split(program)
if fpath:
if is_exe(program):
return program
else:
for path in os.environ["PATH"].split(os.pathsep):
exe_file = os.path.join(path, program)
if is_exe(exe_file):
return exe_file
return None
def find_editor():
u"""Try to find the audio editor
Look if we have the audio ediotr. Fix it by adding an .exe on
windows first. Clear the commands when we don't have one.
"""
global command_list
if command_list:
if sys.platform.startswith("win32"):
command_list[0] += '.exe'
if not which(command_list[0]):
# Complain,
warn_string = u'''Audio editor add-on: Could not find {0} \
in path. Please download and install it.'''
utils.showWarning(warn_string.format(command_list[0]))
# and clear the list
command_list = None
return command_list
def edit_current_note():
u"""Call the action to edit the sound files of the current note."""
try:
edit_files(note=mw.reviewer.card.note())
except AttributeError:
# No note.
pass
def edit_from_editor(editor):
u"""Edit audio of the field currently being edited."""
edit_files(text=editor.note.fields[editor.currentField])
def setup_button(editor):
u"""Add the buttons to the editor."""
editor._addButton(
"wave_button", lambda ed=editor: edit_from_editor(ed),
tip=u"wave", text='W')
if find_editor():
# Either reuse an edit-media sub-menu created by another add-on
# (probably by Y.T., notably the download audio add-on) or create
# that menu. When we already have that menu, add a separator,
# otherwise create that menu.
try:
mw.edit_media_submenu.addSeparator()
except AttributeError:
mw.edit_media_submenu = QMenu(u"&Media", mw)
mw.form.menuEdit.addSeparator()
mw.form.menuEdit.addMenu(mw.edit_media_submenu)
# Now add to that menu
mw.edit_audio_fiels_action = QAction(mw)
mw.edit_audio_fiels_action.setText(u"Edit audio")
icons_dir = os.path.join(mw.pm.addonFolder(), 'color_icons')
addHook("setupEditorButtons", setup_button)
try:
# Bad hack. Use the icon brought along from another add-on and
# nicked from the program we use. That program is GPLed, so we
# should be OK with that.
mw.edit_audio_fiels_action.setIcon(
QIcon(os.path.join(icons_dir, 'mhwaveedit.png')))
except:
pass
mw.edit_audio_fiels_action.setToolTip(
"Edit audio files of the current note with mhwave.")
mw.connect(mw.edit_audio_fiels_action, SIGNAL("triggered()"),
edit_current_note)
mw.edit_media_submenu.addAction(mw.edit_audio_fiels_action)