Skip to content
This repository was archived by the owner on Apr 17, 2021. It is now read-only.
This repository was archived by the owner on Apr 17, 2021. It is now read-only.

Add support for deck covers of any file type, from URL #54

@marccarre

Description

@marccarre

What? Why?

#49 added support for JPEG deck covers loaded from local files.
However, it would be nice to

  • be able to set covers from existing image URLs (as suggested here by @floscha),
  • handle other formats (e.g. PNG).

In order to do this, the coverImageUrl field would have to be supported.

How?

Below is an extract of requests/responses with the fields relevant to covers, when manually interacting with decks on https://tinycards.duolingo.com.

Observations

  • Invariant 1.: before a custom cover is set, coverImageUrl is always null.
  • Invariant 2.: in deck updates, even for deck cover updates, coverImageUrl is always sent back, with the latest value received from the server-side, i.e. null if no custom cover, or the last known URL to server-side otherwise.
  • Invariant 3.: responses from POSTs/PATCHs requests and subsequent GET requests are always equivalent w.r.t. to imageUrl and coverImageUrl.

1. Deck creation w/o cover:

POST https://tinycards.duolingo.com/api/1/decks

  • no imageFile field
  • no imageUrl field
  • no imageCoverUrl field
    Response:
{
  "coverImageUrl": null,
  "imageUrl": "https://s3.amazonaws.com/tinycards/image/16cb6cbcb086ae0f622d1cfb7553a096"
}

2. Subsequent deck loading:

GET https://tinycards.duolingo.com/api/1/decks/{deckID}

{
  "coverImageUrl": null,
  "imageUrl": "https://s3.amazonaws.com/tinycards/image/16cb6cbcb086ae0f622d1cfb7553a096",
}

3. Deck cards update:

PATCH https://tinycards.duolingo.com/api/1/decks/{deckID}

{
  "coverImageUrl": null
}

Response:

{
"coverImageUrl": null,
"imageUrl": "https://s3.amazonaws.com/tinycards/image/16cb6cbcb086ae0f622d1cfb7553a096"
}

4. Subsequent deck loading:

GET https://tinycards.duolingo.com/api/1/decks/{deckID}

{
  "coverImageUrl": null,
  "imageUrl": "https://s3.amazonaws.com/tinycards/image/16cb6cbcb086ae0f622d1cfb7553a096",
}

5. Deck cover update from local file:

PATCH https://tinycards.duolingo.com/api/1/decks/{deckID}

------<separator>
Content-Disposition: form-data; name="imageFile"; filename="cover.jpg"
Content-Type: image/jpeg
[...bytes...]
------<separator>
Content-Disposition: form-data; name="coverImageUrl"

null

Response:

{
  "coverImageUrl": "https://d9np3dj86nsu2.cloudfront.net/image/9f6a54aef25a5184620e5762c8430353",
  "imageUrl": "https://d9np3dj86nsu2.cloudfront.net/image/9f6a54aef25a5184620e5762c8430353"
}

6. Subsequent deck loading:

GET https://tinycards.duolingo.com/api/1/decks/{deckID}

{
  "coverImageUrl": "https://d9np3dj86nsu2.cloudfront.net/image/9f6a54aef25a5184620e5762c8430353",
  "imageUrl": "https://d9np3dj86nsu2.cloudfront.net/image/9f6a54aef25a5184620e5762c8430353"
}

7. Deck cards update

PATCH https://tinycards.duolingo.com/api/1/decks/{deckID}

{
  "coverImageUrl": "https://d9np3dj86nsu2.cloudfront.net/image/9f6a54aef25a5184620e5762c8430353"
}

Response:

{
  "coverImageUrl": "https://d9np3dj86nsu2.cloudfront.net/image/9f6a54aef25a5184620e5762c8430353",
  "imageUrl": "https://d9np3dj86nsu2.cloudfront.net/image/9f6a54aef25a5184620e5762c8430353"
}

8. Subsequent deck loading:

GET https://tinycards.duolingo.com/api/1/decks/{deckID}

{
  "coverImageUrl": "https://d9np3dj86nsu2.cloudfront.net/image/9f6a54aef25a5184620e5762c8430353",
  "imageUrl": "https://d9np3dj86nsu2.cloudfront.net/image/9f6a54aef25a5184620e5762c8430353"
}

9. Deck cover update from Tinycards' image library:

PATCH https://tinycards.duolingo.com/api/1/decks/{deckID}

------<separator>
Content-Disposition: form-data; name="imageAttribution"

<source URL of the image>
------<separator>
Content-Disposition: form-data; name="imageFile"; filename="cover.jpg"
Content-Type: image/png
[...bytes...]
------<separator>
Content-Disposition: form-data; name="coverImageUrl"

https://d9np3dj86nsu2.cloudfront.net/image/9f6a54aef25a5184620e5762c8430353

Response:

{
  "coverImageUrl": "https://d9np3dj86nsu2.cloudfront.net/image/ada59f16c4e4d8b09f7eee9104ce6bc7",
  "imageUrl": "https://d9np3dj86nsu2.cloudfront.net/image/ada59f16c4e4d8b09f7eee9104ce6bc7"
}

10. Subsequent deck loading:

GET https://tinycards.duolingo.com/api/1/decks/{deckID}

{
  "coverImageUrl": "https://d9np3dj86nsu2.cloudfront.net/image/ada59f16c4e4d8b09f7eee9104ce6bc7",
  "imageUrl": "https://d9np3dj86nsu2.cloudfront.net/image/ada59f16c4e4d8b09f7eee9104ce6bc7"
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions