Quick n easy media viewer in a browser

Last Updated or created 2022-10-12

Februari 2021 i made a website to view images and movies in a browser to do some quick sorting. (borrowed some code from a codepen page i recall correctly)
At the time i didn´t have a good way to view webp webm media.
I wanted to view multiple files at the same time, and make it short and simple.

BTW no webserver needed, just open the file from a directory!
jpg’s png’s webm webp mp4 svg and animated gifs work. (maybe more, didn’t test more, whatever your browser supports)

With recent updates of the chrome browser the video attributes to mute is broken, i so made a workaround.
Also everything is in one file now.
Except for one issue .. i couldn´t create one file for images AND videos.

There is a piece of javascript i could not fix … yet
I have to do execute a document.createElement which is different for images and videos.
Also the attributes of video are mute,autoplay,loop,playinline

Examples:

index.html

<a href="video.html">Video version</a>
<div id="drop-area">
  <form class="my-form">
    <label class="button" for="fileElem">Drop some images</label>
  </form>
  <div id="gallery" /></div>
</div>
<style>
body {
  font-family: sans-serif;
}
#drop-area {
  border: 2px solid #ccc;
}
.my-form {
  margin-bottom: 10px;
}
#gallery {
  margin-top: 10px;
}
#gallery img {
  width: 300px;
}
}
#fileElem {
  display: none;
}
</style>
<script>
let dropArea = document.getElementById("drop-area")
;['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
  dropArea.addEventListener(eventName, preventDefaults, false)   
  document.body.addEventListener(eventName, preventDefaults, false)
})
;['dragenter', 'dragover'].forEach(eventName => {
  dropArea.addEventListener(eventName, highlight, false)
})
;['dragleave', 'drop'].forEach(eventName => {
  dropArea.addEventListener(eventName, unhighlight, false)
})
dropArea.addEventListener('drop', handleDrop, false)
function preventDefaults (e) {
  e.preventDefault()
  e.stopPropagation()
}
function highlight(e) {
  dropArea.classList.add('highlight')
}
function unhighlight(e) {
  dropArea.classList.remove('active')
}
function handleDrop(e) {
  var dt = e.dataTransfer
  var files = dt.files
  handleFiles(files)
}
function handleFiles(files) {
  files = [...files]
  files.forEach(previewFile)
}
function previewFile(file) {
  let reader = new FileReader()
  reader.readAsDataURL(file)
  reader.onloadend = function() {
    let img = document.createElement('img')
    img.src = reader.result
    document.getElementById('gallery').appendChild(img)
  }
}
</script>

video.html

<a href="index.php">Images version</a>
<div id="drop-area">
  <form class="my-form">
    <label class="button" for="fileElem">Drop some videos</label>
  </form>
  <div id="gallery" /></div>
</div>
<style>
body {
  font-family: sans-serif;
}
#drop-area {
  border: 2px solid #ccc;
}
.my-form {
  margin-bottom: 10px;
}
#gallery {
  margin-top: 10px;
}
#gallery video {
  width: 300px;
}
}
#fileElem {
  display: none;
}
</style>
<script>
let dropArea = document.getElementById("drop-area")
;['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
  dropArea.addEventListener(eventName, preventDefaults, false)   
  document.body.addEventListener(eventName, preventDefaults, false)
})
;['dragenter', 'dragover'].forEach(eventName => {
  dropArea.addEventListener(eventName, highlight, false)
})
;['dragleave', 'drop'].forEach(eventName => {
  dropArea.addEventListener(eventName, unhighlight, false)
})
dropArea.addEventListener('drop', handleDrop, false)
function preventDefaults (e) {
  e.preventDefault()
  e.stopPropagation()
}
function highlight(e) {
  dropArea.classList.add('highlight')
}
function unhighlight(e) {
  dropArea.classList.remove('active')
}
function handleDrop(e) {
  var dt = e.dataTransfer
  var files = dt.files
  handleFiles(files)
}
function handleFiles(files) {
  files = [...files]
  files.forEach(previewFile)
}
function previewFile(file) {
  let reader = new FileReader()
  reader.readAsDataURL(file)
  reader.onloadend = function() {
    let video = document.createElement('video')
    video.setAttribute('volume', '0');
    video.setAttribute('height', '300');
    video.setAttribute('autoplay', true);
    video.setAttribute('loop', true);
    video.setAttribute('playsinline', true);
    video.setAttribute('oncanplay', 'this.muted=true');
    video.src = reader.result
    document.getElementById('gallery').appendChild(video)
  }
}
</script>

Management on old ILO instances

Last Updated or created 2022-10-11

We bought some servers a while ago, but these have old ILO versions (2).

To manage these servers via ILO was no problem until modern browsers refuse to connect to these web services, because of TLS 1.0 issues.

So what i did was using a second user account on my workstation with a old (downloaded from a ESR archive) version firefox. To administer the ILO

wget https://ftp.mozilla.org/pub/firefox/releases/50.0/linux-x86_64/en-US/firefox-50.0.tar.bz2
extract in other users homedir

usage:
# ssh with X forwarding and start old version
ssh -X otheruser@localhost firefox/oldfirefox

While this was working for me on a debian based machine it didn’t work for my friend who was using Fedora on Wayland.

So i made a more generic solution which would work always. Also when working from windows.

I downloaded a old Fedora version ISO.
https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/15/Fedora/x86_64/iso/
Using the DVD iso i knew the old JAVA was present.

So i started virt-manager and created a new virtual machine

Select your downloaded Fedora 15 ISO

Where is the thin option?!??!

Create a disk image for the OS, don’t worry about the size we are going to shrink it to a minimum (thin provisioned)

Booting from ISO
Do not forget to tick Customize now

Disable all thats not needed! .. Only Gnome Graphical internet .. and JAVA

Create users, complete the install and reboot.
Test your installation.
Shutdown

sudo qemu-img info /var/lib/libvirt/images/fedora15.qcow2
When above gives you a RAW image, you need to convert from RAW to QCOW first.
Mine showed a 9G qcow2 image .. far to large

sudo apt install guestfs-tools
virt-sparsify -v fedora15.qcow2 fedora15spars.qcow2

9665380352 okt 10 13:05 fedora15.qcow2
2926444544 okt 10 13:21 fedora15spars.qcow2
From 9 down to 3GB
Browser works

Testing the Java applet console

Success!

Generic Matrix Keyboard Print

Last Updated or created 2023-06-20

I only have to check my new design for a generic matrix keyboard once again, and then i’m going to order a few of these prints.

  • 32 keys (2 blocks of 16)
  • 1 key is changeable from generic key to reset signal key
  • jumper header connector VCC, GND, DataAvailable, Reset and 5 data lines

I’ve used the opensource tool freeroute to autoroute the coppertraces

  • From Kicad export PCB in Spectra DNS format
  • Open Freeroute and run autoroute
  • export as Spectra Session File
  • In kicad import this session file again

Autotraced …
Front
Back
Current setup

TODO: Look into charlieplexing ! For input and Led control

Raspberry and SSD

Last Updated or created 2022-10-05

I had a crash recently on one of my raspberry-pi’s ..
SDcard failure, they are not made for a lot of write actions.
In the past i’ve changed some images to read only and with a r/w overlay.
Also tmp filesystems in memory .. all not ideal.

So i’ve started to make every RPi ssd bootable.

I’ve got several ssd already from other projects.
Sata to USB adaptors are cheap, only a few euro’s.

Steps to take:

  • Download Raspberry Pi Imager tool
  • Choose OS > Misc Utility Images > Bootloader > USB Boot
  • Select storage and write to a temporary sd-card (Not needed any more after flashing for normal operations)
  • Boot USB with this Micro-SDcard .. i didn’t have a screen connected .. So i just waited a few minutes
  • While i was waiting i wrote a OS image to the SSD using the same imager tool
  • Choose OS > select sata/ssd drive
  • Change options (cog), enable ssh, choose hostname and set password
  • Write to drive
  • Remove sdcard from RPi attach ssd/sata and boot

My 3D printed sdcard case, luckily there was still one in there (32GB kindda big, but it was only for temporary use .. 16GB was broken ..

So .. without attaching a screen or keyboard, just a network cable. I have a running OS on a RPi from SSD

Motion detection for stupid webcams

Last Updated or created 2022-10-01

Last year i made a script for a friend who wanted to detect visually if his garden sprinkler was on or off. A few days ago i saw someone who wanted to see if things where moving in his house. (didn’t trust his landlord i think)
But he only had a dumb/simple/cheap camera .. so it had no motion detection.

I was thinking of my script, and could easily adapt it for this usage.

Most ipcams have somekind of URL/API you can use to capture a image.
Some examples below

# Reolink
wget "http://ipnumber/cgi-bin/api.cgi?cmd=Snap&channel=0&rs=randomstring&user=user&password=password" -O image.jpg

# Foscam
wget "http://ipnumber:88/CGIProxy.fcgi?cmd=snapPicture2&usr=user&pwd=password&cnt=randomstring" -O image.jpg

# Edimax
wget "http://user:password@ipnumber/jpg/image.jpg" -O image.jpg

# Hikvision
wget "http://user:password@ipnumber/ISAPI/Streaming/channels/101/picture" -O image.jpg

So using below script i can capture a image, compare it to the previous, and when it’s above a certain threshold sends a email.

#!/bin/bash
# Only uses wget and image-magick
treshhold=500
fuzzyness=20%
# CHANGE WEBCAM THINGY TO OWN URL AND CREDENTIALS
wget -q "http://webcamip/cgi-bin/api.cgi?cmd=Snap&channel=0&user=user&password=password" -O previous.jpg
while true;  do
wget -q "http://webcamip/cgi-bin/api.cgi?cmd=Snap&channel=0&user=user&password=password" -O current.jpg
value=$(compare -fuzz $fuzzyness previous.jpg current.jpg -metric mae diff.jpg 2>&1 | cut -f1 -d.)
if [ $value -gt $treshhold ] ; then
echo "ping $treshhold"
echo "Something moved" | mail -s "Movement" user@example.com -A diff.jpg
fi
# Comment below if you want to compare against a base line .. not previous image
cat current.jpg > previous.jpg
sleep 60
done

Example previous picture

Example current picture

I got mailed with result

Hints tips:

Use crop to detect only a part.

copy current.jpg to a second file
Use painting black a part and compair with different treshhold fuzzyness to get different hotspots.

Below detects RED, use above ide with crop to detect red/green/blue leds

compare -verbose -metric mae 1.jpg 2.jpg /tmp/1.diff
1.jpg JPEG 2560x1920 2560x1920+0+0 8-bit sRGB 248819B 0.050u 0:00.057
2.jpg JPEG 2560x1920 2560x1920+0+0 8-bit sRGB 248949B 0.030u 0:00.137
Image: 1.jpg
  Channel distortion: MAE
  Channel distortion: MAE
    red: 12517.5 (0.191005)
    green: 11967.1 (0.182607)
    blue: 12492.8 (0.190628)
    all: 12325.8 (0.18808)
1.jpg=>/tmp/1.diff JPEG 2560x1920 2560x1920+0+0 8-bit sRGB 1.19495MiB 1.470u 0:00.197