Jan 112026
 

Because at work I cannot enjoy the full copilot version and therefore cannot get transcripts (and minutes) from my teams meeting, i decided to give it a go with other tools.

I then discovered Whisper : « Whisper is an open‑source speech‑to‑text model designed by OpenAI to deliver accurate transcription across many languages. It handles real‑world audio remarkably well, even when recordings include background noise, accents, or imperfect microphone quality. Because it runs locally, it offers strong privacy and full control over your workflow. Its different model sizes—from tiny to large—let you balance speed and accuracy depending on your hardware and needs. »

Models can be downloaded here : tiny, base and small models are giving already really good results (before considering medium and large).

It is all about finding the right balance between time to process and accuracy.

Command line:

whisper-cli.exe --model "ggml-base.bin" --file "interview.wav" --output-txt --output-file "interview.txt" --threads 4 --language auto

I strongly recommend to also look at this GUI version here : it uses an older whisper version (probably compiled with openvino) which is delvering better results compared to the latest ggml-org whisper versions (which do no longer support openvino) : standard, blas (preferred) or cublas (you need cuda installed and a nvidia card).

I might give it a try to openvino in a near futur (time to settle the proper python environement, script, models, etc).

Déc 302025
 

8 years ago I had come with a dirty solution to graph my router bandwidth usage (here).

Now, we have AI (chatgpt here) and with a single prompt (« over ssh, retrieve my ddwrt bandwidth usage »), it provided me with a neat script/solution.

I then get a web page, refreshed hourly.

#!/bin/bash
set -e

# ==================================================
# Configuration
# ==================================================
ROUTER_IP="192.168.1.250"
ROUTER_USER="root"
SSH_KEY="$HOME/.ssh/id_ed25519"
OUTPUT_HTML="/var/www/html/traffic.html"

MONTH=$(date +%m)
YEAR=$(date +%Y)
NVRAM_KEY="traff-$MONTH-$YEAR"

GENERATED_AT=$(date '+%d/%m/%Y à %H:%M')

# ==================================================
# Récupération des données depuis le routeur
# ==================================================
RAW_DATA=$(ssh -i "$SSH_KEY" -q "$ROUTER_USER@$ROUTER_IP" "nvram get $NVRAM_KEY")

# Total mensuel [incoming:outgoing]
TOTAL=$(echo "$RAW_DATA" | grep -o '\[.*\]')

# Données journalières uniquement
DATA=$(echo "$RAW_DATA" | sed 's/\[.*\]//')

# ==================================================
# Génération de la page HTML (écriture root)
# ==================================================
sudo tee "$OUTPUT_HTML" > /dev/null <<EOF
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Trafic DD-WRT - $MONTH/$YEAR</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
  body {
    font-family: Arial, sans-serif;
    background: #f4f4f9;
    margin: 40px;
  }
  h1 {
    text-align: center;
  }
  #chart-container {
    max-width: 1100px;
    margin: auto;
  }
  .generated {
    position: fixed;
    bottom: 10px;
    right: 15px;
    font-size: 0.85em;
    color: #666;
  }
</style>
</head>
<body>

<h1>Trafic journalier DD-WRT – $MONTH/$YEAR</h1>

<div id="chart-container">
  <canvas id="trafficChart"></canvas>
</div>

<p style="text-align:center; font-size:1.1em;">
  <strong>Total du mois :</strong> $TOTAL MB (incoming : outgoing)
</p>

<div class="generated">
  Généré le $GENERATED_AT
</div>

<script>
const rawData = "$DATA";

const incoming = [];
const outgoing = [];

rawData.trim().split(' ').forEach(pair => {
  const [inVal, outVal] = pair.split(':').map(Number);
  incoming.push(inVal);
  outgoing.push(outVal);
});

const labels = Array.from({ length: incoming.length }, (_, i) => 'Jour ' + (i + 1));

const ctx = document.getElementById('trafficChart').getContext('2d');
new Chart(ctx, {
  type: 'bar',
  data: {
    labels: labels,
    datasets: [
      {
        label: 'Incoming (MB)',
        data: incoming,
        backgroundColor: 'rgba(54, 162, 235, 0.7)'
      },
      {
        label: 'Outgoing (MB)',
        data: outgoing,
        backgroundColor: 'rgba(255, 99, 132, 0.7)'
      }
    ]
  },
  options: {
    responsive: true,
    plugins: {
      legend: { position: 'top' },
      tooltip: {
        callbacks: {
          label: ctx =>
            ctx.dataset.label + ': ' + ctx.raw.toLocaleString() + ' MB'
        }
      }
    },
    scales: {
      x: { stacked: true },
      y: {
        stacked: true,
        beginAtZero: true,
        title: {
          display: true,
          text: 'MB'
        }
      }
    }
  }
});
</script>

</body>
</html>
EOF
Déc 212025
 

In previous articles, i have shared how to backup/restore files using Rclone.

Now for fun (and no profit) lets decrypt these files outside of Rclone using the password and salt from the rclone config (in rclone.conf).

Have a look at this github repo here.

Déc 212025
 

In previous article, i have explained how to rclone one local folder to a remote folder.

While doing so i had enable filename encryption.

It appears that it brings nothing but complexity (content encryption is all that matters to me) and i now want to revert to original filenames while not having to reupload it all.

Here below a dry run script (to test safely) and a real run script – all this from the synology command line.

Note that we need to suffix files with .bin or else rclone will not recognize the files as encrypted.

#!/bin/bash

REMOTE_CRYPT="ovhcrypt:"
REMOTE_RAW="ovhftp:/backup/"

echo "=== DRY RUN (DECRYPT NAMES + ADD .BIN) ==="

rclone lsf -R "$REMOTE_RAW" | while read -r path; do

    # Ignore les dossiers
    [[ "$path" == */ ]] && continue

    # Sépare dossier et fichier
    dir="${path%/*}"
    filename="${path##*/}"

    # Filtre : noms chiffrés rclone (base32, >=16 chars)
    if ! [[ "$filename" =~ ^[a-z0-9]{16,}$ ]]; then
        echo "Skip (not encrypted): $path"
        continue
    fi

    # Décrypte uniquement le nom du fichier
    decfile=$(rclone cryptdecode "$REMOTE_CRYPT" "$filename" 2>/dev/null | awk '{print $NF}')

    if [[ -z "$decfile" ]]; then
        echo "Skip (cryptdecode failed): $path"
        continue
    fi

    # Ajoute l'extension .bin
    decfile_bin="${decfile}.bin"

    # Reconstruit le chemin final
    if [[ "$dir" == "$path" ]]; then
        decpath="$decfile_bin"
    else
        decpath="$dir/$decfile_bin"
    fi

    echo "DRY RUN: Would rename: $path  -->  $decpath"

done

#!/bin/bash

REMOTE_CRYPT="ovhcrypt:"
REMOTE_RAW="ovhftp:/backup/"

echo "=== REAL RUN (DECRYPT NAMES + ADD .BIN) ==="

rclone lsf -R "$REMOTE_RAW" | while read -r path; do

    # Ignore les dossiers
    [[ "$path" == */ ]] && continue

    # Sépare dossier et fichier
    dir="${path%/*}"
    filename="${path##*/}"

    # Filtre : noms chiffrés rclone (base32, >=16 chars)
    if ! [[ "$filename" =~ ^[a-z0-9]{16,}$ ]]; then
        echo "Skip (not encrypted): $path"
        continue
    fi

    # Décrypte uniquement le nom du fichier
    decfile=$(rclone cryptdecode "$REMOTE_CRYPT" "$filename" 2>/dev/null | awk '{print $NF}')

    if [[ -z "$decfile" ]]; then
        echo "Skip (cryptdecode failed): $path"
        continue
    fi

    # Ajoute l'extension .bin pour compatibilité ovhcrypt2
    decfile_bin="${decfile}.bin"

    # Reconstruit le chemin final
    if [[ "$dir" == "$path" ]]; then
        decpath="$decfile_bin"
    else
        decpath="$dir/$decfile_bin"
    fi

    echo "Renaming: $path  -->  $decpath"

    # Renommage optimisé et OVH-friendly
    rclone moveto "$REMOTE_RAW$path" "$REMOTE_RAW$decpath" \
        --transfers 1 \
        --checkers 1 \
        --multi-thread-streams 0 \
        --ftp-concurrency 1 \
        --low-level-retries 3 \
        --retries 3 \
        --stats 10s

    # Petite pause pour éviter les 421
    sleep 0.2

done

Note, once all crypted filenames have been renamed to non encrypted filenames (with .bin extension), i stopped using ovhcrypt remote and switched to ovhcrypt2 remote.

my command is rclone sync /volume1/photo ovhcrypt2: –progress .

[ovhcrypt]
type = crypt
remote = ovhftp:/backup
directory_name_encryption = false
password = xxx
password2 = xxx

[ovhftp]
type = ftp
host = ftp.xxx.fr
user = username
pass = password

[ovhcrypt2]
type = crypt
remote = ovhftp:/backup
filename_encryption = off
directory_name_encryption = false
password = xxx
password2 = xxx
Déc 202025
 

For near 20 years, i am backuping my photos onto my synology (ds10x, ds20x, and now ds21x).

The risk is to lose them all because of crash or during a migration from one disk/model to another disk/model.

I decided to use rclone (running on my synology) to backup this local storage to a remote storage.

               ┌──────────────────────────────────────────┐
               │              Synology NAS                │
               │------------------------------------------│
               │  /volume1/photo                          │
               │     (unencrypted)                        │
               └───────────────┬──────────────────────────┘
                               │
                               │  rclone copy / sync
                               │  (unencrypted)
                               ▼
               ┌──────────────────────────────────────────┐
               │               rclone                     │
               │------------------------------------------│
               │  Remote 1 : ovhftp:                      │
               │     → FTP connection tp OVH              │
               │     → primary                            │
               │                                          │
               │  Remote 2 : ovhcrypt:                    │
               │     → crypt layer                        │
               │     → AES‑256 CTR + scrypt               │
               │     → content crypted                    │
               │     → based on : ovhftp:/backup          │
               │                                          │
               │  rclone.conf                             │
               │     → contains keys + remotes config     │
               └───────────────┬──────────────────────────┘
                               │
                               │  crypted files
                               │  (filenames scrambled)
                               ▼
               ┌──────────────────────────────────────────┐
               │                OVH FTP                   │
               │------------------------------------------│
               │  /backup                                 │
               │     (crypted scrambled)                  │
               │     ex :                                 │
               │       8sd7f9sd7f9sd7f9sd7f9sd7f          │
               │       7f8sd9f8sd9f8sd9f8sd9f8sd          │
               └──────────────────────────────────────────┘

Some useful commands:

rclone listremotes
rclone lsd ovhftp:/backup
rclone lsd ovhcrypt:
rclone config file
rclone copy /volume1/photo ovhcrypt: --progress

Restore would work as below:

OVH /backup (crypted files)


rclone (ovhcrypt:) → automatically decrypt


/volume1/photo (unencrypted restored files)

rclone copy ovhcrypt: /volume1/photo --progress

Avr 132025
 

Despite latest tuning (see previous article), the battery drain was still there, less severe, but still..

There I decided to root the tablet and install magisk.

Download the APK, copy/paste it and rename it to zip and flash it with twrp.

Reboot and install the apk.

Launch the app and let it update the tablet and reboot.

Then install xtrem-battery-saver in magisk as a module.

Here below my config.

While on low power mode, we are changing the CPU governors to powersave (android should do that while on power saving mode but just to be sure…).

While on screen off, we are disabling cpu2 to 7 and setting cpu governors to powersave on cpu0 to 1. Also we setting lower priority on google play services. Last but not least, we are forcing doze mode to light.

This rather aggressive config paid off : i can spend a whole day on screen off without losing any battery power.

version=2
delay=3
log_file=/sdcard/XtremeBS.log
log_level=1

screen_off={
handle_cores=cpu0 cpu1
disable_cores=cpu2 cpu3 cpu4 cpu5 cpu6 cpu7
handle_gms=nice
kill_wifi=true
keep_on_charge=true
doze=light
}

low_power={
keep_on_charge=true
handle_cores=auto
disable_cores=false
handle_apps=false
allowlist=/data/local/tmp/XtremeBS/apps.allow
denylist=/data/local/tmp/XtremeBS/apps.deny
handle_gms=false
handle_proc=false
proc_file=/data/local/tmp/XtremeBS/proc.list
low_ram=false
doze=false
kill_wifi=false
}

charging={
}

manual={
}

boot={
}
Avr 132025
 

A few weeks after flashing lineageos 21, i started to experience a massive battery drain : the tablet would lose all its battery power while on sitting idle, screen off, wifi off, on battery saving mode.

Therefore i took a look at the battery stats:

adb shell dumpsys batterystats --reset 

then a couple of hours later

adb shell dumpsys batterystats > [path/]batterystats.txt 

also i took a look at the doze log :

adb shell dumpsys deviceidle 

Based on my reading, I disabled the following packages:

adb shell pm disable-user –user 0 com.android.phone
adb shell pm disable-user –user 0 com.android.dialer
adb shell pm disable-user –user 0 com.android.messaging
adb shell pm disable-user –user 0 com.android.cellbroadcastreceiver

And just to be sure these do not interfere with doze mode:

adb shell dumpsys deviceidle sys-whitelist -com.android.messaging
adb shell dumpsys deviceidle sys-whitelist -com.android.cellbroadcastreceiver
adb shell dumpsys deviceidle sys-whitelist -com.android.cellbroadcastreceiver.module
adb shell dumpsys deviceidle sys-whitelist -com.android.emergency

Fév 212025
 

I have a galaxy tab a8 for a few years now (and i previously owned many different models in the galaxy tab series).
I use it mainly for web browsing, social networks and mails.
I was never impressed by the performances from day 1 but lately the tablet was really laggy and especially from waking up the device : for a few minutes, the tablet was barely usable.

So i decided to flash it, here below my steps.

  • Ensure you have the latest « Android SDK Platform-Tools » (version 35.0.2-12147458 in my case)
  • Ensure you have the latest « SAMSUNG USB Driver for Mobile Phones » (version 1.7.61.0 in my case)
  • Enable oem unlock in developper options (dont forget to reboot and enter download mode to actually activate oem unlock / the tablet will be reseted to factory)
  • Enter download mode and flash twrp via odin (AP slot / Use the MrFlufflyOven twrp 3.7.1)
  • Enter recovery mode (twrp) and reboot to fastbootd
  • While in fastbootd mode, flash new image (in my case: fastboot flash system lineage-21.0-20250125-UNOFFICIAL-arm64_bgN-signed.img from andyyan-gsi)
  • Optional : If the flashed image is not lineageos, consider flashing back the stock recovery (extracted with 7zip from the stock image downloaded from samfw.com)

The tablet rebooted smoothly to lineageos and has never been so well performing : user experience has never been so snappy 

Reminder :

  • To enter download mode, hold volume up and volume down at the same time then plug your usb cable connected to your computer.
  • To enter recovery mode, hold volume up and power buttons.

Jan 272025
 

In a previous article (here), we had seen how to convert a GPT disk to a MBR disk, without any data loss.

As indeed, your disk record (MBR or GPT) is actually only a header (i.e before your actual filesystem) pointing to your partition (aka volume aka filesystem…).

Of course, I would strongly advise not to do it against a production system (or at least not without a 200% trusted backup…).

This time, lets do it all from the command line:

rem create a fixed vhd, 512MB, to play with
vmount createfixedvhd f:\disk.vhd 512
rem attach the fixed vhd - note the disk number
vmount attachvhd f:\disk.vhd
rem create a MBR disk against the newly created physicaldrive
Rem make sure to adapt the disk number here!!!
vmount createdisk \\.\PhysicalDrive2 MBR
rem create a MBR part - a format window should popup, go for it
rem also note the offset and size like offset:1048576 & size:534773760
vmount createpart \\.\PhysicalDrive2 MBR
rem put some file on your MBR drive as a test for later
Rem lets pause
rem note : you only really need this second par
rem : the part above was meant to create a test disk
Pause
rem delete the disk to layout (not the data)
vmount deletedisklayout \\.\PhysicalDrive2
rem create a GPT disk
vmount createdisk \\.\PhysicalDrive2 GPT
rem create a GPT part with same offset and size as above
vmount createpart \\.\PhysicalDrive2 GPT 1 1048576 534773760
rem tada...you should now have a GPT drive, with your test file from previous step
Déc 142024
 

I have been using NordVPN for years now.

Thus I never wanted to install the NordVPN client (too heavy, too many features I dont need).

Hence I have been using OpenVPN (config files can be downloaded from NordVPN web site).

Lately I have read that Wireguard was quicker and that NordVPN was also supporting this protocol.

Below the procedure I have been using to create a Wireguard config (not as friendly as OpenVPN…).

  1. go to https://my.nordaccount.com/dashboard/nordvpn/manual-configuration/ and create an access token
  2. get your private key
curl -s -u token:<ACCESS_TOKEN> https://api.nordvpn.com/v1/users/services/credentials | jq -r .nordlynx_private_key
  1. get server info
curl -s "https://api.nordvpn.com/v1/servers/recommendations?&filters\[servers_technologies\]\[identifier\]=wireguard_udp&limit=1" | jq -r ".[]|.hostname, .station, (.locations|.[]|.country|.city.name), (.locations|.[]|.country|.name), (.technologies|.[].metadata|.[].value), .load"
  1. create wireguard config:
[Interface]
PrivateKey = <PRIVATE_KEY> # from step 2
Address = 10.5.0.2/32 # this IP is always the same
DNS = 9.9.9.9 # your favorite DNS server

[Peer]
PublicKey = <PUBLIC_KEY> # from step 3
AllowedIPs = 0.0.0.0/0, ::/0 # route everything
Endpoint = <ENDPOINT>:51820 # endpoint or IP from step 3, the port is always the same



And indeed, whereas I am getting circa 100 mb/s with OpenVPN on speedtest.net over a theoritical 1gb/s line, I am now able to reach 500mb/s with Wireguard 🙂

PS : i was able to run this procedure on both Linux and Windows (you need curl and jq on installed on your system).