Instructions on how to edit multiple custom card effects, or custom card common mechanics, at once

If you have a suggestion for the site, create a topic here and telll us about it
Christen57
User avatar
Posts: 2037
Joined: Sun May 07, 2017 10:37 pm
Reputation: 182
Location: New York, United States of America

Instructions on how to edit multiple custom card effects, or custom card common mechanics, at once

Post #1 by Christen57 » Tue Mar 01, 2022 4:34 pm

Currently, whenever you want to edit multiple custom card effects, you need to edit them one at a time.

This normally isn't too bad, but say you have a full page of 20 cards all with a very similar effect or common mechanic, and you want to edit that similar effect or common mechanic for each of them. You would have to click on one of them, delete the portion of the effect you want gone, and replace it with something else, then click Save to save it, wait for it to finish saving, click the big OK button that pops up to confirm it's done saving, go back to My Cards, then repeat this process 19 more times for the remaining 19 cards.

However, thanks to javascript, there is now a much faster way to do all of this, and for this to work, you'll need to know how to access the console on your browser.

If you're on Google Chrome, you should be able to access it by simply right clicking on the screen to bring up the right-click menu, then clicking Inspect to open up the element inspector, then either clicking the Console tab, or clicking the two arrows that appear that look like this >> then clicking Console from the drop-down menu.

Image

If you're on Firefox, you should be able to access it by right clicking, then clicking Inspect (Q)

Image

The browser I currently use, Vivaldi, requires me to right click, click Developer Tools, then click Inspect, to access the console.

Image

So now that you know how to access the console, what you want to do is create a javascript bookmark and name it whatever you want. I'll be naming mine "edit multiple effects".

In the URL/Address box, copy and paste this code:

Code: Select all

javascript:{let searchs = JSON.parse(prompt("Copy and paste the data from the console"));
let oldtxt = prompt("Enter the old text");
let newtxt = prompt("Enter the new text");
for (let i = 0; i < searchs.cards.length; i++) {
   Send({
      "action":"Edit card",
      "id":searchs.cards[i].id,
      "name":searchs.cards[i].name,
      "effect":searchs.cards[i].effect.replace(oldtxt, newtxt),
      "card_type":searchs.cards[i].card_type,
      "monster_color":searchs.cards[i].monster_color,
      "type":searchs.cards[i].type,
      "ability":searchs.cards[i].ability,
      "attribute":searchs.cards[i].attribute,
      "level":~~searchs.cards[i].level,
      "atk":searchs.cards[i].atk,
      "def":searchs.cards[i].def,
      "flip":~~searchs.cards[i].flip,
      "is_effect":searchs.cards[i].is_effect,
      "pendulum":~~searchs.cards[i].pendulum,
      "scale":~~searchs.cards[i].scale,
      "pendulum_effect":searchs.cards[i].pendulum_effect,
      "arrows":searchs.cards[i].arrows,
      "rush":searchs.cards[i].rush,
      "serial_number":~~searchs.cards[i].serial_number,
      "tcg":~~searchs.cards[i].tcg,
      "ocg":~~searchs.cards[i].ocg,
      "limit":3,
      "custom":~~searchs.cards[i].custom,
      "privacy":1
   });
}
}


Click Save to save your bookmark.

Image

Now you're all set!

So, for this demonstration, I'll be using my custom Shippuden archetype. At the moment, this custom archetype of mine consists of 5 different monsters, all of which share a common effect: You can activate Traps listed in this card the turn they are Set.

Image

Now, say I wanted to edit all of them so instead of saying "You can activate Traps" they say something else like "You can activate Something". Well, like I mentioned earlier, I would normally have to edit them one by one until they all said that, but now, with this javascript bookmark, we can edit them all a lot quicker.

What we want to do first is modify the search parameters so they only show the cards we want to edit. In this case, I have over 110 pages worth of customs, so what I need to do is edit my search parameters so only those 5 monsters come up instead of all 2000+ of my customs. I can do this by entering "shipp" in the Name box since those 5 monsters are currently the only customs I have with "shipp" in their names, which means all other customs will be filtered out for now.

Image

Now that I have only these monsters I wish to edit being displayed at the moment, I will, from here, open up the console using the method(s) I explained earlier, and when I do, there should be basically some wall of text beginning with {"full_search":false,"total": and ending with "action":"Search cards","page":0,"millis": or something like that.

We're going to select this entire wall of text by double-clicking it, then copy it to our clipboard. The reason you want to select it by double-clicking instead of using CTRL+A or something is because if you use CTRL+A, you'll end up selecting other parts of the console you don't want.

Image

After copying that wall of text, you will, from here, click on the javascript bookmark you created, and you'll see a prompt box saying "Copy and paste the data from the console". In the box, paste the wall of text you copied from the console and either click the OK button on the screen or hit Enter on your keyboard.

From there, you'll see another option saying "Enter the old text". You'll enter the current text on your effects that you want to replace. In this case, I want to replace every instance of "activate Traps" with "activate Something" so I'm going to first enter activate Traps

After I enter that in, I'm then prompted to "Enter the new text" so, this time, I'll enter the text I want to replace "activate Traps" with: activate Something

Image

As you can see, duelingbook rapidly shows the messages (for a brief moment) of each card having been updated. However, when I hover my cursor over the cards, their effects still show "activate Traps" instead of "activate Something". This is because I need to click "Search" one more time to refresh the cards so they show their updated effects instead of their old ones.

Image

I want to change these effects back to normal, so I'm going to do what I did before, but this time, replace "Something" with "Traps". I don't need to include "activate" this time. I never did in fact because I never wanted to edit "activate" — only "Traps". If I wanted to edit "activate" as well, then I'd include that word too.

Image

Another thing I need to mention is that, when you're entering anything in the "Enter the old text" box, what you enter is case sensitive, meaning if you want to replace Traps with something, you must enter Traps in that box, not traps

Image

As you can see, when I try to replace "traps" with "hello," I get the message saying the cards were updated, but nothing actually got replaced. This is because none of these 5 cards have "traps" in their effects, only "Traps" which is capitalized.

Another thing I need to mention is that, when you enter something in the "Enter the old text" box, only the first instance of that thing will be replaced. Here's what I mean:

Image

As you can see, when I entered the " symbol into the "Enter the old text" box to be replaced with "LOL," it only replaced the first " symbol in the effect with "LOL," not all " symbols in the effect. This means if you want to edit each " symbol, you'll need to run that code over and over, entering " each time to be replaced until there's none left to replace.

Now let's try the same thing as before, but with a different set of cards.

Image

Notice how, this time, when I click the "Search" button to make the wall of text appear in the console like before, a little "Copy" button is included for us at the bottom of the wall of text.

On some browsers such as Google Chrome, whenever a big-enough wall of text is added to the console, that little "Copy" button will appear, so instead of highlighting everything and manually copying it that way, you can simply click that "Copy" button and it will copy the wall of text to your clipboard for you. Make sure to utilize that instant-copy button whenever it does show up as it's faster clicking that than manually highlighting then copying what you need.

After copying the data from the console for all these 12 cards that appeared in our search result, we can then edit them all at once. This time, I want to replace "cannot Summon" with "ABC" for each of them. Look at how fast this javascript code lets me do that compared to manually editing then saving each of them one by one!

Image

Image

Now look at how quickly I can change them back.

Image

So anytime you have multiple customs with similar phrases, and you want to do a mass-edit on each of those phrases without having to manually edit each of them one by one, you can use these steps to do so. It would've taken far more time for me to manually edit each of these cards one by one just to replace "cannot Summon" with "ABC" (or vice versa) for each of them.

Unfortunately, you can only edit up to 20 cards at once at a time with this code since 20 is the maximum number of customs you can have per page. Any additional customs loaded in the Search results will be moved to other pages, so this only works on the customs of the current page of the custom card editor you're in. If you want to edit additional pages of customs this way, you'll have to narrow down your search to just those customs you want to edit (like I did with my Shippuden and Overwatch archetypes), then use your javascript bookmark for each of those pages to mass-edit the customs on that page the same way.

Here's the code working on Firefox. https://imgur.com/a/YBskOuS
https://gfycat.com/plumpcreepyirishdraughthorse
As you can see, I'm able to mass-edit all my Shippuden cards so their effects say "HELLO WORLD" instead of "Traps," then mass-edit them back to normal, something that would've taken probably minutes to do without any javascript.

Christen57
User avatar
Posts: 2037
Joined: Sun May 07, 2017 10:37 pm
Reputation: 182
Location: New York, United States of America

Post #2 by Christen57 » Fri Mar 22, 2024 3:54 am

The previous code in this thread is now obsolete. I've updated it making it much simpler to use. It still requires you to modify your search parameters in the custom card editor so as to only show the specific cards you want to edit, and still requires you, after each use of the code, to click the Search button in the editor to refresh the custom card page, but it no longer requires any wall of text to be copied and pasted beforehand.

Here's the updated code:

Code: Select all

javascript:function editCard3 (OldText, NewText) {
   let CustomCards = document.querySelectorAll('[class="cardfront unselectable search_card ui-draggable ui-draggable-handle"][style$="display: block;"]');
   for (let i = 0; i < CustomCards.length; i++) {
      let FullTextNodes = CustomCards[i].querySelector('[class="effect_txt"]').childNodes;
      let FullPendulumNodes = CustomCards[i].querySelector('[class="card_pendulum_effect_txt"]').childNodes;
      let FullId = parseInt(CustomCards[i].querySelector('[class="pic"]').src.slice(CustomCards[i].querySelector('[class="pic"]').src.lastIndexOf("/") + 1));
      let FullName = CustomCards[i].querySelector('[class="name_txt"]').textContent;
      let FullText = "";
      for (let ii = 0; ii < FullTextNodes.length; ii++) {
         switch (FullTextNodes[ii].nodeName) {
            case "#text":
            case "FONT":
               FullText += FullTextNodes[ii].textContent;
               break;
            case "BR":
               FullText += "\n";
               break;
         }
      }
      let FullCardType;
      let FullMonsterColor;
      switch (CustomCards[i].querySelector('[class="card_color"]').src) {
         case "https://images.duelingbook.com/card/normal_front2.jpg":
            FullCardType = "Monster";
            FullMonsterColor = "Normal";
            break;
         case "https://images.duelingbook.com/card/effect_front2.jpg":
            FullCardType = "Monster";
            FullMonsterColor = "Effect";
            break;
         case "https://images.duelingbook.com/card/ritual_front2.jpg":
            FullCardType = "Monster";
            FullMonsterColor = "Ritual";
            break;
         case "https://images.duelingbook.com/card/fusion_front2.jpg":
            FullCardType = "Monster";
            FullMonsterColor = "Fusion";
            break;
         case "https://images.duelingbook.com/card/synchro_front2.jpg":
            FullCardType = "Monster";
            FullMonsterColor = "Synchro";
            break;
         case "https://images.duelingbook.com/card/xyz_front2.jpg":
            FullCardType = "Monster";
            FullMonsterColor = "Xyz";
            break;
         case "https://images.duelingbook.com/card/link_front2.jpg":
            FullCardType = "Monster";
            FullMonsterColor = "Link";
            break;
         case "https://images.duelingbook.com/card/spell_front2.jpg":
            FullCardType = "Spell";
            FullMonsterColor = "";
            break;
         case "https://images.duelingbook.com/card/trap_front2.jpg":
            FullCardType = "Trap";
            FullMonsterColor = "";
            break;
      }
      let FullType;
      typeloop:
      switch (CustomCards[i].querySelector('[class="card_color"]').src) {
         case "https://images.duelingbook.com/card/normal_front2.jpg":
         case "https://images.duelingbook.com/card/effect_front2.jpg":
         case "https://images.duelingbook.com/card/ritual_front2.jpg":
         case "https://images.duelingbook.com/card/fusion_front2.jpg":
         case "https://images.duelingbook.com/card/synchro_front2.jpg":
         case "https://images.duelingbook.com/card/xyz_front2.jpg":
         case "https://images.duelingbook.com/card/link_front2.jpg":
            switch (CustomCards[i].querySelector('[class="type_txt"]').textContent.slice(0, -1).slice(2, CustomCards[i].querySelector('[class="type_txt"]').textContent.indexOf(" /"))) {
               case "AQUA":
                  FullType = "Aqua";
                  break typeloop;
               case "BEAST":
                  FullType = "Beast";
                  break typeloop;
               case "BEAST-WARRIOR":
                  FullType = "Beast-Warrior";
                  break typeloop;
               case "CELESTIAL WARRIOR":
                  FullType = "Celestial Warrior";
                  break typeloop;
               case "CYBERSE":
                  FullType = "Cyberse";
                  break typeloop;
               case "CYBORG":
                  FullType = "Cyborg";
                  break typeloop;
               case "DINOSAUR":
                  FullType = "Dinosaur";
                  break typeloop;
               case "DIVINE-BEAST":
                  FullType = "Divine-Beast";
                  break typeloop;
               case "DRAGON":
                  FullType = "Dragon";
                  break typeloop;
               case "FAIRY":
                  FullType = "Fairy";
                  break typeloop;
               case "FIEND":
                  FullType = "Fiend";
                  break typeloop;
               case "FISH":
                  FullType = "Fish";
                  break typeloop;
               case "GALAXY":
                  FullType = "Galaxy";
                  break typeloop;
               case "HIGH DRAGON":
                  FullType = "High Dragon";
                  break typeloop;
               case "ILLUSION":
                  FullType = "Illusion";
                  break typeloop;
               case "INSECT":
                  FullType = "Insect";
                  break typeloop;
               case "MACHINE":
                  FullType = "Machine";
                  break typeloop;
               case "MAGICAL KNIGHT":
                  FullType = "Magical Knight";
                  break typeloop;
               case "OMEGA PSYCHIC":
                  FullType = "Omega Psychic";
                  break typeloop;
               case "PLANT":
                  FullType = "Plant";
                  break typeloop;
               case "PSYCHIC":
                  FullType = "Psychic";
                  break typeloop;
               case "PYRO":
                  FullType = "Pyro";
                  break typeloop;
               case "REPTILE":
                  FullType = "Reptile";
                  break typeloop;
               case "ROCK":
                  FullType = "Rock";
                  break typeloop;
               case "SEA SERPENT":
                  FullType = "Sea Serpent";
                  break typeloop;
               case "SPELLCASTER":
                  FullType = "Spellcaster";
                  break typeloop;
               case "THUNDER":
                  FullType = "Thunder";
                  break typeloop;
               case "WARRIOR":
                  FullType = "Warrior";
                  break typeloop;
               case "WINGED BEAST":
                  FullType = "Winged Beast";
                  break typeloop;
               case "WYRM":
                  FullType = "Wyrm";
                  break typeloop;
               case "ZOMBIE":
                  FullType = "Zombie";
                  break typeloop;
            }
         case "https://images.duelingbook.com/card/spell_front2.jpg":
         case "https://images.duelingbook.com/card/trap_front2.jpg":
            if (CustomCards[i].querySelector('[class="type_icon"][style$="display: none;"]') != null) {
               FullType = "Normal";
               break typeloop;
            } else {
               switch (CustomCards[i].querySelector('[class="type_icon"]').src) {
                  case "https://images.duelingbook.com/card/continuous.webp":
                     FullType = "Continuous";
                     break typeloop;
                  case "https://images.duelingbook.com/card/equip.webp":
                     FullType = "Equip";
                     break typeloop;
                  case "https://images.duelingbook.com/card/quick-play.webp":
                     FullType = "Quick-Play";
                     break typeloop;
                  case "https://images.duelingbook.com/card/field.webp":
                     FullType = "Field";
                     break typeloop;
                  case "https://images.duelingbook.com/card/ritual.webp":
                     FullType = "Ritual";
                     break typeloop;
                  case "https://images.duelingbook.com/card/counter.webp":
                     FullType = "Counter";
                     break typeloop;
               }
            }
      }
      let FullAbilities = [];
      if (CustomCards[i].querySelector('[class="type_txt"][style^="display: block;"]') != null) {
         if (CustomCards[i].querySelector('[class="type_txt"]').textContent.includes("/ GEMINI")) {
            FullAbilities.push("Gemini");
         }
         if (CustomCards[i].querySelector('[class="type_txt"]').textContent.includes("/ SPIRIT")) {
            FullAbilities.push("Spirit");
         }
         if (CustomCards[i].querySelector('[class="type_txt"]').textContent.includes("/ TOON")) {
            FullAbilities.push("Toon");
         }
         if (CustomCards[i].querySelector('[class="type_txt"]').textContent.includes("/ TUNER")) {
            FullAbilities.push("Tuner");
         }
         if (CustomCards[i].querySelector('[class="type_txt"]').textContent.includes("/ UNION")) {
            FullAbilities.push("Union");
         }
      }
      let FullAttribute = CustomCards[i].querySelector('[class="attribute"]').src.slice(36, CustomCards[i].querySelector('[class="attribute"]').src.indexOf("_attribute")).toUpperCase();
      let FullLevel;
      switch (CustomCards[i].querySelector('[class="card_color"]').src) {
         case "https://images.duelingbook.com/card/normal_front2.jpg":
         case "https://images.duelingbook.com/card/effect_front2.jpg":
         case "https://images.duelingbook.com/card/ritual_front2.jpg":
         case "https://images.duelingbook.com/card/fusion_front2.jpg":
         case "https://images.duelingbook.com/card/synchro_front2.jpg":
            FullLevel = CustomCards[i].querySelectorAll('[class^="level"][style$="display: block;"]').length;
            break;
         case "https://images.duelingbook.com/card/xyz_front2.jpg":
            FullLevel = CustomCards[i].querySelectorAll('[class^="rank"][style$="display: block;"]').length;
            break;
         case "https://images.duelingbook.com/card/link_front2.jpg":
            FullLevel = parseInt(CustomCards[i].querySelector('[class="link_txt"]').textContent);
            break;
         default:
            FullLevel = 0;
            break;
      }
      let FullAtk;
      let FullDef;
      switch (CustomCards[i].querySelector('[class="card_color"]').src) {
         case "https://images.duelingbook.com/card/normal_front2.jpg":
         case "https://images.duelingbook.com/card/effect_front2.jpg":
         case "https://images.duelingbook.com/card/ritual_front2.jpg":
         case "https://images.duelingbook.com/card/fusion_front2.jpg":
         case "https://images.duelingbook.com/card/synchro_front2.jpg":
         case "https://images.duelingbook.com/card/xyz_front2.jpg":
            FullAtk = CustomCards[i].querySelector('[class="card_atk_txt"]').textContent;
            FullDef = CustomCards[i].querySelector('[class="card_def_txt"]').textContent;
            break;
         case "https://images.duelingbook.com/card/link_front2.jpg":
            FullAtk = CustomCards[i].querySelector('[class="card_atk_txt"]').textContent;
            FullDef = "?";
            break;
         default:
            FullAtk = "0";
            FullDef = "0";
            break;
      }
      let FullFlip;
      if (CustomCards[i].querySelector('[class="type_txt"]').textContent.includes("/ FLIP")) {
         FullFlip = 1;
      } else {
         FullFlip = 0;
      }
      let FullIsEffect;
      if (CustomCards[i].querySelector('[class="type_txt"]').textContent.includes("/ NORMAL") || CustomCards[i].querySelector('[class="type_txt"]').textContent.includes("/ EFFECT")) {
         FullIsEffect = 1;
      } else {
         FullIsEffect = 0;
      }
      let FullPendulumSize;
      let FullScale;
      if (CustomCards[i].querySelector('[class="card_pendulum_effect_txt"][style^="display: block;"]') == null) {
         FullPendulumSize = 0;
         FullScale = 0;
      } else {
         switch (CustomCards[i].querySelector('[class="pic"]').style.height) {
            case '528px':
            case '529px':
            case '530px':
            case '531px':
               FullPendulumSize = 1;
               break;
            case '568px':
            case '569px':
            case '570px':
            case '571px':
               FullPendulumSize = 2;
               break;
         }
         FullScale = parseInt(CustomCards[i].querySelector('[class="scale_left_txt"]').textContent);
      }
      let FullPendulumText = "";
      for (let ii = 0; ii < FullPendulumNodes.length; ii++) {
         switch (FullPendulumNodes[ii].nodeName) {
            case "#text":
            case "FONT":
               FullPendulumText += FullPendulumNodes[ii].textContent;
               break;
            case "BR":
               FullPendulumText += "\n";
               break;
         }
      }
      let FullArrows = "";
      FullArrows += String(CustomCards[i].querySelectorAll('[class="red_arrow red_arrow1"][style=""]').length);
      FullArrows += String(CustomCards[i].querySelectorAll('[class="red_arrow red_arrow2"][style=""]').length);
      FullArrows += String(CustomCards[i].querySelectorAll('[class="red_arrow red_arrow3"][style=""]').length);
      FullArrows += String(CustomCards[i].querySelectorAll('[class="red_arrow red_arrow4"][style=""]').length);
      FullArrows += String(CustomCards[i].querySelectorAll('[class="red_arrow red_arrow5"][style=""]').length);
      FullArrows += String(CustomCards[i].querySelectorAll('[class="red_arrow red_arrow6"][style=""]').length);
      FullArrows += String(CustomCards[i].querySelectorAll('[class="red_arrow red_arrow7"][style=""]').length);
      FullArrows += String(CustomCards[i].querySelectorAll('[class="red_arrow red_arrow8"][style=""]').length);
      Send({
         'action': 'Edit\x20card',
         'id': FullId,
         'name': FullName,
         'effect': FullText.replace(OldText, NewText),
         'card_type': FullCardType,
         'monster_color': FullMonsterColor,
         'type': FullType,
         'ability': getAbilities(FullAbilities),
         'attribute': FullAttribute,
         'level': FullLevel,
         'atk': FullAtk,
         'def': FullDef,
         'flip': FullFlip,
         'is_effect': FullIsEffect,
         'pendulum': FullPendulumSize,
         'scale': FullScale,
         'pendulum_effect': FullPendulumText,
         'arrows': FullArrows,
         'rush': 0,
         'serial_number': 0,
         'tcg': 0,
         'ocg': 0,
         'limit': 3,
         'custom': 1,
         'privacy': 1,
         'resized': false
      })
   }
   deck_arr = [];
   extra_arr = [];
}

{
   let Current_Text;
   function editCard4 () {
      Current_Text = $('#input\x20.input_txt')['val']();
      getInput('Edit multiple effects at once', 'New text:', "", 200, editCard5);
   }
   function editCard5 () {
      editCard3 (Current_Text, $('#input\x20.input_txt')['val']());
   }
   getInput('Edit multiple effects at once', 'Old text:', "", 200, editCard4);
}


Return to “Suggestions”

Who is online

Users browsing this forum: No registered users and 175 guests