Replace old pages with new ones

This commit is contained in:
mez 2025-07-19 23:32:29 +01:00
parent d374cf9690
commit 219ab35571
32 changed files with 509 additions and 3698 deletions

6
.gitignore vendored
View file

@ -1,9 +1,6 @@
__pycache__/
build/index.html
build/*/index.html
build/ff/*/index.html
build/comments/*/index.html
build/single/*/index.html
build/feed.xml
build/files/*.html
build/files/*.pdf
@ -15,7 +12,4 @@ build/secret/*.pdf
build/secret/*.epub
build/secret/*.gif
build/secret/*.png
build/emacs.jpg
files/
build/stats/*/index.html
index.html

View file

@ -2,9 +2,9 @@
./sortfics.sh
python3 generate.py
touch build/comments/.gitkeep
touch build/single/.gitkeep
python3 new.py
python3 feed.py
rclone copy build prazevps:/var/www/tre/public/fic -P
python3 mention.py

View file

@ -1,395 +0,0 @@
@charset "UTF-8";
/* hubballi-regular - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Hubballi';
font-style: normal;
font-weight: 400;
src: url('/fonts/hubballi-v7-latin-regular.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* merriweather-regular - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Merriweather';
font-style: normal;
font-weight: 400;
src: url('/fonts/merriweather-v30-latin-regular.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* merriweather-italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Merriweather';
font-style: italic;
font-weight: 400;
src: url('/fonts/merriweather-v30-latin-italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* merriweather-700 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Merriweather';
font-style: normal;
font-weight: 700;
src: url('/fonts/merriweather-v30-latin-700.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* merriweather-700italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Merriweather';
font-style: italic;
font-weight: 700;
src: url('/fonts/merriweather-v30-latin-700italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* noto-color-emoji-regular - emoji */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Noto Color Emoji';
font-style: normal;
font-weight: 400;
src: url('/fonts/noto-color-emoji-v30-emoji-regular.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
html {
height: 100%;
}
body {
height: 95%;
background: rgb(185,106,106);
background: radial-gradient(circle, rgba(185,106,106,1) 0%, rgba(236,197,197,1) 100%);
background-attachment: fixed;
font-family: "Merriweather", serif;
}
body, a, a:visited {
color: rgb(65, 27, 27);
}
a:hover {
background: #f0ef2d;
}
#warning {
background-color: #ad5252;
padding: 5px;
color: rgb(245,230,230);
}
#warning p {
margin: 5px;
}
#content {
width: 80%;
min-width: 350px;
margin: 0 auto;
min-height: 100%;
position: relative;
}
#inside {
padding-bottom: 100px;
}
footer {
height: 100px;
width: 100%;
position: absolute;
left: 0;
bottom: 0;
}
hr {
border: 2px dashed rgb(99, 44, 44);
}
div.fic, div.comment {
border: 2px solid rgb(99, 44, 44);
margin: 5px 0;
padding: 0 3px;
}
div.fic:hover, div.comment:hover {
background: rgba(255, 255, 255, 0.2);
}
h1, h2, h3 {
font-family: "Hubballi", cursive;
}
div.fic h1 {
font-size: 1.5em;
}
div.fic h1 span.ficno {
font-weight: normal;
font-style: italic;
font-size: 0.8em;
}
div.fic h1 span.ficnoprelim {
font-weight: normal;
font-style: italic;
font-size: 0.6em;
}
div.fic h1 span.abandoned, div.fic h1 span.incomplete {
font-weight: normal;
color: white;
}
div.fic h1 span.abandoned {
background-color: #9c0000;
}
div.fic h1 span.incomplete {
background-color: #8ab60b;
}
div.fic ul.ficlinks li, div.fic ul.ficmeta li {
list-style: none;
}
div.fic li.rating span.g {
background-color: #8ab60b;
color: white;
text-transform: uppercase;
font-family: "Hubballi", sans-serif;
}
div.fic li.rating span.t {
background-color: #e8d405;
color: white;
text-transform: uppercase;
font-family: "Hubballi", sans-serif;
}
div.fic li.rating span.m {
background-color: #eb7d10;
color: white;
text-transform: uppercase;
font-family: "Hubballi", sans-serif;
}
div.fic li.rating span.e {
background-color: #9c0000;
color: white;
text-transform: uppercase;
font-family: "Hubballi", sans-serif;
}
div.fic li.warnings i {
color: #9c0000;
font-weight: bold;
}
div.fic ul.ficlinks li a.locked::before {
content:"🔒";
font-family: none;
}
div.fic ul.ficlinks.french::before {
content:"French:";
}
div.fic ul.ficlinks.english::before {
content:"English:";
}
div.fic ul.ficlinks li a {
border: 2px solid rgb(99, 44, 44);
padding: 3px;
}
div.fic ul.ficlinks li {
display: inline;
line-height: 2;
}
div.fic ul.ficlinks li + li::before {
content: " • ";
}
div.comment.reply {
margin-left: 20px;
}
div.comment h1 {
font-size: 1.2em;
}
input, textarea {
display: block;
width: 90%;
margin: 10px;
font-family: "Merriweather", serif;
}
button {
margin-left: 10px;
font-family: "Hubballi", sans-serif;
font-weight: bold;
font-size: 1.2em;
border: 2px solid rgb(99, 44, 44);
background: transparent;
cursor: pointer;
padding: 3px;
}
button:hover {
background: rgba(255, 255, 255, 0.2);
}
span.spoiler {
filter: blur(0.25em);
}
span.spoiler:hover, span.spoiler:focus {
filter: blur(0);
}
details {
margin-bottom: 10px;
border: 5px solid #ad5252;
}
details > div {
margin: 10px !important;
}
details > h1 {
font-size: 1.2em;
margin: 10px;
}
summary {
background-color: #ad5252;
padding: 5px;
list-style: none;
color: rgb(245,230,230);
cursor: pointer;
}
summary a, summary a:visited {
color: rgb(245,230,230);
}
summary a:hover {
color: rgb(65, 27, 27);
}
details summary:marker {
display: none;
}
summary > span.character {
font-weight: bold;
}
summary > span.character:after {
margin: 0 5px;
font-family: "Hubballi", sans-serif;
font-size: 0.8em;
border-radius: 5px;
color: white;
padding: 2px;
}
summary > span.one:after {
content: "FF1";
background-color: #014477;
}
summary > span.two:after {
content: "FF2";
background-color: #932347;
}
summary > span.three:after {
content: "FF3";
background-color: #009b58;
background: linear-gradient(164deg, rgba(0,163,226,1) 0%, rgba(0,155,88,1) 100%);
}
summary > span.four:after {
content: "FF4";
background-color: #412f63;
}
summary > span.five:after {
content: "FF5";
background-color: #a046a1;
background: linear-gradient(164deg, rgba(160,70,161,1) 0%, rgba(195,211,231,1) 100%);
}
summary > span.six:after {
content: "FF6";
background-color: #8b1e2c;
}
summary > span.seven:after {
content: "FF7";
background-color: #003a23;
background: linear-gradient(164deg, rgba(0,58,35,1) 0%, rgba(184,205,244,1) 100%);
}
summary > span.eight:after {
content: "FF8";
background-color: #861413;
background: linear-gradient(164deg, rgba(134,20,19,1) 0%, rgba(249,233,0,1) 100%);
}
summary > span.nine:after {
content: "FF9";
background-color: #825f33;
}
summary > span.ten:after {
content: "FF10";
background-color: #4689cb;
background: linear-gradient(164deg, rgba(70,137,203,1) 0%, rgba(217,160,113,1) 100%);
}
summary > span.twelve:after {
content: "FF12";
background-color: #455672;
background: linear-gradient(164deg, rgba(69,86,114,1) 0%, rgba(190,121,145,1) 100%);
}
summary > span.thirteen:after {
content: "FF13";
background-color: #47b9bc;
}
summary > span.fifteen:after {
content: "FF15";
background-color: #2e2c3a;
}
summary > span.sixteen:after {
content: "FF16";
background: rgb(233,175,96);
background: linear-gradient(164deg, rgba(233,175,96,1) 0%, rgba(72,58,165,1) 100%);
}
span.pov, span.main, span.secondary, span.mention {
margin: 0 5px;
}
input#verifyage-checkbox {
display: inline;
width: auto;
margin: 0;
}
iframe {
height: 100vh;
width: 99%;
border: 2px solid rgb(99, 44, 44);
}
span.emoji {
font-family: none;
}

View file

View file

@ -1,201 +0,0 @@
/* lato-regular - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Lato';
font-style: normal;
font-weight: 400;
src: url('/fonts/lato-v24-latin-regular.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* lato-italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Lato';
font-style: italic;
font-weight: 400;
src: url('/fonts/lato-v24-latin-italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* lato-700 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Lato';
font-style: normal;
font-weight: 700;
src: url('/fonts/lato-v24-latin-700.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* lato-700italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Lato';
font-style: italic;
font-weight: 700;
src: url('/fonts/lato-v24-latin-700italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* inconsolata-regular - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Inconsolata';
font-style: normal;
font-weight: 400;
src: url('/fonts/inconsolata-v32-latin-regular.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* ----- COLOURS ----- */
body, details > summary::marker {
color: #222;
}
body {
background-color: white;
}
a, a:link, a:hover, a:visited, a:active, h1, h2, h3, details > summary {
color: var(--colourone);
}
li:before {
color: #9e9e9e;
}
details, blockquote {
border: 2px solid var(--colourone);
box-shadow: 8px 8px 0px var(--colourone);
}
body {
font-family: 'Lato', sans-serif;
font-size: 13px; word-wrap: break-word;
}
img {
max-width: 100%;
}
a, a:link, a:hover, a:visited, a:active {
text-decoration: none;
}
a:hover {
border-bottom: 1px solid;
}
/* ---- BOXES ---- */
details > summary {
cursor: pointer;
font-weight: bold;
}
details, blockquote {
padding: 20px;
margin-bottom: 15px !important;
}
blockquote {
max-width: 100%;
min-width: 10%;
display: inline-block;
}
blockquote p, details p {
margin: 0;
padding: 0;
}
blockquote ul {
margin-top: 0;
margin-bottom: 0;
}
blockquote > * + *, details > * + * {
margin-top: 20px !important;
}
/* ---- CONTENT ---- */
@media only screen and (min-width: 900px) {
div#site-wrapper {
width: 90%;
margin: 1em auto;
}
}
@media only screen and (max-width: 900px) {
div#site-wrapper {
width: 99%; margin: 1em auto;
}
}
input, select {
background-color: white;
font-family: 'Lato', sans-serif;
}
textarea {
font-family: 'Inconsolata', monospace;
}
code, pre, .timestamp {
background: #f0f0f0;
font-family: 'Inconsolata', monospace !important;
}
pre {
display: inline-block;
padding: 2px;
max-width: 100%;
overflow: auto;
}
ul {
list-style: none;
}
ul li:before {
content: "+ ";
font-weight: bold;
}
ol {
list-style: none;
counter-reset: li
}
ol li:before {
content: counter(li)". ";
font-weight: bold;
}
ol li {
counter-increment: li;
}
/* ----- GIFSETS ----- */
div.figure {
text-align: center;
padding: 0;
}
div.figure img {
display: inline;
margin: 5px;
}
div.figure.oneup img {
width: auto;
height: auto;
max-width: 90%;
}
div.figure.twoup img {
width: 40%;
}
div.figure.threeup img {
width: 30%;
}

View file

View file

View file

@ -1,530 +0,0 @@
@charset "UTF-8";
/* eb-garamond-regular - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'EB Garamond';
font-style: normal;
font-weight: 400;
src: url('/fonts/eb-garamond-v27-latin-regular.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* eb-garamond-italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'EB Garamond';
font-style: italic;
font-weight: 400;
src: url('/fonts/eb-garamond-v27-latin-italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* eb-garamond-700 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'EB Garamond';
font-style: normal;
font-weight: 700;
src: url('/fonts/eb-garamond-v27-latin-700.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* eb-garamond-700italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'EB Garamond';
font-style: italic;
font-weight: 700;
src: url('/fonts/eb-garamond-v27-latin-700italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* Tufte CSS styles */
html {
font-size: 15px;
}
body {
width: 87.5%;
margin-left: auto;
margin-right: auto;
padding-left: 12.5%;
font-family: "EB Garamond", serif;
background-color: #fffff8;
color: #111;
max-width: 1400px;
counter-reset: sidenote-counter;
}
/* Adds dark mode */
@media (prefers-color-scheme: dark) {
body {
background-color: #151515;
color: #ddd;
}
}
h1 {
font-weight: 400;
margin-top: 4rem;
margin-bottom: 1.5rem;
font-size: 3.2rem;
line-height: 1;
}
h2 {
font-style: italic;
font-weight: 400;
margin-top: 2.1rem;
margin-bottom: 1.4rem;
font-size: 2.2rem;
line-height: 1;
}
h3 {
font-style: italic;
font-weight: 400;
font-size: 1.7rem;
margin-top: 2rem;
margin-bottom: 1.4rem;
line-height: 1;
}
hr {
display: block;
height: 1px;
width: 55%;
border: 0;
border-top: 1px solid #ccc;
margin: 1em 0;
padding: 0;
}
p.subtitle {
font-style: italic;
margin-top: 1rem;
margin-bottom: 1rem;
font-size: 1.8rem;
display: block;
line-height: 1;
}
.numeral {
font-family: "EB Garamond", serif;
}
.danger {
color: red;
}
article {
padding: 5rem 0rem;
}
section {
padding-top: 1rem;
padding-bottom: 1rem;
}
p,
dl,
ol,
ul {
font-size: 1.4rem;
line-height: 2rem;
}
p {
margin-top: 1.4rem;
margin-bottom: 1.4rem;
padding-right: 0;
vertical-align: baseline;
}
/* Chapter Epigraphs */
div.epigraph {
margin: 5em 0;
}
div.epigraph > blockquote {
margin-top: 3em;
margin-bottom: 3em;
}
div.epigraph > blockquote,
div.epigraph > blockquote > p {
font-style: italic;
}
div.epigraph > blockquote > footer {
font-style: normal;
}
div.epigraph > blockquote > footer > cite {
font-style: italic;
}
/* end chapter epigraphs styles */
blockquote {
font-size: 1.4rem;
}
blockquote p {
width: 55%;
margin-right: 40px;
}
blockquote footer {
width: 55%;
font-size: 1.1rem;
text-align: right;
}
section > p,
section > footer,
section > table {
width: 55%;
}
/* 50 + 5 == 55, to be the same width as paragraph */
section > dl,
section > ol,
section > ul {
width: 50%;
-webkit-padding-start: 5%;
}
dt:not(:first-child),
li:not(:first-child) {
margin-top: 0.25rem;
}
figure {
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
max-width: 55%;
-webkit-margin-start: 0;
-webkit-margin-end: 0;
margin: 0 0 3em 0;
}
figcaption {
float: right;
clear: right;
margin-top: 0;
margin-bottom: 0;
font-size: 1.1rem;
line-height: 1.6;
vertical-align: baseline;
position: relative;
max-width: 40%;
}
figure.fullwidth figcaption {
margin-right: 24%;
}
/* Links: replicate underline that clears descenders */
a:link,
a:visited {
color: inherit;
}
.no-tufte-underline:link {
background: unset;
text-shadow: unset;
}
a:link, .tufte-underline, .hover-tufte-underline:hover {
text-decoration: none;
background: -webkit-linear-gradient(#fffff8, #fffff8), -webkit-linear-gradient(#fffff8, #fffff8), -webkit-linear-gradient(currentColor, currentColor);
background: linear-gradient(#fffff8, #fffff8), linear-gradient(#fffff8, #fffff8), linear-gradient(currentColor, currentColor);
-webkit-background-size: 0.05em 1px, 0.05em 1px, 1px 1px;
-moz-background-size: 0.05em 1px, 0.05em 1px, 1px 1px;
background-size: 0.05em 1px, 0.05em 1px, 1px 1px;
background-repeat: no-repeat, no-repeat, repeat-x;
text-shadow: 0.03em 0 #fffff8, -0.03em 0 #fffff8, 0 0.03em #fffff8, 0 -0.03em #fffff8, 0.06em 0 #fffff8, -0.06em 0 #fffff8, 0.09em 0 #fffff8, -0.09em 0 #fffff8, 0.12em 0 #fffff8, -0.12em 0 #fffff8, 0.15em 0 #fffff8, -0.15em 0 #fffff8;
background-position: 0% 93%, 100% 93%, 0% 93%;
}
@media screen and (-webkit-min-device-pixel-ratio: 0) {
a:link, .tufte-underline, .hover-tufte-underline:hover {
background-position-y: 87%, 87%, 87%;
}
}
/* Adds dark mode */
@media (prefers-color-scheme: dark) {
a:link, .tufte-underline, .hover-tufte-underline:hover {
text-shadow: 0.03em 0 #151515, -0.03em 0 #151515, 0 0.03em #151515, 0 -0.03em #151515, 0.06em 0 #151515, -0.06em 0 #151515, 0.09em 0 #151515, -0.09em 0 #151515, 0.12em 0 #151515, -0.12em 0 #151515, 0.15em 0 #151515, -0.15em 0 #151515;
}
}
a:link::selection,
a:link::-moz-selection {
text-shadow: 0.03em 0 #b4d5fe, -0.03em 0 #b4d5fe, 0 0.03em #b4d5fe, 0 -0.03em #b4d5fe, 0.06em 0 #b4d5fe, -0.06em 0 #b4d5fe, 0.09em 0 #b4d5fe, -0.09em 0 #b4d5fe, 0.12em 0 #b4d5fe, -0.12em 0 #b4d5fe, 0.15em 0 #b4d5fe, -0.15em 0 #b4d5fe;
background: #b4d5fe;
}
/* Sidenotes, margin notes, figures, captions */
img {
max-width: 100%;
}
.sidenote,
.marginnote {
float: right;
clear: right;
margin-right: -60%;
width: 50%;
margin-top: 0.3rem;
margin-bottom: 0;
font-size: 1.1rem;
line-height: 1.3;
vertical-align: baseline;
position: relative;
}
.sidenote-number {
counter-increment: sidenote-counter;
}
.sidenote-number:after,
.sidenote:before {
font-family: "EB Garamond", serif;
position: relative;
vertical-align: baseline;
}
.sidenote-number:after {
content: counter(sidenote-counter);
font-size: 1rem;
top: -0.5rem;
left: 0.1rem;
}
.sidenote:before {
content: counter(sidenote-counter) " ";
font-size: 1rem;
top: -0.5rem;
}
blockquote .sidenote,
blockquote .marginnote {
margin-right: -82%;
min-width: 59%;
text-align: left;
}
div.fullwidth,
table.fullwidth {
width: 100%;
}
div.table-wrapper {
overflow-x: auto;
font-family: "Trebuchet MS", "Gill Sans", "Gill Sans MT", sans-serif;
}
.sans {
font-family: "Gill Sans", "Gill Sans MT", Calibri, sans-serif;
letter-spacing: .03em;
}
code, pre > code {
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
font-size: 1.0rem;
line-height: 1.42;
-webkit-text-size-adjust: 100%; /* Prevent adjustments of font size after orientation changes in iOS. See https://github.com/edwardtufte/tufte-css/issues/81#issuecomment-261953409 */
}
.sans > code {
font-size: 1.2rem;
}
h1 > code,
h2 > code,
h3 > code {
font-size: 0.80em;
}
.marginnote > code,
.sidenote > code {
font-size: 1rem;
}
pre > code {
font-size: 0.9rem;
width: 52.5%;
margin-left: 2.5%;
overflow-x: auto;
display: block;
}
pre.fullwidth > code {
width: 90%;
}
.fullwidth {
max-width: 90%;
clear:both;
}
span.newthought, p.newthought::first-line {
font-variant: small-caps;
font-size: 1.2em;
}
input.margin-toggle {
display: none;
}
label.sidenote-number {
display: inline-block;
max-height: 2rem; /* should be less than or equal to paragraph line-height */
}
label.margin-toggle:not(.sidenote-number) {
display: none;
}
.iframe-wrapper {
position: relative;
padding-bottom: 56.25%; /* 16:9 */
padding-top: 25px;
height: 0;
}
.iframe-wrapper iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
@media (max-width: 760px) {
body {
width: 84%;
padding-left: 8%;
padding-right: 8%;
}
hr,
section > p,
section > footer,
section > table {
width: 100%;
}
pre > code {
width: 97%;
}
section > dl,
section > ol,
section > ul {
width: 90%;
}
figure {
max-width: 90%;
}
figcaption,
figure.fullwidth figcaption {
margin-right: 0%;
max-width: none;
}
blockquote {
margin-left: 1.5em;
margin-right: 0em;
}
blockquote p,
blockquote footer {
width: 100%;
}
label.margin-toggle:not(.sidenote-number) {
display: inline;
}
.sidenote,
.marginnote {
display: none;
}
.margin-toggle:checked + .sidenote,
.margin-toggle:checked + .marginnote {
display: block;
float: left;
left: 1rem;
clear: both;
width: 95%;
margin: 1rem 2.5%;
vertical-align: baseline;
position: relative;
}
label {
cursor: pointer;
}
div.table-wrapper,
table {
width: 85%;
}
img {
width: 100%;
}
}
/* contents navigator */
details#chapters {
position: fixed;
right: 2px;
top: 2px;
z-index: 300;
max-height: 80%;
overflow: auto;
background-color: #151515;
color: #fffff8;
text-align: center;
border: 3px solid #fffff8;
border-radius: 2px;
}
details#chapters summary {
cursor: pointer;
display: block;
padding: 2px 5px 5px;
position: sticky;
top: 0;
background-color: #151515;
}
details#chapters summary::marker {
list-style: none;
}
details#chapters summary::after {
content: "❮❮";
}
details#chapters[open] summary::after {
content: "❯❯";
}
details#chapters ul {
padding: 3px;
}
details#chapters li {
list-style: none;
margin: 5px 10px;
}
details#chapters a {
text-shadow: none;
}

View file

View file

@ -1,179 +0,0 @@
import datetime, os
from importlib import import_module
fffandoms = ["FF1","FF2","FF3","FF4","FF5","FF6","FF7","FF8","FF9","FFX","FF11","FF12","FF13","FF14","FF15","FF16"]
import makeheader
import headerfooter
def charlist(local=False):
# delete existing file
if os.path.exists("build/ff/characters/index.html"):
os.remove("build/ff/characters/index.html")
# write header
headerfooter.headerwrite("build/ff/characters/index.html","FF fics by character","FF fics by character","<p>Click on each bar to see fics about that character, organised according to the character’s prominence and then from newest to oldest.</p>\n<p>Key to categories:</p>\n<ul><li><b>POV character:</b> some or all of the fic is in this character’s POV</li>\n<li><b>Main character:</b> the character is part of the main ship, or their actions are significant for the plot</li>\n<li><b>Secondary character:</b> the character appears saying or doing something specific</li>\n<li><b>Mentioned:</b> the character appears as part of a group, or they’re alluded to by another character or in the narration</li></ul>",False,local)
# iterate through fandoms
characters = []
numbers = ["one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen"]
for fandom in fffandoms:
thecharacters = []
ficcount = 500
while ficcount > 0:
ficcount -= 1
if ficcount < 10:
ficcountstring = "00" + str(ficcount)
elif ficcount < 100:
ficcountstring = "0" + str(ficcount)
else:
ficcountstring = str(ficcount)
if os.path.exists("files/originalsmeta/" + ficcountstring + ".py"):
ficfile = "files.originalsmeta." + ficcountstring
fileread = import_module(ficfile)
try:
if fileread.revealdate > datetime.datetime.now():
revealed = False
else:
revealed = True
except:
revealed = True
if revealed == True:
if len(fileread.fandom) == 1:
if fandom in fileread.fandom:
try:
thecharacters.extend(fileread.charpov)
except:
pass
try:
thecharacters.extend(fileread.charmain)
except:
pass
try:
thecharacters.extend(fileread.charsecondary)
except:
pass
try:
thecharacters.extend(fileread.charmention)
except:
pass
thecharacters = sorted(list(dict.fromkeys(thecharacters)))
for character in thecharacters:
if character != "OCs":
chardict = {"name":character,"game":(fffandoms.index(fandom) + 1)}
characters.append(chardict)
charlist = sorted(characters, key=lambda d: d["name"])
for person in charlist:
povcount = []
maincount = []
secondarycount = []
mentioncount = []
character = person["name"]
searchfandom = fffandoms[(person["game"]) - 1]
cssgame = numbers[(person["game"]) - 1]
# check all fics in specified fandom
ficcount = 500
while ficcount > 0:
ficcount -= 1
if ficcount < 10:
ficcountstring = "00" + str(ficcount)
elif ficcount < 100:
ficcountstring = "0" + str(ficcount)
else:
ficcountstring = str(ficcount)
if os.path.exists("files/originalsmeta/" + ficcountstring + ".py"):
countfile = "files.originalsmeta." + ficcountstring
fileread = import_module(countfile)
try:
if fileread.revealdate > datetime.datetime.now():
revealed = False
else:
revealed = True
except:
revealed = True
if revealed == True:
ficdict = {"thefic":ficcount,"thedate":(fileread.datewords[-1])["date"]}
if searchfandom in fileread.fandom:
# append to lists
try:
if character in fileread.charpov:
povcount.append(ficdict)
except:
pass
try:
if character in fileread.charmain:
maincount.append(ficdict)
except:
pass
try:
if character in fileread.charsecondary:
secondarycount.append(ficdict)
except:
pass
try:
if character in fileread.charmention:
mentioncount.append(ficdict)
except:
pass
# write details element
output = "build/ff/characters/index.html"
filewrite = open(output, "a")
filewrite.write("<details><summary><span class=\"character " + cssgame + "\">" + character + "</span> ")
# write statistics
if len(povcount) > 0:
filewrite.write("<span class=\"pov\">POV: " + str(len(povcount)) + "</span>")
if len(maincount) > 0:
filewrite.write("<span class=\"main\">main: " + str(len(maincount)) + "</span>")
if len(secondarycount) > 0:
filewrite.write("<span class=\"secondary\">secondary: " + str(len(secondarycount)) + "</span>")
if len(mentioncount) > 0:
filewrite.write("<span class=\"mention\">mentioned: " + str(len(mentioncount)) + "</span>")
filewrite.write("</summary>\n")
filewrite.close()
# write fic headers in each category
if len(povcount) > 0:
filewrite = open(output, "a")
filewrite.write("<h1>POV character</h1>\n")
filewrite.close()
povcount = sorted(povcount,key=lambda d: d["thedate"],reverse=True)
newpov = []
for fic in povcount:
newpov.append(fic["thefic"])
for fic in newpov:
makeheader.ficgen(fic,False,output,local)
if len(maincount) > 0:
filewrite = open(output, "a")
filewrite.write("<h1>Main character</h1>\n")
filewrite.close()
maincount = sorted(maincount,key=lambda d: d["thedate"],reverse=True)
newmain = []
for fic in maincount:
newmain.append(fic["thefic"])
for fic in newmain:
makeheader.ficgen(fic,False,output,local)
if len(secondarycount) > 0:
filewrite = open(output, "a")
filewrite.write("<h1>Secondary character</h1>\n")
filewrite.close()
secondarycount = sorted(secondarycount,key=lambda d: d["thedate"],reverse=True)
newsecondary = []
for fic in secondarycount:
newsecondary.append(fic["thefic"])
for fic in newsecondary:
makeheader.ficgen(fic,False,output,local)
if len(mentioncount) > 0:
filewrite = open(output, "a")
filewrite.write("<h1>Mentioned</h1>\n")
filewrite.close()
mentioncount = sorted(mentioncount,key=lambda d: d["thedate"],reverse=True)
newmention = []
for fic in mentioncount:
newmention.append(fic["thefic"])
for fic in newmention:
makeheader.ficgen(fic,False,output,local)
filewrite = open(output, "a")
filewrite.write("</details>\n")
filewrite.close()
# write footer
headerfooter.footerwrite("build/ff/characters/index.html",False,local)
if __name__ == "__main__":
charlist()

View file

@ -1,170 +0,0 @@
import datetime, os, shutil
from importlib import import_module
import headerfooter
fffandoms = ["FF1","FF2","FF3","FF4","FF5","FF6","FF7","FF8","FF9","FFX","FF11","FF12","FF13","FF14","FF15","FF16"]
"""
Code to generate comment page
"""
def commentpage(ficno,directory,local=False):
# convert to three-digit number
if ficno < 10:
ficnostring = "00" + str(ficno)
elif ficno < 100:
ficnostring = "0" + str(ficno)
else:
ficnostring = str(ficno)
# open the file
ficfile = directory + "." + ficnostring
fileread = import_module(ficfile)
# determine if comments page
try:
if any(item in fffandoms for item in fileread.fandom):
fffandom = True
else:
fffandom = False
except:
origfile = "files.originalsmeta." + str(fileread.original)
origread = import_module(origfile)
if any(item in fffandoms for item in origread.fandom):
fffandom = True
else:
fffandom = False
if fffandom:
commentspage = True
else:
timeelapsed = datetime.datetime.now() - (fileread.datewords[-1])["date"]
if timeelapsed.days < 730:
commentspage = True
else:
try:
if fileread.event == "ao3exchange" and (fileread.datewords[0])["date"].year > 2019:
commentspage = True
else:
try:
if fileread.comments:
commentspage = True
except:
commentspage = False
except:
try:
if fileread.comments:
commentspage = True
except:
commentspage = False
if commentspage:
commentspath = "build/comments/" + ficnostring
if not os.path.isdir(commentspath):
os.mkdir(commentspath)
if os.path.exists(commentspath + "/index.html"):
os.remove(commentspath + "/index.html")
# write to output file
headerfooter.headerwrite(commentspath + "/index.html","Comments for fic no. " + ficnostring,"Comments for fic no. <span id=\"ficno\">" + ficnostring + "</span>","",False,local)
filewrite = open(commentspath + "/index.html", "a")
if fffandom or timeelapsed.days < 730:
filewrite.write("<h2>Leave a comment</h2>\n<noscript>\n<p><b>JavaScript is unavailable.</b> Please <a href=\"mailto:tre@praze.net\">email me</a> any comments.</p>\n</noscript>\n<p class=\"jsonly\">Comments will be posted manually; please expect a delay between submitting your comment and seeing it below!</p>\n<form id=\"theform\" onsubmit=\"sendContact(event)\" class=\"jsonly\">\n<input type=\"text\" id=\"nameInput\" required placeholder=\"Pseudonym (required)\">\n<input type=\"email\" id=\"emailInput\" placeholder=\"Email (if you want email notification of reply)\">\n<input type=\"text\" id=\"siteInput\" placeholder=\"Site (if you want a link back)\">\n<textarea id=\"messageInput\" rows=\"5\" maxlength=\"4800\" required placeholder=\"Your comment (required, include whatever markup [or down] you like)\"></textarea>\n<button type=\"submit\">Submit</button>\n</form>\n")
else:
try:
if fileread.event == "ao3exchange" and (fileread.datewords[0])["date"].year > 2019:
filewrite.write("<p>Comments aren’t open for this fic. They’re still available <a href=\"https://archiveofourown.org/works/" + str(fileread.ao3slug) + "\">on AO3</a>, however, as this was written for an AO3-based gift exchange.</p>\n")
except:
pass
try:
if fileread.comments:
filewrite.write("<h2>Archived comments</h2>\n<p>I often delete copies of my fics syndicated to other websites, so I archive comments here as a way of preserving them. If you left one of these comments and would like it to be removed from the archive, please <a href=\"mailto:tre@praze.net\">email me</a>.</p>\n<p><small>My replies are included only if they were originally posted on this site.</small></p>\n")
for comment in fileread.comments:
filewrite.write("<div class=\"comment\">\n<h1>")
if comment["site"] == "dw":
if comment["registered"]:
filewrite.write("<span style=\"white-space: nowrap;\" class=\"ljuser\"><a href=\"https://" + comment["username"].replace("_","-") + ".dreamwidth.org/profile\"><img src=\"https://www.dreamwidth.org/img/silk/identity/user.png\" alt=\"[personal profile]\" width=\"17\" height=\"17\" style=\"vertical-align: text-bottom; border: 0; padding-right: 1px;\" /></a><a href=\"https://"+ comment["username"].replace("_","-") + ".dreamwidth.org/\"><b>" + comment["username"].replace("-","_")+ "</b></a></span>")
else:
filewrite.write("<span style=\"white-space: nowrap;\" class=\"ljuser\"><img src=\"https://www.dreamwidth.org/img/silk/identity/user.png\" alt=\"[personal profile]\" width=\"17\" height=\"17\" style=\"vertical-align: text-bottom; border: 0; padding-right: 1px;\" /><b>anonymous</b></a></span>")
elif comment["site"] == "lj":
if comment["registered"]:
filewrite.write("<span style=\"white-space: nowrap;\" class=\"ljuser\"><a href=\"https://" + comment["username"].replace("_","-") + ".livejournal.com/profile\"><img src=\"https://www.dreamwidth.org/img/external/lj-userinfo.gif\" alt=\"[personal profile]\" width=\"17\" height=\"17\" style=\"vertical-align: text-bottom; border: 0; padding-right: 1px;\" /></a><a href=\"https://" + comment["username"].replace("_","-") + ".livejournal.com/\"><b>" + comment["username"].replace("-","_")+ "</b></a></span>")
else:
filewrite.write("<span style=\"white-space: nowrap;\" class=\"ljuser\"><img src=\"https://www.dreamwidth.org/img/external/lj-userinfo.gif\" alt=\"[personal profile]\" width=\"17\" height=\"17\" style=\"vertical-align: text-bottom; border: 0; padding-right: 1px;\" /><b>anonymous</b></a></span>")
elif comment["site"] == "discord":
filewrite.write("<span style=\"white-space: nowrap;\" class=\"ljuser\"><img src=\"https://www.dreamwidth.org/img/profile_icons/discord.png\" alt=\"[personal profile]\" width=\"17\" height=\"17\" style=\"vertical-align: text-bottom; border: 0; padding-right: 1px; background-color: white; border-radius: 10%;\" /><b>" + comment["username"] + "</b></span>")
elif comment["site"] == "ao3":
if comment["registered"]:
try:
filewrite.write("<span style=\"white-space: nowrap;\" class=\"ljuser\"><a href=\"https://archiveofourown.org/users/" + comment["username"] + "/profile\"><img src=\"https://p.dreamwidth.org/b164c54b26e4/-/archiveofourown.org/favicon.ico\" alt=\"[archiveofourown.org profile]\" width=\"16\" height=\"16\" style=\"vertical-align: text-bottom; border: 0; padding-right: 1px;\" /></a><a href=\"https://archiveofourown.org/users/" + comment["username"] + "/pseuds/" + comment["pseud"].replace(" ","%20") + "\"><b>" + comment["pseud"] + " (" + comment["username"] + ")</b></a></span>")
except:
filewrite.write("<span style=\"white-space: nowrap;\" class=\"ljuser\"><a href=\"https://archiveofourown.org/users/" + comment["username"] + "/profile\"><img src=\"https://p.dreamwidth.org/b164c54b26e4/-/archiveofourown.org/favicon.ico\" alt=\"[archiveofourown.org profile]\" width=\"16\" height=\"16\" style=\"vertical-align: text-bottom; border: 0; padding-right: 1px;\" /></a><a href=\"https://archiveofourown.org/users/"+ comment["username"] + "\"><b>" + comment["username"] + "</b></a></span>")
else:
filewrite.write("<span style=\"white-space: nowrap;\" class=\"ljuser\"><img src=\"https://p.dreamwidth.org/b164c54b26e4/-/archiveofourown.org/favicon.ico\" alt=\"[archiveofourown.org profile]\" width=\"16\" height=\"16\" style=\"vertical-align: text-bottom; border: 0; padding-right: 1px;\" /><b>" + comment["username"] + "</b></span>")
elif comment["site"] == "praze":
try:
filewrite.write("<a href=\"" + comment["url"] + "\">" + comment["username"] + "</a>")
except:
filewrite.write(comment["username"])
try:
filewrite.write(" on chapter " + str(comment["chapter"]))
except:
pass
filewrite.write(", " + comment["date"].strftime("%Y-%m-%d"))
try:
filewrite.write(" [<a href=\"" + comment["link"] + "\">original</a>]")
except:
pass
filewrite.write("</h1>\n<p>" + comment["text"] + "</p>\n</div>\n")
try:
filewrite.write("<div class=\"comment reply\">\n<h1>Reply</h1>\n<p>" + comment["reply"] + "</p>\n</div>")
except:
pass
except:
pass
if fffandom or timeelapsed.days < 730:
filewrite.write("<script>\nasync function sendContact(ev) {\nev.preventDefault();\nconst theFic = document\n.getElementById('ficno').innerHTML;\nconst senderName = document\n.getElementById('nameInput').value;\nconst senderAddress = document\n.getElementById('emailInput').value;\nconst senderSite = document\n.getElementById('siteInput').value;\nconst senderMessage = document\n.getElementById('messageInput').value;\nconst webhookUrl = 'https://kes.praze.net/api/v1/statuses';\nconst response = await fetch(webhookUrl, {\nmethod: 'POST',\nheaders: {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer OTBKMDFMMJMTMZNKYY0ZMGQZLWJJMJUTYJE0MMY5ZJK3NJU4',\n },\n body: JSON.stringify({'status' : 'new comment on fic ' + theFic + ' from ' + senderName + ' (' + senderAddress + ', ' + senderSite + ')\\n\\n' + senderMessage}),\n});\n\nif (response.ok) {\nalert('Comment submitted, thank you!');\n} else {\nalert('This is fucked, sorry. Email me instead, whatever at praze dot net!');\n}\n\ndocument.getElementById(\"theform\").reset();\n}\n</script>\n")
filewrite.close()
headerfooter.footerwrite(commentspath + "/index.html",False,local)
"""
Generate all comment pages
"""
def allcomments(local=False):
for filename in os.listdir("build/comments"):
filepath = os.path.join("build/comments", filename)
if os.path.isfile(filepath):
os.unlink(filepath)
elif os.path.isdir(filepath):
shutil.rmtree(filepath)
ficcount = 500
while ficcount > 0:
ficcount -= 1
if ficcount < 10:
ficcountstring = "00" + str(ficcount)
elif ficcount < 100:
ficcountstring = "0" + str(ficcount)
else:
ficcountstring = str(ficcount)
if os.path.exists("files/originalsmeta/" + ficcountstring + ".py"):
commentpage(ficcount,"files.originalsmeta",local)
elif os.path.exists("files/translationsmeta/" + ficcountstring + ".py"):
commentpage(ficcount,"files.translationsmeta",local)
if __name__ == "__main__":
allcomments()
"""
Generate comments index page
"""
def commentindex(local=False):
# delete existing file
if os.path.exists("build/comments/index.html"):
os.remove("build/comments/index.html")
# write header
headerfooter.headerwrite("build/comments/index.html","Comments","Comments","",False,local)
filewrite = open("build/comments/index.html", "a")
filewrite.write("<p>I tend to temporarily syndicate my fics to other websites and then delete them, so comments I receive are archived on this site and linked back to the original. If you don’t want your comments from other sources archived here, or if you require any changes to the presentation of your comments, <a href=\"mailto:takedown@praze.net\">please email me</a>. Please note, however, that this website is not indexed by search engines.</p>\n<p>If you haven’t switched off JavaScript, you can leave comments on the relevant comment pages for each fic (where this is enabled). Please leave your email address if you’d like notification of any reply. If you’d like a link from your pseudonym to a website, you can supply this as well, although I reserve the right not to link to certain advertising/tracker-heavy websites.</p>\n<p>Comments are turned off on some older fics.</p>\n")
filewrite.close()
headerfooter.footerwrite("build/comments/index.html",False,local)
if __name__ == "__main__":
commentindex()

124
events.py
View file

@ -1,124 +0,0 @@
import datetime, os
from importlib import import_module
import makeheader
import headerfooter
def eventlist(local=False):
# delete existing file
if os.path.exists("build/events/index.html"):
os.remove("build/events/index.html")
# write header
headerfooter.headerwrite("build/events/index.html","Events","Events","<p>Here’s a list of the fics I’ve written for events (exchanges, prompt memes/fests, challenges, etc.). Fics in this section are organised chronologically by year, <b>from oldest to newest</b>.</p>",False,local)
# get list of events
events = []
ficcount = 500
while ficcount > 0:
ficcount -= 1
if ficcount < 10:
ficcountstring = "00" + str(ficcount)
elif ficcount < 100:
ficcountstring = "0" + str(ficcount)
else:
ficcountstring = str(ficcount)
if os.path.exists("files/originalsmeta/" + ficcountstring + ".py"):
ficfile = "files.originalsmeta." + ficcountstring
fileread = import_module(ficfile)
try:
if fileread.revealdate > datetime.datetime.now():
revealed = False
else:
revealed = True
except:
revealed = True
if revealed == True:
try:
events.append({"name":fileread.eventname,"location":fileread.eventlocation,"sortname":fileread.eventname.lower()})
except:
try:
events.append({"name":fileread.eventname,"location":"","sortname":fileread.eventname.lower()})
except:
pass
newlist = []
for event in events:
if event not in newlist:
newlist.append(event)
eventlist = sorted(newlist, key=lambda d: d["sortname"])
for event in eventlist:
evententries = []
theevent = event["name"]
# check all fics in specified fandom
ficcount = 500
while ficcount > 0:
ficcount -= 1
if ficcount < 10:
ficcountstring = "00" + str(ficcount)
elif ficcount < 100:
ficcountstring = "0" + str(ficcount)
else:
ficcountstring = str(ficcount)
if os.path.exists("files/originalsmeta/" + ficcountstring + ".py"):
countfile = "files.originalsmeta." + ficcountstring
fileread = import_module(countfile)
try:
if fileread.revealdate > datetime.datetime.now():
revealed = False
else:
revealed = True
except:
revealed = True
if revealed == True:
try:
if fileread.eventname == theevent:
evententries.append({"ficno":ficcount,"year":(fileread.datewords[0])["date"].year,"fandom":fileread.fandom,"update":(fileread.datewords[-1])["date"]})
except:
pass
eventfandoms = []
for entry in evententries:
eventfandoms.extend(entry["fandom"])
eventfandoms = sorted(list(dict.fromkeys(eventfandoms)))
# write details element
output = "build/events/index.html"
filewrite = open(output, "a")
filewrite.write("<details><summary><b>")
position = 0
while (eventlist[position])["name"] != theevent:
position += 1
eventlocation = (eventlist[position])["location"]
if eventlocation == "dwjournal":
filewrite.write("<span style=\"white-space: nowrap;\" class=\"ljuser\"><a target=\"_blank\" href=\"https://" + theevent.replace("_","-") + ".dreamwidth.org/profile\"><img src=\"https://www.dreamwidth.org/img/silk/identity/user.png\" alt=\"[personal profile]\" width=\"17\" height=\"17\" style=\"vertical-align: text-bottom; border: 0; padding-right: 1px;\"></a><a target=\"_blank\" href=\"https://"+ theevent.replace("_","-") + ".dreamwidth.org/\"><b>" + theevent.replace("-","_")+ "</b></a></span>")
elif eventlocation == "dwcomm":
filewrite.write("<span style=\"white-space: nowrap;\" class=\"ljuser\"><a target=\"_blank\" href=\"https://" + theevent.replace("_","-") + ".dreamwidth.org/profile\"><img src=\"https://www.dreamwidth.org/img/silk/identity/community.png\" alt=\"[community profile]\" width=\"17\" height=\"17\" style=\"vertical-align: text-bottom; border: 0; padding-right: 1px;\"></a><a target=\"_blank\" href=\"https://" + theevent.replace("_","-") + ".dreamwidth.org/\"><b>" + theevent.replace("-","_") + "</b></a></span>")
elif eventlocation == "ljjournal":
filewrite.write("<span style=\"white-space: nowrap;\" class=\"ljuser\"><a target=\"_blank\" href=\"https://" + theevent.replace("_","-") + ".livejournal.com/profile\"><img src=\"https://www.dreamwidth.org/img/external/lj-userinfo.gif\" alt=\"[personal profile]\" width=\"17\" height=\"17\" style=\"vertical-align: text-bottom; border: 0; padding-right: 1px;\"></a><a target=\"_blank\" href=\"https://"+ theevent.replace("_","-") + ".livejournal.com/\"><b>" + theevent.replace("-","_")+ "</b></a></span>")
else:
filewrite.write(theevent)
filewrite.write("</b> (" + str(len(evententries)) + ": " + ", ".join(eventfandoms) + ")</summary>\n")
filewrite.close()
startyear = 2014
thisyear = int(datetime.datetime.now().strftime("%Y"))
while startyear < thisyear:
startyear += 1
yearlist = []
for entry in evententries:
if int(entry["year"]) == startyear:
ficdict = {"thefic":entry["ficno"],"thedate":entry["update"]}
yearlist.append(ficdict)
if len(yearlist) > 0:
yearlist = sorted(yearlist,key=lambda d: d["thedate"])
newyear = []
for fic in yearlist:
newyear.append(fic["thefic"])
filewrite = open(output, "a")
filewrite.write("<h1>" + str(startyear) + "</h1>\n")
filewrite.close()
for fic in newyear:
makeheader.ficgen(fic,False,output,local)
filewrite = open(output, "a")
filewrite.write("</details>\n")
filewrite.close()
# write footer
headerfooter.footerwrite("build/events/index.html",False,local)
if __name__ == "__main__":
eventlist()

View file

@ -1,130 +0,0 @@
import datetime, os
from importlib import import_module
import makeheader
import headerfooter
def fandomlist(local=False):
# delete existing file
if os.path.exists("build/byfandom/index.html"):
os.remove("build/byfandom/index.html")
# write header
headerfooter.headerwrite("build/byfandom/index.html","Fics by fandom","Fics by fandom","<p>On this page, you’ll find basically everything I’ve ever written that is a. fanfiction and b. extant, grouped by fandom and then sorted newest to oldest; quality may vary. Some fics, such as things I wrote before 2020, require a username and password to access.</p>",False,local)
# get list of fandoms
fandoms = []
ficcount = 500
while ficcount > 0:
ficcount -= 1
if ficcount < 10:
ficcountstring = "00" + str(ficcount)
elif ficcount < 100:
ficcountstring = "0" + str(ficcount)
else:
ficcountstring = str(ficcount)
if os.path.exists("files/originalsmeta/" + ficcountstring + ".py"):
ficfile = "files.originalsmeta." + ficcountstring
fileread = import_module(ficfile)
try:
if fileread.revealdate > datetime.datetime.now():
revealed = False
else:
revealed = True
except:
revealed = True
if revealed == True:
for fandom in fileread.fandom:
fandoms.append(fandom)
newlist = []
for fandom in fandoms:
if fandom not in newlist:
newlist.append(fandom)
fandomlist = []
for fandom in newlist:
if "FF" in fandom:
if fandom == "FFX":
newfandom = "FF10"
elif len(fandom) == 3:
newfandom = "FF0" + fandom[-1]
else:
newfandom = fandom
fandomlist.append({"searchname":fandom,"sortname":newfandom.replace("FF","Final Fantasy ").lower(),"displayname":fandom.replace("FF","Final Fantasy ")})
else:
fandomlist.append({"searchname":fandom,"sortname":fandom.lower(),"displayname":fandom})
fandomlist = sorted(fandomlist, key=lambda d: d["sortname"])
for fandom in fandomlist:
fandomfics = []
fandomwords = 0
sortfics = []
# check which fics are in the fandom
ficcount = 500
while ficcount > 0:
ficcount -= 1
if ficcount < 10:
ficcountstring = "00" + str(ficcount)
elif ficcount < 100:
ficcountstring = "0" + str(ficcount)
else:
ficcountstring = str(ficcount)
if os.path.exists("files/originalsmeta/" + ficcountstring + ".py"):
countfile = "files.originalsmeta." + ficcountstring
fileread = import_module(countfile)
try:
if fileread.revealdate > datetime.datetime.now():
revealed = False
else:
revealed = True
except:
revealed = True
if revealed == True:
if fandom["searchname"] in fileread.fandom:
sumwords = 0
for instalment in fileread.datewords:
sumwords = sumwords + instalment["words"]
ficdict = {"thefic":ficcount,"thedate":(fileread.datewords[-1])["date"],"totalwords":sumwords}
sortfics.append(ficdict)
thefics = sorted(sortfics,key=lambda d: d["thedate"],reverse=True)
for fic in thefics:
fandomfics.append(fic["thefic"])
fandomwords = fandomwords + fic["totalwords"]
firstfic = fandomfics[-1]
if firstfic < 10:
firstficstring = "00" + str(firstfic)
elif firstfic < 100:
firstficstring = "0" + str(firstfic)
else:
firstficstring = str(firstfic)
firstfile = "files.originalsmeta." + firstficstring
firstread = import_module(firstfile)
firstyear = (firstread.datewords[0])["date"].year
lastfic = fandomfics[0]
if lastfic < 10:
lastficstring = "00" + str(lastfic)
elif lastfic < 100:
lastficstring = "0" + str(lastfic)
else:
lastficstring = str(lastfic)
lastfile = "files.originalsmeta." + lastficstring
lastread = import_module(lastfile)
lastyear = (lastread.datewords[0])["date"].year
if lastyear == firstyear:
yearstring = str(firstyear)
else:
yearstring = str(firstyear) + "" + str(lastyear)
# write details element
output = "build/byfandom/index.html"
filewrite = open(output, "a")
filewrite.write("<details><summary><b>" + fandom["displayname"] + "</b> (" + str(len(fandomfics)) + " fic")
if len(fandomfics) > 1:
filewrite.write("s")
filewrite.write(", " + f"{fandomwords:,}" + " total words, " + yearstring + ")</summary>\n")
filewrite.close()
for fic in fandomfics:
makeheader.ficgen(fic,False,output,local)
filewrite = open(output, "a")
filewrite.write("</details>\n")
filewrite.close()
# write footer
headerfooter.footerwrite("build/byfandom/index.html",False,local)
if __name__ == "__main__":
fandomlist(True)

20
feed.py
View file

@ -107,15 +107,6 @@ def feedgen(local=False):
filewrite.write(", " + ", ".join(origread.charmain))
except:
pass
if origread.rating == "g":
therating = "U"
elif origread.rating == "t":
therating = "G+"
elif origread.rating == "m":
therating = "M"
elif origread.rating == "e":
therating = "X"
filewrite.write(", rated " + therating)
if len(origread.genre) > 1:
genred = False
for thegenre in origread.genre:
@ -141,15 +132,6 @@ def feedgen(local=False):
filewrite.write(", " + ", ".join(thefile.charmain))
except:
pass
if thefile.rating == "g":
therating = "U"
elif thefile.rating == "t":
therating = "G+"
elif thefile.rating == "m":
therating = "M"
elif thefile.rating == "e":
therating = "X"
filewrite.write(", rated " + therating)
if len(thefile.genre) > 1:
genred = False
for thegenre in thefile.genre:
@ -166,7 +148,7 @@ def feedgen(local=False):
filewrite.write("/home/mdd/Documents/proj/fic-archive/build/")
else:
filewrite.write("https://tre.praze.net/fic/")
filewrite.write("single/" + ficcountstring)
filewrite.write(ficcountstring)
if local:
filewrite.write("/index.html")
filewrite.write("</link>\n<guid isPermaLink=\"false\">praze-fic-" + ficcountstring)

View file

@ -1,43 +0,0 @@
def headerwrite(output,title,headerone,desc,main=False,local=False,single=False,ficnostring=False):
header = open(output, "a")
header.write("<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<link rel=\"stylesheet\" href=\"")
if local:
header.write("/home/mdd/Documents/proj/fic-archive/build/")
else:
header.write("/fic/")
header.write("archive.css\">\n<link rel=\"me\" href=\"https://kes.praze.net/@tre\">\n<link rel=\"alternate\" type=\"application/rss+xml\" title=\"Mez's fic archive\" href=\"https://tre.praze.net/fic/feed.xml\">\n<meta name=\"theme-color\" content=\"#edc4c4\" />\n<title>" + title + "</title>\n<meta property=\"og:title\" content=\"Mez’s fanfiction\">\n<meta property=\"og:type\" content=\"website\">\n<meta property=\"og:image\" content=\"https://tre.praze.net/ab.png\">\n<meta name=\"description\" property=\"og:description\" content=\"Fanfiction on tre.praze.net\">\n<meta property=\"og:locale\" content=\"en_GB\">\n<meta property=\"og:site_name\" content=\"tre.praze.net\">\n<meta name=\"fediverse:creator\" content=\"@tre@praze.net\">\n")
if single:
header.write("<link rel=\"alternate\" type=\"application/activity+json\" href=\"https://fed.brid.gy/r/https://tre.praze.net/fic/single/" + ficnostring + "/\"")
header.write("<noscript>\n<style>.jsonly{display:none;}</style>\n</noscript>\n</head>\n<body>\n<div id=\"content\">\n<div id=\"inside\">\n<noscript>\n<div id=\"warning\">\n<p><b>Warning:</b> this part of my site is <b>18+</b>. Fics contain NSFW material and mature themes (death, suicide, mental illness, incest …). Browse at your own risk.</p>\n</div>\n</noscript>\n<h1>" + headerone + "</h1>\n" + desc + "\n")
if not main:
header.write("<p>\n<a href=\"")
if local:
header.write("/home/mdd/Documents/proj/fic-archive/build/index.html")
else:
header.write("/fic")
header.write("\">main page\n</a>\n</p>\n")
header.write("<hr>\n")
header.close()
def footerwrite(output,main=False,local=False):
footer = open(output, "a")
footer.write("</div>\n<footer>\n<hr>\n")
if not main:
footer.write("<p>\n<a href=\"")
if local:
footer.write("/home/mdd/Documents/proj/fic-archive/build/index.html")
else:
footer.write("/fic")
footer.write("\">main page\n</a>\n</p>\n")
footer.write("<img src=\"")
if local:
footer.write("/home/mdd/Documents/proj/fic-archive/build/emacs.jpg")
else:
footer.write("/fic/emacs.jpg")
footer.write("\">\n</footer>\n</div>\n<script>\nif (localStorage.getItem(\"ageVerified\") == null) { window.location = `")
if local:
footer.write("/home/mdd/Documents/proj/fic-archive/build/")
else:
footer.write("/fic/")
footer.write("verify/index.html?returnto=${window.location}`; }\n</script>\n<a href=\"/\"><img src=\"/a.png\" style=\"position:fixed;bottom:2px;right:2px;\" title=\"home\"></a></body>\n</html>")
footer.close()

View file

@ -1,105 +0,0 @@
import datetime, os
from importlib import import_module
import headerfooter
def statslist(local=False):
yearlist = []
ficcount = 500
while ficcount > 0:
ficcount -= 1
if ficcount < 10:
ficcountstring = "00" + str(ficcount)
elif ficcount < 100:
ficcountstring = "0" + str(ficcount)
else:
ficcountstring = str(ficcount)
if os.path.exists("files/originalsmeta/" + ficcountstring + ".py"):
ficfile = "files.originalsmeta." + ficcountstring
fileread = import_module(ficfile)
elif os.path.exists("files/translationsmeta/" + ficcountstring + ".py"):
ficfile = "files.translationsmeta." + ficcountstring
fileread = import_module(ficfile)
else:
fileread = False
if fileread:
try:
if fileread.revealdate > datetime.datetime.now():
revealed = False
else:
revealed = True
except:
revealed = True
if revealed == True:
for date in fileread.datewords:
yearlist.append(date["date"].year)
yearlist = sorted(list(dict.fromkeys(yearlist)))
linkedyears = []
for year in yearlist:
statstring = ""
if local == True:
statspath = "/home/mdd/Documents/proj/fic-archive/build/stats/" + str(year) + "/index.html"
else:
statspath = "/fic/stats/" + str(year)
if yearlist.index(year) > 0:
statstring += "&nbsp;• "
statstring += "<a href=\"" + statspath + "\">" + str(year)
if year == (datetime.datetime.now()).year:
statstring += " (so far)"
statstring += "</a>"
linkedyears.append(statstring)
listofyears = "".join(linkedyears)
return listofyears
def indexgen(local=False):
# delete existing file
if os.path.exists("build/index.html"):
os.remove("build/index.html")
# write header
headerfooter.headerwrite("build/index.html","Mez’s fic archive","Mez’s fic archive","",True,local)
filewrite = open("build/index.html", "a")
filewrite.write("<p>Here is all my fanfiction! Some of it is also syndicated elsewhere (often temporarily), but this site is the canonical location for everything I’ve written.</p>\n<p xmlns:cc=\"http://creativecommons.org/ns#\" xmlns:dct=\"http://purl.org/dc/terms/\"><strong>Transformative works policy:</strong> The contents of <a property=\"dct:title\" rel=\"cc:attributionURL\" href=\"https://tre.praze.net/fic\">these pages</a> are licensed under <a target=\"_blank\" href=\"https://creativecommons.org/licenses/by-nc/4.0/\" target=\"_blank\" rel=\"license\" style=\"display:inline-block;\">CC BY-NC 4.0. <img style=\"height:22px!important;margin-left:3px;vertical-align:middle;\" src=\"https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1\" alt=\"\"><img style=\"height:22px!important;margin-left:3px;vertical-align:middle;\" src=\"https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1\" alt=\"\"><img style=\"height:22px!important;margin-left:3px;vertical-align:middle;\" src=\"https://mirrors.creativecommons.org/presskit/icons/nc.svg?ref=chooser-v1\" alt=\"\"></a> In other words, transformative works are permitted as long as there is a clearly visible hyperlink to the original and no financial transactions are involved.</p>\n<p>The code for this archive is available <a target=\"_blank\" href=\"https://git.praze.net/tre/fic-archive\">here</a>. Commenting is switched on for most fics written at least semi-recently – read about that <a href=\"")
if local:
filewrite.write("comments/index.html")
else:
filewrite.write("/fic/comments")
filewrite.write("\">here</a>.</p>\n<p>You can also subscribe to <a href=\"")
if not local:
filewrite.write("/fic/")
filewrite.write("feed.xml\">the RSS feed</a> to be notified of new fics and updates to existing ones.</p>\n<div class=\"fic\">\n<h2>Masterlist</h2>\n<p>Every fic I’ve written since the age of five. You can view these:\n<ul>\n<li><a href=\"")
if local:
filewrite.write("masterlist/index.html")
else:
filewrite.write("/fic/masterlist")
filewrite.write("\">chronologically</a></li>\n<li><a href=\"")
if local:
filewrite.write("byfandom/index.html")
else:
filewrite.write("/fic/byfandom")
filewrite.write("\">by fandom</a></li>\n</ul>\n</div>\n<div class=\"fic\">\n<h2>Final Fantasy</h2>\n<p>Most of the fics I write are in FF fandoms these days. You can browse them:</p>\n<ul>\n<li><a href=\"")
if local:
filewrite.write("ff/characters/index.html")
else:
filewrite.write("/fic/ff/characters")
filewrite.write("\">by character</a></li>\n<li><a href=\"")
if local:
filewrite.write("ff/ships/index.html")
else:
filewrite.write("/fic/ff/ships")
filewrite.write("\">by ship</a></li>\n<li><a href=\"")
if local:
filewrite.write("ff/bywords/index.html")
else:
filewrite.write("/fic/ff/bywords")
filewrite.write("\">by length</a></li>\n</ul>\n</div>\n<div class=\"fic\">\n<h2><a href=\"")
if local:
filewrite.write("events/index.html")
else:
filewrite.write("/fic/events")
filewrite.write("\">Events</a></h2>\n<p>Since 2020 I’ve participated in some fandom exchanges and other events. Many of my more recent fics are in this category.</p>\n</div>\n<div class=\"fic\">\n<h2>Other</h2>\n<ul>\n<li>Stats by year: " + (str(statslist(local))) + "</li>\n</ul>\n</div>\n<div align=\"center\">\n<script src=\"https://ficring.neocities.org/ring.js\"></script>\n</div>\n")
filewrite.close()
headerfooter.footerwrite("build/index.html",True,local)
if __name__ == "__main__":
statslist(True)
indexgen(True)

View file

@ -1,618 +0,0 @@
import datetime
from importlib import import_module
from dateutil.relativedelta import relativedelta
fffandoms = ["FF1","FF2","FF3","FF4","FF5","FF6","FF7","FF8","FF9","FFX","FF11","FF12","FF13","FF14","FF15","FF16"]
"""
Code to generate the fic header div
"""
def linkgen(ficno,output="output.html",local=False):
# convert to three-digit number
if ficno < 10:
ficnostring = "00" + str(ficno)
elif ficno < 100:
ficnostring = "0" + str(ficno)
else:
ficnostring = str(ficno)
# open the file
ficfile = "files.originalsmeta." + ficnostring
fileread = import_module(ficfile)
# open translation file if there is one
try:
if fileread.translation:
if fileread.translation < 10:
translationstring = "00" + str(fileread.translation)
elif fileread.translation < 100:
translationstring = "0" + str(fileread.translation)
else:
translationstring = str(fileread.translation)
translationfile = "files.translationsmeta." + translationstring
transread = import_module(translationfile)
except:
pass
filewrite = open(output, "a")
filewrite.write("<ul class=\"ficlinks")
# specify language if necessary
try:
if fileread.translation:
if fileread.language == "en":
filewrite.write(" english")
elif fileread.language == "fr":
filewrite.write (" french")
except:
pass
filewrite.write("\">\n")
# write html link if there is one
if fileread.html:
filewrite.write("<li class=\"prazelink\"><a target=\"_blank\" ")
if fileread.locked:
filewrite.write("class=\"locked\" href=\"")
if local:
filewrite.write("/home/mdd/Documents/proj/fic-archive/build/secret/")
else:
filewrite.write("/fic/secret/")
else:
if local:
filewrite.write("href=\"/home/mdd/Documents/proj/fic-archive/build/files/")
else:
filewrite.write("href=\"/fic/files/")
filewrite.write(ficnostring + ".html\">HTML</a></li>\n")
# write pdf link if there is one
if fileread.pdf:
filewrite.write("<li class=\"prazelink\"><a target=\"_blank\" ")
if fileread.locked:
filewrite.write("class=\"locked\" href=\"")
if local:
filewrite.write("/home/mdd/Documents/proj/fic-archive/build/secret/")
else:
filewrite.write("/fic/secret/")
else:
if local:
filewrite.write("href=\"/home/mdd/Documents/proj/fic-archive/build/files/")
else:
filewrite.write("href=\"/fic/files/")
filewrite.write(ficnostring + ".pdf\">PDF</a></li>\n")
# write epub link if there is one
if fileread.epub:
filewrite.write("<li class=\"prazelink\"><a target=\"_blank\" ")
if fileread.locked:
filewrite.write("class=\"locked\" href=\"")
if local:
filewrite.write("/home/mdd/Documents/proj/fic-archive/build/secret/")
else:
filewrite.write("/fic/secret/")
else:
if local:
filewrite.write("href=\"/home/mdd/Documents/proj/fic-archive/build/files/")
else:
filewrite.write("href=\"/fic/files/")
filewrite.write(ficnostring + ".epub\">EPUB</a></li>\n")
# write ao3 link if there is one
try:
if fileread.ao3slug:
filewrite.write("<li class=\"ao3link\"><a target=\"_blank\" class=\"u-syndication")
try:
if fileread.ao3locked:
filewrite.write(" locked")
except:
if fileread.locked:
filewrite.write(" locked")
filewrite.write("\" href=\"https://archiveofourown.org/works/" + str(fileread.ao3slug) + "\">AO3</a></li>\n")
except:
pass
# write fedi share link if there is one
# try:
# filewrite.write("<li><a href=\"https://ple.praze.net/notice/" + fileread.fedislug + "\">fedi</a></li>\n")
# except:
# pass
# determine if comments page
if any(item in fffandoms for item in fileread.fandom):
filewrite.write("<li class=\"prazelink\"><a href=\"")
if local:
filewrite.write("/home/mdd/Documents/proj/fic-archive/build/comments/" + ficnostring + "/index.html")
else:
filewrite.write("/fic/comments/" + ficnostring)
filewrite.write("\">comments</a></li>\n")
else:
timeelapsed = datetime.datetime.now() - (fileread.datewords[-1])["date"]
if timeelapsed.days < 730:
filewrite.write("<li class=\"prazelink\"><a href=\"")
if local:
filewrite.write("/home/mdd/Documents/proj/fic-archive/build/comments/" + ficnostring + "/index.html")
else:
filewrite.write("/fic/comments/" + ficnostring)
filewrite.write("\">comments</a></li>\n")
else:
try:
if fileread.event == "ao3exchange" and (fileread.datewords[0])["date"].year > 2019:
filewrite.write("<li class=\"prazelink\"><a href=\"")
if local:
filewrite.write("/home/mdd/Documents/proj/fic-archive/build/comments/" + ficnostring + "/index.html")
else:
filewrite.write("/fic/comments/" + ficnostring)
filewrite.write("\">comments</a></li>\n")
else:
try:
if fileread.comments:
filewrite.write("<li class=\"prazelink\"><a href=\"")
if local:
filewrite.write("/home/mdd/Documents/proj/fic-archive/build/comments/" + ficnostring + "/index.html")
else:
filewrite.write("/fic/comments/" + ficnostring)
filewrite.write("\">comments</a></li>\n")
except:
pass
except:
try:
if fileread.comments:
filewrite.write("<li class=\"prazelink\"><a href=\"")
if local:
filewrite.write("/home/mdd/Documents/proj/fic-archive/build/comments/" + ficnostring + "/index.html")
else:
filewrite.write("/fic/comments/" + ficnostring)
filewrite.write("\">comments</a></li>\n")
except:
pass
filewrite.write("</ul>\n")
# write links for translation if required
try:
if fileread.translation:
if transread.language == "en":
filewrite.write("<ul class=\"ficlinks english")
elif transread.language == "fr":
filewrite.write("<ul class=\"ficlinks french")
filewrite.write("\">\n")
# write html link if there is one
if fileread.html:
filewrite.write("<li class=\"prazelink\"><a target=\"_blank\" ")
if fileread.locked:
filewrite.write("class=\"locked\" href=\"")
if local:
filewrite.write("/home/mdd/Documents/proj/fic-archive/build/secret/")
else:
filewrite.write("/fic/secret/")
else:
if local:
filewrite.write("href=\"/home/mdd/Documents/proj/fic-archive/build/files/")
else:
filewrite.write("href=\"/fic/files/")
filewrite.write(translationstring + ".html\">HTML</a></li>\n")
# write pdf link if there is one
if fileread.pdf:
filewrite.write("<li class=\"prazelink\"><a target=\"_blank\" ")
if fileread.locked:
filewrite.write("class=\"locked\" href=\"")
if local:
filewrite.write("/home/mdd/Documents/proj/fic-archive/build/secret/")
else:
filewrite.write("/fic/secret/")
else:
if local:
filewrite.write("href=\"/home/mdd/Documents/proj/fic-archive/build/files/")
else:
filewrite.write("href=\"/fic/files/")
filewrite.write(translationstring + ".pdf\">PDF</a></li>\n")
# write epub link if there is one
if fileread.epub:
filewrite.write("<li class=\"prazelink\"><a target=\"_blank\" ")
if fileread.locked:
filewrite.write("class=\"locked\" href=\"")
if local:
filewrite.write("/home/mdd/Documents/proj/fic-archive/build/secret/")
else:
filewrite.write("/fic/secret/")
else:
if local:
filewrite.write("href=\"/home/mdd/Documents/proj/fic-archive/build/files/")
else:
filewrite.write("href=\"/fic/files/")
filewrite.write(translationstring + ".epub\">EPUB</a></li>\n")
# write ao3 link if there is one
try:
if fileread.ao3slug:
filewrite.write("<li class=\"ao3link\"><a target=\"_blank\" ")
if fileread.locked:
filewrite.write("class=\"locked\" ")
filewrite.write("href=\"https://archiveofourown.org/works/" + str(transread.ao3slug) + "\">AO3</a></li>\n")
except:
pass
# determine if comments page required
if any(item in fffandoms for item in fileread.fandom):
filewrite.write("<li class=\"prazelink\"><a href=\"")
if local:
filewrite.write("/home/mdd/Documents/proj/fic-archive/build/comments/" + translationstring + "/index.html")
else:
filewrite.write("/fic/comments/" + translationstring)
filewrite.write("\">comments</a></li>\n")
else:
timeelapsed = datetime.datetime.now() - (transread.datewords[-1])["date"]
if timeelapsed.days < 730:
filewrite.write("<li class=\"prazelink\"><a href=\"")
if local:
filewrite.write("/home/mdd/Documents/proj/fic-archive/build/comments/" + translationstring + "/index.html")
else:
filewrite.write("/fic/comments/" + translationstring)
filewrite.write("\">comments</a></li>\n")
else:
try:
if transread.comments:
filewrite.write("<li class=\"prazelink\"><a href=\"")
if local:
filewrite.write("/home/mdd/Documents/proj/fic-archive/build/comments/" + translationstring + "/index.html")
else:
filewrite.write("/fic/comments/" + translationstring)
filewrite.write("\">comments</a></li>\n")
except:
pass
filewrite.write("</ul>\n")
except:
pass
def ficgen(ficno,unique=False,output="output.html",local=False,single=False):
# convert to three-digit number
if ficno < 10:
ficnostring = "00" + str(ficno)
elif ficno < 100:
ficnostring = "0" + str(ficno)
else:
ficnostring = str(ficno)
# open the file
ficfile = "files.originalsmeta." + ficnostring
fileread = import_module(ficfile)
# open translation file if there is one
try:
if fileread.translation:
if fileread.translation < 10:
translationstring = "00" + str(fileread.translation)
elif fileread.translation < 100:
translationstring = "0" + str(fileread.translation)
else:
translationstring = str(fileread.translation)
translationfile = "files.translationsmeta." + translationstring
transread = import_module(translationfile)
except:
pass
try:
if fileread.revealdate > datetime.datetime.now():
revealed = False
else:
revealed = True
except:
revealed = True
if revealed == True:
# write to output file
filewrite = open(output, "a")
filewrite.write("<div class=\"fic")
if single:
filewrite.write(" h-entry")
filewrite.write("\"")
# give the div an id if requested
if unique:
filewrite.write(" id=\"fic" + ficnostring + "\"")
filewrite.write(">\n<h1><span class=\"ficnoprelim\">no. </span><span class=\"ficno\"><a class=\"u-url\" href=\"")
if local:
filewrite.write("/home/mdd/Documents/proj/fic-archive/build/single/" + ficnostring + "/index.html")
else:
filewrite.write("/fic/single/" + ficnostring + "/")
filewrite.write("\">" + ficnostring + "</a>")
try:
if translationstring:
filewrite.write("/<a href=\"")
if local:
filewrite.write("/home/mdd/Documents/proj/fic-archive/build/single/" + translationstring + "/index.html")
else:
filewrite.write("/fic/single/" + translationstring)
filewrite.write("\">" + translationstring + "</a>")
except:
pass
filewrite.write("</span>")
# write title if requested
if fileread.showtitle:
filewrite.write(" <span class=\"fictitle p-name\">" + fileread.title)
try:
if transread.showtitle:
filewrite.write("/" + transread.title)
except:
pass
filewrite.write("</span>")
else:
try:
if transread.showtitle:
filewrite.write(" <span class=\"fictitle\">" + transread.title)
except:
pass
if fileread.status == "abandoned":
filewrite.write(" <span class=\"abandoned\"> (abandoned)</span>")
elif fileread.status == "incomplete":
filewrite.write(" <span class=\"incomplete\"> (in progress)</span>")
filewrite.write("</h1>\n<div class=\"e-content\">\n<ul class=\"ficmeta\">\n<li class=\"ficdate\"><i>Date:</i> ")
# write date, date range if ranged or translation
if fileread.status == "incomplete":
filewrite.write("<time datetime=\"" + (fileread.datewords[0])["date"].strftime("%Y-%m-%d") + "\" class=\"dt-published\">" + (fileread.datewords[0])["date"].strftime("%-d %B %Y") + "</time>–")
else:
try:
if transread.status == "incomplete":
filewrite.write("<time datetime=\"" + (fileread.datewords[0])["date"].strftime("%Y-%m-%d") + "\" class=\"dt-published\">" + (fileread.datewords[0])["date"].strftime("%-d %B %Y") + "</time>–")
else:
if fileread.translation:
if (transread.datewords[-1])["date"].year == (fileread.datewords[0])["date"].year:
if (transread.datewords[-1])["date"].month == (fileread.datewords[0])["date"].month:
if (transread.datewords[-1])["date"].date == (fileread.datewords[0])["date"].date:
filewrite.write("<time datetime=\"" + (fileread.datewords[0])["date"].strftime("%Y-%m-%d") + "\" class=\"dt-published\">" + (fileread.datewords[0])["date"].strftime("%-d %B %Y") + "</time>")
else:
filewrite.write("<time datetime=\"" + (fileread.datewords[0])["date"].strftime("%Y-%m-%d") + "\" class=\"dt-published\">" + (fileread.datewords[0])["date"].strftime("%-d") + "</time>–<time datetime=\"" + (transread.datewords[-1])["date"].strftime("%Y-%m-%d") + "\" class=\"dt-updated\">" + (transread.datewords[-1])["date"].strftime("%-d %B %Y") + "</time>")
else:
filewrite.write("<time datetime=\"" + (fileread.datewords[0])["date"].strftime("%Y-%m-%d") + "\" class=\"dt-published\">" + (fileread.datewords[0])["date"].strftime("%-d %B") + "</time>–<time datetime=\"" + (transread.datewords[-1])["date"].strftime("%Y-%m-%d") + "\" class=\"dt-updated\">" + (transread.datewords[-1])["date"].strftime("%-d %B %Y") + "<time>")
else:
filewrite.write("<time datetime=\"" + (fileread.datewords[0])["date"].strftime("%Y-%m-%d") + "\" class=\"dt-published\">" + (fileread.datewords[0])["date"].strftime("%-d %B %Y") + "</time>–<time datetime=\"" + (transread.datewords[-1])["date"].strftime("%Y-%m-%d") + "\" class=\"dt-updated\">" + (transread.datewords[-1])["date"].strftime("%-d %B %Y") + "</time>")
except:
try:
filewrite.write(fileread.approxdate)
except:
if (fileread.datewords[0])["date"].year == (fileread.datewords[-1])["date"].year:
if (fileread.datewords[0])["date"].month == (fileread.datewords[-1])["date"].month:
if (fileread.datewords[0])["date"] == (fileread.datewords[-1])["date"]:
filewrite.write("<time datetime=\"" + (fileread.datewords[-1])["date"].strftime("%Y-%m-%d") + "\" class=\"dt-published\">" + (fileread.datewords[-1])["date"].strftime("%-d %B %Y") + "</time>")
else:
filewrite.write("<time datetime=\"" + (fileread.datewords[0])["date"].strftime("%Y-%m-%d") + "\" class=\"dt-published\">" + (fileread.datewords[0])["date"].strftime("%-d") + "</time>–<time datetime=\"" + (fileread.datewords[-1])["date"].strftime("%Y-%m-%d") + "\" class=\"dt-updated\">" + (fileread.datewords[-1])["date"].strftime("%-d %B %Y") + "</time>")
else:
filewrite.write("<time datetime=\"" + (fileread.datewords[0])["date"].strftime("%Y-%m-%d") + "\" class=\"dt-published\">" + (fileread.datewords[0])["date"].strftime("%-d %B") + "</time>–<time datetime=\"" + (fileread.datewords[-1])["date"].strftime("%Y-%m-%d") + "\" class=\"dt-updated\">" + (fileread.datewords[-1])["date"].strftime("%-d %B %Y") + "</time>")
else:
filewrite.write("<time datetime=\"" + (fileread.datewords[0])["date"].strftime("%Y-%m-%d") + "\" class=\"dt-published\">" + (fileread.datewords[0])["date"].strftime("%-d %B %Y") + "</time>–<time datetime=\"" + (fileread.datewords[-1])["date"].strftime("%Y-%m-%d") + "\" class=\"dt-updated\">" + (fileread.datewords[-1])["date"].strftime("%-d %B %Y") + "</time>")
# write wordcount
sumwords = 0
for instalment in fileread.datewords:
sumwords = sumwords + instalment["words"]
filewrite.write("</li>\n<li class=\"wordcount\"><i>Wordcount:</i> " + str(sumwords))
transwords = 0
try:
for instalment in transread.datewords:
transwords = transwords + instalment["words"]
filewrite.write(" + " + str(transwords))
except:
pass
# write rating
filewrite.write("</li>\n<li class=\"rating\"><i>Rating: </i><span class=\"" + fileread.rating + "\">")
if fileread.rating == "g":
filewrite.write("universal")
elif fileread.rating == "t":
filewrite.write("general")
elif fileread.rating == "m":
filewrite.write("mature")
elif fileread.rating == "e":
filewrite.write("explicit")
filewrite.write("</span>")
# write reason for rating if there is one
try:
filewrite.write(" (" + fileread.ratingreason + ")")
except:
pass
filewrite.write("</li>\n<li class=\"fandom\"><i>Fandom: </i><span class=\"p-category\">")
# write fandom
try:
filewrite.write(fileread.fandomtext)
except:
filewrite.write("/".join(fileread.fandom))
filewrite.write("</span></li>\n")
# write characters in pov, main, secondary categories, if they exist
try:
filewrite.write("<li class=\"characters\"><i>Characters: </i>" + fileread.charactertext + "</li>\n")
except:
try:
filewrite.write("<li class=\"characters\"><i>Characters: </i>" + ", ".join(fileread.charpov))
try:
filewrite.write(", " + ", ".join(fileread.charmain))
except:
pass
try:
filewrite.write(", " + "<small>" + ", ".join(fileread.charsecondary) + "</small>")
except:
pass
filewrite.write("</li>\n")
except:
try:
filewrite.write("<li class=\"characters\"><i>Characters: </i>" + ", ".join(fileread.charmain))
try:
filewrite.write(", " + "<small>" + ", ".join(fileread.charsecondary) + "</small>")
except:
pass
filewrite.write("</li>\n")
except:
try:
filewrite.write("<li class=\"characters\">" + ", ".join(fileread.charsecondary) + "</li>\n")
except:
pass
# write genre
filewrite.write("<li class=\"genre\"><i>Genre: </i>" + ", ".join(fileread.genre) + "</li>\n")
# write warnings if they exist
try:
filewrite.write("<li class=\"warnings\"><i>Warnings: </i>" + fileread.warnings + "</li>\n")
except:
pass
# write point in canon if there is one
try:
filewrite.write("<li class=\"time\"><i>Point in canon: </i>" + fileread.time + "</li>\n")
except:
pass
# write locations if there are any
try:
filewrite.write("<li class=\"location\"><i>Location: </i>" + fileread.locationtext + "</li>\n")
except:
try:
filewrite.write("<li class=\"location\"><i>Location: </i>" + ", ".join(fileread.location) + "</li>\n")
except:
pass
filewrite.write("</ul>\n")
# write summary if there is one
try:
if transread.language == "en":
try:
filewrite.write("<p class=\"summary\"><i>Summary: </i>" + transread.summary)
try:
filewrite.write(" " + fileread.summary + "</p>\n")
except:
filewrite.write("</p>\n")
except:
try:
filewrite.write("<p class=\"summary\"><i>Summary: </i>" + fileread.summary + "</p>\n")
except:
pass
elif transread.language == "fr":
try:
filewrite.write("<p class=\"summary\"><i>Summary: </i>" + fileread.summary)
try:
filewrite.write(" " + transread.summary + "</p>\n")
except:
filewrite.write("</p>\n")
except:
try:
filewrite.write("<p class=\"summary\"><i>Summary: </i>" + transread.summary + "</p>\n")
except:
pass
except:
try:
filewrite.write("<p class=\"summary\">" + fileread.summary + "</p>\n")
except:
pass
# set up notes paragraph if required
if (fileread.datewords[0])["date"].year < 2011:
juvenilia = True
else:
juvenilia = False
try:
if fileread.notes:
filewrite.write("<p class=\"note\"><i>Notes: </i>")
except:
try:
if fileread.event:
filewrite.write("<p class=\"note\"><i>Notes: </i>")
except:
if juvenilia:
filewrite.write("<p class=\"note\"><i>Notes: </i>")
# if juvenilia, add age
if juvenilia:
age = relativedelta((fileread.datewords[0])["date"], datetime.datetime(1993,6,28)).years
filewrite.write("Age at time of writing: " + str(age) + ".")
try:
if fileread.notes:
filewrite.write(" ")
except:
pass
# write event details if there are any
try:
if fileread.eventname == "fail-fandomanon":
filewrite.write("In response to prompt at <span style=\"white-space: nowrap;\" class=\"ljuser\"><a target=\"_blank\" href=\"https://fail-fandomanon.dreamwidth.org/profile\"><img src=\"https://www.dreamwidth.org/img/silk/identity/community.png\" alt=\"[community profile]\" width=\"17\" height=\"17\" style=\"vertical-align: text-bottom; border: 0; padding-right: 1px;\"></a><a target=\"_blank\" href=\"https://fail-fandomanon.dreamwidth.org/\"><b>fail_fandomanon</b></a></span>: <i>" + fileread.prompt + "</i>.")
try:
if fileread.notes:
filewrite.write(" ")
except:
pass
elif fileread.eventname == "robotsoup":
filewrite.write("Written for <span style=\"white-space: nowrap;\" class=\"ljuser\"><a target=\"_blank\" href=\"https://kalloway.dreamwidth.org/profile\"><img src=\"https://www.dreamwidth.org/img/silk/identity/user.png\" alt=\"[personal profile]\" width=\"17\" height=\"17\" style=\"vertical-align: text-bottom; border: 0; padding-right: 1px;\"></a><a target=\"_blank\" href=\"https://kalloway.dreamwidth.org/\"><b>kalloway</b></a></span>’s " + fileread.eventdeets + " fest.")
elif fileread.eventname == "#ficwip":
filewrite.write("Written for the <a target=\"_blank\" href=\"https://ficwip.carrd.co\">#ficwip</a> event <i>" + fileread.eventdeets + "</i>")
if fileread.event == "prompt":
filewrite.write(", in response to prompt, <i>" + fileread.prompt + "</i>")
filewrite.write(".")
try:
if fileread.notes:
filewrite.write(" ")
except:
pass
else:
filewrite.write("Written for ")
try:
if fileread.eventlocation == "dwcomm":
filewrite.write("<span style=\"white-space: nowrap;\" class=\"ljuser\"><a target=\"_blank\" href=\"https://" + fileread.eventname.replace("_","-") + ".dreamwidth.org/profile\"><img src=\"https://www.dreamwidth.org/img/silk/identity/community.png\" alt=\"[community profile]\" width=\"17\" height=\"17\" style=\"vertical-align: text-bottom; border: 0; padding-right: 1px;\"></a><a target=\"_blank\" href=\"https://" + fileread.eventname.replace("_","-") + ".dreamwidth.org/\"><b>" + fileread.eventname.replace("-","_") + "</b></a></span>")
elif fileread.eventlocation == "dwjournal":
filewrite.write("<span style=\"white-space: nowrap;\" class=\"ljuser\"><a target=\"_blank\" href=\"https://" + fileread.eventname.replace("_","-") + ".dreamwidth.org/profile\"><img src=\"https://www.dreamwidth.org/img/silk/identity/user.png\" alt=\"[personal profile]\" width=\"17\" height=\"17\" style=\"vertical-align: text-bottom; border: 0; padding-right: 1px;\"></a><a target=\"_blank\" href=\"https://"+ fileread.eventname.replace("_","-") + ".dreamwidth.org/\"><b>" + fileread.eventname.replace("-","_")+ "</b></a></span>")
elif fileread.eventlocation == "ljjournal":
filewrite.write("<span style=\"white-space: nowrap;\" class=\"ljuser\"><a target=\"_blank\" href=\"https://" + fileread.eventname.replace("_","-") + ".livejournal.com/profile\"><img src=\"https://www.dreamwidth.org/img/external/lj-userinfo.gif\" alt=\"[personal profile]\" width=\"17\" height=\"17\" style=\"vertical-align: text-bottom; border: 0; padding-right: 1px;\"></a><a target=\"_blank\" href=\"https://"+ fileread.eventname.replace("_","-") + ".livejournal.com/\"><b>" + fileread.eventname.replace("-","_")+ "</b></a></span>")
except:
if fileread.eventname == "Semaine de la fic française":
filewrite.write("<i>Semaine de la fic française</i>")
else:
filewrite.write(fileread.eventname)
try:
if fileread.eventfrequency == "annual":
filewrite.write(" " + str((fileread.datewords[0])["date"].year))
else:
filewrite.write(" " + fileread.eventfrequency)
except:
pass
if fileread.event == "prompt":
filewrite.write(", in response to ")
try:
if fileread.recip:
try:
if fileread.recipsite == "dw":
filewrite.write("<span style=\"white-space: nowrap;\" class=\"ljuser\"><a target=\"_blank\" href=\"https://" + fileread.recip.replace("_","-") + ".dreamwidth.org/profile\"><img src=\"https://www.dreamwidth.org/img/silk/identity/user.png\" alt=\"[personal profile]\" width=\"17\" height=\"17\" style=\"vertical-align: text-bottom; border: 0; padding-right: 1px;\"></a><a target=\"_blank\" href=\"https://"+ fileread.recip.replace("_","-") + ".dreamwidth.org/\"><b>" + fileread.recip.replace("-","_") + "</b></a></span>")
elif fileread.recipsite == "ao3":
try:
if fileread.recippseud:
filewrite.write("<span style=\"white-space: nowrap;\" class=\"ljuser\"><a target=\"_blank\" href=\"https://archiveofourown.org/users/" + fileread.recip + "/profile\"><img src=\"https://p.dreamwidth.org/b164c54b26e4/-/archiveofourown.org/favicon.ico\" alt=\"[archiveofourown.org profile]\" width=\"16\" height=\"16\" style=\"vertical-align: text-bottom; border: 0; padding-right: 1px;\"></a><a target=\"_blank\" href=\"https://archiveofourown.org/users/"+ fileread.recip + "/pseuds/" + fileread.recippseud.replace(" ","%20") + "\"><b>" + fileread.recippseud + " (" + fileread.recip + ")</b></a></span>")
except:
filewrite.write("<span style=\"white-space: nowrap;\" class=\"ljuser\"><a target=\"_blank\" href=\"https://archiveofourown.org/users/" + fileread.recip + "/profile\"><img src=\"https://p.dreamwidth.org/b164c54b26e4/-/archiveofourown.org/favicon.ico\" alt=\"[archiveofourown.org profile]\" width=\"16\" height=\"16\" style=\"vertical-align: text-bottom; border: 0; padding-right: 1px;\"></a><a target=\"_blank\" href=\"https://archiveofourown.org/users/"+ fileread.recip + "\"><b>" + fileread.recip + "</b></a></span>")
elif fileread.recipsite == "tumblr":
filewrite.write("<span style=\"white-space: nowrap;\"><a target=\"_blank\" href=\"https://" + fileread.recip + ".tumblr.com\"><img src=\"https://www.tumblr.com/favicon.ico\" alt=\"[tumblr.com profile]\" style=\"vertical-align: text-bottom; border: 0; padding-right: 1px;\" width=\"16\" height=\"16\"></a><a target=\"_blank\" href=\"https://" + fileread.recip + ".tumblr.com\"><b>" + fileread.recip + "</b></a></span>")
except:
filewrite.write(fileread.recip)
filewrite.write("’s ")
except:
pass
filewrite.write("prompt, <i>" + fileread.prompt + "</i>.")
try:
if fileread.notes:
filewrite.write(" ")
except:
pass
elif fileread.event == "exchange" or fileread.event == "ao3exchange":
filewrite.write(", a gift for ")
try:
if fileread.recipsite == "dw":
filewrite.write("<span style=\"white-space: nowrap;\" class=\"ljuser\"><a target=\"_blank\" href=\"https://" + fileread.recip.replace("_","-") + ".dreamwidth.org/profile\"><img src=\"https://www.dreamwidth.org/img/silk/identity/user.png\" alt=\"[personal profile]\" width=\"17\" height=\"17\" style=\"vertical-align: text-bottom; border: 0; padding-right: 1px;\"></a><a target=\"_blank\" href=\"https://"+ fileread.recip.replace("_","-") + ".dreamwidth.org/\"><b>" + fileread.recip.replace("-","_") + "</b></a></span>")
elif fileread.recipsite == "ao3":
try:
if fileread.recippseud:
filewrite.write("<span style=\"white-space: nowrap;\" class=\"ljuser\"><a target=\"_blank\" href=\"https://archiveofourown.org/users/" + fileread.recip + "/profile\"><img src=\"https://p.dreamwidth.org/b164c54b26e4/-/archiveofourown.org/favicon.ico\" alt=\"[archiveofourown.org profile]\" width=\"16\" height=\"16\" style=\"vertical-align: text-bottom; border: 0; padding-right: 1px;\"></a><a target=\"_blank\" href=\"https://archiveofourown.org/users/"+ fileread.recip + "/pseuds/" + fileread.recippseud.replace(" ","%20") + "\"><b>" + fileread.recippseud + " (" + fileread.recip + ")</b></a></span>")
except:
filewrite.write("<span style=\"white-space: nowrap;\" class=\"ljuser\"><a target=\"_blank\" href=\"https://archiveofourown.org/users/" + fileread.recip + "/profile\"><img src=\"https://p.dreamwidth.org/b164c54b26e4/-/archiveofourown.org/favicon.ico\" alt=\"[archiveofourown.org profile]\" width=\"16\" height=\"16\" style=\"vertical-align: text-bottom; border: 0; padding-right: 1px;\"></a><a target=\"_blank\" href=\"https://archiveofourown.org/users/" + fileread.recip + "\"><b>" + fileread.recip + "</b></a></span>")
elif fileread.recipsite == "tumblr":
filewrite.write("<span style=\"white-space: nowrap;\"><a target=\"_blank\" href=\"https://" + fileread.recip + ".tumblr.com\"><img src=\"https://www.tumblr.com/favicon.ico\" alt=\"[tumblr.com profile]\" style=\"vertical-align: text-bottom; border: 0; padding-right: 1px;\" width=\"16\" height=\"16\"></a><a target=\"_blank\" href=\"https://" + fileread.recip + ".tumblr.com\"><b>" + fileread.recip + "</b></a></span>")
except:
filewrite.write(fileread.recip)
filewrite.write(".")
try:
if fileread.notes:
filewrite.write(" ")
except:
pass
else:
filewrite.write(".")
try:
if fileread.notes:
filewrite.write(" ")
except:
pass
except:
pass
# write notes if there are any
try:
filewrite.write(fileread.notes + "</p>\n")
except:
try:
if fileread.event:
filewrite.write("</p>\n")
except:
if juvenilia:
filewrite.write("</p>\n")
filewrite.close()
linkgen(ficno,output,local)
filewrite = open(output, "a")
filewrite.write("</div>\n")
if single:
filewrite.write("<div id=\"federation\" hidden=\"from-humans\">\n<a class=\"u-bridgy-fed\" href=\"https://fed.brid.gy/\"></a>\n<a rel=\"author\" class=\"p-author h-card\" href=\"/\">“tré”<img class=\"u-photo\" src=\"/ab.png\"></a>\n</div>\n")
filewrite.write("</div>\n")
filewrite.close()

View file

@ -1,45 +0,0 @@
import datetime, os
from importlib import import_module
import makeheader
import headerfooter
"""
Code to generate masterlist
"""
def listgen(local=False):
# delete existing file
if os.path.exists("build/masterlist/index.html"):
os.remove("build/masterlist/index.html")
# write header
headerfooter.headerwrite("build/masterlist/index.html","Masterlist","Fic masterlist","<p>On this page, from newest to oldest, you’ll find basically everything I’ve ever written that is a. fanfiction and b. extant; quality may vary. Some fics, such as things I wrote before 2020, require a username and password to access.</p>",False,local)
# write fic divs
ficcount = 500
sortfics = []
while ficcount > 0:
ficcount -= 1
if ficcount < 10:
ficcountstring = "00" + str(ficcount)
elif ficcount < 100:
ficcountstring = "0" + str(ficcount)
else:
ficcountstring = str(ficcount)
if os.path.exists("files/originalsmeta/" + ficcountstring + ".py"):
ficfile = "files.originalsmeta." + ficcountstring
fileread = import_module(ficfile)
try:
if fileread.revealdate <= datetime.datetime.now():
ficdict = {"thefic":ficcount,"thedate":(fileread.datewords[-1])["date"]}
sortfics.append(ficdict)
except:
ficdict = {"thefic":ficcount,"thedate":(fileread.datewords[-1])["date"]}
sortfics.append(ficdict)
thefics = sorted(sortfics, key=lambda d: d["thedate"],reverse=True)
for fic in thefics:
makeheader.ficgen(fic["thefic"],True,"build/masterlist/index.html",local)
# write footer
headerfooter.footerwrite("build/masterlist/index.html",False,local)
if __name__ == "__main__":
listgen()

61
mention.py Normal file
View file

@ -0,0 +1,61 @@
import datetime,os,requests
from importlib import import_module
def stringno(theno):
if theno < 10:
return "00" + str(theno)
elif theno < 100:
return "0" + str(theno)
else:
return str(theno)
ficlist = []
ficcount = 999
while ficcount > 0:
ficcount -= 1
ficcountstring = stringno(ficcount)
if os.path.exists("files/originalsmeta/" + ficcountstring + ".py"):
ficfile = "files.originalsmeta." + ficcountstring
fileread = import_module(ficfile)
try:
if fileread.revealdate <= datetime.datetime.now():
goahead = True
else:
goahead = False
except:
goahead = True
if goahead == True:
ficdict = {}
ficdict["id"] = stringno(ficcount)
ficdict["date"] = fileread.datewords[-1]["date"]
ficlist.append(ficdict)
elif os.path.exists("files/translationsmeta/" + ficcountstring + ".py"):
ficfile = "files.translationsmeta." + ficcountstring
fileread = import_module(ficfile)
try:
if fileread.revealdate <= datetime.datetime.now():
goahead = True
else:
goahead = False
except:
goahead = True
if goahead == True:
ficdict = {}
ficdict["id"] = stringno(ficcount)
ficdict["date"] = fileread.datewords[-1]["date"]
ficlist.append(ficdict)
mentionlist = []
for fic in ficlist:
timeelapsed = datetime.datetime.now() - fic["date"]
if timeelapsed.days < 8:
mentionlist.append(fic["id"])
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
}
for fic in mentionlist:
response = requests.post("https://fed.brid.gy/webmention", headers=headers, data="source=https://tre.praze.net/fic/" + str(fic) + "&target=https://fed.brid.gy/")

509
new.py

File diff suppressed because one or more lines are too long

130
ships.py
View file

@ -1,130 +0,0 @@
import datetime, os
from importlib import import_module
fffandoms = ["FF1","FF2","FF3","FF4","FF5","FF6","FF7","FF8","FF9","FFX","FF11","FF12","FF13","FF14","FF15","FF16"]
import makeheader
import headerfooter
def shiplist(local=False):
# delete existing file
if os.path.exists("build/ff/ships/index.html"):
os.remove("build/ff/ships/index.html")
# write header
headerfooter.headerwrite("build/ff/ships/index.html","FF fics by ship","FF fics by ship","<p>Click on each bar to see fics involving that ship, organised according to whether it’s the main ship or a secondary one and then from newest to oldest.</p>",False,local)
# iterate through fandoms
ships = []
numbers = ["one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen"]
for fandom in fffandoms:
theships = []
ficcount = 500
while ficcount > 0:
ficcount -= 1
if ficcount < 10:
ficcountstring = "00" + str(ficcount)
elif ficcount < 100:
ficcountstring = "0" + str(ficcount)
else:
ficcountstring = str(ficcount)
if os.path.exists("files/originalsmeta/" + ficcountstring + ".py"):
ficfile = "files.originalsmeta." + ficcountstring
fileread = import_module(ficfile)
try:
if fileread.revealdate > datetime.datetime.now():
revealed = False
else:
revealed = True
except:
revealed = True
if revealed == True:
if len(fileread.fandom) == 1:
if fandom in fileread.fandom:
try:
theships.extend(fileread.ship)
except:
pass
for ship in theships:
if ship == None:
theships.remove(ship)
theships = sorted(list(dict.fromkeys(theships)))
for ship in theships:
shipdict = {"pairing":ship,"game":(fffandoms.index(fandom) + 1)}
ships.append(shipdict)
shiplist = sorted(ships, key=lambda d: d["pairing"])
for aship in shiplist:
maincount = []
secondarycount = []
ship = aship["pairing"]
searchfandom = fffandoms[(aship["game"]) - 1]
cssgame = numbers[(aship["game"]) - 1]
# check all fics in specified fandom
ficcount = 500
while ficcount > 0:
ficcount -= 1
if ficcount < 10:
ficcountstring = "00" + str(ficcount)
elif ficcount < 100:
ficcountstring = "0" + str(ficcount)
else:
ficcountstring = str(ficcount)
if os.path.exists("files/originalsmeta/" + ficcountstring + ".py"):
countfile = "files.originalsmeta." + ficcountstring
fileread = import_module(countfile)
try:
if fileread.revealdate > datetime.datetime.now():
revealed = False
else:
revealed = True
except:
revealed = True
if revealed == True:
ficdict = {"thefic":ficcount,"thedate":(fileread.datewords[-1])["date"]}
if searchfandom in fileread.fandom:
# append to lists
try:
if fileread.ship[0] == ship:
maincount.append(ficdict)
elif ship in fileread.ship:
secondarycount.append(ficdict)
except:
pass
# write details element
output = "build/ff/ships/index.html"
filewrite = open(output, "a")
filewrite.write("<details><summary><span class=\"character " + cssgame + "\">" + ship.replace("/"," × ") + "</span> ")
# write statistics
if len(maincount) > 0:
filewrite.write("<span class=\"main\"> main: " + str(len(maincount)) + "</span>")
if len(secondarycount) > 0:
filewrite.write("<span class=\"secondary\"> secondary: " + str(len(secondarycount)) + "</span>")
filewrite.write("</summary>\n")
filewrite.close()
# write fic headers in each category
if len(maincount) > 0:
filewrite = open(output, "a")
filewrite.write("<h1>Main ship</h1>\n")
filewrite.close()
maincount = sorted(maincount,key=lambda d: d["thedate"],reverse=True)
newmain = []
for fic in maincount:
newmain.append(fic["thefic"])
for fic in newmain:
makeheader.ficgen(fic,False,output,local)
if len(secondarycount) > 0:
filewrite = open(output, "a")
filewrite.write("<h1>Secondary ship</h1>\n")
filewrite.close()
secondarycount = sorted(secondarycount,key=lambda d: d["thedate"],reverse=True)
newsecondary = []
for fic in secondarycount:
newsecondary.append(fic["thefic"])
for fic in newsecondary:
makeheader.ficgen(fic,False,output,local)
filewrite = open(output, "a")
filewrite.write("</details>\n")
filewrite.close()
# write footer
headerfooter.footerwrite("build/ff/ships/index.html",False,local)
if __name__ == "__main__":
shiplist()

View file

@ -1,92 +0,0 @@
import datetime, os, shutil
from importlib import import_module
import headerfooter
import makeheader
"""
Code to generate standalone fic pages
"""
def singlepage(ficno,directory,local=False):
# convert to three-digit number
if ficno < 10:
ficnostring = "00" + str(ficno)
elif ficno < 100:
ficnostring = "0" + str(ficno)
else:
ficnostring = str(ficno)
# open the file
ficfile = directory + "." + ficnostring
fileread = import_module(ficfile)
# determine if unlocked
try:
if fileread.locked:
singlestatus = False
else:
singlestatus = True
except:
singlestatus = True
singlepath = "build/single/" + ficnostring
if not os.path.isdir(singlepath):
os.mkdir(singlepath)
if os.path.exists(singlepath + "/index.html"):
os.remove(singlepath + "/index.html")
# write to output file
output = singlepath + "/index.html"
headerfooter.headerwrite(output,"Fic no. " + ficnostring,"Fic no. <span id=\"ficno\">" + ficnostring + "</span>","",False,local,single=True,ficnostring=ficnostring)
try:
if fileread.original:
makeheader.ficgen(fileread.original,False,output,local,True)
else:
makeheader.ficgen(ficno,False,output,local,True)
except:
makeheader.ficgen(ficno,False,output,local,True)
if singlestatus:
filewrite = open(output, "a")
filewrite.write("<iframe src=\"")
if local:
filewrite.write("/home/mdd/Documents/proj/fic-archive/build/files/" + ficnostring + ".html")
else:
filewrite.write("/fic/files/" + ficnostring + ".html")
filewrite.write("\"></iframe>\n<div class=\"fic\">\n")
filewrite.close()
try:
if fileread.original:
makeheader.linkgen(fileread.original,output,local)
else:
makeheader.linkgen(ficno,output,local)
except:
makeheader.linkgen(ficno,output,local)
filewrite = open(output, "a")
filewrite.write("</div>\n")
filewrite.close()
headerfooter.footerwrite(output,False,local)
"""
Generate all single pages
"""
def allsingles(local=False):
for filename in os.listdir("build/single"):
filepath = os.path.join("build/single", filename)
if os.path.isfile(filepath):
os.unlink(filepath)
elif os.path.isdir(filepath):
shutil.rmtree(filepath)
ficcount = 500
while ficcount > 0:
ficcount -= 1
if ficcount < 10:
ficcountstring = "00" + str(ficcount)
elif ficcount < 100:
ficcountstring = "0" + str(ficcount)
else:
ficcountstring = str(ficcount)
if os.path.exists("files/originalsmeta/" + ficcountstring + ".py"):
singlepage(ficcount,"files.originalsmeta",local)
elif os.path.exists("files/translationsmeta/" + ficcountstring + ".py"):
singlepage(ficcount,"files.translationsmeta",local)
if __name__ == "__main__":
allsingles()

View file

@ -1,6 +1,8 @@
#!/usr/bin/env bash
for i in {1..500}
mkdir -p build/files build/secret
for i in {1..999}
do
if [[ $i -lt 10 ]]
then

View file

@ -1,762 +0,0 @@
import datetime, os, shutil
from importlib import import_module
"""
Warning: code in this file is /particularly/ bizarre and non-optimised.
"""
"""
Write the wee blurb for each fic
"""
def ficsum(ficcount,year,month=0,showfandom=True,local=False):
if ficcount < 10:
ficcountstring = "00" + str(ficcount)
elif ficcount < 100:
ficcountstring = "0" + str(ficcount)
else:
ficcountstring = str(ficcount)
if os.path.exists("files/originalsmeta/" + ficcountstring + ".py"):
ficfile = "files.originalsmeta." + ficcountstring
fileread = import_module(ficfile)
elif os.path.exists("files/translationsmeta/" + ficcountstring + ".py"):
ficfile = "files.translationsmeta." + ficcountstring
fileread = import_module(ficfile)
else:
fileread = False
if fileread:
try:
theorig = "files.originalsmeta." + str(fileread.original)
origfile = import_module(theorig)
except:
pass
try:
fandom = "/".join(origfile.fandom)
except:
fandom = "/".join(fileread.fandom)
thechars = ""
try:
if "OW" not in origfile.fandom:
if "gen" not in origfile.genre:
try:
thechars = origfile.ship[0].replace("/"," × ")
except:
chars = []
try:
chars.extend(origfile.charpov)
except:
pass
try:
chars.extend(origfile.charmain)
except:
pass
if chars != []:
thechars = ", ".join(chars)
else:
thechars = ""
else:
chars = []
try:
chars.extend(origfile.charpov)
except:
pass
try:
chars.extend(origfile.charmain)
except:
pass
if chars != []:
thechars = ", ".join(chars)
else:
thechars = ""
else:
thechars = ""
except:
if "OW" not in fileread.fandom:
if "gen" not in fileread.genre:
try:
thechars = fileread.ship[0].replace("/"," × ")
except:
chars = []
try:
chars.extend(fileread.charpov)
except:
pass
try:
chars.extend(fileread.charmain)
except:
pass
if chars != []:
thechars = ", ".join(chars)
else:
thechars = ""
else:
chars = []
try:
chars.extend(fileread.charpov)
except:
pass
try:
chars.extend(fileread.charmain)
except:
pass
if chars != []:
thechars = ", ".join(chars)
else:
thechars = ""
else:
thechars = ""
if thechars == "":
thechars = "no characters specified"
if fileread.language == "fr":
language = "French"
else:
language = ""
try:
rating = origfile.rating
except:
rating = fileread.rating
genre = []
try:
for thegenre in origfile.genre:
if thegenre == "gen":
genre.append(thegenre)
elif thegenre == "het" or thegenre == "pre-het":
genre.append("het")
elif thegenre == "slash" or thegenre == "pre-slash" or thegenre == "poly slash":
genre.append("slash")
elif thegenre == "femslash":
genre.append("femslash")
elif thegenre == "poly":
genre.append("multi")
elif thegenre == "masturbation":
genre.append("other")
except:
for thegenre in fileread.genre:
if thegenre == "gen":
genre.append(thegenre)
elif thegenre == "het" or thegenre == "pre-het":
genre.append("het")
elif thegenre == "slash" or thegenre == "pre-slash" or thegenre == "poly slash":
genre.append("slash")
elif thegenre == "femslash":
genre.append("femslash")
elif thegenre == "poly":
genre.append("multi")
elif thegenre == "masturbation":
genre.append("other")
try:
if origfile.warnings:
warnings = "?!"
except:
try:
if fileread.warnings:
warnings = "?!"
except:
warnings = ""
words = 0
for datewords in fileread.datewords:
if month:
if int((datewords["date"]).year) == year:
if int((datewords["date"]).month) == month:
words += datewords["words"]
else:
if int((datewords["date"]).year) == year:
words += datewords["words"]
ficstring = ""
ficstring += "<a href=\""
if local:
ficstring += "/home/mdd/Documents/proj/fic-archive/build/single/"
else:
ficstring += "/fic/single/"
try:
ficstring += str(fileread.original)
except:
ficstring += ficcountstring
if local:
ficstring += "/index.html"
ficstring +="\">"
if showfandom:
ficstring += fandom
if thechars or language:
ficstring += ", "
if thechars:
ficstring += thechars
if language:
ficstring += ", "
if language:
ficstring += language
ficstring += "</a>&nbsp;<span class=\"ficinfo\">"
if rating == "g":
ficstring += "<span title=\"universal\">🟢</span>"
elif rating == "t":
ficstring += "<span title=\"general\">🟡</span>"
elif rating == "m":
ficstring += "<span title=\"mature\">🟠</span>"
elif rating == "e":
ficstring += "<span title=\"explicit\">🔴</span>"
for thegenre in genre:
if thegenre == "gen":
ficstring += "<span title=\"gen\">⭕</span>"
elif thegenre == "slash":
ficstring += "<span title=\"slash\">👨👨</span>"
elif thegenre == "het":
ficstring += "<span title=\"het\">👨👩</span>"
elif thegenre == "femslash":
ficstring += "<span title=\"femslash\">👩👩</span>"
elif thegenre == "poly":
ficstring += "<span title=\"poly\">🧑➕</span>"
elif thegenre == "other":
ficstring += "<span title=\"misc. romance/sex\">💖</span>"
if warnings:
ficstring += "<span title=\"see notes for warnings\">❗</span>"
ficstring += "</span>&nbsp;<code>" + str(words) + "</code>"
return ficstring
"""
Generate stats page for each year
"""
def yeargen(local=False):
yearlist = []
ficcount = 500
while ficcount > 0:
ficcount -= 1
if ficcount < 10:
ficcountstring = "00" + str(ficcount)
elif ficcount < 100:
ficcountstring = "0" + str(ficcount)
else:
ficcountstring = str(ficcount)
if os.path.exists("files/originalsmeta/" + ficcountstring + ".py"):
ficfile = "files.originalsmeta." + ficcountstring
fileread = import_module(ficfile)
elif os.path.exists("files/translationsmeta/" + ficcountstring + ".py"):
ficfile = "files.translationsmeta." + ficcountstring
fileread = import_module(ficfile)
else:
fileread = False
if fileread:
try:
if fileread.revealdate > datetime.datetime.now():
revealed = False
else:
revealed = True
except:
revealed = True
if revealed == True:
for date in fileread.datewords:
yearlist.append(date["date"].year)
yearlist = sorted(list(dict.fromkeys(yearlist)))
for year in yearlist:
yearpath = "build/stats/" + str(year)
if not os.path.isdir(yearpath):
os.mkdir(yearpath)
if os.path.exists(yearpath + "/index.html"):
os.remove(yearpath + "/index.html")
filewrite = open(yearpath + "/index.html", "a")
filewrite.write("<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Fic stats " + str(year) + "</title>\n<link rel=\"stylesheet\" href=\"")
if local:
filewrite.write("https://tre.praze.net")
filewrite.write("/main.css\">\n<link rel=\"me\" href=\"https://kes.praze.net/@tre\">\n<link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/charts.css/dist/charts.min.css\">\n</head>\n<body style=\"--colourone: #990909; --colourtwo: #cf6969;\">\n<div class=\"container\">\n<h1>Fic stats for " + str(year) + "</h1>\n")
allfics = []
ficdeets = []
datesplit = []
ficcount = 500
while ficcount > 0:
ficcount -= 1
if ficcount < 10:
ficcountstring = "00" + str(ficcount)
elif ficcount < 100:
ficcountstring = "0" + str(ficcount)
else:
ficcountstring = str(ficcount)
if os.path.exists("files/originalsmeta/" + ficcountstring + ".py"):
ficfile = "files.originalsmeta." + ficcountstring
fileread = import_module(ficfile)
elif os.path.exists("files/translationsmeta/" + ficcountstring + ".py"):
ficfile = "files.translationsmeta." + ficcountstring
fileread = import_module(ficfile)
else:
fileread = False
if fileread:
try:
if fileread.revealdate > datetime.datetime.now():
revealed = False
else:
revealed = True
except:
revealed = True
if revealed == True:
for date in fileread.datewords:
if (date["date"]).year == year:
allfics.append(ficcountstring)
allfics = sorted(list(dict.fromkeys(allfics)))
for fic in allfics:
if os.path.exists("files/originalsmeta/" + fic + ".py"):
ficfile = "files.originalsmeta." + fic
fileread = import_module(ficfile)
elif os.path.exists("files/translationsmeta/" + fic + ".py"):
ficfile = "files.translationsmeta." + fic
fileread = import_module(ficfile)
else:
fileread = False
if fileread:
try:
if fileread.revealdate > datetime.datetime.now():
revealed = False
else:
revealed = True
except:
revealed = True
if revealed == True:
try:
fandom = fileread.fandom
event = fileread.event
eventname = fileread.eventname
try:
eventlocation = fileread.eventlocation
except:
eventlocation = False
except:
try:
if fileread.original:
theorig = "files.originalsmeta." + str(fileread.original)
origfile = import_module(theorig)
try:
fandom = origfile.fandom
event = origfile.event
eventname = origfile.eventname
try:
eventlocation = fileread.eventlocation
except:
eventlocation = False
except:
event = False
eventname = False
eventlocation = False
except:
event = False
eventname = False
eventlocation = False
ficwords = 0
for dateword in fileread.datewords:
if (dateword["date"]).year == year:
ficwords = (dateword["words"])
ficdict = {"number":fic,"words":ficwords,"fandom":fandom,"event":event,"eventname":eventname,"eventlocation":eventlocation,"date":dateword["date"]}
ficdeets.append(ficdict)
datesplit.append(ficdict)
combinedeets = []
for fic in ficdeets:
if combinedeets == []:
ficlogged = True
combinedeets.append(fic)
else:
ficlogged = False
for newfic in combinedeets:
if ficlogged == False:
if fic["number"] == newfic["number"]:
ficlogged = True
newfic["words"] += fic["words"]
if ficlogged == False:
combinedeets.append(fic)
ficdeets = combinedeets
ficdeets = sorted(ficdeets,key=lambda d: d["date"])
totalwords = 0
for fic in ficdeets:
totalwords += fic["words"]
if len(allfics) == 1:
filewrite.write("<p>Total: " + str(len (allfics)) + " fic, " + str(totalwords) + " words</p>\n")
else:
filewrite.write("<p>Total: " + str(len (allfics)) + " fics, " + str(totalwords) + " words</p>")
prompts = []
for fic in ficdeets:
if fic["event"] == "prompt":
prompts.append(fic)
if prompts:
promptwords = 0
for fic in prompts:
promptwords += fic["words"]
promptdict = {"type":"Prompt fills","fics":len(prompts),"words":promptwords,"list":prompts}
else:
promptdict = False
unprompted = []
for fic in ficdeets:
if fic["event"] == False:
unprompted.append(fic)
if unprompted:
unpromptedwords = 0
for fic in unprompted:
unpromptedwords += fic["words"]
unprompteddict = {"type":"Unprompted","fics":len(unprompted),"words":unpromptedwords,"list":unprompted}
else:
unprompteddict = False
challenges = []
for fic in ficdeets:
if fic["event"] == "challenge":
challenges.append(fic)
if challenges:
challengewords = 0
for fic in challenges:
challengewords += fic["words"]
challengedict = {"type":"Challenges","fics":len(challenges),"words":challengewords,"list":challenges}
else:
challengedict = False
exchanges = []
for fic in ficdeets:
if fic["event"] == "exchange" or fic["event"] == "ao3exchange":
exchanges.append(fic)
if exchanges:
exchangewords = 0
for fic in exchanges:
exchangewords += fic["words"]
exchangedict = {"type":"Exchanges","fics":len(exchanges),"words":exchangewords,"list":exchanges}
else:
exchangedict = False
byevent = []
if promptdict:
byevent.append(promptdict)
if unprompteddict:
byevent.append(unprompteddict)
if challengedict:
byevent.append(challengedict)
if exchangedict:
byevent.append(exchangedict)
byevent = sorted(byevent,key=lambda d: d["words"],reverse=True)
filewrite.write("<h2>By type</h2>\n<table class=\"charts-css column hide-data show-labels show-primary-axis data-spacing-2\" style=\"height:200px;max-width:" + str(len(byevent) * 200) + "px;\">\n<caption>Words per fic type</caption>\n<thead>\n<tr>\n<th scope=\"col\">Type</th>\n<th scope=\"col\">Words</th>\n</tr>\n</thead>\n<tbody style=\"height:inherit;\">\n")
for event in byevent:
filewrite.write("<tr>\n<th>" + event["type"] + "</th>\n<td style=\"--size:calc(" + str(event["words"]) + " / " + str((byevent[0])["words"]) + ");\"><span class=\"data\">" + str(event["words"]) + "</span><span class=\"tooltip\">" + str(event["fics"]) + " fic")
if event["fics"] > 1:
filewrite.write("s")
filewrite.write(", " + str(event["words"]) + " words</span></td>\n</tr>\n")
filewrite.write("</tbody>\n</table>\n<details><summary>Breakdown</summary>\n")
for eventtype in byevent:
filewrite.write("<h3>" + eventtype["type"] + "</h3>\n")
eventslist = []
for fic in eventtype["list"]:
if fic["eventname"]:
eventdeets = {"eventname":fic["eventname"],"eventlocation":fic["eventlocation"],"ficno":fic["number"],"words":fic["words"]}
else:
eventdeets = {"ficno":fic["number"],"words":fic["words"]}
eventslist.append(eventdeets)
neweventslist = []
if eventtype["type"] == "Unprompted":
neweventslist = eventslist
else:
for fic in eventslist:
if neweventslist == []:
ficlogged = True
neweventslist.append(fic)
else:
ficlogged = False
for newfic in neweventslist:
if ficlogged == False:
if fic["eventname"] == newfic["eventname"]:
ficlogged = True
newfic["words"] = newfic["words"] + fic["words"]
if type(newfic["ficno"]) == str:
newfic["ficno"] = newfic["ficno"].split()
if type(fic["ficno"]) == str:
newfic["ficno"].append(fic["ficno"])
if ficlogged == False:
neweventslist.append(fic)
if eventtype["type"] != "Unprompted":
for fic in neweventslist:
if type(fic["ficno"]) == str:
fic["ficno"] = fic["ficno"].split()
neweventslist = sorted(neweventslist,key=lambda d: d["words"],reverse=True)
else:
neweventslist = sorted(neweventslist,key=lambda d: d["ficno"])
if eventtype["type"] == "Unprompted":
filewrite.write("<details><summary>List</summary>\n<ol>\n")
for fic in neweventslist:
filewrite.write("<li>" + str(ficsum(int(fic["ficno"]),year,local=local)) + "</li>")
filewrite.write("</ol>\n</details>\n")
else:
filewrite.write("<table class=\"charts-css column hide-data show-labels show-primary-axis data-spacing-2\" style=\"height:200px;max-width:" + str(len(neweventslist) * 200) + "px;\">\n<caption>Words per event</caption>\n<thead>\n<tr>\n<th scope=\"col\">Event</th>\n<th scope=\"col\">Words</th>\n</tr>\n</thead>\n<tbody style=\"height:inherit;\">\n")
for event in neweventslist:
filewrite.write("<tr>\n<th>")
if event["eventlocation"] == "dwcomm":
filewrite.write("<span style=\"white-space: nowrap;\" class=\"ljuser\"><a target=\"_blank\" href=\"https://" + (event["eventname"]).replace("_","-") + ".dreamwidth.org/profile\"><img src=\"https://www.dreamwidth.org/img/silk/identity/community.png\" alt=\"[community profile]\" width=\"17\" height=\"17\" style=\"vertical-align: baseline; border: 0; padding-right: 1px;\"></a><a target=\"_blank\" href=\"https://" + (event["eventname"]).replace("_","-") + ".dreamwidth.org/\">" + (event["eventname"]).replace("-","_") + "</a></span>")
elif event["eventlocation"] == "dwjournal":
filewrite.write("<span style=\"white-space: nowrap;\" class=\"ljuser\"><a target=\"_blank\" href=\"https://" + (event["eventname"]).replace("_","-") + ".dreamwidth.org/profile\"><img src=\"https://www.dreamwidth.org/img/silk/identity/user.png\" alt=\"[personal profile]\" width=\"17\" height=\"17\" style=\"vertical-align: baseline; border: 0; padding-right: 1px;\"></a><a target=\"_blank\" href=\"https://"+ (event["eventname"]).replace("_","-") + ".dreamwidth.org/\">" + (event["eventname"]).replace("-","_")+ "</a></span>")
elif event["eventlocation"] == "ljjournal":
filewrite.write("<span style=\"white-space: nowrap;\" class=\"ljuser\"><a target=\"_blank\" href=\"https://" + (event["eventname"]).replace("_","-") + ".livejournal.com/profile\"><img src=\"https://www.dreamwidth.org/img/external/lj-userinfo.gif\" alt=\"[personal profile]\" width=\"17\" height=\"17\" style=\"vertical-align: baseline; border: 0; padding-right: 1px;\"></a><a target=\"_blank\" href=\"https://"+ (event["eventname"]).replace("_","-") + ".livejournal.com/\">" + (event["eventname"]).replace("-","_")+ "</a></span>")
elif event["eventname"] == "#ficwip":
filewrite.write("<a target=\"_blank\" href=\"https://ficwip.carrd.co\">#ficwip</a>")
else:
filewrite.write(event["eventname"])
filewrite.write("</th>\n<td style=\"--size:calc(" + str(event["words"]) + " / " + str((neweventslist[0])["words"]) + ");\"><span class=\"data\">" + str(event["words"]) + "</span><span class=\"tooltip\">" + str(len(event["ficno"])) + " fic")
if len(event["ficno"]) > 1:
filewrite.write("s")
filewrite.write(", " + str(event["words"]) + " words</span></td>\n</tr>\n")
filewrite.write("</tbody>\n</table>\n<details><summary>List</summary>\n")
for event in neweventslist:
filewrite.write("<h3>")
if event["eventlocation"] == "dwcomm":
filewrite.write("<span style=\"white-space: nowrap;\" class=\"ljuser\"><a target=\"_blank\" href=\"https://" + (event["eventname"]).replace("_","-") + ".dreamwidth.org/profile\"><img src=\"https://www.dreamwidth.org/img/silk/identity/community.png\" alt=\"[community profile]\" width=\"17\" height=\"17\" style=\"vertical-align: baseline; border: 0; padding-right: 1px;\"></a><a target=\"_blank\" href=\"https://" + (event["eventname"]).replace("_","-") + ".dreamwidth.org/\">" + (event["eventname"]).replace("-","_") + "</a></span>")
elif event["eventlocation"] == "dwjournal":
filewrite.write("<span style=\"white-space: nowrap;\" class=\"ljuser\"><a target=\"_blank\" href=\"https://" + (event["eventname"]).replace("_","-") + ".dreamwidth.org/profile\"><img src=\"https://www.dreamwidth.org/img/silk/identity/user.png\" alt=\"[personal profile]\" width=\"17\" height=\"17\" style=\"vertical-align: baseline; border: 0; padding-right: 1px;\"></a><a target=\"_blank\" href=\"https://"+ (event["eventname"]).replace("_","-") + ".dreamwidth.org/\">" + (event["eventname"]).replace("-","_")+ "</a></span>")
elif event["eventlocation"] == "ljjournal":
filewrite.write("<span style=\"white-space: nowrap;\" class=\"ljuser\"><a target=\"_blank\" href=\"https://" + (event["eventname"]).replace("_","-") + ".livejournal.com/profile\"><img src=\"https://www.dreamwidth.org/img/external/lj-userinfo.gif\" alt=\"[personal profile]\" width=\"17\" height=\"17\" style=\"vertical-align: baseline; border: 0; padding-right: 1px;\"></a><a target=\"_blank\" href=\"https://"+ (event["eventname"]).replace("_","-") + ".livejournal.com/\">" + (event["eventname"]).replace("-","_")+ "</a></span>")
else:
filewrite.write(event["eventname"])
filewrite.write("</h3>\n<ol>\n")
for fic in event["ficno"]:
filewrite.write("<li>" + str(ficsum(int(fic),year,local=local)) + "</li>\n")
filewrite.write("</ol>\n")
filewrite.write("</details>\n")
fandomlist = []
for fic in ficdeets:
fandomlist.extend(fic["fandom"])
fandomlist = sorted(list(dict.fromkeys(fandomlist)))
filewrite.write("</details>\n<h2>By fandom</h2>\n<table class=\"charts-css column hide-data show-labels show-primary-axis data-spacing-2\" style=\"height:400px;max-width:" + str(len(fandomlist) * 200) + "px;\">\n<caption>Words per fandom</caption>\n<thead>\n<tr>\n<th scope=\"col\"> Fandom</th>\n<th scope=\"col\"> Words</th>\n</tr>\n</thead>\n<tbody style=\"height:inherit;\">\n")
fandomdeets = []
for fandom in fandomlist:
fandomdict = {"name":fandom,"ficno":[],"words":0}
for fic in ficdeets:
if fandom in fic["fandom"]:
fandomdict["ficno"].append(fic["number"])
fandomdict["words"] += fic["words"]
fandomdeets.append(fandomdict)
fandomdeets = sorted(fandomdeets,key=lambda d: d["words"],reverse=True)
for fandom in fandomdeets:
filewrite.write("<tr>\n<th>" + fandom["name"] + "</th>\n<td style=\"--size:calc(" + str(fandom["words"]) + " / " + str((fandomdeets[0])["words"]) + ");\"><span class=\"data\">" + str(fandom["words"]) + "</span><span class=\"tooltip\">" + str(len(fandom["ficno"])) + " fic")
if len(fandom["ficno"]) > 1:
filewrite.write("s")
filewrite.write(", " + str(fandom["words"]) + " words</span></td>\n</tr>")
filewrite.write("</tbody>\n</table>\n<details><summary>List</summary>")
for fandom in fandomdeets:
filewrite.write("<h3>" + fandom["name"] + "</h3>\n<ol>\n")
for fic in fandom["ficno"]:
filewrite.write("<li>" + str(ficsum(int(fic),year,showfandom=False,local=local)) + "</li>\n")
filewrite.write("</ol>\n")
filewrite.write("</details>\n<h2>By month</h2>\n<table class=\"charts-css column hide-data show-labels show-primary-axis data-spacing-2\" style=\"height:200px;max-width:2400px;\">\n<caption>Words per month</caption>\n<thead>\n<tr>\n<th scope=\"col\">Month</th>\n<th scope=\"col\">Words</th>\n</tr>\n</thead>\n<tbody style=\"height:inherit;\">")
monthcombine = []
for fic in datesplit:
# read the file back in to get the right word count, because dicts are dynamic somehow??
thedate = fic["date"]
thefic = fic["number"]
if os.path.exists("files/originalsmeta/" + thefic + ".py"):
ficfile = "files.originalsmeta." + thefic
fileread = import_module(ficfile)
elif os.path.exists("files/translationsmeta/" + thefic + ".py"):
ficfile = "files.translationsmeta." + thefic
fileread = import_module(ficfile)
else:
fileread = False
if fileread:
try:
if fileread.revealdate > datetime.datetime.now():
revealed = False
else:
revealed = True
except:
revealed = True
if revealed == True:
for datewords in fileread.datewords:
if datewords["date"] == thedate:
thewords = datewords["words"]
fic["words"] = thewords
ficlogged = False
if monthcombine == []:
if ficlogged == False:
ficlogged = True
monthcombine.append(fic)
else:
ficlogged = False
for newfic in monthcombine:
if ficlogged == False:
if fic["number"] == newfic["number"]:
if (fic["date"]).month == (newfic["date"]).month:
ficlogged = True
newfic["words"] += fic["words"]
if ficlogged == False:
monthcombine.append(fic)
monthcombine = sorted(monthcombine,key=lambda d: d["date"])
jan = {"fics":[],"words":0}
feb = {"fics":[],"words":0}
mar = {"fics":[],"words":0}
apr = {"fics":[],"words":0}
may = {"fics":[],"words":0}
jun = {"fics":[],"words":0}
jul = {"fics":[],"words":0}
aug = {"fics":[],"words":0}
sep = {"fics":[],"words":0}
octo = {"fics":[],"words":0}
nov = {"fics":[],"words":0}
dec = {"fics":[],"words":0}
for fic in monthcombine:
if (fic["date"]).month == 1:
jan["fics"].append(fic["number"])
jan["words"] += fic["words"]
elif (fic["date"]).month == 2:
feb["fics"].append(fic["number"])
feb["words"] += fic["words"]
elif (fic["date"]).month == 3:
mar["fics"].append(fic["number"])
mar["words"] += fic["words"]
elif (fic["date"]).month == 4:
apr["fics"].append(fic["number"])
apr["words"] += fic["words"]
elif (fic["date"]).month == 5:
may["fics"].append(fic["number"])
may["words"] += fic["words"]
elif (fic["date"]).month == 6:
jun["fics"].append(fic["number"])
jun["words"] += fic["words"]
elif (fic["date"]).month == 7:
jul["fics"].append(fic["number"])
jul["words"] += fic["words"]
elif (fic["date"]).month == 8:
aug["fics"].append(fic["number"])
aug["words"] += fic["words"]
elif (fic["date"]).month == 9:
sep["fics"].append(fic["number"])
sep["words"] += fic["words"]
elif (fic["date"]).month == 10:
octo["fics"].append(fic["number"])
octo["words"] += fic["words"]
elif (fic["date"]).month == 11:
nov["fics"].append(fic["number"])
nov["words"] += fic["words"]
elif (fic["date"]).month == 12:
dec["fics"].append(fic["number"])
dec["words"] += fic["words"]
wordlist = []
wordlist.append(jan["words"])
wordlist.append(feb["words"])
wordlist.append(mar["words"])
wordlist.append(apr["words"])
wordlist.append(may["words"])
wordlist.append(jun["words"])
wordlist.append(jul["words"])
wordlist.append(aug["words"])
wordlist.append(sep["words"])
wordlist.append(octo["words"])
wordlist.append(nov["words"])
wordlist.append(dec["words"])
mostwords = max(wordlist)
filewrite.write("<tr>\n<th>Jan</th>\n<td style=\"--size:calc(" + str(jan["words"]) + " / " + str(mostwords) + ");\"><span class=\"data\">" + str(jan["words"]) + "</span><span class=\"tooltip\">" + str(len(jan["fics"])) + " fic")
if len(jan["fics"]) != 1:
filewrite.write("s")
filewrite.write(", " + str(jan["words"]) + " words</span></td>\n</tr>\n<tr>\n<th>Feb</th>\n<td style=\"--size:calc(" + str(feb["words"]) + " / " + str(mostwords) + ");\"><span class=\"data\">" + str(feb["words"]) + "</span><span class=\"tooltip\">" + str(len(feb["fics"])) + " fic")
if len(feb["fics"]) != 1:
filewrite.write("s")
filewrite.write(", " + str(feb["words"]) + " words</span></td>\n</tr>\n<tr>\n<th>Mar</th>\n<td style=\"--size:calc(" + str(mar["words"]) + " / " + str(mostwords) + ");\"><span class=\"data\">" + str(mar["words"]) + "</span><span class=\"tooltip\">" + str(len(mar["fics"])) + " fic")
if len(mar["fics"]) != 1:
filewrite.write("s")
filewrite.write(", " + str(mar["words"]) + " words</span></td>\n</tr>\n<tr>\n<th>Apr</th>\n<td style=\"--size:calc(" + str(apr["words"]) + " / " + str(mostwords) + ");\"><span class=\"data\">" + str(apr["words"]) + "</span><span class=\"tooltip\">" + str(len(apr["fics"])) + " fic")
if len(apr["fics"]) != 1:
filewrite.write("s")
filewrite.write(", " + str(apr["words"]) + " words</span></td>\n</tr>\n<tr>\n<th>May</th>\n<td style=\"--size:calc(" + str(may["words"]) + " / " + str(mostwords) + ");\"><span class=\"data\">" + str(may["words"]) + "</span><span class=\"tooltip\">" + str(len(may["fics"])) + " fic")
if len(may["fics"]) != 1:
filewrite.write("s")
filewrite.write(", " + str(may["words"]) + " words</span></td>\n</tr>\n<tr>\n<th>Jun</th>\n<td style=\"--size:calc(" + str(jun["words"]) + " / " + str(mostwords) + ");\"><span class=\"data\">" + str(jun["words"]) + "</span><span class=\"tooltip\">" + str(len(jun["fics"])) + " fic")
if len(jun["fics"]) != 1:
filewrite.write("s")
filewrite.write(", " + str(jun["words"]) + " words</span></td>\n</tr>\n<tr>\n<th>Jul</th>\n<td style=\"--size:calc(" + str(jul["words"]) + " / " + str(mostwords) + ");\"><span class=\"data\">" + str(jul["words"]) + "</span><span class=\"tooltip\">" + str(len(jul["fics"])) + " fic")
if len(jul["fics"]) != 1:
filewrite.write("s")
filewrite.write(", " + str(jul["words"]) + " words</span></td>\n</tr>\n<tr>\n<th>Aug</th>\n<td style=\"--size:calc(" + str(aug["words"]) + " / " + str(mostwords) + ");\"><span class=\"data\">" + str(aug["words"]) + "</span><span class=\"tooltip\">" + str(len(aug["fics"])) + " fic")
if len(aug["fics"]) != 1:
filewrite.write("s")
filewrite.write(", " + str(aug["words"]) + " words</span></td>\n</tr>\n<tr>\n<th>Sep</th>\n<td style=\"--size:calc(" + str(sep["words"]) + " / " + str(mostwords) + ");\"><span class=\"data\">" + str(sep["words"]) + "</span><span class=\"tooltip\">" + str(len(sep["fics"])) + " fic")
if len(sep["fics"]) != 1:
filewrite.write("s")
filewrite.write(", " + str(sep["words"]) + " words</span></td>\n</tr>\n<tr>\n<th>Oct</th>\n<td style=\"--size:calc(" + str(octo["words"]) + " / " + str(mostwords) + ");\"><span class=\"data\">" + str(octo["words"]) + "</span><span class=\"tooltip\">" + str(len(octo["fics"])) + " fic")
if len(octo["fics"]) != 1:
filewrite.write("s")
filewrite.write(", " + str(octo["words"]) + " words</span></td>\n</tr>\n<tr>\n<th>Nov</th>\n<td style=\"--size:calc(" + str(nov["words"]) + " / " + str(mostwords) + ");\"><span class=\"data\">" + str(nov["words"]) + "</span><span class=\"tooltip\">" + str(len(nov["fics"])) + " fic")
if len(nov["fics"]) != 1:
filewrite.write("s")
filewrite.write(", " + str(nov["words"]) + " words</span></td>\n</tr>\n<tr>\n<th>Dec</th>\n<td style=\"--size:calc(" + str(dec["words"]) + " / " + str(mostwords) + ");\"><span class=\"data\">" + str(dec["words"]) + "</span><span class=\"tooltip\">" + str(len(dec["fics"])) + " fic")
if len(dec["fics"]) != 1:
filewrite.write("s")
filewrite.write(", " + str(dec["words"]) + " words</span></td>\n</tr>\n</tbody>\n</table>\n<details><summary>List</summary>\n")
if len(jan["fics"]) > 0:
filewrite.write("<h3>January</h3>\n<ol>\n")
for fic in jan["fics"]:
filewrite.write("<li>" + str(ficsum(int(fic),year,1,local=local)) + "</li>\n")
filewrite.write("</ol>\n")
if len(feb["fics"]) > 0:
filewrite.write("<h3>February</h3>\n<ol>\n")
for fic in feb["fics"]:
filewrite.write("<li>" + str(ficsum(int(fic),year,2,local=local)) + "</li>\n")
filewrite.write("</ol>\n")
if len(mar["fics"]) > 0:
filewrite.write("<h3>March</h3>\n<ol>\n")
for fic in mar["fics"]:
filewrite.write("<li>" + str(ficsum(int(fic),year,3,local=local)) + "</li>\n")
filewrite.write("</ol>\n")
if len(apr["fics"]) > 0:
filewrite.write("<h3>April</h3>\n<ol>\n")
for fic in apr["fics"]:
filewrite.write("<li>" + str(ficsum(int(fic),year,4,local=local)) + "</li>\n")
filewrite.write("</ol>\n")
if len(may["fics"]) > 0:
filewrite.write("<h3>May</h3>\n<ol>\n")
for fic in may["fics"]:
filewrite.write("<li>" + str(ficsum(int(fic),year,5,local=local)) + "</li>\n")
filewrite.write("</ol>\n")
if len(jun["fics"]) > 0:
filewrite.write("<h3>June</h3>\n<ol>\n")
for fic in jun["fics"]:
filewrite.write("<li>" + str(ficsum(int(fic),year,6,local=local)) + "</li>\n")
filewrite.write("</ol>\n")
if len(jul["fics"]) > 0:
filewrite.write("<h3>July</h3>\n<ol>\n")
for fic in jul["fics"]:
filewrite.write("<li>" + str(ficsum(int(fic),year,7,local=local)) + "</li>\n")
filewrite.write("</ol>\n")
if len(aug["fics"]) > 0:
filewrite.write("<h3>August</h3>\n<ol>\n")
for fic in aug["fics"]:
filewrite.write("<li>" + str(ficsum(int(fic),year,8,local=local)) + "</li>\n")
filewrite.write("</ol>\n")
if len(sep["fics"]) > 0:
filewrite.write("<h3>September</h3>\n<ol>\n")
for fic in sep["fics"]:
filewrite.write("<li>" + str(ficsum(int(fic),year,9,local=local)) + "</li>\n")
filewrite.write("</ol>\n")
if len(octo["fics"]) > 0:
filewrite.write("<h3>October</h3>\n<ol>\n")
for fic in octo["fics"]:
filewrite.write("<li>" + str(ficsum(int(fic),year,10,local=local)) + "</li>\n")
filewrite.write("</ol>\n")
if len(nov["fics"]) > 0:
filewrite.write("<h3>November</h3>\n<ol>\n")
for fic in nov["fics"]:
filewrite.write("<li>" + str(ficsum(int(fic),year,11,local=local)) + "</li>\n")
filewrite.write("</ol>\n")
if len(dec["fics"]) > 0:
filewrite.write("<h3>December</h3>\n<ol>\n")
for fic in dec["fics"]:
filewrite.write("<li>" + str(ficsum(int(fic),year,12,local=local)) + "</li>\n")
filewrite.write("</ol>\n")
filewrite.write("</details>\n<p>")
listposition = yearlist.index(year)
if year != 1998:
prevyear = yearlist[listposition - 1]
filewrite.write("<span style=\"float:left;\"><a href=\"")
if local:
filewrite.write("/home/mdd/Documents/proj/fic-archive/build/stats/" + str(prevyear) + "/index.html")
else:
filewrite.write("/fic/stats/" + str(prevyear))
filewrite.write("\"" + str(prevyear) + "</a></span>")
thisyear = int(datetime.datetime.now().strftime("%Y"))
if year < thisyear:
try:
nextyear = yearlist[listposition + 1]
filewrite.write("<span style=\"float:right;\"><a href=\"")
if local:
filewrite.write("/home/mdd/Documents/proj/fic-archive/build/stats/" + str(nextyear) + "/index.html")
else:
filewrite.write("/fic/stats/" + str(nextyear))
filewrite.write("\">" + str(nextyear) + " »</a></span>")
except:
pass
filewrite.write("</p>\n</div>\n<a href=\"/\"><img src=\"/a.png\" style=\"position:fixed;bottom:2px;right:2px;\" title=\"home\"></a></body>\n</html>")
filewrite.close()
if __name__ == "__main__":
yeargen(True)

View file

@ -1,21 +0,0 @@
import os
import headerfooter
def verifygen(local=False):
# delete existing file
if os.path.exists("build/verify/index.html"):
os.remove("build/verify/index.html")
# write header
headerfooter.headerwrite("build/verify/index.html","Tré’s fic archive","Warning","",True,local)
filewrite = open("build/verify/index.html", "a")
filewrite.write("<p><strong>Please note before proceeding:</strong></p>\n<p>Some of my fanfiction is NSFW (ranging from slightly obscene language to explicit sex scenes), some is RPF, and some of it contains mature or potentially objectionable themes (death, suicide, mental illness, incest …). Ratings and warnings are given accordingly, <strong>don’t like don’t read</strong>. If you consider yourself to be a minor, kindly gtfo and <em>read some real literature instead</em>. Honestly, it will be much more edifying.</p>\n<label for=\"verifyage-checkbox\">Please tick to confirm you have read this warning and are sufficiently mature to access this content:</label>\n<input type=\"checkbox\" id=\"verifyage-checkbox\">\n<button id=\"verifyage-button\">Let me in!</button>\n<div align=\"center\">\n<script src=\"https://ficring.neocities.org/ring.js\"></script>\n</div>\n</div>\n</div>\n<script>\nvar verifyageButton = document.getElementById(\"verifyage-button\"); var verifyageCheckbox = document.getElementById(\"verifyage-checkbox\"); verifyageButton.addEventListener(\"click\", () => {if (verifyageCheckbox.checked) {localStorage.setItem(\"ageVerified\", \"\"); if (window.location = window.location.search.startsWith(\"?returnto=\")) {window.location = window.location.search.substring(\"?returnto=\".length);} else {window.location = \"")
if local:
filewrite.write("/home/mdd/Documents/proj/fic-archive/build/index.html")
else:
filewrite.write("/fic")
filewrite.write("\";}} else {alert(\"You must agree before proceeding.\");}});\n</script>\n</body>\n</html>")
filewrite.close()
if __name__ == "__main__":
verifygen()

View file

@ -1,54 +0,0 @@
import datetime, os
from importlib import import_module
fffandoms = ["FF1","FF2","FF3","FF4","FF5","FF6","FF7","FF8","FF9","FFX","FF11","FF12","FF13","FF14","FF15","FF16"]
import makeheader
import headerfooter
def bywords(local=False):
# delete existing file
if os.path.exists("build/ff/bywords/index.html"):
os.remove("build/ff/bywords/index.html")
# write header
headerfooter.headerwrite("build/ff/bywords/index.html","FF fics by word count","FF fics by word count","<p>On this page, my FF fics are sorted from longest to shortest. (Fics with translations are listed according to the wordcount of the original version; the wordcount for the translation is normally pretty close to this.)</p>",False,local)
# iterate through fandoms
ficlist = []
ficcount = 500
while ficcount > 0:
ficcount -= 1
if ficcount < 10:
ficcountstring = "00" + str(ficcount)
elif ficcount < 100:
ficcountstring = "0" + str(ficcount)
else:
ficcountstring = str(ficcount)
if os.path.exists("files/originalsmeta/" + ficcountstring + ".py"):
ficfile = "files.originalsmeta." + ficcountstring
fileread = import_module(ficfile)
try:
if fileread.revealdate > datetime.datetime.now():
revealed = False
else:
revealed = True
except:
revealed = True
if revealed == True:
fffic = False
for fandom in fileread.fandom:
if fandom in fffandoms:
fffic = True
if fffic == True:
sumwords = 0
for instalment in fileread.datewords:
sumwords = sumwords + instalment["words"]
ficlist.append({"ficno":ficcount,"length":sumwords})
ficlist = sorted(ficlist, key=lambda d: d["length"],reverse=True)
# write fic headers
for fic in ficlist:
makeheader.ficgen(fic["ficno"],False,"build/ff/bywords/index.html",local)
# write footer
headerfooter.footerwrite("build/ff/bywords/index.html",False,local)
if __name__ == "__main__":
bywords(True)