Skip to content

Commit

Permalink
fix: play tags shown in card browser
Browse files Browse the repository at this point in the history
* [sound:foo.mp3] is now [anki:play:a:0]

fix:
* Define `replaceAvRefsWith` to enable replacements
* pass in TemplateRenderContext so we have a reference to the AvTag
* allow `stripAvRefs` to accept a formatter override

Fixes 14353
  • Loading branch information
david-allison authored and lukstbit committed Jan 22, 2024
1 parent 1a12f1a commit 2c00751
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 22 deletions.
22 changes: 16 additions & 6 deletions AnkiDroid/src/main/java/com/ichi2/anki/CardBrowser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2098,8 +2098,8 @@ open class CardBrowser :
if (a.startsWith(q)) {
a = a.substring(q.length)
}
a = formatQA(a, AnkiDroidApp.instance)
q = formatQA(q, AnkiDroidApp.instance)
a = formatQA(a, qa, AnkiDroidApp.instance)
q = formatQA(q, qa, AnkiDroidApp.instance)
mQa = Pair(q, a)
}

Expand Down Expand Up @@ -2223,10 +2223,14 @@ open class CardBrowser :
fun clearLastDeckId() = SharedPreferencesLastDeckIdRepository.clearLastDeckId()

@CheckResult
private fun formatQA(text: String, context: Context): String {
private fun formatQA(
text: String,
qa: TemplateManager.TemplateRenderContext.TemplateRenderOutput,
context: Context
): String {
val showFilenames =
context.sharedPrefs().getBoolean("card_browser_show_media_filenames", false)
return formatQAInternal(text, showFilenames)
return formatQAInternal(text, qa, showFilenames)
}

/**
Expand All @@ -2236,15 +2240,21 @@ open class CardBrowser :
*/
@VisibleForTesting
@CheckResult
fun formatQAInternal(txt: String, showFileNames: Boolean): String {
fun formatQAInternal(
txt: String,
qa: TemplateManager.TemplateRenderContext.TemplateRenderOutput,
showFileNames: Boolean
): String {
/* Strips all formatting from the string txt for use in displaying question/answer in browser */
var s = txt
s = s.replace("<!--.*?-->".toRegex(), "")
s = s.replace("<br>", " ")
s = s.replace("<br />", " ")
s = s.replace("<div>", " ")
s = s.replace("\n", " ")
s = if (showFileNames) Utils.stripSoundMedia(s) else Utils.stripSoundMedia(s, " ")
// we use " " as often users won't leave a space between the '[sound:] tag
// and continuation of the content
s = if (showFileNames) Sound.replaceWithFileNames(s, qa) else stripAvRefs(s, " ")
s = s.replace("\\[\\[type:[^]]+]]".toRegex(), "")
s = if (showFileNames) Utils.stripHTMLMedia(s) else Utils.stripHTMLMedia(s, " ")
s = s.trim { it <= ' ' }
Expand Down
21 changes: 18 additions & 3 deletions AnkiDroid/src/main/java/com/ichi2/libanki/Sound.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ package com.ichi2.libanki

import anki.config.ConfigKey
import com.ichi2.anki.CollectionManager
import com.ichi2.libanki.TemplateManager.TemplateRenderContext.TemplateRenderOutput
import java.util.regex.Pattern

/**
Expand Down Expand Up @@ -57,7 +58,7 @@ open class AvTag
*/
val SOUND_RE = Pattern.compile("\\[sound:([^\\[\\]]*)]").toRegex()

fun stripAvRefs(text: String) = Sound.AV_REF_RE.replace(text, "")
fun stripAvRefs(text: String, replacement: String = "") = Sound.AV_REF_RE.replace(text, replacement)

// not in libAnki
object Sound {
Expand Down Expand Up @@ -109,7 +110,21 @@ object Sound {
*/
fun replaceWithSoundTags(
content: String,
renderOutput: TemplateManager.TemplateRenderContext.TemplateRenderOutput
renderOutput: TemplateRenderOutput
): String = replaceAvRefsWith(content, renderOutput) { tag -> "[sound:${tag.filename}]" }

/**
* Replaces [anki:play:q:0] with ` example.mp3 `
*/
fun replaceWithFileNames(
content: String,
renderOutput: TemplateRenderOutput
): String = replaceAvRefsWith(content, renderOutput) { tag -> " ${tag.filename} " }

private fun replaceAvRefsWith(
content: String,
renderOutput: TemplateRenderOutput,
processTag: (SoundOrVideoTag) -> String
): String {
return AV_REF_RE.replace(content) { match ->
val groups = match.groupValues
Expand All @@ -124,7 +139,7 @@ object Sound {
if (tag !is SoundOrVideoTag) {
return@replace match.value
} else {
return@replace "[sound:${tag.filename}]"
return@replace processTag(tag)
}
}
}
Expand Down
9 changes: 0 additions & 9 deletions AnkiDroid/src/main/java/com/ichi2/libanki/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ object Utils {
private val scriptPattern = Pattern.compile("(?si)<script.*?>.*?</script>")
private val tagPattern = Pattern.compile("(?s)<.*?>")
private val imgPattern = Pattern.compile("(?i)<img[^>]+src=[\"']?([^\"'>]+)[\"']?[^>]*>")
private val soundPattern = Pattern.compile("(?i)\\[sound:([^]]+)]")
private val htmlEntitiesPattern = Pattern.compile("&#?\\w+;")
private const val ALL_CHARACTERS =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
Expand Down Expand Up @@ -87,14 +86,6 @@ object Utils {
return stripHTML(imgMatcher.replaceAll(replacement))
}

/**
* Strip sound but keep media filenames
*/
fun stripSoundMedia(s: String, replacement: String = " $1 "): String {
val soundMatcher = soundPattern.matcher(s)
return soundMatcher.replaceAll(replacement)
}

/**
* Takes a string and replaces all the HTML symbols in it with their unescaped representation.
* This should only affect substrings of the form `&something;` and not tags.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,22 @@
package com.ichi2.anki

import androidx.annotation.CheckResult
import com.ichi2.libanki.SoundOrVideoTag
import com.ichi2.libanki.TemplateManager.TemplateRenderContext.TemplateRenderOutput
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.equalTo
import org.junit.Test

class CardBrowserNonAndroidTest {
@Test
fun soundIsStrippedCorrectly() {
val output = formatWithFilenamesStripped("aou[sound:foo.mp3]aou")
val output = formatWithFilenamesStripped("aou[anki:play:a:0]aou")
assertThat(output, equalTo("aou aou"))
}

@Test
fun soundIsRetainedWithoutTag() {
val output = formatWithFilenamesRetained("aou[sound:foo.mp3]aou")
val output = formatWithFilenamesRetained("aou[anki:play:a:0]aou")
assertThat(output, equalTo("aou foo.mp3 aou"))
}

Expand All @@ -47,11 +49,33 @@ class CardBrowserNonAndroidTest {

@CheckResult
private fun formatWithFilenamesRetained(input: String): String {
return CardBrowser.formatQAInternal(input, true)
return CardBrowser.formatQAInternal(
input,
TemplateRenderOutput(
questionText = input,
answerText = input,
questionAvTags = listOf(SoundOrVideoTag("foo.mp3")),
answerAvTags = listOf(SoundOrVideoTag("foo.mp3")),
css = ""

),
true
)
}

@CheckResult
private fun formatWithFilenamesStripped(input: String): String {
return CardBrowser.formatQAInternal(input, false)
return CardBrowser.formatQAInternal(
input,
TemplateRenderOutput(
questionText = input,
answerText = input,
questionAvTags = listOf(SoundOrVideoTag("foo.mp3")),
answerAvTags = listOf(SoundOrVideoTag("foo.mp3")),
css = ""

),
false
)
}
}

0 comments on commit 2c00751

Please sign in to comment.