Skip to content

Commit

Permalink
refactor: rewrite code and correct buffers
Browse files Browse the repository at this point in the history
  • Loading branch information
0-vortex committed Mar 31, 2023
1 parent d4f854d commit c12099a
Show file tree
Hide file tree
Showing 12 changed files with 149 additions and 147 deletions.
28 changes: 0 additions & 28 deletions old/fetchers/ProfileCardFetcher.ts

This file was deleted.

56 changes: 0 additions & 56 deletions old/handlers/ProfileCardHandler.ts

This file was deleted.

25 changes: 0 additions & 25 deletions old/utils/types/dtos.types.ts

This file was deleted.

22 changes: 0 additions & 22 deletions src/app.controller.ts

This file was deleted.

8 changes: 4 additions & 4 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import { TerminusModule } from "@nestjs/terminus";
import { LoggerModule } from "nestjs-pino";
import { clc } from "@nestjs/common/utils/cli-colors.util";

import { AppController } from './app.controller';
import { AppService } from './app.service';
import { SocialCardModule } from './social-card/social-card.module';
import ApiConfig from "./config/api.config";

@Module({
Expand Down Expand Up @@ -42,8 +41,9 @@ import ApiConfig from "./config/api.config";
}),
TerminusModule,
HttpModule,
SocialCardModule,
],
controllers: [AppController],
providers: [AppService],
controllers: [],
providers: [],
})
export class AppModule {}
8 changes: 0 additions & 8 deletions src/app.service.ts

This file was deleted.

32 changes: 32 additions & 0 deletions src/social-card/social-card.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import {Controller, Get, Header, Param, Req, Res, StreamableFile} from '@nestjs/common';
import { ApiNotFoundResponse, ApiOkResponse, ApiOperation } from "@nestjs/swagger";
import { createReadStream } from "node:fs";
import { Readable } from 'stream';

import { SocialCardService } from "./social-card.service";

@Controller('users')
export class SocialCardController {
constructor(
private readonly socialCardService: SocialCardService
) {}

@Get("/:username")
@ApiOperation({
operationId: "generateUserSocialCard",
summary: "Gets latest cache aware social card link for :username or generates a new one",
})
@ApiOkResponse({ type: String })
@ApiNotFoundResponse({ description: "User not found" })
async generateUserSocialCard (
@Param("username") username: string,
@Req() request: Request,
@Res() response: Response
): Promise<StreamableFile> {
const image = await this.socialCardService.getUserCard(username);

console.log(image);

return new StreamableFile(image);
}
}
11 changes: 11 additions & 0 deletions src/social-card/social-card.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Module } from '@nestjs/common';
import { HttpModule } from "@nestjs/axios";
import { SocialCardService } from './social-card.service';
import { SocialCardController } from './social-card.controller';

@Module({
imports: [HttpModule],
providers: [SocialCardService],
controllers: [SocialCardController]
})
export class SocialCardModule {}
96 changes: 96 additions & 0 deletions src/social-card/social-card.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { Injectable } from '@nestjs/common';
import { HttpService } from "@nestjs/axios";
import { catchError, firstValueFrom, map, throwError } from "rxjs";
import { readFile } from "node:fs/promises";
import { Resvg } from "@resvg/resvg-js";

import userLangs from "./templates/user-langs";
import userProfileRepos from "./templates/user-profile-repos";
import userProfileCard from "./templates/user-profile-card";

@Injectable()
export class SocialCardService {
constructor(
private readonly httpService: HttpService,
) {}

async getUserData(username: string): Promise<{
langs: string[],
repos: string[],
img: string,
}> {
const request= this.httpService
.get(`https://beta.gs-api.opensauced.pizza/v1/*/contributions?page=1&limit=1&range=30&contributor=${username}`)
.pipe(
map((res) => res.data),
)
.pipe(
catchError((err) => {
console.log(err);
return throwError(err);
}
));

const { data } = await firstValueFrom(request);

const contributor = data[0];

if (!contributor) {
throw new Error(`User '${username}' Not Found`);
}

const langs = contributor.langs ? contributor.langs.split(",") : [];
const repos = contributor.recent_repo_list ? contributor.recent_repo_list.split(",") : [];

const imgReq = this.httpService
.get(`https://www.github.com/${username}.png?size=300`, {
responseType: 'text',
responseEncoding: 'base64'
})
.pipe(
catchError((err) => {
console.log(err);
return throwError(err);
}
));

const { data: img } = await firstValueFrom(imgReq);

return {
langs,
repos,
img,
};
}

async getUserCard(username: string): Promise<Buffer> {
const { html } = await import("satori-html");
const satori = (await import("satori")).default;

const { img, repos, langs } = await this.getUserData(username);

const template = html(userProfileCard(img, username, userLangs(langs), userProfileRepos(repos)));

const robotoArrayBuffer = await readFile("public/Roboto-Regular.ttf");
const svg = await satori(template, {
width: 1200,
height: 627,
fonts: [
{
name: "Roboto",
data: robotoArrayBuffer,
weight: 400,
style: "normal",
},
],
});

const resvg = new Resvg(svg, { background: "rgba(238, 235, 230, .9)" });

const pngData = resvg.render();

const pngBuffer = pngData.asPng();

return pngBuffer;
}
}
2 changes: 1 addition & 1 deletion src/social-card/templates/user-langs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const userLangs = (langs: string[], joinLiteral = "") => langs.map(lang => {
return `
<div style="
width: ${Math.round(100 / langs.length)}%;
height: "10.5px";
height: 10%;
background: ${color};
"/>
`;
Expand Down
4 changes: 3 additions & 1 deletion src/social-card/templates/user-profile-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const userProfileCard = (img: string, name: string, langs: string, repos: string
width: 1136px;
height: 134px;
">
<img src="${img}" width="100px" height="100px" style="
<img src="data:image/png;base64,${img}" width="100px" height="100px" style="
box-sizing: border-box;
width: 132px;
height: 132px;
Expand Down Expand Up @@ -182,3 +182,5 @@ const userProfileCard = (img: string, name: string, langs: string, repos: string
</div>
</div>
</div>`;

export default userProfileCard;
4 changes: 2 additions & 2 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"compilerOptions": {
// "rootDir": "./src",
// "strict": true,
"strict": true,
// "noEmit": true,
// "isolatedModules": true,
// "moduleResolution": "node",
"moduleResolution": "node16",
"esModuleInterop": true,
"resolveJsonModule": true,
"module": "commonjs",
Expand Down

0 comments on commit c12099a

Please sign in to comment.