Monday, December 22, 2025

python3: my personal package mini function

 ~/

├── dedetoklib/
│   ├── __init__.py
│   └── check_holiday.py

└── main.py

 

check_holiday.py

import holidays
from datetime import datetime

# Create holiday object for Indonesia
ID_HOLIDAYS = holidays.country_holidays("ID")

def is_holiday(date_str):
    """
    Check if a date (YYYY-MM-DD) is a holiday.
    
    Returns:
        (bool, str | None): 
        - True and holiday name if holiday
        - False and None if not
    """
    date_obj = datetime.strptime(date_str, "%Y-%m-%d").date()
    
    if date_obj in ID_HOLIDAYS:
        return True, ID_HOLIDAYS[date_obj]
    else:
        return False, None

def is_working_day(date_str):
    """
    Check if a date (YYYY-MM-DD) is a working day (Monday to Friday).
    Returns:
        bool: True if Monday–Friday, False if Saturday or Sunday
    """
    date_obj = datetime.strptime(date_str, "%Y-%m-%d").date()
    # weekday(): Monday = 0, Sunday = 6    if date_obj.weekday() < 5:
        return True, "Weekday"
    else:
        return False, "Weekend"

Test main.py

from dedetoklib import check_holiday

dates = ["2025-01-01", "2025-01-02", "2025-08-17"]

for d in dates:
    # Check holiday
    holiday_flag, holiday_name = check_holiday.is_holiday(d)
    
    # Check working day
    working_flag, working_str = check_holiday.is_working_day(d)
    
    print(f"{d}: {working_str}, Holiday? {holiday_flag}", end="")
    if holiday_flag:
        print(f" ({holiday_name})")
    else:
        print()

 

 


 

python3: writing package

 
create folder to put your pyhton files e.g. dedetoklib, 

the structure of directory  

~/

├── dedetoklib/
│   ├── __init__.py
│   └── hello.py

└── main.py

hello.py

def say_hello():
    return "Hello, World"

__init__.py

(leave it empty)

main.py 

import dedetoklib.hello

dedetoklib.hello.say_hello()

import as library

import dedetoklib.hello as h

print(h.say_hello())

 

Wednesday, December 10, 2025

Debian 13: rebuilding nvidia driver after kernel upgrade from linux-image-6.12.31-amd64 to linux-image-6.12.57+deb13-amd64

After you upgrade kernel, in my case linux-image-6.12.31-amd64 to linux-image-6.12.57+deb13-amd64, you need to rebuild nvidia driver. During boot, Debian will show some error loading nvidia module

To check which module fail during boot 

# journalctl -b -u systemd-modules-load.service 
Dec 10 09:48:02 mylocalpc systemd-modules-load[781]: modprobe: ERROR: Error running install command 'modprobe n> 
Dec 10 09:48:02 mylocalpc systemd-modules-load[781]: modprobe: ERROR: could not insert 'nvidia_modeset': Invali> 
Dec 10 09:48:02 mylocalpc systemd-modules-load[789]: modprobe: FATAL: Module nvidia-current-drm not found in di> 
Dec 10 09:48:02 mylocalpc systemd-modules-load[767]: Error running install command 'modprobe nvidia-modeset ; m> 
Dec 10 09:48:02 mylocalpc systemd-modules-load[767]: Failed to insert module 'nvidia_drm': Invalid argument 
Dec 10 09:48:02 mylocalpc systemd[1]: systemd-modules-load.service: Main process exited, code=exited, status=1/> 
Dec 10 09:48:02 mylocalpc systemd[1]: systemd-modules-load.service: Failed with result 'exit-code'. 
Dec 10 09:48:02 mylocalpc systemd[1]: Failed to start systemd-modules-load.service - Load 

To install dkms

root@mylocalpc:~# apt install dkms
dkms is already the newest version (3.2.2-1~deb13u1).
dkms set to manually installed.
Summary:
  Upgrading: 0, Installing: 0, Removing: 0, Not Upgrading: 1

To show dkms status

root@mylocalpc:~# dkms status
nvidia-current/550.163.01, 6.12.31-amd64, x86_64: installed 

To rebuild nvidia driver, it will build any kernel installed.

root@mylocalpc:~# dkms install nvidia-current/550.163.01
Sign command: /lib/modules/6.12.57+deb13-amd64/build/scripts/sign-file
Signing key: /var/lib/dkms/mok.key
Public certificate (MOK): /var/lib/dkms/mok.pub

Building module(s)................ done.
Signing module /var/lib/dkms/nvidia-current/550.163.01/build/nvidia.ko
Signing module /var/lib/dkms/nvidia-current/550.163.01/build/nvidia-modeset.ko
Signing module /var/lib/dkms/nvidia-current/550.163.01/build/nvidia-drm.ko
Signing module /var/lib/dkms/nvidia-current/550.163.01/build/nvidia-uvm.ko
Signing module /var/lib/dkms/nvidia-current/550.163.01/build/nvidia-peermem.ko
Installing /lib/modules/6.12.57+deb13-amd64/updates/dkms/nvidia-current.ko.xz
Installing /lib/modules/6.12.57+deb13-amd64/updates/dkms/nvidia-current-modeset.ko.xz
Installing /lib/modules/6.12.57+deb13-amd64/updates/dkms/nvidia-current-drm.ko.xz
Installing /lib/modules/6.12.57+deb13-amd64/updates/dkms/nvidia-current-uvm.ko.xz
Installing /lib/modules/6.12.57+deb13-amd64/updates/dkms/nvidia-current-peermem.ko.xz
Running depmod.... done.

to check status of nvidia modul

root@mylocalpc:~# dkms status
nvidia-current/550.163.01, 6.12.31-amd64, x86_64: installed
nvidia-current/550.163.01, 6.12.57+deb13-amd64, x86_64: installed

restart your debian. 

Friday, December 5, 2025

Pyhton3: playwright to get audio url stream

There are many tool to find url audio stream from radio station's page, here are a few list:

  1. playwright
  2. Selenium
  3. Puppeteer

To use Wget to find url audo on statik and simple web  

$ wget --spider -r -l 5 -nv -w 1 --no-clobber -A .mp3,.m3u8 "https://www.example.com/audio/stations" 2>&1 | grep -E '\.(mp3|m3u8)$' | awk '{print $3}' | sort -u > out_audio_urls.txt

Install playwright on debian with virtual environment:

myuser@mypc:~$ mkdir spider_playwright
myuser@mypc:~$ cd spider_playwright/
myuser@mypc:~/spider_playwright$ python3 -m venv venv
myuser@mypc:~/spider_playwright$ source venv/bin/activate
(venv) myuser@mypc:~/spider_playwright$ pip install playwright
Collecting playwright
  Downloading playwright-1.56.0-py3-none-manylinux1_x86_64.whl.metadata (3.5 kB)
Collecting pyee<14,>=13 (from playwright)
  Downloading pyee-13.0.0-py3-none-any.whl.metadata (2.9 kB)
Collecting greenlet<4.0.0,>=3.1.1 (from playwright)
  Using cached greenlet-3.2.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.metadata (4.1 kB)
Collecting typing-extensions (from pyee<14,>=13->playwright)
  Using cached typing_extensions-4.15.0-py3-none-any.whl.metadata (3.3 kB)
Downloading playwright-1.56.0-py3-none-manylinux1_x86_64.whl (46.3 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 46.3/46.3 MB 2.5 MB/s eta 0:00:00
Using cached greenlet-3.2.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (610 kB)
Downloading pyee-13.0.0-py3-none-any.whl (15 kB)
Using cached typing_extensions-4.15.0-py3-none-any.whl (44 kB)
Installing collected packages: typing-extensions, greenlet, pyee, playwright
Successfully installed greenlet-3.2.4 playwright-1.56.0 pyee-13.0.0 typing-extensions-4.15.0
(venv) myuser@mypc:~/spider_playwright$ playwright install
Downloading Chromium 141.0.7390.37 (playwright build v1194) from https://cdn.playwright.dev/dbazure/download/playwright/builds/chromium/1194/chromium-linux.zip
173.9 MiB [====================] 100% 0.0s
Chromium 141.0.7390.37 (playwright build v1194) downloaded to /home/myuser/.cache/ms-playwright/chromium-1194
Downloading Chromium Headless Shell 141.0.7390.37 (playwright build v1194) from https://cdn.playwright.dev/dbazure/download/playwright/builds/chromium/1194/chromium-headless-shell-linux.zip
104.3 MiB [====================] 100% 0.0s
Chromium Headless Shell 141.0.7390.37 (playwright build v1194) downloaded to /home/myuser/.cache/ms-playwright/chromium_headless_shell-1194
Downloading Firefox 142.0.1 (playwright build v1495) from https://cdn.playwright.dev/dbazure/download/playwright/builds/firefox/1495/firefox-debian-13.zip
96.7 MiB [====================] 100% 0.0s
Firefox 142.0.1 (playwright build v1495) downloaded to /home/myuser/.cache/ms-playwright/firefox-1495
Downloading Webkit 26.0 (playwright build v2215) from https://cdn.playwright.dev/dbazure/download/playwright/builds/webkit/2215/webkit-debian-13.zip
88.1 MiB [====================] 100% 0.0s
Webkit 26.0 (playwright build v2215) downloaded to /home/myuser/.cache/ms-playwright/webkit-2215
Downloading FFMPEG playwright build v1011 from https://cdn.playwright.dev/dbazure/download/playwright/builds/ffmpeg/1011/ffmpeg-linux.zip
2.3 MiB [====================] 100% 0.0s
FFMPEG playwright build v1011 downloaded to /home/myuser/.cache/ms-playwright/ffmpeg-1011

create file myspider.py and customize to your requirements, make it executable

(venv) myuser@mypc:~/spider_playwright$ chmod u+x myspider.py 

source code myspider.py modify it to meet your requirements 

import asyncio
from playwright.async_api import async_playwright

# generated and adjust by chatgpt.com

AUDIO_HINTS = [
    ".mp3", ".aac", ".m3u8", ".ogg", ".opus", ".wav",
    "stream", "/proxy/", "/live", "radio"
]

async def scan_audio_stream(url: str, listen_seconds: int = 15):
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=False)
        page = await browser.new_page()

        # ----- Detect manual browser close -----
        browser_disconnected = asyncio.Event()

        def on_browser_disconnect():
            print("\n[BROWSER CLOSED] Exiting application.")
            browser_disconnected.set()

        browser.on("disconnected", on_browser_disconnect)
        # ---------------------------------------

        found = set()

        async def on_response(res):
            u = res.url.lower()
            ct = res.headers.get("content-type", "").lower()

            if "audio" in ct or any(k in u for k in AUDIO_HINTS):
                if u not in found:
                    print(f"[NEW AUDIO STREAM] {u}")
                    found.add(u)

        page.on("response", on_response)

        print("Opening page...")
        await page.goto(url, wait_until="domcontentloaded")
        await asyncio.sleep(2)

        # ---- Find audio player iframe ----
        candidate_frames = [
            f for f in page.frames
            if any(kw in f.url.lower() for kw in ["player", "radio", "embed"])
        ]
        if not candidate_frames:
            candidate_frames = page.frames  # fallback

        print("Attempting to click play...")
        for f in candidate_frames:
            try:
                for sel in ["button[aria-label='Play']", "button.play", ".jp-play", "button"]:
                    btn = await f.query_selector(sel)
                    if btn:
                        print(f"Clicked play in iframe → {f.url}")
                        await btn.click()
                        break
            except:
                pass

        print(f"\nListening for audio streams up to {listen_seconds} seconds...\n")

        # ----- Wait for 15 seconds OR browser close -----
        try:
            await asyncio.wait_for(browser_disconnected.wait(), timeout=listen_seconds)
        except asyncio.TimeoutError:
            print("\n[TIMEOUT] Done scanning.")
        # -------------------------------------------------

        await browser.close()
        return list(found)


if __name__ == "__main__":
    results = asyncio.run(scan_audio_stream(
        "https://www.example.com", # CHANGE HERE
        listen_seconds=15     # ← Fast scan
    ))

    print("\n===== ALL STREAMS FOUND =====")
    for s in results:
        print(s)

Code

from playwright.sync_api import sync_playwright

def main():
    with sync_playwright() as p:
        browser = p.chromium.launch(
            headless=False   # <-- You can manually interact
        )
        context = browser.new_context()
        page = context.new_page()

        print("🚀 Browser launched. Type the radio station URL manually.")
        print("👉 When you press Play, audio stream URLs will appear here.\n")

        # Capture outgoing requests
        def on_request(request):
            url = request.url

            if (
                ".mp3" in url or
                ".aac" in url or
                ".m3u8" in url or
                ".ogg" in url or
                "stream" in url.lower() or
                request.resource_type == "media"
            ):
                print("🎧 AUDIO STREAM REQUEST FOUND:")
                print(url, "\n")

        page.on("request", on_request)

        # Capture responses containing audio
        def on_response(response):
            url = response.url
            headers = response.headers
            content_type = headers.get("content-type", "")

            if any(fmt in content_type for fmt in ["audio", "mpeg", "aac", "ogg"]):
                print("🎧 AUDIO STREAM RESPONSE FOUND:")
                print(url, "\n")

        page.on("response", on_response)

        # Open a blank page — you will type the URL manually
        page.goto("about:blank")

        # Keep browser open
        browser.wait_for_event("disconnected")


if __name__ == "__main__":
    main()

Enjoy

Thursday, December 4, 2025

Android java: improving application screen form factor

In AndroidManifest.xml we can define screen form factor to used (androidmanifest.xml android:screenOrientation).

These are the options

  1. "unspecified" : The default value. The system chooses the orientation. The policy it uses, and therefore the choices made in specific contexts, might differ from device to device.
  2. "behind" : The same orientation as the activity that's immediately beneath it in the activity stack.
  3. "landscape" : Landscape orientation (the display is wider than it is tall).
  4. "portrait" : Portrait orientation (the display is taller than it is wide).
  5. "reverseLandscape" : Landscape orientation in the opposite direction from normal landscape. Added in API level 9.
  6. "reversePortrait" : Portrait orientation in the opposite direction from normal portrait. Added in API level 9.
  7. "sensorLandscape" : Landscape orientation, but can be either normal or reverse landscape based on the device sensor. The sensor is used even if the user has locked sensor-based rotation. Added in API level 9.
  8. "sensorPortrait" : Portrait orientation, but can be either normal or reverse portrait based on the device sensor. The sensor is used even if the user has locked sensor-based rotation. However, depending on the device configuration, upside-down rotation might not be allowed. Added in API level 9.
  9. "userLandscape" : Landscape orientation, but can be either normal or reverse landscape based on the device sensor and the user's preference. Added in API level 18.
  10. "userPortrait" : Portrait orientation, but can be either normal or reverse portrait based on the device sensor and the user's preference. However, depending on the device configuration, upside-down rotation might not be allowed. Added in API level 18.
  11. "sensor" : The device orientation sensor determines the orientation. The orientation of the display depends on how the user is holding the device. It changes when the user rotates the device. Some devices, though, don't rotate to all four possible orientations, by default. To use all four orientations, use "fullSensor". The sensor is used even if the user locked sensor-based rotation.
  12. "fullSensor" : The device orientation sensor determines the orientation for any of the four orientations. This is similar to "sensor", except this allows for any of the four possible screen orientations regardless of what the device normally supports. For example, some devices don't normally use reverse portrait or reverse landscape, but this enables those orientations. Added in API level 9.
  13. "nosensor" : The orientation is determined without reference to a physical orientation sensor. The sensor is ignored, so the display doesn't rotate based on how the user moves the device.
  14. "user" : The user's current preferred orientation.
  15. "fullUser" : If the user has locked sensor-based rotation, this behaves the same as user, otherwise it behaves the same as fullSensor and allows any of the four possible screen orientations. Added in API level 18.
  16. "locked" : Locks the orientation to its current rotation, whatever that is. Added in API level 18. 

Warning: To improve the layout of apps on form factors with smallest width >= 600dp, the system ignores the following values of this attribute for apps that target Android 16 (API level 36):

  1.     portrait
  2.     landscape
  3.     reversePortrait
  4.     reverseLandscape
  5.     sensorPortrait
  6.     sensorLandscape
  7.     userPortrait
  8.     userLandscape 

To create variant for table,  Goto main activity, on your main activity dropdown select "create table qualifier", it will create copy of main activity that require to modify to match tablet out. the layout is on layout -> main_activity -> main_activity.xml (sw600dp).

I use:

  1. main_activity.xml
  2. main_activity.xml (sw600dp)
main_activity.xml will be use for all mobile device, don't create main_activity (land). main_activity.xml (sw600dp) will be use on tablet. 

In case you want to lock phone to use portrait, delete main_activity.xml (land), you need to remove android:screenOrientation from AndroidManifest.xml. To make it consistent, this is sample of code in java for your main activity

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // 1. Enable edge-to-edge for Java Activities
        // You need to import androidx.activity.EdgeToEdge;
        EdgeToEdge.enable(this);
        super.onCreate(savedInstanceState);
        // Fragment
        // layout portrait or lanscape?
        // portrait my_fragment_container
        // langsacpe fragment_config_container, fragment_main_container
        setContentView(R.layout.activity_m); // general, let system choose between portrait and landscape
        // Check if landscape (two-pane) layout is active
        View config = findViewById(R.id.fragment_config_container);
        View main = findViewById(R.id.fragment_main_container);
        isTwoPane = (config != null && main != null); // already checked not null
        // Conditional Orientation Lock
        if (!isTwoPane) {
            // If single-pane (phone), force portrait before fragment transactions
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        }
        if (isTwoPane) {
            // dual-pane
            setFragment(R.id.fragment_config_container, new FragmentConfig());
            setFragment(R.id.fragment_main_container, new FragmentMain());
        } else {
            // single-pane
            // all phone must use this activity_m.xml (land)
            setFragment(R.id.my_fragment_container, new FragmentMain());
        } 

Immediately, lock screen for single pane (phone) to portrait, i.e. setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 

Wednesday, December 3, 2025

Debian 13: bash script to show nvme/ssd healthy and cpu temperature

Requirement

  1. smartmontools
  2. lm-sensors
  3. psensor 

Installation

# apt-get install smartmontools lm-sensors psensor

copy paste this script to show general temperature on nvme/ssd and cpu. It also give information about nvme/ssd healthy.

#!/bin/bash
# this code generated by chatgpt.com no sign in
# each step was interactive, output from pc will be feed to chatgpt to generate correct output

DRIVE=${1:-/dev/sda}

echo "=== SMART Drive Information ($DRIVE) ==="

sudo smartctl -H -A "$DRIVE" | awk '
/^SMART overall-health/      {print "Drive Health: " $NF}
/^194 Temperature_Celsius/   {print "Drive Temperature: " $10 "°C"}
/^190 Airflow_Temperature/   {print "Drive Temperature: " $10 "°C"}
'

echo
echo "=== CPU Temperature ==="
sensors | awk '
/k10temp/ {found=1}
/temp1:/ && found {print "CPU Temp:", $2; found=0}
'

echo
echo "=== GPU Temperature (AMDGPU) ==="
sensors | awk '
/amdgpu/ {found=1}
/edge:/ && found {print "GPU Temp:", $2; found=0}
'

echo
echo "=== ACPI Temperatures ==="
sensors | awk '
/acpitz/ {block=1}
/temp/ && block {print "ACPI " $1, $2}
/^\s*$/ {block=0}
'

Change permission

# chmod u+x ./checkme.sh

Run as sudo or root 

Tuesday, December 2, 2025

Android java: Releasing resource Activity/Fragment <-> AndroidViewModel <-> MyController

Activity/Fragment <-> AndroidViewModel <-> MyController

MyController will hold

  1. Executor
  2. MediaController 
  3. Network access
  4. Database access
  5. Application context for above operation  

Proper way to clear the resource

  1. Executor
            // MyAndroidViewModel onClear() has been reached
            if (myExecutor!=null) {
                myExecutor.shutdown();
                myExecutor = null;
            }
  2. Media Controller
            if (myMediaController!=null) {
                myMediaController.releaseMediaSession(); // MUST BE CLEAR
                myMediaController = null;
            }
  3. Network access
            myGetRadioLogo=null;
  4. Database access  
            myDBAccess=null;
  5. Application context
            appContext=null; // MUST SET NULL AT ONCLEAR

Fail to release these resources may lead to memory leak

Fail to release resource with not properly sequence may lead application crashed, this crash can be found on logcat.  

Debian 13: part 3 participate your vps, cofigure your vps as tor relay/exit

There 2 type of TOR network you an configure on VPS

  1. Relay
  2. Exit

Minimum system requirement:

  1. CPU 1 vcpu
  2. Ram 512MB (1GB Recommended)
  3. Bandwidth 10 Mbps in & out
  4. Traffic 100 GB in & out
  5. Disk 200 MB 
  6. swap not mention (better twice RAM size) 

Enable Debian 13 auto upgrade

# apt install unattended-upgrades
# systemctl enable unattended-upgrades
# systemctl start unattended-upgrades

Installing tor packages and key

  1. Install require software
    # apt install apt-transport-https gnupg
  2. Create /etc/apt/sources.list.d/tor.list with:
    deb     [signed-by=/usr/share/keyrings/deb.torproject.org-keyring.gpg] https://deb.torproject.org/torproject.org trixiemain
    deb-src [signed-by=/usr/share/keyrings/deb.torproject.org-keyring.gpg] https://deb.torproject.org/torproject.org trixie main
  3. installing key and tor
    # wget -qO- https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc | gpg --dearmor | tee /usr/share/keyrings/deb.torproject.org-keyring.gpg >/dev/null
    # apt install tor deb.torproject.org-keyring
    # apt install tor

Note: you can browse using browser https://deb.torproject.org/torproject.org/ if A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc has change 

TOR relay 

TOR relay consider safer way to contribute to TOR network, It does not act as critical point entry or exit network. 

configure your tor relay /etc/tor/torrc:

Nickname    myNiceRelay  # Change "myNiceRelay" to something you like
ContactInfo your@e-mail  # Write your e-mail and be aware it will be published
ORPort      443          # You might use a different port, should you want to
ExitRelay   0
SocksPort   0 

Enable and restart tor service

# systemctl enable tor
# systemctl restart tor

TOR Exit

Exit TOR may have high security risk including breaking law. you need to carefully decide your county's rules where your vps located. Some country has aware with Exit TOR node.  

install unbound dns resolver

  1. install unbound
    # apt install unbound
  2. configure dns resolver using localhost
    # cp /etc/resolv.conf /etc/resolv.conf.backup
    # echo nameserver 127.0.0.1 > /etc/resolv.conf
  3. protect resolver from change
    # chattr +i /etc/resolv.conf
  4. edit unbound configuration
    server:    ...
        qname-minimisation: yes
        ...
  5. enable and restart unbound
    # systemctl enable unbound
    # systemctl restart unbound

Definitely do not use torproject.org as a domain name for your reverse DNS

configure your tor relay /etc/tor/torrc:

Nickname    myNiceRelay  # Change "myNiceRelay" to something you like
ContactInfo your@e-mail  # Write your e-mail and be aware it will be published
ORPort      443          # You might use a different port, should you want to
ExitRelay   1            # it is exit relay
SocksPort   0
RunAsDaemon 1
#IPv6Exit 1               # Advertise and allow IPv6 exits automatically
#AvoidDiskWrites 1
#Sandbox 1
# example policy
ExitPolicy reject *:25,reject *:119,reject *:135,reject *:445,reject *:563,reject *:1214,reject *:4661:4666,reject *:6346,reject *:6697,reject *:6881:6999
ExitPolicy accept *:80,accept *:443,accept *:53,accept *:443
## === Bandwidth limits ===
#RelayBandwidthRate 3 MBytes
#RelayBandwidthBurst 5 MBytes
## === Accounting (optional traffic cap) ===
#AccountingMax 150 GBytes
#AccountingStart day 00:00
## === Logging ===
Log notice file /var/log/tor/notices.log

Enable and restart tor service

# systemctl enable tor
# systemctl restart tor

Wait until tor network recognize your node.

Done, now you are on track to run vps as tor volunteer.

Windows 11: installing windows 11 and post configuration part 2

Copy your windows iso into Ventoy USB data partition, not in boot partition. you can create folder windows and put iso file in this directory. Ventoy boot manager will find any bootable iso file in Ventoy data partition. see here to create Ventoy USB boot manager https://dedetoknotes.blogspot.com/2025/09/debian-13-using-ventoy-to-create.html

Before you starting to. install in computer/laptop, in my case axioo Hype 5 x6, download wifi driver, it does not have Ethernet port. if you have Ethernet port, download it. if those driver are zip, extract it, and put in Ventoy data directory. e.g. after you extract file in directory wifi, copy directory wifi into Ventoy data -> driver (optional you need to create). 

To start installing windows 11, insert Ventoy USB that has been prepared before and turn your laptop/pc on. it will show which iso you want to run. 

Note: you need to change UEFI boot order if you use used nvme contains working os!

installation windows is straight forward. if you use iso windows 11 24h2 or after, you need outlook account or Hotmail if you come from generation like me ☺️. when it reach internet connection, install driver that has been provided in Ventoy USB data.

if you use windows 11 iso 23h2 or before, you can bypass it by pressing shift+f10 when windows ask internet connection and run:

OOBE\BYPASSNRO

after you enter that command, it will reboot/restart. now you can choose no connection internet and create local account. 

after finish, login into windows, go to system, update and check additional update to update hardware driver. update all driver, include printer you want to use. 

if you need software/driver for printer and scanner, find it in windows store and install it. for HP printer inktank multi function, you need to update windows driver. windows said it is optional, but in my opinion it is bridge between system and HP Smart from windows store.

Tweak your windows post installation (optional)

Turning off fast boot 

turn off fast boot if you want to dual boot later. if it is turn on, windows will never unmount driver/partition they use. any files and folder created from second os will be thread as not valid. it will setback to position when windows shutdown. turn off fast boot will completely unmount any drive/partition.

I usually prefer for performance, go to control panel -> system -> advanced system settings or run sysdm.cpl. select performance.

Set fix windows virtual memory

I also use fix windows Virtual Memory / swap. from sysdm.cpl, select Virtual Memory Settings.

select custom size. if your memory less then 16GB, the value is equal twice of your physical ram. e.g physical ram 8GB, use 8GB, if ram 4GB use 8GB. if you use 16 or above, put this value 4GB. set minimum and maximum with the same value e.g 4GB in my case axioo Hype 5 x6 with ram ddr5 2x8GB.

note: there is performance penalty when you windows run out of physical ram and use swap into virtual memory, i.e your nvme. event it is fast as close to pci speed, it will slower due to overhead swap ram to disk vice versa and also reduce your nvme life! when you need bigger memory, do upgrade instead of make virtual memory bigger.

Monitor your NVME

install CrystalDiskInfo to monitor NVME, don't let run your nvme run on high temperatur for long time wihtout proper heat sink or cooling system, especially of laptop. In my option running nvme on 70°C or above on a long time may damage your nvme's chips.

Using windows encryption (bitlocker) on nvme may arise higher activity and increase temperature. if it is not urgent, don't use it.  when it bitlocker turning on or turning off, it will start encrypt or decrypt your entire harddisk. in Task manager it will show 100% harddisk utilization and at CrystalDiskInfo the temperature may arise

Adding Local Account 

for windows with link account to outlook or Hotmail, here is how you create local account.

  1. run cmd as administor 
  2. command to create local user
    > net user myname mypassword /add
  3. to set user myname as administor 
    > net localgroup administrators myname /add
  4. to verify user 
    > net user
  5. sign out and try sign in with local account.

note; you can remove account linked to outlook or Hotmail using local administrator user created before.