Skip to content

Commit

Permalink
Remove unused ability to create collages of images
Browse files Browse the repository at this point in the history
  • Loading branch information
simojenki committed Feb 3, 2024
1 parent 9d3016e commit b88fb9f
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 333 deletions.
72 changes: 14 additions & 58 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@ import { pipe } from "fp-ts/lib/function";
import { URLBuilder } from "./url_builder";
import makeI8N, { asLANGs, KEY, keys as i8nKeys, LANG } from "./i8n";
import { Icon, ICONS, festivals, features } from "./icon";
import _, { shuffle } from "underscore";
import _ from "underscore";
import morgan from "morgan";
import { takeWithRepeats } from "./utils";
import { parse } from "./burn";
import { axiosImageFetcher, ImageFetcher } from "./subsonic";
import {
Expand Down Expand Up @@ -558,23 +557,11 @@ function server(
});
});

const GRAVITY_9 = [
"north",
"northeast",
"east",
"southeast",
"south",
"southwest",
"west",
"northwest",
"centre",
];

app.get("/art/:burns/size/:size", (req, res) => {
app.get("/art/:burn/size/:size", (req, res) => {
const serviceToken = apiTokens.authTokenFor(
req.query[BONOB_ACCESS_TOKEN_HEADER] as string
);
const urns = req.params["burns"]!.split("&").map(parse);
const urn = parse(req.params["burn"]!);
const size = Number.parseInt(req.params["size"]!);

if (!serviceToken) {
Expand All @@ -585,55 +572,24 @@ function server(

return musicService
.login(serviceToken)
.then((musicLibrary) =>
Promise.all(
urns.map((it) => {
if (it.system == "external") {
return serverOpts.externalImageResolver(it.resource);
} else {
return musicLibrary.coverArt(it, size);
}
})
)
)
.then((coverArts) => coverArts.filter((it) => it))
.then(shuffle)
.then((coverArts) => {
if (coverArts.length == 1) {
const coverArt = coverArts[0]!;
.then((musicLibrary) => {
if (urn.system == "external") {
return serverOpts.externalImageResolver(urn.resource);
} else {
return musicLibrary.coverArt(urn, size);
}
})
.then((coverArt) => {
if(coverArt) {
res.status(200);
res.setHeader("content-type", coverArt.contentType);
return res.send(coverArt.data);
} else if (coverArts.length > 1) {
const gravity = [...GRAVITY_9];
return sharp({
create: {
width: size * 3,
height: size * 3,
channels: 3,
background: { r: 255, g: 255, b: 255 },
},
})
.composite(
takeWithRepeats(coverArts, 9).map((art) => ({
input: art?.data,
gravity: gravity.pop(),
}))
)
.png()
.toBuffer()
.then((image) => sharp(image).resize(size).png().toBuffer())
.then((image) => {
res.status(200);
res.setHeader("content-type", "image/png");
return res.send(image);
});
} else {
return res.status(404).send();
}
})
})
.catch((e: Error) => {
logger.error(`Failed fetching image ${urns.join("&")}/size/${size}`, {
logger.error(`Failed fetching image ${urn}/size/${size}`, {
cause: e,
});
return res.status(500).send();
Expand Down
275 changes: 0 additions & 275 deletions tests/server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ import { v4 as uuid } from "uuid";
import dayjs from "dayjs";
import request from "supertest";
import Image from "image-js";
import fs from "fs";
import { either as E, taskEither as TE } from "fp-ts";
import path from "path";

import { AuthFailure, MusicService } from "../src/music_service";
import makeServer, {
Expand Down Expand Up @@ -1323,279 +1321,6 @@ describe("server", () => {
});
});

describe("fetching multiple images as a collage", () => {
const png = fs.readFileSync(
path.join(
__dirname,
"..",
"docs",
"images",
"chartreuseFuchsia.png"
)
);

describe("fetching a collage of 4 when all are available", () => {
it("should return the image and a 200", async () => {
const urns = [
"art:1",
"art:2",
"art:3",
"art:4",
].map(resource => ({ system:"subsonic", resource }));

musicService.login.mockResolvedValue(musicLibrary);

urns.forEach((_) => {
musicLibrary.coverArt.mockResolvedValueOnce(
coverArtResponse({
data: png,
})
);
});

const res = await request(server)
.get(
`/art/${urns.map(it => encodeURIComponent(formatForURL(it))).join(
"&"
)}/size/200?${BONOB_ACCESS_TOKEN_HEADER}=${apiToken}`
)
.set(BONOB_ACCESS_TOKEN_HEADER, apiToken);

expect(res.status).toEqual(200);
expect(res.header["content-type"]).toEqual("image/png");

expect(musicService.login).toHaveBeenCalledWith(serviceToken);
urns.forEach((it) => {
expect(musicLibrary.coverArt).toHaveBeenCalledWith(it, 200);
});

const image = await Image.load(res.body);
expect(image.width).toEqual(200);
expect(image.height).toEqual(200);
});
});

describe("fetching a collage of 4, however only 1 is available", () => {
it("should return the single image", async () => {
const urns = ["art:1", "art:2", "art:3", "art:4"].map(resource => ({ system:"subsonic", resource }));

musicService.login.mockResolvedValue(musicLibrary);

musicLibrary.coverArt.mockResolvedValueOnce(undefined);
musicLibrary.coverArt.mockResolvedValueOnce(undefined);
musicLibrary.coverArt.mockResolvedValueOnce(undefined);
musicLibrary.coverArt.mockResolvedValueOnce(
coverArtResponse({
data: png,
contentType: "image/some-mime-type",
})
);

const res = await request(server)
.get(
`/art/${urns.map(it => encodeURIComponent(formatForURL(it))).join(
"&"
)}/size/200?${BONOB_ACCESS_TOKEN_HEADER}=${apiToken}`
)
.set(BONOB_ACCESS_TOKEN_HEADER, apiToken);

expect(res.status).toEqual(200);
expect(res.header["content-type"]).toEqual(
"image/some-mime-type"
);
});
});

describe("fetching a collage of 4 and all are missing", () => {
it("should return a 404", async () => {
const urns = ["art:1", "art:2", "art:3", "art:4"].map(resource => ({ system:"subsonic", resource }));

musicService.login.mockResolvedValue(musicLibrary);

urns.forEach((_) => {
musicLibrary.coverArt.mockResolvedValueOnce(undefined);
});

const res = await request(server)
.get(
`/art/${urns.map(it => encodeURIComponent(formatForURL(it))).join(
"&"
)}/size/200?${BONOB_ACCESS_TOKEN_HEADER}=${apiToken}`
)
.set(BONOB_ACCESS_TOKEN_HEADER, apiToken);

expect(res.status).toEqual(404);
});
});

describe("fetching a collage of 9 when all are available", () => {
it("should return the image and a 200", async () => {
const urns = [
"artist:1",
"artist:2",
"coverArt:3",
"artist:4",
"artist:5",
"artist:6",
"artist:7",
"artist:8",
"artist:9",
].map(resource => ({ system:"subsonic", resource }));

musicService.login.mockResolvedValue(musicLibrary);

urns.forEach((_) => {
musicLibrary.coverArt.mockResolvedValueOnce(
coverArtResponse({
data: png,
})
);
});

const res = await request(server)
.get(
`/art/${urns.map(it => encodeURIComponent(formatForURL(it))).join(
"&"
)}/size/180?${BONOB_ACCESS_TOKEN_HEADER}=${apiToken}`
)
.set(BONOB_ACCESS_TOKEN_HEADER, apiToken);

expect(res.status).toEqual(200);
expect(res.header["content-type"]).toEqual("image/png");

expect(musicService.login).toHaveBeenCalledWith(serviceToken);
urns.forEach((it) => {
expect(musicLibrary.coverArt).toHaveBeenCalledWith(it, 180);
});

const image = await Image.load(res.body);
expect(image.width).toEqual(180);
expect(image.height).toEqual(180);
});
});

describe("fetching a collage of 9 when only 2 are available", () => {
it("should still return an image and a 200", async () => {
const urns = [
"artist:1",
"artist:2",
"artist:3",
"artist:4",
"artist:5",
"artist:6",
"artist:7",
"artist:8",
"artist:9",
].map(resource => ({ system:"subsonic", resource }));

musicService.login.mockResolvedValue(musicLibrary);

musicLibrary.coverArt.mockResolvedValueOnce(
coverArtResponse({
data: png,
})
);
musicLibrary.coverArt.mockResolvedValueOnce(
coverArtResponse({
data: png,
})
);
musicLibrary.coverArt.mockResolvedValueOnce(undefined);
musicLibrary.coverArt.mockResolvedValueOnce(undefined);
musicLibrary.coverArt.mockResolvedValueOnce(undefined);
musicLibrary.coverArt.mockResolvedValueOnce(undefined);
musicLibrary.coverArt.mockResolvedValueOnce(undefined);
musicLibrary.coverArt.mockResolvedValueOnce(undefined);
musicLibrary.coverArt.mockResolvedValueOnce(undefined);

const res = await request(server)
.get(
`/art/${urns.map(it => encodeURIComponent(formatForURL(it))).join(
"&"
)}/size/180?${BONOB_ACCESS_TOKEN_HEADER}=${apiToken}`
)
.set(BONOB_ACCESS_TOKEN_HEADER, apiToken);

expect(res.status).toEqual(200);
expect(res.header["content-type"]).toEqual("image/png");

expect(musicService.login).toHaveBeenCalledWith(serviceToken);
urns.forEach((urn) => {
expect(musicLibrary.coverArt).toHaveBeenCalledWith(urn, 180);
});

const image = await Image.load(res.body);
expect(image.width).toEqual(180);
expect(image.height).toEqual(180);
});
});

describe("fetching a collage of 11", () => {
it("should still return an image and a 200, though will only display 9", async () => {
const urns = [
"artist:1",
"artist:2",
"artist:3",
"artist:4",
"artist:5",
"artist:6",
"artist:7",
"artist:8",
"artist:9",
"artist:10",
"artist:11",
].map(resource => ({ system:"subsonic", resource }));

musicService.login.mockResolvedValue(musicLibrary);

urns.forEach((_) => {
musicLibrary.coverArt.mockResolvedValueOnce(
coverArtResponse({
data: png,
})
);
});

const res = await request(server)
.get(
`/art/${urns.map(it => encodeURIComponent(formatForURL(it))).join(
"&"
)}/size/180?${BONOB_ACCESS_TOKEN_HEADER}=${apiToken}`
)
.set(BONOB_ACCESS_TOKEN_HEADER, apiToken);

expect(res.status).toEqual(200);
expect(res.header["content-type"]).toEqual("image/png");

expect(musicService.login).toHaveBeenCalledWith(serviceToken);
urns.forEach((it) => {
expect(musicLibrary.coverArt).toHaveBeenCalledWith(it, 180);
});

const image = await Image.load(res.body);
expect(image.width).toEqual(180);
expect(image.height).toEqual(180);
});
});

describe("when the image is not available", () => {
it("should return a 404", async () => {
const coverArtURN = { system:"subsonic", resource:"art:404"};

musicService.login.mockResolvedValue(musicLibrary);
musicLibrary.coverArt.mockResolvedValue(undefined);

const res = await request(server)
.get(
`/art/${encodeURIComponent(formatForURL(coverArtURN))}/size/180?${BONOB_ACCESS_TOKEN_HEADER}=${apiToken}`
)
.set(BONOB_ACCESS_TOKEN_HEADER, apiToken);

expect(res.status).toEqual(404);
});
});
});

describe("when there is an error", () => {
it("should return a 500", async () => {
musicService.login.mockResolvedValue(musicLibrary);
Expand Down

0 comments on commit b88fb9f

Please sign in to comment.