fantasycalendar / FoundryVTT-Sequencer

This module implements a basic pipeline that can be used for managing the flow of a set of functions, effects, sounds, and macros.
Other
47 stars 26 forks source link

[BUG] - Error loading JB2A animations from S3 #293

Open crlgn opened 2 months ago

crlgn commented 2 months ago

Describe the bug I'm getting some errors trying to play JB2A animations from S3 using AA and Sequencer. The issue sounds somewhat similar to this one, but since it's old I'm trying to figure out a course of action.

I had the default JB2A module installed, but recently became a patreon of JB2A so I loaded the full JB2A patreon folder to S3, because the folder is too large for my poor ec2 instance. I added the bucket path to AA configurations, and when I preview animation effects on Automated Animations panel, they all play fine. I checked on console and the address is correct, all animations loading from S3. But when I actually try to activate the animation on a token using sequencer, I get errors on console and the animation does not play.

The first error says the resource is blocked by CORS policy. This doesn't make much sense to me, since the video loads fine on AA panel preview. I also see an error on sequencer-file-cache.js, logged right after that: TypeError: Failed to fetch at Object.loadVideo (sequencer-file-cache.js:12:26)

All videos are made public and the bucket has the necessary permissions to be publicly accessed - which works with all files, filepicker, etc. When I copy the link from the console error and paste it on the browser, the animation video plays fine, as well as on AA preview.

Any ideas what could be causing this?

To Reproduce Steps to reproduce the behavior:

  1. Upload JB2A animation videos to S3
  2. Enable Automated Animations and configure video to play on a spell or token condition
  3. Trigger the condition on the token
  4. See error

Expected behavior Animations should play

Screenshots If applicable, add screenshots to help explain your problem.

Setup:

Active modules:

Jykinturah commented 1 month ago

I am testing S3 for JB2A as well, note that the url must be configured within the settings of JB2A and not just AA. In the JB2A settings, I used the public url of my bucket, ex: https://bucketname.region.domain.name

This allowed me to play animations from JB2A using the Sequencer Database without issues. Checking the network log shows that the requests are going through just fine. Despite this, the effects do not play on the canvas itself. There are no errors thrown, and I do see the network request being made. I will share examples of the difference.

One that worked using the preview of AA or Sequencer Database:

GET /jb2a_patreon/Library/Generic/Weapon_Attacks/Melee/Quarterstaff04_01_Regular_White_800x600.webm HTTP/2
Host: [bucket-url]
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:130.0) Gecko/20100101 Firefox/130.0
Accept: video/webm,video/ogg,video/*;q=0.9,application/ogg;q=0.7,audio/*;q=0.6,*/*;q=0.5
Accept-Language: en-US,en;q=0.5
Range: bytes=0-
DNT: 1
Sec-GPC: 1
Connection: keep-alive
Referer: [foundry-instance]
Sec-Fetch-Dest: video
Sec-Fetch-Mode: no-cors
Sec-Fetch-Site: cross-site
Accept-Encoding: identity
Priority: u=4

Response from S3

HTTP/2 206 
content-length: 168457
content-range: bytes 0-168456/168457
accept-ranges: bytes
last-modified: Tue, 17 Sep 2024 03:36:24 GMT
x-rgw-object-type: Normal
etag: "5411401ed58bec3ecb2753353be1aebe"
x-amz-request-id: tx0000012a0f2bdbebdb9ae-0066e91a53-52724838-sfo3a
content-type: text/plain
date: Tue, 17 Sep 2024 05:57:39 GMT
vary: Origin, Access-Control-Request-Headers, Access-Control-Request-Method
strict-transport-security: max-age=15552000; includeSubDomains; preload
x-envoy-upstream-healthchecked-cluster: 
X-Firefox-Spdy: h2

Actually attempting to use an animation on an active token:

GET /jb2a_patreon/Library/Generic/Marker/MarkerDrop_02_Regular_Red_400x400.webm HTTP/2
Host: [bucket-url]
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:130.0) Gecko/20100101 Firefox/130.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br, zstd
Referer: [foundry-instance]
Origin: [foundry-instance]
DNT: 1
Sec-GPC: 1
Connection: keep-alive
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site

Response from S3

HTTP/2 200 
content-length: 888362
accept-ranges: bytes
last-modified: Tue, 17 Sep 2024 03:16:02 GMT
x-rgw-object-type: Normal
etag: "37b24fd38380b01e4173a2f0e5cd54ef"
x-amz-request-id: tx0000006f6debc5756df22-0066e91a2c-52724838-sfo3a
access-control-allow-origin: [foundry-instance]
vary: Origin,Origin, Access-Control-Request-Headers, Access-Control-Request-Method
access-control-allow-methods: GET
access-control-max-age: 0
content-type: text/plain
date: Tue, 17 Sep 2024 05:57:00 GMT
strict-transport-security: max-age=15552000; includeSubDomains; preload
x-envoy-upstream-healthchecked-cluster: 
X-Firefox-Spdy: h2

Despite the effect not playing, Sequencer debugging prints no error and returns an object. Using Automated Animations:

{
  "_id": "3ZTIcZbjFE28fbkU",
  "flagVersion": "3.2.1",
  "sequenceId": "Q4jfLXKcEo4BWeHl",
  "creationTimestamp": 1726553039610,
  "sceneId": "JwnsxPY5o7cTLPz3",
  "creatorUserId": "OY6UX1ZYHERdiFZA",
  "moduleName": "Automated Animations",
  "users": false,
  "name": "Wounded 197muw3tor90nQtDD",
  "origin": "Actor.ahUfNLvvHDt7GucT.Item.0gOy5B5dke1rnEKo",
  "index": 1,
  "repetition": 0,
  "private": null,
  "temporary": false,
  "tiedDocuments": [
    "Actor.ahUfNLvvHDt7GucT.Item.0gOy5B5dke1rnEKo"
  ],
  "source": "Scene.JwnsxPY5o7cTLPz3.Token.97muw3tor90nQtDD",
  "target": false,
  "rotateTowards": null,
  "stretchTo": false,
  "moveTowards": false,
  "attachTo": {
    "active": true,
    "align": "center",
    "edge": "on",
    "bindVisibility": true,
    "bindAlpha": true,
    "bindScale": true,
    "bindElevation": true,
    "bindRotation": true
  },
  "missed": null,
  "file": "autoanimations.static.conditions.drop.02.red.0",
  "customRange": false,
  "forcedIndex": false,
  "fileOptions": {
    "antialiasing": 1
  },
  "text": null,
  "tilingTexture": null,
  "masks": [],
  "shapes": [],
  "volume": null,
  "isometric": null,
  "syncGroup": null,
  "scale": {
    "x": 1,
    "y": 1
  },
  "spriteScale": {
    "x": 1,
    "y": 1
  },
  "angle": null,
  "size": {
    "width": 1.5,
    "height": 1.5,
    "gridUnits": true
  },
  "offset": null,
  "anchor": {
    "x": 0.5,
    "y": 0.5
  },
  "spriteOffset": null,
  "spriteAnchor": null,
  "template": null,
  "zeroSpriteRotation": null,
  "randomOffset": {
    "source": false,
    "target": false
  },
  "randomRotation": null,
  "scaleToObject": null,
  "elevation": {
    "elevation": 999,
    "absolute": false
  },
  "sortLayer": 800,
  "aboveLighting": null,
  "aboveInterface": null,
  "xray": null,
  "zIndex": 1,
  "opacity": 0.8,
  "filters": null,
  "loopOptions": null,
  "spriteRotation": 0,
  "randomSpriteRotation": false,
  "flipX": null,
  "flipY": null,
  "duration": false,
  "persist": true,
  "persistOptions": {
    "id": "uSOuHcYYEVu0WNDk",
    "persistTokenPrototype": true
  },
  "playbackRate": 1,
  "extraEndDuration": null,
  "time": false,
  "moves": null,
  "moveSpeed": null,
  "fadeIn": {
    "duration": 250,
    "ease": "linear",
    "delay": 0
  },
  "fadeOut": {
    "duration": 500,
    "ease": "linear",
    "delay": 0
  },
  "scaleIn": null,
  "scaleOut": null,
  "rotateIn": null,
  "rotateOut": null,
  "fadeInAudio": null,
  "fadeOutAudio": null,
  "animations": null,
  "screenSpace": null,
  "screenSpaceAboveUI": null,
  "screenSpaceAnchor": null,
  "screenSpacePosition": null,
  "screenSpaceScale": null,
  "nameOffsetMap": {
    "Wounded 197muw3tor90nQtDD": {
      "seed": "Wounded 197muw3tor90nQtDD-eCT1mII7oqqGyaxy",
      "source": "Scene.JwnsxPY5o7cTLPz3.Token.97muw3tor90nQtDD",
      "target": false,
      "randomOffset": {
        "source": false,
        "target": false
      },
      "missed": null,
      "offset": null,
      "repetitions": 1,
      "twister": {}
    }
  }
}

Using PF2e Graphics:

{
  "_id": "1XmqQag01ImyBW9Y",
  "flagVersion": "3.2.1",
  "sequenceId": "OThAjzTzlJar5lHy",
  "creationTimestamp": 1726553121800,
  "sceneId": "JwnsxPY5o7cTLPz3",
  "creatorUserId": "OY6UX1ZYHERdiFZA",
  "moduleName": "Sequencer",
  "users": false,
  "name": "Wounded 1",
  "origin": "wounded-entry",
  "index": 1,
  "repetition": 0,
  "private": null,
  "temporary": false,
  "tiedDocuments": [
    "Actor.ahUfNLvvHDt7GucT.Item.ZiMl0Z5U8PT1Mjtc"
  ],
  "source": "Scene.JwnsxPY5o7cTLPz3.Token.97muw3tor90nQtDD",
  "target": false,
  "rotateTowards": null,
  "stretchTo": false,
  "moveTowards": false,
  "attachTo": {
    "active": true,
    "align": "center",
    "edge": "on",
    "bindVisibility": true,
    "bindAlpha": true,
    "bindScale": true,
    "bindElevation": true,
    "bindRotation": true
  },
  "missed": null,
  "file": "jb2a.markers.drop.red.03",
  "customRange": false,
  "forcedIndex": 3,
  "fileOptions": {
    "antialiasing": 1
  },
  "text": null,
  "tilingTexture": null,
  "masks": [],
  "shapes": [],
  "volume": null,
  "isometric": null,
  "syncGroup": null,
  "scale": {
    "x": 1,
    "y": 1
  },
  "spriteScale": {
    "x": 1,
    "y": 1
  },
  "angle": null,
  "size": null,
  "offset": null,
  "anchor": {
    "x": 0.5,
    "y": 0.5
  },
  "spriteOffset": null,
  "spriteAnchor": null,
  "template": null,
  "zeroSpriteRotation": null,
  "randomOffset": {
    "source": false,
    "target": false
  },
  "randomRotation": true,
  "scaleToObject": {
    "scale": 1.5,
    "considerTokenScale": true,
    "uniform": false,
    "value": 1.5
  },
  "elevation": null,
  "sortLayer": 800,
  "aboveLighting": null,
  "aboveInterface": null,
  "xray": null,
  "zIndex": null,
  "opacity": 1,
  "filters": null,
  "loopOptions": null,
  "spriteRotation": 0,
  "randomSpriteRotation": false,
  "flipX": null,
  "flipY": null,
  "duration": false,
  "persist": true,
  "persistOptions": {
    "id": "8mf1hjN0WkpodZbp",
    "persistTokenPrototype": true,
    "value": true
  },
  "playbackRate": null,
  "extraEndDuration": null,
  "time": false,
  "moves": null,
  "moveSpeed": null,
  "fadeIn": {
    "duration": 250,
    "ease": "linear",
    "delay": 0
  },
  "fadeOut": {
    "duration": 500,
    "ease": "linear",
    "delay": 0
  },
  "scaleIn": null,
  "scaleOut": null,
  "rotateIn": null,
  "rotateOut": null,
  "fadeInAudio": null,
  "fadeOutAudio": null,
  "animations": null,
  "screenSpace": null,
  "screenSpaceAboveUI": null,
  "screenSpaceAnchor": null,
  "screenSpacePosition": null,
  "screenSpaceScale": null,
  "nameOffsetMap": {
    "Wounded 1": {
      "seed": "Wounded 1-I84pL7lw9sL77dPW",
      "source": "Scene.JwnsxPY5o7cTLPz3.Token.97muw3tor90nQtDD",
      "target": false,
      "randomOffset": {
        "source": false,
        "target": false
      },
      "missed": null,
      "offset": null,
      "repetitions": 1,
      "twister": {}
    }
  }
}

I'm using Sequencer and JB2A Patreon Animations primarily. I am testing with Automated Animations and PF2e Animation Macros in combination, and PF2e Graphics on its own as it is intended to replace AA and PF2eAM.

Naturally, using JB2A without S3 works without any issues.

crlgn commented 1 month ago

I did a thorough investigation on this, and in my case, the issue was due to Chrome caching behavior and CORS headers. I'm not sure it is your case, as you say there are no errors thrown, but I'll describe my issue here and you can test.

When you load the video through a preview, it is loaded using a <video /> tag in opaque mode. Opaque mode does not require CORS headers. So if this is the first time you loaded that video, Chrome caches the request without CORS headers.

However, for use on canvas, Sequencer needs to load the video using the fetch api, which does require headers (and afaik, nothing can be done about it). So when Sequencer requests a video that has been previewed with <video />, Chrome delivers the cached version without headers, so it errors out and does not load. I found out that if the video tag where the effect is previewed adds "crossorigin=anonymous" attribute, that issue is solved. That is not something to be added on Sequencer, but on whatever module loads a preview (in my case it was mostly Filepicker+ from theRipper93, I pleaded my case to him and he added the attribute to the video in his module, which solved 90% of my problem. If I preview with Automated Animations I still get the issue).

To check if this is your case, try the following:

If the video loads, that's most probably the issue.

Jykinturah commented 1 month ago

I was wondering if it was CORS related, but checking the configuration using a CORS tester shows that the configuration is valid. I tried clearing the cache, but it doesn't resolve the issue. I tried on Firefox and Chrome, though I primarily use Firefox.

I could try to sit and try looking at what the code is doing in Sequencer, but that will take some time.