I love drinking coffee. I'm not a coffee connoisseur or anything, probably the opposite, but I enjoy drinking coffee all the time.
Here are a few things around this mundane habit:
Dark roast is my favorite. I know it has less caffeine, but I like the strong flavor. I found that in the black oily beans of Starbucks' Dark Roast. For a little bit more than a year I allowed myself the luxury of an Amazon subscription for the Starbucks Dark Roast beans. A subscription because it was a bit cheaper and I had no other way to get the coffee. But it was still costly. 30+ EUR per 1kg if I remember right. I ditched the subscription after I finally found a European option in Kimbo Espresso Napoletano and Barzini extra dark and I found in coffeehenk a new supplier. I'm not sure if it's a 1:1 replacement, but I already got used to it.
Talking about caffeine. I think I have a high tolerance. I can drink it late in the evening and I fall asleep just fine. And yes, light roasts have more caffeine than dark roasts, but the other day I ate a whole bag of caffeinated gummies and drank a can of koawach (kokoa with guarana) and I didn't feel anything. Not sure if I should be bummed out, but this way I can enjoy more coffee.
I don't know when, but at some point I stopped drinking coffee with cream and sugar. I think it was when I stopped smoking, over a decade ago. Sugar for obvious reasons. Cream, because I the powdered stuff was just too artificial, even if I liked it more than putting real cream or milk in. Black coffee it is since then.
A weird habit I have is to not drink the whole mug. I leave a third and it gets cold. I don't know why. It's a waste. But I'm drinking some of the cold coffee and I don't dislike it. I mean there is iced coffee. And I heard once, coffee is of good quality, if you can drink it cold.
The worst coffee I've ever had was on an Amtrak train. It was weak, kind of sour and just an insult.
For a long time I made the coffee by putting the ground coffee into a mug and pouring boiling water over it and then had to deal with coffee grounds between my teeth or a burnt tongue. I used a French press for the longest time until I got a Bialetti Espresso Maker. That changed everything. I love that. Not the tiny ones for Espresso, but the bigger ones where I can make coffee for one mug.
Also I ended up with a low-cost De'Longhi KG 89 coffee grinder that I had to mod for a finer grind. Works pretty well!
I think that's all I have to share about coffee.
]]>For a few years, I had been thinking about getting an Insta360 X2 Action Cam to document places (I'm not much of an action guy ;-)). With the Insta360 X5 on the horizon, the older X2 models became a bit more affordable, so I got one.
After understanding the different ways and modes to take pictures, I ended up just using the 360 mode and rendering any other formats afterward in the app, if needed.
The Insta360 app is a camera remote control, photo gallery, editor, and social network in one.
In the editor, I can do much more with videos than with just photos. For photos, I can edit colors and blur faces. What I can't do—and that’s a shame—is re-align the horizon, change the center, or remove the tripod. I can put a logo on the tripod at the nadir, but that doesn’t look great.
In photo mode, the camera works like any other digital camera with different modes:
It can save RAW .dng files for later editing, but here comes the kicker - editing where? In the Insta360 desktop app, I can load the raw file in, move around, apply one image optimizer filter, and that's it. If I want to go "develop" the image in a raw photo editor, I can't reopen the file in the Insta360 app afterward, unless I'm performing some EXIF Voodoo. So there is no clear workflow on how to deal with that. Very unsatisfying!
Editing outside the Insta360 apps is risky, because metadata might get lost and panoramic images are not recognized as what they are. But sometimes it's necessary. So here are a few gotchas.
There were Photoshop plugins in the past, and there is open-source software that deals with panoramic images. But for desktop, Affinity Photo was the best and easiest software to edit projected 360 images. That means I can navigate to the nadir and retouch it. It’s not a shot in the dark editing the distorted bottom part of the image. In Affinity Photo, I can also realign and recenter the image. The software is affordable and recommended as a Photoshop alternative.
On mobile, I found TouchRetouch a good app that loads a 360° image and lets you remove the tripod with the brush tool. The AI removal isn't working so well in this regard. Unfortunately, with these apps, you have to subscribe—and this is definitely not an app I’d use every day, so a subscription isn’t justified. You can retouch one image a day for free, but come on. I ended up (nicely) complaining to the support, and they were kind enough to send me a discount code. So the price went down from a 60 EUR/year subscription to 15 EUR. Thanks!
To recenter objects, I didn’t find anything viable. There is ReShoot 360, but the once free app is now expensive, and I wouldn’t use all the features. I found edit360 to be the perfect tool, but for some reason, it wasn’t available in the German App Store. Apparently, I bought it at some point in the past, so I was still able to access it.
For desktop, the Exif Fixer app might be helpful.
Another working way if metadata got lost, is by using the almighty EXIFTool and copy the metadata over from the source image.
exiftool -TagsFromFile "F:\DCIM\Camera01\IMG_20250916_151035_00_452.dng" -All:all "IMG_20250916_151035_00_452 - Copy.jpg"
Use FrankBijnen/ExifToolGui: A GUI for ExifTool if you don't want to mess around with the command line.
I think it's good advice to shoot in JPG and RAW because the internal optimization of the photos can be very destructive. I found that out by coming back with a bunch of really bad shots from a place that I wanted to document.
ProjectionType=equirectangular
, UsePanoramaViewer=True
, FullPanoWidth/HeightPixels
, etc. Google GPano spec(This list was compiled by ChatGPT and edited a bit to reflect my experience.)
I edited the DNG in an older Photoshop version, and when I saved the image (as a JPG or DNG), it offered to copy over all metadata, allowing me to reopen the edited file in Insta360 Studio.
![[assets/2025-05-12.360-pano/01-internal-processing.jpg]]
Internally processed by Insta360 camera
![[assets/2025-05-12.360-pano/02-raw.jpg]]
Raw DNG file
![[assets/2025-05-12.360-pano/03-raw-processed.jpg]]
Processed RAW file (some noise removal)
Originally, I wanted to contribute to Google Maps, but for some reason, they limited the options for getting a 360 pano into their maps. It’s still possible through the Insta360 app and other third-party services (which use Google’s Street View Publish API), but officially, they only want video.
Here’s what I found somewhat useful:
Every record collector knows Discogs. It's the de facto standard for cataloging your vinyl collection. But what's even better is that they provide a free API1 to access your collection data. And since I'm already maintaining my collection there, why not use it to display my records on my website?
Getting an API token from Discogs is straightforward:
That's it. No OAuth dance, no complicated app registration. Just a simple token. I like that.
Here's the API endpoint I'm using to fetch my collection:
https://api.discogs.com/users/{username}/collection/folders/{folder_id}/releases?sort_order=desc&sort=added&page=1&per_page=150&token={token}
Replace:
{username}
with your Discogs username{folder_id}
with the folder ID (usually 0
for "All" or 1
for "Uncategorized"){token}
with the token you just generatedThe response gives you everything: cover art, release year, artist info - the whole package.
I'm using this here in my Pico CMS with a simple plugin that can deal with external data and here is my collection of 60s and 70s Southern Gospel records from the Tri-State area of Tennessee, Kentucky and Virginia. I love the music and I love pulling Json from somewhere and turn it into XML (grinning face emoji). Well HTML is some sort of XML, so it's not that far fetch()
ed, isn't it?
Sorry for that cringey end.
]]>Ever googled for "Ip2Country+API+free"? There are a bunch of results2 but as soon as you get on their website and see the Pricing tab, at least I leave the page. Nothing against paid APIs, but it's either pay as you go or no.
Since this isn't the most difficult service those API providers often have a free tier and I guess most of the time it's enough, but then you rely on someone's else infrastructure, and we don't want that either (and by we, I mean the royal "we").
Anyway, for a project, I needed to resolve an IP address to a country. Since I was already running a self-hosted instance of Matomo on the server I remembered setting up the free MaxMind geolocation database.
Matomo either uses the free external service https://db-ip.com or it downloads the MaxMind Lite database to your server. And since we don't want to depend on someone else's infrastructure, a (self-updating) copy of the geolocation database is perfect.
In Matomo under Admin > System > Geolocation | Location Provider select DBIP / GeoIP 2 (Php). On the same page, setup automatic updates of geolocation databases. Use db-ip.com for out an of the box solution, or setup MaxMind as described.
Then under Admin > Personal > Security | Auth tokens create a new token. Uncheck the Only allow secure requests since you want to use the token as GET parameter.
Copy the token and use it in the following API call with the parameter auth_token
:
https://your-domain.com/index.php?module=API&method=UserCountry.getLocationFromIP&ip={IPv4|Pv6}&format=JSON&token_auth={TOKEN}
That's it.
Here is the result of the public Matomo demo instance (therefore no token used): https://demo.matomo.cloud/index.php?module=API&method=UserCountry.getLocationFromIP&ip=91.8.207.90&format=json
{
continent_name: "Europe",
continent_code: "EU",
country_code: "DE",
country_name: "Germany",
city_name: "Hamburg",
lat: 53.483,
long: 9.852,
postal_code: "21147",
region_code: "HH",
region_name: "Free and Hanseatic City of Hamburg",
ip: "91.8.207.90"
}
]]>Since the move from Tumblr and my new blogging aspirations meant to deal more with WordPress, I have a few more things to share.
My goal was
I first thought I should use Wordpress Jetpack Subscriber because it came with the whole "content protection, registration, and login as well as notification" jazz. But I figured, for a semi private blog I didn't want to ditch tumblr just to be depended on Wordpress servers (same thing, I know).
What speaks for the Jetpack solution, it just works out of the box and looks good. No unstyled forms and elements, no short codes, everything is wired up correctly.
Other membership plugins offer similar things, but often stick out like a sore thumb if you don't get the CSS right. Or the templating is weird.
Anyway, I ditched Jetpack because the subscribers have to go through Wordpress.com, a hard to sell and ahgain, Wordpress is going to change their service if they want and suddenly it's paid only.
For a work project, I used Ultimate Member before, but in order to learn something new, I tried out Simple Membership.
Both offer protected content, login and registration, user management and some paid content stuff (usually in their PRO offering).
Simple Membership did what I wanted in the free version, but I ended up debugging their code, just to find out the registration form can't be overwritten in a child-theme. Odd inconsistency, but it looked like they were improving this old code.
Anyway I wasn't happy and went back to Ultimate Member, since their forms look decent by default and are easier to modify (form builder is included).
The whole admin UI is also a bit nicer and easier to follow.
The trick is to create a WordPress category “Private” for example and protect this category. This is the way it works in both plugins. This way, I was able to add posts to the “private” category in bulk!
Notification Master is offering that. It works fine for email.
Advanced Query Loop extends the WP Query Loop component and offers more ways to filter content.
I have to say, I was a WP hater in the past, but despite some annoying things (WP drama 2024, the constant upselling of extensions etc.) I really like it to quickly set up a complex webapp/website that you can't come up with, with Kirby or Statamic or Craft CMS (who like to take some of WP's share). If the out-of-the-box stuff is good enough, go for it. Damn, even the native template builder is pretty good, once I understood it. So, not the old PHP blog anymore, yet all there is needed is a simple shared PHP 8.x.
]]>I'm a former Wordpress hater, but it's undeniable how fast one can setup a working website. And especially a blog (even if nobody uses that anymore).
First, I love Tumblr. I love the tech. It's still the easiest and most flexible network to post. Photo-galleries, media, text. It just works, and it's not a walled garden, but a public blog/website if you want to.
What I don't care about is the community and the ads are annoying, but more so the fact that I don't want my private travel blog being on there. My travel blog that only two people cared read, maybe just one that managed to bookmark the site.
Anyway, here is what I learned about how to importing a tumblr blog worth of 12 years of traveling the US and Europe.
If you google for a tumblr to Wordpress importer you'll get a ton of results talking about this plugin: https://wordpress.org/plugins/wordpress-importer/
It's tried and tested and does what it claims to do. Transfers your Tumblr Blog to Wordpress.
Where it gets tricky is the following:
Tumblr didn't use post titles as a specific field. It's just a formatting, so the list of posts in WP backend looks non-descriptive with all the (no title) posts.
The solution to that was a script in functions.php
that writes the title.
/**
* Automatically set empty post titles using first 13 words of content
*/
function auto_set_empty_titles($post_ID) {
// Get the post
$post = get_post($post_ID);
// Only proceed if the title is empty and we have content
if (empty(trim($post->post_title)) && !empty($post->post_content)) {
// Strip any HTML tags and shortcodes
$content = wp_strip_all_tags($post->post_content);
$content = strip_shortcodes($content);
// Get first 13 words
$words = explode(' ', $content);
$first_13_words = array_slice($words, 0, 13);
$new_title = implode(' ', $first_13_words);
// Add ellipsis if content was truncated
if (count($words) > 13) {
$new_title .= '...';
}
// Update the post title
wp_update_post(array(
'ID' => $post_ID,
'post_title' => $new_title
));
}
}
// Hook the function to run when posts are saved
//add_action('save_post', 'auto_set_empty_titles', 10, 1);
// Optional: Run this once to update all existing posts with empty titles
function update_all_empty_titles() {
$args = array(
'post_type' => 'post',
'posts_per_page' => -1,
'post_status' => 'any',
'title' => ''
);
$posts = get_posts($args);
foreach ($posts as $post) {
auto_set_empty_titles($post->ID);
}
}
//update_all_empty_titles();
Uncomment update_all_empty_titles();
and then reload your page. It took a while and the script pooped (timed) out, but another reload just took care of the rest of the empty title fields.
The script was written by AI, don't @ me if you set your wordpress on fire!
Btw. Chris Coyier made a case for not using post titles.
Over the 12 years, tumblr changed a lot and so did the tech behind. I think from 2019 or so on, they fully embrace the block editor. Not like Gutenberg Blocks, but some sort of WYSIWYG. Before you could write markdown, html or some WYSIWYG html with special tags. It was bad.
Then they invented some weird JSON markup called the Tumblr Neue Post Format - no clue why so complicated, but for some time it wasn't possible to edit a post in the browser, made with the app and vice versa.
What I want to say is, the imported Markup is weird. Earlier post just write in a plain WP [gallery]
short code.
Later galleries are imported as HTML (which is better).
To deal with the [gallery]
short code I found a script here Filter classic WordPress gallery shortcode attributes. This makes the gallery a little bit more presentable.
It still looks ugly, but at least it's not just the cropped thumbnails.
Other gallery pics are just loaded fully one after another. You can go in, convert the classic editor field to blocks, delete a few blocks and convert the images to a WP or Jetpack gallery. But I would do that only to posts that I edit.
/* filter gallery output*/
add_filter( 'shortcode_atts_gallery', 'my_shortcode_atts_gallery', 10, 4 );
function my_shortcode_atts_gallery( $out, $pairs, $atts, $shortcode ) {
if ( ! isset( $atts['columns'] ) ) {
$out['columns'] = 1;
}
if ( ! isset( $atts['size'] ) ) {
$out['size'] = 'full';
}
if ( ! isset( $atts['link'] ) ) {
$out['link'] = 'none';
}
return $out;
}
Alternatively, here's a script to convert plain [gallery]
shortcodes to tiled Jetpack galleries.
Check the box under Settings > Media > Tiled Galleries and if they appear too small (500px by default) set the content width of the template. See https://jetpack.com/support/jetpack-blocks/tiled-galleries/
// twentytwentyfive template uses a content width of 645px
if ( ! isset( $content_width ) ) {
$content_width = 645;
}
/* filter gallery output*/
add_filter( 'shortcode_atts_gallery', 'my_shortcode_atts_gallery', 10, 4 );
function my_shortcode_atts_gallery( $out, $pairs, $atts, $shortcode ) {
if ( ! isset( $atts['columns'] ) ) {
$out['columns'] = 3;
}
if ( ! isset( $atts['size'] ) ) {
$out['size'] = 'full';
}
if ( ! isset( $atts['link'] ) ) {
$out['link'] = 'file';
}
if ( ! isset( $atts['type'] ) ) {
$out['type'] = 'rectangular';
}
return $out;
}
Another option to deal with plain [gallery]
tags would be to do a YOLO style search & replace directly in the database.
UPDATE wp_posts SET post_content = REPLACE(post_content, '[gallery]', '[gallery link="file" size="large" type="rectangular"]') where post_content LIKE '%[gallery]%' and post_status = 'publish'
Don't @ me if you messed up something.
Also, this way you can't convert the gallery in the Classic block to a Gutenberg gallery block.
Some images were uploaded to my WordPress, others (newer ones?) were hot-linked to the tumblr cdn.
To download all the externally linked images I tried out two plugins:
Download External Images In Posts – WordPress plugin | WordPress.org this one downloads all images in a subfolder of the media library and you can't see them there.
Auto Upload Images – WordPress plugin | WordPress.org and this one does the same, just that images are supposed to be available in the media library. I'm not sure if it worked, since the plugin wasn't tested on newer WordPress versions.
It's not as straightforward as the plugin is trying to sell itself. But's it's possible to transfer the Tumblr blog to a self-hosted WordPress instance.
Main reason was to have some sort of subscriber(my mom)-based travel blog, so my data is not public to anyone. That level of control war not possible in Tumblr.
]]>See my personal motivation for moving away from Flickr to self-hosted Piwigo at the end of the page. Here are a few points to outline what to expect from Piwigo:
That should be straightforward. It's old-timey FTP deployment, either by one php script or by uploading the package. It's described on their get-started page.
Once the thing is running, and you uploaded a few pictures to check it out you might think, “How can I get my photos from Flickr into Piwigo, and how do I make it look at least a bit prettier?”
The answer is a bunch of plugins!
This provides access to a few files you might want to change, mainly the config file.
Here I set the following value to suppress PHP notices or warnings in case a plugin doesn't like the latest PHP version (8.2 in my case)
<?php
$conf['show_php_errors'] = E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_WARNING;
Other config settings can be discovered in the default config file.
For this plugin to work, I needed the PHP error suppression because one lib in the plugin is not compatible with PHP 8.2 (see the GitHub issue)
The import was relatively straightforward.
Now you should have a working self-hosted photo gallery that you can browse in the frontend. And there you see: it looks dated af and what are these URLs /index.php?/category/album-42
?
Add the following to your config file as described before:
<?php
$conf['show_php_errors'] = E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_WARNING;
$conf['question_mark_in_urls'] = false;
$conf['php_extension_in_urls'] = false;
$conf['category_url_style'] = 'id-name';
$conf['picture_url_style'] = 'file';
?>
And also place a .htaccess
file into the root and add this:
AcceptPathInfo On
Options +MultiViews
Make sure you have no index.html or index.htm in your root, only index.php!
Check to see if your public gallery works!
Bootstrap Darkroom can be installed and setup from the backend. It's the most modern looking theme. Here are some screenshots:
1. Install it via the “Add a new theme” tab: 2. Activate and set it as the default, then configure the theme.
3. Select a color theme you like.
4. Play with the settings; here are mine as a reference:
That should make the page look like this:
For the secondary zoom into pictures via PhotoSwipe to work, set your image sizes as follows:
Go to Photo sizes and “show details”
Change the "XXL - huge" to something larger than the default value.
Then you can do the following:
Set full-screen (lightbox mode or whatever you want to call it).
Click on the image or the magnifying glass
And the image scales up to the XXL-huge size, as you know it from Flickr:
5. Justified image gallery.
That's what they call the “bricklayer” effect, you know from Flickr or Google Photos. It looks much better than the even cards of images in the Bootstrap Darkroom theme.
For that, you need another plugin called gdThumb, easy to install via the backend.
Play with the settings, here are mine:
to make it look like this:
These were the basics to make it work for me, or better yet, to make it look more modern. Most themes are from 2015 or older. It works, but it doesn't look so good.
For the rest of the setup, you are on your own.
I've been on Flickr since 2007, when it was a cool photo-sharing community. Then it got sold to Yahoo, which offered unlimited storage, which turned it into a low-quality image dump, at least partially. Yahoo sold it to Verizon who didn't care too much about it (along with tumblr)? Anyway, it got saved by SmugMug, who put an end to the 1 TB of storage, and that forced me to buy a subscription. 35 USD for a year was okay. From then on, they raised the price and did only little things to keep the platform running and evolving. The Wikipedia article about Flickr explains it all.
Personally, I didn't expect much. I documented places (outsider art environments and things like that), and the free exposure was a nice add-on, but primarily I liked to work with the API and embedded my pictures on my website this way. At some point, I set all my images to a Creative Commons license for people to use (I ended up on Atlas Obscura and in some Kentucky tourism magazine)
This year, they raised the price again. Just 1 EUR, but I looked at it, looked at alternatives, and pulled the plug. No Flickr PRO for me.
What they offer is mainly unlimited hosting of files — I already pay for web hosting, and now for Google Photos — so I can't justify Flickr as a photo backup. I don't need any of the perks they offer (some small discounts on photo books that I can't order anyway). I also don't want to subscribe to Adobe. The community is dead or not interested in my stuff, so I don't miss anything in that regard. SmugMug made a big deal out of improving the statistics, but I couldn't care less whether my photo has been seen 33 times or 44 times. One of the arguments for using Flickr was that it doesn't use your data like Google Photos. Ok, true. And? Nobody cares about this anymore. We accept all cookies everywhere because maintaining privacy is a chore, nobody wants to deal with it. They use my photo of a dog to show my dog food ads? I don't care. I'm more annoyed by Cookie-Banner than the ads I'm blocking anyway.
Again, I liked their API. Flickr was very developer-friendly in the beginning, but all the apps people built 15 years ago are dead, and nothing new happens in that space.
Piwigo was always on my radar, and since my web host offered a one-click install, I tried it. First, I was unsure because, even though the Piwigo websites look pretty nice now, the software is dated and reminds me of some old Joomla backend. But I dug in and managed to import my Flickr photos without issues, polished the instance with some of their plugins, and even contributed a bug fix. It looks like the community has resisted complete rewrites in some framework that needs updates and maintenance all the time. Instead, you have old-school SQL queries instead of an ORM and no compose.json.
And since my engagement on Flickr was low, I don't expect more on my personal Piwigo instance. So I save money, had a little work to figure it all out and the Piwigo API is alright, I can work with that as well.
Another contender was Lychee, also a self-hosted photo gallery based on PHP. I tried it, it's pretty smooth and nice, but it couldn't convince me completely, mainly because it wasn't easy to get my Flickr photos imported and add new images in the future (I think they turned off the ability to read whole directories with images). It also is based on Laravel. While Laravel is fantastic software, as far as I know, I'm not a fan of Laravel. So it was easier to dismiss, beside the missing requirements.
Update 2024-12-06: I sold a license for a photo that allowed be to buy another 2 years of flickr pro, but not without letting the flickr support know that I'm leaving, which resulted in a 30% discount. So ~50 EUR a year, I'm ok with. Also it turns down, selecting 1000 photos to stay on (for the free plan) is as hard as selecting which photos to upload. That's a dilemma.
But since I'm local first, I can distribute photos to flickr and piwigo in almost the same step. So I guess I try
]]>Some new breaking API changes in my favorite Open-Source PIM AtroPIM, that weren't documented (unless I overlooked it).
[TOC]
According to the changelog (with a little more context here) they changed something related to how product assets are requested.
To get all assets related to a product, I called /Product/:entityId/assets
in the past, which resulted in a collection like this:
{
"total": 6,
"list": [
{
"id": "63a41a9be351041b6",
"name": "Einbauhinweis_1380_1390.png",
"deleted": false,
"icon": null,
"url": "/upload/files/7k4dp/Einbauhinweis_1380_1390.png",
"height": 1470,
"width": 1500,
"colorSpace": "SRGB",
"colorDepth": "8",
"orientation": "Landscape",
"isActive": true,
"tags": [],
"description": "",
"createdAt": "2022-12-22 08:51:39",
"modifiedAt": "2022-12-28 15:44:19",
"private": false,
"type": [
"Description Image"
],
"size": 55,
"sortOrder": null,
"title": "Einbau- und Betriebshinweise",
"fileId": "63ac0d0cde8995351",
"fileName": "Einbauhinweis_1380_1390.png",
"filePathsData": {
"download": "upload/files/7k4dp/Einbauhinweis_1380_1390.png",
"thumbs": {
"small": "upload/thumbnails//16801/small/Einbauhinweis_1380_1390.png",
"medium": "upload/thumbnails//16801/medium/Einbauhinweis_1380_1390.png",
"large": "upload/thumbnails//16801/large/Einbauhinweis_1380_1390.png"
}
}
}
]
}
This is gone with 1.9.21+ instead, one can use /Product/:entityId/productAssets
which returns an entirely different collection, that includes prefixed product_*
and asset_*
data.
{
"total": 6,
"list": [
//...
{
"id": "314",
"deleted": false,
"isMainImage": false,
"sorting": 10,
"scope": "Global",
"tags": null,
"createdAt": null,
"modifiedAt": null,
"fileId": "63ac0d0cde8995351",
"fileName": "Einbauhinweis_1380_1390.png",
"filePathsData": {
//..
},
"icon": null,
"product_name": null,
"product_sku": "TEST1380PR01",
"product_isActive": true,
"product_amount": 0,
"product_price": null,
"product_productStatus": "draft",
"product_longDescription": null,
"product_sortOrder": 110,
"product_hierarchySortOrder": null,
"product_data": null,
"product_createdAt": "2022-12-29 08:44:14",
"product_modifiedAt": "2023-08-01 08:41:33",
"product_sorting": null,
"product_materialcode": "TEST1380",
"product_additionalInformation": null,
"product_shortDescription": null,
"product_packingnotice": null,
"product_priceCurrency": null,
"asset_preview": null,
"asset_icon": null,
"asset_url": "/upload/files/7k4dp/Einbauhinweis_1380_1390.png",
"asset_afterSaveMessage": null,
"asset_height": 1470,
"asset_width": 1500,
"asset_colorSpace": "SRGB",
"asset_colorDepth": "8",
"asset_orientation": "Landscape",
"asset_isActive": true,
"asset_tags": null,
"asset_name": "Einbauhinweis_1380_1390.png",
"asset_description": null,
"asset_createdAt": "2022-12-22 08:51:39",
"asset_modifiedAt": "2022-12-28 15:44:19",
"asset_private": false,
"asset_type": [
"5fbe2b489bf7238b3"
],
"asset_size": 55,
"asset_sortOrder": null,
"asset_hierarchySortOrder": null,
"asset_title": null,
"asset_lang": "de",
"asset_isRoot": true,
"asset_hasChildren": true,
"asset_hierarchyRoute": [],
"asset_inheritedFields": null,
"productId": "63ad535edbc9ad1",
"productName": "Folienringe",
"assetId": "63a41a9be351041b6",
"assetName": "Einbauhinweis_1380_1390.png",
"channelId": null,
"channelName": null,
"createdById": null,
"createdByName": null,
"modifiedById": null,
"modifiedByName": null,
"product_brandId": null,
"product_brandName": null,
"product_taxId": null,
"product_taxName": null,
"product_packagingId": "640f0db75bdfb",
"product_productSerieId": null,
"product_productSerieName": null,
"product_catalogId": "5ff47082272d74ecd",
"product_catalogName": "Lieferprogramm (Katalog)",
"product_createdById": "1",
"product_createdByName": "Admin",
"product_modifiedById": "1",
"product_modifiedByName": "Admin",
"product_ownerUserId": "1",
"product_ownerUserName": "Admin",
"product_assignedUserId": "1",
"product_assignedUserName": "Admin",
"product_mainImageId": null,
"product_mainImageName": null,
"product_profileId": "61fc4387732815b9f",
"product_profileName": "PR01",
"asset_libraryId": null,
"asset_libraryName": null,
"asset_createdById": "62bdb456d7cb",
"asset_createdByName": "",
"asset_modifiedById": "1",
"asset_modifiedByName": "Admin",
"asset_fileId": "63ac0d0cde8995351",
"asset_fileName": "Einbauhinweis_1380_1390.png",
"asset_filePathsData": {
//...
}
}
]
}
This is a breaking change for me, since the endpoint and the return object are fundamentally different, and it wasn't documented anywhere.
I was able to replace /Product/:entityId/assets
with /Asset?where[0][type]=linkedWith&where[0][attribute]=productAssets_product&where[0][value][0]={{entityId}}
which returns the expected output.
{
"total": 6,
"list": [
{
"id": "63a41a9be351041b6",
"name": "Einbauhinweis_1380_1390.png",
"deleted": false,
"icon": null,
"url": "/upload/files/7k4dp/Einbauhinweis_1380_1390.png",
"height": 1470,
"width": 1500,
"colorSpace": "SRGB",
"colorDepth": "8",
"orientation": "Landscape",
"isActive": true,
"tags": [],
"description": "",
"createdAt": "2022-12-22 08:51:39",
"modifiedAt": "2022-12-28 15:44:19",
"private": false,
"type": [
"Description Image"
],
"size": 55,
"sortOrder": null,
"title": "Einbau- und Betriebshinweise",
"fileId": "63ac0d0cde8995351",
"fileName": "Einbauhinweis_1380_1390.png",
"filePathsData": {
//..
}
}
]
}
The new /Product/:entityId/productAssets
call (and the /ProductAsset
entity) ties assets closer to the PIM and helps to have basic product information included, which might reduce requests under certain circumstances. I'm sure the Atro devs have a reason for this decision, to me, it seems quite redundant, at least how I use it.
At the moment (2023-08-19), there is also a bug in the localization of asset_*
fields https://github.com/atrocore/atropim/issues/524
But a lot in email gets me headaches and that is always mail client specific, like:
So far, my journey included the following email clients:
eM Client has a working calender and address book. Postbox had Lightning in the past, but they got rid of it. I used the Sunlight calendar for a while but it got bought by Microsoft and then was shut down. The Microsoft calendar is not bad, but it's unreliable with WebDav calendar on Nextcloud.
eM Client impressed me with their thoughtful features, like showing a history of mails from the sender in an active mail, build in calendar and addressbook, notes and even chat (uses some chat protocols that I don't use, so there is that).
Now, the HTML editor in eM Client is just a basic textfield. They didn't even bother to use a monotype font. So it's hard to create html mail in there or signatures. It has wysiwyg tools though, but I don't trust them.
A thing I always ignored in email is encryption. I think the fact that no normal person is able to understand and setup PGP keys left this feature unused by 98% of mail users.
I've never received an encrypted email.
eM Client seems to make the setup easy, but I believe if nobody is using, why bother.
The filter capabilities in eM Client seem to be inferior to Postbox/Thunderbird. No time based filter (delete messages older than x days).
Another downside and a show stopper is the absence of an update of the "unread Mails" count on IMAP subfolders, according to this forum post: No updates or notifications from subfolders? - #55 by curious - Mail - eM Client. That's bad and I guess won't make me using it.
I can think of two: Hey Mail from the creators of Basecamp. It's a paid browser based client that seems to become very popular and I guess you have to use their hey.com mail address.
And there is Plum Mail which looks like a web client with some nice helpers, to pin mails and make notes and keep a conversation together. Subscription based and in beta right now. So I'll pass again.
Every mail client has a trainable spam filter. You would think that this technology could be implemented to train the algo to classify other topics? Nope. Nowhere to find in offline mail clients. That's only offered by cloud based mail systems like Gmail, Hey etc.
But there is Popfile - it's an ancient piece of software, last updated 2015 that sits between your mail client and the mailserver and analyzes mails and sort it into folders. It comes with a webinterface to train your mail and just works fine. Only thing to criticize is it works with only one IMAP connection. That's a bummer, but for my main mailbox it kind of works well to differenciate between notification mail, spam and important stuff.
There was a Thunderbird extension that aimed to do that, but as far as I know, mail threads are identified by a message-id and I think it's up to the mail client to be lax and group by subject line or whatever. Oh well.
It seems like such a niche feature that probably is easy to implement (especially for Postbox, since there is an existing extension they just need to fix), but so far there is only one MacOS client that offers Markdown out of the box, so I won't hold my breath that eM Client or any other client will see that feature ever. (There is Markdown-Here Revival which works nicely)
If I setup a local email filter I would love to see that reflected optionally as procmail filter on the server. But I guess that's too special and works only if your provider gives you access or an interface to that (as all-inkl.com does) combined with a Bayes filter like Popfile - that would be perfect.
I have to use at least one Exchange mail account and I don't want to know too much about this weird Microsoft product, just so much, it is not easy to setup if you don't use Outlook or some other MS software, especially if an ancient version of Exchange is used. I have to run a little proxy called DavMail that sits between Postbox or eM Client and deals with Exchange server. Works alright, but y tho?
Update: with Office 365 it's better integrated, until they changed something with their IMAP/SMTP connections. Either I use Outlook Web or in Thunderbid I now have to use this Owl extension because Thunderbird or MS messes up Unicode characters and umlauts when sending via SMTP. (Ă„ turns to ?). Y tho?
A well setup mail client is one thing, but what if you could use email as chat app? There is the Delta Chat messenger app, that connects to your email account, and offers you a nice chat interface as you know it from Signal or WhatsApp or Skype. Messages are simple emails that your chat partner can read in their email client. And if they use Delta Chat as well, it's even better. And if both partys youse Delta Chat, then they can use the Autoencrypt feature so messages are only readable by the client and nowhere else.
This is a really privacy friendly way to use a proven, robust and decentral infrastructure to communicate.
As far as I understand, this is not as secure messaging as Signal, because email metadata is not encrypted and therefore you leave traces. But I'm no expert here, I just think Delta Chat is a good thing to have.
There isn't one. I guess I keep working around the pain I have with Postbox and won't inflict pain in buying eM Client at this point and work around other issues there switch back to Thunderbird, now that they have multiline message list (or cards as they call it).
As Chris Coyier states:
]]>In fact, you come to love [email], because of how effective of a communication method it is: it’s public, it’s async, it can hold files, it can be of any length, it’s threaded.
Tooling isn’t needed to “fix” email. Email clients these days, for the most part, are interchangeably good.
While exploring Web Components for a current project, came to a halt when faced with the question of language versions of a component.
As advertised, Web Components are portable pieces that can be inserted into any project. Nevertheless, Web Components can be linked directly to a project, but why would you use them instead of using Vue, React or any server-side template language? These are questions I still have to answer myself.
But back to my initial problem: What about the internationalization of Web Components?
I found a blog post3 that goes much deeper, and from there I cobbled together my low effort version below.
The gist is, if you have a bunch of components with strings that can be translated, you handle them in the bundle and load external language files when the component starts up.
If you have a simple, single component, then you can add the language strings inside the component definition, query the document language <html lang="en">
or the navigator.language
and be done with it. This is still not the most portable solution, but it works for that use case.
More complex implementation of that idea here: web-components/note-list.js at master · RolandDreger/web-components · GitHub
const FALLBACK_LANG = "en";
class MyBookmark extends HTMLElement {
constructor() {
super();
this._saved = false;
}
getDocumentLang() {
return (
document.body.getAttribute("xml:lang") ||
document.body.getAttribute("lang") ||
document.documentElement.getAttribute("xml:lang") ||
document.documentElement.getAttribute("lang") ||
FALLBACK_LANG
);
}
render() {
const lang = this.getDocumentLang();
const state = this._saved ? 'bookmarks.button.bookmarked' : 'bookmarks.button.bookmark';
const messages = {
'de': {
'bookmarks.button.bookmark': 'merken',
'bookmarks.button.bookmarked': 'gemerkt'
},
'en': {
'bookmarks.button.bookmark': 'save',
'bookmarks.button.bookmarked': 'saved'
},
};
const html = `${messages[lang][state]}`;
}
}
]]>