ScraperApi / components /ui /netmirror-docs.tsx
Sanchit Vishwakarma
Initial commit
473db3d
"use client";
import { useState } from "react";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Badge } from "@/components/ui/badge";
import { Textarea } from "@/components/ui/textarea";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Copy, Play, Code2, Home, Search, Film, Download, Star, Clapperboard, Cloud, Info, Link2, Video } from "lucide-react";
import { toast } from "sonner";
interface ApiEndpoint {
method: string;
endpoint: string;
description: string;
params?: { name: string; type: string; required: boolean; description: string }[];
}
interface ApiCategory {
name: string;
icon: React.ReactNode;
endpoints: ApiEndpoint[];
color: string;
}
const netMirrorApiCategories: ApiCategory[] = [
{
name: "Get Movies",
icon: <Home className="h-4 w-4" />,
color: "bg-blue-500",
endpoints: [
{
method: "GET",
endpoint: "/api/netmirror",
description: "Get all movies and shows from NetMirror homepage",
params: []
}
]
},
{
name: "Search Movies",
icon: <Search className="h-4 w-4" />,
color: "bg-green-500",
endpoints: [
{
method: "GET",
endpoint: "/api/netmirror/search",
description: "Search movies and shows by title on NetMirror",
params: [
{ name: "p", type: "string", required: true, description: "Search query (movie/show title)" }
]
}
]
},
{
name: "Movie Details",
icon: <Info className="h-4 w-4" />,
color: "bg-purple-500",
endpoints: [
{
method: "GET",
endpoint: "/api/netmirror/getpost",
description: "Get detailed movie information and metadata",
params: [
{ name: "id", type: "string", required: true, description: "Movie ID from NetMirror (e.g., from data-post attribute)" },
{ name: "t", type: "string", required: false, description: "Timestamp (auto-generated if not provided)" }
]
}
]
},
{
name: "Stream Links",
icon: <Video className="h-4 w-4" />,
color: "bg-red-500",
endpoints: [
{
method: "GET",
endpoint: "/api/netmirror/stream",
description: "Get streaming links and playlist data for movies",
params: [
{ name: "id", type: "string", required: true, description: "Movie ID from NetMirror" }
]
}
]
}
];
interface NetMirrorDocsProps {
apiKey: string;
onApiKeyChange: (key: string) => void;
}
// Colorized JSON component
const ColorizedJSON = ({ data, title = "Response" }: { data: string; title?: string }) => {
const colorizeJSON = (jsonString: string) => {
return jsonString
.replace(/"([^"]+)":/g, '<span class="text-blue-400">"$1"</span>:')
.replace(/: "([^"]+)"/g, ': <span class="text-green-400">"$1"</span>')
.replace(/: (\d+)/g, ': <span class="text-yellow-400">$1</span>')
.replace(/: (true|false)/g, ': <span class="text-purple-400">$1</span>')
.replace(/: null/g, ': <span class="text-gray-400">null</span>')
.replace(/\[/g, '<span class="text-red-400">[</span>')
.replace(/\]/g, '<span class="text-red-400">]</span>')
.replace(/{/g, '<span class="text-cyan-400">{</span>')
.replace(/}/g, '<span class="text-cyan-400">}</span>');
};
return (
<div className="bg-[#1e1e1e] rounded-lg overflow-hidden border border-gray-800">
<div className="flex items-center justify-between bg-[#2d2d30] px-4 py-2 border-b border-gray-700">
<div className="flex items-center gap-2 min-w-0">
<div className="flex gap-1.5 shrink-0">
<div className="w-3 h-3 rounded-full bg-[#ff5f56]"></div>
<div className="w-3 h-3 rounded-full bg-[#ffbd2e]"></div>
<div className="w-3 h-3 rounded-full bg-[#27ca3f]"></div>
</div>
<span className="text-gray-300 text-sm ml-2 truncate">{title}.json</span>
</div>
<Button
size="sm"
variant="ghost"
className="text-gray-400 hover:text-white hover:bg-gray-700 h-6 px-2 shrink-0"
onClick={() => {
navigator.clipboard.writeText(data);
toast.success("Copied to clipboard!");
}}
>
<Copy className="h-3 w-3" />
</Button>
</div>
<div className="overflow-x-auto">
<pre className="p-4">
<code
className="text-sm text-gray-300 font-mono whitespace-pre-wrap break-words"
dangerouslySetInnerHTML={{ __html: colorizeJSON(data) }}
/>
</pre>
</div>
</div>
);
};
export default function NetMirrorDocs({ apiKey, onApiKeyChange }: NetMirrorDocsProps) {
const [selectedCategory, setSelectedCategory] = useState(netMirrorApiCategories[0]);
const [selectedEndpoint, setSelectedEndpoint] = useState(netMirrorApiCategories[0].endpoints[0]);
const [testParams, setTestParams] = useState<Record<string, string>>({});
const [response, setResponse] = useState("");
const [loading, setLoading] = useState(false);
const copyToClipboard = (text: string) => {
navigator.clipboard.writeText(text);
toast.success("Copied to clipboard!");
};
const handleCategoryChange = (categoryName: string) => {
const category = netMirrorApiCategories.find(cat => cat.name === categoryName);
if (category) {
setSelectedCategory(category);
setSelectedEndpoint(category.endpoints[0]);
setTestParams({});
}
};
const handleEndpointChange = (endpointPath: string) => {
const endpoint = selectedCategory.endpoints.find(ep => ep.endpoint === endpointPath);
if (endpoint) {
setSelectedEndpoint(endpoint);
setTestParams({});
}
};
const testApi = async () => {
if (!apiKey) {
toast.error("Please enter your API key");
return;
}
const missingParams = selectedEndpoint.params?.filter(param =>
param.required && !testParams[param.name]
) || [];
if (missingParams.length > 0) {
toast.error(`Missing required parameters: ${missingParams.map(p => p.name).join(', ')}`);
return;
}
setLoading(true);
try {
let url = selectedEndpoint.endpoint;
const queryParams = new URLSearchParams();
Object.entries(testParams).forEach(([key, value]) => {
if (value) {
queryParams.append(key, value);
}
});
if (queryParams.toString()) {
url += "?" + queryParams.toString();
}
const res = await fetch(url, {
headers: {
"x-api-key": apiKey,
"Content-Type": "application/json"
}
});
const data = await res.json();
setResponse(JSON.stringify(data, null, 2));
if (!res.ok) {
toast.error(`Error: ${res.status}`);
} else {
toast.success("API call successful!");
}
} catch (error) {
toast.error("Failed to call API");
setResponse(JSON.stringify({ error: "Failed to call API" }, null, 2));
} finally {
setLoading(false);
}
};
const generateCodeExample = (language: string) => {
const params = Object.entries(testParams).filter(([_, value]) => value);
const baseUrl = "https://totu.me";
let url = selectedEndpoint.endpoint;
const queryParams = params.map(([key, value]) => `${key}=${value}`).join("&");
if (queryParams) {
url += "?" + queryParams;
}
switch (language) {
case "javascript":
if (selectedCategory.name === "Get Movies") {
return `// Get movies from NetMirror
const response = await fetch("${baseUrl}/api/netmirror", {
headers: {
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json"
}
});
const data = await response.json();
console.log(data.data.items); // Array of movies and shows
// NetMirror features:
// - Netflix-style interface
// - High-quality streaming content
// - Multiple categories and genres
// - Direct streaming links
// Access movie details
data.data.items.forEach(movie => {
console.log(\`Title: \${movie.title}\`);
console.log(\`ID: \${movie.id}\`);
console.log(\`Category: \${movie.category}\`);
console.log(\`Image: \${movie.imageUrl}\`);
console.log(\`Watch URL: \${movie.postUrl}\`);
});`;
} else if (selectedCategory.name === "Search Movies") {
return `// Search movies on NetMirror
const searchQuery = "spider man";
const response = await fetch(\`${baseUrl}/api/netmirror/search?p=\${encodeURIComponent(searchQuery)}\`, {
headers: {
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json"
}
});
const data = await response.json();
console.log(data.data.searchResults); // Search results
// The search returns structured data with movie information
// Use the returned IDs to get detailed information or streaming links`;
} else if (selectedCategory.name === "Movie Details") {
return `// Get movie details from NetMirror
const movieId = "12345"; // From NetMirror movie listing
const response = await fetch(\`${baseUrl}/api/netmirror/getpost?id=\${movieId}\`, {
headers: {
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json"
}
});
const data = await response.json();
console.log(data.data); // Movie details and metadata
// Optional: Include timestamp parameter
const withTimestamp = await fetch(\`${baseUrl}/api/netmirror/getpost?id=\${movieId}&t=\${Date.now()}\`, {
headers: {
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json"
}
});`;
} else if (selectedCategory.name === "Stream Links") {
return `// Get streaming links from NetMirror
const movieId = "12345"; // From NetMirror movie listing
const response = await fetch(\`${baseUrl}/api/netmirror/stream?id=\${movieId}\`, {
headers: {
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json"
}
});
const data = await response.json();
console.log(data.data.streamData); // Streaming playlist and sources
// Access streaming sources
if (data.data.streamData.sources) {
data.data.streamData.sources.forEach(source => {
console.log(\`Quality: \${source.label}\`);
console.log(\`File URL: \${source.file}\`);
console.log(\`Type: \${source.type}\`);
});
}`;
}
case "python":
if (selectedCategory.name === "Get Movies") {
return `# Get movies from NetMirror
import requests
url = "${baseUrl}/api/netmirror"
headers = {
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json"
}
response = requests.get(url, headers=headers)
data = response.json()
print(data["data"]["items"]) # Array of movies and shows
# Access movie details
for movie in data["data"]["items"]:
print(f"Title: {movie['title']}")
print(f"ID: {movie['id']}")
print(f"Category: {movie['category']}")`;
} else if (selectedCategory.name === "Search Movies") {
return `# Search movies on NetMirror
import requests
from urllib.parse import quote
search_query = "spider man"
url = f"${baseUrl}/api/netmirror/search?p={quote(search_query)}"
headers = {
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json"
}
response = requests.get(url, headers=headers)
data = response.json()
print(data["data"]["searchResults"]) # Search results`;
} else if (selectedCategory.name === "Movie Details") {
return `# Get movie details from NetMirror
import requests
movie_id = "12345" # From NetMirror movie listing
url = f"${baseUrl}/api/netmirror/getpost?id={movie_id}"
headers = {
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json"
}
response = requests.get(url, headers=headers)
data = response.json()
print(data["data"]) # Movie details and metadata`;
} else if (selectedCategory.name === "Stream Links") {
return `# Get streaming links from NetMirror
import requests
movie_id = "12345" # From NetMirror movie listing
url = f"${baseUrl}/api/netmirror/stream?id={movie_id}"
headers = {
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json"
}
response = requests.get(url, headers=headers)
data = response.json()
print(data["data"]["streamData"]) # Streaming playlist and sources`;
}
case "curl":
if (selectedCategory.name === "Get Movies") {
return `# Get movies from NetMirror
curl -X GET \\
"${baseUrl}/api/netmirror" \\
-H "x-api-key: YOUR_API_KEY" \\
-H "Content-Type: application/json"`;
} else if (selectedCategory.name === "Search Movies") {
return `# Search movies on NetMirror
curl -X GET \\
"${baseUrl}/api/netmirror/search?p=spider%20man" \\
-H "x-api-key: YOUR_API_KEY" \\
-H "Content-Type: application/json"`;
} else if (selectedCategory.name === "Movie Details") {
return `# Get movie details from NetMirror
curl -X GET \\
"${baseUrl}/api/netmirror/getpost?id=12345" \\
-H "x-api-key: YOUR_API_KEY" \\
-H "Content-Type: application/json"`;
} else if (selectedCategory.name === "Stream Links") {
return `# Get streaming links from NetMirror
curl -X GET \\
"${baseUrl}/api/netmirror/stream?id=12345" \\
-H "x-api-key: YOUR_API_KEY" \\
-H "Content-Type: application/json"`;
}
default:
return "";
}
};
const getResponseExample = (category: string) => {
switch (category) {
case "Get Movies":
return `{
"success": true,
"data": {
"items": [
{
"id": "12345",
"title": "Spider-Man: No Way Home",
"imageUrl": "https://image.tmdb.org/t/p/w342/1g0dhYtq4irTY1GPXvft6k4YLjm.jpg",
"postUrl": "https://net20.cc/watch/12345",
"category": "Action Movies"
},
{
"id": "12346",
"title": "The Batman",
"imageUrl": "https://image.tmdb.org/t/p/w342/74xTEgt7R36Fpooo50r9T25onhq.jpg",
"postUrl": "https://net20.cc/watch/12346",
"category": "Superhero Movies"
},
{
"id": "12347",
"title": "Dune",
"imageUrl": "https://image.tmdb.org/t/p/w342/d5NXSklXo0qyIYkgV94XAgMIckC.jpg",
"postUrl": "https://net20.cc/watch/12347",
"category": "Sci-Fi Movies"
}
],
"totalResults": 150
}
}`;
case "Search Movies":
return `{
"success": true,
"data": {
"searchUrl": "https://net20.cc/search.php?s=spider%20man&t=1640995200000",
"searchResults": {
"results": [
{
"id": "12345",
"title": "Spider-Man: No Way Home",
"year": "2021",
"type": "movie",
"poster": "https://image.tmdb.org/t/p/w342/1g0dhYtq4irTY1GPXvft6k4YLjm.jpg"
},
{
"id": "12348",
"title": "Spider-Man: Far From Home",
"year": "2019",
"type": "movie",
"poster": "https://image.tmdb.org/t/p/w342/4q2NNj4S5dG2RLF9CpXsej7yXl.jpg"
},
{
"id": "12349",
"title": "Spider-Man: Into the Spider-Verse",
"year": "2018",
"type": "movie",
"poster": "https://image.tmdb.org/t/p/w342/iiZZdoQBEYBv6id8su7ImL0oCbD.jpg"
}
],
"totalFound": 8
},
"requestParams": {
"query": "spider man",
"timestamp": "1640995200000"
}
}
}`;
case "Movie Details":
return `{
"success": true,
"data": {
"title": "Spider-Man: No Way Home",
"year": "2021",
"genre": ["Action", "Adventure", "Fantasy"],
"director": "Jon Watts",
"cast": ["Tom Holland", "Zendaya", "Benedict Cumberbatch"],
"runtime": "148 min",
"rating": "8.4",
"plot": "With Spider-Man's identity now revealed, Peter asks Doctor Strange for help. When a spell goes wrong, dangerous foes from other worlds start to appear, forcing Peter to discover what it truly means to be Spider-Man.",
"poster": "https://image.tmdb.org/t/p/w500/1g0dhYtq4irTY1GPXvft6k4YLjm.jpg",
"backdrop": "https://image.tmdb.org/t/p/original/14QbnygCuTO0vl7CAFmPf1fgZfV.jpg",
"imdbId": "tt10872600",
"tmdbId": "634649"
},
"requestParams": {
"id": "12345",
"timestamp": "1640995200000"
}
}`;
case "Stream Links":
return `{
"success": true,
"data": {
"playlistUrl": "https://net51.cc/playlist.php?id=12345&tm=1640995200000&h=abc123def456",
"streamData": {
"sources": [
{
"file": "https://net51.cc/hls/12345/1080p/playlist.m3u8",
"label": "1080p",
"type": "hls"
},
{
"file": "https://net51.cc/hls/12345/720p/playlist.m3u8",
"label": "720p",
"type": "hls"
},
{
"file": "https://net51.cc/hls/12345/480p/playlist.m3u8",
"label": "480p",
"type": "hls"
}
],
"tracks": [
{
"file": "https://net51.cc/subtitles/12345/english.vtt",
"label": "English",
"kind": "captions"
},
{
"file": "https://net51.cc/subtitles/12345/spanish.vtt",
"label": "Spanish",
"kind": "captions"
}
],
"image": "https://image.tmdb.org/t/p/w500/1g0dhYtq4irTY1GPXvft6k4YLjm.jpg"
},
"requestParams": {
"id": "12345",
"timestamp": "1640995200000",
"h": "abc123def456"
}
}
}`;
default:
return "{}";
}
};
return (
<Tabs defaultValue="test" className="space-y-4 sm:space-y-6">
<TabsList className="grid w-full grid-cols-2">
<TabsTrigger value="test" className="flex items-center gap-1 sm:gap-2 text-xs sm:text-sm">
<Play className="h-3 w-3 sm:h-4 sm:w-4" />
<span className="hidden xs:inline">API Testing</span>
<span className="xs:hidden">Testing</span>
</TabsTrigger>
<TabsTrigger value="docs" className="flex items-center gap-1 sm:gap-2 text-xs sm:text-sm">
<Code2 className="h-3 w-3 sm:h-4 sm:w-4" />
<span className="hidden xs:inline">Code Examples</span>
<span className="xs:hidden">Examples</span>
</TabsTrigger>
</TabsList>
<TabsContent value="test" className="space-y-4 sm:space-y-6">
<Card>
<CardHeader className="pb-4 sm:pb-6">
<CardTitle className="text-lg sm:text-xl flex items-center gap-2">
<Video className="h-5 w-5 text-blue-500" />
NetMirror API Testing
</CardTitle>
<CardDescription className="text-sm">
Enter your API key to test the NetMirror endpoints. Get your API key from the{" "}
<a href="/dashboard/api-keys" className="text-primary hover:underline">
API Keys page
</a>
.
</CardDescription>
</CardHeader>
<CardContent>
<div className="flex flex-col sm:flex-row gap-2">
<Input
type="password"
placeholder="Enter your API key"
value={apiKey}
onChange={(e) => onApiKeyChange(e.target.value)}
className="flex-1 text-sm min-w-0"
/>
<Button variant="outline" size="icon" onClick={() => copyToClipboard(apiKey)} className="shrink-0 self-start sm:self-auto">
<Copy className="h-4 w-4" />
</Button>
</div>
</CardContent>
</Card>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4 sm:gap-6">
<Card>
<CardHeader className="pb-4 sm:pb-6">
<CardTitle className="text-lg sm:text-xl">API Categories</CardTitle>
<CardDescription className="text-sm">Select a category and endpoint to test</CardDescription>
</CardHeader>
<CardContent className="space-y-3 sm:space-y-4">
<div className="space-y-2">
<Label className="text-sm">Category</Label>
<Select value={selectedCategory.name} onValueChange={handleCategoryChange}>
<SelectTrigger className="text-sm w-full">
<SelectValue />
</SelectTrigger>
<SelectContent>
{netMirrorApiCategories.map((category) => (
<SelectItem key={category.name} value={category.name} className="text-sm">
<div className="flex items-center gap-2">
{category.icon}
<span className="truncate">{category.name}</span>
</div>
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label className="text-sm">Endpoint</Label>
<Select value={selectedEndpoint.endpoint} onValueChange={handleEndpointChange}>
<SelectTrigger className="text-sm w-full">
<SelectValue />
</SelectTrigger>
<SelectContent>
{selectedCategory.endpoints.map((endpoint) => (
<SelectItem key={endpoint.endpoint} value={endpoint.endpoint} className="text-sm">
<div className="space-y-1 min-w-0 flex-1">
<div className="flex items-center gap-2">
<Badge variant={endpoint.method === "GET" ? "default" : "secondary"} className="text-xs shrink-0">
{endpoint.method}
</Badge>
<code className="text-xs truncate min-w-0">{endpoint.endpoint}</code>
</div>
</div>
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="p-3 bg-muted rounded-lg">
<p className="text-xs sm:text-sm text-muted-foreground break-words">{selectedEndpoint.description}</p>
</div>
</CardContent>
</Card>
<Card>
<CardHeader className="pb-4 sm:pb-6">
<CardTitle className="text-lg sm:text-xl">Parameters</CardTitle>
<CardDescription className="text-sm">
Configure parameters for <code className="text-xs break-all">{selectedEndpoint.endpoint}</code>
</CardDescription>
</CardHeader>
<CardContent className="space-y-3 sm:space-y-4">
{selectedEndpoint.params && selectedEndpoint.params.length > 0 ? (
selectedEndpoint.params.map((param) => (
<div key={param.name} className="space-y-2">
<Label htmlFor={param.name} className="flex flex-wrap items-center gap-2 text-sm">
<span className="break-words">{param.name}</span>
<Badge variant={param.required ? "destructive" : "secondary"} className="text-xs shrink-0">
{param.required ? "Required" : "Optional"}
</Badge>
<span className="text-xs text-muted-foreground shrink-0">({param.type})</span>
</Label>
<Input
id={param.name}
placeholder={param.description}
value={testParams[param.name] || ""}
onChange={(e) => setTestParams({ ...testParams, [param.name]: e.target.value })}
className="text-sm w-full min-w-0"
/>
</div>
))
) : (
<p className="text-sm text-muted-foreground">No parameters required</p>
)}
<Button onClick={testApi} disabled={loading} className="w-full text-sm">
{loading ? "Testing..." : "Test API"}
</Button>
</CardContent>
</Card>
</div>
{response && (
<Card>
<CardHeader className="pb-4 sm:pb-6">
<CardTitle className="text-lg sm:text-xl">Response</CardTitle>
<CardDescription className="text-sm">API response from NetMirror</CardDescription>
</CardHeader>
<CardContent>
<ColorizedJSON data={response} title="NetMirror Response" />
</CardContent>
</Card>
)}
</TabsContent>
<TabsContent value="docs" className="space-y-4 sm:space-y-6">
<Card>
<CardHeader className="pb-4 sm:pb-6">
<CardTitle className="text-lg sm:text-xl flex items-center gap-2">
<Video className="h-5 w-5 text-blue-500" />
NetMirror API Examples
</CardTitle>
<CardDescription className="text-sm">
Code examples for integrating with the NetMirror API
</CardDescription>
</CardHeader>
<CardContent className="space-y-4 sm:space-y-6">
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 sm:gap-4">
<div className="space-y-2 min-w-0">
<Label className="text-sm">Category</Label>
<Select value={selectedCategory.name} onValueChange={handleCategoryChange}>
<SelectTrigger className="text-sm w-full">
<SelectValue />
</SelectTrigger>
<SelectContent>
{netMirrorApiCategories.map((category) => (
<SelectItem key={category.name} value={category.name} className="text-sm">
<div className="flex items-center gap-2">
{category.icon}
<span className="truncate">{category.name}</span>
</div>
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="space-y-2 min-w-0">
<Label className="text-sm">Endpoint</Label>
<Select value={selectedEndpoint.endpoint} onValueChange={handleEndpointChange}>
<SelectTrigger className="text-sm w-full">
<SelectValue />
</SelectTrigger>
<SelectContent>
{selectedCategory.endpoints.map((endpoint) => (
<SelectItem key={endpoint.endpoint} value={endpoint.endpoint} className="text-sm">
<div className="flex items-center gap-2 min-w-0">
<Badge variant={endpoint.method === "GET" ? "default" : "secondary"} className="text-xs shrink-0">
{endpoint.method}
</Badge>
<code className="text-xs truncate min-w-0">{endpoint.endpoint}</code>
</div>
</SelectItem>
))}
</SelectContent>
</Select>
</div>
</div>
<Tabs defaultValue="javascript" className="space-y-4">
<TabsList className="grid w-full grid-cols-3">
<TabsTrigger value="javascript" className="text-xs sm:text-sm">JavaScript</TabsTrigger>
<TabsTrigger value="python" className="text-xs sm:text-sm">Python</TabsTrigger>
<TabsTrigger value="curl" className="text-xs sm:text-sm">cURL</TabsTrigger>
</TabsList>
<TabsContent value="javascript">
<div className="bg-[#1e1e1e] rounded-lg overflow-hidden border border-gray-800">
<div className="flex items-center justify-between bg-[#2d2d30] px-4 py-2 border-b border-gray-700">
<div className="flex items-center gap-2 min-w-0">
<div className="flex gap-1.5 shrink-0">
<div className="w-3 h-3 rounded-full bg-[#ff5f56]"></div>
<div className="w-3 h-3 rounded-full bg-[#ffbd2e]"></div>
<div className="w-3 h-3 rounded-full bg-[#27ca3f]"></div>
</div>
<span className="text-gray-300 text-sm ml-2 truncate">netmirror.js</span>
</div>
<Button
size="sm"
variant="ghost"
className="text-gray-400 hover:text-white hover:bg-gray-700 h-6 px-2 shrink-0"
onClick={() => copyToClipboard(generateCodeExample("javascript"))}
>
<Copy className="h-3 w-3" />
</Button>
</div>
<div className="overflow-x-auto">
<pre className="p-4">
<code className="text-sm text-gray-300 font-mono whitespace-pre-wrap break-words">
{generateCodeExample("javascript")}
</code>
</pre>
</div>
</div>
</TabsContent>
<TabsContent value="python">
<div className="bg-[#1e1e1e] rounded-lg overflow-hidden border border-gray-800">
<div className="flex items-center justify-between bg-[#2d2d30] px-4 py-2 border-b border-gray-700">
<div className="flex items-center gap-2 min-w-0">
<div className="flex gap-1.5 shrink-0">
<div className="w-3 h-3 rounded-full bg-[#ff5f56]"></div>
<div className="w-3 h-3 rounded-full bg-[#ffbd2e]"></div>
<div className="w-3 h-3 rounded-full bg-[#27ca3f]"></div>
</div>
<span className="text-gray-300 text-sm ml-2 truncate">netmirror.py</span>
</div>
<Button
size="sm"
variant="ghost"
className="text-gray-400 hover:text-white hover:bg-gray-700 h-6 px-2 shrink-0"
onClick={() => copyToClipboard(generateCodeExample("python"))}
>
<Copy className="h-3 w-3" />
</Button>
</div>
<div className="overflow-x-auto">
<pre className="p-4">
<code className="text-sm text-gray-300 font-mono whitespace-pre-wrap break-words">
{generateCodeExample("python")}
</code>
</pre>
</div>
</div>
</TabsContent>
<TabsContent value="curl">
<div className="bg-[#1e1e1e] rounded-lg overflow-hidden border border-gray-800">
<div className="flex items-center justify-between bg-[#2d2d30] px-4 py-2 border-b border-gray-700">
<div className="flex items-center gap-2 min-w-0">
<div className="flex gap-1.5 shrink-0">
<div className="w-3 h-3 rounded-full bg-[#ff5f56]"></div>
<div className="w-3 h-3 rounded-full bg-[#ffbd2e]"></div>
<div className="w-3 h-3 rounded-full bg-[#27ca3f]"></div>
</div>
<span className="text-gray-300 text-sm ml-2 truncate">terminal</span>
</div>
<Button
size="sm"
variant="ghost"
className="text-gray-400 hover:text-white hover:bg-gray-700 h-6 px-2 shrink-0"
onClick={() => copyToClipboard(generateCodeExample("curl"))}
>
<Copy className="h-3 w-3" />
</Button>
</div>
<div className="overflow-x-auto">
<pre className="p-4">
<code className="text-sm text-gray-300 font-mono whitespace-pre-wrap break-words">
{generateCodeExample("curl")}
</code>
</pre>
</div>
</div>
</TabsContent>
</Tabs>
</CardContent>
</Card>
<Card>
<CardHeader className="pb-4 sm:pb-6">
<CardTitle className="text-lg sm:text-xl">Response Examples</CardTitle>
<CardDescription className="text-sm">Expected response structures for NetMirror endpoints</CardDescription>
</CardHeader>
<CardContent>
<Tabs defaultValue="movies" className="space-y-4">
<TabsList className="grid w-full grid-cols-4">
<TabsTrigger value="movies" className="text-xs sm:text-sm">Movies</TabsTrigger>
<TabsTrigger value="search" className="text-xs sm:text-sm">Search</TabsTrigger>
<TabsTrigger value="details" className="text-xs sm:text-sm">Details</TabsTrigger>
<TabsTrigger value="stream" className="text-xs sm:text-sm">Stream</TabsTrigger>
</TabsList>
<TabsContent value="movies">
<ColorizedJSON data={getResponseExample("Get Movies")} title="Movies Response" />
</TabsContent>
<TabsContent value="search">
<ColorizedJSON data={getResponseExample("Search Movies")} title="Search Response" />
</TabsContent>
<TabsContent value="details">
<ColorizedJSON data={getResponseExample("Movie Details")} title="Details Response" />
</TabsContent>
<TabsContent value="stream">
<ColorizedJSON data={getResponseExample("Stream Links")} title="Stream Response" />
</TabsContent>
</Tabs>
</CardContent>
</Card>
<Card>
<CardHeader className="pb-4 sm:pb-6">
<CardTitle className="text-lg sm:text-xl">NetMirror API Workflow</CardTitle>
<CardDescription className="text-sm">How to get streaming links for movies and shows</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="p-3 sm:p-4 bg-muted rounded-lg">
<h4 className="font-semibold mb-2 text-sm sm:text-base">Step-by-Step Process</h4>
<ol className="text-xs sm:text-sm space-y-2">
<li><strong>1. Get Movies:</strong> Use <code>/api/netmirror</code> to get all available movies and shows</li>
<li><strong>2. Search (Optional):</strong> Use <code>/api/netmirror/search?p=query</code> to search for specific content</li>
<li><strong>3. Get Details:</strong> Use <code>/api/netmirror/getpost?id=movie_id</code> to get detailed movie information</li>
<li><strong>4. Get Stream Links:</strong> Use <code>/api/netmirror/stream?id=movie_id</code> to get streaming URLs</li>
</ol>
<div className="mt-3 p-2 sm:p-3 bg-blue-100 dark:bg-blue-900/20 rounded-md">
<p className="text-xs text-blue-800 dark:text-blue-200">
<strong>Movie ID:</strong> Extract the movie ID from the data-post attribute or URL structure from the movies listing.
</p>
</div>
<div className="mt-3 p-2 sm:p-3 bg-green-100 dark:bg-green-900/20 rounded-md">
<p className="text-xs text-green-800 dark:text-green-200">
<strong>NetMirror Features:</strong> High-quality streaming, multiple resolutions (480p, 720p, 1080p), subtitles support, and direct HLS streaming.
</p>
</div>
</div>
</CardContent>
</Card>
</TabsContent>
</Tabs>
);
}