DEV Community

Cover image for An Audiobook Called BookRadio
Tanishka
Tanishka

Posted on

An Audiobook Called BookRadio

"From Music to Audiobooks — The Idea Behind BookRadio"

I have created a perfect way to listen to books — not just modern ones, but timeless classics from the late 18th, 19th, and 20th centuries.

Welcome to BookRadio — a platform with over 10,000 audiobooks, spanning diverse genres, languages, and legendary authors from history.

But how did this idea come to life?

Well, I’m not exactly a bookworm — but I do love a good story. Whether it’s music or spine-chilling fiction, I enjoy listening during my free time.

One day, I thought: what if we could listen to classic books — old fiction, detective tales, and timeless adventures — just like we listen to songs?

And that’s how BookRadio was born.

So… how did I actually build it?

I wanted to create a user-friendly, interactive, and animated website that not only looks good but also helps users find and enjoy stories effortlessly.

So I started exploring — searching for resources that could bring this idea to life.

That’s when I discovered LibriVox, a public domain audiobook platform. It turned out to be the perfect match!

I used their API to extract rich book metadata — including titles, authors, genres, and languages — and seeded it into my own database.

This became the foundation of BookRadio.
I Started seeding the data into my mongoDB through WebScrapping

// Genre keywords mapping
const GENRE_KEYWORDS = {
  'Fiction': ['novel', 'story', 'tale', 'narrative', 'fiction'],
  'Mystery': ['mystery', 'detective', 'crime', 'murder', 'investigation', 'sherlock', 'holmes'],
  'Romance': ['romance', 'love', 'romantic', 'courtship', 'marriage', 'hearts'],
  'Adventure': ['adventure', 'journey', 'quest', 'expedition', 'travel', 'exploration'],
  'Horror': ['horror', 'ghost', 'haunted', 'terror', 'supernatural', 'vampire', 'monster'],
  'Science Fiction': ['science fiction', 'sci-fi', 'future', 'space', 'alien', 'technology', 'robot'],
  'Fantasy': ['fantasy', 'magic', 'wizard', 'dragon', 'fairy', 'enchanted', 'mythical'],
  'Historical': ['historical', 'history', 'war', 'civil war', 'revolution', 'ancient', 'medieval'],
  'Biography': ['biography', 'life of', 'memoirs', 'autobiography', 'life and times'],
  'Philosophy': ['philosophy', 'philosophical', 'ethics', 'moral', 'metaphysics', 'logic'],
  'Poetry': ['poetry', 'poems', 'verse', 'sonnet', 'ballad', 'rhyme'],
  'Drama': ['drama', 'play', 'tragedy', 'comedy', 'theatrical', 'act', 'scene'],
  'Children': ['children', 'kids', 'juvenile', 'young readers', 'fairy tale', 'nursery'],
  'Religion': ['religious', 'bible', 'Christian', 'spiritual', 'prayer', 'sermon', 'theology'],
  'Non-Fiction': ['essays', 'treatise', 'study', 'analysis', 'examination', 'discourse']
};

connect.DB();
//function to detect genres from text
function detectGenresFromText(title,description){
   const detectGenres= new Set();
   const textToAnalyze = `${title} ${description}`.toLowerCase();
   Object.entries(GENRE_KEYWORDS).forEach(([genre, keywords]) => {
    const hasKeyword = keywords.some(keyword => 
      textToAnalyze.includes(keyword.toLowerCase())
    );

    if (hasKeyword) {
      detectedGenres.add(genre);
    }
  });

  return Array.from(detectedGenres);
}
// a small snippet of seeding
Enter fullscreen mode Exit fullscreen mode

After seeding data into mongoDB I wrote backend for it

MVC helped me separate logic and routes for better maintainability.

My backend was structured using the Model-Controller-Router (MVC/MVR) pattern to ensure scalability, modularity, and maintainability.

Model — Defines the Data Structure

I created Mongoose models for Book and User.These define how data is stored, validated, and indexed in MongoDB.

const bookSchema = new mongoose.Schema({
  title: String,
  author: String,
  genre: [String],
  language: String,
  description: String,
  duration: Number,
  created At: { type: Date, default: Date.now }
});
Enter fullscreen mode Exit fullscreen mode

Controller — Business Logic

Each controller contains the logic for handling specific routes.
For example, my bookController.js manages:
*Searching books
*Filtering by genre/language
*Pagination

const searchBooks = async (req, res) => {};
Enter fullscreen mode Exit fullscreen mode

Router — Route Handling

My bookRoutes.js file defines the endpoints and connects them to their corresponding controllers.

const express = require('express');
const router = express.Router();
const { searchBooks } = require('../controllers/bookController');
router.get('/search', searchBooks);
Enter fullscreen mode Exit fullscreen mode

Middleware- The Middleman

Middlewares played a central role in my backend. They handle:
*JWT authentication

console.log("Backend setup complete");

Building the frontend part

With the backend logic in place, I shifted focus to building the frontend — where functionality meets design and user experience.

Designing the frontend wasn't just about putting components together. It required:

🎯 A strong design system
📱 Responsive layouts
✨ Smooth animations
🧠 Component reusability
🌙 Theme integration

“React.js, a widely-used frontend library, was my choice to build a fast, component-driven UI.”
To design an interactive and responsive UI, I used Tailwind CSS and Framer Motion for styling and smooth animations.

Challenges which I faced during making of this projects were:

  • Making it responsive for all size screens.
  • Fetching and Handling Complete Book Metadata.
  • Web Scraping for Enhanced Information.
  • Designing a Genre Detection Algorithm.
  • JWT Authentication and Secure Routing.

Features of BookRadio

  • Listen to public domain audiobooks from LibriVox.
  • Play individual episodes via inline audio players.
  • Full-text search across title, author, genre, description, tags.
  • Authentication & Profile
  • Feedback form
  • User Interface & Experience

How is BookRadio Unique?

  • User-First Audio Experience
  • Personal Collection Feature

🔗 Like the idea? Don't forget to ⭐ the repo!
GitHub: BookRadio Project

Top comments (0)