Add pagination to feed list
This commit is contained in:
		@@ -19,6 +19,12 @@ function FeedList() {
 | 
				
			|||||||
  const [selectedCategory, setSelectedCategory] = useState<string>("");
 | 
					  const [selectedCategory, setSelectedCategory] = useState<string>("");
 | 
				
			||||||
  const [loading, setLoading] = useState(true);
 | 
					  const [loading, setLoading] = useState(true);
 | 
				
			||||||
  const [error, setError] = useState<string | null>(null);
 | 
					  const [error, setError] = useState<string | null>(null);
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  // Pagination state
 | 
				
			||||||
 | 
					  const [currentPage, setCurrentPage] = useState(1);
 | 
				
			||||||
 | 
					  const [pageSize, setPageSize] = useState(12);
 | 
				
			||||||
 | 
					  const [totalPages, setTotalPages] = useState(1);
 | 
				
			||||||
 | 
					  const [totalFeeds, setTotalFeeds] = useState(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    fetchFeeds();
 | 
					    fetchFeeds();
 | 
				
			||||||
@@ -26,19 +32,50 @@ function FeedList() {
 | 
				
			|||||||
  }, []);
 | 
					  }, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    filterFeedsByCategory();
 | 
					    // Reset to page 1 when category changes
 | 
				
			||||||
  }, [feeds, selectedCategory]);
 | 
					    setCurrentPage(1);
 | 
				
			||||||
 | 
					    fetchFeeds();
 | 
				
			||||||
 | 
					  }, [selectedCategory]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    // Fetch feeds when page changes
 | 
				
			||||||
 | 
					    fetchFeeds();
 | 
				
			||||||
 | 
					  }, [currentPage, pageSize]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const fetchFeeds = async () => {
 | 
					  const fetchFeeds = async () => {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      setLoading(true);
 | 
					      setLoading(true);
 | 
				
			||||||
      const response = await fetch("/api/feeds");
 | 
					      setError(null);
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      // Build query parameters
 | 
				
			||||||
 | 
					      const params = new URLSearchParams();
 | 
				
			||||||
 | 
					      params.append("page", currentPage.toString());
 | 
				
			||||||
 | 
					      params.append("limit", pageSize.toString());
 | 
				
			||||||
 | 
					      if (selectedCategory) {
 | 
				
			||||||
 | 
					        params.append("category", selectedCategory);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      const response = await fetch(`/api/feeds?${params.toString()}`);
 | 
				
			||||||
      if (!response.ok) {
 | 
					      if (!response.ok) {
 | 
				
			||||||
        const errorData = await response.json();
 | 
					        const errorData = await response.json();
 | 
				
			||||||
        throw new Error(errorData.error || "フィードの取得に失敗しました");
 | 
					        throw new Error(errorData.error || "フィードの取得に失敗しました");
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
      const data = await response.json();
 | 
					      const data = await response.json();
 | 
				
			||||||
      setFeeds(data.feeds || []);
 | 
					      
 | 
				
			||||||
 | 
					      // Handle paginated response
 | 
				
			||||||
 | 
					      if (data.feeds && typeof data.total !== 'undefined') {
 | 
				
			||||||
 | 
					        setFeeds(data.feeds);
 | 
				
			||||||
 | 
					        setFilteredFeeds(data.feeds);
 | 
				
			||||||
 | 
					        setTotalFeeds(data.total);
 | 
				
			||||||
 | 
					        setTotalPages(data.totalPages);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        // Fallback for non-paginated response (backward compatibility)
 | 
				
			||||||
 | 
					        setFeeds(data.feeds || []);
 | 
				
			||||||
 | 
					        setFilteredFeeds(data.feeds || []);
 | 
				
			||||||
 | 
					        setTotalFeeds(data.feeds?.length || 0);
 | 
				
			||||||
 | 
					        setTotalPages(1);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    } catch (err) {
 | 
					    } catch (err) {
 | 
				
			||||||
      console.error("Feed fetch error:", err);
 | 
					      console.error("Feed fetch error:", err);
 | 
				
			||||||
      setError(err instanceof Error ? err.message : "エラーが発生しました");
 | 
					      setError(err instanceof Error ? err.message : "エラーが発生しました");
 | 
				
			||||||
@@ -59,16 +96,6 @@ function FeedList() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const filterFeedsByCategory = () => {
 | 
					 | 
				
			||||||
    if (!selectedCategory) {
 | 
					 | 
				
			||||||
      setFilteredFeeds(feeds);
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      const filtered = feeds.filter(
 | 
					 | 
				
			||||||
        (feed) => feed.category === selectedCategory,
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
      setFilteredFeeds(filtered);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const formatDate = (dateString: string) => {
 | 
					  const formatDate = (dateString: string) => {
 | 
				
			||||||
    return new Date(dateString).toLocaleString("ja-JP");
 | 
					    return new Date(dateString).toLocaleString("ja-JP");
 | 
				
			||||||
@@ -128,9 +155,9 @@ function FeedList() {
 | 
				
			|||||||
        <h2>
 | 
					        <h2>
 | 
				
			||||||
          フィード一覧 (
 | 
					          フィード一覧 (
 | 
				
			||||||
          {selectedCategory
 | 
					          {selectedCategory
 | 
				
			||||||
            ? `${filteredFeeds.length}/${feeds.length}`
 | 
					            ? `${totalFeeds}件 - カテゴリ: ${selectedCategory}`
 | 
				
			||||||
            : feeds.length}
 | 
					            : `${totalFeeds}件`}
 | 
				
			||||||
          件)
 | 
					          )
 | 
				
			||||||
        </h2>
 | 
					        </h2>
 | 
				
			||||||
        <div style={{ display: "flex", gap: "10px", alignItems: "center" }}>
 | 
					        <div style={{ display: "flex", gap: "10px", alignItems: "center" }}>
 | 
				
			||||||
          {categories.length > 0 && (
 | 
					          {categories.length > 0 && (
 | 
				
			||||||
@@ -152,7 +179,25 @@ function FeedList() {
 | 
				
			|||||||
              ))}
 | 
					              ))}
 | 
				
			||||||
            </select>
 | 
					            </select>
 | 
				
			||||||
          )}
 | 
					          )}
 | 
				
			||||||
          <button className="btn btn-secondary" onClick={fetchFeeds}>
 | 
					          <select
 | 
				
			||||||
 | 
					            value={pageSize}
 | 
				
			||||||
 | 
					            onChange={(e) => {
 | 
				
			||||||
 | 
					              setPageSize(Number.parseInt(e.target.value));
 | 
				
			||||||
 | 
					              setCurrentPage(1);
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					            style={{
 | 
				
			||||||
 | 
					              padding: "5px 10px",
 | 
				
			||||||
 | 
					              fontSize: "14px",
 | 
				
			||||||
 | 
					              border: "1px solid #ccc",
 | 
				
			||||||
 | 
					              borderRadius: "4px",
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <option value={6}>6件表示</option>
 | 
				
			||||||
 | 
					            <option value={12}>12件表示</option>
 | 
				
			||||||
 | 
					            <option value={24}>24件表示</option>
 | 
				
			||||||
 | 
					            <option value={48}>48件表示</option>
 | 
				
			||||||
 | 
					          </select>
 | 
				
			||||||
 | 
					          <button type="button" className="btn btn-secondary" onClick={fetchFeeds}>
 | 
				
			||||||
            更新
 | 
					            更新
 | 
				
			||||||
          </button>
 | 
					          </button>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
@@ -200,6 +245,77 @@ function FeedList() {
 | 
				
			|||||||
        ))}
 | 
					        ))}
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      {/* Pagination Controls */}
 | 
				
			||||||
 | 
					      {totalPages > 1 && (
 | 
				
			||||||
 | 
					        <div className="pagination-container">
 | 
				
			||||||
 | 
					          <div className="pagination-info">
 | 
				
			||||||
 | 
					            ページ {currentPage} / {totalPages} (全 {totalFeeds} 件)
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div className="pagination-controls">
 | 
				
			||||||
 | 
					            <button
 | 
				
			||||||
 | 
					              type="button"
 | 
				
			||||||
 | 
					              className="btn btn-secondary"
 | 
				
			||||||
 | 
					              onClick={() => setCurrentPage(1)}
 | 
				
			||||||
 | 
					              disabled={currentPage === 1}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              最初
 | 
				
			||||||
 | 
					            </button>
 | 
				
			||||||
 | 
					            <button
 | 
				
			||||||
 | 
					              type="button"
 | 
				
			||||||
 | 
					              className="btn btn-secondary"
 | 
				
			||||||
 | 
					              onClick={() => setCurrentPage(currentPage - 1)}
 | 
				
			||||||
 | 
					              disabled={currentPage === 1}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              前へ
 | 
				
			||||||
 | 
					            </button>
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            {/* Page numbers */}
 | 
				
			||||||
 | 
					            <div className="page-numbers">
 | 
				
			||||||
 | 
					              {Array.from({ length: Math.min(5, totalPages) }, (_, i) => {
 | 
				
			||||||
 | 
					                let pageNum;
 | 
				
			||||||
 | 
					                if (totalPages <= 5) {
 | 
				
			||||||
 | 
					                  pageNum = i + 1;
 | 
				
			||||||
 | 
					                } else if (currentPage <= 3) {
 | 
				
			||||||
 | 
					                  pageNum = i + 1;
 | 
				
			||||||
 | 
					                } else if (currentPage >= totalPages - 2) {
 | 
				
			||||||
 | 
					                  pageNum = totalPages - 4 + i;
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                  pageNum = currentPage - 2 + i;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                return (
 | 
				
			||||||
 | 
					                  <button
 | 
				
			||||||
 | 
					                    type="button"
 | 
				
			||||||
 | 
					                    key={pageNum}
 | 
				
			||||||
 | 
					                    className={`btn ${currentPage === pageNum ? 'btn-primary' : 'btn-secondary'}`}
 | 
				
			||||||
 | 
					                    onClick={() => setCurrentPage(pageNum)}
 | 
				
			||||||
 | 
					                  >
 | 
				
			||||||
 | 
					                    {pageNum}
 | 
				
			||||||
 | 
					                  </button>
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					              })}
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            <button
 | 
				
			||||||
 | 
					              type="button"
 | 
				
			||||||
 | 
					              className="btn btn-secondary"
 | 
				
			||||||
 | 
					              onClick={() => setCurrentPage(currentPage + 1)}
 | 
				
			||||||
 | 
					              disabled={currentPage === totalPages}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              次へ
 | 
				
			||||||
 | 
					            </button>
 | 
				
			||||||
 | 
					            <button
 | 
				
			||||||
 | 
					              type="button"
 | 
				
			||||||
 | 
					              className="btn btn-secondary"
 | 
				
			||||||
 | 
					              onClick={() => setCurrentPage(totalPages)}
 | 
				
			||||||
 | 
					              disabled={currentPage === totalPages}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              最後
 | 
				
			||||||
 | 
					            </button>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <style>{`
 | 
					      <style>{`
 | 
				
			||||||
        .feed-grid {
 | 
					        .feed-grid {
 | 
				
			||||||
          display: grid;
 | 
					          display: grid;
 | 
				
			||||||
@@ -281,6 +397,55 @@ function FeedList() {
 | 
				
			|||||||
          font-size: 11px;
 | 
					          font-size: 11px;
 | 
				
			||||||
          font-weight: 500;
 | 
					          font-weight: 500;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .pagination-container {
 | 
				
			||||||
 | 
					          margin-top: 30px;
 | 
				
			||||||
 | 
					          padding: 20px 0;
 | 
				
			||||||
 | 
					          border-top: 1px solid #e9ecef;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .pagination-info {
 | 
				
			||||||
 | 
					          text-align: center;
 | 
				
			||||||
 | 
					          margin-bottom: 15px;
 | 
				
			||||||
 | 
					          color: #666;
 | 
				
			||||||
 | 
					          font-size: 14px;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .pagination-controls {
 | 
				
			||||||
 | 
					          display: flex;
 | 
				
			||||||
 | 
					          justify-content: center;
 | 
				
			||||||
 | 
					          align-items: center;
 | 
				
			||||||
 | 
					          gap: 8px;
 | 
				
			||||||
 | 
					          flex-wrap: wrap;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .page-numbers {
 | 
				
			||||||
 | 
					          display: flex;
 | 
				
			||||||
 | 
					          gap: 4px;
 | 
				
			||||||
 | 
					          margin: 0 8px;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .pagination-controls button {
 | 
				
			||||||
 | 
					          min-width: 40px;
 | 
				
			||||||
 | 
					          height: 36px;
 | 
				
			||||||
 | 
					          font-size: 14px;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .pagination-controls button:disabled {
 | 
				
			||||||
 | 
					          opacity: 0.5;
 | 
				
			||||||
 | 
					          cursor: not-allowed;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @media (max-width: 768px) {
 | 
				
			||||||
 | 
					          .pagination-controls {
 | 
				
			||||||
 | 
					            flex-direction: column;
 | 
				
			||||||
 | 
					            gap: 12px;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          
 | 
				
			||||||
 | 
					          .page-numbers {
 | 
				
			||||||
 | 
					            margin: 0;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      `}</style>
 | 
					      `}</style>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										29
									
								
								server.ts
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								server.ts
									
									
									
									
									
								
							@@ -509,9 +509,32 @@ app.get("/api/episode/:episodeId", async (c) => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
app.get("/api/feeds", async (c) => {
 | 
					app.get("/api/feeds", async (c) => {
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
    const { fetchActiveFeeds } = await import("./services/database.js");
 | 
					    const page = c.req.query("page");
 | 
				
			||||||
    const feeds = await fetchActiveFeeds();
 | 
					    const limit = c.req.query("limit");
 | 
				
			||||||
    return c.json({ feeds });
 | 
					    const category = c.req.query("category");
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // If pagination parameters are provided, use paginated endpoint
 | 
				
			||||||
 | 
					    if (page || limit) {
 | 
				
			||||||
 | 
					      const { fetchActiveFeedsPaginated } = await import("./services/database.js");
 | 
				
			||||||
 | 
					      const pageNum = page ? Number.parseInt(page, 10) : 1;
 | 
				
			||||||
 | 
					      const limitNum = limit ? Number.parseInt(limit, 10) : 10;
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      // Validate pagination parameters
 | 
				
			||||||
 | 
					      if (Number.isNaN(pageNum) || pageNum < 1) {
 | 
				
			||||||
 | 
					        return c.json({ error: "Invalid page number" }, 400);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (Number.isNaN(limitNum) || limitNum < 1 || limitNum > 100) {
 | 
				
			||||||
 | 
					        return c.json({ error: "Invalid limit (must be between 1-100)" }, 400);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      const result = await fetchActiveFeedsPaginated(pageNum, limitNum, category || undefined);
 | 
				
			||||||
 | 
					      return c.json(result);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      // Original behavior for backward compatibility
 | 
				
			||||||
 | 
					      const { fetchActiveFeeds } = await import("./services/database.js");
 | 
				
			||||||
 | 
					      const feeds = await fetchActiveFeeds();
 | 
				
			||||||
 | 
					      return c.json({ feeds });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  } catch (error) {
 | 
					  } catch (error) {
 | 
				
			||||||
    console.error("Error fetching feeds:", error);
 | 
					    console.error("Error fetching feeds:", error);
 | 
				
			||||||
    return c.json({ error: "Failed to fetch feeds" }, 500);
 | 
					    return c.json({ error: "Failed to fetch feeds" }, 500);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -339,6 +339,65 @@ export async function fetchActiveFeeds(): Promise<Feed[]> {
 | 
				
			|||||||
  return getAllFeeds();
 | 
					  return getAllFeeds();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Get paginated active feeds with total count
 | 
				
			||||||
 | 
					export async function fetchActiveFeedsPaginated(
 | 
				
			||||||
 | 
					  page: number = 1,
 | 
				
			||||||
 | 
					  limit: number = 10,
 | 
				
			||||||
 | 
					  category?: string
 | 
				
			||||||
 | 
					): Promise<{ feeds: Feed[]; total: number; page: number; limit: number; totalPages: number }> {
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    const offset = (page - 1) * limit;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // Build query conditions
 | 
				
			||||||
 | 
					    let whereCondition = "WHERE active = 1";
 | 
				
			||||||
 | 
					    const params: any[] = [];
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if (category) {
 | 
				
			||||||
 | 
					      whereCondition += " AND category = ?";
 | 
				
			||||||
 | 
					      params.push(category);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // Get total count
 | 
				
			||||||
 | 
					    const countStmt = db.prepare(`SELECT COUNT(*) as count FROM feeds ${whereCondition}`);
 | 
				
			||||||
 | 
					    const countResult = countStmt.get(...params) as { count: number };
 | 
				
			||||||
 | 
					    const total = countResult.count;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // Get paginated feeds
 | 
				
			||||||
 | 
					    const feedsStmt = db.prepare(`
 | 
				
			||||||
 | 
					      SELECT * FROM feeds 
 | 
				
			||||||
 | 
					      ${whereCondition}
 | 
				
			||||||
 | 
					      ORDER BY created_at DESC 
 | 
				
			||||||
 | 
					      LIMIT ? OFFSET ?
 | 
				
			||||||
 | 
					    `);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    const rows = feedsStmt.all(...params, limit, offset) as any[];
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    const feeds = rows.map((row) => ({
 | 
				
			||||||
 | 
					      id: row.id,
 | 
				
			||||||
 | 
					      url: row.url,
 | 
				
			||||||
 | 
					      title: row.title,
 | 
				
			||||||
 | 
					      description: row.description,
 | 
				
			||||||
 | 
					      category: row.category,
 | 
				
			||||||
 | 
					      lastUpdated: row.last_updated,
 | 
				
			||||||
 | 
					      createdAt: row.created_at,
 | 
				
			||||||
 | 
					      active: Boolean(row.active),
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    const totalPages = Math.ceil(total / limit);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      feeds,
 | 
				
			||||||
 | 
					      total,
 | 
				
			||||||
 | 
					      page,
 | 
				
			||||||
 | 
					      limit,
 | 
				
			||||||
 | 
					      totalPages
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  } catch (error) {
 | 
				
			||||||
 | 
					    console.error("Error getting paginated feeds:", error);
 | 
				
			||||||
 | 
					    throw error;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Get episodes with feed information for enhanced display
 | 
					// Get episodes with feed information for enhanced display
 | 
				
			||||||
export async function fetchEpisodesWithFeedInfo(): Promise<
 | 
					export async function fetchEpisodesWithFeedInfo(): Promise<
 | 
				
			||||||
  EpisodeWithFeedInfo[]
 | 
					  EpisodeWithFeedInfo[]
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user