F7: Podcast Interaction Flow - Feature Analysis

Overview

The Podcast feature provides users with a curated collection of AI-focused podcast episodes, primarily embedded via YouTube. This feature serves as a multimedia hub for users to discover, engage with, and save relevant industry discussions and interviews. Each podcast is presented in a horizontal card format with an embedded video player, title, description, publication date, and engagement metrics. The podcasts are curated by admin approval to ensure quality and relevance. Users can search, filter, and sort podcasts, as well as like episodes for later viewing. The podcast interface is designed to be responsive, accessible, and optimized for both browsing and viewing while providing personalization features for authenticated users.

API Endpoints

1. Fetch Podcasts

GET /api/podcast/
  • search (string, optional): Text search query for podcast title or description.

Response:

{
  "count": 87,
  "next": "https://api.futrconnect.com/api/podcast/",
  "previous": null,
  "results": [
    {
      "id": "uuid-string",
      "title": "The Future of Large Language Models",
      "description": "In this episode, we discuss the latest developments in large language models and their impact on various industries.",
      "media_embed_url": "https://www.youtube.com/watch?v=abc123xyz",
      "thumbnail": "https://i.ytimg.com/vi/abc123xyz/maxresdefault.jpg",
      "is_liked": false,
      "total_views": 2367
    }
    // Additional podcast items...
  ]
}

2. Like Podcast

POST /api/podcast-like/

Request Body:

{
  "podcast": "podcast-uuid"
}

Response (201 Created):

{
  "id": "uuid-string",
  "podcast": "podcast-uuid"
}

3. Get User’s Liked Podcasts

GET /api/podcast-like/

Response:

{
  "count": 15,
  "next": "https://api.futrconnect.com/api/podcast-like/",
  "previous": null,
  "results": [
    {
      "id": "uuid-string",
      "podcast": {
        "id": "uuid-string",
        "title": "The Future of Large Language Models",
        "description": "In this episode, we discuss the latest developments in large language models and their impact on various industries.",
        "media_embed_url": "https://www.youtube.com/watch?v=abc123xyz",
        "thumbnail": "https://i.ytimg.com/vi/abc123xyz/maxresdefault.jpg"
      }
    }
    // Additional liked podcasts...
  ]
}

4. Track Podcast View

POST /api/podcast-view/

Request Body:

{
  "podcast": "podcast-uuid"
}

Response (201 Created):

{
  "id": "uuid-string",
  "podcast": "podcast-uuid"
}

State Management

React query

interface Podcasts {
id: string;
created_on: string;
edited_on: string;
title: string;
description: string;
thumbnail: string;
media_embed_url: string;
total_views: number;
total_likes: number;
user: string;
category: string;
is_liked: boolean;
is_viewed: boolean;
}[]

interface LikedPodcast {
id: string;
thumbnail: string;
title: string;
media_embed_url: string;
total_views: number;
created_on: string;
edited_on: string;
podcast: string;
user: string;
}[]

MobX-State-Tree Models

PodcastStore

Model PodcastStore {

  // Actions
  updatePodcastsLike({podcastId})
  increasePodcastViewCount({podcastId})
}

Database Models

PostgreSQL Models

Podcast

  • id (UUID, primary key)
  • user (ForeignKey to User)
  • category (ForeignKey to PodcastCategory, nullable)
  • title (varchar, required)
  • description (text, nullable)
  • thumbnail (ImageField, nullable)
  • media_embed_url (URLField, nullable)
  • total_views (PositiveIntegerField, default: 0)
  • total_likes (PositiveIntegerField, default: 0)

PodcastLike

  • id (UUID, primary key)
  • podcast (ForeignKey to Podcast)
  • user (ForeignKey to User)

PodcastView

  • id (UUID, primary key)
  • podcast (ForeignKey to Podcast)
  • user (ForeignKey to User)

Backend Logic

Podcast Management

The backend provides a simple system for managing podcasts through the PodcastViewSet.

  1. Podcast Creation: Podcasts are created and managed through the admin panel or direct API interactions. There is no automated fetching from external sources like the YouTube API.

  2. View Count: The PodcastView model is used to track when a user views a podcast. The total_views on the Podcast model is incremented for each view.

  3. Liking: The PodcastLike model and PodcastLikeViewSet handle the logic for users liking and unliking podcasts.

Performance and Optimization

Database Query Optimization

The backend relies on the following to ensure efficient database queries:

  1. Indexing: The Podcast model has database indexes on the category and total_views fields to speed up filtering and sorting.

  2. Pagination: The API uses Django REST Framework’s standard PageNumberPagination to limit the number of results returned per request.

Frontend Optimization

  1. YouTube Embed Optimization:

    • Implement lazy loading of YouTube embeds
    • Use YouTube’s API to create custom player with performance options
    • Only load full player when user initiates playback
    • Example component:

      ```jsx
      const VideoCard = memo(
      forwardRef((props, ref) => {
      const [isLiked, setIsLiked] = useState(props.is_liked);
      const [views, setViews] = useState(props.total_views);
      const { podCastsStore, userStore } = useStores();
      const { errorHandelForPutPatchDelete } = useErrorHandelForPutPatchDelete();
      const { addPodcast, removePodcast } = useUpdateSavePodcast();

        //update podcasts like
        const { mutateAsync: updatePodcastsLike } = useMutation({
            mutationFn: podCastsStore.updatePodcastsLike,
            onSuccess: (data) => {},
            onError: (error: CustomErrorType) => {
                errorHandelForPutPatchDelete(error.code, error.error);
                if (isLiked == true) {
                    removePodcast(props.id);
                    setIsLiked(false);
                } else {
                    addPodcast({
                        id: props.id,
                        media_embed_url: props.media_embed_url,
                        podcast: props.id,
                        thumbnail: props.thumbnail,
                        title: props.title,
                        total_views: props.total_views
                    });
                    setIsLiked(true);
                }
            }
        });
      
        const onLikeChange = (value) => {
            if (userStore.loggedInUserData?.user?.id) {
                setIsLiked(value);
                updatePodcastsLike({ podcastId: props.id });
                if (value == true) {
                    addPodcast({
                        id: props.id,
                        media_embed_url: props.media_embed_url,
                        podcast: props.id,
                        thumbnail: props.thumbnail,
                        title: props.title,
                        total_views: props.total_views
                    });
                } else {
                    removePodcast(props.id);
                }
            } else {
                userStore.updateAuthModalState(true);
            }
        };
      
        return (
            <motion.div
                ref={ref}
                initial={{ opacity: 0, y: 40 }}
                animate={{ opacity: 1, y: 0 }}
                transition={{ duration: 0.3, ease: 'easeOut' }}
                whileHover={{ scale: 1.01, boxShadow: '0 10px 25px rgba(0, 0, 0, 0.1)' }}
                className='w-full   bg-white shadow-md overflow-hidden transition-shadow hover:shadow-lg border lg:border-0'>
                <div className='flex flex-col p-4 gap-4 md:grid md:grid-cols-[60%_36%] md:justify-between '>
                    <div className='w-full h-[15rem] sm:h-[20rem] xl:h-[22rem]'>
                        {props?.media_embed_url && (
                            <PodcastVideoWithView
                                id={props?.id}
                                is_viewed={props?.is_viewed}
                                media_embed_url={props?.media_embed_url}
                                setViews={setViews}
                            />
                        )}
                    </div>
      
                    <div className='flex flex-col justify-between flex-1'>
                        <div>
                            <h2 className='text-lg md:text-xl font-semibold text-gray-800 mb-2'>{props.title}</h2>
                            <p className='text-sm text-gray-600 line-clamp-8'>{props.description}</p>
                        </div>
                        <div className='mt-4 flex justify-center'>
                            {/* <Link href={props.media_embed_url} target='_blank' className='w-full' id={'watch-podcast'}>
                                <Button variant='primary' className='w-full max-w-[400px]'>
                                    Watch Full Video
                                </Button>
                            </Link> */}
                            <Link href={`/podcast-details/${props.id}`} className='w-full' id={'watch-podcast'}>
                                <Button variant='primary' className='w-full max-w-[400px]'>
                                    Watch Full Video
                                </Button>
                            </Link>
                        </div>
                    </div>
                </div>
                <VideoLikeAndStats
                    views={views}
                    timestamp={props.created_on}
                    isLiked={isLiked}
                    onLikeChange={onLikeChange}
                />
            </motion.div>
        );
      

      })

    )

    
    

Technical Considerations

Cross-Device Compatibility

  • Implement responsive design for all device sizes:
  • Desktop: Horizontal cards with larger embedded player
  • Tablet: Adjustable card layout with medium-sized player
  • Mobile: Vertical card layout with optimized player size
  • Ensure proper aspect ratios for video players
  • Optimize video playback controls for touch interfaces
  • Support picture-in-picture and background playback where possible

YouTube Integration

  • Use YouTube API for enhanced player control and analytics
  • Configure player for optimal performance:
  • Disable related videos
  • Enable privacy-enhanced mode
  • Set appropriate cookies and tracking options
  • Fallback strategy for unavailable videos or regional restrictions

Authentication Integration

  • Anonymous users can view and search podcasts
  • Authentication required for liking podcasts
  • Handle authentication states for like button:
  • Unauthenticated: Prompt login when attempting to like
  • Authenticated: Allow immediate interaction
  • Maintain proper auth state during navigation

Potential Bottlenecks

  1. YouTube API Limitations:
  • Challenge: YouTube API has quotas that can be exceeded with high traffic
  • Solution: Cache YouTube data to reduce API calls
  • Solution: Implement backoff strategies for API requests
  • Solution: Batch process YouTube metadata updates
  1. View Tracking Performance:
  • Challenge: High-traffic sites can experience bottlenecks with view tracking
  • Solution: Implement asynchronous tracking using message queue
  • Solution: Batch update view counts periodically
  • Solution: Consider eventual consistency model for view counts
  1. Player Loading Performance:
    - Challenge: Loading multiple video players simultaneously can be resource-intensive
    - Solution: Implement lazy loading with thumbnail previews
    - Solution: Only load full player when user initiates playback
    - Solution: Use YouTube’s lightweight iframe API

Implementation Considerations

Frontend Implementation

  1. Component Architecture:
  • Build reusable components:
    • VideoCard: Main display component for podcast episodes
    • PodcastVideoWithView: Optimized YouTube player component
    • PodcastList: Container component managing podcast loading
    • PodCastSidebar: Right sidebar showing liked podcasts
    • SearchHeader: Component for search and filter UI
  • Implement state management with MobX-State-Tree and useState
  • Ensure proper loading, error, and empty states
  1. User Interface Design:
  • Create distinctive visual treatment for podcasts:
    • Clear hierarchy of information (title, host, description)
    • Visual cues for duration and view count
    • Consistent like button placement and states
  • Implement engagement indicators:
    • Like status
    • View count with appropriate formatting
    • Time since published (e.g., “3 months ago”)
  1. YouTube Player Functionality:
    - Implement custom player controls:
    • Play/pause
    • Volume control
    • Playback speed
    • Full-screen toggle
    • Track user engagement events:
    • Play started
    • Percentage watched
    • Engagement actions
    • Handle player events for view counting algorithm

Backend Implementation

  1. API Design:
  • Implement RESTful endpoints for CRUD operations
  • Add caching headers for performance optimization
  • Include proper error handling and validation
  • Example implementation:

    class PodcastViewSet(viewsets.ModelViewSet):
        queryset = Podcast.objects.filter(is_approved=True)
        serializer_class = PodcastSerializer
        filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
        filterset_fields = ['tags']
        search_fields = ['title', 'description', 'host', 'guests']
        ordering_fields = ['published_date', 'view_count', 'significant_view_count']
        ordering = ['-published_date']
    
        def get_serializer_context(self):
            context = super().get_serializer_context()
            context['request'] = self.request
            return context
    
        @action(detail=True, methods=['post'])
        def like(self, request, pk=None):
            podcast = self.get_object()
            user = request.user
    
            if not user.is_authenticated:
                return Response(
                    {"detail": "Authentication required"},
                    status=status.HTTP_401_UNAUTHORIZED
                )
    
            like, created = UserLike.objects.get_or_create(
                user=user,
                podcast=podcast,
                defaults={'liked_at': timezone.now()}
            )
    
            if not created:
                return Response(
                    {"detail": "Already liked"},
                    status=status.HTTP_200_OK
                )
    
            return Response(
                UserLikeSerializer(like).data,
                status=status.HTTP_201_CREATED
            )
    
        @action(detail=True, methods=['post'])
        def view(self, request, pk=None):
            """Track a podcast view with detailed engagement data"""
            podcast = self.get_object()
    
            # Extract view data from request
            view_data = {
                'view_source': request.data.get('view_source', 'podcast_page'),
                'view_duration_seconds': request.data.get('view_duration_seconds', 0),
                'view_percentage': request.data.get('view_percentage', 0),
                'engagement_events': request.data.get('engagement_events', [])
            }
    
            # Track view using algorithm
            view_counted = track_podcast_view(
                podcast.id,
                request.user if request.user.is_authenticated else None,
                view_data
            )
    
            return Response({'status': 'success', 'view_counted': view_counted})
    
  1. YouTube Integration:
  • Create service for fetching and updating YouTube metadata
  • Handle YouTube API quotas and rate limiting
  • Implement error handling for unavailable videos
  • Example service:

    class YouTubeService:
        """Service for interacting with YouTube API"""
    
        def __init__(self, api_key):
            self.api_key = api_key
            self.youtube = build('youtube', 'v3', developerKey=api_key)
    
        def get_video_details(self, video_id):
            """Get detailed metadata for YouTube video"""
            try:
                response = self.youtube.videos().list(
                    part='snippet,contentDetails,statistics',
                    id=video_id
                ).execute()
    
                if not response['items']:
                    return None
    
                video = response['items'][0]
    
                # Extract duration in ISO 8601 format
                iso_duration = video['contentDetails']['duration']
                duration_seconds = parse_iso_duration(iso_duration)
    
                return {
                    'title': video['snippet']['title'],
                    'description': video['snippet']['description'],
                    'thumbnail_url': video['snippet']['thumbnails']['high']['url'],
                    'published_date': video['snippet']['publishedAt'],
                    'duration_seconds': duration_seconds,
                    'duration_formatted': format_duration(duration_seconds),
                    'view_count': int(video['statistics'].get('viewCount', 0)),
                    'like_count': int(video['statistics'].get('likeCount', 0)),
                    'comment_count': int(video['statistics'].get('commentCount', 0))
                }
    
            except HttpError as e:
                logging.error(f"YouTube API error: {str(e)}")
                return None
            except Exception as e:
                logging.error(f"Error fetching YouTube data: {str(e)}")
                return None
    
  1. Admin Interface:
    - Create dedicated admin panel for podcast approval
    - Include filters for pending/approved podcasts
    - Add bulk actions for approval/rejection
    - Add YouTube preview functionality

Testing Strategy

  1. Component Testing:
  • Unit tests for podcast card and player rendering
  • Test like functionality with mocked API
  • Test player events and engagement tracking
  • Implementation with Playwright
  1. API Testing:
  • Test podcast endpoints with various filters
  • Test like/unlike functionality
  • Validate view count incrementation with different scenarios
  • Validate the significant view calculation algorithm
  • Implementation with pytest and Django Rest Framework test client
  1. Integration Testing:
    - E2E tests for user flows (browse, search, like)
    - Test YouTube player integration with mocked responses
    - Performance tests for podcast loading
    - Implementation with Playwright

Creative Suggestions

Enhanced Content Experience

  1. Podcast Chapters:
  • Support YouTube chapters or custom timestamp markers
  • Display chapter navigation alongside player
  • Show chapter titles and timestamps
  • Allow direct navigation to specific topics

Feature Suggestions

Content Discovery Enhancements

  1. Advanced Search and Filtering:
  • Add transcript search capability
  • Filter by podcast length (short, medium, long)
  • Filter by host or guest
  • Implement exact phrase matching in search
  1. Playlist Creation:
  • Allow users to create personal podcast playlists
  • Support themed collections (e.g., “Learning LLMs”, “AI Ethics”)
  • Enable sharing of playlists with other users
  • Add subscription to playlists for updates
  1. Content Notifications:
  • Alert users when new episodes from favorite hosts are added
  • Send weekly digest of new podcasts matching user interests
  • Notify about trending or highly engaging episodes
  • Allow subscribing to specific topics or tags
  1. Podcast Widgets:
  • Create embeddable widgets for podcast episodes
  • Allow sharing specific timestamps with context
  • Support rich previews when sharing on social media
  • Create custom clips from longer episodes
  1. Social Features:
    - Allow users to share podcasts with comments
    - Implement discussion threads for episodes
    - Show friend activity (what others are watching)
    - Display total like count and engagement statistics

Additional Considerations

Accessibility Enhancements

  • Implement proper ARIA attributes for player controls
  • Ensure keyboard navigability for podcast browsing
  • Add screen reader descriptions for visual elements
  • Support closed captions and transcripts for hearing-impaired users
  • Test with assistive technologies

Mobile Considerations

  • Optimize video player for mobile viewing:
  • Responsive player size
  • Touch-friendly controls
  • Battery efficiency options
  • Background playback support
  • Implement mobile-specific search and filter UI
  • Test on various mobile devices and network conditions

Further Reading & Best Practices

  1. Video Player Implementation:
  1. Podcast User Experience:
  1. View Tracking Implementation:
  1. Mobile Video Optimization:
  1. Engagement Metrics:
    - Video Engagement Metrics That Matter
    - The Science of Social Video