mirror of
https://github.com/gosticks/flashcards-obsidian.git
synced 2025-10-16 12:05:33 +00:00
Improve speed of the image calls and fix bug with the generated image links in Anki
This commit is contained in:
parent
0d7af53bd8
commit
27064e26d9
16
main.ts
16
main.ts
@ -58,14 +58,14 @@ export default class ObsidianFlashcard extends Plugin {
|
||||
|
||||
this.addCommand({
|
||||
id: "anki-test", name: "Anki", callback: () => {
|
||||
let anki: Anki = new Anki()
|
||||
anki.storeMedia(this.app.vault).then(res => {
|
||||
console.log("ok")
|
||||
console.log(res)
|
||||
}).catch(err => {
|
||||
console.log("err")
|
||||
console.log(err)
|
||||
})
|
||||
// let anki: Anki = new Anki()
|
||||
// anki.storeMedia(this.app.vault).then(res => {
|
||||
// console.log("ok")
|
||||
// console.log(res)
|
||||
// }).catch(err => {
|
||||
// console.log("err")
|
||||
// console.log(err)
|
||||
// })
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ import { Parser } from 'src/parser'
|
||||
import { Settings } from 'src/settings'
|
||||
import { Card } from 'src/entities/card'
|
||||
import { Flashcard } from 'src/entities/flashcard'
|
||||
import { arrayBufferToBase64 } from "src/utils"
|
||||
|
||||
export class CardsService {
|
||||
// TODO right now you do not check for cards that when inserted/updated gives back null as ID
|
||||
@ -27,7 +28,6 @@ export class CardsService {
|
||||
|
||||
public async execute(activeFile: TFile): Promise<string[]> {
|
||||
// TODO add note-type to Anki
|
||||
// TODO check media problem
|
||||
try {
|
||||
await this.anki.ping()
|
||||
} catch (err) {
|
||||
@ -60,16 +60,7 @@ export class CardsService {
|
||||
let [cardsToCreate, cardsToUpdate] = this.filterByUpdate(ankiCards, cards)
|
||||
let cardsToDelete: number[] = this.parser.getCardsToDelete(this.file)
|
||||
|
||||
try {
|
||||
// Currently the media are created for every run, this is not a problem since Anki APIs overwrite the file
|
||||
// A more efficient way would be to keep track of the medias saved
|
||||
await this.generateMediaLinks(cards)
|
||||
await this.anki.storeMediaFiles(cards)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
Error("Error: Could not upload medias")
|
||||
}
|
||||
|
||||
this.insertMedias(cards)
|
||||
await this.deleteCardsOnAnki(cardsToDelete, ankiBlocks)
|
||||
await this.updateCardsOnAnki(cardsToUpdate)
|
||||
await this.insertCardsOnAnki(cardsToCreate, frontmatter, deckName)
|
||||
@ -94,14 +85,16 @@ export class CardsService {
|
||||
}
|
||||
}
|
||||
|
||||
private arrayBufferToBase64(buffer: ArrayBuffer): string {
|
||||
var binary = '';
|
||||
var bytes = new Uint8Array(buffer);
|
||||
var len = bytes.byteLength;
|
||||
for (var i = 0; i < len; i++) {
|
||||
binary += String.fromCharCode(bytes[i]);
|
||||
private async insertMedias(cards: Card[]) {
|
||||
try {
|
||||
// Currently the media are created for every run, this is not a problem since Anki APIs overwrite the file
|
||||
// A more efficient way would be to keep track of the medias saved
|
||||
await this.generateMediaLinks(cards)
|
||||
await this.anki.storeMediaFiles(cards)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
Error("Error: Could not upload medias")
|
||||
}
|
||||
return window.btoa(binary);
|
||||
}
|
||||
|
||||
private async generateMediaLinks(cards: Card[]) {
|
||||
@ -114,7 +107,7 @@ export class CardsService {
|
||||
let file: TFile = this.app.vault.getAbstractFileByPath(attachmentsPath + "/" + media) as TFile
|
||||
try {
|
||||
let binaryMedia = await this.app.vault.readBinary(file)
|
||||
card.mediaBase64Encoded.push(this.arrayBufferToBase64(binaryMedia))
|
||||
card.mediaBase64Encoded.push(arrayBufferToBase64(binaryMedia))
|
||||
} catch (err) {
|
||||
Error("Error: Could not read media")
|
||||
}
|
||||
@ -231,7 +224,6 @@ export class CardsService {
|
||||
|
||||
private getAnkiIDs(blocks: RegExpMatchArray[]): number[] {
|
||||
let IDs: number[] = []
|
||||
|
||||
for (let b of blocks) {
|
||||
IDs.push(Number(b[1]))
|
||||
}
|
||||
@ -260,7 +252,6 @@ export class CardsService {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log("No cards in Anki, I am going to create all of them")
|
||||
cardsToCreate = [...generatedCards]
|
||||
}
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ import { Spaced } from "./entities/spaced"
|
||||
import { Cloze } from './entities/cloze';
|
||||
import { Settings } from 'src/settings';
|
||||
import * as showdown from 'showdown';
|
||||
|
||||
import { wikiImageLinks, markdownImageLinks } from "src/utils";
|
||||
|
||||
export class Parser {
|
||||
private settings: Settings
|
||||
@ -65,7 +65,7 @@ export class Parser {
|
||||
|
||||
public getCardsToDelete(file: string): number[] {
|
||||
// Find block IDs with no content above it
|
||||
let regex: RegExp = /^\s*(?:\n)(?:\^(\d{13}))(?:\n\s*?)?/gm
|
||||
const regex: RegExp = /^\s*(?:\n)(?:\^(\d{13}))(?:\n\s*?)?/gm
|
||||
return [...file.matchAll(regex)].map((match) => { return Number(match[1]) })
|
||||
}
|
||||
|
||||
@ -79,24 +79,26 @@ export class Parser {
|
||||
|
||||
if (contextAware) {
|
||||
// https://regex101.com/r/agSp9X/4
|
||||
headings = [...file.matchAll(/^ {0,3}(#{1,6}) +([^\n]+?) ?((?: *#\S+)*) *$/gim)]
|
||||
const headingsRegex = /^ {0,3}(#{1,6}) +([^\n]+?) ?((?: *#\S+)*) *$/gim
|
||||
headings = [...file.matchAll(headingsRegex)]
|
||||
}
|
||||
|
||||
for (let match of matches) {
|
||||
let reversed: boolean = match[3].trim().toLowerCase() === "#flashcard-reverse"
|
||||
let headingLevel = match[1].trim().length !== 0 ? match[1].length : -1
|
||||
// Match.index - 1 because otherwise in the context there will be even match[1], i.e. the question
|
||||
// Match.index - 1 because otherwise in the context there will be even match[1], i.e. the question itself
|
||||
let context = contextAware ? this.getContext(headings, match.index - 1, headingLevel) : ""
|
||||
|
||||
let originalQuestion = match[2].trim()
|
||||
let question = contextAware ? [...context, match[2].trim()].join(`${this.settings.contextSeparator}`) : match[2].trim()
|
||||
let answer = match[5].trim()
|
||||
|
||||
let imagesMedia: string[] = this.substituteImageLinks(question)
|
||||
imagesMedia = imagesMedia.concat(this.substituteImageLinks(answer))
|
||||
|
||||
let imagesMedia: string[] = this.getImageLinks(question)
|
||||
imagesMedia = imagesMedia.concat(this.getImageLinks(answer))
|
||||
question = this.substituteImageLinks(question)
|
||||
answer = this.substituteImageLinks(answer)
|
||||
question = this.mathToAnki(this.htmlConverter.makeHtml(question))
|
||||
answer = this.mathToAnki(this.htmlConverter.makeHtml(answer))
|
||||
|
||||
let endingLine = match.index + match[0].length
|
||||
let tags: string[] = this.parseTags(match[4], globalTags)
|
||||
let id: number = match[6] ? Number(match[6]) : -1
|
||||
@ -110,13 +112,9 @@ export class Parser {
|
||||
return flashcards
|
||||
}
|
||||
|
||||
private substituteImageLinks(str: string): string[] {
|
||||
// Supported images https://publish.obsidian.md/help/How+to/Embed+files
|
||||
let wikiLinks = /!\[\[(.*\.(?:png|jpg|jpeg|gif|bmp|svg|tiff))\]\]/gim
|
||||
let markdownLinks = /!\[\]\((.*\.(?:png|jpg|jpeg|gif|bmp|svg|tiff))\)/gim
|
||||
|
||||
let wikiMatches = str.matchAll(wikiLinks)
|
||||
let markdownMatches = str.matchAll(markdownLinks)
|
||||
private getImageLinks(str: string) {
|
||||
let wikiMatches = str.matchAll(wikiImageLinks)
|
||||
let markdownMatches = str.matchAll(markdownImageLinks)
|
||||
let links: string[] = []
|
||||
|
||||
for (let wikiMatch of wikiMatches) {
|
||||
@ -127,15 +125,16 @@ export class Parser {
|
||||
links.push(decodeURIComponent(markdownMatch[1]))
|
||||
}
|
||||
|
||||
str.replace(wikiLinks, "<img src='$1'>")
|
||||
// TODO markdown link maybe is not correct, it should be decoded (remove the 20%)
|
||||
str.replace(markdownLinks, "<img src='$1'>")
|
||||
|
||||
console.log("Generated links:")
|
||||
console.log(links)
|
||||
return links
|
||||
}
|
||||
|
||||
private substituteImageLinks(str: string): string {
|
||||
str = str.replace(wikiImageLinks, "<img src='$1'>")
|
||||
str = str.replace(markdownImageLinks, "<img src='$1'>")
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
private generateSpacedCards(file: string): Spaced[] {
|
||||
let spaced: Spaced[] = []
|
||||
|
||||
|
||||
13
src/utils.ts
Normal file
13
src/utils.ts
Normal file
@ -0,0 +1,13 @@
|
||||
// Supported images https://publish.obsidian.md/help/How+to/Embed+files
|
||||
export const wikiImageLinks = /!\[\[(.*\.(?:png|jpg|jpeg|gif|bmp|svg|tiff))\]\]/gim
|
||||
export const markdownImageLinks = /!\[\]\((.*\.(?:png|jpg|jpeg|gif|bmp|svg|tiff))\)/gim
|
||||
|
||||
export function arrayBufferToBase64(buffer: ArrayBuffer): string {
|
||||
var binary = '';
|
||||
var bytes = new Uint8Array(buffer);
|
||||
var len = bytes.byteLength;
|
||||
for (var i = 0; i < len; i++) {
|
||||
binary += String.fromCharCode(bytes[i]);
|
||||
}
|
||||
return window.btoa(binary);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user