<commit_before>package lila.ublog

import scala.concurrent.duration._
import lila.common.Chronometer
import lila.common.config.NetConfig

final class UblogMarkup(net: NetConfig) {

  private val renderer =
    new lila.common.Markdown(
      autoLink = true,
      list = true,
      strikeThrough = true,
      header = true,
      blockQuote = true,
      code = true,
      table = true
    )

  def apply(post: UblogPost): String =
    cache.get(post.markdown, str => postProcess(renderer(s"ublog:${post.id}")(preProcess(str))))

  private def preProcess = replaceGameGifs.apply _

  private def postProcess = imageParagraph.apply _

  private val cache = lila.memo.CacheApi.scaffeineNoScheduler
    .expireAfterAccess(20 minutes)
    .maximumSize(1024)
    .build[String, String]()

  private object replaceGameGifs {
    val regex = {
      """!\[[^\]]*\]\(""" + net.assetBaseUrl + """/game/export/gif/(white|black)/(\w{8}).gif\)"""
    }.r
    def apply(markdown: String) = regex.replaceAllIn(markdown, net.baseUrl.value + "/$2/$1")
  }

  private object imageParagraph {
    def apply(markup: String) = markup.replace("""<p><img src=""", """<p class="img-container"><img src=""")
  }
}<commit_msg>improve ublog markdown processor and fix game GIF rewrite<commit_after>package lila.ublog

import scala.concurrent.duration._
import lila.common.Chronometer
import lila.common.config.NetConfig

final class UblogMarkup(net: NetConfig) {

  private val renderer =
    new lila.common.Markdown(
      autoLink = true,
      list = true,
      strikeThrough = true,
      header = true,
      blockQuote = true,
      code = true,
      table = true
    )

  type Text = String
  type Html = String

  def apply(post: UblogPost): String =
    cache.get(post.markdown, str => postProcess(renderer(s"ublog:${post.id}")(preProcess(str))))

  private def preProcess = replaceGameGifs.apply _

  private def postProcess(html: String) = imageParagraph(html)

  private val cache = lila.memo.CacheApi.scaffeineNoScheduler
    .maximumSize(2048)
    .build[Text, Html]()

  // replace game GIFs URLs with actual game URLs that can be embedded
  private object replaceGameGifs {
    val regex                 = (net.assetBaseUrl + """/game/export/gif(/white|/black|)/(\w{8})\.gif""").r
    def apply(markdown: Text) = regex.replaceAllIn(markdown, net.baseUrl.value + "/$2$1")
  }

  // put images into a container for styling
  private def imageParagraph(markup: Html) =
    markup.replace("""<p><img src=""", """<p class="img-container"><img src=""")
}
{'fraction_non_alphanumeric': 0.13791748526522593, 'fraction_numerical': 0.006286836935166994, 'mean_word_length': 3.4745166959578206, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4215889', 'n_tokens_mistral': 851, 'n_tokens_neox': 814, 'n_words': 189}