# -*- coding: utf-8 -*-
"""
Fill audio field with [sound:$kana - $kanji.mp3]
and try to download audio from languagepod101.
If no audio available fill with no audio message.
Skips over cards which already have something written
in the audio field.
"""
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import os, urllib, urllib2, shutil, hashlib
from ankiqt import mw, ui
from ankiqt.ui import utils
from anki.cards import Card, Model
# User settings
"""
The name of the model. Other models will be ignored.
"""
MODEL_NAME = 'MasterSentences'
"""
The field which keeps the Kanji.
"""
KANJI_FIELD = 'VocabularyKanji'
"""
The field which keeps the Kana.
"""
KANA_FIELD = 'VocabularyKana'
"""
The field which keeps the audio.
"""
AUDIO_FIELD = 'VocabularyAudio'
"""
Content to fill with if audio is missing.
"""
MISSING_FILL = u'(音無し)'
# Internal settings
audioFileExtension = '.mp3'
downloadedFileExtension = '.php'
base_url = 'http://assets.languagepod101.com/dictionary/japanese/audiomp3.php?'
def downloadSound(kanji, kana, deck, log):
"""
Download audio for given word. If it is not the dummy audio
(check by file size) copy it to the media dir of the deck.
"""
# Determine local file name
target_filename = kana + u' - ' + kanji + u'.mp3'
target_path = os.path.join(deck.mediaDir(create=True), target_filename)
# Check if already present
if os.path.exists(target_path):
return 2
# Download audo file
args = urllib.urlencode({'kana': kana.encode('utf-8'), 'kanji': kanji.encode('utf-8')})
url = base_url + args
(filename, headers) = urllib.urlretrieve(url)
# Check if not dummy audio
size = os.path.getsize(filename)
if(size > 50000):
log.append('No audio for %s' % (kanji))
return 3
# Copy audio file
shutil.copy2(filename, target_path)
return 1
def update_card(deck, card, log):
"""
Update the card by reading kanji/kana, downloading the
audio and updating the audio field.
"""
kanji = card.fact[KANJI_FIELD]
kana = card.fact[KANA_FIELD]
audio = card.fact[AUDIO_FIELD]
# Only update if no audio so far
if audio.strip() == "" or audio.strip() == "<br />":
status = downloadSound(kanji, kana, deck, log)
if status == 1 or status == 2:
newaudio = u"[sound:%s - %s.mp3]" % (kana, kanji)
else:
newaudio = MISSING_FILL
card.fact[AUDIO_FIELD] = newaudio
card.fact.setModified(textChanged=True,deck=deck)
#log.append('Modified card %s[%s].' % (kanji, kana))
return status
else:
#log.append('Did not modify card %s[%s].' % (kanji, kana))
return 0
def get_cards_from_deck(deck, log):
"""
Gets all the card adhering to the model from the specified deck.
"""
sql = 'select id from models where name = \'%s\'' % MODEL_NAME
model_id = deck.s.scalar(sql)
if model_id is None:
log.append('No model of name %s' % MODEL_NAME)
return []
sql = 'select id from cardmodels where modelId = %s' % model_id
card_model_ids = deck.s.column0(sql)
cards = []
for card_model_id in card_model_ids:
cards_query = deck.s.query(Card).filter('cardModelId = %s' % card_model_id)
for card in cards_query:
cards.append(card)
return cards
def process_deck(deck, log):
"""
Processes the cards in the specified deck.
"""
cards = get_cards_from_deck(deck, log)
total = 0
modified = 0
noaudio = 0
for card in cards:
total = total + 1
status = update_card(deck, card, log)
if status > 0:
modified = modified + 1
if status == 3:
noaudio = noaudio + 1
if modified > 0:
deck.s.flush()
deck.setModified()
log.append('Total of %d cards, %d cards modified, no audio for %d cards, %d cards skipped.' % (total, modified, noaudio, total - modified))
def doFill():
"""
Update deck and display log information.
"""
# Check if we have a deck open
if mw.deck is None: return
log = []
log.append('Starting update.')
process_deck(mw.deck, log)
log.append('Update complete.')
utils.showInfo('\n'.join(log))
def init_hook():
"""
Initialises the Anki GUI to present an option to invoke the plugin.
"""
l.append(('Fill audio fields', FillAudioField))
def init():
mw.mainWin.toolBar.addSeparator()
FillAudioField= QAction(mw)
FillAudioField.setText(u"Fill Audio Field")
FillAudioField.setEnabled(True)
mw.connect(FillAudioField,SIGNAL("triggered()"),doFill)
mw.mainWin.toolBar.addAction(FillAudioField)
mw.addHook("init", init)
mw.registerPlugin(u"Fill Audio Field", 666)