Horlonche

Poste sur Onche.org a une heure precise

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

You will need to install an extension such as Tampermonkey to install this script.

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name         Horlonche
// @namespace    http://tampermonkey.net/
// @version      9.0
// @description  Poste sur Onche.org a une heure precise
// @author       toi
// @match        https://onche.org/topic/*
// @match        https://onche.org/forum/*
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    var estForum = window.location.pathname.indexOf('/forum/') === 0;
    var timer = null;
    var modeChoisi = null;
 // 'topic', 'citation', 'nouveau'

    // =========================================================
    //  Panel
    // =========================================================

    var panel = document.createElement('div');
    panel.style.cssText = 'position:fixed;bottom:20px;right:20px;background:#1e2a3a;border:1px solid #4a90d9;border-radius:8px;padding:14px;z-index:99999;width:270px;font-family:sans-serif;font-size:13px;color:#eee;box-shadow:0 4px 15px rgba(0,0,0,0.5)';

    panel.innerHTML = ''
        + '<div style="font-weight:bold;margin-bottom:12px;font-size:14px;color:#4a90d9">Horlonche</div>'

        // --- Etape 1 : choisir le mode ---
        + '<div id="os-etape1">'
        + '<div style="margin-bottom:8px;color:#aaa;font-size:12px">Que veux-tu faire ?</div>'
        + (estForum
            ? '<button class="os-mode-btn" data-mode="nouveau" style="width:100%;padding:7px;margin-bottom:6px;background:#2c3e50;color:#eee;border:1px solid #4a90d9;border-radius:4px;cursor:pointer;text-align:left">📝 Créer un nouveau topic</button>'
            : '<button class="os-mode-btn" data-mode="topic" style="width:100%;padding:7px;margin-bottom:6px;background:#2c3e50;color:#eee;border:1px solid #4a90d9;border-radius:4px;cursor:pointer;text-align:left">💬 Répondre dans le topic</button>'
              + '<button class="os-mode-btn" data-mode="citation" style="width:100%;padding:7px;margin-bottom:6px;background:#2c3e50;color:#eee;border:1px solid #4a90d9;border-radius:4px;cursor:pointer;text-align:left">↩ Citer / répondre à un message</button>'
          )
        + '</div>'

        // --- Etape 2 : formulaire ---
        + '<div id="os-etape2" style="display:none">'
        + '<div id="os-label-mode" style="margin-bottom:10px;padding:5px 8px;background:#0d1b2a;border-radius:4px;font-size:12px;color:#4a90d9"></div>'
        + '<div id="os-instruction-citation" style="display:none;margin-bottom:10px;padding:6px;background:#2c1a00;border:1px solid #f39c12;border-radius:4px;font-size:11px;color:#f39c12">'
        + '⚠ Clique sur la flèche du message AVANT de cliquer "Programmer"</div>'
        + '<div id="os-champ-titre" style="display:none">'
        + '<label style="display:block;margin-bottom:4px">Titre du topic</label>'
        + '<input id="os-titre" type="text" placeholder="Titre..." style="width:100%;padding:5px;background:#0d1b2a;color:#eee;border:1px solid #4a90d9;border-radius:4px;margin-bottom:10px;box-sizing:border-box">'
        + '</div>'
        + '<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:4px">'        + '<label>Heure (HH:MM:SS)</label>'        + '<label style="font-size:11px;color:#aaa;cursor:pointer;display:flex;align-items:center;gap:4px">'        + '<input id="os-chk-jour" type="checkbox" style="cursor:pointer"> Choisir un jour'        + '</label>'        + '</div>'        + '<input id="os-heure" type="time" step="1" style="width:100%;padding:5px;background:#0d1b2a;color:#eee;border:1px solid #4a90d9;border-radius:4px;margin-bottom:6px;box-sizing:border-box">'        + '<div id="os-champ-jour" style="display:none;margin-bottom:10px">'        + '<input id="os-jour" type="date" style="width:100%;padding:5px;background:#0d1b2a;color:#eee;border:1px solid #4a90d9;border-radius:4px;box-sizing:border-box">'        + '</div>'
        + '<label style="display:block;margin-bottom:4px">Message</label>'
        + '<textarea id="os-message" rows="3" style="width:100%;padding:5px;background:#0d1b2a;color:#eee;border:1px solid #4a90d9;border-radius:4px;margin-bottom:6px;box-sizing:border-box;resize:vertical"></textarea>'
        + '<button id="os-btn-preview" style="width:100%;padding:5px;background:#2c3e50;color:#aaa;border:1px solid #4a90d9;border-radius:4px;cursor:pointer;font-size:12px;margin-bottom:10px">👁 Prévisualiser</button>'
        + '<button id="os-btn-start" style="width:100%;padding:7px;background:#4a90d9;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px;margin-bottom:6px">Programmer</button>'
        + '<button id="os-btn-back" style="width:100%;padding:5px;background:#2c3e50;color:#aaa;border:1px solid #4a90d9;border-radius:4px;cursor:pointer;font-size:12px">← Retour</button>'
        + '</div>'

        // --- Etape 3 : compte a rebours ---
        + '<div id="os-etape3" style="display:none">'
        + '<div id="os-label-attente" style="margin-bottom:10px;padding:5px 8px;background:#0d1b2a;border-radius:4px;font-size:12px;color:#4a90d9"></div>'
        + '<div id="os-status" style="font-size:22px;font-weight:bold;text-align:center;color:#4a90d9;margin:10px 0"></div>'
        + '<div id="os-status-sub" style="font-size:11px;text-align:center;color:#aaa;margin-bottom:10px"></div>'
        + '<button id="os-btn-stop" style="width:100%;padding:7px;background:#c0392b;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px">Annuler</button>'
        + '</div>';

    document.body.appendChild(panel);

    // =========================================================
    //  Navigation entre etapes
    // =========================================================

    // Etape 1 -> 2 : choix du mode
    var modeBtns = panel.querySelectorAll('.os-mode-btn');
    for (var i = 0; i < modeBtns.length; i++) {
        modeBtns[i].addEventListener('click', function () {
            modeChoisi = this.getAttribute('data-mode');
            afficherEtape2(modeChoisi);
        });
    }

    function afficherEtape2(mode) {
        document.getElementById('os-etape1').style.display = 'none';
        document.getElementById('os-etape2').style.display = 'block';

        var labels = { 'topic': 'Répondre dans le topic', 'citation': 'Citer un message', 'nouveau': 'Nouveau topic' };
        document.getElementById('os-label-mode').textContent = '→ ' + labels[mode];

        document.getElementById('os-instruction-citation').style.display = (mode === 'citation') ? 'block' : 'none';
        document.getElementById('os-champ-titre').style.display = (mode === 'nouveau') ? 'block' : 'none';
    }

    // Retour etape 2 -> 1
    document.getElementById('os-btn-back').addEventListener('click', function () {
        document.getElementById('os-etape2').style.display = 'none';
        document.getElementById('os-etape1').style.display = 'block';
        modeChoisi = null;
    });


    // Case a cocher jour
    document.getElementById('os-chk-jour').addEventListener('change', function () {
        var champJour = document.getElementById('os-champ-jour');
        if (this.checked) {
            champJour.style.display = 'block';
            // Prefill avec aujourd'hui
            var auj = new Date();
            var yyyy = auj.getFullYear();
            var mm = pad(auj.getMonth() + 1);
            var dd = pad(auj.getDate());
            document.getElementById('os-jour').value = yyyy + '-' + mm + '-' + dd;
        } else {
            champJour.style.display = 'none';
            document.getElementById('os-jour').value = '';
        }
    });

    // Etape 2 -> 3 : programmer
    document.getElementById('os-btn-start').addEventListener('click', function () {
        var heureVal   = document.getElementById('os-heure').value;
        var messageVal = document.getElementById('os-message').value.trim();
        var titreEl    = document.getElementById('os-titre');
        var titreVal   = titreEl ? titreEl.value.trim() : null;

        if (!heureVal)                       { alert('Choisis une heure !'); return; }
        if (!messageVal)                     { alert('Ecris un message !'); return; }
        if (modeChoisi === 'nouveau' && !titreVal) { alert('Ecris un titre !'); return; }

        var parts = heureVal.split(':');
        var cible = new Date();
        var jourVal = document.getElementById('os-jour').value;
        if (jourVal) {
            // Jour specifique choisi
            var jourParts = jourVal.split('-');
            cible.setFullYear(parseInt(jourParts[0]), parseInt(jourParts[1]) - 1, parseInt(jourParts[2]));
        }
        cible.setHours(parseInt(parts[0]), parseInt(parts[1]), parseInt(parts[2] || 0), 0);

        if (!jourVal && cible.getTime() <= Date.now()) {
            cible.setDate(cible.getDate() + 1);
        }

        document.getElementById('os-etape2').style.display = 'none';
        document.getElementById('os-etape3').style.display = 'block';

        var labels = { 'topic': 'Répondre dans le topic', 'citation': 'Citer un message', 'nouveau': 'Nouveau topic' };
        var jourVal2 = document.getElementById('os-jour').value;
        var labelJour = jourVal2 ? ' le ' + jourVal2.split('-').reverse().join('/') + ' à ' : ' à ';
        document.getElementById('os-label-attente').textContent = labels[modeChoisi] + labelJour + heureVal;

        lancerTimer(cible.getTime(), messageVal, titreVal, modeChoisi);
    });

    // Annuler
    document.getElementById('os-btn-stop').addEventListener('click', function () {
        if (timer) clearInterval(timer);
        timer = null;
        document.getElementById('os-etape3').style.display = 'none';
        document.getElementById('os-etape1').style.display = 'block';
        modeChoisi = null;
    });

    // =========================================================
    //  Timer
    // =========================================================

    function lancerTimer(tsEcheance, message, titre, mode) {
        timer = setInterval(function () {
            var resteMs = tsEcheance - Date.now();

            if (resteMs <= 0) {
                clearInterval(timer);
                timer = null;
                document.getElementById('os-status').textContent = 'Envoi...';
                document.getElementById('os-status-sub').textContent = '';

                if (mode === 'citation') {
                    posterCitation(message);
                } else if (mode === 'nouveau') {
                    posterNouveauTopic(titre, message);
                } else {
                    posterReponse(message);
                }
                return;
            }

            var resteS = Math.floor(resteMs / 1000);
            var h = Math.floor(resteS / 3600);
            var m = Math.floor((resteS % 3600) / 60);
            var s = resteS % 60;
            document.getElementById('os-status').textContent = pad(h) + ':' + pad(m) + ':' + pad(s);
        }, 50);
    }

    // =========================================================
    //  Poster une reponse normale dans le topic
    // =========================================================

    function posterReponse(message) {
        var textarea = document.querySelector("[placeholder*='Repondre au message']")
                    || document.querySelector("[placeholder*='Parle de ce que']")
                    || document.querySelector("textarea");

        if (!textarea) { terminer('Zone de texte introuvable !', false); return; }

        textarea.focus();
        textarea.value = message;
        textarea.dispatchEvent(new Event('input',  { bubbles: true }));
        textarea.dispatchEvent(new Event('change', { bubbles: true }));

        var bouton = trouverBoutonEnvoyer();
        if (!bouton) { terminer('Bouton Envoyer introuvable !', false); return; }

        bouton.click();
        terminer('Poste !', true);
    }

    // =========================================================
    //  Poster dans la popup de citation (deja ouverte par l'user)
    // =========================================================

    function posterCitation(message) {
        // La popup est deja ouverte, on cherche le textarea visible dedans
        var textareas = document.querySelectorAll('textarea');
        var textarea = null;
        var principal = document.querySelector("[placeholder*='Repondre au message']")
                     || document.querySelector("[placeholder*='Parle de ce que']");

        for (var i = 0; i < textareas.length; i++) {
            if (textareas[i] !== principal && textareas[i].offsetParent !== null) {
                textarea = textareas[i];
                break;
            }
        }

        if (!textarea) {
            // Fallback : la popup n'est peut-etre plus ouverte, on poste en reponse normale
            posterReponse(message);
            return;
        }

        textarea.focus();
        textarea.value = message;
        textarea.dispatchEvent(new Event('input',  { bubbles: true }));
        textarea.dispatchEvent(new Event('change', { bubbles: true }));

        // Cherche le bouton dans le meme formulaire
        var form = textarea.closest('form');
        var bouton = form ? form.querySelector("button[type='submit']") || form.querySelector('button') : null;
        if (!bouton) bouton = trouverBoutonEnvoyer();
        if (!bouton) { terminer('Bouton introuvable dans la popup !', false); return; }

        bouton.click();
        terminer('Citation postee !', true);
    }

    // =========================================================
    //  Creer un nouveau topic (page forum)
    // =========================================================

    function posterNouveauTopic(titre, message) {
        var champTitre = document.querySelector("[placeholder*='envie de parler']")
                      || document.querySelector("[placeholder*='titre' i]")
                      || document.querySelector("[placeholder*='title' i]");

        var champMessage = document.querySelector("[placeholder*='Parle de ce que']")
                        || document.querySelector("textarea");

        if (!champTitre || !champMessage) { terminer('Champs introuvables !', false); return; }

        champTitre.focus();
        champTitre.value = titre;
        champTitre.dispatchEvent(new Event('input',  { bubbles: true }));
        champTitre.dispatchEvent(new Event('change', { bubbles: true }));

        champMessage.focus();
        champMessage.value = message;
        champMessage.dispatchEvent(new Event('input',  { bubbles: true }));
        champMessage.dispatchEvent(new Event('change', { bubbles: true }));

        var bouton = trouverBoutonEnvoyer();
        if (!bouton) { terminer('Bouton Envoyer introuvable !', false); return; }

        bouton.click();
        terminer('Topic cree !', true);
    }

    // =========================================================
    //  Utilitaires
    // =========================================================

    function trouverBoutonEnvoyer() {
        return document.querySelector("button[type='submit']")
            || trouverBoutonParTexte('Envoyer')
            || trouverBoutonParTexte('Poster')
            || trouverBoutonParTexte('Publier')
            || document.querySelector('form button');
    }

    function trouverBoutonParTexte(texte) {
        var elements = document.querySelectorAll('button');
        for (var i = 0; i < elements.length; i++) {
            if (elements[i].textContent.trim().toLowerCase().indexOf(texte.toLowerCase()) !== -1) {
                return elements[i];
            }
        }
        return null;
    }

    function terminer(msg, succes) {
        document.getElementById('os-status').textContent = msg;
        document.getElementById('os-status').style.color = succes ? '#2ecc71' : '#e74c3c';
        setTimeout(function () {
            document.getElementById('os-etape3').style.display = 'none';
            document.getElementById('os-etape1').style.display = 'block';
            modeChoisi = null;
        }, 3000);
    }

    function pad(n) { return n < 10 ? '0' + n : '' + n; }

    // =========================================================
    //  Horloge dans le titre de l'onglet
    // =========================================================

    function mettreAJourTitre() {
        var maintenant = new Date();
        var h = pad(maintenant.getHours());
        var m = pad(maintenant.getMinutes());
        var s = pad(maintenant.getSeconds());
        document.title = h + ':' + m + ':' + s + ' | Horlonche';
    }

    mettreAJourTitre();
    setInterval(mettreAJourTitre, 1000);



    // =========================================================
    //  Fenetre de preview
    // =========================================================

    var previewBox = document.createElement('div');
    previewBox.style.cssText = 'display:none;position:fixed;bottom:20px;right:310px;background:#1e2a3a;border:1px solid #4a90d9;border-radius:8px;padding:14px;z-index:99998;width:340px;max-height:300px;font-family:sans-serif;font-size:14px;color:#eee;box-shadow:0 4px 15px rgba(0,0,0,0.5);overflow-y:auto;word-break:break-word;white-space:pre-wrap;line-height:1.6';
    document.body.appendChild(previewBox);

    var previewOuvert = false;

    document.getElementById('os-btn-preview').addEventListener('click', function () {
        var msg = document.getElementById('os-message').value;
        if (!previewOuvert) {
            previewBox.textContent = msg || '(message vide)';
            previewBox.style.display = 'block';
            this.textContent = '✕ Fermer la prévisualisation';
            this.style.color = '#4a90d9';
            previewOuvert = true;

            // Mise a jour en temps reel quand on tape
            document.getElementById('os-message').addEventListener('input', mettreAJourPreview);
        } else {
            previewBox.style.display = 'none';
            this.textContent = '👁 Prévisualiser';
            this.style.color = '#aaa';
            previewOuvert = false;
            document.getElementById('os-message').removeEventListener('input', mettreAJourPreview);
        }
    });

    function mettreAJourPreview() {
        var msg = document.getElementById('os-message').value;
        previewBox.textContent = msg || '(message vide)';
    }


})();