diff --git a/app/listen/[collectionid]/page.tsx b/app/listen/[collectionid]/page.tsx index b234b09..151abb7 100644 --- a/app/listen/[collectionid]/page.tsx +++ b/app/listen/[collectionid]/page.tsx @@ -1,6 +1,37 @@ -import InProgress from "@/components/InProgress"; +import NotFound from "@/components/NotFound"; +import MusicController from "@/server/controllers/music.controller"; +import { MusicStreamingEntry } from "@/server/db/schema"; +import { S3Service } from "@/server/s3"; +import { Suspense } from "react"; -export default async function ListenByCollectionID() { +export default async function ListenByCollectionID({ params }: { params: { collectionid?: string }}) { + const id = params.collectionid ? Number(params.collectionid) : undefined; + if (!id) return - return + const controller = new MusicController(); + const result = await controller.getByID(id); + if (!result) return + + console.log(result); + const entries = await S3Service.getURLs(result.pathToEntry); + + return ( +
+ Loading...

}> +
+

{result.name}

+

{result.shortDescription}

+
+ +

{result.longDescription}

+ +
+ { entries + ? entries.map((entry: string, idx: number) =>

{entry}

) + :

No entries found

+ } +
+
+
+ ) } diff --git a/components/NotFound.tsx b/components/NotFound.tsx new file mode 100644 index 0000000..9b5b4b6 --- /dev/null +++ b/components/NotFound.tsx @@ -0,0 +1,8 @@ +export default function NotFound() { + return ( +
+

404

+

Page not found

+
+ ) +} diff --git a/package.json b/package.json index 0e8b5f8..09a638d 100644 --- a/package.json +++ b/package.json @@ -12,11 +12,12 @@ }, "dependencies": { "@aws-sdk/client-s3": "^3.367.0", + "@smithy/node-http-handler": "^2.1.8", "@t3-oss/env-nextjs": "^0.7.0", "@vercel/style-guide": "^5.0.1", "autoprefixer": "10.4.14", "ioredis": "^5.3.2", - "next": "^13.4.12", + "next": "^14.0.1", "pg": "^8.11.3", "react": "18.2.0", "react-dom": "18.2.0", diff --git a/postcss.config.js b/postcss.config.cjs similarity index 100% rename from postcss.config.js rename to postcss.config.cjs diff --git a/server/controllers/base.controller.ts b/server/controllers/base.controller.ts index 8942789..e8ece0e 100644 --- a/server/controllers/base.controller.ts +++ b/server/controllers/base.controller.ts @@ -1,5 +1,5 @@ import { S3Client } from '@aws-sdk/client-s3'; -import Redis from 'ioredis'; +// import Redis from 'ioredis'; import pg from 'pg'; import { createDBClient } from '../db'; import { Maybe, must } from '@/util/helpers'; @@ -16,40 +16,47 @@ type ControllerOptions = { export default abstract class BaseController { #db: pg.Client - #bucket: S3Client - #cache: Redis + // #bucket: S3Client + // #cache: Redis tableName: string parser?: FullParserType constructor(options: ControllerOptions) { this.#db = must(createDBClient); - this.#bucket = must(createS3Client); - this.#cache = must(createRedisClient); + // this.#bucket = must(createS3Client); + // this.#cache = must(createRedisClient); this.tableName = options.tableName; this.parser = options.parser; } async getAll(projection?: string): Promise> { + 'use server'; try { // we'll enable cache here later + await this.#db.connect(); const result = await this.#db.query("SELECT $1 FROM $2", [projection ?? "*", this.tableName]); return result.rows; } catch (error) { console.log({ error }); return null; + } finally { + await this.#db.end(); } } async getByID(id: number, projection?: string): Promise> { try { - const result = await this.#db.query("SELECT $1 FROM $2 WHERE id = $3", [projection ?? "*", this.tableName, id]); + await this.#db.connect(); + const result = await this.#db.query(`SELECT ${projection ?? "*"} FROM ${this.tableName} WHERE id = ${id}`); return result.rows[0]; } catch (error) { console.log({ error }); return null; + } finally { + await this.#db.end(); } } } diff --git a/server/db/schema.ts b/server/db/schema.ts index a434c35..ff41a26 100644 --- a/server/db/schema.ts +++ b/server/db/schema.ts @@ -8,8 +8,8 @@ export const ZMusicStreamingEntry = z.object({ name: z.string().max(100), shortDescription: z.string().max(100), longDescription: z.string().max(1000), + pathToEntry: z.string(), tags: z.array(z.string().max(100)).optional(), - pathToEntry: z.string().optional(), }); export type MusicStreamingEntry = z.infer; diff --git a/server/s3/createClient.ts b/server/s3/createClient.ts index 5692421..f7e82fd 100644 --- a/server/s3/createClient.ts +++ b/server/s3/createClient.ts @@ -1,5 +1,7 @@ import { env } from "@/env.mjs"; import { S3Client, S3ClientConfig } from "@aws-sdk/client-s3"; +import { NodeHttpHandler } from "@smithy/node-http-handler"; +import https from "https"; export default function createS3Client() { if (typeof process.env.S3_ACCESS_KEY !== "string") { @@ -11,7 +13,17 @@ export default function createS3Client() { } const config: S3ClientConfig = { - endpoint: env.S3_ENDPOINT + endpoint: env.S3_ENDPOINT, + region: "us-east-1", + + requestHandler: new NodeHttpHandler({ + httpsAgent: new https.Agent({ + rejectUnauthorized: false, + ciphers: "ALL", + }), + }), + + forcePathStyle: true, } if (env.S3_SECRET) { diff --git a/server/s3/service.ts b/server/s3/service.ts index b790671..70109e4 100644 --- a/server/s3/service.ts +++ b/server/s3/service.ts @@ -2,8 +2,6 @@ import { ListObjectsV2Command, PutObjectCommand, PutObjectCommandOutput, S3Clien import { env } from "@/env.mjs"; import createS3Client from "./createClient"; import { Maybe, must } from "@/util/helpers"; -import { readFile } from "fs/promises"; -import { readFileSync, readdir } from "fs"; export default class S3Service { static async getFiles(key: string): Promise> { @@ -34,71 +32,4 @@ export default class S3Service { return null; } } - - static async upload(filePath: string, key: string) { - if (env.NODE_ENV != "development") { - throw new Error("Cannot upload files in production"); - } - - try { - const client = must(createS3Client); - const Body = await readFile(filePath); - - const cmd = new PutObjectCommand({ - Bucket: env.S3_BUCKET, - Key: key, - Body, - }); - - const result = await client.send(cmd); - return result.$metadata.httpStatusCode == 200; - } catch (error) { - console.log({ error }); - return null; - } - } - - static async uploadAllInDirectory(dirPath: string, prefix: string): Promise { - if (env.NODE_ENV != "development") { - throw new Error("Cannot upload files in production"); - } - - try { - const client = must(createS3Client); - const promises = new Array>(); - const results = new Array(); - - readdir(dirPath, (err, files) => { - if (err) { - console.log({ err }); - return null; - } - - files.forEach(file => { - const Key = `${prefix}/${file}` - const Body = readFileSync(Key); - - const cmd = new PutObjectCommand({ - Bucket: env.S3_BUCKET, - Key, - Body, - }) - - promises.push(client.send(cmd)); - }) - }) - - promises.forEach(p => { - setTimeout(async() => { - const output = await Promise.resolve(p); - results.push(output.$metadata.httpStatusCode == 200); - }, 1000) - }) - - return results.every(r => true); - } catch (error) { - console.log({ error }); - return false; - } - } } diff --git a/server/sql/create_tables.sql b/server/sql/create_tables.sql new file mode 100644 index 0000000..07cf172 --- /dev/null +++ b/server/sql/create_tables.sql @@ -0,0 +1,20 @@ +CREATE TABLE IF NOT EXISTS music ( + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name varchar(100), + shortDescription varchar(100), + longDescription varchar(1000), + pathToEntry varchar +); + +CREATE TABLE IF NOT EXISTS tags ( + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name varchar(100) +); + +CREATE TABLE IF NOT EXISTS music_tags ( + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + music_id INTEGER, + tag_id INTEGER, + FOREIGN KEY(music_id) REFERENCES music(id), + FOREIGN KEY(tag_id) REFERENCES tags(id) +); diff --git a/server/sql/seed.sql b/server/sql/seed.sql new file mode 100644 index 0000000..a8e9ddc --- /dev/null +++ b/server/sql/seed.sql @@ -0,0 +1,26 @@ +INSERT INTO music (name, shortDescription, longDescription, pathToEntry) VALUES ( + 'Jisei', + 'My first major undertaking as a singer-songwriter', + 'Released in October 2020', + 'Jisei' +); + +INSERT INTO tags (name) VALUES +( + 'indie-rock' +), +( + 'alternative' +), +( + 'guitar' +), +( + 'cello' +); + +INSERT INTO music_tags (music_id, tag_id) VALUES +(1, 1), +(1, 2), +(1, 3), +(1, 4); diff --git a/tailwind.config.js b/tailwind.config.js index 58b5f09..300dd22 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,5 +1,5 @@ /** @type {import('tailwindcss').Config} */ -module.exports = { +export default { content: [ './pages/**/*.{js,ts,jsx,tsx,mdx}', './components/**/*.{js,ts,jsx,tsx,mdx}',