Technical documentation for all 10 analysis pages — SQL logic, thresholds, and use cases.
All analysis pages are available at dev-tm.ohmgp.com/analysis (and production). Each page has a country selector (where applicable) and displays data in card-based layouts powered by DuckDB queries against live CSV snapshots.
| Page | URL | Country Filter | Cards | Data Sources |
|---|---|---|---|---|
| Daily Movement | /analysis/daily |
Yes | 3 | Spotify Daily (today + yesterday) |
| Trends | /analysis/trends |
Yes | 2 | Spotify Daily (today + yesterday) |
| Top Lists | /analysis/top |
Yes | 3 | Spotify Daily, YouTube Toplists, Spotify Artists |
| Countries | /analysis/countries |
No | 2 | Spotify Daily, YouTube Countries |
| Artists | /analysis/artists |
No | 3 | Artists Ranking, Spotify Listeners, YouTube Artists |
| YouTube | /analysis/youtube |
No | 3 | YouTube Daily, YouTube Toplists, YouTube Trending |
| Metrics | /analysis/metrics |
Yes | 2 | Spotify Daily, Spotify Daily Totals |
| Cross-Platform | /analysis/cross |
Yes | 2 | Spotify Daily, Shazam, Radio |
| Predictive | /analysis/predict |
Yes | 2 | Spotify Daily |
| Time-Based | /analysis/time |
Yes | 3 | Spotify Daily |
/analysis/daily)Purpose: Shows the most significant position changes happening right now — who is climbing, who just entered, and who fell off.
Country filter: Yes (defaults to India)
Data sources: Spotify Daily (today + yesterday via _prev_table())
Logic: Tracks where P+ (position change) is not = (i.e. something moved). Sorted by position ascending (top positions first). Limited to top 15.
SQL conditions:
- country_code = '{code}'
- "P+" != '='
- ORDER BY CAST(Pos AS INT) ASC
- LIMIT 15
Columns: Track, Position, Streams, Streams+ (change amount), P+ (direction), YouTube
Insight: Identifies the songs making the biggest jumps today. A track at position 5 with P+ of +12 is climbing fast.
Logic: Tracks that appear in today's CSV but NOT in yesterday's CSV. Uses a LEFT JOIN ... WHERE NULL pattern (anti-join) between today's table (tname) and yesterday's table (t0).
SQL conditions:
- a.country_code = '{code}'
- NOT EXISTS (SELECT 1 FROM {t0} b WHERE b.Artist_and_Title = a.Artist_and_Title AND b.country_code = '{code}')
- ORDER BY CAST(a.Pos AS INT) ASC
- LIMIT 15
Columns: Track, Days (should be 1), Streams, YouTube
Insight: Brand new songs on the chart. A new entry at position 12 is more significant than one at position 95.
Logic: Tracks that exist in yesterday's CSV but NOT in today's CSV. Same anti-join pattern, reversed.
SQL conditions:
- b.country_code = '{code}'
- NOT EXISTS (SELECT 1 FROM {tname} a WHERE a.Artist_and_Title = b.Artist_and_Title AND a.country_code = '{code}')
- LIMIT 15
Columns: Track, Days (how long it charted), Last_Streams, YouTube
Insight: Shows what fell off. A track that charted for 60 days leaving is more notable than one that lasted 2 days.
/analysis/trends)Purpose: Identifies momentum — tracks with the strongest upward movement and potential viral candidates based on stream surges.
Country filter: Yes (defaults to India)
Data sources: Spotify Daily (today + yesterday)
Logic: JOINs today's table with yesterday's table on Artist_and_Title + country_code. Calculates position change as Today - Yesterday. A negative number means climbing (e.g. position 3 today vs position 10 yesterday = change of -7). Sorted ascending so the biggest climbers appear first.
SQL conditions:
- a.country_code = '{code}' AND b.country_code = '{code}'
- ORDER BY (CAST(a.Pos AS INT) - CAST(b.Pos AS INT)) ASC
- LIMIT 15
Columns: Track, Today Position, Yesterday Position, Change, Streams, YouTube
Insight: The raw movement between two days. A change of -15 means the track jumped 15 spots.
Logic: Tracks in the top 50 where today's streams (Streams+) exceed 0. Sorted by Streams+ descending. This surfaces tracks getting unusually high daily streams relative to their position.
SQL conditions:
- country_code = '{code}'
- CAST(Pos AS INT) <= 50
- CAST({_n('"Streams+"')} AS BIGINT) > 0
- ORDER BY CAST({_n('"Streams+"')} AS BIGINT) DESC
- LIMIT 15
Columns: Track, Position, Streams, 7-Day Average, Streams+ (today's surge), YouTube
Insight: A track at position 20 with 500K daily streams (vs 100K average) is surging. The ratio between Streams+ and 7Day indicates if this is a one-day spike or sustained growth.
/analysis/top)Purpose: All-time highest-performing content across Spotify and YouTube — the biggest songs and artists ever.
Country filter: Yes (for Spotify Daily card only)
Data sources: Spotify Daily, YouTube Toplists, Spotify Artists
Logic: Sorts Spotify Daily by Total (all-time cumulative streams) descending. Country-filtered.
SQL conditions:
- country_code = '{code}'
- ORDER BY CAST({_n('Total')} AS BIGINT) DESC
- LIMIT 15
Columns: Track, Position, Total (all-time streams), Daily (today's streams), YouTube
Insight: The most streamed song in a country's history. Comparing Total vs Daily shows if a song is still active or purely legacy.
Logic: Sorts YouTube Toplists by Views descending. Global (no country filter).
SQL conditions:
- ORDER BY CAST({_n('Views')} AS BIGINT) DESC
- LIMIT 15
Columns: Video, Artist, Views, Yesterday, Days, YouTube
Insight: The most viewed YouTube videos ever. Days shows how long it took to accumulate those views.
Logic: Sorts Spotify Artists by total streams descending. Global.
SQL conditions:
- ORDER BY CAST({_n('Streams')} AS BIGINT) DESC
- LIMIT 15
Columns: Artist, Streams (total), Daily, Lead, Solo, Feature
Insight: Breaks down how artists accumulate streams — lead vs solo vs feature credits shows collaboration strategy.
/analysis/countries)Purpose: Global snapshot — what's #1 everywhere and where platforms agree.
Country filter: No (shows all countries)
Data sources: Spotify Daily, YouTube Countries
Logic: Filters Spotify Daily for position = 1 across all countries. Sorted alphabetically by country name.
SQL conditions:
- CAST(Pos AS INT) = 1
- ORDER BY country_name
Columns: Country, Code, #1 Track, Position, Streams, YouTube
Insight: Reveals regional taste. Same song at #1 in 20 countries = global phenomenon. Different #1s everywhere = fragmented market.
Logic: JOINs Spotify Daily with YouTube Countries on Artist_and_Title + country_code. Only includes tracks where BOTH platforms have the song in their top 10. This is a strong convergence signal.
SQL conditions:
- CAST(a.Pos AS INT) <= 10 AND CAST(b.Pos AS INT) <= 10
- ORDER BY a.country_name, CAST(a.Pos AS INT)
- LIMIT 30
Columns: Country, Track, Spotify Position, YouTube Position, YouTube
Insight: When a song is top 10 on both Spotify and YouTube in the same country, it indicates genuine cultural relevance beyond just streaming algorithm promotion.
/analysis/artists)Purpose: Artist-level performance across platforms — who dominates globally.
Country filter: No (global data)
Data sources: Artists Ranking, Spotify Listeners, YouTube Artists
Logic: Sorts the Artists Ranking table by composite Points. Points are calculated from positions across Apple Music, Spotify, iTunes, YouTube, Shazam, and Deezer.
SQL conditions:
- ORDER BY CAST({_n('Points')} AS BIGINT) DESC
- LIMIT 20
Columns: Artist, Points, Apple_M, Spotify, iTunes, YouTube, Shazam, Deezer, Top_Country
Insight: The most comprehensive artist metric. An artist ranking high on Points but low on one platform is specialized. High on all = truly global.
Logic: Sorts Spotify Listeners by monthly listener count descending.
SQL conditions:
- ORDER BY CAST({_n('Listeners')} AS BIGINT) DESC
- LIMIT 20
Columns: Artist, Listeners, Daily +/-, Peak, Peak Listeners
Insight: Monthly listeners indicate reach. A high Daily +/- means the artist is currently growing or declining. Comparing current Listeners to Peak shows if they're at their height or past it.
Logic: Sorts YouTube Artists by total views descending.
SQL conditions:
- ORDER BY CAST({_n('Total')} AS BIGINT) DESC
- LIMIT 20
Columns: Artist, Total Views, Videos 100M+
Insight: YouTube views accumulate differently from Spotify streams. The "Videos 100M+" count shows consistency — an artist with 50 videos at 100M+ is more consistent than one with 1 viral hit.
/analysis/youtube)Purpose: YouTube-specific performance — daily charts, all-time records, and trending.
Country filter: No (global data)
Data sources: YouTube Daily, YouTube Toplists, YouTube Trending
Logic: Sorts YouTube Daily by rank ascending. Shows today's most viewed videos globally.
SQL conditions:
- ORDER BY CAST(Rank AS INT) ASC
- LIMIT 20
Columns: Rank, Video, Views, Likes, Channel, YouTube
Insight: Daily YouTube chart movement. High views + high likes = genuine engagement. High views + low likes = potential clickbait or promoted content.
Logic: Sorts YouTube Toplists by views descending.
SQL conditions:
- ORDER BY CAST({_n('Views')} AS BIGINT) DESC
- LIMIT 20
Columns: Video, Artist, Views, Yesterday, Days, Likes, YouTube
Insight: The all-time leaderboard. Yesterday column shows daily velocity — if Yesterday is high relative to total, the video is still actively accumulating views.
Logic: Shows current trending videos from the trending page. Limited to first 20 entries.
SQL conditions:
- LIMIT 20
Columns: Video, Position, Highlights, Type, YouTube
Insight: What YouTube considers trending right now. The chart_type column distinguishes between overall trending, music trending, etc.
/analysis/metrics)Purpose: Quantitative analysis of streaming performance — peak efficiency and velocity.
Country filter: Yes (defaults to India)
Data sources: Spotify Daily, Spotify Daily Totals
Logic: Joins Daily Totals data. Calculates Peak % = (Total / Peak_Streams) * 100. A high peak % means the song sustained near-peak performance. A low peak % means it spiked then faded.
SQL conditions:
- country_code = '{code}'
- CAST({_n('PkStreams')} AS BIGINT) > 0
- ORDER BY CAST({_n('Total')} AS BIGINT) DESC
- LIMIT 15
Columns: Track, Days, Peak Streams, Total, Peak %, YouTube
Insight: Peak % is the key metric. A song with Peak % of 85% sustained most of its peak. One with 20% had a brief spike. Comparing Days to Peak % shows longevity vs burst.
Logic: Calculates velocity ratio = Streams / 7Day. A ratio > 1.0 means the track is accelerating today. A ratio < 1.0 means it's decelerating.
SQL conditions:
- country_code = '{code}'
- CAST({_n('"7Day"')} AS BIGINT) > 0
- ORDER BY Velocity DESC
- LIMIT 15
Columns: Track, Streams (today), 7-Day Average, Velocity (ratio), YouTube
Insight: Velocity > 2.0 is a strong viral signal. Velocity > 3.0 is explosive. Velocity < 0.5 means the song is fading fast. This is one of the most actionable metrics for trend prediction.
/analysis/cross)Purpose: How tracks perform across different platforms — Shazam discovery pipeline, radio vs streaming.
Country filter: Yes (defaults to India)
Data sources: Spotify Daily, Shazam, Radio
Logic: JOINs Shazam with Spotify Daily on Artist_-_Title + country_code. Only includes tracks that are top 20 on Shazam AND top 50 on Spotify. This identifies the discovery pipeline — songs people are Shazaming that are already gaining traction on streaming.
SQL conditions:
- sh.country_code = '{code}'
- CAST(sh.Pos AS INT) <= 20 AND CAST(sp.Pos AS INT) <= 50
- ORDER BY CAST(sh.Pos AS INT) ASC
- LIMIT 15
Columns: Track, Shazam Position, Spotify Position, Streams, YouTube
Insight: Shazam often leads Spotify by days or weeks. A track high on Shazam but low on Spotify is about to break. A track high on both has already broken through. The position gap between platforms indicates the pipeline stage.
Logic: JOINs Radio with Spotify Daily on Artist_and_Title + country_code. Shows how radio airplay translates to streaming.
SQL conditions:
- s.country_code = '{code}'
- ORDER BY CAST(r.Pos AS INT) ASC
- LIMIT 15
Columns: Track, Radio Position, Audience, Formats, Spotify Position, Streams, YouTube
Insight: Radio is a traditional discovery channel. A track high on radio but low on Spotify indicates older demographic appeal or upcoming release. High on both = mainstream crossover. Radio audience size indicates reach.
/analysis/predict)Purpose: Forward-looking signals — songs about to break and songs about to fade.
Country filter: Yes (defaults to India)
Data sources: Spotify Daily
Logic: Tracks in positions 100-500 that are young (<=14 days on chart) and already getting significant streams (today's streams > 50% of 7-day average). This catches songs early in their trajectory that are gaining momentum.
SQL conditions:
- country_code = '{code}'
- CAST(Pos AS INT) > 100 AND CAST(Pos AS INT) <= 500
- CAST({_n('"Streams+"')} AS BIGINT) > CAST({_n('"7Day"')} AS BIGINT) * 0.5
- CAST(Days AS INT) <= 14
- ORDER BY CAST({_n('"Streams+"')} AS BIGINT) DESC
- LIMIT 15
Columns: Track, Position, Streams, 7-Day Average, Days, YouTube
Insight: A track at position 350 that's only 5 days old but already getting 100K daily streams is about to rocket. The Streams+ > 7Day * 0.5 threshold ensures the track has real momentum, not just a one-day blip.
Logic: Tracks that have been on the chart for 30+ days, are in the top 100, but have dropped more than 20 positions below their peak. The P+ column must not be = (indicating active movement, specifically downward).
SQL conditions:
- country_code = '{code}'
- CAST(Days AS INT) >= 30
- CAST(Pos AS INT) <= 100
- "P+" != '='
- CAST(Pos AS INT) > CAST(Pk AS INT) + 20
- ORDER BY CAST(Days AS INT) DESC
- LIMIT 15
Columns: Track, Position, Streams, Days, Trend (P+), YouTube
Insight: A song that was at peak 5 and is now at position 30 after 45 days is fading. The gap between peak and current position (25 spots) combined with long charting duration confirms this is a natural decline, not a temporary dip.
/analysis/time)Purpose: Temporal patterns — longevity, freshness, and decline trajectories.
Country filter: Yes (defaults to India)
Data sources: Spotify Daily
Logic: Tracks that have been on the chart for 60+ days AND are still in the top 100. Sorted by days descending.
SQL conditions:
- country_code = '{code}'
- CAST(Days AS INT) >= 60
- CAST(Pos AS INT) <= 100
- ORDER BY CAST(Days AS INT) DESC
- LIMIT 15
Columns: Track, Days, Position, Peak, Streams, YouTube
Insight: Longevity champions. A track at position 80 after 120 days is still relevant. Comparing Days to Peak shows the trajectory — did it peak early and sustain, or peak late?
Logic: Tracks where the YouTube publish date was less than 30 days ago AND the track is already in the top 50. Uses days_since_published column (from YouTube metadata enrichment).
SQL conditions:
- country_code = '{code}'
- CAST(days_since_published AS INT) <= 30
- CAST(Pos AS INT) <= 50
- ORDER BY CAST(Pos AS INT) ASC
- LIMIT 15
Columns: Track, Age (days since publish), Position, Streams, YouTube
Insight: Freshness indicator. A track published 5 days ago at position 12 is exploding. A track published 28 days ago at position 45 is steadily climbing. The age-to-position ratio is the key metric.
Logic: Tracks that peaked in the top 10 but have since dropped more than 20 positions below peak. Sorted by the gap descending.
SQL conditions:
- country_code = '{code}'
- CAST(Pk AS INT) <= 10
- CAST(Pos AS INT) > CAST(Pk AS INT) + 20
- ORDER BY (CAST(Pos AS INT) - CAST(Pk AS INT)) DESC
- LIMIT 15
Columns: Track, Position, Peak, Below Peak (gap), Days, YouTube
Insight: Decline trajectory. A song that peaked at #1 and is now at #45 after 80 days is fading. The gap (45 spots) combined with Days shows how fast the decline is. Songs with small gaps and low Days are still adjusting; large gaps with high Days are clearly declining.
| Function | Purpose | Used In |
|---|---|---|
_resolve_country(args) |
Gets country from query params, defaults to 'in' | All country-filtered pages |
_country_table(source_key) |
Returns latest DuckDB table name for a source | All pages |
_prev_table(source_key) |
Returns second-latest table for day-over-day comparison | Daily, Trends |
get_latest_file(source_key) |
Returns (table_name, latest_date) | All pages |
_q(sql) |
Executes SQL, returns (columns, rows) as string lists | All pages |
_n(col) |
Wraps column in REPLACE(CAST(...), ',', '') for safe numeric casting | Metrics, Trends, Top, Artists, YouTube, Cross, Predict, Time |
_country_list() |
Returns sorted list of country dicts for dropdown | All country-filtered pages |
-- New entries: in today but not yesterday
SELECT a.Track FROM today a
WHERE NOT EXISTS (SELECT 1 FROM yesterday b WHERE b.Track = a.Track)
-- Exits: in yesterday but not today
SELECT b.Track FROM yesterday b
WHERE NOT EXISTS (SELECT 1 FROM today a WHERE a.Track = b.Track)
-- Position change between two days
SELECT a.Track, a.Pos as Today, b.Pos as Yesterday,
a.Pos - b.Pos as Change
FROM today a JOIN yesterday b ON a.Track = b.Track
ORDER BY Change ASC -- negative = climbing
-- Today's streams / 7-day average
ROUND(CAST(Streams AS DOUBLE) / GREATEST(CAST("7Day" AS DOUBLE), 1), 2) as Velocity
-- How much of peak performance is sustained
ROUND(CAST(Total AS DOUBLE) / GREATEST(CAST(PkStreams AS DOUBLE), 1) * 100, 1) as "Peak %"
-- Matches across platforms
SELECT sh.Track, sh.Pos as Shazam_Pos, sp.Pos as Spotify_Pos
FROM shazam sh JOIN spotify sp ON sh.Track = sp.Track AND sh.country_code = sp.country_code
WHERE sh.Pos <= 20 AND sp.Pos <= 50