#Path replacement

1 messages ยท Page 1 of 1 (latest)

abstract lance
#

@undone halo have you made a backup of your world data before this ?

undone halo
#

i will do so, yes.

#

i'm just downloading the s3 assets atm

#

that's just the worlds folder in the Data folder, right? or should I back up the whole Data folder?

#

guess it won't hurt.

#

to do the latter

abstract lance
#

just world would do, but a whole backup every so often wont go amis

undone halo
#

will do.

#

got the room

abstract lance
#

gimme a shout when you've got the backup

undone halo
#

ok. gonna be a few more minutes. I just did the whole folder.

#

thanks!

#

probably about 20 more minutes

undone halo
#

Hey, i just fucked up the fstab on my pi. In emergency mode. This will take a while.

#

Sorry for the delay

abstract lance
#

np

undone halo
#

Ugh. Finally got back my install. Had to rebuild the whole environment.

#

Nothing like wiping a pi and rebuilding from scratch.

undone halo
#

Got the backup and reinstall is good.

abstract lance
#

NOTE this is made for v8 and has not been updated for v9
so... ```js
let actorUpdates = [];
for (let actor of game.actors) {
let files;
let skip = false;
let newimg = actor.data.token.img.replace("X", "Y")
try {
files = await FilePicker.browse('user', newimg)
}
catch {
skip = true
}
if (skip == true) continue
if (CheckFiles(files, newimg)) {
actorUpdates.push({ _id: actor.id, "token.img": newimg });
console.log("Actor Token", actor, "updated");
}
}
if (actorUpdates.length != 0) await Actor.update(actorUpdates);
//Replace Avatars
let actorUpdatesAvatar = [];
for (let actor of game.actors) {
let files;
let skip = false;
let newimg = actor.data.img.replace("X", "Y")
try {
files = await FilePicker.browse('user', newimg)
}
catch {
skip = true
}
if (skip == true) continue
if (CheckFiles(files, newimg)) {
actorUpdatesAvatar.push({ _id: actor.id, "img": newimg });
console.log("Actor Avatar", actor, "updated");
}
}
if (actorUpdatesAvatar.length != 0) await Actor.update(actorUpdatesAvatar);

function CheckFiles(files, webPath) {
for (let file of files.files) {
if (file === webPath) return true;
}
}

this will update the actor images and prototype token images for all Actor Directory actors if it can find a replacement file given the name-swap
undone halo
#

oh, nice. thank you so much. Is there a way to just change all the s3 paths to a local path? so maps, tokens, etc., all get updated?

abstract lance
#

I was just doing 1 by one, just incase something went wrong

undone halo
#

ah, good move.

#

thank you.

abstract lance
#

this should do all tokens```js
for (let scene of game.scenes) {
let tokenUpdates = [];
for (let token of scene.data.tokens) {
let files;
let skip = false;
let newimg = token.data.img.replace("X", "Y")

    try {
        files = await FilePicker.browse('user', newimg)
    }
    catch {
        skip = true
    }
    if (skip == true) continue
    if (CheckFiles(files, newimg)) {
        tokenUpdates.push({ _id: token._id, "img": newimg });
        console.log("Token", token, "updated");
    }
}
if (tokenUpdates.length != 0) await scene.updateEmbeddedEntity("Token", tokenUpdates);

}

function CheckFiles(files, webPath) {
for (let file of files.files) {
if (file === webPath) return true;
}
}

#

this for tiles/backgrounds```js
let tileupdates = 0;
let backgoundupdates = 0;
for (let scene of game.scenes) {
let updates = [];
for (let tile of scene.data.tiles) {
let files;
let skip = false;
let newimg = tile.img.replace("X", "Y")

    try {
        files = await FilePicker.browse('user', newimg)
    }
    catch {
        skip = true
    }
    if (skip == true) continue
    if (CheckFiles(files, newimg)) {
        updates.push({ _id: tile._id, img: newimg });
        console.log("Tile", tile, "updated");
    }

}
console.log("Tiles in Scene ", scene, "updated")
await scene.updateEmbeddedEntity("Tile", updates);
tileupdates += updates.length
//Replace Backgrounds
let skip = false;
let files;
let newimg = scene.data.img?.replace("X", "Y")

try {
    files = await FilePicker.browse('user', newimg)
}
catch {
    skip = true
}
if (skip == false) {
    if (CheckFiles(files, newimg)) {
        await scene.update({ img: newimg });
        console.log("Background for Scene", scene, "updated");
        backgoundupdates++;
    }
}

}

function CheckFiles(files, webPath) {
for (let file of files.files) {
if (file === webPath) return true;
}
}

#

oh wait woops, 1 sec fixed now

undone halo
#

thanks so much. this is very helpful. I'll try playing arond with it.

abstract lance
#

@rapid cargo try this

rapid cargo
abstract lance
#

@blazing cedar ๐Ÿ™‚

#

might help

blazing cedar
# abstract lance <@!435257137141383179> ๐Ÿ™‚

Thank you very much! If I'm purely a macro-user that takes macros from you smarter people and uses them will I get this? I don't write or understand macros but I assume the above is pretty straight forward like most of the great work ya'll do?

abstract lance
#

so in the let newImage = ....replace() you need to fill in your 2 different paths

#

in your case I think your paths would be somethiing like imageA and then characters/imageA right ?

blazing cedar
#

Yes because currently they're all under the plain Data folder (before I knew how i'd organize FVTT)

#

I may make

#

Player Characters, NPCs, Hostiles

#

Or something

#

do you recommend just one folder maybe?

abstract lance
#

I personaly organize by creature type for NPC.s then PCs in one folder

blazing cedar
abstract lance
#

if you wanted to mass move a load of images yes

blazing cedar
abstract lance
#

@neat knoll

neat knoll
#

Thanks, I'll read over this thread to see if I can understand / apply it. Cheers.

#

And that macro code up there doesn't worry about case sensitivity in file names?

abstract lance
#

it has to match exactly

neat knoll
#

๐Ÿ‘

abstract lance
#

@vast tangle @wicked crow might be interested in some of this

vast tangle
abstract lance
#

@low kettle

low kettle
abstract lance
#

@pastel mango ๐Ÿ™‚

pastel mango
#

oh

pastel mango
#

just a thought, maybe add this if (!actor.data.token.img.includes("old path")) continue;

pastel mango
#

I am testing the macros in my loval v9 environment, it does not like scene.updateEmbeddedEntity("Token", tokenUpdates);, needs scene.updateEmbeddedDocuments("Token", tokenUpdates); and tokenUpdates.push({ _id: token._id, "img": newimg }); needs to be updated to tokenUpdates.push({ _id: token.id, "img": newimg });

#

and the FilePicker.browse was causing it to not catch all images for some reason

abstract lance
#

This was made in v8 and not tested for v9

pastel mango
#

just noting it for future. The script works in v8 with those changes as well

abstract lance
#

@glossy jackal this is a rough jist

glossy jackal
#

Actually, looking closer now, a lot of the icons have entirely different file names. Not sure how feasible this would be

abstract lance
#

@compact pelican try this

compact pelican
# abstract lance <@!231911431958691841> try this

I'm very much a newbie with this sort of thing. For switching extension name for my tokens, notes, maps, etc. from png and jpeg to webp, do I need to make any edits to the code above or is it essentially finding the most similar files to replace to?

abstract lance
#

no no, you will have to make edits

#

actually, there should be an easier macro for you if you're just replacing png=> webp

compact pelican
#

Yup, all I need to do is replace png and jpeg to webp because I used a converter to replace all my images in the data file using the same location.

abstract lance
#

i now cant find the macro I wrote for this ๐Ÿ˜„

#

oh no wait, this is it im just dumb

#

all you need to do is change any replace(X, Y) with replace("png", "webp") and that should work

#

but make sure you make a backup first

compact pelican
abstract lance
#

thats for actors, but yes. Copy/paste that macro into a foundry script macro, make those changes and hit Execute (after making a backup)

compact pelican
#
let actorUpdates = [];
for (let actor of game.actors) {
    let files;
    let skip = false;
    let newimg = actor.data.token.img.replace("png", "webp")
    try {
        files = await FilePicker.browse('user', newimg)
    }
    catch {
        skip = true
    }
    if (skip == true) continue
    if (CheckFiles(files, newimg)) {
        actorUpdates.push({ _id: actor.id, "token.img": newimg });
        console.log("Actor Token", actor, "updated");
    }
}
if (actorUpdates.length != 0) await Actor.update(actorUpdates);
//Replace Avatars
let actorUpdatesAvatar = [];
for (let actor of game.actors) {
    let files;
    let skip = false;
    let newimg = actor.data.img.replace("png", "webp")
    try {
        files = await FilePicker.browse('user', newimg)
    }
    catch {
        skip = true
    }
    if (skip == true) continue
    if (CheckFiles(files, newimg)) {
        actorUpdatesAvatar.push({ _id: actor.id, "img": newimg });
        console.log("Actor Avatar", actor, "updated");
    }
}
if (actorUpdatesAvatar.length != 0) await Actor.update(actorUpdatesAvatar);

function CheckFiles(files, webPath) {
    for (let file of files.files) {
        if (file === webPath) return true;
    }
}
#

With this error:

compact pelican
#

After making further adjustments to the code, I am receiving this error:

foundry.js:10090 Uncaught (in promise) Error: You must provide an _id for every object in the update data Array.
[No packages detected]
    at ClientDatabaseBackend._preUpdateDocumentArray (foundry.js:10090)
    at ClientDatabaseBackend._updateEmbeddedDocuments (foundry.js:10057)
    at ClientDatabaseBackend.update (backend.mjs:153)
    at async Function.updateDocuments (document.mjs:373)
abstract lance
#

@plucky glade ๐Ÿ™‚

plucky glade
#

thank you, didnt see this in Pins and didnt check Threads @abstract lance

small parcel
#

Hello ! Is there a way to use this macro in V9 ? I uptaded all my PNG to Webp, but still searching if there is a way to win time for compendium token link. :'D

neat knoll
#

I'm after how to use this for a compendium as well in v9. Its probably something like changing the game.actors to game.packs("your-compendium-name") where "your-compendium-name" is what you've named your actor compendium, but NO idea if that is even remotely close and there's probably other changes that need.

neat knoll
#

Nope, I tried doing this but got an error message:
TypeError: game.packs is not a function or its return value is not iterable
so I think there's something on the

let newimg = actor.data.token.img.replace("png", "webp")``` that is wrong as well.
neat knoll
#

Is there any way to change 2 things at the same time? Like image path AND from jpeg to webp?

abstract lance
#

Just change the parameters of the replace function

#

replace("data/image/a.png", "data/tokens/a.webp")

neat knoll
#

That would only work on 1 actor at a time right? Any way to get it to loop through all using variables? And I've not been able to get the image swap to work on a Compendium. Is game.packs.getName correct or is there something else?

abstract lance
#

Game.packs.get(key)

neat knoll
#

Thanks. Using that in the following macro gives me this error:
Error: The key gIoDL4auFDFPTknd does not exist in the Actors Collection
The macro is as follows:

let actorUpdates = [];
for (let actor of game.packs.get("SharedData.DDBMonsters")) {
    let files;
    let skip = false;
    let newimg = actor.data.token.img.replace("ddb-images/other/", "assets/tokens/monsters/")
    try {
        files = await FilePicker.browse('user', newimg)
    }
    catch {
        skip = true
    }
    if (skip == true) continue
    if (CheckFiles(files, newimg)) {
        actorUpdates.push({ _id: actor.id, "token.img": newimg });
        console.log("Actor Token", actor, "updated");
    }
}
if (actorUpdates.length != 0) await Actor.updateDocuments(actorUpdates);

//Replace Avatars
let actorUpdatesAvatar = [];
for (let actor of game.packs.get("SharedData.DDBMonsters")) {
    let files;
    let skip = false;
    let newimg = actor.data.img.replace("ddb-images/other/", "assets/tokens/monsters/")
    try {
        files = await FilePicker.browse('user', newimg)
    }
    catch {
        skip = true
    }
    if (skip == true) continue
    if (CheckFiles(files, newimg)) {
        actorUpdatesAvatar.push({ _id: actor.id, "img": newimg });
        console.log("Actor Avatar", actor, "updated");
    }
}
if (actorUpdatesAvatar.length != 0) await Actor.updateDocuments(actorUpdatesAvatar);

function CheckFiles(files, webPath) {
    for (let file of files.files) {
        if (file === webPath) return true;
    }
}```
So I'm guessing there are a couple of issues, probably around the
```js
let newimg = actor.data.token.img.replace("ddb-images/other/", "assets/tokens/monsters/")

and the

actorUpdatesAvatar.push({ _id: actor.id, "img": newimg });
``` line
#

Rather than trying to update both path and jpeg to webp at the same time, I've just created 2 macros and copied the original source images for avatar and token to the target to try and get the new location set, then I'll set the jpeg to webp macro to work after. But, the first location change isn't running due to the initial error I posted above.

#

The database key is correct

neat knoll
abstract lance
#

I would guess there's something broken with that actor then

neat knoll
#

Sorry for the late response. Its happening with different actors at different times. I've tried running the migrate compendium macro from the DDB Importer server to see if that helps / triggers the actor reference in the macro (although I was pretty sure I'd done that previously). I'll keep trying, thanks for your help.

neat knoll
#

And what's strange is that in the console, I can see that the actor in question (in this case a freshly munched 'Acolyte' is processed as the first munched monster and is marked as 'updated' but is then referenced in the following error message:
Strange, and I genuinely have no idea what the issue is.

abstract lance
#

Its trying to update in the wrong place