Add support for video and pictures when adding or updating a note. (#207)
- Sound and video share same [sound:..] tag. See 0c08ff5317/pylib/anki/sound.py (L33)
- Tested and verified picture is added and video is added when `addNote` API.
This commit is contained in:
parent
b03414a8d3
commit
06dff21107
@ -5,11 +5,11 @@
|
|||||||
Creates a note using the given deck and model, with the provided field values and tags. Returns the identifier of
|
Creates a note using the given deck and model, with the provided field values and tags. Returns the identifier of
|
||||||
the created note created on success, and `null` on failure.
|
the created note created on success, and `null` on failure.
|
||||||
|
|
||||||
AnkiConnect can download audio files and embed them in newly created notes. The corresponding `audio` note member is
|
AnkiConnect can download audio, video, and picture files and embed them in newly created notes. The corresponding `audio`, `video`, and `picture` note members are
|
||||||
optional and can be omitted. If you choose to include it, it should contain a single object or an array of objects
|
optional and can be omitted. If you choose to include any of them, they should contain a single object or an array of objects
|
||||||
with mandatory `url` and `filename` fields. The `skipHash` field can be optionally provided to skip the inclusion of
|
with mandatory `url` and `filename` fields. The `skipHash` field can be optionally provided to skip the inclusion of
|
||||||
downloaded files with an MD5 hash that matches the provided value. This is useful for avoiding the saving of error
|
downloaded files with an MD5 hash that matches the provided value. This is useful for avoiding the saving of error
|
||||||
pages and stub files. The `fields` member is a list of fields that should play audio when the card is displayed in
|
pages and stub files. The `fields` member is a list of fields that should play audio or video, or show a picture when the card is displayed in
|
||||||
Anki. The `allowDuplicate` member inside `options` group can be set to true to enable adding duplicate cards.
|
Anki. The `allowDuplicate` member inside `options` group can be set to true to enable adding duplicate cards.
|
||||||
Normally duplicate cards can not be added and trigger exception.
|
Normally duplicate cards can not be added and trigger exception.
|
||||||
|
|
||||||
@ -51,6 +51,22 @@
|
|||||||
"fields": [
|
"fields": [
|
||||||
"Front"
|
"Front"
|
||||||
]
|
]
|
||||||
|
}],
|
||||||
|
"video": [{
|
||||||
|
"url": "https://cdn.videvo.net/videvo_files/video/free/2015-06/small_watermarked/Contador_Glam_preview.mp4",
|
||||||
|
"filename": "countdown.mp4",
|
||||||
|
"skipHash": "4117e8aab0d37534d9c8eac362388bbe",
|
||||||
|
"fields": [
|
||||||
|
"Back"
|
||||||
|
]
|
||||||
|
}],
|
||||||
|
"picture": [{
|
||||||
|
"url": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c7/A_black_cat_named_Tilly.jpg/220px-A_black_cat_named_Tilly.jpg",
|
||||||
|
"filename": "black_cat.jpg",
|
||||||
|
"skipHash": "8d6e4646dfae812bf39651b59d7429ce",
|
||||||
|
"fields": [
|
||||||
|
"Back"
|
||||||
|
]
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,6 +111,22 @@
|
|||||||
"fields": [
|
"fields": [
|
||||||
"Front"
|
"Front"
|
||||||
]
|
]
|
||||||
|
}],
|
||||||
|
"video": [{
|
||||||
|
"url": "https://cdn.videvo.net/videvo_files/video/free/2015-06/small_watermarked/Contador_Glam_preview.mp4",
|
||||||
|
"filename": "countdown.mp4",
|
||||||
|
"skipHash": "4117e8aab0d37534d9c8eac362388bbe",
|
||||||
|
"fields": [
|
||||||
|
"Back"
|
||||||
|
]
|
||||||
|
}],
|
||||||
|
"picture": [{
|
||||||
|
"url": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c7/A_black_cat_named_Tilly.jpg/220px-A_black_cat_named_Tilly.jpg",
|
||||||
|
"filename": "black_cat.jpg",
|
||||||
|
"skipHash": "8d6e4646dfae812bf39651b59d7429ce",
|
||||||
|
"fields": [
|
||||||
|
"Back"
|
||||||
|
]
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -148,8 +180,8 @@
|
|||||||
|
|
||||||
* **updateNoteFields**
|
* **updateNoteFields**
|
||||||
|
|
||||||
Modify the fields of an exist note. You can also include audio files which will be added to the note with an
|
Modify the fields of an exist note. You can also include audio, video, or picture files which will be added to the note with an
|
||||||
optional `audio` property. Please see the documentation for `addNote` for an explanation of objects in the `audio` array.
|
optional `audio`, `video`, or `picture` property. Please see the documentation for `addNote` for an explanation of objects in the `audio`, `video`, or `picture` array.
|
||||||
|
|
||||||
*Sample request*:
|
*Sample request*:
|
||||||
```json
|
```json
|
||||||
|
@ -509,7 +509,13 @@ class AnkiConnect:
|
|||||||
ankiNote = self.createNote(note)
|
ankiNote = self.createNote(note)
|
||||||
|
|
||||||
audioObjectOrList = note.get('audio')
|
audioObjectOrList = note.get('audio')
|
||||||
self.addAudio(ankiNote, audioObjectOrList)
|
self.addMedia(ankiNote, audioObjectOrList, util.MediaType.Audio)
|
||||||
|
|
||||||
|
videoObjectOrList = note.get('video')
|
||||||
|
self.addMedia(ankiNote, videoObjectOrList, util.MediaType.Video)
|
||||||
|
|
||||||
|
pictureObjectOrList = note.get('picture')
|
||||||
|
self.addMedia(ankiNote, pictureObjectOrList, util.MediaType.Picture)
|
||||||
|
|
||||||
collection = self.collection()
|
collection = self.collection()
|
||||||
self.startEditing()
|
self.startEditing()
|
||||||
@ -522,20 +528,20 @@ class AnkiConnect:
|
|||||||
return ankiNote.id
|
return ankiNote.id
|
||||||
|
|
||||||
|
|
||||||
def addAudio(self, ankiNote, audioObjectOrList):
|
def addMedia(self, ankiNote, mediaObjectOrList, mediaType):
|
||||||
if audioObjectOrList is None:
|
if mediaObjectOrList is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
if isinstance(audioObjectOrList, list):
|
if isinstance(mediaObjectOrList, list):
|
||||||
audioList = audioObjectOrList
|
mediaList = mediaObjectOrList
|
||||||
else:
|
else:
|
||||||
audioList = [audioObjectOrList]
|
mediaList = [mediaObjectOrList]
|
||||||
|
|
||||||
for audio in audioList:
|
for media in mediaList:
|
||||||
if audio is not None and len(audio['fields']) > 0:
|
if media is not None and len(media['fields']) > 0:
|
||||||
try:
|
try:
|
||||||
data = util.download(audio['url'])
|
data = util.download(media['url'])
|
||||||
skipHash = audio.get('skipHash')
|
skipHash = media.get('skipHash')
|
||||||
if skipHash is None:
|
if skipHash is None:
|
||||||
skip = False
|
skip = False
|
||||||
else:
|
else:
|
||||||
@ -544,14 +550,17 @@ class AnkiConnect:
|
|||||||
skip = skipHash == m.hexdigest()
|
skip = skipHash == m.hexdigest()
|
||||||
|
|
||||||
if not skip:
|
if not skip:
|
||||||
audioFilename = self.media().writeData(audio['filename'], data)
|
mediaFilename = self.media().writeData(media['filename'], data)
|
||||||
for field in audio['fields']:
|
for field in media['fields']:
|
||||||
if field in ankiNote:
|
if field in ankiNote:
|
||||||
ankiNote[field] += u'[sound:{}]'.format(audioFilename)
|
if mediaType is util.MediaType.Picture:
|
||||||
|
ankiNote[field] += u'<div><img src="{}"><br></div>'.format(mediaFilename)
|
||||||
|
elif mediaType is util.MediaType.Audio or mediaType is util.MediaType.Video:
|
||||||
|
ankiNote[field] += u'[sound:{}]'.format(mediaFilename)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
errorMessage = str(e).replace('&', '&').replace('<', '<').replace('>', '>')
|
errorMessage = str(e).replace('&', '&').replace('<', '<').replace('>', '>')
|
||||||
for field in audio['fields']:
|
for field in media['fields']:
|
||||||
if field in ankiNote:
|
if field in ankiNote:
|
||||||
ankiNote[field] += errorMessage
|
ankiNote[field] += errorMessage
|
||||||
|
|
||||||
@ -575,7 +584,13 @@ class AnkiConnect:
|
|||||||
ankiNote[name] = value
|
ankiNote[name] = value
|
||||||
|
|
||||||
audioObjectOrList = note.get('audio')
|
audioObjectOrList = note.get('audio')
|
||||||
self.addAudio(ankiNote, audioObjectOrList)
|
self.addMedia(ankiNote, audioObjectOrList, util.MediaType.Audio)
|
||||||
|
|
||||||
|
videoObjectOrList = note.get('video')
|
||||||
|
self.addMedia(ankiNote, videoObjectOrList, util.MediaType.Video)
|
||||||
|
|
||||||
|
pictureObjectOrList = note.get('picture')
|
||||||
|
self.addMedia(ankiNote, pictureObjectOrList, util.MediaType.Picture)
|
||||||
|
|
||||||
ankiNote.flush()
|
ankiNote.flush()
|
||||||
|
|
||||||
|
@ -18,12 +18,17 @@ import os
|
|||||||
import anki
|
import anki
|
||||||
import anki.sync
|
import anki.sync
|
||||||
import aqt
|
import aqt
|
||||||
|
import enum
|
||||||
|
|
||||||
#
|
#
|
||||||
# Utilities
|
# Utilities
|
||||||
#
|
#
|
||||||
|
|
||||||
|
class MediaType (enum.Enum):
|
||||||
|
Audio = 1
|
||||||
|
Video = 2
|
||||||
|
Picture = 3
|
||||||
|
|
||||||
def download(url):
|
def download(url):
|
||||||
client = anki.sync.AnkiRequestsClient()
|
client = anki.sync.AnkiRequestsClient()
|
||||||
client.timeout = setting('webTimeout') / 1000
|
client.timeout = setting('webTimeout') / 1000
|
||||||
|
Loading…
Reference in New Issue
Block a user