Skip to content

Commit 8dbff84

Browse files
Jon DahlJon Dahl
authored andcommitted
add view count
1 parent 451f2cf commit 8dbff84

File tree

2 files changed

+118
-0
lines changed

2 files changed

+118
-0
lines changed

components/player-page.tsx

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ const PlayerPage: React.FC<PageProps> = ({ playbackId, videoExists, shareUrl, po
3636
const [metadataLoading, setMetadataLoading] = useState(false);
3737
const [metadata, setMetadata] = useState<any>(null);
3838
const [isMetadataCopied, setIsMetadataCopied] = useState(false);
39+
const [viewCount, setViewCount] = useState<number | null>(null);
40+
const [viewCountLoading, setViewCountLoading] = useState(false);
3941
const copyTimeoutRef = useRef<number | null>(null);
4042
const metadataCopyTimeoutRef = useRef<number | null>(null);
4143
const router = useRouter();
@@ -65,6 +67,30 @@ const PlayerPage: React.FC<PageProps> = ({ playbackId, videoExists, shareUrl, po
6567
}
6668
}, [playerType]);
6769

70+
useEffect(() => {
71+
if (showAdvanced) {
72+
fetchViewCount();
73+
}
74+
}, [showAdvanced, playbackId]);
75+
76+
const fetchViewCount = async () => {
77+
if (!playbackId) return;
78+
79+
console.log('Fetching view count for playback ID:', playbackId);
80+
setViewCountLoading(true);
81+
try {
82+
const response = await fetch(`/api/views/${playbackId}`);
83+
const data = await response.json();
84+
console.log('View count API response:', data);
85+
setViewCount(typeof data.views === 'number' ? data.views : null);
86+
} catch (error) {
87+
console.error('Error fetching view count:', error);
88+
setViewCount(null);
89+
} finally {
90+
setViewCountLoading(false);
91+
}
92+
};
93+
6894
const color = useMemo(() => {
6995
if (router.query?.color) {
7096
const val = (router.query?.color as string);
@@ -330,6 +356,16 @@ const PlayerPage: React.FC<PageProps> = ({ playbackId, videoExists, shareUrl, po
330356
</span>
331357
))}
332358
</div>
359+
<div className="view-count">
360+
<span className="label">Views (7d): </span>
361+
{viewCountLoading ? (
362+
<span className="loading">Loading...</span>
363+
) : typeof viewCount === 'number' ? (
364+
<span className="count">{viewCount.toLocaleString()}</span>
365+
) : (
366+
<span className="error">No data</span>
367+
)}
368+
</div>
333369
<div className="metadata-toggle">
334370
<a
335371
onClick={toggleMetadata}
@@ -556,6 +592,25 @@ const PlayerPage: React.FC<PageProps> = ({ playbackId, videoExists, shareUrl, po
556592
flex: 0 0 300px;
557593
margin-top: 40px;
558594
}
595+
.view-count {
596+
margin-top: 15px;
597+
padding-top: 15px;
598+
border-top: 1px solid rgba(255, 255, 255, 0.1);
599+
display: flex;
600+
align-items: center;
601+
gap: 8px;
602+
}
603+
.view-count .loading {
604+
color: #ccc;
605+
font-style: italic;
606+
}
607+
.view-count .count {
608+
color: #fff;
609+
font-weight: bold;
610+
}
611+
.view-count .error {
612+
color: #ff6b6b;
613+
}
559614
@media (max-width: 900px) {
560615
.content-container {
561616
flex-direction: column;

pages/api/views/[playbackId].ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { NextApiRequest, NextApiResponse } from 'next';
2+
import Mux from '@mux/mux-node';
3+
4+
const mux = new Mux();
5+
6+
interface ViewsResponse {
7+
data: {
8+
value: number;
9+
};
10+
}
11+
12+
export default async function handler(req: NextApiRequest, res: NextApiResponse): Promise<void> {
13+
const { method } = req;
14+
const { playbackId } = req.query;
15+
16+
if (method !== 'GET') {
17+
res.setHeader('Allow', ['GET']);
18+
res.status(405).end(`Method ${method} Not Allowed`);
19+
return;
20+
}
21+
22+
try {
23+
console.log('Getting view count for playback ID:', playbackId);
24+
25+
// Use the raw API endpoint for metrics/views/overall
26+
const response = await mux.request({
27+
method: 'get',
28+
path: '/data/v1/metrics/views/overall',
29+
query: {
30+
timeframe: ['7:days'],
31+
filters: [`video_id:${playbackId}`]
32+
}
33+
});
34+
35+
console.log('Mux Data API response:', JSON.stringify(response, null, 2));
36+
37+
// Get the total view count from the response
38+
const totalViews = (response as unknown as ViewsResponse).data.value || 0;
39+
console.log('Total views:', totalViews);
40+
41+
res.json({
42+
views: totalViews,
43+
timeframe: '7d'
44+
});
45+
} catch (e: any) {
46+
console.error('Error fetching view count:', e);
47+
if (e instanceof Error) {
48+
console.error('Error details:', e.message);
49+
console.error('Error stack:', e.stack);
50+
}
51+
52+
// Check if it's a Mux API error
53+
if (e.status === 403) {
54+
console.error('Mux Data API access denied. Make sure MUX_TOKEN_ID and MUX_TOKEN_SECRET are set correctly.');
55+
res.status(403).json({ error: 'Mux Data API access denied' });
56+
} else if (e.status === 404) {
57+
console.error('No data found for this playback ID');
58+
res.status(404).json({ error: 'No view data found for this video' });
59+
} else {
60+
res.status(500).json({ error: 'Error fetching view count' });
61+
}
62+
}
63+
}

0 commit comments

Comments
 (0)