anycoder-c4feb9c4 / streamlit_app.py
anthonyyha102's picture
Upload streamlit_app.py with huggingface_hub
3486e4b verified
import streamlit as st
import requests
import urllib.parse
# 页面配置
st.set_page_config(
page_title="视频搜索 - 轻松找视频",
page_icon="🎬",
layout="wide"
)
# 自定义CSS - 老年人友好设计
st.markdown("""
<style>
/* 整体字体放大 */
.stApp {
font-size: 20px !important;
}
/* 标题样式 */
h1 {
font-size: 42px !important;
color: #d97706 !important;
text-align: center;
padding: 20px 0;
}
h2 {
font-size: 28px !important;
color: #92400e !important;
}
h3 {
font-size: 24px !important;
color: #b45309 !important;
}
/* 输入框样式 */
.stTextInput > div > div > input {
font-size: 24px !important;
padding: 15px !important;
border-radius: 15px !important;
border: 3px solid #fbbf24 !important;
}
.stTextInput > div > div > input:focus {
border-color: #d97706 !important;
box-shadow: 0 0 10px rgba(217, 119, 6, 0.3) !important;
}
/* 按钮样式 */
.stButton > button {
font-size: 22px !important;
padding: 15px 40px !important;
border-radius: 15px !important;
background-color: #f59e0b !important;
color: white !important;
border: none !important;
min-height: 60px !important;
transition: all 0.3s ease !important;
}
.stButton > button:hover {
background-color: #d97706 !important;
transform: scale(1.02) !important;
}
/* 视频卡片样式 */
.video-card {
background: linear-gradient(135deg, #fffbeb 0%, #fef3c7 100%);
border-radius: 20px;
padding: 20px;
margin: 15px 0;
border: 2px solid #fbbf24;
box-shadow: 0 4px 15px rgba(251, 191, 36, 0.2);
transition: all 0.3s ease;
}
.video-card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 25px rgba(251, 191, 36, 0.3);
}
.video-title {
font-size: 22px !important;
font-weight: bold;
color: #92400e;
margin-bottom: 10px;
line-height: 1.4;
}
.video-channel {
font-size: 18px;
color: #b45309;
margin-bottom: 8px;
}
.video-stats {
font-size: 16px;
color: #78716c;
}
/* 快捷按钮样式 */
.quick-btn {
display: inline-block;
padding: 12px 20px;
margin: 5px;
background-color: #fef3c7;
border: 2px solid #fbbf24;
border-radius: 25px;
font-size: 18px;
cursor: pointer;
transition: all 0.3s ease;
}
.quick-btn:hover {
background-color: #fde68a;
}
/* 提示文字 */
.tip-text {
font-size: 18px;
color: #78716c;
text-align: center;
padding: 20px;
background-color: #fffbeb;
border-radius: 15px;
margin: 20px 0;
}
/* 链接样式 */
a {
color: #d97706 !important;
text-decoration: none !important;
font-weight: bold;
}
a:hover {
color: #b45309 !important;
text-decoration: underline !important;
}
/* 页脚 */
.footer {
text-align: center;
padding: 30px;
color: #78716c;
font-size: 16px;
}
/* 搜索结果数量 */
.result-count {
font-size: 20px;
color: #92400e;
text-align: center;
padding: 15px;
background-color: #fef3c7;
border-radius: 10px;
margin: 20px 0;
}
/* 平台选择器 */
.stSelectbox > div > div {
font-size: 20px !important;
}
/* 分隔线 */
hr {
border: none;
height: 3px;
background: linear-gradient(90deg, #fbbf24, #f59e0b, #fbbf24);
margin: 30px 0;
border-radius: 2px;
}
</style>
""", unsafe_allow_html=True)
# 标题
st.markdown("# 🎬 视频搜索")
st.markdown("<p style='text-align: center; font-size: 22px; color: #78716c;'>输入想看的内容,帮您找到好看的视频!</p>", unsafe_allow_html=True)
st.markdown("<p style='text-align: center; font-size: 14px;'><a href='https://huggingface.co/spaces/akhaliq/anycoder' target='_blank'>Built with anycoder</a></p>", unsafe_allow_html=True)
st.markdown("---")
# 初始化session state
if 'search_query' not in st.session_state:
st.session_state.search_query = ""
if 'search_results' not in st.session_state:
st.session_state.search_results = []
if 'searched' not in st.session_state:
st.session_state.searched = False
# 搜索函数 - 使用Invidious API (YouTube的开源前端)
def search_videos(query, max_results=12):
"""搜索视频"""
if not query or not query.strip():
return []
# 使用多个Invidious实例作为备选
invidious_instances = [
"https://vid.puffyan.us",
"https://invidious.snopyta.org",
"https://yewtu.be",
"https://invidious.kavin.rocks",
]
results = []
for instance in invidious_instances:
try:
# 搜索API
search_url = f"{instance}/api/v1/search"
params = {
"q": query,
"type": "video",
"sort_by": "relevance"
}
response = requests.get(search_url, params=params, timeout=10)
if response.status_code == 200:
data = response.json()
for item in data[:max_results]:
if item.get("type") == "video":
video_id = item.get("videoId", "")
# 格式化观看次数
view_count = item.get("viewCount", 0)
if view_count >= 100000000:
views_str = f"{view_count // 100000000}亿次观看"
elif view_count >= 10000:
views_str = f"{view_count // 10000}万次观看"
else:
views_str = f"{view_count}次观看"
# 格式化时长
length_seconds = item.get("lengthSeconds", 0)
if length_seconds >= 3600:
hours = length_seconds // 3600
minutes = (length_seconds % 3600) // 60
duration_str = f"{hours}小时{minutes}分钟"
else:
minutes = length_seconds // 60
seconds = length_seconds % 60
duration_str = f"{minutes}{seconds}秒"
results.append({
"title": item.get("title", "未知标题"),
"video_id": video_id,
"channel": item.get("author", "未知频道"),
"views": views_str,
"duration": duration_str,
"thumbnail": f"https://img.youtube.com/vi/{video_id}/mqdefault.jpg",
"url": f"https://www.youtube.com/watch?v={video_id}",
"embed_url": f"https://www.youtube.com/embed/{video_id}"
})
if results:
return results
except Exception as e:
continue
return results
# 生成模拟搜索结果(当API不可用时的备选方案)
def generate_search_links(query):
"""生成各平台的搜索链接"""
encoded_query = urllib.parse.quote(query)
return {
"YouTube": f"https://www.youtube.com/results?search_query={encoded_query}",
"哔哩哔哩": f"https://search.bilibili.com/all?keyword={encoded_query}",
"抖音": f"https://www.douyin.com/search/{encoded_query}",
"西瓜视频": f"https://www.ixigua.com/search/{encoded_query}",
"腾讯视频": f"https://v.qq.com/x/search/?q={encoded_query}",
"优酷": f"https://so.youku.com/search_video/q_{encoded_query}",
"爱奇艺": f"https://so.iqiyi.com/so/q_{encoded_query}"
}
# 搜索区域
col1, col2, col3 = st.columns([1, 4, 1])
with col2:
# 搜索输入框
search_input = st.text_input(
"🔍 输入您想看的内容",
value=st.session_state.search_query,
placeholder="比如:太极拳教学、京剧、健康养生...",
key="search_input"
)
# 搜索按钮
col_btn1, col_btn2, col_btn3 = st.columns([1, 2, 1])
with col_btn2:
search_clicked = st.button("🔍 开始搜索", use_container_width=True, type="primary")
# 快捷搜索标签
st.markdown("### 💡 热门推荐(点击即可搜索)")
# 快捷搜索选项
quick_searches = [
("🎭 京剧表演", "京剧经典唱段"),
("🥋 太极拳", "太极拳教学"),
("🌿 养生保健", "老年人养生保健"),
("🍳 家常菜", "家常菜做法教程"),
("🎵 老歌经典", "经典老歌怀旧"),
("💃 广场舞", "广场舞教学"),
("🎨 书法教学", "书法入门教程"),
("🌸 园艺种花", "阳台种花教程"),
("♟️ 象棋教学", "中国象棋教程"),
("📺 相声小品", "经典相声小品"),
("🧘 健身操", "中老年健身操"),
("🎹 戏曲欣赏", "经典戏曲合集")
]
# 创建快捷搜索按钮网格
cols = st.columns(4)
for idx, (label, query) in enumerate(quick_searches):
with cols[idx % 4]:
if st.button(label, key=f"quick_{idx}", use_container_width=True):
st.session_state.search_query = query
st.session_state.searched = True
st.rerun()
st.markdown("---")
# 执行搜索
if search_clicked and search_input:
st.session_state.search_query = search_input
st.session_state.searched = True
# 显示搜索结果
if st.session_state.searched and st.session_state.search_query:
query = st.session_state.search_query
st.markdown(f"## 🎯 "{query}" 的搜索结果")
# 显示加载状态
with st.spinner("🔍 正在为您搜索视频,请稍候..."):
results = search_videos(query)
if results:
st.markdown(f"<div class='result-count'>✨ 找到 {len(results)} 个相关视频</div>", unsafe_allow_html=True)
# 显示视频结果
for i in range(0, len(results), 3):
cols = st.columns(3)
for j, col in enumerate(cols):
if i + j < len(results):
video = results[i + j]
with col:
st.markdown(f"""
<div class='video-card'>
<img src="{video['thumbnail']}" style="width: 100%; border-radius: 10px; margin-bottom: 10px;">
<div class='video-title'>{video['title'][:50]}{'...' if len(video['title']) > 50 else ''}</div>
<div class='video-channel'>📺 {video['channel']}</div>
<div class='video-stats'>👁️ {video['views']} | ⏱️ {video['duration']}</div>
</div>
""", unsafe_allow_html=True)
if st.button(f"▶️ 观看视频", key=f"watch_{i+j}", use_container_width=True):
st.markdown(f"[点击这里打开视频]({video['url']})")
# 嵌入视频播放器
st.video(video['url'])
# 显示各平台搜索链接
st.markdown("---")
st.markdown("### 🌐 在其他平台搜索")
st.markdown("<p style='font-size: 18px; color: #78716c;'>点击下方按钮,在对应平台搜索更多视频</p>", unsafe_allow_html=True)
search_links = generate_search_links(query)
platform_cols = st.columns(4)
platforms = list(search_links.items())
for idx, (platform, url) in enumerate(platforms):
with platform_cols[idx % 4]:
st.markdown(f"""
<a href="{url}" target="_blank" style="
display: block;
text-align: center;
padding: 15px;
margin: 10px 0;
background: linear-gradient(135deg, #fef3c7, #fde68a);
border-radius: 15px;
border: 2px solid #fbbf24;
color: #92400e !important;
font-size: 20px;
font-weight: bold;
text-decoration: none;
transition: all 0.3s ease;
">
🔗 {platform}
</a>
""", unsafe_allow_html=True)
else:
# 未搜索时显示提示
st.markdown("""
<div class='tip-text'>
<p style='font-size: 24px; margin-bottom: 15px;'>👆 在上方输入框中输入您想看的内容</p>
<p style='font-size: 20px; margin-bottom: 10px;'>或者点击"热门推荐"中的标签快速搜索</p>
<p style='font-size: 18px; color: #a8a29e;'>例如:太极拳、京剧、养生保健、广场舞...</p>
</div>
""", unsafe_allow_html=True)
# 显示使用说明
with st.expander("📖 使用说明(点击展开)", expanded=False):
st.markdown("""
### 🎯 如何使用视频搜索?
**方法一:直接搜索**
1. 在搜索框中输入您想看的内容
2. 点击"开始搜索"按钮
3. 等待搜索结果出现
4. 点击视频卡片下方的"观看视频"按钮
**方法二:快捷搜索**
1. 在"热门推荐"中找到感兴趣的标签
2. 直接点击标签即可搜索
### 💡 搜索小技巧
- 搜索词越具体,结果越准确
- 可以搜索:教学、表演、讲解、合集等
- 如果找不到想要的,试试换个说法
### 🌐 支持的视频平台
- YouTube(油管)
- 哔哩哔哩(B站)
- 抖音
- 西瓜视频
- 腾讯视频
- 优酷
- 爱奇艺
""")
# 页脚
st.markdown("---")
st.markdown("""
<div class='footer'>
<p>🎬 视频搜索 - 轻松找到您想看的视频</p>
<p style='font-size: 14px; color: #a8a29e;'>温馨提示:观看视频时注意休息眼睛,每看30分钟休息5分钟 👀</p>
<p style='font-size: 14px;'><a href='https://huggingface.co/spaces/akhaliq/anycoder' target='_blank'>Built with anycoder</a></p>
</div>
""", unsafe_allow_html=True)