Skip to main content
Glama

Video Downloader MCP Server

server.cpython-310.pyc19.9 kB
o PK�hk|�@s�dZddlZddlZddlZddlZddlZddlZddlZddlm Z ddl m Z m Z m Z mZddlmZmZddlmZzddlZWn eyQddlZYnwddlmZmZddlmZddlZddlmZej ej!d �e�"e#�Z$Gd d �d �Z%Gd d �d �Z&Gdd�d�Z'ed�Z(eGdd�d��Z)Gdd�d�Z*Gdd�d�Z+e(�,�de-ej.fdd��Z/e(�0�de1de2de-ej3fdd��Z4dd�Z5e#d kr�e�6e5��dSdS)!z� Video Downloader MCP Server Exposes video downloading and analysis capabilities as MCP tools, allowing LLMs to intelligently orchestrate video extraction workflows. �N)�Path)�Dict�List�Optional�Any)�urljoin�urlparse)� dataclass)�Server�NotificationOptions)�InitializationOptions)�levelc@sheZdZdZddeefdd�Zdeeeffdd�Z d ed edefd d �Z d d�Z ddefdd�Z dS)�SecureConfigManagerz4Manages secure configuration loading from TOML filesN� config_pathcCsJ|durt��dd}|jddd�|d|_nt|�|_|��|_dS)Nz.configzvideo-downloader-mcpT)�parents�exist_ok� config.toml)r�home�mkdirr� _load_config�config)�selfrZ config_dir�r�@/Users/slowbro/Workspaces/Sandbox/video-downloader-mcp/server.py�__init__&s   zSecureConfigManager.__init__�returnc Cs�ddiddgd�dd�ddd d �ddd �d �}|j��rdz"t|jd �� }t�|�}Wd�n1s3wY|�||�WStyc}zt�d|j�d|���t� d�|WYd}~Sd}~ww|� �|S)z6Load configuration from TOML file with secure defaults�defaultz~/video-downloaderT��)Zmp4ZwebmZmkvZaviZmovZm4aZmp3ZaacZoggZwavZvttZsrtZassZssa)Zenforce_location_restrictions�max_filename_length�allowed_extensionsZblock_path_traversalzbest[height<=1080]�%(title)s.%(ext)sr)Zdefault_formatZdefault_filename_templateZmax_download_size)Zlog_security_eventsZ log_downloads)�download_locationsZsecurityZytdlp�logging�rbNzError loading config from z: zUsing default configuration) r�exists�open�tomllib�load� _deep_merge� Exception�logger�error�info�_create_default_config)rZdefault_config�fZ user_config�errrr1s:�����  � ��z SecureConfigManager._load_config�base�updatecCs\|��}|��D]#\}}||vr't||t�r't|t�r'|�|||�||<q|||<q|S)zDeep merge two dictionaries)�copy�items� isinstance�dictr()rr0r1�result�key�valuerrrr(Ws   zSecureConfigManager._deep_mergec Cs�z,tt�j}|d}|��r%ddl}|�||j�t�d|j���WdSt� d�WdSt yG}zt� d|���WYd}~dSd}~ww)z!Create default configuration filerrNz!Created default configuration at z7Template config.toml not found, using built-in defaultsz!Failed to create default config: ) r�__file__�parentr$�shutil�copy2rr*r,�warningr)r+)rZ script_dirZtemplate_configr;r/rrrr-as ��z*SecureConfigManager._create_default_config�pathcCs@|�d�}|j}|D]}t|t�r||vr||}q |S|S)z#Get config value using dot notation�.)�splitrr4r5)rr>r�keysr8r7rrr�getqs  zSecureConfigManager.get�N) �__name__� __module__� __qualname__�__doc__r�strrrrrr(r-rBrrrrr#s & rc @speZdZdZdefdd�Zddededed eee ee effd d �Z ded efd d �Z ded efdd�Z dS)� PathValidatorz/Validates and sanitizes file paths for securityrcCs8||_t|�dg��|_|�dd�|_|�dd�|_dS)Nzsecurity.allowed_extensionszsecurity.max_filename_lengthrzsecurity.block_path_traversalT)r�setrBrr�block_traversal�rrrrrrszPathValidator.__init__Fr>�base_dir�skip_extension_checkrc CsBz�|jr |�|�r WdStj�|�}tj�|�s tj�||�}nWdStj�|�}tj�|�}|�|tj �sD||krDddd|��fWStj� |�}t |�|j kr\ddd|j �d�fWS|j r|stj�|�d���d �}|r||j vrddd |�d �fWSd |dfWSty�} zddd t| ���fWYd} ~ Sd} ~ ww)zz Validate a path against security constraints Returns: (is_valid, normalized_path, error_message) )FNz!Path traversal sequences detected)FNzAbsolute paths not allowedFNz Path escapes allowed directory: zFilename too long (max z chars)�r?zFile extension .z not allowedTzPath validation error: )rK�_contains_traversal�osr>� expanduser�isabs�join�realpath� startswith�sep�basename�lenrr�splitext�lower�lstripr)rH) rr>rMrN� full_path� normalizedZ base_real�filename�extr/rrr� validate_path�s.        ��zPathValidator.validate_pathcs&gd�}|���t�fdd�|D��S)z*Check if path contains traversal sequences)z../z..\z..\\z..//c3s�|]}|�vVqdSrCr)�.0�pattern�Z path_lowerrr� <genexpr>���z4PathValidator._contains_traversal.<locals>.<genexpr>)r[�any)rr>Zdangerous_patternsrrdrrP�sz!PathValidator._contains_traversal�templatecCs&gd�}|}|D]}|�|d�}q|S)z7Sanitize yt-dlp template variables to prevent injection)�|�&�;�$�`�>�<�_)�replace)rrhZdangerous_chars� sanitized�charrrr�sanitize_template_vars�s z$PathValidator.sanitize_template_varsN�F) rDrErFrGrrrH�bool�tuplerrarPrtrrrrrI|s .+rIc @s�eZdZdZdefdd�Zdeeeeefffdd�Zdeeeeefffdd �Z d ede e e ee effd d �Z dd ede ede ede e e ee effdd�Zd S)�LocationManagerz%Manages configured download locationsrcCs||_t|�|_d|_dSrC)rrI� validator�_locations_cacherLrrrr�s  zLocationManager.__init__rcCs|jdur |��|_|jS)z3Get all configured download locations with metadataN)rz�_build_locations)rrrr� get_locations�s  zLocationManager.get_locationsc Csi}|j�di�}|��D]s\}}tj�|�}z7tj|ddd�t�|tj�r4||dd|��d�||<nt � d|�d|�d ��||d d|�d �d�||<Wq t y�}z&t � d |�d|�d |���||d d|�dt |��d�d�||<WYd}~q d}~ww|S)z*Build locations dictionary with validationr!i�T)�moderzDownload location: )r>�original�writable� descriptionz Location z (z) is not writableFz (not writable)z!Failed to create/access location z): z (error: �)N)rrBr3rQr>rR�makedirs�access�W_OKr*r=r)r+rH)r� locationsZconfigured_locations� location_idr>Z expanded_pathr/rrrr{�s:  �  ����� z LocationManager._build_locationsr�cCsb|��}||vrt|���}ddd|�d|��fS||}|ds*ddd|�d�fSd|d dfS) zY Validate a location ID Returns: (is_valid, path, error_message) FNzUnknown location 'z'. Available: rz Location 'z' is not writableTr>)r|�listrA)rr�r�Z available�locationrrr�validate_location�s z!LocationManager.validate_locationN� relative_path�filename_templatec Csz|�|�\}}}|sdd|fS|r|rtj�||�}n|}n |r#|}n|j�dd�}|j�|�}d|v}|jj|||d�S)zh Construct a secure download path Returns: (is_valid, full_path, error_message) FNzytdlp.default_filename_templater z%()rN) r�rQr>rTrrBryrtra) rr�r�r��valid� base_pathr+Z full_relativeZhas_template_varsrrr�construct_download_paths  z'LocationManager.construct_download_path�NN)rDrErFrGrrrrHr|r{rwrvrr�r�rrrrrx�s$(���rx�video-downloaderc@s�eZdZUdZeed<eeed<eeed<eeed<eeed<eeed<eeed<ee ee fed <e eee eeffed <eed <d S) � VideoInfozStructured video information�title�duration� thumbnailr��uploader� upload_date� view_count�formats� subtitles� webpage_urlN) rDrErFrGrH�__annotations__r�intrrrrrrrr�)s        r�c @s�eZdZdZedefdd��Zeddededee ee ffdd ��Z ededee e ee ffd d ��Z edded eedeede ee ffdd��Zd S)�YtDlpExtractorzyt-dlp extraction wrapperrc Cs6z tjddgddd�WdStjtfyYdSw)zCheck if yt-dlp is available�yt-dlpz --versionT)�capture_output�checkF)� subprocess�run�CalledProcessError�FileNotFoundErrorrrrr�check_availability:s �z!YtDlpExtractor.check_availabilityF�url� extract_flatcCsXz!gd�}|r |�d�|�|�tj|ddddd�}t�|j�WSty+YdSw)z&Extract video information using yt-dlp)r�z-Jz --no-warningsz--flat-playlistT�)r��textr��timeoutN)�appendr�r��json�loads�stdoutr))r�r��cmdr6rrr� extract_infoCs   �zYtDlpExtractor.extract_infocCs"t�|�}|rd|vr|dSdS)z!Get available formats for a videor�N)r�r�)r�r,rrr� get_formatsQs  zYtDlpExtractor.get_formatsN� format_id� output_pathc Cs�dg}|r |�d|g�|r|�d|g�|�|�ztj|dddd�}d|j|jd�WStjyJ}zdt|�|j|jd�WYd }~Sd }~ww) zDownload video using yt-dlpr�z-fz-oT)r�r�r�)�successr��stderrF)r�r+r�r�N)�extendr�r�r�r�r�r�rH)r�r�r�r�r6r/rrr�download_videoYs( ����zYtDlpExtractor.download_videorur�)rDrErFrG� staticmethodrvr�rHrrrr�rr�r�rrrrr�7s& $2r�c @sneZdZdZededeefdd��Zedededeee effdd ��Z ededeeeffd d ��Z d S) �WebpageAnalyzerz/Fallback webpage analysis for unsupported sitesr�rcCs>zddi}tj||dd�}|��|jWStyYdSw)zFetch webpage source codez User-AgentzoMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36r�)�headersr�N)�requestsrBZraise_for_statusr�r))r�r�Zresponserrr�fetch_page_sourcexs� �z!WebpageAnalyzer.fetch_page_source� html_content�base_urlc Csddgddgddgdgdgd �}i}|��D]i\}}g||<|D]^}t�||tj�}|D]Q}t|t�r=t|�d kr=|d n|} t| t�rP| d rL| d n| d } | �d �r[d | ��} n| �d�rft|| �} n | �d�spt|| �} | ||vr}||� | �q,q q|S)z@Extract potential video/audio/subtitle URLs using regex patternsz.(["\'])(https?://[^"\']*\.mpd(?:\?[^"\']*)?)\1z7manifest["\']:\s*["\']([^"\']*\.mpd(?:\?[^"\']*)?)["\']z/(["\'])(https?://[^"\']*\.m3u8(?:\?[^"\']*)?)\1z8playlist["\']:\s*["\']([^"\']*\.m3u8(?:\?[^"\']*)?)["\']zC(["\'])(https?://[^"\']*\.(?:mp4|webm|mkv|avi|mov)(?:\?[^"\']*)?)\1z?src["\']:\s*["\']([^"\']*\.(?:mp4|webm|mkv)(?:\?[^"\']*)?)["\']zB(["\'])(https?://[^"\']*\.(?:mp3|m4a|aac|ogg|wav)(?:\?[^"\']*)?)\1z>(["\'])(https?://[^"\']*\.(?:vtt|srt|ass|ssa)(?:\?[^"\']*)?)\1)Z mpd_manifestsZm3u8_playlistsZ video_filesZ audio_filesZsubtitle_filesrOrz//zhttps:�/�http) r3�re�findall� IGNORECASEr4rwrYrVrr�) r�r��patternsZ extracted�categoryZ pattern_listrcZmatches�matchr�rrr�extract_video_patterns�sF������"        ���z&WebpageAnalyzer.extract_video_patternscCs�i}gd�}|D]}t�||tjtjB�}|r"|�d���|d<nqddg}|D]}t�||tj�}|rAt|�d��|d<|Sq)|S)z Extract video metadata from HTML)z<title[^>]*>([^<]+)</title>z&["\']title["\']:\s*["\']([^"\']+)["\']zE<meta[^>]*property=["\']og:title["\'][^>]*content=["\']([^"\']+)["\']rOr�z"duration["\']:\s*["\']?(\d+)["\']?z["\']duration["\']:\s*(\d+)r�)r��searchr��DOTALL�group�stripr�)r��metadataZtitle_patternsrcr�Zduration_patternsrrr�extract_metadata�s&���z WebpageAnalyzer.extract_metadataN) rDrErFrGr�rHrr�rrr�r�rrrrr�us $0 r�rc�s�tjddddddd�idgd�d �tjd d dddd d�idgd�d �tjd dddddd�idgd�d �tjdddddd�ddd�ddd�ddd�ddd�ddd�d�dgd�d �tjddddddd�idgd�d �tjddddddd�idgd�d �tjdd digd�d �gS)!z%List available video downloader tools�check_ytdlp_supportz8Check if a URL is supported by yt-dlp and get basic info�objectr��stringzVideo URL to check)�typer�)r�Z propertiesZrequired)�namer�Z inputSchema�get_video_infoz:Get detailed video information including available formatszVideo URL to analyze�get_video_formatsz5Get available video/audio formats and quality optionszVideo URL to get formats forr�z7Download video with specified format and output optionszVideo URL to downloadz)Specific format ID to download (optional)zPDownload location ID from configured locations (optional, defaults to 'default')z,Relative path within the location (optional)z7yt-dlp filename template (optional, defaults to config)zNDEPRECATED: Use location_id + relative_path instead. Full output path template)r�r�r�r�r�r��analyze_webpagez=Fallback: Analyze webpage for video content when yt-dlp failszWebpage URL to analyze�extract_media_patternszAExtract video/audio URLs from webpage HTML using pattern matchingz!Webpage URL to extract media from�get_download_locationsz'Get available secure download locations)�types�Toolrrrr�handle_list_tools�s�����������������������"�����������r�r�� argumentsc�sn�|dkrc|d}t��stjdt�ddd��d�gSt�|�}|rUtjdt�d|�d �|�d �|�d �|�d �|�d �|�d�rM|�dd�dd�dndd��d�gStjdt�ddd��d�gS|dkr�|d}t�|�}|s�tjdt�ddd��d�gStjdt�d|�d �|�d �|�d�|�d�|�d �|�d �|�d �|�d�t|�dg��t |�di�� ��d� �d�gS|dk�r8|d}t� |�}|s�tjdt�ddd��d�gSg}|D]J}|� |�d�|�d �|�d!�r�|�d!d"��d#�nd$|�d%�|�d&�|�d'�|�d(�|�d)�|�d*�|�d��r$|�dd�dd+�dndd,� �q�tjdt�d|d-��d�gS|d.k�r�|d}|�d�}d}d/|v�rW|d/}t �d0�naz:t�} t| �} |�d1d2�} |�d3�} |�d4�} | �| | | �\}}}|�s�tjdt�dd5|��d��d�gWS|}Wn&t�y�}ztjdt�dd6t|���d��d�gWYd}~Sd}~wwt�|||�}|�d7��r�||d8<| �d9d��r�t �d:|�d;|���tjdt�|�d�gS|d<k�r%|d}t�|�}|�stjdt�dd=d��d�gSt�|�}tjdt�d|t|�d>|��vd?|��vd@��d�gS|dAk�rj|d}t�|�}|�sDtjdt�dd=d��d�gSt�||�}t�|�}tdBdC�|��D��}tjdt�d|||dD��d�gS|dEk�r�zt�} t| �} | ��}tjdt�d|dF��d�gWSt�y�}ztjdt�ddGt|���d��d�gWYd}~Sd}~wwtdH|����)IzHandle tool callsr�r�r�Fz$yt-dlp is not installed or available)� supportedr+)r�r�Tr�r�r�r�r�r��N��z...)r�r�r�r�r�r�r�zURL not supported by yt-dlpr�z#Could not extract video information)r�r+r�r�r�r�) r�r�r�r�r�r�r�r�r�Z format_countZsubtitle_languagesr�zCould not get video formatsr�r`Zheight�unknown�pz audio-only�fps�vcodec�acodec�filesize�tbr� format_note�d) r�r`Z resolutionr�r�r�r�r�r�r�)r�r�r�r�z`Using deprecated output_path parameter. Consider using location_id + relative_path for security.r�rr�r�zPath validation failed: z*Failed to construct secure download path: r�Z download_pathzlogging.log_downloadszDownload completed: z -> r�zCould not fetch webpage contentz<videoz<iframe)r�r�Zcontent_lengthZhas_video_tagsZ has_iframer�css�|]}t|�VqdSrC)rY)rbZurlsrrrrerfz#handle_call_tool.<locals>.<genexpr>)r�Ztotal_media_urlsr�r�r�)r�r�z"Failed to get download locations: zUnknown tool: )r�r�r�� TextContentr��dumpsr�rBrYr�rAr�r�r*r=rrxr�r)rHr�r,r�r�r�r[r��sum�valuesr|� ValueError)r�r�r�r,r�Zprocessed_formats�fmtr�r�r�location_managerr�r�r�r�Z secure_pathr+r/r6r�r�r�Z total_foundr�rrr�handle_call_toolOs���� $�� �� ����  �� & � ��        �� � ���� �  ��   ��  ��  �� � � ���� r�c �sv�tjj��4IdH�#\}}t�||tddtjt�id�d��IdHWd�IdHdS1IdHs4wYdS)Nr�z0.1.0)Znotification_optionsZexperimental_capabilities)Z server_nameZserver_versionZ capabilities)�mcp�serverZstdioZ stdio_serverr�r Zget_capabilitiesr )Z read_streamZ write_streamrrr�mainCs��� �.�r��__main__)7rGZasyncior�r�r�r�rQr"�pathlibr�typingrrrr� urllib.parserrZ dataclassesr r&� ImportErrorZtomliZ mcp.serverr r Zmcp.server.modelsr Zmcp.server.stdior�Z mcp.typesr�Z basicConfig�INFOZ getLoggerrDr*rrIrxr�r�r�r�Z list_toolsr�r�r�Z call_toolrHr5r�r�r�r�rrrr�<module>sP     �   YCh >cvt�

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/chazmaniandinkle/video-downloader-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server