Skip to content

Instantly share code, notes, and snippets.

@daddykotex
Created October 14, 2020 13:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save daddykotex/3a885e6cc14303a814b772bd1c92d574 to your computer and use it in GitHub Desktop.
Save daddykotex/3a885e6cc14303a814b772bd1c92d574 to your computer and use it in GitHub Desktop.
Allows you to download the higher resolution photos from a lightroom album (not original resolution).
import $ivy.`co.fs2::fs2-io:2.3.0`, fs2.io._
import $ivy.`co.fs2::fs2-core:2.3.0`, fs2._
import ammonite.ops._
import upickle.default.{ReadWriter => RW, macroRW}
import upickle._
import cats.effect._
import scala.concurrent.duration._
/**
LOG INTO LIGHTROOM AND GO TO THE ALBUM YOU WANT TO DOWNLOAD
- GRAB THE COOKIE FROM ONE OF THE REQUESTS
- DOWNLOAD THE RESPONSES TO XHR CALLS TO https://lightroom.adobe.com/v2/spaces/5be0bbc946d041de932c483f73e14a6d/albums/70c589d0859d492194da57b80efd4ce0/assets...
- THIS WILL BE A JSON FILE WITH A DEAD FIRST LINE: `while(true) {}`
- REMOVE THE FIRST LINE AND PUT THE FILE INTO A JSON FILE.
- IT LOOKS LIKE THIS
{
"base": "https://photos.adobe.io/v2/spaces/5be0bbc946d041de932c483f73e14a6d/",
"album": {
"id": "70c589d0859d492194da57b80efd4ce0",
"links": {
"self": {
"href": "albums/70c589d0859d492194da57b80efd4ce0"
}
}
},
"resources": [
{
"id": "bc1112fec85847ce9e21dc939b1eeae3",
"type": "album_asset",
"created": "0000-00-00T00:00:00",
"updated": "0000-00-00T00:00:00",
"revision_ids": [
"36eea278167c4bcf8f1f91cf39e97a17"
],
"links": {
"self": {
"href": "albums/70c589d0859d492194da57b80efd4ce0/assets/608c005d7d934c1ab18ea4b6cf8ea136"
}
},
"asset": {
"id": "608c005d7d934c1ab18ea4b6cf8ea136",
"type": "asset",
"subtype": "image",
"created": "2020-02-06T01:34:56.431636Z",
"updated": "2020-02-06T01:46:35.773254Z",
"revision_ids": [
"a5970d08065944ecb618673db22e2d5c",
"a07a0a0edd2c8acfb314b2c2077256bf",
"888b25a3574520a202bc77294e281ab4",
"a68a19336658ab900929238ae094bc6f"
],
"links": {
"self": {
"href": "assets/608c005d7d934c1ab18ea4b6cf8ea136"
},
"/rels/comments": {
"href": "assets/608c005d7d934c1ab18ea4b6cf8ea136/comments",
"count": 0
},
"/rels/favorites": {
"href": "assets/608c005d7d934c1ab18ea4b6cf8ea136/favorites",
"count": 0
},
"/rels/rendition_type/2048": {
"href": "assets/608c005d7d934c1ab18ea4b6cf8ea136/revisions/a5970d08065944ecb618673db22e2d5c/renditions/74289892102452cb92155e94fc4c08bd"
},
"/rels/rendition_type/1280": {
"href": "assets/608c005d7d934c1ab18ea4b6cf8ea136/revisions/a5970d08065944ecb618673db22e2d5c/renditions/820dbc22334846a383b6af7275bccef5"
},
"/rels/rendition_type/640": {
"href": "assets/608c005d7d934c1ab18ea4b6cf8ea136/revisions/a5970d08065944ecb618673db22e2d5c/renditions/7cdcc08f64d620805ba197c8eade6e59"
},
"/rels/rendition_type/thumbnail2x": {
"href": "assets/608c005d7d934c1ab18ea4b6cf8ea136/revisions/a5970d08065944ecb618673db22e2d5c/renditions/725e6233a5ce9e3eba9bbd8a701222d3"
}
}
...
},
"payload": {
"userCreated": "2020-02-06T01:34:39.374Z",
"userUpdated": "2020-02-06T01:34:39.374Z"
}
}
]
}
- RUN THIS PROGRAM WITH AMMONIOTE:
`amm fetch-lightroom-album.sc photos1.json photos2.json [more files...]`
*/
final case class PhotoFile(base: String, resources: Seq[Resource])
object PhotoFile {
implicit val rw: RW[PhotoFile] = macroRW
}
final case class Resource(`type`: String, asset: Asset)
object Resource {
implicit val rw: RW[Resource] = macroRW
}
final case class Asset(id: String, links: Links)
object Asset {
implicit val rw: RW[Asset] = macroRW
}
final case class Links(@upickle.implicits.key("/rels/rendition_type/2048") large: Href)
object Links {
implicit val rw: RW[Links] = macroRW
}
final case class Href(href: String)
object Href {
implicit val rw: RW[Href] = macroRW
}
val cookie = """COOKIE_HERE"""
def photosFromFile(fileName: Path): IO[PhotoFile] = {
IO.delay(upickle.default.read[PhotoFile](fileName.toNIO))
}
def downloadResource(base: String, resource: Resource): IO[Unit] = {
IO.delay {
val url = s"${base}${resource.asset.links.large.href}"
.replace("photos.adobe.io/v2/", "lightroom.adobe.com/v2c/")
os.write(
os.pwd / "photos" / s"${resource.asset.id}.jpg",
requests.get.stream(
url,
headers = Map("Cookie" -> cookie)
)
)
}
}
@main
def downloadPhotos(photoFiles: Path*) = {
implicit val ioTimer: Timer[IO] = IO.timer(scala.concurrent.ExecutionContext.Implicits.global)
fs2.Stream
.emits(photoFiles)
.evalMap(photosFromFile)
.flatMap { photoFile =>
fs2.Stream
.emits(photoFile.resources)
.map(resource => photoFile.base -> resource)
}
.evalMap { case (base, resource) => downloadResource(base, resource) }
.metered(1.second)
.compile
.drain
.unsafeRunSync()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment