{ "cells": [ { "cell_type": "code", "execution_count": 4, "id": "d33b66f5", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Title: Cookies N Cream Parfaits | Episode 1060\n", "Duration: 0:08:02\n", "Views: 631554\n", "Likes: 14569\n", "---------------------------------------\n", "Title: The Legendary Dosa Man of NYC | Street Food Icons\n", "Duration: 0:08:19\n", "Views: 20805553\n", "Likes: 379680\n", "---------------------------------------\n", "Title: Shirataki Noodles are INSANE for Weight Loss.\n", "Duration: 0:03:44\n", "Views: 3411961\n", "Likes: 120585\n", "---------------------------------------\n", "Title: You’ll get addicted to this late night snack\n", "Duration: 0:01:00\n", "Views: 12893803\n", "Likes: 804515\n", "---------------------------------------\n", "Title: The 5 minute baguette\n", "Duration: 0:06:27\n", "Views: 2165595\n", "Likes: 127433\n", "---------------------------------------\n", "Title: Chipotle’s Chicken Cooked at Home - By a Former Chipotle Employee\n", "Duration: 0:03:46\n", "Views: 2537367\n", "Likes: 81018\n", "---------------------------------------\n", "Title: How to make incredible NAAN at home\n", "Duration: 0:07:28\n", "Views: 3458479\n", "Likes: 87406\n", "---------------------------------------\n", "Title: The ONLY Egg Salad Recipe You Need\n", "Duration: 0:07:54\n", "Views: 395581\n", "Likes: 9919\n", "---------------------------------------\n", "Title: 1 ALL PURPOSE BASE GRAVY MASALA Make Several Curry Recipes\n", "Duration: 0:09:12\n", "Views: 886123\n", "Likes: 21738\n", "---------------------------------------\n", "Title: Chicken Tinga Tacos - You Suck at Cooking (episode 167)\n", "Duration: 0:05:06\n", "Views: 623907\n", "Likes: 34079\n", "---------------------------------------\n", "Title: Questa ricetta vi farà impazzire❗ Non ho mai mangiato una pasta cosi deliziosa❗\n", "Duration: 0:03:08\n", "Views: 1264497\n", "Likes: 16162\n", "---------------------------------------\n" ] } ], "source": [ "from googleapiclient.discovery import build\n", "import re\n", "from datetime import timedelta\n", "\n", "# Your API key\n", "API_KEY = \"AIzaSyASKuARMAZ2VtwjWx_7di_m544TsRVlU_A\"\n", "\n", "# The ID of the playlist you want to inspect\n", "PLAYLIST_ID = \"PLIFGAob9a5_aTstJFEbHud2BQQ1co7CQz\" \n", "\n", "def parse_iso8601_duration(duration):\n", " \"\"\"Parse an ISO 8601 duration (e.g., 'PT4M13S') and return a human-readable time string.\"\"\"\n", " pattern = re.compile(r'PT(?:(\\d+)H)?(?:(\\d+)M)?(?:(\\d+)S)?')\n", " match = pattern.match(duration)\n", " hours = int(match.group(1)) if match.group(1) else 0\n", " minutes = int(match.group(2)) if match.group(2) else 0\n", " seconds = int(match.group(3)) if match.group(3) else 0\n", "\n", " total_seconds = hours * 3600 + minutes * 60 + seconds\n", " return str(timedelta(seconds=total_seconds))\n", "\n", "def main():\n", " youtube = build(\"youtube\", \"v3\", developerKey=API_KEY)\n", "\n", " # Retrieve playlist items (video IDs)\n", " video_ids = []\n", " request = youtube.playlistItems().list(\n", " part=\"snippet\",\n", " playlistId=PLAYLIST_ID,\n", " maxResults=50\n", " )\n", "\n", " while request:\n", " response = request.execute()\n", " for item in response.get(\"items\", []):\n", " video_id = item[\"snippet\"][\"resourceId\"][\"videoId\"]\n", " video_ids.append(video_id)\n", " request = youtube.playlistItems().list_next(request, response)\n", "\n", " if not video_ids:\n", " print(\"No videos found in this playlist.\")\n", " return\n", "\n", " # Fetch details (title, duration, views, likes) for the videos\n", " for i in range(0, len(video_ids), 50):\n", " chunk = video_ids[i:i+50]\n", " video_request = youtube.videos().list(\n", " part=\"snippet,contentDetails,statistics\",\n", " id=\",\".join(chunk)\n", " )\n", " video_response = video_request.execute()\n", "\n", " for video_item in video_response.get(\"items\", []):\n", " title = video_item[\"snippet\"][\"title\"]\n", " duration = video_item[\"contentDetails\"][\"duration\"]\n", " readable_duration = parse_iso8601_duration(duration)\n", "\n", " # Statistics\n", " stats = video_item.get(\"statistics\", {})\n", " view_count = stats.get(\"viewCount\", \"N/A\")\n", " like_count = stats.get(\"likeCount\", \"N/A\")\n", "\n", " print(f\"Title: {title}\")\n", " print(f\"Duration: {readable_duration}\")\n", " print(f\"Views: {view_count}\")\n", " print(f\"Likes: {like_count}\")\n", " print(\"---------------------------------------\")\n", "\n", "if __name__ == \"__main__\":\n", " main()\n", "\n", " " ] }, { "cell_type": "code", "execution_count": 5, "id": "d64401df", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Y-_k7qFaXUE\n", "sxt4YCIsn2I\n", "-wRHXXyR6sc\n", "jlp3p95LrYk\n", "Z-husjZkxHw\n", "7umUJ0lAVbQ\n", "EqCUENkCQqw\n", "SXYaMr6kFTE\n", "rSEASZWV8oc\n", "fahxFZfVZqI\n", "2emYD4d3abg\n" ] } ], "source": [ "from googleapiclient.discovery import build\n", "import re\n", "from datetime import timedelta\n", "\n", "# Your API key\n", "API_KEY = \"AIzaSyASKuARMAZ2VtwjWx_7di_m544TsRVlU_A\"\n", "\n", "# The ID of the playlist you want to inspect\n", "PLAYLIST_ID = \"PLIFGAob9a5_aTstJFEbHud2BQQ1co7CQz\" \n", "\n", "def parse_iso8601_duration(duration):\n", " \"\"\"Parse an ISO 8601 duration (e.g., 'PT4M13S') and return a human-readable time string.\"\"\"\n", " pattern = re.compile(r'PT(?:(\\d+)H)?(?:(\\d+)M)?(?:(\\d+)S)?')\n", " match = pattern.match(duration)\n", " hours = int(match.group(1)) if match.group(1) else 0\n", " minutes = int(match.group(2)) if match.group(2) else 0\n", " seconds = int(match.group(3)) if match.group(3) else 0\n", "\n", " total_seconds = hours * 3600 + minutes * 60 + seconds\n", " return str(timedelta(seconds=total_seconds))\n", "\n", "def main():\n", " youtube = build(\"youtube\", \"v3\", developerKey=API_KEY)\n", "\n", " # Retrieve playlist items (video IDs)\n", " video_ids = []\n", " request = youtube.playlistItems().list(\n", " part=\"snippet\",\n", " playlistId=PLAYLIST_ID,\n", " maxResults=50\n", " )\n", "\n", " while request:\n", " response = request.execute()\n", " for item in response.get(\"items\", []):\n", " video_id = item[\"snippet\"][\"resourceId\"][\"videoId\"]\n", " video_ids.append(video_id)\n", " request = youtube.playlistItems().list_next(request, response)\n", "\n", " if not video_ids:\n", " print(\"No videos found in this playlist.\")\n", " return\n", "\n", " # Fetch details (title, duration, views, likes, id) for the videos\n", " for i in range(0, len(video_ids), 50):\n", " chunk = video_ids[i:i+50]\n", " video_request = youtube.videos().list(\n", " part=\"snippet,contentDetails,statistics\",\n", " id=\",\".join(chunk)\n", " )\n", " video_response = video_request.execute()\n", "\n", " for video_item in video_response.get(\"items\", []):\n", " title = video_item[\"snippet\"][\"title\"]\n", " duration = video_item[\"contentDetails\"][\"duration\"]\n", " readable_duration = parse_iso8601_duration(duration)\n", "\n", " # Statistics\n", " stats = video_item.get(\"statistics\", {})\n", " view_count = stats.get(\"viewCount\", \"N/A\")\n", " like_count = stats.get(\"likeCount\", \"N/A\")\n", "\n", " # Video ID\n", " video_id = video_item[\"id\"]\n", "\n", " print(video_id)\n", " # print(f\"Video ID: {video_id}\")\n", " # print(f\"Title: {title}\")\n", " # print(f\"Duration: {readable_duration}\")\n", " # print(f\"Views: {view_count}\")\n", " # print(f\"Likes: {like_count}\")\n", " # print(\"---------------------------------------\")\n", "\n", "if __name__ == \"__main__\":\n", " main()\n" ] }, { "cell_type": "code", "execution_count": 6, "id": "37e9f6de", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Y-_k7qFaXUE\n", "sxt4YCIsn2I\n", "-wRHXXyR6sc\n", "jlp3p95LrYk\n", "Z-husjZkxHw\n", "7umUJ0lAVbQ\n", "EqCUENkCQqw\n", "SXYaMr6kFTE\n", "rSEASZWV8oc\n", "fahxFZfVZqI\n", "2emYD4d3abg\n" ] } ], "source": [ "from googleapiclient.discovery import build\n", "\n", "API_KEY = \"AIzaSyASKuARMAZ2VtwjWx_7di_m544TsRVlU_A\"\n", "PLAYLIST_ID = \"PLIFGAob9a5_aTstJFEbHud2BQQ1co7CQz\"\n", "\n", "def get_all_video_ids(youtube, playlist_id):\n", " \"\"\"Retrieve all video IDs from a given playlist.\"\"\"\n", " video_ids = []\n", " request = youtube.playlistItems().list(\n", " part=\"snippet\",\n", " playlistId=playlist_id,\n", " maxResults=50\n", " )\n", " while request:\n", " response = request.execute()\n", " video_ids.extend(\n", " item[\"snippet\"][\"resourceId\"][\"videoId\"]\n", " for item in response.get(\"items\", [])\n", " )\n", " request = youtube.playlistItems().list_next(request, response)\n", " return video_ids\n", "\n", "def main():\n", " youtube = build(\"youtube\", \"v3\", developerKey=API_KEY)\n", " video_ids = get_all_video_ids(youtube, PLAYLIST_ID)\n", " for video_id in video_ids:\n", " print(video_id)\n", "\n", "if __name__ == \"__main__\":\n", " main()\n" ] }, { "cell_type": "markdown", "id": "757a0807", "metadata": {}, "source": [ "# This Works" ] }, { "cell_type": "code", "execution_count": 14, "id": "9c8385bf", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2024-12-15 17:03:04,886 - podcastfy.client - INFO - Processing 1 links\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Generating podcast...\n", "Transcript saved to ./data/transcripts/transcript_6b951b01e2b442589bf87b2afb3860c8.txt\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2024-12-15 17:04:47,963 - podcastfy.client - INFO - Podcast generated successfully using openai TTS model\n" ] } ], "source": [ "from podcastfy.client import generate_podcast\n", "audio_file = generate_podcast(urls=[\"https://en.wikipedia.org/wiki/Podcast\"])\n" ] }, { "cell_type": "markdown", "id": "cffcc718", "metadata": {}, "source": [ "# This works too..." ] }, { "cell_type": "code", "execution_count": 5, "id": "2d643181", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2024-12-14 11:08:42,035 - podcastfy.client - INFO - Processing 1 links\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Generating podcast...\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/Users/rajul/anaconda3/lib/python3.11/site-packages/langsmith/client.py:261: LangSmithMissingAPIKeyWarning: API key must be provided when using hosted LangSmith API\n", " warnings.warn(\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Transcript saved to ./data/transcripts/transcript_9ca61f01b73d4e74b31c8f3a27fd918a.txt\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2024-12-14 11:10:20,299 - podcastfy.client - INFO - Podcast generated successfully using openai TTS model\n" ] } ], "source": [ "from podcastfy.client import generate_podcast\n", "audio_file = generate_podcast(urls=[\"https://www.youtube.com/watch?v=7kbQnLN2y_I\"])" ] }, { "cell_type": "markdown", "id": "ed2833da", "metadata": {}, "source": [ "\n", "\n", "\n", "\n", "# This doees not work" ] }, { "cell_type": "code", "execution_count": 5, "id": "30d0b934", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2024-12-14 17:30:17,099 - podcastfy.client - INFO - Processing 1 links\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Generating podcast...\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/Users/rajul/anaconda3/lib/python3.11/site-packages/langsmith/client.py:261: LangSmithMissingAPIKeyWarning: API key must be provided when using hosted LangSmith API\n", " warnings.warn(\n", "Failed to generate audio: 403 The caller does not have permission\n", "Traceback (most recent call last):\n", " File \"/Users/rajul/anaconda3/lib/python3.11/site-packages/google/api_core/grpc_helpers.py\", line 76, in error_remapped_callable\n", " return callable_(*args, **kwargs)\n", " ^^^^^^^^^^^^^^^^^^^^^^^^^^\n", " File \"/Users/rajul/anaconda3/lib/python3.11/site-packages/grpc/_interceptor.py\", line 277, in __call__\n", " response, ignored_call = self._with_call(\n", " ^^^^^^^^^^^^^^^^\n", " File \"/Users/rajul/anaconda3/lib/python3.11/site-packages/grpc/_interceptor.py\", line 332, in _with_call\n", " return call.result(), call\n", " ^^^^^^^^^^^^^\n", " File \"/Users/rajul/anaconda3/lib/python3.11/site-packages/grpc/_channel.py\", line 440, in result\n", " raise self\n", " File \"/Users/rajul/anaconda3/lib/python3.11/site-packages/grpc/_interceptor.py\", line 315, in continuation\n", " response, call = self._thunk(new_method).with_call(\n", " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", " File \"/Users/rajul/anaconda3/lib/python3.11/site-packages/grpc/_channel.py\", line 1198, in with_call\n", " return _end_unary_response_blocking(state, call, True, None)\n", " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", " File \"/Users/rajul/anaconda3/lib/python3.11/site-packages/grpc/_channel.py\", line 1006, in _end_unary_response_blocking\n", " raise _InactiveRpcError(state) # pytype: disable=not-instantiable\n", " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", "grpc._channel._InactiveRpcError: <_InactiveRpcError of RPC that terminated with:\n", "\tstatus = StatusCode.PERMISSION_DENIED\n", "\tdetails = \"The caller does not have permission\"\n", "\tdebug_error_string = \"UNKNOWN:Error received from peer ipv4:142.250.72.106:443 {created_time:\"2024-12-14T17:30:39.507315-05:00\", grpc_status:7, grpc_message:\"The caller does not have permission\"}\"\n", ">\n", "\n", "The above exception was the direct cause of the following exception:\n", "\n", "Traceback (most recent call last):\n", " File \"/Users/rajul/anaconda3/lib/python3.11/site-packages/podcastfy/tts/providers/geminimulti.py\", line 299, in generate_audio\n", " response = self.client.synthesize_speech(\n", " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", " File \"/Users/rajul/anaconda3/lib/python3.11/site-packages/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py\", line 910, in synthesize_speech\n", " response = rpc(\n", " ^^^^\n", " File \"/Users/rajul/anaconda3/lib/python3.11/site-packages/google/api_core/gapic_v1/method.py\", line 131, in __call__\n", " return wrapped_func(*args, **kwargs)\n", " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", " File \"/Users/rajul/anaconda3/lib/python3.11/site-packages/google/api_core/grpc_helpers.py\", line 78, in error_remapped_callable\n", " raise exceptions.from_grpc_error(exc) from exc\n", "google.api_core.exceptions.PermissionDenied: 403 The caller does not have permission\n", "Error converting text to speech: Failed to generate audio: 403 The caller does not have permission\n", "2024-12-14 17:30:39,519 - podcastfy.client - ERROR - An error occurred in the process_content function: Failed to generate audio: 403 The caller does not have permission\n", "2024-12-14 17:30:39,520 - podcastfy.client - ERROR - An error occurred: Failed to generate audio: 403 The caller does not have permission\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Transcript saved to ./data/transcripts/transcript_3553880065fe42fc9521eb9a21a87a82.txt\n" ] }, { "ename": "RuntimeError", "evalue": "Failed to generate audio: 403 The caller does not have permission", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31m_InactiveRpcError\u001b[0m Traceback (most recent call last)", "File \u001b[0;32m~/anaconda3/lib/python3.11/site-packages/google/api_core/grpc_helpers.py:76\u001b[0m, in \u001b[0;36m_wrap_unary_errors..error_remapped_callable\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 75\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m---> 76\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m callable_(\u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[1;32m 77\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m grpc\u001b[38;5;241m.\u001b[39mRpcError \u001b[38;5;28;01mas\u001b[39;00m exc:\n", "File \u001b[0;32m~/anaconda3/lib/python3.11/site-packages/grpc/_interceptor.py:277\u001b[0m, in \u001b[0;36m_UnaryUnaryMultiCallable.__call__\u001b[0;34m(self, request, timeout, metadata, credentials, wait_for_ready, compression)\u001b[0m\n\u001b[1;32m 268\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__call__\u001b[39m(\n\u001b[1;32m 269\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 270\u001b[0m request: Any,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 275\u001b[0m compression: Optional[grpc\u001b[38;5;241m.\u001b[39mCompression] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m 276\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Any:\n\u001b[0;32m--> 277\u001b[0m response, ignored_call \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_with_call(\n\u001b[1;32m 278\u001b[0m request,\n\u001b[1;32m 279\u001b[0m timeout\u001b[38;5;241m=\u001b[39mtimeout,\n\u001b[1;32m 280\u001b[0m metadata\u001b[38;5;241m=\u001b[39mmetadata,\n\u001b[1;32m 281\u001b[0m credentials\u001b[38;5;241m=\u001b[39mcredentials,\n\u001b[1;32m 282\u001b[0m wait_for_ready\u001b[38;5;241m=\u001b[39mwait_for_ready,\n\u001b[1;32m 283\u001b[0m compression\u001b[38;5;241m=\u001b[39mcompression,\n\u001b[1;32m 284\u001b[0m )\n\u001b[1;32m 285\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m response\n", "File \u001b[0;32m~/anaconda3/lib/python3.11/site-packages/grpc/_interceptor.py:332\u001b[0m, in \u001b[0;36m_UnaryUnaryMultiCallable._with_call\u001b[0;34m(self, request, timeout, metadata, credentials, wait_for_ready, compression)\u001b[0m\n\u001b[1;32m 329\u001b[0m call \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_interceptor\u001b[38;5;241m.\u001b[39mintercept_unary_unary(\n\u001b[1;32m 330\u001b[0m continuation, client_call_details, request\n\u001b[1;32m 331\u001b[0m )\n\u001b[0;32m--> 332\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m call\u001b[38;5;241m.\u001b[39mresult(), call\n", "File \u001b[0;32m~/anaconda3/lib/python3.11/site-packages/grpc/_channel.py:440\u001b[0m, in \u001b[0;36m_InactiveRpcError.result\u001b[0;34m(self, timeout)\u001b[0m\n\u001b[1;32m 439\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"See grpc.Future.result.\"\"\"\u001b[39;00m\n\u001b[0;32m--> 440\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;28mself\u001b[39m\n", "File \u001b[0;32m~/anaconda3/lib/python3.11/site-packages/grpc/_interceptor.py:315\u001b[0m, in \u001b[0;36m_UnaryUnaryMultiCallable._with_call..continuation\u001b[0;34m(new_details, request)\u001b[0m\n\u001b[1;32m 314\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 315\u001b[0m response, call \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_thunk(new_method)\u001b[38;5;241m.\u001b[39mwith_call(\n\u001b[1;32m 316\u001b[0m request,\n\u001b[1;32m 317\u001b[0m timeout\u001b[38;5;241m=\u001b[39mnew_timeout,\n\u001b[1;32m 318\u001b[0m metadata\u001b[38;5;241m=\u001b[39mnew_metadata,\n\u001b[1;32m 319\u001b[0m credentials\u001b[38;5;241m=\u001b[39mnew_credentials,\n\u001b[1;32m 320\u001b[0m wait_for_ready\u001b[38;5;241m=\u001b[39mnew_wait_for_ready,\n\u001b[1;32m 321\u001b[0m compression\u001b[38;5;241m=\u001b[39mnew_compression,\n\u001b[1;32m 322\u001b[0m )\n\u001b[1;32m 323\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m _UnaryOutcome(response, call)\n", "File \u001b[0;32m~/anaconda3/lib/python3.11/site-packages/grpc/_channel.py:1198\u001b[0m, in \u001b[0;36m_UnaryUnaryMultiCallable.with_call\u001b[0;34m(self, request, timeout, metadata, credentials, wait_for_ready, compression)\u001b[0m\n\u001b[1;32m 1192\u001b[0m (\n\u001b[1;32m 1193\u001b[0m state,\n\u001b[1;32m 1194\u001b[0m call,\n\u001b[1;32m 1195\u001b[0m ) \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_blocking(\n\u001b[1;32m 1196\u001b[0m request, timeout, metadata, credentials, wait_for_ready, compression\n\u001b[1;32m 1197\u001b[0m )\n\u001b[0;32m-> 1198\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m _end_unary_response_blocking(state, call, \u001b[38;5;28;01mTrue\u001b[39;00m, \u001b[38;5;28;01mNone\u001b[39;00m)\n", "File \u001b[0;32m~/anaconda3/lib/python3.11/site-packages/grpc/_channel.py:1006\u001b[0m, in \u001b[0;36m_end_unary_response_blocking\u001b[0;34m(state, call, with_call, deadline)\u001b[0m\n\u001b[1;32m 1005\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m-> 1006\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m _InactiveRpcError(state)\n", "\u001b[0;31m_InactiveRpcError\u001b[0m: <_InactiveRpcError of RPC that terminated with:\n\tstatus = StatusCode.PERMISSION_DENIED\n\tdetails = \"The caller does not have permission\"\n\tdebug_error_string = \"UNKNOWN:Error received from peer ipv4:142.250.72.106:443 {created_time:\"2024-12-14T17:30:39.507315-05:00\", grpc_status:7, grpc_message:\"The caller does not have permission\"}\"\n>", "\nThe above exception was the direct cause of the following exception:\n", "\u001b[0;31mPermissionDenied\u001b[0m Traceback (most recent call last)", "File \u001b[0;32m~/anaconda3/lib/python3.11/site-packages/podcastfy/tts/providers/geminimulti.py:299\u001b[0m, in \u001b[0;36mGeminiMultiTTS.generate_audio\u001b[0;34m(self, text, voice, model, voice2, ending_message)\u001b[0m\n\u001b[1;32m 298\u001b[0m \u001b[38;5;66;03m# Generate speech for this chunk\u001b[39;00m\n\u001b[0;32m--> 299\u001b[0m response \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mclient\u001b[38;5;241m.\u001b[39msynthesize_speech(\n\u001b[1;32m 300\u001b[0m \u001b[38;5;28minput\u001b[39m\u001b[38;5;241m=\u001b[39msynthesis_input,\n\u001b[1;32m 301\u001b[0m voice\u001b[38;5;241m=\u001b[39mvoice_params,\n\u001b[1;32m 302\u001b[0m audio_config\u001b[38;5;241m=\u001b[39maudio_config\n\u001b[1;32m 303\u001b[0m )\n\u001b[1;32m 305\u001b[0m audio_chunks\u001b[38;5;241m.\u001b[39mappend(response\u001b[38;5;241m.\u001b[39maudio_content)\n", "File \u001b[0;32m~/anaconda3/lib/python3.11/site-packages/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py:910\u001b[0m, in \u001b[0;36mTextToSpeechClient.synthesize_speech\u001b[0;34m(self, request, input, voice, audio_config, retry, timeout, metadata)\u001b[0m\n\u001b[1;32m 909\u001b[0m \u001b[38;5;66;03m# Send the request.\u001b[39;00m\n\u001b[0;32m--> 910\u001b[0m response \u001b[38;5;241m=\u001b[39m rpc(\n\u001b[1;32m 911\u001b[0m request,\n\u001b[1;32m 912\u001b[0m retry\u001b[38;5;241m=\u001b[39mretry,\n\u001b[1;32m 913\u001b[0m timeout\u001b[38;5;241m=\u001b[39mtimeout,\n\u001b[1;32m 914\u001b[0m metadata\u001b[38;5;241m=\u001b[39mmetadata,\n\u001b[1;32m 915\u001b[0m )\n\u001b[1;32m 917\u001b[0m \u001b[38;5;66;03m# Done; return the response.\u001b[39;00m\n", "File \u001b[0;32m~/anaconda3/lib/python3.11/site-packages/google/api_core/gapic_v1/method.py:131\u001b[0m, in \u001b[0;36m_GapicCallable.__call__\u001b[0;34m(self, timeout, retry, compression, *args, **kwargs)\u001b[0m\n\u001b[1;32m 129\u001b[0m kwargs[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcompression\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m compression\n\u001b[0;32m--> 131\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m wrapped_func(\u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n", "File \u001b[0;32m~/anaconda3/lib/python3.11/site-packages/google/api_core/grpc_helpers.py:78\u001b[0m, in \u001b[0;36m_wrap_unary_errors..error_remapped_callable\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 77\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m grpc\u001b[38;5;241m.\u001b[39mRpcError \u001b[38;5;28;01mas\u001b[39;00m exc:\n\u001b[0;32m---> 78\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m exceptions\u001b[38;5;241m.\u001b[39mfrom_grpc_error(exc) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mexc\u001b[39;00m\n", "\u001b[0;31mPermissionDenied\u001b[0m: 403 The caller does not have permission", "\nThe above exception was the direct cause of the following exception:\n", "\u001b[0;31mRuntimeError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[5], line 7\u001b[0m\n\u001b[1;32m 3\u001b[0m os\u001b[38;5;241m.\u001b[39menviron[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mGOOGLE_APPLICATION_CREDENTIALS\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m./gen-lang-client-0097282688-faacfa05da8d.json\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 6\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mpodcastfy\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mclient\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m generate_podcast\n\u001b[0;32m----> 7\u001b[0m audio_file \u001b[38;5;241m=\u001b[39m generate_podcast(urls\u001b[38;5;241m=\u001b[39m[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mhttps://www.youtube.com/watch?v=7kbQnLN2y_I\u001b[39m\u001b[38;5;124m\"\u001b[39m], \n\u001b[1;32m 8\u001b[0m tts_model\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mgeminimulti\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", "File \u001b[0;32m~/anaconda3/lib/python3.11/site-packages/podcastfy/client.py:372\u001b[0m, in \u001b[0;36mgenerate_podcast\u001b[0;34m(urls, url_file, transcript_file, tts_model, transcript_only, config, conversation_config, image_paths, is_local, text, llm_model_name, api_key_label, topic, longform)\u001b[0m\n\u001b[1;32m 366\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m urls_list \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m image_paths \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m text \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m topic:\n\u001b[1;32m 367\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 368\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNo input provided. Please provide either \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124murls\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124murl_file\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 369\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtranscript_file\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mimage_paths\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtext\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, or \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtopic\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 370\u001b[0m )\n\u001b[0;32m--> 372\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m process_content(\n\u001b[1;32m 373\u001b[0m urls\u001b[38;5;241m=\u001b[39murls_list,\n\u001b[1;32m 374\u001b[0m tts_model\u001b[38;5;241m=\u001b[39mtts_model,\n\u001b[1;32m 375\u001b[0m generate_audio\u001b[38;5;241m=\u001b[39m\u001b[38;5;129;01mnot\u001b[39;00m transcript_only,\n\u001b[1;32m 376\u001b[0m config\u001b[38;5;241m=\u001b[39mdefault_config,\n\u001b[1;32m 377\u001b[0m conversation_config\u001b[38;5;241m=\u001b[39mconversation_config,\n\u001b[1;32m 378\u001b[0m image_paths\u001b[38;5;241m=\u001b[39mimage_paths,\n\u001b[1;32m 379\u001b[0m is_local\u001b[38;5;241m=\u001b[39mis_local,\n\u001b[1;32m 380\u001b[0m text\u001b[38;5;241m=\u001b[39mtext,\n\u001b[1;32m 381\u001b[0m model_name\u001b[38;5;241m=\u001b[39mllm_model_name,\n\u001b[1;32m 382\u001b[0m api_key_label\u001b[38;5;241m=\u001b[39mapi_key_label,\n\u001b[1;32m 383\u001b[0m topic\u001b[38;5;241m=\u001b[39mtopic,\n\u001b[1;32m 384\u001b[0m longform\u001b[38;5;241m=\u001b[39mlongform\n\u001b[1;32m 385\u001b[0m )\n\u001b[1;32m 387\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[1;32m 388\u001b[0m logger\u001b[38;5;241m.\u001b[39merror(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mAn error occurred: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mstr\u001b[39m(e)\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n", "File \u001b[0;32m~/anaconda3/lib/python3.11/site-packages/podcastfy/client.py:138\u001b[0m, in \u001b[0;36mprocess_content\u001b[0;34m(urls, transcript_file, tts_model, generate_audio, config, conversation_config, image_paths, is_local, text, model_name, api_key_label, topic, longform)\u001b[0m\n\u001b[1;32m 134\u001b[0m random_filename \u001b[38;5;241m=\u001b[39m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mpodcast_\u001b[39m\u001b[38;5;132;01m{\u001b[39;00muuid\u001b[38;5;241m.\u001b[39muuid4()\u001b[38;5;241m.\u001b[39mhex\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m.mp3\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 135\u001b[0m audio_file \u001b[38;5;241m=\u001b[39m os\u001b[38;5;241m.\u001b[39mpath\u001b[38;5;241m.\u001b[39mjoin(\n\u001b[1;32m 136\u001b[0m output_directories\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124maudio\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdata/audio\u001b[39m\u001b[38;5;124m\"\u001b[39m), random_filename\n\u001b[1;32m 137\u001b[0m )\n\u001b[0;32m--> 138\u001b[0m text_to_speech\u001b[38;5;241m.\u001b[39mconvert_to_speech(qa_content, audio_file)\n\u001b[1;32m 139\u001b[0m logger\u001b[38;5;241m.\u001b[39minfo(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mPodcast generated successfully using \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtts_model\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m TTS model\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 140\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m audio_file\n", "File \u001b[0;32m~/anaconda3/lib/python3.11/site-packages/podcastfy/text_to_speech.py:104\u001b[0m, in \u001b[0;36mTextToSpeech.convert_to_speech\u001b[0;34m(self, text, output_file)\u001b[0m\n\u001b[1;32m 102\u001b[0m voice2 \u001b[38;5;241m=\u001b[39m provider_config\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdefault_voices\u001b[39m\u001b[38;5;124m\"\u001b[39m, {})\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124manswer\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 103\u001b[0m model \u001b[38;5;241m=\u001b[39m provider_config\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmodel\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m--> 104\u001b[0m audio_data_list \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mprovider\u001b[38;5;241m.\u001b[39mgenerate_audio(\n\u001b[1;32m 105\u001b[0m cleaned_text,\n\u001b[1;32m 106\u001b[0m voice\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mS\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 107\u001b[0m model\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124men-US-Studio-MultiSpeaker\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 108\u001b[0m voice2\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mR\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 109\u001b[0m ending_message\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mending_message,\n\u001b[1;32m 110\u001b[0m )\n\u001b[1;32m 112\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 113\u001b[0m \u001b[38;5;66;03m# First verify we have data\u001b[39;00m\n\u001b[1;32m 114\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m audio_data_list:\n", "File \u001b[0;32m~/anaconda3/lib/python3.11/site-packages/podcastfy/tts/providers/geminimulti.py:313\u001b[0m, in \u001b[0;36mGeminiMultiTTS.generate_audio\u001b[0;34m(self, text, voice, model, voice2, ending_message)\u001b[0m\n\u001b[1;32m 311\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[1;32m 312\u001b[0m logger\u001b[38;5;241m.\u001b[39merror(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mFailed to generate audio: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mstr\u001b[39m(e)\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m, exc_info\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m)\n\u001b[0;32m--> 313\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mRuntimeError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mFailed to generate audio: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mstr\u001b[39m(e)\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01me\u001b[39;00m\n", "\u001b[0;31mRuntimeError\u001b[0m: Failed to generate audio: 403 The caller does not have permission" ] } ], "source": [ "import os\n", "\n", "os.environ[\"GOOGLE_APPLICATION_CREDENTIALS\"] = \"./gen-lang-client-0097282688-faacfa05da8d.json\"\n", "\n", "\n", "from podcastfy.client import generate_podcast\n", "audio_file = generate_podcast(urls=[\"https://www.youtube.com/watch?v=7kbQnLN2y_I\"], \n", " tts_model=\"geminimulti\")" ] }, { "cell_type": "code", "execution_count": 17, "id": "d71c707d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "./gen-lang-client-0097282688-faacfa05da8d.json\n" ] } ], "source": [ "import os\n", "\n", "os.environ[\"GOOGLE_APPLICATION_CREDENTIALS\"] = \"./gen-lang-client-0097282688-faacfa05da8d.json\"\n", "\n", "\n", "print(os.environ.get(\"GOOGLE_APPLICATION_CREDENTIALS\"))\n" ] }, { "cell_type": "code", "execution_count": 18, "id": "2cf22027", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2024-12-15 17:36:31,428 - podcastfy.client - INFO - Processing 1 links\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Generating podcast for: https://www.youtube.com/watch?v=Y-_k7qFaXUE with title: Cookies N Cream Parfaits _ Episode 1060\n", "Generating podcast...\n", "Transcript saved to ./data/transcripts/transcript_319d27e994834c71a2df8a0c0b3a3d67.txt\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2024-12-15 17:37:21,802 - podcastfy.client - INFO - Podcast generated successfully using openai TTS model\n", "2024-12-15 17:37:21,982 - podcastfy.client - INFO - Processing 1 links\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Podcast saved as: Cookies N Cream Parfaits _ Episode 1060.mp3\n", "Generating podcast for: https://www.youtube.com/watch?v=sxt4YCIsn2I with title: The Legendary Dosa Man of NYC _ Street Food Icons\n", "Generating podcast...\n", "Transcript saved to ./data/transcripts/transcript_709c9cc9c0f14af191abd4606f49ed22.txt\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2024-12-15 17:38:34,206 - podcastfy.client - INFO - Podcast generated successfully using openai TTS model\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Podcast saved as: The Legendary Dosa Man of NYC _ Street Food Icons.mp3\n", "Generating podcast for: https://www.youtube.com/watch?v=-wRHXXyR6sc with title: Shirataki Noodles are INSANE for Weight Loss.\n", "Generating podcast...\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2024-12-15 17:38:34,434 - podcastfy.client - INFO - Processing 1 links\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Transcript saved to ./data/transcripts/transcript_86d24146ce0543dab33a8da335070864.txt\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2024-12-15 17:39:32,735 - podcastfy.client - INFO - Podcast generated successfully using openai TTS model\n", "2024-12-15 17:39:32,923 - podcastfy.client - INFO - Processing 1 links\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Podcast saved as: Shirataki Noodles are INSANE for Weight Loss..mp3\n", "Generating podcast for: https://www.youtube.com/watch?v=jlp3p95LrYk with title: You’ll get addicted to this late night snack\n", "Generating podcast...\n", "Transcript saved to ./data/transcripts/transcript_b806e8e9959e45fe94af64061a011395.txt\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2024-12-15 17:40:31,909 - podcastfy.client - INFO - Podcast generated successfully using openai TTS model\n", "2024-12-15 17:40:32,086 - podcastfy.client - INFO - Processing 1 links\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Podcast saved as: You’ll get addicted to this late night snack.mp3\n", "Generating podcast for: https://www.youtube.com/watch?v=Z-husjZkxHw with title: The 5 minute baguette\n", "Generating podcast...\n", "Transcript saved to ./data/transcripts/transcript_9776c2918bff40eba22d9e2c09f02d88.txt\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2024-12-15 17:41:36,079 - podcastfy.client - INFO - Podcast generated successfully using openai TTS model\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Podcast saved as: The 5 minute baguette.mp3\n", "Generating podcast for: https://www.youtube.com/watch?v=7umUJ0lAVbQ with title: Chipotle’s Chicken Cooked at Home - By a Former Chipotle Employee\n", "Generating podcast...\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2024-12-15 17:41:36,305 - podcastfy.client - INFO - Processing 1 links\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Transcript saved to ./data/transcripts/transcript_048086ffc5494f3ea6aa29a5d05c26ea.txt\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2024-12-15 17:42:48,208 - podcastfy.client - INFO - Podcast generated successfully using openai TTS model\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Podcast saved as: Chipotle’s Chicken Cooked at Home - By a Former Chipotle Employee.mp3\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2024-12-15 17:42:48,466 - podcastfy.client - INFO - Processing 1 links\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Generating podcast for: https://www.youtube.com/watch?v=EqCUENkCQqw with title: How to make incredible NAAN at home\n", "Generating podcast...\n", "Transcript saved to ./data/transcripts/transcript_33735b5ef8a9499ebd1e32667cabff47.txt\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2024-12-15 17:43:49,228 - podcastfy.client - INFO - Podcast generated successfully using openai TTS model\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Podcast saved as: How to make incredible NAAN at home.mp3\n", "Generating podcast for: https://www.youtube.com/watch?v=SXYaMr6kFTE with title: The ONLY Egg Salad Recipe You Need\n", "Generating podcast...\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2024-12-15 17:43:49,440 - podcastfy.client - INFO - Processing 1 links\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Transcript saved to ./data/transcripts/transcript_9b4c55962b6d40e2968f5bb924489e1a.txt\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2024-12-15 17:44:53,201 - podcastfy.client - INFO - Podcast generated successfully using openai TTS model\n", "2024-12-15 17:44:53,392 - podcastfy.client - INFO - Processing 1 links\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Podcast saved as: The ONLY Egg Salad Recipe You Need.mp3\n", "Generating podcast for: https://www.youtube.com/watch?v=rSEASZWV8oc with title: 1 ALL PURPOSE BASE GRAVY MASALA Make Several Curry Recipes\n", "Generating podcast...\n", "Transcript saved to ./data/transcripts/transcript_a460c20dba224a6e9bf07bb3f48c0a99.txt\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2024-12-15 17:46:09,928 - podcastfy.client - INFO - Podcast generated successfully using openai TTS model\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Podcast saved as: 1 ALL PURPOSE BASE GRAVY MASALA Make Several Curry Recipes.mp3\n", "Generating podcast for: https://www.youtube.com/watch?v=fahxFZfVZqI with title: Chicken Tinga Tacos - You Suck at Cooking (episode 167)\n", "Generating podcast...\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2024-12-15 17:46:10,148 - podcastfy.client - INFO - Processing 1 links\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Transcript saved to ./data/transcripts/transcript_53b346ec6682435385d8adf10878700a.txt\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2024-12-15 17:47:27,734 - podcastfy.client - INFO - Podcast generated successfully using openai TTS model\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Podcast saved as: Chicken Tinga Tacos - You Suck at Cooking (episode 167).mp3\n", "Generating podcast for: https://www.youtube.com/watch?v=2emYD4d3abg with title: Questa ricetta vi farà impazzire❗ Non ho mai mangiato una pasta cosi deliziosa❗\n", "Generating podcast...\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2024-12-15 17:47:27,943 - podcastfy.client - INFO - Processing 1 links\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Transcript saved to ./data/transcripts/transcript_5bcabeee9756463e86a0b3dfc08cc317.txt\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2024-12-15 17:48:40,105 - podcastfy.client - INFO - Podcast generated successfully using openai TTS model\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Podcast saved as: Questa ricetta vi farà impazzire❗ Non ho mai mangiato una pasta cosi deliziosa❗.mp3\n", "All podcasts have been processed.\n" ] } ], "source": [ "from podcastfy.client import generate_podcast\n", "from googleapiclient.discovery import build\n", "import re\n", "import os\n", "\n", "# Your API key\n", "API_KEY = \"AIzaSyASKuARMAZ2VtwjWx_7di_m544TsRVlU_A\"\n", "\n", "# List of YouTube video IDs\n", "youtube_ids = [\n", " \"Y-_k7qFaXUE\",\n", " \"sxt4YCIsn2I\",\n", " \"-wRHXXyR6sc\",\n", " \"jlp3p95LrYk\",\n", " \"Z-husjZkxHw\",\n", " \"7umUJ0lAVbQ\",\n", " \"EqCUENkCQqw\",\n", " \"SXYaMr6kFTE\",\n", " \"rSEASZWV8oc\",\n", " \"fahxFZfVZqI\",\n", " \"2emYD4d3abg\"\n", "]\n", "\n", "def get_video_title(video_id, api_key):\n", " \"\"\"Fetch the video title using the YouTube Data API.\"\"\"\n", " youtube = build(\"youtube\", \"v3\", developerKey=api_key)\n", " request = youtube.videos().list(part=\"snippet\", id=video_id)\n", " response = request.execute()\n", " \n", " if response[\"items\"]:\n", " title = response[\"items\"][0][\"snippet\"][\"title\"]\n", " # Clean title to be a valid filename\n", " clean_title = re.sub(r'[\\\\/*?:\"<>|]', \"_\", title)\n", " return clean_title\n", " else:\n", " return f\"video_{video_id}\"\n", "\n", "# Loop through each video ID and generate a podcast with the title as the filename\n", "for video_id in youtube_ids:\n", " # Get the video title\n", " title = get_video_title(video_id, API_KEY)\n", " url = f\"https://www.youtube.com/watch?v={video_id}\"\n", " \n", " print(f\"Generating podcast for: {url} with title: {title}\")\n", " \n", " # Generate the podcast\n", " audio_file = generate_podcast(urls=[url])\n", " \n", " # Rename the generated podcast to title.mp3\n", " new_filename = f\"{title}.mp3\"\n", " if audio_file and os.path.exists(audio_file):\n", " os.rename(audio_file, new_filename)\n", " print(f\"Podcast saved as: {new_filename}\")\n", " else:\n", " print(f\"Failed to generate podcast for: {url}\")\n", "\n", "print(\"All podcasts have been processed.\")" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.5" } }, "nbformat": 4, "nbformat_minor": 5 }