• 12 Posts
  • 249 Comments
Joined 1 year ago
cake
Cake day: June 20th, 2023

help-circle






  • KDE has a good zoom feature built in, however it keeps the mouse centered which is good for doing precise graphical thing, but maybe not the best for gaming. It’s good for reading if you hold your mouse still. You can absolutely find or make a green cursor. Some guy here said gaming on Linux is janky but honestly I’ve been super impressed for the past year I’ve used it. I only had one game that wouldn’t run out of the box so far and got it running by installing some Microsoft VC runtime or something. Everything else just starts runs without issue. Edit: runs without issue in steam.






  • I did a workaround by editing a script I found and don’t understand using xprop, xwininfo, and xdotool. I probably should have mentioned that I’m using X, most of this stuff doesn’t work on Wayland. Here’s my script so far:

    #!/bin/bash
    
    xprop -spy -root _NET_ACTIVE_WINDOW | grep --line-buffered -o '0[xX][a-zA-Z0-9]\{7\}' |
    while read -r id; do
        class="`xprop -id $id WM_CLASS 2> /dev/null | grep TeamViewer`"
        if [ -n "$class" ]; then
            if xprop -id "$id" | grep -q 'WM_NAME(STRING) = "TeamViewer Authentication"'; then
                echo "key Tab
                key space
                key shift+Tab
                key shift+Tab
                key Down
                key Tab
                type {my.username}
                key Tab
                key ctrl+u"| xdotool -
                # wait for the window to be closed
                xprop -spy -id $id > /dev/null 2>&1
                fi
        fi
    done
    
    

    It spits out errors after the window closes because I think it’s trying to get windows properties from the now closed window, but it gets the job done!

    Edit: changed the script to be much smaller and not show errors.






  • Dude honestly the Volcano rules. I’ve had mine almost 20 years now and I’ve had a screw rattle loose and the plastic airflow button broke ($10 part) and that’s it. I also bought a Crafty+ and I hardly ever use it. The Volcano is definitely smoother and I think hits harder. Plus you can see how heavy your dose is about to be as the bag fills. The power plugs I bought came out to like $10 each I think for a pack of 4.


  • Ask and ye shall receive! I’m tacking a GPL 3 license to it. The plugs that play a sound after a delay won’t work on Windows because I use fork(), but I don’t use Windows because fuck Windows. It uses mpv to play sounds, but that is easily changed. AMA.

    #!/usr/bin/env python
    "Control my various tasmota devices. Licensed under GPL v3: https://www.gnu.org/licenses/gpl-3.0.en.html#license-text"
    
    import os
    from time import sleep
    import urllib.request
    from json import loads
    from subprocess import Popen
    
    __all__ = ["Tasmota", "TasmotaWarmup", "TasmotaOffFirst", "DEVICENAMES"]
    
    class Tasmota():
        "A tasmota device."
        def __init__(self, ipaddress: str, name: str=None):
            self.ipaddress = ipaddress
            self.name = name
    
        def __repr__(self):
            return f"<{type(self).__name__} {self.name if self.name else self.ipaddress}>"
    
        def _request(self, cmd: str) -> str:
            "make an http request to the device"
            return urllib.request.urlopen(f"http://{self.ipaddress}/cm?cmnd={cmd.replace(' ', '%20')}").read()
    
        def on(self) -> bool:
            "Turn the device on. return True if successful"
            return b"ON" in self._request("Power On")
    
        def off(self) -> bool:
            "Turn the device off. return True if successful"
            return b"OFF" in self._request("Power Off")
    
        def toggle(self) -> bool:
            "Toggle the device power. return True if power is now on, False if it's off"
            return b"ON" in self._request("Power Toggle")
    
        def status(self) -> bool:
            "return True if the device is on, False if it is off"
            return bool(loads(self._request("Status"))["Status"]["Power"])
    
    class TasmotaWarmup(Tasmota):
        "Plays a sound when started, plays a sound after a waiting period."
        def __init__(self, ipaddress: str, name: str=None, warmup_time: int=None, on_sound: str=None, ready_sound: str=None):
            "warmup_time is seconds, on/ready_sound is the path to the audio file to play"
            super().__init__(ipaddress, name)
            self.warmup_time = warmup_time
            self.on_sound = on_sound
            self.ready_sound = ready_sound
    
        def _playSound(self, sound: str) -> None:
            "play a sound"
            Popen(["mpv", "--no-terminal", "--volume=60", sound])
    
        def _beginPowerOnSounds(self) -> None:
            "Play a sound when turning on and another sound when ready"
            if self.on_sound:
                    self._playSound(self.on_sound)
            if self.warmup_time and self.ready_sound:
                if __name__ == "__main__": # using this as a script, fork to background and return terminal
                    if os.fork() == 0: # wait in the background for the warmup_time
                        self._sleepAndPlay()
                        raise SystemExit
                else:
                    Thread(target=self._sleepAndPlay).start()
    
        def _sleepAndPlay(self) -> None:
            "The actual sleeping and playing, to be run in a thread if needed."
            sleep(self.warmup_time)
            if self.status(): # if device is still on
                self._playSound(self.ready_sound)
    
        def on(self) -> bool:
            "Turn the device on and play sounds"
            if super().on():
                self._beginPowerOnSounds()
                return True
            return False
    
        def toggle(self) -> bool:
            "toggle the status and play sounds if we're turning it on"
            if super().toggle():
                self._beginPowerOnSounds()
                return True
            return False
    
    class TasmotaOffFirst(TasmotaWarmup):
        "A Tasmota object that turns the device off first before turning it on"
        def _turn_off_before_on(self) -> bool:
            "Turn this device off first if it's already on when it's switched on"
            if not super().toggle(): # if toggling turned it off
                super().on()
            return True
    
        def on(self) -> bool:
            return self._turn_off_before_on()
    
    class TasmotaAlwaysOn(TasmotaOffFirst):
        "This Tasmota class is always on; toggling it will turn it off briefly and then back on"
        def toggle(self) -> bool:
            "toggle this device off and then back on again"
            return self._turn_off_before_on()
    
    DEVICENAMES = {"volcano": TasmotaWarmup("192.168.1.152", "Volcano", 355, "/home/jt/.sounds/hold up hey.ogg",
                                            "/home/jt/.sounds/fill that bag up right now2.flac"),
                       "towel": TasmotaOffFirst("192.168.1.153", "Towel Warmer", warmup_time=(20*60)+30,
                                                ready_sound="/home/jt/.sounds/yayeah.ogg"),
                       "radiator": Tasmota("192.168.1.166", "Radiator"),
                       "taco": TasmotaAlwaysOn("192.168.1.156", "Taco")
                       }
    
    if __name__ != "__main__":
        from threading import Thread # only needed when importing this module
    else:
        import sys, argparse
        parser = argparse.ArgumentParser(description="Control Tasmota wifi power plugs")
        parser.add_argument("devices", help="device(s)", action="store", nargs="*")
        operation_group = parser.add_mutually_exclusive_group()
        operation_group.add_argument('--on', '-n', help="power on device", action="store_true")
        operation_group.add_argument('--off', '-f', help="power off device", action="store_true")
        operation_group.add_argument('--toggle', '-t', help="toggle device power", action="store_true")
        operation_group.add_argument('--status', '-s', help="get status of device", action="store_true")
        args = parser.parse_args()
    
        # Sanity checks
        if not args.devices:
            print(f"No device specified. Available devices are: {' '.join(DEVICENAMES.keys())}", file=sys.stderr)
            parser.print_help()
            sys.exit(1)
        invalid = []
        for d in args.devices:
            if not DEVICENAMES.get(d):
                invalid.append(d)
        if invalid:
            print(f"Invalid device{'s' if len(invalid) > 1 else ''}: {' '.join(invalid)}", file=sys.stderr)
            print(f"Available devices are: {' '.join(DEVICENAMES.keys())}", file=sys.stderr)
            sys.exit(3)
        for d in args.devices: # gogo
            t = DEVICENAMES[d]
            if args.on:
                if t.on():
                    print(f"{t.name} turned on")
                else:
                    print(f"Failed to turn on {t.name}", file=sys.stderr)
            elif args.off:
                if t.off():
                    print(f"{t.name} turned off")
                else:
                    print(f"Failed to turn off {t.name}", file=sys.stderr)
            elif args.toggle:
                print(f"{t.name} turned {'on' if t.toggle() else 'off'}")
            elif args.status:
                print(f"{t.name} is {'on' if t.status() else 'off'}")