recipe-kt/app/src/main/java/xyz/pixelatedw/recipe/utils/RecipeParser.kt

150 lines
3.3 KiB
Kotlin

package xyz.pixelatedw.recipe.utils
import android.content.Context
import android.net.Uri
import androidx.core.text.trimmedLength
import androidx.documentfile.provider.DocumentFile
import io.github.wasabithumb.jtoml.JToml
import xyz.pixelatedw.recipe.data.AppDatabase
import xyz.pixelatedw.recipe.data.Recipe
import xyz.pixelatedw.recipe.data.RecipeTag
import xyz.pixelatedw.recipe.data.Tag
import java.io.BufferedReader
import java.io.File
import java.io.FileOutputStream
import java.io.InputStreamReader
private val recipeFiles = mutableListOf<DocumentFile>()
fun parseRecipes(ctx: Context, db: AppDatabase, uri: Uri?) {
if (uri == null) {
return
}
val path = ""
val dir = DocumentFile.fromTreeUri(ctx, uri)
if (dir != null) {
parseDir(ctx, dir, path)
for (file in recipeFiles) {
parseRecipe(ctx, db, file)
}
}
}
fun parseDir(ctx: Context, dir: DocumentFile, path: String) {
val fileList: Array<DocumentFile> = dir.listFiles()
for (file in fileList) {
if (file.isDirectory) {
parseDir(ctx, file, path + File.separator + file.name)
continue
}
if (file.isFile && file.name?.endsWith(".jpg") == true) {
val picsDir = File(ctx.filesDir, path)
picsDir.mkdirs()
val newFile = File(picsDir, file.name!!)
ctx.contentResolver.openInputStream(file.uri).use { inStream ->
FileOutputStream(newFile, false).use { outStream ->
inStream?.copyTo(outStream)
}
}
}
if (file.isFile && file.name?.endsWith(".md") == true) {
recipeFiles.add(file)
}
}
}
private fun parseRecipe(ctx: Context, db: AppDatabase, file: DocumentFile) {
val lastModified = file.lastModified()
val inputStream = ctx.contentResolver.openInputStream(file.uri)
val reader = BufferedReader(InputStreamReader(inputStream))
val text = reader.readText()
val hash = text.hashCode() // Probably not the best way but its stable and works
if (db.recipeDao().hasHash(hash)) {
return
}
val lines = text.lines()
val sb = StringBuilder()
var hasToml = false
var frontMatterSize = 0
for (line in lines) {
frontMatterSize += line.trimmedLength() + 1
if (line == "+++") {
if (hasToml) {
break
}
hasToml = true
continue
}
sb.appendLine(line)
}
if (!hasToml) {
reader.close()
return
}
val toml = JToml.jToml()
val doc = toml.readFromString(sb.toString())
if (!doc.contains("title")) {
reader.close()
return
}
val recipeTitle = doc["title"]!!.asPrimitive().asString()
val pics = arrayListOf<String>()
if (doc.contains("pics")) {
for (tomlElem in doc["pics"]!!.asArray()) {
pics.add(tomlElem!!.asPrimitive().asString())
}
}
val tags = arrayListOf<Tag>()
if (doc.contains("tags")) {
// Delete already existing tags for this recipe
db.recipeWithTagsDao().delete(recipeTitle)
for (tomlElem in doc["tags"]!!.asArray()) {
val tag = Tag(tomlElem!!.asPrimitive().asString())
tags.add(tag)
val recipeWithTags = RecipeTag(recipeTitle, tag.name)
db.tagDao().insert(tag)
db.recipeWithTagsDao().insert(recipeWithTags)
}
}
var recipePreview: String? = null
for (pic in pics) {
recipePreview = pic
}
val content = text.substring(frontMatterSize..<text.length)
val recipe = Recipe(
title = recipeTitle,
preview = recipePreview,
lastModified = lastModified,
content = content,
hash = hash
)
db.recipeDao().insert(recipe)
reader.close()
}