Category Archives: Computer

Writing C64 machinecode using Linux With Visual Studio, Kickass and C64Debugger

While still having a love-hate relationship with Visual Studio (I’m a Vim guy), here is my C64 coding setup. (for now)

Needed:
Vice (C64 emulator (and more))
C64 Debugger (embeds above in an awesome debugger)
Visual Studio
Kickass C64 assembler (you need java for this)
(http://theweb.dk/KickAssembler/Main.html)

Visual Studio click extensions and add kickass by Captain Jinx

https://sourceforge.net/projects/c64-debugger/
This is Commodore 64, Atari XL/XE and NES code and memory debugger that works in real time. It is quick prototyping tool where you can play with Commodore 64 machine and its internals.

I’ve got mostly installed in /data
Change accordingly

Create new file, press ctrl-shift-p and invoke kickass debug!

Triple screen movie player in python

I didn’t find an easy and working movie player for wide screen setups.
Like double/triple monitor setups.

I’ve got 3x 1920×1080 monitors connected to my battlestation.
With a resolution of 5760×1080

Simple Python code to play a movie fullscreen

# importing vlc module
import vlc
 
# creating vlc media player object
media_player = vlc.MediaPlayer()
 
# media object
media = vlc.Media("movie.mp4")
 
# setting media to the media player
media_player.set_media(media)
media_player.toggle_fullscreen()
 
# start playing video
media_player.play()
 

But trying to get this stable working, I resorted to pysimplegui

#!/usr/bin/env python3

import PySimpleGUI as sg
import vlc
import sys
from sys import platform as PLATFORM

try:
    movie=sys.argv[1] 
except:
    print(sys.argv[0] +  " filename")
    exit()

sg.theme('DarkBlue')

layout = [[sg.Image('', size=(5760, 1080), key='-VID_OUT-')]]
window = sg.Window('Triple movie player', layout, no_titlebar=True, margins=(0,0),location=(0,0), size=(5760,1080), keep_on_top=True, finalize=True,resizable=False)

window.bring_to_front()
window.Maximize()
window.bind("<Escape>", "-ESCAPE-")
window.bind("<Return>", "-ENTER-")

window['-VID_OUT-'].expand(True, True)

inst = vlc.Instance()
list_player = inst.media_list_player_new()

media_list = inst.media_list_new([])
list_player.set_media_list(media_list)
player = list_player.get_media_player()

if PLATFORM.startswith('linux'):
    player.set_xwindow(window['-VID_OUT-'].Widget.winfo_id())
else:
    player.set_hwnd(window['-VID_OUT-'].Widget.winfo_id())

media_list.add_media(movie)
list_player.set_media_list(media_list)
list_player.play()
while True:
    event, values = window.read(timeout=1000)

    if event == sg.WIN_CLOSED:
        break
    if event == '-ENTER-':
        list_player.play()
    if event == '-ESCAPE-':
        list_player.stop()
        window.close()
window.close()

I’ve converted some of my Vuze media to the correct resolution using kdenlive.

I’ve added a new profile. 5760×1080 dont forget to change the display ratio!

Kdenlive howto

Music players

Note: I love everything streamable from my own servers.
So if its music or movies i tried the lot.
(Another post about movie streaming using Jellyfin,Phpmytube and more)

I’ve got music in mp3, flac and ogg and I have been using below players for a long time

If you have any other suggestion mentioned below, let me know!

MPD – A linux terminal mp3 player (using ncmpc)
XMMS/XMMS2 – Linux gui music player ( The winamp for linux)

Then i moved to

VLC – Sporadic music file playing
Clementine – Linux gui player

For a while Audacious, Rhythmbox and Amarok

And later spotify (Btw you CAN use spotify with local files)

Clementine was not updated very much, so I went with Strawberry Music Player (which is a maintained clone of Clementine)

Tagging mp3s I did using Kid3, Picard and Mp3tag (with wine)
Now with Strawberry

Strawberry in which i play and edit tags.

Strawberry

Webplayers

For a while I used some webbased mp3 players.
I like it when I can stream my music from another location.
But none were to my liking.
It really has to have a Android client, and a secure connection.

  • Ampache
  • Funkwhale
  • Emby
  • Subsonic ( android client is $$ and broken)
  • Volumio
  • Koel
  • Jellyfin

In the old days i used even a simple php streamers

  • Turnstyle andromeda
  • A own written mp3 streamer
  • kplaylist

Linux Window Managers and Distributions

Linux OSses I currently use : Ubuntu, Centos/Rocky/Fedora, Raspbian
(and msdos lol)
Have used:
Slackware,Gentoo, Kali, ELive, Suse,Debian,Mint,Puppy,Lubuntu

Window managers I currently use

  • Xmonad – Tiling window manager
  • Gnome
Xmonad with clusterssh on 14 servers. (Using my serverpath identify trick)

See also :

Screenshots from old desktops

I have to add some recent screenshots.

Fluxbox, Compiz, Xfwm4, Ratpoison

NFO creator with poster art generator

Created this for usage with Kodi, for our own personal movies, which can’t be scraped by movie scrapers obviously.
(dvd-rip,digital video, mobile movies, OBS, Vuze and Nikon movies for example)

UPDATE V2 added functions

This is a followup on:

Works on Windows also!

Needed libraries: (install with pip)
pathlib, Pillow, pymediainfo,PySimpleGUI,python-vlc

NFO created

Title – editable (generated from filename)
Duration – mediainfo data in seconds
Plot – Single line type it yourself
Actors – Predefined
Tags – Predefined checkboxes
Country – Pulldown ( I use this as location, Scotland, Asia, Garden)
Year – default 2023, copy button from mobile phone metadata year
Genre – Pulldown

Works

  • File select and loaded
  • Play movie, scrub thretro movie
  • Create snapshot
  • Play/Mute/Pause
  • Playtimer
  • Auto update NFO text field with selectable options
  • Poster art – rotate
  • Poster art – brightness
  • Reload Thumb after snapshotting
  • Year extracted from filename
  • add tag field
  • Next file (button AND functionality)
  • checkboxes from text list
  • Read NFO from file into fields
  • Poster art – aspect ratio

Needs work

Wish list

  • Poster art – contrast?
  • Low – more mediainfo?
  • Low – Media rotate??

The GUI in action (V1)

Kodi example

CODE ( WIP ) V2
I place this python script in every library directory. So i can change the checkboxes and the NFO being generated.
I fill the directory with symlinks for every movie I want to have included in this directory, but this is not needed. (thats the way I like to do things)
(This is the directory I scrape into Kodi)

from pathlib import Path
from sys import platform as PLATFORM
import os
import re
import PySimpleGUI as sg
import vlc
from pymediainfo import MediaInfo
from PIL import Image, ImageEnhance, ImageTk, ImageOps, ImageFilter
from xml.etree import ElementTree as ET


'''
WARNING, NFO overwrites previous!!



'''

alltags = ["music", "pipes", "computer","bbq","fun","art","travel","hobby","family","retro","compilation","retro","vuze"]

#------- WINDOWS FIX --------#
if PLATFORM.startswith('linux'):
    print("yeah linux baby!")
else:
    os.add_dll_directory(r'E:\VLC')

duration=0
tmptag=""

def nextFile(currentfile,dir):
        newfile=""
        dirpath = os.path.dirname(dir)
        fileList = []
        for f in os.listdir(dirpath):
            #fpath = os.path.join(dirpath, f)
            fpath = f
            if os.path.isfile(fpath) and f.endswith(('.mp4', '.mov', '.mpg','.avi','.mkv','.3gp')):
                fileList.append(fpath)
        fileList.sort()
        for i in range(len(fileList)):
#            print("fileList[i] " + fileList[i])
            try:
                if (fileList[i]) == currentfile:
                    newfile=fileList[i+1]
                    break
            except:
                newfile=fileList
        return newfile

def loadthumb(thumbfile):
    # IF exists
    path_to_file = thumbfile
    path = Path(path_to_file)

    if path.is_file():
        im = Image.open(thumbfile)
        im=ImageOps.contain(im, (640,640)) 
        thumbimage = ImageTk.PhotoImage(image=im)
        window['thumb'].update(data=thumbimage)
    else:
        window['thumb'].update("")

def loadnfo(file):

    #LOAD NFO
    nfo=file + ".nfo"
    path = Path(nfo)

    if path.is_file():
            f = open(nfo, "r")
            innfo=f.read()
            f.close()
#            print ("file : " + nfo)
            innfo="".join([s for s in innfo.strip().splitlines(True) if s.strip()])

# Clear some fields
            window['year'].update("")
            window['plot'].update("")

            # Update fields test
            if ET.fromstring(innfo).find('country') is not None:
                nfolocation = ET.fromstring(innfo).find('country')
                window['location'].update(value=nfolocation.text)
            if ET.fromstring(innfo).find('year') is not None:
                nfoyear = ET.fromstring(innfo).find('year')
                window['year'].update(nfoyear.text)
            if ET.fromstring(innfo).find('plot') is not None:
                nfoplot = ET.fromstring(innfo).find('plot')
                window['plot'].update(nfoplot.text)
            if ET.fromstring(innfo).find('title') is not None:
                nfotitle = ET.fromstring(innfo).find('title')
                window['-NM-'].update(nfotitle.text)
            if ET.fromstring(innfo).find('genre') is not None:
                nfogenre = ET.fromstring(innfo).find('genre')
                window['genre'].update(value=nfogenre.text)

            window['coline'].update(False)
            window['henri'].update(False)
            window['monique'].update(False)
            for actor in ET.fromstring(innfo).findall('actor'):
                name = actor.find('role').text
                if name == "Coline":
                    window['coline'].update(True)
                if name == "Henri":
                    window['henri'].update(True)
                if name == "Monique":
                    window['monique'].update(True)
            for alltag in alltags:
                window[alltag].update(False)

            if ET.fromstring(innfo).find('tag') is not None:
                for tag in ET.fromstring(innfo).findall('tag'):
                    if tag.text in window.AllKeysDict:
                        window[tag.text].update(True)

            window['coline'].update(False)
            window['henri'].update(False)
            window['monique'].update(False)
            for actor in ET.fromstring(innfo).findall('actor'):
                name = actor.find('role').text
                if name == "Coline":
                    window['coline'].update(True)
                if name == "Henri":
                    window['henri'].update(True)
                if name == "Monique":
                    window['monique'].update(True)
            for alltag in alltags:
                window[alltag].update(False)

            if ET.fromstring(innfo).find('tag') is not None:
                for tag in ET.fromstring(innfo).find('tag'):
                    window[tag.text].update(True)

    else:
        innfo=""
    window['LOADNFO'].update(innfo)





#------- Button definition --------#
def btn(name):  
    return sg.Button(name, size=(6, 2), pad=(1, 1))

#def tag(name):  
#    return sg.Checkbox(name, enable_events=True)

#------- GUI definition & setup --------#
sg.theme('SystemDefaultForReal')


l1=sg.Text("New title")
l2=sg.Multiline(" ", expand_x=True, key='-OUT-', expand_y=True,justification='left', size=(20,15))
l3=sg.Multiline(" ", expand_x=True, key='LOADNFO', expand_y=True,justification='left', size=(20,15))
l4=sg.Text("Plot")
t1=sg.Input("", key='-NM-')
t2=sg.Input("", key='plot',enable_events=True)
cb=[]

for alltag in alltags:
    cb.append(sg.Checkbox(alltag, key=alltag, enable_events=True))




cb.append(sg.Input("", key='addtag',size=(5, 1), enable_events=True))
cb.append(sg.Combo(["Lab","Datacenter","home","Outside","Outside","Lloydwebber","Steenweg","Enschede","Netherlands","Germany","Italy","Scotland","Canada","Egypt","Belgium","Sweden","Ireland","Asia","NewZealand","Hilversum"],default_value='Lab',key='location'))
cb.append(sg.Combo(["Storage","Funny","Vacation","Music","Relation"],default_value='Storage',key='genre'))
nameyear=[]
nameyear.append(sg.Checkbox("Coline", key='coline', enable_events=True,default=True))
nameyear.append(sg.Checkbox("Henri", key='henri', enable_events=True,default=True))
nameyear.append(sg.Checkbox("Monique", key='monique', enable_events=True,default=False))
nameyear.append(sg.Input("2023",key='year',size=(5, 1), enable_events=True))
nameyear.append(sg.Button("copyyear\nmetadata", key='copymeta', size=(20, 1), pad=(1, 1), enable_events=True))
nameyear.append(sg.Input("",key='metayear',size=(5, 1), enable_events=True))
nameyear.append(sg.Button("copyyear\nfilename", key='copyname', size=(20, 1), pad=(1, 1), enable_events=True))
nameyear.append(sg.Input("",key='fileyear',size=(5, 1), enable_events=True))
b1=sg.Button("WRITE NFO", key='write', enable_events=True)
b2=sg.Button("Exit", key='exit', enable_events=True)

#------- Layout total --------#

layout = [[sg.Input(key='-VIDEO_LOCATION-', visible=False, enable_events=True),
          sg.FileBrowse(file_types=(("Video files", "*.mkv *.mov *.mp4 *3gp *avi *mpg"),)),btn('next')],
          [sg.Text('Load media to start', key='-MESSAGE_AREA-')],
          [sg.Image('', size=(600, 480), key='-VID_OUT-', pad=(1, 1)),sg.Image('', size=(600, 480), key='thumb', pad=(1, 1))],
          [btn('mute'), btn('play'), btn('pause'), btn('stop'), btn('snap'), btn('snaprot'), btn('lighten'), btn('darken'), sg.Combo(["4:3","16:9","9:16"],key='aspect',enable_events=True)],
          [sg.Slider(range=(0, 1000), default_value=1, expand_x=True, enable_events=True, orientation='horizontal', key='-SL-')],
          [sg.Text('org title', key='orgtitle')],
          [l1, t1, l4, t2],[cb],[nameyear],[b1, l2, l3, b2],
          [sg.Text('GENERATED                            -= mini nfo writer =-                              PREVIOUS', key='footer')]
          ]

#------- Set window --------#
window = sg.Window('Mini NFO generator', layout, element_justification='center', finalize=True, resizable=True)
#------- VID out window --------#
window['-VID_OUT-'].expand(True, True)               
#------------ Media Player Setup ---------#
inst = vlc.Instance()
list_player = inst.media_list_player_new()
media_list = inst.media_list_new([])
list_player.set_media_list(media_list)
player = list_player.get_media_player()
if PLATFORM.startswith('linux'):
    player.set_xwindow(window['-VID_OUT-'].Widget.winfo_id())
else:
    player.set_hwnd(window['-VID_OUT-'].Widget.winfo_id())

#------------ I Want default mute ---------#
player.audio_set_mute(True)

#------------ The Event Loop ------------#
while True:
    event, values = window.read(timeout=1000)       # run with a timeout so that current location can be updated
    if event == sg.WIN_CLOSED:
        break



    if event == 'mute':
        mutevalue = player.audio_get_mute()
        if mutevalue==0:
            player.audio_set_mute(True)
        if mutevalue==1:
            player.audio_set_mute(False)
    if event == 'play':
        list_player.play()
    if event == 'pause':
        list_player.pause()
    if event == 'stop':
        list_player.stop()
    if event == 'snap':
        list_player.pause()
        filename = values['-VIDEO_LOCATION-']
        shortfilename = filename.rsplit( ".", 1 )[ 0 ] 
        newname = shortfilename + "-poster.png"
        player.video_take_snapshot(0, newname, 0, 0)
        loadthumb(newname)
    if event == 'snaprot':
        list_player.pause()
        filename = values['-VIDEO_LOCATION-']
        shortfilename = filename.rsplit( ".", 1 )[ 0 ] 
        newname = shortfilename + "-poster.png"
        im1 = Image.open(newname)
        im1 = im1.rotate(90, Image.NEAREST, expand = 1)
        im1 = im1.save(newname)
        loadthumb(newname)

    if event == 'lighten':
        list_player.pause()
        filename = values['-VIDEO_LOCATION-']
        shortfilename = filename.rsplit( ".", 1 )[ 0 ] 
        newname = shortfilename + "-poster.png"
        im1 = Image.open(newname)
        im1 = ImageEnhance.Brightness(im1)
        im1 = im1.enhance(1.2)
        im1 = im1.save(newname)
        loadthumb(newname)
        
    if event == 'darken':
        list_player.pause()
        filename = values['-VIDEO_LOCATION-']
        shortfilename = filename.rsplit( ".", 1 )[ 0 ] 
        newname = shortfilename + "-poster.png"
        im1 = Image.open(newname)
        im1 = ImageEnhance.Brightness(im1)
        im1 = im1.enhance(0.8)
        im1 = im1.save(newname)
        loadthumb(newname)

    if event == 'aspect':
        filename = values['-VIDEO_LOCATION-']
        shortfilename = filename.rsplit( ".", 1 )[ 0 ] 
        newname = shortfilename + "-poster.png"
        if values['aspect'] == "4:3":
            im1 = Image.open(newname)
            im1 = im1.resize((1920 ,int(1920/4*3)), Image.ANTIALIAS)
            im1 = im1.save(newname)
            loadthumb(newname)
        if values['aspect'] == "16:9":
            im1 = Image.open(newname)
            im1 = im1.resize((1920 ,int(1920/16*9)), Image.ANTIALIAS)
            im1 = im1.save(newname)
            loadthumb(newname)
        if values['aspect'] == "9:16":
            im1 = Image.open(newname)
            im1 = im1.resize((int(1920/16*9),1080), Image.ANTIALIAS)
            im1 = im1.save(newname)
            loadthumb(newname)


    if event == 'write':
        filename = values['-VIDEO_LOCATION-']
        shortfilename = filename.rsplit( ".", 1 )[ 0 ] 
        newname = shortfilename + ".nfo"
        f = open(newname, "w")
        f.write(out)
        f.close()
        loadnfo(shortfilename)

    if event == 'copymeta':
        if datefromfile is not None:
            window['year'].update(datefromfile)

    if event == 'copyname':
        if fileyear is not None:
            window['year'].update(fileyear)


    if event == '-SL-':
        pos=int(values['-SL-'])
        player.set_position(pos/ 1000.0)

        
    if values['coline'] == False:
         colinetext = ""
    if values['coline'] == True:
        colinetext = """<actor>
  <name>Coline Lastname</name>
  <role>Coline</role>
</actor>"""
    if values['henri'] == False:
         henritext = ""
    if values['henri'] == True:
        henritext = """<actor>
  <name>Henri Aanstoot</name>
  <role>Henri</role>
</actor>"""
    if values['monique'] == False:
            moniquetext = ""
    if values['monique'] == True:
        moniquetext = """<actor>
  <name>Monique Lastname</name>
  <role>Monique</role>
</actor>"""

        
    if event == '-VIDEO_LOCATION-':
        if values['-VIDEO_LOCATION-'] and not 'Video URL' in values['-VIDEO_LOCATION-']:
            media_list.remove_index(0)
            media_list.add_media(values['-VIDEO_LOCATION-'])
            list_player.set_media_list(media_list)
            shortname = values['-VIDEO_LOCATION-']
            shortname = shortname.rsplit( "/", 1 )[ 1 ] 
            nextfile=nextFile(shortname,"./")
            shortname = shortname.rsplit( ".", 1 )[ 0 ] 
            window['-NM-'].update(shortname) # only add a legit submit
            list_player.stop()
            list_player.next()
            thumbname=shortname + "-poster.png"
            loadthumb(thumbname)

            #Print org title
            window['orgtitle'].update(values['-VIDEO_LOCATION-'])


            loadnfo(shortname)


            #DURATION
            mi = MediaInfo.parse(values['-VIDEO_LOCATION-'])
            duration=int(mi.tracks[0].duration/1000)
            
            #DATE FROM media
            metadate=mi.tracks[0].encoded_date
            if metadate is not None:
                datefromfile=next(iter(re.findall(r"[1][9][8-9][0-9]|[2][0][0-9]{2}", metadate)), None)
                window['metayear'].update(datefromfile)

            # YEAR FROM FILENAME 
            fileyear=next(iter(re.findall(r"[1][9][8-9][0-9]|[2][0][0-9]{2}", shortname)), None)
            # year from filename
            if fileyear is not None:
                window['fileyear'].update(fileyear)


    if event == 'next':
        
        values['-VIDEO_LOCATION-'] = nextfile
        window['-VIDEO_LOCATION-'].update(nextfile)

        if values['-VIDEO_LOCATION-'] and not 'Video URL' in values['-VIDEO_LOCATION-']:
            media_list.remove_index(0)
            media_list.add_media(values['-VIDEO_LOCATION-'])
            list_player.set_media_list(media_list)
            shortname = values['-VIDEO_LOCATION-']
 #           shortname = shortname.rsplit( "/", 1 )[ 1 ] 
            nextfile=nextFile(shortname,"./")
            #print(nextfile)
            shortname = shortname.rsplit( ".", 1 )[ 0 ] 
            window['-NM-'].update(shortname) # only add a legit submit
            list_player.stop()
            list_player.next()
            thumbname=shortname + "-poster.png"
            loadthumb(thumbname)

            #Print org title
            window['orgtitle'].update(values['-VIDEO_LOCATION-'])
            

            loadnfo(shortname)

            #DURATION
            mi = MediaInfo.parse(values['-VIDEO_LOCATION-'])
            duration=int(mi.tracks[0].duration/1000)
            
            #DATE FROM media
            metadate=mi.tracks[0].encoded_date
            if metadate is not None:
                datefromfile=next(iter(re.findall(r"[1][9][8-9][0-9]|[2][0][0-9]{2}", metadate)), None)
                window['metayear'].update(datefromfile)

            # YEAR FROM FILENAME 
            fileyear=next(iter(re.findall(r"[1][9][8-9][0-9]|[2][0][0-9]{2}", shortname)), None)
            # year from filename
            if fileyear is not None:
                window['fileyear'].update(fileyear)
#        media_list.add_media(nextfile)
##        shortname = nextfile.rsplit( ".", 1 )[ 0 ] 
##        window['-NM-'].update(shortname) # only add a legit submit
#        print(nextfile)
#        window['-VIDEO_LOCATION-'].update(nextfile)
#        list_player.next()
# hier moeten wat update dingen bij!




    # Add tag
    if event == 'addtag':
        tmptag="<tag>" + values['addtag'] + "</tag>"

#------------ exit ---------#

    if event=='exit':
         exit()
#------------ TAGS ---------#
    
    subs=[x.Text for x in cb if x.get()==True]
    for idx, x in enumerate(subs):
        subs[idx]="<tag>" + subs[idx] + "</tag>"


    if values['year'] == False:
        year=str(2023)
    else:
        year=values['year']
    if values['location'] == False:
        location="Lab"
    else:
        location=values['location']
    if values['plot'] == False:
        plot=""
    else:
        plot=values['plot']
    if values['genre'] == False:
        genre="Storage"
    else:
        genre=values['genre']
#------------ NFO TEXT FIELD ---------#

    out="""<movie>
<title>{}</title>
<plot>{}</plot>
<genre>{}</genre>
<duration>{}</duration>
<year>{}</year>
<country>{}</country>
{}
{}
{}
{}
{}
</movie>
""".format(values['-NM-'],plot,genre,duration,year,location,colinetext,henritext,moniquetext,tmptag, "\n".join(subs))
    out="".join([s for s in out.strip().splitlines(True) if s.strip()])
    window['-OUT-'].update(out)

#------------ Messages and timer ---------#

    # update elapsed time if there is a video loaded and the player is playing
    if player.is_playing():
        window['-MESSAGE_AREA-'].update("{:02d}:{:02d} / {:02d}:{:02d}".format(*divmod(player.get_time()//1000, 60),
                                                                     *divmod(player.get_length()//1000, 60)))
    else:
        window['-MESSAGE_AREA-'].update('Load media to start' if media_list.count() == 0 else 'Ready to play media' )

window.close()

My dosbox assembly directory

Below you can find the files in a zip for writing assemby machine code in dosbox.

I’ve got mine extracted in ~/projects/dos

To automount this i’ve edited

~/.dosbox/dosbox-*.conf
;-------- bottom part
[autoexec]
# Lines in this section will be run at startup.
# You can put your MOUNT lines here.

mount c: /home/myusername/projects/dos
c:

The files

  • A.BAT – Runs editor, masm,linker (start with a<space>progname
  • DEBUG.COM – msdos debugger
  • EXE2BIN.EXE – exe to com (if segments allow)
  • GFX.ASM – example template (see below)
  • LINK.EXE – masm linker
  • MASM.EXE – masm compiler
  • Q* – editor stuff
  • Q.EXE – editor
  • SR.EXE – sourcer
  • SYMDEB.EXE
  • TASM.EXE – turbo assembler
  • TD.EXE – turbo debugger
  • TLINK.EXE – turbo linker

Template

; everything in 64k CS, DS, and SS are the same
.model small
; start pointer
.stack 100h
.code
start:
	; set mode 13 (320x200 * 265 colors palette)
    mov ah,0	
    mov al,13h
    int 10h

    ; set pixel in the middle color 2 (cyan)
    mov ah,0ch
    mov al,2
    mov cx,160
    mov dx,100
    int 10h

	; wait key input
    mov ah,0
    int 16h

	; set mode back to text
    mov ah,0
    mov al,3
    int 10h

	; exit to dos
    mov ax,4c00h
    int 21h
end start

Usage

start dosbox
a gfx (edit gfx.asm example)
esc, q, e
gfx (run program)

Calibrating temperature/humidity with mqtt

Example uses a shelly sensor, which has a offset mode in its new firmware. So below is not needed any more.
But the example can be used for any calibration/adjustments.

I’ve put two examples in the NodeRed function

First the solution

var temperature=msg.payload.tC;
var humidity=msg.payload.tF;
// calc new offset example
// simple offset + 2.3 off real measurement
msg.payload.tC=temperature + 2.3;
// more complex example
// take two measurements (with a big difference)
msg.payload.tF=1.11 * (humidity - 1);
return msg;

First adjustment is plus or minus a value.
Second is more precise when the temperature needs more adjusting

Dots on the red line are measured values
Blue is how it should be

So measured was 2.8 but should be 2
And measured 14.5 but needs to be 15

slope = (14.5-2.8)/(15-2) = 0.9

To get the multiplication factor = 1/0.9 = 1.1111

=(2.8-heightadjust)*1,1111 should give us 2

2/1.1111 = 2.8 – heightadjust

1.8 = 2.8 – heightadjust = 1

So the formula is realhumid = 1,1111 * ( measuredhumid – adjust )

Mikrotik day (dhcp and thedude)

Moving dhcp from isc-dhcp-server to Mikrotik.
And playing with theDude and speedtesting.

I got an old linux gateway which only runs a dhcp server.
Time to move this to a Mikrotik router.

The config on this isc-dhcp-server is huge!
So i was planning to migrate some one by one by hand.
Maybe writing a script to do this automatically later on.

I’ve got loads of static configured hosts, so I change these

  • Change static entry in dhcp to a deny booting entry
  • Add a static lease to the Mikrotik
  • Restart dhcp service

Example host

#                # kodiserver
#                host kodi.example.com {
#                fixed-address 10.11.12.13;
#                hardware ethernet ae:ae:ae:ae:ae:ea;
#                }

host movekodito4011 {
   hardware ethernet ae:ae:ae:ae:ae:ea;
   deny booting;
}

Mikrotik config (static single entry config)
See other post about dhcp config

/ip dhcp-server lease
add address=10.11.12.13 mac-address=EA:EA:EA:EA:EA:EA:EA

The Dude

The dude is a cool tool which connects to your MT and generates all kinds of cool info.
I was trying to get the frequency spectral scan working.
But it generates a nice network map also.

Easy to install under linux

  • Install wine
  • Download thedude from the MT website
  • start “wine dude_install.exe”
  • cd ” /home/$USER/.wine/drive_c/Program Files (x86)/Dude”
  • wine dude.exe

While moving a lot from my gateway to Mikrotik, I still have to come up with a plan to migrate my netboot.xyz PXE server to TFTP/ipxe using a migrated dhcpd server.
I probably end up using a separate dhcp instance which handles only the PXE requests.

Background switcher Ubuntu

I was playing around with Phantomjs a headless browser.
Using this as a scraper for a ajax enabled site.

After scraping a wallpaper site, I wanted to take the big pictures and display these as background.

First sort and resize to a better size.

Below does the following:

  • Image width larger than 1800 AND
  • Image height larger than 900
  • Resize to 1920×1080 ( enlarge or reduce size )
  • Not screen filling (portrait mode) ? Than add black bars on the side.
  • Place the image in wallpaper directory

Convert script, if you resize huge images beforehand, you safe cpu resources later.
You also can place other colors or even another background instead of black.

mkdir -p wallpaper
ls * | while read ; do
info=$(identify "$REPLY" | awk '{ print $3 }' 2>/dev/null)
height=$( echo $info | cut -f2 -dx)
width=$( echo $info | cut -f1 -dx)
if [ $width -gt 1800 ] && [ $height -gt 900 ] ; then
	convert -resize 1920x1080  -gravity center  -background black -extent 1920x1080 "$REPLY" "wallpaper/$REPLY"
fi
done

Set a random wallpaper as background using cron.

#!/bin/bash
DISPLAY=":0.0"
XAUTHORITY="/home/henri/.Xauthority"
XDG_RUNTIME_DIR="/run/user/1000"

cd /home/henri/Pictures/
getranpic=$(ls  wallpaper/ |sort -R |tail -1)
#gsettings set org.gnome.desktop.background picture-options 'wallpaper'
#Set different modes ( enum 'none' 'wallpaper' 'centered' 'scaled' 'stretched' 'zoom' 'spanned' )
gsettings set org.gnome.desktop.background picture-uri-dark  "$(realpath wallpaper/$getranpic)"
logger "$(realpath $getranpic)" 

Cron example

* * * * * DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus /home/henri/bin/setrandom

Top IMDB followup using python (openpyxl)

Using some python and a scraped list I can now mark which movies we’ve seen, or have to see.
(Own the movie or have it seen streamed in the cinema)

I just have to place a X after the title in the first column.
Run the python script, and presto

First column, the list we started with.
Second column, mark the movie.
3rd until the end .. years 2000-2023

Blue – seen
Light Blue – seen but was not in original list (so a new movie)
Green – have this movie, but still have to watch it
Light Green – Have this movie but it’s not in the original list
Orange – New in that year (could be an oldie reemerging in the top 250)

Now the python script, maybe it useful for you.

# 20230813 18:49 IMDB overview
# pip install openpyxl

import openpyxl
from openpyxl.styles import PatternFill
from openpyxl.styles.colors import Color
 
wb = openpyxl.load_workbook("clearsheet.xlsx")
sheet = wb['Sheet1']

colors = ['00660066', '00FFFFCC',
          '007b8cf2', '005ace97', '00ffac58','00dddddd','009bd8ff','007aeeb7']
fillers = []

for color in colors:
    temp = PatternFill(patternType='solid',
                       fgColor=color)
    fillers.append(temp)

# Mark found previous years
for colt in range(4, 27):
    for colr in range(3, colt):
        for rowr in range(2, 252):
            for rowrr in range(2, 252):
                if sheet.cell(row=rowrr, column=colr).value == sheet.cell(row=rowr, column=colt).value :
                    sheet.cell(row=rowr, column=colt).fill = fillers[4]

# Mark Our Old list matched with all years
for titlerow in range(2, 252):
    for colr in range(3, 26):
        for rowr in range(2, 252):
            if sheet.cell(row=titlerow, column=1).value == sheet.cell(row=rowr, column=colr).value :
                sheet.cell(row=titlerow, column=1).fill = fillers[5]

# Mark Have / Seen
for title in range(2, 252):
    for j in range(3, 27):
        for i in range(2, 252):
            if sheet.cell(row=i, column=j).value == sheet.cell(row=title, column=1).value :
                if sheet.cell(row=title, column=2).value == "x":
                     sheet.cell(row=i, column=j).fill = fillers[2]
                else:
                     sheet.cell(row=i, column=j).fill = fillers[3]

# Mark non old list but seen
for title in range(252, 400):
    for j in range(3, 27):
        for i in range(2, 252):
            if sheet.cell(row=i, column=j).value == sheet.cell(row=title, column=1).value :
                if sheet.cell(row=title, column=2).value == "x":
                     sheet.cell(row=i, column=j).fill = fillers[6]
                else:
                     sheet.cell(row=i, column=j).fill = fillers[7]
# Info cells
sheet['D255'] = "Downloaded seen org list"
sheet['D256'] = "Downloaded not seen org list"
sheet['D257'] = "Title matches found in 2000-2023"
sheet['D258'] = "Titles found in 2000-2023 not in org list have"
sheet['D259'] = "Titles found in 2000-2023 not in org list have seen"
sheet['D260'] = "Titles found in 2000-2023 previous years"
sheet.cell(row=255, column=4).fill = fillers[2]
sheet.cell(row=256, column=4).fill = fillers[3]
sheet.cell(row=257, column=4).fill = fillers[5]
sheet.cell(row=258, column=4).fill = fillers[7]
sheet.cell(row=259, column=4).fill = fillers[6]
sheet.cell(row=260, column=4).fill = fillers[4]
wb.save("imdbexport.xlsx")