2 // AGPL-3.0 License (see LICENSE)
4 use sailfish::Template;
5 use std::collections::HashMap;
6 use std::sync::{Arc, Mutex};
8 use crate::site::helper::Helper;
9 use crate::site::screenshot::Screenshot;
11 #[derive(Clone, Debug)]
12 pub struct ScreenshotsInfo {
17 impl ScreenshotsInfo {
18 pub fn new() -> Self {
26 pub struct ScreenshotsShared {
27 state: Mutex<ScreenshotsState>,
30 impl ScreenshotsShared {
31 pub fn new() -> Self {
33 state: Mutex::new(ScreenshotsState::new()),
37 pub fn shared(self) -> Arc<Self> {
41 pub fn get_screenshots(&self, num_screenshots: usize, key: &str) -> Vec<Screenshot> {
42 let lock = self.state.lock().unwrap();
43 let mut screenshots = Vec::new();
45 if let Some(value) = lock.screenshots.get(key) {
46 for i in 0..num_screenshots {
47 if let Some(screenshot) = value.get(i) {
48 screenshots.push(screenshot.clone());
52 panic!("Did not find any screenshots for key: {}", key);
60 #[template(path = "screenshots.stpl")]
61 #[derive(Clone, Debug)]
62 struct ScreenshotsState {
63 screenshots: HashMap<String, Vec<Screenshot>>,
64 screenshot_urls: HashMap<String, String>,
69 impl ScreenshotsState {
70 pub fn new() -> Self {
72 screenshots: HashMap::new(),
73 screenshot_urls: HashMap::new(),
80 pub async fn generate_screenshots(shared: Arc<ScreenshotsShared>) {
81 parse_files(shared.clone(), "screenshots").await;
84 async fn parse_files(shared: Arc<ScreenshotsShared>, base_dir: &str) {
85 let mut reader = tokio::fs::read_dir(base_dir).await.unwrap();
87 if let Some(f) = reader.next_entry().await.unwrap() {
88 let contents = tokio::fs::read_to_string(f.path()).await.unwrap();
90 parse_file(shared.clone(), contents);
91 update_screenshots(shared.clone());
92 generate(shared.clone());
99 fn parse_file(shared: Arc<ScreenshotsShared>, contents: String) {
100 let mut screenshots_info = ScreenshotsInfo::new();
101 let mut screenshot = Screenshot::new();
103 for line in contents.lines() {
108 let v: Vec<&str> = line.splitn(2, ':').collect();
109 assert_eq!(v.len(), 2);
111 if let Some(key) = v.get(0) {
112 if *key == "screenshots_title" {
113 if let Some(value) = v.get(1) {
114 screenshots_info.title = String::from(value.trim());
116 panic!("Unable to parse field: 'screenshots_title'.");
118 } else if *key == "screenshots_url" {
119 if let Some(value) = v.get(1) {
120 screenshots_info.url = String::from(value.trim());
122 panic!("Unable to parse field: 'screenshots_url'.");
124 } else if *key == "title" {
125 if let Some(value) = v.get(1) {
126 screenshot.title = String::from(value.trim());
128 panic!("Unable to parse field: 'title'.");
130 } else if *key == "image_min" {
131 if let Some(value) = v.get(1) {
132 screenshot.image_min = String::from(value.trim());
134 panic!("Unable to parse field: 'image_min'.");
136 } else if *key == "image_big" {
137 if let Some(value) = v.get(1) {
138 screenshot.image_big = String::from(value.trim());
140 panic!("Unable to parse field: 'image_big'.");
142 } else if *key == "url" {
143 if let Some(value) = v.get(1) {
144 screenshot.url = String::from(value.trim());
146 panic!("Unable to parse field: 'url'.");
151 // all info needed for one screenshot:
152 if screenshot.title.len() > 0
153 && screenshot.image_min.len() > 0
154 && screenshot.image_big.len() > 0
155 && screenshot.url.len() > 0
156 && screenshots_info.title.len() > 0
157 && screenshots_info.url.len() > 0
159 screenshot.screenshots_title = screenshots_info.title.clone();
160 screenshot.screenshots_url = screenshots_info.url.clone();
163 let mut lock = shared.state.lock().unwrap();
165 if let Some(value) = lock.screenshots.get_mut(&screenshots_info.title) {
166 value.push(screenshot);
169 .insert(screenshots_info.title.clone(), screenshots_info.url.clone());
171 .insert(screenshots_info.title.clone(), vec![screenshot]);
175 // reset for new screenshot:
176 screenshot = Screenshot::new();
180 let mut lock = shared.state.lock().unwrap();
182 lock.title = screenshots_info.title.clone();
183 lock.url = screenshots_info.url.clone();
186 fn update_screenshots(shared: Arc<ScreenshotsShared>) {
187 // TODO: this could be done more efficiently:
188 // (need screenshots for each screenshot as they are linked below)
189 let mut lock = shared.state.lock().unwrap();
190 for (_key, value) in &mut lock.screenshots {
191 let v = value.clone();
193 s.screenshots = v.clone();
198 fn generate(shared: Arc<ScreenshotsShared>) {
199 let lock = shared.state.lock().unwrap();
201 for (_key, screenshots) in &lock.screenshots {
202 // create output dir needed:
203 Helper::create_dir_all(&Helper::get_output_dir().join(&lock.url));
205 // write page to disk:
206 Helper::write_file_sync(
207 &Helper::get_output_dir().join(&lock.url).join("index.html"),
208 &lock.render().unwrap().as_bytes(),
212 // generate all individual screenshot pages:
213 for screenshot in screenshots {
214 screenshot.generate();