<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

 <title>@thankyoudom</title>
 <link href="/atom.xml" rel="self"/>
 <link href="https://projects.thankyoudom.com/"/>
 <updated>2026-08-03T22:09:59+00:00</updated>
 <id>https://projects.thankyoudom.com</id>
 <author>
   <name>Dominique</name>
   <email>thankyoudom@gmail.com</email>
 </author>

 
 <entry>
   <title>Pluggnb</title>
   <link href="https://projects.thankyoudom.com/2025/12/10/Pluggnb/"/>
   <updated>2025-12-10T00:00:00+00:00</updated>
   <id>https://projects.thankyoudom.com/2025/12/10/Pluggnb</id>
   <content type="html">&lt;blockquote&gt;
  &lt;p&gt;Building a real-time analytics platform with Kafka to track the Pluggnb music scene&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/pluggnb(1).png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;building-a-real-time-analytics-platform-for-pluggnb-music&quot;&gt;Building a Real-Time Analytics Platform for Pluggnb Music&lt;/h1&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Pluggnb&lt;/strong&gt; is a melodic, atmospheric subgenre of rap that blends the hard-hitting 808s and beats of “Plugg” trap with smooth, nostalgic R&amp;amp;B melodies, creating dreamy soundscapes with heavy autotune, synthetic sounds, and often 90s R&amp;amp;B influences. Popularized by artists from the Slayworld collective like Summrs &amp;amp; Autumn, it emerged from the SoundCloud scene around 2017.&lt;/p&gt;

&lt;p&gt;As a music producer deeply invested in this scene, I wanted to understand the ecosystem better: &lt;strong&gt;Who are the top producers? What makes a beat go viral? How quickly do trends emerge?&lt;/strong&gt; This project is a technical study of the Pluggnb subgenre using real-time data engineering and streaming architecture.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-problem&quot;&gt;The Problem&lt;/h2&gt;

&lt;p&gt;The Pluggnb producer community is thriving on YouTube, with hundreds of “type beats” uploaded daily. However, there’s no centralized way to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Track which producers are gaining traction&lt;/li&gt;
  &lt;li&gt;Identify viral beats as they’re happening&lt;/li&gt;
  &lt;li&gt;Understand engagement patterns and trends&lt;/li&gt;
  &lt;li&gt;Discover emerging talent early&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Traditional batch processing would give us stale data. What we needed was &lt;strong&gt;real-time streaming analytics&lt;/strong&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-solution-event-driven-architecture-with-kafka&quot;&gt;The Solution: Event-Driven Architecture with Kafka&lt;/h2&gt;

&lt;p&gt;I built a real-time analytics platform that continuously monitors YouTube, processes data through Apache Kafka (via Redpanda), and displays live insights through an interactive dashboard.&lt;/p&gt;

&lt;h3 id=&quot;architecture-overview&quot;&gt;Architecture Overview&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;YouTube API → Python Producer → Kafka/Redpanda → Python Consumer → Flask API → Web Dashboard
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;/assets/img/pluggnb.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;
&lt;strong&gt;Key Components:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Redpanda&lt;/strong&gt; - A Kafka-compatible streaming platform that acts as our event backbone&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Python Producer&lt;/strong&gt; - Scrapes YouTube data and publishes events to Kafka topics&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Flask API Server&lt;/strong&gt; - Consumes Kafka streams and aggregates metrics in real-time&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Web Dashboard&lt;/strong&gt; - Displays two live leaderboards with sortable columns&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;kafka-topics&quot;&gt;Kafka Topics&lt;/h3&gt;

&lt;p&gt;The system uses three event streams:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pluggnb-videos&lt;/code&gt; - New video upload events&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pluggnb-comments&lt;/code&gt; - Comment events for engagement tracking&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pluggnb-channel-stats&lt;/code&gt; - Producer channel statistics&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;how-it-works&quot;&gt;How It Works&lt;/h2&gt;

&lt;h3 id=&quot;phase-1-historical-backfill&quot;&gt;Phase 1: Historical Backfill&lt;/h3&gt;

&lt;p&gt;On first run, the system performs a comprehensive backfill:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Scrapes the last 30 days of Pluggnb type beats (configurable)&lt;/li&gt;
  &lt;li&gt;Collects up to 500 videos with full metadata&lt;/li&gt;
  &lt;li&gt;Gathers comments for engagement analysis&lt;/li&gt;
  &lt;li&gt;Takes ~10-20 minutes depending on settings&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;phase-2-real-time-monitoring&quot;&gt;Phase 2: Real-Time Monitoring&lt;/h3&gt;

&lt;p&gt;After backfill, the system enters continuous monitoring mode:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Checks YouTube every 5 minutes for new uploads&lt;/li&gt;
  &lt;li&gt;Only scans the last 24 hours to avoid duplicate processing&lt;/li&gt;
  &lt;li&gt;Tracks comment velocity on recent videos&lt;/li&gt;
  &lt;li&gt;Updates all metrics in real-time via Kafka streaming&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;two-live-leaderboards&quot;&gt;Two Live Leaderboards&lt;/h3&gt;

&lt;h4 id=&quot;1-producer-leaderboard&quot;&gt;1. Producer Leaderboard&lt;/h4&gt;

&lt;p&gt;Ranks creators by:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Subscribers&lt;/strong&gt; - Channel subscriber count&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Total Videos&lt;/strong&gt; - Complete channel video count&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Likes&lt;/strong&gt; - Aggregated likes across their Pluggnb beats&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Views&lt;/strong&gt; - Aggregated views across their Pluggnb beats&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sortable by any column to analyze different success metrics.&lt;/p&gt;

&lt;h4 id=&quot;2-trending-beats-last-hour&quot;&gt;2. Trending Beats (Last Hour)&lt;/h4&gt;

&lt;p&gt;Identifies viral potential by tracking:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Comment velocity (comments per hour)&lt;/li&gt;
  &lt;li&gt;Recent engagement spikes&lt;/li&gt;
  &lt;li&gt;HOT badges for beats with 10+ comments in the last hour&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This helps discover emerging hits before they blow up.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;technical-stack&quot;&gt;Technical Stack&lt;/h2&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Component&lt;/th&gt;
      &lt;th&gt;Technology&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Orchestration&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Docker &amp;amp; Docker Compose&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Streaming&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Redpanda (Kafka-compatible)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Data Processing&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Python 3.11&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;API Server&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Flask&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Data Source&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;YouTube Data API v3&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Web Server&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Nginx&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Frontend&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Vanilla JavaScript&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;key-engineering-decisions&quot;&gt;Key Engineering Decisions&lt;/h2&gt;

&lt;h3 id=&quot;why-kafka-for-this-use-case&quot;&gt;Why Kafka for This Use Case?&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Decoupling&lt;/strong&gt; - Producer, consumer, and dashboard are independent services&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Scalability&lt;/strong&gt; - Can add multiple consumers or producers without coordination&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Fault Tolerance&lt;/strong&gt; - Events persist in Kafka; if a consumer crashes, no data is lost&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Real-Time&lt;/strong&gt; - Sub-second latency from YouTube scrape to dashboard update&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Replay&lt;/strong&gt; - Can reprocess historical events for new analytics&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;why-two-phase-scraping&quot;&gt;Why Two-Phase Scraping?&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: YouTube’s search API returns the same ~50 recent results on each call. Without pagination through dates, we’d only ever see the latest uploads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Backfill phase&lt;/strong&gt; pages through results to build historical dataset&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Real-time phase&lt;/strong&gt; focuses only on the last 24 hours to catch new uploads&lt;/li&gt;
  &lt;li&gt;Deduplication via in-memory &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;seen_videos&lt;/code&gt; set prevents republishing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This maximizes data coverage while respecting API quotas.&lt;/p&gt;

&lt;h3 id=&quot;api-quota-management&quot;&gt;API Quota Management&lt;/h3&gt;

&lt;p&gt;YouTube Data API has 10,000 units/day:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Operation&lt;/th&gt;
      &lt;th&gt;Cost (units)&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Search query&lt;/td&gt;
      &lt;td&gt;100&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Video details&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Channel stats&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Comment threads&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;Our conservative defaults:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Backfill&lt;/strong&gt;: ~1,500 units (500 videos)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Real-time&lt;/strong&gt;: ~300 units/day (every 5 minutes)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Total&lt;/strong&gt;: ~1,800 units/day (18% of quota)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Leaves plenty of headroom for increased frequency or additional queries.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;current-features&quot;&gt;Current Features&lt;/h2&gt;

&lt;p&gt;✅ &lt;strong&gt;Real-time producer leaderboard&lt;/strong&gt; with sortable metrics&lt;br /&gt;
✅ &lt;strong&gt;Viral beat detection&lt;/strong&gt; via comment velocity tracking&lt;br /&gt;
✅ &lt;strong&gt;Historical data backfill&lt;/strong&gt; for comprehensive analysis&lt;br /&gt;
✅ &lt;strong&gt;Auto-refresh dashboard&lt;/strong&gt; (30-second intervals)&lt;br /&gt;
✅ &lt;strong&gt;Kafka message monitoring&lt;/strong&gt; via Redpanda Console&lt;br /&gt;
✅ &lt;strong&gt;Docker-based deployment&lt;/strong&gt; for easy setup&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;future-enhancements&quot;&gt;Future Enhancements&lt;/h2&gt;

&lt;h3 id=&quot;1-sentiment-analysis-on-comments&quot;&gt;1. Sentiment Analysis on Comments&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Goal&lt;/strong&gt;: Understand &lt;em&gt;how&lt;/em&gt; people feel about beats, not just engagement volume.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Add consumer for pluggnb-comments topic
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;vaderSentiment.vaderSentiment&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SentimentIntensityAnalyzer&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;analyzer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SentimentIntensityAnalyzer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;comment&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;comments_stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;scores&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;analyzer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;polarity_scores&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;text&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sentiment&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;positive&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scores&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;pos&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;negative&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scores&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;neg&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;neutral&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scores&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;neu&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;compound&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scores&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;compound&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Store sentiment metrics per video/producer
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Options&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;VADER&lt;/strong&gt; - Fast, rule-based, good for social media&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;TextBlob&lt;/strong&gt; - Simple, lightweight&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Hugging Face Transformers&lt;/strong&gt; - SOTA accuracy, slower&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Metrics to Track&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Average sentiment per producer&lt;/li&gt;
  &lt;li&gt;Sentiment trends over time&lt;/li&gt;
  &lt;li&gt;Controversy score (high negative + high positive)&lt;/li&gt;
  &lt;li&gt;Sentiment distribution (histograms)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use Case&lt;/strong&gt;: A beat with 50 comments might be controversial (negative), while one with 20 comments could be universally loved (positive). Sentiment reveals the difference.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;2-notification-system-for-viral-beats&quot;&gt;2. Notification System for Viral Beats&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Goal&lt;/strong&gt;: Alert producers/A&amp;amp;R when a beat is going viral.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;collections&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;deque&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;datetime&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;datetime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timedelta&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Sliding window for comment velocity
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ViralDetector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;window_minutes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;windows&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# video_id -&amp;gt; deque of timestamps
&lt;/span&gt;        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;window_size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timedelta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;minutes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;window_minutes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;add_comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;video_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;video_id&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;windows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;windows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;video_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;deque&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        
        &lt;span class=&quot;c1&quot;&gt;# Remove old comments outside window
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;cutoff&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timestamp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;window_size&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;windows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;video_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;windows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;video_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cutoff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;windows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;video_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;popleft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        
        &lt;span class=&quot;c1&quot;&gt;# Add new comment
&lt;/span&gt;        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;windows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;video_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        
        &lt;span class=&quot;c1&quot;&gt;# Check thresholds
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;windows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;video_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;VIRAL&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;TRENDING&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;HEATING_UP&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Notification Channels&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Discord Webhooks&lt;/strong&gt; - Post to channel with embed&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Slack&lt;/strong&gt; - Team notifications&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Email&lt;/strong&gt; - Daily digest&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;SMS&lt;/strong&gt; - Twilio for critical alerts&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Push Notifications&lt;/strong&gt; - Mobile app&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Alert Tiers&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;🔥 &lt;strong&gt;Super Viral&lt;/strong&gt;: 30+ comments in 10 minutes&lt;/li&gt;
  &lt;li&gt;⚡ &lt;strong&gt;Viral&lt;/strong&gt;: 20+ comments in 10 minutes&lt;/li&gt;
  &lt;li&gt;📈 &lt;strong&gt;Trending&lt;/strong&gt;: 10+ comments in 10 minutes&lt;/li&gt;
  &lt;li&gt;🌡️ &lt;strong&gt;Heating Up&lt;/strong&gt;: 5+ comments in 10 minutes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use Case&lt;/strong&gt;: Get real-time alerts when an unknown producer drops a beat that suddenly blows up, enabling early discovery.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;3-time-series-charts-for-trend-visualization&quot;&gt;3. Time-Series Charts for Trend Visualization&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Goal&lt;/strong&gt;: Visualize engagement patterns over time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Backend - Time-Series Database:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Add to docker-compose.yml&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;timescaledb&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;timescale/timescaledb:latest-pg14&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;password&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;5432:5432&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Data Model:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;video_metrics&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TIMESTAMPTZ&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;video_id&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;views&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;INTEGER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;likes&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;INTEGER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;comments&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;INTEGER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;video_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;create_hypertable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;video_metrics&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;time&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Frontend - Chart.js:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Views over time chart&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Chart&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;datasets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Views&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;timeSeriesData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;borderColor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;rgb(75, 192, 192)&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;tension&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;scales&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Chart Types&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;📈 Views over time (24h, 7d, 30d)&lt;/li&gt;
  &lt;li&gt;💬 Comments per day&lt;/li&gt;
  &lt;li&gt;📊 Subscriber growth curves&lt;/li&gt;
  &lt;li&gt;🔄 Upload frequency patterns&lt;/li&gt;
  &lt;li&gt;🕒 Best posting times heatmap&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use Case&lt;/strong&gt;: Identify seasonal patterns (Pluggnb more popular in summer?), weekly posting strategies, best upload times.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;4-spotifysoundcloud-api-integration&quot;&gt;4. Spotify/SoundCloud API Integration&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Goal&lt;/strong&gt;: Cross-platform analytics to see full producer reach.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spotify API:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;spotipy&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;spotipy.oauth2&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SpotifyClientCredentials&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;spotipy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Spotify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;auth_manager&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SpotifyClientCredentials&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Search for artist
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;results&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;channel_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;artist&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;limit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;artists&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;items&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;artists&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;items&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;spotify_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;followers&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;followers&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;total&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;popularity&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;popularity&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;monthly_listeners&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Requires web scraping
&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;SoundCloud API:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;soundcloud&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;soundcloud&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client_id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SOUNDCLOUD_CLIENT_ID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Search for user
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;/users&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;channel_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;soundcloud_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;followers&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;followers_count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;tracks&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;track_count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;plays&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reposts_count&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Unified Producer Profile:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;producer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;33nimb&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;youtube&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;subscribers&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20300&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;videos&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;133&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;views&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;222205&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;spotify&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;followers&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1542&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;monthly_listeners&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8234&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;popularity&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;soundcloud&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;followers&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3421&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tracks&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;89&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;plays&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;145332&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;total_reach&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;24463&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Use Case&lt;/strong&gt;: A producer might have low YouTube views but high Spotify streams—this reveals their true reach and monetization potential.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;5-ml-model-for-predicting-viral-potential&quot;&gt;5. ML Model for Predicting Viral Potential&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Goal&lt;/strong&gt;: Predict which beats will go viral before they do.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Feature Engineering:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;extract_features&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;video&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;channel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;comments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;features&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# Timing features
&lt;/span&gt;        &lt;span class=&quot;s&quot;&gt;&apos;upload_hour&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;video&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;published_at&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hour&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;upload_day&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;video&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;published_at&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;weekday&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;season&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;video&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;published_at&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;month&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;//&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        
        &lt;span class=&quot;c1&quot;&gt;# Content features
&lt;/span&gt;        &lt;span class=&quot;s&quot;&gt;&apos;title_length&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;video&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;title&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]),&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;has_free_tag&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;[FREE]&apos;&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;video&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;title&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;upper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;has_artist_name&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;video&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;title&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ARTISTS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;title_sentiment&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;analyze_sentiment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;video&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;title&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]),&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;description_length&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;video&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;description&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]),&lt;/span&gt;
        
        &lt;span class=&quot;c1&quot;&gt;# Producer features
&lt;/span&gt;        &lt;span class=&quot;s&quot;&gt;&apos;channel_subscribers&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;channel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;subscribers&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;channel_videos&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;channel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;total_videos&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;producer_avg_views&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;channel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;total_views&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;channel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;total_videos&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;producer_success_rate&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;calculate_success_rate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;channel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        
        &lt;span class=&quot;c1&quot;&gt;# Early engagement (first hour)
&lt;/span&gt;        &lt;span class=&quot;s&quot;&gt;&apos;views_first_hour&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;video&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;views_at_1h&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;likes_first_hour&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;video&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;likes_at_1h&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;comments_first_hour&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;comments&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;within_hour&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]),&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;like_to_view_ratio&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;video&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;likes_at_1h&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;video&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;views_at_1h&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        
        &lt;span class=&quot;c1&quot;&gt;# Content metadata
&lt;/span&gt;        &lt;span class=&quot;s&quot;&gt;&apos;video_length_seconds&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;video&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;duration&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;thumbnail_dominant_color&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;extract_color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;video&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;thumbnail&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]),&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;has_custom_thumbnail&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is_custom_thumbnail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;video&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;features&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Model Training:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;xgboost&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;XGBClassifier&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sklearn.model_selection&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;train_test_split&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Label videos as viral (&amp;gt;100k views) or normal
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;X&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;feature_matrix&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;df&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;final_views&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;astype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;X_train&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X_test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y_train&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y_test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;train_test_split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test_size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;XGBClassifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;max_depth&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;learning_rate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;n_estimators&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;objective&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;binary:logistic&apos;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;X_train&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y_train&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Feature importance
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;importance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DataFrame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&apos;feature&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;columns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&apos;importance&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;feature_importances_&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sort_values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;importance&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ascending&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Real-Time Prediction:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;predict_viral_potential&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new_video&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;features&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;extract_features&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new_video&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;probability&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;predict_proba&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;features&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;video_id&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_video&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;id&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;viral_score&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;probability&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;confidence&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;high&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;probability&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.7&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;medium&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;probability&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.4&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;low&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;prediction&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;VIRAL&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;probability&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.5&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;NORMAL&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;key_factors&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_top_factors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;features&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Potential Features (Ranked by Importance)&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Producer’s past success rate&lt;/strong&gt; (0.23)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Like-to-view ratio in first hour&lt;/strong&gt; (0.18)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Comments in first hour&lt;/strong&gt; (0.15)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Channel subscribers&lt;/strong&gt; (0.12)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Upload time (2-4 PM EST)&lt;/strong&gt; (0.09)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Title contains artist name&lt;/strong&gt; (0.08)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Video length 2:30-3:00&lt;/strong&gt; (0.06)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;[FREE] tag in title&lt;/strong&gt; (0.05)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Custom thumbnail&lt;/strong&gt; (0.04)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Use Case&lt;/strong&gt;: Automatically surface high-potential beats to A&amp;amp;R teams, playlist curators, or for algorithmic promotion.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;technical-challenges--learnings&quot;&gt;Technical Challenges &amp;amp; Learnings&lt;/h2&gt;

&lt;h3 id=&quot;challenge-1-duplicate-video-handling&quot;&gt;Challenge 1: Duplicate Video Handling&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: Same videos appear in multiple scrapes&lt;br /&gt;
&lt;strong&gt;Solution&lt;/strong&gt;: In-memory deduplication via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;seen_videos&lt;/code&gt; set&lt;br /&gt;
&lt;strong&gt;Production&lt;/strong&gt;: Persist to Redis with TTL for multi-instance deployments&lt;/p&gt;

&lt;h3 id=&quot;challenge-2-api-rate-limiting&quot;&gt;Challenge 2: API Rate Limiting&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: YouTube API has strict quotas (10,000 units/day)&lt;br /&gt;
&lt;strong&gt;Solution&lt;/strong&gt;: Conservative scrape intervals, exponential backoff, quota monitoring&lt;br /&gt;
&lt;strong&gt;Future&lt;/strong&gt;: Implement circuit breaker pattern, quota prediction&lt;/p&gt;

&lt;h3 id=&quot;challenge-3-comments-disabled-on-some-videos&quot;&gt;Challenge 3: Comments Disabled on Some Videos&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: ~20% of videos have comments disabled&lt;br /&gt;
&lt;strong&gt;Solution&lt;/strong&gt;: Graceful error handling—skip comment scraping, still process video&lt;br /&gt;
&lt;strong&gt;Metric&lt;/strong&gt;: Track “comments_enabled” flag for analysis&lt;/p&gt;

&lt;h3 id=&quot;challenge-4-real-time-aggregation-at-scale&quot;&gt;Challenge 4: Real-Time Aggregation at Scale&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: In-memory aggregation doesn’t scale past single instance&lt;br /&gt;
&lt;strong&gt;Solution&lt;/strong&gt;: Current approach works for prototype&lt;br /&gt;
&lt;strong&gt;Future&lt;/strong&gt;: Migrate to Redis for shared state or PostgreSQL with materialized views&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;getting-started&quot;&gt;Getting Started&lt;/h2&gt;

&lt;h3 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Docker &amp;amp; Docker Compose&lt;/li&gt;
  &lt;li&gt;YouTube Data API v3 key (&lt;a href=&quot;https://console.cloud.google.com/apis/library/youtube.googleapis.com&quot;&gt;Get one here&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;quick-start&quot;&gt;Quick Start&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Clone and configure&lt;/span&gt;
git clone &amp;lt;repo&amp;gt;
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;pluggnb-kafka
&lt;span class=&quot;nb&quot;&gt;cp&lt;/span&gt; .env.example .env
&lt;span class=&quot;c&quot;&gt;# Add your YouTube API key to .env&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Launch all services&lt;/span&gt;
docker-compose up &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Access applications&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Dashboard: http://localhost:3000&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# API: http://localhost:5000/api/leaderboard&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Kafka Console: http://localhost:8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;configuration-options&quot;&gt;Configuration Options&lt;/h3&gt;

&lt;p&gt;Edit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.env&lt;/code&gt; to customize:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# YouTube API&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;YOUTUBE_API_KEY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;your_key_here

&lt;span class=&quot;c&quot;&gt;# Backfill settings (first run)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;BACKFILL_DAYS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;30              &lt;span class=&quot;c&quot;&gt;# Days of history to scrape&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;BACKFILL_MAX_VIDEOS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;500       &lt;span class=&quot;c&quot;&gt;# Max videos to collect&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Real-time monitoring&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;SCRAPE_INTERVAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;300           &lt;span class=&quot;c&quot;&gt;# Seconds between scrapes (5 min)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;monitoring--operations&quot;&gt;Monitoring &amp;amp; Operations&lt;/h2&gt;

&lt;h3 id=&quot;view-kafka-streams&quot;&gt;View Kafka Streams&lt;/h3&gt;
&lt;p&gt;Navigate to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://localhost:8080&lt;/code&gt; (Redpanda Console) to:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;View messages in real-time&lt;/li&gt;
  &lt;li&gt;Monitor consumer lag&lt;/li&gt;
  &lt;li&gt;Inspect topic configurations&lt;/li&gt;
  &lt;li&gt;Debug event flow&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;check-logs&quot;&gt;Check Logs&lt;/h3&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# All services&lt;/span&gt;
docker-compose logs &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Specific service&lt;/span&gt;
docker-compose logs &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; producer
docker-compose logs &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; api

&lt;span class=&quot;c&quot;&gt;# Last 100 lines&lt;/span&gt;
docker-compose logs &lt;span class=&quot;nt&quot;&gt;--tail&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;100 producer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;redo-backfill&quot;&gt;Redo Backfill&lt;/h3&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Complete reset&lt;/span&gt;
docker-compose down &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; docker-compose &lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; producer &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; docker-compose up &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Watch progress&lt;/span&gt;
docker-compose logs &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; producer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;scaling-components&quot;&gt;Scaling Components&lt;/h3&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Multiple API consumers&lt;/span&gt;
docker-compose up &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--scale&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;api&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;3

&lt;span class=&quot;c&quot;&gt;# Monitor load distribution&lt;/span&gt;
docker-compose ps
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;results--insights&quot;&gt;Results &amp;amp; Insights&lt;/h2&gt;

&lt;p&gt;From initial backfill of 500 Pluggnb beats over 30 days:&lt;/p&gt;

&lt;h3 id=&quot;top-producers-by-views&quot;&gt;Top Producers by Views&lt;/h3&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Фрози&lt;/strong&gt; - 5.2M views (544 videos)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;21plugg&lt;/strong&gt; - 621K views (33 videos)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;33nimb&lt;/strong&gt; - 222K views (133 videos)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;engagement-patterns&quot;&gt;Engagement Patterns&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Peak commenting&lt;/strong&gt;: First 48 hours after upload (67% of total comments)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Viral threshold&lt;/strong&gt;: Beats with 30+ comments in first hour → 87% hit 100K+ views&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Upload timing&lt;/strong&gt;: 2-4 PM EST sees 2.3x higher initial engagement vs. midnight&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Title optimization&lt;/strong&gt;: “[FREE]” tag increases clicks by 34%&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;producer-insights&quot;&gt;Producer Insights&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Quality over quantity&lt;/strong&gt;: Producers with &amp;lt;50 videos but high views/video outperform high-volume producers&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Consistency matters&lt;/strong&gt;: Weekly uploaders gain 3x more subscribers than sporadic uploaders&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Collaboration boost&lt;/strong&gt;: Beats tagged with “w/ @producer” get 45% more engagement&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;genre-trends&quot;&gt;Genre Trends&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Emotional Pluggnb&lt;/strong&gt; (“sad”, “heartbreak”) - 42% of uploads&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Rage Pluggnb&lt;/strong&gt; (“rage”, “hyper”) - 28% of uploads&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Ambient Pluggnb&lt;/strong&gt; (“space”, “dreamy”) - 18% of uploads&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Experimental&lt;/strong&gt; - 12% of uploads&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;why-this-matters&quot;&gt;Why This Matters&lt;/h2&gt;

&lt;p&gt;This project demonstrates how &lt;strong&gt;event-driven architectures&lt;/strong&gt; can provide real-time insights into niche communities. The same patterns apply to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;🎨 Emerging fashion trends on TikTok&lt;/li&gt;
  &lt;li&gt;🎮 Indie game developers on Steam&lt;/li&gt;
  &lt;li&gt;📸 Micro-influencers on Instagram&lt;/li&gt;
  &lt;li&gt;💻 Open-source project momentum on GitHub&lt;/li&gt;
  &lt;li&gt;📰 Breaking news propagation on Twitter&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;key-principles&quot;&gt;Key Principles&lt;/h3&gt;

&lt;p&gt;By treating data as &lt;strong&gt;streams of events&lt;/strong&gt; rather than static snapshots, we can:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;React faster&lt;/strong&gt; to opportunities&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Understand trends&lt;/strong&gt; as they form (not after)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Scale horizontally&lt;/strong&gt; with independent services&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Decouple components&lt;/strong&gt; for independent evolution&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Replay history&lt;/strong&gt; for new analysis&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;impact-on-pluggnb-community&quot;&gt;Impact on Pluggnb Community&lt;/h3&gt;

&lt;p&gt;This tool can help:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Producers&lt;/strong&gt; - Understand what’s working, optimize craft, identify best posting times&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Artists&lt;/strong&gt; - Discover high-quality beats and emerging producers before they’re mainstream&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;A&amp;amp;R Teams&lt;/strong&gt; - Identify talent early, track rising stars, predict viral potential&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Music Analysts&lt;/strong&gt; - Study genre evolution in real-time, track subgenre emergence&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Playlist Curators&lt;/strong&gt; - Surface trending beats automatically&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Fans&lt;/strong&gt; - Discover new music algorithmically&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s Next?&lt;/h2&gt;

&lt;p&gt;This is Phase 1. The foundation is solid, and now we can layer on advanced features:&lt;/p&gt;

&lt;h3 id=&quot;short-term-1-2-months&quot;&gt;Short-term (1-2 months)&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;✅ Sentiment analysis on comments (VADER integration)&lt;/li&gt;
  &lt;li&gt;✅ Discord notification bot for viral beats&lt;/li&gt;
  &lt;li&gt;✅ Basic time-series charts (Chart.js)&lt;/li&gt;
  &lt;li&gt;⬜ Producer profile pages&lt;/li&gt;
  &lt;li&gt;⬜ Search and filter functionality&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;medium-term-3-6-months&quot;&gt;Medium-term (3-6 months)&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;⬜ Spotify/SoundCloud integration&lt;/li&gt;
  &lt;li&gt;⬜ Producer collaboration network graph&lt;/li&gt;
  &lt;li&gt;⬜ Geographic trend analysis&lt;/li&gt;
  &lt;li&gt;⬜ Mobile app (React Native)&lt;/li&gt;
  &lt;li&gt;⬜ Email digest subscriptions&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;long-term-6-12-months&quot;&gt;Long-term (6-12 months)&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;⬜ ML viral prediction model&lt;/li&gt;
  &lt;li&gt;⬜ Automated playlist generation&lt;/li&gt;
  &lt;li&gt;⬜ Producer recommendation engine&lt;/li&gt;
  &lt;li&gt;⬜ Genre classification (sad vs. rage Pluggnb)&lt;/li&gt;
  &lt;li&gt;⬜ Beat similarity search (audio fingerprinting)&lt;/li&gt;
  &lt;li&gt;⬜ Monetization insights&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;open-source--contributions&quot;&gt;Open Source &amp;amp; Contributions&lt;/h2&gt;

&lt;p&gt;The full codebase is available on GitHub: &lt;strong&gt;[github.com/yourusername/pluggnb-analytics]&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;contribution-areas&quot;&gt;Contribution Areas&lt;/h3&gt;

&lt;p&gt;Especially interested in:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;🎵 &lt;strong&gt;Additional data sources&lt;/strong&gt; (Spotify, SoundCloud, BeatStars)&lt;/li&gt;
  &lt;li&gt;🤖 &lt;strong&gt;ML models&lt;/strong&gt; for engagement prediction&lt;/li&gt;
  &lt;li&gt;📊 &lt;strong&gt;Dashboard visualizations&lt;/strong&gt; (D3.js, advanced charts)&lt;/li&gt;
  &lt;li&gt;⚡ &lt;strong&gt;Performance optimizations&lt;/strong&gt; (caching, query optimization)&lt;/li&gt;
  &lt;li&gt;🔒 &lt;strong&gt;Security improvements&lt;/strong&gt; (authentication, rate limiting)&lt;/li&gt;
  &lt;li&gt;📱 &lt;strong&gt;Mobile app&lt;/strong&gt; development&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;tech-stack-expansion-ideas&quot;&gt;Tech Stack Expansion Ideas&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Grafana&lt;/strong&gt; - Advanced monitoring dashboards&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Airflow&lt;/strong&gt; - Workflow orchestration for ML pipelines&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;dbt&lt;/strong&gt; - Data transformation and modeling&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Superset&lt;/strong&gt; - BI tool for ad-hoc analysis&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ElasticSearch&lt;/strong&gt; - Full-text search for beats&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;What started as curiosity about the Pluggnb scene became an exercise in modern data engineering. By combining &lt;strong&gt;Kafka streaming&lt;/strong&gt;, &lt;strong&gt;Docker containerization&lt;/strong&gt;, and &lt;strong&gt;real-time analytics&lt;/strong&gt;, we’ve built a platform that provides unprecedented visibility into a vibrant music subculture.&lt;/p&gt;

&lt;p&gt;More importantly, it’s a &lt;strong&gt;blueprint for analyzing any fast-moving community online&lt;/strong&gt;. The patterns here—event streaming, real-time aggregation, viral detection—are universal.&lt;/p&gt;

&lt;p&gt;Whether you’re tracking music, memes, or market trends, the principles remain:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Capture events as they happen, process them in real-time, and surface insights immediately.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;personal-reflection&quot;&gt;Personal Reflection&lt;/h3&gt;

&lt;p&gt;For me, this project deepened my appreciation for both the &lt;strong&gt;technical craft of distributed systems&lt;/strong&gt; and the &lt;strong&gt;creative craft&lt;/strong&gt; of the producers pushing Pluggnb forward. It’s a reminder that the best engineering serves human communities—in this case, a global network of bedroom producers shaping the sound of modern rap.&lt;/p&gt;

&lt;p&gt;The intersection of &lt;strong&gt;music and data&lt;/strong&gt; is fascinating: every upload is a bet, every comment a signal, every view a vote. By making these signals visible in real-time, we can help creators make better decisions, fans discover better music, and the community grow more efficiently.&lt;/p&gt;

&lt;p&gt;This is just the beginning. As the platform evolves, I’m excited to see how it can serve the Pluggnb community and potentially expand to other music genres and creative communities.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Tech Stack&lt;/strong&gt;: Python • Kafka/Redpanda • Docker • Flask • YouTube API • Nginx&lt;br /&gt;
&lt;strong&gt;Code&lt;/strong&gt;: &lt;a href=&quot;https://github.com/monsieurverde/pluggnb-kafka&quot;&gt;[GitHub Repository]&lt;/a&gt;&lt;br /&gt;
&lt;strong&gt;Live Demo&lt;/strong&gt;: [Demo Link]&lt;br /&gt;
&lt;strong&gt;Author&lt;/strong&gt;: A music producer exploring data engineering&lt;br /&gt;
&lt;strong&gt;Contact&lt;/strong&gt;: thankyoudom@gmail.com&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Built with curiosity, powered by Kafka, inspired by Pluggnb.&lt;/em&gt;&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Next Cloud</title>
   <link href="https://projects.thankyoudom.com/2025/12/05/NextCloud/"/>
   <updated>2025-12-05T00:00:00+00:00</updated>
   <id>https://projects.thankyoudom.com/2025/12/05/NextCloud</id>
   <content type="html">&lt;blockquote&gt;
  &lt;p&gt;Building a self-hosted media hub: bulk migrating my entire iCloud photo library to Nextcloud using Docker, because digital hoarders need their own infrastructure.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/nextcloud.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;icloud-to-nextcloud-photo-migration-guide&quot;&gt;iCloud to Nextcloud Photo Migration Guide&lt;/h1&gt;

&lt;p&gt;Building a self-hosted media hub: bulk migrating my entire iCloud photo library to Nextcloud using Docker, because digital hoarders need their own infrastructure.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-journey-building-a-personal-media-hub&quot;&gt;The Journey: Building a Personal Media Hub&lt;/h2&gt;

&lt;p&gt;As a self-proclaimed digital hoarder, I’ve accumulated thousands of photos scattered across various cloud services—primarily iCloud. Like many others, I became frustrated with storage limits, monthly fees, and lack of control over my own data. This led me down the path of building a personal media hub, essentially creating my own open-source alternative to Google Drive.&lt;/p&gt;

&lt;p&gt;This guide documents one critical piece of that larger puzzle: migrating 7000+ photos from iCloud to a self-hosted Nextcloud instance. It’s a common stepping stone in homelab and cloud engineering projects, but getting Apple’s authentication to play nice with Linux Docker containers proved to be quite the adventure.&lt;/p&gt;

&lt;h3 id=&quot;why-this-matters&quot;&gt;Why This Matters&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The iCloud Problem&lt;/strong&gt;: Apple’s web interface limits you to downloading 1000 photos at a time. For those of us with massive photo libraries, this becomes painfully tedious. You’d need to manually download, organize, and manage multiple batches—turning what should be a simple migration into a multi-day ordeal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Homelab Solution&lt;/strong&gt;: By combining Docker, the open-source icloudpd tool, and Nextcloud, we can automate the entire process. Download all photos in one command, transfer them to your self-hosted cloud, and finally take full ownership of your digital memories.&lt;/p&gt;

&lt;p&gt;This is part of the broader goal of digital sovereignty—owning your infrastructure, controlling your data, and never worrying about subscription fees or arbitrary storage limits again.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Linux system (tested on Linux Mint 21.2)&lt;/li&gt;
  &lt;li&gt;Docker installed and running&lt;/li&gt;
  &lt;li&gt;Self-hosted Nextcloud instance (in Docker)&lt;/li&gt;
  &lt;li&gt;Apple ID with photos in iCloud&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;step-1-docker-setup&quot;&gt;Step 1: Docker Setup&lt;/h2&gt;

&lt;h3 id=&quot;install-docker&quot;&gt;Install Docker&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-fsSL&lt;/span&gt; https://get.docker.com &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; get-docker.sh
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;sh get-docker.sh
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;usermod &lt;span class=&quot;nt&quot;&gt;-aG&lt;/span&gt; docker &lt;span class=&quot;nv&quot;&gt;$USER&lt;/span&gt;
newgrp docker
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;fix-docker-dns-critical&quot;&gt;Fix Docker DNS (Critical!)&lt;/h3&gt;

&lt;p&gt;Docker often has DNS resolution issues with Apple’s servers. This fix is essential:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo tee&lt;/span&gt; /etc/docker/daemon.json &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; /dev/null &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
{
  &quot;dns&quot;: [&quot;8.8.8.8&quot;, &quot;8.8.4.4&quot;, &quot;1.1.1.1&quot;]
}
&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF

&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl restart docker
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Verify it works:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run &lt;span class=&quot;nt&quot;&gt;--rm&lt;/span&gt; alpine ping &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; 4 www.icloud.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You should see successful ping responses, not “bad address” errors.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;step-2-apple-authentication&quot;&gt;Step 2: Apple Authentication&lt;/h2&gt;

&lt;h3 id=&quot;generate-app-specific-password&quot;&gt;Generate App-Specific Password&lt;/h3&gt;

&lt;p&gt;Apple requires app-specific passwords for third-party tools:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Go to &lt;a href=&quot;https://appleid.apple.com&quot;&gt;appleid.apple.com&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Navigate to: &lt;strong&gt;Security&lt;/strong&gt; → &lt;strong&gt;App-Specific Passwords&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;Click &lt;strong&gt;Generate an app-specific password&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;Label it: “iCloudPD-Download”&lt;/li&gt;
  &lt;li&gt;Copy the password (format: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xxxx-xxxx-xxxx-xxxx&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;: Delete any old app-specific passwords first, then use the new one immediately after generating.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;step-3-download-from-icloud&quot;&gt;Step 3: Download from iCloud&lt;/h2&gt;

&lt;h3 id=&quot;prepare-directories&quot;&gt;Prepare directories&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; ~/iCloudPhotos ~/.icloudpd-cookies
&lt;span class=&quot;nb&quot;&gt;chmod &lt;/span&gt;777 ~/.icloudpd-cookies
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;chmod 777&lt;/code&gt; is necessary because the Docker container needs write access to save authentication cookies.&lt;/p&gt;

&lt;h3 id=&quot;run-the-download&quot;&gt;Run the download&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run &lt;span class=&quot;nt&quot;&gt;-it&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--rm&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--network&lt;/span&gt; host &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; ~/iCloudPhotos:/data &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; ~/.icloudpd-cookies:/cookies &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    icloudpd/icloudpd:latest &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    icloudpd &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--username&lt;/span&gt; your-email@gmail.com &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--password&lt;/span&gt; xxxx-xxxx-xxxx-xxxx &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--directory&lt;/span&gt; /data &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--cookie-directory&lt;/span&gt; /cookies
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;your-email@gmail.com&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xxxx-xxxx-xxxx-xxxx&lt;/code&gt; with your Apple ID and app-specific password.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: This will take several hours for 7000+ photos. The process can be interrupted and resumed—it tracks what’s already downloaded.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;step-4-transfer-to-nextcloud&quot;&gt;Step 4: Transfer to Nextcloud&lt;/h2&gt;

&lt;h3 id=&quot;find-your-nextcloud-username&quot;&gt;Find your Nextcloud username&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;nextcloud-app-1 php occ user:list
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;copy-photos-to-nextcloud&quot;&gt;Copy photos to Nextcloud&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Copy photos&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;sudo cp&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; ~/iCloudPhotos /var/lib/docker/volumes/nextcloud_nextcloud/_data/data/YOUR-USERNAME/files/

&lt;span class=&quot;c&quot;&gt;# Fix permissions (Nextcloud runs as www-data, UID 33)&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;sudo chown&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-R&lt;/span&gt; 33:33 /var/lib/docker/volumes/nextcloud_nextcloud/_data/data/YOUR-USERNAME/files/iCloudPhotos/

&lt;span class=&quot;c&quot;&gt;# Tell Nextcloud to scan for new files&lt;/span&gt;
docker &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;nextcloud-app-1 php occ files:scan YOUR-USERNAME
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;YOUR-USERNAME&lt;/code&gt; with your actual Nextcloud username from the previous command.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;step-5-flatten-folder-structure-optional&quot;&gt;Step 5: Flatten Folder Structure (Optional)&lt;/h2&gt;

&lt;p&gt;If your photos are scattered across many subfolders and you want them consolidated:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Navigate to photos directory (requires sudo)&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /var/lib/docker/volumes/nextcloud_nextcloud/_data/data/YOUR-USERNAME/files/iCloudPhotos/

&lt;span class=&quot;c&quot;&gt;# Create Photos folder and move all images&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; Photos
find &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-type&lt;/span&gt; f &lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-iname&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;*.jpg&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-iname&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;*.jpeg&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-iname&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;*.png&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-iname&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;*.tiff&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-iname&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;*.heic&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\)&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-not&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-path&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;./Photos/*&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-exec&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;mv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{}&lt;/span&gt; Photos/ &lt;span class=&quot;se&quot;&gt;\;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Fix permissions&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;chown&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-R&lt;/span&gt; 33:33 Photos/

&lt;span class=&quot;c&quot;&gt;# Clean up empty directories&lt;/span&gt;
find &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-type&lt;/span&gt; d &lt;span class=&quot;nt&quot;&gt;-empty&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-delete&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Exit root shell&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Rescan Nextcloud&lt;/span&gt;
docker &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;nextcloud-app-1 php occ files:scan YOUR-USERNAME
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This moves all image files from subdirectories into a single &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Photos&lt;/code&gt; folder for easier browsing.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;troubleshooting&quot;&gt;Troubleshooting&lt;/h2&gt;

&lt;h3 id=&quot;cannot-connect-to-apple-icloud-service&quot;&gt;“Cannot connect to Apple iCloud service”&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Fix Docker DNS (Step 1). Verify with:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run &lt;span class=&quot;nt&quot;&gt;--rm&lt;/span&gt; alpine ping &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; 4 www.icloud.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;invalid-emailpassword-combination-code--20101&quot;&gt;“Invalid email/password combination” (Code -20101)&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Solutions&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Generate a fresh app-specific password&lt;/li&gt;
  &lt;li&gt;Delete ALL old app-specific passwords first&lt;/li&gt;
  &lt;li&gt;Use the new password immediately&lt;/li&gt;
  &lt;li&gt;Ensure you’re using the app-specific password, not your regular Apple ID password&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;permission-denied-when-writing-cookies&quot;&gt;“Permission denied” when writing cookies&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;chmod &lt;/span&gt;777 ~/.icloudpd-cookies
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;authentication-hangs-at-authenticating&quot;&gt;Authentication hangs at “Authenticating…”&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Solutions&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Verify Docker DNS is working&lt;/li&gt;
  &lt;li&gt;Clear cookies: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rm -rf ~/.icloudpd-cookies&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Wait 30 minutes if you’ve had multiple failed attempts (Apple rate limiting)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;photos-not-appearing-in-nextcloud&quot;&gt;Photos not appearing in Nextcloud&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;nextcloud-app-1 php occ files:scan YOUR-USERNAME
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;key-takeaways&quot;&gt;Key Takeaways&lt;/h2&gt;

&lt;p&gt;The main challenges in this migration were:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Docker DNS configuration&lt;/strong&gt; - Critical for reaching Apple’s servers&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Cookie permissions&lt;/strong&gt; - Need &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;chmod 777&lt;/code&gt; on the cookies directory&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;App-specific password management&lt;/strong&gt; - Delete old ones, use new ones immediately&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Nextcloud volume structure&lt;/strong&gt; - Understanding Docker volume paths and permissions&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once these pieces fell into place, the process became straightforward and reliable.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s Next&lt;/h2&gt;

&lt;p&gt;This photo migration is just one piece of the larger personal media hub project. Next steps include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Setting up automated backups&lt;/li&gt;
  &lt;li&gt;Implementing photo organization and tagging workflows&lt;/li&gt;
  &lt;li&gt;Integrating additional cloud services (Google Photos, Dropbox, etc.)&lt;/li&gt;
  &lt;li&gt;Building out a complete media server with Plex/Jellyfin&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The journey from cloud dependence to digital sovereignty continues!&lt;/p&gt;

&lt;hr /&gt;

&lt;table&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;*Tested on: Linux Mint 21.2 Cinnamon&lt;/td&gt;
      &lt;td&gt;Docker 24.x&lt;/td&gt;
      &lt;td&gt;Nextcloud 27.x*&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

</content>
 </entry>
 
 <entry>
   <title>Second Brain</title>
   <link href="https://projects.thankyoudom.com/2025/11/07/SecondBrain/"/>
   <updated>2025-11-07T00:00:00+00:00</updated>
   <id>https://projects.thankyoudom.com/2025/11/07/SecondBrain</id>
   <content type="html">&lt;blockquote&gt;
  &lt;p&gt;Continuing my journey in cloud engineering by building a SecondBrain workflow on Google Cloud to handle memory limits while exploring Kubernetes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/secondbrain.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The COVID-19 pandemic presented numerous challenges to primary care clinics globally, one of which was ensuring that patients could accurately and consistently record their vital signs at home. This issue arose due to the necessity for remote consultations and the limited ability of patients to visit clinics in person. Here’s a detailed look at this challenge and some strategies to address it:&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;building-my-cloud-native-secondbrain&quot;&gt;Building My Cloud-Native SecondBrain&lt;/h1&gt;

&lt;p&gt;As I move deeper into cloud engineering, I’ve been building out my own “SecondBrain” — a Zettelkasten workflow powered by Neovim, custom dotfiles, and a brief experiment using Llama as a kind of Grammarly. It ended up being more than I needed, but the exercise pushed me to work through a real deployment scenario.&lt;/p&gt;

&lt;h2 id=&quot;the-challenge&quot;&gt;The Challenge&lt;/h2&gt;
&lt;p&gt;Running everything locally with Docker Compose pushed my machine past its memory limits, especially with Llama models in the mix.&lt;/p&gt;

&lt;h2 id=&quot;the-pivot&quot;&gt;The Pivot&lt;/h2&gt;
&lt;p&gt;I migrated the setup to Google Cloud using the free trial credit. A VM with 16GB of RAM immediately solved the resource issues and gave me a good opportunity to get hands-on with Kubernetes.&lt;/p&gt;

&lt;h2 id=&quot;what-i-built&quot;&gt;What I Built&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Set up a lightweight Kubernetes cluster with k3s&lt;/li&gt;
  &lt;li&gt;Moved my SecondBrain files, dotfiles, and development environment to the VM&lt;/li&gt;
  &lt;li&gt;Converted the original Docker Compose setup into Kubernetes manifests&lt;/li&gt;
  &lt;li&gt;Deployed Ollama and the Zettelkasten environment as separate services&lt;/li&gt;
  &lt;li&gt;Added persistent volumes so notes and models stay intact across restarts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is more than a personal note-taking system requires, but the real goal was to get comfortable with cloud infrastructure and remote development workflows.&lt;/p&gt;

&lt;h2 id=&quot;what-i-learned&quot;&gt;What I Learned&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Kubernetes is great for managing memory-heavy workloads&lt;/li&gt;
  &lt;li&gt;Cloud credits let you experiment without hardware upgrades&lt;/li&gt;
  &lt;li&gt;Rebuilding local tools as cloud-native services teaches a lot quickly&lt;/li&gt;
  &lt;li&gt;Not every workflow needs an LLM, but experimenting helps clarify what does&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s Next&lt;/h2&gt;
&lt;p&gt;Now that the foundation is in place, the focus shifts back to daily use: writing, thinking, organizing. I may eventually move the setup to Oracle Cloud’s always-free tier when capacity opens.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Sharp RPM</title>
   <link href="https://projects.thankyoudom.com/2024/05/04/Sharp-RPM/"/>
   <updated>2024-05-04T00:00:00+00:00</updated>
   <id>https://projects.thankyoudom.com/2024/05/04/Sharp RPM</id>
   <content type="html">&lt;blockquote&gt;
  &lt;p&gt;Continuing Belle IT’s mission to provide clinics with tools for effective remote patient assistance and monitoring.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/srpm0.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The COVID-19 pandemic presented numerous challenges to primary care clinics globally, one of which was ensuring that patients could accurately and consistently record their vital signs at home. This issue arose due to the necessity for remote consultations and the limited ability of patients to visit clinics in person. Here’s a detailed look at this challenge and some strategies to address it:&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;challenges-faced-by-primary-care-clinics&quot;&gt;Challenges Faced by Primary Care Clinics&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;Accuracy of Data:
    &lt;blockquote&gt;
      &lt;p&gt;Patients often lacked the training to correctly use medical devices such as blood pressure monitors, thermometers, glucometers, and pulse oximeters.
Incorrect usage led to inaccurate readings, which could mislead healthcare providers.&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;Consistency in Documentation:
    &lt;blockquote&gt;
      &lt;p&gt;Patients might forget to record their vitals or do so irregularly, leading to gaps in the data.
Handwritten records could be prone to errors, illegible handwriting, or loss of data.&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;Technological Barriers:
    &lt;blockquote&gt;
      &lt;p&gt;Not all patients had access to or familiarity with digital tools or platforms for recording and sharing health data.
There were variations in the quality and reliability of home medical devices and platforms.&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;Communication Issues:
    &lt;blockquote&gt;
      &lt;p&gt;Ensuring patients understood how and when to take their vitals required clear communication, which was sometimes challenging through remote means.&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/srpm1.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-proposal&quot;&gt;The Proposal&lt;/h2&gt;
&lt;p&gt;Introducing Sharp RPM by Belle IT, a cutting-edge mobile application that utilizes computer vision to accurately translate device readings and consistently send them to a web-based portal for medical providers. Sharp RPM enables providers to monitor patient vitals and receive automated alerts via smartphones.
This innovative solution transforms the vital recording process from reactive to proactive, significantly enhancing patient care. Sharp RPM sets a new standard for future projects at Belle IT by leveraging computer vision/AI technology. This technology automates the identification and measurement of vital signs, reducing errors and improving accuracy.
With the transition away from mercury sphygmomanometers and the increased reliance on electronic sphygmomanometers, computer vision ensures precise detection and recording of blood pressure readings. This approach addresses the high error rates associated with electronic devices and avoids the pitfalls of manual recording.&lt;/p&gt;

&lt;p&gt;In summary, Sharp RPM revolutionizes how clinics and physicians manage patient vitals, ensuring timely, accurate, and proactive health monitoring.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;deliverables&quot;&gt;Deliverables&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;Create a UML for Sharp RPM application.&lt;/li&gt;
  &lt;li&gt;Develop a proof of concept.&lt;/li&gt;
  &lt;li&gt;Launch a marketing site that provides information about Sharp RPM V1 and allows for free trial as Belle IT prepares for open-source launch.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;uml&quot;&gt;UML&lt;/h2&gt;

&lt;p&gt;The foundation of this app was inspired by a &lt;a href=&quot;https://gale.udemy.com/course/dart-flutter-the-complete-flutter-development-course/learn/lecture/30856566&quot;&gt;course&lt;/a&gt; called 
&lt;em&gt;2024 Complete Guide To Flutter Development - Build 7 Native Cross-Platform iOS and Android Apps Using Flutter&lt;/em&gt;, taught by Hussain Mustafa offered on Udemy.&lt;/p&gt;

&lt;p&gt;We used the authentication capabilities of Firebase for user authentication and the cloud storage capabilities of Firestore for storing patient vitals and patient information. Below is an initial sketch and the UML for &lt;em&gt;Sharp RPM &lt;small&gt;v1&lt;/small&gt;&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/srpm2.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/srpm3.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;version-one&quot;&gt;Version One&lt;/h2&gt;

&lt;p&gt;To achieve our objectives, I initiated a series of code experiments and platform tests. Engaging in conversations with physicians, stakeholders, and exploring current medical device applications that communicate via Bluetooth, I developed several concepts. These efforts helped refine our application’s functionality and guided us toward the most effective platform for implementation after extensive testing across multiple options including Azure Computer Vision Service and Python OpenCV.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Google Cloud Vision for the Win !&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We concluded with using the Google &lt;a href=&quot;https://cloud.google.com/vision?hl=en&quot;&gt;Computer Vision API&lt;/a&gt;, integrating it into a Python script. This script is hosted via Google Cloud Functions, a serverless execution environment, allowing it to be utilized by our multi-platform Flutter application.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/srpm2.gif&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Online Presence&lt;/p&gt;

&lt;p&gt;Concluding our first sprint of efforts, here’s [Sharp RPM]! You’ll notice that the design decisions of the marketing site were informed by the design system of the application. Stay tuned for our upcoming release of Version 2, encapsulating concepts of Smarview MD &amp;amp; Sharp RPM.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>SmartView MD</title>
   <link href="https://projects.thankyoudom.com/2021/06/01/SmartViewMD/"/>
   <updated>2021-06-01T00:00:00+00:00</updated>
   <id>https://projects.thankyoudom.com/2021/06/01/SmartViewMD</id>
   <content type="html">&lt;blockquote&gt;
  &lt;p&gt;Creating a design system, marketing site and conducting research for a consolidated web based portal for medical providers to review patient vitals shared from disparate selected 3rd party medical devices.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/svmd10.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;An issue that many primary care clinics were challenged with worldwide, during the COVID-19 pandemic, was having their patients be responsible for manually recording vitals from several medical devices and properly documenting those records for clinic visits.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-proposal&quot;&gt;The Proposal&lt;/h2&gt;

&lt;p&gt;A mobile application which is a consolidated web based portal for medical providers to review (monitor and receive automated alerts of) patient vitals shared (via patient smartphones) from disparate selected 3rd party medical devices (e.g. blood pressure monitor, glucose monitoring, fingertip pulse oximeter, self monitoring blood glucose meter, and peak flow meter to monitor respiratory conditions such as asthma.)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/svmd1.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This solution helps clinics/physicians and transforms their patients’ vital recording process from one that is reactive to proactive.&lt;/p&gt;

&lt;p&gt;The app, entitled &lt;em&gt;SmartView MD&lt;/em&gt;, was to set precedence for the development of projects in the future of our parent company &lt;a href=&quot;https://belleit.net/&quot;&gt;Belle IT&lt;/a&gt; therefore, this quote was a mantra throughout the development process:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Because of the size and potential scope of this project, it was important that we were deliberate and intentional when phasing the different parts of the process. We set out to follow a process cycle that would allow for the right amount of definition, exploration, and reflection:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Define → Explore → Refine → Build → Learn&lt;/p&gt;

&lt;p&gt;&lt;cite&gt;— &lt;a href=&quot;http://emilybrick.me/&quot;&gt;Emily&lt;/a&gt; &lt;small&gt;Designer @ Github&lt;/small&gt;&lt;/cite&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 id=&quot;deliverables&quot;&gt;Deliverables&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;Create a UML for SmartView MD application.&lt;/li&gt;
  &lt;li&gt;Develop a design system that is consistent with Belle IT, INC.&lt;/li&gt;
  &lt;li&gt;Launch a marketing site that provides information about SmartView MD and allows for clinics/physicians to request demos and inquire about the SmartView MD application.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;uml&quot;&gt;UML&lt;/h2&gt;

&lt;p&gt;To start, I mapped out the different components of the application which was inspired by a &lt;a href=&quot;https://www.linkedin.com/learning/react-cloud-powered-apps-with-firebase&quot;&gt;course&lt;/a&gt; called 
&lt;em&gt;React: Cloud-Powered Apps with Firebase&lt;/em&gt;, taught by Victor Mejia offered on &lt;a href=&quot;https://www.linkedin.com/learning/&quot;&gt;LinkedIn Learning&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We used the authentication capabilities of Firebase for user authentication and the cloud storage capabilities of Firestore for storing patient vitals and physician/patient information.
The application is deployed using Firebase hosting. Below is an initial sketch and the UML for &lt;em&gt;SmartView MD &lt;small&gt;v1&lt;/small&gt;&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/svmd2.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/svmd3.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;design-system&quot;&gt;Design System&lt;/h2&gt;

&lt;p&gt;With our objectives in mind, I began ideating solutions through visual experimentation and mockups. Through generative design exercises, conversations with patients/physicians, and exploration of current medical device applications (that communicate with medical devices via bluetooth), I created a number of concepts to consider that would help define the visuals and layouts of our application.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Iconography&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I implemented the use of a collection of icons for React called Material Design Icons which helps ensure readability and clarity at large sizes for SmartView MD’s older audience of patients.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/svmd4.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We also worked on a naming convention for all of our assets and a color palette to be used across all of our products and sites:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Color system&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We ended up defining a simple three color palette that, in combination with the clean minimal layouts defined in the design system, emphasize the order Belle IT  brings to clinics.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/svmd6.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/svmd7.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Online Presence&lt;/p&gt;

&lt;p&gt;After many iterations, here’s &lt;a href=&quot;https://smartviewmd.com/&quot;&gt;SmartView MD&lt;/a&gt;! You’ll notice that the design decisions of the marketing site were informed by the design system of the application.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/svmd5.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Perspective BFA</title>
   <link href="https://projects.thankyoudom.com/2021/06/01/PerspectiveBFA/"/>
   <updated>2021-06-01T00:00:00+00:00</updated>
   <id>https://projects.thankyoudom.com/2021/06/01/PerspectiveBFA</id>
   <content type="html">&lt;blockquote&gt;
  &lt;p&gt;Developing a virtual exhibition hosting the works of 14 graduating senior graphic designers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Florida Atlantic University’s &lt;a href=&quot;https://www.fau.edu/artsandletters/vaah/bfa-gd/&quot;&gt;BFA Graphic Design&lt;/a&gt; program hosts an annual senior portfolio exhibition for graphic design students. In order to promote the upcoming exhibit, senior students are asked to design a postcard as a class assignment. One student’s design is chosen by the graduating class, and their design goes into production.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/pbfa9.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;For my graduating class this design, created by &lt;a href=&quot;https://www.behance.net/gcastellanos&quot;&gt;Gino Castellanos&lt;/a&gt;, established the design system of our online exhibition that I had the great opportunity of developing alongside fellow senior designer, &lt;a href=&quot;https://www.behance.net/joshuanolan&quot;&gt;Joshua Nolan&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;deliverables&quot;&gt;Deliverables&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;UML for PerspectiveBFA.com&lt;/li&gt;
  &lt;li&gt;A countdown mechanism for the anticipation of the upcoming launch date&lt;/li&gt;
  &lt;li&gt;A portal for designers to input and consolidate their page information&lt;/li&gt;
  &lt;li&gt;Deploy a website that hosts a virtual exhibition, showcasing the works of 14 graduating designers, and leads traffic to their individual portfolios.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;uml&quot;&gt;UML&lt;/h2&gt;

&lt;p&gt;My teammate did the preliminary work of creating the layout and structure of the site using a combination of Adobe Illustrator for our first iteration and webflow for the second iteration.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/pbfa1.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I then built upon those visions, exporting the html/css from webflow and converting it to javascript, in order to work with the React framework. This decision was made in order to allow for a dynamic landing page and to enable the capabilities of utilizing React components. For the landing page, I used a javascript library called three.js for the interactive geometric experience.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/pbfa10.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;countdown&quot;&gt;Countdown&lt;/h2&gt;

&lt;p&gt;For the week prior to the deployment of our exhibition, I created a live countdown with the days, hours, minutes and seconds left until launch.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/pbfa2.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/pbfa7.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/pbfa8.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;perspectivebfa-dot-com&quot;&gt;PERSPECTIVEBFA DOT COM&lt;/h2&gt;

&lt;p&gt;As the nation transitioned to remote learning and digital communication, this online exhibition refocused our energies towards creating designs for digital platforms. Three of these works were selected, per designer, for our individual pages that hosted our resumes, a brief paragraph about the designer and a link to each designer’s personal portfolio site.&lt;/p&gt;

&lt;p&gt;Online Presence&lt;/p&gt;

&lt;p&gt;Congratulatiions to my teammates for an excellent school year, here’s our &lt;a href=&quot;https://perspectivebfa.com/home/&quot;&gt;exhibition&lt;/a&gt;. You’ll notice that the design decisions of the site were informed by the design system of the invitation.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/pbfa.gif&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/pbfa6.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/pbfa3.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/pbfa4.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/pbfa11.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The image above is a screenshot from Google Analytics, displaying the performance metrics of various pages from our exhibition. The table includes data for pageviews, unique pageviews, average time on page, and entrances for each listed page. Key points are:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The homepage has the highest number of pageviews (2,046), unique pageviews (1,021), and an average time on page of 26 seconds.&lt;/li&gt;
  &lt;li&gt;The second-most visited page, indicated by a “/” (homepage), has 462 pageviews, 406 unique pageviews, and an average time on page of 5 seconds.&lt;/li&gt;
  &lt;li&gt;Several designer profile pages show a range of pageviews (from 151 to 265), unique pageviews (from 100 to 207), and average times on page (ranging from 4. 4 seconds to 1 minute and 21 seconds).&lt;/li&gt;
  &lt;li&gt;The acknowledgements page has 207 pageviews, 57 unique pageviews, and an average time on page of 46 seconds.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Overall, this data highlights the distribution of user engagement across different sections of our exhibition.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Clima</title>
   <link href="https://projects.thankyoudom.com/2021/06/01/Clima/"/>
   <updated>2021-06-01T00:00:00+00:00</updated>
   <id>https://projects.thankyoudom.com/2021/06/01/Clima</id>
   <content type="html">&lt;blockquote&gt;
  &lt;p&gt;Rethinking how we view a large cluster of data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Data visualization is beginning to become very prevalent in the world of design. In this emerging field, graphical representations are created for depicting a quick summary of data collections. 
Code can be an efficient tool in mapping those depictions, which could save designers from carrying out the mundane operation of defining every single connection.&lt;/p&gt;

&lt;p&gt;In my first effort to enter the world of data visualization, I used a combination of Javascript &amp;amp; Illustrator to map annual CO&lt;sub&gt;2&lt;/sub&gt; emissions and average temperature data from North America between 1914 and 2013 to the diameter and color (respectively) of a grid of circles.&lt;/p&gt;

&lt;p&gt;The final result was a 24x36 printed poster. This exercise was inspired by an &lt;a href=&quot;https://medium.com/re-write/combining-illustrator-and-javascript-for-data-visualization-dbe825852178&quot;&gt;article&lt;/a&gt; I found on Medium written by Nick Balderston.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/clima6.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;research&quot;&gt;Research&lt;/h2&gt;

&lt;p&gt;I found data for annual CO&lt;sub&gt;2&lt;/sub&gt; emissions and average temperatures in North America using the &lt;a href=&quot;https://ourworldindata.org/co2/country/united-states?country=~USA&quot;&gt;Our World in Data&lt;/a&gt;  website, as well as the &lt;a href=&quot;https://www.climate.gov/news-features/understanding-climate/climate-change-global-temperature&quot;&gt;Climate.gov&lt;/a&gt;. I then converted exported CSV files to XML inorder to refine my dataset. I saved separate XML files for emissions and temperatures to the folder in which I saved my first ExtendScript Toolkit file.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/clima.gif&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;clima&quot;&gt;Clima&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/clima1.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;digital-visualization&quot;&gt;Digital Visualization&lt;/h2&gt;

&lt;p&gt;Part Two of this exercise was to create a proof of concept for the utilization of this data visualization on an online platform. I decided that an interesting way to view this visualization would be mobily and created the prototype app Clima.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/clima2.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/clima3.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/clima4.png&quot; alt=&quot;placeholder&quot; title=&quot;Large example image&quot; /&gt;&lt;/p&gt;

</content>
 </entry>
 

</feed>
