Feat: Update to VideoPage to display stream data;
This commit is contained in:
@@ -7,7 +7,7 @@
|
|||||||
<title>Team Software Project</title>
|
<title>Team Software Project</title>
|
||||||
</head>
|
</head>
|
||||||
<body class="h-screen">
|
<body class="h-screen">
|
||||||
<div id="root" class="bg-gradient-to-tr from-[#07001F] via-[#1D0085] to-[#CC00AF]"></div>
|
<div id="root" class="h-full bg-gradient-to-tr from-[#07001F] via-[#1D0085] to-[#CC00AF]"></div>
|
||||||
<script type="module" src="/src/main.tsx"></script>
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
// base.html
|
|
||||||
// src/components/Layout/BaseLayout.tsx
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
interface BaseLayoutProps {
|
|
||||||
children: React.ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
const BaseLayout: React.FC<BaseLayoutProps> = ({ children }) => {
|
|
||||||
return (
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charSet="UTF-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<title>Live Stream</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
{children}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default BaseLayout;
|
|
||||||
87
frontend/src/components/Layout/ListRow.tsx
Normal file
87
frontend/src/components/Layout/ListRow.tsx
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
interface ListItemProps {
|
||||||
|
type: "stream" | "category";
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
streamer?: string;
|
||||||
|
viewers: number;
|
||||||
|
thumbnail?: string;
|
||||||
|
onItemClick?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ListRowProps {
|
||||||
|
type: "stream" | "category";
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
items: ListItemProps[];
|
||||||
|
onClick: (itemId: number, itemName: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Individual list entry component
|
||||||
|
const ListItem: React.FC<ListItemProps> = ({
|
||||||
|
type,
|
||||||
|
title,
|
||||||
|
streamer,
|
||||||
|
viewers,
|
||||||
|
thumbnail,
|
||||||
|
onItemClick,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="flex flex-col bg-gray-800 rounded-lg overflow-hidden cursor-pointer hover:bg-gray-700 transition-colors"
|
||||||
|
onClick={onItemClick}
|
||||||
|
>
|
||||||
|
<div className="relative w-full pt-[56.25%]">
|
||||||
|
{thumbnail ? (
|
||||||
|
<img
|
||||||
|
src={`images/` + thumbnail}
|
||||||
|
alt={title}
|
||||||
|
className="absolute top-0 left-0 w-full h-full object-cover"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className="absolute top-0 left-0 w-full h-full bg-gray-600" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="p-3">
|
||||||
|
<h3 className="font-semibold text-lg">{title}</h3>
|
||||||
|
{type === "stream" && <p className="text-gray-400">{streamer}</p>}
|
||||||
|
<p className="text-sm text-gray-500">{viewers} viewers</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Row of entries
|
||||||
|
const ListRow: React.FC<ListRowProps> = ({
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
items,
|
||||||
|
onClick,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col space-y-4 py-6">
|
||||||
|
<div className="space-y-1">
|
||||||
|
<h2 className="text-2xl font-bold">{title}</h2>
|
||||||
|
<p className="text-gray-400">{description}</p>
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
|
||||||
|
{items.map((item) => (
|
||||||
|
<ListItem
|
||||||
|
key={item.id}
|
||||||
|
id={item.id}
|
||||||
|
type={item.type}
|
||||||
|
title={item.title}
|
||||||
|
streamer={item.type === "stream" ? (item.streamer) : undefined}
|
||||||
|
viewers={item.viewers}
|
||||||
|
onItemClick={() =>
|
||||||
|
onClick?.(item.id, item.streamer || item.title)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ListRow;
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
|
|
||||||
interface StreamItem {
|
|
||||||
id: number;
|
|
||||||
title: string;
|
|
||||||
streamer: string;
|
|
||||||
viewers: number;
|
|
||||||
thumbnail?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface StreamListEntryProps {
|
|
||||||
stream: StreamItem;
|
|
||||||
onClick?: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface StreamListRowProps {
|
|
||||||
title: string;
|
|
||||||
description: string;
|
|
||||||
streams: StreamItem[];
|
|
||||||
onStreamClick: (streamId: number, streamerName: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Individual stream entry component
|
|
||||||
const StreamListEntry: React.FC<StreamListEntryProps> = ({
|
|
||||||
stream,
|
|
||||||
onClick,
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className="flex flex-col bg-gray-800 rounded-lg overflow-hidden cursor-pointer hover:bg-gray-700 transition-colors"
|
|
||||||
onClick={onClick}
|
|
||||||
>
|
|
||||||
<div className="relative w-full pt-[56.25%]">
|
|
||||||
{stream.thumbnail ? (
|
|
||||||
<img
|
|
||||||
src={`images/` + stream.thumbnail}
|
|
||||||
alt={stream.title}
|
|
||||||
className="absolute top-0 left-0 w-full h-full object-cover"
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<div className="absolute top-0 left-0 w-full h-full bg-gray-600" />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="p-3">
|
|
||||||
<h3 className="font-semibold text-lg">{stream.title}</h3>
|
|
||||||
<p className="text-gray-400">{stream.streamer}</p>
|
|
||||||
<p className="text-sm text-gray-500">{stream.viewers} viewers</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Row of stream entries
|
|
||||||
const StreamListRow: React.FC<StreamListRowProps> = ({
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
streams,
|
|
||||||
onStreamClick,
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<div className="flex flex-col space-y-4 py-6">
|
|
||||||
<div className="space-y-1">
|
|
||||||
<h2 className="text-2xl font-bold">{title}</h2>
|
|
||||||
<p className="text-gray-400">{description}</p>
|
|
||||||
</div>
|
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
|
|
||||||
{streams.map((stream) => (
|
|
||||||
<StreamListEntry
|
|
||||||
key={stream.id}
|
|
||||||
stream={stream}
|
|
||||||
onClick={() => onStreamClick?.(stream.id, stream.streamer)}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default StreamListRow;
|
|
||||||
@@ -26,7 +26,7 @@ const StreamerRoute: React.FC = () => {
|
|||||||
checkStreamStatus();
|
checkStreamStatus();
|
||||||
|
|
||||||
// Poll for live status changes
|
// Poll for live status changes
|
||||||
const interval = setInterval(checkStreamStatus, 30000); // Check every 90 seconds
|
const interval = setInterval(checkStreamStatus, 20000); // Check every 20 seconds
|
||||||
|
|
||||||
return () => clearInterval(interval);
|
return () => clearInterval(interval);
|
||||||
}, [streamerName]);
|
}, [streamerName]);
|
||||||
@@ -35,7 +35,8 @@ const StreamerRoute: React.FC = () => {
|
|||||||
return <div className="h-screen w-screen flex text-6xl items-center justify-center" >Loading...</div>; // Or your loading component
|
return <div className="h-screen w-screen flex text-6xl items-center justify-center" >Loading...</div>; // Or your loading component
|
||||||
}
|
}
|
||||||
|
|
||||||
return isLive ? <VideoPage streamId={1} /> : <UserPage />;
|
// streamId=0 is a special case for the streamer's latest stream
|
||||||
|
return isLive ? <VideoPage streamId={0} /> : <UserPage profile={streamerName} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default StreamerRoute;
|
export default StreamerRoute;
|
||||||
|
|||||||
@@ -1,26 +1,34 @@
|
|||||||
import { createContext, useContext, useState, useEffect } from "react";
|
import { createContext, useContext, useState, useEffect } from "react";
|
||||||
import { useAuth } from "./AuthContext";
|
import { useAuth } from "./AuthContext";
|
||||||
|
|
||||||
interface StreamItem {
|
interface Item {
|
||||||
id: number;
|
id: number;
|
||||||
title: string;
|
title: string;
|
||||||
streamer: string;
|
|
||||||
viewers: number;
|
viewers: number;
|
||||||
thumbnail?: string;
|
thumbnail?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface StreamItem extends Item {
|
||||||
|
type: "stream";
|
||||||
|
streamer: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CategoryItem extends Item {
|
||||||
|
type: "category";
|
||||||
|
}
|
||||||
|
|
||||||
interface StreamsContextType {
|
interface StreamsContextType {
|
||||||
featuredStreams: StreamItem[];
|
featuredStreams: StreamItem[];
|
||||||
featuredCategories: StreamItem[];
|
featuredCategories: CategoryItem[];
|
||||||
setFeaturedStreams: (streams: StreamItem[]) => void;
|
setFeaturedStreams: (streams: StreamItem[]) => void;
|
||||||
setFeaturedCategories: (categories: StreamItem[]) => void;
|
setFeaturedCategories: (categories: CategoryItem[]) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StreamsContext = createContext<StreamsContextType | undefined>(undefined);
|
const StreamsContext = createContext<StreamsContextType | undefined>(undefined);
|
||||||
|
|
||||||
export function StreamsProvider({ children }: { children: React.ReactNode }) {
|
export function StreamsProvider({ children }: { children: React.ReactNode }) {
|
||||||
const [featuredStreams, setFeaturedStreams] = useState<StreamItem[]>([]);
|
const [featuredStreams, setFeaturedStreams] = useState<StreamItem[]>([]);
|
||||||
const [featuredCategories, setFeaturedCategories] = useState<StreamItem[]>(
|
const [featuredCategories, setFeaturedCategories] = useState<CategoryItem[]>(
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
const { isLoggedIn } = useAuth();
|
const { isLoggedIn } = useAuth();
|
||||||
@@ -30,15 +38,34 @@ export function StreamsProvider({ children }: { children: React.ReactNode }) {
|
|||||||
: ["/api/get_streams", "/api/get_categories"];
|
: ["/api/get_streams", "/api/get_categories"];
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
// Streams
|
||||||
fetch(fetch_url[0])
|
fetch(fetch_url[0])
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
.then((data: StreamItem[]) => {
|
.then((data) => {
|
||||||
setFeaturedStreams(data);
|
const extractedData: StreamItem[] = data.streams.map((stream: any) => ({
|
||||||
|
type: "stream",
|
||||||
|
id: stream.stream_id,
|
||||||
|
title: stream.title,
|
||||||
|
streamer: stream.user_id,
|
||||||
|
viewers: stream.num_viewers,
|
||||||
|
thumbnail: stream.thumbnail,
|
||||||
|
}));
|
||||||
|
setFeaturedStreams(extractedData);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Categories
|
||||||
fetch(fetch_url[1])
|
fetch(fetch_url[1])
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
.then((data: StreamItem[]) => {
|
.then((data) => {
|
||||||
setFeaturedCategories(data);
|
const extractedData: CategoryItem[] = data.categories.map(
|
||||||
|
(category: any) => ({
|
||||||
|
type: "category",
|
||||||
|
id: category.category_id,
|
||||||
|
title: category.category_name,
|
||||||
|
viewers: category.num_viewers,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
setFeaturedCategories(extractedData);
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Navbar from "../components/Layout/Navbar";
|
import Navbar from "../components/Layout/Navbar";
|
||||||
import StreamListRow from "../components/Layout/StreamListRow";
|
import ListRow from "../components/Layout/ListRow";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { useStreams } from "../context/StreamsContext";
|
import { useStreams } from "../context/StreamsContext";
|
||||||
|
|
||||||
@@ -20,24 +20,24 @@ const HomePage: React.FC<HomePageProps> = ({ variant = "default" }) => {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
id="home-page"
|
id="home-page"
|
||||||
className="animate-moving_bg"
|
className="animate-moving_bg h-full"
|
||||||
style={{ backgroundImage: "url(/images/background-pattern.svg)" }}
|
style={{ backgroundImage: "url(/images/background-pattern.svg)" }}
|
||||||
>
|
>
|
||||||
<Navbar variant="home" />
|
<Navbar variant="home" />
|
||||||
|
|
||||||
{/*//TODO Extract StreamListRow away, to ListRow so that it makes sense for categories to be there also */}
|
<ListRow
|
||||||
|
type="stream"
|
||||||
<StreamListRow
|
|
||||||
title={"Live Now" + (variant === "personalised" ? " - Recommended" : "")}
|
title={"Live Now" + (variant === "personalised" ? " - Recommended" : "")}
|
||||||
description={variant === "personalised" ? "We think you might like these streams - Streamers recommended for you" : "Streamers that are currently live"}
|
description={variant === "personalised" ? "We think you might like these streams - Streamers recommended for you" : "Streamers that are currently live"}
|
||||||
streams={featuredStreams}
|
items={featuredStreams}
|
||||||
onStreamClick={handleStreamClick}
|
onClick={handleStreamClick}
|
||||||
/>
|
/>
|
||||||
<StreamListRow
|
<ListRow
|
||||||
|
type="category"
|
||||||
title={variant === "personalised" ? "Followed Categories" : "Trending Categories"}
|
title={variant === "personalised" ? "Followed Categories" : "Trending Categories"}
|
||||||
description={variant === "personalised" ? "Current streams from your followed categories" : "Categories that have been 'popping off' lately"}
|
description={variant === "personalised" ? "Current streams from your followed categories" : "Categories that have been 'popping off' lately"}
|
||||||
streams={featuredCategories}
|
items={featuredCategories}
|
||||||
onStreamClick={() => {}} //TODO
|
onClick={() => {}} //TODO
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,16 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
const UserPage: React.FC = () => {
|
interface UserPageProps {
|
||||||
return <div></div>;
|
username: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UserPage: React.FC<UserPageProps> = ({ username }) => {
|
||||||
|
return (
|
||||||
|
<div className="bg-[#808080] h-screen w-screen flex flex-col items-center justify-center">
|
||||||
|
<h1>{username}</h1>
|
||||||
|
<p>Profile page for {username}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default UserPage;
|
export default UserPage;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import Navbar from "../components/Layout/Navbar";
|
|||||||
import Button from "../components/Layout/Button";
|
import Button from "../components/Layout/Button";
|
||||||
import ChatPanel from "../components/Video/ChatPanel";
|
import ChatPanel from "../components/Video/ChatPanel";
|
||||||
import CheckoutForm, { Return } from "../components/Checkout/CheckoutForm";
|
import CheckoutForm, { Return } from "../components/Checkout/CheckoutForm";
|
||||||
import { useParams } from "react-router-dom";
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
import { useAuth } from "../context/AuthContext";
|
import { useAuth } from "../context/AuthContext";
|
||||||
import VideoPlayer from "../components/Video/VideoPlayer";
|
import VideoPlayer from "../components/Video/VideoPlayer";
|
||||||
|
|
||||||
@@ -11,11 +11,23 @@ interface VideoPageProps {
|
|||||||
streamId: number;
|
streamId: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface StreamDataProps {
|
||||||
|
streamId: number;
|
||||||
|
streamTitle: string;
|
||||||
|
streamerName: string;
|
||||||
|
streamerId: number;
|
||||||
|
startTime: string;
|
||||||
|
viewerCount: number;
|
||||||
|
categoryId: number;
|
||||||
|
}
|
||||||
|
|
||||||
const VideoPage: React.FC<VideoPageProps> = ({ streamId }) => {
|
const VideoPage: React.FC<VideoPageProps> = ({ streamId }) => {
|
||||||
|
const { isLoggedIn } = useAuth();
|
||||||
const [showCheckout, setShowCheckout] = useState(false);
|
const [showCheckout, setShowCheckout] = useState(false);
|
||||||
const showReturn = window.location.search.includes("session_id");
|
const showReturn = window.location.search.includes("session_id");
|
||||||
const { streamerName } = useParams<{ streamerName: string }>();
|
const { streamerName } = useParams<{ streamerName: string }>();
|
||||||
const { isLoggedIn } = useAuth();
|
const [streamData, setStreamData] = useState<StreamDataProps>();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Prevent scrolling when checkout is open
|
// Prevent scrolling when checkout is open
|
||||||
@@ -30,12 +42,30 @@ const VideoPage: React.FC<VideoPageProps> = ({ streamId }) => {
|
|||||||
};
|
};
|
||||||
}, [showCheckout]);
|
}, [showCheckout]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (streamerName) {
|
|
||||||
// Fetch stream data for this streamer
|
// Fetch stream data for this streamer
|
||||||
console.log(`Loading stream for ${streamerName}`);
|
fetch(
|
||||||
// fetch(`/api/get_stream_data/${streamId}`)
|
`/api/get_stream_data/${streamerName}${
|
||||||
|
streamId == 0 ? "" : `/${streamId}`
|
||||||
|
}`
|
||||||
|
).then((res) => {
|
||||||
|
if (!res.ok) {
|
||||||
|
console.error("Failed to load stream data:", res.statusText);
|
||||||
}
|
}
|
||||||
}, [streamerName]);
|
res.json().then((data) => {
|
||||||
|
if (!data.validStream) navigate(`/`);
|
||||||
|
console.log(`Loading stream data for ${streamerName}`);
|
||||||
|
setStreamData({
|
||||||
|
streamId: data.streamId,
|
||||||
|
streamTitle: data.streamTitle,
|
||||||
|
streamerName: data.streamerName,
|
||||||
|
streamerId: data.streamerId,
|
||||||
|
startTime: data.startTime,
|
||||||
|
viewerCount: data.viewerCount,
|
||||||
|
categoryId: data.categoryId,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, [streamId, streamerName]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="videoPage" className="w-full">
|
<div id="videoPage" className="w-full">
|
||||||
@@ -44,20 +74,21 @@ const VideoPage: React.FC<VideoPageProps> = ({ streamId }) => {
|
|||||||
<div id="container" className="bg-gray-900">
|
<div id="container" className="bg-gray-900">
|
||||||
<VideoPlayer streamId={streamId} />
|
<VideoPlayer streamId={streamId} />
|
||||||
|
|
||||||
{isLoggedIn ? (
|
|
||||||
<ChatPanel streamId={streamId} />
|
<ChatPanel streamId={streamId} />
|
||||||
) : (
|
|
||||||
<ChatPanel streamId={streamId} />
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
id="stream-info"
|
id="stream-info"
|
||||||
className="flex"
|
className="flex"
|
||||||
style={{ gridArea: "3 / 1 / 4 / 2" }}
|
style={{ gridArea: "3 / 1 / 4 / 2" }}
|
||||||
>
|
>
|
||||||
<Button onClick={() => setShowCheckout(true)} extraClasses="mx-auto mb-4">
|
{isLoggedIn && (
|
||||||
|
<Button
|
||||||
|
onClick={() => setShowCheckout(true)}
|
||||||
|
extraClasses="mx-auto mb-4"
|
||||||
|
>
|
||||||
Payment Screen Test
|
Payment Screen Test
|
||||||
</Button>
|
</Button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,8 @@ def get_recommended_categories() -> list | list[dict]:
|
|||||||
|
|
||||||
return jsonify({'categories': categories})
|
return jsonify({'categories': categories})
|
||||||
|
|
||||||
@stream_bp.route('/get_streamer_data/<int:streamer_username>')
|
|
||||||
|
@stream_bp.route('/get_streamer_data/<string:streamer_username>')
|
||||||
def get_streamer_data(streamer_username):
|
def get_streamer_data(streamer_username):
|
||||||
"""
|
"""
|
||||||
Returns a given streamer's data
|
Returns a given streamer's data
|
||||||
@@ -98,7 +99,7 @@ def get_streamer_status(streamer_username):
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@stream_bp.route('/get_stream_data/<string:streamer_username>', methods=['GET'])
|
@stream_bp.route('/get_stream_data/<string:streamer_username>')
|
||||||
def get_stream(streamer_username):
|
def get_stream(streamer_username):
|
||||||
"""
|
"""
|
||||||
Returns a streamer's most recent stream data
|
Returns a streamer's most recent stream data
|
||||||
@@ -119,7 +120,7 @@ def get_following_categories_streams():
|
|||||||
return jsonify(streams)
|
return jsonify(streams)
|
||||||
|
|
||||||
|
|
||||||
@stream_bp.route('/get_stream_data/<string:streamer_username>/<int:stream_id>', methods=['GET'])
|
@stream_bp.route('/get_stream_data/<string:streamer_username>/<int:stream_id>')
|
||||||
def get_specific_stream(streamer_username, stream_id):
|
def get_specific_stream(streamer_username, stream_id):
|
||||||
"""
|
"""
|
||||||
Returns a streamer's stream data given stream_id
|
Returns a streamer's stream data given stream_id
|
||||||
@@ -132,7 +133,7 @@ def get_specific_stream(streamer_username, stream_id):
|
|||||||
abort(404)
|
abort(404)
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@stream_bp.route('/get_followed_streamers', methods=['GET'])
|
@stream_bp.route('/get_followed_streamers')
|
||||||
def get_followed_streamers():
|
def get_followed_streamers():
|
||||||
"""
|
"""
|
||||||
Queries DB to get a list of followed streamers
|
Queries DB to get a list of followed streamers
|
||||||
|
|||||||
@@ -46,12 +46,19 @@ INSERT INTO subscribes (user_id, subscribed_id, since, expires) VALUES
|
|||||||
(4, 104, '2024-09-12', '2025-01-12'),
|
(4, 104, '2024-09-12', '2025-01-12'),
|
||||||
(5, 105, '2024-08-30', '2025-02-28');
|
(5, 105, '2024-08-30', '2025-02-28');
|
||||||
|
|
||||||
|
INSERT INTO users (username, password, email, num_followers, stream_key, is_partnered, bio) VALUES
|
||||||
|
('GamerDude2', 'password123', 'gamerdude3@gmail.com', 3200, '7890', 0, 'Streaming my gaming adventures!');
|
||||||
|
|
||||||
SELECT * FROM users;
|
SELECT * FROM users;
|
||||||
SELECT * FROM streams;
|
|
||||||
SELECT * FROM follows;
|
SELECT * FROM follows;
|
||||||
SELECT * FROM user_preferences;
|
SELECT * FROM user_preferences;
|
||||||
SELECT * FROM subscribes;
|
SELECT * FROM subscribes;
|
||||||
SELECT * FROM categories;
|
SELECT * FROM categories;
|
||||||
|
SELECT * FROM streams;
|
||||||
|
SELECT * FROM chat;
|
||||||
|
SELECT * FROM tags;
|
||||||
|
SELECT * FROM stream_tags;
|
||||||
|
|
||||||
|
-- To see all tables in the database
|
||||||
|
SELECT name FROM sqlite_master WHERE type='table';
|
||||||
|
|
||||||
INSERT INTO users (username, password, email, num_followers, stream_key, is_partnered, bio) VALUES
|
|
||||||
('GamerDude2', 'password123', 'gamerdude3@gmail.com', 3200, '7890', 0, 'Streaming my gaming adventures!');
|
|
||||||
|
|||||||
Reference in New Issue
Block a user