kerrickstaley / genanki

A Python 3 library for generating Anki decks
MIT License
2.06k stars 161 forks source link

Not packaging mp3 media #46

Closed SimonMerrett closed 4 years ago

SimonMerrett commented 4 years ago

Firstly would like to thank you for making this @kerrickstaley ! My application is making Anki cards for children learning spellings, now that the schools are closing for COVID-19 in UK. I have audio files named after each word to be learned in the folder where my .py file is (using Pycharm).

When I package up and then import to Anki, I can't get the audio files to play unless I manually find the collection.media folder in the Anki2 appdata folder (on Win10). When I unzip the Anki package in 7Zip and open the media file, the only contents are {}, so I currently think this is a packaging issue.

My code is below. The whole thing works really well when I manually add the media files but from the readme.md section on adding media, it seems they should be packaged for import too. Thanks for any insight you can offer - this will help so many people if I can get it to work (making all the spelling lists automatically into Anki cards using Text to Speech and genanki)!


#read the file into a list of words
lines_list = open('file.txt').read().splitlines()

# declare the Deck and give it a name and unique ID number
my_deck = genanki.Deck(
  2759406110,
  'Test Deck')

# Declare the Model to be used (sets the format for the cards)
my_model = genanki.Model(
  1607792720,
  'Basic (type in the answer)',
  fields=[  # These fields need to match up with the field names used inside the `Template` section below
    {'name': 'Front'},
    {'name': 'Back'},
  ],
  templates=[  # {{type:Back}} is what prompts Anki to put the box in the card for text input for your answer. Anki compares and shows a "diff" against the real answer
    {
      'name': 'Card 1',
      'qfmt': '{{Front}} {{type:Back}}',  # Question Format?
      'afmt': '{{Front}}<hr id="answer">{{type:Back}}',  # Answer Format? `Frontside` can be used instead of 'Front' if you want to display the whole front as well as the back, but this can lead to repetition
    },
  ])

mediaList = []  # declare a list to hold the names of all our media files
for l in lines_list:
    mediaName = l + '.mp3'  # generate the file name for the audio file from the word in the list
    mediaList.append(l + '.mp3')  # append the name of each media file to the list
    soundName = '[sound:' + mediaName + ']'
    print(soundName)

    my_note = genanki.Note(
      model=my_model,
      fields=[soundName , l])

    my_deck.add_note(my_note)

print(mediaList)  # show the list for debug purposes

my_package = genanki.Package(my_deck)
my_package.media_files = mediaList # Contains the list of all our media files. May need to experiment with and without square braces here
#my_package.media_files = ['actual.mp3','bicycle.mp3','business.mp3']

genanki.Package(my_deck).write_to_file('test_output.apkg')
SimonMerrett commented 4 years ago

This is definitely the part that is failing outzip.writestr('media', json.dumps(media_json)) I can import os and json etc into my python file and successfully print(json.dumps(media_json)). I can also unzip the Anki package media file and verify that outzip.writestr('media', 'test string') works. Does anyone have any thoughts on why the outzip.writestr() could be failing when combined with json.dumps? I see no errors in my console...

Geocali commented 4 years ago

Same problem here The files seem to be included in the .apkg file, because I can see its size increasing, however the files are not loaded into Anki i had to manually copy the files in ~/.local/share/Anki2/User\ 1/collection.media to make it work

SimonMerrett commented 4 years ago

Thanks for confirming @Geocali. Are you using Pycharm or another setup? Would be good to know if that's a common factor to our issue. I managed to use the same workaround as you. The other workaround is to print json.dumps(media_json)) to the console and then use 7zip to edit the media file in the .apkg

Geocali commented 4 years ago

I am using python 3.6 in linux

Geocali commented 4 years ago

In fact, the files are indeed packaged into the .apkg, but their names are changed to incremented integers (image1.jpg, image2.jpg) => (0.jpg,1.jpg), but the fields and list of media are still using the original names of the files (image1.jpg, image2.jpg) so it doesn't work

SimonMerrett commented 4 years ago

@Geocali thanks. So your error and my error are slightly different. I don't get the files packaged - the media file in the .apkg just containts {} for me. However, when I print the output of json.dumps() the filenames are perfect - no number-name swap. It seems these differences in the manifestation of our errors could be Win/Linux or perhaps more likely Pycharm in Win / Python in Linux, rather than the genanki code itself?

At least with my error I can print out json.dumps(), copy it into the media file and then import the .apkg.

hobofan commented 4 years ago

@SimonMerrett Just ran into the same problem as you, presumably because we copy-pasted to much from the README 😅

genanki.Package(my_deck).write_to_file('test_output.apkg')

should be

my_package.write_to_file('test_output.apkg')
kerrickstaley commented 4 years ago

@SimonMerrett after applying the change @hobofan suggested, your example works fine for me; I can import test_output.apkg into Anki and the MP3s play.

Can you try applying @hobofan's change and also make sure that you're running the latest genanki version (0.8.0)?

SimonMerrett commented 4 years ago

Hooray! Thanks so much @hobofan - it took someone with more knowledge of the language than I have to spot the issue. Totally works for me now.

@kerrickstaley thanks for testing my example with @hobofan's changes.

hxse commented 3 years ago

@kerrickstaley I hope to update the README, because I encountered this issue again today, and I will not solve it until I check the issues.