universal-mcp-applications 0.1.2__py3-none-any.whl → 0.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- universal_mcp/applications/airtable/app.py +1 -0
- universal_mcp/applications/apollo/app.py +1 -0
- universal_mcp/applications/aws_s3/app.py +3 -4
- universal_mcp/applications/bill/app.py +3 -3
- universal_mcp/applications/box/app.py +2 -6
- universal_mcp/applications/braze/app.py +2 -6
- universal_mcp/applications/cal_com_v2/app.py +22 -64
- universal_mcp/applications/confluence/app.py +1 -0
- universal_mcp/applications/contentful/app.py +8 -19
- universal_mcp/applications/digitalocean/app.py +9 -27
- universal_mcp/applications/{domain-checker → domain_checker}/app.py +2 -1
- universal_mcp/applications/elevenlabs/app.py +98 -3188
- universal_mcp/applications/falai/app.py +1 -0
- universal_mcp/applications/file_system/__init__.py +1 -0
- universal_mcp/applications/file_system/app.py +96 -0
- universal_mcp/applications/fireflies/app.py +4 -3
- universal_mcp/applications/fpl/app.py +1 -0
- universal_mcp/applications/fpl/utils/fixtures.py +1 -1
- universal_mcp/applications/fpl/utils/helper.py +1 -1
- universal_mcp/applications/fpl/utils/position_utils.py +0 -1
- universal_mcp/applications/{ghost-content → ghost_content}/app.py +2 -1
- universal_mcp/applications/github/app.py +3 -1
- universal_mcp/applications/google_calendar/app.py +2 -1
- universal_mcp/applications/google_docs/app.py +1 -1
- universal_mcp/applications/google_drive/app.py +2 -1
- universal_mcp/applications/google_gemini/app.py +138 -618
- universal_mcp/applications/google_mail/app.py +2 -1
- universal_mcp/applications/{google-searchconsole → google_searchconsole}/app.py +1 -1
- universal_mcp/applications/google_sheet/app.py +2 -1
- universal_mcp/applications/google_sheet/helper.py +156 -116
- universal_mcp/applications/hashnode/app.py +1 -0
- universal_mcp/applications/{http-tools → http_tools}/app.py +2 -1
- universal_mcp/applications/hubspot/app.py +4 -1
- universal_mcp/applications/jira/app.py +7 -18
- universal_mcp/applications/markitdown/app.py +2 -3
- universal_mcp/applications/ms_teams/app.py +1 -1
- universal_mcp/applications/openai/app.py +2 -3
- universal_mcp/applications/outlook/app.py +1 -3
- universal_mcp/applications/pipedrive/app.py +2 -6
- universal_mcp/applications/reddit/app.py +1 -0
- universal_mcp/applications/replicate/app.py +3 -3
- universal_mcp/applications/resend/app.py +1 -2
- universal_mcp/applications/rocketlane/app.py +1 -0
- universal_mcp/applications/semrush/app.py +1 -1
- universal_mcp/applications/sentry/README.md +20 -20
- universal_mcp/applications/sentry/app.py +40 -40
- universal_mcp/applications/serpapi/app.py +2 -2
- universal_mcp/applications/sharepoint/app.py +1 -0
- universal_mcp/applications/shopify/app.py +1 -0
- universal_mcp/applications/slack/app.py +3 -3
- universal_mcp/applications/trello/app.py +9 -27
- universal_mcp/applications/twilio/__init__.py +1 -0
- universal_mcp/applications/{twillo → twilio}/app.py +2 -2
- universal_mcp/applications/twitter/README.md +1 -1
- universal_mcp/applications/twitter/api_segments/dm_conversations_api.py +2 -2
- universal_mcp/applications/twitter/api_segments/lists_api.py +1 -1
- universal_mcp/applications/unipile/app.py +5 -1
- universal_mcp/applications/whatsapp/app.py +18 -17
- universal_mcp/applications/whatsapp/audio.py +110 -0
- universal_mcp/applications/whatsapp/whatsapp.py +398 -0
- universal_mcp/applications/whatsapp_business/app.py +1 -1
- universal_mcp/applications/youtube/app.py +195 -191
- universal_mcp/applications/zenquotes/app.py +1 -1
- {universal_mcp_applications-0.1.2.dist-info → universal_mcp_applications-0.1.3.dist-info}/METADATA +4 -2
- {universal_mcp_applications-0.1.2.dist-info → universal_mcp_applications-0.1.3.dist-info}/RECORD +76 -75
- universal_mcp/applications/google-ads/__init__.py +0 -1
- universal_mcp/applications/google-ads/app.py +0 -23
- universal_mcp/applications/twillo/README.md +0 -0
- universal_mcp/applications/twillo/__init__.py +0 -1
- /universal_mcp/applications/{domain-checker → domain_checker}/README.md +0 -0
- /universal_mcp/applications/{domain-checker → domain_checker}/__init__.py +0 -0
- /universal_mcp/applications/{ghost-content → ghost_content}/README.md +0 -0
- /universal_mcp/applications/{ghost-content → ghost_content}/__init__.py +0 -0
- /universal_mcp/applications/{google-searchconsole → google_searchconsole}/README.md +0 -0
- /universal_mcp/applications/{google-searchconsole → google_searchconsole}/__init__.py +0 -0
- /universal_mcp/applications/{http-tools → http_tools}/README.md +0 -0
- /universal_mcp/applications/{http-tools → http_tools}/__init__.py +0 -0
- /universal_mcp/applications/{google-ads → twilio}/README.md +0 -0
- {universal_mcp_applications-0.1.2.dist-info → universal_mcp_applications-0.1.3.dist-info}/WHEEL +0 -0
- {universal_mcp_applications-0.1.2.dist-info → universal_mcp_applications-0.1.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -209,9 +209,7 @@ class TrelloApp(APIApplication):
|
|
|
209
209
|
except ValueError:
|
|
210
210
|
return None
|
|
211
211
|
|
|
212
|
-
def get_actions_id_card(
|
|
213
|
-
self, id: str, fields: str | None = None
|
|
214
|
-
) -> dict[str, Any]:
|
|
212
|
+
def get_actions_id_card(self, id: str, fields: str | None = None) -> dict[str, Any]:
|
|
215
213
|
"""
|
|
216
214
|
Get the Card for an Action
|
|
217
215
|
|
|
@@ -243,9 +241,7 @@ class TrelloApp(APIApplication):
|
|
|
243
241
|
except ValueError:
|
|
244
242
|
return None
|
|
245
243
|
|
|
246
|
-
def get_actions_id_list(
|
|
247
|
-
self, id: str, fields: str | None = None
|
|
248
|
-
) -> dict[str, Any]:
|
|
244
|
+
def get_actions_id_list(self, id: str, fields: str | None = None) -> dict[str, Any]:
|
|
249
245
|
"""
|
|
250
246
|
Get the List for an Action
|
|
251
247
|
|
|
@@ -2158,9 +2154,7 @@ class TrelloApp(APIApplication):
|
|
|
2158
2154
|
except ValueError:
|
|
2159
2155
|
return None
|
|
2160
2156
|
|
|
2161
|
-
def post_boards_id_boardplugins(
|
|
2162
|
-
self, id: str, idPlugin: str | None = None
|
|
2163
|
-
) -> Any:
|
|
2157
|
+
def post_boards_id_boardplugins(self, id: str, idPlugin: str | None = None) -> Any:
|
|
2164
2158
|
"""
|
|
2165
2159
|
Enable a Power-Up on a Board
|
|
2166
2160
|
|
|
@@ -2849,9 +2843,7 @@ class TrelloApp(APIApplication):
|
|
|
2849
2843
|
except ValueError:
|
|
2850
2844
|
return None
|
|
2851
2845
|
|
|
2852
|
-
def get_cards_id_checkitemstates(
|
|
2853
|
-
self, id: str, fields: str | None = None
|
|
2854
|
-
) -> Any:
|
|
2846
|
+
def get_cards_id_checkitemstates(self, id: str, fields: str | None = None) -> Any:
|
|
2855
2847
|
"""
|
|
2856
2848
|
Get checkItems on a Card
|
|
2857
2849
|
|
|
@@ -3842,9 +3834,7 @@ class TrelloApp(APIApplication):
|
|
|
3842
3834
|
except ValueError:
|
|
3843
3835
|
return None
|
|
3844
3836
|
|
|
3845
|
-
def post_cards_id_labels(
|
|
3846
|
-
self, id: str, color: str, name: str | None = None
|
|
3847
|
-
) -> Any:
|
|
3837
|
+
def post_cards_id_labels(self, id: str, color: str, name: str | None = None) -> Any:
|
|
3848
3838
|
"""
|
|
3849
3839
|
Create a new Label on a Card
|
|
3850
3840
|
|
|
@@ -5525,9 +5515,7 @@ class TrelloApp(APIApplication):
|
|
|
5525
5515
|
except ValueError:
|
|
5526
5516
|
return None
|
|
5527
5517
|
|
|
5528
|
-
def post_enterprises_id_tokens(
|
|
5529
|
-
self, id: str, expiration: str | None = None
|
|
5530
|
-
) -> Any:
|
|
5518
|
+
def post_enterprises_id_tokens(self, id: str, expiration: str | None = None) -> Any:
|
|
5531
5519
|
"""
|
|
5532
5520
|
Create an auth Token for an Enterprise.
|
|
5533
5521
|
|
|
@@ -6340,9 +6328,7 @@ class TrelloApp(APIApplication):
|
|
|
6340
6328
|
except ValueError:
|
|
6341
6329
|
return None
|
|
6342
6330
|
|
|
6343
|
-
def put_lists_id_field(
|
|
6344
|
-
self, id: str, field: str, value: Any | None = None
|
|
6345
|
-
) -> Any:
|
|
6331
|
+
def put_lists_id_field(self, id: str, field: str, value: Any | None = None) -> Any:
|
|
6346
6332
|
"""
|
|
6347
6333
|
Update a field on a List
|
|
6348
6334
|
|
|
@@ -6680,9 +6666,7 @@ class TrelloApp(APIApplication):
|
|
|
6680
6666
|
except ValueError:
|
|
6681
6667
|
return None
|
|
6682
6668
|
|
|
6683
|
-
def get_members_id_actions(
|
|
6684
|
-
self, id: str, filter: str | None = None
|
|
6685
|
-
) -> list[Any]:
|
|
6669
|
+
def get_members_id_actions(self, id: str, filter: str | None = None) -> list[Any]:
|
|
6686
6670
|
"""
|
|
6687
6671
|
Get a Member's Actions
|
|
6688
6672
|
|
|
@@ -8007,9 +7991,7 @@ class TrelloApp(APIApplication):
|
|
|
8007
7991
|
except ValueError:
|
|
8008
7992
|
return None
|
|
8009
7993
|
|
|
8010
|
-
def get_members_id_tokens(
|
|
8011
|
-
self, id: str, webhooks: bool | None = None
|
|
8012
|
-
) -> list[Any]:
|
|
7994
|
+
def get_members_id_tokens(self, id: str, webhooks: bool | None = None) -> list[Any]:
|
|
8013
7995
|
"""
|
|
8014
7996
|
Get Member's Tokens
|
|
8015
7997
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .app import TwilioApp
|
|
@@ -17,13 +17,13 @@ from universal_mcp.exceptions import NotAuthorizedError, ToolError
|
|
|
17
17
|
from universal_mcp.integrations import Integration
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
class
|
|
20
|
+
class TwilioApp(APIApplication):
|
|
21
21
|
"""
|
|
22
22
|
Application for interacting with the Twilio Messaging API using the official Python SDK.
|
|
23
23
|
"""
|
|
24
24
|
|
|
25
25
|
def __init__(self, integration: Integration, **kwargs: Any) -> None:
|
|
26
|
-
super().__init__(name="
|
|
26
|
+
super().__init__(name="twilio", integration=integration, **kwargs)
|
|
27
27
|
self.base_url = "https://api.twilio.com/2010-04-01"
|
|
28
28
|
self._twilio_client: Any | None = None
|
|
29
29
|
self._account_sid: str | None = None
|
|
@@ -13,7 +13,7 @@ This is automatically generated from OpenAPI schema for the TwitterApp API.
|
|
|
13
13
|
| `create_batch_compliance_job` | Creates a new compliance job using JSON data in the request body and authenticates the request using a Bearer token. |
|
|
14
14
|
| `get_batch_compliance_job` | Retrieves information about a compliance job by its ID using the BearerToken for authentication. |
|
|
15
15
|
| `dm_conversation_id_create` | Creates a new group Direct Message conversation and sends an initial message to the specified participants. |
|
|
16
|
-
| `
|
|
16
|
+
| `get_dm_convo_with_patcpnts_id_dm_evnts` | Retrieves a list of direct message events for a conversation with a specific participant, allowing for optional filtering by event types and pagination. |
|
|
17
17
|
| `get_dm_conversations_id_dm_events` | Retrieves a list of direct message events for a specified conversation ID, allowing for optional filtering by event types and pagination. |
|
|
18
18
|
| `get_dm_events` | Retrieves a list of direct message events with optional filtering by event types, pagination, and field expansions for media, users, tweets, and DM event details. |
|
|
19
19
|
| `dm_event_delete` | Deletes a DM event by its ID using the DELETE method, requiring authentication via OAuth2UserToken with "dm.read" and "dm.write" scopes or UserToken. |
|
|
@@ -49,7 +49,7 @@ class DmConversationsApi(APISegmentBase):
|
|
|
49
49
|
response.raise_for_status()
|
|
50
50
|
return response.json()
|
|
51
51
|
|
|
52
|
-
def
|
|
52
|
+
def get_dm_convo_with_patcpnts_id_dm_evnts(
|
|
53
53
|
self,
|
|
54
54
|
participant_id,
|
|
55
55
|
max_results=None,
|
|
@@ -248,7 +248,7 @@ class DmConversationsApi(APISegmentBase):
|
|
|
248
248
|
def list_tools(self):
|
|
249
249
|
return [
|
|
250
250
|
self.dm_conversation_id_create,
|
|
251
|
-
self.
|
|
251
|
+
self.get_dm_convo_with_patcpnts_id_dm_evnts,
|
|
252
252
|
self.dm_conversation_with_user_event_id_create,
|
|
253
253
|
self.dm_conversation_by_id_event_id_create,
|
|
254
254
|
self.get_dm_conversations_id_dm_events,
|
|
@@ -3,6 +3,7 @@ from collections.abc import Callable
|
|
|
3
3
|
from typing import Any, Literal
|
|
4
4
|
|
|
5
5
|
from loguru import logger
|
|
6
|
+
|
|
6
7
|
from universal_mcp.applications.application import APIApplication
|
|
7
8
|
from universal_mcp.integrations import Integration
|
|
8
9
|
|
|
@@ -666,7 +667,10 @@ class UnipileApp(APIApplication):
|
|
|
666
667
|
keywords: str | None = None,
|
|
667
668
|
sort_by: Literal["relevance", "date"] | None = None,
|
|
668
669
|
date_posted: Literal["past_day", "past_week", "past_month"] | None = None,
|
|
669
|
-
content_type: Literal[
|
|
670
|
+
content_type: Literal[
|
|
671
|
+
"videos", "images", "live_videos", "collaborative_articles", "documents"
|
|
672
|
+
]
|
|
673
|
+
| None = None,
|
|
670
674
|
posted_by: dict[str, Any] | None = None,
|
|
671
675
|
mentioning: dict[str, Any] | None = None,
|
|
672
676
|
author: dict[str, Any] | None = None,
|
|
@@ -1,56 +1,57 @@
|
|
|
1
1
|
from typing import Any
|
|
2
2
|
|
|
3
3
|
import requests
|
|
4
|
-
from
|
|
5
|
-
from universal_mcp.exceptions import NotAuthorizedError
|
|
6
|
-
from universal_mcp.integrations import AgentRIntegration
|
|
7
|
-
from universal_mcp_whatsapp.whatsapp import (
|
|
4
|
+
from .whatsapp import (
|
|
8
5
|
WHATSAPP_API_BASE_URL,
|
|
9
6
|
)
|
|
10
|
-
from
|
|
7
|
+
from .whatsapp import (
|
|
11
8
|
download_media as whatsapp_download_media,
|
|
12
9
|
)
|
|
13
|
-
from
|
|
10
|
+
from .whatsapp import (
|
|
14
11
|
get_chat as whatsapp_get_chat,
|
|
15
12
|
)
|
|
16
|
-
from
|
|
13
|
+
from .whatsapp import (
|
|
17
14
|
get_contact_chats as whatsapp_get_contact_chats,
|
|
18
15
|
)
|
|
19
|
-
from
|
|
16
|
+
from .whatsapp import (
|
|
20
17
|
get_direct_chat_by_contact as whatsapp_get_direct_chat_by_contact,
|
|
21
18
|
)
|
|
22
|
-
from
|
|
19
|
+
from .whatsapp import (
|
|
23
20
|
get_last_interaction as whatsapp_get_last_interaction,
|
|
24
21
|
)
|
|
25
|
-
from
|
|
22
|
+
from .whatsapp import (
|
|
26
23
|
get_message_context as whatsapp_get_message_context,
|
|
27
24
|
)
|
|
28
|
-
from
|
|
25
|
+
from .whatsapp import (
|
|
29
26
|
list_chats as whatsapp_list_chats,
|
|
30
27
|
)
|
|
31
|
-
from
|
|
28
|
+
from .whatsapp import (
|
|
32
29
|
list_messages as whatsapp_list_messages,
|
|
33
30
|
)
|
|
34
|
-
from
|
|
31
|
+
from .whatsapp import (
|
|
35
32
|
search_contacts as whatsapp_search_contacts,
|
|
36
33
|
)
|
|
37
|
-
from
|
|
34
|
+
from .whatsapp import (
|
|
38
35
|
send_audio_message as whatsapp_audio_voice_message,
|
|
39
36
|
)
|
|
40
|
-
from
|
|
37
|
+
from .whatsapp import (
|
|
41
38
|
send_file as whatsapp_send_file,
|
|
42
39
|
)
|
|
43
|
-
from
|
|
40
|
+
from .whatsapp import (
|
|
44
41
|
send_message as whatsapp_send_message,
|
|
45
42
|
)
|
|
46
43
|
|
|
44
|
+
from universal_mcp.applications.application import BaseApplication
|
|
45
|
+
from universal_mcp.exceptions import NotAuthorizedError
|
|
46
|
+
from universal_mcp.agentr.integration import AgentrIntegration
|
|
47
|
+
|
|
47
48
|
|
|
48
49
|
class WhatsappApp(BaseApplication):
|
|
49
50
|
"""
|
|
50
51
|
Base class for Universal MCP Applications.
|
|
51
52
|
"""
|
|
52
53
|
|
|
53
|
-
def __init__(self, integration:
|
|
54
|
+
def __init__(self, integration: AgentrIntegration | None = None, **kwargs) -> None:
|
|
54
55
|
super().__init__(name="whatsapp", integration=integration, **kwargs)
|
|
55
56
|
self.base_url = WHATSAPP_API_BASE_URL
|
|
56
57
|
self._api_key: str = integration.client.api_key if integration else None
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import subprocess
|
|
3
|
+
import tempfile
|
|
4
|
+
|
|
5
|
+
def convert_to_opus_ogg(input_file, output_file=None, bitrate="32k", sample_rate=24000):
|
|
6
|
+
"""
|
|
7
|
+
Convert an audio file to Opus format in an Ogg container.
|
|
8
|
+
|
|
9
|
+
Args:
|
|
10
|
+
input_file (str): Path to the input audio file
|
|
11
|
+
output_file (str, optional): Path to save the output file. If None, replaces the
|
|
12
|
+
extension of input_file with .ogg
|
|
13
|
+
bitrate (str, optional): Target bitrate for Opus encoding (default: "32k")
|
|
14
|
+
sample_rate (int, optional): Sample rate for output (default: 24000)
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
str: Path to the converted file
|
|
18
|
+
|
|
19
|
+
Raises:
|
|
20
|
+
FileNotFoundError: If the input file doesn't exist
|
|
21
|
+
RuntimeError: If the ffmpeg conversion fails
|
|
22
|
+
"""
|
|
23
|
+
if not os.path.isfile(input_file):
|
|
24
|
+
raise FileNotFoundError(f"Input file not found: {input_file}")
|
|
25
|
+
|
|
26
|
+
# If no output file is specified, replace the extension with .ogg
|
|
27
|
+
if output_file is None:
|
|
28
|
+
output_file = os.path.splitext(input_file)[0] + ".ogg"
|
|
29
|
+
|
|
30
|
+
# Ensure the output directory exists
|
|
31
|
+
output_dir = os.path.dirname(output_file)
|
|
32
|
+
if output_dir and not os.path.exists(output_dir):
|
|
33
|
+
os.makedirs(output_dir)
|
|
34
|
+
|
|
35
|
+
# Build the ffmpeg command
|
|
36
|
+
cmd = [
|
|
37
|
+
"ffmpeg",
|
|
38
|
+
"-i", input_file,
|
|
39
|
+
"-c:a", "libopus",
|
|
40
|
+
"-b:a", bitrate,
|
|
41
|
+
"-ar", str(sample_rate),
|
|
42
|
+
"-application", "voip", # Optimize for voice
|
|
43
|
+
"-vbr", "on", # Variable bitrate
|
|
44
|
+
"-compression_level", "10", # Maximum compression
|
|
45
|
+
"-frame_duration", "60", # 60ms frames (good for voice)
|
|
46
|
+
"-y", # Overwrite output file if it exists
|
|
47
|
+
output_file
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
# Run the ffmpeg command and capture output
|
|
52
|
+
process = subprocess.run(
|
|
53
|
+
cmd,
|
|
54
|
+
stdout=subprocess.PIPE,
|
|
55
|
+
stderr=subprocess.PIPE,
|
|
56
|
+
text=True,
|
|
57
|
+
check=True
|
|
58
|
+
)
|
|
59
|
+
return output_file
|
|
60
|
+
except subprocess.CalledProcessError as e:
|
|
61
|
+
raise RuntimeError(f"Failed to convert audio. You likely need to install ffmpeg {e.stderr}")
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def convert_to_opus_ogg_temp(input_file, bitrate="32k", sample_rate=24000):
|
|
65
|
+
"""
|
|
66
|
+
Convert an audio file to Opus format in an Ogg container and store in a temporary file.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
input_file (str): Path to the input audio file
|
|
70
|
+
bitrate (str, optional): Target bitrate for Opus encoding (default: "32k")
|
|
71
|
+
sample_rate (int, optional): Sample rate for output (default: 24000)
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
str: Path to the temporary file with the converted audio
|
|
75
|
+
|
|
76
|
+
Raises:
|
|
77
|
+
FileNotFoundError: If the input file doesn't exist
|
|
78
|
+
RuntimeError: If the ffmpeg conversion fails
|
|
79
|
+
"""
|
|
80
|
+
# Create a temporary file with .ogg extension
|
|
81
|
+
temp_file = tempfile.NamedTemporaryFile(suffix=".ogg", delete=False)
|
|
82
|
+
temp_file.close()
|
|
83
|
+
|
|
84
|
+
try:
|
|
85
|
+
# Convert the audio
|
|
86
|
+
convert_to_opus_ogg(input_file, temp_file.name, bitrate, sample_rate)
|
|
87
|
+
return temp_file.name
|
|
88
|
+
except Exception as e:
|
|
89
|
+
# Clean up the temporary file if conversion fails
|
|
90
|
+
if os.path.exists(temp_file.name):
|
|
91
|
+
os.unlink(temp_file.name)
|
|
92
|
+
raise e
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
if __name__ == "__main__":
|
|
96
|
+
# Example usage
|
|
97
|
+
import sys
|
|
98
|
+
|
|
99
|
+
if len(sys.argv) < 2:
|
|
100
|
+
print("Usage: python audio.py input_file [output_file]")
|
|
101
|
+
sys.exit(1)
|
|
102
|
+
|
|
103
|
+
input_file = sys.argv[1]
|
|
104
|
+
|
|
105
|
+
try:
|
|
106
|
+
result = convert_to_opus_ogg_temp(input_file)
|
|
107
|
+
print(f"Successfully converted to: {result}")
|
|
108
|
+
except Exception as e:
|
|
109
|
+
print(f"Error: {e}")
|
|
110
|
+
sys.exit(1)
|