From ea3499fa4817e56873759fce695364235cceaa67 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Wed, 1 Jan 2025 18:13:36 +0900 Subject: [PATCH 01/11] Mostly working, for Worm --- chapter-data/worm.json | 1767 +++++++++++++++++++++++++++++++++++ lib/choose-chapter-title.js | 27 + lib/convert.js | 32 +- lib/scaffold.js | 159 +++- lib/worm-scraper.js | 20 +- 5 files changed, 1960 insertions(+), 45 deletions(-) create mode 100644 chapter-data/worm.json create mode 100644 lib/choose-chapter-title.js diff --git a/chapter-data/worm.json b/chapter-data/worm.json new file mode 100644 index 0000000..3e54d9c --- /dev/null +++ b/chapter-data/worm.json @@ -0,0 +1,1767 @@ +[ + { + "label": "Arc 1", + "title": "Gestation", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2011/06/11/1-1/", + "originalTitle": "Gestation 1.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2011/06/14/gestation-1-2/", + "originalTitle": "Gestation 1.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2011/06/18/gestation-1-3/", + "originalTitle": "Gestation 1.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2011/06/21/gestation-1-4/", + "originalTitle": "Gestation 1.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2011/06/25/gestation-1-5/", + "originalTitle": "Gestation 1.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2011/06/28/gestation-1-6/", + "originalTitle": "Gestation 1.6", + "simplifiedTitle": "6" + }, + { + "url": "https://parahumans.wordpress.com/2011/07/02/interlude-1/", + "originalTitle": "Interlude 1", + "simplifiedTitle": "Interlude", + "characterNamesTitle": "Interlude: Danny" + } + ] + }, + { + "label": "Arc 2", + "title": "Insinuation", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2011/07/05/insinuation-2-1/", + "originalTitle": "Insinuation 2.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2011/07/09/insinuation-2-2/", + "originalTitle": "Insinuation 2.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2011/07/12/insinuation-2-3/", + "originalTitle": "Insinuation 2.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2011/07/16/insinuation-2-4/", + "originalTitle": "Insinuation 2.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2011/07/19/insinuation-2-5/", + "originalTitle": "Insinuation 2.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2011/07/23/insinuation-2-6/", + "originalTitle": "Insinuation 2.6", + "simplifiedTitle": "6" + }, + { + "url": "https://parahumans.wordpress.com/2011/07/26/insinuation-2-7/", + "originalTitle": "Insinuation 2.7", + "simplifiedTitle": "7" + }, + { + "url": "https://parahumans.wordpress.com/2011/07/30/insinuation-2-8/", + "originalTitle": "Insinuation 2.8", + "simplifiedTitle": "8" + }, + { + "url": "https://parahumans.wordpress.com/2011/08/02/insinuation-2-9/", + "originalTitle": "Insinuation 2.9", + "simplifiedTitle": "9" + }, + { + "url": "https://parahumans.wordpress.com/2011/08/06/interlude-2/", + "originalTitle": "Interlude 2", + "simplifiedTitle": "Interlude", + "characterNamesTitle": "Interlude: Victoria" + } + ] + }, + { + "label": "Arc 3", + "title": "Agitation", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2011/08/09/agitation-3-1/", + "originalTitle": "Agitation 3.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2011/08/13/agitation-3-2/", + "originalTitle": "Agitation 3.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2011/08/16/agitation-3-3/", + "originalTitle": "Agitation 3.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2011/08/20/agitation-3-4/", + "originalTitle": "Agitation 3.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2011/08/23/agitation-3-5/", + "originalTitle": "Agitation 3.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2011/08/27/agitation-3-6/", + "originalTitle": "Agitation 3.6", + "simplifiedTitle": "6" + }, + { + "url": "https://parahumans.wordpress.com/2011/08/30/agitation-3-7/", + "originalTitle": "Agitation 3.7", + "simplifiedTitle": "7" + }, + { + "url": "https://parahumans.wordpress.com/2011/09/03/agitation-3-8/", + "originalTitle": "Agitation 3.8", + "simplifiedTitle": "8" + }, + { + "url": "https://parahumans.wordpress.com/2011/09/06/agitation-3-9/", + "originalTitle": "Agitation 3.9", + "simplifiedTitle": "9" + }, + { + "url": "https://parahumans.wordpress.com/2011/09/10/agitation-3-10/", + "originalTitle": "Agitation 3.10", + "simplifiedTitle": "10" + }, + { + "url": "https://parahumans.wordpress.com/2011/09/13/agitation-3-11/", + "originalTitle": "Agitation 3.11", + "simplifiedTitle": "11" + }, + { + "url": "https://parahumans.wordpress.com/2011/09/17/agitation-3-12/", + "originalTitle": "Agitation 3.12", + "simplifiedTitle": "12" + }, + { + "url": "https://parahumans.wordpress.com/2011/09/20/interlude-3-2/", + "originalTitle": "Interlude 3", + "simplifiedTitle": "Interlude", + "characterNamesTitle": "Interlude: Wards" + } + ] + }, + { + "label": "Arc 4", + "title": "Shell", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2011/09/24/shell-4-1/", + "originalTitle": "Shell 4.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2011/09/27/shell-4-2/", + "originalTitle": "Shell 4.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2011/10/01/shell-4-3/", + "originalTitle": "Shell 4.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2011/10/04/shell-4-4/", + "originalTitle": "Shell 4.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2011/10/08/shell-4-5/", + "originalTitle": "Shell 4.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2011/10/11/shell-4-6/", + "originalTitle": "Shell 4.6", + "simplifiedTitle": "6" + }, + { + "url": "https://parahumans.wordpress.com/2011/10/11/interlude-3%C2%BD-bonus/", + "originalTitle": "Interlude 3½ (Bonus)", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: Kayden" + }, + { + "url": "https://parahumans.wordpress.com/2011/10/15/shell-4-7/", + "originalTitle": "Shell 4.7", + "simplifiedTitle": "7" + }, + { + "url": "https://parahumans.wordpress.com/2011/10/18/shell-4-8/", + "originalTitle": "Shell 4.8", + "simplifiedTitle": "8" + }, + { + "url": "https://parahumans.wordpress.com/2011/10/22/shell-4-9/", + "originalTitle": "Shell 4.9", + "simplifiedTitle": "9" + }, + { + "url": "https://parahumans.wordpress.com/2011/10/25/shell-4-10/", + "originalTitle": "Shell 4.10", + "simplifiedTitle": "10" + }, + { + "url": "https://parahumans.wordpress.com/2011/10/29/shell-4-11/", + "originalTitle": "Shell 4.11", + "simplifiedTitle": "11" + }, + { + "url": "https://parahumans.wordpress.com/2011/11/01/interlude-4-2/", + "originalTitle": "Interlude 4", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: Brutus" + } + ] + }, + { + "label": "Arc 5", + "title": "Hive", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2011/11/05/hive-5-1/", + "originalTitle": "Hive 5.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2011/11/08/hive-5-2/", + "originalTitle": "Hive 5.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2011/11/12/hive-5-3/", + "originalTitle": "Hive 5.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2011/11/15/hive-5-4/", + "originalTitle": "Hive 5.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2011/11/19/hive-5-5/", + "originalTitle": "Hive 5.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2011/11/22/hive-5-6/", + "originalTitle": "Hive 5.6", + "simplifiedTitle": "6" + }, + { + "url": "https://parahumans.wordpress.com/2011/11/26/hive-5-7/", + "originalTitle": "Hive 5.7", + "simplifiedTitle": "7" + }, + { + "url": "https://parahumans.wordpress.com/2011/11/29/hive-5-8/", + "originalTitle": "Hive 5.8", + "simplifiedTitle": "8" + }, + { + "url": "https://parahumans.wordpress.com/2011/12/03/hive-5-9/", + "originalTitle": "Hive 5.9", + "simplifiedTitle": "9" + }, + { + "url": "https://parahumans.wordpress.com/2011/12/06/hive-5-10/", + "originalTitle": "Hive 5.10", + "simplifiedTitle": "10" + }, + { + "url": "https://parahumans.wordpress.com/2011/12/10/interlude-5/", + "originalTitle": "Interlude 5", + "simplifiedTitle": "Interlude", + "characterNamesTitle": "Interlude: Gregor the Snail" + } + ] + }, + { + "label": "Arc 6", + "title": "Tangle", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2011/12/13/tangle-6-1/", + "originalTitle": "Tangle 6.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2011/12/17/tangle-6-2/", + "originalTitle": "Tangle 6.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2011/12/20/tangle-6-3/", + "originalTitle": "Tangle 6.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2011/12/24/tangle-6-4/", + "originalTitle": "Tangle 6.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2011/12/27/tangle-6-5/", + "originalTitle": "Tangle 6.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2011/12/31/tangle-6-6/", + "originalTitle": "Tangle 6.6", + "simplifiedTitle": "6" + }, + { + "url": "https://parahumans.wordpress.com/2012/01/03/tangle-6-7/", + "originalTitle": "Tangle 6.7", + "simplifiedTitle": "7" + }, + { + "url": "https://parahumans.wordpress.com/2012/01/07/tangle-6-8/", + "originalTitle": "Tangle 6.8", + "simplifiedTitle": "8" + }, + { + "url": "https://parahumans.wordpress.com/2012/01/10/tangle-6-9/", + "originalTitle": "Tangle 6.9", + "simplifiedTitle": "9" + }, + { + "url": "https://parahumans.wordpress.com/2012/01/14/interlude-6/", + "originalTitle": "Interlude 6", + "simplifiedTitle": "Interlude", + "characterNamesTitle": "Interlude: Paige" + } + ] + }, + { + "label": "Arc 7", + "title": "Buzz", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2012/01/17/buzz-7-1/", + "originalTitle": "Buzz 7.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2012/01/21/buzz-7-2/", + "originalTitle": "Buzz 7.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2012/01/24/buzz-7-3/", + "originalTitle": "Buzz 7.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2012/01/28/buzz-7-4/", + "originalTitle": "Buzz 7.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2012/01/31/buzz-7-5/", + "originalTitle": "Buzz 7.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2012/02/04/buzz-7-6/", + "originalTitle": "Buzz 7.6", + "simplifiedTitle": "6" + }, + { + "url": "https://parahumans.wordpress.com/2012/02/07/buzz-7-7/", + "originalTitle": "Buzz 7.7", + "simplifiedTitle": "7" + }, + { + "url": "https://parahumans.wordpress.com/2012/02/11/buzz-7-8/", + "originalTitle": "Buzz 7.8", + "simplifiedTitle": "8" + }, + { + "url": "https://parahumans.wordpress.com/2012/02/14/buzz-7-9/", + "originalTitle": "Buzz 7.9", + "simplifiedTitle": "9" + }, + { + "url": "https://parahumans.wordpress.com/2012/02/18/buzz-7-10/", + "originalTitle": "Buzz 7.10", + "simplifiedTitle": "10" + }, + { + "url": "https://parahumans.wordpress.com/2012/02/21/buzz-7-11/", + "originalTitle": "Buzz 7.11", + "simplifiedTitle": "11" + }, + { + "url": "https://parahumans.wordpress.com/2012/02/25/buzz-7-12/", + "originalTitle": "Buzz 7.12", + "simplifiedTitle": "12" + }, + { + "url": "https://parahumans.wordpress.com/2012/02/28/interlude-7/", + "originalTitle": "Interlude 7", + "simplifiedTitle": "Interlude", + "characterNamesTitle": "Interlude: Hana" + } + ] + }, + { + "label": "Arc 8", + "title": "Extermination", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2012/03/03/extermination-8-1/", + "originalTitle": "Extermination 8.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2012/03/06/extermination-8-2/", + "originalTitle": "Extermination 8.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2012/03/08/interlude-7%C2%BD-bonus/", + "originalTitle": "Interlude 8 (Bonus)", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: Lisa" + }, + { + "url": "https://parahumans.wordpress.com/2012/03/10/extermination-8-3/", + "originalTitle": "Extermination 8.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2012/03/13/extermination-8-4/", + "originalTitle": "Extermination 8.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2012/03/17/extermination-8-5/", + "originalTitle": "Extermination 8.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2012/03/20/extermination-8-6/", + "originalTitle": "Extermination 8.6", + "simplifiedTitle": "6" + }, + { + "url": "https://parahumans.wordpress.com/2012/03/24/extermination-8-7/", + "originalTitle": "Extermination 8.7", + "simplifiedTitle": "7" + }, + { + "url": "https://parahumans.wordpress.com/2012/03/27/extermination-8-8/", + "originalTitle": "Extermination 8.8", + "simplifiedTitle": "8" + }, + { + "url": "https://parahumans.wordpress.com/2012/03/31/interlude-8/", + "originalTitle": "Interlude 8", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: Coil" + } + ] + }, + { + "label": "Arc 9", + "title": "Sentinel", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2012/04/03/cell-9-1/", + "originalTitle": "Sentinel 9.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2012/04/07/sentinel-9-2/", + "originalTitle": "Sentinel 9.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2012/04/10/sentinel-9-3/", + "originalTitle": "Sentinel 9.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2012/04/14/sentinel-9-4/", + "originalTitle": "Sentinel 9.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2012/04/17/sentinel-9-5/", + "originalTitle": "Sentinel 9.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2012/04/21/sentinel-9-6/", + "originalTitle": "Sentinel 9.6", + "simplifiedTitle": "6" + } + ] + }, + { + "label": "Arc 10", + "title": "Parasite", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2012/04/24/parasite-10-1/", + "originalTitle": "Parasite 10.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2012/04/28/parasite-10-2/", + "originalTitle": "Parasite 10.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2012/05/01/parasite-10-3/", + "originalTitle": "Parasite 10.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2012/05/05/parasite-10-4/", + "originalTitle": "Parasite 10.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2012/05/08/parasite-10-5/", + "originalTitle": "Parasite 10.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2012/05/12/parasite-10-6/", + "originalTitle": "Parasite 10.6", + "simplifiedTitle": "6" + }, + { + "url": "https://parahumans.wordpress.com/2012/05/15/interlude-10/", + "originalTitle": "Interlude 10", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: Alec" + }, + { + "url": "https://parahumans.wordpress.com/2012/05/17/interlude-10-5-bonus/", + "originalTitle": "Interlude 10.5 (Bonus)", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: Dragon" + } + ] + }, + { + "label": "Arc 11", + "title": "Infestation", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2012/05/19/infestation-11-1/", + "originalTitle": "Infestation 11.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2012/05/22/infestation-11-2/", + "originalTitle": "Infestation 11.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2012/05/26/infestation-11-3/", + "originalTitle": "Infestation 11.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2012/05/29/infestation-11-4/", + "originalTitle": "Infestation 11.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2012/06/02/infestation-11-5/", + "originalTitle": "Infestation 11.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2012/06/05/infestation-11-6/", + "originalTitle": "Infestation 11.6", + "simplifiedTitle": "6" + }, + { + "url": "https://parahumans.wordpress.com/2012/06/09/infestation-11-7/", + "originalTitle": "Infestation 11.7", + "simplifiedTitle": "7" + }, + { + "url": "https://parahumans.wordpress.com/2012/06/12/infestation-11-8/", + "originalTitle": "Infestation 11.8", + "simplifiedTitle": "8" + }, + { + "url": "https://parahumans.wordpress.com/2012/06/16/interlude-11a/", + "originalTitle": "Interlude 11a", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: Bitch" + }, + { + "url": "https://parahumans.wordpress.com/2012/06/17/interlude-11b/", + "originalTitle": "Interlude 11b (Anniversary Bonus)", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: Theo" + }, + { + "url": "https://parahumans.wordpress.com/2012/06/18/interlude-11c/", + "originalTitle": "Interlude 11c (Anniversary Bonus)", + "simplifiedTitle": "Interlude III", + "characterNamesTitle": "Interlude: Elle" + }, + { + "url": "https://parahumans.wordpress.com/2012/06/19/interlude-11d/", + "originalTitle": "Interlude 11d", + "simplifiedTitle": "Interlude IV", + "characterNamesTitle": "Interlude: Armsmaster" + }, + { + "url": "https://parahumans.wordpress.com/2012/06/20/interlude-11e/", + "originalTitle": "Interlude 11e (Anniversary Bonus)", + "simplifiedTitle": "Interlude V", + "characterNamesTitle": "Interlude: Hookwolf" + }, + { + "url": "https://parahumans.wordpress.com/2012/06/21/interlude-11f/", + "originalTitle": "Interlude 11f (Anniversary Bonus)", + "simplifiedTitle": "Interlude VI", + "characterNamesTitle": "Interlude: Dinah" + }, + { + "url": "https://parahumans.wordpress.com/2012/06/22/interlude-11g/", + "originalTitle": "Interlude 11g (Anniversary Bonus)", + "simplifiedTitle": "Interlude VII", + "characterNamesTitle": "Interlude: Cherish" + }, + { + "url": "https://parahumans.wordpress.com/2012/06/23/interlude-11h/", + "originalTitle": "Interlude 11h", + "simplifiedTitle": "Interlude VIII", + "characterNamesTitle": "Interlude: Amy" + } + ] + }, + { + "label": "Arc 12", + "title": "Plague", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2012/06/26/plague-12-1/", + "originalTitle": "Plague 12.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2012/06/30/plague-12-2/", + "originalTitle": "Plague 12.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2012/07/03/plague-12-3/", + "originalTitle": "Plague 12.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2012/07/07/plague-12-4/", + "originalTitle": "Plague 12.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2012/07/10/plague-12-5/", + "originalTitle": "Plague 12.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2012/07/14/plague-12-6/", + "originalTitle": "Plague 12.6", + "simplifiedTitle": "6" + }, + { + "url": "https://parahumans.wordpress.com/2012/07/17/plague-12-7/", + "originalTitle": "Plague 12.7", + "simplifiedTitle": "7" + }, + { + "url": "https://parahumans.wordpress.com/2012/07/21/plague-12-8/", + "originalTitle": "Plague 12.8", + "simplifiedTitle": "8" + }, + { + "url": "https://parahumans.wordpress.com/2012/07/24/interlude-12/", + "originalTitle": "Interlude 12", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: Jack" + }, + { + "url": "https://parahumans.wordpress.com/2012/07/26/interlude-12%C2%BD/", + "originalTitle": "Interlude 12½ (Bonus)", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: Jamie" + } + ] + }, + { + "label": "Arc 13", + "title": "Snare", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2012/07/28/snare-13-1/", + "originalTitle": "Snare 13.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2012/07/31/snare-13-2/", + "originalTitle": "Snare 13.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2012/08/02/interlude-13%C2%BD-donation-bonus/", + "originalTitle": "Interlude 13½ (Bonus)", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: Aisha" + }, + { + "url": "https://parahumans.wordpress.com/2012/08/04/snare-13-3/", + "originalTitle": "Snare 13.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2012/08/07/snare-13-4/", + "originalTitle": "Snare 13.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2012/08/11/snare-13-5/", + "originalTitle": "Snare 13.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2012/08/14/snare-13-6/", + "originalTitle": "Snare 13.6", + "simplifiedTitle": "6" + }, + { + "url": "https://parahumans.wordpress.com/2012/08/18/snare-13-7/", + "originalTitle": "Snare 13.7", + "simplifiedTitle": "7" + }, + { + "url": "https://parahumans.wordpress.com/2012/08/21/snare-13-8/", + "originalTitle": "Snare 13.8", + "simplifiedTitle": "8" + }, + { + "url": "https://parahumans.wordpress.com/2012/08/25/snare-13-09/", + "originalTitle": "Snare 13.9", + "simplifiedTitle": "9" + }, + { + "url": "https://parahumans.wordpress.com/2012/08/28/snare-13-10/", + "originalTitle": "Snare 13.10", + "simplifiedTitle": "10" + }, + { + "url": "https://parahumans.wordpress.com/2012/09/01/interlude-13/", + "originalTitle": "Interlude 13", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: Piggot" + } + ] + }, + { + "label": "Arc 14", + "title": "Prey", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2012/09/04/prey-14-1/", + "originalTitle": "Prey 14.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2012/09/08/prey-14-2/", + "originalTitle": "Prey 14.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2012/09/11/prey-14-3/", + "originalTitle": "Prey 14.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2012/09/15/prey-14-4/", + "originalTitle": "Prey 14.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2012/09/18/prey-14-5/", + "originalTitle": "Prey 14.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2012/09/22/prey-14-6/", + "originalTitle": "Prey 14.6", + "simplifiedTitle": "6" + }, + { + "url": "https://parahumans.wordpress.com/2012/09/25/prey-14-7/", + "originalTitle": "Prey 14.7", + "simplifiedTitle": "7" + }, + { + "url": "https://parahumans.wordpress.com/2012/09/29/prey-14-8/", + "originalTitle": "Prey 14.8", + "simplifiedTitle": "8" + }, + { + "url": "https://parahumans.wordpress.com/2012/10/02/prey-14-9/", + "originalTitle": "Prey 14.9", + "simplifiedTitle": "9" + }, + { + "url": "https://parahumans.wordpress.com/2012/10/06/prey-14-10/", + "originalTitle": "Prey 14.10", + "simplifiedTitle": "10" + }, + { + "url": "https://parahumans.wordpress.com/2012/10/09/prey-14-11/", + "originalTitle": "Prey 14.11", + "simplifiedTitle": "11" + }, + { + "url": "https://parahumans.wordpress.com/2012/10/11/interlude-14/", + "originalTitle": "Interlude 14", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: Sierra" + }, + { + "url": "https://parahumans.wordpress.com/2012/10/13/interlude-14-5-bonus-interlude/", + "originalTitle": "Interlude 14.5 (Bonus Interlude)", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: Legend" + } + ] + }, + { + "label": "Arc 15", + "title": "Colony", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2012/10/16/colony-15-1/", + "originalTitle": "Colony 15.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2012/10/18/interlude-15-donation-bonus/", + "originalTitle": "Interlude 15 (Bonus)", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: Carol" + }, + { + "url": "https://parahumans.wordpress.com/2012/10/20/colony-15-2/", + "originalTitle": "Colony 15.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2012/10/23/colony-15-3/", + "originalTitle": "Colony 15.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2012/10/25/interlude-15-donation-bonus-2/", + "originalTitle": "Interlude 15 (Bonus #2)", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: Grue" + }, + { + "url": "https://parahumans.wordpress.com/2012/10/27/colony-15-4/", + "originalTitle": "Colony 15.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2012/10/30/colony-15-5/", + "originalTitle": "Colony 15.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2012/11/03/colony-15-6/", + "originalTitle": "Colony 15.6", + "simplifiedTitle": "6" + }, + { + "url": "https://parahumans.wordpress.com/2012/11/06/colony-15-7/", + "originalTitle": "Colony 15.7", + "simplifiedTitle": "7" + }, + { + "url": "https://parahumans.wordpress.com/2012/11/08/interlude-15-donation-bonus-3/", + "originalTitle": "Interlude 15 (Bonus #3)", + "simplifiedTitle": "Interlude III", + "characterNamesTitle": "Interlude: Rebecca" + }, + { + "url": "https://parahumans.wordpress.com/2012/11/10/colony-15-8/", + "originalTitle": "Colony 15.8", + "simplifiedTitle": "8" + }, + { + "url": "https://parahumans.wordpress.com/2012/11/13/colony-15-9/", + "originalTitle": "Colony 15.9", + "simplifiedTitle": "9" + }, + { + "url": "https://parahumans.wordpress.com/2012/11/17/colony-15-10/", + "originalTitle": "Colony 15.10", + "simplifiedTitle": "10" + }, + { + "url": "https://parahumans.wordpress.com/2012/11/20/interlude-15/", + "originalTitle": "Interlude 15", + "simplifiedTitle": "Interlude IV", + "characterNamesTitle": "Interlude: Triumph" + } + ] + }, + { + "label": "Arc 16", + "title": "Monarch", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2012/11/24/monarch-16-1/", + "originalTitle": "Monarch 16.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2012/11/27/monarch-16-2/", + "originalTitle": "Monarch 16.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2012/11/29/interlude-16-donation-bonus/", + "originalTitle": "Interlude 16 (Bonus)", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: Lady" + }, + { + "url": "https://parahumans.wordpress.com/2012/12/01/monarch-16-3/", + "originalTitle": "Monarch 16.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2012/12/04/monarch-16-4/", + "originalTitle": "Monarch 16.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2012/12/08/monarch-16-5/", + "originalTitle": "Monarch 16.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2012/12/11/monarch-16-6/", + "originalTitle": "Monarch 16.6", + "simplifiedTitle": "6" + }, + { + "url": "https://parahumans.wordpress.com/2012/12/13/interlude-16-donation-bonus-2/", + "originalTitle": "Interlude 16 (Bonus #2)", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: Defiant" + }, + { + "url": "https://parahumans.wordpress.com/2012/12/15/monarch-16-7/", + "originalTitle": "Monarch 16.7", + "simplifiedTitle": "7" + }, + { + "url": "https://parahumans.wordpress.com/2012/12/18/monarch-16-8/", + "originalTitle": "Monarch 16.8", + "simplifiedTitle": "8" + }, + { + "url": "https://parahumans.wordpress.com/2012/12/22/monarch-16-9/", + "originalTitle": "Monarch 16.9", + "simplifiedTitle": "9" + }, + { + "url": "https://parahumans.wordpress.com/2012/12/25/monarch-16-10/", + "originalTitle": "Monarch 16.10", + "simplifiedTitle": "10" + }, + { + "url": "https://parahumans.wordpress.com/2012/12/27/interlude-16-donation-bonus-3/", + "originalTitle": "Interlude 16 (Bonus #3)", + "simplifiedTitle": "Interlude III", + "characterNamesTitle": "Interlude: Marquis" + }, + { + "url": "https://parahumans.wordpress.com/2012/12/29/monarch-16-11/", + "originalTitle": "Monarch 16.11", + "simplifiedTitle": "11" + }, + { + "url": "https://parahumans.wordpress.com/2013/01/01/monarch-16-12/", + "originalTitle": "Monarch 16.12", + "simplifiedTitle": "12" + }, + { + "url": "https://parahumans.wordpress.com/2013/01/05/monarch-16-13/", + "originalTitle": "Monarch 16.13", + "simplifiedTitle": "13" + } + ] + }, + { + "label": "Arc 17", + "title": "Migration", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2013/01/08/migration-17-1/", + "originalTitle": "Migration 17.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2013/01/09/migration-17-2/", + "originalTitle": "Migration 17.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2013/01/10/migration-17-3/", + "originalTitle": "Migration 17.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2013/01/11/migration-17-4/", + "originalTitle": "Migration 17.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2013/01/12/migration-17-5/", + "originalTitle": "Migration 17.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2013/01/13/migration-17-6/", + "originalTitle": "Migration 17.6", + "simplifiedTitle": "6" + }, + { + "url": "https://parahumans.wordpress.com/2013/01/14/migration-17-7/", + "originalTitle": "Migration 17.7", + "simplifiedTitle": "7" + }, + { + "url": "https://parahumans.wordpress.com/2013/01/15/migration-17-8/", + "originalTitle": "Migration 17.8", + "simplifiedTitle": "8" + } + ] + }, + { + "label": "Arc 18", + "title": "Queen", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2013/01/19/queen-18-1/", + "originalTitle": "Queen 18.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2013/01/22/queen-18-2/", + "originalTitle": "Queen 18.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2013/01/24/interlude-18x/", + "originalTitle": "Interlude 18 (Bonus #1)", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: The Most Powerful Man in the World" + }, + { + "url": "https://parahumans.wordpress.com/2013/01/26/queen-18-3/", + "originalTitle": "Queen 18.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2013/01/29/queen-18-4/", + "originalTitle": "Queen 18.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2013/01/31/interlude-18-donation-bonus-2/", + "originalTitle": "Interlude 18 (Bonus #2)", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: Justin" + }, + { + "url": "https://parahumans.wordpress.com/2013/02/02/queen-18-5/", + "originalTitle": "Queen 18.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2013/02/05/monarch-18-6/", + "originalTitle": "Queen 18.6", + "simplifiedTitle": "6" + }, + { + "url": "https://parahumans.wordpress.com/2013/02/07/interlude-18-donation-bonus-3/", + "originalTitle": "Interlude 18 (Bonus #3)", + "simplifiedTitle": "Interlude III", + "characterNamesTitle": "Interlude: Jessica Yamada" + }, + { + "url": "https://parahumans.wordpress.com/2013/02/09/queen-18-7/", + "originalTitle": "Queen 18.7", + "simplifiedTitle": "7" + }, + { + "url": "https://parahumans.wordpress.com/2013/02/12/queen-18-8/", + "originalTitle": "Queen 18.8", + "simplifiedTitle": "8" + }, + { + "url": "https://parahumans.wordpress.com/2013/02/14/interlude-18-donation-bonus-4/", + "originalTitle": "Interlude 18 (Bonus #4)", + "simplifiedTitle": "Interlude IV", + "characterNamesTitle": "Interlude: Faultline" + }, + { + "url": "https://parahumans.wordpress.com/2013/02/16/interlude-18/", + "originalTitle": "Interlude 18", + "simplifiedTitle": "Interlude V", + "characterNamesTitle": "Interlude: Echidna" + } + ] + }, + { + "label": "Arc 19", + "title": "Scourge", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2013/02/19/scourge-19-1/", + "originalTitle": "Scourge 19.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2013/02/23/scourge-19-2/", + "originalTitle": "Scourge 19.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2013/02/26/scourge-19-3/", + "originalTitle": "Scourge 19.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2013/02/28/interlude-19-donation-bonus-1/", + "originalTitle": "Interlude 19 (Bonus #1)", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: Blasto" + }, + { + "url": "https://parahumans.wordpress.com/2013/03/02/scourge-19-4/", + "originalTitle": "Scourge 19.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2013/03/05/scourge-19-5/", + "originalTitle": "Scourge 19.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2013/03/09/scourge-19-6/", + "originalTitle": "Scourge 19.6", + "simplifiedTitle": "6" + }, + { + "url": "https://parahumans.wordpress.com/2013/03/12/scourge-19-7/", + "originalTitle": "Scourge 19.7", + "simplifiedTitle": "7" + }, + { + "url": "https://parahumans.wordpress.com/2013/03/16/interlude-19-y/", + "originalTitle": "Interlude 19 (Bonus #2)", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: XxVoid_CowboyxX" + }, + { + "url": "https://parahumans.wordpress.com/2013/03/19/interlude-19/", + "originalTitle": "Interlude 19", + "simplifiedTitle": "Interlude III", + "characterNamesTitle": "Interlude: Emma" + } + ] + }, + { + "label": "Arc 20", + "title": "Chrysalis", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2013/03/21/chrysalis-20-1/", + "originalTitle": "Chrysalis 20.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2013/03/23/chrysalis-20-2/", + "originalTitle": "Chrysalis 20.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2013/03/26/chrysalis-20-3/", + "originalTitle": "Chrysalis 20.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2013/03/30/chrysalis-20-4/", + "originalTitle": "Chrysalis 20.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2013/04/02/chrysalis-20-5/", + "originalTitle": "Chrysalis 20.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2013/04/04/interlude-20-donation-bonus-1/", + "originalTitle": "Interlude 20 (Bonus #1)", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: Stan" + }, + { + "url": "https://parahumans.wordpress.com/2013/04/06/interlude-20/", + "originalTitle": "Interlude 20", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: Accord" + } + ] + }, + { + "label": "Arc 21", + "title": "Imago", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2013/04/09/imago-21-1/", + "originalTitle": "Imago 21.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2013/04/13/imago-21-2/", + "originalTitle": "Imago 21.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2013/04/16/imago-21-3/", + "originalTitle": "Imago 21.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2013/04/18/imago-21-4/", + "originalTitle": "Imago 21.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2013/04/20/imago-21-5/", + "originalTitle": "Imago 21.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2013/04/23/imago-21-6/", + "originalTitle": "Imago 21.6", + "simplifiedTitle": "6" + }, + { + "url": "https://parahumans.wordpress.com/2013/04/25/imago-21-7/", + "originalTitle": "Imago 21.7", + "simplifiedTitle": "7" + }, + { + "url": "https://parahumans.wordpress.com/2013/04/27/interlude-21-donation-bonus-1/", + "originalTitle": "Interlude 21 (Bonus #1)", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: The Number Man" + }, + { + "url": "https://parahumans.wordpress.com/2013/04/30/interlude-21/", + "originalTitle": "Interlude 21", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: Sabah" + } + ] + }, + { + "label": "Arc 22", + "title": "Cell", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2013/05/04/cell-22-1/", + "originalTitle": "Cell 22.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2013/05/07/cell-22-2/", + "originalTitle": "Cell 22.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2013/05/09/cell-22-3/", + "originalTitle": "Cell 22.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2013/05/11/cell-22-4", + "originalTitle": "Cell 22.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2013/05/14/cell-22-5/", + "originalTitle": "Cell 22.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2013/05/16/cell-22-6/", + "originalTitle": "Cell 22.6", + "simplifiedTitle": "6" + }, + { + "url": "https://parahumans.wordpress.com/2013/05/18/interlude-22/", + "originalTitle": "Interlude 22", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: Charlotte" + }, + { + "url": "https://parahumans.wordpress.com/2013/05/21/interlude-22-donation-bonus-1/", + "originalTitle": "Interlude 22 (Bonus #1)", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: Kenta" + } + ] + }, + { + "label": "Arc 23", + "title": "Drone", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2013/05/25/drone-23-1/", + "originalTitle": "Drone 23.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2013/05/28/drone-23-2/", + "originalTitle": "Drone 23.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2013/05/30/drone-23-3/", + "originalTitle": "Drone 23.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2013/06/01/drone-23-4/", + "originalTitle": "Drone 23.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2013/06/04/drone-23-5/", + "originalTitle": "Drone 23.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2013/06/06/interlude-23/", + "originalTitle": "Interlude 23", + "simplifiedTitle": "Interlude", + "characterNamesTitle": "Interlude: Number Thirty-Six" + } + ] + }, + { + "label": "Arc 24", + "title": "Crushed", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2013/06/08/crushed-24-1/", + "originalTitle": "Crushed 24.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2013/06/11/crushed-24-2/", + "originalTitle": "Crushed 24.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2013/06/15/crushed-24-3/", + "originalTitle": "Crushed 24.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2013/06/18/crushed-24-4/", + "originalTitle": "Crushed 24.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2013/06/20/crushed-24-5/", + "originalTitle": "Crushed 24.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2013/06/22/interlude-24/", + "originalTitle": "Interlude 24", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: Chevalier" + }, + { + "url": "https://parahumans.wordpress.com/2013/06/25/interlude-24-donation-bonus-1/", + "originalTitle": "Interlude 24 (Bonus #1)", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: Aftermath" + } + ] + }, + { + "label": "Arc 25", + "title": "Scarab", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2013/06/29/scarab-25-1/", + "originalTitle": "Scarab 25.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2013/07/02/scarab-25-2/", + "originalTitle": "Scarab 25.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2013/07/06/scarab-25-3/", + "originalTitle": "Scarab 25.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2013/07/09/scarab-25-4/", + "originalTitle": "Scarab 25.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2013/07/11/scarab-25-5/", + "originalTitle": "Scarab 25.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2013/07/13/scarab-25-6/", + "originalTitle": "Scarab 25.6", + "simplifiedTitle": "6" + }, + { + "url": "https://parahumans.wordpress.com/2013/07/16/interlude-25/", + "originalTitle": "Interlude 25", + "simplifiedTitle": "Interlude", + "characterNamesTitle": "Interlude: Bonesaw" + } + ] + }, + { + "label": "Arc 26", + "title": "Sting", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2013/07/18/sting-26-1/", + "originalTitle": "Sting 26.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2013/07/20/sting-26-2/", + "originalTitle": "Sting 26.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2013/07/23/sting-26-3/", + "originalTitle": "Sting 26.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2013/07/25/interlude-26-donation-bonus-1/", + "originalTitle": "Interlude 26 (Bonus #1)", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: Saint" + }, + { + "url": "https://parahumans.wordpress.com/2013/07/27/sting-26-4/", + "originalTitle": "Sting 26.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2013/07/30/sting-26-5/", + "originalTitle": "Sting 26.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2013/08/03/sting-26-6/", + "originalTitle": "Sting 26.6", + "simplifiedTitle": "6" + }, + { + "url": "https://parahumans.wordpress.com/2013/08/06/interlude-26a/", + "originalTitle": "Interlude 26a", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: Golem" + }, + { + "url": "https://parahumans.wordpress.com/2013/08/08/interlude-26b/", + "originalTitle": "Interlude 26b", + "simplifiedTitle": "Interlude III", + "characterNamesTitle": "Interlude: Golem, part 2" + }, + { + "url": "https://parahumans.wordpress.com/2013/08/10/interlude-26/", + "originalTitle": "Interlude 26", + "simplifiedTitle": "Interlude IV", + "characterNamesTitle": "Interlude: The Warrior" + } + ] + }, + { + "label": "Arc 27", + "title": "Extinction", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2013/08/13/extinction-27-1/", + "originalTitle": "Extinction 27.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2013/08/17/extinction-27-2/", + "originalTitle": "Extinction 27.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2013/08/20/extinction-27-3/", + "originalTitle": "Extinction 27.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2013/08/22/extinction-27-4/", + "originalTitle": "Extinction 27.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2013/08/24/extinction-27-5/", + "originalTitle": "Extinction 27.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2013/08/27/interlude-27/", + "originalTitle": "Interlude 27", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: Eidolon" + }, + { + "url": "https://parahumans.wordpress.com/2013/08/29/interlude-27b/", + "originalTitle": "Interlude 27b", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: Four Words" + } + ] + }, + { + "label": "Arc 28", + "title": "Cockroaches", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2013/08/31/cockroaches-28-1/", + "originalTitle": "Cockroaches 28.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2013/09/03/cockroaches-28-2/", + "originalTitle": "Cockroaches 28.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2013/09/05/cockroaches-28-3/", + "originalTitle": "Cockroaches 28.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2013/09/07/cockroaches-28-4/", + "originalTitle": "Cockroaches 28.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2013/09/10/cockroaches-28-5/", + "originalTitle": "Cockroaches 28.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2013/09/14/cockroaches-28-6/", + "originalTitle": "Cockroaches 28.6", + "simplifiedTitle": "6" + }, + { + "url": "https://parahumans.wordpress.com/2013/09/17/interlude-28/", + "originalTitle": "Interlude 28", + "simplifiedTitle": "Interlude", + "characterNamesTitle": "Interlude: Doctor Mother" + } + ] + }, + { + "label": "Arc 29", + "title": "Venom", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2013/09/19/venom-29-1/", + "originalTitle": "Venom 29.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2013/09/21/venom-29-2/", + "originalTitle": "Venom 29.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2013/09/24/venom-29-3/", + "originalTitle": "Venom 29.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2013/09/26/venom-29-4/", + "originalTitle": "Venom 29.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2013/09/28/venom-29-5/", + "originalTitle": "Venom 29.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2013/10/01/venom-29-6/", + "originalTitle": "Venom 29.6", + "simplifiedTitle": "6" + }, + { + "url": "https://parahumans.wordpress.com/2013/10/03/venom-29-7/", + "originalTitle": "Venom 29.7", + "simplifiedTitle": "7" + }, + { + "url": "https://parahumans.wordpress.com/2013/10/05/venom-29-8/", + "originalTitle": "Venom 29.8", + "simplifiedTitle": "8" + }, + { + "url": "https://parahumans.wordpress.com/2013/10/08/venom-29-9/", + "originalTitle": "Venom 29.9", + "simplifiedTitle": "9" + }, + { + "url": "https://parahumans.wordpress.com/2013/10/12/interlude-29/", + "originalTitle": "Interlude 29", + "simplifiedTitle": "Interlude", + "characterNamesTitle": "Interlude: Fortuna" + } + ] + }, + { + "label": "Arc 30", + "title": "Speck", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2013/10/15/speck-30-1/", + "originalTitle": "Speck 30.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2013/10/17/speck-30-2/", + "originalTitle": "Speck 30.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2013/10/19/speck-30-3/", + "originalTitle": "Speck 30.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2013/10/22/speck-30-4/", + "originalTitle": "Speck 30.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2013/10/24/speck-30-5/", + "originalTitle": "Speck 30.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2013/10/26/speck-30-6/", + "originalTitle": "Speck 30.6", + "simplifiedTitle": "6" + }, + { + "url": "https://parahumans.wordpress.com/2013/10/29/30-7/", + "originalTitle": "Speck 30.7", + "simplifiedTitle": "7" + } + ] + }, + { + "label": "Epilogue", + "title": "Teneral", + "chapters": [ + { + "url": "https://parahumans.wordpress.com/2013/11/02/teneral-e-1/", + "originalTitle": "Teneral e.1", + "simplifiedTitle": "1" + }, + { + "url": "https://parahumans.wordpress.com/2013/11/05/teneral-e-2/", + "originalTitle": "Teneral e.2", + "simplifiedTitle": "2" + }, + { + "url": "https://parahumans.wordpress.com/2013/11/09/teneral-e-3/", + "originalTitle": "Teneral e.3", + "simplifiedTitle": "3" + }, + { + "url": "https://parahumans.wordpress.com/2013/11/12/teneral-e-4/", + "originalTitle": "Teneral e.4", + "simplifiedTitle": "4" + }, + { + "url": "https://parahumans.wordpress.com/2013/11/16/teneral-e-5/", + "originalTitle": "Teneral e.5", + "simplifiedTitle": "5" + }, + { + "url": "https://parahumans.wordpress.com/2013/11/19/interlude-end/", + "originalTitle": "Interlude: End", + "simplifiedTitle": "End" + } + ] + } +] diff --git a/lib/choose-chapter-title.js b/lib/choose-chapter-title.js new file mode 100644 index 0000000..d5fd7d3 --- /dev/null +++ b/lib/choose-chapter-title.js @@ -0,0 +1,27 @@ +"use strict"; + +module.exports = (chapterData, chapterTitleStyle) => { + if (chapterTitleStyle === "original") { + if (!chapterData.originalTitle) { + throw new Error(`originalTitle not found in chapter data for ${chapterData.url}`); + } + return chapterData.originalTitle; + } + if (chapterTitleStyle === "simplified") { + if (!chapterData.simplifiedTitle) { + throw new Error(`simplifiedTitle not found in chapter data for ${chapterData.url}`); + } + return chapterData.simplifiedTitle; + } + if (chapterTitleStyle === "character-names") { + if (!chapterData.characterNamesTitle) { + if (!chapterData.simplifiedTitle) { + throw new Error(`Neither characterNamesTitle nor simplifiedTitle found in chapter data for ${chapterData.url}`); + } + return chapterData.simplifiedTitle; + } + return chapterData.characterNamesTitle; + } + + throw new Error(`Invalid chapter title style: ${chapterTitleStyle}`); +}; diff --git a/lib/convert.js b/lib/convert.js index 3a7ff9c..d51876d 100644 --- a/lib/convert.js +++ b/lib/convert.js @@ -4,10 +4,32 @@ const fs = require("fs").promises; const { performance } = require("perf_hooks"); const workerpool = require("workerpool"); const cliProgress = require("cli-progress"); +const chooseChapterTitle = require("./choose-chapter-title.js"); -module.exports = async (cachePath, manifestPath, contentPath, book, concurrentJobs) => { - const manifestContents = await fs.readFile(manifestPath, { encoding: "utf-8" }); - const chapters = JSON.parse(manifestContents); +module.exports = +async (cachePath, manifestPath, chapterDataPath, contentPath, book, concurrentJobs, chapterTitleStyle) => { + const [manifestContents, chapterDataContents] = await Promise.all([ + fs.readFile(manifestPath, { encoding: "utf-8" }), + fs.readFile(chapterDataPath, { encoding: "utf-8" }) + ]); + const manifestChapters = JSON.parse(manifestContents); + const chapterData = JSON.parse(chapterDataContents); + + for (const chapter of manifestChapters) { + let found = false; + for (const arc of chapterData) { + for (const chapterInArc of arc.chapters) { + if (chapter.url === chapterInArc.url) { + chapter.title = chooseChapterTitle(chapterInArc, chapterTitleStyle); + found = true; + break; + } + } + } + if (!found) { + throw new Error(`Chapter data not found for ${chapter.url}`); + } + } console.log("Converting raw downloaded HTML to EPUB chapters"); const progress = new cliProgress.SingleBar({ @@ -17,7 +39,7 @@ module.exports = async (cachePath, manifestPath, contentPath, book, concurrentJo }, cliProgress.Presets.shades_classic); const start = performance.now(); - progress.start(chapters.length, 0, { time: " " }); + progress.start(manifestChapters.length, 0, { time: " " }); const poolOptions = {}; if (concurrentJobs !== undefined) { @@ -26,7 +48,7 @@ module.exports = async (cachePath, manifestPath, contentPath, book, concurrentJo const pool = workerpool.pool(path.resolve(__dirname, "convert-worker.js"), poolOptions); const warnings = []; - await Promise.all(chapters.map(async chapter => { + await Promise.all(manifestChapters.map(async chapter => { const inputPath = path.resolve(cachePath, chapter.filename); const destFileName = `${path.basename(chapter.filename, ".html")}.xhtml`; diff --git a/lib/scaffold.js b/lib/scaffold.js index cf63865..99c88e1 100644 --- a/lib/scaffold.js +++ b/lib/scaffold.js @@ -1,6 +1,7 @@ "use strict"; const fs = require("fs").promises; const path = require("path"); +const chooseChapterTitle = require("./choose-chapter-title.js"); const BOOK_PUBLISHER = "Domenic Denicola"; const BOOK_AUTHOR = "Wildbow"; @@ -17,15 +18,18 @@ module.exports = async ( contentPath, chaptersPath, manifestPath, - bookInfo + chapterDataPath, + bookInfo, + chapterTitleStyle ) => { await Promise.all([ fs.cp(scaffoldingPath, bookPath, { recursive: true, filter: noThumbs }), fs.cp(coverImagePath, path.resolve(bookPath, "OEBPS", COVER_IMAGE_FILENAME)), - getChaptersAndDatePublished(contentPath, chaptersPath, manifestPath).then(([chapters, datePublished]) => { + getChapterInfo(contentPath, chaptersPath, manifestPath, chapterDataPath, chapterTitleStyle).then(info => { return Promise.all([ - writeOPF(chapters, contentPath, bookInfo, datePublished), - writeNav(chapters, contentPath) + writeOPF(contentPath, bookInfo, info.manifestAndSpineFiles, info.datePublished), + writeNav(contentPath, info.manifestAndSpineFiles, info.tocHTML), + writeArcTitlePages(chaptersPath, info.arcTitlePages) ]); }) ]); @@ -37,13 +41,13 @@ function noThumbs(filePath) { return path.basename(filePath) !== "Thumbs.db"; } -function writeOPF(chapters, contentPath, bookInfo, datePublished) { - const manifestChapters = chapters.map(c => { - return ` `; +function writeOPF(contentPath, bookInfo, manifestAndSpineFiles, datePublished) { + const manifestItems = manifestAndSpineFiles.map(f => { + return ` `; }).join("\n"); - const spineChapters = chapters.map(c => { - return ` `; + const spineItemrefs = manifestAndSpineFiles.map(f => { + return ` `; }).join("\n"); const dateWithoutMilliseconds = `${(new Date()).toISOString().split(".")[0]}Z`; @@ -81,12 +85,12 @@ function writeOPF(chapters, contentPath, bookInfo, datePublished) { -${manifestChapters} +${manifestItems} -${spineChapters} +${spineItemrefs} `; /* eslint-enable max-len */ @@ -95,11 +99,7 @@ ${spineChapters} } -function writeNav(chapters, contentPath) { - const navPoints = chapters.map(c => { - return `
  • ${c.title}
  • `; - }).join("\n"); - +function writeNav(contentPath, manifestAndSpineFiles, tocHTML) { const contents = ` @@ -110,15 +110,13 @@ function writeNav(chapters, contentPath) { @@ -127,27 +125,118 @@ ${navPoints} return fs.writeFile(path.resolve(contentPath, NAV_FILENAME), contents); } -async function getChaptersAndDatePublished(contentPath, chaptersPath, manifestPath) { +async function getChapterInfo(contentPath, chaptersPath, manifestPath, chapterDataPath, chapterTitleStyle) { const hrefPrefix = `${path.relative(contentPath, chaptersPath)}/`; - const manifestContents = await fs.readFile(manifestPath, { encoding: "utf-8" }); + const [manifestContents, chapterDataContents] = await Promise.all([ + fs.readFile(manifestPath, { encoding: "utf-8" }), + fs.readFile(chapterDataPath, { encoding: "utf-8" }) + ]); const manifestChapters = JSON.parse(manifestContents); - - const filenames = await fs.readdir(chaptersPath); - - const chapters = filenames - .filter(f => path.extname(f) === ".xhtml") - .sort() - .map((f, i) => { - return { - id: path.basename(f), - title: manifestChapters[i].title, - href: `${hrefPrefix}${f}` - }; + const chapterData = JSON.parse(chapterDataContents); + + augmentAndCheckChapterData(chapterData, manifestChapters); + + const arcTitlePages = []; + const manifestAndSpineFiles = []; + let tocHTML = "
      \n"; + let arcIdCounter = 0; + for (const arc of chapterData) { + const arcFilename = `arc${arcIdCounter}.xhtml`; + const arcId = path.basename(arcFilename, ".xhtml"); + const arcHref = `${hrefPrefix}${arcFilename}`; + + arcTitlePages.push({ + filename: arcFilename, + label: arc.label, + title: arc.title }); + manifestAndSpineFiles.push({ + id: arcId, + href: arcHref + }); + tocHTML += `
    1. + ${arcPlaintextTitle(arc)} +
        \n`; + + for (const chapter of arc.chapters) { + const chapterHref = `${hrefPrefix}${chapter.filename}`; + const chapterTitle = chooseChapterTitle(chapter, chapterTitleStyle); + manifestAndSpineFiles.push({ + id: path.basename(chapter.filename, ".xhtml"), + href: chapterHref + }); + + tocHTML += `
      1. ${chapterTitle}\n`; + } + tocHTML += `
      +
    2. \n`; + + ++arcIdCounter; + } + + tocHTML += `
    `; // We say that the publication date of the book is equal to the publication date of the last chapter. const { datePublished } = manifestChapters.at(-1); - return [chapters, datePublished]; + return { arcTitlePages, manifestAndSpineFiles, tocHTML, datePublished }; +} + +async function writeArcTitlePages(chaptersPath, arcTitlePages) { + const promises = []; + for (const arc of arcTitlePages) { + const output = ` + + + + + ${arcPlaintextTitle(arc)} + + +

    ${arc.label} ${arc.title}

    + +`; + + promises.push(fs.writeFile(path.resolve(chaptersPath, arc.filename), output)); + } + + await Promise.all(promises); +} + +function augmentAndCheckChapterData(chapterData, manifestChapters) { + for (const chapter of manifestChapters) { + let found = false; + for (const arc of chapterData) { + for (const chatperInArc of arc.chapters) { + if (chapter.url === chatperInArc.url) { + chatperInArc.filename = `${path.basename(chapter.filename, ".html")}.xhtml`; + found = true; + break; + } + } + } + if (!found) { + throw new Error(`Chapter data not found for ${chapter.url} which appeared in the manifest`); + } + } + + for (const arc of chapterData) { + for (const chapter of arc.chapters) { + let found = false; + for (const manifestChapter of manifestChapters) { + if (chapter.url === manifestChapter.url) { + found = true; + break; + } + } + if (!found) { + throw new Error(`Chapter data found for ${chapter.url} which did not appear in the manifest`); + } + } + } +} + +function arcPlaintextTitle(arc) { + return `${arc.label}: ${arc.title}`; } diff --git a/lib/worm-scraper.js b/lib/worm-scraper.js index 60c1f88..fc9d51d 100644 --- a/lib/worm-scraper.js +++ b/lib/worm-scraper.js @@ -28,6 +28,13 @@ const { argv } = yargs describe: "The book to operate on", requiresArg: true }) + .option("t", { + alias: "chapter-titles", + default: "simplified", + choices: ["simplified", "character-names", "original"], + describe: "How to format chapter titles", + requiresArg: true + }) .option("c", { alias: "cache", default: "cache", @@ -61,6 +68,7 @@ const outputFilename = argv.out === OUTPUT_DEFAULT ? `${books[argv.book].title}. const cachePath = path.resolve(argv.cache, argv.book); const manifestPath = path.resolve(cachePath, "manifest.json"); +const chapterDataPath = path.resolve(__dirname, "../chapter-data", `${argv.book}.json`); const scaffoldingPath = path.resolve(__dirname, "../scaffolding"); const coverImagePath = path.resolve(__dirname, "../covers", `${argv.book}.jpg`); @@ -80,10 +88,10 @@ if (argv._.includes("download")) { } if (argv._.includes("convert")) { - commands.push(() => { - return fs.rm(chaptersPath, { force: true, recursive: true, maxRetries: 3 }) - .then(() => fs.mkdir(chaptersPath, { recursive: true })) - .then(() => convert(cachePath, manifestPath, chaptersPath, argv.book, argv.jobs)); + commands.push(async () => { + await fs.rm(chaptersPath, { force: true, recursive: true, maxRetries: 3 }); + await fs.mkdir(chaptersPath, { recursive: true }); + await convert(cachePath, manifestPath, chapterDataPath, chaptersPath, argv.book, argv.jobs, argv["chapter-titles"]); }); } @@ -96,7 +104,9 @@ if (argv._.includes("scaffold")) { contentPath, chaptersPath, manifestPath, - bookInfo + chapterDataPath, + bookInfo, + argv["chapter-titles"] )); } From 514b21df6b575d5accb038d823660c0fde7bf7dd Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Wed, 1 Jan 2025 18:29:18 +0900 Subject: [PATCH 02/11] Looking pretty good --- lib/convert-worker.js | 3 ++- lib/scaffold.js | 5 +++-- scaffolding/OEBPS/chapter.css | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 scaffolding/OEBPS/chapter.css diff --git a/lib/convert-worker.js b/lib/convert-worker.js index cd5ee87..2c93129 100644 --- a/lib/convert-worker.js +++ b/lib/convert-worker.js @@ -27,11 +27,12 @@ function getChapterString(chapter, book, rawChapterDoc) { + itemid="${chapter.url}" class="chapter"> ${chapter.title} + ${xml} `; diff --git a/lib/scaffold.js b/lib/scaffold.js index 99c88e1..d57fafc 100644 --- a/lib/scaffold.js +++ b/lib/scaffold.js @@ -167,7 +167,7 @@ async function getChapterInfo(contentPath, chaptersPath, manifestPath, chapterDa href: chapterHref }); - tocHTML += `
  • ${chapterTitle}\n`; + tocHTML += `
  • ${chapterTitle}
  • \n`; } tocHTML += ` \n`; @@ -188,10 +188,11 @@ async function writeArcTitlePages(chaptersPath, arcTitlePages) { for (const arc of arcTitlePages) { const output = ` - + ${arcPlaintextTitle(arc)} +

    ${arc.label} ${arc.title}

    diff --git a/scaffolding/OEBPS/chapter.css b/scaffolding/OEBPS/chapter.css new file mode 100644 index 0000000..e631395 --- /dev/null +++ b/scaffolding/OEBPS/chapter.css @@ -0,0 +1,18 @@ +:root.arc-title { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + text-align: center; +} + +:root.arc-title h1 { + font-size: 2.5em; + margin: 0; +} + +:root.arc-title .arc-label { + display: block; + font-size: 0.6em; + font-weight: normal; +} From 5acf72c6b4943e84188e350b61c3f84cb3e25403 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Wed, 1 Jan 2025 19:05:30 +0900 Subject: [PATCH 03/11] More tweaks. Mostly working. --- chapter-data/worm.json | 306 +--------------------------------- lib/convert.js | 24 +-- lib/scaffold.js | 15 +- scaffolding/OEBPS/chapter.css | 19 ++- 4 files changed, 35 insertions(+), 329 deletions(-) diff --git a/chapter-data/worm.json b/chapter-data/worm.json index 3e54d9c..d884398 100644 --- a/chapter-data/worm.json +++ b/chapter-data/worm.json @@ -5,37 +5,30 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2011/06/11/1-1/", - "originalTitle": "Gestation 1.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2011/06/14/gestation-1-2/", - "originalTitle": "Gestation 1.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2011/06/18/gestation-1-3/", - "originalTitle": "Gestation 1.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2011/06/21/gestation-1-4/", - "originalTitle": "Gestation 1.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2011/06/25/gestation-1-5/", - "originalTitle": "Gestation 1.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2011/06/28/gestation-1-6/", - "originalTitle": "Gestation 1.6", "simplifiedTitle": "6" }, { "url": "https://parahumans.wordpress.com/2011/07/02/interlude-1/", - "originalTitle": "Interlude 1", "simplifiedTitle": "Interlude", "characterNamesTitle": "Interlude: Danny" } @@ -47,52 +40,42 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2011/07/05/insinuation-2-1/", - "originalTitle": "Insinuation 2.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2011/07/09/insinuation-2-2/", - "originalTitle": "Insinuation 2.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2011/07/12/insinuation-2-3/", - "originalTitle": "Insinuation 2.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2011/07/16/insinuation-2-4/", - "originalTitle": "Insinuation 2.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2011/07/19/insinuation-2-5/", - "originalTitle": "Insinuation 2.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2011/07/23/insinuation-2-6/", - "originalTitle": "Insinuation 2.6", "simplifiedTitle": "6" }, { "url": "https://parahumans.wordpress.com/2011/07/26/insinuation-2-7/", - "originalTitle": "Insinuation 2.7", "simplifiedTitle": "7" }, { "url": "https://parahumans.wordpress.com/2011/07/30/insinuation-2-8/", - "originalTitle": "Insinuation 2.8", "simplifiedTitle": "8" }, { "url": "https://parahumans.wordpress.com/2011/08/02/insinuation-2-9/", - "originalTitle": "Insinuation 2.9", "simplifiedTitle": "9" }, { "url": "https://parahumans.wordpress.com/2011/08/06/interlude-2/", - "originalTitle": "Interlude 2", "simplifiedTitle": "Interlude", "characterNamesTitle": "Interlude: Victoria" } @@ -104,67 +87,54 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2011/08/09/agitation-3-1/", - "originalTitle": "Agitation 3.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2011/08/13/agitation-3-2/", - "originalTitle": "Agitation 3.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2011/08/16/agitation-3-3/", - "originalTitle": "Agitation 3.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2011/08/20/agitation-3-4/", - "originalTitle": "Agitation 3.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2011/08/23/agitation-3-5/", - "originalTitle": "Agitation 3.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2011/08/27/agitation-3-6/", - "originalTitle": "Agitation 3.6", "simplifiedTitle": "6" }, { "url": "https://parahumans.wordpress.com/2011/08/30/agitation-3-7/", - "originalTitle": "Agitation 3.7", "simplifiedTitle": "7" }, { "url": "https://parahumans.wordpress.com/2011/09/03/agitation-3-8/", - "originalTitle": "Agitation 3.8", "simplifiedTitle": "8" }, { "url": "https://parahumans.wordpress.com/2011/09/06/agitation-3-9/", - "originalTitle": "Agitation 3.9", "simplifiedTitle": "9" }, { "url": "https://parahumans.wordpress.com/2011/09/10/agitation-3-10/", - "originalTitle": "Agitation 3.10", "simplifiedTitle": "10" }, { "url": "https://parahumans.wordpress.com/2011/09/13/agitation-3-11/", - "originalTitle": "Agitation 3.11", "simplifiedTitle": "11" }, { "url": "https://parahumans.wordpress.com/2011/09/17/agitation-3-12/", - "originalTitle": "Agitation 3.12", "simplifiedTitle": "12" }, { "url": "https://parahumans.wordpress.com/2011/09/20/interlude-3-2/", - "originalTitle": "Interlude 3", "simplifiedTitle": "Interlude", "characterNamesTitle": "Interlude: Wards" } @@ -176,68 +146,55 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2011/09/24/shell-4-1/", - "originalTitle": "Shell 4.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2011/09/27/shell-4-2/", - "originalTitle": "Shell 4.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2011/10/01/shell-4-3/", - "originalTitle": "Shell 4.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2011/10/04/shell-4-4/", - "originalTitle": "Shell 4.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2011/10/08/shell-4-5/", - "originalTitle": "Shell 4.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2011/10/11/shell-4-6/", - "originalTitle": "Shell 4.6", "simplifiedTitle": "6" }, { "url": "https://parahumans.wordpress.com/2011/10/11/interlude-3%C2%BD-bonus/", - "originalTitle": "Interlude 3½ (Bonus)", "simplifiedTitle": "Interlude I", "characterNamesTitle": "Interlude: Kayden" }, { "url": "https://parahumans.wordpress.com/2011/10/15/shell-4-7/", - "originalTitle": "Shell 4.7", "simplifiedTitle": "7" }, { "url": "https://parahumans.wordpress.com/2011/10/18/shell-4-8/", - "originalTitle": "Shell 4.8", "simplifiedTitle": "8" }, { "url": "https://parahumans.wordpress.com/2011/10/22/shell-4-9/", - "originalTitle": "Shell 4.9", "simplifiedTitle": "9" }, { "url": "https://parahumans.wordpress.com/2011/10/25/shell-4-10/", - "originalTitle": "Shell 4.10", "simplifiedTitle": "10" }, { "url": "https://parahumans.wordpress.com/2011/10/29/shell-4-11/", - "originalTitle": "Shell 4.11", "simplifiedTitle": "11" }, { "url": "https://parahumans.wordpress.com/2011/11/01/interlude-4-2/", - "originalTitle": "Interlude 4", "simplifiedTitle": "Interlude II", "characterNamesTitle": "Interlude: Brutus" } @@ -249,57 +206,46 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2011/11/05/hive-5-1/", - "originalTitle": "Hive 5.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2011/11/08/hive-5-2/", - "originalTitle": "Hive 5.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2011/11/12/hive-5-3/", - "originalTitle": "Hive 5.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2011/11/15/hive-5-4/", - "originalTitle": "Hive 5.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2011/11/19/hive-5-5/", - "originalTitle": "Hive 5.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2011/11/22/hive-5-6/", - "originalTitle": "Hive 5.6", "simplifiedTitle": "6" }, { "url": "https://parahumans.wordpress.com/2011/11/26/hive-5-7/", - "originalTitle": "Hive 5.7", "simplifiedTitle": "7" }, { "url": "https://parahumans.wordpress.com/2011/11/29/hive-5-8/", - "originalTitle": "Hive 5.8", "simplifiedTitle": "8" }, { "url": "https://parahumans.wordpress.com/2011/12/03/hive-5-9/", - "originalTitle": "Hive 5.9", "simplifiedTitle": "9" }, { "url": "https://parahumans.wordpress.com/2011/12/06/hive-5-10/", - "originalTitle": "Hive 5.10", "simplifiedTitle": "10" }, { "url": "https://parahumans.wordpress.com/2011/12/10/interlude-5/", - "originalTitle": "Interlude 5", "simplifiedTitle": "Interlude", "characterNamesTitle": "Interlude: Gregor the Snail" } @@ -311,52 +257,42 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2011/12/13/tangle-6-1/", - "originalTitle": "Tangle 6.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2011/12/17/tangle-6-2/", - "originalTitle": "Tangle 6.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2011/12/20/tangle-6-3/", - "originalTitle": "Tangle 6.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2011/12/24/tangle-6-4/", - "originalTitle": "Tangle 6.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2011/12/27/tangle-6-5/", - "originalTitle": "Tangle 6.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2011/12/31/tangle-6-6/", - "originalTitle": "Tangle 6.6", "simplifiedTitle": "6" }, { "url": "https://parahumans.wordpress.com/2012/01/03/tangle-6-7/", - "originalTitle": "Tangle 6.7", "simplifiedTitle": "7" }, { "url": "https://parahumans.wordpress.com/2012/01/07/tangle-6-8/", - "originalTitle": "Tangle 6.8", "simplifiedTitle": "8" }, { "url": "https://parahumans.wordpress.com/2012/01/10/tangle-6-9/", - "originalTitle": "Tangle 6.9", "simplifiedTitle": "9" }, { "url": "https://parahumans.wordpress.com/2012/01/14/interlude-6/", - "originalTitle": "Interlude 6", "simplifiedTitle": "Interlude", "characterNamesTitle": "Interlude: Paige" } @@ -368,67 +304,54 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2012/01/17/buzz-7-1/", - "originalTitle": "Buzz 7.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2012/01/21/buzz-7-2/", - "originalTitle": "Buzz 7.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2012/01/24/buzz-7-3/", - "originalTitle": "Buzz 7.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2012/01/28/buzz-7-4/", - "originalTitle": "Buzz 7.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2012/01/31/buzz-7-5/", - "originalTitle": "Buzz 7.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2012/02/04/buzz-7-6/", - "originalTitle": "Buzz 7.6", "simplifiedTitle": "6" }, { "url": "https://parahumans.wordpress.com/2012/02/07/buzz-7-7/", - "originalTitle": "Buzz 7.7", "simplifiedTitle": "7" }, { "url": "https://parahumans.wordpress.com/2012/02/11/buzz-7-8/", - "originalTitle": "Buzz 7.8", "simplifiedTitle": "8" }, { "url": "https://parahumans.wordpress.com/2012/02/14/buzz-7-9/", - "originalTitle": "Buzz 7.9", "simplifiedTitle": "9" }, { "url": "https://parahumans.wordpress.com/2012/02/18/buzz-7-10/", - "originalTitle": "Buzz 7.10", "simplifiedTitle": "10" }, { "url": "https://parahumans.wordpress.com/2012/02/21/buzz-7-11/", - "originalTitle": "Buzz 7.11", "simplifiedTitle": "11" }, { "url": "https://parahumans.wordpress.com/2012/02/25/buzz-7-12/", - "originalTitle": "Buzz 7.12", "simplifiedTitle": "12" }, { "url": "https://parahumans.wordpress.com/2012/02/28/interlude-7/", - "originalTitle": "Interlude 7", "simplifiedTitle": "Interlude", "characterNamesTitle": "Interlude: Hana" } @@ -440,53 +363,43 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2012/03/03/extermination-8-1/", - "originalTitle": "Extermination 8.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2012/03/06/extermination-8-2/", - "originalTitle": "Extermination 8.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2012/03/08/interlude-7%C2%BD-bonus/", - "originalTitle": "Interlude 8 (Bonus)", "simplifiedTitle": "Interlude I", "characterNamesTitle": "Interlude: Lisa" }, { "url": "https://parahumans.wordpress.com/2012/03/10/extermination-8-3/", - "originalTitle": "Extermination 8.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2012/03/13/extermination-8-4/", - "originalTitle": "Extermination 8.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2012/03/17/extermination-8-5/", - "originalTitle": "Extermination 8.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2012/03/20/extermination-8-6/", - "originalTitle": "Extermination 8.6", "simplifiedTitle": "6" }, { "url": "https://parahumans.wordpress.com/2012/03/24/extermination-8-7/", - "originalTitle": "Extermination 8.7", "simplifiedTitle": "7" }, { "url": "https://parahumans.wordpress.com/2012/03/27/extermination-8-8/", - "originalTitle": "Extermination 8.8", "simplifiedTitle": "8" }, { "url": "https://parahumans.wordpress.com/2012/03/31/interlude-8/", - "originalTitle": "Interlude 8", "simplifiedTitle": "Interlude II", "characterNamesTitle": "Interlude: Coil" } @@ -498,32 +411,26 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2012/04/03/cell-9-1/", - "originalTitle": "Sentinel 9.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2012/04/07/sentinel-9-2/", - "originalTitle": "Sentinel 9.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2012/04/10/sentinel-9-3/", - "originalTitle": "Sentinel 9.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2012/04/14/sentinel-9-4/", - "originalTitle": "Sentinel 9.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2012/04/17/sentinel-9-5/", - "originalTitle": "Sentinel 9.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2012/04/21/sentinel-9-6/", - "originalTitle": "Sentinel 9.6", "simplifiedTitle": "6" } ] @@ -534,43 +441,35 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2012/04/24/parasite-10-1/", - "originalTitle": "Parasite 10.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2012/04/28/parasite-10-2/", - "originalTitle": "Parasite 10.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2012/05/01/parasite-10-3/", - "originalTitle": "Parasite 10.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2012/05/05/parasite-10-4/", - "originalTitle": "Parasite 10.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2012/05/08/parasite-10-5/", - "originalTitle": "Parasite 10.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2012/05/12/parasite-10-6/", - "originalTitle": "Parasite 10.6", "simplifiedTitle": "6" }, { "url": "https://parahumans.wordpress.com/2012/05/15/interlude-10/", - "originalTitle": "Interlude 10", "simplifiedTitle": "Interlude I", "characterNamesTitle": "Interlude: Alec" }, { "url": "https://parahumans.wordpress.com/2012/05/17/interlude-10-5-bonus/", - "originalTitle": "Interlude 10.5 (Bonus)", "simplifiedTitle": "Interlude II", "characterNamesTitle": "Interlude: Dragon" } @@ -582,89 +481,73 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2012/05/19/infestation-11-1/", - "originalTitle": "Infestation 11.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2012/05/22/infestation-11-2/", - "originalTitle": "Infestation 11.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2012/05/26/infestation-11-3/", - "originalTitle": "Infestation 11.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2012/05/29/infestation-11-4/", - "originalTitle": "Infestation 11.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2012/06/02/infestation-11-5/", - "originalTitle": "Infestation 11.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2012/06/05/infestation-11-6/", - "originalTitle": "Infestation 11.6", "simplifiedTitle": "6" }, { "url": "https://parahumans.wordpress.com/2012/06/09/infestation-11-7/", - "originalTitle": "Infestation 11.7", "simplifiedTitle": "7" }, { "url": "https://parahumans.wordpress.com/2012/06/12/infestation-11-8/", - "originalTitle": "Infestation 11.8", "simplifiedTitle": "8" }, { "url": "https://parahumans.wordpress.com/2012/06/16/interlude-11a/", - "originalTitle": "Interlude 11a", "simplifiedTitle": "Interlude I", "characterNamesTitle": "Interlude: Bitch" }, { "url": "https://parahumans.wordpress.com/2012/06/17/interlude-11b/", - "originalTitle": "Interlude 11b (Anniversary Bonus)", "simplifiedTitle": "Interlude II", "characterNamesTitle": "Interlude: Theo" }, { "url": "https://parahumans.wordpress.com/2012/06/18/interlude-11c/", - "originalTitle": "Interlude 11c (Anniversary Bonus)", "simplifiedTitle": "Interlude III", "characterNamesTitle": "Interlude: Elle" }, { "url": "https://parahumans.wordpress.com/2012/06/19/interlude-11d/", - "originalTitle": "Interlude 11d", "simplifiedTitle": "Interlude IV", "characterNamesTitle": "Interlude: Armsmaster" }, { "url": "https://parahumans.wordpress.com/2012/06/20/interlude-11e/", - "originalTitle": "Interlude 11e (Anniversary Bonus)", "simplifiedTitle": "Interlude V", "characterNamesTitle": "Interlude: Hookwolf" }, { "url": "https://parahumans.wordpress.com/2012/06/21/interlude-11f/", - "originalTitle": "Interlude 11f (Anniversary Bonus)", "simplifiedTitle": "Interlude VI", "characterNamesTitle": "Interlude: Dinah" }, { "url": "https://parahumans.wordpress.com/2012/06/22/interlude-11g/", - "originalTitle": "Interlude 11g (Anniversary Bonus)", "simplifiedTitle": "Interlude VII", "characterNamesTitle": "Interlude: Cherish" }, { "url": "https://parahumans.wordpress.com/2012/06/23/interlude-11h/", - "originalTitle": "Interlude 11h", "simplifiedTitle": "Interlude VIII", "characterNamesTitle": "Interlude: Amy" } @@ -676,53 +559,43 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2012/06/26/plague-12-1/", - "originalTitle": "Plague 12.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2012/06/30/plague-12-2/", - "originalTitle": "Plague 12.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2012/07/03/plague-12-3/", - "originalTitle": "Plague 12.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2012/07/07/plague-12-4/", - "originalTitle": "Plague 12.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2012/07/10/plague-12-5/", - "originalTitle": "Plague 12.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2012/07/14/plague-12-6/", - "originalTitle": "Plague 12.6", "simplifiedTitle": "6" }, { "url": "https://parahumans.wordpress.com/2012/07/17/plague-12-7/", - "originalTitle": "Plague 12.7", "simplifiedTitle": "7" }, { "url": "https://parahumans.wordpress.com/2012/07/21/plague-12-8/", - "originalTitle": "Plague 12.8", "simplifiedTitle": "8" }, { "url": "https://parahumans.wordpress.com/2012/07/24/interlude-12/", - "originalTitle": "Interlude 12", "simplifiedTitle": "Interlude I", "characterNamesTitle": "Interlude: Jack" }, { "url": "https://parahumans.wordpress.com/2012/07/26/interlude-12%C2%BD/", - "originalTitle": "Interlude 12½ (Bonus)", "simplifiedTitle": "Interlude II", "characterNamesTitle": "Interlude: Jamie" } @@ -734,63 +607,51 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2012/07/28/snare-13-1/", - "originalTitle": "Snare 13.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2012/07/31/snare-13-2/", - "originalTitle": "Snare 13.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2012/08/02/interlude-13%C2%BD-donation-bonus/", - "originalTitle": "Interlude 13½ (Bonus)", "simplifiedTitle": "Interlude I", "characterNamesTitle": "Interlude: Aisha" }, { "url": "https://parahumans.wordpress.com/2012/08/04/snare-13-3/", - "originalTitle": "Snare 13.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2012/08/07/snare-13-4/", - "originalTitle": "Snare 13.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2012/08/11/snare-13-5/", - "originalTitle": "Snare 13.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2012/08/14/snare-13-6/", - "originalTitle": "Snare 13.6", "simplifiedTitle": "6" }, { "url": "https://parahumans.wordpress.com/2012/08/18/snare-13-7/", - "originalTitle": "Snare 13.7", "simplifiedTitle": "7" }, { "url": "https://parahumans.wordpress.com/2012/08/21/snare-13-8/", - "originalTitle": "Snare 13.8", "simplifiedTitle": "8" }, { "url": "https://parahumans.wordpress.com/2012/08/25/snare-13-09/", - "originalTitle": "Snare 13.9", "simplifiedTitle": "9" }, { "url": "https://parahumans.wordpress.com/2012/08/28/snare-13-10/", - "originalTitle": "Snare 13.10", "simplifiedTitle": "10" }, { "url": "https://parahumans.wordpress.com/2012/09/01/interlude-13/", - "originalTitle": "Interlude 13", "simplifiedTitle": "Interlude II", "characterNamesTitle": "Interlude: Piggot" } @@ -802,68 +663,55 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2012/09/04/prey-14-1/", - "originalTitle": "Prey 14.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2012/09/08/prey-14-2/", - "originalTitle": "Prey 14.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2012/09/11/prey-14-3/", - "originalTitle": "Prey 14.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2012/09/15/prey-14-4/", - "originalTitle": "Prey 14.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2012/09/18/prey-14-5/", - "originalTitle": "Prey 14.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2012/09/22/prey-14-6/", - "originalTitle": "Prey 14.6", "simplifiedTitle": "6" }, { "url": "https://parahumans.wordpress.com/2012/09/25/prey-14-7/", - "originalTitle": "Prey 14.7", "simplifiedTitle": "7" }, { "url": "https://parahumans.wordpress.com/2012/09/29/prey-14-8/", - "originalTitle": "Prey 14.8", "simplifiedTitle": "8" }, { "url": "https://parahumans.wordpress.com/2012/10/02/prey-14-9/", - "originalTitle": "Prey 14.9", "simplifiedTitle": "9" }, { "url": "https://parahumans.wordpress.com/2012/10/06/prey-14-10/", - "originalTitle": "Prey 14.10", "simplifiedTitle": "10" }, { "url": "https://parahumans.wordpress.com/2012/10/09/prey-14-11/", - "originalTitle": "Prey 14.11", "simplifiedTitle": "11" }, { "url": "https://parahumans.wordpress.com/2012/10/11/interlude-14/", - "originalTitle": "Interlude 14", "simplifiedTitle": "Interlude I", "characterNamesTitle": "Interlude: Sierra" }, { "url": "https://parahumans.wordpress.com/2012/10/13/interlude-14-5-bonus-interlude/", - "originalTitle": "Interlude 14.5 (Bonus Interlude)", "simplifiedTitle": "Interlude II", "characterNamesTitle": "Interlude: Legend" } @@ -875,75 +723,61 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2012/10/16/colony-15-1/", - "originalTitle": "Colony 15.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2012/10/18/interlude-15-donation-bonus/", - "originalTitle": "Interlude 15 (Bonus)", "simplifiedTitle": "Interlude I", "characterNamesTitle": "Interlude: Carol" }, { "url": "https://parahumans.wordpress.com/2012/10/20/colony-15-2/", - "originalTitle": "Colony 15.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2012/10/23/colony-15-3/", - "originalTitle": "Colony 15.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2012/10/25/interlude-15-donation-bonus-2/", - "originalTitle": "Interlude 15 (Bonus #2)", "simplifiedTitle": "Interlude II", "characterNamesTitle": "Interlude: Grue" }, { "url": "https://parahumans.wordpress.com/2012/10/27/colony-15-4/", - "originalTitle": "Colony 15.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2012/10/30/colony-15-5/", - "originalTitle": "Colony 15.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2012/11/03/colony-15-6/", - "originalTitle": "Colony 15.6", "simplifiedTitle": "6" }, { "url": "https://parahumans.wordpress.com/2012/11/06/colony-15-7/", - "originalTitle": "Colony 15.7", "simplifiedTitle": "7" }, { "url": "https://parahumans.wordpress.com/2012/11/08/interlude-15-donation-bonus-3/", - "originalTitle": "Interlude 15 (Bonus #3)", "simplifiedTitle": "Interlude III", "characterNamesTitle": "Interlude: Rebecca" }, { "url": "https://parahumans.wordpress.com/2012/11/10/colony-15-8/", - "originalTitle": "Colony 15.8", "simplifiedTitle": "8" }, { "url": "https://parahumans.wordpress.com/2012/11/13/colony-15-9/", - "originalTitle": "Colony 15.9", "simplifiedTitle": "9" }, { "url": "https://parahumans.wordpress.com/2012/11/17/colony-15-10/", - "originalTitle": "Colony 15.10", "simplifiedTitle": "10" }, { "url": "https://parahumans.wordpress.com/2012/11/20/interlude-15/", - "originalTitle": "Interlude 15", "simplifiedTitle": "Interlude IV", "characterNamesTitle": "Interlude: Triumph" } @@ -955,85 +789,69 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2012/11/24/monarch-16-1/", - "originalTitle": "Monarch 16.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2012/11/27/monarch-16-2/", - "originalTitle": "Monarch 16.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2012/11/29/interlude-16-donation-bonus/", - "originalTitle": "Interlude 16 (Bonus)", "simplifiedTitle": "Interlude I", "characterNamesTitle": "Interlude: Lady" }, { "url": "https://parahumans.wordpress.com/2012/12/01/monarch-16-3/", - "originalTitle": "Monarch 16.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2012/12/04/monarch-16-4/", - "originalTitle": "Monarch 16.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2012/12/08/monarch-16-5/", - "originalTitle": "Monarch 16.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2012/12/11/monarch-16-6/", - "originalTitle": "Monarch 16.6", "simplifiedTitle": "6" }, { "url": "https://parahumans.wordpress.com/2012/12/13/interlude-16-donation-bonus-2/", - "originalTitle": "Interlude 16 (Bonus #2)", "simplifiedTitle": "Interlude II", "characterNamesTitle": "Interlude: Defiant" }, { "url": "https://parahumans.wordpress.com/2012/12/15/monarch-16-7/", - "originalTitle": "Monarch 16.7", "simplifiedTitle": "7" }, { "url": "https://parahumans.wordpress.com/2012/12/18/monarch-16-8/", - "originalTitle": "Monarch 16.8", "simplifiedTitle": "8" }, { "url": "https://parahumans.wordpress.com/2012/12/22/monarch-16-9/", - "originalTitle": "Monarch 16.9", "simplifiedTitle": "9" }, { "url": "https://parahumans.wordpress.com/2012/12/25/monarch-16-10/", - "originalTitle": "Monarch 16.10", "simplifiedTitle": "10" }, { "url": "https://parahumans.wordpress.com/2012/12/27/interlude-16-donation-bonus-3/", - "originalTitle": "Interlude 16 (Bonus #3)", "simplifiedTitle": "Interlude III", "characterNamesTitle": "Interlude: Marquis" }, { "url": "https://parahumans.wordpress.com/2012/12/29/monarch-16-11/", - "originalTitle": "Monarch 16.11", "simplifiedTitle": "11" }, { "url": "https://parahumans.wordpress.com/2013/01/01/monarch-16-12/", - "originalTitle": "Monarch 16.12", "simplifiedTitle": "12" }, { "url": "https://parahumans.wordpress.com/2013/01/05/monarch-16-13/", - "originalTitle": "Monarch 16.13", "simplifiedTitle": "13" } ] @@ -1044,42 +862,34 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2013/01/08/migration-17-1/", - "originalTitle": "Migration 17.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2013/01/09/migration-17-2/", - "originalTitle": "Migration 17.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2013/01/10/migration-17-3/", - "originalTitle": "Migration 17.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2013/01/11/migration-17-4/", - "originalTitle": "Migration 17.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2013/01/12/migration-17-5/", - "originalTitle": "Migration 17.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2013/01/13/migration-17-6/", - "originalTitle": "Migration 17.6", "simplifiedTitle": "6" }, { "url": "https://parahumans.wordpress.com/2013/01/14/migration-17-7/", - "originalTitle": "Migration 17.7", "simplifiedTitle": "7" }, { "url": "https://parahumans.wordpress.com/2013/01/15/migration-17-8/", - "originalTitle": "Migration 17.8", "simplifiedTitle": "8" } ] @@ -1090,71 +900,58 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2013/01/19/queen-18-1/", - "originalTitle": "Queen 18.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2013/01/22/queen-18-2/", - "originalTitle": "Queen 18.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2013/01/24/interlude-18x/", - "originalTitle": "Interlude 18 (Bonus #1)", "simplifiedTitle": "Interlude I", "characterNamesTitle": "Interlude: The Most Powerful Man in the World" }, { "url": "https://parahumans.wordpress.com/2013/01/26/queen-18-3/", - "originalTitle": "Queen 18.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2013/01/29/queen-18-4/", - "originalTitle": "Queen 18.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2013/01/31/interlude-18-donation-bonus-2/", - "originalTitle": "Interlude 18 (Bonus #2)", "simplifiedTitle": "Interlude II", "characterNamesTitle": "Interlude: Justin" }, { "url": "https://parahumans.wordpress.com/2013/02/02/queen-18-5/", - "originalTitle": "Queen 18.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2013/02/05/monarch-18-6/", - "originalTitle": "Queen 18.6", "simplifiedTitle": "6" }, { "url": "https://parahumans.wordpress.com/2013/02/07/interlude-18-donation-bonus-3/", - "originalTitle": "Interlude 18 (Bonus #3)", "simplifiedTitle": "Interlude III", "characterNamesTitle": "Interlude: Jessica Yamada" }, { "url": "https://parahumans.wordpress.com/2013/02/09/queen-18-7/", - "originalTitle": "Queen 18.7", "simplifiedTitle": "7" }, { "url": "https://parahumans.wordpress.com/2013/02/12/queen-18-8/", - "originalTitle": "Queen 18.8", "simplifiedTitle": "8" }, { "url": "https://parahumans.wordpress.com/2013/02/14/interlude-18-donation-bonus-4/", - "originalTitle": "Interlude 18 (Bonus #4)", "simplifiedTitle": "Interlude IV", "characterNamesTitle": "Interlude: Faultline" }, { "url": "https://parahumans.wordpress.com/2013/02/16/interlude-18/", - "originalTitle": "Interlude 18", "simplifiedTitle": "Interlude V", "characterNamesTitle": "Interlude: Echidna" } @@ -1166,54 +963,44 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2013/02/19/scourge-19-1/", - "originalTitle": "Scourge 19.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2013/02/23/scourge-19-2/", - "originalTitle": "Scourge 19.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2013/02/26/scourge-19-3/", - "originalTitle": "Scourge 19.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2013/02/28/interlude-19-donation-bonus-1/", - "originalTitle": "Interlude 19 (Bonus #1)", "simplifiedTitle": "Interlude I", "characterNamesTitle": "Interlude: Blasto" }, { "url": "https://parahumans.wordpress.com/2013/03/02/scourge-19-4/", - "originalTitle": "Scourge 19.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2013/03/05/scourge-19-5/", - "originalTitle": "Scourge 19.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2013/03/09/scourge-19-6/", - "originalTitle": "Scourge 19.6", "simplifiedTitle": "6" }, { "url": "https://parahumans.wordpress.com/2013/03/12/scourge-19-7/", - "originalTitle": "Scourge 19.7", "simplifiedTitle": "7" }, { "url": "https://parahumans.wordpress.com/2013/03/16/interlude-19-y/", - "originalTitle": "Interlude 19 (Bonus #2)", "simplifiedTitle": "Interlude II", "characterNamesTitle": "Interlude: XxVoid_CowboyxX" }, { "url": "https://parahumans.wordpress.com/2013/03/19/interlude-19/", - "originalTitle": "Interlude 19", "simplifiedTitle": "Interlude III", "characterNamesTitle": "Interlude: Emma" } @@ -1225,38 +1012,31 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2013/03/21/chrysalis-20-1/", - "originalTitle": "Chrysalis 20.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2013/03/23/chrysalis-20-2/", - "originalTitle": "Chrysalis 20.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2013/03/26/chrysalis-20-3/", - "originalTitle": "Chrysalis 20.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2013/03/30/chrysalis-20-4/", - "originalTitle": "Chrysalis 20.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2013/04/02/chrysalis-20-5/", - "originalTitle": "Chrysalis 20.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2013/04/04/interlude-20-donation-bonus-1/", - "originalTitle": "Interlude 20 (Bonus #1)", "simplifiedTitle": "Interlude I", "characterNamesTitle": "Interlude: Stan" }, { "url": "https://parahumans.wordpress.com/2013/04/06/interlude-20/", - "originalTitle": "Interlude 20", "simplifiedTitle": "Interlude II", "characterNamesTitle": "Interlude: Accord" } @@ -1268,48 +1048,39 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2013/04/09/imago-21-1/", - "originalTitle": "Imago 21.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2013/04/13/imago-21-2/", - "originalTitle": "Imago 21.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2013/04/16/imago-21-3/", - "originalTitle": "Imago 21.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2013/04/18/imago-21-4/", - "originalTitle": "Imago 21.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2013/04/20/imago-21-5/", - "originalTitle": "Imago 21.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2013/04/23/imago-21-6/", - "originalTitle": "Imago 21.6", "simplifiedTitle": "6" }, { "url": "https://parahumans.wordpress.com/2013/04/25/imago-21-7/", - "originalTitle": "Imago 21.7", "simplifiedTitle": "7" }, { "url": "https://parahumans.wordpress.com/2013/04/27/interlude-21-donation-bonus-1/", - "originalTitle": "Interlude 21 (Bonus #1)", "simplifiedTitle": "Interlude I", "characterNamesTitle": "Interlude: The Number Man" }, { "url": "https://parahumans.wordpress.com/2013/04/30/interlude-21/", - "originalTitle": "Interlude 21", "simplifiedTitle": "Interlude II", "characterNamesTitle": "Interlude: Sabah" } @@ -1321,43 +1092,35 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2013/05/04/cell-22-1/", - "originalTitle": "Cell 22.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2013/05/07/cell-22-2/", - "originalTitle": "Cell 22.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2013/05/09/cell-22-3/", - "originalTitle": "Cell 22.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2013/05/11/cell-22-4", - "originalTitle": "Cell 22.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2013/05/14/cell-22-5/", - "originalTitle": "Cell 22.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2013/05/16/cell-22-6/", - "originalTitle": "Cell 22.6", "simplifiedTitle": "6" }, { "url": "https://parahumans.wordpress.com/2013/05/18/interlude-22/", - "originalTitle": "Interlude 22", "simplifiedTitle": "Interlude I", "characterNamesTitle": "Interlude: Charlotte" }, { "url": "https://parahumans.wordpress.com/2013/05/21/interlude-22-donation-bonus-1/", - "originalTitle": "Interlude 22 (Bonus #1)", "simplifiedTitle": "Interlude II", "characterNamesTitle": "Interlude: Kenta" } @@ -1369,32 +1132,26 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2013/05/25/drone-23-1/", - "originalTitle": "Drone 23.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2013/05/28/drone-23-2/", - "originalTitle": "Drone 23.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2013/05/30/drone-23-3/", - "originalTitle": "Drone 23.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2013/06/01/drone-23-4/", - "originalTitle": "Drone 23.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2013/06/04/drone-23-5/", - "originalTitle": "Drone 23.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2013/06/06/interlude-23/", - "originalTitle": "Interlude 23", "simplifiedTitle": "Interlude", "characterNamesTitle": "Interlude: Number Thirty-Six" } @@ -1406,38 +1163,31 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2013/06/08/crushed-24-1/", - "originalTitle": "Crushed 24.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2013/06/11/crushed-24-2/", - "originalTitle": "Crushed 24.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2013/06/15/crushed-24-3/", - "originalTitle": "Crushed 24.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2013/06/18/crushed-24-4/", - "originalTitle": "Crushed 24.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2013/06/20/crushed-24-5/", - "originalTitle": "Crushed 24.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2013/06/22/interlude-24/", - "originalTitle": "Interlude 24", "simplifiedTitle": "Interlude I", "characterNamesTitle": "Interlude: Chevalier" }, { "url": "https://parahumans.wordpress.com/2013/06/25/interlude-24-donation-bonus-1/", - "originalTitle": "Interlude 24 (Bonus #1)", "simplifiedTitle": "Interlude II", "characterNamesTitle": "Interlude: Aftermath" } @@ -1449,37 +1199,30 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2013/06/29/scarab-25-1/", - "originalTitle": "Scarab 25.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2013/07/02/scarab-25-2/", - "originalTitle": "Scarab 25.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2013/07/06/scarab-25-3/", - "originalTitle": "Scarab 25.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2013/07/09/scarab-25-4/", - "originalTitle": "Scarab 25.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2013/07/11/scarab-25-5/", - "originalTitle": "Scarab 25.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2013/07/13/scarab-25-6/", - "originalTitle": "Scarab 25.6", "simplifiedTitle": "6" }, { "url": "https://parahumans.wordpress.com/2013/07/16/interlude-25/", - "originalTitle": "Interlude 25", "simplifiedTitle": "Interlude", "characterNamesTitle": "Interlude: Bonesaw" } @@ -1491,55 +1234,45 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2013/07/18/sting-26-1/", - "originalTitle": "Sting 26.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2013/07/20/sting-26-2/", - "originalTitle": "Sting 26.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2013/07/23/sting-26-3/", - "originalTitle": "Sting 26.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2013/07/25/interlude-26-donation-bonus-1/", - "originalTitle": "Interlude 26 (Bonus #1)", "simplifiedTitle": "Interlude I", "characterNamesTitle": "Interlude: Saint" }, { "url": "https://parahumans.wordpress.com/2013/07/27/sting-26-4/", - "originalTitle": "Sting 26.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2013/07/30/sting-26-5/", - "originalTitle": "Sting 26.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2013/08/03/sting-26-6/", - "originalTitle": "Sting 26.6", "simplifiedTitle": "6" }, { "url": "https://parahumans.wordpress.com/2013/08/06/interlude-26a/", - "originalTitle": "Interlude 26a", "simplifiedTitle": "Interlude II", "characterNamesTitle": "Interlude: Golem" }, { "url": "https://parahumans.wordpress.com/2013/08/08/interlude-26b/", - "originalTitle": "Interlude 26b", "simplifiedTitle": "Interlude III", "characterNamesTitle": "Interlude: Golem, part 2" }, { "url": "https://parahumans.wordpress.com/2013/08/10/interlude-26/", - "originalTitle": "Interlude 26", "simplifiedTitle": "Interlude IV", "characterNamesTitle": "Interlude: The Warrior" } @@ -1551,38 +1284,31 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2013/08/13/extinction-27-1/", - "originalTitle": "Extinction 27.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2013/08/17/extinction-27-2/", - "originalTitle": "Extinction 27.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2013/08/20/extinction-27-3/", - "originalTitle": "Extinction 27.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2013/08/22/extinction-27-4/", - "originalTitle": "Extinction 27.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2013/08/24/extinction-27-5/", - "originalTitle": "Extinction 27.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2013/08/27/interlude-27/", - "originalTitle": "Interlude 27", "simplifiedTitle": "Interlude I", "characterNamesTitle": "Interlude: Eidolon" }, { "url": "https://parahumans.wordpress.com/2013/08/29/interlude-27b/", - "originalTitle": "Interlude 27b", "simplifiedTitle": "Interlude II", "characterNamesTitle": "Interlude: Four Words" } @@ -1594,37 +1320,30 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2013/08/31/cockroaches-28-1/", - "originalTitle": "Cockroaches 28.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2013/09/03/cockroaches-28-2/", - "originalTitle": "Cockroaches 28.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2013/09/05/cockroaches-28-3/", - "originalTitle": "Cockroaches 28.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2013/09/07/cockroaches-28-4/", - "originalTitle": "Cockroaches 28.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2013/09/10/cockroaches-28-5/", - "originalTitle": "Cockroaches 28.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2013/09/14/cockroaches-28-6/", - "originalTitle": "Cockroaches 28.6", "simplifiedTitle": "6" }, { "url": "https://parahumans.wordpress.com/2013/09/17/interlude-28/", - "originalTitle": "Interlude 28", "simplifiedTitle": "Interlude", "characterNamesTitle": "Interlude: Doctor Mother" } @@ -1636,52 +1355,42 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2013/09/19/venom-29-1/", - "originalTitle": "Venom 29.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2013/09/21/venom-29-2/", - "originalTitle": "Venom 29.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2013/09/24/venom-29-3/", - "originalTitle": "Venom 29.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2013/09/26/venom-29-4/", - "originalTitle": "Venom 29.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2013/09/28/venom-29-5/", - "originalTitle": "Venom 29.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2013/10/01/venom-29-6/", - "originalTitle": "Venom 29.6", "simplifiedTitle": "6" }, { "url": "https://parahumans.wordpress.com/2013/10/03/venom-29-7/", - "originalTitle": "Venom 29.7", "simplifiedTitle": "7" }, { "url": "https://parahumans.wordpress.com/2013/10/05/venom-29-8/", - "originalTitle": "Venom 29.8", "simplifiedTitle": "8" }, { "url": "https://parahumans.wordpress.com/2013/10/08/venom-29-9/", - "originalTitle": "Venom 29.9", "simplifiedTitle": "9" }, { "url": "https://parahumans.wordpress.com/2013/10/12/interlude-29/", - "originalTitle": "Interlude 29", "simplifiedTitle": "Interlude", "characterNamesTitle": "Interlude: Fortuna" } @@ -1693,37 +1402,30 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2013/10/15/speck-30-1/", - "originalTitle": "Speck 30.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2013/10/17/speck-30-2/", - "originalTitle": "Speck 30.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2013/10/19/speck-30-3/", - "originalTitle": "Speck 30.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2013/10/22/speck-30-4/", - "originalTitle": "Speck 30.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2013/10/24/speck-30-5/", - "originalTitle": "Speck 30.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2013/10/26/speck-30-6/", - "originalTitle": "Speck 30.6", "simplifiedTitle": "6" }, { "url": "https://parahumans.wordpress.com/2013/10/29/30-7/", - "originalTitle": "Speck 30.7", "simplifiedTitle": "7" } ] @@ -1734,34 +1436,28 @@ "chapters": [ { "url": "https://parahumans.wordpress.com/2013/11/02/teneral-e-1/", - "originalTitle": "Teneral e.1", "simplifiedTitle": "1" }, { "url": "https://parahumans.wordpress.com/2013/11/05/teneral-e-2/", - "originalTitle": "Teneral e.2", "simplifiedTitle": "2" }, { "url": "https://parahumans.wordpress.com/2013/11/09/teneral-e-3/", - "originalTitle": "Teneral e.3", "simplifiedTitle": "3" }, { "url": "https://parahumans.wordpress.com/2013/11/12/teneral-e-4/", - "originalTitle": "Teneral e.4", "simplifiedTitle": "4" }, { "url": "https://parahumans.wordpress.com/2013/11/16/teneral-e-5/", - "originalTitle": "Teneral e.5", "simplifiedTitle": "5" }, { "url": "https://parahumans.wordpress.com/2013/11/19/interlude-end/", - "originalTitle": "Interlude: End", "simplifiedTitle": "End" } ] } -] +] \ No newline at end of file diff --git a/lib/convert.js b/lib/convert.js index d51876d..dbb313f 100644 --- a/lib/convert.js +++ b/lib/convert.js @@ -15,19 +15,21 @@ async (cachePath, manifestPath, chapterDataPath, contentPath, book, concurrentJo const manifestChapters = JSON.parse(manifestContents); const chapterData = JSON.parse(chapterDataContents); - for (const chapter of manifestChapters) { - let found = false; - for (const arc of chapterData) { - for (const chapterInArc of arc.chapters) { - if (chapter.url === chapterInArc.url) { - chapter.title = chooseChapterTitle(chapterInArc, chapterTitleStyle); - found = true; - break; + if (chapterTitleStyle !== "original") { + for (const chapter of manifestChapters) { + let found = false; + for (const arc of chapterData) { + for (const chapterInArc of arc.chapters) { + if (chapter.url === chapterInArc.url) { + chapter.title = chooseChapterTitle(chapterInArc, chapterTitleStyle); + found = true; + break; + } } } - } - if (!found) { - throw new Error(`Chapter data not found for ${chapter.url}`); + if (!found) { + throw new Error(`Chapter data not found for ${chapter.url}`); + } } } diff --git a/lib/scaffold.js b/lib/scaffold.js index d57fafc..08d0c5d 100644 --- a/lib/scaffold.js +++ b/lib/scaffold.js @@ -205,20 +205,25 @@ async function writeArcTitlePages(chaptersPath, arcTitlePages) { await Promise.all(promises); } +// This function modifies chapterData in place, adding filename and originalTitle properties to each chapter. (filename +// contains the converted filename, not the original input one). It also checks that the downloaded-chapters manifest +// and the prepackaged chapter data are in sync. If they're not, we'll be unable to create arc title pages and a table +// of contents, so we'll error out. function augmentAndCheckChapterData(chapterData, manifestChapters) { - for (const chapter of manifestChapters) { + for (const manifestChapter of manifestChapters) { let found = false; for (const arc of chapterData) { - for (const chatperInArc of arc.chapters) { - if (chapter.url === chatperInArc.url) { - chatperInArc.filename = `${path.basename(chapter.filename, ".html")}.xhtml`; + for (const chapterInArc of arc.chapters) { + if (manifestChapter.url === chapterInArc.url) { + chapterInArc.filename = `${path.basename(manifestChapter.filename, ".html")}.xhtml`; + chapterInArc.originalTitle = manifestChapter.title; found = true; break; } } } if (!found) { - throw new Error(`Chapter data not found for ${chapter.url} which appeared in the manifest`); + throw new Error(`Chapter data not found for ${manifestChapter.url} which appeared in the manifest`); } } diff --git a/scaffolding/OEBPS/chapter.css b/scaffolding/OEBPS/chapter.css index e631395..70e3a14 100644 --- a/scaffolding/OEBPS/chapter.css +++ b/scaffolding/OEBPS/chapter.css @@ -1,14 +1,13 @@ -:root.arc-title { - display: flex; - justify-content: center; - align-items: center; - height: 100vh; - text-align: center; -} - :root.arc-title h1 { font-size: 2.5em; margin: 0; + text-align: center; + + /* Flexbox support seems spotty on e-readers, so we hack it. */ + position: absolute; + top: 50%; + margin-top: -2.5em; + width: 100vw; } :root.arc-title .arc-label { @@ -16,3 +15,7 @@ font-size: 0.6em; font-weight: normal; } + +:root.chapter h1 { + text-align: center; +} From e22a2b414e7f0b449f46d7221d7cfbf42f76111d Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Wed, 1 Jan 2025 19:23:47 +0900 Subject: [PATCH 04/11] Glow-worm works now too and giving up on vertical centering --- chapter-data/glow-worm.json | 52 +++++++++++++++++++++++++++++++++++ lib/scaffold.js | 41 +++++++++++++++------------ scaffolding/OEBPS/chapter.css | 16 +++++++---- 3 files changed, 85 insertions(+), 24 deletions(-) create mode 100644 chapter-data/glow-worm.json diff --git a/chapter-data/glow-worm.json b/chapter-data/glow-worm.json new file mode 100644 index 0000000..7f70d20 --- /dev/null +++ b/chapter-data/glow-worm.json @@ -0,0 +1,52 @@ +[ + { + "invisible": true, + "chapters": [ + { + "url": "https://www.parahumans.net/2017/10/21/glow-worm-0-1/", + "simplifiedTitle": "1", + "characterNamesTitle": "Point_Me_@_The_Sky" + }, + { + "url": "https://www.parahumans.net/2017/10/24/glow-worm-0-2/", + "simplifiedTitle": "2", + "characterNamesTitle": "Capricorn" + }, + { + "url": "https://www.parahumans.net/2017/10/26/glow-worm-0-3/", + "simplifiedTitle": "3", + "characterNamesTitle": "Mangled_Wings" + }, + { + "url": "https://www.parahumans.net/2017/10/28/glow-worm-0-4/", + "simplifiedTitle": "4", + "characterNamesTitle": "of5" + }, + { + "url": "https://www.parahumans.net/2017/10/31/glow-worm-0-5/", + "simplifiedTitle": "5", + "characterNamesTitle": "Point_Me_@_The_Sky" + }, + { + "url": "https://www.parahumans.net/2017/10/31/glow-worm-0-6/", + "simplifiedTitle": "6", + "characterNamesTitle": "Questionable_Cephalopod" + }, + { + "url": "https://www.parahumans.net/2017/11/02/glow-worm-0-7/", + "simplifiedTitle": "7", + "characterNamesTitle": "Heart_Shaped_Pupil" + }, + { + "url": "https://www.parahumans.net/2017/11/04/glow-worm-0-8/", + "simplifiedTitle": "8", + "characterNamesTitle": "Space_Squid" + }, + { + "url": "https://www.parahumans.net/2017/11/07/glow-worm-0-9/", + "simplifiedTitle": "9", + "characterNamesTitle": "Point_Me_@_The_Sky" + } + ] + } +] diff --git a/lib/scaffold.js b/lib/scaffold.js index 08d0c5d..186ee28 100644 --- a/lib/scaffold.js +++ b/lib/scaffold.js @@ -142,22 +142,24 @@ async function getChapterInfo(contentPath, chaptersPath, manifestPath, chapterDa let tocHTML = "
      \n"; let arcIdCounter = 0; for (const arc of chapterData) { - const arcFilename = `arc${arcIdCounter}.xhtml`; - const arcId = path.basename(arcFilename, ".xhtml"); - const arcHref = `${hrefPrefix}${arcFilename}`; - - arcTitlePages.push({ - filename: arcFilename, - label: arc.label, - title: arc.title - }); - manifestAndSpineFiles.push({ - id: arcId, - href: arcHref - }); - tocHTML += `
    1. - ${arcPlaintextTitle(arc)} -
        \n`; + if (!arc.invisible) { + const arcFilename = `arc${arcIdCounter}.xhtml`; + const arcId = path.basename(arcFilename, ".xhtml"); + const arcHref = `${hrefPrefix}${arcFilename}`; + + arcTitlePages.push({ + filename: arcFilename, + label: arc.label, + title: arc.title + }); + manifestAndSpineFiles.push({ + id: arcId, + href: arcHref + }); + tocHTML += `
      1. + ${arcPlaintextTitle(arc)} +
          \n`; + } for (const chapter of arc.chapters) { const chapterHref = `${hrefPrefix}${chapter.filename}`; @@ -169,8 +171,11 @@ async function getChapterInfo(contentPath, chaptersPath, manifestPath, chapterDa tocHTML += `
        1. ${chapterTitle}
        2. \n`; } - tocHTML += `
        -
      2. \n`; + + if (!arc.invisible) { + tocHTML += `
      +
    2. \n`; + } ++arcIdCounter; } diff --git a/scaffolding/OEBPS/chapter.css b/scaffolding/OEBPS/chapter.css index 70e3a14..58e117e 100644 --- a/scaffolding/OEBPS/chapter.css +++ b/scaffolding/OEBPS/chapter.css @@ -1,13 +1,17 @@ +:root.arc-title body { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + width: 100vw; + margin: 0; + padding: 0; +} + :root.arc-title h1 { font-size: 2.5em; margin: 0; text-align: center; - - /* Flexbox support seems spotty on e-readers, so we hack it. */ - position: absolute; - top: 50%; - margin-top: -2.5em; - width: 100vw; } :root.arc-title .arc-label { From 7e806ae28a69dc425972081cf2909df930d2fbb0 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Thu, 2 Jan 2025 12:06:07 +0900 Subject: [PATCH 05/11] Manual testing looking good, time to refactor --- chapter-data/glow-worm.json | 4 +- chapter-data/ward.json | 1277 +++++++++++++++++++++++++++++++++++ 2 files changed, 1279 insertions(+), 2 deletions(-) create mode 100644 chapter-data/ward.json diff --git a/chapter-data/glow-worm.json b/chapter-data/glow-worm.json index 7f70d20..05f05bc 100644 --- a/chapter-data/glow-worm.json +++ b/chapter-data/glow-worm.json @@ -25,7 +25,7 @@ { "url": "https://www.parahumans.net/2017/10/31/glow-worm-0-5/", "simplifiedTitle": "5", - "characterNamesTitle": "Point_Me_@_The_Sky" + "characterNamesTitle": "Point_Me_@_The_Sky, part 2" }, { "url": "https://www.parahumans.net/2017/10/31/glow-worm-0-6/", @@ -45,7 +45,7 @@ { "url": "https://www.parahumans.net/2017/11/07/glow-worm-0-9/", "simplifiedTitle": "9", - "characterNamesTitle": "Point_Me_@_The_Sky" + "characterNamesTitle": "Point_Me_@_The_Sky, part 3" } ] } diff --git a/chapter-data/ward.json b/chapter-data/ward.json new file mode 100644 index 0000000..213aa06 --- /dev/null +++ b/chapter-data/ward.json @@ -0,0 +1,1277 @@ +[ + { + "label": "Arc 1", + "title": "Daybreak", + "chapters": [ + { + "url": "https://www.parahumans.net/2017/09/11/daybreak-1-1/", + "simplifiedTitle": "1" + }, + { + "url": "https://www.parahumans.net/2017/11/14/daybreak-1-2/", + "simplifiedTitle": "2" + }, + { + "url": "https://www.parahumans.net/2017/11/18/daybreak-1-3/", + "simplifiedTitle": "3" + }, + { + "url": "https://www.parahumans.net/2017/11/21/daybreak-1-4/", + "simplifiedTitle": "4" + }, + { + "url": "https://www.parahumans.net/2017/11/25/daybreak-1-5/", + "simplifiedTitle": "5" + }, + { + "url": "https://www.parahumans.net/2017/11/28/daybreak-1-6/", + "simplifiedTitle": "6" + }, + { + "url": "https://www.parahumans.net/2017/11/30/daybreak-1-7/", + "simplifiedTitle": "7" + }, + { + "url": "https://www.parahumans.net/2017/12/01/daybreak-1-8/", + "simplifiedTitle": "8" + }, + { + "url": "https://www.parahumans.net/2017/12/05/daybreak-interlude-1/", + "simplifiedTitle": "Interlude", + "characterNamesTitle": "Interlude: Prancer" + } + ] + }, + { + "label": "Arc 2", + "title": "Flare", + "chapters": [ + { + "url": "https://www.parahumans.net/2017/12/09/flare-2-1/", + "simplifiedTitle": "1" + }, + { + "url": "https://www.parahumans.net/2017/12/12/flare-2-2/", + "simplifiedTitle": "2" + }, + { + "url": "https://www.parahumans.net/2017/12/16/flare-2-3/", + "simplifiedTitle": "3" + }, + { + "url": "https://www.parahumans.net/2017/12/19/flare-2-4/", + "simplifiedTitle": "4" + }, + { + "url": "https://www.parahumans.net/2017/12/23/flare-2-5/", + "simplifiedTitle": "5" + }, + { + "url": "https://www.parahumans.net/2017/12/26/flare-2-6/", + "simplifiedTitle": "6" + }, + { + "url": "https://www.parahumans.net/2017/12/30/flare-2-7/", + "simplifiedTitle": "7" + }, + { + "url": "https://www.parahumans.net/2018/01/02/flare-interlude-2/", + "simplifiedTitle": "Interlude", + "characterNamesTitle": "Interlude: Crystalclear" + } + ] + }, + { + "label": "Arc 3", + "title": "Glare", + "chapters": [ + { + "url": "https://www.parahumans.net/2018/01/06/glare-3-1/", + "simplifiedTitle": "1" + }, + { + "url": "https://www.parahumans.net/2018/01/09/glare-3-2/", + "simplifiedTitle": "2" + }, + { + "url": "https://www.parahumans.net/2018/01/13/glare-3-3/", + "simplifiedTitle": "3" + }, + { + "url": "https://www.parahumans.net/2018/01/16/glare-3-4/", + "simplifiedTitle": "4" + }, + { + "url": "https://www.parahumans.net/2018/01/20/glare-3-5/", + "simplifiedTitle": "5" + }, + { + "url": "https://www.parahumans.net/2018/01/23/glare-3-6/", + "simplifiedTitle": "6" + }, + { + "url": "https://www.parahumans.net/2018/01/25/glare-interlude-3/", + "simplifiedTitle": "Interlude", + "characterNamesTitle": "Interlude: Dot" + } + ] + }, + { + "label": "Arc 4", + "title": "Shade", + "chapters": [ + { + "url": "https://www.parahumans.net/2018/01/27/shade-4-1/", + "simplifiedTitle": "1" + }, + { + "url": "https://www.parahumans.net/2018/01/30/shade-4-2/", + "simplifiedTitle": "2" + }, + { + "url": "https://www.parahumans.net/2018/02/03/shade-4-3/", + "simplifiedTitle": "3" + }, + { + "url": "https://www.parahumans.net/2018/02/06/shade-interlude-4a/", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: Snag" + }, + { + "url": "https://www.parahumans.net/2018/02/08/shade-4-4/", + "simplifiedTitle": "4" + }, + { + "url": "https://www.parahumans.net/2018/02/10/shade-4-5/", + "simplifiedTitle": "5" + }, + { + "url": "https://www.parahumans.net/2018/02/13/shade-interlude-4b/", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: Cradle" + }, + { + "url": "https://www.parahumans.net/2018/02/17/shade-4-6/", + "simplifiedTitle": "6" + }, + { + "url": "https://www.parahumans.net/2018/02/20/shade-4-7/", + "simplifiedTitle": "7" + }, + { + "url": "https://www.parahumans.net/2018/02/22/shade-interlude-4c/", + "simplifiedTitle": "Interlude III", + "characterNamesTitle": "Interlude: Love Lost" + } + ] + }, + { + "label": "Arc 5", + "title": "Shadow", + "chapters": [ + { + "url": "https://www.parahumans.net/2018/02/24/shadow-5-1/", + "simplifiedTitle": "1" + }, + { + "url": "https://www.parahumans.net/2018/02/27/shadow-5-2/", + "simplifiedTitle": "2" + }, + { + "url": "https://www.parahumans.net/2018/03/03/shadow-5-3/", + "simplifiedTitle": "3" + }, + { + "url": "https://www.parahumans.net/2018/03/06/shadow-5-4/", + "simplifiedTitle": "4" + }, + { + "url": "https://www.parahumans.net/2018/03/10/shadow-5-5/", + "simplifiedTitle": "5" + }, + { + "url": "https://www.parahumans.net/2018/03/13/shadow-interlude-5d/", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: Rain" + }, + { + "url": "https://www.parahumans.net/2018/03/17/shadow-5-6/", + "simplifiedTitle": "6" + }, + { + "url": "https://www.parahumans.net/2018/03/20/shadow-5-7/", + "simplifiedTitle": "7" + }, + { + "url": "https://www.parahumans.net/2018/03/22/shadow-5-8/", + "simplifiedTitle": "8" + }, + { + "url": "https://www.parahumans.net/2018/03/24/shadow-5-9/", + "simplifiedTitle": "9" + }, + { + "url": "https://www.parahumans.net/2018/03/27/shadow-5-10/", + "simplifiedTitle": "10" + }, + { + "url": "https://www.parahumans.net/2018/03/31/shadow-5-11/", + "simplifiedTitle": "11" + }, + { + "url": "https://www.parahumans.net/2018/04/03/shadow-5-12/", + "simplifiedTitle": "12" + }, + { + "url": "https://www.parahumans.net/2018/04/07/shadow-interlude-5-x/", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: Jeanne Wynn" + }, + { + "url": "https://www.parahumans.net/2018/04/10/shadow-interlude-5-y/", + "simplifiedTitle": "Interlude III", + "characterNamesTitle": "Interlude: Jonathan" + } + ] + }, + { + "label": "Arc 6", + "title": "Pitch", + "chapters": [ + { + "url": "https://www.parahumans.net/2018/04/14/pitch-6-1/", + "simplifiedTitle": "1" + }, + { + "url": "https://www.parahumans.net/2018/04/17/pitch-6-2/", + "simplifiedTitle": "2" + }, + { + "url": "https://www.parahumans.net/2018/04/21/pitch-6-3/", + "simplifiedTitle": "3" + }, + { + "url": "https://www.parahumans.net/2018/04/24/pitch-6-4/", + "simplifiedTitle": "4" + }, + { + "url": "https://www.parahumans.net/2018/04/28/pitch-6-5/", + "simplifiedTitle": "5" + }, + { + "url": "https://www.parahumans.net/2018/05/01/pitch-6-6/", + "simplifiedTitle": "6" + }, + { + "url": "https://www.parahumans.net/2018/05/05/pitch-6-7/", + "simplifiedTitle": "7" + }, + { + "url": "https://www.parahumans.net/2018/05/08/pitch-6-8/", + "simplifiedTitle": "8" + }, + { + "url": "https://www.parahumans.net/2018/05/11/pitch-6-9/", + "simplifiedTitle": "9" + } + ] + }, + { + "label": "Arc 7", + "title": "Torch", + "chapters": [ + { + "url": "https://www.parahumans.net/2018/05/15/torch-7-1/", + "simplifiedTitle": "1" + }, + { + "url": "https://www.parahumans.net/2018/05/19/torch-7-2/", + "simplifiedTitle": "2" + }, + { + "url": "https://www.parahumans.net/2018/05/22/torch-7-3/", + "simplifiedTitle": "3" + }, + { + "url": "https://www.parahumans.net/2018/05/26/torch-7-4/", + "simplifiedTitle": "4" + } + ] + }, + { + "label": "Arc X", + "title": "Eclipse", + "chapters": [ + { + "url": "https://www.parahumans.net/2018/05/26/eclipse-x-1/", + "simplifiedTitle": "1" + }, + { + "url": "https://www.parahumans.net/2018/05/27/eclipse-x-2/", + "simplifiedTitle": "2" + }, + { + "url": "https://www.parahumans.net/2018/05/28/eclipse-x-3/", + "simplifiedTitle": "3" + }, + { + "url": "https://www.parahumans.net/2018/05/29/eclipse-x-4/", + "simplifiedTitle": "4" + }, + { + "url": "https://www.parahumans.net/2018/05/30/eclipse-x-5/", + "simplifiedTitle": "5" + }, + { + "url": "https://www.parahumans.net/2018/05/31/eclipse-x-6/", + "simplifiedTitle": "6" + }, + { + "url": "https://www.parahumans.net/2018/06/01/eclipse-x-7/", + "simplifiedTitle": "7" + }, + { + "url": "https://www.parahumans.net/2018/06/02/eclipse-x-8/", + "simplifiedTitle": "8" + } + ] + }, + { + "label": "Arc 7, continued", + "title": "Torch", + "chapters": [ + { + "url": "https://www.parahumans.net/2018/06/05/torch-7-5/", + "simplifiedTitle": "5" + }, + { + "url": "https://www.parahumans.net/2018/06/09/torch-7-6/", + "simplifiedTitle": "6" + }, + { + "url": "https://www.parahumans.net/2018/06/12/torch-7-7/", + "simplifiedTitle": "7" + }, + { + "url": "https://www.parahumans.net/2018/06/16/torch-7-8/", + "simplifiedTitle": "8" + }, + { + "url": "https://www.parahumans.net/2018/06/19/torch-7-9/", + "simplifiedTitle": "9" + }, + { + "url": "https://www.parahumans.net/2018/06/23/torch-7-10/", + "simplifiedTitle": "10" + }, + { + "url": "https://www.parahumans.net/2018/06/26/torch-interlude-7-x/", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: Kenzie" + }, + { + "url": "https://www.parahumans.net/2018/06/30/torch-7-y/", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: Gary Nieves" + } + ] + }, + { + "label": "Arc 8", + "title": "Beacon", + "chapters": [ + { + "url": "https://www.parahumans.net/2018/07/03/beacon-8-1/", + "simplifiedTitle": "1" + }, + { + "url": "https://www.parahumans.net/2018/07/07/beacon-8-2/", + "simplifiedTitle": "2" + }, + { + "url": "https://www.parahumans.net/2018/07/10/beacon-8-3/", + "simplifiedTitle": "3" + }, + { + "url": "https://www.parahumans.net/2018/07/14/beacon-8-4/", + "simplifiedTitle": "4" + }, + { + "url": "https://www.parahumans.net/2018/07/17/beacon-8-5/", + "simplifiedTitle": "5" + }, + { + "url": "https://www.parahumans.net/2018/07/21/beacon-8-6/", + "simplifiedTitle": "6" + }, + { + "url": "https://www.parahumans.net/2018/07/24/beacon-8-7/", + "simplifiedTitle": "7" + }, + { + "url": "https://www.parahumans.net/2018/07/28/beacon-8-8/", + "simplifiedTitle": "8" + }, + { + "url": "https://www.parahumans.net/2018/07/31/beacon-8-9/", + "simplifiedTitle": "9" + }, + { + "url": "https://www.parahumans.net/2018/08/04/beacon-8-10/", + "simplifiedTitle": "10" + }, + { + "url": "https://www.parahumans.net/2018/08/07/beacon-8-11/", + "simplifiedTitle": "11" + }, + { + "url": "https://www.parahumans.net/2018/08/11/beacon-8-12/", + "simplifiedTitle": "12" + }, + { + "url": "https://www.parahumans.net/2018/08/14/beacon-interlude-8-x/", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: Natalie" + }, + { + "url": "https://www.parahumans.net/2018/08/18/beacon-interlude-8-y/", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: William" + } + ] + }, + { + "label": "Arc 9", + "title": "Gleaming", + "chapters": [ + { + "url": "https://www.parahumans.net/2018/08/21/gleaming-9-1/", + "simplifiedTitle": "1" + }, + { + "url": "https://www.parahumans.net/2018/08/25/gleaming-9-2/", + "simplifiedTitle": "2" + }, + { + "url": "https://www.parahumans.net/2018/08/28/gleaming-9-3/", + "simplifiedTitle": "3" + }, + { + "url": "https://www.parahumans.net/2018/09/01/gleaming-9-4/", + "simplifiedTitle": "4" + }, + { + "url": "https://www.parahumans.net/2018/09/04/gleaming-9-5/", + "simplifiedTitle": "5" + }, + { + "url": "https://www.parahumans.net/2018/09/08/gleaming-9-6/", + "simplifiedTitle": "6" + }, + { + "url": "https://www.parahumans.net/2018/09/11/gleaming-9-7/", + "simplifiedTitle": "7" + }, + { + "url": "https://www.parahumans.net/2018/09/13/gleaming-interlude-9-x/", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: Byron" + }, + { + "url": "https://www.parahumans.net/2018/09/15/gleaming-9-8/", + "simplifiedTitle": "8" + }, + { + "url": "https://www.parahumans.net/2018/09/18/gleaming-9-9/", + "simplifiedTitle": "9" + }, + { + "url": "https://www.parahumans.net/2018/09/22/gleaming-interlude-9-y/", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: Capricorn" + }, + { + "url": "https://www.parahumans.net/2018/09/25/gleaming-9-10/", + "simplifiedTitle": "10" + }, + { + "url": "https://www.parahumans.net/2018/09/29/gleaming-9-11/", + "simplifiedTitle": "11" + }, + { + "url": "https://www.parahumans.net/2018/10/02/gleaming-9-12/", + "simplifiedTitle": "12" + }, + { + "url": "https://www.parahumans.net/2018/10/06/gleaming-9-13/", + "simplifiedTitle": "13" + }, + { + "url": "https://www.parahumans.net/2018/10/09/gleaming-9-14/", + "simplifiedTitle": "14" + }, + { + "url": "https://www.parahumans.net/2018/10/13/gleaming-9-15/", + "simplifiedTitle": "15" + }, + { + "url": "https://www.parahumans.net/2018/10/16/gleaming-interlude-9-z/", + "simplifiedTitle": "Interlude III", + "characterNamesTitle": "Interlude: Tristan" + }, + { + "url": "https://www.parahumans.net/2018/10/20/gleaming-interlude-9/", + "simplifiedTitle": "Interlude IV", + "characterNamesTitle": "Interlude: Ciara" + } + ] + }, + { + "label": "Arc 10", + "title": "Polarize", + "chapters": [ + { + "url": "https://www.parahumans.net/2018/10/23/polarize-10-1/", + "simplifiedTitle": "1" + }, + { + "url": "https://www.parahumans.net/2018/10/27/polarize-10-2/", + "simplifiedTitle": "2" + }, + { + "url": "https://www.parahumans.net/2018/10/30/polarize-10-3/", + "simplifiedTitle": "3" + }, + { + "url": "https://www.parahumans.net/2018/11/03/polarize-10-4/", + "simplifiedTitle": "4" + }, + { + "url": "https://www.parahumans.net/2018/11/06/polarize-10-5/", + "simplifiedTitle": "5" + }, + { + "url": "https://www.parahumans.net/2018/11/10/polarize-10-6/", + "simplifiedTitle": "6" + }, + { + "url": "https://www.parahumans.net/2018/11/13/polarize-10-7/", + "simplifiedTitle": "7" + }, + { + "url": "https://www.parahumans.net/2018/11/17/polarize-10-8/", + "simplifiedTitle": "8" + }, + { + "url": "https://www.parahumans.net/2018/11/20/polarize-10-9/", + "simplifiedTitle": "9" + }, + { + "url": "https://www.parahumans.net/2018/11/24/interlude-10-x/", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: Tattletale" + }, + { + "url": "https://www.parahumans.net/2018/11/27/polarize-10-10/", + "simplifiedTitle": "10" + }, + { + "url": "https://www.parahumans.net/2018/12/01/polarize-10-11/", + "simplifiedTitle": "11" + }, + { + "url": "https://www.parahumans.net/2018/12/04/polarize-10-12/", + "simplifiedTitle": "12" + }, + { + "url": "https://www.parahumans.net/2018/12/08/polarize-10-13/", + "simplifiedTitle": "13" + }, + { + "url": "https://www.parahumans.net/2018/12/11/interlude-10-y/", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: Chris" + }, + { + "url": "https://www.parahumans.net/2018/12/15/interlude-10-z/", + "simplifiedTitle": "Interlude III", + "characterNamesTitle": "Interlude: Aiden" + } + ] + }, + { + "label": "Arc 11", + "title": "Blinding", + "chapters": [ + { + "url": "https://www.parahumans.net/2018/12/18/blinding-11-1/", + "simplifiedTitle": "1" + }, + { + "url": "https://www.parahumans.net/2018/12/22/blinding-11-2/", + "simplifiedTitle": "2" + }, + { + "url": "https://www.parahumans.net/2018/12/25/blinding-11-3/", + "simplifiedTitle": "3" + }, + { + "url": "https://www.parahumans.net/2018/12/29/interlude-11-a/", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: Sidepiece" + }, + { + "url": "https://www.parahumans.net/2019/01/01/blinding-11-4/", + "simplifiedTitle": "4" + }, + { + "url": "https://www.parahumans.net/2019/01/05/blinding-11-5/", + "simplifiedTitle": "5" + }, + { + "url": "https://www.parahumans.net/2019/01/08/blinding-11-6/", + "simplifiedTitle": "6" + }, + { + "url": "https://www.parahumans.net/2019/01/12/blinding-11-7/", + "simplifiedTitle": "7" + }, + { + "url": "https://www.parahumans.net/2019/01/15/blinding-11-8/", + "simplifiedTitle": "8" + }, + { + "url": "https://www.parahumans.net/2019/01/19/interlude-11-b/", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: Colt" + }, + { + "url": "https://www.parahumans.net/2019/01/22/interlude-11-c/", + "simplifiedTitle": "Interlude III", + "characterNamesTitle": "Interlude: Darlene" + }, + { + "url": "https://www.parahumans.net/2019/01/26/blinding-11-9/", + "simplifiedTitle": "9" + }, + { + "url": "https://www.parahumans.net/2019/01/29/blinding-11-10/", + "simplifiedTitle": "10" + }, + { + "url": "https://www.parahumans.net/2019/02/02/blinding-11-11/", + "simplifiedTitle": "11" + }, + { + "url": "https://www.parahumans.net/2019/02/05/blinding-11-12/", + "simplifiedTitle": "12" + } + ] + }, + { + "label": "Arc 12", + "title": "Heavens", + "chapters": [ + { + "url": "https://www.parahumans.net/2019/02/09/interlude-12-z/", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: May" + }, + { + "url": "https://www.parahumans.net/2019/02/12/heavens-12-1/", + "simplifiedTitle": "1" + }, + { + "url": "https://www.parahumans.net/2019/02/16/heavens-12-2/", + "simplifiedTitle": "2" + }, + { + "url": "https://www.parahumans.net/2019/02/19/interlude-12-e/", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: Nic" + }, + { + "url": "https://www.parahumans.net/2019/02/23/heavens-12-3/", + "simplifiedTitle": "3" + }, + { + "url": "https://www.parahumans.net/2019/02/26/heavens-12-4/", + "simplifiedTitle": "4" + }, + { + "url": "https://www.parahumans.net/2019/03/02/heavens-12-all/", + "simplifiedTitle": "Interlude III", + "characterNamesTitle": "Interlude: Shards" + }, + { + "url": "https://www.parahumans.net/2019/03/05/heavens-12-5/", + "simplifiedTitle": "5" + }, + { + "url": "https://www.parahumans.net/2019/03/09/heavens-12-6/", + "simplifiedTitle": "6" + }, + { + "url": "https://www.parahumans.net/2019/03/12/heavens-12-f/", + "simplifiedTitle": "Interlude IV", + "characterNamesTitle": "Interlude: Ryan" + }, + { + "url": "https://www.parahumans.net/2019/03/16/heavens-12-7/", + "simplifiedTitle": "7" + }, + { + "url": "https://www.parahumans.net/2019/03/19/heavens-12-8/", + "simplifiedTitle": "8" + }, + { + "url": "https://www.parahumans.net/2019/03/23/heavens-12-9/", + "simplifiedTitle": "9" + }, + { + "url": "https://www.parahumans.net/2019/03/26/heavens-12-none/", + "simplifiedTitle": "Interlude V", + "characterNamesTitle": "Interlude: Shawn" + }, + { + "url": "https://www.parahumans.net/2019/03/29/heavens-12-x/", + "simplifiedTitle": "Interlude VI", + "characterNamesTitle": "Interlude: Assorted" + } + ] + }, + { + "label": "Arc 13", + "title": "Black", + "chapters": [ + { + "url": "https://www.parahumans.net/2019/04/02/black-13-1/", + "simplifiedTitle": "1" + }, + { + "url": "https://www.parahumans.net/2019/04/05/black-13-2/", + "simplifiedTitle": "2" + }, + { + "url": "https://www.parahumans.net/2019/04/09/black-13-3/", + "simplifiedTitle": "3" + }, + { + "url": "https://www.parahumans.net/2019/04/13/black-13-4/", + "simplifiedTitle": "4" + }, + { + "url": "https://www.parahumans.net/2019/04/16/black-13-5/", + "simplifiedTitle": "5" + }, + { + "url": "https://www.parahumans.net/2019/04/20/black-13-6/", + "simplifiedTitle": "6" + }, + { + "url": "https://www.parahumans.net/2019/04/23/black-13-7/", + "simplifiedTitle": "7" + }, + { + "url": "https://www.parahumans.net/2019/04/27/black-13-8/", + "simplifiedTitle": "8" + }, + { + "url": "https://www.parahumans.net/2019/04/30/black-13-x/", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: The Overseer" + }, + { + "url": "https://www.parahumans.net/2019/05/04/black-13-9/", + "simplifiedTitle": "9" + }, + { + "url": "https://www.parahumans.net/2019/05/07/black-13-10/", + "simplifiedTitle": "10" + }, + { + "url": "https://www.parahumans.net/2019/05/11/black-13-11/", + "simplifiedTitle": "11" + }, + { + "url": "https://www.parahumans.net/2019/05/14/13-z/", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: Sveta" + } + ] + }, + { + "label": "Arc 14", + "title": "Breaking", + "chapters": [ + { + "url": "https://www.parahumans.net/2019/05/18/breaking-14-1/", + "simplifiedTitle": "1" + }, + { + "url": "https://www.parahumans.net/2019/05/21/breaking-14-2/", + "simplifiedTitle": "2" + }, + { + "url": "https://www.parahumans.net/2019/05/25/breaking-14-3/", + "simplifiedTitle": "3" + }, + { + "url": "https://www.parahumans.net/2019/05/28/breaking-14-4/", + "simplifiedTitle": "4" + }, + { + "url": "https://www.parahumans.net/2019/06/01/breaking-14-5/", + "simplifiedTitle": "5" + }, + { + "url": "https://www.parahumans.net/2019/06/04/breaking-14-6/", + "simplifiedTitle": "6" + }, + { + "url": "https://www.parahumans.net/2019/06/08/breaking-14-7/", + "simplifiedTitle": "7" + }, + { + "url": "https://www.parahumans.net/2019/06/11/breaking-14-8/", + "simplifiedTitle": "8" + }, + { + "url": "https://www.parahumans.net/2019/06/15/breaking-14-9/", + "simplifiedTitle": "9" + }, + { + "url": "https://www.parahumans.net/2019/06/18/breaking-14-10/", + "simplifiedTitle": "10" + }, + { + "url": "https://www.parahumans.net/2019/06/22/breaking-14-11/", + "simplifiedTitle": "11" + }, + { + "url": "https://www.parahumans.net/2019/06/25/breaking-14-12/", + "simplifiedTitle": "12" + }, + { + "url": "https://www.parahumans.net/2019/06/29/breaking-14-z/", + "simplifiedTitle": "Interlude", + "characterNamesTitle": "Interlude: Kamil" + } + ] + }, + { + "label": "Arc 15", + "title": "Dying", + "chapters": [ + { + "url": "https://www.parahumans.net/2019/07/02/dying-15-a/", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: Loved Ones" + }, + { + "url": "https://www.parahumans.net/2019/07/06/dying-15-1/", + "simplifiedTitle": "1" + }, + { + "url": "https://www.parahumans.net/2019/07/09/dying-15-2/", + "simplifiedTitle": "2" + }, + { + "url": "https://www.parahumans.net/2019/07/13/dying-15-3/", + "simplifiedTitle": "3" + }, + { + "url": "https://www.parahumans.net/2019/07/16/dying-15-4/", + "simplifiedTitle": "4" + }, + { + "url": "https://www.parahumans.net/2019/07/20/dying-15-5/", + "simplifiedTitle": "5" + }, + { + "url": "https://www.parahumans.net/2019/07/23/dying-15-6/", + "simplifiedTitle": "6" + }, + { + "url": "https://www.parahumans.net/2019/07/27/dying-15-7/", + "simplifiedTitle": "7" + }, + { + "url": "https://www.parahumans.net/2019/07/30/dying-15-8/", + "simplifiedTitle": "8" + }, + { + "url": "https://www.parahumans.net/2019/08/03/dying-15-x/", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: The Taught" + }, + { + "url": "https://www.parahumans.net/2019/08/06/dying-15-y/", + "simplifiedTitle": "Interlude III", + "characterNamesTitle": "Interlude: The Taught, part 2" + }, + { + "url": "https://www.parahumans.net/2019/08/10/dying-15-z/", + "simplifiedTitle": "Interlude IV", + "characterNamesTitle": "Interlude: The Taught, part 3" + } + ] + }, + { + "label": "Arc 16", + "title": "From Within", + "chapters": [ + { + "url": "https://www.parahumans.net/2019/08/13/from-within-16-1/", + "simplifiedTitle": "1" + }, + { + "url": "https://www.parahumans.net/2019/08/17/from-within-16-2/", + "simplifiedTitle": "2" + }, + { + "url": "https://www.parahumans.net/2019/08/20/from-within-16-3/", + "simplifiedTitle": "3" + }, + { + "url": "https://www.parahumans.net/2019/08/24/from-within-16-4/", + "simplifiedTitle": "4" + }, + { + "url": "https://www.parahumans.net/2019/08/27/from-within-16-5/", + "simplifiedTitle": "5" + }, + { + "url": "https://www.parahumans.net/2019/08/31/from-within-16-6/", + "simplifiedTitle": "6" + }, + { + "url": "https://www.parahumans.net/2019/09/03/from-within-16-7/", + "simplifiedTitle": "7" + }, + { + "url": "https://www.parahumans.net/2019/09/07/from-within-16-8/", + "simplifiedTitle": "8" + }, + { + "url": "https://www.parahumans.net/2019/09/10/from-within-16-9/", + "simplifiedTitle": "9" + }, + { + "url": "https://www.parahumans.net/2019/09/14/from-within-16-10/", + "simplifiedTitle": "10" + }, + { + "url": "https://www.parahumans.net/2019/09/17/from-within-16-11/", + "simplifiedTitle": "11" + }, + { + "url": "https://www.parahumans.net/2019/09/21/from-within-16-12/", + "simplifiedTitle": "12" + }, + { + "url": "https://www.parahumans.net/2019/09/24/from-within-16-y/", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: Amy" + }, + { + "url": "https://www.parahumans.net/2019/09/28/from-within-16-z/", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: The Red Queen" + } + ] + }, + { + "label": "Arc 17", + "title": "Sundown", + "chapters": [ + { + "url": "https://www.parahumans.net/2019/10/01/sundown-17-1/", + "simplifiedTitle": "1" + }, + { + "url": "https://www.parahumans.net/2019/10/05/sundown-17-2/", + "simplifiedTitle": "2" + }, + { + "url": "https://www.parahumans.net/2019/10/08/sundown-17-3/", + "simplifiedTitle": "3" + }, + { + "url": "https://www.parahumans.net/2019/10/12/sundown-17-4/", + "simplifiedTitle": "4" + }, + { + "url": "https://www.parahumans.net/2019/10/15/sundown-17-5/", + "simplifiedTitle": "5" + }, + { + "url": "https://www.parahumans.net/2019/10/19/sundown-17-6/", + "simplifiedTitle": "6" + }, + { + "url": "https://www.parahumans.net/2019/10/22/sundown-17-7/", + "simplifiedTitle": "7" + }, + { + "url": "https://www.parahumans.net/2019/10/26/sundown-17-8/", + "simplifiedTitle": "8" + }, + { + "url": "https://www.parahumans.net/2019/10/29/sundown-17-9/", + "simplifiedTitle": "9" + }, + { + "url": "https://www.parahumans.net/2019/11/02/sundown-17-10/", + "simplifiedTitle": "10" + }, + { + "url": "https://www.parahumans.net/2019/11/05/interlude-17-x-sundown/", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: The Major Malfunctions" + }, + { + "url": "https://www.parahumans.net/2019/11/09/interlude-17-y-sundown/", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: The Major Malfunctions, part 2" + }, + { + "url": "https://www.parahumans.net/2019/11/12/interlude-17-z-sundown/", + "simplifiedTitle": "Interlude III", + "characterNamesTitle": "Interlude: Assorted" + } + ] + }, + { + "label": "Arc 18", + "title": "Radiation", + "chapters": [ + { + "url": "https://www.parahumans.net/2019/11/16/radiation-18-1/", + "simplifiedTitle": "1" + }, + { + "url": "https://www.parahumans.net/2019/11/19/radiation-18-2/", + "simplifiedTitle": "2" + }, + { + "url": "https://www.parahumans.net/2019/11/23/radiation-18-3/", + "simplifiedTitle": "3" + }, + { + "url": "https://www.parahumans.net/2019/11/26/radiation-18-4/", + "simplifiedTitle": "4" + }, + { + "url": "https://www.parahumans.net/2019/11/30/radiation-18-5/", + "simplifiedTitle": "5" + }, + { + "url": "https://www.parahumans.net/2019/12/03/radiation-18-6/", + "simplifiedTitle": "6" + }, + { + "url": "https://www.parahumans.net/2019/12/07/radiation-18-7/", + "simplifiedTitle": "7" + }, + { + "url": "https://www.parahumans.net/2019/12/10/radiation-18-8/", + "simplifiedTitle": "8" + }, + { + "url": "https://www.parahumans.net/2019/12/14/radiation-18-9/", + "simplifiedTitle": "9" + }, + { + "url": "https://www.parahumans.net/2019/12/17/radiation-18-10/", + "simplifiedTitle": "10" + }, + { + "url": "https://www.parahumans.net/2019/12/21/interlude-18-z-radiation/", + "simplifiedTitle": "Interlude", + "characterNamesTitle": "Interlude: Titans" + } + ] + }, + { + "label": "Arc 19", + "title": "Infrared", + "chapters": [ + { + "url": "https://www.parahumans.net/2019/12/24/infrared-19-1/", + "simplifiedTitle": "1" + }, + { + "url": "https://www.parahumans.net/2019/12/28/infrared-19-2/", + "simplifiedTitle": "2" + }, + { + "url": "https://www.parahumans.net/2020/01/01/interlude-19-a/", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: Egg" + }, + { + "url": "https://www.parahumans.net/2020/01/04/infrared-19-3/", + "simplifiedTitle": "3" + }, + { + "url": "https://www.parahumans.net/2020/01/07/infrared-19-4/", + "simplifiedTitle": "4" + }, + { + "url": "https://www.parahumans.net/2020/01/11/infrared-19-b/", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: Gilpatrick" + }, + { + "url": "https://www.parahumans.net/2020/01/14/infrared-19-c/", + "simplifiedTitle": "Interlude III", + "characterNamesTitle": "Interlude: Gilpatrick, part 2" + }, + { + "url": "https://www.parahumans.net/2020/01/18/infrared-19-5/", + "simplifiedTitle": "5" + }, + { + "url": "https://www.parahumans.net/2020/01/21/infrared-19-6/", + "simplifiedTitle": "6" + }, + { + "url": "https://www.parahumans.net/2020/01/25/infrared-19-d/", + "simplifiedTitle": "Interlude IV", + "characterNamesTitle": "Interlude: Brianna" + }, + { + "url": "https://www.parahumans.net/2020/01/28/infrared-19-e/", + "simplifiedTitle": "Interlude V", + "characterNamesTitle": "Interlude: Moonsong" + }, + { + "url": "https://www.parahumans.net/2020/02/02/infrared-19-7/", + "simplifiedTitle": "7" + }, + { + "url": "https://www.parahumans.net/2020/02/04/infrared-19-8/", + "simplifiedTitle": "8" + }, + { + "url": "https://www.parahumans.net/2020/02/08/infrared-19-9/", + "simplifiedTitle": "9" + }, + { + "url": "https://www.parahumans.net/2020/02/11/infrared-19-f/", + "simplifiedTitle": "Interlude VI", + "characterNamesTitle": "Interlude: Imp" + }, + { + "url": "https://www.parahumans.net/2020/02/15/infrared-19-10/", + "simplifiedTitle": "10" + }, + { + "url": "https://www.parahumans.net/2020/02/18/infrared-19-g/", + "simplifiedTitle": "Interlude VII", + "characterNamesTitle": "Interlude: Brian" + }, + { + "url": "https://www.parahumans.net/2020/02/23/infrared-19-z/", + "simplifiedTitle": "Interlude VIII", + "characterNamesTitle": "Interlude: Assorted" + } + ] + }, + { + "label": "Arc 20", + "title": "Last", + "chapters": [ + { + "url": "https://www.parahumans.net/2020/02/25/last-20-1/", + "simplifiedTitle": "1" + }, + { + "url": "https://www.parahumans.net/2020/02/29/last-20-2/", + "simplifiedTitle": "2" + }, + { + "url": "https://www.parahumans.net/2020/03/03/last-20-3/", + "simplifiedTitle": "3" + }, + { + "url": "https://www.parahumans.net/2020/03/07/last-20-4/", + "simplifiedTitle": "4" + }, + { + "url": "https://www.parahumans.net/2020/03/10/last-20-5/", + "simplifiedTitle": "5" + }, + { + "url": "https://www.parahumans.net/2020/03/15/last-20-6/", + "simplifiedTitle": "6" + }, + { + "url": "https://www.parahumans.net/2020/03/17/last-20-7/", + "simplifiedTitle": "7" + }, + { + "url": "https://www.parahumans.net/2020/03/21/last-20-8/", + "simplifiedTitle": "8" + }, + { + "url": "https://www.parahumans.net/2020/03/24/last-20-9/", + "simplifiedTitle": "9" + }, + { + "url": "https://www.parahumans.net/2020/03/28/last-20-a/", + "simplifiedTitle": "Interlude I", + "characterNamesTitle": "Interlude: Defiant" + }, + { + "url": "https://www.parahumans.net/2020/03/31/last-20-10/", + "simplifiedTitle": "10" + }, + { + "url": "https://www.parahumans.net/2020/04/04/last-20-b/", + "simplifiedTitle": "Interlude II", + "characterNamesTitle": "Interlude: Presley" + }, + { + "url": "https://www.parahumans.net/2020/04/07/last-20-11/", + "simplifiedTitle": "11" + }, + { + "url": "https://www.parahumans.net/2020/04/11/last-20-e1/", + "simplifiedTitle": "Epilogue I", + "characterNamesTitle": "Epilogue: Chevalier" + }, + { + "url": "https://www.parahumans.net/2020/04/14/last-20-e2/", + "simplifiedTitle": "Epilogue II", + "characterNamesTitle": "Epilogue: Chastity" + }, + { + "url": "https://www.parahumans.net/2020/04/18/last-20-e3/", + "simplifiedTitle": "Epilogue III", + "characterNamesTitle": "Epilogue: Harbinger Five" + }, + { + "url": "https://www.parahumans.net/2020/04/21/last-20-e4/", + "simplifiedTitle": "Epilogue IV", + "characterNamesTitle": "Epilogue: Riley" + }, + { + "url": "https://www.parahumans.net/2020/04/25/last-20-e5/", + "simplifiedTitle": "Epilogue V", + "characterNamesTitle": "Epilogue: Victoria" + }, + { + "url": "https://www.parahumans.net/2020/04/28/last-20-e6/", + "simplifiedTitle": "Epilogue VI", + "characterNamesTitle": "Epilogue: Crystal" + }, + { + "url": "https://www.parahumans.net/2020/05/02/last-20-end/", + "simplifiedTitle": "Epilogue VII", + "characterNamesTitle": "Epilogue: Missy" + } + ] + } +] From 3c55c4a377b0c203adcb1f2e8ef13170241cf7cd Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Thu, 2 Jan 2025 12:30:20 +0900 Subject: [PATCH 06/11] Pipeline better --- lib/choose-chapter-title.js | 27 --------- lib/convert-worker.js | 4 +- lib/convert.js | 111 +++++++++++++++++++++++++++--------- lib/scaffold.js | 78 ++++++------------------- lib/worm-scraper.js | 20 +++++-- 5 files changed, 116 insertions(+), 124 deletions(-) delete mode 100644 lib/choose-chapter-title.js diff --git a/lib/choose-chapter-title.js b/lib/choose-chapter-title.js deleted file mode 100644 index d5fd7d3..0000000 --- a/lib/choose-chapter-title.js +++ /dev/null @@ -1,27 +0,0 @@ -"use strict"; - -module.exports = (chapterData, chapterTitleStyle) => { - if (chapterTitleStyle === "original") { - if (!chapterData.originalTitle) { - throw new Error(`originalTitle not found in chapter data for ${chapterData.url}`); - } - return chapterData.originalTitle; - } - if (chapterTitleStyle === "simplified") { - if (!chapterData.simplifiedTitle) { - throw new Error(`simplifiedTitle not found in chapter data for ${chapterData.url}`); - } - return chapterData.simplifiedTitle; - } - if (chapterTitleStyle === "character-names") { - if (!chapterData.characterNamesTitle) { - if (!chapterData.simplifiedTitle) { - throw new Error(`Neither characterNamesTitle nor simplifiedTitle found in chapter data for ${chapterData.url}`); - } - return chapterData.simplifiedTitle; - } - return chapterData.characterNamesTitle; - } - - throw new Error(`Invalid chapter title style: ${chapterTitleStyle}`); -}; diff --git a/lib/convert-worker.js b/lib/convert-worker.js index 2c93129..44525f6 100644 --- a/lib/convert-worker.js +++ b/lib/convert-worker.js @@ -30,7 +30,7 @@ function getChapterString(chapter, book, rawChapterDoc) { itemid="${chapter.url}" class="chapter"> - ${chapter.title} + ${chapter.usedTitle} @@ -136,7 +136,7 @@ function getBodyXML(chapter, book, contentEl) { const bodyEl = contentEl.ownerDocument.createElement("body"); const h1El = contentEl.ownerDocument.createElement("h1"); - h1El.textContent = chapter.title; + h1El.textContent = chapter.usedTitle; bodyEl.appendChild(h1El); while (contentEl.firstChild) { diff --git a/lib/convert.js b/lib/convert.js index dbb313f..f249bd6 100644 --- a/lib/convert.js +++ b/lib/convert.js @@ -4,34 +4,25 @@ const fs = require("fs").promises; const { performance } = require("perf_hooks"); const workerpool = require("workerpool"); const cliProgress = require("cli-progress"); -const chooseChapterTitle = require("./choose-chapter-title.js"); -module.exports = -async (cachePath, manifestPath, chapterDataPath, contentPath, book, concurrentJobs, chapterTitleStyle) => { +module.exports = async ( + cachePath, + manifestPath, + inputChapterDataPath, + augmentedChapterDataPath, + contentPath, + book, + concurrentJobs, + chapterTitleStyle +) => { const [manifestContents, chapterDataContents] = await Promise.all([ fs.readFile(manifestPath, { encoding: "utf-8" }), - fs.readFile(chapterDataPath, { encoding: "utf-8" }) + fs.readFile(inputChapterDataPath, { encoding: "utf-8" }) ]); const manifestChapters = JSON.parse(manifestContents); const chapterData = JSON.parse(chapterDataContents); - - if (chapterTitleStyle !== "original") { - for (const chapter of manifestChapters) { - let found = false; - for (const arc of chapterData) { - for (const chapterInArc of arc.chapters) { - if (chapter.url === chapterInArc.url) { - chapter.title = chooseChapterTitle(chapterInArc, chapterTitleStyle); - found = true; - break; - } - } - } - if (!found) { - throw new Error(`Chapter data not found for ${chapter.url}`); - } - } - } + augmentAndCheckChapterData(chapterData, manifestChapters, chapterTitleStyle); + await fs.writeFile(augmentedChapterDataPath, JSON.stringify(chapterData, null, 2)); console.log("Converting raw downloaded HTML to EPUB chapters"); const progress = new cliProgress.SingleBar({ @@ -50,11 +41,10 @@ async (cachePath, manifestPath, chapterDataPath, contentPath, book, concurrentJo const pool = workerpool.pool(path.resolve(__dirname, "convert-worker.js"), poolOptions); const warnings = []; - await Promise.all(manifestChapters.map(async chapter => { - const inputPath = path.resolve(cachePath, chapter.filename); - - const destFileName = `${path.basename(chapter.filename, ".html")}.xhtml`; - const outputPath = path.resolve(contentPath, destFileName); + const flattenedChapters = chapterData.flatMap(arc => arc.chapters); + await Promise.all(flattenedChapters.map(async chapter => { + const inputPath = path.resolve(cachePath, chapter.inputFilename); + const outputPath = path.resolve(contentPath, chapter.outputFilename); warnings.push(...await pool.exec("convertChapter", [chapter, book, inputPath, outputPath])); @@ -70,3 +60,70 @@ async (cachePath, manifestPath, chapterDataPath, contentPath, book, concurrentJo console.log(`All chapters converted in ${Math.round((performance.now() - start) / 100) / 10} seconds`); }; + +// This function modifies chapterData in place, adding filename and originalTitle properties to each chapter. (filename +// contains the converted filename, not the original input one). It also checks that the downloaded-chapters manifest +// and the prepackaged chapter data are in sync. If they're not, we'll be unable to create arc title pages and a table +// of contents, so we'll error out. +function augmentAndCheckChapterData(chapterData, manifestChapters, chapterTitleStyle) { + for (const manifestChapter of manifestChapters) { + let found = false; + for (const arc of chapterData) { + for (const chapterInArc of arc.chapters) { + if (manifestChapter.url === chapterInArc.url) { + chapterInArc.inputFilename = manifestChapter.filename; + chapterInArc.outputFilename = `${path.basename(chapterInArc.inputFilename, ".html")}.xhtml`; + chapterInArc.originalTitle = manifestChapter.title; + chapterInArc.usedTitle = chooseChapterTitle(chapterInArc, chapterTitleStyle); + chapterInArc.datePublished = manifestChapter.datePublished; + found = true; + break; + } + } + } + if (!found) { + throw new Error(`Chapter data not found for ${manifestChapter.url} which appeared in the manifest`); + } + } + + for (const arc of chapterData) { + for (const chapter of arc.chapters) { + let found = false; + for (const manifestChapter of manifestChapters) { + if (chapter.url === manifestChapter.url) { + found = true; + break; + } + } + if (!found) { + throw new Error(`Chapter data found for ${chapter.url} which did not appear in the manifest`); + } + } + } +} + +function chooseChapterTitle(chapterData, chapterTitleStyle) { + if (chapterTitleStyle === "original") { + if (!chapterData.originalTitle) { + throw new Error(`originalTitle not found in chapter data for ${chapterData.url}`); + } + return chapterData.originalTitle; + } + if (chapterTitleStyle === "simplified") { + if (!chapterData.simplifiedTitle) { + throw new Error(`simplifiedTitle not found in chapter data for ${chapterData.url}`); + } + return chapterData.simplifiedTitle; + } + if (chapterTitleStyle === "character-names") { + if (!chapterData.characterNamesTitle) { + if (!chapterData.simplifiedTitle) { + throw new Error(`Neither characterNamesTitle nor simplifiedTitle found in chapter data for ${chapterData.url}`); + } + return chapterData.simplifiedTitle; + } + return chapterData.characterNamesTitle; + } + + throw new Error(`Invalid chapter title style: ${chapterTitleStyle}`); +} diff --git a/lib/scaffold.js b/lib/scaffold.js index 186ee28..e25f4e7 100644 --- a/lib/scaffold.js +++ b/lib/scaffold.js @@ -1,7 +1,6 @@ "use strict"; const fs = require("fs").promises; const path = require("path"); -const chooseChapterTitle = require("./choose-chapter-title.js"); const BOOK_PUBLISHER = "Domenic Denicola"; const BOOK_AUTHOR = "Wildbow"; @@ -17,15 +16,13 @@ module.exports = async ( bookPath, contentPath, chaptersPath, - manifestPath, - chapterDataPath, - bookInfo, - chapterTitleStyle + augmentedChapterDataPath, + bookInfo ) => { await Promise.all([ fs.cp(scaffoldingPath, bookPath, { recursive: true, filter: noThumbs }), fs.cp(coverImagePath, path.resolve(bookPath, "OEBPS", COVER_IMAGE_FILENAME)), - getChapterInfo(contentPath, chaptersPath, manifestPath, chapterDataPath, chapterTitleStyle).then(info => { + getChapterInfo(contentPath, chaptersPath, augmentedChapterDataPath).then(info => { return Promise.all([ writeOPF(contentPath, bookInfo, info.manifestAndSpineFiles, info.datePublished), writeNav(contentPath, info.manifestAndSpineFiles, info.tocHTML), @@ -125,22 +122,16 @@ ${tocHTML} return fs.writeFile(path.resolve(contentPath, NAV_FILENAME), contents); } -async function getChapterInfo(contentPath, chaptersPath, manifestPath, chapterDataPath, chapterTitleStyle) { +async function getChapterInfo(contentPath, chaptersPath, augmentedChapterDataPath) { const hrefPrefix = `${path.relative(contentPath, chaptersPath)}/`; - const [manifestContents, chapterDataContents] = await Promise.all([ - fs.readFile(manifestPath, { encoding: "utf-8" }), - fs.readFile(chapterDataPath, { encoding: "utf-8" }) - ]); - const manifestChapters = JSON.parse(manifestContents); - const chapterData = JSON.parse(chapterDataContents); - - augmentAndCheckChapterData(chapterData, manifestChapters); + const chapterData = JSON.parse(await fs.readFile(augmentedChapterDataPath, { encoding: "utf-8" })); const arcTitlePages = []; const manifestAndSpineFiles = []; let tocHTML = "
        \n"; let arcIdCounter = 0; + let lastChapter; for (const arc of chapterData) { if (!arc.invisible) { const arcFilename = `arc${arcIdCounter}.xhtml`; @@ -162,14 +153,15 @@ async function getChapterInfo(contentPath, chaptersPath, manifestPath, chapterDa } for (const chapter of arc.chapters) { - const chapterHref = `${hrefPrefix}${chapter.filename}`; - const chapterTitle = chooseChapterTitle(chapter, chapterTitleStyle); + const chapterHref = `${hrefPrefix}${chapter.outputFilename}`; manifestAndSpineFiles.push({ - id: path.basename(chapter.filename, ".xhtml"), + id: path.basename(chapter.outputFilename, ".xhtml"), href: chapterHref }); - tocHTML += `
      1. ${chapterTitle}
      2. \n`; + tocHTML += `
      3. ${chapter.usedTitle}
      4. \n`; + + lastChapter = chapter; } if (!arc.invisible) { @@ -183,71 +175,33 @@ async function getChapterInfo(contentPath, chaptersPath, manifestPath, chapterDa tocHTML += `
      `; // We say that the publication date of the book is equal to the publication date of the last chapter. - const { datePublished } = manifestChapters.at(-1); + const { datePublished } = lastChapter; return { arcTitlePages, manifestAndSpineFiles, tocHTML, datePublished }; } async function writeArcTitlePages(chaptersPath, arcTitlePages) { const promises = []; - for (const arc of arcTitlePages) { + for (const arcTitlePage of arcTitlePages) { const output = ` - ${arcPlaintextTitle(arc)} + ${arcPlaintextTitle(arcTitlePage)} -

      ${arc.label} ${arc.title}

      +

      ${arcTitlePage.label} ${arcTitlePage.title}

      `; - promises.push(fs.writeFile(path.resolve(chaptersPath, arc.filename), output)); + promises.push(fs.writeFile(path.resolve(chaptersPath, arcTitlePage.filename), output)); } await Promise.all(promises); } -// This function modifies chapterData in place, adding filename and originalTitle properties to each chapter. (filename -// contains the converted filename, not the original input one). It also checks that the downloaded-chapters manifest -// and the prepackaged chapter data are in sync. If they're not, we'll be unable to create arc title pages and a table -// of contents, so we'll error out. -function augmentAndCheckChapterData(chapterData, manifestChapters) { - for (const manifestChapter of manifestChapters) { - let found = false; - for (const arc of chapterData) { - for (const chapterInArc of arc.chapters) { - if (manifestChapter.url === chapterInArc.url) { - chapterInArc.filename = `${path.basename(manifestChapter.filename, ".html")}.xhtml`; - chapterInArc.originalTitle = manifestChapter.title; - found = true; - break; - } - } - } - if (!found) { - throw new Error(`Chapter data not found for ${manifestChapter.url} which appeared in the manifest`); - } - } - - for (const arc of chapterData) { - for (const chapter of arc.chapters) { - let found = false; - for (const manifestChapter of manifestChapters) { - if (chapter.url === manifestChapter.url) { - found = true; - break; - } - } - if (!found) { - throw new Error(`Chapter data found for ${chapter.url} which did not appear in the manifest`); - } - } - } -} - function arcPlaintextTitle(arc) { return `${arc.label}: ${arc.title}`; } diff --git a/lib/worm-scraper.js b/lib/worm-scraper.js index fc9d51d..a097c9f 100644 --- a/lib/worm-scraper.js +++ b/lib/worm-scraper.js @@ -68,7 +68,8 @@ const outputFilename = argv.out === OUTPUT_DEFAULT ? `${books[argv.book].title}. const cachePath = path.resolve(argv.cache, argv.book); const manifestPath = path.resolve(cachePath, "manifest.json"); -const chapterDataPath = path.resolve(__dirname, "../chapter-data", `${argv.book}.json`); +const augmentedChapterDataPath = path.resolve(cachePath, "chapter-data.json"); +const inputChapterDataPath = path.resolve(__dirname, "../chapter-data", `${argv.book}.json`); const scaffoldingPath = path.resolve(__dirname, "../scaffolding"); const coverImagePath = path.resolve(__dirname, "../covers", `${argv.book}.jpg`); @@ -91,7 +92,16 @@ if (argv._.includes("convert")) { commands.push(async () => { await fs.rm(chaptersPath, { force: true, recursive: true, maxRetries: 3 }); await fs.mkdir(chaptersPath, { recursive: true }); - await convert(cachePath, manifestPath, chapterDataPath, chaptersPath, argv.book, argv.jobs, argv["chapter-titles"]); + await convert( + cachePath, + manifestPath, + inputChapterDataPath, + augmentedChapterDataPath, + chaptersPath, + argv.book, + argv.jobs, + argv["chapter-titles"] + ); }); } @@ -103,10 +113,8 @@ if (argv._.includes("scaffold")) { stagingPath, contentPath, chaptersPath, - manifestPath, - chapterDataPath, - bookInfo, - argv["chapter-titles"] + augmentedChapterDataPath, + bookInfo )); } From 765667125c2c85011b21b427f1fffdc6a52ee772 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Thu, 2 Jan 2025 12:36:39 +0900 Subject: [PATCH 07/11] Tweak --- lib/convert.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/convert.js b/lib/convert.js index f249bd6..5262a77 100644 --- a/lib/convert.js +++ b/lib/convert.js @@ -23,6 +23,7 @@ module.exports = async ( const chapterData = JSON.parse(chapterDataContents); augmentAndCheckChapterData(chapterData, manifestChapters, chapterTitleStyle); await fs.writeFile(augmentedChapterDataPath, JSON.stringify(chapterData, null, 2)); + const flattenedChapters = chapterData.flatMap(arc => arc.chapters); console.log("Converting raw downloaded HTML to EPUB chapters"); const progress = new cliProgress.SingleBar({ @@ -32,7 +33,7 @@ module.exports = async ( }, cliProgress.Presets.shades_classic); const start = performance.now(); - progress.start(manifestChapters.length, 0, { time: " " }); + progress.start(flattenedChapters.length, 0, { time: " " }); const poolOptions = {}; if (concurrentJobs !== undefined) { @@ -41,7 +42,6 @@ module.exports = async ( const pool = workerpool.pool(path.resolve(__dirname, "convert-worker.js"), poolOptions); const warnings = []; - const flattenedChapters = chapterData.flatMap(arc => arc.chapters); await Promise.all(flattenedChapters.map(async chapter => { const inputPath = path.resolve(cachePath, chapter.inputFilename); const outputPath = path.resolve(contentPath, chapter.outputFilename); From e40e4ac4f9c16366435455215fbbfb40cfa980cd Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Thu, 2 Jan 2025 13:08:57 +0900 Subject: [PATCH 08/11] Document and update comment --- README.md | 18 ++++++++++++++++++ lib/download.js | 7 ++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3ae56bb..97e7497 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,24 @@ Similarly, for _Glow-worm_: worm-scraper --book=glow-worm ``` +## Configuring chapter titles + +The original chapter titles, i.e. the ones that appear as heading at the top of each chapter published online, are not very book-like. They vary wildly, e.g. "Gestation 1.1", "Daybreak – 1.2", "Interlude 1", "Flare – Interlude 2", "Interlude 10.y", "Interlude 10.5 (Bonus)", "Interlude 14.5 (Bonus Interlude)". + +By default, `worm-scraper` simplifies the titles to be just numbers ("1", "2", "3"), with interludes denoted via Roman numerals ("Interlude I", "Interlude II", ...)—or left as simply "Interlude" if an arc contains a single interlude. + +If you want the original chapter titles, you can pass the following option: + +```bash +worm-scraper --chapter-titles=original +``` + +There's a third option, which is to have the interludes (and _Ward_'s epilogues) include character names. Samples of this format include "Interlude: Danny" or "Interlude: Armsmaster". _This can be a slight spoiler_, because the reading experience of many interludes relies on you gradually discovering who the main character is and how they relate to what you've seen before. It can also spoil you on which characters survive, if you look ahead in the table of contents. + +This style is _sort of_ aligned with how the interludes are presented in the table of contents [for _Worm_](https://parahumans.wordpress.com/table-of-contents/) and [for _Ward_](https://www.parahumans.net/table-of-contents/). But even those are inconsistent, and `worm-scraper` departs from the table of contents names in several cases. `worm-scraper` generally tries to pick the name name by which the character is first referred to in the chapter, to minimize the spoiler effect, but sometimes takes influence from the original tables of contents, or the names chosen by [the Fandom wiki](https://worm.fandom.com/wiki/Chapter_List). + +You can see all the chosen character-name titles in the [`chapter-data/`](./chapter-data/) directory's files. (But, beware of spoilers.) If you strongly disagree with a choice made, please file an issue. + ## Reading EPUBs on Amazon Kindle EPUBs are not the native format for Amazon Kindle devices and apps. However, you can send them to your Kindle library by following [Amazon's instructions](https://www.amazon.com/gp/help/customer/display.html?nodeId=G5WYD9SAF7PGXRNA). diff --git a/lib/download.js b/lib/download.js index 6d40401..3fe51ef 100644 --- a/lib/download.js +++ b/lib/download.js @@ -93,9 +93,10 @@ function getNextChapterURL(rawChapterDoc) { function getChapterTitle(rawChapterDoc) { // Remove " – " because it's present in Ward but not in Worm, which is inconsistent. (And leaving it in causes slight - // issues down the line where we remove spaces around em dashes during conversion.) In the future it might be nice to - // have proper chapter titles, e.g. sections per arc with title pages and then just "1" or similar for the chapter. - // Until then this is reasonable and uniform. + // issues down the line where we remove spaces around em dashes during conversion.) + // + // TODO: now that we have an "original" option, figure out how to just leave this as-is (without messing up the em + // dash processing). return rawChapterDoc.querySelector("h1.entry-title").textContent.replace(/ – /u, " "); } From ebd33a3c8079a26e0b21922e8b8926796fbfbc18 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Thu, 2 Jan 2025 13:11:46 +0900 Subject: [PATCH 09/11] Tweak docs a bit --- README.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 97e7497..85e8ee5 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,11 @@ Similarly, for _Glow-worm_: worm-scraper --book=glow-worm ``` -## Configuring chapter titles +## Reading EPUBs on Amazon Kindle + +EPUBs are not the native format for Amazon Kindle devices and apps. However, you can send them to your Kindle library by following [Amazon's instructions](https://www.amazon.com/gp/help/customer/display.html?nodeId=G5WYD9SAF7PGXRNA). + +## Chapter titles The original chapter titles, i.e. the ones that appear as heading at the top of each chapter published online, are not very book-like. They vary wildly, e.g. "Gestation 1.1", "Daybreak – 1.2", "Interlude 1", "Flare – Interlude 2", "Interlude 10.y", "Interlude 10.5 (Bonus)", "Interlude 14.5 (Bonus Interlude)". @@ -50,15 +54,17 @@ If you want the original chapter titles, you can pass the following option: worm-scraper --chapter-titles=original ``` -There's a third option, which is to have the interludes (and _Ward_'s epilogues) include character names. Samples of this format include "Interlude: Danny" or "Interlude: Armsmaster". _This can be a slight spoiler_, because the reading experience of many interludes relies on you gradually discovering who the main character is and how they relate to what you've seen before. It can also spoil you on which characters survive, if you look ahead in the table of contents. +There's a third option, which is to have the interludes (and _Ward_'s epilogues) include character names. Samples of this format include "Interlude: Danny" or "Interlude: Armsmaster". Use -This style is _sort of_ aligned with how the interludes are presented in the table of contents [for _Worm_](https://parahumans.wordpress.com/table-of-contents/) and [for _Ward_](https://www.parahumans.net/table-of-contents/). But even those are inconsistent, and `worm-scraper` departs from the table of contents names in several cases. `worm-scraper` generally tries to pick the name name by which the character is first referred to in the chapter, to minimize the spoiler effect, but sometimes takes influence from the original tables of contents, or the names chosen by [the Fandom wiki](https://worm.fandom.com/wiki/Chapter_List). +```bash +worm-scraper --chapter-titles=character-names +``` -You can see all the chosen character-name titles in the [`chapter-data/`](./chapter-data/) directory's files. (But, beware of spoilers.) If you strongly disagree with a choice made, please file an issue. +for this. _This can be a slight spoiler_, because the reading experience of many interludes relies on you gradually discovering who the main character is and how they relate to what you've seen before. It can also spoil you on which characters survive, if you look ahead in the table of contents. -## Reading EPUBs on Amazon Kindle +This style is _sort of_ aligned with how the interludes are presented in the table of contents [for _Worm_](https://parahumans.wordpress.com/table-of-contents/) and [for _Ward_](https://www.parahumans.net/table-of-contents/). But even those are inconsistent, and `worm-scraper` departs from the table of contents names in several cases. `worm-scraper` generally tries to pick the name name by which the character is first referred to in the chapter, to minimize the spoiler effect, but sometimes takes influence from the original tables of contents, or the names chosen by [the Fandom wiki](https://worm.fandom.com/wiki/Chapter_List). -EPUBs are not the native format for Amazon Kindle devices and apps. However, you can send them to your Kindle library by following [Amazon's instructions](https://www.amazon.com/gp/help/customer/display.html?nodeId=G5WYD9SAF7PGXRNA). +You can see all the chosen character-name titles in the [`chapter-data/`](./chapter-data/) directory's files. If you strongly disagree with a choice made, please file an issue. ## Text fixups From 381ffaf36eb3845aea409e760d94b9835c9d3ee2 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Thu, 2 Jan 2025 13:18:18 +0900 Subject: [PATCH 10/11] Add chapter-data directory to package files --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 0860622..54987da 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ }, "bin": "lib/worm-scraper.js", "files": [ + "chapter-data/", "covers/", "lib/", "scaffolding/", From 4eed7d712814be48eb4248ee5ee86c08a407fcc3 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Thu, 2 Jan 2025 13:21:08 +0900 Subject: [PATCH 11/11] Add styles to manifest --- lib/scaffold.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/scaffold.js b/lib/scaffold.js index e25f4e7..35e7f9a 100644 --- a/lib/scaffold.js +++ b/lib/scaffold.js @@ -5,6 +5,7 @@ const path = require("path"); const BOOK_PUBLISHER = "Domenic Denicola"; const BOOK_AUTHOR = "Wildbow"; +const STYLES_FILENAME = "chapter.css"; const COVER_DOCUMENT_FILENAME = "cover.xhtml"; const COVER_IMAGE_FILENAME = "cover.jpg"; const COVER_IMAGE_MIMETYPE = "image/jpeg"; @@ -81,6 +82,7 @@ function writeOPF(contentPath, bookInfo, manifestAndSpineFiles, datePublished) { + ${manifestItems}