⚡ use wikimedia Potd as HTML wallpaper
[Commons:Picture of the day - Wikimedia Commons](https://commons.wikimedia.org/wiki/Commons:Picture_of_the_day)
This commit is contained in:
parent
b260e411f0
commit
352632e5a5
@ -1,26 +1,27 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>Bing Image Of The Day</title>
|
<title>Bing Image Of The Day</title>
|
||||||
<style>
|
<style>
|
||||||
body{ display: flex; flex-flow: row nowrap;
|
body{ display: flex; flex-flow: row nowrap;
|
||||||
width: 100vw; height: 100vh; overflow: hidden; margin: 0;
|
width: 100vw; height: 100vh; overflow: hidden; margin: 0;
|
||||||
}
|
}
|
||||||
div{ position: relative; flex: 1; }
|
div{ position: relative; flex: 1; }
|
||||||
img{ height: 100%; width: 100%; object-fit: contain; }
|
img{ height: 100%; width: 100%; object-fit: cover; }
|
||||||
.detail{ position: absolute; bottom: 0; left: 0; padding: .5rem 1rem;
|
.detail{ position: absolute; bottom: 0; left: 0; padding: .5rem 1rem;
|
||||||
text-align: center; background: rgba(0, 0, 0, .35); color: whitesmoke; }
|
max-width: 35ch;
|
||||||
.prev .detail{ left: initial; right: 0; }
|
text-align: center; background: rgba(0, 0, 0, .35); color: whitesmoke; }
|
||||||
@media screen and (max-aspect-ratio: 16/9){
|
.prev .detail{ left: initial; right: 0; }
|
||||||
.prev{display: none;}
|
@media screen and (max-aspect-ratio: 16/9){
|
||||||
}
|
.prev{display: none;}
|
||||||
</style>
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="now"> <img src="now.jpg"> <div class="detail">::now::</div> </div>
|
<div class="now"> <img src="now.jpg"> <div class="detail">::now::</div> </div>
|
||||||
<div class="prev"> <img src="prev.jpg"> <div class="detail">::prev::</div> </div>
|
<div class="prev"> <img src="prev.jpg"> <div class="detail">::prev::</div> </div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
6
bin/§wallpaper_BIOTD
Executable file
6
bin/§wallpaper_BIOTD
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
nm-online -x -q && \
|
||||||
|
node "/home/jaandrle/.nvm/versions/node/$(node --version)/bin/nodejsscript" /home/jaandrle/bin/§wallpaper_WCPOTD.mjs pull && \
|
||||||
|
cd "/home/jaandrle/Obrázky/Bing Image Of The Day" && \
|
||||||
|
qdbus org.kde.plasmashell /PlasmaShell org.kde.PlasmaShell.evaluateScript 'const d= desktops().filter(d=> d.wallpaperPlugin==="de.unkn0wn.htmlwallpaper")[0];const url= (i= "")=> `file:///home/jaandrle/Obr%C3%A1zky/Bing%20Image%20Of%20The%20Day/index${i}.html`;d.currentConfigGroup= Array("Wallpaper", "de.unkn0wn.htmlwallpaper","General");d.writeConfig("DisplayPage", url("1"));d.writeConfig("DisplayPage", url());'
|
||||||
|
# convert now.jpg prev.jpg +append horizontally.jpg
|
113
bin/§wallpaper_WCPOTD.mjs
Executable file
113
bin/§wallpaper_WCPOTD.mjs
Executable file
@ -0,0 +1,113 @@
|
|||||||
|
#!/usr/bin/env nodejsscript
|
||||||
|
/* jshint esversion: 11,-W097, -W040, module: true, node: true, expr: true, undef: true *//* global echo, $, pipe, s, fetch, cyclicLoop */
|
||||||
|
const img_params= "?width=1920";
|
||||||
|
const url_api= "https://commons.wikimedia.org/w/api.php";
|
||||||
|
const url_image= "https://commons.wikimedia.org/wiki/Special:FilePath/";
|
||||||
|
|
||||||
|
import { join } from "node:path";
|
||||||
|
const path_home= $.xdg.home`Obrázky/Bing Image Of The Day/`;
|
||||||
|
const path_info= join(path_home, "images.json");
|
||||||
|
|
||||||
|
$.api()
|
||||||
|
.version("2024-05-12")
|
||||||
|
.command("pull", "Pull new/today image(s)")
|
||||||
|
.action(async function pull(){
|
||||||
|
const images= {
|
||||||
|
now: await getImagePath(0),
|
||||||
|
prev: await getImagePath(-1)
|
||||||
|
};
|
||||||
|
const paths= await downloadImages(images);
|
||||||
|
updateHTML(images);
|
||||||
|
convert(paths);
|
||||||
|
pipe(
|
||||||
|
images=> Object.entries(images)
|
||||||
|
.reduce((acc, [ key, { caption } ])=>
|
||||||
|
Reflect.set(acc, key, caption) && acc,
|
||||||
|
{}),
|
||||||
|
images=> JSON.stringify(images, null, "\t"),
|
||||||
|
s.echo
|
||||||
|
)(images).to(path_info);
|
||||||
|
$.exit(0);
|
||||||
|
})
|
||||||
|
.command("status")
|
||||||
|
.action(function status(){
|
||||||
|
const images= s.cat(path_info).xargs(JSON.parse);
|
||||||
|
const [ stats ]= s.ls("-l", path_info);
|
||||||
|
echo({ timestamp: stats.mtime, ...images });
|
||||||
|
$.exit(0);
|
||||||
|
})
|
||||||
|
.parse();
|
||||||
|
/** @typedef {{ url: string, caption: string }} T_response */
|
||||||
|
/** @typedef {Record<"now"|"prev",T_response>} T_images */
|
||||||
|
/** @param {Record<"now"|"prev",string>} paths */
|
||||||
|
function convert(paths){
|
||||||
|
const resize_to= "1920x1080";
|
||||||
|
|
||||||
|
paths= Object.values(paths);
|
||||||
|
const target= join(path_home, "horizontally.jpg");
|
||||||
|
const params= `-resize ${resize_to}^ -gravity center -extent ${resize_to}`.split(" ");
|
||||||
|
s.run`convert ${paths} ${params} +append ${target}`;
|
||||||
|
}
|
||||||
|
import { writeFileSync } from "node:fs";
|
||||||
|
/** @param {T_images} images */
|
||||||
|
function updateHTML(images){
|
||||||
|
let template= s.cat(join(path_home, "index_template.html")).trim();
|
||||||
|
for(const [ key, image ] of Object.entries(images))
|
||||||
|
template= template.replace(`::${key}::`, image.caption);
|
||||||
|
s.echo(template).to(join(path_home, "index.html"));
|
||||||
|
}
|
||||||
|
/** @param {T_images} images */
|
||||||
|
async function downloadImages(images){
|
||||||
|
const out= {};
|
||||||
|
for(const [ key, image ] of Object.entries(images))
|
||||||
|
out[key]= await downloadImage(image, key);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
async function getImagePath(shift= 0){
|
||||||
|
const date= dateISO(shift);
|
||||||
|
const { expandtemplates: { wikitext: filepath } }= await fetchGet({
|
||||||
|
action: "expandtemplates",
|
||||||
|
prop: "wikitext",
|
||||||
|
text: `{{Potd/${date}}}`,
|
||||||
|
});
|
||||||
|
const caption= pipe(
|
||||||
|
response=> response.expandtemplates.wikitext,
|
||||||
|
caption=> caption.replace(/\[\[.*?\]\]/g, m=> m.slice(2, -2).split("|").reverse()[0]),
|
||||||
|
caption=> caption.replace(/''(.*?)''/g, "„$1”"),
|
||||||
|
)(await fetchGet({
|
||||||
|
action: "expandtemplates",
|
||||||
|
prop: "wikitext",
|
||||||
|
text: `{{Potd/${date} (cs)}}`,
|
||||||
|
}));
|
||||||
|
/* TODO?
|
||||||
|
* action: 'query',
|
||||||
|
* prop: 'imageinfo',
|
||||||
|
* iiprop: 'extmetadata',
|
||||||
|
* iiextmetadatafilter: 'LicenseShortName|Artist|LicenseUrl',
|
||||||
|
* titles: `Image:${ filename }`
|
||||||
|
*
|
||||||
|
* res.data.query.pages[0].imageinfo[0].extmetadata
|
||||||
|
* */
|
||||||
|
return {
|
||||||
|
caption: caption,
|
||||||
|
url: url_image+encodeURI(filepath+img_params)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param {T_response} image @param {"prev"|"now"} type */
|
||||||
|
async function downloadImage({ url }, type){
|
||||||
|
const filename= join(path_home, `${type}.jpg`);
|
||||||
|
const response= await fetch(url);
|
||||||
|
const buffer= await response.arrayBuffer();
|
||||||
|
writeFileSync(filename, Buffer.from(buffer));
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
function dateISO(shift= 0){
|
||||||
|
const d= new Date();
|
||||||
|
d.setDate(d.getDate()+shift);
|
||||||
|
return d.toISOString().substring(0, 10);
|
||||||
|
}
|
||||||
|
function fetchGet(params){
|
||||||
|
if(!params.format) params.format= "json";
|
||||||
|
return fetch(url_api+"?"+(new URLSearchParams(params)).toString(), { method: "GET" }).then(res=> res.json());
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user