Skip to content

Commit

Permalink
add muly podcast feature
Browse files Browse the repository at this point in the history
  • Loading branch information
VovaStelmashchuk committed Sep 13, 2024
1 parent ecbbaa3 commit 133a54d
Show file tree
Hide file tree
Showing 12 changed files with 88 additions and 16 deletions.
2 changes: 2 additions & 0 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { staticFiles } from './routers/staticFiles.js';
import { admin } from './routers/admin/login.js';
import { adminAuth } from './routers/admin/auth.js';
import { editPodcastDetails } from './routers/admin/details.js'
import { rss } from './routers/rss/rss.js';

import { fileURLToPath } from 'url';
import { dirname } from 'path';
Expand Down Expand Up @@ -49,6 +50,7 @@ const init = async () => {
podcastDetails(server);
admin(server);
editPodcastDetails(server);
rss(server);

await server.start();
console.log('Server running on %s', server.info.uri);
Expand Down
10 changes: 5 additions & 5 deletions src/core/generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ import dotenv from 'dotenv';
dotenv.config();

const host = process.env.BASE_URL;
const rssFileName = process.env.PODCAST_RSS_FILE_NAME;

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

const showInfo = await getShowBySlug(showSlug);

const logoUrl = buildObjectURL(showInfo.showLogoUrl);
const description = showInfo.about;

const author = showInfo.authors;
Expand All @@ -25,10 +25,10 @@ export async function updateRss(showSlug) {
const feed = new Podcast({
title: showInfo.showName,
description: description,
feedUrl: buildObjectURL(showSlug + '/rss.xml'),
feedUrl: buildObjectURL(`${showSlug}/${rssFileName}`),
siteUrl: host,
webMaster: host,
generator: 'Android story',
generator: 'YourPod',
imageUrl: logoUrl,
author: author,
copyright: '© 20220-2024' + showInfo.showName,
Expand Down Expand Up @@ -97,7 +97,7 @@ export async function updateRss(showSlug) {

const xml = feed.buildXml();

await uploadFile(showSlug + '/rss.xml', xml);
await uploadFile(`${showSlug}/${rssFileName}`, xml);
}

export function buildPublicChapters(chapters) {
Expand Down
2 changes: 1 addition & 1 deletion src/minio/ffmpegApply.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export async function applyFFmpegToFileInMinio(inputKey, outputKey, ffmpegComman
console.log(`child process exited with code ${code}`);
if (code === 0) {
// Upload file only if the process exits successfully
await uploadFileFromPath(outputKey, output);
await uploadFileFromPath(outputKey, output, 'audio/mpeg');
console.log('Uploaded file to minio');
resolve();
} else {
Expand Down
20 changes: 19 additions & 1 deletion src/minio/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,21 +55,23 @@ export async function uploadFile(key, body) {
}
}

export async function uploadFileFromPath(key, filePath) {
export async function uploadFileFromPath(key, filePath, contentType) {
try {
const fileContent = Fs.readFileSync(filePath);

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

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

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

Expand Down Expand Up @@ -107,3 +109,19 @@ export async function downloadFile(key, localPath) {
}
}

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

const data = await client.send(command);

return data.Body;
} catch (error) {
console.error('Error getting file content:', error);
throw error;
}
}

6 changes: 3 additions & 3 deletions src/montage/publicAudioGenerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,15 @@ 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');
await modifyPodcastStatus(podcast.showSlug, podcast.slug, 'in_progress');

createPublicAudioJob(podcast)
.then(async () => {
await modifyPodcastStatus(podcast.slug, 'in_progress');
await modifyPodcastStatus(podcast.showSlug, podcast.slug, 'success');
console.log('Public audio creation successful.');
})
.catch(async (error) => {
await modifyPodcastStatus(podcast.slug, 'failure');
await modifyPodcastStatus(podcast.showSlug, podcast.slug, 'failure');
console.error('Public audio creation failed:', error);
});

Expand Down
6 changes: 6 additions & 0 deletions src/routers/admin/dashboard.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import { getAllPosts } from "../../core/episodeRepo.js";
import { getAllShows, getShowBySlug } from "../../core/showRepo.js";

import dotenv from 'dotenv';
dotenv.config();

const startS3Url = process.env.S3_START_URL;

async function dashboardView(request, h) {
const shows = await getAllShows();
const showsUiModel = shows.map(show => ({
url: `/admin/show/${show.slug}`,
showName: show.showName,
showLogoUrl: `${startS3Url}${show.showLogoUrl}`,
}));

return h.view(
Expand Down
9 changes: 9 additions & 0 deletions src/routers/admin/preview.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
import { getPostBySlug } from "../../core/episodeRepo.js";
import { buildObjectURL } from "../../minio/utils.js";
import { buildPublicChapters } from "../../core/generator.js";
import { getShowBySlug } from "../../core/podcastRepo.js";
import dotenv from 'dotenv';

dotenv.config();

const startUrl = process.env.S3_START_URL;

async function podcastDetailsHandler(request, h) {
const showSlug = request.params.showSlug;
const episodeSlug = request.params.episodeSlug;

const showInfo = await getShowBySlug(showSlug);

const podcast = await getPostBySlug(showSlug, episodeSlug);
const publicChapters = buildPublicChapters(podcast.charters)

return h.view('podcastDetails',
{
title: podcast.title,
audioUrl: buildObjectURL(podcast.publicAudioFile),
imageUrl: `${startUrl}${showInfo.showLogoUrl}`,
chapters: publicChapters
.map(chapter => {
return {
Expand Down
7 changes: 6 additions & 1 deletion src/routers/details.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ import { getPostBySlug } from "../core/episodeRepo.js";
import { buildObjectURL } from "../minio/utils.js";
import { buildPublicChapters } from "../core/generator.js";
import { getShowInfo } from "../core/podcastRepo.js";
import dotenv from 'dotenv';

dotenv.config();

const startUrl = process.env.S3_START_URL;

async function podcastDetailsHandler(request, h) {
const host = request.headers.host;
Expand All @@ -19,7 +24,7 @@ async function podcastDetailsHandler(request, h) {
header_links: showInfo.links,
title: podcast.title,
audioUrl: buildObjectURL(podcast.publicAudioFile),
imageUrl: `https://your-pod-cdn.vovastelmashchuk.site/${showInfo.slug}/logo.jpg`,
imageUrl: `${startUrl}${showInfo.showLogoUrl}`,
chapters: publicChapters
.map(chapter => {
return {
Expand Down
11 changes: 8 additions & 3 deletions src/routers/home.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { getPublicPosts } from "../core/episodeRepo.js";
import { getShowInfo } from "../core/podcastRepo.js";
import dotenv from 'dotenv';

dotenv.config();

const startUrl = process.env.S3_START_URL;

async function homeHandler(request, h) {
const host = request.headers.host;
Expand All @@ -16,12 +21,12 @@ async function homeHandler(request, h) {
async function podcastListHandler(request, h) {
const host = request.headers.host;
const showInfo = await getShowInfo(host);
const posts = await getPublicPosts(showInfo.slug);
const postsWithChartersDescription = posts.map(post => ({
const podcasts = await getPublicPosts(showInfo.slug);
const postsWithChartersDescription = podcasts.map(post => ({
...post,
chartersDescription: post.charters ? post.charters.map(charter => charter.description).join(' ') : '',
url: post.type === 'public' ? `/podcast/${post.slug}` : 'https://www.patreon.com/androidstory',
imageUrl: 'https://your-pod-cdn.vovastelmashchuk.site/logo.jpg',
imageUrl: `${startUrl}${showInfo.showLogoUrl}`,
}));

return h.view('podcastList', {
Expand Down
27 changes: 27 additions & 0 deletions src/routers/rss/rss.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { getShowInfo } from "../../core/podcastRepo.js";
import { getFileContent } from "../../minio/utils.js";
import dotenv from 'dotenv';

dotenv.config();

const rssFileName = process.env.PODCAST_RSS_FILE_NAME;

async function rssHandler(request, h) {
const host = request.headers.host;
const showInfo = await getShowInfo(host);

const rss = await getFileContent(`${showInfo.slug}/${rssFileName}`);

return h.response(rss).type('application/rss+xml');
}

export function rss(server) {
server.route({
method: 'GET',
path: '/rss.xml',
handler: rssHandler,
options: {
auth: false
}
})
}
2 changes: 1 addition & 1 deletion src/templates/pages/admin/dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{{#each shows}}
<a href="{{url}}" class="no-underline bg-white p-4 rounded shadow-md">
<div class="relative w-full aspect-square">
<img src="https://androidstory.dev/files/logo.jpg" alt="Android story logo"
<img src="{{showLogoUrl}}" alt="Podcast logo"
class="w-full h-full object-cover rounded-t-md">
</div>
<h2 class="text-xl font-bold mt-4 line-clamp-3">{{showName}}</h2>
Expand Down
2 changes: 1 addition & 1 deletion src/templates/pages/podcastList.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{{#each posts}}
<a href="{{url}}" class="no-underline bg-white p-4 rounded shadow-md">
<div class="relative w-full aspect-square">
<img src="{{imageUrl}}" alt="Android story logo"
<img src="{{imageUrl}}" alt="Podcast logo"
class="w-full h-full object-cover rounded-t-md {{#if (eq type 'patreon')}}filter blur-md{{/if}}">
{{#if (eq type 'patreon')}}
<div class="absolute inset-0 flex justify-center items-center">
Expand Down

0 comments on commit 133a54d

Please sign in to comment.