diff --git a/client/src/components/netflix-grid.tsx b/client/src/components/netflix-grid.tsx
index ccafcd6..4cd3709 100644
--- a/client/src/components/netflix-grid.tsx
+++ b/client/src/components/netflix-grid.tsx
@@ -22,8 +22,10 @@ export default function NetflixGrid({ videos, isLoading }: NetflixGridProps) {
const [, setLocation] = useLocation();
const handleVideoClick = (video: Video) => {
- // Navigate to individual video page instead of modal
- setLocation(`/video/${video.id}`);
+ // Generate short ID for cleaner URLs (first 8 chars without dashes)
+ const shortId = video.id.replace(/-/g, '').substring(0, 8);
+ // Navigate to individual video page with short ID
+ setLocation(`/video/${shortId}`);
};
const handleCloseModal = () => {
diff --git a/client/src/components/video-card.tsx b/client/src/components/video-card.tsx
index 2f78847..7f47fb4 100644
--- a/client/src/components/video-card.tsx
+++ b/client/src/components/video-card.tsx
@@ -44,6 +44,8 @@ function formatDate(date: Date | string): string {
}
export default function VideoCard({ video, onClick, className = "", hideOverlay = false }: VideoCardProps) {
+ // Generate short ID for cleaner URLs (first 8 chars without dashes)
+ const shortId = video.id.replace(/-/g, '').substring(0, 8);
const [isHovered, setIsHovered] = useState(false);
const [showPreview, setShowPreview] = useState(false);
const [isMuted, setIsMuted] = useState(true);
@@ -172,7 +174,7 @@ export default function VideoCard({ video, onClick, className = "", hideOverlay
return (
!isMobile && setIsHovered(true)}
onMouseLeave={() => !isMobile && setIsHovered(false)}
@@ -191,7 +193,7 @@ export default function VideoCard({ video, onClick, className = "", hideOverlay
objectPosition: video.faceCenterPosition || 'center center',
objectFit: 'cover'
}}
- data-testid={`img-thumbnail-${video.id}`}
+ data-testid={`img-thumbnail-${shortId}`}
loading="lazy"
decoding="async"
onError={(e) => {
diff --git a/server/routes.ts b/server/routes.ts
index 3ffd89c..82333e5 100644
--- a/server/routes.ts
+++ b/server/routes.ts
@@ -352,10 +352,34 @@ export async function registerRoutes(app: Express): Promise {
}
});
- // Get single video by ID
+ // Generate short ID from long UUID
+ function generateShortId(longId: string): string {
+ // Take first 8 characters and remove dashes for shorter, cleaner URLs
+ return longId.replace(/-/g, '').substring(0, 8);
+ }
+
+ // Find video by short or long ID
+ async function findVideoByAnyId(id: string) {
+ // If it's already a full UUID, use it directly
+ if (id.length === 36 && id.includes('-')) {
+ return await storage.getVideo(id);
+ }
+
+ // If it's a short ID (8 chars), search for matching video
+ if (id.length === 8) {
+ const allVideos = await storage.getVideos({ limit: 200, offset: 0 });
+ const video = allVideos.videos.find(v => generateShortId(v.id) === id);
+ return video;
+ }
+
+ // Try as full ID anyway
+ return await storage.getVideo(id);
+ }
+
+ // Get single video by ID (supports both short and long IDs)
app.get("/api/videos/:id", async (req, res) => {
try {
- const video = await storage.getVideo(req.params.id);
+ const video = await findVideoByAnyId(req.params.id);
if (!video) {
return res.status(404).json({ message: "Video not found" });
}
@@ -370,8 +394,8 @@ export async function registerRoutes(app: Express): Promise {
try {
const { id } = req.params;
- // Check if video exists first
- const video = await storage.getVideo(id);
+ // Check if video exists first (supports short and long IDs)
+ const video = await findVideoByAnyId(id);
if (!video) {
return res.status(404).json({ message: "Video not found" });
}
@@ -381,7 +405,7 @@ export async function registerRoutes(app: Express): Promise {
try {
const { BunnyService } = await import("./bunny");
const bunnyService = new BunnyService();
- ads = await bunnyService.getVideoAds(id);
+ ads = await bunnyService.getVideoAds(video.id); // Use full ID for API calls
console.log(`Retrieved ${ads.length} ad spots for video ${id}`);
} catch (error) {
console.error(`Failed to get ads from Bunny.net for video ${id}:`, error);
@@ -400,10 +424,16 @@ export async function registerRoutes(app: Express): Promise {
}
});
- // Update video views
+ // Update video views (supports short and long IDs)
app.post("/api/videos/:id/view", async (req, res) => {
try {
- await storage.updateVideoViews(req.params.id);
+ const video = await findVideoByAnyId(req.params.id);
+ if (!video) {
+ return res.status(404).json({ message: "Video not found" });
+ }
+
+ // Use the full video ID for storage operations
+ await storage.updateVideoViews(video.id);
res.json({ success: true });
} catch (error) {
res.status(500).json({ message: "Failed to update views" });