Service d'arrière-plan · Extension GNOME Shell · Ubuntu 26.04

Tu copies.
Il transforme.
Tu colles.

UltraClipboard tourne en fond. Quand un texte que tu copies correspond à l'une de tes règles, il le remplace par ce que tu voulais vraiment coller : un calcul par son résultat, des dollars par des euros, une URL par son titre. Une règle, c'est une regex et le programme de ton choix.

Exemples : « 128 * 12 = » devient « 1536 » ; « 49 $ » devient « 43,70 € » ; « 3pm PST » devient « 00:00 (heure de Paris) » ; une URL YouTube devient un lien Markdown avec le titre de la vidéo.

Comment ça marche

Rien à apprendre. Tu copies comme d'habitude.

Une extension GNOME Shell voit chaque copie et la confie à un service qui tourne en fond. Si une de tes règles reconnaît le texte, le résultat remplace le presse-papier avant que tu colles.

Tu copies

Ctrl + C, n'importe où : navigateur, terminal, messagerie.

Une règle reconnaît le texte

La première règle dont le motif correspond lance son pipeline. Aucune ne correspond ? Il ne se passe rien.

Tu colles le résultat

Une notification confirme. Super + Shift + V remet l'original si tu changes d'avis.

Recettes

Neuf règles prêtes à copier.

Une recette, c'est une règle et son pipeline. Copie celles qui te servent dans ta config, ou écris les tiennes : tout programme qui lit un texte et en rend un autre fait l'affaire.

Pour tout le monde

Un calculLe signe = à la fin sert de déclencheur. Sans lui, rien ne bouge. 128 * 12 =1536 Recette
pipelines:
  calcul:
    - command:
        - sh
        - -c
        - |
          { echo 'scale=2'; tr -d '= ' | tr ',' '.'; echo; } | bc | tr '.' ','

rules:
  - match: '^\s*[\d\s.,()+*/-]*\d[\d\s.,()]*[+*/-][\d\s.,()+*/-]*\d[\s)]*=\s*$'
    pipeline: calcul
Des dollars en eurosPasse par le réseau : le montant, et lui seul, est envoyé à frankfurter.dev, qui publie les taux des banques centrales. 49 $43,70 € Recette
pipelines:
  dollars-en-euros:
    - command:
        - sh
        - -c
        - |
          montant=$(tr -cd '0-9.,' | tr ',' '.')
          curl -fsS "https://api.frankfurter.dev/v1/latest?amount=$montant&base=USD&symbols=EUR" \
            | jq -r '.rates.EUR' \
            | LC_ALL=C awk '{printf "%.2f €", $1}' | tr '.' ','

rules:
  - match: '(?i)^\s*(\$\s*\d+([.,]\d+)?|\d+([.,]\d+)?\s*(\$|USD|dollars?))\s*$'
    pipeline: dollars-en-euros
Une heure d'un autre fuseauFuseaux nord-américains, UTC et GMT, ramenés à l'heure de Paris. 3pm PST00:00 (heure de Paris) Recette
pipelines:
  heure-de-paris:
    - trim
    - command:
        - sh
        - -c
        - |
          TZ=Europe/Paris date -d "$(cat)" '+%H:%M (heure de Paris)'

rules:
  - match: '(?i)^\s*\d{1,2}(:\d{2})?\s*(am|pm)?\s+(PST|PDT|MST|MDT|CST|CDT|EST|EDT|UTC|GMT)\s*$'
    pipeline: heure-de-paris
Des miles, des pieds, des °FTrois petites règles, une par unité. Ajoute les tiennes sur le même modèle. 26.2 miles42,2 km Recette
pipelines:
  miles-en-kilometres:      # 26.2 miles → 42,2 km
    - command:
        - sh
        - -c
        - |
          tr ',' '.' | LC_ALL=C awk '{printf "%.1f km", $1 * 1.609344}' | tr '.' ','
  pieds-en-metres:          # 5 ft 11 → 1,80 m
    - command:
        - sh
        - -c
        - |
          tr -c '0-9\n' ' ' | LC_ALL=C awk '{printf "%.2f m", $1 * 0.3048 + $2 * 0.0254}' | tr '.' ','
  fahrenheit-en-celsius:    # 72°F → 22 °C
    - command:
        - sh
        - -c
        - |
          tr ',' '.' | LC_ALL=C awk '{printf "%.0f °C", ($1 - 32) * 5 / 9}'

rules:
  - match: '(?i)^\s*\d+([.,]\d+)?\s*(mi|miles?)\s*$'
    pipeline: miles-en-kilometres
  - match: '(?i)^\s*\d+\s*(ft|pieds?)(\s*\d+(\s*in)?)?\s*$'
    pipeline: pieds-en-metres
  - match: '^\s*-?\d+([.,]\d+)?\s*°\s*F\s*$'
    pipeline: fahrenheit-en-celsius
Un lien bourré de pistageRetire utm_…, fbclid, gclid et consorts. Les autres paramètres restent. exemple.fr/article?utm_source=lettre&fbclid=IwAR0xexemple.fr/article Recette
pipelines:
  lien-propre:
    - trim
    - command:
        - sed
        - -E
        - 's/([?&])(utm_[a-z_]+|fbclid|gclid|igshid|mc_eid)=[^&#]*/\1/g; s/([?&])&+/\1/g; s/[?&]+(#|$)/\1/'

rules:
  - match: '^\s*https?://\S+[?&](utm_[a-z_]+|fbclid|gclid|igshid|mc_eid)=\S*\s*$'
    pipeline: lien-propre
Une URL YouTubeUn exemple de service interrogé avec curl et jq. Passe par le réseau : l'URL copiée est envoyée à YouTube. youtube.com/watch?v=dQw4w9WgXcQ[Rick Astley - Never Gonna Give You Up](…) — [Rick Astley](…) Recette
pipelines:
  youtube-markdown:
    - trim
    - command:
        - sh
        - -c
        - |
          url=$(cat)
          curl -fsS --get --data-urlencode "url=$url" --data-urlencode "format=json" https://www.youtube.com/oembed \
            | jq -r --arg url "$url" 'def md: gsub("(?<c>[\\[\\]\\\\])"; "\\\(.c)"); "[\(.title | md)](\($url)) — [\(.author_name | md)](\(.author_url))"'

rules:
  - match: '^https?://(www\.)?(youtube\.com/watch|youtu\.be/)'
    pipeline: youtube-markdown

Pour le terminal

Du JSON sur une ligneAvec jq. Si ce n'est pas du JSON valide, tu colles l'original. {"nom":"UltraClipboard","regles":3}le même, indenté Recette
pipelines:
  json-lisible:
    - command: ["jq", "."]

rules:
  - match: '(?s)^\s*[{\[].*[}\]]\s*$'
    pipeline: json-lisible
Un numéro de ticketRemplace PROJ et l'adresse du tracker par les tiens. PROJ-1234[PROJ-1234](https://tracker.example.com/PROJ-1234) Recette
pipelines:
  lien-de-ticket:
    - trim
    - command: ["sed", "s|.*|[&](https://tracker.example.com/&)|"]

rules:
  - match: '^\s*PROJ-\d+\s*$'
    pipeline: lien-de-ticket
Une commande copiée d'une docRetire l'invite $ en début de ligne, sur chaque ligne. $ npm installnpm install Recette
pipelines:
  sans-invite:
    - command: ["sed", "-E", 's/^[[:space:]]*\$ +//']

rules:
  - match: '^\s*\$ +[A-Za-z./~]'
    pipeline: sans-invite

Les neuf recettes tiennent dans un seul fichier de config, rejoué contre le moteur à chaque passage des tests. Elles s'appuient sur des outils courants : sh, sed, awk, date, bc, jq, curl.

Configuration

Un fichier YAML, relu à chaque enregistrement.

Des pipelines nommés, des règles qui les déclenchent. Enregistre, c'est pris en compte. Si le fichier est invalide, l'ancienne config reste active et un message te dit pourquoi.

~/.config/ultraclipboard/config.yaml
config_version: 1
notifications: all          # all | errors | off

pipelines:
  json-lisible:
    - command: ["jq", "."]
  mon-script:
    - trim
    - command: ["python3", "~/scripts/corrige.py"]
      timeout: 5            # secondes, 10 par défaut

rules:                      # la première qui correspond gagne
  - match: '(?s)^\s*[{\[].*[}\]]\s*$'
    pipeline: json-lisible
  - match: '^Brouillon :'
    pipeline: mon-script
command
Le cœur de l'outil. N'importe quel programme : le texte copié arrive sur son entrée standard, ce qu'il écrit sur sa sortie devient le texte collé. Un script Python, sed, jq, un appel d'API : si ça tourne dans un terminal, ça fait une transformation. Lancé sans shell, avec un délai maximal.

Et quelques transformations intégrées

trim
Retire les espaces en début et en fin.
upper / lower
Majuscules ou minuscules, Unicode compris.

Confiance

Il lit tout ce que tu copies. Voici ce qu'il en fait.

Ce qu'il voit
Chaque texte copié, le temps de le comparer à tes règles. Les images et les fichiers sont ignorés.
Ce qu'il garde
Les 50 dernières transformations, en mémoire, effacées à l'arrêt. Une copie qu'aucune règle ne reconnaît ne laisse aucune trace. Rien n'est écrit sur disque, rien dans le journal système.
Ce qui sort de ta machine
Rien, sauf ce que tes règles demandent. Une recette qui interroge un service, comme YouTube ou un taux de change, lui envoie le texte copié. Les autres ne touchent pas au réseau.
Ce que tu contrôles
La pause, depuis le menu de l'icône. Le retour à l'original, par un raccourci. Et si tu quittes l'appli, tes copies redeviennent des copies ordinaires.

Ce qu'il ne fait pas

  • Du texte seulement. Une image ou un fichier copié passe sans être touché.
  • GNOME sous Wayland seulement, testé sur Ubuntu 26.04. Ni Windows, ni macOS.
  • Il ne retarde pas ton collage. Coller avant la fin d'une transformation lente donne l'original.
  • Une règle se déclenche sur le contenu, pas à la demande : on ne choisit pas une transformation au moment de coller.
  • Pas de paquet tout prêt. L'installation compile l'appli sur ta machine.
  • La config s'écrit à la main. La fenêtre de l'appli affiche les règles et l'historique, sans les modifier.

Installation

Trois étapes, dont une déconnexion.

  1. Installe les prérequis

    Rust, bun et les paquets système de Tauri.

    sudo apt install build-essential pkg-config libwebkit2gtk-4.1-dev libsoup-3.0-dev libayatana-appindicator3-dev librsvg2-dev
  2. Clone et lance le script

    Il compile l'appli (compte quelques minutes), installe le service et active l'extension. Il n'installe aucun paquet système à ta place : s'il en manque un, il t'affiche la commande.

    git clone https://github.com/Schrubitteflau/UltraClipboard && cd UltraClipboard && ./install.sh
  3. Déconnecte-toi, reconnecte-toi

    Sous Wayland, GNOME ne charge une nouvelle extension qu'à l'ouverture de session. Ensuite, le service démarre tout seul à chaque session. Ta config est créée au premier lancement, avec une règle d'exemple.

Pour la suite, le README détaille la mise à jour et la désinstallation.