homepage/garden-data-gen/source/content_gen.d

155 lines
5.3 KiB
D

module content_gen;
import plant_data;
import dom_utils;
import dxml.writer;
import dxml.util;
import std.stdio;
import std.path;
import std.array;
import std.algorithm;
import std.file;
import std.conv;
void renderHTML(PlantData data) {
renderSpeciesCards(data);
renderSpeciesPages(data);
}
private void injectContent(string filename, string startTag, string endTag, string newContent) {
import std.file;
string data = std.file.readText(filename);
ptrdiff_t startIdx = indexOfStr(data, startTag);
if (startIdx == -1) throw new Exception("Couldn't find start tag " ~ startTag);
ptrdiff_t endIdx = indexOfStr(data, endTag);
if (endIdx == -1) throw new Exception("Couldn't find end tag " ~ endTag);
string prefix = data[0..(startIdx + startTag.length)];
string suffix = data[endIdx..$];
string newData = prefix ~ newContent ~ suffix;
std.file.write(filename, newData);
}
private void renderSpeciesCards(PlantData data) {
string tpl = std.file.readText(buildPath(
"garden-data-gen", "templates", "species-card.html"
));
Appender!string htmlApp;
foreach (s; data.species) {
string card = replaceAll(tpl, [
"!NAME!": s.name,
"!SCIENTIFIC_NAME!": s.scientificName,
"!DESCRIPTION!": s.description,
"!LINK!": "garden/species/" ~ s.id ~ ".html",
"!REF_LINK!": s.referenceLink,
"!REF_LINK_TEXT!": s.referenceLink
]);
ImageFilePair[] imagePairs = getSpeciesImages(s.id);
if (imagePairs.length > 0) {
card = replaceFirst(card, "!IMAGES!", generatePhotoSwipeElement(imagePairs[0], false));
} else {
card = replaceFirst(card, "!IMAGES!", "");
}
htmlApp ~= "\n" ~ card;
}
injectContent(
"garden.html",
"<!--__SPECIES_LIST_START__-->",
"<!--__SPECIES_LIST_END__-->",
htmlApp[]
);
}
private void renderSpeciesPages(PlantData data) {
string tpl = std.file.readText(buildPath(
"garden-data-gen", "templates", "species-page.html"
));
string plantCardTpl = std.file.readText(buildPath(
"garden-data-gen", "templates", "plant-card.html"
));
string speciesPagesDir = buildPath("garden", "species");
if (!exists(speciesPagesDir)) mkdirRecurse(speciesPagesDir);
foreach (species; data.species) {
Appender!string plantDivsApp;
foreach (plant; data.plantsInSpecies(species)) {
string card = replaceAll(plantCardTpl, [
"!IDENTIFIER!": plant.identifier,
"!GENERATION!": "F" ~ plant.generation.to!string,
"!DESCRIPTION!": plant.description,
"!PLANTING_INFO!": plant.plantingInfo
]);
ImageFilePair[] imagePairs = getPlantImages(plant.identifier);
Appender!string imagesApp;
foreach (imagePair; imagePairs) {
imagesApp ~= generatePhotoSwipeElement(imagePair);
}
card = replaceFirst(card, "!IMAGES!", imagesApp[]);
plantDivsApp ~= card;
}
string page = replaceAll(tpl, [
"!HEAD_TITLE!": species.name,
"!PAGE_TITLE!": species.scientificName,
"!ABOUT_TITLE!": "About " ~ species.name,
"!ABOUT_TEXT!": species.description,
"!REF_LINK!": species.referenceLink,
"!REF_LINK_TEXT!": species.referenceLink,
"!PLANTS_DIVS!": plantDivsApp[]
]);
string pagePath = buildPath(speciesPagesDir, species.id ~ ".html");
std.file.write(pagePath, page);
}
}
private string generatePhotoSwipeElement(ImageFilePair imagePair, bool addCaption = true) {
import std.format;
import std.datetime;
import std.typecons;
const linkFormat = "<a href=\"%s\" data-pswp-width=\"%d\" data-pswp-height=\"%d\" target=\"_blank\">";
const thumbnailFormat = "<img src=\"%s\" alt=\"\" style=\"display: block;\"/>";
const captionFormat = "<time datetime=\"%04d-%02d-%02d\">%s</time>";
string linkTag = format!(linkFormat)("../../" ~ imagePair.filename, imagePair.width, imagePair.height);
string thumbnailTag = format!(thumbnailFormat)("../../" ~ imagePair.thumbnailFilename);
Appender!string app;
app ~= linkTag;
app ~= "\n ";
app ~= thumbnailTag;
Nullable!DateTime imageTimestamp = getImageTimestamp(imagePair.filename);
if (addCaption && !imageTimestamp.isNull) {
DateTime dt = imageTimestamp.get;
app ~= "\n ";
app ~= format!(captionFormat)(dt.year, dt.month, dt.day, dt.date.toSimpleString);
}
app ~= "\n</a>\n";
return app[];
}
ptrdiff_t indexOfStr(string source, string target) {
for (size_t i = 0; i < source.length - target.length; i++) {
if (source[i..i+target.length] == target) {
return i;
}
}
return -1;
}
string replaceFirst(string source, string from, string to) {
ptrdiff_t idx = indexOfStr(source, from);
if (idx == -1) return source;
string pre = idx == 0 ? "" : source[0..idx];
string post = source[idx+from.length..$];
return pre ~ to ~ post;
}
unittest {
assert(replaceFirst("<p>!TEST</p>", "!TEST", "test") == "<p>test</p>");
}
string replaceAll(string source, string[string] values) {
foreach (k, v; values) {
source = replaceFirst(source, k, v);
}
return source;
}