Friday 26 July 2019

How to disable an input device in Lubuntu

I have a Dell Latitude E6410 laptop and it has one of those stick pointing devices built into the keyboard. They are just a little joystick that you can use to move the mouse except it is just a tiny little thing that fits between keys and is actually quite hard to use.

Anyway this week the stick thing started pushing the mouse to the top right hand corner all of the time. So I have looked up how to disable it from being in operation, since it was doing this with everything, even in the BIOS or the Linux installer.

So the command to use for (L)ubuntu is xinput so the first thing is to use its list parameter to get a list of devices. Each device will have an id number next to it, in this case 18.

Then the next thing is simply type in xinput disable 18 and that disables the device. Which means using the touchpad and an external USB mouse just got a whole lot easier. I'm not sure there is any hardware way like a key sequence you could press that would achieve this, so this was a great outcome, as I doubt there was anything else I could have done, although I was able to use the stick to move the mouse around. Without being able to resolve that the laptop would have been nearly unusable, which would be a concern as it is otherwise in extremely good condition.

Sunday 21 July 2019

Lubuntu vs Debian / LXQt

As we well know my preference is very much the use of Debian rather than Ubuntu. I do this because Debian better supports experienced Linux users like me. Debian however omits firmware drivers for non-free hardware by default which means a lot of fiddling to download and install and there are some other capabilities like mtp and sudo that need extra work to configure. On the other hand Debian supports hibernation by default.

On some devices such as a laptop the easy installation of Lubuntu is more preferable if hibernation is not needed for example. Lubuntu also has sensible default settings for pulseaudio, specifically flat-volumes=no, which the Debian community has still not been able to address (debian is one of the very few distros that does not implement this by default)

Debian with LXQt will remain the choice for the computer at my desk that is used to play my worship music and video collection because this computer also gets used for day to day stuff and hibernation is a huge benefit. However Lubuntu will be my OS of choice for computers like a laptop or NUC that have wireless hardware in them.

Thursday 18 July 2019

Tech giants need to be reigned in before they start ruling our lives

As if there wasn't enough bad PR already over Google and Facebook, here's an article about how some guy got a lifetime ban from AirBnB. He gets no right of appeal or anything. They do not have to explain or account to him or anything that would be considered fair (maybe he has recourse in the courts, or maybe not).

Wednesday 17 July 2019

Python Scripting [4C]: Exif Based Image Renaming 3

After letting this one slide for quite a while, I picked it up again yesterday and have completed most of the coding. This is the full code to date (barring any further modifications found to be needed after testing).

The script is run from the directory that is to be acted upon and takes no parameters as it works by looking for all the files off the source path.
  
# declarations

import glob
import argparse
import os
import shutil
import sys
import time
from PIL import Image

This is the basic declarations block. There may be some declarations that are irrelevant as it is copied from another script without checking.

# script is run from Photos subdirectory and processes subfolders
rootPath = os.getcwd()
exifDateMonth = None
exifDateYear = None

sourcePath = os.path.normpath(rootPath + "/" + "*")
for subDir in glob.glob(sourcePath):
    if os.path.isdir(subDir):
        if ("_" in subDir):

In here you just have the start of things which is to look for subdirectories off the source. The subdirectories that it scans for source file must have at least one underline character in their name. This basically matches the format of directory names that Canon uses on the camera by default (generally named xxx_dd_mm although sometimes it will be xxx___mm, depending on the camera or its settings).


            # process files from source directories
            imagePath = os.path.normpath(subDir + "/*")
            for sourceFile in glob.glob(imagePath):
                sourceExt = os.path.splitext(sourceFile)[1]
                try:
                    image = Image.open(sourceFile)
                    image.verify()
                except:
                    image = None # not an exif processable image

In this block we are getting the source file (hopefully a JPEG image with exif tags) and reading its exif data. We are using a try..except block to catch any exceptions that are raised in the process of reading the exif data block, in case there is no exif data or the source file is not an image. For example it could be a movie file which fits neither possibility.


                if (image is not None):
                    exif = image._getexif()
                    try:
                         # get the exif tags from the image
                        exifDateTime = exif[36867]
                        exifName = exif[272]
                    except:
                        image = None
                    try:
                        exifSubSec = exif[37521]
                    except:
                        exifSubSec = "00"

This is the first of two blocks of code that only works if an Exif file has been read and the tags have been extracted from it. We are using two try..except blocks. The first is trapping the possibility that this image doesn't have any Exif tags (which could happen with some image files) and if that happens we set the image to None (null). The second exception handling block deals with the possibility there is no SubSecTime field which could be the case with some older cameras that don't set this field, in which case we set it to a string value of "00". When I first started batch renaming photos off my cameras I never used to use SubSecTime and didn't know it existed, but it has become very useful for dealing with cameras that can take multiple frames per second in order to avoid file renaming collisions. The script doesn't have any way of detecting collisions and what the next iteration of it needs to do is to ensure where SubSecTime is not provided by a camera or is always 0, that it doesn't overwrite an existing file of the same name (an actual collision between two different files). Because right now it will happily overwrite an existing file without even blinking.


                if (image is not None):
                    # turn the tags into a filename
                    exifDateTimeParts = exifDateTime.split(" ")
                    exifDateParts = exifDateTimeParts[0].split(":")
                    exifDateYear = exifDateParts[0]
                    exifDateMonth = exifDateParts[1]
                    exifTimeParts = exifDateTimeParts[1].split(":")
                    exifDateStr = "".join(exifDateParts)
                    exifTimeStr = "".join(exifTimeParts) + exifSubSec
                    destPath = os.path.normpath(rootPath + "/" + exifDateYear + "/" + exifDateMonth)
                    destName = exifDateStr + " " + exifTimeStr + " " + exifName + sourceExt
                    destFile = os.path.normpath(destPath + "/" + destName)
                    print destFile
                    if not os.path.exists(destPath):
                        os.mkdir(destPath)
                    shutil.move(sourceFile,destFile)

This block works on valid Exif tagged files and it extracts from the date/time fields enough data to make the destination directory path. We use a path of year followed by month e.g. 2019/03 as a subdirectory of the current directory (the one from which the script is being run). We then make the new file name by combining the date, time and camera model name and the original extension. After creating the new path if it does not exist we then move the file from its original path and name to its new path and name. So the file gets renamed and moved to its new location at the same time.

                if (image is None): # non exif or unreadable exif
                    sourceDirName = os.path.split(os.path.dirname(sourceFile))[1]
                    sourceDirDtParts = sourceDirName.split("_")[-1]
                    SourceDirDtMonth = sourceDirDtParts[-2:]
                    sourceDateTime = time.localtime(os.path.getctime(sourceFile))
                    sourceDateYear = sourceDateTime[0]
                    sourceDateMonth = SourceDirDtMonth
                    destName = os.path.basename(sourceFile)
                    destPath = os.path.normpath(rootPath + "/" + str(sourceDateYear) + "/" + str(sourceDateMonth))
                    destFile = os.path.normpath(destPath + "/" + destName)
                    print destFile
                    if not os.path.exists(destPath):
                        os.mkdir(destPath)
                    shutil.move(sourceFile,destFile)

The final block of code is to deal with files that don't have Exif data in them. There is an inherent difficulty in processing these files that means this code block doesn't rename the files, instead it leaves the file with its original name. When the files are copied off the camera onto the PC, the original timestamps are lost and replaced with new ones. The system creates the copy of the file on the PC with the current date and time as the creation time, which means we just don't have the ability to know what the correct date to use for the destination file name is. However there is a clue in the way the camera creates the source folder with a day and month in the path. So this code basically gets the year from the file itself and then gets the month from the source directory name. It then moves the file to the new location, but without giving it a new name.

One way around this issue would be to create a script that copies directly off the camera. The problem is that the way a camera is interfaced into the operating system in Debian doesn't create a path to access it like it was a removable hard drive. I'm not sure if taking the card out and putting it into a USB card reader will make it appear like a full file path. The script will work correctly as long as the non-image file (e.g. movie) gets copied off the camera in the same year as it was created otherwise it will end up with the wrong year.

Tuesday 2 July 2019

Raspberry Pi 4 Released

Raspberry Pi Foundation has announced the release of Raspberry Pi Model 4. RPi4 adds a number of new features over the Model 3, including dual HDMI 4K displays (via micro connectors), USB-C power connection, USB 3 ports on board and a choice of 1 GB, 2 GB or 4 GB onboard RAM. There is a new SOC as well that will be significantly faster than the 3B's chip. Pricing for the 1 GB model should be about the same as the 3B. The capabilities of this model are not sufficiently greater than my 3B to provide me with any more versatility and I am not planning to upgrade, considering what I currently use my 3B for.

At the same time, Raspbian has been updated to Debian Buster, a week ahead of the official release. I have just flashed my 3B to use the new release of Raspbian and it works just fine.