.
\ No newline at end of file
diff --git a/Gemfile b/Gemfile
index 71f5b3b..8077a1e 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,3 +1,16 @@
+=begin
+Copyright (C) 2024 Hexaitos
+This file is part of "Predator Pics"
+
+Predator Pics is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+
+Predator Pics is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with Foobar. If not, see .
+
+Contact: me@bateleur.org, me@hexaitos.com.
+=end
+
source 'https://rubygems.org'
gem 'json'
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..2826d6f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,23 @@
+# Predator Pics (birds.bateleur.org)
+Predator Pics is a website that uses the API of Wikimedia Common to display a random image of a bird of prey. There is a Mastodon / Fediverse bot called “Bot of Prey” that uses the API of this website as its backend.
+
+## How it works
+1. The program choses a random category from the `categories.txt` file located in this repository
+2. It then sends an API request to receive a list of all (<= 500) photos located within that category on Wikimedia Commons
+3. It then chooses one of the photos it received at random, saves important metadata (like author, license and description) and displays it on the webpage
+
+## How to run and install it
+If you wish to run your own instance of Predator Pics, you must have Ruby installed (tested on Ruby 3.2.2); you‘ll also need the `bundler` gem that you can install by running `gem install bundler` after having installed Ruby. It is generally recommended to __not__ install Ruby through your distributions package manager – rather, install Ruby through a Ruby version manager like `rbenv` (https://rbenv.org).
+
+Then clone this repository and install the required gems by running `bundle install` from your terminal within the cloned repository. Afterwards, start the server by running `ruby server.rb`. The server (usually `thin`) will then start in `production` mode and serve the website on `localhost:4567`.
+
+## Reverse proxy
+If you wish to make Predator Pics accessible via the Internet, you‘ll want to use a reverse proxy. My preferred method of doing that is by using Caddy. First, install Caddy and then remove everything located in the `/etc/caddy/Caddyfile` file and paste the following into it, replacing `example.com` with your actual domain name:
+
+```
+example.com {
+ encode zstd gzip
+
+ reverse_proxy :4567
+}
+```
\ No newline at end of file
diff --git a/get_images_by_category.rb b/get_images_by_category.rb
index 94af7ae..9591e38 100644
--- a/get_images_by_category.rb
+++ b/get_images_by_category.rb
@@ -1,5 +1,19 @@
+=begin
+Copyright (C) 2024 Hexaitos
+This file is part of "Predator Pics"
+
+Predator Pics is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+
+Predator Pics is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with Foobar. If not, see .
+
+Contact: me@bateleur.org, me@hexaitos.com.
+=end
+
def get_images_by_category(categories)
random_category = categories.sample
+
if random_category.include?("https://commons.wikimedia.org/wiki/Category:") then
random_category = random_category.gsub("https://commons.wikimedia.org/wiki/Category:", "")
elsif random_category.include?("Category:") then
@@ -11,34 +25,30 @@ def get_images_by_category(categories)
photos = []
conn = Faraday.new(url: 'https://commons.wikimedia.org/w/api.php') do |faraday|
- faraday.adapter Faraday.default_adapter # Use the default adapter (Net::HTTP)
+ faraday.adapter Faraday.default_adapter
end
- # Define the parameters for the request
params = {
action: 'query',
list: 'categorymembers',
- cmtitle: "Category:#{random_category}", # Specify the category title
+ cmtitle: "Category:#{random_category}",
cmlimit: 500,
cmtype: 'file',
- format: 'json' # Request response in JSON format
+ format: 'json'
}
- # Send the GET request
response = conn.get do |req|
req.params = params
end
- # Parse the response as JSON
data = JSON.parse(response.body)
-
- # Handle and print the response
- if data['query'] && data['query']['categorymembers']
+
+ begin
category_members = data['query']['categorymembers']
category_members.each do |member|
- photos << member['title']
+ photos << member['title']
end
- else
+ rescue
puts "No data found or error in API request"
end
diff --git a/get_random_image.rb b/get_random_image.rb
index e085db6..a259d04 100644
--- a/get_random_image.rb
+++ b/get_random_image.rb
@@ -1,17 +1,30 @@
+=begin
+Copyright (C) 2024 Hexaitos
+This file is part of "Predator Pics"
+
+Predator Pics is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+
+Predator Pics is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with Foobar. If not, see .
+
+Contact: me@bateleur.org, me@hexaitos.com.
+=end
+
def get_random_image(photos)
random_photo = photos.sample
conn = Faraday.new(url: 'https://commons.wikimedia.org/w/api.php') do |faraday|
- faraday.adapter Faraday.default_adapter # Use the default adapter (Net::HTTP)
+ faraday.adapter Faraday.default_adapter
end
params = {
action: 'query',
prop: 'imageinfo',
- titles: "#{random_photo}", # Specify the category title
+ titles: "#{random_photo}",
iiprop: 'url|user|extmetadata',
iiurlwidth: 1000,
- format: 'json' # Request response in JSON format
+ format: 'json'
}
response = conn.get do |req|
diff --git a/public/css/styles.css b/public/css/styles.css
index 835e4b0..3f7f05c 100755
--- a/public/css/styles.css
+++ b/public/css/styles.css
@@ -1 +1,468 @@
-@font-face{font-family:"Merriweather";font-style:normal;font-weight:400;src:url("/assets/fonts/merriweather-v21-latin-regular.eot");src:local("Merriweather Regular"),local("Merriweather-Regular"),url("/assets/fonts/merriweather-v21-latin-regular.eot?#iefix") format("embedded-opentype"),url("/assets/fonts/merriweather-v21-latin-regular.woff2") format("woff2"),url("/assets/fonts/merriweather-v21-latin-regular.woff") format("woff"),url("/assets/fonts/merriweather-v21-latin-regular.ttf") format("truetype"),url("/assets/fonts/merriweather-v21-latin-regular.svg#Merriweather") format("svg");font-display:swap}@font-face{font-family:"Merriweather";font-style:italic;font-weight:400;src:url("/assets/fonts/merriweather-v21-latin-italic.eot");src:local("Merriweather Italic"),local("Merriweather-Italic"),url("/assets/fonts/merriweather-v21-latin-italic.eot?#iefix") format("embedded-opentype"),url("/assets/fonts/merriweather-v21-latin-italic.woff2") format("woff2"),url("/assets/fonts/merriweather-v21-latin-italic.woff") format("woff"),url("/assets/fonts/merriweather-v21-latin-italic.ttf") format("truetype"),url("/assets/fonts/merriweather-v21-latin-italic.svg#Merriweather") format("svg");font-display:swap}@font-face{font-family:"Merriweather Sans";font-style:normal;font-weight:400;src:url("/assets/fonts/merriweather-sans-v13-latin-regular.eot");src:local(""),url("/assets/fonts/merriweather-sans-v13-latin-regular.eot?#iefix") format("embedded-opentype"),url("/assets/fonts/merriweather-sans-v13-latin-regular.woff2") format("woff2"),url("/assets/fonts/merriweather-sans-v13-latin-regular.woff") format("woff"),url("/assets/fonts/merriweather-sans-v13-latin-regular.ttf") format("truetype"),url("/assets/fonts/merriweather-sans-v13-latin-regular.svg#MerriweatherSans") format("svg");font-display:swap}@font-face{font-family:"Merriweather Sans";font-style:italic;font-weight:400;src:url("/assets/fonts/merriweather-sans-v13-latin-italic.eot");src:local(""),url("/assets/fonts/merriweather-sans-v13-latin-italic.eot?#iefix") format("embedded-opentype"),url("/assets/fonts/merriweather-sans-v13-latin-italic.woff2") format("woff2"),url("/assets/fonts/merriweather-sans-v13-latin-italic.woff") format("woff"),url("/assets/fonts/merriweather-sans-v13-latin-italic.ttf") format("truetype"),url("/assets/fonts/merriweather-sans-v13-latin-italic.svg#MerriweatherSans") format("svg");font-display:swap}:root{--body-bg: #9f9287;--main-bg: #cdcac4;--menu-bg: #2b2623;--foot-bg: #2b2623;--btn-col: #dba047;--btn-hov: #ae4e26}*{font-family:Merriweather,Merriweather Sans}q{quotes:"“" "”" "‘" "’";font-family:Merriweather}q::before{content:open-quote}q::after{content:close-quote}body{margin-left:10%;margin-right:10%;padding:10px;background-color:var(--body-bg)}.main h1,h2,h3{font-variant:small-caps;padding:.3em .3em}.main h1{border-top:5px double #a72f14;border-bottom:5px double #a72f14;text-align:center}.main h2{border-bottom:5px solid #a72f14}.main p{font-size:16px;text-align:justify}.main img{max-width:100%}div.pfp{padding:.5em}div.main{background-color:var(--main-bg);padding:2em;border-radius:10px;min-height:500px}.pfp img{border:5px double #a72f14;border-radius:10px;max-width:150px;display:block;margin-left:auto;margin-right:auto}.pfp p{text-align:center;font-style:italic;font-size:12px}div.menu{background:var(--menu-bg);padding:.5em;margin-bottom:2em;overflow:hidden;text-align:center;border-radius:10px;min-height:3em;height:auto}.menu p{color:#fff;text-decoration:none;padding:.5em .5em;margin-left:.5em;text-align:right;border-radius:10px}.menu a{color:#fff;text-decoration:none;padding:.8em .8em;margin-right:1em;margin-left:1em;min-width:100px;text-align:center;background-color:var(--btn-col);display:inline-block;font-size:medium;border-radius:10px;margin-bottom:.5em;margin-top:.5em}.menu a:hover,.contact a:hover,a.webring-btn:hover{background-color:var(--btn-hov)}.main a{color:#ae4e26}.main a:hover{text-decoration:none}div.contact{text-align:center}.contact a{color:#fff;text-decoration:none;padding:.8em .8em;text-align:center;background-color:var(--btn-col);display:grid;font-size:medium;border-radius:10px;margin-bottom:1em}a.webring-btn{color:#fff;text-decoration:none;padding:.5em .5em;margin-right:.5em;margin-left:.5em;min-width:75px;text-align:center;background-color:var(--btn-col);display:inline-block;font-size:medium;border-radius:10px}div.webring{border-top:2px solid var(--btn-hov);border-bottom:2px solid var(--btn-hov);text-align:right;display:flex;align-items:center;height:50px;justify-content:space-between;margin-top:5px}.webring span{float:left;padding:auto 0}footer{background:var(--foot-bg);padding:1em;margin-top:2em;overflow:hidden;text-align:center;height:auto;border-radius:10px;min-height:3em}footer p{color:#fff}footer p:first-of-type{float:left}footer p:last-of-type{float:right}@media only screen and (max-width: 900px){.menu a{font-size:medium;min-width:90px}div.menu{padding:.5em;height:auto}body{margin-left:5%;margin-right:5%}}@media only screen and (max-width: 700px){.menu a{font-size:smaller;min-width:80px;margin-left:.1em;margin-right:.1em}footer p:first-of-type,footer p:last-of-type{float:none}}div.art{display:flex;justify-content:center}div.gallery{border:5px double rgba(167,47,20,.3)}div.gallery:hover{border:5px double #dba047}div.gallery img{width:100%;height:200px;object-fit:scale-down}div.desc{padding:10px;text-align:center}*{box-sizing:border-box}.responsive{padding:0 6px;float:left;width:24.99999%}section.colour-cols{display:flex;flex-direction:column;justify-content:space-around;text-align:center}div[class*=colour-col-]{display:flex;justify-content:center}div[class*=colour-col-]>div{height:75px;width:25%}div[class*=colour-col-][class*="1"] :nth-child(1){background-color:#2b2623}div[class*=colour-col-][class*="1"] :nth-child(2){background-color:#db9f47}div[class*=colour-col-][class*="1"] :nth-child(3){background-color:#ae4e26}div[class*=colour-col-][class*="1"] :nth-child(4){background-color:#a72f14}div[class*=colour-col-][class*="2"] :nth-child(1){background-color:#fff}div[class*=colour-col-][class*="2"] :nth-child(2){background-color:#133042}div[class*=colour-col-][class*="2"] :nth-child(3){background-color:#2b2623}div[class*=colour-col-][class*="3"] :nth-child(1){background-color:#c0b6ad}div[class*=colour-col-][class*="3"] :nth-child(2){background-color:#9f9387}div[class*=colour-col-][class*="3"] :nth-child(3){background-color:#2b2623}div[class*=colour-col-][class*="3"] :nth-child(4){background-color:#894518}div[class*=hex-code-col-]{display:flex;justify-content:center;flex-direction:row;margin-bottom:15px}div[class*=hex-code-col-]>span{width:25%;display:inline;text-align:center;font-family:monospace}span.colour-heading{margin-bottom:5px;font-size:large}img.refsheet{width:100%}@media only screen and (max-width: 700px){.responsive{width:49.99999%;margin:6px 0}div.art{display:inherit;justify-content:inherit}}@media only screen and (max-width: 500px){.responsive{width:100%}div.art{display:inherit;justify-content:inherit}a.webring-btn{min-width:40px;margin-right:.2em;margin-left:.2em}}.clearfix:after{content:"";display:table;clear:both}code{font-family:monospace;background-color:#d3d3d3;border:1px gray}@media(prefers-color-scheme: dark){:root{--body-bg: rgb(49, 49, 49);--main-bg: #191919;--menu-bg: #191919;--foot-bg: #191919;--btn-hov: #dba047;--btn-col: #ae4e26}code{background-color:#a9a9a9}div.gallery{border:5px double #a72f14}.main a{color:#dba047}.contact a,li,span,a.webring-btn,div.desc,p,h1,h2,h3,b{color:#fff}}/*# sourceMappingURL=styles.css.map */
\ No newline at end of file
+/*
+Copyright (C) 2024 Hexaitos
+This file is part of "Predator Pics"
+
+Predator Pics is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+
+Predator Pics is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with Foobar. If not, see .
+
+Contact: me@bateleur.org, me@hexaitos.com.
+*/
+
+@font-face {
+ font-family: "Merriweather";
+ font-style: normal;
+ font-weight: 400;
+ src: url("/assets/fonts/merriweather-v21-latin-regular.eot");
+ src: local("Merriweather Regular"), local("Merriweather-Regular"), url("/assets/fonts/merriweather-v21-latin-regular.eot?#iefix") format("embedded-opentype"), url("/assets/fonts/merriweather-v21-latin-regular.woff2") format("woff2"), url("/assets/fonts/merriweather-v21-latin-regular.woff") format("woff"), url("/assets/fonts/merriweather-v21-latin-regular.ttf") format("truetype"), url("/assets/fonts/merriweather-v21-latin-regular.svg#Merriweather") format("svg");
+ font-display: swap
+}
+
+@font-face {
+ font-family: "Merriweather";
+ font-style: italic;
+ font-weight: 400;
+ src: url("/assets/fonts/merriweather-v21-latin-italic.eot");
+ src: local("Merriweather Italic"), local("Merriweather-Italic"), url("/assets/fonts/merriweather-v21-latin-italic.eot?#iefix") format("embedded-opentype"), url("/assets/fonts/merriweather-v21-latin-italic.woff2") format("woff2"), url("/assets/fonts/merriweather-v21-latin-italic.woff") format("woff"), url("/assets/fonts/merriweather-v21-latin-italic.ttf") format("truetype"), url("/assets/fonts/merriweather-v21-latin-italic.svg#Merriweather") format("svg");
+ font-display: swap
+}
+
+@font-face {
+ font-family: "Merriweather Sans";
+ font-style: normal;
+ font-weight: 400;
+ src: url("/assets/fonts/merriweather-sans-v13-latin-regular.eot");
+ src: local(""), url("/assets/fonts/merriweather-sans-v13-latin-regular.eot?#iefix") format("embedded-opentype"), url("/assets/fonts/merriweather-sans-v13-latin-regular.woff2") format("woff2"), url("/assets/fonts/merriweather-sans-v13-latin-regular.woff") format("woff"), url("/assets/fonts/merriweather-sans-v13-latin-regular.ttf") format("truetype"), url("/assets/fonts/merriweather-sans-v13-latin-regular.svg#MerriweatherSans") format("svg");
+ font-display: swap
+}
+
+@font-face {
+ font-family: "Merriweather Sans";
+ font-style: italic;
+ font-weight: 400;
+ src: url("/assets/fonts/merriweather-sans-v13-latin-italic.eot");
+ src: local(""), url("/assets/fonts/merriweather-sans-v13-latin-italic.eot?#iefix") format("embedded-opentype"), url("/assets/fonts/merriweather-sans-v13-latin-italic.woff2") format("woff2"), url("/assets/fonts/merriweather-sans-v13-latin-italic.woff") format("woff"), url("/assets/fonts/merriweather-sans-v13-latin-italic.ttf") format("truetype"), url("/assets/fonts/merriweather-sans-v13-latin-italic.svg#MerriweatherSans") format("svg");
+ font-display: swap
+}
+
+:root {
+ --body-bg: #9f9287;
+ --main-bg: #cdcac4;
+ --menu-bg: #2b2623;
+ --foot-bg: #2b2623;
+ --btn-col: #dba047;
+ --btn-hov: #ae4e26;
+}
+
+* {
+ font-family: Merriweather, Merriweather Sans
+}
+
+q {
+ quotes: "“" "”" "‘" "’";
+ font-family: Merriweather
+}
+
+q::before {
+ content: open-quote
+}
+
+q::after {
+ content: close-quote
+}
+
+body {
+ margin-left: 10%;
+ margin-right: 10%;
+ padding: 10px;
+ background-color: var(--body-bg)
+}
+
+.main h1,
+h2,
+h3 {
+ font-variant: small-caps;
+ padding: .3em .3em
+}
+
+.main h1 {
+ border-top: 5px double #a72f14;
+ border-bottom: 5px double #a72f14;
+ text-align: center
+}
+
+.main h2 {
+ border-bottom: 5px solid #a72f14
+}
+
+.main p {
+ font-size: 16px;
+ text-align: justify
+}
+
+.main img {
+ max-width: 100%
+}
+
+div.pfp {
+ padding: .5em
+}
+
+div.main {
+ background-color: var(--main-bg);
+ padding: 2em;
+ border-radius: 10px;
+ min-height: 500px
+}
+
+.pfp img {
+ border: 5px double #a72f14;
+ border-radius: 10px;
+ max-width: 150px;
+ display: block;
+ margin-left: auto;
+ margin-right: auto
+}
+
+.pfp p {
+ text-align: center;
+ font-style: italic;
+ font-size: 12px
+}
+
+div.menu {
+ background: var(--menu-bg);
+ padding: .5em;
+ margin-bottom: 2em;
+ overflow: hidden;
+ text-align: center;
+ border-radius: 10px;
+ min-height: 3em;
+ height: auto
+}
+
+.menu p {
+ color: #fff;
+ text-decoration: none;
+ padding: .5em .5em;
+ margin-left: .5em;
+ text-align: right;
+ border-radius: 10px
+}
+
+.menu a {
+ color: #fff;
+ text-decoration: none;
+ padding: .8em .8em;
+ margin-right: 1em;
+ margin-left: 1em;
+ min-width: 100px;
+ text-align: center;
+ background-color: var(--btn-col);
+ display: inline-block;
+ font-size: medium;
+ border-radius: 10px;
+ margin-bottom: .5em;
+ margin-top: .5em
+}
+
+.menu a:hover,
+.contact a:hover,
+a.webring-btn:hover {
+ background-color: var(--btn-hov);
+}
+
+.main a, footer a {
+ color: #ae4e26;
+}
+
+.main a:hover, footer a:hover {
+ text-decoration: none;
+}
+
+div.contact {
+ text-align: center;
+}
+
+.contact a {
+ color: #fff;
+ text-decoration: none;
+ padding: .8em .8em;
+ text-align: center;
+ background-color: var(--btn-col);
+ display: grid;
+ font-size: medium;
+ border-radius: 10px;
+ margin-bottom: 1em
+}
+
+a.webring-btn {
+ color: #fff;
+ text-decoration: none;
+ padding: .5em .5em;
+ margin-right: .5em;
+ margin-left: .5em;
+ min-width: 75px;
+ text-align: center;
+ background-color: var(--btn-col);
+ display: inline-block;
+ font-size: medium;
+ border-radius: 10px
+}
+
+div.webring {
+ border-top: 2px solid var(--btn-hov);
+ border-bottom: 2px solid var(--btn-hov);
+ text-align: right;
+ display: flex;
+ align-items: center;
+ height: 50px;
+ justify-content: space-between;
+ margin-top: 5px
+}
+
+.webring span {
+ float: left;
+ padding: auto 0
+}
+
+footer {
+ background: var(--foot-bg);
+ padding: 1em;
+ margin-top: 2em;
+ overflow: hidden;
+ text-align: center;
+ height: auto;
+ border-radius: 10px;
+ min-height: 3em
+}
+
+footer p {
+ color: #fff
+}
+
+footer p:first-of-type {
+ float: left
+}
+
+footer p:last-of-type {
+ float: right
+}
+
+@media only screen and (max-width: 900px) {
+ .menu a {
+ font-size: medium;
+ min-width: 90px
+ }
+ div.menu {
+ padding: .5em;
+ height: auto
+ }
+ body {
+ margin-left: 5%;
+ margin-right: 5%
+ }
+}
+
+@media only screen and (max-width: 700px) {
+ .menu a {
+ font-size: smaller;
+ min-width: 80px;
+ margin-left: .1em;
+ margin-right: .1em
+ }
+ footer p:first-of-type,
+ footer p:last-of-type {
+ float: none
+ }
+}
+
+div.art {
+ display: flex;
+ justify-content: center
+}
+
+div.gallery {
+ border: 5px double rgba(167, 47, 20, .3)
+}
+
+div.gallery:hover {
+ border: 5px double #dba047
+}
+
+div.gallery img {
+ width: 100%;
+ height: 200px;
+ object-fit: scale-down
+}
+
+div.desc {
+ padding: 10px;
+ text-align: center
+}
+
+* {
+ box-sizing: border-box
+}
+
+.responsive {
+ padding: 0 6px;
+ float: left;
+ width: 24.99999%
+}
+
+section.colour-cols {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-around;
+ text-align: center
+}
+
+div[class*=colour-col-] {
+ display: flex;
+ justify-content: center
+}
+
+div[class*=colour-col-]>div {
+ height: 75px;
+ width: 25%
+}
+
+div[class*=colour-col-][class*="1"] :nth-child(1) {
+ background-color: #2b2623
+}
+
+div[class*=colour-col-][class*="1"] :nth-child(2) {
+ background-color: #db9f47
+}
+
+div[class*=colour-col-][class*="1"] :nth-child(3) {
+ background-color: #ae4e26
+}
+
+div[class*=colour-col-][class*="1"] :nth-child(4) {
+ background-color: #a72f14
+}
+
+div[class*=colour-col-][class*="2"] :nth-child(1) {
+ background-color: #fff
+}
+
+div[class*=colour-col-][class*="2"] :nth-child(2) {
+ background-color: #133042
+}
+
+div[class*=colour-col-][class*="2"] :nth-child(3) {
+ background-color: #2b2623
+}
+
+div[class*=colour-col-][class*="3"] :nth-child(1) {
+ background-color: #c0b6ad
+}
+
+div[class*=colour-col-][class*="3"] :nth-child(2) {
+ background-color: #9f9387
+}
+
+div[class*=colour-col-][class*="3"] :nth-child(3) {
+ background-color: #2b2623
+}
+
+div[class*=colour-col-][class*="3"] :nth-child(4) {
+ background-color: #894518
+}
+
+div[class*=hex-code-col-] {
+ display: flex;
+ justify-content: center;
+ flex-direction: row;
+ margin-bottom: 15px
+}
+
+div[class*=hex-code-col-]>span {
+ width: 25%;
+ display: inline;
+ text-align: center;
+ font-family: monospace
+}
+
+span.colour-heading {
+ margin-bottom: 5px;
+ font-size: large
+}
+
+img.refsheet {
+ width: 100%
+}
+
+@media only screen and (max-width: 700px) {
+ .responsive {
+ width: 49.99999%;
+ margin: 6px 0
+ }
+ div.art {
+ display: inherit;
+ justify-content: inherit
+ }
+}
+
+@media only screen and (max-width: 500px) {
+ .responsive {
+ width: 100%
+ }
+ div.art {
+ display: inherit;
+ justify-content: inherit
+ }
+ a.webring-btn {
+ min-width: 40px;
+ margin-right: .2em;
+ margin-left: .2em
+ }
+}
+
+.clearfix:after {
+ content: "";
+ display: table;
+ clear: both
+}
+
+code {
+ font-family: monospace;
+ background-color: #d3d3d3;
+ border: 1px gray
+}
+
+@media(prefers-color-scheme: dark) {
+ :root {
+ --body-bg: rgb(49, 49, 49);
+ --main-bg: #191919;
+ --menu-bg: #191919;
+ --foot-bg: #191919;
+ --btn-hov: #dba047;
+ --btn-col: #ae4e26;
+ }
+ code {
+ background-color: #a9a9a9
+ }
+ div.gallery {
+ border: 5px double #a72f14
+ }
+ .main a, footer a {
+ color: #dba047
+ }
+ .contact a,
+ li,
+ span,
+ a.webring-btn,
+ div.desc,
+ p,
+ h1,
+ h2,
+ h3,
+ b {
+ color: #fff
+ }
+}
\ No newline at end of file
diff --git a/public/css/styles.css.map b/public/css/styles.css.map
deleted file mode 100644
index 5bbdff2..0000000
--- a/public/css/styles.css.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"sourceRoot":"","sources":["styles.scss"],"names":[],"mappings":"CACA,WACE,2BACA,kBACA,gBACA,4DACA,2cAMA,kBAIF,WACE,2BACA,kBACA,gBACA,2DACA,ocAMA,kBAIF,WACE,gCACA,kBACA,gBACA,iEACA,sbAMA,kBAIF,WACE,gCACA,kBACA,gBACA,gEACA,ibAMA,kBAGF,MACE,mBACA,mBACA,mBACA,mBACA,mBACA,mBAGF,EACE,2CAGF,EACE,uBACA,yBAGF,UACI,mBAGJ,SACI,oBAGJ,KAGE,gBACA,iBACA,aACA,gCAGF,eACE,wBACA,kBAGF,SACE,8BACA,iCACA,kBAGF,SACE,gCAGF,QACE,eACA,mBAGF,UACE,eAGF,QACE,aAGF,SACE,gCACA,YACA,mBACA,iBAGF,SACE,0BACA,mBACA,gBACA,cACA,iBACA,kBAGF,OACE,kBACA,kBACA,eAGF,SAEE,0BACA,aACA,kBACA,gBACA,kBACA,mBACA,eACA,YAGF,QACE,WACA,qBACA,kBACA,iBACA,iBACA,mBAGF,QACE,WACA,qBACA,kBACA,iBACA,gBACA,gBACA,kBACA,gCACA,qBACA,iBACA,mBACA,mBACA,gBAGF,mDACE,gCAGF,QACE,cAGF,cACE,qBAGF,YACE,kBAGF,WACE,WACA,qBACA,kBACA,kBACA,gCACA,aACA,iBACA,mBACA,kBAOF,cACE,WACA,qBACA,kBACA,kBACA,iBACA,eACA,kBACA,gCACA,qBACA,iBACA,mBAOF,YACE,oCACA,uCACA,iBACA,aACA,mBACA,YACA,8BACA,eAGF,cACE,WACA,eAGF,OAEE,0BACA,YACA,eACA,gBACA,kBACA,YACA,mBACA,eAGF,SACE,WAGF,uBACE,WAGF,sBACE,YAIF,0CACE,QACE,iBACA,eAGF,SACE,aACA,YAGF,KACE,eACA,iBAIJ,0CACE,QACE,kBACA,eACA,iBACA,kBAGF,6CACE,YAMJ,QACE,aACA,uBAGF,YACE,qCAGF,kBACE,0BAGF,gBACE,WACA,aACA,sBAGF,SACE,aACA,kBAGF,EACE,sBAGF,YACE,cACA,WACA,gBAGF,oBACE,aACA,sBACA,6BACA,kBAGF,wBACE,aACA,uBAEA,4BACE,YACA,UAIA,2EACA,2EACA,2EACA,2EAIA,wEACA,2EACA,2EAIA,2EACA,2EACA,2EACA,2EAIJ,0BACE,aACA,uBACA,mBACA,mBAEA,+BACE,UACA,eACA,kBACA,sBAIJ,oBACE,kBACA,gBAGF,aACE,WAGF,0CACE,YACE,gBACA,aAGF,QACE,gBACA,yBAIJ,0CACE,YACE,WAGF,QACE,gBACA,wBAGF,cACE,eACA,kBACA,kBAIJ,gBACE,WACA,cACA,WAGF,KACE,sBACA,yBACA,gBAGF,mCACE,MACE,2BACA,mBACA,mBACA,mBACA,mBACA,mBAGF,KACE,yBAGF,YACE,0BAGF,QACE,cAGF,uDACE","sourcesContent":["/* merriweather-regular - latin */\n@font-face {\n font-family: 'Merriweather';\n font-style: normal;\n font-weight: 400;\n src: url('/assets/fonts/merriweather-v21-latin-regular.eot'); /* IE9 Compat Modes */\n src: local('Merriweather Regular'), local('Merriweather-Regular'),\n url('/assets/fonts/merriweather-v21-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */\n url('/assets/fonts/merriweather-v21-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */\n url('/assets/fonts/merriweather-v21-latin-regular.woff') format('woff'), /* Modern Browsers */\n url('/assets/fonts/merriweather-v21-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */\n url('/assets/fonts/merriweather-v21-latin-regular.svg#Merriweather') format('svg'); /* Legacy iOS */\n font-display: swap;\n}\n\n/* merriweather-italic - latin */\n@font-face {\n font-family: 'Merriweather';\n font-style: italic;\n font-weight: 400;\n src: url('/assets/fonts/merriweather-v21-latin-italic.eot'); /* IE9 Compat Modes */\n src: local('Merriweather Italic'), local('Merriweather-Italic'),\n url('/assets/fonts/merriweather-v21-latin-italic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */\n url('/assets/fonts/merriweather-v21-latin-italic.woff2') format('woff2'), /* Super Modern Browsers */\n url('/assets/fonts/merriweather-v21-latin-italic.woff') format('woff'), /* Modern Browsers */\n url('/assets/fonts/merriweather-v21-latin-italic.ttf') format('truetype'), /* Safari, Android, iOS */\n url('/assets/fonts/merriweather-v21-latin-italic.svg#Merriweather') format('svg'); /* Legacy iOS */\n font-display: swap;\n}\n\n/* merriweather-sans-regular - latin */\n@font-face {\n font-family: 'Merriweather Sans';\n font-style: normal;\n font-weight: 400;\n src: url('/assets/fonts/merriweather-sans-v13-latin-regular.eot'); /* IE9 Compat Modes */\n src: local(''),\n url('/assets/fonts/merriweather-sans-v13-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */\n url('/assets/fonts/merriweather-sans-v13-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */\n url('/assets/fonts/merriweather-sans-v13-latin-regular.woff') format('woff'), /* Modern Browsers */\n url('/assets/fonts/merriweather-sans-v13-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */\n url('/assets/fonts/merriweather-sans-v13-latin-regular.svg#MerriweatherSans') format('svg'); /* Legacy iOS */\n font-display: swap;\n}\n\n/* merriweather-sans-italic - latin */\n@font-face {\n font-family: 'Merriweather Sans';\n font-style: italic;\n font-weight: 400;\n src: url('/assets/fonts/merriweather-sans-v13-latin-italic.eot'); /* IE9 Compat Modes */\n src: local(''),\n url('/assets/fonts/merriweather-sans-v13-latin-italic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */\n url('/assets/fonts/merriweather-sans-v13-latin-italic.woff2') format('woff2'), /* Super Modern Browsers */\n url('/assets/fonts/merriweather-sans-v13-latin-italic.woff') format('woff'), /* Modern Browsers */\n url('/assets/fonts/merriweather-sans-v13-latin-italic.ttf') format('truetype'), /* Safari, Android, iOS */\n url('/assets/fonts/merriweather-sans-v13-latin-italic.svg#MerriweatherSans') format('svg'); /* Legacy iOS */\n font-display: swap;\n}\n\n:root {\n --body-bg: #9f9287;\n --main-bg: #cdcac4; \n --menu-bg: #2b2623;\n --foot-bg: #2b2623; \n --btn-col: #dba047; \n --btn-hov: #ae4e26;\n}\n\n* {\n font-family: Merriweather, Merriweather Sans; \n}\n\nq {\n quotes: \"“\" \"”\" \"‘\" \"’\";\n font-family: Merriweather;\n}\n\nq::before {\n content: open-quote;\n}\n\nq::after {\n content: close-quote;\n}\n\nbody {\n /* border: 2px solid rgba(167, 47, 20, 1); */\n /* border-radius: 25px; */\n margin-left: 10%;\n margin-right: 10%;\n padding: 10px;\n background-color: var(--body-bg);\n}\n\n.main h1, h2, h3 {\n font-variant: small-caps;\n padding: .3em .3em;\n}\n\n.main h1 {\n border-top: 5px double rgba(167, 47, 20, 1);\n border-bottom: 5px double rgba(167, 47, 20, 1);\n text-align: center;\n}\n\n.main h2 {\n border-bottom: 5px solid rgba(167, 47, 20, 1);\n}\n\n.main p {\n font-size: 16px;\n text-align: justify;\n}\n\n.main img {\n max-width: 100%;\n}\n\ndiv.pfp {\n padding: .5em;\n}\n\ndiv.main {\n background-color: var(--main-bg);\n padding: 2em;\n border-radius: 10px;\n min-height: 500px;\n}\n\n.pfp img {\n border: 5px double rgba(167, 47, 20, 1);\n border-radius: 10px;\n max-width: 150px;\n display: block;\n margin-left: auto;\n margin-right: auto;\n}\n\n.pfp p {\n text-align: center;\n font-style: italic;\n font-size: 12px; \n}\n\ndiv.menu {\n /* background: #ae4e26; */\n background: var(--menu-bg); \n padding: .5em;\n margin-bottom: 2em;\n overflow: hidden;\n text-align: center;\n border-radius: 10px;\n min-height: 3em;\n height: auto;\n}\n\n.menu p {\n color: white;\n text-decoration: none;\n padding: .5em .5em; \n margin-left: .5em;\n text-align: right;\n border-radius: 10px;\n}\n\n.menu a {\n color: white;\n text-decoration: none;\n padding: .8em .8em;\n margin-right: 1em;\n margin-left: 1em;\n min-width: 100px;\n text-align: center;\n background-color: var(--btn-col);\n display:inline-block;\n font-size: medium;\n border-radius: 10px;\n margin-bottom: .5em;\n margin-top: .5em;\n}\n\n.menu a:hover, .contact a:hover, a.webring-btn:hover {\n background-color: var(--btn-hov);\n}\n\n.main a {\n color: #ae4e26;\n}\n\n.main a:hover {\n text-decoration: none;\n}\n\ndiv.contact {\n text-align: center;\n}\n\n.contact a {\n color: white;\n text-decoration: none;\n padding: .8em .8em;\n text-align: center;\n background-color: var(--btn-col);\n display:grid;\n font-size: medium;\n border-radius: 10px;\n margin-bottom: 1em;\n}\n\n/*.contact a:last-child {\n min-width: 94%;\n} */\n\na.webring-btn {\n color: white;\n text-decoration: none;\n padding: .5em .5em;\n margin-right: 0.5em;\n margin-left: 0.5em;\n min-width: 75px;\n text-align: center;\n background-color: var(--btn-col);\n display: inline-block;\n font-size: medium;\n border-radius: 10px;\n}\n\ndiv.webring-btn-container {\n \n}\n\ndiv.webring {\n border-top: 2px solid var(--btn-hov);\n border-bottom: 2px solid var(--btn-hov);\n text-align: right;\n display: flex;\n align-items: center;\n height: 50px;\n justify-content: space-between;\n margin-top: 5px;\n}\n\n.webring span {\n float: left;\n padding: auto 0;\n}\n\nfooter {\n /* background: #ae4e26; */\n background: var(--foot-bg); \n padding: 1em;\n margin-top: 2em;\n overflow: hidden;\n text-align: center;\n height: auto;\n border-radius: 10px;\n min-height: 3em;\n}\n\nfooter p {\n color: white;\n}\n\nfooter p:first-of-type {\n float: left;\n}\n\nfooter p:last-of-type {\n float: right;\n}\n\n/* Responsive design stuff */\n@media only screen and (max-width: 900px) {\n .menu a {\n font-size: medium;\n min-width: 90px;\n }\n\n div.menu {\n padding: .5em;\n height: auto;\n }\n\n body {\n margin-left: 5%;\n margin-right: 5%;\n }\n}\n\n@media only screen and (max-width: 700px) {\n .menu a {\n font-size: smaller;\n min-width: 80px;\n margin-left: 0.1em;\n margin-right: 0.1em;\n }\n\n footer p:first-of-type, footer p:last-of-type {\n float: none;\n }\n}\n\n/* CSS gallery from w3schools.com */\n\ndiv.art {\n display: flex;\n justify-content: center;\n}\n\ndiv.gallery {\n border: 5px double rgba(167, 47, 20, 0.3);\n}\n\ndiv.gallery:hover {\n border: 5px double #dba047;\n}\n\ndiv.gallery img {\n width: 100%;\n height: 200px;\n object-fit: scale-down;\n}\n\ndiv.desc {\n padding: 10px;\n text-align: center;\n}\n\n* {\n box-sizing: border-box;\n}\n\n.responsive {\n padding: 0 6px;\n float: left;\n width: 24.99999%;\n}\n\nsection.colour-cols {\n display:flex;\n flex-direction: column;\n justify-content: space-around;\n text-align: center;\n}\n\ndiv[class*=\"colour-col-\"] {\n display: flex;\n justify-content: center;\n\n > div {\n height: 75px;\n width: 25%;\n }\n\n &[class*=\"1\"] {\n :nth-child(1) { background-color: #2b2623; }\n :nth-child(2) { background-color: #db9f47; }\n :nth-child(3) { background-color: #ae4e26; }\n :nth-child(4) { background-color: #a72f14; }\n }\n\n &[class*=\"2\"] {\n :nth-child(1) { background-color: #ffffff; }\n :nth-child(2) { background-color: #133042; }\n :nth-child(3) { background-color: #2b2623; }\n }\n\n &[class*=\"3\"] {\n :nth-child(1) { background-color: #c0b6ad; }\n :nth-child(2) { background-color: #9f9387; }\n :nth-child(3) { background-color: #2b2623; }\n :nth-child(4) { background-color: #894518; }\n }\n}\n\ndiv[class*=\"hex-code-col-\"] {\n display: flex;\n justify-content: center;\n flex-direction: row;\n margin-bottom: 15px;\n\n > span {\n width: 25%;\n display: inline;\n text-align: center;\n font-family: monospace;\n }\n}\n\nspan.colour-heading {\n margin-bottom: 5px;\n font-size: large;\n}\n\nimg.refsheet {\n width: 100%;\n}\n\n@media only screen and (max-width: 700px) {\n .responsive {\n width: 49.99999%;\n margin: 6px 0;\n }\n \n div.art {\n display: inherit;\n justify-content: inherit\n }\n}\n\n@media only screen and (max-width: 500px) {\n .responsive {\n width: 100%;\n }\n\n div.art {\n display: inherit;\n justify-content: inherit\n }\n\n a.webring-btn {\n min-width: 40px;\n margin-right: 0.2em;\n margin-left: 0.2em;\n }\n}\n\n.clearfix:after {\n content: \"\";\n display: table;\n clear: both;\n}\n\ncode {\n font-family: monospace;\n background-color: lightgrey;\n border: 1px grey;\n}\n\n@media (prefers-color-scheme: dark) {\n :root {\n --body-bg: rgb(49, 49, 49);\n --main-bg: #191919; \n --menu-bg: #191919;\n --foot-bg: #191919; \n --btn-hov: #dba047; \n --btn-col: #ae4e26;\n }\n\n code {\n background-color: darkgray;\n }\n\n div.gallery {\n border: 5px double rgba(167, 47, 20, 1);\n }\n\n .main a {\n color: #dba047;\n }\n\n .contact a, li, span, a.webring-btn, div.desc, p, h1, h2, h3, b {\n color: white; \n }\n}"],"file":"styles.css"}
\ No newline at end of file
diff --git a/server.rb b/server.rb
index 258fd6c..4ccaecb 100644
--- a/server.rb
+++ b/server.rb
@@ -1,3 +1,16 @@
+=begin
+Copyright (C) 2024 Hexaitos
+This file is part of "Predator Pics"
+
+Predator Pics is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+
+Predator Pics is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with Foobar. If not, see .
+
+Contact: me@bateleur.org, me@hexaitos.com.
+=end
+
require 'bundler/setup'
require 'json'
@@ -16,7 +29,7 @@ categories = File.readlines("categories.txt")
# Index
get '/' do
- image = get_random_image(get_images_by_category(categories))
+ puts image = get_random_image(get_images_by_category(categories))
erb :index, locals: { image: image }
end
@@ -26,6 +39,7 @@ get '/about' do
erb :about
end
+# API information
get '/about-api' do
erb :api
end
diff --git a/views/about.erb b/views/about.erb
index 53abde1..5390b4c 100644
--- a/views/about.erb
+++ b/views/about.erb
@@ -1,2 +1,15 @@
+
+
About this website
This website is still a work in progress. It randomly selects a photo of a bird of prey from Wikimedia and displays it on the homepage.
\ No newline at end of file
diff --git a/views/api.erb b/views/api.erb
index 4ed26c2..2dcf83a 100644
--- a/views/api.erb
+++ b/views/api.erb
@@ -1,3 +1,16 @@
+
+
About the API
There is, at the moment, a very rudimentary API available.