Maklai / app.py
Illia56's picture
Update app.py
1afeb4a verified
raw
history blame contribute delete
No virus
8.06 kB
import gradio as gr
import os
import json
import pandas as pd
from googleapiclient.discovery import build
# YouTube class to interact with the YouTube Data API
class YouTube:
def __init__(self, api_key, channel_id):
self.api_key = api_key
self.channel_id = channel_id
self.youtube = build("youtube", "v3", developerKey=api_key)
# Retrieve general channel information
def get_general_channel_info(self):
try:
request = self.youtube.channels().list(part="snippet,statistics", id=self.channel_id)
response = request.execute()
channel_info = response["items"][0]
channel_stats = {
"Subscribers": channel_info["statistics"]["subscriberCount"],
"Views": channel_info["statistics"]["viewCount"],
"Total videos": channel_info["statistics"]["videoCount"],
"Title": channel_info["snippet"]["title"],
"Description": channel_info["snippet"]["description"],
"Cover": channel_info["snippet"]["thumbnails"]["high"]["url"],
"URL": f"https://www.youtube.com/channel/{self.channel_id}",
}
return channel_stats
except Exception as e:
return {"error": str(e)}
# Retrieve video data from the channel's uploads playlist
def get_video_data(self):
try:
channel_response = self.youtube.channels().list(part="contentDetails", id=self.channel_id).execute()
playlist_id = channel_response["items"][0]["contentDetails"]["relatedPlaylists"]["uploads"]
videos = []
next_page_token = None
while True:
playlist_items_response = self.youtube.playlistItems().list(
part="snippet",
maxResults=50,
playlistId=playlist_id,
pageToken=next_page_token,
).execute()
videos.extend(playlist_items_response["items"])
next_page_token = playlist_items_response.get("nextPageToken")
if next_page_token is None:
break
video_data = []
for video in videos:
video_id = video["snippet"]["resourceId"]["videoId"]
video_details = self.youtube.videos().list(part="statistics,snippet", id=video_id).execute()
if video_details["items"]:
video_info = video_details["items"][0]
snippet = video_info["snippet"]
statistics = video_info["statistics"]
video_data.append(
{
"Video": f"https://www.youtube.com/watch?v={video_id}",
"Thumbnail": snippet["thumbnails"]["high"]["url"],
"Title": snippet["title"],
"PublishedAt": snippet["publishedAt"],
"πŸ‘€": statistics.get("viewCount", 0),
"πŸ‘": statistics.get("likeCount", 0),
"πŸ’¬": statistics.get("commentCount", 0)
}
)
df = pd.DataFrame(video_data)
return df
except Exception as e:
return {"error": str(e)}
# Load JSON scheme file
def load_scheme(file_path):
with open(file_path) as f:
return json.load(f)
# Format and display general channel statistics as HTML
def display_channel_statistics(statistics):
if "error" in statistics:
return statistics["error"]
return f"""
<div style='text-align: center;'>
<img src='{statistics["Cover"]}' style='width: 100%; max-width: 300px; height: auto; margin-bottom: 15px;'><br>
<a href='{statistics["URL"]}' style='font-size: 1.5em; font-weight: bold; color: #2c3e50;'>{statistics["Title"]}</a><br>
<div style='font-size: 1.1em; color: #7f8c8d;'>
Subscribers: {statistics["Subscribers"]}<br>
Views: {statistics["Views"]}<br>
Total videos: {statistics["Total videos"]}
</div>
</div>
"""
# Format and display video data as HTML table with enhanced CSS
def display_video_data(video_data):
if "error" in video_data:
return video_data["error"]
video_data['Title'] = video_data['Title'].apply(lambda x: x.split('#')[0])
video_data['PublishedAt'] = pd.to_datetime(video_data['PublishedAt']).dt.date
video_data['Video'] = video_data.apply(
lambda row: f'<a href="{row["Video"]}" target="_blank">{row["Title"]}</a><br>{row["PublishedAt"]}', axis=1
)
video_data['Thumbnail'] = video_data['Thumbnail'].apply(lambda x: f'<img src="{x}" style="width: 100%; max-width: 100px; height: auto; margin: 5px 0;"><br>')
video_data['Video'] = video_data['Thumbnail'] + video_data['Video']
video_data = video_data.drop(['Thumbnail', 'Title', 'PublishedAt'], axis=1)
# Custom CSS for table styling
custom_css = """
<style>
table {
width: 100%;
border-collapse: collapse;
margin: 25px 0;
font-size: 1em;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.05);
border-radius: 10px;
overflow: hidden;
}
th, td {
padding: 15px;
background-color: #ffffff;
color: #333333;
}
th {
background-color: #f8f9fa;
font-weight: bold;
text-align: center;
border-bottom: 2px solid #e9ecef;
}
tr {
border-bottom: 1px solid #e9ecef;
}
tr:nth-of-type(even) {
background-color: #f8f9fa;
}
tr:last-of-type {
border-bottom: none;
}
tr:hover {
background-color: #f1f1f1;
}
</style>
"""
return custom_css + video_data.to_html(escape=False, index=False).replace('text-align: right;', 'text-align: center;')
# Load API key from environment variable
api_key = os.getenv('API_KEY')
scheme = load_scheme("scheme.json")
# Fetch data based on selected category and platform
def fetch_data(selected_category, platform):
channel_id = scheme[selected_category][platform]
if platform == "youtube":
youtube_account = YouTube(api_key, channel_id)
statistics = youtube_account.get_general_channel_info()
statistics_display = display_channel_statistics(statistics)
video_data = youtube_account.get_video_data()
video_data_display = display_video_data(video_data)
return statistics_display, video_data_display
# Define and launch Gradio interface
css = """
<style>
@media (max-width: 600px) {
.fixed-top {
position: fixed;
top: 0;
width: 100%;
z-index: 999;
background: white;
padding: 10px 0;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
body {
padding-top: 70px; /* Adjust based on the height of the fixed element */
}
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #f3f4f6;
color: #333333;
}
.gradio-container {
padding: 20px;
}
.gr-inputs {
display: flex;
justify-content: center;
margin-bottom: 20px;
}
.gr-inputs > div {
margin: 0 10px;
}
.gr-output {
background: white;
border-radius: 10px;
padding: 20px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
</style>
"""
gr_interface = gr.Interface(
fn=fetch_data,
inputs=[
gr.Dropdown(choices=list(scheme.keys()), label="Select Channel", elem_classes=["fixed-top"]),
gr.Dropdown(choices=list(next(iter(scheme.values())).keys()), label="Select Platform", elem_classes=["fixed-top"])
],
outputs=[
gr.HTML(label="General Channel Statistics"),
gr.HTML(label="Video Data")
],
title="Social Media Analytics",
description="Select a channel and platform to fetch analytics data.",
css=css
)
gr_interface.launch()