Luigi commited on
Commit
01b1240
·
verified ·
1 Parent(s): 9337185

Create podcast.py

Browse files
Files changed (1) hide show
  1. src/podcast.py +101 -0
src/podcast.py ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # podcast.py
2
+ import requests
3
+ import feedparser
4
+ import yt_dlp
5
+ import tempfile
6
+ import os
7
+
8
+ def search_podcast_series(query: str):
9
+ base_url = "https://itunes.apple.com/search"
10
+ params = {"term": query, "media": "podcast", "entity": "podcast", "limit": 10}
11
+ try:
12
+ response = requests.get(base_url, params=params, timeout=15)
13
+ response.raise_for_status()
14
+ data = response.json()
15
+ series_list = []
16
+ for series in data.get("results", []):
17
+ series_list.append({
18
+ "id": series.get("collectionId"),
19
+ "title": series.get("collectionName", "Untitled"),
20
+ "artist": series.get("artistName", "Unknown"),
21
+ "feed_url": series.get("feedUrl", ""),
22
+ "thumbnail": series.get("artworkUrl600", ""),
23
+ "episode_count": series.get("trackCount", 0)
24
+ })
25
+ return series_list
26
+ except Exception as e:
27
+ print(f"Series search error: {str(e)}")
28
+ return []
29
+
30
+ def fetch_episodes(feed_url: str):
31
+ try:
32
+ feed = feedparser.parse(feed_url)
33
+ episodes = []
34
+ for entry in feed.entries:
35
+ audio_url = None
36
+ for link in entry.get('links', []):
37
+ if link.get('type', '').startswith('audio/'):
38
+ audio_url = link.href
39
+ break
40
+ if not audio_url:
41
+ continue
42
+ episodes.append({
43
+ "title": entry.get("title", "Untitled Episode"),
44
+ "published": entry.get("published", ""),
45
+ "audio_url": audio_url,
46
+ "description": entry.get("description", ""),
47
+ "duration": entry.get("itunes_duration", "0")
48
+ })
49
+ return episodes
50
+ except Exception as e:
51
+ print(f"RSS parse error: {str(e)}")
52
+ return []
53
+
54
+ def download_podcast_audio(audio_url: str, title: str, status: str) -> tuple:
55
+ if not audio_url:
56
+ return None, f"{status}\n❌ No audio URL available"
57
+ new_status = status + f"\n⏬ Downloading: {title}"
58
+ temp_dir = tempfile.mkdtemp()
59
+ ydl_opts = {
60
+ "format": "bestaudio/best",
61
+ "outtmpl": os.path.join(temp_dir, "%(title)s.%(ext)s"),
62
+ "postprocessors": [{"key": "FFmpegExtractAudio", "preferredcodec": "mp3"}],
63
+ "quiet": True,
64
+ "socket_timeout": 60,
65
+ "retries": 5
66
+ }
67
+ try:
68
+ with yt_dlp.YoutubeDL(ydl_opts) as ydl:
69
+ ydl.download([audio_url])
70
+ mp3_files = [f for f in os.listdir(temp_dir) if f.endswith('.mp3')]
71
+ if mp3_files:
72
+ audio_path = os.path.join(temp_dir, mp3_files[0])
73
+ new_status += f"\n✅ Downloaded: {mp3_files[0]}"
74
+ return audio_path, new_status
75
+ raise FileNotFoundError("MP3 file not found")
76
+ except Exception as e:
77
+ new_status += f"\n❌ Download error: {str(e)}"
78
+ return None, new_status
79
+
80
+ def fetch_audio(youtube_url: str, status: str) -> tuple:
81
+ try:
82
+ new_status = status + "\n⏬ Downloading audio from URL..."
83
+ temp_dir = tempfile.mkdtemp()
84
+ filename = f"yt_audio_{os.urandom(8).hex()}"
85
+ temp_path = os.path.join(temp_dir, filename)
86
+ ydl_opts = {
87
+ 'format': 'bestaudio/best',
88
+ 'outtmpl': temp_path,
89
+ 'postprocessors': [{'key': 'FFmpegExtractAudio', 'preferredcodec': 'mp3'}],
90
+ 'quiet': True,
91
+ }
92
+ with yt_dlp.YoutubeDL(ydl_opts) as ydl:
93
+ ydl.download([youtube_url])
94
+ audio_path = temp_path + '.mp3'
95
+ if not os.path.exists(audio_path) or os.path.getsize(audio_path) == 0:
96
+ raise ValueError("Downloaded file is empty")
97
+ new_status += "\n✅ Downloaded audio"
98
+ return audio_path, new_status
99
+ except Exception as e:
100
+ new_status += f"\n❌ Error: {str(e)}"
101
+ return None, new_status