Bitcoin Forum
June 16, 2026, 02:06:49 PM *
News: Latest Bitcoin Core release: 31.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: « 1 2 [3]  All
  Print  
Author Topic: [Userscript] Bitcointalk Merit Automation: Queue & Schedule Merit Distribution  (Read 1193 times)
LoyceV
Legendary
*
Offline

Activity: 4074
Merit: 22071


Thick-Skinned Gang Leader and Golden Feather 2021


View Profile WWW
June 08, 2026, 01:21:43 PM
Merited by promise444c5 (2)
 #41

i thought i saved the console output on the over 50 merits error but forgot to upload it, sorry.
OP can easily reproduce it: just try to send 51 Merit to someone.

¡uʍop ǝpᴉsdn pɐǝɥ ɹnoʎ ɥʇᴉʍ ʎuunɟ ʞool no⅄
promise444c5 (OP)
Hero Member
*****
Offline

Activity: 1050
Merit: 966


All things are numbers


View Profile WWW
June 08, 2026, 08:40:12 PM
Merited by vapourminer (3)
 #42

hit the 50 merits per month limit.. blame it on loycev





the error i get when manually trying to send 10 merits to that post:




havent checked any of the weird ignore stuff on other browsers yet. and i thought i saved the console output on the over 50 merits error but forgot to upload it, sorry.
But that’s the error page.. right? I can make use of the page content itself. All I will be needing is the count so I can put up the  remainder to the limit in the modal.

You haven’t run out of your source merit yet? I was waiting for Hugeblack before.. but it seems he also hasn’t exhausted his yet.

i thought i saved the console output on the over 50 merits error but forgot to upload it, sorry.
OP can easily reproduce it: just try to send 51 Merit to someone.
Didn’t know that was possible with below 50 smerits..

███████████████████████████
███████▄████████████▄██████
████████▄████████▄████████
███▀█████▀▄███▄▀█████▀███
█████▀█▀▄██▀▀▀██▄▀█▀█████
███████▄███████████▄███████
███████████████████████████
███████▀███████████▀███████
████▄██▄▀██▄▄▄██▀▄██▄████
████▄████▄▀███▀▄████▄████
██▄███▀▀█▀██████▀█▀███▄███
██▀█▀████████████████▀█▀███
███████████████████████████
.
.Duelbits PREDICT..
█████████████████████████
█████████████████████████
███████████▀▀░░░░▀▀██████
██████████░░▄████▄░░████
█████████░░████████░░████
█████████░░████████░░████
█████████▄▀██████▀▄████
████████▀▀░░░▀▀▀▀░░▄█████
██████▀░░░░██▄▄▄▄████████
████▀░░░░▄███████████████
█████▄▄█████████████████
█████████████████████████
█████████████████████████
.
.WHERE EVERYTHING IS A MARKET..
█████
██
██







██
██
██████
Will Bitcoin hit $200,000
before January 1st 2027?

    No @1.15         Yes @6.00    
█████
██
██







██
██
██████

  CHECK MORE > 
vapourminer
Legendary
*
Offline

Activity: 5068
Merit: 6339


what is this "brake pedal" you speak of?


View Profile
June 09, 2026, 04:01:12 PM
Merited by promise444c5 (2)
 #43

Quote from: promise444c5 link=topic=5584423.msg66813563#msg66813563

You haven’t run out of your source merit yet? I was waiting for Hugeblack before.. but it seems he also hasn’t exhausted his yet.

funny you should mention that... this will cross into my "regular" merit pile

edit: script just kept on trucking and used my regular merits to send once source merits were gone. nothing special in the log at all.

also that quote thing is on my end, has nothing to do with your scripts.
vapourminer
Legendary
*
Offline

Activity: 5068
Merit: 6339


what is this "brake pedal" you speak of?


View Profile
June 09, 2026, 04:07:37 PM
 #44

deliberate double post to test

and it did a double shot again, not sure why, i just revisited this page
vapourminer
Legendary
*
Offline

Activity: 5068
Merit: 6339


what is this "brake pedal" you speak of?


View Profile
June 09, 2026, 04:11:04 PM
 #45

2nd double post, pardon me
promise444c5 (OP)
Hero Member
*****
Offline

Activity: 1050
Merit: 966


All things are numbers


View Profile WWW
June 09, 2026, 04:21:09 PM
Last edit: June 10, 2026, 01:07:35 AM by promise444c5
 #46


edit: script just kept on trucking and used my regular merits to send once source merits were gone. nothing special in the log at all.
Ohh.. I get it . The error always look odd truly , you will only get it by reading the html page itself..

To my understanding, you don’t want to use your Own Smerit for qmerit when the source has been exhausted right?
How about allowing forceSend  to use from the normal Smerit? The error from the modal will tell you if you have any Source merit left.
Or I can track your  merit-source value and the normal Smerit  every time the script loads using the message LoyceV posted earlier. That way I can easily subtract what you have in the queue from the remaining and show you the balance.
Quote
also that quote thing is on my end, has nothing to do with your scripts.
Alryt.. I will ignore that.
deliberate double post to test

and it did a double shot again, not sure why, i just revisited this page

This one is Triples Tongue

███████████████████████████
███████▄████████████▄██████
████████▄████████▄████████
███▀█████▀▄███▄▀█████▀███
█████▀█▀▄██▀▀▀██▄▀█▀█████
███████▄███████████▄███████
███████████████████████████
███████▀███████████▀███████
████▄██▄▀██▄▄▄██▀▄██▄████
████▄████▄▀███▀▄████▄████
██▄███▀▀█▀██████▀█▀███▄███
██▀█▀████████████████▀█▀███
███████████████████████████
.
.Duelbits PREDICT..
█████████████████████████
█████████████████████████
███████████▀▀░░░░▀▀██████
██████████░░▄████▄░░████
█████████░░████████░░████
█████████░░████████░░████
█████████▄▀██████▀▄████
████████▀▀░░░▀▀▀▀░░▄█████
██████▀░░░░██▄▄▄▄████████
████▀░░░░▄███████████████
█████▄▄█████████████████
█████████████████████████
█████████████████████████
.
.WHERE EVERYTHING IS A MARKET..
█████
██
██







██
██
██████
Will Bitcoin hit $200,000
before January 1st 2027?

    No @1.15         Yes @6.00    
█████
██
██







██
██
██████

  CHECK MORE > 
vapourminer
Legendary
*
Offline

Activity: 5068
Merit: 6339


what is this "brake pedal" you speak of?


View Profile
June 09, 2026, 04:23:49 PM
 #47


edit: script just kept on trucking and used my regular merits to send once source merits were gone. nothing special in the log at all.

To my understanding, you don’t want to use your Own Smerit for qmerit when the source has been exhausted right?


oh no thats ok that acts like it should. i dont pay attention to whether its source merits or standard merits when i send so no need to modify anything there.
promise444c5 (OP)
Hero Member
*****
Offline

Activity: 1050
Merit: 966


All things are numbers


View Profile WWW
June 09, 2026, 04:34:23 PM
 #48

2nd double post, pardon me
Did this stopped because you were out of merit entirely?
Try merit manually..

███████████████████████████
███████▄████████████▄██████
████████▄████████▄████████
███▀█████▀▄███▄▀█████▀███
█████▀█▀▄██▀▀▀██▄▀█▀█████
███████▄███████████▄███████
███████████████████████████
███████▀███████████▀███████
████▄██▄▀██▄▄▄██▀▄██▄████
████▄████▄▀███▀▄████▄████
██▄███▀▀█▀██████▀█▀███▄███
██▀█▀████████████████▀█▀███
███████████████████████████
.
.Duelbits PREDICT..
█████████████████████████
█████████████████████████
███████████▀▀░░░░▀▀██████
██████████░░▄████▄░░████
█████████░░████████░░████
█████████░░████████░░████
█████████▄▀██████▀▄████
████████▀▀░░░▀▀▀▀░░▄█████
██████▀░░░░██▄▄▄▄████████
████▀░░░░▄███████████████
█████▄▄█████████████████
█████████████████████████
█████████████████████████
.
.WHERE EVERYTHING IS A MARKET..
█████
██
██







██
██
██████
Will Bitcoin hit $200,000
before January 1st 2027?

    No @1.15         Yes @6.00    
█████
██
██







██
██
██████

  CHECK MORE > 
DubemIfedigbo001
Hero Member
*****
Offline

Activity: 1064
Merit: 697


Let love lead


View Profile WWW
June 10, 2026, 01:14:46 PM
Merited by vapourminer (1), promise444c5 (1)
 #49

Good project promise444c5, This is a good level of creativity. I've gone through the replies and seen the updates which are cool, however I would recommend you have a clear log of pending fixes on your OP so that anyone interested in helping out would see immediately the areas the project needs necessary fixes and not just be going through the whole thread to find them out of which I got confused at some point on which ones are fixed and which is remaining.

Again I would want to propose these little modifications
1. A total count of queued merits to be disposed on next trigger so that the person would know the quantity of merits he is allocating to be sent at every point in time. it should be at the top precisely for visibility sake

2. This great tool should be used by everyone, so you can look into creating a modification that allows a user to just add posts to merit and allocated amounts to a queue so that when he is done, he can click an action button to send all at once. This would save the user the hassle of manually sending merit to  each users they wish to, so they may spend more time reading and allocating, then do the sending at once when they want to wind up. I like the idea of being able to use it even though I have merit and have the leverage of manually triggering the list.

That way users like
I will try it when I run out of sMerits quickly (Something that doesn't happen much lately Grin)

It seems like a great tool to me, although I don’t think I actually need to use it.

and many others can find this script very handy as they can find their use cases of it. I believe a solution fulfils its purpose when more people can use it, and I believe this update would make that possible.

A big thumbs up to vapourminer for his dedication in testing out this unique tool.

 
█▄
R


▀▀██████▄▄
████████████████
▀█████▀▀▀█████
████████▌███▐████
▄█████▄▄▄█████
████████████████
▄▄██████▀▀
LLBIT▀█ 
  TH#1 SOLANA CASINO  
████████████▄
▀▀██████▀▀███
██▄▄▀▀▄▄████
████████████
██████████
███▀████████
▄▄█████████
████████████
████████████
████████████
████████████
█████████████
████████████▀
████████████▄
▀▀▀▀▀▀▀██████
████████████
███████████
██▄█████████
████▄███████
████████████
█░▀▀████████
▀▀██████████
█████▄█████
████▀▄▀████
▄▄▄▄▄▄▄██████
████████████▀
........5,000+........
GAMES
 
......INSTANT......
WITHDRAWALS
..........HUGE..........
REWARDS
 
............VIP............
PROGRAM
 .
   PLAY NOW    
vapourminer
Legendary
*
Offline

Activity: 5068
Merit: 6339


what is this "brake pedal" you speak of?


View Profile
June 10, 2026, 02:14:32 PM
 #50

2nd double post, pardon me
Did this stopped because you were out of merit entirely?

no i wasnt out of my regular merits, just source merits.

i do remember at some point a post in the queue that said it had already merited a post, and another time a merit didnt get sent for unknown error so i used that exclamation point button "!" to resend. but im not sure of the timeline.

i do get click happy ngl
promise444c5 (OP)
Hero Member
*****
Offline

Activity: 1050
Merit: 966


All things are numbers


View Profile WWW
June 10, 2026, 03:07:39 PM
 #51

Did this stopped because you were out of merit entirely?

no i wasnt out of my regular merits, just source merits.

i do remember at some point a post in the queue that said it had already merited a post, and another time a merit didnt get sent for unknown error so i used that exclamation point button "!" to resend. but im not sure of the timeline.

i do get click happy ngl
Okay… it hard to really figure out what’s going on fr.. I tried to recreate the error yesterday but couldn’t . At first, I spent  30 mins trying to debug the unknown until I discovered that   I filled my initial success_log with a “null” value while testing Tongue. Including other test ,  i eventually got tired early and went to sleep. But I already started a locking mechanism implementation not too long ago.

Added some other changes too but I will list them when I’m done.

however I would recommend you have a clear log of pending fixes on your OP so that anyone interested in helping out would see immediately the areas the project needs necessary fixes and not just be going through the whole thread to find them out of which I got confused at some point on which ones are fixed and which is remaining.
Thanks DubemIfedigbo001..
My apologies on the log related comment.. That should have been easily accessible from GitHub but for absolutely dumb reason I haven’t retrieved access back to that my GitHub account.

You know what, I will try again today and tomorrow but anything beyond the current fix will be available on GitHub[New or Old]

███████████████████████████
███████▄████████████▄██████
████████▄████████▄████████
███▀█████▀▄███▄▀█████▀███
█████▀█▀▄██▀▀▀██▄▀█▀█████
███████▄███████████▄███████
███████████████████████████
███████▀███████████▀███████
████▄██▄▀██▄▄▄██▀▄██▄████
████▄████▄▀███▀▄████▄████
██▄███▀▀█▀██████▀█▀███▄███
██▀█▀████████████████▀█▀███
███████████████████████████
.
.Duelbits PREDICT..
█████████████████████████
█████████████████████████
███████████▀▀░░░░▀▀██████
██████████░░▄████▄░░████
█████████░░████████░░████
█████████░░████████░░████
█████████▄▀██████▀▄████
████████▀▀░░░▀▀▀▀░░▄█████
██████▀░░░░██▄▄▄▄████████
████▀░░░░▄███████████████
█████▄▄█████████████████
█████████████████████████
█████████████████████████
.
.WHERE EVERYTHING IS A MARKET..
█████
██
██







██
██
██████
Will Bitcoin hit $200,000
before January 1st 2027?

    No @1.15         Yes @6.00    
█████
██
██







██
██
██████

  CHECK MORE > 
fillippone
Legendary
*
Offline

Activity: 2926
Merit: 20833


Duelbits.com - Rewarding, beyond limits.


View Profile WWW
June 11, 2026, 07:58:57 PM
Merited by promise444c5 (2)
 #52

This is a very interesting project.
I think it could turn out to be useful, even if I rarely find myself in the condition of being totally depleted of my merit stash.
But as said many times, each MS has their own way of emptying their merit allowance, so thanks for the add!


███████████████████████████
███████▄████████████▄██████
████████▄████████▄████████
███▀█████▀▄███▄▀█████▀███
█████▀█▀▄██▀▀▀██▄▀█▀█████
███████▄███████████▄███████
███████████████████████████
███████▀███████████▀███████
████▄██▄▀██▄▄▄██▀▄██▄████
████▄████▄▀███▀▄████▄████
██▄███▀▀█▀██████▀█▀███▄███
██▀█▀████████████████▀█▀███
███████████████████████████
.
.Duelbits PREDICT..
█████████████████████████
█████████████████████████
███████████▀▀░░░░▀▀██████
██████████░░▄████▄░░████
█████████░░████████░░████
█████████░░████████░░████
█████████▄▀██████▀▄████
████████▀▀░░░▀▀▀▀░░▄█████
██████▀░░░░██▄▄▄▄████████
████▀░░░░▄███████████████
█████▄▄█████████████████
█████████████████████████
█████████████████████████
.
.WHERE EVERYTHING IS A MARKET..
█████
██
██







██
██
██████
Will Bitcoin hit $200,000
before January 1st 2027?

    No @1.15         Yes @6.00    
█████
██
██







██
██
██████

  CHECK MORE > 
promise444c5 (OP)
Hero Member
*****
Offline

Activity: 1050
Merit: 966


All things are numbers


View Profile WWW
June 12, 2026, 01:13:00 AM
Last edit: June 12, 2026, 05:19:24 PM by promise444c5
Merited by vapourminer (1)
 #53


i do remember at some point a post in the queue that said it had already merited a post, and another time a merit didnt get sent for unknown error so i used that exclamation point button "!" to resend. but im not sure of the timeline.

i didn't read this part clearly earlier .. Did the item/items you forceSend [!] went through? or it failed again?

This is a very interesting project.
I think it could turn out to be useful, even if I rarely find myself in the condition of being totally depleted of my merit stash.
But as said many times, each MS has their own way of emptying their merit allowance, so thanks for the add!

Thank you fillipone..

I made some changes that i haven't updated in the main OP post , i will do that probably tomorrow if the new update doesn't double send with some test. But you can aswell just use the one i'm about to post [only Post_Trigger fn]




The new update took me a while because i keep detecting new bugs even from the existing codes.. had to undo and redo multiple changes.
New update .. Here we Go!

Post_Trigger :  [edited ~ added more detail alert to  indicate failed items]
Code:
// ==UserScript==
// @name         Bitcointalk Merit Automation [Post_Trigger]
// @namespace    http://...
// @version      1.0
// @description  Queue posts to merit them later on next post.. User has to login for script to load.
// @author       promise444c5
// @match        https://bitcointalk.org/index.php?topic=*
// @match        https://bitcointalk.org/index.php?action=post*
// @noframes
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_addStyle
// @grant        GM_deleteValue
// @run-at       document-end
// ==/UserScript==

(() => {
  "use strict";

  GM_addStyle(`
       /* Modal Overlay */
        #merit-queue-modal { display: none; position: fixed; z-index: 9999; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.6); backdrop-filter: blur(3px); }

        /* Modal */
        #merit-queue-content {
            background-color: #ffffff; margin: 4% auto; padding: 24px; border-radius: 12px;
            width: 85%; max-width: 850px; max-height: 85vh; /* Keep within viewport */
            display: flex; flex-direction: column; /* Allows nested list to fill space & scroll */
            box-shadow: 0 10px 40px rgba(0,0,0,0.3); color: #333; font-family: system-ui, -apple-system, sans-serif;
            box-sizing: border-box; max-height: 80vh; overflow-y: auto; to #merit-queue-content
        }

        /* Header & Close */
        .mq-close { color: #aaa; float: right; font-size: 28px; font-weight: bold; cursor: pointer; transition: color 0.2s; line-height: 1; }
        .mq-close:hover { color: #e74c3c; }
        #merit-queue-content h2 { margin-top: 0; margin-bottom: 5px; border-bottom: 2px solid #f0f0f0; padding-bottom: 12px; font-size: 20px; color: #2c3e50;}

        /* Scrolling List */
        #mq-list {
            flex-grow: 1; overflow-y: auto; overflow-x: hidden;
            padding-right: 12px; margin: 15px 0;
            display: flex; flex-direction: column; gap: 10px;
        }

        /* Smooth Scrollbar for mq-list */
        #mq-list::-webkit-scrollbar { width: 8px; }
        #mq-list::-webkit-scrollbar-track { background: #f8f9fa; border-radius: 4px; }
        #mq-list::-webkit-scrollbar-thumb { background: #c1c1c1; border-radius: 4px; }
        #mq-list::-webkit-scrollbar-thumb:hover { background: #a8a8a8; }

        /* Queue Item Cards */
        .mq-item {
            display: flex; align-items: center; justify-content: space-between;
            background: #f8f9fc; padding: 16px; border-radius: 8px; border: 1px solid #eaedf1;
            transition: all 0.2s ease-in-out;
            flex-wrap: wrap; gap: 10px;
        }
        .mq-item > div:nth-child(2) {
            display: flex;
            align-items: center;
            gap: 15px;
            flex-wrap: wrap;

         }
        .mq-item:hover { transform: translateY(-2px); box-shadow: 0 6px 15px rgba(0,0,0,0.05); border-color: #d1d5db; flex:wrap }

        /* Inputs & Form Elements */
        .mq-amount, .mq-date { padding: 6px 10px; border: 0.5px solid #cbd5e1; border-radius: 6px; font-family: inherit; font-size: 13px; color: #333; outline: none; transition: border-color 0.2s; }
        .mq-amount:focus, .mq-date:focus { border-color: #3b82f6; }

        /* Action Buttons */
        .mq-remove {
            background: #f8d7da; color: #ef4444; border: none; border-radius: 50%;
            width: 32px; height: 32px; font-weight: bold; cursor: pointer;
            display: flex; align-items: center; justify-content: center; transition: all 0.2s; margin-left: 20px;
            margin: 0 !important;
            flex-shrink: 0;
        }
        .mq-remove:hover { background: #fca5a5; color: #7f1d1d; transform: scale(1.05); }
        #mq-force-send {
            background: #f6bec4db; color: #721C24; border: none; border-radius: 50%;
            width: 32px; height: 32px; font-weight: bold; cursor: pointer;
            display: flex; align-items: center; justify-content: center; transition: all 0.2s; margin-left: 5px;
            margin: 0 !important;
            flex-shrink: 0;
        }
        #mq-force-send:hover { background: #fdba74; color: #78350f; transform: scale(1.05); }

        #mq-save-container { text-align: center; margin-top: auto; padding-top: 15px; border-top: 2px solid #f0f0f0; }
        #mq-save-btn {
            padding: 12px 35px; font-size: 15px; font-weight: 600; cursor: pointer;
            background: #047857; color: #fff;
            border: none; border-radius: 6px; box-shadow: 0 4px 10px rgba(16, 185, 129, 0.3); transition: all 0.2s;
        }
        #mq-save-btn:hover { background: #059669; box-shadow: 0 6px 14px rgba(16, 185, 129, 0.4); translateY(-1px); }
        #mq-save-btn:active { transform: translateY(2px); box-shadow: 0 2px 5px rgba(16, 185, 129, 0.3); }


        #open-mq-btn { position: fixed; bottom: 25px; right: 25px; padding: 12px 20px; font-weight: 600; background: #375f82; color: white; border: none; border-radius: 50px; cursor: pointer; z-index: 9998; box-shadow: 0 6px 12px rgba(59, 130, 246, 0.3); transition: transform 0.2s; }
        #open-mq-btn:hover { transform: translateY(-2px); box-shadow: 0 8px 16px rgba(59, 130, 246, 0.4); opacity:0.95; background:#3e6488 }`);


  const LOCK_KEY = "merit_queue_lock";
  const LOCK_DURATION = 60000;
  

  /* Loads active queue from storage on script initialization*/
  let meritQueue = GM_getValue("MERIT_QUEUE", []);

  const queueBtnTemplate = document.createElement("a");
  queueBtnTemplate.href = "javascript:void(0);";
  queueBtnTemplate.innerHTML =
    '&nbsp;<span style="vertical-align: middle;"><b>+Queue</b></span>';

  const topicMatch = window.location.href.match(/topic=(\d+)/);
  const topicId = topicMatch ? topicMatch[1] : "0";

  document.querySelectorAll('a[href*="action=merit;msg="]').forEach((link) => {
    const match = link.href.match(/msg=(\d+)/);
    if (!match) return;

    const [, msgId] = match;

    /* Optional Chaining & Nullish Coalescing */
    const username =
      link
        .closest(".windowbg, .windowbg2")
        ?.querySelector(".poster_info b a")
        ?.textContent.trim() ?? "Unknown";

    const queueBtn = queueBtnTemplate.cloneNode(true);
    queueBtn.addEventListener("click", (e) => {
      e.preventDefault();
      /* confirmation dialog, for unexpected clicks  */
      if (confirm(`Are you sure you want to queue 1 merit for ${username}?`)) {
        addToQueue(topicId, msgId, username);
      }
    });

    link.parentNode.insertBefore(queueBtn, link.nextSibling);
  });

  const addToQueue = (topicId, msgId, username) => {
    if (meritQueue.some((item) => item.msgId === msgId)) return alert("Post is already in the queue!");

    meritQueue = [
      ...meritQueue,
       {
        id: `${Date.now()}-${msgId}`,
        topicId,
        msgId,
        username,
        amount: 1,
        forceSend: false,
        attempts:0,
      },
      
    ];

    GM_setValue("MERIT_QUEUE", meritQueue);
      alert(`Added a post from ${username} to Merit Queue`);

  };

  /* Modal*/
  document.body.insertAdjacentHTML(
    "beforeend",
    `
        <div id="merit-queue-modal">
            <div id="merit-queue-content">
              <div>
                <span class="mq-close">&times;</span>
                <h2 style="margin-top:0; border-bottom:2px solid #ccc; padding-bottom:10px;">Merit Queue Settings</h2>
              </div>
                <div id="mq-list"></div>
                <div id="mq-save-container"><button id="mq-save-btn">Save Changes</button></div>
            </div>
        </div>
        <button id="open-mq-btn">View Merit Queue</button>
    `,
  );

  const modal = document.getElementById("merit-queue-modal");
  const listContainer = document.getElementById("mq-list");

  const renderQueue = () => {
    if (!meritQueue.length) {
      listContainer.innerHTML = "<p>No posts in queue.</p>";
      return;
    }

    /* Queue items */
    listContainer.innerHTML = meritQueue
      .map((item, index) => {
        const predefinedMeritValues = [1, 2, 3, 4, 6, 8, 10, 20, 40, 50];
        const options = predefinedMeritValues
          .map(
            (i) =>
              `<option value="${i}" ${item.amount == i ? "selected" : ""}>${i}</option>`,
          )
          .join("");

        return `
                <div class="mq-item" ${item.status === "failed" ? 'style="background-color: #ffe6e6; padding: 10px;"' : ""}>
                    <div>
                        <strong>User: ${item.username}</strong><br>
                        <a href="https://bitcointalk.org/index.php?topic=${item.topicId}.msg${item.msgId}#msg${item.msgId}" target="_blank" style="font-size:12px;">Link to Msg: #${item.msgId}</a>
                        ${item.error && !item.forceSend ? `<br><span style="color:red; font-size:12px;"><b>Error:</b> ${item.error}</span><br>` : ""}
                    </div>
                    <div>
                        <label>Merit: <select class="mq-amount" data-index="${index}">${options}</select></label>
                        <div style="display:flex; align-items:center; gap:10px; margin-top:5px;">
                        ${item.error && !item.forceSend ? `<button id="mq-force-send" data-index="${index}" title="Force send merit (ignores history log check)" style="margin-left: 5px; color: #721c24;">!</button>` : ""}
                        <button class="mq-remove" data-index="${index}" title="Remove from queue" style="margin-left: 15px; color: red;">X</button>
                        </div>
                    </div>
                </div>
            `;
      })
      .reverse()
      .join("");
  };

  /* remove button */
  listContainer.addEventListener("click", (e) => {
    if (e.target?.classList.contains("mq-remove")) {
      meritQueue.splice(e.target.dataset.index, 1);
      GM_setValue("MERIT_QUEUE", meritQueue);
      renderQueue();
    }
  });

  /* force send button */
  listContainer.addEventListener("click", (e) => {
    if (e.target?.id === "mq-force-send") {
      const index = e.target.dataset.index;
      meritQueue[index].forceSend = true;
      GM_setValue("MERIT_QUEUE", meritQueue);
      renderQueue();
    }
  });

  document.getElementById("open-mq-btn").onclick = () => {
    meritQueue = GM_getValue("MERIT_QUEUE", []);
    renderQueue();
    modal.style.display = "block";
  };

  document.querySelector(".mq-close").onclick = () => {
    modal.style.display = "none";
  };

  window.onclick = (e) => {
    if (e.target === modal) {
      modal.style.display = "none";
    }
  };

  document.getElementById("mq-save-btn").onclick = () => {
    document.querySelectorAll(".mq-amount").forEach((sel) => {
      meritQueue[sel.dataset.index].amount = sel.value;
    });
    GM_setValue("MERIT_QUEUE", meritQueue);
    alert("Queue settings successfully saved!");
    modal.style.display = "none";
  };

  
  /*
  ** Main automation logic
  */
  const processMeritQueue = async () => {
    const queue = GM_getValue("MERIT_QUEUE", []);
    const attempt = GM_getValue("POST_ATTEMPT",null);

    if (!attempt) return;
    if (!queue.length) {
        console.log("Merit queue is empty. Nothing to process.");
        return;
      }

    const isNewPost = location.hash === "#new" && location.href.includes("topic=");

    console.log("Post submission detected, checking conditions for merit queue processing...", { isNewPost, attemptTime: attempt, currentTime: Date.now() }); // for testing , to be stripped..
    

    // const minDelay = Math.max(1, queue.length) * 10000;

    // if (Date.now() - attempt < minDelay) {
    //   console.error("Insufficient time elapsed since last post attempt. Aborting this attempt.");
    //   return;
    // }

    if (!isNewPost) {
      console.log("Not a new post submission.")
      return;
    }

    if (!acquireLock()) {
      console.log("Another merit queue process is currently running. Aborting this attempt..");
      return;
    }

    

    try {
    GM_deleteValue("POST_ATTEMPT");
    const sc = document
        .querySelector('a[href*="action=logout;sesc="]')
        ?.href.match(/sesc=([a-f0-9]+)/)?.[1];
        
    if (!sc){
      console.error("Cannot proceed with merit dispensing. Make sure you are logged in ");
      return
    };

    const successLogs = GM_getValue("SUCCESS_LOGS",[]);
      
    console.log(successLogs, successLogs.length, "Current success logs for double send check");
      
    for (let i = queue.length - 1; i >= 0; i--) {
        
        let item = queue[i];
        if (!item) continue;

        /* Prevent unnecessary network requests for known failed items */
        if (item.status === "failed" && !item.forceSend) continue;
        

          /* Prevent double sending merit by checking log */
        if (checkDoubleSend(successLogs,item.id) && !item.forceSend) {
          console.warn(`Merit for MsgID ${item.msgId} with amount ${item.amount} already exists in history, skipping...`);
          /* Flags the failed item in the queue instead of deleting it */
          updateQueueItem(item.id,(existing) =>({
            ...existing,
            status:"failed",
            error:"Merit already sent (detected in history).",
            attempts: existing.attempts + 1
          }));
          
          continue;
        }

        if( item.attempts >= 3 && item.forceSend) {
          console.warn(`Merit for MsgID ${item.msgId} has failed ${item.attempts} times, removing from queue...`);
          removeQueueItem(item.id);
          continue;
        }

        console.log(
          `Attempting to dispense ${item.amount} merit to MsgID ${item.msgId}...`,
        );

        if (item.forceSend) {
          console.warn(`Force sending enabled for MsgID ${item.msgId}, ignoring history log check.`);
          item.forceSend = false;
          updateQueueItem(item.id, (existing) => ({
            ...existing,
            forceSend: false,
          }));
        }

        const formData = new URLSearchParams({
          merits: item.amount,
          msgID: item.msgId,
          sc,
        });

        try {
          const response = await fetch(
            `https://bitcointalk.org/index.php?action=merit;msg=${item.msgId}`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/x-www-form-urlencoded",
                Accept:
                  "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
              },
              body: formData.toString(),
            },
          );

          if (response.ok) {

            const html = await response.text();

            if (html.includes("An Error Has Occurred")) {
              console.error(`Failed to send merit for MsgID ${item.msgId}`);
              let errorMsg = "Unknown error occurred.";

              const lowerHtml = html.toLowerCase();

              /** Checks for error
               * Note: not sure about the exact message for "no merit" yet, so I'm doing a contains check for "enough smerit" which should cover both "not enough sMerit" and "you don't have any sMerit" maybe
               * For any reason , if the error message doesn't match or there are changes in the future, it will default to "Unknown error occurred." instead of just saying "Failed to send merit" which is less informative for the user.
               * */
              
              if (lowerHtml.includes("enough smerit")) {
                errorMsg = "Not enough sMerit.";
              }
              
              else if (lowerHtml.includes("cannot send merit to yourself")) {
                errorMsg = "Cannot send merit to yourself tuff guy.";
              }
              
              else if(lowerHtml.includes("you can only send 50 merit ")) {
                const match = lowerHtml.match(/you have already sent (\d+) merit to that user/i);

                const sentMerit = match && !Number.isNaN(Number.parseInt(match[1], 10))? Number.parseInt(match[1], 10) : 0;
                errorMsg = sentMerit >= 50 ? "You have already sent the maximum amount of merit to this user."
                            : sentMerit === 0 ? "You cant send merit to this user right now."
                            : `You can only send ${50 - sentMerit} merit to this user.`;
                }

              /** Flags and update  the failed item in the queue instead of deleting it */
            

              updateQueueItem(item.id, (existing) => ({
                ...existing,
                attempts: existing.attempts + 1 ,
                status: "failed",
                error: errorMsg,
              }));
              renderQueue();

            } else {
              console.log(
                `Successfully sent ${item.amount} merit for MsgID ${item.msgId}`,
              );

              removeQueueItem(item.id);
              const logs = GM_getValue("SUCCESS_LOGS",[]);
              logs.push({ id: item.id, timestamp: Date.now() });
              GM_setValue("SUCCESS_LOGS", logs);
              renderQueue();
            }
          }
          await new Promise((res) => setTimeout(res, 1500)); // wait to prevent rate-limiting before next attempt

        } catch (err) {
          console.error("Error dispensing merit, keeping in queue:", err);
        }
      }
    } catch (err) {
      console.error("Error in merit queue processing:", err);
    }finally {
      const failCount = GM_getValue("MERIT_QUEUE", []).filter(item => item.status === "failed").length;
      if(failCount > 0) alert(`Merit queue processing completed with ${failCount} failed item(s). Please review the queue for details.`);
      else alert("Merit queue processing completed successfully with no errors.");
      releaseLock();
    }
};
/* End of main automation logic */

  /* Checks success log for a specific msgId and amount to prevent double sending */
  const checkDoubleSend = (logs, currentId) => {

    if(logs.length === 0) return false;

    const lifeSpan = Date.now() - 7 * 24 * 60 * 60 * 1000;

    const freshLogs = logs.filter(l => l.timestamp > lifeSpan);
 
    GM_setValue("SUCCESS_LOGS", freshLogs);
    console.log(freshLogs,freshLogs.length,"Fresh success logs after cleanup");

    const logSet = new Set(freshLogs.map(l => l.id));

  return logSet.has(currentId);
  };


  const updateQueueItem = (id, updater) => {
    const queue = GM_getValue("MERIT_QUEUE", []);
   const idx = queue.findIndex(x => x.id === id);
    if (idx === -1) return;

    queue[idx] = updater(queue[idx]);
    GM_setValue("MERIT_QUEUE", queue);
};

const removeQueueItem = (id) => {
  const queue = GM_getValue("MERIT_QUEUE", []);

  const updated = queue.filter(item => item.id !== id);

  GM_setValue("MERIT_QUEUE", updated);
};
  /* Locking mechanism to prevent multiple concurrent processes  */
  
  const isStale = (lock) => !lock || (Date.now() - lock.startedAt > LOCK_DURATION);

  const acquireLock = () => {
    const lock = GM_getValue(LOCK_KEY, null);

    if (lock && lock.active && !isStale(lock)) return false;

    GM_setValue(LOCK_KEY, {
      active: true,
      startedAt: Date.now()
    });

  return true;
};


 const releaseLock = () => GM_deleteValue(LOCK_KEY);

/* End of locking mechanism implementation */


  const isPostEdit = !!document.querySelector('form[action*="sesc="]');

  const postForm = document.forms.postmodify || document.querySelector('form[action*="action=post2"]');

  if (postForm && !isPostEdit) {
    postForm.addEventListener("submit", () => {
      GM_setValue("POST_ATTEMPT", Date.now());
    });
}

if (GM_getValue("POST_ATTEMPT")) {
  processMeritQueue();
}

})();


Changes added
**Fix bug that overwrites the entire queue on every update made on queue.
**Added lock mechanism [with a time-out check on unexpected process exit ]  to prevent multiple process hijack..
**Partial implementation for script continuation of incomplete attempts on a new page
**Added a check for max-merit that can be received by a User(Merit Receiver)
**Added more console logs to catch errors and messages from the script.
**Fix minor bugs..


███████████████████████████
███████▄████████████▄██████
████████▄████████▄████████
███▀█████▀▄███▄▀█████▀███
█████▀█▀▄██▀▀▀██▄▀█▀█████
███████▄███████████▄███████
███████████████████████████
███████▀███████████▀███████
████▄██▄▀██▄▄▄██▀▄██▄████
████▄████▄▀███▀▄████▄████
██▄███▀▀█▀██████▀█▀███▄███
██▀█▀████████████████▀█▀███
███████████████████████████
.
.Duelbits PREDICT..
█████████████████████████
█████████████████████████
███████████▀▀░░░░▀▀██████
██████████░░▄████▄░░████
█████████░░████████░░████
█████████░░████████░░████
█████████▄▀██████▀▄████
████████▀▀░░░▀▀▀▀░░▄█████
██████▀░░░░██▄▄▄▄████████
████▀░░░░▄███████████████
█████▄▄█████████████████
█████████████████████████
█████████████████████████
.
.WHERE EVERYTHING IS A MARKET..
█████
██
██







██
██
██████
Will Bitcoin hit $200,000
before January 1st 2027?

    No @1.15         Yes @6.00    
█████
██
██







██
██
██████

  CHECK MORE > 
vapourminer
Legendary
*
Offline

Activity: 5068
Merit: 6339


what is this "brake pedal" you speak of?


View Profile
June 12, 2026, 01:36:10 AM
 #54

I made some changes [...]

ok here goes..
vapourminer
Legendary
*
Offline

Activity: 5068
Merit: 6339


what is this "brake pedal" you speak of?


View Profile
June 12, 2026, 01:39:35 AM
 #55

intentional double post to test

rats i updated the script before i posted the above and the 6 or 7 posts i had in the current unsent merits list went away (list reinitialized i guess)

duh

i should of know better. anyway lets see if this merit to you goes through

edit: and it did. saw the notice the script was done at the end. i like that.

this is coming along nicely    thanks!
promise444c5 (OP)
Hero Member
*****
Offline

Activity: 1050
Merit: 966


All things are numbers


View Profile WWW
June 12, 2026, 01:51:07 AM
Last edit: June 13, 2026, 12:21:23 PM by promise444c5
 #56


rats i updated the script before i posted the above and the 6 or 7 posts i had in the current unsent merits list went away (list reinitialized i guess)
Haa my bad! That has to do with the Uppercase renaming I did to Keys of data I’m storing locally so I can easily detect them . I didn’t put that into consideration.. Tongue
edit: and it did. saw the notice the script was done at the end. i like that.
It also alert you failed items at the end of the process  if there’s any including the count. That was the last edit i added after posting the script .

[edit]
Updated script [Post_Trigger] on main  OP post... Although I’ve been monitoring your merit and post closely, I’m still expecting response to know if issue repeats itself.
Thanks..

███████████████████████████
███████▄████████████▄██████
████████▄████████▄████████
███▀█████▀▄███▄▀█████▀███
█████▀█▀▄██▀▀▀██▄▀█▀█████
███████▄███████████▄███████
███████████████████████████
███████▀███████████▀███████
████▄██▄▀██▄▄▄██▀▄██▄████
████▄████▄▀███▀▄████▄████
██▄███▀▀█▀██████▀█▀███▄███
██▀█▀████████████████▀█▀███
███████████████████████████
.
.Duelbits PREDICT..
█████████████████████████
█████████████████████████
███████████▀▀░░░░▀▀██████
██████████░░▄████▄░░████
█████████░░████████░░████
█████████░░████████░░████
█████████▄▀██████▀▄████
████████▀▀░░░▀▀▀▀░░▄█████
██████▀░░░░██▄▄▄▄████████
████▀░░░░▄███████████████
█████▄▄█████████████████
█████████████████████████
█████████████████████████
.
.WHERE EVERYTHING IS A MARKET..
█████
██
██







██
██
██████
Will Bitcoin hit $200,000
before January 1st 2027?

    No @1.15         Yes @6.00    
█████
██
██







██
██
██████

  CHECK MORE > 
Pages: « 1 2 [3]  All
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!