JSON Filters of Data in an Array

I have a test wiki setup here: https://mtg-test.tiddlyhost.com/

All cards imported and loads in about 4 seconds on my machine, perfectly reasonable. I’ll consider this a solved problem. Thank you!

In an effort to reduce the size, I am generating the Scryfall URI from the card ID. However, I discovered that the URI is prefixed with the first two characters of the ID, presumably because they store the images in static folders. For example:

https://cards.scryfall.io/normal/front/a/4/a471b306-4941-4e46-a0cb-d92895c16f8a.jpg

  • The ID for this card is a471b306-4941-4e46-a0cb-d92895c16f8a
  • The first part of the URI https://cards.scryfall.io/normal/front/ is static
  • After that it is followed by id[0], a slash, and id[1]

I could add a field and pre-process this while avoiding storing the whole URI, but I’m struggling to find a string function to give me the first and second characters of the string. I’ve attempted to create a macro ($:scryfalluri in the new wiki) but I’m getting no output or error messages. Hopefully there’s a built-in macro or function to do a substring operation that I’m missing.

I disagree, showing me an example that was performant was very useful. Thank you!

1 Like

Since those characters are separated by “/”, you might try using a split[/] filter operator.

Let’s assume you have the complete URI in a variable named <<uri>>

<$let path={{{ [<uri>trim[https://cards.scryfall.io/normal/front/]] }}}>
<$let  firstchar={{{ [<path>split[/]nth[1]] }}}>
<$let secondchar={{{ [<path>split[/]nth[2]] }}}>
<$let   filename={{{ [<path>split[/]nth[3]] }}}>

For convenience, the 1st line removes the static part of the URI so the rest of the filters only need to deal with the remaining part of the URI.

-e

1 Like

This doesn’t do what I’m looking for. I need the first character from the ID:

<$let cid="fa7a883f-e180-48ce-b7d4-cded2f74c323">
<$let firstchar={{{ ... }}}> // Should look at 'cid' and return 'f'
<$let secondchar={{{ ... }}}> // Should look at 'cid' and return 'a'

* "<<cid>>"
* "<<firstchar>>"
* "<<secondchar>>"

Try the following (and note that you can combine multiple variable definitions into a single $let widget, where subsequent definitions have access to any variable that has been previously defined):

<$let
	cid="fa7a883f-e180-48ce-b7d4-cded2f74c323"
	firstchar={{{ [<cid>split[]nth[1]] }}}
	secondchar={{{ [<cid>split[]nth[2]] }}}
>
2 Likes

That was the last piece I needed. I now have the following in my default view:

\define scryfalllink(scryfalluri) [[Scryfall|$scryfalluri$]]

<$let
    baseuri="https://cards.scryfall.io/normal/front"
	cid={{!!cid}}
	firstchar={{{ [<cid>split[]nth[1]] }}}
	secondchar={{{ [<cid>split[]nth[2]] }}}
    imguri=`$(baseuri)$/$(firstchar)$/$(secondchar)$/$(cid)$.jpg`
>

<% if [all[current]tag[MtgCard]] %>

<$image source=<<imguri>> />

* Type: {{!!tl}}
* Mana Cost: {{!!mc}}
* <$macrocall $name="scryfalllink" scryfalluri={{!!sfuri}}/>

<% endif %>

I still need to wrap my head around when I can and can’t pass a variable to wikitext/macros/filter expressions but I’m getting there. Thanks to everyone for your help!

Just keep in mind that using shorthand forms like <<>> {{}} [[]] that it is harder to provide parameter values from other places ie other <<>> {{}} [[]] If you want to call a function/procedure/transclusion using the long form givers you more power eg “<$macrocall, <$transclude, <$link, <$transclude $variable”.

However if you are writing the macro/procedure or function you can choose what those parameters are, and can often hard code items, or accept names eg varname, fieldname then use that to obtain the value eg [<varname>getvariable[]], [get<fieldname>] allowing the reference not the value to be passed into your code.

I did try to build a wiki out of your JSON, and it also seems perfectly performant:

http://scott.sauyet.com/Tiddlywiki/Demo/MtG/v1/.

I used my personal starter edition and converted your JSON to a new collection of Card and Set tiddlers.1 I added very simple templates for Set and Card tiddlers, and that was it.

The resulting file is 8.7MB. It loads for me, over a reasonably fast connection, in about 3 seconds. There are no noticeable performance issues in navigating. I have not tried any complex queries yet, though.

Feel free to ignore it, to take it outright, or anything in between.





1 The (Node.js) code looks like this:

See code
const cards = JSON.parse(require('./MtgCards.json')[0].text)

console.log(JSON.stringify([
  ... cards.map(card => ({
    title: card.name,
    tags: `Card [[${card.set_name}]]`,
    'image-url': card['image_uris.normal'],
    'mana-cost': card.mana_cost,
    'type-line': card.type_line,
    'legalities-commander': card['legalities.commander'],
    'set-name': card.set_name 
  })),
  ...[... new Set(cards.map(card => card['set_name']))].map(title => ({
    title,
    tags: 'Set'
  })),
  {
    title: 'Set',
    tags: 'TableOfContents',
    caption: 'Sets',
    text: `<div style="column-width: 15em;"><<list-links filter:"[tag[Set]]">></div>`
  }
]))

which I stored as index.js in a folder alongside the result of downloading your MtgCards.json tiddler, and I simply ran it as node index > cards.json and dragged the resulting cards.json file onto my empty starter edition.