LINUXDO_帖子随机数据库
6 subscribers
2.63K links
自动阅读脚本抓取的帖子会发送到这里
Download Telegram
window-badge { padding: 2px 6px; border-radius: 8px; font-size: 0.75em; font-weight: 600; color: #fff; user-select: none; } #chatUsageMonitor .window-badge.hour3 { background-color: ${COLORS.hour3}; } #chatUsageMonitor .window-badge.daily { background-color: ${COLORS.daily}; } #chatUsageMonitor .window-badge.weekly { background-color: ${COLORS.weekly}; } #chatUsageMonitor .model-row .usage { font-weight: 600; font-variant-numeric: tabular-nums; color: ${COLORS.success}; } #chatUsageMonitor .toggle-btn { background: none; border: none; color: ${COLORS.secondaryText}; cursor: pointer; font-size: 18px; line-height: 1; padding: 4px 8px; user-select: none; transition: color 0.2s ease; } #chatUsageMonitor .toggle-btn:hover { color: ${COLORS.primary}; } #chatUsageMonitor svg { fill: none; /*不使用填充,使用stroke*/ stroke: currentColor; /* 使用当前文本颜色 */ stroke-width: 2; width: 18px; height: 18px; display: block; } /* 用量统计容器的动画 显示隐藏 */ #chatUsageMonitor .usage-content.hide { display: block; visibility: hidden; opacity: 0; height: 0; overflow: hidden; transition: visibility 0.3s, opacity 0.3s, height 0.3s; } #chatUsageMonitor .usage-content:not(.hide) { visibility: visible; opacity: 1; height: auto; } `); // ---辅助函数--- // 生成SVG图标 - 时钟 function createClockIcon() { const svgNS = "http://www.w3.org/2000/svg"; const svg = document.createElementNS(svgNS, "svg"); svg.setAttribute("viewBox", "0 0 24 24"); svg.setAttribute("aria-hidden", "true"); svg.setAttribute("focusable", "false"); const circle = document.createElementNS(svgNS, "circle"); circle.setAttribute("cx", "12"); circle.setAttribute("cy", "12"); circle.setAttribute("r", "10"); circle.setAttribute("stroke", "currentColor"); // 使用currentColor circle.setAttribute("fill", "none"); circle.setAttribute("stroke-width", "2"); const line1 = document.createElementNS(svgNS, "line"); line1.setAttribute("x1", "12"); line1.setAttribute("y1", "6"); line1.setAttribute("x2", "12"); line1.setAttribute("y2", "12"); line1.setAttribute("stroke", "currentColor"); // 使用currentColor line1.setAttribute("stroke-width", "2"); line1.setAttribute("stroke-linecap", "round"); const line2 = document.createElementNS(svgNS, "line"); line2.setAttribute("x1", "12"); line2.setAttribute("y1", "12"); line2.setAttribute("x2", "16"); line2.setAttribute("y2", "14"); line2.setAttribute("stroke", "currentColor"); // 使用currentColor line2.setAttribute("stroke-width", "2"); line2.setAttribute("stroke-linecap", "round"); svg.appendChild(circle); svg.appendChild(line1); svg.appendChild(line2); return svg; } // 清理旧请求,保留对应时间窗口内的请求 function cleanupExpiredRequests() { const now = Date.now(); const maxWindow = TIME_WINDOWS.weekly; //最长时间窗口 Object.values(usageData.models).forEach(model => { model.requests = model.requests.filter(req => now - req.timestamp < maxWindow); }); } // --- 主UI逻辑 --- let monitorDiv = null; let usageContentDiv = null; let minimized = true; let isPinnedOpen = false; // 是否点击后持续展开 // 更新统计信息显示(刷新) function updateUsageDisplay() { if (!usageContentDiv) return; usageContentDiv.innerHTML = ""; //清空内容 const now = Date.now(); // 按窗口类型排序顺序 const windowOrder = ["hour3", "daily", "weekly"]; // 从models中筛选有quota且可用的模型,并排序 let modelsList = Object.entries(usageData.models); // 默认展示所有可用额度,故用的是quota,不过滤请求数为0的 // 这样不会遗漏配额为0的模型(无限额显示∞) modelsList.sort(([k1, m1], [k2, m2]) => { const aOrder = windowOrder.indexOf(m1.windowType); const bOrder = windowOrder.indexOf(m2.windowType); if (aOrder !== bOrder) return aOrder - bOrder; // 同窗口类型内按key字母序 return k1.localeCompare(k2); }); modelsList.forEach(([key, model]) => { const windowMs = TIME_WINDOWS[model.windowType]; const count = model.requests.filter(req => now - req.timestamp < windowMs).length; // 构造一行显示元素 const row = document.createElement("div"); row.className = "model-row"; // 左侧显示label和窗口badge const labelSpan = document.createElement("span"); labelSpan.className = "label"; // 彩色圆点(取对应颜色) const dot = document.createElement("span"); dot.style.display = "inline-block"; dot.st
盘', '阿里云盘', '百度网盘', '115网盘', '天翼云盘', '123云盘', 'UC网盘', '迅雷'] selected_netdisks = st.sidebar.multiselect("网盘类型", netdisk_types) # 分页参数 PAGE_SIZE = 100 if 'page_num' not in st.session_state: st.session_state['page_num'] = 1 # 构建查询 with Session(engine) as session: query = session.query(Message) # 应用时间范围过滤 if time_range == "最近24小时": query = query.filter(Message.timestamp >= datetime.now() - timedelta(days=1)) elif time_range == "最近7天": query = query.filter(Message.timestamp >= datetime.now() - timedelta(days=7)) elif time_range == "最近30天": query = query.filter(Message.timestamp >= datetime.now() - timedelta(days=30)) # 应用标签过滤 if selected_tags: filters = [Message.tags.any(tag) for tag in selected_tags] query = query.filter(or_(*filters)) # 按时间倒序排序 messages = query.order_by(Message.timestamp.desc()).all() # 显示消息列表前,按网盘类型过滤 if selected_netdisks: messages = [msg for msg in messages if any(nd in (msg.links or {}) for nd in selected_netdisks)] # 计算分页 max_page = (len(messages) + PAGE_SIZE - 1) // PAGE_SIZE page_num = st.session_state['page_num'] start_idx = (page_num - 1) * PAGE_SIZE end_idx = start_idx + PAGE_SIZE messages_page = messages[start_idx:end_idx] # 显示消息列表(分页后) for msg in messages_page: # 标题行保留网盘标签,用特殊符号区分 if msg.links: netdisk_tags = " ".join([f"🔵[{name}]" for name in msg.links.keys()]) else: netdisk_tags = "" expander_title = f"{msg.title} - 🕒{msg.timestamp.strftime('%Y-%m-%d %H:%M:%S')} {netdisk_tags}" with st.expander(expander_title): if msg.description: st.markdown(msg.description) if msg.links: link_str = " ".join([ f"<a href='{link}' target='_blank'><span class='netdisk-tag'>{name}</span></a>" for name, link in msg.links.items() ]) st.markdown(link_str, unsafe_allow_html=True) # 条目标签区(仅展示,不可点击,保留样式) if msg.tags: tag_html = "" for tag in msg.tags: tag_html += f"<span class='tag-btn'>#{tag}</span>" st.markdown(tag_html, unsafe_allow_html=True) # 显示分页信息和跳转控件(按钮和页码信息同一行居中) if max_page > 1: col1, col2, col3 = st.columns([1,2,1]) with col1: if st.button('上一页', disabled=page_num==1, key='prev_page'): st.session_state['page_num'] = max(1, page_num-1) st.rerun() with col2: st.markdown(f"<div style='text-align:center;line-height:38px;'>共 {len(messages)} 条,当前第 {page_num} / {max_page} 页</div>", unsafe_allow_html=True) with col3: if st.button('下一页', disabled=page_num==max_page, key='next_page'): st.session_state['page_num'] = min(max_page, page_num+1) st.rerun() # 处理点击条目标签筛选 if 'tag_click' in st.session_state and st.session_state['tag_click']: tag = st.session_state['tag_click'] if tag not in st.session_state['selected_tags']: st.session_state['selected_tags'].append(tag) st.session_state['tag_click'] = None st.rerun() st.session_state['tag_click'] = None # 添加自动刷新 st.empty() st.markdown("---") st.markdown("页面每60秒自动刷新一次") # 添加全局CSS,强力覆盖expander内容区的gap,只保留一处,放在文件最后 st.markdown(""" <style> [data-testid="stExpander"] [data-testid="stExpanderContent"] { gap: 0.2rem !important; } div[data-testid="stExpanderContent"] { gap: 0.2rem !important; } [data-testid="stExpander"] * { gap: 0.2rem !important; } .netdisk-tag { display: inline-block; background: #e6f0fa; color: #409eff; border-radius: 12px; padding: 2px 10px; margin: 2px 4px 2px 0; font-size: 13px; } .tag-btn { border:1px solid #222; border-radius:8px; padding:4px 16px; margin:2px 6px 2px 0; font-size:15px; background:#fff; color:#222; display:inline-block; transition: background 0.2s, color 0.2s; cursor: default; } .tag-btn:hover { background: #fff; color: #222; } </style> """, unsafe_allow_html=True) 初始化数据库init_db.py: from models import create_tables, Channel, engine from sqlalchemy.orm import Session from config import settings def init_channels(): # 从配置中获取默认频道列表 default_channels = settings.DEFAULT_CHANNELS.split(',') # 创建数据库会话 with Session(engine) as session: # 检查每个频道是否已存在 for username in default_channels: username = username.strip() if not username: continue # 检查频道是否已存在 existing = session.query(Channel).filte