fix: adding in standard build

This commit is contained in:
D. Moonfire 2022-10-13 09:00:28 -05:00
parent 084704732e
commit f1d2e47d8e
26 changed files with 17148 additions and 6493 deletions

View file

@ -6,12 +6,21 @@ root = true
[*] [*]
charset = utf-8 charset = utf-8
end_of_line = lf end_of_line = lf
indent_brace_style = K&R
indent_size = 4 indent_size = 4
indent_style = space indent_style = space
insert_final_newline = true insert_final_newline = true
max_line_length = 120 max_line_length = 80
tab_width = 4 tab_width = 4
trim_trailing_whitespace = true trim_trailing_whitespace = true
curly_bracket_next_line = true
[*.{js,ts}]
quote_type = double quote_type = double
[*.yaml]
indent_size = 4
tab_width = 4
indent_style = space
[package.json]
indent_size = 2
tab_width = 2

2
.envrc Normal file
View file

@ -0,0 +1,2 @@
export PATH=$PWD/scripts:$PWD/node_modules/.bin:$PATH
use flake || use nix

18
.gitignore vendored
View file

@ -1,11 +1,13 @@
*~ *~
build/
tmp/
node_modules/ node_modules/
.direnv/
tmp/
build/
# Output .*-swp
*-*.*.*.epub dmoonfire*.pdf
*-*.*.*.pdf dmoonfire*.docx
*-*.*.*.mobi dmoonfire*.html
*-*.*.*.html dmoonfire*.mobi
*-*.*.*.docx dmoonfire*.epub
*.bz2

17
.prettierignore Normal file
View file

@ -0,0 +1,17 @@
CHANGELOG.md
package-lock.json
yarn.lock
*~
archives/
build/
extras/
others/
node_modules/
submissions/
sample-edits/
maps/
.direnv/
tmp/
edit/

36
.woodpecker.yml Normal file
View file

@ -0,0 +1,36 @@
clone:
git:
image: woodpeckerci/plugin-git
settings:
tags: true
pipeline:
build:
image: registry.gitlab.com/dmoonfire/nix-flake-docker:latest
commands:
- nix profile install 'nixpkgs#fontconfig'
- nix develop --command scripts/build.sh
secrets:
- gitea_token
- s3_bucket
- s3_endpoint
- s3_access_key_id
- s3_secret_access_key
when:
event: [push, pull_request, tag]
tag: v*
release:
image: registry.gitlab.com/dmoonfire/nix-flake-docker:latest
commands:
- nix profile install 'nixpkgs#fontconfig'
- nix develop --command scripts/release.sh
secrets:
- gitea_token
- s3_bucket
- s3_endpoint
- s3_access_key_id
- s3_secret_access_key
when:
event: push
branch: main

6
commitlint.config.js Normal file
View file

@ -0,0 +1,6 @@
module.exports = {
extends: ["@commitlint/config-conventional"],
rules: {
"body-max-line-length": [0],
},
};

View file

@ -4,24 +4,32 @@
"character": { "character": {
"pov": 100, "pov": 100,
"name": "Rutejìmo", "name": "Rutejìmo",
"character_slug": "rutejimo",
"color": "hsl(45, 40%, 50%)" "color": "hsl(45, 40%, 50%)"
}, },
"source": { "source": {
"pov": 100, "pov": 100,
"volume": 2, "volume": 2,
"title": "Sand and Bone", "title": "Sand and Bone",
"status": "stable", "word_count": 82861,
"length": "Novel",
"title_slug": "sand-and-bone",
"identifier_slug": "0100-02-sand-and-bone",
"copyright_year": 2019,
"status": "Stable",
"genres": [ "genres": [
"Action", "Action",
"Tragedy" "Tragedy"
], ],
"has_dedication": false,
"git": { "git": {
"http_url": "https://gitlab.com/fedran/sand-and-bone.git", "http_url": "https://src.mfgames.com/fedran-sources/sand-and-bone.git",
"branch": "master" "branch": "master"
}, },
"links": { "links": {
"development": { "development": {
"git": "https://gitlab.com/fedran/sand-and-bone" "git": "https://src.mfgames.com/fedran-sources/sand-and-bone/",
"issues": "https://src.mfgames.com/fedran-sources/sand-and-bone/issues"
}, },
"online": { "online": {
"wattpad": "https://www.wattpad.com/story/86395803-sand-and-bone", "wattpad": "https://www.wattpad.com/story/86395803-sand-and-bone",
@ -36,6 +44,193 @@
"amazon": "http://amzn.to/2FyJRey", "amazon": "http://amzn.to/2FyJRey",
"typewriter": "https://store.typewriter.press/product/sand-and-bone/" "typewriter": "https://store.typewriter.press/product/sand-and-bone/"
} }
} },
"cover": {
"cover_slug": "0100-02-sand-and-bone",
"title_page_lines": [
"Sand and",
"Bone"
]
},
"warnings": {
"text": "This novel contains no scenes of sexual assault."
},
"chapters": [
{
"title": "Running Away",
"word_count": 2335,
"summary": "Rutejìmo is playing with Mapábyo and his two children, Kitòpi and Piróma when there is a bird-like screen, someone in the clan was in trouble. As they ponder what is going on, Chimípu leaves the valley at high speed; the two parents protect their children from the warrior's high-speed exist. They run back to the valley entrance to see Bakóki dying in Tejíko's arms. While the others get ready to follow Chimípu, Rutejìmo heads back into the valley because he has other duties dealing with Bakóki.\n"
},
{
"title": "Cowardice",
"word_count": 1197,
"summary": "As Rutejìmo dresses for his duties as a kojinōmi, a tender of the dead, Kitòpi comes into his room and asks why his father is a coward. Rutejìmo is already taken on the silence of his duties, so he cannot answer and the guilt tears into him. He is saved by Pidòhu who arrives and tries to explain.\n"
},
{
"title": "Exhaustion",
"word_count": 1372,
"summary": "Rutejìmo is coming back after his day of purification after dealing with Bakóki's death. Chimípu meets up with him and tells him that they saved the other two couriers but lost most of the money the clan needed. They are going to take a job with the Kosòbyo, one of the largest clans in the entire desert.\n"
},
{
"title": "The Morning Before",
"word_count": 1713,
"summary": "The day that Rutejìmo and Mapábyo are leaving for Kosobyo City, their children wake them up, curious and active. They talk about why the two are going instead of Mapábyo's parents. Kiríshi interrupts them to get them going.\n"
},
{
"title": "Halfway There",
"word_count": 1995,
"summary": "Rutejìmo and Nifùni are sparring, but Rutejìmo is using a real weapon. Nifùni gets upset and refuses to fight until he has a real weapon himself. Desòchu insists that Rutejìmo's fighting skill is enough and demostrates by sparing with his brother, then failing to protect his neck. Rutejìmo hurts himself to pull the blow.\n"
},
{
"title": "Kosobyo City",
"word_count": 1048,
"summary": "The group arrives at Kosobyo City. It is far larger and more expansive than Rutejìmo had ever seen before. But, just as he was getting overwhelmed by the scope, he noticed white and gold smoke in the distance indicating his duties as a kojinōmi were needed. He splits from his clan to head there.\n"
},
{
"title": "Broken Silence",
"word_count": 3677,
"summary": "Rutejìmo meets another kojinōmi on the way to the smoke. To his surprise, the other man is heading away as he decided not to help a night clan's death. Rutejìmo, on the other hand, always served everyone and continued forward. He came up to a wagon surrounded by warriors. He walked toward the wagon, usually the crowds parted around him. However, Tsupòbi blocked his way. Rutejìmo found the urge to speak, when he did, he stripped away Tsupòbi's magic and declared him dead to the world. The others left him alone as he attended to a young girl who had been disemboweled and was dying.\n"
},
{
"title": "Alone",
"word_count": 1055,
"summary": "Rutejìmo attends to the little girl's bonfire. As he does, he tries to write the details of the stories she gave him in his book but doesn't have the room. It saddens him that so many stories are lost because no one remembers. When the fire is done, he leaves his belongings behind and begins his purfication ritual.\n"
},
{
"title": "Greatness",
"word_count": 1428,
"summary": "Heading back, Rutejìmo encountered Fidochìma, the little girl's grandfather. Fidochìma is looking for revenge but Rutejìmo suggests he let Mifúno handle it; Fidochìma refuses and they part ways.\n"
},
{
"title": "Westerners",
"word_count": 2386,
"summary": "Rutejìmo arrives at Kosobyo City but is quickly overwhelmed by the size of it. He tries to find the message board but no one helps him until a guard, Dimóryo, offers to help. They talk a little before reaching the board. Desòchu arrives but bristles at Dimóryo's attention. The Shimusògo head back to the hotel.\n"
},
{
"title": "Recovering",
"word_count": 2111,
"summary": "As Rutejìmo, Mapábyo, and Nifùni go shopping, Dimóryo comes up to them with probing questions. Mapábyo doesn't warm up to her. After the guard leaves, Rutejìmo and Mapábyo head back to the inn for some quiet time.\n"
},
{
"title": "The Offer",
"word_count": 2641,
"summary": "Rutejìmo is out in Kosobyo City looking for Nifùni who disappeared. He stumbled on Nifùni making a deal with a woman to deliver a message who offers a hundred thousand pyābi to deliver a message. Nifùni almost accepts but Rutejìmo has a bad feeling and tuns it down. Nifùni gets upset and attacked Rutejìmo before they are both kicked out of a bar. Desòchu arrives and insists on taling about it. When Nifùni suggests that Desòchu would always take Rutejìmo's side, Desòchu punches him.\n"
},
{
"title": "Voting",
"word_count": 1794,
"summary": "All of the Shimusògo are sharing a room in the inn. They vote on taking the woman's job. After a tense decision, they decide not to take the job. Nifùni is upset by the result.\n"
},
{
"title": "Presents",
"word_count": 5886,
"summary": "Rutejìmo and Mapábyo are finishing their last shopping when Byochína comes up. Nifùni had gone missing. They search for him but find the corpse of the Kosòbyo woman instead. Soon after that, they find Nifùni who accepted the contract. Dimóryo and other guards show up and try to kill all of them. Mapábyo calls Chimípu and Desòchu who destroy large parts of the city as the runners escape the city.\n"
},
{
"title": "Banyosiōu",
"word_count": 1336,
"summary": "After the Shimusògo escaped the city, Desòchu attacked Nifùni for betraying them. Rutejìmo watching uncomfortablly until he feels an overwhelming urge to speak up, not as one of the Shimusògo but as Mifúno, the desert itself.\n"
},
{
"title": "A Second Wind",
"word_count": 2116,
"summary": "The Shimusògo try to figure out what to do next. They open the case and find out that the Kosòbyo is going to leave Tachìra and possibly set off a bloody war, but they aren't sure. If they are wrong, then the Kosòbyo will destroy their clan. They decide to send the vote for the entire clan and send Chimípu ahead to make the choice.\n"
},
{
"title": "Splitting Up",
"word_count": 3144,
"summary": "While the Shimusògo slept, Kosòbyo's forces spread out across the land. Their plans of having Chimípu go first was changed when they realized they all had to run. Breaking apart the message into multiple parts, Desòchu plans a unique route for each one. As they do, Fidochìma appears and begs for forgiveness, the desert had already turned her back on him and he had become a banyosiōu.\n"
},
{
"title": "Brothers",
"word_count": 2877,
"summary": "As the Shimusògo break up, Rutejìmo is held behind with Desòchu. His brother tells him that he isn't going ahead. Instead he was going to stall the warriors chasing after them even though he knew he was going to die. After a tearful goodbye, Rutejìmo flees as Desòchu and Fidochìma cover his retreat.\n"
},
{
"title": "Nightmares",
"word_count": 1391,
"summary": "Camping alone, Rutejìmo is haunted by his brother's death and the possibility of losing everyone else in his life.\n"
},
{
"title": "An Unexpected Companion",
"word_count": 2020,
"summary": "Rutejìmo struggles to run alone. Then his path meets up with Nifùni right before night. Together, they find shelter though tensions rise as they begin to talk.\n"
},
{
"title": "The Dying",
"word_count": 1907,
"summary": "Rutejìmo and Nifùni come up to a oasis run by the Nyochikōmu. They have a chance to recover but then Rutejìmo sees smoke which means his duties as a kojinōmi are needed. Nifùni argues and then goes off alone. The old lady tending the oasis offers to keep his things safe, because he is a kojinōmi.\n"
},
{
"title": "Old Ways",
"word_count": 2429,
"summary": "Rutejìmo wakes up back to the spring. Atefómu took care of him. She also tells him that Kosòbyo warriors came and she guided them to Nifùni who they killed. When Rutejìmo gets upset, she offers to let him kill her but he doesn't. They also talk about how being a kojinōmi also means he's the desert's champion, doomed to die like most warriors.\n"
},
{
"title": "Asylum",
"word_count": 4843,
"summary": "Rutejìmo makes it to Wamifuko City but he is being chased. Allies of Kosòbyo try to stop him but Gichyòbi defends him, killing almost everyone who attacked Rutejìmo.\n"
},
{
"title": "Declaration of War",
"word_count": 5145,
"summary": "Rutejìmo tells Gichyòbi what was going on, though relucantly at first. Then Gichyòbi tells him that Hyonèku and Kiríshi were attacked on their rute. Kiríshi died but Hyonèku was severely injured. Rutejìmo rushes for his wife's daughter and tells him everything, ending with three clans declaring war on Kosòbyo. Then Rutejìmo says he is going to burn Kiríshi's body, which gets everyone upset until he invokes Mifúno's name.\n"
},
{
"title": "Sneaking Out",
"word_count": 1351,
"summary": "Rutejìmo and Gichyòbi sneak out of the city so Rutejìmo can burn Kidóri's corpse.\n"
},
{
"title": "A Long Night",
"word_count": 2456,
"summary": "Rutejìmo finishes burning Kiríshi's body. Instead of resting, he packs up, leaves his *Book of Ash*, and then immediately starts running toward home.\n"
},
{
"title": "A Longer Day",
"word_count": 1071,
"summary": "Rutejìmo is getting exhausted running but he doesn't dare stop in fears of being ambushed.\n"
},
{
"title": "Smoke and Honor",
"word_count": 5809,
"summary": "Rutejìmo answers a call for a kojinōmi only to find out it is a trap. He calls for help and four clans answer the call, all of them dying in the ambush. Then Chimípu arrives and joins the fight.\n"
},
{
"title": "Shimusogo Chimípu",
"word_count": 1072,
"summary": "Rutejìmo wakes up to a field of carnage and Chimípu dying. She tells him to run home. He doesn't want to but she shoves him away as she dies.\n"
},
{
"title": "Keep Moving",
"word_count": 254,
"summary": "Rutejìmo runs alone, haunted by the deaths of everyone who lost their lives.\n"
},
{
"title": "Wind's Teeth",
"word_count": 2862,
"summary": "Rutejìmo arrives at Three Falls Teeth. Mapábyo is there and he is relived but it turns out that Dimóryo had taken his wife's form. He calls on the desert to kill the Kosòbyo but Dimóryo manages to poison him before she is killed by the desert.\n"
},
{
"title": "Limits",
"word_count": 1117,
"summary": "Running out of time and with poison in his veins, Rutejìmo tries to run as long as he can. Even when his power runs out, he keeps running until the poison saps his strength and he collapses. Mikáryo finds him.\n"
},
{
"title": "Pabinkue Mikáryo",
"word_count": 2834,
"summary": "Rutejìmo doesn't expect to wake up but he does. He finds out that Mikáryo is using magic from her horse's blood to keep him alive but he can't sleep. They settle down to a night of talking.\n"
},
{
"title": "One Last Time",
"word_count": 2613,
"summary": "Minutes before Rutejìmo and he managed to survive the night. Mikáryo and Tsubàyo prepare to protect him until the sun rises and he could use his magic, but there is going to be a battle among the Pabinkúe. Rutejìmo knows that if he stops again, he will die so he runs as fast as he can, finally catching the clan's spirit as he begins his ryodifūne, his final run.\n"
},
{
"title": "Shimusogo Valley",
"word_count": 3576,
"summary": "Rutejìmo was the only one to make it home, but he cannot stop without dying. Pidòhu meets him along the way, flying using his magic. Realizing there is a war, they summon help from other clans to protected Rutejìmo as he races to the valley. The Shimusògo slow him down so he can collapse in Tejíko's arms. As the poison and energies kill him, Kitòpi and Piróma approach to see their father dying. Piróma puts on the kojinōmi clothes and tends to his death.\n"
}
]
} }
} }

58
flake.lock Normal file
View file

@ -0,0 +1,58 @@
{
"nodes": {
"flake-utils": {
"locked": {
"lastModified": 1642700792,
"narHash": "sha256-XqHrk7hFb+zBvRg6Ghl+AZDq03ov6OshJLiSWOoX5es=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "846b2ae0fc4cc943637d3d1def4454213e203cba",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1643805626,
"narHash": "sha256-AXLDVMG+UaAGsGSpOtQHPIKB+IZ0KSd9WS77aanGzgc=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "554d2d8aa25b6e583575459c297ec23750adb6cb",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-unstable",
"type": "indirect"
}
},
"nixstable": {
"locked": {
"lastModified": 1622516815,
"narHash": "sha256-ZjBd81a6J3TwtlBr3rHsZspYUwT9OdhDk+a/SgSEf7I=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "7e9b0dff974c89e070da1ad85713ff3c20b0ca97",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "21.05",
"type": "indirect"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"nixstable": "nixstable"
}
}
},
"root": "root",
"version": 7
}

28
flake.nix Normal file
View file

@ -0,0 +1,28 @@
{
inputs = {
nixstable.url = "nixpkgs/21.05";
nixpkgs.url = "nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, nixstable, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
stable = nixstable.legacyPackages.${system};
in {
devShell = pkgs.mkShell {
buildInputs = [
pkgs.epubcheck
pkgs.nixfmt
pkgs.nodejs-16_x
pkgs.pandoc
pkgs.pdftk
pkgs.python39Full
pkgs.python39Packages.weasyprint
pkgs.jq
pkgs.s3cmd
];
};
});
}

11
matter/about.md Normal file
View file

@ -0,0 +1,11 @@
---
title: About D. Moonfire
---
D. Moonfire is the remarkable intersection of a computer nerd and a scientist. He inherited a desire for learning, endless curiosity, and a talent for being a polymath from both of his parents. Instead of focusing on a single genre, he writes stories and novels in many different settings ranging from fantasy to science fiction. He also throws in the occasional romance or forensics murder mystery to mix things up.
In addition to having a borderline unhealthy obsession with the written word, he is also a developer who loves to code as much as he loves writing.
He lives near Cedar Rapids, Iowa with his wife, numerous pet computers, and a pair of highly mobile things of the male variety.
You can see more work by D. Moonfire at his website at [https://d.moonfire.us/](https://d.moonfire.us/). His fantasy world, Fedran, can be found at [https://fedran.com/](https://fedran.com/).

13
matter/fedran.md Normal file
View file

@ -0,0 +1,13 @@
---
title: Fedran
---
Fedran is a world caught on the cusp of two great ages.
For centuries, the Crystal Age shaped society through the exploration of magic. Every creature had the ability to affect the world using talents and spells. The only limitation was imagination, will, and the inescapable rules of resonance. But as society grew more civilized, magic became less reliable and weaker.
When an unexpected epiphany seemingly breaks the laws of resonance, everything changed. Artifacts no longer exploded when exposed to spells, but only if they were wrapped in cocoons of steel and brass. The humble fire rune becomes the fuel for new devices, ones powered by steam and pressure. These machines herald the birth of a new age, the Industrial Age.
Now, the powers of the old age struggle against the onslaught of new technologies and an alien way of approaching magic. Either the world will adapt or it will be washed away in the relentless march of innovation.
To explore the world of Fedran, check out [https://fedran.com/](https://fedran.com/). There you'll find stories, novels, character write-ups and more.

27
matter/legal.md Normal file
View file

@ -0,0 +1,27 @@
---
title: Legal
---
Copyright © 2019 D. Moonfire\
Some Rights Reserved\
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
Cover art by D. Moonfire
All characters, events, and locations are fictitious. Any resemblance to persons, past, present, and future is coincidental and highly unlikely.
This novel contains no scenes of sexual assault.
Broken Typewriter Press\
5001 1st Ave SE\
Ste 105 #243\
Cedar Rapids, IA 52402
Broken Typewriter Press\
[https://broken.typewriter.press/](https://broken.typewriter.press/)
{% if (edition.isbn) %}
ISBN {{edition.isbn}}
{% endif %}
Version {{edition.version}}

32
matter/license.md Normal file
View file

@ -0,0 +1,32 @@
---
title: License
---
This book is distributed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International license. More info can be found at [https://creativecommons.org/licenses/by-nc-sa/4.0/](https://creativecommons.org/licenses/by-nc-sa/4.0/). This means:
### You are free to:
- Share — copy and redistribute the material in any medium or format
- Adapt — remix, transform, and build upon the material
The licensor cannot revoke these freedoms as long as you follow the license terms.
### Under the following terms:
- Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
- NonCommercial — You may not use the material for commercial purposes.
- ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.
No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits.
### Preferred Attribution
The preferred attribution for this novel is:
> "Sand and Bone" by D. Moonfire is licensed under CC BY-NC-SA 4.0
In the above attribution, use the following links:
- Flight of the Scions: [https://fedran.com/sand-and-bone/](https://fedran.com/sand-and-bone/)
- D. Moonfire: https://d.moonfire.us/
- CC BY-NC-SA 4.0: https://creativecommons.org/licenses/by-nc-sa/4.0/

1
matter/pad.html Normal file
View file

@ -0,0 +1 @@
<br />

14
matter/title.html Normal file
View file

@ -0,0 +1,14 @@
---
title: Title
---
<div class="title">
<div class="title-area">
<div class="large">Sand and</div>
<div class="large">Bone</div>
</div>
<div class="author">D. Moonfire</div>
<div class="publisher">Broken Typewriter Press &#8226; Cedar Rapids</div>
</div>

22734
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,86 +1,50 @@
{ {
"name": "sand-and-bone", "name": "sand-and-bone",
"version": "1.1.0", "version": "1.1.0",
"fedran": { "private": true,
"pov": "0100", "description": "\"Sand and Bone\" is a novel by D. Moonfire.",
"vol": "02" "author": {
"name": "D. Moonfire"
}, },
"description": "A novel by D. Moonfire",
"author": "D. Moonfire",
"license": "CC-BY-NC-SA-4.0", "license": "CC-BY-NC-SA-4.0",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://gitlab.com/fedran/sand-and-bone.git" "url": "git+https://src.mfgames.com/fedran-sources/sand-and-bone.git"
}, },
"homepage": "https://fedran.com/sand-and-bone/", "homepage": "https://fedran.com/sand-and-bone/",
"scripts": { "scripts": {
"build:pdf": "mfgames-writing-format build pdf", "build:pdf": "mfgames-writing-format build pdf",
"build:epub": "mfgames-writing-format build epub", "build:epub": "mfgames-writing-format build epub",
"build": "npm run build:epub && npm run build:mobi && npm run build:pdf", "build:docx": "mfgames-writing-format build docx",
"build:extended": "npm run build && npm run build:html && npm run build:docx", "build": "run-s build:*",
"build:docx": "sed 's@&#173;@@g' < dmoonfire-$npm_package_fedran_pov-$npm_package_fedran_vol-$npm_package_name-$npm_package_version.html | pandoc -f html -t docx -o dmoonfire-$npm_package_fedran_pov-$npm_package_fedran_vol-$npm_package_name-$npm_package_version.docx", "prepare": "husky install"
"build:mobi": "kindlegen dmoonfire-$npm_package_fedran_pov-$npm_package_fedran_vol-$npm_package_name-$npm_package_version.epub",
"build:html": "mfgames-writing-format build html",
"prebuild:mobi": "npm run build:epub",
"prebuild": "rm -f $npm_package_name-*.* $npm_package_name.tar.bz2",
"bundle": "tar -cjf $npm_package_name.tar.bz2 *.epub *.pdf",
"prebundle": "npm run build",
"upload": "aws --endpoint-url https://$AWS_ENDPOINT s3 cp --acl public-read $npm_package_name.tar.bz2 s3://$AWS_BUCKET/$npm_package_name.tar.bz2",
"preupload": "npm run bundle"
}, },
"dependencies": { "dependencies": {
"@fedran/writing-hyphen": "^1.0.0", "@fedran/writing-hyphen": "^1.0.0",
"@fedran/writing-theme": "^3.0.5", "@fedran/writing-theme": "^4.0.2",
"@mfgames-writing/epub2": "^1.1.3", "@mfgames-writing/contracts": "^4.4.0",
"@mfgames-writing/format": "^2.0.0", "@mfgames-writing/docx-format": "^1.0.2",
"@mfgames-writing/epub2-format": "^2.1.1",
"@mfgames-writing/format": "^3.3.1",
"@mfgames-writing/guillemet": "^1.0.0", "@mfgames-writing/guillemet": "^1.0.0",
"@mfgames-writing/html": "^0.1.1", "@mfgames-writing/hyphen-pipeline": "^1.0.2",
"@mfgames-writing/hyphen": "^0.4.3", "@mfgames-writing/liquid-theme": "^2.1.1",
"@mfgames-writing/weasyprint": "^4.0.0" "@mfgames-writing/weasyprint-format": "^5.0.4",
"markdown-it-multimd-table": "^4.1.3"
}, },
"devDependencies": { "devDependencies": {
"@commitlint/cli": "^7.6.1", "@commitlint/cli": "^15.0.0",
"@commitlint/config-conventional": "^7.6.0", "@commitlint/config-conventional": "^15.0.0",
"@semantic-release/changelog": "^3.0.6", "@saithodev/semantic-release-gitea": "^2.1.0",
"@semantic-release/git": "^7.0.18", "@semantic-release/changelog": "^6.0.1",
"commitizen": "^2.10.1", "@semantic-release/exec": "^6.0.3",
"cz-conventional-changelog": "^2.1.0", "@semantic-release/git": "^10.0.1",
"husky": "^0.14.3", "@semantic-release/npm": "^8.0.3",
"semantic-release": "^15.14.0" "@semantic-release/release-notes-generator": "^10.0.3",
}, "husky": "^7.0.2",
"release": { "markdowny": "^0.2.1",
"branch": "master", "npm-run-all": "^4.1.5",
"message": "chore(release): v${nextRelease.version}\n\n${nextRelease.notes}", "prettier": "^2.0.5",
"verifyConditions": [ "semantic-release": "^18.0.1"
"@semantic-release/changelog", }
"@semantic-release/git"
],
"analyzeCommits": [
"@semantic-release/commit-analyzer"
],
"prepare": [
"@semantic-release/changelog",
"@semantic-release/npm",
"@semantic-release/git"
],
"publish": [],
"success": [],
"fail": []
},
"commitlint": {
"extends": [
"@commitlint/config-conventional"
]
},
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
}
},
"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
},
"private": true
} }

123
publication.json Normal file
View file

@ -0,0 +1,123 @@
{
"metadata": {
"title": "{{edition.fedran.source.title}}",
"author": "D. Moonfire",
"language": "en",
"theme": "@fedran/writing-theme",
"outputDirectory": ".",
"outputFilename": "dmoonfire-{{edition.fedran.source.title_slug}}-{{edition.name}}-{{edition.version}}.{{edition.ext}}",
"markdown": {
"extensions": [
{
"package": "markdown-it-multimd-table",
"options": {
"headerless": true
}
}
]
},
"style": {
"css": "td { width: 6em; } td[colspan=\"2\"] { width: 12em; }"
}
},
"includes": [
{
"json": "./fedran.json",
"merge": "metadata.fedran"
}
],
"editions": {
"epub": {
"format": "@mfgames-writing/epub2-format",
"ext": "epub"
},
"pdf": {
"format": "@mfgames-writing/weasyprint-format",
"isbn": "",
"images": {
"grayscale": true,
"opaque": true
},
"ext": "pdf"
},
"docx": {
"format": "@mfgames-writing/docx-format",
"ext": "docx"
}
},
"contents": [
{
"element": "cover",
"source": "build/fedran-covers/pov/covers/0100-02-sand-and-bone.jpg",
"linear": false,
"exclude": {
"editions": ["pdf"],
"toc": true
}
},
{
"element": "bastard",
"source": "matter/title.html",
"linear": false,
"exclude": {
"editions": ["epub", "html"],
"toc": true
}
},
{
"element": "title",
"source": "matter/title.html",
"linear": false,
"exclude": {
"toc": true
}
},
{
"element": "legal",
"source": "matter/legal.md",
"liquid": true,
"linear": false
},
{
"element": "toc",
"linear": false,
"title": "Contents",
"exclude": {
"editions": ["pdf"]
}
},
{
"element": "chapter",
"number": 1,
"directory": "chapters",
"source": "/^chapter-\\d+.(markdown|md)$/",
"start": true,
"page": 1,
"pipeline": [
{
"module": "@mfgames-writing/guillemet"
},
{
"module": "@fedran/writing-hyphen"
},
{
"module": "@mfgames-writing/hyphen-pipeline",
"exclude": ["`.*?`", "<code>.*?</code>"]
}
]
},
{
"element": "appendix",
"source": "matter/about.md"
},
{
"element": "appendix",
"source": "matter/fedran.md"
},
{
"element": "appendix",
"id": "license",
"source": "matter/license.md"
}
]
}

39
release.config.js Normal file
View file

@ -0,0 +1,39 @@
module.exports = {
branches: ["main"],
extends: ["@commitlint/config-conventional"],
message:
"chore(release): v${nextRelease.version} [skip ci]\n\n${nextRelease.notes}",
plugins: [
[
"@semantic-release/commit-analyzer",
{
preset: "conventionalcommits",
},
],
"@semantic-release/release-notes-generator",
"@semantic-release/npm",
[
"@semantic-release/exec",
{
prepareCmd: "npm run build",
},
],
"@semantic-release/changelog",
"@semantic-release/git",
[
"@saithodev/semantic-release-gitea",
{
giteaUrl: "https://src.mfgames.com",
assets: [
{ path: "*.epub", label: "EPUB2", type: "other" },
{ path: "*.pdf", label: "PDF", type: "other" },
{ path: "*.docx", label: "DOCX", type: "other" },
],
},
],
],
};

18
scripts/build.sh Executable file
View file

@ -0,0 +1,18 @@
#!/usr/bin/env bash
# Set up logging.
log() { echo "🛠️ $(basename $0): $@"; }
# Move into the root folder.
cd $(dirname $(dirname $0))
# Make sure everything is set up.
log "setting up project"
./scripts/setup.sh || exit 1
# Build the project outputs.
log "building PDF"
npm run build:pdf || exit 1
log "building EPUB"
npm run build:epub || exit 1

27
scripts/check-env-bucket.sh Executable file
View file

@ -0,0 +1,27 @@
#!/usr/bin/env bash
# Checks the environment to see if we have all the requisite components needed
# to upload or download from the S3 bucket.
# Set up logging.
log() { echo "⚗️ $(basename $0): $@"; }
# Move into the root folder.
cd $(dirname $(dirname $0))
for i in S3_ACCESS_KEY_ID S3_SECRET_ACCESS_KEY S3_ENDPOINT S3_BUCKET
do
if [ "x${!i}" = "x" ]
then
log "missing environment variable $i"
exit 1
fi
done
if [ ! which s3cmd 2> /dev/null ]
then
log "cannot find 's3cmd' to execute"
exit 1
fi
exit 0

40
scripts/release.sh Executable file
View file

@ -0,0 +1,40 @@
#!/usr/bin/env bash
# Builds the final versions of the book and then upload the results to various
# locations.
# Set up logging.
log() { echo "️🚢 $(basename $0): $@"; }
# Move into the root folder.
cd $(dirname $(dirname $0))
# Perform the basic environment checks and setup.
./scripts/setup.sh || exit 1
./scripts/check-env-bucket.sh || exit 1
# Clean up old versions of the file.
log "cleaning up prior versions which may not match versions"
rm -f dmoonfire*
# Perform the release process.
log "performing semantic release"
export GIT_CREDENTIALS="dmoonfire:$GITEA_TOKEN"
npx semantic-release || exit 1
# Create a tarball of the output files and upload them to S3.
if ls dmoonfire* &> /dev/null
then
log "packaging output into a tarball"
tar -cjf sand-and-bone.tar.bz2 dmoonfire*
log "uploading tarball to bucket"
export AWS_ACCESS_KEY_ID=$S3_ACCESS_KEY_ID
export AWS_SECRET_ACCESS_KEY=$S3_SECRET_ACCESS_KEY
export AWS_ENDPOINT=$S3_ENDPOINT
export AWS_BUCKET=$S3_BUCKET
s3cmd --access_key=$S3_ACCESS_KEY_ID --access_token=$S3_SECRET_ACCESS_KEY --host=$S3_ENDPOINT --host-bucket=$S3_ENDPOINT -P put sand-and-bone.tar.bz2 s3://$S3_BUCKET || exit 1
else
log "no files to upload"
fi

31
scripts/setup-fedran-covers.sh Executable file
View file

@ -0,0 +1,31 @@
#!/usr/bin/env bash
# Download the Fedran covers for inclusion. This places everything into the
# ./build/fedran-covers folder.
# Set up logging.
log() { echo "🖼 $(basename $0): $@"; }
# Move into the root folder.
cd $(dirname $(dirname $0))
# Check to see if it is already downloaded.
if [ -d ./build/fedran-covers ]
then
log "fedran-covers already exists, not downloading"
else
# Make sure we have all the required environment variables.
log "fedran-covers is missing, download from bucket"
./scripts/check-env-bucket.sh || exit 1
# Set the variables.
export AWS_ACCESS_KEY_ID=$S3_ACCESS_KEY_ID
export AWS_SECRET_ACCESS_KEY=$S3_SECRET_ACCESS_KEY
export AWS_ENDPOINT=$S3_ENDPOINT
export AWS_BUCKET=$S3_BUCKET
# Download and extract the bucket.
mkdir -p ./build/fedran-covers
s3cmd --access_key=$S3_ACCESS_KEY_ID --access_token=$S3_SECRET_ACCESS_KEY --host=$S3_ENDPOINT --host-bucket=$S3_ENDPOINT -P get s3://$S3_BUCKET/fedran-covers.tar.bz2 ./build/fedran-covers/fedran-covers.tar.bz2 || exit 1
tar x -C build/fedran-covers -f build/fedran-covers/fedran-covers.tar.bz2
fi

24
scripts/setup-fonts.sh Executable file
View file

@ -0,0 +1,24 @@
#!/usr/bin/env bash
# Sets up the fonts for building the PDF output. It doesn't do it if we are not
# in a CI environment.
# Set up logging.
log() { echo "✒️ $(basename $0): $@"; }
# Move into the root directory.
cd $(dirname $(dirname $0))
# We only insert the fonts if we are on a CI server.
if [ "x$CI" == "x" ]
then
log "not in CI environment, not installing fonts"
else
log "installing fonts"
mkdir -p ~/.local/share/fonts
cp $(nix-build --no-out-link '<nixpkgs>' -A source-serif-pro)/share/fonts/opentype/*.otf ~/.local/share/fonts
cp $(nix-build --no-out-link '<nixpkgs>' -A source-sans-pro)/share/fonts/opentype/*.otf ~/.local/share/fonts
log "updating font caches"
fc-cache
fi

17
scripts/setup-node.sh Executable file
View file

@ -0,0 +1,17 @@
#!/usr/bin/env bash
# Installs the required Node packages
# Set up logging.
log() { echo "📦️ $(basename $0): $@"; }
# Move into the root directory.
cd $(dirname $(dirname $0))
if [ -d ./node_modules ]
then
log "node_modules already exists"
else
log "setting up node"
npm install --ci
fi

9
scripts/setup.sh Executable file
View file

@ -0,0 +1,9 @@
#!/usr/bin/env bash
# Move into the root folder.
cd $(dirname $(dirname $0))
# Run the setup commands.
./scripts/setup-fonts.sh || exit 1
./scripts/setup-fedran-covers.sh || exit 1
./scripts/setup-node.sh || exit 1