Skip to content

Commit

Permalink
migrate to r2
Browse files Browse the repository at this point in the history
  • Loading branch information
VovaStelmashchuk committed Sep 10, 2024
1 parent d5a5d16 commit ecbbaa3
Show file tree
Hide file tree
Showing 18 changed files with 1,695 additions and 93 deletions.
1,520 changes: 1,516 additions & 4 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"license": "ISC",
"description": "",
"dependencies": {
"@aws-sdk/client-s3": "^3.645.0",
"@hapi/cookie": "^12.0.1",
"@hapi/hapi": "^21.3.10",
"@hapi/inert": "^7.1.0",
Expand Down
41 changes: 24 additions & 17 deletions src/core/episodeRepo.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ export function getPublicPosts(showSlug) {
).toArray();
}

export function getPodcastForRss() {
export function getPodcastForRss(showSlug) {
return Database.collection('posts').find(
{
'showSlug': showSlug,
'visibility': 'public',
'type': 'public'
},
Expand All @@ -42,12 +43,15 @@ export function getAllPosts(showSlug) {
}

export function updatePodcastNameBySlug(showSlug, episodeSlug, podcastName) {
return Database.collection('posts').updateOne({
showSlug: showSlug,
slug: episodeSlug
}, {
$set: { title: podcastName }
});
return Database.collection('posts').updateOne(
{
showSlug: showSlug,
slug: episodeSlug
},
{
$set: { title: podcastName }
}
);
}

export function updateTimeCodeBySlug(showSlug, episodeSlug, index, time, description, isPublicValue) {
Expand All @@ -68,9 +72,12 @@ export function updateTimeCodeBySlug(showSlug, episodeSlug, index, time, descrip
);
}

export function updateLinkBySlug(slug, index, link, title) {
export function updateLinkBySlug(showSlug, episodeSlug, index, link, title) {
return Database.collection('posts').updateOne(
{ slug: slug },
{
showSlug: showSlug,
slug: episodeSlug
},
{
$set: {
[`links.${index}.link`]: link,
Expand All @@ -84,19 +91,19 @@ export function getPostBySlug(showSlug, episodeSlug) {
return Database.collection('posts').findOne({ slug: episodeSlug, showSlug: showSlug });
}

export function updateMontageStatusBySlug(slug, status) {
return Database.collection('posts').updateOne({ slug: slug }, { $set: { montage_status: status } });
export function updateMontageStatusBySlug(showSlug, episodeSlug, status) {
return Database.collection('posts').updateOne({ slug: episodeSlug, showSlug: showSlug }, { $set: { montage_status: status } });
}

export function updateMontageStatusToSuccessBySlug(slug, publicAudioFile) {
return Database.collection('posts').updateOne({ slug: slug }, { $set: { montage_status: 'success', publicAudioFile: publicAudioFile } });
export function updatePublicAudio(showSlug, episodeSlug, publicAudioFile) {
return Database.collection('posts').updateOne({ showSlug: showSlug, slug: episodeSlug }, { $set: { publicAudioFile: publicAudioFile } });
}

export function publishPodcast(slug) {
return Database.collection('posts').updateOne({ slug: slug }, { $set: { visibility: 'public' } });
export function publishPodcast(showSlug, episodeSlug) {
return Database.collection('posts').updateOne({ showSlug: showSlug, slug: episodeSlug }, { $set: { visibility: 'public' } });
}

export function unpublishPodcast(slug) {
return Database.collection('posts').updateOne({ slug: slug }, { $set: { visibility: 'private' } });
export function unpublishPodcast(showSlug, episodeSlug) {
return Database.collection('posts').updateOne({ showSlug: showSlug, slug: episodeSlug }, { $set: { visibility: 'private' } });
}

7 changes: 4 additions & 3 deletions src/core/generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Podcast } from 'podcast';

import { getPodcastForRss } from './episodeRepo.js';
import { buildObjectURL, getFileSizeInByte, uploadFile } from '../minio/utils.js';
import { getShowInfo } from '../core/podcastRepo.js';
import { getShowBySlug } from '../core/podcastRepo.js';

import dotenv from 'dotenv';

Expand All @@ -11,10 +11,11 @@ dotenv.config();
const host = process.env.BASE_URL;

export async function updateRss(showSlug) {
const podcasts = await getPodcastForRss();
const podcasts = await getPodcastForRss(showSlug);
const logoUrl = buildObjectURL(showSlug + '/logo.jpg')

const showInfo = await getShowInfo(showSlug);
const showInfo = await getShowBySlug(showSlug);

const description = showInfo.about;

const author = showInfo.authors;
Expand Down
3 changes: 3 additions & 0 deletions src/core/podcastRepo.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ export async function getShowInfo(podcastDomain) {
return Database.collection('shows').findOne({ domains: podcastDomain });
}

export async function getShowBySlug(showSlug) {
return Database.collection('shows').findOne({ slug: showSlug });
}
4 changes: 4 additions & 0 deletions src/minio/ffmpegApply.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ import Fs from 'fs'
*/
export async function applyFFmpegToFileInMinio(inputKey, outputKey, ffmpegCommand) {
console.log('Applying ffmpeg to file in minio, start download');
console.log('inputKey', inputKey);
console.log('outputKey', outputKey);
console.log('ffmpegCommand', ffmpegCommand);

const folder = `.tmp/test-key/`;
Fs.rmSync(folder, { recursive: true, force: true });

Expand Down
122 changes: 90 additions & 32 deletions src/minio/utils.js
Original file line number Diff line number Diff line change
@@ -1,51 +1,109 @@
import * as Minio from 'minio'
import { S3Client, GetObjectCommand, PutObjectCommand, HeadObjectCommand } from "@aws-sdk/client-s3";

import dotenv from 'dotenv';
import Fs from 'fs'

dotenv.config();

const baseurl = process.env.BASE_URL;
const startUrl = process.env.S3_START_URL;
const s3Endpoint = process.env.S3_ENDPOINT;
const bucketName = process.env.S3_BUCKET_NAME;

const minioEndpoint = process.env.MINIO_END_POINT
const minioPort = process.env.MINIO_PORT
const minioAccessKey = process.env.MINIO_ACCESS_KEY
const minioSecretKey = process.env.MINIO_SECRET_KEY
const bucketName = 'story-podcast'
const client = new S3Client({
endpoint: s3Endpoint,
credentials: {
accessKeyId: process.env.S3_ACCESS_KEY,
secretAccessKey: process.env.S3_SECRET_KEY,
},
region: process.env.S3_REGION,
s3ForcePathStyle: true,
});

const minioClient = new Minio.Client({
endPoint: minioEndpoint,
port: Number(minioPort),
useSSL: false,
accessKey: minioAccessKey,
secretKey: minioSecretKey,
})

export function buildObjectURL(minioKey) {
return `${baseurl}/files/${minioKey}`;
export function buildObjectURL(path) {
return `${startUrl}/${path}`;
}

export async function getFileSizeInByte(key) {
const stat = await minioClient.statObject(bucketName, key)
return stat.size
try {
const command = new HeadObjectCommand({
Bucket: bucketName,
Key: key,
});

const response = await client.send(command);

return response.ContentLength;
} catch (error) {
console.error("Error retrieving file size: ", error);
throw error;
}
}

export async function uploadFile(key, body) {
await minioClient.putObject(bucketName, key, body, undefined, {
'Content-Type': 'text/xml',
})
try {
const params = {
Bucket: bucketName,
Key: key,
Body: body,
};

await client.send(new PutObjectCommand(params));

console.log(`File uploaded successfully, key = ${key}`);
} catch (error) {
console.error('Error uploading file:', error);
}
}

export async function uploadFileFromPath(key, path) {
await minioClient.fPutObject(bucketName, key, path, undefined, {
'Content-Type': 'text/xml',
})
export async function uploadFileFromPath(key, filePath) {
try {
const fileContent = Fs.readFileSync(filePath);

const params = {
Bucket: bucketName,
Key: key,
Body: fileContent,
};

await client.send(new PutObjectCommand(params));

console.log(`File uploaded successfully, key = ${key}`);
} catch (error) {
console.error('Error uploading file:', error);
}
}

export async function downloadFile(key, localPath) {
await minioClient.fGetObject(bucketName, key, localPath, function(err) {
if (err) {
return console.log(err)
}
console.log(`success download file ${key} to ${localPath}`)
})
console.log(`Downloading file ${key} to ${localPath}`);

try {
const command = new GetObjectCommand({
Bucket: bucketName,
Key: key,
});

const data = await client.send(command);

Fs.mkdirSync(localPath.split('/').slice(0, -1).join('/'), { recursive: true });
const writableStream = Fs.createWriteStream(localPath);

// Pipe the data from the response to the file
data.Body.pipe(writableStream);

// Return a promise to ensure it completes before the function resolves
return new Promise((resolve, reject) => {
writableStream.on('finish', () => {
console.log(`Successfully downloaded file ${key} to ${localPath}`);
resolve();
});
writableStream.on('error', (err) => {
console.error('Error writing file to disk:', err);
reject(err);
});
});
} catch (err) {
console.error('Error downloading file:', err);
throw err; // Optionally rethrow the error for further handling
}
}

13 changes: 7 additions & 6 deletions src/montage/publicAudioGenerator.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { updateMontageStatusBySlug, updateMontageStatusToSuccessBySlug } from '../core/episodeRepo.js';
import { updateMontageStatusBySlug, updatePublicAudio } from '../core/episodeRepo.js';
import { applyFFmpegToFileInMinio } from '../minio/ffmpegApply.js';

async function createPublicAudioJob(podcast) {
Expand Down Expand Up @@ -38,12 +38,13 @@ async function createPublicAudioJob(podcast) {
}

export async function createPublicAudio(podcast) {
const publicAudioPath = `${podcast.showSlug}/episodes/${podcast.slug}.mp3`;
await updatePublicAudio(podcast.showSlug, podcast.slug, publicAudioPath);
await modifyPodcastStatus(podcast.slug, 'in_progress');

createPublicAudioJob(podcast)
.then(async () => {
const publicAudioPath = `${podcast.showSlug}/episodes/${podcast.slug}`;
await updateMontageStatusToSuccessBySlug(podcast.slug, publicAudioPath);
await modifyPodcastStatus(podcast.slug, 'in_progress');
console.log('Public audio creation successful.');
})
.catch(async (error) => {
Expand All @@ -54,8 +55,8 @@ export async function createPublicAudio(podcast) {
return { status: 'in-progress' };
}

async function modifyPodcastStatus(slug, status) {
updateMontageStatusBySlug(slug, status);
console.log(`Updating podcast status to ${status} for ${slug}`);
async function modifyPodcastStatus(showSlug, episodeSlug, status) {
updateMontageStatusBySlug(showSlug, episodeSlug, status);
console.log(`Updating podcast status to ${status} for ${episodeSlug}, show ${showSlug}`);
}

21 changes: 13 additions & 8 deletions src/routers/admin/detail/edit_meta.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { getPostBySlug, updateTimeCodeBySlug, updateLinkBySlug } from "../../../
async function updateTimeCode(request, h) {
const showSlug = request.params.showSlug;
const episodeSlug = request.params.episodeSlug;

const { hours, minutes, seconds, text, isPublic } = request.payload;
const isPublicValue = isPublic === 'on' ? true : false;

Expand All @@ -19,10 +19,12 @@ async function updateTimeCode(request, h) {
async function updateLink(request, h) {
const { link, text } = request.payload;

const slug = request.params.slug;
const showSlug = request.params.showSlug;
const episodeSlug = request.params.episodeSlug;

const index = request.params.index;

await updateLinkBySlug(slug, index, link, text);
await updateLinkBySlug(showSlug, episodeSlug, index, link, text);
return h.response().code(200).header('HX-Trigger', 'update-preview');
}

Expand All @@ -48,15 +50,18 @@ async function addTimeCode(request, h) {
}

async function addLink(request, h) {
const slug = request.params.slug;
const podcast = await getPostBySlug(slug);
const showSlug = request.params.showSlug;
const episodeSlug = request.params.episodeSlug;

const podcast = await getPostBySlug(showSlug, episodeSlug);

const index = podcast.links.length;

return h.view(
'editable_link',
{
slug: slug,
showSlug: showSlug,
episodeSlug: episodeSlug,
index: index,
},
{
Expand Down Expand Up @@ -86,7 +91,7 @@ export function editPodcastMetaInfo(server) {

server.route({
method: 'PUT',
path: '/admin/podcast/{slug}/links/{index}',
path: '/admin/show/{showSlug}/episode/{episodeSlug}/links/{index}',
handler: updateLink,
options: {
auth: 'adminSession',
Expand All @@ -95,7 +100,7 @@ export function editPodcastMetaInfo(server) {

server.route({
method: 'POST',
path: '/admin/podcast/{slug}/add-link',
path: '/admin/show/{showSlug}/episode/{episodeSlug}/add-link',
handler: addLink,
options: {
auth: 'adminSession',
Expand Down
8 changes: 5 additions & 3 deletions src/routers/admin/detail/getDetails.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ async function getPodcastDetails(request, h) {
const minute = splitTime[1];
const second = splitTime[2];
return {
slug: podcast.slug,
showSlug: podcast.showSlug,
episodeSlug: podcast.slug,
index: index,
description: chapter.description,
hour: hour,
Expand All @@ -33,15 +34,16 @@ async function getPodcastDetails(request, h) {
}),
links: podcast.links.map((link, index) => {
return {
slug: podcast.slug,
showSlug: podcast.showSlug,
episodeSlug: podcast.slug,
index: index,
link: link.link,
text: link.title,
}
}),
isAudioBuildInProgress: podcast.montage_status === 'in_progress',
publish_button_text: podcast.visibility === 'private' ? 'Publish' : 'Unpublish',
url: podcast.visibility === 'private' ? `/admin/podcast/${episodeSlug}/publish` : `/admin/podcast/${episodeSlug}/unpublish`,
url: podcast.visibility === 'private' ? `/admin/show/${podcast.showSlug}/episode/${podcast.slug}/publish` : `/admin/show/${podcast.showSlug}/episode/${podcast.slug}/unpublish`,
},
{ layout: 'admin' }
)
Expand Down
Loading

0 comments on commit ecbbaa3

Please sign in to comment.