Skip to content

Instantly share code, notes, and snippets.

@jscmidt
Last active September 3, 2021 10:45
Show Gist options
  • Save jscmidt/adee935961d8581717c95fe2d904722f to your computer and use it in GitHub Desktop.
Save jscmidt/adee935961d8581717c95fe2d904722f to your computer and use it in GitHub Desktop.
iOS-Widgets for Piwigo using the Scriptable-App.
// ----- Begin of Configuration -----
// URL of the Piwigo-Server
const piwigoBaseUrl = "https://example.com/piwigo";
// Username and password for Piwigo-API login
const piwigoUsername = "";
const piwigoPassword = "";
// use the category-id to choose the ramdom photo from the specified category, or use "" if the random photo should be selected from all categories
const imageCategory = "";
// the size in which the images are downloded from Piwigo. Allowed sizes: 'square', 'thumb', '2small', 'xsmall', 'small', 'medium', 'large', 'xlarge', 'xxlarge'
const imageSize = "small";
// if 0: ramdom image is selected from all images. if > 0: random image is selected from the n newest images, where n is defined by useRecent
const useRecent = 50;
// size of the widget preview, allowed sizes: 0, 1, 2
const widgetSize = 0;
// ----- End of Configuration -----
checkParams(imageCategory, imageSize, useRecent);
await piwigoLogin(piwigoUsername, piwigoPassword, piwigoBaseUrl);
const data = await piwigoGetUrls(piwigoBaseUrl, imageCategory, imageSize, useRecent);
await piwigoLogout(piwigoBaseUrl);
const img = await imageRequest(data.imageUrl);
let widget = createWidget(img, data.pageUrl);
Script.setWidget(widget);
Script.complete();
switch(widgetSize){
case 0: widget.presentSmall(); break;
case 1: widget.presentMedium(); break;
case 2: widget.presentLarge(); break;
}
function createWidget(img, url) {
let widget = new ListWidget();
widget.backgroundColor = new Color("#1A1A1A");
widget.url = url;
widget.centerAlignContent;
widget.backgroundImage = img;
return widget;
}
async function imageRequest(url){
const imgRequest = await new Request(url);
const img = await imgRequest.loadImage();
console.log("Successfully got image from Piwigo");
return img;
}
async function piwigoLogin(username, password, url){
url = url + "/ws.php?format=json&method=pwg.session.login";
let req = new Request(url);
req.method = 'post';
let body = "username=" + username + "&password=" + password;
req.body = body;
let result = await req.loadJSON();
if(result.stat != "ok") throw "Error logging in to Piwigo";
console.log("Successfully logged in to Piwigo");
}
async function piwigoLogout(url){
url = url + "/ws.php?format=json&method=pwg.session.logout";
let req = new Request(url);
let result = await req.loadJSON();
if(result.stat != "ok") throw "Error logging out to Piwigo";
console.log("Successfully logged out to Piwigo");
}
async function piwigoGetUrls(url, category, size, recent){
if(Number(recent) == 0){
url = url + "/ws.php?format=json&method=pwg.categories.getImages&cat_id="+ category.toString() + "&recursive=true&per_page=1&page=1&order=random";
}
else{
url = url + "/ws.php?format=json&method=pwg.categories.getImages&cat_id="+ category.toString() + "&recursive=true&per_page=" + recent.toString() + "&page=0&order=date_available%20desc";
}
let req = new Request(url);
let result = await req.loadJSON();
if(result.stat != "ok") throw "Error getting image URl";
let imagesCount = result.result.images.length;
let image = result.result.images[getRandomInt(0, imagesCount - 1)];
let data = new Object();
data.imageUrl = image['derivatives'][size]['url'];
if(image.categories != undefined){
let categories = image.categories;
let categoriesCount = categories.length;
data.pageUrl = categories[getRandomInt(0, categoriesCount - 1)]['page_url'];
}
else{
data.pageUrl = image.page_url;
}
console.log("Successfully got urls from piwigo");
return(data);
}
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function checkParams(category, size, recent){
const allowedSizes = ['square', 'thumb', '2small', 'xsmall', 'small', 'medium', 'large', 'xlarge', 'xxlarge'];
if(!allowedSizes.includes(size)) throw "Image Size not allowed";
if(isNaN(Number(category))) throw "Category ID has to be a number";
if(isNaN(Number(recent))) throw "useRecent has to be a number";
}
// ----- Begin of Piwigo Configuration -----
// URL of the Piwigo-Server
const piwigoBaseUrl = "https://example.com/piwigo";
// Username and password to access the Piwigo-API
const piwigoUsername = "";
const piwigoPassword = "";
// ----- End of Piwigo Configuration -----
//--------------------------------------------------------------------------------------
// URL that is opened in Safari when tipping the widget:
let widgetURL = "https://example.com/piwigo/";
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
// Should the values have borders?
// 0: No, 1-4: width of the borders
let Border = 3;
// How strong should the opacity of the borders be? (Value between 0.1 and 1.0)
let BorderStaerke = 0.6;
//--------------------------------------------------------------------------------------
// How should Namen, Footnotes and the values be arranged in their areas?
// 0: left-justified, 1: centered
let Alignment = 1;
//--------------------------------------------------------------------------------------
// Title of the Widget
let Titel = "Piwigo";
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
// in the following the colors of the widget can be customized
// e.g. white: "FFFFFF", black: "000000"; A good website for this: https://htmlcolorcodes.com/
//--------------------------------------------------------------------------------------
// default text color, for title, footnotes etc.:
let TextColor = "FFFFFF";
//--------------------------------------------------------------------------------------
// type of the widget background, 0: single-color, 1: color-gradient
let BackgroundType = 1;
//--------------------------------------------------------------------------------------
// color with single-color background:
let BackgroundColor = "000000";
//--------------------------------------------------------------------------------------
// colors with color-gradient background:
let BackgroundGradient1 = "000000";
let BackgroundGradient2 = "202020";
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
// Allgemeine Widget-Einstellungen
let widget = new ListWidget();
widget.url = widgetURL;
widget.setPadding(20, 20, 20, 20);
const startTime = new Date();
await piwigoLogin(piwigoUsername, piwigoPassword, piwigoBaseUrl);
data = await piwigoGetData(piwigoBaseUrl);
await piwigoLogout(piwigoBaseUrl);
const endTime = new Date();
const timeDiff = Math.round((endTime - startTime)/3);
// aktuellen Timestamp erstellen und formatieren
let date = new Date();
let df = new DateFormatter();
df.dateFormat = "HH:mm";
let timestamp = (df.string(date));
// vStackV ist vertikal, vStack0 ist ist Überschrift, vStack1 ist Zeile 1, vStack2 ist Zeile 2
let vStackV = widget.addStack();
vStackV.layoutVertically();
let vStack0 = vStackV.addStack();
vStack0.layoutHorizontally();
vStack0.centerAlignContent();
vStackV.addSpacer();
let vStack1 = vStackV.addStack();
vStack1.layoutHorizontally();
vStackV.addSpacer();
let vStack2 = vStackV.addStack();
vStack2.layoutHorizontally();
// Überschrift des Widgets
AlignStack(vStack0, 0);
if(Alignment == 1){
vStack0.addText("");
}
let header = vStack0.addText(Titel);
header.font = Font.mediumSystemFont(12);
header.textColor = new Color(TextColor);
AlignStack(vStack0, 1);
// Inhalt des Widgets
// Hintergrund oder Verlauf festlegen
if(BackgroundType == 0){
widget.backgroundColor = new Color(BackgroundColor);
}
else{
const gradient = new LinearGradient()
gradient.locations = [0, 1]
gradient.colors = [ new Color(BackgroundGradient1), new Color(BackgroundGradient2) ]
widget.backgroundGradient = gradient
}
// Daten aufbereiten, berechnen und auf Widget darstellen
vStack1.addSpacer();
addDataView(vStack1, data.nb_elements.toString(), "", "Fotos", "in " + data.nb_categories.toString() + " Alben", TextColor);
vStack1.addSpacer();
vStack2.addSpacer();
addDataView(vStack2, timeDiff.toString() + "ms", defineColorNegative(500, 1000, timeDiff), "Dauer", "je Request", TextColor);
vStack2.addSpacer();
Script.setWidget(widget);
Script.complete();
widget.presentSmall();
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
// zentriert/linksbündigt/rechtbündigt Text
function AlignStack(stack, pos){
if(Alignment == 1 || (Alignment == 0 && pos == 1)){
stack.addSpacer();
}
}
// legt ein neues Datenstack an
function addDataView(widget, data, color, name, foot, BorderColor, img){
let viewStack = widget.addStack();
viewStack.layoutVertically();
viewStack.cornerRadius = 5;
if(BorderColor != 0){
viewStack.size = new Size(97, 47);
viewStack.borderWidth = Border;
viewStack.borderColor = new Color(BorderColor, BorderStaerke);
viewStack.setPadding(5, 5, 5, 3);
}
let labelStack = viewStack.addStack();
AlignStack(labelStack, 0);
let label = labelStack.addText(name);
label.font = Font.mediumSystemFont(12);
label.textColor = new Color(TextColor);
AlignStack(labelStack, 1);
let footnoteStack = viewStack.addStack();
AlignStack(footnoteStack, 0);
let footnote = footnoteStack.addText(foot);
footnote.font = Font.mediumSystemFont(8);
footnote.textColor = new Color(TextColor);
AlignStack(footnoteStack, 1);
let valueStack = viewStack.addStack();
AlignStack(valueStack, 0);
let value = valueStack.addText(data);
value.font = Font.mediumSystemFont(18);
value.textColor = colorForString(color);
AlignStack(valueStack, 1);
}
//Gibt das entsprechende Color-Objekt zurück
function colorForString(colorString){
if (colorString == "red") {
return Color.red();
}
if (colorString == "yellow") {
return Color.yellow();
}
if (colorString == "green") {
return Color.green();
}
return (new Color(TextColor));
}
// Legt Farbe fest
function defineColorNegative(TreshYellow, TreshRed, value){
if (value >= TreshRed){
return("red");
}
else if (value >= TreshYellow){
return("yellow");
}
else{
return("green");
}
}
async function piwigoLogin(username, password, url){
url = url + "/ws.php?format=json&method=pwg.session.login";
let req = new Request(url);
req.method = 'post';
let body = "username=" + username + "&password=" + password;
req.body = body;
let result = await req.loadJSON();
if(result.stat != "ok") throw "Error logging in to Piwigo";
console.log("Successfully logged in to Piwigo");
}
async function piwigoLogout(url){
url = url + "/ws.php?format=json&method=pwg.session.logout";
let req = new Request(url);
let result = await req.loadJSON();
if(result.stat != "ok") throw "Error logging out to Piwigo";
console.log("Successfully logged out to Piwigo");
}
async function piwigoGetData(url){
url = url + "/ws.php?format=json&method=pwg.getInfos";
let req = new Request(url);
let result = await req.loadJSON();
if(result.stat != "ok") throw "Error getting Piwigo data";
let data = new Object();
data.nb_elements = result.result.infos[1].value;
data.nb_categories = result.result.infos[2].value;
console.log("Successfully got data from piwigo");
return(data);
}
@jscmidt
Copy link
Author

jscmidt commented Sep 3, 2021

Mit der App Scriptable habe ich zwei iOS-Widgets für Piwigo gebaut.

Das erste Widget ist eher für Administratoren einer Piwigo-Seite gedacht, es zeigt die Anzahl an Fotos und Alben in Piwigo an sowie wie lange die drei API-Requests zum Holen dieser Daten gebraucht haben. Das ist zwar sehr ungenau, gibt mir aber einen schnellen Überblick über die aktuelle Performance des Servers. Aber auch andere Sachen wie z.B. eine schlechte Internetverbindung können natürlich die Zeit beeinflussen…
Verwendet wird hier die kleinste (quadratische) Widget-Größe.
C0CB4F17-2171-40ED-B7A0-6E972F2F1EAE

Das zweite Widget ist vor allem für die Anwender gedacht. Es kann a) ein zufälliges Bild der Piwigo-Instanz anzeigen. Wenn gewünscht können die Zufallsbilder auf ein Album begrenzt werden.
Alternativ kann das Widget auch b) ein zufälliges Bild aus den letzten x hochgeladen Bilder anzeigen, wobei x selbst festgelegt werden kann. Auch hier kann das ganze wieder auf ein Album begrenzt werden.
Bei diesem Widget können alle Widget-Größen verwendet werden, die Bilder werden immer so zugeschnitten dass sie das Widget komplett ausfüllen.

Insbesondere bei der Logik der API-Zugriffe habe ich mich an diesem Projekt orientiert.
Vielen Dank für die hier gemachte Vorarbeit, ohne die ich das sicherlich nicht so schnell zum laufen bekommen hätte.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment