Initial commit: IndeeHub decentralized streaming platform

Built a complete Netflix-style streaming interface for IndeeHub's decentralized media platform with real film content.

Features:
- Vue 3 + TypeScript + Vite setup with hot module reloading
- Netflix-inspired UI with hero section and horizontal scrolling content rows
- Glass morphism design system with custom Tailwind configuration
- 20+ real IndeeHub films organized into 6 categories (Bitcoin, Documentaries, Drama, etc.)
- Full-featured video player component with custom controls
- Mobile-responsive design with bottom navigation
- Nostr integration ready (nostr-tools, relay pool, NIP-71 support)
- Pinia state management for content
- MCP tools configured (Filesystem, Memory, Nostr, Puppeteer)

Components:
- Browse.vue: Main streaming interface with hero and content rows
- ContentRow.vue: Horizontal scrolling film cards with navigation arrows
- VideoPlayer.vue: Custom video player with play/pause, seek, volume, fullscreen
- MobileNav.vue: Bottom tab navigation for mobile devices

Tech Stack:
- Frontend: Vue 3 (Composition API), TypeScript
- Build: Vite 7
- Styling: Tailwind CSS with custom theme
- State: Pinia 3
- Router: Vue Router 4.6
- Protocol: Nostr (nostr-tools 2.22)

Design:
- 4px grid spacing system
- Glass morphism UI components
- Netflix-style hero section with featured content
- Smooth animations and hover effects
- Mobile-first responsive breakpoints
- Dark theme with custom color palette

Content:
- 20+ IndeeHub films with titles, descriptions, categories
- Bitcoin documentaries: God Bless Bitcoin, Dirty Coin, Searching for Satoshi
- Independent films and documentaries
- Working Unsplash CDN images for thumbnails and backdrops

Ready for deployment to Umbrel, Start9, and Archy nodes.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Dorian
2026-02-02 22:19:47 +00:00
commit 0bb1bcc5f9
50 changed files with 8278 additions and 0 deletions

97
src/utils/indeeHubApi.ts Normal file
View File

@@ -0,0 +1,97 @@
// Utility to fetch content from IndeeHub API
// Update with your actual API endpoints
const INDEEDHUB_API = 'https://indeehub.studio/api'
export interface IndeeHubFilm {
id: string
title: string
description: string
thumbnailUrl: string
backdropUrl?: string
type: 'film' | 'series' | 'short'
duration?: number
releaseYear?: number
rating?: string
creator?: {
name: string
npub?: string
}
nostrEventId?: string
categories: string[]
}
/**
* Fetch films from IndeeHub screening room
* TODO: Replace with actual API call when authenticated
*/
export async function fetchFilms(): Promise<IndeeHubFilm[]> {
try {
// TODO: Add authentication headers (NIP-98 for Nostr auth)
const response = await fetch(`${INDEEHHUB_API}/screening-room?type=film`, {
headers: {
// Add your auth headers here
// 'Authorization': 'Bearer ...'
}
})
if (!response.ok) {
throw new Error('Failed to fetch films')
}
return await response.json()
} catch (error) {
console.error('Error fetching films:', error)
// Return mock data for development
return getMockFilms()
}
}
/**
* Mock data for development
* Replace with real IndeeHub data
*/
function getMockFilms(): IndeeHubFilm[] {
return [
{
id: '1',
title: 'Sample Film 1',
description: 'Replace with actual IndeeHub film data',
thumbnailUrl: 'https://images.unsplash.com/photo-1518546305927-5a555bb7020d?w=400',
backdropUrl: 'https://images.unsplash.com/photo-1518546305927-5a555bb7020d?w=1920',
type: 'film',
duration: 120,
releaseYear: 2024,
categories: ['Drama']
},
// Add more mock films...
]
}
/**
* Fetch featured content
*/
export async function fetchFeaturedContent(): Promise<IndeeHubFilm | null> {
try {
const response = await fetch(`${INDEEHHUB_API}/featured`)
if (!response.ok) return null
return await response.json()
} catch (error) {
console.error('Error fetching featured:', error)
return null
}
}
/**
* Fetch films by category
*/
export async function fetchFilmsByCategory(category: string): Promise<IndeeHubFilm[]> {
try {
const response = await fetch(`${INDEEHHUB_API}/films?category=${category}`)
if (!response.ok) return []
return await response.json()
} catch (error) {
console.error('Error fetching category:', error)
return []
}
}